Enable CIDER with KLU for DC, OP, and TRAN analyses. Small signal AC analysis is not yet supported for CIDER complex valued device KLU matrices. The examples/cider testcases produce printed simulation result values which have slight differences between Sparse and KLU. Differences are probably expected and in a few cases are ~1-2%, sometimes a little more. This should be good enough for most CIDER analyses. Francesco did a good piece of work. Runtimes are significantly shorter with KLU.

This commit is contained in:
Brian Taylor
2026-02-03 13:55:12 +01:00
committed by Holger Vogt
parent 20561d309d
commit 7af862af3d
18 changed files with 854 additions and 9 deletions
+37 -1
View File
@@ -14,6 +14,8 @@ Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group
#include "ngspice/complex.h"
#include "ngspice/spmatrix.h"
#include "ngspice/ifsim.h"
#include "ngspice/cktdefs.h"
#include "ngspice/ftedefs.h"
#include "onedext.h"
#include "oneddefs.h"
@@ -29,7 +31,17 @@ extern IFfrontEnd *SPfrontEnd;
*/
SPcomplex yAc;
#ifdef KLU
static void small_signal_check(char *where)
{
if (ft_curckt->ci_ckt->CKTmode == MODEAC
|| ft_curckt->ci_ckt->CKTmode == MODEACNOISE) {
fprintf(stderr, "Error: CIDER %s small signal simulation is not (yet) supported with 'option klu'.\n", where);
fprintf(stderr, " Use 'option sparse' instead.\n");
controlled_exit(1);
}
}
#endif
int
NUMDadmittance(ONEdevice *pDevice, double omega, SPcomplex *yd)
@@ -45,6 +57,11 @@ NUMDadmittance(ONEdevice *pDevice, double omega, SPcomplex *yd)
bool SORFailed;
double startTime;
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
small_signal_check("NUMDadmittance");
}
#endif
/* Each time we call this counts as one AC iteration. */
pDevice->pStats->numIters[STAT_AC] += 1;
@@ -119,6 +136,7 @@ NUMDadmittance(ONEdevice *pDevice, double omega, SPcomplex *yd)
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
// Not implemented
pDevice->matrix->SMPkluMatrix->KLUmatrixIsComplex = KLUMatrixComplex ;
} else {
#endif
@@ -196,6 +214,11 @@ NBJTadmittance(ONEdevice *pDevice, double omega, SPcomplex *yIeVce,
SPcomplex cOmega, pIeVce, pIcVce, pIeVbe, pIcVbe;
double startTime;
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
small_signal_check("NBJTadmittance");
}
#endif
/* Each time we call this counts as one AC iteration. */
pDevice->pStats->numIters[STAT_AC] += 1;
@@ -315,6 +338,7 @@ NBJTadmittance(ONEdevice *pDevice, double omega, SPcomplex *yIeVce,
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
// Not implemented
pDevice->matrix->SMPkluMatrix->KLUmatrixIsComplex = KLUMatrixComplex ;
} else {
#endif
@@ -552,6 +576,11 @@ NUMDys(ONEdevice *pDevice, SPcomplex *s, SPcomplex *yd)
SPcomplex *y;
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
small_signal_check("NUMDys");
}
#endif
/*
* change context names of solution vectors for ac analysis dcDeltaSolution
* stores the real part and copiedSolution stores the imaginary part of the
@@ -580,6 +609,7 @@ NUMDys(ONEdevice *pDevice, SPcomplex *s, SPcomplex *yd)
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
// Not implemented
pDevice->matrix->SMPkluMatrix->KLUmatrixIsComplex = KLUMatrixComplex ;
} else {
#endif
@@ -640,6 +670,11 @@ NBJTys(ONEdevice *pDevice, SPcomplex *s, SPcomplex *yIeVce,
SPcomplex temp, cOmega;
SPcomplex pIeVce, pIcVce, pIeVbe, pIcVbe;
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
small_signal_check("NBJTys");
}
#endif
/*
* change context names of solution vectors for ac analysis dcDeltaSolution
* stores the real part and copiedSolution stores the imaginary part of the
@@ -667,6 +702,7 @@ NBJTys(ONEdevice *pDevice, SPcomplex *s, SPcomplex *yIeVce,
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
// Not implemented
pDevice->matrix->SMPkluMatrix->KLUmatrixIsComplex = KLUMatrixComplex ;
} else {
#endif
+45
View File
@@ -16,6 +16,9 @@ Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group
#include "ngspice/bool.h"
#include "ngspice/macros.h"
#include "ngspice/ifsim.h"
#include "ngspice/cktdefs.h"
#include "ngspice/ftedefs.h"
#include "twoddefs.h"
#include "twodext.h"
#include "ngspice/cidersupt.h"
@@ -28,6 +31,18 @@ extern IFfrontEnd *SPfrontEnd;
*/
SPcomplex yTotal;
#ifdef KLU
static void small_signal_check(char *where)
{
if (ft_curckt->ci_ckt->CKTmode == MODEAC
|| ft_curckt->ci_ckt->CKTmode == MODEACNOISE) {
fprintf(stderr, "Error: CIDER %s small signal simulation is not (yet) supported with 'option klu'.\n", where);
fprintf(stderr, " Use 'option sparse' instead.\n");
controlled_exit(1);
}
}
#endif
int
NUMD2admittance(TWOdevice *pDevice, double omega, SPcomplex *yd)
{
@@ -42,6 +57,11 @@ NUMD2admittance(TWOdevice *pDevice, double omega, SPcomplex *yd)
bool SORFailed;
double startTime;
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
small_signal_check("NUMD2admittance");
}
#endif
/* Each time we call this counts as one AC iteration. */
pDevice->pStats->numIters[STAT_AC] += 1;
@@ -192,6 +212,11 @@ NBJT2admittance(TWOdevice *pDevice, double omega, SPcomplex *yIeVce,
SPcomplex cOmega;
double startTime;
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
small_signal_check("NBJT2admittance");
}
#endif
/* Each time we call this counts as one AC iteration. */
pDevice->pStats->numIters[STAT_AC] += 1;
@@ -416,6 +441,11 @@ NUMOSadmittance(TWOdevice *pDevice, double omega, struct mosAdmittances *yAc)
SPcomplex *y, cOmega;
double startTime;
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
small_signal_check("NUMOSadmittance");
}
#endif
/* Each time we call this counts as one AC iteration. */
pDevice->pStats->numIters[STAT_AC] += 1;
@@ -1151,6 +1181,11 @@ NUMD2ys(TWOdevice *pDevice, SPcomplex *s, SPcomplex *yIn)
bool deltaVContact = FALSE;
SPcomplex temp, cOmega;
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
small_signal_check("NUMD2ys");
}
#endif
/*
* change context names of solution vectors for ac analysis dcDeltaSolution
* stores the real part and copiedSolution stores the imaginary part of the
@@ -1252,6 +1287,11 @@ NBJT2ys(TWOdevice *pDevice, SPcomplex *s, SPcomplex *yIeVce, SPcomplex *yIcVce,
SPcomplex pIeVce, pIcVce, pIeVbe, pIcVbe;
SPcomplex temp, cOmega;
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
small_signal_check("NBJT2ys");
}
#endif
pDevice->solverType = SLV_SMSIG;
rhsReal = pDevice->rhs;
rhsImag = pDevice->rhsImag;
@@ -1375,6 +1415,11 @@ NUMOSys(TWOdevice *pDevice, SPcomplex *s, struct mosAdmittances *yAc)
SPcomplex *y;
SPcomplex temp, cOmega;
#ifdef KLU
if (pDevice->matrix->CKTkluMODE) {
small_signal_check("NUMOSys");
}
#endif
pDevice->solverType = SLV_SMSIG;
rhsReal = pDevice->rhs;
rhsImag = pDevice->rhsImag;
+2 -1
View File
@@ -1149,7 +1149,8 @@ TWObindCSC (TWOdevice *pDevice)
}
} else { /* Horizontal Slice */
if ( nIndex <= 1 ) { /* Top Side */
//if ( nIndex <= 1 ) { /* Top Side */
if ( nIndex == 0 || nIndex == 3 ) { /* Left (Top?) Side : bug 483 */
CREATE_KLU_BINDING_TABLE_CIDER(fNPsiIn, fNPsiInBinding, nEqn, psiEqnInM) ;
CREATE_KLU_BINDING_TABLE_CIDER(fNPsiInP1, fNPsiInP1Binding, nEqn, psiEqnInP) ;
+2 -1
View File
@@ -786,7 +786,8 @@ TWONbindCSC (TWOdevice *pDevice)
}
} else { /* Horizontal Slice */
if ( nIndex <= 1 ) { /* Top Side */
//if ( nIndex <= 1 ) { /* Top Side */
if ( nIndex == 0 || nIndex == 3 ) { /* Left (Top?) Side : bug 483 */
CREATE_KLU_BINDING_TABLE_CIDER(fNPsiIn, fNPsiInBinding, nEqn, psiEqnInM) ;
CREATE_KLU_BINDING_TABLE_CIDER(fNPsiInP1, fNPsiInP1Binding, nEqn, psiEqnInP) ;
+2 -1
View File
@@ -786,7 +786,8 @@ TWOPbindCSC (TWOdevice *pDevice)
}
} else { /* Horizontal Slice */
if ( nIndex <= 1 ) { /* Top Side */
//if ( nIndex <= 1 ) { /* Top Side */
if ( nIndex == 0 || nIndex == 3 ) { /* Left (Top?) Side : bug 483 */
CREATE_KLU_BINDING_TABLE_CIDER(fPPsiIn, fPPsiInBinding, pEqn, psiEqnInM) ;
CREATE_KLU_BINDING_TABLE_CIDER(fPPsiInP1, fPPsiInP1Binding, pEqn, psiEqnInP) ;
+1 -1
View File
@@ -44,7 +44,7 @@ NBJTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
ONEmaterial *pM, *pMaterial = NULL, *materialList = NULL;
double startTime;
#ifdef KLU
#if defined(KLU) && defined(NOT_WITH_CIDER)
if (ckt->CKTkluMODE) {
fprintf(stderr, "Error: CIDER simulation is not (yet) supported with 'option klu'.\n");
fprintf(stderr, " Use 'option sparse' instead.\n");
+1 -1
View File
@@ -47,7 +47,7 @@ NBJT2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
DOPtable *dopTableList = NULL;
double startTime;
#ifdef KLU
#if defined(KLU) && defined(NOT_WITH_CIDER)
if (ckt->CKTkluMODE) {
fprintf(stderr, "Error: CIDER simulation is not (yet) supported with 'option klu'.\n");
fprintf(stderr, " Use 'option sparse' instead.\n");
+1 -1
View File
@@ -46,7 +46,7 @@ NUMDsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
double startTime;
#ifdef KLU
#if defined(KLU) && defined(NOT_WITH_CIDER)
if (ckt->CKTkluMODE) {
fprintf(stderr, "Error: CIDER simulation is not (yet) supported with 'option klu'.\n");
fprintf(stderr, " Use 'option sparse' instead.\n");
+1 -1
View File
@@ -47,7 +47,7 @@ NUMD2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
DOPtable *dopTableList = NULL;
double startTime;
#ifdef KLU
#if defined(KLU) && defined(NOT_WITH_CIDER)
if (ckt->CKTkluMODE) {
fprintf(stderr, "Error: CIDER simulation is not (yet) supported with 'option klu'.\n");
fprintf(stderr, " Use 'option sparse' instead.\n");
+1 -1
View File
@@ -47,7 +47,7 @@ NUMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
DOPtable *dopTableList = NULL;
double startTime;
#ifdef KLU
#if defined(KLU) && defined(NOT_WITH_CIDER)
if (ckt->CKTkluMODE) {
fprintf(stderr, "Error: CIDER simulation is not (yet) supported with 'option klu'.\n");
fprintf(stderr, " Use 'option sparse' instead.\n");