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