diff --git a/src/spicelib/analysis/cktsetup.c b/src/spicelib/analysis/cktsetup.c index ccdb3f9b5..985739c64 100644 --- a/src/spicelib/analysis/cktsetup.c +++ b/src/spicelib/analysis/cktsetup.c @@ -13,14 +13,8 @@ Author: 1985 Thomas L. Quarles #include "ngspice/smpdefs.h" #include "ngspice/cktdefs.h" #include "ngspice/devdefs.h" -#include "ngspice/gendefs.h" #include "ngspice/sperror.h" #include "ngspice/fteext.h" -#include "ngspice/cpextern.h" - -/* device headers needed by CKTtopologyReduce() to mark dangling passives */ -#include "../devices/cap/capdefs.h" -#include "../devices/res/resdefs.h" #ifdef XSPICE #include "ngspice/enh.h" @@ -36,131 +30,6 @@ Author: 1985 Thomas L. Quarles return(E_NOMEM);\ } -/* Topology reduction for removing dangling capacitors and resistors. - * - * A node whose only connection is a single passive terminal (a degree-1 - * "dangling" node, e.g. the dead end of an opamp compensation cap) carries no - * steady current/charge, but its row becomes ill-conditioned as the timestep - * shrinks and shows up as a spurious "Timestep too small" abort. Commercial - * fast simulators simply remove such elements from the matrix. This - * pass does the same: it finds dangling passive leaves and marks the owning - * capacitor/resistor so that, at load time, the device contributes nothing and - * its floating node is pinned with a unit diagonal (kept nonsingular). - * - * Node degree is counted GENERICALLY over every device type through the - * GENnode() terminal array, so no device family can be missed (which would - * wrongly prune a live node). Only capacitors and resistors are ever removed. - * Disable with `set no_topo_reduce` in .spiceinit. */ -static void -CKTtopologyReduce(CKTcircuit *ckt) -{ - int i, t, nterm, maxnode, removed_total = 0, reported = 0; - int captype = -1, restype = -1; - int *degree; - GENmodel *gmod; - GENinstance *ginst; - - if (cp_getvar("no_topo_reduce", CP_BOOL, NULL, 0)) - return; - - maxnode = ckt->CKTmaxEqNum; - if (maxnode < 1) - return; - - degree = TMALLOC(int, maxnode + 1); - if (!degree) - return; - for (i = 0; i <= maxnode; i++) - degree[i] = 0; - - /* complete, type-agnostic node degree over all device terminals */ - for (i = 0; i < DEVmaxnum; i++) { - if (!DEVices[i] || !ckt->CKThead[i] || !DEVices[i]->DEVpublic.terms) - continue; - nterm = *(DEVices[i]->DEVpublic.terms); - if (DEVices[i]->DEVpublic.name) { - if (!strcmp(DEVices[i]->DEVpublic.name, "Capacitor")) captype = i; - else if (!strcmp(DEVices[i]->DEVpublic.name, "Resistor")) restype = i; - } - for (gmod = ckt->CKThead[i]; gmod; gmod = gmod->GENnextModel) - for (ginst = gmod->GENinstances; ginst; ginst = ginst->GENnextInstance) { - int *nodes = GENnode(ginst); - for (t = 0; t < nterm; t++) { - int nd = nodes[t]; - if (nd > 0 && nd <= maxnode) - degree[nd]++; - } - } - } - - if (captype < 0 && restype < 0) { - FREE(degree); - return; - } - - /* Leaf-prune to a fixpoint: removing a dangling passive can drop its other - * node to degree 1, exposing the next leaf of a dangling chain. */ - for (;;) { - int removed_this_pass = 0; - - if (captype >= 0) { - CAPmodel *cm; - for (cm = (CAPmodel *)ckt->CKThead[captype]; cm; cm = CAPnextModel(cm)) - for (CAPinstance *ci = CAPinstances(cm); ci; ci = CAPnextInstance(ci)) { - int pn = ci->CAPposNode, nn = ci->CAPnegNode, mode = 0; - if (ci->CAPdangling) - continue; - if (pn > 0 && degree[pn] == 1) mode |= 1; - if (nn > 0 && degree[nn] == 1) mode |= 2; - if (!mode) - continue; - ci->CAPdangling = mode; - if (mode & 1) degree[pn] = 0; else if (pn > 0) degree[pn]--; - if (mode & 2) degree[nn] = 0; else if (nn > 0) degree[nn]--; - removed_this_pass++; - if (reported++ < 40) - fprintf(stdout, - "Topology reduction: removed dangling capacitor %s " - "(floating node %s)\n", ci->CAPname, - (char *)CKTnodName(ckt, (mode & 2) ? nn : pn)); - } - } - - if (restype >= 0) { - RESmodel *rm; - for (rm = (RESmodel *)ckt->CKThead[restype]; rm; rm = RESnextModel(rm)) - for (RESinstance *ri = RESinstances(rm); ri; ri = RESnextInstance(ri)) { - int pn = ri->RESposNode, nn = ri->RESnegNode, mode = 0; - if (ri->RESdangling) - continue; - if (pn > 0 && degree[pn] == 1) mode |= 1; - if (nn > 0 && degree[nn] == 1) mode |= 2; - if (!mode) - continue; - ri->RESdangling = mode; - if (mode & 1) degree[pn] = 0; else if (pn > 0) degree[pn]--; - if (mode & 2) degree[nn] = 0; else if (nn > 0) degree[nn]--; - removed_this_pass++; - if (reported++ < 40) - fprintf(stdout, - "Topology reduction: removed dangling resistor %s " - "(floating node %s)\n", ri->RESname, - (char *)CKTnodName(ckt, (mode & 2) ? nn : pn)); - } - } - - removed_total += removed_this_pass; - if (!removed_this_pass) - break; - } - - if (removed_total) - fprintf(stdout, "Topology reduction: %d dangling passive(s) removed " - "from the matrix.\n", removed_total); - - FREE(degree); -} - int CKTsetup(CKTcircuit *ckt) { @@ -247,13 +116,6 @@ CKTsetup(CKTcircuit *ckt) } } - /* Topology reduction for removing dangling capacitors and resistors: - * mark dangling (degree-1) passive leaves - * for removal. Done after all device setups (so the node degrees are - * complete) but before the matrix is converted/bound for the linear - * solver -- it only changes load-time stamping, not the matrix structure. */ - CKTtopologyReduce(ckt); - #ifdef XSPICE /* gtri - begin - Setup for adding rshunt option resistors */ diff --git a/src/spicelib/devices/cap/capdefs.h b/src/spicelib/devices/cap/capdefs.h index 3f6d10e6f..32dda86e0 100644 --- a/src/spicelib/devices/cap/capdefs.h +++ b/src/spicelib/devices/cap/capdefs.h @@ -64,12 +64,6 @@ typedef struct sCAPinstance { unsigned CAPbv_maxGiven : 1; /* flags indicates maximum voltage is given */ int CAPsenParmNo; /* parameter # for sensitivity use; set equal to 0 if not a design parameter*/ - int CAPdangling; /* topology reduction: 0 = normal device; - bit0 set => pos node is a dangling (degree-1) floating node, - bit1 set => neg node is a dangling floating node. A dangling - cap is removed from the system: it contributes no - charge/current and its floating node(s) are pinned with a unit - diagonal so the matrix stays nonsingular. Set in CKTtopologyReduce(). */ #ifdef KLU BindElement *CAPposPosBinding ; diff --git a/src/spicelib/devices/cap/capload.c b/src/spicelib/devices/cap/capload.c index e0dcecb7a..d7ed3224d 100644 --- a/src/spicelib/devices/cap/capload.c +++ b/src/spicelib/devices/cap/capload.c @@ -50,19 +50,6 @@ CAPload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTrhsOld+here->CAPnegNode) ; } if(ckt->CKTmode & (MODETRAN | MODEAC)) { - if (here->CAPdangling) { - /* Topology reduction: this cap hangs on a - * floating (degree-1) node. Remove it from the system: - * pin the floating node(s) with a unit diagonal so the - * matrix stays nonsingular, and contribute no charge or - * current. This eliminates the spurious LTE pressure - * that otherwise drives "Timestep too small" at the - * dangling node (set in CKTtopologyReduce()). */ - if (here->CAPdangling & 1) *(here->CAPposPosPtr) += 1.0; - if (here->CAPdangling & 2) *(here->CAPnegNegPtr) += 1.0; - *(ckt->CKTstate0+here->CAPqcap) = 0.0; - continue; - } #ifndef PREDICTOR if(ckt->CKTmode & MODEINITPRED) { *(ckt->CKTstate0+here->CAPqcap) = @@ -84,20 +71,10 @@ CAPload(GENmodel *inModel, CKTcircuit *ckt) *(ckt->CKTstate1+here->CAPccap) = *(ckt->CKTstate0+here->CAPccap); } - /* Tiny conductance in parallel with the capacitor so that a - * node connected only through capacitors (e.g. a dangling - * compensation cap) still has a DC reference and cannot drift - * into a singular/ill-conditioned operating point. This - * restores the 1e15 ohm "avoid floating nodes" resistor that - * the old behavioral C=f(v) expansion placed across the cap; - * 1e-15 S is negligible for caps on driven nodes. */ - { - double gpar = 1e-15; - *(here->CAPposPosPtr) += m * geq + gpar; - *(here->CAPnegNegPtr) += m * geq + gpar; - *(here->CAPposNegPtr) -= m * geq + gpar; - *(here->CAPnegPosPtr) -= m * geq + gpar; - } + *(here->CAPposPosPtr) += m * geq; + *(here->CAPnegNegPtr) += m * geq; + *(here->CAPposNegPtr) -= m * geq; + *(here->CAPnegPosPtr) -= m * geq; *(ckt->CKTrhs+here->CAPposNode) -= m * ceq; *(ckt->CKTrhs+here->CAPnegNode) += m * ceq; } else diff --git a/src/spicelib/devices/res/resdefs.h b/src/spicelib/devices/res/resdefs.h index d8a9fcc0a..e6c2c6b39 100644 --- a/src/spicelib/devices/res/resdefs.h +++ b/src/spicelib/devices/res/resdefs.h @@ -81,10 +81,6 @@ typedef struct sRESinstance { unsigned RESbv_maxGiven : 1; /* flags indicates maximum voltage is given */ int RESsenParmNo; /* parameter # for sensitivity use; * set equal to 0 if not a design parameter*/ - int RESdangling; /* topology reduction: 0 = normal device; - bit0 => pos node dangling, bit1 => neg node dangling. A dangling - resistor is removed from the system and its floating node(s) - pinned with a unit diagonal. Set in CKTtopologyReduce(). */ #ifndef NONOISE double RESnVar[NSTATVARS][RESNSRCS]; diff --git a/src/spicelib/devices/res/resload.c b/src/spicelib/devices/res/resload.c index 884583f30..db4ac539f 100644 --- a/src/spicelib/devices/res/resload.c +++ b/src/spicelib/devices/res/resload.c @@ -25,16 +25,6 @@ RESload(GENmodel *inModel, CKTcircuit *ckt) for (here = RESinstances(model); here != NULL ; here = RESnextInstance(here)) { - if (here->RESdangling) { - /* Topology reduction: dangling (degree-1) resistor. - * Remove it from the system, pin the floating node(s) with a - * unit diagonal (set in CKTtopologyReduce()). */ - if (here->RESdangling & 1) *(here->RESposPosPtr) += 1.0; - if (here->RESdangling & 2) *(here->RESnegNegPtr) += 1.0; - here->REScurrent = 0.0; - continue; - } - here->REScurrent = (*(ckt->CKTrhsOld+here->RESposNode) - *(ckt->CKTrhsOld+here->RESnegNode)) * here->RESconduct;