void M_BacksubstLU_SP(void *pA, void *pV) { M_MatrixSP *A = pA; M_Vector *v = pV; /* this makes SPARSE solve in place */ spSolve(A->d, v->v, v->v); }
/* * lusolve1 >>> Solves fmat*x=b * *fmat : a pointer to the sparse matrix factored by lufact * b,v * two arrays of size n the matrix size */ void C2F(lusolve1)(int *fmatindex, double *b, double *x, int *ierr) { char *fmat; if (getluptr((int)*fmatindex, &fmat) == -1) { *ierr = 1; return; } *ierr = 0; spSolve(fmat, (spREAL*)b, (spREAL*)x); }
void NUMDconductance(ONEdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff, double *gd) { ONEelem *pElem = pDevice->elemArray[pDevice->numNodes - 1]; ONEnode *pNode; ONEedge *pEdge; int index; double dPsiDv, dNDv, dPDv, *incVpn; *gd = 0.0; /* zero the rhs before loading in the new rhs */ for (index = 1; index <= pDevice->numEqns; index++) { pDevice->rhs[index] = 0.0; } /* compute incremental changes due to N contact */ pNode = pElem->pLeftNode; pDevice->rhs[pNode->psiEqn] = pElem->epsRel * pElem->rDx; if (pElem->elemType == SEMICON) { pEdge = pElem->pEdge; pDevice->rhs[pNode->nEqn] = -pEdge->dJnDpsiP1; pDevice->rhs[pNode->pEqn] = -pEdge->dJpDpsiP1; } incVpn = pDevice->dcDeltaSolution; spSolve(pDevice->matrix, pDevice->rhs, incVpn, NIL(spREAL), NIL(spREAL)); pElem = pDevice->elemArray[1]; pNode = pElem->pRightNode; pEdge = pElem->pEdge; dPsiDv = incVpn[pNode->psiEqn]; if (pElem->elemType == SEMICON) { dNDv = incVpn[pNode->nEqn]; dPDv = incVpn[pNode->pEqn]; *gd += pEdge->dJnDpsiP1 * dPsiDv + pEdge->dJnDnP1 * dNDv + pEdge->dJpDpsiP1 * dPsiDv + pEdge->dJpDpP1 * dPDv; } /* For transient analysis, add the displacement term */ if (tranAnalysis) { *gd -= intCoeff[0] * pElem->epsRel * pElem->rDx * dPsiDv; } *gd *= -GNorm * pDevice->area; }
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); }
/* nu-Norm calculation based upon work done at Stanford. */ double TWOnuNorm(TWOdevice *pDevice) { double norm = 0.0; double temp; int index; /* the LU Decomposed matrix is available. use it to calculate x */ spSolve(pDevice->matrix, pDevice->rhs, pDevice->rhsImag, NULL, NULL); /* the solution is in the rhsImag vector */ /* compute L2-norm of the rhsImag vector */ for (index = 1; index <= pDevice->numEqns; index++) { temp = pDevice->rhsImag[index]; norm += temp * temp; } norm = sqrt(norm); return (norm); }
/* * SMPsolve() */ void SMPsolve(SMPmatrix *Matrix, double RHS[], double Spare[]) { spSolve( (void *)Matrix, RHS, RHS, (spREAL*)NULL, (spREAL*)NULL ); }
/* * SMPcSolve() */ void SMPcSolve(SMPmatrix *Matrix, double RHS[], double iRHS[], double Spare[], double iSpare[]) { spSolve( (void *)Matrix, RHS, RHS, iRHS, iRHS ); }
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, NULL, NULL); /* 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, NULL, NULL); /* 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); }
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); }
void NBJTconductance(ONEdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff, double *dIeDVce, double *dIcDVce, double *dIeDVbe, double *dIcDVbe) { ONEelem *pLastElem = pDevice->elemArray[pDevice->numNodes - 1]; ONEelem *pBaseElem = pDevice->elemArray[pDevice->baseIndex - 1]; ONEelem *pElem; ONEnode *pNode; ONEedge *pEdge; int index; double dPsiDVce, dPsiDVbe, dNDVce, dNDVbe, dPDVce, dPDVbe; double *incVce, *incVbe; double nConc, pConc; double area = pDevice->area; *dIeDVce = 0.0; *dIcDVce = 0.0; *dIeDVbe = 0.0; *dIcDVbe = 0.0; /* zero the rhs before loading in the new rhs */ for (index = 1; index <= pDevice->numEqns; index++) { pDevice->rhs[index] = 0.0; } /* store the new rhs for computing CE incremental quantities */ pNode = pLastElem->pLeftNode; pDevice->rhs[pNode->psiEqn] = pLastElem->epsRel * pLastElem->rDx; if (pLastElem->elemType == SEMICON) { pEdge = pLastElem->pEdge; pDevice->rhs[pNode->nEqn] = -pEdge->dJnDpsiP1; pDevice->rhs[pNode->pEqn] = -pEdge->dJpDpsiP1; } incVce = pDevice->dcDeltaSolution; spSolve(pDevice->matrix, pDevice->rhs, incVce, NIL(spREAL), NIL(spREAL)); /* zero the rhs before loading in the new rhs base contribution */ for (index = 1; index <= pDevice->numEqns; index++) { pDevice->rhs[index] = 0.0; } pNode = pBaseElem->pRightNode; if (pNode->baseType == N_TYPE) { nConc = *(pDevice->devState0 + pNode->nodeN); pDevice->rhs[pNode->nEqn] = nConc * pNode->eg; } else if (pNode->baseType == P_TYPE) { pConc = *(pDevice->devState0 + pNode->nodeP); pDevice->rhs[pNode->pEqn] = pConc * pNode->eg; } else { printf("NBJTconductance: unknown base type\n"); } incVbe = pDevice->copiedSolution; spSolve(pDevice->matrix, pDevice->rhs, incVbe, NIL(spREAL), NIL(spREAL)); pElem = pDevice->elemArray[1];/* first element */ pEdge = pElem->pEdge; pNode = pElem->pRightNode; dPsiDVce = incVce[pNode->psiEqn]; dPsiDVbe = incVbe[pNode->psiEqn]; if (pElem->elemType == SEMICON) { dNDVce = incVce[pNode->nEqn]; dPDVce = incVce[pNode->pEqn]; dNDVbe = incVbe[pNode->nEqn]; dPDVbe = incVbe[pNode->pEqn]; *dIeDVce += pEdge->dJnDpsiP1 * dPsiDVce + pEdge->dJnDnP1 * dNDVce + pEdge->dJpDpsiP1 * dPsiDVce + pEdge->dJpDpP1 * dPDVce; *dIeDVbe += pEdge->dJnDpsiP1 * dPsiDVbe + pEdge->dJnDnP1 * dNDVbe + pEdge->dJpDpsiP1 * dPsiDVbe + pEdge->dJpDpP1 * dPDVbe; } /* For transient analysis add the displacement term */ if (tranAnalysis) { *dIeDVce -= intCoeff[0] * pElem->epsRel * dPsiDVce * pElem->rDx; *dIeDVbe -= intCoeff[0] * pElem->epsRel * dPsiDVbe * pElem->rDx; } pElem = pDevice->elemArray[pDevice->numNodes - 1]; /* last element */ pEdge = pElem->pEdge; pNode = pElem->pLeftNode; dPsiDVce = incVce[pNode->psiEqn]; dPsiDVbe = incVbe[pNode->psiEqn]; if (pElem->elemType == SEMICON) { dNDVce = incVce[pNode->nEqn]; dPDVce = incVce[pNode->pEqn]; dNDVbe = incVbe[pNode->nEqn]; dPDVbe = incVbe[pNode->pEqn]; *dIcDVce += -pEdge->dJnDpsiP1 * dPsiDVce + pEdge->dJnDn * dNDVce + -pEdge->dJpDpsiP1 * dPsiDVce + pEdge->dJpDp * dPDVce + /* add terms since adjacent to boundary */ pEdge->dJnDpsiP1 + pEdge->dJpDpsiP1; *dIcDVbe += -pEdge->dJnDpsiP1 * dPsiDVbe + pEdge->dJnDn * dNDVbe + -pEdge->dJpDpsiP1 * dPsiDVbe + pEdge->dJpDp * dPDVbe; } if (tranAnalysis) { *dIcDVce += intCoeff[0] * pElem->epsRel * (dPsiDVce - 1.0) * pElem->rDx; *dIcDVbe += intCoeff[0] * pElem->epsRel * dPsiDVbe * pElem->rDx; } *dIeDVce *= -GNorm * area; *dIcDVce *= -GNorm * area; *dIeDVbe *= -GNorm * area; *dIcDVbe *= -GNorm * area; }
/* 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); } } } }
int StanfordSolveSparseMatrix(Kentry* Kentries, double b[], int numUniqueEntries, int size, double soln[]) { int i; int row; int col; double value; spMatrix A; spError err, Error; spREAL AbsThreshold,RelThreshold; spREAL *pElement; #ifdef REALLY_OUTPUT_A_WHOLE_BUNCH FILE *fp; fp = NULL; fp = fopen("nonzero-inside-solver-call","w"); fprintf(fp,"title goes here (%i nonzero)\n",numUniqueEntries); fprintf(fp,"%i real\n",size); for (i = 0; i < numUniqueEntries; i++) { /* we add 1 to row and col numbers for sparse */ fprintf(fp,"%i %i %lf\n",Kentries[i].row+SPARSE_OFFSET,Kentries[i].col+SPARSE_OFFSET, Kentries[i].value); } fprintf(fp,"0 0 0.0\n"); for (i = 0; i < size; i++) { fprintf(fp,"%lf\n",b[i+SPARSE_OFFSET]); } fclose(fp); #endif /* create the matrix */ debugprint(stddbg," allocate A matrix.\n"); fflush(stdout); A = spCreate(size, 0, &err); if( err >= spFATAL || A == NULL) { fprintf(stderr,"error allocating matrix.\n"); exit(-1); } for (i = 0; i < numUniqueEntries; i++) { if (!(i % (int)(numUniqueEntries/50.0))) { debugprint(stddbg,"inserting into A: %i of %i\n",i,numUniqueEntries); } row = Kentries[i].row+SPARSE_OFFSET; col = Kentries[i].col+SPARSE_OFFSET; value = Kentries[i].value; pElement = spGetElement(A,row,col); if (pElement == NULL) { fprintf(stderr, "error: insufficient memory available.\n"); exit(-1); } *pElement = value; } debugprint(stddbg," free memory for Kentries\n"); deleteKentries(Kentries); spSetReal( A ); #if MODIFIED_NODAL spMNA_Preorder( A ); #endif RelThreshold = 0; AbsThreshold = 0; debugprint(stddbg," order and factor matrix.\n"); Error = spOrderAndFactor( A, b, RelThreshold, AbsThreshold, 1 ); if ( Error >= spFATAL ) { fprintf(stdout,"Fatal error (%i)\n",Error); exit(-1); } /* spPrint( A,1,1,1); */ for (i = 0; i <= size; i++) { soln[0] = 0; } debugprint(stddbg," call spSolve.\n"); spSolve( A, b, soln); debugprint(stddbg," destroy A.\n"); spDestroy(A); return 0; }
int main(int argc, char* argv[]) { int i; char title[1024]; char line[1024]; int size; int row; int col; double value; spMatrix A; spREAL x[4096]; spREAL b[4096]; spError err, Error; spREAL AbsThreshold,RelThreshold; spREAL *pElement; FILE *fp = NULL; if (argc != 2) { fprintf(stderr,"usage: sptest <matrix_filename>\n"); exit(-1); } fprintf(stdout,"Reading file [%s]\n",argv[1]); if ((fp = fopen(argv[1],"r")) == NULL) { fprintf(stderr,"Error opening file [%s]\n",argv[1]); exit(-1); } title[0]='\0'; fgets(title,1024,fp); fgets(line,1024,fp); if (sscanf(line,"%i real",&size) != 1) { fprintf(stderr,"Error reading size.\n"); exit(-1); } // create the matrix A = spCreate(size, 0, &err); if( err >= spFATAL || A == NULL) { fprintf(stderr,"error allocating matrix.\n"); exit(-1); } while (0 == 0) { line[0]='\0'; fgets(line,1024,fp); if (sscanf(line,"%i %i %lf",&row,&col,&value) != 3) { fprintf(stderr,"Error reading matrix.\n"); exit(-1); } if (row == 0 && col == 0) break; //spElement *pElement; pElement = spGetElement(A,row,col); if (pElement == NULL) { fprintf(stderr, "error: insufficient memory available.\n"); exit(-1); } *pElement = value; pElement = spGetElement(A,row,col); } b[0] = 0; for (i = 1; i <= size; i++) { line[0]='\0'; fgets(line,1024,fp); if (sscanf(line,"%lf",&value) != 1) { fprintf(stderr,"Error reading RHS.\n"); exit(-1); } b[i] = value; } spSetReal( A ); /*spPrint( A,1,1,1);*/ #if MODIFIED_NODAL spMNA_Preorder( A ); #endif RelThreshold = 0; AbsThreshold = 0; Error = spOrderAndFactor( A, b, RelThreshold, AbsThreshold, 1 ); if ( Error >= spFATAL ) { fprintf(stdout,"Fatal error (%i)\n",Error); exit(-1); } /*spPrint( A,1,1,1);*/ for (i = 0; i <= size; i++) { x[0] = 0; } spSolve( A, b, x); /* Print the Solution. */ for (i = 1; i <= size; i++) { fprintf(stdout,"diplacement[%i] = %lg\n",i,x[i]); } spDestroy(A); return 0; }