1 /**********
2 Copyright 1990 Regents of the University of California.  All rights reserved.
3 Author: 1988 Jaijeet S Roychowdhury
4 **********/
5 
6 #include "ngspice/ngspice.h"
7 #include "ngspice/cktdefs.h"
8 #include "ngspice/distodef.h"
9 #include "ngspice/sperror.h"
10 
11 
12 static void
DISswap(double ** a,double ** b)13 DISswap(double **a, double **b)
14 {
15     SWAP(double *, *a, *b);
16 }
17 
18 static void
DmemAlloc(double ** a,int size)19 DmemAlloc(double **a, int size)
20 {
21 *a = TMALLOC(double, size + 1);
22 }
23 
24 
25 
26 static void
DstorAlloc(double *** header,int size)27 DstorAlloc(double ***header, int size)
28 {
29 *header = TMALLOC(double *, size);
30 }
31 
32 
33 
34 int
DISTOan(CKTcircuit * ckt,int restart)35 DISTOan(CKTcircuit *ckt, int restart)
36 {
37 
38     double freq;
39     static	double freqTol;	/* tolerence parameter for finding final frequency */
40     static int NoOfPoints;
41     static int size;
42     static int displacement;
43     int error;
44     int i;
45     int numNames;
46     IFuid *nameList;
47     IFuid freqUid;
48     runDesc *acPlot = NULL;
49     DISTOAN *job = (DISTOAN *) ckt->CKTcurJob;
50     static char *nof2src = "No source with f2 distortion input";
51 #ifdef DISTODEBUG
52     double time,time1;
53 #endif
54 
55         NG_IGNORE(restart);
56 
57 
58 		/* start at beginning */
59 
60 #ifdef D_DBG_BLOCKTIMES
61 time1 = SPfrontEnd->IFseconds();
62 #endif
63         switch(job->DstepType) {
64 
65         case DECADE:
66             job->DfreqDelta =
67 					exp(log(10.0)/job->DnumSteps);
68 		freqTol = job->DfreqDelta *
69 				job->DstopF1 * ckt->CKTreltol;
70 	    NoOfPoints = 1 + (int)floor ((job->DnumSteps) / log(10.0) * log((job->DstopF1+freqTol)/(job->DstartF1)));
71             break;
72         case OCTAVE:
73             job->DfreqDelta =
74 					exp(log(2.0)/job->DnumSteps);
75 		freqTol = job->DfreqDelta *
76 				job->DstopF1 * ckt->CKTreltol;
77 	    NoOfPoints = 1 + (int)floor ((job->DnumSteps) / log(2.0) * log((job->DstopF1+freqTol)/(job->DstartF1)));
78             break;
79         case LINEAR:
80             job->DfreqDelta =
81 					(job->DstopF1 -
82 					job->DstartF1)/
83 					(job->DnumSteps+1);
84 		freqTol = job->DfreqDelta * ckt->CKTreltol;
85 					NoOfPoints = job->DnumSteps+1+ (int)floor(freqTol/(job->DfreqDelta));
86             break;
87         default:
88             return(E_BADPARM);
89         }
90 
91 	error = CKTop(ckt,
92 		(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT,
93 		(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT,
94 		ckt->CKTdcMaxIter);
95 	if(error) return(error);
96 
97 	ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
98 	error = CKTload(ckt);
99 	if(error) return(error);
100 
101 	error = CKTnames(ckt,&numNames,&nameList);
102 	if(error) return(error);
103 
104 	if (ckt->CKTkeepOpInfo) {
105 	    /* Dump operating point. */
106             error = SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob,
107                                                "Distortion Operating Point",
108                                                NULL, IF_REAL,
109                                                numNames, nameList, IF_REAL,
110                                                &acPlot);
111 	    if(error) return(error);
112 	    CKTdump(ckt, 0.0, acPlot);
113 	    SPfrontEnd->OUTendPlot (acPlot);
114 	    acPlot = NULL;
115 	}
116 
117 #ifdef D_DBG_BLOCKTIMES
118 time1 = SPfrontEnd->IFseconds() - time1;
119 printf("Time for initial work (including op. pt.): %g seconds \n", time1);
120 #endif
121 
122 #ifdef D_DBG_BLOCKTIMES
123 time1 = SPfrontEnd->IFseconds();
124 #endif
125 	error = CKTdisto(ckt,D_SETUP);
126 #ifdef D_DBG_BLOCKTIMES
127 time1 = SPfrontEnd->IFseconds() - time1;
128 printf("Time outside D_SETUP: %g seconds \n", time1);
129 #endif
130 	if (error) return(error);
131 
132 	displacement = 0;
133 
134 #ifdef D_DBG_BLOCKTIMES
135 time1 = SPfrontEnd->IFseconds();
136 #endif
137         freq = job->DstartF1;
138 	if (job->Df2wanted) {
139 	/*
140 	omegadelta = 2.0 * M_PI * freq *(1. - job->Df2ovrF1);
141 	*/
142     /* keeping f2 const to be compatible with spectre */
143 	job->Domega2 = 2.0 * M_PI * freq * job->Df2ovrF1;
144 	}
145 	DstorAlloc( &(job->r1H1stor),NoOfPoints+2);
146 	DstorAlloc( &(job->r2H11stor),NoOfPoints+2);
147 	DstorAlloc( &(job->i1H1stor),NoOfPoints+2);
148 	DstorAlloc( &(job->i2H11stor),NoOfPoints+2);
149 	size = SMPmatSize(ckt->CKTmatrix);
150 	if (! job->r1H1ptr)
151 		{
152 		DmemAlloc( &(job->r1H1ptr) , size+2);
153 		if (! job->r1H1ptr) return (E_NOMEM);
154 		}
155 
156 	if (! job->r2H11ptr)
157 		{
158 		DmemAlloc( &(job->r2H11ptr) , size+2);
159 		if (! job->r2H11ptr) return (E_NOMEM);
160 		}
161 	if (! job->i1H1ptr)
162 		{
163 		DmemAlloc( &(job->i1H1ptr) , size+2);
164 		if (! job->i1H1ptr) return (E_NOMEM);
165 		}
166 
167 	if (! job->i2H11ptr)
168 		{
169 		DmemAlloc( &(job->i2H11ptr) , size+2);
170 		if (! job->i2H11ptr) return (E_NOMEM);
171 		}
172 
173 	if (! (job->Df2wanted))
174 		{
175 		DstorAlloc( &(job->r3H11stor),NoOfPoints+2);
176 		DstorAlloc( &(job->i3H11stor),NoOfPoints+2);
177 		if (! job->r3H11ptr)
178 			{
179 			DmemAlloc( &(job->r3H11ptr) , size+2);
180 			if (! job->r3H11ptr) return (E_NOMEM);
181 			}
182 		if (! job->i3H11ptr)
183 			{
184 			DmemAlloc( &(job->i3H11ptr) , size+2);
185 			if (! job->i3H11ptr) return (E_NOMEM);
186 			}
187 		} else {
188 		DstorAlloc ( &(job->r1H2stor),NoOfPoints+2);
189 		DstorAlloc ( &(job->i1H2stor),NoOfPoints+2);
190 		DstorAlloc ( &(job->r2H12stor),NoOfPoints+2);
191 		DstorAlloc ( &(job->i2H12stor),NoOfPoints+2);
192 		DstorAlloc ( &(job->r2H1m2stor),NoOfPoints+2);
193 		DstorAlloc ( &(job->i2H1m2stor),NoOfPoints+2);
194 		DstorAlloc ( &(job->r3H1m2stor),NoOfPoints+2);
195 		DstorAlloc ( &(job->i3H1m2stor),NoOfPoints+2);
196 		if (! job->r1H2ptr)
197 			{
198 			DmemAlloc( &(job->r1H2ptr) , size+2);
199 			if (! job->r1H2ptr) return (E_NOMEM);
200 			}
201 
202 		if (! job->r2H12ptr)
203 			{
204 			DmemAlloc( &(job->r2H12ptr) , size+2);
205 			if (! job->r2H12ptr) return (E_NOMEM);
206 			}
207 
208 		if (! job->r2H1m2ptr)
209 			{
210 			DmemAlloc( &(job->r2H1m2ptr) , size+2);
211 			if (! job->r2H1m2ptr) return (E_NOMEM);
212 			}
213 
214 		if (! job->r3H1m2ptr)
215 			{
216 			DmemAlloc( &(job->r3H1m2ptr) , size+2);
217 			if (! job->r3H1m2ptr) return (E_NOMEM);
218 			}
219 		if (! job->i1H2ptr)
220 			{
221 			DmemAlloc( &(job->i1H2ptr) , size+2);
222 			if (! job->i1H2ptr) return (E_NOMEM);
223 			}
224 
225 		if (! job->i2H12ptr)
226 			{
227 			DmemAlloc( &(job->i2H12ptr) , size+2);
228 			if (! job->i2H12ptr) return (E_NOMEM);
229 			}
230 
231 		if (! job->i2H1m2ptr)
232 			{
233 			DmemAlloc( &(job->i2H1m2ptr) , size+2);
234 			if (! job->i2H1m2ptr) return (E_NOMEM);
235 			}
236 
237 		if (! job->i3H1m2ptr)
238 			{
239 			DmemAlloc( &(job->i3H1m2ptr) , size+2);
240 			if (! job->i3H1m2ptr) return (E_NOMEM);
241 			}
242 }
243 
244 #ifdef D_DBG_BLOCKTIMES
245 time1 = SPfrontEnd->IFseconds() - time1;
246 printf("Time for other setup (storage allocation etc.): %g seconds \n", time1);
247 #endif
248 
249 
250 
251 #ifdef D_DBG_BLOCKTIMES
252 time1 = SPfrontEnd->IFseconds();
253 #endif
254     while(freq <= job->DstopF1+freqTol) {
255 
256 /*
257         if(SPfrontEnd->IFpauseTest()) {
258             job->DsaveF1 = freq;
259             return(E_PAUSE);
260         }
261 	*/
262         ckt->CKTomega = 2.0 * M_PI *freq;
263 	job->Domega1 = ckt->CKTomega;
264         ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODEAC;
265 #ifdef D_DBG_SMALLTIMES
266 time = SPfrontEnd->IFseconds();
267 #endif
268 	error = CKTacLoad(ckt);
269 #ifdef D_DBG_SMALLTIMES
270 time = SPfrontEnd->IFseconds() - time;
271 printf("Time for CKTacLoad: %g seconds \n", time);
272 #endif
273 	if (error) return(error);
274 #ifdef D_DBG_SMALLTIMES
275 time = SPfrontEnd->IFseconds();
276 #endif
277 	error = CKTdisto(ckt,D_RHSF1); /* sets up the RHS vector
278 			for all inputs corresponding to F1 */
279 #ifdef D_DBG_SMALLTIMES
280 time = SPfrontEnd->IFseconds() - time;
281 printf("Time outside DISTO_RHSFIX: %g seconds \n", time);
282 #endif
283 	if (error) return(error);
284 #ifdef D_DBG_SMALLTIMES
285 time = SPfrontEnd->IFseconds();
286 #endif
287 	error = NIdIter(ckt);
288 #ifdef D_DBG_SMALLTIMES
289 time = SPfrontEnd->IFseconds() - time;
290 printf("Time for NIdIter: %g seconds \n", time);
291 #endif
292 	if (error) return(error);
293 	DISswap(&(ckt->CKTrhsOld),&(job->r1H1ptr));
294 	DISswap(&(ckt->CKTirhsOld),&(job->i1H1ptr));
295 
296 	ckt->CKTomega *= 2;
297 	error = CKTacLoad(ckt);
298 	if (error) return(error);
299 #ifdef D_DBG_SMALLTIMES
300 time = SPfrontEnd->IFseconds();
301 #endif
302 	error = CKTdisto(ckt,D_TWOF1);
303 #ifdef D_DBG_SMALLTIMES
304 time = SPfrontEnd->IFseconds() - time;
305 printf("Time outside D_TWOF1: %g seconds \n", time);
306 #endif
307 	if (error) return(error);
308 	error = NIdIter(ckt);
309 	if (error) return(error);
310 	DISswap(&(ckt->CKTrhsOld),&(job->r2H11ptr));
311 	DISswap(&(ckt->CKTirhsOld),&(job->i2H11ptr));
312 
313 	if (! (job->Df2wanted ))
314 		{
315 
316 
317 		ckt->CKTomega = 3 * job->Domega1;
318 		error = CKTacLoad(ckt);
319 		if (error) return(error);
320 #ifdef D_DBG_SMALLTIMES
321 time = SPfrontEnd->IFseconds();
322 #endif
323 		error = CKTdisto(ckt,D_THRF1);
324 #ifdef D_DBG_SMALLTIMES
325 time = SPfrontEnd->IFseconds() - time;
326 printf("Time outside D_THRF1: %g seconds \n", time);
327 #endif
328 		if (error) return(error);
329 		error = NIdIter(ckt);
330 		if (error) return(error);
331 		DISswap(&(ckt->CKTrhsOld),&(job->r3H11ptr));
332 		DISswap(&(ckt->CKTirhsOld),&(job->i3H11ptr));
333 
334 
335 		}
336 		else if (job->Df2given)
337 		{
338 
339 
340 		/*
341 		ckt->CKTomega = job->Domega1 - omegadelta;
342 		job->Domega2 = ckt->CKTomega;
343 		*/
344 		ckt->CKTomega = job->Domega2;
345 		error = CKTacLoad(ckt);
346 		if (error) return(error);
347 #ifdef D_DBG_SMALLTIMES
348 time = SPfrontEnd->IFseconds();
349 #endif
350 		error = CKTdisto(ckt,D_RHSF2);
351 #ifdef D_DBG_SMALLTIMES
352 time = SPfrontEnd->IFseconds() - time;
353 printf("Time outside DISTO_RHSFIX: %g seconds \n", time);
354 #endif
355 		if (error) return(error);
356 		error = NIdIter(ckt);
357 		if (error) return(error);
358 		DISswap(&(ckt->CKTrhsOld),&(job->r1H2ptr));
359 		DISswap(&(ckt->CKTirhsOld),&(job->i1H2ptr));
360 
361 
362 		ckt->CKTomega = job->Domega1 +
363 					job->Domega2;
364 		error = CKTacLoad(ckt);
365 		if (error) return(error);
366 #ifdef D_DBG_SMALLTIMES
367 time = SPfrontEnd->IFseconds();
368 #endif
369 		error = CKTdisto(ckt,D_F1PF2);
370 #ifdef D_DBG_SMALLTIMES
371 time = SPfrontEnd->IFseconds() - time;
372 printf("Time outside D_F1PF2: %g seconds \n", time);
373 #endif
374 		if (error) return(error);
375 		error = NIdIter(ckt);
376 		if (error) return(error);
377 		DISswap(&(ckt->CKTrhsOld),&(job->r2H12ptr));
378 		DISswap(&(ckt->CKTirhsOld),&(job->i2H12ptr));
379 
380 
381 
382 		ckt->CKTomega = job->Domega1 -
383 					    job->Domega2;
384 		error = CKTacLoad(ckt);
385 		if (error) return(error);
386 #ifdef D_DBG_SMALLTIMES
387 time = SPfrontEnd->IFseconds();
388 #endif
389 		error = CKTdisto(ckt,D_F1MF2);
390 #ifdef D_DBG_SMALLTIMES
391 time = SPfrontEnd->IFseconds() - time;
392 printf("Time outside D_F1MF2: %g seconds \n", time);
393 #endif
394 		if (error) return(error);
395 		error = NIdIter(ckt);
396 		if (error) return(error);
397 		DISswap(&(ckt->CKTrhsOld),&(job->r2H1m2ptr));
398 		DISswap(&(ckt->CKTirhsOld),&(job->i2H1m2ptr));
399 
400 
401 		ckt->CKTomega = 2*job->Domega1 -
402 						job->Domega2;
403 		error = CKTacLoad(ckt);
404 		if (error) return(error);
405 #ifdef D_DBG_SMALLTIMES
406 time = SPfrontEnd->IFseconds();
407 #endif
408 		error = CKTdisto(ckt,D_2F1MF2);
409 #ifdef D_DBG_SMALLTIMES
410 time = SPfrontEnd->IFseconds() - time;
411 printf("Time outside D_2F1MF2: %g seconds \n", time);
412 #endif
413 		if (error) return(error);
414 		error = NIdIter(ckt);
415 		if (error) return(error);
416 		DISswap(&(ckt->CKTrhsOld),&(job->r3H1m2ptr));
417 		DISswap(&(ckt->CKTirhsOld),&(job->i3H1m2ptr));
418 
419 
420 		}
421 	else
422 	{
423         errMsg = TMALLOC(char, strlen(nof2src) + 1);
424         strcpy(errMsg,nof2src);
425 	return(E_NOF2SRC);
426 	}
427 
428 
429 
430 
431 		DmemAlloc( &(job->r1H1stor[displacement]),size);
432 		DISswap(&(job->r1H1stor[displacement]),&(job->r1H1ptr));
433 		job->r1H1stor[displacement][0]=freq;
434 		DmemAlloc( &(job->r2H11stor[displacement]),size);
435 		DISswap(&(job->r2H11stor[displacement]),&((job->r2H11ptr)));
436 		job->r2H11stor[displacement][0]=freq;
437 		DmemAlloc( &(job->i1H1stor[displacement]),size);
438 		DISswap(&(job->i1H1stor[displacement]),&((job->i1H1ptr)));
439 		job->i1H1stor[displacement][0]=0.0;
440 		DmemAlloc( &(job->i2H11stor[displacement]),size);
441 		DISswap(&(job->i2H11stor[displacement]),&((job->i2H11ptr)));
442 		job->i2H11stor[displacement][0]=0.0;
443 	if (! (job->Df2wanted))
444 	{
445 	  DmemAlloc( &(job->r3H11stor[displacement]),size);
446 	  DISswap(&(job->r3H11stor[displacement]),&((job->r3H11ptr)));
447 	  job->r3H11stor[displacement][0]=freq;
448 	  DmemAlloc( &(job->i3H11stor[displacement]),size);
449 	  DISswap(&(job->i3H11stor[displacement]),&((job->i3H11ptr)));
450 	  job->i3H11stor[displacement][0]=0.0;
451 	} else {
452 	  DmemAlloc( &(job->r1H2stor[displacement]),size);
453 	  DISswap(&(job->r1H2stor[displacement]),&((job->r1H2ptr)));
454 	  job->r1H2stor[displacement][0]=freq;
455 	  DmemAlloc( &(job->r2H12stor[displacement]),size);
456 	  DISswap(&(job->r2H12stor[displacement]),&((job->r2H12ptr)));
457 	  job->r2H12stor[displacement][0]=freq;
458 	  DmemAlloc( &(job->r2H1m2stor[displacement]),size);
459 	  DISswap(&(job->r2H1m2stor[displacement]),&((job->r2H1m2ptr)));
460 	  job->r2H1m2stor[displacement][0]=freq;
461 	  DmemAlloc( &(job->r3H1m2stor[displacement]),size);
462 	  DISswap(&(job->r3H1m2stor[displacement]),&((job->r3H1m2ptr)));
463 	  job->r3H1m2stor[displacement][0]=freq;
464 
465 	  DmemAlloc( &(job->i1H2stor[displacement]),size);
466 	  DISswap(&(job->i1H2stor[displacement]),&((job->i1H2ptr)));
467 	  job->i1H2stor[displacement][0]=0.0;
468 	  DmemAlloc( &(job->i2H12stor[displacement]),size);
469 	  DISswap(&(job->i2H12stor[displacement]),&((job->i2H12ptr)));
470 	  job->i2H12stor[displacement][0]=0.0;
471 	  DmemAlloc( &(job->i2H1m2stor[displacement]),size);
472 	  DISswap(&(job->i2H1m2stor[displacement]),&((job->i2H1m2ptr)));
473 	  job->i2H1m2stor[displacement][0]=0.0;
474 	  DmemAlloc( &(job->i3H1m2stor[displacement]),size);
475 	  DISswap(&(job->i3H1m2stor[displacement]),&((job->i3H1m2ptr)));
476 	  job->i3H1m2stor[displacement][0]=0.0;
477 	  }
478 	  displacement++;
479 
480 
481 
482         switch(job->DstepType) {
483         case DECADE:
484         case OCTAVE:
485             freq *= job->DfreqDelta;
486             if(job->DfreqDelta==1) goto endsweep;
487             break;
488         case LINEAR:
489             freq += job->DfreqDelta;
490             if(job->DfreqDelta==0) goto endsweep;
491             break;
492         default:
493             return(E_INTERN);
494         }
495 	}
496 #ifdef D_DBG_BLOCKTIMES
497 time1 = SPfrontEnd->IFseconds() - time1;
498 printf("Time inside frequency loop: %g seconds \n", time1);
499 #endif
500 
501 endsweep:
502 
503 
504     /* output routines to process the H's and output actual ckt variable
505        values */
506 #ifdef D_DBG_BLOCKTIMES
507 time1 = SPfrontEnd->IFseconds();
508 #endif
509 
510 
511 
512 	if (! job->Df2wanted) {
513 	error = CKTnames(ckt,&numNames,&nameList);
514 	if(error) return(error);
515 	SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL);
516         SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob,
517                                    "DISTORTION - 2nd harmonic",
518                                    freqUid, IF_REAL,
519                                    numNames, nameList, IF_COMPLEX,
520                                    &acPlot);
521         if (job->DstepType != LINEAR) {
522 	    SPfrontEnd->OUTattributes (acPlot, NULL, OUT_SCALE_LOG, NULL);
523 	}
524        for (i=0; i< displacement ; i++)
525        {
526 	DkerProc(D_TWOF1,job->r2H11stor[i],
527 			     job->i2H11stor[i],
528 				 size, job);
529 	ckt->CKTrhsOld = job->r2H11stor[i];
530 	ckt->CKTirhsOld = job->i2H11stor[i];
531 	error = CKTacDump(ckt,ckt->CKTrhsOld[0],acPlot);
532         if(error) return(error);
533 	}
534 	SPfrontEnd->OUTendPlot (acPlot);
535 	acPlot = NULL;
536 
537 	error = CKTnames(ckt,&numNames,&nameList);
538 	if(error) return(error);
539 	SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL);
540         SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob,
541                                    "DISTORTION - 3rd harmonic",
542                                    freqUid, IF_REAL,
543                                    numNames, nameList, IF_COMPLEX,
544                                    &acPlot);
545        for (i=0; i< displacement ; i++)
546        {
547 	DkerProc(D_THRF1,job->r3H11stor[i],
548 			     job->i3H11stor[i],
549 				 size, job);
550 	ckt->CKTrhsOld = job->r3H11stor[i];
551 	ckt->CKTirhsOld = job->i3H11stor[i];
552 	error = CKTacDump(ckt,ckt->CKTrhsOld[0],acPlot);
553 	}
554 	SPfrontEnd->OUTendPlot (acPlot);
555 	acPlot = NULL;
556 
557 	} else {
558 
559 
560 	error = CKTnames(ckt,&numNames,&nameList);
561 	if(error) return(error);
562 	SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL);
563         SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob,
564                                    "DISTORTION - IM: f1+f2",
565                                    freqUid, IF_REAL,
566                                    numNames, nameList, IF_COMPLEX,
567                                    &acPlot);
568 	   for (i=0; i< displacement ; i++)
569 	   {
570 	DkerProc(D_F1PF2,job->r2H12stor[i],
571 			     job->i2H12stor[i],
572 				 size, job);
573 	ckt->CKTrhsOld = job->r2H12stor[i];
574 	ckt->CKTirhsOld = job->i2H12stor[i];
575 	error = CKTacDump(ckt,ckt->CKTrhsOld[0],acPlot);
576 	    if(error) return(error);
577 	    }
578 	SPfrontEnd->OUTendPlot (acPlot);
579 	acPlot = NULL;
580 
581 	error = CKTnames(ckt,&numNames,&nameList);
582 	if(error) return(error);
583 	SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL);
584         SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob,
585                                    "DISTORTION - IM: f1-f2",
586                                    freqUid, IF_REAL,
587                                    numNames, nameList, IF_COMPLEX,
588                                    &acPlot);
589 	   for (i=0; i< displacement ; i++)
590 	   {
591 	DkerProc(D_F1MF2,
592 			    job->r2H1m2stor[i],
593 			    job->i2H1m2stor[i],
594 				 size, job);
595 	ckt->CKTrhsOld = job->r2H1m2stor[i];
596 	ckt->CKTirhsOld = job->i2H1m2stor[i];
597 	error = CKTacDump(ckt,ckt->CKTrhsOld[0],acPlot);
598 	    if(error) return(error);
599 	    }
600 	SPfrontEnd->OUTendPlot (acPlot);
601 	acPlot = NULL;
602 
603 	error = CKTnames(ckt,&numNames,&nameList);
604 	if(error) return(error);
605 	SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL);
606         SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob,
607                                    "DISTORTION - IM: 2f1-f2",
608                                    freqUid, IF_REAL,
609                                    numNames, nameList, IF_COMPLEX,
610                                    &acPlot);
611 	   for (i=0; i< displacement ; i++)
612 	   {
613 	DkerProc(D_2F1MF2,
614 			job->r3H1m2stor[i],
615 			job->i3H1m2stor[i],
616 				 size, job);
617 	ckt->CKTrhsOld = job->r3H1m2stor[i];
618 	ckt->CKTirhsOld = job->i3H1m2stor[i];
619 	error = CKTacDump(ckt,ckt->CKTrhsOld[0],acPlot);
620 	    if(error) return(error);
621 	    }
622 	SPfrontEnd->OUTendPlot (acPlot);
623 	acPlot = NULL;
624 
625     }
626 FREE(job->r1H1ptr);
627 FREE(job->i1H1ptr);
628 FREE(job->r2H11ptr);
629 FREE(job->i2H11ptr);
630 
631 FREE(job->r1H1stor);
632 FREE(job->i1H1stor);
633 FREE(job->r2H11stor);
634 FREE(job->i2H11stor);
635 
636 	if (! (job->Df2wanted))
637 	{
638 FREE(job->r3H11ptr);
639 FREE(job->i3H11ptr);
640 
641 FREE(job->i3H11stor);
642 FREE(job->r3H11stor);
643 }
644 else {
645 
646 FREE(job->r2H1m2ptr);
647 FREE(job->r3H1m2ptr);
648 FREE(job->r1H2ptr);
649 FREE(job->i1H2ptr);
650 FREE(job->r2H12ptr);
651 FREE(job->i2H12ptr);
652 FREE(job->i2H1m2ptr);
653 FREE(job->i3H1m2ptr);
654 
655 FREE(job->r1H2stor);
656 FREE(job->r2H12stor);
657 FREE(job->r2H1m2stor);
658 FREE(job->r3H1m2stor);
659 FREE(job->i1H2stor);
660 FREE(job->i2H12stor);
661 FREE(job->i2H1m2stor);
662 FREE(job->i3H1m2stor);
663     }
664 #ifdef D_DBG_BLOCKTIMES
665 time1 = SPfrontEnd->IFseconds() - time1;
666 printf("Time for output and deallocation: %g seconds \n", time1);
667 #endif
668     return(OK);
669 }
670