📄 cktop.c
字号:
/**********Copyright 1990 Regents of the University of California. All rights reserved.Author: 1985 Thomas L. QuarlesModified: 2000 AlansFixesModified: 2005 Paolo Nenzi - Restructured**********/#include "ngspice.h"#include "cktdefs.h"#include "devdefs.h"#include "sperror.h"static int dynamic_gmin (CKTcircuit *, long int, long int, int);static int spice3_gmin (CKTcircuit *, long int, long int, int);static int gillespie_src (CKTcircuit *, long int, long int, int);static int spice3_src (CKTcircuit *, long int, long int, int);intCKTop (CKTcircuit * ckt, long int firstmode, long int continuemode, int iterlim){ int converged;ckt->CKTmode = firstmode; if (!ckt->CKTnoOpIter){#ifdef XSPICE/* gtri - begin - wbk - add convergence problem reporting flags */ if ((ckt->CKTnumGminSteps <= 0) && (ckt->CKTnumSrcSteps <= 0)) ckt->enh->conv_debug.last_NIiter_call = MIF_TRUE; else ckt->enh->conv_debug.last_NIiter_call = MIF_FALSE;/* gtri - end - wbk - add convergence problem reporting flags */#endif converged = NIiter (ckt, iterlim); } else { converged = 1; /* the 'go directly to gmin stepping' option */ } if (converged != 0) { /* no convergence on the first try, so we do something else */ /* first, check if we should try gmin stepping */ if (ckt->CKTnumGminSteps >= 1){ if (ckt->CKTnumGminSteps == 1){ converged = dynamic_gmin(ckt, firstmode, continuemode, iterlim); } else { converged = spice3_gmin(ckt, firstmode, continuemode, iterlim); } } if (!converged) /* If gmin-stepping worked... move out */ return (0); /* ... otherwise try stepping sources ... * now, we'll try source stepping - we scale the sources * to 0, converge, then start stepping them up until they * are at their normal values */ if (ckt->CKTnumSrcSteps >= 1){ if (ckt->CKTnumSrcSteps == 1) converged = gillespie_src(ckt, firstmode, continuemode, iterlim); else converged = spice3_src(ckt, firstmode, continuemode, iterlim); }#ifdef XSPICE/* gtri - begin - wbk - add convergence problem reporting flags */ ckt->enh->conv_debug.last_NIiter_call = MIF_FALSE;/* gtri - end - wbk - add convergence problem reporting flags */#endif } return (converged); }/* CKTconvTest(ckt) * this is a driver program to iterate through all the various * convTest functions provided for the circuit elements in the * given circuit */intCKTconvTest (CKTcircuit * ckt){ extern SPICEdev **DEVices; int i; int error = OK;#ifdef PARALLEL_ARCH int ibuf[2]; long type = MT_CONV, length = 2;#endif /* PARALLEL_ARCH */ for (i = 0; i < DEVmaxnum; i++) { if (((*DEVices[i]).DEVconvTest != NULL) && (ckt->CKThead[i] != NULL)) { error = (*((*DEVices[i]).DEVconvTest)) (ckt->CKThead[i], ckt); }#ifdef PARALLEL_ARCH if (error || ckt->CKTnoncon) goto combine;#else if (error) return (error); if (ckt->CKTnoncon) { /* printf("convTest: device %s failed\n", * (*DEVices[i]).DEVpublic.name); */ return (OK); }#endif /* PARALLEL_ARCH */ }#ifdef PARALLEL_ARCHcombine: /* See if any of the DEVconvTest functions bailed. If not, proceed. */ ibuf[0] = error; ibuf[1] = ckt->CKTnoncon; IGOP_ (&type, ibuf, &length, "+"); ckt->CKTnoncon = ibuf[1]; if (ibuf[0] != error) { error = E_MULTIERR; } return (error);#else return (OK);#endif /* PARALLEL_ARCH */}/* Dynamic gmin stepping * Algorithm by Alan Gillespie * Modified 2005 - Paolo Nenzi (extracted from CKTop.c code) * * return value: * 0 -> method converged * 1 -> method failed * * Note that no path out of this code allows ckt->CKTdiagGmin to be * anything but CKTgshunt. */static intdynamic_gmin (CKTcircuit * ckt, long int firstmode, long int continuemode, int iterlim){ double OldGmin, gtarget, factor; int success, failed, converged; int NumNodes, iters, i; double *OldRhsOld, *OldCKTstate0; CKTnode *n; ckt->CKTmode = firstmode; (*(SPfrontEnd->IFerror)) (ERR_INFO, "starting dynamic Gmin stepping", (IFuid *) NULL); NumNodes = 0; for (n = ckt->CKTnodes; n; n = n->next) NumNodes++; OldRhsOld = (double *) MALLOC ((NumNodes + 1) * sizeof (double)); OldCKTstate0 = (double *) MALLOC ((ckt->CKTnumStates + 1) * sizeof (double)); for (n = ckt->CKTnodes; n; n = n->next) *(ckt->CKTrhsOld + n->number) = 0; for (i = 0; i < ckt->CKTnumStates; i++) *(ckt->CKTstate0 + i) = 0; factor = ckt->CKTgminFactor; OldGmin = 1e-2; ckt->CKTdiagGmin = OldGmin / factor; gtarget = MAX (ckt->CKTgmin, ckt->CKTgshunt); success = failed = 0; while ((!success) && (!failed)){ fprintf (stderr, "\rTrying gmin = %12.4E ", ckt->CKTdiagGmin); ckt->CKTnoncon = 1; iters = ckt->CKTstat->STATnumIter; converged = NIiter (ckt, ckt->CKTdcTrcvMaxIter); iters = (ckt->CKTstat->STATnumIter) - iters; if (converged == 0){ ckt->CKTmode = continuemode; (*(SPfrontEnd->IFerror)) (ERR_INFO, "One successful Gmin step", (IFuid *) NULL); if (ckt->CKTdiagGmin <= gtarget){ success = 1; } else { i = 0; for (n = ckt->CKTnodes; n; n = n->next){ OldRhsOld[i] = *(ckt->CKTrhsOld + n->number); i++; } for (i = 0; i < ckt->CKTnumStates; i++){ *(OldCKTstate0 + i) = *(ckt->CKTstate0 + i); } if (iters <= (ckt->CKTdcTrcvMaxIter / 4)){ factor *= sqrt (factor); if (factor > ckt->CKTgminFactor) factor = ckt->CKTgminFactor; } if (iters > (3 * ckt->CKTdcTrcvMaxIter / 4)) factor = sqrt (factor); OldGmin = ckt->CKTdiagGmin; if ((ckt->CKTdiagGmin) < (factor * gtarget)){ factor = ckt->CKTdiagGmin / gtarget; ckt->CKTdiagGmin = gtarget; } else { ckt->CKTdiagGmin /= factor; } } } else { if (factor < 1.00005){ failed = 1; (*(SPfrontEnd->IFerror)) (ERR_WARNING, "Last gmin step failed", (IFuid *) NULL); } else { factor = sqrt (sqrt (factor)); ckt->CKTdiagGmin = OldGmin / factor; i = 0; for (n = ckt->CKTnodes; n; n = n->next){ *(ckt->CKTrhsOld + n->number) = OldRhsOld[i]; i++; } for (i = 0; i < ckt->CKTnumStates; i++){ *(ckt->CKTstate0 + i) = *(OldCKTstate0 + i); } } } } ckt->CKTdiagGmin = ckt->CKTgshunt; FREE (OldRhsOld); FREE (OldCKTstate0);#ifdef XSPICE/* gtri - begin - wbk - add convergence problem reporting flags */ if (ckt->CKTnumSrcSteps <= 0) ckt->enh->conv_debug.last_NIiter_call = MIF_TRUE; else ckt->enh->conv_debug.last_NIiter_call = MIF_FALSE;/* gtri - end - wbk - add convergence problem reporting flags */#endif converged = NIiter (ckt, iterlim); if (converged != 0){ (*(SPfrontEnd->IFerror)) (ERR_WARNING, "Dynamic Gmin stepping failed", (IFuid *) NULL); } else { (*(SPfrontEnd->IFerror)) (ERR_INFO, "Dynamic Gmin stepping completed", (IFuid *) NULL);#ifdef XSPICE/* gtri - begin - wbk - add convergence problem reporting flags */ ckt->enh->conv_debug.last_NIiter_call = MIF_FALSE;/* gtri - end - wbk - add convergence problem reporting flags */#endif } return (converged);}/* Spice3 gmin stepping * Modified 2000 - Alan Gillespie (added gshunt) * Modified 2005 - Paolo Nenzi (extracted from CKTop.c code) * * return value: * 0 -> method converged * 1 -> method failed * * Note that no path out of this code allows ckt->CKTdiagGmin to be * anything but CKTgshunt. */static intspice3_gmin (CKTcircuit * ckt, long int firstmode, long int continuemode, int iterlim){ int converged, i; ckt->CKTmode = firstmode; (*(SPfrontEnd->IFerror)) (ERR_INFO, "starting Gmin stepping", (IFuid *) NULL); if (ckt->CKTgshunt == 0) ckt->CKTdiagGmin = ckt->CKTgmin; else ckt->CKTdiagGmin = ckt->CKTgshunt; for (i = 0; i < ckt->CKTnumGminSteps; i++) ckt->CKTdiagGmin *= ckt->CKTgminFactor; for (i = 0; i <= ckt->CKTnumGminSteps; i++){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -