Browse Source
Transient op calculation added to the standard operating point code.
Transient op calculation added to the standard operating point code.
When standard iteration, gmin stepping and source stepping fail, try a transient simulation (like tran with uic option) to determine the op. Implemented for AC and Tran simulation.pre-master-46
4 changed files with 685 additions and 0 deletions
-
2src/include/ngspice/cktdefs.h
-
1src/spicelib/analysis/Makefile.am
-
4src/spicelib/analysis/cktop.c
-
678src/spicelib/analysis/optran.c
@ -0,0 +1,678 @@ |
|||
/********** |
|||
Copyright 2019 Holger Vogt All rights reserved. |
|||
Author: 2019 Holger Vogt |
|||
Modified BSD license |
|||
**********/ |
|||
|
|||
/* subroutine to generate OP by TRANSIENT analysis */ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "cktaccept.h" |
|||
#include "ngspice/trandefs.h" |
|||
#include "ngspice/sperror.h" |
|||
#include "ngspice/fteext.h" |
|||
#include "ngspice/missing_math.h" |
|||
|
|||
/* for setting breakpoints required by dbs data base */ |
|||
extern struct dbcomm *dbs; |
|||
#include "ngspice/ftedebug.h" |
|||
|
|||
#ifdef XSPICE |
|||
/* gtri - add - wbk - Add headers */ |
|||
#include "ngspice/miftypes.h" |
|||
|
|||
#include "ngspice/evt.h" |
|||
#include "ngspice/enh.h" |
|||
#include "ngspice/mif.h" |
|||
#include "ngspice/evtproto.h" |
|||
#include "ngspice/ipctiein.h" |
|||
/* gtri - end - wbk - Add headers */ |
|||
#endif |
|||
|
|||
#ifdef SHARED_MODULE |
|||
extern int add_bkpt(void); |
|||
extern int sharedsync(double*, double*, double, double, double, int, int*, int); |
|||
extern int ng_ident; /* for debugging */ |
|||
#endif |
|||
|
|||
static double *opbreaks; |
|||
static int OPbreakSize; |
|||
static double opfinaltime = 1e-6; |
|||
|
|||
int OPclrBreak(CKTcircuit *ckt) |
|||
{ |
|||
double *tmp; |
|||
int j; |
|||
|
|||
NG_IGNORE(ckt); |
|||
|
|||
if (OPbreakSize > 2) { |
|||
tmp = TMALLOC(double, OPbreakSize - 1); |
|||
if (tmp == NULL) |
|||
return (E_NOMEM); |
|||
for (j = 1; j < OPbreakSize; j++) { |
|||
tmp[j - 1] = opbreaks[j]; |
|||
} |
|||
FREE(opbreaks); |
|||
OPbreakSize--; |
|||
opbreaks = tmp; |
|||
} |
|||
else { |
|||
opbreaks[0] = opbreaks[1]; |
|||
opbreaks[1] = opfinaltime; |
|||
} |
|||
return (OK); |
|||
} |
|||
|
|||
|
|||
int OPsetBreak(CKTcircuit *ckt, double time) |
|||
{ |
|||
double *tmp; |
|||
int i, j; |
|||
|
|||
|
|||
for (i = 0; i < OPbreakSize; i++) { |
|||
if (opbreaks[i] > time) { /* passed */ |
|||
if ((opbreaks[i] - time) <= ckt->CKTminBreak) { |
|||
/* very close together - take earlier point */ |
|||
#ifdef TRACE_BREAKPOINT |
|||
printf("[t:%e] \t %e replaces %e\n", ckt->CKTtime, time, |
|||
ckt->CKTbreaks[i]); |
|||
CKTbreakDump(ckt); |
|||
#endif |
|||
opbreaks[i] = time; |
|||
return (OK); |
|||
} |
|||
if (i > 0 && time - opbreaks[i - 1] <= ckt->CKTminBreak) { |
|||
/* very close together, but after, so skip */ |
|||
#ifdef TRACE_BREAKPOINT |
|||
printf("[t:%e] \t %e skipped\n", ckt->CKTtime, time); |
|||
CKTbreakDump(ckt); |
|||
#endif |
|||
return (OK); |
|||
} |
|||
/* fits in middle - new array & insert */ |
|||
tmp = TMALLOC(double, OPbreakSize + 1); |
|||
if (tmp == NULL) |
|||
return (E_NOMEM); |
|||
for (j = 0; j < i; j++) { |
|||
tmp[j] = opbreaks[j]; |
|||
} |
|||
tmp[i] = time; |
|||
#ifdef TRACE_BREAKPOINT |
|||
printf("[t:%e] \t %e added\n", ckt->CKTtime, time); |
|||
CKTbreakDump(ckt); |
|||
#endif |
|||
for (j = i; j < OPbreakSize; j++) { |
|||
tmp[j + 1] = opbreaks[j]; |
|||
} |
|||
FREE(opbreaks); |
|||
OPbreakSize++; |
|||
opbreaks = tmp; |
|||
|
|||
return (OK); |
|||
} |
|||
} |
|||
/* never found it - beyond end of time - extend out idea of time */ |
|||
if (time - opbreaks[OPbreakSize - 1] <= ckt->CKTminBreak) { |
|||
/* very close tegether - keep earlier, throw out new point */ |
|||
#ifdef TRACE_BREAKPOINT |
|||
printf("[t:%e] \t %e skipped (at the end)\n", ckt->CKTtime, time); |
|||
CKTbreakDump(ckt); |
|||
#endif |
|||
return (OK); |
|||
} |
|||
/* fits at end - grow array & add on */ |
|||
opbreaks = TREALLOC(double, opbreaks, OPbreakSize + 1); |
|||
OPbreakSize++; |
|||
opbreaks[OPbreakSize - 1] = time; |
|||
#ifdef TRACE_BREAKPOINT |
|||
printf("[t:%e] \t %e added at end\n", ckt->CKTtime, time); |
|||
CKTbreakDump(ckt); |
|||
#endif |
|||
return (OK); |
|||
} |
|||
|
|||
|
|||
/* Do a simple transient simulation, starting with time 0 until opfinaltime. |
|||
No output vectors are generated, actual times and breakpoints are kept local. |
|||
When returning, the matrix is left in its current state. |
|||
Thus this algorithm creates an operating point to start other simulations. |
|||
The code is derived from dctran.c by removing all un-needed parts.*/ |
|||
int |
|||
OPtran(CKTcircuit *ckt) |
|||
{ |
|||
int i; |
|||
double olddelta; |
|||
double delta; |
|||
double newdelta; |
|||
double *temp; |
|||
|
|||
double optime = 0; |
|||
|
|||
int converged; |
|||
int firsttime; |
|||
int error; |
|||
int save_order; |
|||
long save_mode; |
|||
double maxstepsize = 0.0; |
|||
|
|||
int ltra_num; |
|||
|
|||
#if defined SHARED_MODULE |
|||
int redostep; |
|||
#endif |
|||
|
|||
ACAN *acjob = (ACAN *) ckt->CKTcurJob; |
|||
TRANan *trjob = (TRANan *) ckt->CKTcurJob; |
|||
NOISEAN *nojob = (NOISEAN *) ckt->CKTcurJob; |
|||
|
|||
if(optime == 0) { |
|||
|
|||
int type = ckt->CKTcurJob->JOBtype; |
|||
|
|||
SPfrontEnd->IFerrorf(ERR_INFO, "Transient op started"); |
|||
|
|||
/* Set the final time */ |
|||
/* If we are in transient simulation */ |
|||
if (type == 4 && ckt->CKTstep > 0.) |
|||
opfinaltime = 100. * ckt->CKTstep; |
|||
/* We are in AC mode */ |
|||
else if (type == 1 && acjob->ACstartFreq > 0) { |
|||
opfinaltime = 0.1 / acjob->ACstartFreq; |
|||
ckt->CKTstep = opfinaltime / 1000.; |
|||
} |
|||
/* Noise analysis */ |
|||
else if (type == 8 && nojob->NstartFreq > 0) { |
|||
opfinaltime = 0.1 / nojob->NstartFreq; |
|||
ckt->CKTstep = opfinaltime / 1000.; |
|||
} |
|||
|
|||
delta=MIN(opfinaltime/100,ckt->CKTstep)/10; |
|||
|
|||
/* begin LTRA code addition */ |
|||
if (ckt->CKTtimePoints != NULL) |
|||
FREE(ckt->CKTtimePoints); |
|||
|
|||
if (ckt->CKTstep >= ckt->CKTmaxStep) |
|||
maxstepsize = ckt->CKTstep; |
|||
else |
|||
maxstepsize = ckt->CKTmaxStep; |
|||
|
|||
ckt->CKTsizeIncr = 10; |
|||
ckt->CKTtimeIndex = -1; /* before the DC soln has been stored */ |
|||
ckt->CKTtimeListSize = (int) ceil( opfinaltime / maxstepsize ); |
|||
ltra_num = CKTtypelook("LTRA"); |
|||
if (ltra_num >= 0 && ckt->CKThead[ltra_num] != NULL) |
|||
ckt->CKTtimePoints = TMALLOC(double, ckt->CKTtimeListSize); |
|||
/* end LTRA code addition */ |
|||
|
|||
opbreaks = TMALLOC(double, 2); |
|||
if(opbreaks == NULL) return(E_NOMEM); |
|||
opbreaks[0] = 0; |
|||
opbreaks[1] = opfinaltime; |
|||
OPbreakSize = 2; |
|||
|
|||
#ifdef SHARED_MODULE |
|||
add_bkpt(); |
|||
#endif |
|||
|
|||
firsttime = 1; |
|||
save_mode = (ckt->CKTmode&MODEUIC) | MODETRANOP | MODEINITJCT; |
|||
save_order = ckt->CKTorder; |
|||
|
|||
|
|||
#ifdef XSPICE |
|||
/* gtri - begin - wbk - Add Breakpoint stuff */ |
|||
|
|||
/* Initialize the temporary breakpoint variables to infinity */ |
|||
g_mif_info.breakpoint.current = 1.0e30; |
|||
g_mif_info.breakpoint.last = 1.0e30; |
|||
|
|||
/* gtri - end - wbk - Add Breakpoint stuff */ |
|||
#endif |
|||
ckt->CKTorder = 1; |
|||
for(i=0;i<7;i++) { |
|||
ckt->CKTdeltaOld[i]=ckt->CKTmaxStep; |
|||
} |
|||
ckt->CKTdelta = delta; |
|||
#ifdef STEPDEBUG |
|||
(void)printf("delta initialized to %g\n",ckt->CKTdelta); |
|||
#endif |
|||
ckt->CKTsaveDelta = opfinaltime/50; |
|||
|
|||
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITTRAN; |
|||
/* modeinittran set here */ |
|||
ckt->CKTag[0]=ckt->CKTag[1]=0; |
|||
memcpy(ckt->CKTstate1, ckt->CKTstate0, |
|||
(size_t) ckt->CKTnumStates * sizeof(double)); |
|||
|
|||
} else { |
|||
/* saj As traninit resets CKTmode */ |
|||
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITPRED; |
|||
if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5; |
|||
firsttime=0; |
|||
goto resume; |
|||
} |
|||
|
|||
/* 650 */ |
|||
nextTime: |
|||
|
|||
/* begin LTRA code addition */ |
|||
if (ckt->CKTtimePoints) { |
|||
ckt->CKTtimeIndex++; |
|||
if (ckt->CKTtimeIndex >= ckt->CKTtimeListSize) { |
|||
/* need more space */ |
|||
int need; |
|||
need = (int) ceil( (opfinaltime - optime) / maxstepsize ); |
|||
if (need < ckt->CKTsizeIncr) |
|||
need = ckt->CKTsizeIncr; |
|||
ckt->CKTtimeListSize += need; |
|||
ckt->CKTtimePoints = TREALLOC(double, ckt->CKTtimePoints, ckt->CKTtimeListSize); |
|||
ckt->CKTsizeIncr = (int) ceil(1.4 * ckt->CKTsizeIncr); |
|||
} |
|||
ckt->CKTtimePoints[ckt->CKTtimeIndex] = optime; |
|||
} |
|||
/* end LTRA code addition */ |
|||
|
|||
error = CKTaccept(ckt); |
|||
/* check if current breakpoint is outdated; if so, clear */ |
|||
if (optime > opbreaks[0]) |
|||
OPclrBreak(ckt); |
|||
|
|||
/* |
|||
* Breakpoint handling scheme: |
|||
* When a timepoint t is accepted (by CKTaccept), clear all previous |
|||
* breakpoints, because they will never be needed again. |
|||
* |
|||
* t may itself be a breakpoint, or indistinguishably close. DON'T |
|||
* clear t itself; recognise it as a breakpoint and act accordingly |
|||
* |
|||
* if t is not a breakpoint, limit the timestep so that the next |
|||
* breakpoint is not crossed |
|||
*/ |
|||
|
|||
ckt->CKTbreak = 0; |
|||
/* XXX Error will cause single process to bail. */ |
|||
if(error) { |
|||
tfree(opbreaks); |
|||
return(error); |
|||
} |
|||
#ifdef XSPICE |
|||
/* gtri - begin - wbk - Update event queues/data for accepted timepoint */ |
|||
/* Note: this must be done AFTER sending results to SI so it can't */ |
|||
/* go next to CKTaccept() above */ |
|||
if(ckt->evt->counts.num_insts > 0) |
|||
EVTaccept(ckt, optime); |
|||
/* gtri - end - wbk - Update event queues/data for accepted timepoint */ |
|||
#endif |
|||
|
|||
/* We are finished */ |
|||
if(AlmostEqualUlps( optime, opfinaltime, 100 ) ) { |
|||
tfree(opbreaks); |
|||
SPfrontEnd->IFerrorf(ERR_INFO, "Transient op finished successfully"); |
|||
return(OK); |
|||
} |
|||
|
|||
resume: |
|||
#ifdef HAS_PROGREP |
|||
if (optime == 0.) |
|||
SetAnalyse( "optran init", 0); |
|||
else |
|||
SetAnalyse( "optran", (int)((optime * 1000.) / opfinaltime + 0.5)); |
|||
#endif |
|||
ckt->CKTdelta = |
|||
MIN(ckt->CKTdelta,ckt->CKTmaxStep); |
|||
#ifdef XSPICE |
|||
/* gtri - begin - wbk - Cut integration order if first timepoint after breakpoint */ |
|||
/* if(optime == g_mif_info.breakpoint.last) */ |
|||
if ( AlmostEqualUlps( optime, g_mif_info.breakpoint.last, 100 ) ) |
|||
ckt->CKTorder = 1; |
|||
/* gtri - end - wbk - Cut integration order if first timepoint after breakpoint */ |
|||
|
|||
#endif |
|||
|
|||
/* are we at a breakpoint, or indistinguishably close? */ |
|||
/* if ((optime == opbreaks[0]) || (opbreaks[0] - */ |
|||
if ( AlmostEqualUlps( optime, opbreaks[0], 100 ) || |
|||
opbreaks[0] - optime <= ckt->CKTdelmin) { |
|||
/* first timepoint after a breakpoint - cut integration order */ |
|||
/* and limit timestep to .1 times minimum of time to next breakpoint, |
|||
* and previous timestep |
|||
*/ |
|||
ckt->CKTorder = 1; |
|||
|
|||
ckt->CKTdelta = MIN(ckt->CKTdelta, .1 * MIN(ckt->CKTsaveDelta, |
|||
opbreaks[1] - opbreaks[0])); |
|||
|
|||
if(firsttime) { |
|||
/* set a breakpoint to reduce ringing of current in devices */ |
|||
if (ckt->CKTmode & MODEUIC) |
|||
OPsetBreak(ckt, ckt->CKTstep); |
|||
|
|||
ckt->CKTdelta /= 10; |
|||
#ifdef STEPDEBUG |
|||
(void)printf("delta cut for initial timepoint\n"); |
|||
#endif |
|||
} |
|||
|
|||
#ifndef XSPICE |
|||
/* don't want to get below delmin for no reason */ |
|||
ckt->CKTdelta = MAX(ckt->CKTdelta, ckt->CKTdelmin*2.0); |
|||
#endif |
|||
|
|||
} |
|||
|
|||
#ifndef XSPICE |
|||
else if(optime + ckt->CKTdelta >= opbreaks[0]) { |
|||
ckt->CKTsaveDelta = ckt->CKTdelta; |
|||
ckt->CKTdelta = opbreaks[0] - optime; |
|||
ckt->CKTbreak = 1; /* why? the current pt. is not a bkpt. */ |
|||
} |
|||
#endif /* !XSPICE */ |
|||
|
|||
|
|||
#ifdef XSPICE |
|||
/* gtri - begin - wbk - Add Breakpoint stuff */ |
|||
|
|||
if(optime + ckt->CKTdelta >= g_mif_info.breakpoint.current) { |
|||
/* If next time > temporary breakpoint, force it to the breakpoint */ |
|||
/* And mark that timestep was set by temporary breakpoint */ |
|||
ckt->CKTsaveDelta = ckt->CKTdelta; |
|||
ckt->CKTdelta = g_mif_info.breakpoint.current - optime; |
|||
g_mif_info.breakpoint.last = optime + ckt->CKTdelta; |
|||
} else { |
|||
/* Else, mark that timestep was not set by temporary breakpoint */ |
|||
g_mif_info.breakpoint.last = 1.0e30; |
|||
} |
|||
|
|||
/* gtri - end - wbk - Add Breakpoint stuff */ |
|||
|
|||
/* gtri - begin - wbk - Modify Breakpoint stuff */ |
|||
/* Throw out any permanent breakpoint times <= current time */ |
|||
for (;;) { |
|||
#ifdef STEPDEBUG |
|||
printf(" brk_pt: %g ckt_time: %g ckt_min_break: %g\n",opbreaks[0], optime, ckt->CKTminBreak); |
|||
#endif |
|||
if(AlmostEqualUlps(opbreaks[0], optime, 100) || |
|||
opbreaks[0] <= optime + ckt->CKTminBreak) { |
|||
#ifdef STEPDEBUG |
|||
printf("throwing out permanent breakpoint times <= current time (brk pt: %g)\n",opbreaks[0]); |
|||
printf(" ckt_time: %g ckt_min_break: %g\n",optime, ckt->CKTminBreak); |
|||
#endif |
|||
OPclrBreak(ckt); |
|||
} else { |
|||
break; |
|||
} |
|||
} |
|||
/* Force the breakpoint if appropriate */ |
|||
if(optime + ckt->CKTdelta > opbreaks[0]) { |
|||
ckt->CKTbreak = 1; |
|||
ckt->CKTsaveDelta = ckt->CKTdelta; |
|||
ckt->CKTdelta = opbreaks[0] - optime; |
|||
} |
|||
|
|||
/* gtri - end - wbk - Modify Breakpoint stuff */ |
|||
|
|||
#ifdef SHARED_MODULE |
|||
/* Either directly go to next time step, or modify ckt->CKTdelta depending on |
|||
synchronization requirements. sharedsync() returns 0. */ |
|||
sharedsync(&optime, &ckt->CKTdelta, 0, opfinaltime, |
|||
ckt->CKTdelmin, 0, &ckt->CKTstat->STATrejected, 0); |
|||
#endif |
|||
|
|||
/* gtri - begin - wbk - Do event solution */ |
|||
|
|||
if(ckt->evt->counts.num_insts > 0) { |
|||
|
|||
/* if time = 0 and op_alternate was specified as false during */ |
|||
/* dcop analysis, call any changed instances to let them */ |
|||
/* post their outputs with their associated delays */ |
|||
if((optime == 0.0) && (! ckt->evt->options.op_alternate)) |
|||
EVTiter(ckt); |
|||
|
|||
/* while there are events on the queue with event time <= next */ |
|||
/* projected analog time, process them */ |
|||
while((g_mif_info.circuit.evt_step = EVTnext_time(ckt)) |
|||
<= (optime + ckt->CKTdelta)) { |
|||
|
|||
/* Initialize temp analog bkpt to infinity */ |
|||
g_mif_info.breakpoint.current = 1e30; |
|||
|
|||
/* Pull items off queue and process them */ |
|||
EVTdequeue(ckt, g_mif_info.circuit.evt_step); |
|||
EVTiter(ckt); |
|||
|
|||
/* If any instances have forced an earlier */ |
|||
/* next analog time, cut the delta */ |
|||
if(opbreaks[0] < g_mif_info.breakpoint.current) |
|||
if(opbreaks[0] > optime + ckt->CKTminBreak) |
|||
g_mif_info.breakpoint.current = opbreaks[0]; |
|||
if(g_mif_info.breakpoint.current < optime + ckt->CKTdelta) { |
|||
/* Breakpoint must be > last accepted timepoint */ |
|||
/* and >= current event time */ |
|||
if(g_mif_info.breakpoint.current > optime + ckt->CKTminBreak && |
|||
g_mif_info.breakpoint.current >= g_mif_info.circuit.evt_step) { |
|||
ckt->CKTsaveDelta = ckt->CKTdelta; |
|||
ckt->CKTdelta = g_mif_info.breakpoint.current - optime; |
|||
g_mif_info.breakpoint.last = optime + ckt->CKTdelta; |
|||
} |
|||
} |
|||
|
|||
} /* end while next event time <= next analog time */ |
|||
} /* end if there are event instances */ |
|||
|
|||
/* gtri - end - wbk - Do event solution */ |
|||
#else |
|||
|
|||
#ifdef SHARED_MODULE |
|||
/* Either directly go to next time step, or modify ckt->CKTdelta depending on |
|||
synchronization requirements. sharedsync() returns 0. |
|||
*/ |
|||
sharedsync(&optime, &ckt->CKTdelta, 0, opfinaltime, |
|||
ckt->CKTdelmin, 0, &ckt->CKTstat->STATrejected, 0); |
|||
#endif |
|||
|
|||
#endif |
|||
for(i=5; i>=0; i--) |
|||
ckt->CKTdeltaOld[i+1] = ckt->CKTdeltaOld[i]; |
|||
ckt->CKTdeltaOld[0] = ckt->CKTdelta; |
|||
|
|||
temp = ckt->CKTstates[ckt->CKTmaxOrder+1]; |
|||
for(i=ckt->CKTmaxOrder;i>=0;i--) { |
|||
ckt->CKTstates[i+1] = ckt->CKTstates[i]; |
|||
} |
|||
ckt->CKTstates[0] = temp; |
|||
|
|||
/* 600 */ |
|||
for (;;) { |
|||
#if defined SHARED_MODULE |
|||
redostep = 1; |
|||
#endif |
|||
|
|||
olddelta=ckt->CKTdelta; |
|||
/* time abort? */ |
|||
optime += ckt->CKTdelta; |
|||
|
|||
ckt->CKTdeltaOld[0]=ckt->CKTdelta; |
|||
NIcomCof(ckt); |
|||
save_mode = ckt->CKTmode; |
|||
save_order = ckt->CKTorder; |
|||
#ifdef XSPICE |
|||
/* gtri - begin - wbk - Add Breakpoint stuff */ |
|||
|
|||
/* Initialize temporary breakpoint to infinity */ |
|||
g_mif_info.breakpoint.current = 1.0e30; |
|||
|
|||
/* gtri - end - wbk - Add Breakpoint stuff */ |
|||
|
|||
|
|||
/* gtri - begin - wbk - add convergence problem reporting flags */ |
|||
/* delta is forced to equal delmin on last attempt near line 650 */ |
|||
if(ckt->CKTdelta <= ckt->CKTdelmin) |
|||
ckt->enh->conv_debug.last_NIiter_call = MIF_TRUE; |
|||
else |
|||
ckt->enh->conv_debug.last_NIiter_call = MIF_FALSE; |
|||
/* gtri - begin - wbk - add convergence problem reporting flags */ |
|||
|
|||
|
|||
/* gtri - begin - wbk - Call all hybrids */ |
|||
|
|||
/* gtri - begin - wbk - Set evt_step */ |
|||
|
|||
if(ckt->evt->counts.num_insts > 0) { |
|||
g_mif_info.circuit.evt_step = optime; |
|||
} |
|||
/* gtri - end - wbk - Set evt_step */ |
|||
#endif |
|||
|
|||
converged = NIiter(ckt,ckt->CKTtranMaxIter); |
|||
|
|||
#ifdef XSPICE |
|||
if(ckt->evt->counts.num_insts > 0) { |
|||
g_mif_info.circuit.evt_step = optime; |
|||
EVTcall_hybrids(ckt); |
|||
} |
|||
/* gtri - end - wbk - Call all hybrids */ |
|||
|
|||
#endif |
|||
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITPRED; |
|||
if(firsttime) { |
|||
memcpy(ckt->CKTstate2, ckt->CKTstate1, |
|||
(size_t) ckt->CKTnumStates * sizeof(double)); |
|||
memcpy(ckt->CKTstate3, ckt->CKTstate1, |
|||
(size_t) ckt->CKTnumStates * sizeof(double)); |
|||
} |
|||
/* txl, cpl addition */ |
|||
if (converged == 1111) { |
|||
tfree(opbreaks); |
|||
return(converged); |
|||
} |
|||
|
|||
if(converged != 0) { |
|||
|
|||
#ifndef SHARED_MODULE |
|||
optime = optime -ckt->CKTdelta; |
|||
#else |
|||
redostep = 1; |
|||
#endif |
|||
|
|||
ckt->CKTdelta = ckt->CKTdelta/8; |
|||
|
|||
if(firsttime) { |
|||
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITTRAN; |
|||
} |
|||
ckt->CKTorder = 1; |
|||
|
|||
#ifdef XSPICE |
|||
/* gtri - begin - wbk - Add Breakpoint stuff */ |
|||
|
|||
/* Force backup if temporary breakpoint is < current time */ |
|||
} else if(g_mif_info.breakpoint.current < optime) { |
|||
ckt->CKTsaveDelta = ckt->CKTdelta; |
|||
optime -= ckt->CKTdelta; |
|||
ckt->CKTdelta = g_mif_info.breakpoint.current - optime; |
|||
g_mif_info.breakpoint.last = optime + ckt->CKTdelta; |
|||
|
|||
if(firsttime) { |
|||
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITTRAN; |
|||
} |
|||
ckt->CKTorder = 1; |
|||
|
|||
/* gtri - end - wbk - Add Breakpoint stuff */ |
|||
#endif |
|||
|
|||
} else { |
|||
if (firsttime) { |
|||
firsttime = 0; |
|||
#if !defined SHARED_MODULE |
|||
goto nextTime; /* no check on |
|||
* first time point |
|||
*/ |
|||
#else |
|||
redostep = 0; |
|||
goto chkStep; |
|||
#endif |
|||
} |
|||
newdelta = ckt->CKTdelta; |
|||
error = CKTtrunc(ckt,&newdelta); |
|||
if(error) { |
|||
return(error); |
|||
tfree(opbreaks); |
|||
} |
|||
if (newdelta > .9 * ckt->CKTdelta) { |
|||
if ((ckt->CKTorder == 1) && (ckt->CKTmaxOrder > 1)) { /* don't rise the order for backward Euler */ |
|||
newdelta = ckt->CKTdelta; |
|||
ckt->CKTorder = 2; |
|||
error = CKTtrunc(ckt, &newdelta); |
|||
if (error) { |
|||
tfree(opbreaks); |
|||
return(error); |
|||
} |
|||
if (newdelta <= 1.05 * ckt->CKTdelta) { |
|||
ckt->CKTorder = 1; |
|||
} |
|||
} |
|||
/* time point OK - 630 */ |
|||
ckt->CKTdelta = newdelta; |
|||
|
|||
#if !defined SHARED_MODULE |
|||
/* go to 650 - trapezoidal */ |
|||
goto nextTime; |
|||
#else |
|||
redostep = 0; |
|||
goto chkStep; |
|||
#endif |
|||
} else { |
|||
|
|||
#ifndef SHARED_MODULE |
|||
optime = optime -ckt->CKTdelta; |
|||
ckt->CKTstat->STATrejected ++; |
|||
#else |
|||
redostep = 1; |
|||
#endif |
|||
|
|||
ckt->CKTdelta = newdelta; |
|||
} |
|||
} |
|||
|
|||
if (ckt->CKTdelta <= ckt->CKTdelmin) { |
|||
if (olddelta > ckt->CKTdelmin) { |
|||
ckt->CKTdelta = ckt->CKTdelmin; |
|||
} else { |
|||
errMsg = CKTtrouble(ckt, "Timestep too small"); |
|||
tfree(opbreaks); |
|||
return(E_TIMESTEP); |
|||
} |
|||
} |
|||
#ifdef XSPICE |
|||
/* gtri - begin - wbk - Do event backup */ |
|||
|
|||
if(ckt->evt->counts.num_insts > 0) |
|||
EVTbackup(ckt, optime + ckt->CKTdelta); |
|||
|
|||
/* gtri - end - wbk - Do event backup */ |
|||
#endif |
|||
|
|||
#ifdef SHARED_MODULE |
|||
/* redostep == 0: |
|||
Either directly go to next time step, or modify ckt->CKTdelta depending on |
|||
synchronization requirements. sharedsync() returns 0. |
|||
redostep == 1: |
|||
No convergence, or too large truncation error. |
|||
Redo the last time step by subtracting olddelta, and modify ckt->CKTdelta |
|||
depending on synchronization requirements. sharedsync() returns 1. |
|||
User-supplied redo request: |
|||
sharedsync() may return 1 if the user has decided to do so in the callback |
|||
function. |
|||
*/ |
|||
chkStep: |
|||
if(sharedsync(&optime, &ckt->CKTdelta, olddelta, opfinaltime, |
|||
ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0) |
|||
goto nextTime; |
|||
#endif |
|||
|
|||
} |
|||
/* NOTREACHED */ |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue