/*ARGSUSED*/ int SMPluFac(SMPmatrix *Matrix, double PivTol, double Gmin) { spSetReal( (void *)Matrix ); LoadGmin( (void *)Matrix, Gmin ); return spFactor( (void *)Matrix ); }
int M_FactorizeLU_SP(void *pA) { M_MatrixSP *A = pA; int err; err = spFactor(A->d); if(err >= spFATAL) { spErrorMessage( A->d, stderr, "edacious"); return -1; } return 0; }
int pgDCAnalysis(Circuit *ckt) { FILE *pf; char line[1024]; assert(ckt->theDeviceList); /* build the MNA matrix */ if( pgBuildMNAEquation(ckt) == -1) return -1; /* print the matrix in asiic form */ /* spPrint(theMatrix, 0, 1, 1); */ printf("External size of the matrix: %d\n",spGetSize(theMatrix,1)); printf("Internal size of the matrix: %d\n",spGetSize(theMatrix,0)); fflush(stdout); /* LU decomposition */ if( spFactor(theMatrix) != spOKAY ) { error_mesg(INT_ERROR,"Matrix factorization error."); return -1; } /* solve it */ spSolve(theMatrix, theRhs, theSol); /* store the outcome */ if(!ckt->theNodeArray) pgBuildNodeArray(ckt); pgComputeStateFromRes(ckt); pgPrintResult(theSol, ckt->nMatrixSize); // Following statements will cause crash in linux 7/9/02 Sheldon //spDestroy(theMatrix); //free(theRhs); //free(theSol); }
void TWOresetJacobian(TWOdevice *pDevice) { int error; if (!OneCarrier) { TWO_jacLoad(pDevice); } else if (OneCarrier == N_TYPE) { TWONjacLoad(pDevice); } else if (OneCarrier == P_TYPE) { TWOPjacLoad(pDevice); } else { printf("TWOresetJacobian: unknown carrier type\n"); exit(-1); } error = spFactor(pDevice->matrix); if (foundError(error)) { exit(-1); } }
/*ARGSUSED*/ int SMPcLUfac(SMPmatrix *Matrix, double PivTol) { spSetComplex( (void *)Matrix ); return spFactor( (void *)Matrix ); }
void C2F(lufact1)(double *val, int *lln, int *col, int *n, int *nel, int *fmatindex, double *eps, double *releps, int *nrank, int *ierr) { int error, i, i0, i1, k, j; char *fmat; spREAL *pelement; *ierr = 0; fmat = spCreate(*n, 0, &error); if (error != spOKAY) { *ierr = 1; return; } *fmatindex = addluptr (fmat); if ( *fmatindex == -1) { *ierr = 1; return; } i0 = 0; i1 = i0; i = 1; for (k = 0 ; k < *nel; k++) { i0 = i0 + 1; while (i0 - i1 > lln[i - 1]) { i1 = i0; i = i + 1; i0 = i0 + 1; } j = col[k]; pelement = spGetElement(fmat, i, j); if (pelement == 0) { *ierr = 2; return; } spADD_REAL_ELEMENT(pelement, (spREAL)(val[k])); } /* Fix the AbsThresold with scilex %eps */ spFixThresold(fmat, *eps, *releps); /* spPrint((char *) *fmat,1,1,1); */ error = spFactor(fmat); spGetNumRank(fmat, nrank); switch (error) { case spZERO_DIAG: Scierror(999, _("%s: A zero was encountered on the diagonal the matrix.\n"), "zero_diag"); break; case spNO_MEMORY: *ierr = 3; break; case spSINGULAR: *ierr = -1; /*Singular matrix" */ break; case spSMALL_PIVOT: *ierr = -2; /* matrix is singular at precision level */ break; } }
int NUMOSadmittance(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", 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); }
int NUMD2admittance(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); }
void NUMOSys(TWOdevice *pDevice, SPcomplex *s, 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 *rhsReal, *rhsImag; double *solnReal, *solnImag; SPcomplex *y; SPcomplex temp, cOmega; pDevice->solverType = SLV_SMSIG; rhsReal = pDevice->rhs; rhsImag = pDevice->rhsImag; solnReal = pDevice->dcDeltaSolution; solnImag = pDevice->copiedSolution; /* use a normalized radian frequency */ CMPLX_MULT_SCALAR(cOmega, *s, TNorm); 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, pDContact); 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) { CMPLX_MULT_SCALAR(temp, cOmega, dxdy); spADD_COMPLEX_ELEMENT(pNode->fNN, -temp.real, -temp.imag); spADD_COMPLEX_ELEMENT(pNode->fPP, temp.real, temp.imag); } else if (OneCarrier == N_TYPE) { CMPLX_MULT_SCALAR(temp, cOmega, dxdy); spADD_COMPLEX_ELEMENT(pNode->fNN, -temp.real, -temp.imag); } else if (OneCarrier == P_TYPE) { CMPLX_MULT_SCALAR(temp, cOmega, dxdy); spADD_COMPLEX_ELEMENT(pNode->fPP, temp.real, temp.imag); } } } } } spFactor(pDevice->matrix); spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag); 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); for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } storeNewRhs(pDevice, pSContact); /* don't need to LU factor the jacobian since it exists */ spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag); 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); for (index = 1; index <= pDevice->numEqns; index++) { rhsImag[index] = 0.0; } storeNewRhs(pDevice, pGContact); spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag); 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); }
void NUMD2ys(TWOdevice *pDevice, SPcomplex *s, SPcomplex *yIn) { TWOnode *pNode; TWOelem *pElem; int index, eIndex; double dxdy; double *solnReal, *solnImag; double *rhsReal, *rhsImag; SPcomplex yAc, *y; BOOLEAN deltaVContact = FALSE; SPcomplex temp, cOmega; /* * 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 */ CMPLX_MULT_SCALAR(cOmega, *s, TNorm); 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) { CMPLX_MULT_SCALAR(temp, cOmega, dxdy); spADD_COMPLEX_ELEMENT(pNode->fNN, -temp.real, -temp.imag); spADD_COMPLEX_ELEMENT(pNode->fPP, temp.real, temp.imag); } else if (OneCarrier == N_TYPE) { CMPLX_MULT_SCALAR(temp, cOmega, dxdy); spADD_COMPLEX_ELEMENT(pNode->fNN, -temp.real, -temp.imag); } else if (OneCarrier == P_TYPE) { CMPLX_MULT_SCALAR(temp, cOmega, dxdy); spADD_COMPLEX_ELEMENT(pNode->fPP, temp.real, temp.imag); } } } } } spFactor(pDevice->matrix); spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag); y = contactAdmittance(pDevice, pDevice->pFirstContact, deltaVContact, solnReal, solnImag, &cOmega); CMPLX_ASSIGN_VALUE(yAc, y->real, y->imag); CMPLX_ASSIGN(*yIn, yAc); CMPLX_NEGATE_SELF(*yIn); CMPLX_MULT_SELF_SCALAR(*yIn, GNorm * pDevice->width * LNorm); }
/* the iteration driving loop and convergence check */ void TWOdcSolve(TWOdevice *pDevice, int iterationLimit, BOOLEAN newSolver, BOOLEAN tranAnalysis, TWOtranInfo *info) { TWOnode *pNode; TWOelem *pElem; int size = pDevice->numEqns; int index, eIndex, error; int timesConverged = 0; BOOLEAN quitLoop; BOOLEAN debug; BOOLEAN negConc = FALSE; double *rhs = pDevice->rhs; double *solution = pDevice->dcSolution; double *delta = pDevice->dcDeltaSolution; double poissNorm, contNorm; double startTime, totalStartTime; double totalTime, loadTime, factorTime, solveTime, updateTime, checkTime; double orderTime = 0.0; totalTime = loadTime = factorTime = solveTime = updateTime = checkTime = 0.0; totalStartTime = SPfrontEnd->IFseconds(); quitLoop = FALSE; debug = (!tranAnalysis && TWOdcDebug) || (tranAnalysis && TWOtranDebug); pDevice->iterationNumber = 0; pDevice->converged = FALSE; if (debug) { if (pDevice->poissonOnly) { fprintf(stdout, "Equilibrium Solution:\n"); } else { fprintf(stdout, "Bias Solution:\n"); } fprintf(stdout, "Iteration RHS Norm\n"); } while (!(pDevice->converged || (pDevice->iterationNumber > iterationLimit) || quitLoop)) { pDevice->iterationNumber++; if ((!pDevice->poissonOnly) && (iterationLimit > 0) &&(!tranAnalysis)) { TWOjacCheck(pDevice, tranAnalysis, info); } /* LOAD */ startTime = SPfrontEnd->IFseconds(); if (pDevice->poissonOnly) { TWOQsysLoad(pDevice); } else if (!OneCarrier) { TWO_sysLoad(pDevice, tranAnalysis, info); } else if (OneCarrier == N_TYPE) { TWONsysLoad(pDevice, tranAnalysis, info); } else if (OneCarrier == P_TYPE) { TWOPsysLoad(pDevice, tranAnalysis, info); } pDevice->rhsNorm = maxNorm(rhs, size); loadTime += SPfrontEnd->IFseconds() - startTime; if (debug) { fprintf(stdout, "%7d %11.4e%s\n", pDevice->iterationNumber - 1, pDevice->rhsNorm, negConc ? " negative conc encountered" : ""); negConc = FALSE; } /* FACTOR */ startTime = SPfrontEnd->IFseconds(); error = spFactor(pDevice->matrix); factorTime += SPfrontEnd->IFseconds() - startTime; if (newSolver) { if (pDevice->iterationNumber == 1) { orderTime = factorTime; } else if (pDevice->iterationNumber == 2) { orderTime -= factorTime - orderTime; factorTime -= orderTime; if (pDevice->poissonOnly) { pDevice->pStats->orderTime[STAT_SETUP] += orderTime; } else { pDevice->pStats->orderTime[STAT_DC] += orderTime; } newSolver = FALSE; } } if (foundError(error)) { if (error == spSINGULAR) { int badRow, badCol; spWhereSingular(pDevice->matrix, &badRow, &badCol); printf("***** singular at (%d,%d)\n", badRow, badCol); } pDevice->converged = FALSE; quitLoop = TRUE; continue; } /* SOLVE */ startTime = SPfrontEnd->IFseconds(); spSolve(pDevice->matrix, rhs, delta, NULL, NULL); solveTime += SPfrontEnd->IFseconds() - startTime; /* UPDATE */ startTime = SPfrontEnd->IFseconds(); /* Use norm reducing Newton method for DC bias solutions only. */ if ((!pDevice->poissonOnly) && (iterationLimit > 0) && (!tranAnalysis) && (pDevice->rhsNorm > 1e-1)) { error = TWOnewDelta(pDevice, tranAnalysis, info); if (error) { pDevice->converged = FALSE; quitLoop = TRUE; updateTime += SPfrontEnd->IFseconds() - startTime; continue; } } for (index = 1; index <= size; index++) { solution[index] += delta[index]; } updateTime += SPfrontEnd->IFseconds() - startTime; /* CHECK CONVERGENCE */ startTime = SPfrontEnd->IFseconds(); /* Check if updates have gotten sufficiently small. */ if (pDevice->iterationNumber != 1) { pDevice->converged = TWOdeltaConverged(pDevice); } /* Check if the residual is smaller than abstol. */ if (pDevice->converged && (!pDevice->poissonOnly) && (!tranAnalysis)) { if (!OneCarrier) { TWO_rhsLoad(pDevice, tranAnalysis, info); } else if (OneCarrier == N_TYPE) { TWONrhsLoad(pDevice, tranAnalysis, info); } else if (OneCarrier == P_TYPE) { TWOPrhsLoad(pDevice, tranAnalysis, info); } pDevice->rhsNorm = maxNorm(rhs, size); if (pDevice->rhsNorm > pDevice->abstol) { pDevice->converged = FALSE; } if ((++timesConverged >= 2) && (pDevice->rhsNorm < 1e3 * pDevice->abstol)) { pDevice->converged = TRUE; } else if (timesConverged >= 5) { pDevice->converged = FALSE; quitLoop = TRUE; continue; } } else if (pDevice->converged && pDevice->poissonOnly) { TWOQrhsLoad(pDevice); pDevice->rhsNorm = maxNorm(rhs, size); if (pDevice->rhsNorm > pDevice->abstol) { pDevice->converged = FALSE; } if (++timesConverged >= 5) { pDevice->converged = TRUE; } } /* Check if the carrier concentrations are negative. */ if (pDevice->converged && (!pDevice->poissonOnly)) { /* Clear garbage entry since carrier-free elements reference it. */ solution[0] = 0.0; for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) { pElem = pDevice->elements[eIndex]; for (index = 0; index <= 3; index++) { if (pElem->evalNodes[index]) { pNode = pElem->pNodes[index]; if (solution[pNode->nEqn] < 0.0) { pDevice->converged = FALSE; negConc = TRUE; if (tranAnalysis) { quitLoop = TRUE; } else { solution[pNode->nEqn] = 0.0; } } if (solution[pNode->pEqn] < 0.0) { pDevice->converged = FALSE; negConc = TRUE; if (tranAnalysis) { quitLoop = TRUE; } else { solution[pNode->pEqn] = 0.0; } } } } } if (!pDevice->converged) { if (!OneCarrier) { TWO_rhsLoad(pDevice, tranAnalysis, info); } else if (OneCarrier == N_TYPE) { TWONrhsLoad(pDevice, tranAnalysis, info); } else if (OneCarrier == P_TYPE) { TWOPrhsLoad(pDevice, tranAnalysis, info); } pDevice->rhsNorm = maxNorm(rhs, size); } } checkTime += SPfrontEnd->IFseconds() - startTime; } totalTime += SPfrontEnd->IFseconds() - totalStartTime; if (tranAnalysis) { pDevice->pStats->loadTime[STAT_TRAN] += loadTime; pDevice->pStats->factorTime[STAT_TRAN] += factorTime; pDevice->pStats->solveTime[STAT_TRAN] += solveTime; pDevice->pStats->updateTime[STAT_TRAN] += updateTime; pDevice->pStats->checkTime[STAT_TRAN] += checkTime; pDevice->pStats->numIters[STAT_TRAN] += pDevice->iterationNumber; } else if (pDevice->poissonOnly) { pDevice->pStats->loadTime[STAT_SETUP] += loadTime; pDevice->pStats->factorTime[STAT_SETUP] += factorTime; pDevice->pStats->solveTime[STAT_SETUP] += solveTime; pDevice->pStats->updateTime[STAT_SETUP] += updateTime; pDevice->pStats->checkTime[STAT_SETUP] += checkTime; pDevice->pStats->numIters[STAT_SETUP] += pDevice->iterationNumber; } else { pDevice->pStats->loadTime[STAT_DC] += loadTime; pDevice->pStats->factorTime[STAT_DC] += factorTime; pDevice->pStats->solveTime[STAT_DC] += solveTime; pDevice->pStats->updateTime[STAT_DC] += updateTime; pDevice->pStats->checkTime[STAT_DC] += checkTime; pDevice->pStats->numIters[STAT_DC] += pDevice->iterationNumber; } if (debug) { if (!tranAnalysis) { pDevice->rhsNorm = maxNorm(rhs, size); fprintf(stdout, "%7d %11.4e%s\n", pDevice->iterationNumber, pDevice->rhsNorm, negConc ? " negative conc in solution" : ""); } if (pDevice->converged) { if (!pDevice->poissonOnly) { poissNorm = contNorm = 0.0; rhs[0] = 0.0; /* Make sure garbage entry is clear. */ for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) { pElem = pDevice->elements[eIndex]; for (index = 0; index <= 3; index++) { if (pElem->evalNodes[index]) { pNode = pElem->pNodes[index]; poissNorm = MAX(poissNorm,ABS(rhs[pNode->psiEqn])); contNorm = MAX(contNorm,ABS(rhs[pNode->nEqn])); contNorm = MAX(contNorm,ABS(rhs[pNode->pEqn])); } } } fprintf(stdout, "Residual: %11.4e C/um poisson, %11.4e A/um continuity\n", poissNorm * EpsNorm * VNorm * 1e-4, contNorm * JNorm * LNorm * 1e-4); } else { fprintf(stdout, "Residual: %11.4e C/um poisson\n", pDevice->rhsNorm * EpsNorm * VNorm * 1e-4); } } } }