/********** Copyright 1992 Regents of the University of California. All rights reserved. Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group Author: 1992 David A. Gates, U. C. Berkeley CAD Group **********/ #include "ngspice/ngspice.h" #include "ngspice/numglobs.h" #include "ngspice/numconst.h" #include "ngspice/numenum.h" #include "ngspice/onemesh.h" #include "ngspice/onedev.h" #include "ngspice/carddefs.h" #include "ngspice/spmatrix.h" #include "onedext.h" #include "oneddefs.h" #include void ONEprnSolution(FILE *file, ONEdevice *pDevice, OUTPcard *output) { int index, i; int numVars = 0; ONEnode **nodeArray=NULL; ONEnode *pNode; ONEelem *pElem, *pPrevElem; ONEmaterial *info=NULL; double data[50]; double eField, refPsi = 0.0, eGap, dGap; double mun, mup, jc, jd, jn, jp, jt; double coeff1, coeff2; if (output->OUTPnumVars == -1) { /* First pass. Need to count number of variables in output. */ numVars++; /* For the X scale */ if (output->OUTPdoping) { numVars++; } if (output->OUTPpsi) { numVars++; } if (output->OUTPequPsi) { numVars++; } if (output->OUTPvacPsi) { numVars++; } if (output->OUTPnConc) { numVars++; } if (output->OUTPpConc) { numVars++; } if (output->OUTPphin) { numVars++; } if (output->OUTPphip) { numVars++; } if (output->OUTPphic) { numVars++; } if (output->OUTPphiv) { numVars++; } if (output->OUTPeField) { numVars++; } if (output->OUTPjc) { numVars++; } if (output->OUTPjd) { numVars++; } if (output->OUTPjn) { numVars++; } if (output->OUTPjp) { numVars++; } if (output->OUTPjt) { numVars++; } if (output->OUTPuNet) { numVars++; } if (output->OUTPmun) { numVars++; } if (output->OUTPmup) { numVars++; } output->OUTPnumVars = numVars; } /* generate the work array for printing node info */ XCALLOC(nodeArray, ONEnode *, 1 + pDevice->numNodes); /* store the nodes in this work array and print out later */ for (index = 1; index < pDevice->numNodes; index++) { pElem = pDevice->elemArray[index]; if (refPsi == 0.0 && pElem->matlInfo->type == SEMICON) { refPsi = pElem->matlInfo->refPsi; } for (i = 0; i <= 1; i++) { if (pElem->evalNodes[i]) { pNode = pElem->pNodes[i]; nodeArray[pNode->nodeI] = pNode; } } } /* Initialize rawfile */ numVars = output->OUTPnumVars; fprintf(file, "Title: Device %s internal state\n", pDevice->name); fprintf(file, "Plotname: Device Cross Section\n"); fprintf(file, "Flags: real\n"); fprintf(file, "Command: deftype p xs cross\n"); fprintf(file, "Command: deftype v distance m\n"); fprintf(file, "Command: deftype v concentration cm^-3\n"); fprintf(file, "Command: deftype v electric_field V/cm\n"); fprintf(file, "Command: deftype v current_density A/cm^2\n"); fprintf(file, "Command: deftype v concentration/time cm^-3/s\n"); fprintf(file, "Command: deftype v mobility cm^2/Vs\n"); fprintf(file, "No. Variables: %d\n", numVars); fprintf(file, "No. Points: %d\n", pDevice->numNodes); numVars = 0; fprintf(file, "Variables:\n"); fprintf(file, "\t%d x distance\n", numVars++); if (output->OUTPpsi) { fprintf(file, "\t%d psi voltage\n", numVars++); } if (output->OUTPequPsi) { fprintf(file, "\t%d equ.psi voltage\n", numVars++); } if (output->OUTPvacPsi) { fprintf(file, "\t%d vac.psi voltage\n", numVars++); } if (output->OUTPphin) { fprintf(file, "\t%d phin voltage\n", numVars++); } if (output->OUTPphip) { fprintf(file, "\t%d phip voltage\n", numVars++); } if (output->OUTPphic) { fprintf(file, "\t%d phic voltage\n", numVars++); } if (output->OUTPphiv) { fprintf(file, "\t%d phiv voltage\n", numVars++); } if (output->OUTPdoping) { fprintf(file, "\t%d dop concentration\n", numVars++); } if (output->OUTPnConc) { fprintf(file, "\t%d n concentration\n", numVars++); } if (output->OUTPpConc) { fprintf(file, "\t%d p concentration\n", numVars++); } if (output->OUTPeField) { fprintf(file, "\t%d e electric_field\n", numVars++); } if (output->OUTPjc) { fprintf(file, "\t%d jc current_density\n", numVars++); } if (output->OUTPjd) { fprintf(file, "\t%d jd current_density\n", numVars++); } if (output->OUTPjn) { fprintf(file, "\t%d jn current_density\n", numVars++); } if (output->OUTPjp) { fprintf(file, "\t%d jp current_density\n", numVars++); } if (output->OUTPjt) { fprintf(file, "\t%d jt current_density\n", numVars++); } if (output->OUTPuNet) { fprintf(file, "\t%d unet concentration/time\n", numVars++); } if (output->OUTPmun) { fprintf(file, "\t%d mun mobility\n", numVars++); } if (output->OUTPmup) { fprintf(file, "\t%d mup mobility\n", numVars++); } fprintf(file, "Binary:\n"); for (index = 1; index <= pDevice->numNodes; index++) { pNode = nodeArray[index]; if ((index > 1) && (index < pDevice->numNodes)) { pElem = pNode->pRightElem; pPrevElem = pNode->pLeftElem; if (pElem->evalNodes[0]) { info = pElem->matlInfo; } else if (pPrevElem->evalNodes[1]) { info = pPrevElem->matlInfo; } coeff1 = pPrevElem->dx / (pPrevElem->dx + pElem->dx); coeff2 = pElem->dx / (pPrevElem->dx + pElem->dx); eField = -coeff1 * pElem->pEdge->dPsi * pElem->rDx - coeff2 * pPrevElem->pEdge->dPsi * pPrevElem->rDx; mun = coeff1 * pElem->pEdge->mun + coeff2 * pPrevElem->pEdge->mun; mup = coeff1 * pElem->pEdge->mup + coeff2 * pPrevElem->pEdge->mup; jn = coeff1 * pElem->pEdge->jn + coeff2 * pPrevElem->pEdge->jn; jp = coeff1 * pElem->pEdge->jp + coeff2 * pPrevElem->pEdge->jp; jd = coeff1 * pElem->pEdge->jd + coeff2 * pPrevElem->pEdge->jd; } else if (index == 1) { info = pNode->pRightElem->matlInfo; eField = 0.0; mun = pNode->pRightElem->pEdge->mun; mup = pNode->pRightElem->pEdge->mup; jn = pNode->pRightElem->pEdge->jn; jp = pNode->pRightElem->pEdge->jp; jd = pNode->pRightElem->pEdge->jd; } else { info = pNode->pLeftElem->matlInfo; eField = 0.0; mun = pNode->pLeftElem->pEdge->mun; mup = pNode->pLeftElem->pEdge->mup; jn = pNode->pLeftElem->pEdge->jn; jp = pNode->pLeftElem->pEdge->jp; jd = pNode->pLeftElem->pEdge->jd; } jc = jn + jp; jt = jc + jd; /* Crude hack to get around the fact that the base node wipes out 'eg' */ if (index == pDevice->baseIndex) { eGap = info->eg0; dGap = 0.0; } else { eGap = pNode->eg * VNorm; dGap = 0.5 * (info->eg0 - eGap); } /* Now fill in the data array */ numVars = 0; data[numVars++] = pNode->x * 1e-2; if (output->OUTPpsi) { data[numVars++] = (pNode->psi - refPsi) * VNorm; } if (output->OUTPequPsi) { data[numVars++] = (pNode->psi0 - refPsi) * VNorm; } if (output->OUTPvacPsi) { data[numVars++] = pNode->psi * VNorm; } if (output->OUTPphin) { if (info->type != INSULATOR) { data[numVars++] = (pNode->psi - refPsi - log(pNode->nConc / pNode->nie)) * VNorm; } else { data[numVars++] = 0.0; } } if (output->OUTPphip) { if (info->type != INSULATOR) { data[numVars++] = (pNode->psi - refPsi + log(pNode->pConc / pNode->nie)) * VNorm; } else { data[numVars++] = 0.0; } } if (output->OUTPphic) { data[numVars++] = (pNode->psi + pNode->eaff) * VNorm + dGap; } if (output->OUTPphiv) { data[numVars++] = (pNode->psi + pNode->eaff) * VNorm + dGap + eGap; } if (output->OUTPdoping) { data[numVars++] = pNode->netConc * NNorm; } if (output->OUTPnConc) { data[numVars++] = pNode->nConc * NNorm; } if (output->OUTPpConc) { data[numVars++] = pNode->pConc * NNorm; } if (output->OUTPeField) { data[numVars++] = eField * ENorm; } if (output->OUTPjc) { data[numVars++] = jc * JNorm; } if (output->OUTPjd) { data[numVars++] = jd * JNorm; } if (output->OUTPjn) { data[numVars++] = jn * JNorm; } if (output->OUTPjp) { data[numVars++] = jp * JNorm; } if (output->OUTPjt) { data[numVars++] = jt * JNorm; } if (output->OUTPuNet) { data[numVars++] = pNode->uNet * NNorm / TNorm; } if (output->OUTPmun) { data[numVars++] = mun; } if (output->OUTPmup) { data[numVars++] = mup; } fwrite(data, sizeof(double), (size_t) numVars, file); } FREE(nodeArray); } /* * XXX This is what the SPARSE element structure looks like. We can't take it * from its definition because the include file redefines all sorts of * things. Note that we are violating data encapsulation to find out the * size of this thing. */ struct MatrixElement { spREAL Real; spREAL Imag; int Row; int Col; struct MatrixElement *NextInRow; struct MatrixElement *NextInCol; }; void ONEmemStats(FILE *file, ONEdevice *pDevice) { const char memFormat[] = "%-20s" "%10d" "%10" PRIuPTR "\n"; /* static const char sumFormat[] = "%20s %-10d\n";*/ int size; size_t memory; ONEmaterial *pMaterial; ONEcontact *pContact; int numContactNodes; fprintf(file, "----------------------------------------\n"); fprintf(file, "Device %s Memory Usage:\n", pDevice->name); fprintf(file, "Item Count Bytes\n"); fprintf(file, "----------------------------------------\n"); size = 1; memory = (size_t) size * sizeof(ONEdevice); fprintf(file, memFormat, "Device", size, memory); size = pDevice->numNodes - 1; memory = (size_t) size * sizeof(ONEelem); fprintf(file, memFormat, "Elements", size, memory); size = pDevice->numNodes; memory = (size_t) size * sizeof(ONEnode); fprintf(file, memFormat, "Nodes", size, memory); size = pDevice->numNodes - 1; memory = (size_t) size * sizeof(ONEedge); fprintf(file, memFormat, "Edges", size, memory); size = pDevice->numNodes; memory = (size_t) size * sizeof(ONEelem *); size = 0; for (pMaterial = pDevice->pMaterials; pMaterial; pMaterial = pMaterial->next) size++; memory += (size_t) size * sizeof(ONEmaterial); size = numContactNodes = 0; for (pContact = pDevice->pFirstContact; pContact; pContact = pContact->next) { numContactNodes += pContact->numNodes; size++; } memory += (size_t) size * sizeof(ONEcontact); size = numContactNodes; memory += (size_t) size * sizeof(ONEnode *); size = 0; fprintf(file, "%-20s%10s%10" PRIuPTR "\n", "Misc Mesh", "n/a", memory); size = pDevice->numOrigEquil; memory = (size_t) size * sizeof(struct MatrixElement); fprintf(file, memFormat, "Equil Orig NZ", size, memory); size = pDevice->numFillEquil; memory = (size_t) size * sizeof(struct MatrixElement); fprintf(file, memFormat, "Equil Fill NZ", size, memory); size = pDevice->numOrigEquil + pDevice->numFillEquil; memory = (size_t) size * sizeof(struct MatrixElement); fprintf(file, memFormat, "Equil Tot NZ", size, memory); size = pDevice->dimEquil; memory = (size_t) size * 4 * sizeof(double); fprintf(file, memFormat, "Equil Vectors", size, memory); size = pDevice->numOrigBias; memory = (size_t) size * sizeof(struct MatrixElement); fprintf(file, memFormat, "Bias Orig NZ", size, memory); size = pDevice->numFillBias; memory = (size_t) size * sizeof(struct MatrixElement); fprintf(file, memFormat, "Bias Fill NZ", size, memory); size = pDevice->numOrigBias + pDevice->numFillBias; memory = (size_t) size * sizeof(struct MatrixElement); fprintf(file, memFormat, "Bias Tot NZ", size, memory); size = pDevice->dimBias; memory = (size_t) size * 5 * sizeof(double); fprintf(file, memFormat, "Bias Vectors", size, memory); size = (pDevice->numNodes - 1) * ONEnumEdgeStates + pDevice->numNodes * ONEnumNodeStates; memory = (size_t) size * sizeof(double); fprintf(file, memFormat, "State Vector", size, memory); } void ONEcpuStats(FILE *file, ONEdevice *pDevice) { static const char cpuFormat[] = "%-20s%10g%10g%10g%10g%10g\n"; ONEstats *pStats = pDevice->pStats; double total; int iTotal; fprintf(file, "----------------------------------------------------------------------\n"); fprintf(file, "Device %s Time Usage:\n", pDevice->name); fprintf(file, "Item SETUP DC TRAN AC TOTAL\n"); fprintf(file, "----------------------------------------------------------------------\n"); total = pStats->setupTime[STAT_SETUP] + pStats->setupTime[STAT_DC] + pStats->setupTime[STAT_TRAN] + pStats->setupTime[STAT_AC]; fprintf(file, cpuFormat, "Setup Time", pStats->setupTime[STAT_SETUP], pStats->setupTime[STAT_DC], pStats->setupTime[STAT_TRAN], pStats->setupTime[STAT_AC], total); total = pStats->loadTime[STAT_SETUP] + pStats->loadTime[STAT_DC] + pStats->loadTime[STAT_TRAN] + pStats->loadTime[STAT_AC]; fprintf(file, cpuFormat, "Load Time", pStats->loadTime[STAT_SETUP], pStats->loadTime[STAT_DC], pStats->loadTime[STAT_TRAN], pStats->loadTime[STAT_AC], total); total = pStats->orderTime[STAT_SETUP] + pStats->orderTime[STAT_DC] + pStats->orderTime[STAT_TRAN] + pStats->orderTime[STAT_AC]; fprintf(file, cpuFormat, "Order Time", pStats->orderTime[STAT_SETUP], pStats->orderTime[STAT_DC], pStats->orderTime[STAT_TRAN], pStats->orderTime[STAT_AC], total); total = pStats->factorTime[STAT_SETUP] + pStats->factorTime[STAT_DC] + pStats->factorTime[STAT_TRAN] + pStats->factorTime[STAT_AC]; fprintf(file, cpuFormat, "Factor Time", pStats->factorTime[STAT_SETUP], pStats->factorTime[STAT_DC], pStats->factorTime[STAT_TRAN], pStats->factorTime[STAT_AC], total); total = pStats->solveTime[STAT_SETUP] + pStats->solveTime[STAT_DC] + pStats->solveTime[STAT_TRAN] + pStats->solveTime[STAT_AC]; fprintf(file, cpuFormat, "Solve Time", pStats->solveTime[STAT_SETUP], pStats->solveTime[STAT_DC], pStats->solveTime[STAT_TRAN], pStats->solveTime[STAT_AC], total); total = pStats->updateTime[STAT_SETUP] + pStats->updateTime[STAT_DC] + pStats->updateTime[STAT_TRAN] + pStats->updateTime[STAT_AC]; fprintf(file, cpuFormat, "Update Time", pStats->updateTime[STAT_SETUP], pStats->updateTime[STAT_DC], pStats->updateTime[STAT_TRAN], pStats->updateTime[STAT_AC], total); total = pStats->checkTime[STAT_SETUP] + pStats->checkTime[STAT_DC] + pStats->checkTime[STAT_TRAN] + pStats->checkTime[STAT_AC]; fprintf(file, cpuFormat, "Check Time", pStats->checkTime[STAT_SETUP], pStats->checkTime[STAT_DC], pStats->checkTime[STAT_TRAN], pStats->checkTime[STAT_AC], total); total = pStats->setupTime[STAT_SETUP] + pStats->setupTime[STAT_DC] + pStats->setupTime[STAT_TRAN] + pStats->setupTime[STAT_AC]; fprintf(file, cpuFormat, "Misc Time", pStats->miscTime[STAT_SETUP], pStats->miscTime[STAT_DC], pStats->miscTime[STAT_TRAN], pStats->miscTime[STAT_AC], total); fprintf(file, "%-40s%10g%10s%10g\n", "LTE Time", pStats->lteTime, "", pStats->lteTime); total = pStats->totalTime[STAT_SETUP] + pStats->totalTime[STAT_DC] + pStats->totalTime[STAT_TRAN] + pStats->totalTime[STAT_AC]; fprintf(file, cpuFormat, "Total Time", pStats->totalTime[STAT_SETUP], pStats->totalTime[STAT_DC], pStats->totalTime[STAT_TRAN], pStats->totalTime[STAT_AC], total); iTotal = pStats->numIters[STAT_SETUP] + pStats->numIters[STAT_DC] + pStats->numIters[STAT_TRAN] + pStats->numIters[STAT_AC]; fprintf(file, "%-20s%10d%10d%10d%10d%10d\n", "Iterations", pStats->numIters[STAT_SETUP], pStats->numIters[STAT_DC], pStats->numIters[STAT_TRAN], pStats->numIters[STAT_AC], iTotal); }