1 /**********
2 Copyright 1990 Regents of the University of California. All rights reserved.
3 Author: 1988 Wayne A. Christopher, U. C. Berkeley CAD Group
4 Modified: 2000 AlansFixes, 2013/2015 patch by Krzysztof Blaszkowski
5 **********/
6
7 /*
8 * This module replaces the old "writedata" routines in nutmeg.
9 * Unlike the writedata routines, the OUT routines are only called by
10 * the simulator routines, and only call routines in nutmeg. The rest
11 * of nutmeg doesn't deal with OUT at all.
12 */
13
14 #include "ngspice/ngspice.h"
15 #include "ngspice/cpdefs.h"
16 #include "ngspice/ftedefs.h"
17 #include "ngspice/dvec.h"
18 #include "ngspice/plot.h"
19 #include "ngspice/sim.h"
20 #include "ngspice/inpdefs.h" /* for INPtables */
21 #include "ngspice/ifsim.h"
22 #include "ngspice/jobdefs.h"
23 #include "ngspice/iferrmsg.h"
24 #include "circuits.h"
25 #include "outitf.h"
26 #include "variable.h"
27 #include <fcntl.h>
28 #include "ngspice/cktdefs.h"
29 #include "ngspice/inpdefs.h"
30 #include "breakp2.h"
31 #include "runcoms.h"
32 #include "plotting/graf.h"
33 #include "../misc/misc_time.h"
34
35 extern char *spice_analysis_get_name(int index);
36 extern char *spice_analysis_get_description(int index);
37 extern int EVTsetup_plot(CKTcircuit* ckt, char* plotname);
38
39
40 static int beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analName,
41 char *refName, int refType, int numNames, char **dataNames, int dataType,
42 bool windowed, runDesc **runp);
43 static int addDataDesc(runDesc *run, char *name, int type, int ind, int meminit);
44 static int addSpecialDesc(runDesc *run, char *name, char *devname, char *param, int depind, int meminit);
45 static void fileInit(runDesc *run);
46 static void fileInit_pass2(runDesc *run);
47 static void fileStartPoint(FILE *fp, bool bin, int num);
48 static void fileAddRealValue(FILE *fp, bool bin, double value);
49 static void fileAddComplexValue(FILE *fp, bool bin, IFcomplex value);
50 static void fileEndPoint(FILE *fp, bool bin);
51 static void fileEnd(runDesc *run);
52 static void plotInit(runDesc *run);
53 static void plotAddRealValue(dataDesc *desc, double value);
54 static void plotAddComplexValue(dataDesc *desc, IFcomplex value);
55 static void plotEnd(runDesc *run);
56 static bool parseSpecial(char *name, char *dev, char *param, char *ind);
57 static bool name_eq(char *n1, char *n2);
58 static bool getSpecial(dataDesc *desc, runDesc *run, IFvalue *val);
59 static void freeRun(runDesc *run);
60 static int InterpFileAdd(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr);
61 static int InterpPlotAdd(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr);
62
63 /*Output data to spice module*/
64 #ifdef TCL_MODULE
65 #include "ngspice/tclspice.h"
66 #elif defined SHARED_MODULE
67 extern int sh_ExecutePerLoop(void);
68 extern int sh_vecinit(runDesc *run);
69 #endif
70
71 /*Suppressing progress info in -o option */
72 #ifndef HAS_WINGUI
73 extern bool orflag;
74 #endif
75
76 // fixme
77 // ugly hack to work around missing api to specify the "type" of signals
78 int fixme_onoise_type = SV_NOTYPE;
79 int fixme_inoise_type = SV_NOTYPE;
80
81
82 #define DOUBLE_PRECISION 15
83
84
85 static clock_t lastclock, currclock, startclock;
86 static double *rowbuf;
87 static size_t column, rowbuflen;
88
89 static bool shouldstop = FALSE; /* Tell simulator to stop next time it asks. */
90
91 static bool interpolated = FALSE;
92 static double *valueold, *valuenew;
93
94 #ifdef SHARED_MODULE
95 static bool savenone = FALSE;
96 #endif
97
98 /* The two "begin plot" routines share all their internals... */
99
100 int
OUTpBeginPlot(CKTcircuit * circuitPtr,JOB * analysisPtr,IFuid analName,IFuid refName,int refType,int numNames,IFuid * dataNames,int dataType,runDesc ** plotPtr)101 OUTpBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr,
102 IFuid analName,
103 IFuid refName, int refType,
104 int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr)
105 {
106 char *name;
107
108 if (ft_curckt->ci_ckt == circuitPtr)
109 name = ft_curckt->ci_name;
110 else
111 name = "circuit name";
112
113 return (beginPlot(analysisPtr, circuitPtr, name,
114 analName, refName, refType, numNames,
115 dataNames, dataType, FALSE,
116 plotPtr));
117 }
118
119
120 int
OUTwBeginPlot(CKTcircuit * circuitPtr,JOB * analysisPtr,IFuid analName,IFuid refName,int refType,int numNames,IFuid * dataNames,int dataType,runDesc ** plotPtr)121 OUTwBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr,
122 IFuid analName,
123 IFuid refName, int refType,
124 int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr)
125 {
126
127 return (beginPlot(analysisPtr, circuitPtr, "circuit name",
128 analName, refName, refType, numNames,
129 dataNames, dataType, TRUE,
130 plotPtr));
131 }
132
133
134 static int
beginPlot(JOB * analysisPtr,CKTcircuit * circuitPtr,char * cktName,char * analName,char * refName,int refType,int numNames,char ** dataNames,int dataType,bool windowed,runDesc ** runp)135 beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analName, char *refName, int refType, int numNames, char **dataNames, int dataType, bool windowed, runDesc **runp)
136 {
137 runDesc *run;
138 struct save_info *saves;
139 bool *savesused = NULL;
140 int numsaves;
141 int i, j, depind = 0;
142 char namebuf[BSIZE_SP], parambuf[BSIZE_SP], depbuf[BSIZE_SP];
143 char *ch, tmpname[BSIZE_SP];
144 bool saveall = TRUE;
145 bool savealli = FALSE;
146 char *an_name;
147 int initmem;
148 /*to resume a run saj
149 *All it does is reassign the file pointer and return (requires *runp to be NULL if this is not needed)
150 */
151
152 if (dataType == 666 && numNames == 666) {
153 run = *runp;
154 run->writeOut = ft_getOutReq(&run->fp, &run->runPlot, &run->binary,
155 run->type, run->name);
156
157 } else {
158 /*end saj*/
159
160 /* Check to see if we want to print informational data. */
161 if (cp_getvar("printinfo", CP_BOOL, NULL, 0))
162 fprintf(cp_err, "(debug printing enabled)\n");
163
164 /* Check to see if we want to save only interpolated data. */
165 if (cp_getvar("interp", CP_BOOL, NULL, 0)) {
166 interpolated = TRUE;
167 fprintf(cp_out, "Warning: Interpolated raw file data!\n\n");
168 }
169
170 *runp = run = TMALLOC(struct runDesc, 1);
171
172 /* First fill in some general information. */
173 run->analysis = analysisPtr;
174 run->circuit = circuitPtr;
175 run->name = copy(cktName);
176 run->type = copy(analName);
177 run->windowed = windowed;
178 run->numData = 0;
179
180 an_name = spice_analysis_get_name(analysisPtr->JOBtype);
181 ft_curckt->ci_last_an = an_name;
182
183 /* Now let's see which of these things we need. First toss in the
184 * reference vector. Then toss in anything that getSaves() tells
185 * us to save that we can find in the name list. Finally unpack
186 * the remaining saves into parameters.
187 */
188 numsaves = ft_getSaves(&saves);
189 if (numsaves) {
190 savesused = TMALLOC(bool, numsaves);
191 saveall = FALSE;
192 for (i = 0; i < numsaves; i++) {
193 if (saves[i].analysis && !cieq(saves[i].analysis, an_name)) {
194 /* ignore this one this time around */
195 savesused[i] = TRUE;
196 continue;
197 }
198
199 /* Check for ".save all" and new synonym ".save allv" */
200
201 if (cieq(saves[i].name, "all") || cieq(saves[i].name, "allv")) {
202 saveall = TRUE;
203 savesused[i] = TRUE;
204 saves[i].used = 1;
205 continue;
206 }
207
208 /* And now for the new ".save alli" option */
209
210 if (cieq(saves[i].name, "alli")) {
211 savealli = TRUE;
212 savesused[i] = TRUE;
213 saves[i].used = 1;
214 continue;
215 }
216 #ifdef SHARED_MODULE
217 /* this may happen if shared ngspice*/
218 if (cieq(saves[i].name, "none")) {
219 savenone = TRUE;
220 saveall = TRUE;
221 savesused[i] = TRUE;
222 saves[i].used = 1;
223 continue;
224 }
225 #endif
226 }
227 }
228
229 if (numsaves && !saveall)
230 initmem = numsaves;
231 else
232 initmem = numNames;
233
234 /* Pass 0. */
235 if (refName) {
236 addDataDesc(run, refName, refType, -1, initmem);
237 for (i = 0; i < numsaves; i++)
238 if (!savesused[i] && name_eq(saves[i].name, refName)) {
239 savesused[i] = TRUE;
240 saves[i].used = 1;
241 }
242 } else {
243 run->refIndex = -1;
244 }
245
246
247 /* Pass 1. */
248 if (numsaves && !saveall) {
249 for (i = 0; i < numsaves; i++) {
250 if (!savesused[i]) {
251 for (j = 0; j < numNames; j++) {
252 if (name_eq(saves[i].name, dataNames[j])) {
253 addDataDesc(run, dataNames[j], dataType, j, initmem);
254 savesused[i] = TRUE;
255 saves[i].used = 1;
256 break;
257 }
258 /* generate a vector of real time information */
259 else if (ft_ngdebug && refName && eq(refName, "time") && eq(saves[i].name, "speedcheck")) {
260 addDataDesc(run, "speedcheck", IF_REAL, j, initmem);
261 savesused[i] = TRUE;
262 saves[i].used = 1;
263 break;
264 }
265 }
266 }
267 }
268 } else {
269 for (i = 0; i < numNames; i++)
270 if (!refName || !name_eq(dataNames[i], refName))
271 /* Save the node as long as it's an internal device node */
272 if (!strstr(dataNames[i], "#internal") &&
273 !strstr(dataNames[i], "#source") &&
274 !strstr(dataNames[i], "#drain") &&
275 !strstr(dataNames[i], "#collector") &&
276 !strstr(dataNames[i], "#emitter") &&
277 !strstr(dataNames[i], "#base"))
278 {
279 addDataDesc(run, dataNames[i], dataType, i, initmem);
280 }
281 /* generate a vector of real time information */
282 if (ft_ngdebug && refName && eq(refName, "time")) {
283 addDataDesc(run, "speedcheck", IF_REAL, numNames, initmem);
284 }
285 }
286
287 /* Pass 1 and a bit.
288 This is a new pass which searches for all the internal device
289 nodes, and saves the terminal currents instead */
290
291 if (savealli) {
292 depind = 0;
293 for (i = 0; i < numNames; i++) {
294 if (strstr(dataNames[i], "#internal") ||
295 strstr(dataNames[i], "#source") ||
296 strstr(dataNames[i], "#drain") ||
297 strstr(dataNames[i], "#collector") ||
298 strstr(dataNames[i], "#emitter") ||
299 strstr(dataNames[i], "#base"))
300 {
301 tmpname[0] = '@';
302 tmpname[1] = '\0';
303 strncat(tmpname, dataNames[i], BSIZE_SP-1);
304 ch = strchr(tmpname, '#');
305
306 if (strstr(ch, "#collector")) {
307 strcpy(ch, "[ic]");
308 } else if (strstr(ch, "#base")) {
309 strcpy(ch, "[ib]");
310 } else if (strstr(ch, "#emitter")) {
311 strcpy(ch, "[ie]");
312 if (parseSpecial(tmpname, namebuf, parambuf, depbuf))
313 addSpecialDesc(run, tmpname, namebuf, parambuf, depind, initmem);
314 strcpy(ch, "[is]");
315 } else if (strstr(ch, "#drain")) {
316 strcpy(ch, "[id]");
317 if (parseSpecial(tmpname, namebuf, parambuf, depbuf))
318 addSpecialDesc(run, tmpname, namebuf, parambuf, depind, initmem);
319 strcpy(ch, "[ig]");
320 } else if (strstr(ch, "#source")) {
321 strcpy(ch, "[is]");
322 if (parseSpecial(tmpname, namebuf, parambuf, depbuf))
323 addSpecialDesc(run, tmpname, namebuf, parambuf, depind, initmem);
324 strcpy(ch, "[ib]");
325 } else if (strstr(ch, "#internal") && (tmpname[1] == 'd')) {
326 strcpy(ch, "[id]");
327 } else {
328 fprintf(cp_err,
329 "Debug: could output current for %s\n", tmpname);
330 continue;
331 }
332 if (parseSpecial(tmpname, namebuf, parambuf, depbuf)) {
333 if (*depbuf) {
334 fprintf(stderr,
335 "Warning : unexpected dependent variable on %s\n", tmpname);
336 } else {
337 addSpecialDesc(run, tmpname, namebuf, parambuf, depind, initmem);
338 }
339 }
340 }
341 }
342 }
343
344
345 /* Pass 2. */
346 for (i = 0; i < numsaves; i++) {
347
348 if (savesused[i])
349 continue;
350
351 if (!parseSpecial(saves[i].name, namebuf, parambuf, depbuf)) {
352 if (saves[i].analysis)
353 fprintf(cp_err, "Warning: can't parse '%s': ignored\n",
354 saves[i].name);
355 continue;
356 }
357
358 /* Now, if there's a dep variable, do we already have it? */
359 if (*depbuf) {
360 for (j = 0; j < run->numData; j++)
361 if (name_eq(depbuf, run->data[j].name))
362 break;
363 if (j == run->numData) {
364 /* Better add it. */
365 for (j = 0; j < numNames; j++)
366 if (name_eq(depbuf, dataNames[j]))
367 break;
368 if (j == numNames) {
369 fprintf(cp_err,
370 "Warning: can't find '%s': value '%s' ignored\n",
371 depbuf, saves[i].name);
372 continue;
373 }
374 addDataDesc(run, dataNames[j], dataType, j, initmem);
375 savesused[i] = TRUE;
376 saves[i].used = 1;
377 depind = j;
378 } else {
379 depind = run->data[j].outIndex;
380 }
381 }
382
383 addSpecialDesc(run, saves[i].name, namebuf, parambuf, depind, initmem);
384 }
385
386 if (numsaves) {
387 for (i = 0; i < numsaves; i++) {
388 tfree(saves[i].analysis);
389 tfree(saves[i].name);
390 }
391 tfree(saves);
392 tfree(savesused);
393 }
394
395 if (numNames &&
396 ((run->numData == 1 && run->refIndex != -1) ||
397 (run->numData == 0 && run->refIndex == -1)))
398 {
399 fprintf(cp_err, "Error: no data saved for %s; analysis not run\n",
400 spice_analysis_get_description(analysisPtr->JOBtype));
401 return E_NOTFOUND;
402 }
403
404 /* Now that we have our own data structures built up, let's see what
405 * nutmeg wants us to do.
406 */
407 run->writeOut = ft_getOutReq(&run->fp, &run->runPlot, &run->binary,
408 run->type, run->name);
409
410 if (run->writeOut) {
411 fileInit(run);
412 } else {
413 plotInit(run);
414 if (refName)
415 run->runPlot->pl_ndims = 1;
416 #ifdef XSPICE
417 /* set the current plot name into the event job */
418 if (run->runPlot->pl_typename)
419 EVTsetup_plot(run->circuit, run->runPlot->pl_typename);
420 #endif
421 }
422 }
423
424 /* define storage for old and new data, to allow interpolation */
425 if (interpolated && run->circuit->CKTcurJob->JOBtype == 4) {
426 valueold = TMALLOC(double, run->numData);
427 for (i = 0; i < run->numData; i++)
428 valueold[i] = 0.0;
429 valuenew = TMALLOC(double, run->numData);
430 }
431
432 /*Start BLT, initilises the blt vectors saj*/
433 #ifdef TCL_MODULE
434 blt_init(run);
435 #elif defined SHARED_MODULE
436 sh_vecinit(run);
437 #endif
438
439 startclock = clock();
440 return (OK);
441 }
442
443 /* Initialze memory for the list of all vectors in the current plot.
444 Add a standard vector to this plot */
445 static int
addDataDesc(runDesc * run,char * name,int type,int ind,int meminit)446 addDataDesc(runDesc *run, char *name, int type, int ind, int meminit)
447 {
448 dataDesc *data;
449
450 /* initialize memory (for all vectors or given by 'save') */
451 if (!run->numData) {
452 /* even if input 0, do a malloc */
453 run->data = TMALLOC(dataDesc, ++meminit);
454 run->maxData = meminit;
455 }
456 /* If there is need for more memory */
457 else if (run->numData == run->maxData) {
458 run->maxData = (int)(run->maxData * 1.1) + 1;
459 run->data = TREALLOC(dataDesc, run->data, run->maxData);
460 }
461
462 data = &run->data[run->numData];
463 /* so freeRun will get nice NULL pointers for the fields we don't set */
464 memset(data, 0, sizeof(dataDesc));
465
466 data->name = copy(name);
467 data->type = type;
468 data->gtype = GRID_LIN;
469 data->regular = TRUE;
470 data->outIndex = ind;
471
472 /* It's the reference vector. */
473 if (ind == -1)
474 run->refIndex = run->numData;
475
476 run->numData++;
477
478 return (OK);
479 }
480
481 /* Initialze memory for the list of all vectors in the current plot.
482 Add a special vector (e.g. @q1[ib]) to this plot */
483 static int
addSpecialDesc(runDesc * run,char * name,char * devname,char * param,int depind,int meminit)484 addSpecialDesc(runDesc *run, char *name, char *devname, char *param, int depind, int meminit)
485 {
486 dataDesc *data;
487 char *unique, *freeunique; /* unique char * from back-end */
488 int ret;
489
490 if (!run->numData) {
491 /* even if input 0, do a malloc */
492 run->data = TMALLOC(dataDesc, ++meminit);
493 run->maxData = meminit;
494 }
495 else if (run->numData == run->maxData) {
496 run->maxData = (int)(run->maxData * 1.1) + 1;
497 run->data = TREALLOC(dataDesc, run->data, run->maxData);
498 }
499
500 data = &run->data[run->numData];
501 /* so freeRun will get nice NULL pointers for the fields we don't set */
502 memset(data, 0, sizeof(dataDesc));
503
504 data->name = copy(name);
505
506 freeunique = unique = copy(devname);
507
508 /* unique will be overridden, if it already exists */
509 ret = INPinsertNofree(&unique, ft_curckt->ci_symtab);
510 data->specName = unique;
511
512 if (ret == E_EXISTS)
513 tfree(freeunique);
514
515 data->specParamName = copy(param);
516
517 data->specIndex = depind;
518 data->specType = -1;
519 data->specFast = NULL;
520 data->regular = FALSE;
521
522 run->numData++;
523
524 return (OK);
525 }
526
527
528 static void
OUTpD_memory(runDesc * run,IFvalue * refValue,IFvalue * valuePtr)529 OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
530 {
531 int i, n = run->numData;
532
533 for (i = 0; i < n; i++) {
534
535 dataDesc *d;
536
537 #ifdef TCL_MODULE
538 /*Locks the blt vector to stop access*/
539 blt_lockvec(i);
540 #endif
541
542 d = &run->data[i];
543
544 if (d->outIndex == -1) {
545 if (d->type == IF_REAL)
546 plotAddRealValue(d, refValue->rValue);
547 else if (d->type == IF_COMPLEX)
548 plotAddComplexValue(d, refValue->cValue);
549 } else if (d->regular) {
550 if (ft_ngdebug && d->type == IF_REAL && eq(d->name, "speedcheck")) {
551 /* current time */
552 clock_t cl = clock();
553 double tt = ((double)cl - (double)startclock) / CLOCKS_PER_SEC;
554 plotAddRealValue(d, tt);
555 }
556 else if (d->type == IF_REAL)
557 plotAddRealValue(d, valuePtr->v.vec.rVec[d->outIndex]);
558 else if (d->type == IF_COMPLEX)
559 plotAddComplexValue(d, valuePtr->v.vec.cVec[d->outIndex]);
560 } else {
561 IFvalue val;
562
563 /* should pre-check instance */
564 if (!getSpecial(d, run, &val))
565 continue;
566
567 if (d->type == IF_REAL)
568 plotAddRealValue(d, val.rValue);
569 else if (d->type == IF_COMPLEX)
570 plotAddComplexValue(d, val.cValue);
571 else
572 fprintf(stderr, "OUTpData: unsupported data type\n");
573 }
574
575 #ifdef TCL_MODULE
576 /*relinks and unlocks vector*/
577 blt_relink(i, d->vec);
578 #endif
579
580 }
581 }
582
583
584 int
OUTpData(runDesc * plotPtr,IFvalue * refValue,IFvalue * valuePtr)585 OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr)
586 {
587 runDesc *run = plotPtr; // FIXME
588 int i;
589
590 run->pointCount++;
591
592 #ifdef TCL_MODULE
593 steps_completed = run->pointCount;
594 #endif
595 /* interpolated batch mode output to file/plot in transient analysis */
596 if (interpolated && run->circuit->CKTcurJob->JOBtype == 4) {
597 if (run->writeOut) { /* To file */
598 InterpFileAdd(run, refValue, valuePtr);
599 }
600 else { /* To plot */
601 InterpPlotAdd(run, refValue, valuePtr);
602 }
603 return OK;
604 }
605
606 /* standard batch mode output to file */
607 else if (run->writeOut) {
608 if (run->pointCount == 1) {
609 fileInit_pass2(run);
610 }
611
612 fileStartPoint(run->fp, run->binary, run->pointCount);
613
614 if (run->refIndex != -1) {
615 if (run->isComplex) {
616 fileAddComplexValue(run->fp, run->binary, refValue->cValue);
617
618 /* While we're looking at the reference value, print it to the screen
619 every quarter of a second, to give some feedback without using
620 too much CPU time */
621 #ifndef HAS_WINGUI
622 if (!orflag && !ft_norefprint) {
623 currclock = clock();
624 if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) {
625 fprintf(stderr, " Reference value : % 12.5e\r",
626 refValue->cValue.real);
627 lastclock = currclock;
628 }
629 }
630 #endif
631 }
632 else { /* And the same for a non-complex (real) value */
633 fileAddRealValue(run->fp, run->binary, refValue->rValue);
634 #ifndef HAS_WINGUI
635 if (!orflag && !ft_norefprint) {
636 currclock = clock();
637 if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) {
638 fprintf(stderr, " Reference value : % 12.5e\r",
639 refValue->rValue);
640 lastclock = currclock;
641 }
642 }
643 #endif
644 }
645 }
646
647 for (i = 0; i < run->numData; i++) {
648 /* we've already printed reference vec first */
649 if (run->data[i].outIndex == -1) {
650 continue;
651 }
652
653 #ifdef TCL_MODULE
654 blt_add(i, refValue ? refValue->rValue : NAN);
655 #endif
656
657 if (run->data[i].regular) {
658 if (run->data[i].type == IF_REAL)
659 fileAddRealValue(run->fp, run->binary,
660 valuePtr->v.vec.rVec [run->data[i].outIndex]);
661 else if (run->data[i].type == IF_COMPLEX)
662 fileAddComplexValue(run->fp, run->binary,
663 valuePtr->v.vec.cVec [run->data[i].outIndex]);
664 else
665 fprintf(stderr, "OUTpData: unsupported data type\n");
666 }
667 else {
668 IFvalue val;
669 /* should pre-check instance */
670 if (!getSpecial(&run->data[i], run, &val)) {
671
672 /* If this is the first data point, print a warning for any unrecognized
673 variables, since this has not already been checked */
674
675 if (run->pointCount == 1)
676 fprintf(stderr, "Warning: unrecognized variable - %s\n",
677 run->data[i].name);
678
679 if (run->isComplex) {
680 val.cValue.real = 0;
681 val.cValue.imag = 0;
682 fileAddComplexValue(run->fp, run->binary, val.cValue);
683 }
684 else {
685 val.rValue = 0;
686 fileAddRealValue(run->fp, run->binary, val.rValue);
687 }
688
689 continue;
690 }
691
692 if (run->data[i].type == IF_REAL)
693 fileAddRealValue(run->fp, run->binary, val.rValue);
694 else if (run->data[i].type == IF_COMPLEX)
695 fileAddComplexValue(run->fp, run->binary, val.cValue);
696 else
697 fprintf(stderr, "OUTpData: unsupported data type\n");
698 }
699
700 #ifdef TCL_MODULE
701 blt_add(i, valuePtr->v.vec.rVec [run->data[i].outIndex]);
702 #endif
703
704 }
705
706 fileEndPoint(run->fp, run->binary);
707
708 /* Check that the write to disk completed successfully, otherwise abort */
709
710 if (ferror(run->fp)) {
711 fprintf(stderr, "Warning: rawfile write error !!\n");
712 shouldstop = TRUE;
713 }
714
715 }
716 else {
717 OUTpD_memory(run, refValue, valuePtr);
718
719 /* This is interactive mode. Update the screen with the reference
720 variable just the same */
721
722 #ifndef HAS_WINGUI
723 if (!orflag && !ft_norefprint) {
724 currclock = clock();
725 if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) {
726 if (run->isComplex) {
727 fprintf(stderr, " Reference value : % 12.5e\r",
728 refValue ? refValue->cValue.real : NAN);
729 } else {
730 fprintf(stderr, " Reference value : % 12.5e\r",
731 refValue ? refValue->rValue : NAN);
732 }
733 lastclock = currclock;
734 }
735 }
736 #endif
737
738 gr_iplot(run->runPlot);
739 }
740
741 if (ft_bpcheck(run->runPlot, run->pointCount) == FALSE)
742 shouldstop = TRUE;
743
744 #ifdef TCL_MODULE
745 Tcl_ExecutePerLoop();
746 #elif defined SHARED_MODULE
747 sh_ExecutePerLoop();
748 #endif
749
750 return OK;
751 } /* end of function OUTpData */
752
753
754
OUTwReference(runDesc * plotPtr,IFvalue * valuePtr,void ** refPtr)755 int OUTwReference(runDesc*plotPtr, IFvalue *valuePtr, void **refPtr)
756 {
757 NG_IGNORE(refPtr);
758 NG_IGNORE(valuePtr);
759 NG_IGNORE(plotPtr);
760
761 return OK;
762 }
763
764
765 int
OUTwData(runDesc * plotPtr,int dataIndex,IFvalue * valuePtr,void * refPtr)766 OUTwData(runDesc *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr)
767 {
768 NG_IGNORE(refPtr);
769 NG_IGNORE(valuePtr);
770 NG_IGNORE(dataIndex);
771 NG_IGNORE(plotPtr);
772
773 return OK;
774 }
775
776
777 int
OUTwEnd(runDesc * plotPtr)778 OUTwEnd(runDesc *plotPtr)
779 {
780 NG_IGNORE(plotPtr);
781
782 return OK;
783 }
784
785
786 int
OUTendPlot(runDesc * plotPtr)787 OUTendPlot(runDesc *plotPtr)
788 {
789 if (plotPtr->writeOut) {
790 fileEnd(plotPtr);
791 } else {
792 gr_end_iplot();
793 plotEnd(plotPtr);
794 }
795
796 tfree(valueold);
797 tfree(valuenew);
798
799 freeRun(plotPtr);
800
801 return (OK);
802 }
803
804
805 int
OUTbeginDomain(runDesc * plotPtr,IFuid refName,int refType,IFvalue * outerRefValue)806 OUTbeginDomain(runDesc *plotPtr, IFuid refName, int refType, IFvalue *outerRefValue)
807 {
808 NG_IGNORE(outerRefValue);
809 NG_IGNORE(refType);
810 NG_IGNORE(refName);
811 NG_IGNORE(plotPtr);
812
813 return (OK);
814 }
815
816
817 int
OUTendDomain(runDesc * plotPtr)818 OUTendDomain(runDesc *plotPtr)
819 {
820 NG_IGNORE(plotPtr);
821
822 return (OK);
823 }
824
825
826 int
OUTattributes(runDesc * plotPtr,IFuid varName,int param,IFvalue * value)827 OUTattributes(runDesc *plotPtr, IFuid varName, int param, IFvalue *value)
828 {
829 runDesc *run = plotPtr; // FIXME
830 GRIDTYPE type;
831
832 struct dvec *d;
833
834 NG_IGNORE(value);
835
836 if (param == OUT_SCALE_LIN)
837 type = GRID_LIN;
838 else if (param == OUT_SCALE_LOG)
839 type = GRID_XLOG;
840 else
841 return E_UNSUPP;
842
843 if (run->writeOut) {
844 if (varName) {
845 int i;
846 for (i = 0; i < run->numData; i++)
847 if (!strcmp(varName, run->data[i].name))
848 run->data[i].gtype = type;
849 } else {
850 run->data[run->refIndex].gtype = type;
851 }
852 } else {
853 if (varName) {
854 for (d = run->runPlot->pl_dvecs; d; d = d->v_next)
855 if (!strcmp(varName, d->v_name))
856 d->v_gridtype = type;
857 } else if (param == PLOT_COMB) {
858 for (d = run->runPlot->pl_dvecs; d; d = d->v_next)
859 d->v_plottype = PLOT_COMB;
860 } else {
861 run->runPlot->pl_scale->v_gridtype = type;
862 }
863 }
864
865 return (OK);
866 }
867
868
869 /* The file writing routines.
870 Write a raw file in batch mode (-b and -r flags).
871 Writing a raw file in interactive or control mode is handled
872 by raw_write() in rawfile.c */
873 static void
fileInit(runDesc * run)874 fileInit(runDesc *run)
875 {
876 char buf[513];
877 int i;
878 size_t n;
879
880 lastclock = clock();
881
882 /* This is a hack. */
883 run->isComplex = FALSE;
884 for (i = 0; i < run->numData; i++)
885 if (run->data[i].type == IF_COMPLEX)
886 run->isComplex = TRUE;
887
888 n = 0;
889 sprintf(buf, "Title: %s\n", run->name);
890 n += strlen(buf);
891 fputs(buf, run->fp);
892 sprintf(buf, "Date: %s\n", datestring());
893 n += strlen(buf);
894 fputs(buf, run->fp);
895 sprintf(buf, "Plotname: %s\n", run->type);
896 n += strlen(buf);
897 fputs(buf, run->fp);
898 sprintf(buf, "Flags: %s\n", run->isComplex ? "complex" : "real");
899 n += strlen(buf);
900 fputs(buf, run->fp);
901 sprintf(buf, "No. Variables: %d\n", run->numData);
902 n += strlen(buf);
903 fputs(buf, run->fp);
904 sprintf(buf, "No. Points: ");
905 n += strlen(buf);
906 fputs(buf, run->fp);
907
908 fflush(run->fp); /* Gotta do this for LATTICE. */
909 if (run->fp == stdout || (run->pointPos = ftell(run->fp)) <= 0)
910 run->pointPos = (long) n;
911 fprintf(run->fp, "0 \n"); /* Save 8 spaces here. */
912
913 /*fprintf(run->fp, "Command: version %s\n", ft_sim->version);*/
914 fprintf(run->fp, "Variables:\n");
915
916 printf("No. of Data Columns : %d \n", run->numData);
917 }
918
919
920 static int
guess_type(const char * name)921 guess_type(const char *name)
922 {
923 int type;
924
925 if (substring("#branch", name))
926 type = SV_CURRENT;
927 else if (cieq(name, "time"))
928 type = SV_TIME;
929 else if ( cieq(name, "speedcheck"))
930 type = SV_TIME;
931 else if (cieq(name, "frequency"))
932 type = SV_FREQUENCY;
933 else if (ciprefix("inoise", name))
934 type = fixme_inoise_type;
935 else if (ciprefix("onoise", name))
936 type = fixme_onoise_type;
937 else if (cieq(name, "temp-sweep"))
938 type = SV_TEMP;
939 else if (cieq(name, "res-sweep"))
940 type = SV_RES;
941 else if (cieq(name, "i-sweep"))
942 type = SV_CURRENT;
943 else if ((*name == '@') && substring("[g", name)) /* token starting with [g */
944 type = SV_ADMITTANCE;
945 else if ((*name == '@') && substring("[c", name))
946 type = SV_CAPACITANCE;
947 else if ((*name == '@') && substring("[i", name))
948 type = SV_CURRENT;
949 else if ((*name == '@') && substring("[q", name))
950 type = SV_CHARGE;
951 else if ((*name == '@') && substring("[p]", name)) /* token is exactly [p] */
952 type = SV_POWER;
953 else
954 type = SV_VOLTAGE;
955
956 return type;
957 }
958
959
960 static void
fileInit_pass2(runDesc * run)961 fileInit_pass2(runDesc *run)
962 {
963 int i, type;
964
965 for (i = 0; i < run->numData; i++) {
966
967 char *name = run->data[i].name;
968
969 type = guess_type(name);
970
971 if (type == SV_CURRENT) {
972 char *branch = strstr(name, "#branch");
973 if (branch)
974 *branch = '\0';
975 fprintf(run->fp, "\t%d\ti(%s)\t%s", i, name, ft_typenames(type));
976 if (branch)
977 *branch = '#';
978 } else if (type == SV_VOLTAGE) {
979 fprintf(run->fp, "\t%d\tv(%s)\t%s", i, name, ft_typenames(type));
980 } else {
981 fprintf(run->fp, "\t%d\t%s\t%s", i, name, ft_typenames(type));
982 }
983
984 if (run->data[i].gtype == GRID_XLOG)
985 fprintf(run->fp, "\tgrid=3");
986
987 fprintf(run->fp, "\n");
988 }
989
990 fprintf(run->fp, "%s:\n", run->binary ? "Binary" : "Values");
991 fflush(run->fp);
992
993 /* Allocate Row buffer */
994
995 if (run->binary) {
996 rowbuflen = (size_t) (run->numData);
997 if (run->isComplex)
998 rowbuflen *= 2;
999 rowbuf = TMALLOC(double, rowbuflen);
1000 } else {
1001 rowbuflen = 0;
1002 rowbuf = NULL;
1003 }
1004 }
1005
1006
1007 static void
fileStartPoint(FILE * fp,bool bin,int num)1008 fileStartPoint(FILE *fp, bool bin, int num)
1009 {
1010 if (!bin)
1011 fprintf(fp, "%d\t", num - 1);
1012
1013 /* reset buffer pointer to zero */
1014
1015 column = 0;
1016 }
1017
1018
1019 static void
fileAddRealValue(FILE * fp,bool bin,double value)1020 fileAddRealValue(FILE *fp, bool bin, double value)
1021 {
1022 if (bin)
1023 rowbuf[column++] = value;
1024 else
1025 fprintf(fp, "\t%.*e\n", DOUBLE_PRECISION, value);
1026 }
1027
1028
1029 static void
fileAddComplexValue(FILE * fp,bool bin,IFcomplex value)1030 fileAddComplexValue(FILE *fp, bool bin, IFcomplex value)
1031 {
1032 if (bin) {
1033 rowbuf[column++] = value.real;
1034 rowbuf[column++] = value.imag;
1035 } else {
1036 fprintf(fp, "\t%.*e,%.*e\n", DOUBLE_PRECISION, value.real,
1037 DOUBLE_PRECISION, value.imag);
1038 }
1039 }
1040
1041
1042 static void
fileEndPoint(FILE * fp,bool bin)1043 fileEndPoint(FILE *fp, bool bin)
1044 {
1045 /* write row buffer to file */
1046 /* otherwise the data has already been written */
1047
1048 if (bin)
1049 fwrite(rowbuf, sizeof(double), rowbuflen, fp);
1050 }
1051
1052
1053 /* Here's the hack... Run back and fill in the number of points. */
1054
1055 static void
fileEnd(runDesc * run)1056 fileEnd(runDesc *run)
1057 {
1058 if (run->fp != stdout) {
1059 long place = ftell(run->fp);
1060 fseek(run->fp, run->pointPos, SEEK_SET);
1061 fprintf(run->fp, "%d", run->pointCount);
1062 fprintf(stdout, "\nNo. of Data Rows : %d\n", run->pointCount);
1063 fseek(run->fp, place, SEEK_SET);
1064 } else {
1065 /* Yet another hack-around */
1066 fprintf(stderr, "@@@ %ld %d\n", run->pointPos, run->pointCount);
1067 }
1068
1069 fflush(run->fp);
1070
1071 tfree(rowbuf);
1072 }
1073
1074
1075 /* The plot maintenance routines. */
1076
1077 static void
plotInit(runDesc * run)1078 plotInit(runDesc *run)
1079 {
1080 struct plot *pl = plot_alloc(run->type);
1081 struct dvec *v;
1082 int i;
1083
1084 pl->pl_title = copy(run->name);
1085 pl->pl_name = copy(run->type);
1086 pl->pl_date = copy(datestring());
1087 pl->pl_ndims = 0;
1088 plot_new(pl);
1089 plot_setcur(pl->pl_typename);
1090 run->runPlot = pl;
1091
1092 /* This is a hack. */
1093 /* if any of them complex, make them all complex */
1094 run->isComplex = FALSE;
1095 for (i = 0; i < run->numData; i++)
1096 if (run->data[i].type == IF_COMPLEX)
1097 run->isComplex = TRUE;
1098
1099 for (i = 0; i < run->numData; i++) {
1100 dataDesc *dd = &run->data[i];
1101 char *name;
1102
1103 if (isdigit_c(dd->name[0]))
1104 name = tprintf("V(%s)", dd->name);
1105 else
1106 name = copy(dd->name);
1107
1108 v = dvec_alloc(name,
1109 guess_type(name),
1110 run->isComplex
1111 ? (VF_COMPLEX | VF_PERMANENT)
1112 : (VF_REAL | VF_PERMANENT),
1113 0, NULL);
1114
1115 vec_new(v);
1116 dd->vec = v;
1117 }
1118 }
1119
1120 /* prepare the vector length data for memory allocation
1121 If new, and tran or pss, length is TSTOP / TSTEP plus some margin.
1122 If allocated length is exceeded, check progress. When > 20% then extrapolate memory needed,
1123 if less than 20% then just double the size.
1124 If not tran or pss, return fixed value (1024) of memory to be added.
1125 */
1126 static inline int
vlength2delta(int len)1127 vlength2delta(int len)
1128 {
1129 #ifdef SHARED_MODULE
1130 if (savenone)
1131 /* We need just a vector length of 1 */
1132 return 1;
1133 #endif
1134 /* TSTOP / TSTEP */
1135 int points = ft_curckt->ci_ckt->CKTtimeListSize;
1136 /* transient and pss analysis (points > 0) upon start */
1137 if (len == 0 && points > 0) {
1138 /* number of timesteps plus some overhead */
1139 return points + 100;
1140 }
1141 /* transient and pss if original estimate is exceeded */
1142 else if (points > 0) {
1143 /* check where we are */
1144 double timerel = ft_curckt->ci_ckt->CKTtime / ft_curckt->ci_ckt->CKTfinalTime;
1145 /* return an estimate of the appropriate number of time points, if more than 20% of
1146 the anticipated total time has passed */
1147 if (timerel > 0.2)
1148 return (int)(len / timerel) - len + 1;
1149 /* If not, just double the available memory */
1150 else
1151 return len;
1152 }
1153 /* other analysis types that do not set CKTtimeListSize */
1154 else
1155 return 1024;
1156 }
1157
1158
1159 static void
plotAddRealValue(dataDesc * desc,double value)1160 plotAddRealValue(dataDesc *desc, double value)
1161 {
1162 struct dvec *v = desc->vec;
1163
1164 #ifdef SHARED_MODULE
1165 if (savenone)
1166 /* always save new data to same location */
1167 v->v_length = 0;
1168 #endif
1169
1170 if (v->v_length >= v->v_alloc_length)
1171 dvec_extend(v, v->v_length + vlength2delta(v->v_length));
1172
1173 if (isreal(v)) {
1174 v->v_realdata[v->v_length] = value;
1175 } else {
1176 /* a real parading as a VF_COMPLEX */
1177 v->v_compdata[v->v_length].cx_real = value;
1178 v->v_compdata[v->v_length].cx_imag = 0.0;
1179 }
1180
1181 v->v_length++;
1182 v->v_dims[0] = v->v_length; /* va, must be updated */
1183 }
1184
1185
1186 static void
plotAddComplexValue(dataDesc * desc,IFcomplex value)1187 plotAddComplexValue(dataDesc *desc, IFcomplex value)
1188 {
1189 struct dvec *v = desc->vec;
1190
1191 #ifdef SHARED_MODULE
1192 if (savenone)
1193 v->v_length = 0;
1194 #endif
1195
1196 if (v->v_length >= v->v_alloc_length)
1197 dvec_extend(v, v->v_length + vlength2delta(v->v_length));
1198
1199 v->v_compdata[v->v_length].cx_real = value.real;
1200 v->v_compdata[v->v_length].cx_imag = value.imag;
1201
1202 v->v_length++;
1203 v->v_dims[0] = v->v_length; /* va, must be updated */
1204 }
1205
1206
1207 static void
plotEnd(runDesc * run)1208 plotEnd(runDesc *run)
1209 {
1210 fprintf(stdout, "\nNo. of Data Rows : %d\n", run->pointCount);
1211 }
1212
1213
1214 /* ParseSpecial takes something of the form "@name[param,index]" and rips
1215 * out name, param, andstrchr.
1216 */
1217
1218 static bool
parseSpecial(char * name,char * dev,char * param,char * ind)1219 parseSpecial(char *name, char *dev, char *param, char *ind)
1220 {
1221 char *s;
1222
1223 *dev = *param = *ind = '\0';
1224
1225 if (*name != '@')
1226 return FALSE;
1227 name++;
1228
1229 s = dev;
1230 while (*name && (*name != '['))
1231 *s++ = *name++;
1232 *s = '\0';
1233
1234 if (!*name)
1235 return TRUE;
1236 name++;
1237
1238 s = param;
1239 while (*name && (*name != ',') && (*name != ']'))
1240 *s++ = *name++;
1241 *s = '\0';
1242
1243 if (*name == ']')
1244 return (!name[1] ? TRUE : FALSE);
1245 else if (!*name)
1246 return FALSE;
1247 name++;
1248
1249 s = ind;
1250 while (*name && (*name != ']'))
1251 *s++ = *name++;
1252 *s = '\0';
1253
1254 if (*name && !name[1])
1255 return TRUE;
1256 else
1257 return FALSE;
1258 }
1259
1260
1261 /* This routine must match two names with or without a V() around them. */
1262
1263 static bool
name_eq(char * n1,char * n2)1264 name_eq(char *n1, char *n2)
1265 {
1266 char buf1[BSIZE_SP], buf2[BSIZE_SP], *s;
1267
1268 if ((s = strchr(n1, '(')) != NULL) {
1269 strcpy(buf1, s);
1270 if ((s = strchr(buf1, ')')) == NULL)
1271 return FALSE;
1272 *s = '\0';
1273 n1 = buf1;
1274 }
1275
1276 if ((s = strchr(n2, '(')) != NULL) {
1277 strcpy(buf2, s);
1278 if ((s = strchr(buf2, ')')) == NULL)
1279 return FALSE;
1280 *s = '\0';
1281 n2 = buf2;
1282 }
1283
1284 return (strcmp(n1, n2) ? FALSE : TRUE);
1285 }
1286
1287
1288 static bool
getSpecial(dataDesc * desc,runDesc * run,IFvalue * val)1289 getSpecial(dataDesc *desc, runDesc *run, IFvalue *val)
1290 {
1291 IFvalue selector;
1292 struct variable *vv;
1293
1294 selector.iValue = desc->specIndex;
1295 if (INPaName(desc->specParamName, val, run->circuit, &desc->specType,
1296 desc->specName, &desc->specFast, ft_sim, &desc->type,
1297 &selector) == OK) {
1298 desc->type &= (IF_REAL | IF_COMPLEX); /* mask out other bits */
1299 return TRUE;
1300 }
1301
1302 if ((vv = if_getstat(run->circuit, &desc->name[1])) != NULL) {
1303 /* skip @ sign */
1304 desc->type = IF_REAL;
1305 if (vv->va_type == CP_REAL)
1306 val->rValue = vv->va_real;
1307 else if (vv->va_type == CP_NUM)
1308 val->rValue = vv->va_num;
1309 else if (vv->va_type == CP_BOOL)
1310 val->rValue = (vv->va_bool ? 1.0 : 0.0);
1311 else
1312 return FALSE; /* not a real */
1313 tfree(vv);
1314 return TRUE;
1315 }
1316
1317 return FALSE;
1318 }
1319
1320
1321 static void
freeRun(runDesc * run)1322 freeRun(runDesc *run)
1323 {
1324 int i;
1325
1326 for (i = 0; i < run->numData; i++) {
1327 tfree(run->data[i].name);
1328 tfree(run->data[i].specParamName);
1329 }
1330
1331 tfree(run->data);
1332 tfree(run->type);
1333 tfree(run->name);
1334
1335 tfree(run);
1336 }
1337
1338
1339 int
OUTstopnow(void)1340 OUTstopnow(void)
1341 {
1342 if (ft_intrpt || shouldstop) {
1343 ft_intrpt = shouldstop = FALSE;
1344 return (1);
1345 }
1346
1347 return (0);
1348 }
1349
1350
1351 /* Print out error messages. */
1352
1353 static struct mesg {
1354 char *string;
1355 long flag;
1356 } msgs[] = {
1357 { "Warning", ERR_WARNING } ,
1358 { "Fatal error", ERR_FATAL } ,
1359 { "Panic", ERR_PANIC } ,
1360 { "Note", ERR_INFO } ,
1361 { NULL, 0 }
1362 };
1363
1364
1365 void
OUTerror(int flags,char * format,IFuid * names)1366 OUTerror(int flags, char *format, IFuid *names)
1367 {
1368 struct mesg *m;
1369 char buf[BSIZE_SP], *s, *bptr;
1370 int nindex = 0;
1371
1372 if ((flags == ERR_INFO) && cp_getvar("printinfo", CP_BOOL, NULL, 0))
1373 return;
1374
1375 for (m = msgs; m->flag; m++)
1376 if (flags & m->flag)
1377 fprintf(cp_err, "%s: ", m->string);
1378
1379 for (s = format, bptr = buf; *s; s++) {
1380 if (*s == '%' && (s == format || s[-1] != '%') && s[1] == 's') {
1381 if (names[nindex])
1382 strcpy(bptr, names[nindex]);
1383 else
1384 strcpy(bptr, "(null)");
1385 bptr += strlen(bptr);
1386 s++;
1387 nindex++;
1388 } else {
1389 *bptr++ = *s;
1390 }
1391 }
1392
1393 *bptr = '\0';
1394 fprintf(cp_err, "%s\n", buf);
1395 fflush(cp_err);
1396 }
1397
1398
1399 void
OUTerrorf(int flags,const char * format,...)1400 OUTerrorf(int flags, const char *format, ...)
1401 {
1402 struct mesg *m;
1403 va_list args;
1404
1405 if ((flags == ERR_INFO) && cp_getvar("printinfo", CP_BOOL, NULL, 0))
1406 return;
1407
1408 for (m = msgs; m->flag; m++)
1409 if (flags & m->flag)
1410 fprintf(cp_err, "%s: ", m->string);
1411
1412 va_start (args, format);
1413
1414 vfprintf(cp_err, format, args);
1415 fputc('\n', cp_err);
1416
1417 fflush(cp_err);
1418
1419 va_end(args);
1420 }
1421
1422
1423 static int
InterpFileAdd(runDesc * run,IFvalue * refValue,IFvalue * valuePtr)1424 InterpFileAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
1425 {
1426 int i;
1427 static double timeold = 0.0, timenew = 0.0, timestep = 0.0;
1428 bool nodata = FALSE;
1429 bool interpolatenow = FALSE;
1430
1431 if (run->pointCount == 1) {
1432 fileInit_pass2(run);
1433 timestep = run->circuit->CKTinitTime + run->circuit->CKTstep;
1434 }
1435
1436 if (run->refIndex != -1) {
1437 /* Save first time step */
1438 if (refValue->rValue == run->circuit->CKTinitTime) {
1439 timeold = refValue->rValue;
1440 fileStartPoint(run->fp, run->binary, run->pointCount);
1441 fileAddRealValue(run->fp, run->binary, run->circuit->CKTinitTime);
1442 interpolatenow = nodata = FALSE;
1443 }
1444 /* Save last time step */
1445 else if (refValue->rValue == run->circuit->CKTfinalTime) {
1446 timeold = refValue->rValue;
1447 fileStartPoint(run->fp, run->binary, run->pointCount);
1448 fileAddRealValue(run->fp, run->binary, run->circuit->CKTfinalTime);
1449 interpolatenow = nodata = FALSE;
1450 }
1451 /* Save exact point */
1452 else if (refValue->rValue == timestep) {
1453 timeold = refValue->rValue;
1454 fileStartPoint(run->fp, run->binary, run->pointCount);
1455 fileAddRealValue(run->fp, run->binary, timestep);
1456 timestep += run->circuit->CKTstep;
1457 interpolatenow = nodata = FALSE;
1458 }
1459 else if (refValue->rValue > timestep) {
1460 /* add the next time step value to the vector */
1461 fileStartPoint(run->fp, run->binary, run->pointCount);
1462 timenew = refValue->rValue;
1463 fileAddRealValue(run->fp, run->binary, timestep);
1464 timestep += run->circuit->CKTstep;
1465 nodata = FALSE;
1466 interpolatenow = TRUE;
1467 }
1468 else {
1469 /* Do not save this step */
1470 run->pointCount--;
1471 timeold = refValue->rValue;
1472 nodata = TRUE;
1473 interpolatenow = FALSE;
1474 }
1475 #ifndef HAS_WINGUI
1476 if (!orflag && !ft_norefprint) {
1477 currclock = clock();
1478 if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) {
1479 fprintf(stderr, " Reference value : % 12.5e\r",
1480 refValue->rValue);
1481 lastclock = currclock;
1482 }
1483 }
1484 #endif
1485
1486 }
1487
1488 for (i = 0; i < run->numData; i++) {
1489 /* we've already printed reference vec first */
1490 if (run->data[i].outIndex == -1)
1491 continue;
1492
1493 #ifdef TCL_MODULE
1494 blt_add(i, refValue ? refValue->rValue : NAN);
1495 #endif
1496
1497 if (run->data[i].regular) {
1498 /* Store value or interpolate and store or do not store any value to file */
1499 if (!interpolatenow && !nodata) {
1500 /* store the first or last value */
1501 valueold[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1502 fileAddRealValue(run->fp, run->binary, valueold[i]);
1503 }
1504 else if (interpolatenow) {
1505 /* Interpolate time if actual time is greater than proposed next time step */
1506 double newval;
1507 valuenew[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1508 newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
1509 fileAddRealValue(run->fp, run->binary, newval);
1510 valueold[i] = valuenew[i];
1511 }
1512 else if (nodata)
1513 /* Just keep the transient output value corresponding to timeold,
1514 but do not store to file */
1515 valueold[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1516 } else {
1517 IFvalue val;
1518 /* should pre-check instance */
1519 if (!getSpecial(&run->data[i], run, &val)) {
1520
1521 /* If this is the first data point, print a warning for any unrecognized
1522 variables, since this has not already been checked */
1523 if (run->pointCount == 1)
1524 fprintf(stderr, "Warning: unrecognized variable - %s\n",
1525 run->data[i].name);
1526 val.rValue = 0;
1527 fileAddRealValue(run->fp, run->binary, val.rValue);
1528 continue;
1529 }
1530 if (!interpolatenow && !nodata) {
1531 /* store the first or last value */
1532 valueold[i] = val.rValue;
1533 fileAddRealValue(run->fp, run->binary, valueold[i]);
1534 }
1535 else if (interpolatenow) {
1536 /* Interpolate time if actual time is greater than proposed next time step */
1537 double newval;
1538 valuenew[i] = val.rValue;
1539 newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
1540 fileAddRealValue(run->fp, run->binary, newval);
1541 valueold[i] = valuenew[i];
1542 }
1543 else if (nodata)
1544 /* Just keep the transient output value corresponding to timeold,
1545 but do not store to file */
1546 valueold[i] = val.rValue;
1547 }
1548
1549 #ifdef TCL_MODULE
1550 blt_add(i, valuePtr->v.vec.rVec [run->data[i].outIndex]);
1551 #endif
1552
1553 }
1554
1555 fileEndPoint(run->fp, run->binary);
1556
1557 /* Check that the write to disk completed successfully, otherwise abort */
1558 if (ferror(run->fp)) {
1559 fprintf(stderr, "Warning: rawfile write error !!\n");
1560 shouldstop = TRUE;
1561 }
1562
1563 if (ft_bpcheck(run->runPlot, run->pointCount) == FALSE)
1564 shouldstop = TRUE;
1565
1566 #ifdef TCL_MODULE
1567 Tcl_ExecutePerLoop();
1568 #elif defined SHARED_MODULE
1569 sh_ExecutePerLoop();
1570 #endif
1571 return(OK);
1572 }
1573
1574 static int
InterpPlotAdd(runDesc * run,IFvalue * refValue,IFvalue * valuePtr)1575 InterpPlotAdd(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
1576 {
1577 int i, iscale = -1;
1578 static double timeold = 0.0, timenew = 0.0, timestep = 0.0;
1579 bool nodata = FALSE;
1580 bool interpolatenow = FALSE;
1581
1582 if (run->pointCount == 1)
1583 timestep = run->circuit->CKTinitTime + run->circuit->CKTstep;
1584
1585 /* find the scale vector */
1586 for (i = 0; i < run->numData; i++)
1587 if (run->data[i].outIndex == -1) {
1588 iscale = i;
1589 break;
1590 }
1591 if (iscale == -1)
1592 fprintf(stderr, "Error: no scale vector found\n");
1593
1594 #ifdef TCL_MODULE
1595 /*Locks the blt vector to stop access*/
1596 blt_lockvec(iscale);
1597 #endif
1598
1599 /* Save first time step */
1600 if (refValue->rValue == run->circuit->CKTinitTime) {
1601 timeold = refValue->rValue;
1602 plotAddRealValue(&run->data[iscale], refValue->rValue);
1603 interpolatenow = nodata = FALSE;
1604 }
1605 /* Save last time step */
1606 else if (refValue->rValue == run->circuit->CKTfinalTime) {
1607 timeold = refValue->rValue;
1608 plotAddRealValue(&run->data[iscale], run->circuit->CKTfinalTime);
1609 interpolatenow = nodata = FALSE;
1610 }
1611 /* Save exact point */
1612 else if (refValue->rValue == timestep) {
1613 timeold = refValue->rValue;
1614 plotAddRealValue(&run->data[iscale], timestep);
1615 timestep += run->circuit->CKTstep;
1616 interpolatenow = nodata = FALSE;
1617 }
1618 else if (refValue->rValue > timestep) {
1619 /* add the next time step value to the vector */
1620 timenew = refValue->rValue;
1621 plotAddRealValue(&run->data[iscale], timestep);
1622 timestep += run->circuit->CKTstep;
1623 nodata = FALSE;
1624 interpolatenow = TRUE;
1625 }
1626 else {
1627 /* Do not save this step */
1628 run->pointCount--;
1629 timeold = refValue->rValue;
1630 nodata = TRUE;
1631 interpolatenow = FALSE;
1632 }
1633
1634 #ifdef TCL_MODULE
1635 /*relinks and unlocks vector*/
1636 blt_relink(iscale, (run->data[iscale]).vec);
1637 #endif
1638
1639 #ifndef HAS_WINGUI
1640 if (!orflag && !ft_norefprint) {
1641 currclock = clock();
1642 if ((currclock-lastclock) > (0.25*CLOCKS_PER_SEC)) {
1643 fprintf(stderr, " Reference value : % 12.5e\r",
1644 refValue->rValue);
1645 lastclock = currclock;
1646 }
1647 }
1648 #endif
1649
1650 for (i = 0; i < run->numData; i++) {
1651 if (i == iscale)
1652 continue;
1653
1654 #ifdef TCL_MODULE
1655 /*Locks the blt vector to stop access*/
1656 blt_lockvec(i);
1657 #endif
1658
1659 if (run->data[i].regular) {
1660 /* Store value or interpolate and store or do not store any value to file */
1661 if (!interpolatenow && !nodata) {
1662 /* store the first or last value */
1663 valueold[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1664 plotAddRealValue(&run->data[i], valueold[i]);
1665 }
1666 else if (interpolatenow) {
1667 /* Interpolate time if actual time is greater than proposed next time step */
1668 double newval;
1669 valuenew[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1670 newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
1671 plotAddRealValue(&run->data[i], newval);
1672 valueold[i] = valuenew[i];
1673 }
1674 else if (nodata)
1675 /* Just keep the transient output value corresponding to timeold,
1676 but do not store to file */
1677 valueold[i] = valuePtr->v.vec.rVec [run->data[i].outIndex];
1678 } else {
1679 IFvalue val;
1680 /* should pre-check instance */
1681 if (!getSpecial(&run->data[i], run, &val))
1682 continue;
1683 if (!interpolatenow && !nodata) {
1684 /* store the first or last value */
1685 valueold[i] = val.rValue;
1686 plotAddRealValue(&run->data[i], valueold[i]);
1687 }
1688 else if (interpolatenow) {
1689 /* Interpolate time if actual time is greater than proposed next time step */
1690 double newval;
1691 valuenew[i] = val.rValue;
1692 newval = (timestep - run->circuit->CKTstep - timeold)/(timenew - timeold) * (valuenew[i] - valueold[i]) + valueold[i];
1693 plotAddRealValue(&run->data[i], newval);
1694 valueold[i] = valuenew[i];
1695 }
1696 else if (nodata)
1697 /* Just keep the transient output value corresponding to timeold,
1698 but do not store to file */
1699 valueold[i] = val.rValue;
1700 }
1701
1702 #ifdef TCL_MODULE
1703 /*relinks and unlocks vector*/
1704 blt_relink(i, (run->data[i]).vec);
1705 #endif
1706
1707 }
1708
1709 gr_iplot(run->runPlot);
1710
1711 if (ft_bpcheck(run->runPlot, run->pointCount) == FALSE)
1712 shouldstop = TRUE;
1713
1714 #ifdef TCL_MODULE
1715 Tcl_ExecutePerLoop();
1716 #elif defined SHARED_MODULE
1717 sh_ExecutePerLoop();
1718 #endif
1719
1720 return(OK);
1721 }
1722