1 /**********
2 Copyright 1991 Regents of the University of California.  All rights reserved.
3 Author:	1987 Kartikeya Mayaram, U. C. Berkeley CAD Group
4 **********/
5 
6 #include "ngspice/ngspice.h"
7 #include "ngspice/cktdefs.h"
8 #include "ngspice/smpdefs.h"
9 #include "numddefs.h"
10 #include "ngspice/numconst.h"
11 #include "ngspice/numenum.h"
12 #include "ngspice/sperror.h"
13 #include "../../../ciderlib/oned/onedext.h"
14 #include "ngspice/cidersupt.h"
15 #include "ngspice/ciderinp.h"
16 #include "ngspice/suffix.h"
17 #include "ngspice/meshext.h"
18 
19 #define TSCALLOC(var, size, type)\
20 if (size && (var =(type *)calloc(1, (unsigned)(size)*sizeof(type))) == NULL) {\
21    return(E_NOMEM);\
22 }
23 
24 
25 int
NUMDsetup(SMPmatrix * matrix,GENmodel * inModel,CKTcircuit * ckt,int * states)26 NUMDsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
27 /*
28  * load the structure with those pointers needed later for fast matrix
29  * loading
30  */
31 {
32   register NUMDmodel *model = (NUMDmodel *) inModel;
33   register NUMDinstance *inst;
34   METHcard *methods;
35   MODLcard *models;
36   OPTNcard *options;
37   OUTPcard *outputs;
38   int error;
39   int xMeshSize;
40   ONEdevice *pDevice;
41   ONEcoord *xCoordList = NULL;
42   ONEdomain *domainList = NULL;
43   ONEmaterial *pM, *pMaterial = NULL, *materialList = NULL;
44   DOPprofile *profileList = NULL;
45   DOPtable *dopTableList = NULL;
46   double startTime;
47 
48 
49   /* loop through all the models */
50   for (; model != NULL; model = NUMDnextModel(model)) {
51     if (!model->NUMDpInfo) {
52       TSCALLOC(model->NUMDpInfo, 1, ONEtranInfo);
53     }
54     methods = model->NUMDmethods;
55     if (!methods) {
56       TSCALLOC(methods, 1, METHcard);
57       model->NUMDmethods = methods;
58     }
59     models = model->NUMDmodels;
60     if (!models) {
61       TSCALLOC(models, 1, MODLcard);
62       model->NUMDmodels = models;
63     }
64     options = model->NUMDoptions;
65     if (!options) {
66       TSCALLOC(options, 1, OPTNcard);
67       model->NUMDoptions = options;
68     }
69     outputs = model->NUMDoutputs;
70     if (!outputs) {
71       TSCALLOC(outputs, 1, OUTPcard);
72       model->NUMDoutputs = outputs;
73     }
74     if (!methods->METHvoltPredGiven) {
75       methods->METHvoltPred = FALSE;
76     }
77     if (!methods->METHmobDerivGiven) {
78       methods->METHmobDeriv = TRUE;
79     }
80     if (!methods->METHoneCarrierGiven) {
81       methods->METHoneCarrier = FALSE;
82     }
83     if (!methods->METHacAnalysisMethodGiven) {
84       methods->METHacAnalysisMethod = SOR;
85     }
86     if (!methods->METHdabstolGiven) {
87       methods->METHdabstol = DABSTOL1D;
88     }
89     if (!methods->METHdreltolGiven) {
90       methods->METHdreltol = ckt->CKTreltol;
91     }
92     if (!methods->METHitLimGiven) {
93       methods->METHitLim = 20;
94     }
95     if (!methods->METHomegaGiven || methods->METHomega <= 0.0) {
96       methods->METHomega = 2.0 * M_PI /* radians/sec */ ;
97     }
98     if (!options->OPTNdefaGiven || options->OPTNdefa <= 0.0) {
99       options->OPTNdefa = 1.0e4 /* cm^2 */ ;
100     }
101     if (!options->OPTNdeviceTypeGiven) {
102       options->OPTNdeviceType = OPTN_DIODE;
103     }
104     if (!options->OPTNicFileGiven) {
105       options->OPTNicFile = NULL;
106       options->OPTNunique = FALSE;		/* Can't form a unique name. */
107     }
108     if (!options->OPTNuniqueGiven) {
109       options->OPTNunique = FALSE;
110     }
111 
112     /* Set up the rest of the card lists */
113     if ((error = MODLsetup(model->NUMDmodels)) != 0)
114       return (error);
115     BandGapNarrowing = models->MODLbandGapNarrowing;
116     ConcDepLifetime = models->MODLconcDepLifetime;
117     TempDepMobility = models->MODLtempDepMobility;
118     ConcDepMobility = models->MODLconcDepMobility;
119 
120     if ((error = OUTPsetup(model->NUMDoutputs)) != 0)
121       return (error);
122     if ((error = MATLsetup(model->NUMDmaterials, &materialList)) != 0)
123       return (error);
124     if ((error = MOBsetup(model->NUMDmobility, materialList)) != 0)
125       return (error);
126     if ((error = MESHsetup('x', model->NUMDxMeshes, &xCoordList, &xMeshSize)) != 0)
127       return (error);
128     if ((error = DOMNsetup(model->NUMDdomains, &domainList,
129 	    xCoordList, NULL, materialList)) != 0)
130       return (error);
131     if ((error = BDRYsetup(model->NUMDboundaries,
132 	    xCoordList, NULL, domainList)) != 0)
133       return (error);
134     if ((error = CONTsetup(model->NUMDcontacts, NULL)) != 0)
135       return (error);
136     if ((error = DOPsetup(model->NUMDdopings, &profileList,
137 	    &dopTableList, xCoordList, NULL)) != 0)
138       return (error);
139     model->NUMDmatlInfo = materialList;
140     model->NUMDprofiles = profileList;
141     model->NUMDdopTables = dopTableList;
142 
143     /* loop through all the instances of the model */
144     for (inst = NUMDinstances(model); inst != NULL;
145          inst = NUMDnextInstance(inst)) {
146 
147       startTime = SPfrontEnd->IFseconds();
148 
149       if ((!inst->NUMDprintGiven)) {
150 	inst->NUMDprint = 0;
151       } else if (inst->NUMDprint <= 0) {
152 	inst->NUMDprint = 1;
153       }
154       if ((!inst->NUMDicFileGiven)) {
155 	if (options->OPTNunique) {
156 	  inst->NUMDicFile = tprintf("%s.%s", options->OPTNicFile, inst->NUMDname);
157 	} else if (options->OPTNicFile != NULL) {
158 	  inst->NUMDicFile = tprintf("%s", options->OPTNicFile);
159 	} else {
160 	  inst->NUMDicFile = NULL;
161 	}
162       }
163       inst->NUMDstate = *states;
164       *states += NUMDnumStates;
165 
166       if (!inst->NUMDpDevice) {
167 	/* Assign the mesh info to each instance. */
168 	TSCALLOC(pDevice, 1, ONEdevice);
169 	TSCALLOC(pDevice->pStats, 1, ONEstats);
170 	pDevice->name = inst->NUMDname;
171 	pDevice->solverType = SLV_NONE;
172 	pDevice->numNodes = xMeshSize;
173 	pDevice->abstol = methods->METHdabstol;
174 	pDevice->reltol = methods->METHdreltol;
175 	pDevice->rhsImag = NULL;
176 	TSCALLOC(pDevice->elemArray, pDevice->numNodes, ONEelem *);
177 
178 	/* Create a copy of material data that can change with temperature. */
179 	pDevice->pMaterials = NULL;
180 	for (pM = materialList; pM != NULL; pM = pM->next) {
181 	  if (pDevice->pMaterials == NULL) {
182 	    TSCALLOC(pMaterial, 1, ONEmaterial);
183 	    pDevice->pMaterials = pMaterial;
184 	  } else {
185 	    TSCALLOC(pMaterial->next, 1, ONEmaterial);
186 	    pMaterial = pMaterial->next;
187 	  }
188 	  /* Copy everything, then fix the incorrect pointer. */
189 	  memcpy(pMaterial, pM, sizeof(ONEmaterial));
190 	  pMaterial->next = NULL;
191 	}
192 
193 	/* generate the mesh structure for the device */
194 	ONEbuildMesh(pDevice, xCoordList, domainList, pDevice->pMaterials);
195 
196 	/* store the device info in the instance */
197 	inst->NUMDpDevice = pDevice;
198       }
199       /* Now update the state pointers. */
200       ONEgetStatePointers(inst->NUMDpDevice, states);
201 
202       /* Wipe out statistics from previous runs (if any). */
203       memset(inst->NUMDpDevice->pStats, 0, sizeof(ONEstats));
204 
205       inst->NUMDpDevice->pStats->totalTime[STAT_SETUP] +=
206 	  SPfrontEnd->IFseconds() - startTime;
207 
208       /* macro to make elements with built in test for out of memory */
209 #define TSTALLOC(ptr,first,second) \
210 do { if ((inst->ptr = SMPmakeElt(matrix, inst->first, inst->second)) == NULL){\
211   return(E_NOMEM);\
212 } } while(0)
213 
214       TSTALLOC(NUMDposPosPtr, NUMDposNode, NUMDposNode);
215       TSTALLOC(NUMDnegNegPtr, NUMDnegNode, NUMDnegNode);
216       TSTALLOC(NUMDnegPosPtr, NUMDnegNode, NUMDposNode);
217       TSTALLOC(NUMDposNegPtr, NUMDposNode, NUMDnegNode);
218     }
219     /* Clean up lists */
220     killCoordInfo(xCoordList);
221     killDomainInfo(domainList);
222   }
223   return (OK);
224 }
225