📄 twoadmit.c
字号:
/**********Copyright 1991 Regents of the University of California. All rights reserved.Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group$Id: twoadmit.c,v 1.3 2005/05/21 12:37:24 sjborley Exp $**********//* Functions to compute the ac admittances of a device. */#include "ngspice.h"#include "numglobs.h"#include "numenum.h"#include "numconst.h"#include "twodev.h"#include "twomesh.h"#include "complex.h"#include "spmatrix.h"#include "bool.h"#include "macros.h"#include "ifsim.h"#include "twoddefs.h" #include "twodext.h"#include "cidersupt.h"extern IFfrontEnd *SPfrontEnd;/* * mmhhh this may cause troubles * Paolo Nenzi 2002 */ SPcomplex yTotal;intNUMD2admittance(TWOdevice *pDevice, double omega, SPcomplex *yd){ TWOnode *pNode; TWOelem *pElem; int index, eIndex; double dxdy; double *solnReal, *solnImag; double *rhsReal, *rhsImag; SPcomplex yAc, cOmega, *y; BOOLEAN deltaVContact = FALSE; BOOLEAN SORFailed; double startTime; /* Each time we call this counts as one AC iteration. */ pDevice->pStats->numIters[STAT_AC] += 1; /* * change context names of solution vectors for ac analysis dcDeltaSolution * stores the real part and copiedSolution stores the imaginary part of the * ac solution vector */ pDevice->solverType = SLV_SMSIG; rhsReal = pDevice->rhs; rhsImag = pDevice->rhsImag; solnReal = pDevice->dcDeltaSolution; solnImag = pDevice->copiedSolution; /* use a normalized radian frequency */ omega *= TNorm; CMPLX_ASSIGN_VALUE(cOmega, 0.0, omega); if ((AcAnalysisMethod == SOR) || (AcAnalysisMethod == SOR_ONLY)) { /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* zero the rhsImag */ for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } /* store the new rhs vector */ storeNewRhs(pDevice, pDevice->pLastContact); pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; if (SORFailed && AcAnalysisMethod == SOR) { AcAnalysisMethod = DIRECT; printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n", omega / (TWO_PI * TNorm) ); } else if (SORFailed) { /* Told to only do SOR, so give up. */ printf("SOR failed at %g Hz, returning null admittance.\n", omega / (TWO_PI * TNorm) ); CMPLX_ASSIGN_VALUE(*yd, 0.0, 0.0); return (AcAnalysisMethod); } } if (AcAnalysisMethod == DIRECT) { /* LOAD */ startTime = SPfrontEnd->IFseconds(); for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } /* solve the system of equations directly */ if (!OneCarrier) { TWO_jacLoad(pDevice); } else if (OneCarrier == N_TYPE) { TWONjacLoad(pDevice); } else if (OneCarrier == P_TYPE) { TWOPjacLoad(pDevice); } storeNewRhs(pDevice, pDevice->pLastContact); spSetComplex(pDevice->matrix); for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) { pElem = pDevice->elements[eIndex]; if (pElem->elemType == SEMICON) { dxdy = 0.25 * pElem->dx * pElem->dy; for (index = 0; index <= 3; index++) { pNode = pElem->pNodes[index]; if (pNode->nodeType != CONTACT) { if (!OneCarrier) { spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega); spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega); } else if (OneCarrier == N_TYPE) { spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega); } else if (OneCarrier == P_TYPE) { spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega); } } } } } pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* FACTOR */ startTime = SPfrontEnd->IFseconds(); spFactor(pDevice->matrix); pDevice->pStats->factorTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; } /* MISC */ startTime = SPfrontEnd->IFseconds(); y = contactAdmittance(pDevice, pDevice->pFirstContact, deltaVContact, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc, -y->real, -y->imag); CMPLX_ASSIGN(*yd, yAc); CMPLX_MULT_SELF_SCALAR(*yd, GNorm * pDevice->width * LNorm); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; return (AcAnalysisMethod);}intNBJT2admittance(TWOdevice *pDevice, double omega, SPcomplex *yIeVce, SPcomplex *yIcVce, SPcomplex *yIeVbe, SPcomplex *yIcVbe){ TWOcontact *pEmitContact = pDevice->pLastContact; TWOcontact *pColContact = pDevice->pFirstContact; TWOcontact *pBaseContact = pDevice->pFirstContact->next; TWOnode *pNode; TWOelem *pElem; int index, eIndex; double width = pDevice->width; double dxdy; double *solnReal, *solnImag; double *rhsReal, *rhsImag; BOOLEAN SORFailed; SPcomplex *y; SPcomplex pIeVce, pIcVce, pIeVbe, pIcVbe; SPcomplex cOmega; double startTime; /* Each time we call this counts as one AC iteration. */ pDevice->pStats->numIters[STAT_AC] += 1; pDevice->solverType = SLV_SMSIG; rhsReal = pDevice->rhs; rhsImag = pDevice->rhsImag; solnReal = pDevice->dcDeltaSolution; solnImag = pDevice->copiedSolution; /* use a normalized radian frequency */ omega *= TNorm; CMPLX_ASSIGN_VALUE(cOmega, 0.0, omega); if ((AcAnalysisMethod == SOR) || (AcAnalysisMethod == SOR_ONLY)) { /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* zero the rhs before loading in the new rhs */ for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } storeNewRhs(pDevice, pColContact); pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; if (SORFailed && AcAnalysisMethod == SOR) { AcAnalysisMethod = DIRECT; printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n", omega / (TWO_PI * TNorm) ); } else if (SORFailed) { /* Told to only do SOR, so give up. */ printf("SOR failed at %g Hz, returning null admittance.\n", omega / (TWO_PI * TNorm) ); CMPLX_ASSIGN_VALUE(*yIeVce, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIcVce, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIeVbe, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIcVbe, 0.0, 0.0); return (AcAnalysisMethod); } else { /* MISC */ startTime = SPfrontEnd->IFseconds(); y = contactAdmittance(pDevice, pEmitContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(pIeVce, y->real, y->imag); y = contactAdmittance(pDevice, pColContact, TRUE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(pIcVce, y->real, y->imag); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* load in the base contribution to the rhs */ for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } storeNewRhs(pDevice, pBaseContact); pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; if (SORFailed && AcAnalysisMethod == SOR) { AcAnalysisMethod = DIRECT; printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n", omega / (TWO_PI * TNorm) ); } else if (SORFailed) { /* Told to only do SOR, so give up. */ printf("SOR failed at %g Hz, returning null admittance.\n", omega / (TWO_PI * TNorm) ); CMPLX_ASSIGN_VALUE(*yIeVce, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIcVce, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIeVbe, 0.0, 0.0); CMPLX_ASSIGN_VALUE(*yIcVbe, 0.0, 0.0); return (AcAnalysisMethod); } } } if (AcAnalysisMethod == DIRECT) { /* LOAD */ startTime = SPfrontEnd->IFseconds(); for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } /* solve the system of equations directly */ if (!OneCarrier) { TWO_jacLoad(pDevice); } else if (OneCarrier == N_TYPE) { TWONjacLoad(pDevice); } else if (OneCarrier == P_TYPE) { TWOPjacLoad(pDevice); } storeNewRhs(pDevice, pColContact); spSetComplex(pDevice->matrix); for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) { pElem = pDevice->elements[eIndex]; if (pElem->elemType == SEMICON) { dxdy = 0.25 * pElem->dx * pElem->dy; for (index = 0; index <= 3; index++) { pNode = pElem->pNodes[index]; if (pNode->nodeType != CONTACT) { if (!OneCarrier) { spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega); spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega); } else if (OneCarrier == N_TYPE) { spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega); } else if (OneCarrier == P_TYPE) { spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega); } } } } } pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* FACTOR */ startTime = SPfrontEnd->IFseconds(); spFactor(pDevice->matrix); pDevice->pStats->factorTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* MISC */ startTime = SPfrontEnd->IFseconds(); y = contactAdmittance(pDevice, pEmitContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(pIeVce, y->real, y->imag); y = contactAdmittance(pDevice, pColContact, TRUE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(pIcVce, y->real, y->imag); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* LOAD */ startTime = SPfrontEnd->IFseconds(); for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } storeNewRhs(pDevice, pBaseContact); pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* FACTOR: already done, no need to repeat. */ /* SOLVE */ startTime = SPfrontEnd->IFseconds(); spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; } /* MISC */ startTime = SPfrontEnd->IFseconds(); y = contactAdmittance(pDevice, pEmitContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(pIeVbe, y->real, y->imag); y = contactAdmittance(pDevice, pColContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(pIcVbe, y->real, y->imag); CMPLX_ASSIGN(*yIeVce, pIeVce); CMPLX_ASSIGN(*yIeVbe, pIeVbe); CMPLX_ASSIGN(*yIcVce, pIcVce); CMPLX_ASSIGN(*yIcVbe, pIcVbe); CMPLX_MULT_SELF_SCALAR(*yIeVce, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(*yIeVbe, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(*yIcVce, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(*yIcVbe, GNorm * width * LNorm); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; return (AcAnalysisMethod);}intNUMOSadmittance(TWOdevice *pDevice, double omega, struct mosAdmittances *yAc){ TWOcontact *pDContact = pDevice->pFirstContact; TWOcontact *pGContact = pDevice->pFirstContact->next; TWOcontact *pSContact = pDevice->pFirstContact->next->next;/* TWOcontact *pBContact = pDevice->pLastContact; */ TWOnode *pNode; TWOelem *pElem; int index, eIndex; double width = pDevice->width; double dxdy; double *solnReal, *solnImag; double *rhsReal, *rhsImag; BOOLEAN SORFailed; SPcomplex *y, cOmega; double startTime; /* Each time we call this counts as one AC iteration. */ pDevice->pStats->numIters[STAT_AC] += 1; pDevice->solverType = SLV_SMSIG; rhsReal = pDevice->rhs; rhsImag = pDevice->rhsImag; solnReal = pDevice->dcDeltaSolution; solnImag = pDevice->copiedSolution; /* use a normalized radian frequency */ omega *= TNorm; CMPLX_ASSIGN_VALUE(cOmega, 0.0, omega); if ((AcAnalysisMethod == SOR) || (AcAnalysisMethod == SOR_ONLY)) { /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* zero the rhs before loading in the new rhs */ for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } storeNewRhs(pDevice, pDContact); pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; if (SORFailed && AcAnalysisMethod == SOR) { AcAnalysisMethod = DIRECT; printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n", omega / (TWO_PI * TNorm) ); } else if (SORFailed) { /* Told to only do SOR, so give up. */ printf("SOR failed at %g Hz, returning null admittance.\n", omega / (TWO_PI * TNorm) ); CMPLX_ASSIGN_VALUE(yAc->yIdVdb, 0.0, 0.0); CMPLX_ASSIGN_VALUE(yAc->yIdVsb, 0.0, 0.0); CMPLX_ASSIGN_VALUE(yAc->yIdVgb, 0.0, 0.0); CMPLX_ASSIGN_VALUE(yAc->yIsVdb, 0.0, 0.0); CMPLX_ASSIGN_VALUE(yAc->yIsVsb, 0.0, 0.0); CMPLX_ASSIGN_VALUE(yAc->yIsVgb, 0.0, 0.0); CMPLX_ASSIGN_VALUE(yAc->yIgVdb, 0.0, 0.0); CMPLX_ASSIGN_VALUE(yAc->yIgVsb, 0.0, 0.0); CMPLX_ASSIGN_VALUE(yAc->yIgVgb, 0.0, 0.0); return (AcAnalysisMethod); } else { /* MISC */ startTime = SPfrontEnd->IFseconds(); y = contactAdmittance(pDevice, pDContact, TRUE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIdVdb, y->real, y->imag); y = contactAdmittance(pDevice, pSContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIsVdb, y->real, y->imag); y = GateTypeAdmittance(pDevice, pGContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIgVdb, y->real, y->imag); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* load in the source contribution to the rhs */ for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } storeNewRhs(pDevice, pSContact); pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* SOLVE */ startTime = SPfrontEnd->IFseconds(); SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega); pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; if (SORFailed && AcAnalysisMethod == SOR) { AcAnalysisMethod = DIRECT; printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n", omega / (TWO_PI * TNorm) ); } else if (SORFailed) { /* Told to only do SOR, so give up. */ printf("SOR failed at %g Hz, returning null admittance.\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -