ngspice/src/ciderlib/twod/twoprint.c

562 lines
17 KiB
C

/**********
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/twomesh.h"
#include "ngspice/twodev.h"
#include "ngspice/carddefs.h"
#include "ngspice/spmatrix.h"
#include "ngspice/bool.h"
#include "twoddefs.h"
#include "twodext.h"
#include <inttypes.h>
void
TWOprnSolution(FILE *file, TWOdevice *pDevice, OUTPcard *output)
{
int index, xIndex, yIndex;
int numVars = 0;
TWOnode ***nodeArray = NULL;
TWOnode *pNode;
TWOmaterial *info;
double data[50];
double ex, ey, refPsi = 0.0, eGap, dGap;
double mun, mup;
double jcx, jdx, jnx, jpx, jtx;
double jcy, jdy, jny, jpy, jty;
double *xScale = pDevice->xScale;
double *yScale = pDevice->yScale;
if (output->OUTPnumVars == -1) {
/* First pass. Need to count number of variables in output. */
numVars += 2; /* For the X & Y scales */
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 += 2;
}
if (output->OUTPjc) {
numVars += 2;
}
if (output->OUTPjd) {
numVars += 2;
}
if (output->OUTPjn) {
numVars += 2;
}
if (output->OUTPjp) {
numVars += 2;
}
if (output->OUTPjt) {
numVars += 2;
}
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, TWOnode **, 1 + pDevice->numXNodes);
for (xIndex = 1; xIndex <= pDevice->numXNodes; xIndex++) {
XCALLOC(nodeArray[xIndex], TWOnode *, 1 + pDevice->numYNodes);
}
/* store the nodes in this work array and print out later */
for (xIndex = 1; xIndex < pDevice->numXNodes; xIndex++) {
for (yIndex = 1; yIndex < pDevice->numYNodes; yIndex++) {
TWOelem *pElem = pDevice->elemArray[xIndex][yIndex];
if (pElem != NULL) {
if (refPsi == 0.0 && pElem->matlInfo->type == SEMICON) {
refPsi = pElem->matlInfo->refPsi;
}
for (index = 0; index < 4; index++) {
if (pElem->evalNodes[index]) {
pNode = pElem->pNodes[index];
nodeArray[pNode->nodeI][pNode->nodeJ] = 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->numXNodes * pDevice->numYNodes);
fprintf(file, "Dimensions: %d,%d\n",
pDevice->numXNodes, pDevice->numYNodes);
numVars = 0;
fprintf(file, "Variables:\n");
fprintf(file, "\t%d y distance\n", numVars++);
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 ex electric_field\n", numVars++);
fprintf(file, "\t%d ey electric_field\n", numVars++);
}
if (output->OUTPjc) {
fprintf(file, "\t%d jcx current_density\n", numVars++);
fprintf(file, "\t%d jcy current_density\n", numVars++);
}
if (output->OUTPjd) {
fprintf(file, "\t%d jdx current_density\n", numVars++);
fprintf(file, "\t%d jdy current_density\n", numVars++);
}
if (output->OUTPjn) {
fprintf(file, "\t%d jnx current_density\n", numVars++);
fprintf(file, "\t%d jny current_density\n", numVars++);
}
if (output->OUTPjp) {
fprintf(file, "\t%d jpx current_density\n", numVars++);
fprintf(file, "\t%d jpy current_density\n", numVars++);
}
if (output->OUTPjt) {
fprintf(file, "\t%d jtx current_density\n", numVars++);
fprintf(file, "\t%d jty 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 (xIndex = 1; xIndex <= pDevice->numXNodes; xIndex++) {
for (yIndex = 1; yIndex <= pDevice->numYNodes; yIndex++) {
pNode = nodeArray[xIndex][yIndex];
if (pNode != NULL) {
TWOelem *pElem = NULL;
/* Find the element to which this node belongs. */
for (index = 0; index < 4; index++) {
pElem = pNode->pElems[index];
if (pElem != NULL && pElem->evalNodes[(index + 2) % 4])
break;
}
nodeFields(pElem, pNode, &ex, &ey);
nodeCurrents(pElem, pNode, &mun, &mup,
&jnx, &jny, &jpx, &jpy, &jdx, &jdy);
jcx = jnx + jpx;
jcy = jny + jpy;
jtx = jcx + jdx;
jty = jcy + jdy;
info = pElem->matlInfo;
eGap = pNode->eg * VNorm;
dGap = 0.5 * (info->eg0 - eGap);
/* Now fill in the data array */
numVars = 0;
data[numVars++] = yScale[yIndex] * 1e-2;
data[numVars++] = xScale[xIndex] * 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++] = ex * ENorm;
data[numVars++] = ey * ENorm;
}
if (output->OUTPjc) {
data[numVars++] = jcx * JNorm;
data[numVars++] = jcy * JNorm;
}
if (output->OUTPjd) {
data[numVars++] = jdx * JNorm;
data[numVars++] = jdy * JNorm;
}
if (output->OUTPjn) {
data[numVars++] = jnx * JNorm;
data[numVars++] = jny * JNorm;
}
if (output->OUTPjp) {
data[numVars++] = jpx * JNorm;
data[numVars++] = jpy * JNorm;
}
if (output->OUTPjt) {
data[numVars++] = jtx * JNorm;
data[numVars++] = jty * 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);
} else {
for (index = 0; index < output->OUTPnumVars; index++) {
data[index] = 0.0;
}
data[0] = yScale[yIndex] * 1e-2;
data[1] = xScale[xIndex] * 1e-2;
fwrite(data, sizeof(double), (size_t) numVars, file);
}
}
}
/* Delete work array. */
for (xIndex = 1; xIndex <= pDevice->numXNodes; xIndex++) {
FREE(nodeArray[xIndex]);
}
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
TWOmemStats(FILE *file, TWOdevice *pDevice)
{
const char memFormat[] = "%-20s" "%10d" "%10" PRIuPTR "\n";
/* static const char sumFormat[] = "%20s %-10d\n"; */
int size;
size_t memory;
TWOmaterial *pMaterial;
TWOcontact *pContact;
TWOchannel *pChannel;
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(TWOdevice);
fprintf( file, memFormat, "Device", size, memory );
size = pDevice->numElems;
memory = (size_t) size * sizeof(TWOelem);
fprintf( file, memFormat, "Elements", size, memory );
size = pDevice->numNodes;
memory = (size_t) size * sizeof(TWOnode);
fprintf( file, memFormat, "Nodes", size, memory );
size = pDevice->numEdges;
memory = (size_t) size * sizeof(TWOedge);
fprintf( file, memFormat, "Edges", size, memory );
size = pDevice->numXNodes;
memory = (size_t) size * sizeof(TWOelem **);
size = (pDevice->numXNodes-1) * pDevice->numYNodes;
memory += (size_t) size * sizeof(TWOelem *);
size = pDevice->numElems + 1;
memory += (size_t) size * sizeof(TWOelem *);
size = pDevice->numXNodes + pDevice->numYNodes;
memory += (size_t) size * sizeof(double);
size = 0;
for (pMaterial = pDevice->pMaterials; pMaterial; pMaterial = pMaterial->next)
size++;
memory += (size_t) size * sizeof(TWOmaterial);
size = numContactNodes = 0;
for (pContact = pDevice->pFirstContact; pContact; pContact = pContact->next) {
numContactNodes += pContact->numNodes;
size++;
}
memory += (size_t) size * sizeof(TWOcontact);
size = numContactNodes;
memory += (size_t) size * sizeof(TWOnode *);
size = 0;
for (pChannel = pDevice->pChannel; pChannel; pChannel = pChannel->next)
size++;
memory += (size_t) size * sizeof(TWOchannel);
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->numEdges * TWOnumEdgeStates +
pDevice->numNodes * TWOnumNodeStates;
memory = (size_t) size * sizeof(double);
fprintf( file, memFormat, "State Vector", size, memory );
}
void
TWOcpuStats(FILE *file, TWOdevice *pDevice)
{
static const char cpuFormat[] = "%-20s%10g%10g%10g%10g%10g\n";
TWOstats *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);
}