/* * Name: DOMNsetup * Purpose: convert a list of DOMNcard's to DOMNdomain's * Formals: cardList: list of cards to setup * domainList: returns the list of DOMNdomain's * xMeshList: list of coordinates in the x mesh * yMeshList: list of coordinates in the y mesh * Returns: OK/E_PRIVATE * Users: numerical devices * Calls: DOMNcheck */ int DOMNsetup(DOMNcard *cardList, DOMNdomain **domainList, MESHcoord *xMeshList, MESHcoord *yMeshList, MaterialInfo *materialList) { DOMNcard *card; DOMNdomain *newDomain = NULL; int ixMin, ixMax, iyMin, iyMax; int cardNum = 0; int error; char ebuf[512]; /* error message buffer */ /* Initialize list of domains */ *domainList = NULL; /* Check the card list */ if ((error = DOMNcheck( cardList, materialList )) != 0) return( error ); /* Find the limits on the indices */ MESHiBounds( xMeshList, &ixMin, &ixMax ); MESHiBounds( yMeshList, &iyMin, &iyMax ); error = OK; for ( card = cardList; card != NULL; card = card->DOMNnextCard ) { cardNum++; if (*domainList == NULL) { RALLOC( newDomain, DOMNdomain, 1 ); *domainList = newDomain; } else { RALLOC( newDomain->next, DOMNdomain, 1 ); newDomain = newDomain->next; } newDomain->id = card->DOMNnumber; newDomain->material = card->DOMNmaterial; newDomain->next = NULL; if (card->DOMNixLowGiven) { newDomain->ixLo = MAX(card->DOMNixLow, ixMin); } else if (card->DOMNxLowGiven) { newDomain->ixLo = MESHlocate( xMeshList, card->DOMNxLow ); } else { newDomain->ixLo = ixMin; } if (card->DOMNixHighGiven) { newDomain->ixHi = MIN(card->DOMNixHigh, ixMax); } else if (card->DOMNxHighGiven) { newDomain->ixHi = MESHlocate( xMeshList, card->DOMNxHigh ); } else { newDomain->ixHi = ixMax; } if (newDomain->ixLo > newDomain->ixHi) { sprintf( ebuf, "domain card %d has low x index (%d) > high x index (%d)", cardNum, newDomain->ixLo, newDomain->ixHi ); SPfrontEnd->IFerror( ERR_WARNING, ebuf, NULL ); error = E_PRIVATE; } if (card->DOMNiyLowGiven) { newDomain->iyLo = MAX(card->DOMNiyLow, iyMin); } else if (card->DOMNyLowGiven) { newDomain->iyLo = MESHlocate( yMeshList, card->DOMNyLow ); } else { newDomain->iyLo = iyMin; } if (card->DOMNiyHighGiven) { newDomain->iyHi = MIN(card->DOMNiyHigh, iyMax); } else if (card->DOMNyHighGiven) { newDomain->iyHi = MESHlocate( yMeshList, card->DOMNyHigh ); } else { newDomain->iyHi = iyMax; } if (newDomain->iyLo > newDomain->iyHi) { sprintf( ebuf, "domain card %d has low y index (%d) > high y index (%d)", cardNum, newDomain->iyLo, newDomain->iyHi ); SPfrontEnd->IFerror( ERR_WARNING, ebuf, NULL ); error = E_PRIVATE; } } return( error ); }
/* * Name: BDRYsetup * Purpose: Checks BDRY cards and then sets the indices * Formals: cardList: list of cards to setup, returns with indices set * xMeshList: list of coordinates in the x mesh * yMeshList: list of coordinates in the y mesh * Returns: OK/E_PRIVATE * Users: numerical devices * Calls: BDRYcheck */ int BDRYsetup(BDRYcard *cardList, MESHcoord *xMeshList, MESHcoord *yMeshList,DOMNdomain *domnList) { BDRYcard *card; int ixMin, ixMax, iyMin, iyMax; int cardNum = 0; int error; char ebuf[512]; /* error message buffer */ /* Check the card list */ if ((error = BDRYcheck( cardList, domnList ))) return( error ); /* Find the limits on the indices */ MESHiBounds( xMeshList, &ixMin, &ixMax ); MESHiBounds( yMeshList, &iyMin, &iyMax ); error = OK; for ( card = cardList; card != NIL(BDRYcard); card = card->BDRYnextCard ) { cardNum++; if (card->BDRYixLowGiven) { card->BDRYixLow = MAX(card->BDRYixLow, ixMin); } else if (card->BDRYxLowGiven) { card->BDRYixLow = MESHlocate( xMeshList, card->BDRYxLow ); } else { card->BDRYixLow = ixMin; } if (card->BDRYixHighGiven) { card->BDRYixHigh = MIN(card->BDRYixHigh, ixMax); } else if (card->BDRYxHighGiven) { card->BDRYixHigh = MESHlocate( xMeshList, card->BDRYxHigh ); } else { card->BDRYixHigh = ixMax; } if (card->BDRYixLow > card->BDRYixHigh) { sprintf( ebuf, "boundary card %d has low x index (%d) > high x index (%d)", cardNum, card->BDRYixHigh, card->BDRYixLow ); SPfrontEnd->IFerror( ERR_WARNING, ebuf, NIL(IFuid) ); error = E_PRIVATE; } if (card->BDRYiyLowGiven) { card->BDRYiyLow = MAX(card->BDRYiyLow, iyMin); } else if (card->BDRYyLowGiven) { card->BDRYiyLow = MESHlocate( yMeshList, card->BDRYyLow ); } else { card->BDRYiyLow = iyMin; } if (card->BDRYiyHighGiven) { card->BDRYiyHigh = MIN(card->BDRYiyHigh, iyMax); } else if (card->BDRYyHighGiven) { card->BDRYiyHigh = MESHlocate( yMeshList, card->BDRYyHigh ); } else { card->BDRYiyHigh = iyMax; } if (card->BDRYiyLow > card->BDRYiyHigh) { sprintf( ebuf, "boundary card %d has low y index (%d) > high y index (%d)", cardNum, card->BDRYiyHigh, card->BDRYiyLow ); SPfrontEnd->IFerror( ERR_WARNING, ebuf, NIL(IFuid) ); error = E_PRIVATE; } } return( error ); }
/* * Name: ELCTsetup * Purpose: convert a list of ELCTcard's to ELCTelectrode's * Formals: cardList: list of cards to setup * electrodeList: returns the list of ELCTelectrode's * xMeshList: list of coordinates in the x mesh * yMeshList: list of coordinates in the y mesh * Returns: OK/E_PRIVATE * Users: numerical devices * Calls: ELCTcheck */ int ELCTsetup(ELCTcard *cardList, ELCTelectrode **electrodeList, MESHcoord *xMeshList, MESHcoord *yMeshList) { ELCTcard *card; ELCTelectrode *newElectrode = NULL; int ixMin, ixMax, iyMin, iyMax; int cardNum = 0; int error; char ebuf[512]; /* error message buffer */ /* Initialize list of electrodes */ *electrodeList = NULL; /* Check the card list */ if ((error = ELCTcheck( cardList )) != 0) return( error ); /* Find the limits on the indices */ MESHiBounds( xMeshList, &ixMin, &ixMax ); MESHiBounds( yMeshList, &iyMin, &iyMax ); error = OK; for ( card = cardList; card != NULL; card = card->ELCTnextCard ) { cardNum++; if (*electrodeList == NULL) { RALLOC( newElectrode, ELCTelectrode, 1 ); *electrodeList = newElectrode; } else { RALLOC( newElectrode->next, ELCTelectrode, 1 ); newElectrode = newElectrode->next; } newElectrode->next = NULL; newElectrode->id = card->ELCTnumber; newElectrode->workf = 4.10 /* electron volts */; if (card->ELCTixLowGiven) { newElectrode->ixLo = MAX(card->ELCTixLow, ixMin); } else if (card->ELCTxLowGiven) { newElectrode->ixLo = MESHlocate( xMeshList, card->ELCTxLow ); } else { newElectrode->ixLo = ixMin; } if (card->ELCTixHighGiven) { newElectrode->ixHi = MIN(card->ELCTixHigh, ixMax); } else if (card->ELCTxHighGiven) { newElectrode->ixHi = MESHlocate( xMeshList, card->ELCTxHigh ); } else { newElectrode->ixHi = ixMax; } if (newElectrode->ixLo > newElectrode->ixHi) { sprintf( ebuf, "electrode card %d has low x index (%d) > high x index (%d)", cardNum, newElectrode->ixLo, newElectrode->ixHi ); SPfrontEnd->IFerror( ERR_WARNING, ebuf, NULL ); error = E_PRIVATE; } if (card->ELCTiyLowGiven) { newElectrode->iyLo = MAX(card->ELCTiyLow, iyMin); } else if (card->ELCTyLowGiven) { newElectrode->iyLo = MESHlocate( yMeshList, card->ELCTyLow ); } else { newElectrode->iyLo = iyMin; } if (card->ELCTiyHighGiven) { newElectrode->iyHi = MIN(card->ELCTiyHigh, iyMax); } else if (card->ELCTyHighGiven) { newElectrode->iyHi = MESHlocate( yMeshList, card->ELCTyHigh ); } else { newElectrode->iyHi = iyMax; } if (newElectrode->iyLo > newElectrode->iyHi) { sprintf( ebuf, "electrode card %d has low y index (%d) > high y index (%d)", cardNum, newElectrode->iyLo, newElectrode->iyHi ); SPfrontEnd->IFerror( ERR_WARNING, ebuf, NULL ); error = E_PRIVATE; } } return( error ); }
int NBJTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) /* * load the diode structure with those pointers needed later for fast matrix * loading */ { register NBJTmodel *model = (NBJTmodel *) inModel; register NBJTinstance *inst; METHcard *methods; MODLcard *models; OPTNcard *options; OUTPcard *outputs; int error; int xMeshSize; ONEdevice *pDevice; ONEcoord *xCoordList = NULL; ONEdomain *domainList = NULL; DOPprofile *profileList = NULL; DOPtable *dopTableList = NULL; ONEmaterial *pM, *pMaterial = NULL, *materialList = NULL; double startTime; /* loop through all the diode models */ for (; model != NULL; model = model->NBJTnextModel) { if (!model->NBJTpInfo) { TSCALLOC(model->NBJTpInfo, 1, ONEtranInfo); } methods = model->NBJTmethods; if (!methods) { TSCALLOC(methods, 1, METHcard); model->NBJTmethods = methods; } models = model->NBJTmodels; if (!models) { TSCALLOC(models, 1, MODLcard); model->NBJTmodels = models; } options = model->NBJToptions; if (!options) { TSCALLOC(options, 1, OPTNcard); model->NBJToptions = options; } outputs = model->NBJToutputs; if (!outputs) { TSCALLOC(outputs, 1, OUTPcard); model->NBJToutputs = outputs; } if (!methods->METHvoltPredGiven) { methods->METHvoltPred = FALSE; } if (!methods->METHmobDerivGiven) { methods->METHmobDeriv = TRUE; } if (!methods->METHoneCarrierGiven) { methods->METHoneCarrier = FALSE; } if (!methods->METHacAnalysisMethodGiven) { methods->METHacAnalysisMethod = SOR; } if (!methods->METHdabstolGiven) { methods->METHdabstol = DABSTOL1D; } if (!methods->METHdreltolGiven) { methods->METHdreltol = ckt->CKTreltol; } if (!methods->METHitLimGiven) { methods->METHitLim = 20; } if (!methods->METHomegaGiven || methods->METHomega <= 0.0) { methods->METHomega = 2.0 * M_PI /* radians/sec */ ; } if (!options->OPTNdefaGiven || options->OPTNdefa <= 0.0) { options->OPTNdefa = 1.0e4 /* cm^2 */ ; } if (!options->OPTNbaseLengthGiven) { options->OPTNbaseLength = 0.0; } if (!options->OPTNbaseAreaGiven) { options->OPTNbaseArea = 1.0; } if (!options->OPTNdeviceTypeGiven) { options->OPTNdeviceType = OPTN_BIPOLAR; } if (!options->OPTNicFileGiven) { options->OPTNicFile = NULL; options->OPTNunique = FALSE; /* Can't form a unique name. */ } if (!options->OPTNuniqueGiven) { options->OPTNunique = FALSE; } /* Set up the rest of the card lists */ if ((error = MODLsetup(model->NBJTmodels)) != 0) return (error); BandGapNarrowing = models->MODLbandGapNarrowing; ConcDepLifetime = models->MODLconcDepLifetime; TempDepMobility = models->MODLtempDepMobility; ConcDepMobility = models->MODLconcDepMobility; if ((error = OUTPsetup(model->NBJToutputs)) != 0) return (error); if ((error = MATLsetup(model->NBJTmaterials, &materialList)) != 0) return (error); if ((error = MOBsetup(model->NBJTmobility, materialList)) != 0) return (error); if ((error = MESHsetup('x', model->NBJTxMeshes, &xCoordList, &xMeshSize)) != 0) return (error); if ((error = DOMNsetup(model->NBJTdomains, &domainList, xCoordList, NULL, materialList)) != 0) return (error); if ((error = BDRYsetup(model->NBJTboundaries, xCoordList, NULL, domainList)) != 0) return (error); if ((error = CONTsetup(model->NBJTcontacts, NULL)) != 0) return (error); if ((error = DOPsetup(model->NBJTdopings, &profileList, &dopTableList, xCoordList, NULL)) != 0) return (error); model->NBJTmatlInfo = materialList; model->NBJTprofiles = profileList; model->NBJTdopTables = dopTableList; /* loop through all the instances of the model */ for (inst = model->NBJTinstances; inst != NULL; inst = inst->NBJTnextInstance) { startTime = SPfrontEnd->IFseconds(); if (!inst->NBJTprintGiven) { inst->NBJTprint = 0; } else if (inst->NBJTprint <= 0) { inst->NBJTprint = 1; } if (!inst->NBJTicFileGiven) { if (options->OPTNunique) { inst->NBJTicFile = tprintf("%s.%s", options->OPTNicFile, inst->NBJTname); } else if (options->OPTNicFile != NULL) { inst->NBJTicFile = tprintf("%s", options->OPTNicFile); } else { inst->NBJTicFile = NULL; } } inst->NBJTstate = *states; *states += NBJTnumStates; if (!inst->NBJTpDevice) { /* Assign the mesh info to each instance. */ TSCALLOC(pDevice, 1, ONEdevice); TSCALLOC(pDevice->pStats, 1, ONEstats); pDevice->name = inst->NBJTname; pDevice->solverType = SLV_NONE; pDevice->numNodes = xMeshSize; pDevice->abstol = methods->METHdabstol; pDevice->reltol = methods->METHdreltol; pDevice->rhsImag = NULL; TSCALLOC(pDevice->elemArray, pDevice->numNodes, ONEelem *); /* Create a copy of material data that can change with temperature. */ pDevice->pMaterials = NULL; for (pM = materialList; pM != NULL; pM = pM->next) { if (pDevice->pMaterials == NULL) { TSCALLOC(pMaterial, 1, ONEmaterial); pDevice->pMaterials = pMaterial; } else { TSCALLOC(pMaterial->next, 1, ONEmaterial); pMaterial = pMaterial->next; } /* Copy everything, then fix the incorrect pointer. */ memcpy(pMaterial, pM, sizeof(ONEmaterial)); pMaterial->next = NULL; } /* generate the mesh structure for the device */ ONEbuildMesh(pDevice, xCoordList, domainList, pDevice->pMaterials); if (options->OPTNbaseDepthGiven) { /* The base contact depth has been specified in the input. */ pDevice->baseIndex = MESHlocate(xCoordList, options->OPTNbaseDepth); } else { pDevice->baseIndex = -1; /* Invalid index acts as a flag */ } /* store the device info in the instance */ inst->NBJTpDevice = pDevice; } /* Now update the state pointers. */ ONEgetStatePointers(inst->NBJTpDevice, states); /* Wipe out statistics from previous runs (if any). */ memset(inst->NBJTpDevice->pStats, 0, sizeof(ONEstats)); inst->NBJTpDevice->pStats->totalTime[STAT_SETUP] += SPfrontEnd->IFseconds() - startTime; /* macro to make elements with built in test for out of memory */ #define TSTALLOC(ptr,first,second) \ do { if ((inst->ptr = SMPmakeElt(matrix, inst->first, inst->second)) == NULL){\ return(E_NOMEM);\ } } while(0) TSTALLOC(NBJTcolColPtr, NBJTcolNode, NBJTcolNode); TSTALLOC(NBJTbaseBasePtr, NBJTbaseNode, NBJTbaseNode); TSTALLOC(NBJTemitEmitPtr, NBJTemitNode, NBJTemitNode); TSTALLOC(NBJTcolBasePtr, NBJTcolNode, NBJTbaseNode); TSTALLOC(NBJTcolEmitPtr, NBJTcolNode, NBJTemitNode); TSTALLOC(NBJTbaseColPtr, NBJTbaseNode, NBJTcolNode); TSTALLOC(NBJTbaseEmitPtr, NBJTbaseNode, NBJTemitNode); TSTALLOC(NBJTemitColPtr, NBJTemitNode, NBJTcolNode); TSTALLOC(NBJTemitBasePtr, NBJTemitNode, NBJTbaseNode); } /* Clean up lists */ killCoordInfo(xCoordList); killDomainInfo(domainList); }