1 /**********
2 Copyright 1991 Regents of the University of California.  All rights reserved.
3 Author:	1987 Kartikeya Mayaram, U. C. Berkeley CAD Group
4 **********/
5 
6 /* Functions to compute terminal conductances & currents. */
7 
8 #include "ngspice/ngspice.h"
9 #include "ngspice/numglobs.h"
10 #include "ngspice/numenum.h"
11 #include "ngspice/twomesh.h"
12 #include "ngspice/twodev.h"
13 #include "ngspice/bool.h"
14 #include "ngspice/spmatrix.h"
15 #include "twoddefs.h"
16 #include "twodext.h"
17 
18 
19 void
NUMD2conductance(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,double * gd)20    NUMD2conductance(TWOdevice *pDevice, BOOLEAN tranAnalysis,
21                     double *intCoeff, double *gd)
22 {
23   TWOcontact *pContact = pDevice->pFirstContact;
24   double *incVpn;
25   BOOLEAN deltaVContact = FALSE;
26 
27   /*
28    * store the new rhs for computing the incremental quantities
29    * with the second to last node. solve the system of equations
30    */
31   incVpn = pDevice->dcDeltaSolution;
32   storeNewRhs( pDevice, pDevice->pLastContact );
33   spSolve( pDevice->matrix, pDevice->rhs, incVpn, NULL, NULL);
34 
35   incVpn = pDevice->dcDeltaSolution;
36   *gd = contactConductance( pDevice, pContact, deltaVContact, incVpn,
37 			  tranAnalysis, intCoeff );
38   *gd *= - GNorm * pDevice->width * LNorm;
39 }
40 
41 void
NBJT2conductance(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,double * dIeDVce,double * dIcDVce,double * dIeDVbe,double * dIcDVbe)42    NBJT2conductance(TWOdevice *pDevice, BOOLEAN tranAnalysis,
43                     double *intCoeff, double *dIeDVce, double *dIcDVce,
44 	   	    double *dIeDVbe, double *dIcDVbe)
45 {
46   TWOcontact *pEmitContact = pDevice->pLastContact;
47   TWOcontact *pColContact = pDevice->pFirstContact;
48   TWOcontact *pBaseContact = pDevice->pFirstContact->next;
49   double width = pDevice->width;
50   double *incVce, *incVbe;
51 
52   /*
53    * store the new rhs for computing the incremental quantities
54    * incVce (dcDeltaSolution) and incVbe (copiedSolution) are used to
55    * store the incremental quantities associated with Vce and Vbe
56    */
57 
58   incVce = pDevice->dcDeltaSolution;
59   incVbe = pDevice->copiedSolution;
60   storeNewRhs( pDevice, pColContact );
61   spSolve( pDevice->matrix, pDevice->rhs, incVce, NULL, NULL);
62   storeNewRhs( pDevice, pBaseContact );
63   spSolve( pDevice->matrix, pDevice->rhs, incVbe, NULL, NULL);
64 
65   *dIeDVce = contactConductance( pDevice, pEmitContact, FALSE, incVce,
66 				tranAnalysis, intCoeff );
67   *dIeDVbe = contactConductance( pDevice, pEmitContact, FALSE, incVbe,
68 				tranAnalysis, intCoeff );
69 
70   *dIcDVce = contactConductance( pDevice, pColContact, TRUE, incVce,
71 				tranAnalysis, intCoeff );
72   *dIcDVbe = contactConductance( pDevice, pColContact, FALSE, incVbe,
73 				tranAnalysis, intCoeff );
74   *dIeDVce *= GNorm * width * LNorm;
75   *dIcDVce *= GNorm * width * LNorm;
76   *dIeDVbe *= GNorm * width * LNorm;
77   *dIcDVbe *= GNorm * width * LNorm;
78 }
79 
80 void
NUMOSconductance(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,struct mosConductances * dIdV)81    NUMOSconductance(TWOdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff,
82                     struct mosConductances *dIdV)
83 {
84   TWOcontact *pDContact = pDevice->pFirstContact;
85   TWOcontact *pGContact = pDevice->pFirstContact->next;
86   TWOcontact *pSContact = pDevice->pFirstContact->next->next;
87   double width = pDevice->width;
88   double *incVdb, *incVsb, *incVgb;
89 
90   /*
91    * store the new rhs for computing the incremental quantities
92    * incVdb (dcDeltaSolution)
93    */
94 
95   incVdb = pDevice->dcDeltaSolution;
96   incVsb = pDevice->copiedSolution;
97   incVgb = pDevice->rhsImag;
98   storeNewRhs( pDevice, pDContact );
99   spSolve( pDevice->matrix, pDevice->rhs, incVdb, NULL, NULL);
100   storeNewRhs( pDevice, pSContact );
101   spSolve( pDevice->matrix, pDevice->rhs, incVsb, NULL, NULL);
102   storeNewRhs( pDevice, pGContact );
103   spSolve( pDevice->matrix, pDevice->rhs, incVgb, NULL, NULL);
104 
105   dIdV->dIdDVdb = contactConductance( pDevice, pDContact, TRUE,
106 				     incVdb, tranAnalysis, intCoeff );
107   dIdV->dIsDVdb = contactConductance( pDevice, pSContact, FALSE,
108 				     incVdb, tranAnalysis, intCoeff );
109   dIdV->dIgDVdb = GateTypeConductance( pDevice, pGContact, FALSE,
110 				      incVdb, tranAnalysis, intCoeff );
111   dIdV->dIdDVsb = contactConductance( pDevice, pDContact, FALSE,
112 				     incVsb, tranAnalysis, intCoeff );
113   dIdV->dIsDVsb = contactConductance( pDevice, pSContact, TRUE,
114 				     incVsb, tranAnalysis, intCoeff );
115   dIdV->dIgDVsb = GateTypeConductance( pDevice, pGContact, FALSE,
116 				      incVsb, tranAnalysis, intCoeff );
117   dIdV->dIdDVgb = contactConductance( pDevice, pDContact, FALSE,
118 				     incVgb, tranAnalysis, intCoeff );
119   dIdV->dIsDVgb = contactConductance( pDevice, pSContact, FALSE,
120 				     incVgb, tranAnalysis, intCoeff );
121   dIdV->dIgDVgb = GateTypeConductance( pDevice, pGContact, TRUE,
122 				      incVgb, tranAnalysis, intCoeff );
123 
124   dIdV->dIdDVdb *= GNorm * width * LNorm;
125   dIdV->dIdDVsb *= GNorm * width * LNorm;
126   dIdV->dIdDVgb *= GNorm * width * LNorm;
127   dIdV->dIsDVdb *= GNorm * width * LNorm;
128   dIdV->dIsDVsb *= GNorm * width * LNorm;
129   dIdV->dIsDVgb *= GNorm * width * LNorm;
130   dIdV->dIgDVdb *= GNorm * width * LNorm;
131   dIdV->dIgDVsb *= GNorm * width * LNorm;
132   dIdV->dIgDVgb *= GNorm * width * LNorm;
133 
134 }
135 
136 double
contactCurrent(TWOdevice * pDevice,TWOcontact * pContact)137   contactCurrent(TWOdevice *pDevice, TWOcontact *pContact)
138 {
139   /* computes the current through the contact given in pContact */
140   int index, i, numContactNodes;
141   TWOnode *pNode;
142   TWOelem *pElem;
143   TWOedge *pHEdge, *pVEdge;
144   double dx, dy;
145   double jTotal = 0.0;
146 
147   numContactNodes = pContact->numNodes;
148   for ( index = 0; index < numContactNodes; index++ ) {
149     pNode = pContact->pNodes[ index ];
150     for ( i = 0; i <= 3; i++ ) {
151       pElem = pNode->pElems[ i ];
152       if ( pElem != NULL ) {
153 	dx = 0.5 * pElem->dx;
154 	dy = 0.5 * pElem->dy;
155 	switch ( i ) {
156 	case 0:
157 	  /* Bottom Right node */
158 	  pHEdge = pElem->pBotEdge;
159 	  pVEdge = pElem->pRightEdge;
160 	  jTotal += pElem->epsRel * ( -dy * pHEdge->jd - dx * pVEdge->jd );
161 	  if ( pElem->elemType == SEMICON ) {
162 	    jTotal += -dy * (pHEdge->jn + pHEdge->jp)
163 	      -dx * (pVEdge->jn + pVEdge->jp);
164 	  }
165 	  break;
166 	case 1:
167 	  /* Bottom Left node */
168 	  pHEdge = pElem->pBotEdge;
169 	  pVEdge = pElem->pLeftEdge;
170 	  jTotal += pElem->epsRel * ( dy * pHEdge->jd - dx * pVEdge->jd );
171 	  if ( pElem->elemType == SEMICON ) {
172 	    jTotal += dy * (pHEdge->jn + pHEdge->jp)
173 	      -dx * (pVEdge->jn + pVEdge->jp);
174 	  }
175 	  break;
176 	case 2:
177 	  /* Top Left node */
178 	  pHEdge = pElem->pTopEdge;
179 	  pVEdge = pElem->pLeftEdge;
180 	  jTotal += pElem->epsRel * ( dy * pHEdge->jd + dx * pVEdge->jd );
181 	  if ( pElem->elemType == SEMICON ) {
182 	    jTotal += dy * (pHEdge->jn + pHEdge->jp)
183 	      + dx * (pVEdge->jn + pVEdge->jp);
184 	  }
185 	  break;
186 	case 3:
187 	  /* Top Right Node */
188 	  pHEdge = pElem->pTopEdge;
189 	  pVEdge = pElem->pRightEdge;
190 	  jTotal += pElem->epsRel * ( -dy * pHEdge->jd + dx * pVEdge->jd );
191 	  if ( pElem->elemType == SEMICON ) {
192 	    jTotal += -dy * (pHEdge->jn + pHEdge->jp)
193 	      + dx * (pVEdge->jn + pVEdge->jp);
194 	  }
195 	  break;
196 	}
197       }
198     }
199   }
200 
201   return( jTotal * pDevice->width * LNorm * JNorm );
202 }
203 
204 double
oxideCurrent(TWOdevice * pDevice,TWOcontact * pContact,BOOLEAN tranAnalysis)205   oxideCurrent(TWOdevice *pDevice, TWOcontact *pContact,
206                BOOLEAN tranAnalysis)
207 {
208   /* computes the current through the contact given in pContact */
209   int index, i, numContactNodes;
210   TWOnode *pNode;
211   TWOelem *pElem;
212   TWOedge *pHEdge, *pVEdge;
213   double dx, dy;
214   double jTotal = 0.0;
215 
216   if ( !tranAnalysis ) {
217     return( jTotal );
218   }
219 
220   numContactNodes = pContact->numNodes;
221   for ( index = 0; index < numContactNodes; index++ ) {
222     pNode = pContact->pNodes[ index ];
223     for ( i = 0; i <= 3; i++ ) {
224       pElem = pNode->pElems[ i ];
225       if ( pElem != NULL ) {
226 	dx = 0.5 * pElem->dx;
227 	dy = 0.5 * pElem->dy;
228 	switch ( i ) {
229 	case 0:
230 	  /* Bottom Right node */
231 	  pHEdge = pElem->pBotEdge;
232 	  pVEdge = pElem->pRightEdge;
233 	  jTotal += pElem->epsRel * ( -dy * pHEdge->jd - dx * pVEdge->jd );
234 	  break;
235 	case 1:
236 	  /* Bottom Left node */
237 	  pHEdge = pElem->pBotEdge;
238 	  pVEdge = pElem->pLeftEdge;
239 	  jTotal += pElem->epsRel * ( dy * pHEdge->jd - dx * pVEdge->jd );
240 	  break;
241 	case 2:
242 	  /* Top Left node */
243 	  pHEdge = pElem->pTopEdge;
244 	  pVEdge = pElem->pLeftEdge;
245 	  jTotal += pElem->epsRel * ( dy * pHEdge->jd + dx * pVEdge->jd );
246 	  break;
247 	case 3:
248 	  /* Top Right Node */
249 	  pHEdge = pElem->pTopEdge;
250 	  pVEdge = pElem->pRightEdge;
251 	  jTotal += pElem->epsRel * ( -dy * pHEdge->jd + dx * pVEdge->jd );
252 	  break;
253 	}
254       }
255     }
256   }
257 
258   return( jTotal * pDevice->width * LNorm * JNorm );
259 }
260 
261 
262 double
contactConductance(TWOdevice * pDevice,TWOcontact * pContact,BOOLEAN delVContact,double * dxDv,BOOLEAN tranAnalysis,double * intCoeff)263    contactConductance(TWOdevice *pDevice, TWOcontact *pContact,
264                       BOOLEAN delVContact, double *dxDv,
265 	              BOOLEAN tranAnalysis, double *intCoeff)
266 {
267   /* computes the conductance of the contact given in pContact */
268   int index, i, numContactNodes;
269   TWOnode *pNode, *pHNode = NULL, *pVNode = NULL;
270   TWOelem *pElem;
271   TWOedge *pHEdge = NULL, *pVEdge = NULL;
272   double dPsiDv, dnDv, dpDv;
273   double gTotal = 0.0;
274   int nInc, pInc;
275 
276   NG_IGNORE(pDevice);
277 
278   /* for one carrier the rest of this code relies on appropriate
279      current derivative term to be zero */
280   if ( !OneCarrier ) {
281     nInc = 1;
282     pInc = 2;
283   } else {
284     nInc = 1;
285     pInc = 1;
286   }
287 
288   numContactNodes = pContact->numNodes;
289   for ( index = 0; index < numContactNodes; index++ ) {
290     pNode = pContact->pNodes[ index ];
291     for ( i = 0; i <= 3; i++ ) {
292       pElem = pNode->pElems[ i ];
293       if ( pElem != NULL ) {
294 	switch ( i ) {
295 	case 0:
296 	  /* the TL element */
297 	  pHNode = pElem->pBLNode;
298 	  pVNode = pElem->pTRNode;
299 	  pHEdge = pElem->pBotEdge;
300 	  pVEdge = pElem->pRightEdge;
301 	  if ( pElem->elemType == SEMICON ) {
302 	    /* compute the derivatives with n,p */
303 	    if ( pHNode->nodeType != CONTACT ) {
304 	      dnDv = dxDv[ pHNode->nEqn ];
305 	      dpDv = dxDv[ pHNode->pEqn ];
306 	      gTotal -= 0.5 * pElem->dy * (pHEdge->dJnDn * dnDv
307 					   + pHEdge->dJpDp * dpDv);
308 	    }
309 	    if ( pVNode->nodeType != CONTACT ) {
310 	      dnDv = dxDv[ pVNode->nEqn ];
311 	      dpDv = dxDv[ pVNode->pEqn ];
312 	      gTotal -= 0.5 * pElem->dx * (pVEdge->dJnDn * dnDv
313 					   + pVEdge->dJpDp * dpDv);
314 	    }
315 	  }
316 	  break;
317 	case 1:
318 	  /* the TR element */
319 	  pHNode = pElem->pBRNode;
320 	  pVNode = pElem->pTLNode;
321 	  pHEdge = pElem->pBotEdge;
322 	  pVEdge = pElem->pLeftEdge;
323 	  if ( pElem->elemType == SEMICON ) {
324 	    /* compute the derivatives with n,p */
325 	    if ( pHNode->nodeType != CONTACT ) {
326 	      dnDv = dxDv[ pHNode->nEqn ];
327 	      dpDv = dxDv[ pHNode->pEqn ];
328 	      gTotal += 0.5 * pElem->dy * (pHEdge->dJnDnP1 * dnDv
329 					   + pHEdge->dJpDpP1 * dpDv);
330 	    }
331 	    if ( pVNode->nodeType != CONTACT ) {
332 	      dnDv = dxDv[ pVNode->nEqn ];
333 	      dpDv = dxDv[ pVNode->pEqn ];
334 	      gTotal -= 0.5 * pElem->dx * (pVEdge->dJnDn * dnDv
335 					   + pVEdge->dJpDp * dpDv);
336 	    }
337 	  }
338 	  break;
339 	case 2:
340 	  /* the BR element*/
341 	  pHNode = pElem->pTRNode;
342 	  pVNode = pElem->pBLNode;
343 	  pHEdge = pElem->pTopEdge;
344 	  pVEdge = pElem->pLeftEdge;
345 	  if ( pElem->elemType == SEMICON ) {
346 	    /* compute the derivatives with n,p */
347 	    if ( pHNode->nodeType != CONTACT ) {
348 	      dnDv = dxDv[ pHNode->nEqn ];
349 	      dpDv = dxDv[ pHNode->pEqn ];
350 	      gTotal += 0.5 * pElem->dy * (pHEdge->dJnDnP1 * dnDv
351 					   + pHEdge->dJpDpP1 * dpDv);
352 	    }
353 	    if ( pVNode->nodeType != CONTACT ) {
354 	      dnDv = dxDv[ pVNode->nEqn ];
355 	      dpDv = dxDv[ pVNode->pEqn ];
356 	      gTotal += 0.5 * pElem->dx * (pVEdge->dJnDnP1 * dnDv
357 					   + pVEdge->dJpDpP1 * dpDv);
358 	    }
359 	  }
360 	  break;
361 	case 3:
362 	  /* the BL element */
363 	  pHNode = pElem->pTLNode;
364 	  pVNode = pElem->pBRNode;
365 	  pHEdge = pElem->pTopEdge;
366 	  pVEdge = pElem->pRightEdge;
367 	  if ( pElem->elemType == SEMICON ) {
368 	    /* compute the derivatives with n,p */
369 	    if ( pHNode->nodeType != CONTACT ) {
370 	      dnDv = dxDv[ pHNode->nEqn ];
371 	      dpDv = dxDv[ pHNode->pEqn ];
372 	      gTotal -= 0.5 * pElem->dy * (pHEdge->dJnDn * dnDv
373 					   + pHEdge->dJpDp * dpDv);
374 	    }
375 	    if ( pVNode->nodeType != CONTACT ) {
376 	      dnDv = dxDv[ pVNode->nEqn ];
377 	      dpDv = dxDv[ pVNode->pEqn ];
378 	      gTotal += 0.5 * pElem->dx * (pVEdge->dJnDnP1 * dnDv
379 					   + pVEdge->dJpDpP1 * dpDv);
380 	    }
381 	  }
382 	  break;
383 	}
384 	if ( pElem->elemType == SEMICON ) {
385 	  if ( pHNode->nodeType != CONTACT ) {
386 	    dPsiDv = dxDv[ pHNode->psiEqn ];
387 	    gTotal += 0.5 * pElem->dy * dPsiDv * (pHEdge->dJnDpsiP1 + pHEdge->dJpDpsiP1 );
388 	    if ( delVContact ) {
389 	      gTotal -= 0.5 * pElem->dy * (pHEdge->dJnDpsiP1 + pHEdge->dJpDpsiP1 );
390 	    }
391 	  }
392 	  if ( pVNode->nodeType != CONTACT ) {
393 	    dPsiDv = dxDv[ pVNode->psiEqn ];
394 	    gTotal += 0.5 * pElem->dx * dPsiDv * (pVEdge->dJnDpsiP1 + pVEdge->dJpDpsiP1 );
395 	    if ( delVContact ) {
396 	      gTotal -= 0.5 * pElem->dx * (pVEdge->dJnDpsiP1 + pVEdge->dJpDpsiP1 );
397 	    }
398 	  }
399 	}
400 	if ( tranAnalysis ) {
401 	  /* add the displacement current terms */
402 	  if ( pHNode->nodeType != CONTACT ) {
403 	    dPsiDv = dxDv[ pHNode->psiEqn ];
404 	    gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx * dPsiDv;
405 	    if ( delVContact ) {
406 	      gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx;
407 	    }
408 	  }
409 	  if ( pVNode->nodeType != CONTACT ) {
410 	    dPsiDv = dxDv[ pVNode->psiEqn ];
411 	    gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy * dPsiDv;
412 	    if ( delVContact ) {
413 	      gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy;
414 	    }
415 	  }
416 	}
417       }
418     }
419   }
420 
421   return( gTotal );
422 }
423 
424 
425 double
oxideConductance(TWOdevice * pDevice,TWOcontact * pContact,BOOLEAN delVContact,double * dxDv,BOOLEAN tranAnalysis,double * intCoeff)426    oxideConductance(TWOdevice *pDevice, TWOcontact *pContact,
427                     BOOLEAN delVContact, double *dxDv,
428 	            BOOLEAN tranAnalysis, double *intCoeff)
429 {
430   /* computes the conductance of the contact given in pContact */
431   int index, i, numContactNodes;
432   TWOnode *pNode, *pHNode = NULL, *pVNode = NULL;
433   TWOelem *pElem;
434   double dPsiDv;
435   double gTotal = 0.0;
436 
437   NG_IGNORE(pDevice);
438 
439   if ( !tranAnalysis ) {
440     return( gTotal );
441   }
442 
443   numContactNodes = pContact->numNodes;
444   for ( index = 0; index < numContactNodes; index++ ) {
445     pNode = pContact->pNodes[ index ];
446     for ( i = 0; i <= 3; i++ ) {
447       pElem = pNode->pElems[ i ];
448       if ( pElem != NULL ) {
449 	switch ( i ) {
450 	case 0:
451 	  /* the TL element */
452 	  pHNode = pElem->pBLNode;
453 	  pVNode = pElem->pTRNode;
454 	  break;
455 	case 1:
456 	  /* the TR element */
457 	  pHNode = pElem->pBRNode;
458 	  pVNode = pElem->pTLNode;
459 	  break;
460 	case 2:
461 	  /* the BR element*/
462 	  pHNode = pElem->pTRNode;
463 	  pVNode = pElem->pBLNode;
464 	  break;
465 	case 3:
466 	  /* the BL element */
467 	  pHNode = pElem->pTLNode;
468 	  pVNode = pElem->pBRNode;
469 	  break;
470 	}
471 	/* add the displacement current terms */
472 	if ( pHNode->nodeType != CONTACT ) {
473 	  dPsiDv = dxDv[ pHNode->psiEqn ];
474 	  gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx * dPsiDv;
475 	  if ( delVContact ) {
476 	    gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dyOverDx;
477 	  }
478 	}
479 	if ( pVNode->nodeType != CONTACT ) {
480 	  dPsiDv = dxDv[ pVNode->psiEqn ];
481 	  gTotal -= intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy * dPsiDv;
482 	  if ( delVContact ) {
483 	    gTotal += intCoeff[0] * pElem->epsRel * 0.5 * pElem->dxOverDy;
484 	  }
485 	}
486       }
487     }
488   }
489 
490   return( gTotal );
491 }
492 
493 /* these functions are used for solving the complete system of
494  * equations directly using LU decomposition   1/22/88
495  */
496 
497 void
NUMD2current(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,double * id)498    NUMD2current(TWOdevice *pDevice, BOOLEAN tranAnalysis,
499                 double *intCoeff, double *id)
500 {
501   TWOcontact *pPContact = pDevice->pFirstContact;
502 /*  TWOcontact *pNContact = pDevice->pLastContact; */
503   double ip, ipPrime, *solution;
504 /*  double in;*/
505   BOOLEAN deltaVContact = FALSE;
506 
507   solution = pDevice->dcDeltaSolution;
508   ip = contactCurrent( pDevice, pPContact );
509   /*
510   in = contactCurrent( pDevice, pNContact );
511   fprintf(stdout, "DIO current: ( %11.4e error )\n", ip+in );
512   fprintf(stdout, "     Ip = %11.4e     In = %11.4e\n", ip, in );
513   */
514 
515   /*
516    * for the additional contribution to id will make use of
517    * contactConductance. This function will be called
518    * with the dcDeltaSolution vector instead of the incremental quantities
519    */
520   ipPrime = contactConductance( pDevice, pPContact, deltaVContact,
521 			       solution, tranAnalysis, intCoeff );
522 
523   ipPrime *= JNorm * pDevice->width * LNorm;
524   ip += ipPrime;
525   *id = ip;
526 }
527 
528 void
NBJT2current(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,double * ie,double * ic)529    NBJT2current(TWOdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff,
530                 double *ie, double *ic)
531 {
532   TWOcontact *pEmitContact = pDevice->pLastContact;
533   TWOcontact *pColContact = pDevice->pFirstContact;
534 /*  TWOcontact *pBaseContact = pDevice->pFirstContact->next; */
535   double *solution, iePrime, icPrime;
536 /*  double ib; */
537 
538   solution = pDevice->dcDeltaSolution;
539 
540   *ie = contactCurrent( pDevice, pEmitContact );
541   *ic = contactCurrent( pDevice, pColContact );
542   /*
543   ib = contactCurrent( pDevice, pBaseContact );
544   fprintf(stdout, "BJT current: ( %11.4e error )\n", *ic+ib+*ie );
545   fprintf(stdout, "     Ic = %11.4e     Ib = %11.4e\n", *ic, ib );
546   fprintf(stdout, "     Ie = %11.4e\n", *ie );
547   */
548 
549   iePrime = contactConductance( pDevice, pEmitContact, FALSE, solution,
550 			       tranAnalysis, intCoeff );
551 
552   icPrime = contactConductance( pDevice, pColContact, FALSE, solution,
553 			       tranAnalysis, intCoeff );
554 
555   iePrime *= JNorm * pDevice->width * LNorm;
556   icPrime *= JNorm * pDevice->width * LNorm;
557 
558   *ie += iePrime;
559   *ic += icPrime;
560 }
561 
562 void
NUMOScurrent(TWOdevice * pDevice,BOOLEAN tranAnalysis,double * intCoeff,double * id,double * is,double * ig)563    NUMOScurrent(TWOdevice *pDevice, BOOLEAN tranAnalysis, double *intCoeff,
564                 double *id, double *is, double *ig)
565 {
566   TWOcontact *pDContact = pDevice->pFirstContact;
567   TWOcontact *pGContact = pDevice->pFirstContact->next;
568   TWOcontact *pSContact = pDevice->pFirstContact->next->next;
569 /*  TWOcontact *pBContact = pDevice->pLastContact; */
570   double *solution, idPrime, isPrime, igPrime;
571 /*  double ib; */
572 
573   solution = pDevice->dcDeltaSolution;
574 
575   *id = contactCurrent( pDevice, pDContact );
576 
577 /*
578  * This is a terrible hack
579  */
580 
581 #ifdef NORMAL_GATE
582   *ig = GateTypeCurrent( pDevice, pGContact, tranAnalysis );
583 #else
584   *ig = GateTypeCurrent( pDevice, pGContact);
585 #endif
586 
587   *is = contactCurrent( pDevice, pSContact );
588   /*
589   ib = contactCurrent( pDevice, pBContact );
590   fprintf(stdout, "MOS current: ( %11.4e error )\n", *id+*ig+*is+ib );
591   fprintf(stdout, "     Id = %11.4e     Is = %11.4e\n", *id, *is );
592   fprintf(stdout, "     Ig = %11.4e     Ib = %11.4e\n", *ig, ib );
593   */
594 
595   idPrime = contactConductance( pDevice, pDContact, FALSE,
596 			       solution, tranAnalysis, intCoeff );
597 
598   isPrime = contactConductance( pDevice, pSContact, FALSE,
599 			       solution, tranAnalysis, intCoeff );
600 
601   igPrime = GateTypeConductance( pDevice, pGContact, FALSE,
602 				solution, tranAnalysis, intCoeff );
603 
604   idPrime *= JNorm * pDevice->width * LNorm;
605   isPrime *= JNorm * pDevice->width * LNorm;
606   igPrime *= JNorm * pDevice->width * LNorm;
607 
608   *id += idPrime;
609   *is += isPrime;
610   *ig += igPrime;
611 }
612