twocont.c

来自「ngspice又一个电子CAD仿真软件代码.功能更全」· C语言 代码 · 共 1,053 行 · 第 1/3 页

C
1,053
字号
/**********Copyright 1991 Regents of the University of California.  All rights reserved.Author:	1987 Kartikeya Mayaram, U. C. Berkeley CAD GroupAuthor:	1991 David A. Gates, U. C. Berkeley CAD Group$Id: twocont.c,v 1.3 2005/05/21 12:37:24 sjborley Exp $**********/#include "ngspice.h"#include "numglobs.h"#include "numenum.h"#include "twomesh.h"#include "twodev.h"#include "bool.h"#include "spmatrix.h"#include "twoddefs.h"#include "twodext.h"#include "cidersupt.h"#include "../../maths/misc/bernoull.h"/* * Functions to setup and solve the continuity equations. * Both continuity equations are solved. * Separate functions are used for one continuity equation. *//* * setup matrix pointers to Jacobian values and  * store direct pointers with the nodes */void   TWO_jacBuild(TWOdevice *pDevice){  char *matrix = pDevice->matrix;  double *spGetElement();  TWOelem *pElem;  TWOnode *pNode;  TWOchannel *pCh;  int eIndex, nIndex;  int nextIndex;			/* index of node to find next element */  int psiEqn, nEqn, pEqn;		/* scratch for deref'd eqn numbers */  int psiEqnTL = 0, nEqnTL = 0, pEqnTL = 0;  int psiEqnTR = 0, nEqnTR = 0, pEqnTR = 0;  int psiEqnBR = 0, nEqnBR = 0, pEqnBR = 0;  int psiEqnBL = 0, nEqnBL = 0, pEqnBL = 0;  int psiEqnInM = 0, psiEqnInP = 0;	/* scratch for deref'd surface eqns */  int psiEqnOxM = 0, psiEqnOxP = 0;	/* M= more negative, P= more positive */    for ( eIndex = 1; eIndex <= pDevice->numElems; eIndex++ ) {    pElem = pDevice->elements[ eIndex ];        /* first the self terms */    for ( nIndex = 0; nIndex <= 3; nIndex++ ) {      pNode = pElem->pNodes[ nIndex ];      /* get poisson-only pointer */      psiEqn = pNode->psiEqn;      pNode->fPsiPsi = spGetElement( matrix, psiEqn, psiEqn );            if ( pElem->elemType == SEMICON ) {	/* get continuity-coupling terms */	nEqn = pNode->nEqn;	pEqn = pNode->pEqn;	/* pointers for additional terms */	pNode->fPsiN = spGetElement( matrix, psiEqn, nEqn );	pNode->fPsiP = spGetElement( matrix, psiEqn, pEqn );	pNode->fNPsi = spGetElement( matrix, nEqn, psiEqn );	pNode->fNN = spGetElement( matrix, nEqn, nEqn );	pNode->fNP = spGetElement( matrix, nEqn, pEqn );	pNode->fPPsi = spGetElement( matrix, pEqn, psiEqn );	pNode->fPN = spGetElement( matrix, pEqn, nEqn );	pNode->fPP = spGetElement( matrix, pEqn, pEqn );      } else {	nEqn = 0;	pEqn = 0;      }      /* save equation indices */      switch ( nIndex ) {      case 0: /* TL Node */	psiEqnTL = psiEqn;	nEqnTL = nEqn;	pEqnTL = pEqn;	break;      case 1: /* TR Node */	psiEqnTR = psiEqn;	nEqnTR = nEqn;	pEqnTR = pEqn;	break;      case 2: /* BR Node */	psiEqnBR = psiEqn;	nEqnBR = nEqn;	pEqnBR = pEqn;	break;      case 3: /* BL Node */	psiEqnBL = psiEqn;	nEqnBL = nEqn;	pEqnBL = pEqn;	break;      default:	break;      }    }        /* now terms to couple to adjacent nodes */    pNode = pElem->pTLNode;    pNode->fPsiPsiiP1 = spGetElement(matrix, psiEqnTL, psiEqnTR );    pNode->fPsiPsijP1 = spGetElement(matrix, psiEqnTL, psiEqnBL );    if ( pElem->elemType == SEMICON ) {      /* continuity equation pointers */      pNode->fNPsiiP1    = spGetElement( matrix, nEqnTL, psiEqnTR );      pNode->fNNiP1      = spGetElement( matrix, nEqnTL, nEqnTR );      pNode->fNPsijP1    = spGetElement( matrix, nEqnTL, psiEqnBL );      pNode->fNNjP1      = spGetElement( matrix, nEqnTL, nEqnBL );      pNode->fPPsiiP1    = spGetElement( matrix, pEqnTL, psiEqnTR );      pNode->fPPiP1      = spGetElement( matrix, pEqnTL, pEqnTR );      pNode->fPPsijP1    = spGetElement( matrix, pEqnTL, psiEqnBL );      pNode->fPPjP1      = spGetElement( matrix, pEqnTL, pEqnBL );      /* Surface Mobility Model depends on diagonal node values */      if ( MobDeriv && SurfaceMobility && pElem->channel ) {	pNode->fNPsiiP1jP1 = spGetElement( matrix, nEqnTL, psiEqnBR );	pNode->fNNiP1jP1   = spGetElement( matrix, nEqnTL, nEqnBR );	pNode->fPPsiiP1jP1 = spGetElement( matrix, pEqnTL, psiEqnBR );	pNode->fPPiP1jP1   = spGetElement( matrix, pEqnTL, pEqnBR );      }    }        pNode = pElem->pTRNode;    pNode->fPsiPsiiM1 = spGetElement(matrix, psiEqnTR, psiEqnTL );    pNode->fPsiPsijP1 = spGetElement(matrix, psiEqnTR, psiEqnBR );    if ( pElem->elemType == SEMICON ) {      /* continuity equation pointers */      pNode->fNPsiiM1    = spGetElement( matrix, nEqnTR, psiEqnTL );      pNode->fNNiM1      = spGetElement( matrix, nEqnTR, nEqnTL );      pNode->fNPsijP1    = spGetElement( matrix, nEqnTR, psiEqnBR );      pNode->fNNjP1      = spGetElement( matrix, nEqnTR, nEqnBR );      pNode->fPPsiiM1    = spGetElement( matrix, pEqnTR, psiEqnTL );      pNode->fPPiM1      = spGetElement( matrix, pEqnTR, pEqnTL );      pNode->fPPsijP1    = spGetElement( matrix, pEqnTR, psiEqnBR );      pNode->fPPjP1      = spGetElement( matrix, pEqnTR, pEqnBR );      /* Surface Mobility Model depends on diagonal node values */      if ( MobDeriv && SurfaceMobility && pElem->channel ) {	pNode->fNPsiiM1jP1 = spGetElement( matrix, nEqnTR, psiEqnBL );	pNode->fNNiM1jP1   = spGetElement( matrix, nEqnTR, nEqnBL );	pNode->fPPsiiM1jP1 = spGetElement( matrix, pEqnTR, psiEqnBL );	pNode->fPPiM1jP1   = spGetElement( matrix, pEqnTR, pEqnBL );      }    }        pNode = pElem->pBRNode;    pNode->fPsiPsiiM1 = spGetElement(matrix, psiEqnBR, psiEqnBL );    pNode->fPsiPsijM1 = spGetElement(matrix, psiEqnBR, psiEqnTR );    if ( pElem->elemType == SEMICON ) {      /* continuity equation pointers */      pNode->fNPsiiM1    = spGetElement( matrix, nEqnBR, psiEqnBL );      pNode->fNNiM1      = spGetElement( matrix, nEqnBR, nEqnBL );      pNode->fNPsijM1    = spGetElement( matrix, nEqnBR, psiEqnTR );      pNode->fNNjM1      = spGetElement( matrix, nEqnBR, nEqnTR );      pNode->fPPsiiM1    = spGetElement( matrix, pEqnBR, psiEqnBL );      pNode->fPPiM1      = spGetElement( matrix, pEqnBR, pEqnBL );      pNode->fPPsijM1    = spGetElement( matrix, pEqnBR, psiEqnTR );      pNode->fPPjM1      = spGetElement( matrix, pEqnBR, pEqnTR );      /* Surface Mobility Model depends on diagonal node values */      if ( MobDeriv && SurfaceMobility && pElem->channel ) {	pNode->fNPsiiM1jM1 = spGetElement( matrix, nEqnBR, psiEqnTL );	pNode->fNNiM1jM1   = spGetElement( matrix, nEqnBR, nEqnTL );	pNode->fPPsiiM1jM1 = spGetElement( matrix, pEqnBR, psiEqnTL );	pNode->fPPiM1jM1   = spGetElement( matrix, pEqnBR, pEqnTL );      }    }        pNode = pElem->pBLNode;    pNode->fPsiPsiiP1 = spGetElement(matrix, psiEqnBL, psiEqnBR );    pNode->fPsiPsijM1 = spGetElement(matrix, psiEqnBL, psiEqnTL );    if ( pElem->elemType == SEMICON ) {      /* continuity equation pointers */      pNode->fNPsiiP1    = spGetElement( matrix, nEqnBL, psiEqnBR );      pNode->fNNiP1      = spGetElement( matrix, nEqnBL, nEqnBR );      pNode->fNPsijM1    = spGetElement( matrix, nEqnBL, psiEqnTL );      pNode->fNNjM1      = spGetElement( matrix, nEqnBL, nEqnTL );      pNode->fPPsiiP1    = spGetElement( matrix, pEqnBL, psiEqnBR );      pNode->fPPiP1      = spGetElement( matrix, pEqnBL, pEqnBR );      pNode->fPPsijM1    = spGetElement( matrix, pEqnBL, psiEqnTL );      pNode->fPPjM1      = spGetElement( matrix, pEqnBL, pEqnTL );      /* Surface Mobility Model depends on diagonal node values */      if ( MobDeriv && SurfaceMobility && pElem->channel ) {	pNode->fNPsiiP1jM1 = spGetElement( matrix, nEqnBL, psiEqnTR );	pNode->fNNiP1jM1   = spGetElement( matrix, nEqnBL, nEqnTR );	pNode->fPPsiiP1jM1 = spGetElement( matrix, pEqnBL, psiEqnTR );	pNode->fPPiP1jM1   = spGetElement( matrix, pEqnBL, pEqnTR );      }    }  }  /*    * Add terms for surface-field of inversion-layer mobility model.   * Elements MUST be made from silicon for this to work.   * No empty elements are allowed.   * Don't need these pointers if SurfaceMobility isn't set.   */  if ( MobDeriv && SurfaceMobility ) {    for ( pCh = pDevice->pChannel; pCh != NIL(TWOchannel);	 pCh = pCh->next ) {      pElem = pCh->pNElem;      switch (pCh->type) {      case 0:	psiEqnInM = pElem->pBLNode->psiEqn;	psiEqnInP = pElem->pBRNode->psiEqn;	psiEqnOxM = pElem->pTLNode->psiEqn;	psiEqnOxP = pElem->pTRNode->psiEqn;	break;      case 1:	psiEqnInM = pElem->pTLNode->psiEqn;	psiEqnInP = pElem->pBLNode->psiEqn;	psiEqnOxM = pElem->pTRNode->psiEqn;	psiEqnOxP = pElem->pBRNode->psiEqn;	break;      case 2:	psiEqnInM = pElem->pTLNode->psiEqn;	psiEqnInP = pElem->pTRNode->psiEqn;	psiEqnOxM = pElem->pBLNode->psiEqn;	psiEqnOxP = pElem->pBRNode->psiEqn;	break;      case 3:	psiEqnInM = pElem->pTRNode->psiEqn;	psiEqnInP = pElem->pBRNode->psiEqn;	psiEqnOxM = pElem->pTLNode->psiEqn;	psiEqnOxP = pElem->pBLNode->psiEqn;	break;      }      pElem = pCh->pSeed;      nextIndex = (pCh->type + 2)%4;      while (pElem && pElem->channel == pCh->id) {	for ( nIndex = 0; nIndex <= 3; nIndex++ ) {	  pNode = pElem->pNodes[ nIndex ];	  psiEqn = pNode->psiEqn;	  nEqn = pNode->nEqn;	  pEqn = pNode->pEqn;	  if ( pCh->type % 2 == 0 ) { /* Vertical Slice */	    if ( nIndex == 0 || nIndex == 3 ) { /* Left Side */	      pNode->fNPsiIn   = spGetElement( matrix, nEqn, psiEqnInM );	      pNode->fNPsiInP1 = spGetElement( matrix, nEqn, psiEqnInP );	      pNode->fNPsiOx   = spGetElement( matrix, nEqn, psiEqnOxM );	      pNode->fNPsiOxP1 = spGetElement( matrix, nEqn, psiEqnOxP );	      pNode->fPPsiIn   = spGetElement( matrix, pEqn, psiEqnInM );	      pNode->fPPsiInP1 = spGetElement( matrix, pEqn, psiEqnInP );	      pNode->fPPsiOx   = spGetElement( matrix, pEqn, psiEqnOxM );	      pNode->fPPsiOxP1 = spGetElement( matrix, pEqn, psiEqnOxP );	    } else { /* Right Side */	      pNode->fNPsiInM1 = spGetElement( matrix, nEqn, psiEqnInM );	      pNode->fNPsiIn   = spGetElement( matrix, nEqn, psiEqnInP );	      pNode->fNPsiOxM1 = spGetElement( matrix, nEqn, psiEqnOxM );	      pNode->fNPsiOx   = spGetElement( matrix, nEqn, psiEqnOxP );	      pNode->fPPsiInM1 = spGetElement( matrix, pEqn, psiEqnInM );	      pNode->fPPsiIn   = spGetElement( matrix, pEqn, psiEqnInP );	      pNode->fPPsiOxM1 = spGetElement( matrix, pEqn, psiEqnOxM );	      pNode->fPPsiOx   = spGetElement( matrix, pEqn, psiEqnOxP );	    }	  } else { /* Horizontal Slice */	    if ( nIndex <= 1 ) { /* Top Side */	      pNode->fNPsiIn   = spGetElement( matrix, nEqn, psiEqnInM );	      pNode->fNPsiInP1 = spGetElement( matrix, nEqn, psiEqnInP );	      pNode->fNPsiOx   = spGetElement( matrix, nEqn, psiEqnOxM );	      pNode->fNPsiOxP1 = spGetElement( matrix, nEqn, psiEqnOxP );	      pNode->fPPsiIn   = spGetElement( matrix, pEqn, psiEqnInM );	      pNode->fPPsiInP1 = spGetElement( matrix, pEqn, psiEqnInP );	      pNode->fPPsiOx   = spGetElement( matrix, pEqn, psiEqnOxM );	      pNode->fPPsiOxP1 = spGetElement( matrix, pEqn, psiEqnOxP );	    } else { /* Bottom Side */	      pNode->fNPsiInM1 = spGetElement( matrix, nEqn, psiEqnInM );	      pNode->fNPsiIn   = spGetElement( matrix, nEqn, psiEqnInP );	      pNode->fNPsiOxM1 = spGetElement( matrix, nEqn, psiEqnOxM );	      pNode->fNPsiOx   = spGetElement( matrix, nEqn, psiEqnOxP );	      pNode->fPPsiInM1 = spGetElement( matrix, pEqn, psiEqnInM );	      pNode->fPPsiIn   = spGetElement( matrix, pEqn, psiEqnInP );	      pNode->fPPsiOxM1 = spGetElement( matrix, pEqn, psiEqnOxM );	      pNode->fPPsiOx   = spGetElement( matrix, pEqn, psiEqnOxP );	    }	  }	} /* endfor nIndex */	pElem = pElem->pElems[ nextIndex ];      } /* endwhile pElem */    } /* endfor pCh */  } /* endif SurfaceMobility */}/* *  The Jacobian and Rhs are loaded by the following function. *  Inputs are the transient analysis flag and the transient *  information structure */void   TWO_sysLoad(TWOdevice *pDevice, BOOLEAN tranAnalysis, TWOtranInfo *info){  TWOelem *pElem;  TWOnode *pNode;  TWOedge *pHEdge, *pVEdge;  TWOedge *pTEdge, *pBEdge, *pLEdge, *pREdge;  TWOchannel *pCh;  int index, eIndex;  int nextIndex;			/* index of node to find next element */  double *pRhs = pDevice->rhs;  double dx, dy, dxdy, dyOverDx, dxOverDy;  double ds;  double dPsiT, dPsiB, dPsiL, dPsiR;  double rhsN, rhsP;  double generation, TWOavalanche();  double nConc, pConc;  double perTime = 0.0;    /* first compute the currents and derivatives */  TWO_commonTerms( pDevice, FALSE, tranAnalysis, info );    /* find reciprocal timestep */  if ( tranAnalysis ) {    perTime = info->intCoeff[0];  }    /* zero the rhs vector */  for ( index = 1 ; index <= pDevice->numEqns ; index++ ) {    pRhs[ index ] = 0.0;  }    /* zero the matrix */  spClear( pDevice->matrix );    for ( eIndex = 1; eIndex <= pDevice->numElems; eIndex++ ) {    pElem = pDevice->elements[ eIndex ];        dx = 0.5 * pElem->dx;    dy = 0.5 * pElem->dy;    dxdy = dx * dy;    dxOverDy = 0.5 * pElem->epsRel * pElem->dxOverDy;    dyOverDx = 0.5 * pElem->epsRel * pElem->dyOverDx;        pTEdge = pElem->pTopEdge;    pBEdge = pElem->pBotEdge;    pLEdge = pElem->pLeftEdge;    pREdge = pElem->pRightEdge;    dPsiT = pTEdge->dPsi;    dPsiB = pBEdge->dPsi;    dPsiL = pLEdge->dPsi;    dPsiR = pREdge->dPsi;        /* load for all i,j */    for ( index = 0; index <= 3; index++ ) {      pNode = pElem->pNodes[ index ];      if ( pNode->nodeType != CONTACT ) {	*(pNode->fPsiPsi) += dyOverDx + dxOverDy;	if ( index <= 1 ) {	  pHEdge = pTEdge;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?