From d1761f8d6e1335f49d3ee64caae00c5e2d82e64e Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 24 Jul 2018 22:30:40 +0200 Subject: [PATCH] read the complete input file at once during inizialization instaed of reading the file line by line, and instaed of re-reading from the beginning in case of time stepping back. This saves a vast amount of simulation time if the input file is large. --- src/xspice/icm/analog/file_source/cfunc.mod | 202 +++++++++++++------- 1 file changed, 132 insertions(+), 70 deletions(-) diff --git a/src/xspice/icm/analog/file_source/cfunc.mod b/src/xspice/icm/analog/file_source/cfunc.mod index e48be0d64..dc52859bb 100644 --- a/src/xspice/icm/analog/file_source/cfunc.mod +++ b/src/xspice/icm/analog/file_source/cfunc.mod @@ -13,16 +13,18 @@ AUTHORS 20 May 2011 Thomas Sailer 03 Sep 2012 Holger Vogt 27 Feb 2017 Marcel Hendrix + 23 JUL 2018 Holger Vogt -MODIFICATIONS +MODIFICATIONS SUMMARY This file contains the model-specific routines used to functionally describe the file source code model used - to read an array of analog values per time step from a file. + to read an array from a file containing lines with + time and analog values, and returning them per time step. INTERFACES @@ -76,6 +78,14 @@ struct filesource_state { }; +struct infiledata { + double *datavec; + int vecallocated; + int maxoccupied; + int actpointer; + int size; +}; + typedef struct { double *amplinterval; /* the storage array for the @@ -87,6 +97,9 @@ typedef struct { struct filesource_state *state; /* the storage array for the filesource status. */ + struct infiledata *indata; /* the storage vector for the input data + sourced from file. */ + } Local_Data_t; @@ -108,6 +121,7 @@ MODIFICATIONS 07 Sept 2012 Holger Vogt 27 Feb 2017 Marcel Hendrix + 23 JUL 2018 Holger Vogt SUMMARY @@ -142,15 +156,18 @@ static void cm_filesource_callback(ARGS, Mif_Callback_Reason_t reason) { switch (reason) { - case MIF_CB_DESTROY: { - Local_Data_t *loc = STATIC_VAR (locdata); - fclose(loc->state->fp); - free(loc->state); - free(loc->amplinterval); - free(loc->timeinterval); - free(loc); - break; - } + case MIF_CB_DESTROY: { + Local_Data_t *loc = STATIC_VAR (locdata); + if (loc->state->fp) + fclose(loc->state->fp); + free(loc->state); + free(loc->amplinterval); + free(loc->timeinterval); + free(loc->indata->datavec); + free(loc->indata); + free(loc); + break; + } } } @@ -158,8 +175,10 @@ cm_filesource_callback(ARGS, Mif_Callback_Reason_t reason) void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. */ { int size = PORT_SIZE(out); + int stepsize = size + 1; int amplscalesize; int amploffssize; + int j; Local_Data_t *loc; /* Pointer to local static data, not to be included in the state vector */ @@ -169,7 +188,7 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. } if (INIT == 1) { - int i; + int i, count; CALLBACK = cm_filesource_callback; @@ -180,11 +199,18 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. /* Allocate storage for internal state */ loc->timeinterval = (double*)calloc(2, sizeof(double)); loc->amplinterval = (double*)calloc(2 * (size_t) size, sizeof(double)); - loc->state = (struct filesource_state*)malloc(sizeof(struct filesource_state)); + loc->state = (struct filesource_state*)malloc(sizeof(struct filesource_state)); + loc->indata = (struct infiledata*)malloc(sizeof(struct infiledata)); + loc->indata->datavec = (double*)malloc(sizeof(double) * stepsize * 1000); + loc->indata->vecallocated = stepsize * 1000; + loc->indata->maxoccupied = 0; + loc->indata->actpointer = 0; + loc->indata->size = stepsize; loc->timeinterval[0] = loc->timeinterval[1] = PARAM_NULL(timeoffset) ? 0.0 : PARAM(timeoffset); for (i = 0; i < size; ++i) loc->amplinterval[2 * i] = loc->amplinterval[2 * i + 1] = PARAM_NULL(amploffset) ? 0.0 : PARAM(amploffset[i]); + /* open the file */ loc->state->fp = fopen_with_path(PARAM(file), "r"); loc->state->atend = 0; if (!loc->state->fp) { @@ -195,82 +221,118 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. sprintf(p, "%s%s%s", lbuffer, DIR_PATHSEP, PARAM(file)); loc->state->fp = fopen(p, "r"); free(p); - } + } if (!loc->state->fp) { cm_message_printf("cannot open file %s", PARAM(file)); loc->state->atend = 1; } } + /* read, preprocess and store the data */ + amplscalesize = PARAM_NULL(amplscale) ? 0 : PARAM_SIZE(amplscale); + amploffssize = PARAM_NULL(amploffset) ? 0 : PARAM_SIZE(amploffset); + count = 0; + while (!loc->state->atend) { + char line[512]; + char *cp, *cpdel; + char *cp2; + double t, tprev = 0; + int i; + if (!fgets(line, sizeof(line), loc->state->fp)) { + loc->state->atend = 1; + break; + } + cpdel = cp = strdup(line); + + /* read the time channel; update the time difference */ + while (*cp && isspace_c(*cp)) + ++cp; + if (*cp == '#' || *cp == ';') { + free(cpdel); + continue; + } + t = strtod(cp, &cp2); + if (cp2 == cp) { + free(cpdel); + continue; + } + cp = cp2; + if (!PARAM_NULL(timescale)) + t *= PARAM(timescale); + if (!PARAM_NULL(timerelative) && PARAM(timerelative) == MIF_TRUE) + t += tprev; + else if (!PARAM_NULL(timeoffset)) + t += PARAM(timeoffset); + + tprev = t; + + /* before storing, check if vector size is large enough. + If not, add another 1000*size doubles */ + if (count > loc->indata->vecallocated - size) { + loc->indata->vecallocated += size * 1000; + loc->indata->datavec = (double*)realloc(loc->indata->datavec, sizeof(double) * loc->indata->vecallocated); + } + if(loc->indata->datavec == NULL){ + cm_message_printf("cannot allocate enough memory"); + break; // loc->state->atend = 1; + } + loc->indata->datavec[count++] = t; + + /* read the data channels; update the amplitude difference of each channel */ + for (i = 0; i < size; ++i) { + while (*cp && (isspace_c(*cp) || *cp == ',')) + ++cp; + t = strtod(cp, &cp2); + if (cp2 == cp) + break; + cp = cp2; + if (i < amplscalesize) + t *= PARAM(amplscale[i]); + if (i < amploffssize) + t += PARAM(amploffset[i]); + loc->indata->datavec[count++] = t; + } + free(cpdel); + } + loc->indata->maxoccupied = count; + + if(loc->state->fp) { + fclose(loc->state->fp); + loc->state->fp = NULL; + } + /* point to the next time */ + loc->indata->actpointer = stepsize; } - amplscalesize = PARAM_NULL(amplscale) ? 0 : PARAM_SIZE(amplscale); - amploffssize = PARAM_NULL(amploffset) ? 0 : PARAM_SIZE(amploffset); loc = STATIC_VAR (locdata); /* The file pointer is at the same position it was for the last simulator TIME ... * If TIME steps backward, for example due to a second invocation of a 'tran' analysis - * then we need to rewind the file to start from the beginning. + * step back in datavec[loc->indata->actpointer] . */ if (TIME < loc->timeinterval[0]) { - rewind(loc->state->fp); - loc->timeinterval[0] = loc->timeinterval[1] = PARAM_NULL(timeoffset) ? 0.0 : PARAM(timeoffset); + while (TIME < loc->indata->datavec[loc->indata->actpointer] && loc->indata->actpointer >= 0) + loc->indata->actpointer -= stepsize; + loc->timeinterval[0] = loc->indata->datavec[loc->indata->actpointer]; } + loc->timeinterval[1] = loc->indata->datavec[loc->indata->actpointer + stepsize]; - while (TIME >= loc->timeinterval[1] && !loc->state->atend) { - char line[512]; - char *cp, *cpdel; - char *cp2; - double t; - int i; - - if (!fgets(line, sizeof(line), loc->state->fp)) { - loc->state->atend = 1; - break; + while (TIME > loc->timeinterval[1]) { + loc->indata->actpointer += stepsize; + if (loc->indata->actpointer > loc->indata->maxoccupied) { + /* we are done */ + return; } - cpdel = cp = strdup(line); + loc->timeinterval[1] = loc->indata->datavec[loc->indata->actpointer]; + } + loc->timeinterval[0] = loc->indata->datavec[loc->indata->actpointer - stepsize]; - /* read the time channel; update the time difference */ - while (*cp && isspace_c(*cp)) - ++cp; - if (*cp == '#' || *cp == ';') { - free(cpdel); - continue; - } - t = strtod(cp, &cp2); - if (cp2 == cp) { - free(cpdel); - continue; - } - cp = cp2; - if (!PARAM_NULL(timescale)) - t *= PARAM(timescale); - if (!PARAM_NULL(timerelative) && PARAM(timerelative) == MIF_TRUE) - t += loc->timeinterval[1]; - else if (!PARAM_NULL(timeoffset)) - t += PARAM(timeoffset); - loc->timeinterval[0] = loc->timeinterval[1]; - loc->timeinterval[1] = t; - - /* read the channels; update the amplitude difference of each channel */ - for (i = 0; i < size; ++i) - loc->amplinterval[2 * i] = loc->amplinterval[2 * i + 1]; - for (i = 0; i < size; ++i) { - while (*cp && (isspace_c(*cp) || *cp == ',')) - ++cp; - t = strtod(cp, &cp2); - if (cp2 == cp) - break; - cp = cp2; - if (i < amplscalesize) - t *= PARAM(amplscale[i]); - if (i < amploffssize) - t += PARAM(amploffset[i]); - loc->amplinterval[2 * i + 1] = t; - } - free(cpdel); + for (j = 0; j < size; j++) { + loc->amplinterval[2 * j] = loc->indata->datavec[loc->indata->actpointer - stepsize + j + 1]; + loc->amplinterval[2 * j + 1] = loc->indata->datavec[loc->indata->actpointer + j + 1]; } - if (!loc->state->atend && loc->timeinterval[0] <= TIME && TIME <= loc->timeinterval[1]) { + + if (loc->timeinterval[0] <= TIME && TIME <= loc->timeinterval[1]) { if (!PARAM_NULL(amplstep) && PARAM(amplstep) == MIF_TRUE) { int i; for (i = 0; i < size; ++i)