📄 twoadmit.c
字号:
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, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIdVsb, y->real, y->imag); y = contactAdmittance(pDevice, pSContact, TRUE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIsVsb, y->real, y->imag); y = GateTypeAdmittance(pDevice, pGContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIgVsb, y->real, y->imag); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; /* LOAD */ startTime = SPfrontEnd->IFseconds(); /* load in the gate contribution to the rhs */ for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } storeNewRhs(pDevice, pGContact); 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); } } } } if (AcAnalysisMethod == DIRECT) { /* solve the system of equations directly */ /* LOAD */ startTime = SPfrontEnd->IFseconds(); for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } storeNewRhs(pDevice, pDContact); /* Need to load & factor jacobian once. */ if (!OneCarrier) { TWO_jacLoad(pDevice); } else if (OneCarrier == N_TYPE) { TWONjacLoad(pDevice); } else if (OneCarrier == P_TYPE) { TWOPjacLoad(pDevice); } 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, 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(); for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } storeNewRhs(pDevice, pSContact); 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, pDContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIdVsb, y->real, y->imag); y = contactAdmittance(pDevice, pSContact, TRUE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIsVsb, y->real, y->imag); y = GateTypeAdmittance(pDevice, pGContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIgVsb, 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, pGContact); 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, pDContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIdVgb, y->real, y->imag); y = contactAdmittance(pDevice, pSContact, FALSE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIsVgb, y->real, y->imag); y = GateTypeAdmittance(pDevice, pGContact, TRUE, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc->yIgVgb, y->real, y->imag); CMPLX_MULT_SELF_SCALAR(yAc->yIdVdb, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(yAc->yIdVsb, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(yAc->yIdVgb, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(yAc->yIsVdb, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(yAc->yIsVsb, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(yAc->yIsVgb, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(yAc->yIgVdb, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(yAc->yIgVsb, GNorm * width * LNorm); CMPLX_MULT_SELF_SCALAR(yAc->yIgVgb, GNorm * width * LNorm); pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime; return (AcAnalysisMethod);}BOOLEAN TWOsorSolve(TWOdevice *pDevice, double *xReal, double *xImag, double omega){ double dxdy; double wRelax = 1.0; /* SOR relaxation parameter */ double *rhsReal = pDevice->rhs; double *rhsSOR = pDevice->rhsImag; BOOLEAN SORConverged = FALSE; BOOLEAN SORFailed = FALSE; int numEqns = pDevice->numEqns; int iterationNum; int indexN, indexP; int index, eIndex; TWOnode *pNode; TWOelem *pElem; /* clear xReal and xImag arrays */ for (index = 1; index <= numEqns; index++) { xReal[index] = 0.0; xImag[index] = 0.0; } iterationNum = 1; for (; (!SORConverged) &&(!SORFailed); iterationNum++) { for (index = 1; index <= numEqns; index++) { rhsSOR[index] = 0.0; } for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) { pElem = pDevice->elements[eIndex]; dxdy = 0.25 * pElem->dx * pElem->dy; for (index = 0; index <= 3; index++) { pNode = pElem->pNodes[index]; if ((pNode->nodeType != CONTACT) && (pElem->elemType == SEMICON)) { if (!OneCarrier) { indexN = pNode->nEqn; indexP = pNode->pEqn; rhsSOR[indexN] -= dxdy * omega * xImag[indexN]; rhsSOR[indexP] += dxdy * omega * xImag[indexP]; } else if (OneCarrier == N_TYPE) { indexN = pNode->nEqn; rhsSOR[indexN] -= dxdy * omega * xImag[indexN]; } else if (OneCarrier == P_TYPE) { indexP = pNode->pEqn; rhsSOR[indexP] += dxdy * omega * xImag[indexP]; } } } } /* now add the terms from rhs to rhsImag */ for (index = 1; index <= numEqns; index++) { rhsSOR[index] += rhsReal[index]; } /* compute xReal(k+1). solution stored in rhsImag */ spSolve(pDevice->matrix, rhsSOR, rhsSOR, NIL(spREAL), NIL(spREAL)); /* modify solution when wRelax is not 1 */ if (wRelax != 1) { for (index = 1; index <= numEqns; index++) { rhsSOR[index] = (1 - wRelax) * xReal[index] + wRelax * rhsSOR[index]; } } if (iterationNum > 1) { SORConverged = hasSORConverged(xReal, rhsSOR, numEqns); } /* copy real solution into xReal */ for (index = 1; index <= numEqns; index++) { xReal[index] = rhsSOR[index]; } /* now compute the imaginary part of the solution xImag */ for (index = 1; index <= numEqns; index++) { rhsSOR[index] = 0.0; } for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) { pElem = pDevice->elements[eIndex]; dxdy = 0.25 * pElem->dx * pElem->dy; for (index = 0; index <= 3; index++) { pNode = pElem->pNodes[index]; if ((pNode->nodeType != CONTACT) && (pElem->elemType == SEMICON)) { if (!OneCarrier) { indexN = pNode->nEqn; indexP = pNode->pEqn; rhsSOR[indexN] += dxdy * omega * xReal[indexN]; rhsSOR[indexP] -= dxdy * omega * xReal[indexP]; } else if (OneCarrier == N_TYPE) { indexN = pNode->nEqn; rhsSOR[indexN] += dxdy * omega * xReal[indexN]; } else if (OneCarrier == P_TYPE) { indexP = pNode->pEqn; rhsSOR[indexP] -= dxdy * omega * xReal[indexP]; } } } } /* compute xImag(k+1) */ spSolve(pDevice->matrix, rhsSOR, rhsSOR, NIL(spREAL), NIL(spREAL)); /* modify solution when wRelax is not 1 */ if (wRelax != 1) { for (index = 1; index <= numEqns; index++) { rhsSOR[index] = (1 - wRelax) * xImag[index] + wRelax * rhsSOR[index]; } } if (iterationNum > 1) { SORConverged = SORConverged && hasSORConverged(xImag, rhsSOR, numEqns); } /* copy imag solution into xImag */ for (index = 1; index <= numEqns; index++) { xImag[index] = rhsSOR[index]; } if ((iterationNum > 4) && !SORConverged) { SORFailed = TRUE; } if (TWOacDebug) printf("SOR iteration number = %d\n", iterationNum); } return (SORFailed);}SPcomplex *contactAdmittance(TWOdevice *pDevice, TWOcontact *pContact, BOOLEAN delVContact, double *xReal, double *xImag, SPcomplex *cOmega){ TWOnode *pNode, *pHNode = NULL, *pVNode = NULL; TWOedge *pHEdge = NULL, *pVEdge = NULL; int index, i, indexPsi, indexN, indexP, numContactNodes; TWOelem *pElem; SPcomplex psiAc, nAc, pAc; SPcomplex prod1, prod2, sum; double temp; CMPLX_ASSIGN_VALUE(yTotal, 0.0, 0.0); numContactNodes = pContact->numNodes; for (index = 0; index < numContactNodes; index++) { pNode = pContact->pNodes[index]; for (i = 0; i <= 3; i++) { pElem = pNode->pElems[i]; if (pElem != NIL(TWOelem)) { switch (i) { case 0: /* the TL element */ pHNode = pElem->pBLNode; pVNode = pElem->pTRNode; pHEdge = pElem->pBotEdge; pVEdge = pElem->pRightEdge; if (pElem->elemType == SEMICON) { /* compute the derivatives with n,p */ if (pHNode->nodeType != CONTACT) { indexN = pHNode->nEqn; indexP = pHNode->pEqn; CMPLX_ASSIGN_VALUE(nAc, xReal[indexN], xImag[indexN]); CMPLX_ASSIGN_VALUE(pAc, xReal[indexP], xImag[indexP]); CMPLX_MULT_SCALAR(prod1, nAc, pHEdge->dJnDn); CMPLX_MULT_SCALAR(prod2, pAc, pHEdge->dJpDp); CMPLX_ADD(sum, prod1, prod2); CMPLX_MULT_SCALAR(prod1, sum, 0.5 * pElem->dy); CMPLX_SUBT_ASSIGN(yTotal, prod1); } if (pVNode->nodeType != CONTACT) { indexN = pVNode->nEqn; indexP = pVNode->pEqn; CMPLX_ASSIGN_VALUE(nAc, xReal[indexN], xImag[indexN]); CMPLX_ASSIGN_VALUE(pAc, xReal[indexP], xImag[indexP]); CMPLX_MULT_SCALAR(prod1, nAc, pVEdge->dJnDn); CMPLX_MULT_SCALAR(prod2, pAc, pVEdge->dJpDp); CMPLX_ADD(sum, prod1, prod2); CMPLX_MULT_SCALAR(prod1, sum, 0.5 * pElem->dx); CMPLX_SUBT_ASSIGN(yTotal, prod1); } } break; case 1: /* the TR element */ pHNode = pElem->pBRNode; pVNode = pElem->pTLNode; pHEdge = pElem->pBotEdge; pVEdge = pElem->pLeftEdge; if (pElem->elemType == SEMICON) { /* compute the derivatives with n,p */ if (pHNode->nodeType != CONTACT) { indexN = pHNode->nEqn; indexP = pHNode->pEqn; CMPLX_ASSIGN_VALUE(nAc, xReal[indexN], xImag[indexN]); CMPLX_ASSIGN_VALUE(pAc, xReal[indexP], xImag[indexP]); CMPLX_MULT_SCALAR(prod1, nAc, pHEdge->dJnDnP1); CMPLX_MULT_SCALAR(prod2, pAc, pHEdge->dJpDpP1); CMPLX_ADD(sum, prod1, prod2); CMPLX_MULT_SCALAR(prod1, sum, 0.5 * pElem->dy); CMPLX_ADD_ASSIGN(yTotal, prod1); } if (pVNode->nodeType != CONTACT) { indexN = pVNode->nEqn; indexP = pVNode->pEqn; CMPLX_ASSIGN_VALUE(nAc, xReal[indexN], xImag[indexN]); CMPLX_ASSIGN_VALUE(pAc, xReal[indexP], xImag[indexP]); CMPLX_MULT_SCALAR(prod1, nAc, pVEdge->dJnDn); CMPLX_MULT_SCALAR(prod2, pAc, pVEdge->dJpDp); CMPLX_ADD(sum, prod1, prod2); CMPLX_MULT_SCALAR(prod1, sum, 0.5 * pElem->dx); CMPLX_SUBT_ASSIGN(yTotal, prod1); } } break; case 2: /* the BR element */ pHNode = pElem->pTRNode; pVNode = pElem->pBLNode; pHEdge = pElem->pTopEdge; pVEdge = pElem->pLeftEdge; if (pElem->elemType == SEMICON) { /* compute the derivatives with n,p */ if (pHNode->nodeType != CONTACT) { indexN = pHNode->nEqn; indexP = pHNode->pEqn; CMPLX_ASSIGN_VALUE(nAc, xReal[indexN], xImag[indexN]); CMPLX_ASSIGN_VALUE(pAc, xReal[indexP], xImag[indexP]); CMPLX_MULT_SCALAR(prod1, nAc, pHEdge->dJnDnP1); CMPLX_MULT_SCALAR(prod2, pAc, pHEdge->dJpDpP1); CMPLX_ADD(sum, prod1, prod2); CMPLX_MULT_SCALAR(prod1, sum, 0.5 * pElem->dy); CMPLX_ADD_ASSIGN(yTotal, prod1); } if (pVNode->nodeType != CONTACT) { indexN = pVNode->nEqn; indexP = pVNode->pEqn; CMPLX_ASSIGN_VALUE(nAc, xReal[indexN], xImag[indexN]); CMPLX_ASSIGN_VALUE(pAc, xReal[indexP], xImag[indexP]); CMPLX_MULT_SCALAR(prod1, nAc, pVEdge->dJnDnP1); CMPLX_MULT_SCALAR(prod2, pAc, pVEdge->dJpDpP1); CMPLX_ADD(sum, prod1, prod2); CMPLX_MULT_SCALAR(prod1, sum, 0.5 * pElem->dx); CMPLX_ADD_ASSIGN(yTotal, prod1); } } break; case 3: /* the BL element */ pHNode = pElem->pTLNode; pVNode = pElem->pBRNode; pHEdge = pElem->pTopEdge; pVEdge = pElem->pRightEdge;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -