📄 onesolve.c
字号:
*(pDevice->devState0 + pNode->nodePsi) = pNode->psi; if (pElem->elemType IS SEMICON) { pNode->nConc = solution[pNode->nEqn]; pNode->pConc = solution[pNode->pEqn]; *(pDevice->devState0 + pNode->nodeN) = pNode->nConc; *(pDevice->devState0 + pNode->nodeP) = pNode->pConc; } } } } } } miscTime += SPfrontEnd->IFseconds() - startTime; if (tranAnalysis) { pDevice->pStats->setupTime[STAT_TRAN] += setupTime; pDevice->pStats->miscTime[STAT_TRAN] += miscTime; } else { pDevice->pStats->setupTime[STAT_DC] += setupTime; pDevice->pStats->miscTime[STAT_DC] += miscTime; }}/* Copy the device's equilibrium state into the solution vector. */voidONEstoreEquilibGuess(pDevice) ONEdevice *pDevice;{ int nIndex, eIndex; double *solution = pDevice->dcSolution; double refPsi; ONEelem *pElem; ONEnode *pNode; for (eIndex = 1; eIndex < pDevice->numNodes; eIndex++) { pElem = pDevice->elemArray[eIndex]; refPsi = pElem->matlInfo->refPsi; for (nIndex = 0; nIndex <= 1; nIndex++) { if (pElem->evalNodes[nIndex]) { pNode = pElem->pNodes[nIndex]; if (pNode->nodeType ISNOT CONTACT) { solution[pNode->psiEqn] = pNode->psi0; if (pElem->elemType IS SEMICON) { solution[pNode->nEqn] = pNode->nie * exp(pNode->psi0 - refPsi); solution[pNode->pEqn] = pNode->nie * exp(-pNode->psi0 + refPsi); } } } } }}/* Copy the device's internal state into the solution vector. */voidONEstoreInitialGuess(pDevice) ONEdevice *pDevice;{ int nIndex, eIndex; double *solution = pDevice->dcSolution; ONEelem *pElem; ONEnode *pNode; for (eIndex = 1; eIndex < pDevice->numNodes; eIndex++) { pElem = pDevice->elemArray[eIndex]; for (nIndex = 0; nIndex <= 1; nIndex++) { if (pElem->evalNodes[nIndex]) { pNode = pElem->pNodes[nIndex]; if (pNode->nodeType ISNOT CONTACT) { solution[pNode->psiEqn] = pNode->psi; if (pElem->elemType IS SEMICON) { solution[pNode->nEqn] = pNode->nConc; solution[pNode->pEqn] = pNode->pConc; } } } } }}#define NORM_RED_MAXITERS 10intONEnewDelta(pDevice, tranAnalysis, info) ONEdevice *pDevice; BOOLEAN tranAnalysis; ONEtranInfo *info;{ int index, iterNum; double newNorm, fib, lambda, fibn, fibp; BOOLEAN acceptable = FALSE, error = FALSE; iterNum = 0; lambda = 1.0; fibn = 1.0; fibp = 1.0; /* * Copy the contents of dcSolution into copiedSolution and modify * dcSolution by adding the deltaSolution. */ for (index = 1; index <= pDevice->numEqns; index++) { pDevice->copiedSolution[index] = pDevice->dcSolution[index]; pDevice->dcSolution[index] += pDevice->dcDeltaSolution[index]; } if (pDevice->poissonOnly) { ONEQrhsLoad(pDevice); } else { ONE_rhsLoad(pDevice, tranAnalysis, info); } newNorm = maxNorm(pDevice->rhs, pDevice->numEqns); if (pDevice->rhsNorm <= pDevice->abstol) { lambda = 0.0; newNorm = pDevice->rhsNorm; } else if (newNorm < pDevice->rhsNorm) { acceptable = TRUE; } else { /* chop the step size so that deltax is acceptable */ if (ONEdcDebug) { fprintf(stdout, " %11.4e %11.4e\n", newNorm, lambda); } while (NOT acceptable) { iterNum++; if (iterNum > NORM_RED_MAXITERS) { error = TRUE; lambda = 0.0; /* Don't break out until after we've reset the device. */ } fib = fibp; fibp = fibn; fibn += fib; lambda *= (fibp / fibn); for (index = 1; index <= pDevice->numEqns; index++) { pDevice->dcSolution[index] = pDevice->copiedSolution[index] + lambda * pDevice->dcDeltaSolution[index]; } if (pDevice->poissonOnly) { ONEQrhsLoad(pDevice); } else { ONE_rhsLoad(pDevice, tranAnalysis, info); } newNorm = maxNorm(pDevice->rhs, pDevice->numEqns); if (error) { break; } if (newNorm <= pDevice->rhsNorm) { acceptable = TRUE; } if (ONEdcDebug) { fprintf(stdout, " %11.4e %11.4e\n", newNorm, lambda); } } } /* Restore the previous dcSolution and store the new deltaSolution. */ pDevice->rhsNorm = newNorm; for (index = 1; index <= pDevice->numEqns; index++) { pDevice->dcSolution[index] = pDevice->copiedSolution[index]; pDevice->dcDeltaSolution[index] *= lambda; } return(error);}/* Predict the values of the internal variables at the next timepoint. *//* Needed for Predictor-Corrector LTE estimation */voidONEpredict(pDevice, info) ONEdevice *pDevice; ONEtranInfo *info;{ int nIndex, eIndex; ONEnode *pNode; ONEelem *pElem; double startTime, miscTime = 0.0; /* TRANSIENT MISC */ startTime = SPfrontEnd->IFseconds(); for (eIndex = 1; eIndex < pDevice->numNodes; eIndex++) { pElem = pDevice->elemArray[eIndex]; for (nIndex = 0; nIndex <= 1; nIndex++) { if (pElem->evalNodes[nIndex]) { pNode = pElem->pNodes[nIndex]; pNode->psi = *(pDevice->devState1 + pNode->nodePsi); if (pElem->elemType IS SEMICON AND pNode->nodeType ISNOT CONTACT) { pNode->nPred = predict(pDevice->devStates, info, pNode->nodeN); pNode->pPred = predict(pDevice->devStates, info, pNode->nodeP); pNode->nConc = pNode->nPred; pNode->pConc = pNode->pPred; } } } } miscTime += SPfrontEnd->IFseconds() - startTime; pDevice->pStats->miscTime[STAT_TRAN] += miscTime;}/* Estimate the device's overall truncation error. */doubleONEtrunc(pDevice, info, delta) ONEdevice *pDevice; ONEtranInfo *info; double delta;{ int nIndex, eIndex; ONEelem *pElem; ONEnode *pNode; double tolN, tolP, lte, relError, temp, relLTE; double lteCoeff = info->lteCoeff; double mult = 10.0; double reltol; double startTime, lteTime = 0.0; /* TRANSIENT LTE */ startTime = SPfrontEnd->IFseconds(); relError = 0.0; reltol = pDevice->reltol * mult; /* Need to get the predictor for the current order. */ /* The scheme currently used is very dumb. Need to fix later. */ /* XXX Why is the scheme dumb? Never understood this. */ computePredCoeff(info->method, info->order, info->predCoeff, info->delta); for (eIndex = 1; eIndex < pDevice->numNodes; eIndex++) { pElem = pDevice->elemArray[eIndex]; for (nIndex = 0; nIndex <= 1; nIndex++) { if (pElem->evalNodes[nIndex]) { pNode = pElem->pNodes[nIndex]; if (pElem->elemType IS SEMICON AND pNode->nodeType ISNOT CONTACT) { tolN = pDevice->abstol + reltol * ABS(pNode->nConc); tolP = pDevice->abstol + reltol * ABS(pNode->pConc); pNode->nPred = predict(pDevice->devStates, info, pNode->nodeN); pNode->pPred = predict(pDevice->devStates, info, pNode->nodeP); lte = lteCoeff * (pNode->nConc - pNode->nPred); temp = lte / tolN; relError += temp * temp; lte = lteCoeff * (pNode->pConc - pNode->pPred); temp = lte / tolP; relError += temp * temp; } } } } /* Make sure error is non-zero. */ relError = MAX(pDevice->abstol, relError); /* The total relative error has been calculated norm-2 squared. */ relError = sqrt(relError / pDevice->numEqns); /* Use the order of the integration method to compute new delta. */ temp = delta / pow(relError, 1.0 / (info->order + 1)); lteTime += SPfrontEnd->IFseconds() - startTime; pDevice->pStats->lteTime += lteTime; return (temp);}/* Save info from state table into the internal state. */voidONEsaveState(pDevice) ONEdevice *pDevice;{ int nIndex, eIndex; ONEnode *pNode; ONEelem *pElem; for (eIndex = 1; eIndex < pDevice->numNodes; eIndex++) { pElem = pDevice->elemArray[eIndex]; for (nIndex = 0; nIndex <= 1; nIndex++) { if (pElem->evalNodes[nIndex]) { pNode = pElem->pNodes[nIndex]; pNode->psi = *(pDevice->devState1 + pNode->nodePsi); if (pElem->elemType IS SEMICON AND pNode->nodeType ISNOT CONTACT) { pNode->nConc = *(pDevice->devState1 + pNode->nodeN); pNode->pConc = *(pDevice->devState1 + pNode->nodeP); } } } }}/* Function to compute Nu norm of the rhs vector. *//* Nu-norm calculation based upon work done at Stanford. */doubleONEnuNorm(pDevice) ONEdevice *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, NIL(spREAL), NIL(spREAL)); /* Compute L2-norm of the solution vector (stored in rhsImag) */ return (l2Norm(pDevice->rhsImag, pDevice->numEqns));}/* * Check for numerical errors in the Jacobian. Useful debugging aid when new * models are being incorporated. */voidONEjacCheck(pDevice, tranAnalysis, info) ONEdevice *pDevice; BOOLEAN tranAnalysis; ONEtranInfo *info;{ int index, rIndex; double del, diff, tol, *dptr; double *spFindElement(); if (ONEjacDebug) { ONE_sysLoad(pDevice, tranAnalysis, info); /* * spPrint( pDevice->matrix, 0, 1, 1 ); */ pDevice->rhsNorm = maxNorm(pDevice->rhs, pDevice->numEqns); for (index = 1; index <= pDevice->numEqns; index++) { if (1e3 * ABS(pDevice->rhs[index]) > pDevice->rhsNorm) { fprintf(stderr, "eqn %d: res %11.4e, norm %11.4e\n", index, pDevice->rhs[index], pDevice->rhsNorm); } } for (index = 1; index <= pDevice->numEqns; index++) { pDevice->rhsImag[index] = pDevice->rhs[index]; } for (index = 1; index <= pDevice->numEqns; index++) { pDevice->copiedSolution[index] = pDevice->dcSolution[index]; del = 1e-4 * pDevice->abstol + 1e-6 * ABS(pDevice->dcSolution[index]); pDevice->dcSolution[index] += del; ONE_rhsLoad(pDevice, tranAnalysis, info); pDevice->dcSolution[index] = pDevice->copiedSolution[index]; for (rIndex = 1; rIndex <= pDevice->numEqns; rIndex++) { diff = (pDevice->rhsImag[rIndex] - pDevice->rhs[rIndex]) / del; dptr = spFindElement(pDevice->matrix, rIndex, index); /* * if ( dptr ISNOT NIL(double) ) { fprintf( stderr, "[%d][%d]: FD = * %11.4e, AJ = %11.4e\n", rIndex, index, diff, *dptr ); } else { * fprintf( stderr, "[%d][%d]: FD = %11.4e, AJ = %11.4e\n", rIndex, * index, diff, 0.0 ); } */ if (dptr ISNOT NIL(double)) { tol = (1e-4 * pDevice->abstol) + (1e-2 * MAX(ABS(diff), ABS(*dptr))); if ((diff != 0.0) && (ABS(diff - *dptr) > tol)) { fprintf(stderr, "Mismatch[%d][%d]: FD = %11.4e, AJ = %11.4e\n\t FD-AJ = %11.4e vs. %11.4e\n", rIndex, index, diff, *dptr, ABS(diff - *dptr), tol); } } else { if (diff != 0.0) { fprintf(stderr, "Missing [%d][%d]: FD = %11.4e, AJ = 0.0\n", rIndex, index, diff); } } } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -