Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_Diode.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2014 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_Diode.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 02/28/00
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.296.2.3 $
40 //
41 // Revision Date : $Date: 2014/03/06 23:33:43 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 #include <Xyce_config.h>
46 
47 // ---------- Standard Includes ----------
48 #ifdef HAVE_CMATH
49 #include <cmath>
50 #else
51 #include <math.h>
52 #endif
53 
54 // ---------- Xyce Includes ----------
55 #include <N_DEV_Const.h>
56 #include <N_DEV_DeviceOptions.h>
57 #include <N_DEV_Diode.h>
58 #include <N_DEV_ExternData.h>
59 #include <N_DEV_MatrixLoadData.h>
60 #include <N_DEV_SolverState.h>
61 #include <N_DEV_Message.h>
62 #include <N_ERH_ErrorMgr.h>
63 
64 #include <N_LAS_Matrix.h>
65 #include <N_LAS_Vector.h>
66 
67 namespace Xyce {
68 namespace Device {
69 namespace Diode {
70 
72 {
73  p.addPar ("AREA", 1.0, &Diode::Instance::Area)
74  .setCategory(CAT_GEOMETRY)
75  .setDescription("Area scaling value (scales IS, ISR, IKF, RS, CJ0, and IBV)");
76 
77  p.addPar ("IC", 0.0, &Diode::Instance::InitCond)
78  .setGivenMember(&Diode::Instance::InitCondGiven)
79  .setCategory(CAT_NONE);
80 
81  p.addPar ("TEMP", 0.0, &Diode::Instance::Temp)
82  .setExpressionAccess(ParameterType::TIME_DEP)
83  .setDescription("Device temperature");
84 
85  p.addPar ("OFF", 0, &Diode::Instance::off)
86  .setUnit(U_LOGIC)
87  .setCategory(CAT_CONTROL)
88  .setDescription("Initial voltage drop across device set to zero");
89  p.addPar ("LAMBERTW", 0, &Diode::Instance::lambertWFlag)
90  .setUnit(U_LOGIC)
91  .setCategory(CAT_CONTROL)
92  .setDescription("Option to solve diode equations with the Lambert-W function");
93 }
94 
96 {
97  p.addPar ("IS", 1.0e-14, &Diode::Model::IS)
98  .setUnit(U_AMP)
99  .setCategory(CAT_CURRENT)
100  .setDescription("Saturation current");
101 
102  // synonym for IS
103  p.addPar ("JS", 1.0e-14, &Diode::Model::IS)
104  .setUnit(U_AMP)
105  .setCategory(CAT_CURRENT)
106  .setDescription("Saturation current");
107 
108  p.addPar ("RS", 0.0, &Diode::Model::RS)
109  .setExpressionAccess(ParameterType::MIN_RES)
110  .setUnit(U_OHM)
111  .setCategory(CAT_RES)
112  .setDescription("Parasitic resistance");
113 
114  p.addPar ("N", 1.0, &Diode::Model::N)
115  .setCategory(CAT_PROCESS)
116  .setOriginalValueStored(true)
117  .setDescription("Emission coefficient");
118 
119  p.addPar ("ISR", 0.0, &Diode::Model::ISR)
120  .setUnit(U_AMP)
121  .setCategory(CAT_CURRENT)
122  .setDescription("Recombination current parameter (level 2)");
123 
124  p.addPar ("NR", 2.0, &Diode::Model::NR)
125  .setCategory(CAT_NONE)
126  .setDescription("Emission coefficient for ISR (level 2)");
127 
128  p.addPar ("IKF", 0.0, &Diode::Model::IKF)
129  .setUnit(U_AMP)
130  .setCategory(CAT_CURRENT)
131  .setDescription("High-injection \"knee\" current (level 2)");
132 
133  p.addPar ("TT", 0.0, &Diode::Model::TT)
134  .setUnit(U_SECOND)
135  .setCategory(CAT_PROCESS)
136  .setDescription("Transit time");
137 
138  p.addPar ("CJO", 0.0, &Diode::Model::CJO)
139  .setExpressionAccess(ParameterType::MIN_CAP)
140  .setUnit(U_FARAD)
141  .setCategory(CAT_CAP)
142  .setDescription("Zero-bias p-n depletion capacitance");
143 
144  // synonyms for CJO
145  p.addPar ("CJ", 0.0, &Diode::Model::CJO)
146  .setExpressionAccess(ParameterType::MIN_CAP)
147  .setUnit(U_FARAD)
148  .setCategory(CAT_CAP)
149  .setDescription("Zero-bias p-n depletion capacitance");
150 
151  p.addPar ("CJ0", 0.0, &Diode::Model::CJO)
152  .setExpressionAccess(ParameterType::MIN_CAP)
153  .setUnit(U_FARAD)
154  .setCategory(CAT_CAP)
155  .setDescription("Zero-bias p-n depletion capacitance");
156 
157  p.addPar ("VJ", 1.0, &Diode::Model::VJ)
158  .setUnit(U_VOLT)
159  .setCategory(CAT_VOLT)
160  .setDescription("Potential for p-n junction");
161 
162  p.addPar ("M", 0.5, &Diode::Model::M)
163  .setCategory(CAT_PROCESS)
164  .setDescription("Grading parameter for p-n junction");
165 
166  p.addPar ("EG", 1.11, &Diode::Model::EG)
167  .setUnit(U_EV)
168  .setCategory(CAT_PROCESS)
169  .setDescription("Bandgap voltage (barrier height)");
170 
171  p.addPar ("XTI", 3.0, &Diode::Model::XTI)
172  .setCategory(CAT_TEMP)
173  .setDescription("IS temperature exponent");
174 
175  p.addPar ("TIKF", 0.0, &Diode::Model::TIKF)
176  .setUnit(U_DEGCM1)
177  .setCategory(CAT_TEMP)
178  .setDescription("IKF temperature coefficient (linear) (level 2)");
179 
180  p.addPar ("TBV1", 0.0, &Diode::Model::TBV1)
181  .setUnit(U_DEGCM1)
182  .setCategory(CAT_TEMP)
183  .setDescription("BV temperature coefficient (linear) (level 2)");
184 
185  p.addPar ("TBV2", 0.0, &Diode::Model::TBV2)
186  .setUnit(U_DEGCM2)
187  .setCategory(CAT_TEMP)
188  .setDescription("BV temperature coefficient (quadratic) (level 2)");
189 
190  p.addPar ("TRS1", 0.0, &Diode::Model::TRS1)
191  .setUnit(U_DEGCM1)
192  .setCategory(CAT_TEMP)
193  .setDescription("RS temperature coefficient (linear) (level 2)");
194 
195  p.addPar ("TRS2", 0.0, &Diode::Model::TRS2)
196  .setUnit(U_DEGCM2)
197  .setCategory(CAT_TEMP)
198  .setDescription("RS temperature coefficient (quadratic) (level 2)");
199 
200  p.addPar ("FC", 0.5, &Diode::Model::FC)
201  .setCategory(CAT_CAP)
202  .setDescription("Forward-bias depletion capacitance coefficient");
203 
204  p.addPar ("BV", 1E99, &Diode::Model::BV)
205  .setGivenMember(&Diode::Model::BVGiven)
206  .setUnit(U_VOLT)
207  .setCategory(CAT_VOLT)
208  .setDescription("Reverse breakdown \"knee\" voltage");
209 
210  // synonym for BV
211  p.addPar ("VB", 1E99, &Diode::Model::BV)
212  .setGivenMember(&Diode::Model::BVGiven)
213  .setUnit(U_VOLT)
214  .setCategory(CAT_VOLT)
215  .setDescription("Reverse breakdown \"knee\" voltage");
216 
217  p.addPar ("IBV", 1.0e-3, &Diode::Model::IBV)
218  .setUnit(U_AMP)
219  .setCategory(CAT_CURRENT)
220  .setDescription("Reverse breakdown \"knee\" current");
221 
222  p.addPar ("IRF", 1.0, &Diode::Model::IRF)
223  .setCategory(CAT_CURRENT)
224  .setDescription("Reverse current fitting factor");
225 
226  p.addPar ("NBV", 1.0, &Diode::Model::NBV)
227  .setCategory(CAT_PROCESS)
228  .setDescription("Reverse breakdown ideality factor (level 2)");
229 
230  p.addPar ("IBVL", 0.0, &Diode::Model::IBVL)
231  .setUnit(U_AMP)
232  .setCategory(CAT_CURRENT)
233  .setDescription("Low-level reverse breakdown \"knee\" current (level 2)");
234 
235  p.addPar ("NBVL", 1.0, &Diode::Model::NBVL)
236  .setCategory(CAT_PROCESS)
237  .setDescription("Low-level reverse breakdown ideality factor (level 2)");
238 
239  p.addPar ("TNOM", 0.0, &Diode::Model::TNOM)
240  .setCategory(CAT_NONE)
241  .setDescription("");
242 
243  p.addPar ("KF", 0.0, &Diode::Model::KF)
244  .setCategory(CAT_FLICKER)
245  .setDescription("Flicker noise coefficient");
246 
247  p.addPar ("AF", 1.0, &Diode::Model::AF)
248  .setCategory(CAT_FLICKER)
249  .setDescription("Flicker noise exponent");
250 }
251 
252 
253 
254 std::vector< std::vector<int> > Instance::jacStamp_RS;
255 std::vector< std::vector<int> > Instance::jacStamp;
256 
257 std::vector<int> Instance::jacMap_RS;
258 std::vector<int> Instance::jacMap;
259 
260 std::vector< std::vector<int> > Instance::jacMap2_RS;
261 std::vector< std::vector<int> > Instance::jacMap2;
262 
263 //-----------------------------------------------------------------------------
264 // Function : Instance::processParams
265 // Purpose :
266 // Special Notes :
267 // Scope : public
268 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
269 // Creation Date : 6/03/02
270 //-----------------------------------------------------------------------------
272 {
274  return true;
275 }
276 
277 //-----------------------------------------------------------------------------
278 // Function : Instance::Instance
279 // Purpose : "instance block" constructor
280 // Special Notes :
281 // Scope : public
282 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
283 // Creation Date : 3/16/00
284 //-----------------------------------------------------------------------------
286  const Configuration & configuration,
287  const InstanceBlock & instance_block,
288  Model & model,
289  const FactoryBlock & factory_block)
290  : DeviceInstance(instance_block, configuration.getInstanceParameters(), factory_block),
291  model_(model),
292  off(0),
293  Area(1.0),
294  InitCond(0.0),
295  Temp(getDeviceOptions().temp.getImmutableValue<double>()),
296  lambertWFlag(0),
297  InitCondGiven(false),
298  tJctPot(0.0),
299  tJctCap(0.0),
300  tDepCap(0.0),
301  tSatCur(0.0),
302  tVcrit(0.0),
303  tF1(0.0),
304  tBrkdwnV(0.0),
305  tSatCurR(0.0),
306  tIKF(0.0),
307  tRS(0.0),
308  tIRF(1.0),
309  Id(0.0),
310  Gd(0.0),
311  Cd(0.0),
312  Gcd(0.0),
313  Icd(0.0),
314  Qd(0.0),
315  Gspr(0.0),
316  Vpp(0.0),
317  Vp(0.0),
318  Vn(0.0),
319  Vc(0.0),
320  Vd(0.0),
321  Vd_old(0.0),
322  Vd_orig(0.0),
323  newtonIterOld(0),
324  li_Pos(-1),
325  li_Neg(-1),
326  li_Pri(-1),
327  APosEquPosNodeOffset(-1),
328  APosEquPriNodeOffset(-1),
329  ANegEquNegNodeOffset(-1),
330  ANegEquPriNodeOffset(-1),
331  APriEquPosNodeOffset(-1),
332  APriEquNegNodeOffset(-1),
333  APriEquPriNodeOffset(-1),
335  fPosEquPosNodePtr(0),
336  fPosEquPriNodePtr(0),
337  fNegEquNegNodePtr(0),
338  fNegEquPriNodePtr(0),
339  fPriEquPosNodePtr(0),
340  fPriEquNegNodePtr(0),
341  fPriEquPriNodePtr(0),
342  qPosEquPosNodePtr(0),
343  qPosEquPriNodePtr(0),
344  qNegEquNegNodePtr(0),
345  qNegEquPriNodePtr(0),
346  qPriEquPosNodePtr(0),
347  qPriEquNegNodePtr(0),
348  qPriEquPriNodePtr(0),
349 #endif
350  li_storevd(-1),
351  li_store_dev_i(-1)
352 {
353  numIntVars = 1;
354  numExtVars = 2;
355  numStateVars = 0;
356  setNumStoreVars(1);
357  numLeadCurrentStoreVars = 1; // lead current DEV_I
358 
359  if( jacStamp.empty() )
360  {
361  jacStamp_RS.resize(3);
362  jacStamp_RS[0].resize(2);
363  jacStamp_RS[0][0]=0;
364  jacStamp_RS[0][1]=2;
365  jacStamp_RS[1].resize(2);
366  jacStamp_RS[1][0]=1;
367  jacStamp_RS[1][1]=2;
368  jacStamp_RS[2].resize(3);
369  jacStamp_RS[2][0]=0;
370  jacStamp_RS[2][1]=1;
371  jacStamp_RS[2][2]=2;
372 
373  jacMap_RS.clear();
375  jacStamp, jacMap, jacMap2, 2, 0, 3);
376 
377  }
378 
379  // Set params to constant default values:
380  setDefaultParams ();
381 
382  // Set params according to instance line and constant defaults from metadata:
383  setParams (instance_block.params);
384 
385  // Set any non-constant parameter defaults:
386  if (!given("LAMBERTW"))
388  if (!given("TEMP"))
389  Temp = getDeviceOptions().temp.getImmutableValue<double>();
390  if ( (model_.RS == 0.0) || (lambertWFlag == 1) )
391  numIntVars = 0;
392  if ( model_.CJO == 0.0 )
393  numStateVars = 1;
394  if ( (model_.RS == 0.0) && (lambertWFlag == 1) )
395  model_.RS =1.0e-12;
396 
397  // Calculate any parameters specified as expressions:
399 
400  // calculate dependent (ie computed) params and check for errors:
401  processParams ();
402 }
403 
404 //-----------------------------------------------------------------------------
405 // Function : Instance::~Instance
406 // Purpose : destructor
407 // Special Notes :
408 // Scope : public
409 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
410 // Creation Date : 3/16/00
411 //-----------------------------------------------------------------------------
413 {
414 }
415 
416 // Additional Declarations
417 //-----------------------------------------------------------------------------
418 // Function : Instance::registerLIDs
419 // Purpose : function for registering, and setting up, local ID's.
420 // Special Notes :
421 // Scope : public
422 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
423 // Creation Date : 6/20/02
424 //-----------------------------------------------------------------------------
425 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
426  const std::vector<int> & extLIDVecRef)
427 {
428  AssertLIDs(intLIDVecRef.size() == numIntVars);
429  AssertLIDs(extLIDVecRef.size() == numExtVars);
430 
431 #ifdef Xyce_DEBUG_DEVICE
432 
433  if (getDeviceOptions().debugLevel > 0)
434  {
435  Xyce::dout() << std::endl << section_divider << std::endl;
436  Xyce::dout() << "In Instance::register LIDs\n\n";
437  Xyce::dout() << "name = " << getName() << std::endl;
438  Xyce::dout() << "number of internal variables: " << numIntVars << std::endl;
439  Xyce::dout() << "number of external variables: " << numExtVars << std::endl;
440  }
441 #endif
442 
443  // copy over the global ID lists.
444  intLIDVec = intLIDVecRef;
445  extLIDVec = extLIDVecRef;
446 
447  // Now use these lists to obtain the indices into the linear algebra
448  // entities. This assumes an order.
449 
450  li_Pos = extLIDVec[0];
451  li_Neg = extLIDVec[1];
452 
453  //Setup of Pri node indices
454  //If RS=0, Pri=Pos Node
455  //--------------------------
456  if( model_.RS && (lambertWFlag != 1) )
457  li_Pri = intLIDVec[0];
458  else
459  li_Pri = li_Pos;
460 
461 #ifdef Xyce_DEBUG_DEVICE
462  if (getDeviceOptions().debugLevel > 0)
463  {
464  Xyce::dout() << "\nSolution and RHS variables:\n";
465  Xyce::dout() << "\nli_Pos = ";
466  Xyce::dout().width(4);
467  Xyce::dout() << li_Pos << std::endl;
468 
469  Xyce::dout() << "\nli_Neg = ";
470  Xyce::dout().width(4);
471  Xyce::dout() << li_Neg << std::endl;
472 
473  Xyce::dout() << "\nli_Pri = ";
474  Xyce::dout().width(4);
475  Xyce::dout() << li_Pri << std::endl;
476 
477  }
478 #endif
479 
480 
481 
482 #ifdef Xyce_DEBUG_DEVICE
483  if (getDeviceOptions().debugLevel > 0)
484  {
485  Xyce::dout() << "\nEnd of Instance::register LIDs\n";
486  Xyce::dout() << section_divider << std::endl;
487  }
488 #endif
489 }
490 
491 //-----------------------------------------------------------------------------
492 // Function : Instance::getIntNameMap
493 // Purpose :
494 // Special Notes :
495 // Scope : public
496 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
497 // Creation Date : 05/13/05
498 //-----------------------------------------------------------------------------
499 std::map<int,std::string> & Instance::getIntNameMap ()
500 {
501  // set up the internal name map, if it hasn't been already.
502  if (intNameMap.empty ())
503  {
504  std::string tmpstr;
505  if ( li_Pos != li_Pri )
506  {
507  tmpstr = getName()+"_internal";
508  spiceInternalName (tmpstr);
509  intNameMap[ li_Pri ] = tmpstr;
510  }
511  }
512 
513  return intNameMap;
514 }
515 
516 //-----------------------------------------------------------------------------
517 // Function : Instance::registerStateLIDs
518 // Purpose :
519 // Special Notes :
520 // Scope : public
521 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
522 // Creation Date : 6/20/02
523 //-----------------------------------------------------------------------------
524 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
525 {
526  AssertLIDs(staLIDVecRef.size() == numStateVars);
527 
528  // copy over the global ID lists:
529  staLIDVec = staLIDVecRef;
530 }
531 
532 //-----------------------------------------------------------------------------
533 // Function : Instance::registerStoreLIDs
534 // Purpose :
535 // Special Notes :
536 // Scope : public
537 // Creator : Eric Keiter
538 // Creation Date :
539 //-----------------------------------------------------------------------------
541  const std::vector<int> & stoLIDVecRef )
542 {
543  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
544 
545 // copy over the global ID lists:
546  stoLIDVec = stoLIDVecRef;
547  li_storevd = stoLIDVec[0];
548  if( loadLeadCurrent )
549  {
550  li_store_dev_i = stoLIDVec[1];
551  }
552 
553 #ifdef Xyce_DEBUG_DEVICE
554  if (getDeviceOptions().debugLevel > 0)
555  {
556  Xyce::dout() << "li_storevd = " << li_storevd;
557  }
558 #endif
559 
560 }
561 
562 //-----------------------------------------------------------------------------
563 // Function : N_DEV_DiodeInstance::getStoreNameMap
564 // Purpose :
565 // Special Notes :
566 // Scope : public
567 // Creator : Richard Schiek, Electrical Systems Modeling
568 // Creation Date : 03/27/2013
569 //-----------------------------------------------------------------------------
570 std::map<int, std::string> & N_DEV_DiodeInstance::getStoreNameMap ()
571 {
572  // set up the internal name map, if it hasn't been already.
573  if( storeNameMap.empty () )
574  {
575  // change subcircuitname:devicetype_deviceName to
576  // devicetype:subcircuitName:deviceName
577  std::string modName(getName());
578  spiceInternalName(modName);
579  std::string tmpstr;
580  tmpstr = modName+":vd";
581  storeNameMap[ li_storevd ] = tmpstr;
582  if( loadLeadCurrent )
583  {
584  tmpstr = modName+":DEV_I";
585  storeNameMap[ li_store_dev_i ] = tmpstr;
586  }
587  }
588  return storeNameMap;
589 }
590 
591 
592 //-----------------------------------------------------------------------------
593 // Function : N_DEV_DiodeInstance::jacobianStamp
594 // Purpose :
595 // Special Notes :
596 // Scope : public
597 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
598 // Creation Date : 9/2/02
599 //-----------------------------------------------------------------------------
600 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
601 {
602  if( model_.RS && (lambertWFlag != 1) )
603  return jacStamp_RS;
604  else
605  return jacStamp;
606 }
607 
608 //-----------------------------------------------------------------------------
609 // Function : Instance::registerJacLIDs
610 // Purpose :
611 // Special Notes :
612 // Scope : public
613 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
614 // Creation Date : 9/2/02
615 //-----------------------------------------------------------------------------
616 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
617 {
618  DeviceInstance::registerJacLIDs( jacLIDVec );
619  std::vector<int> map;
620  std::vector< std::vector<int> > map2;
621 
622  if( model_.RS && (lambertWFlag != 1) )
623  {
624  map = jacMap_RS;
625  map2 = jacMap2_RS;
626  }
627  else
628  {
629  map = jacMap;
630  map2 = jacMap2;
631  }
632 
633  APosEquPosNodeOffset = jacLIDVec[map[0]][map2[0][0]];
634  APosEquPriNodeOffset = jacLIDVec[map[0]][map2[0][1]];
635 
636  ANegEquNegNodeOffset = jacLIDVec[map[1]][map2[1][0]];
637  ANegEquPriNodeOffset = jacLIDVec[map[1]][map2[1][1]];
638 
639  APriEquPosNodeOffset = jacLIDVec[map[2]][map2[2][0]];
640  APriEquNegNodeOffset = jacLIDVec[map[2]][map2[2][1]];
641  APriEquPriNodeOffset = jacLIDVec[map[2]][map2[2][2]];
642 
643 }
644 
645 //-----------------------------------------------------------------------------
646 // Function : Instance::setupPointers
647 // Purpose :
648 // Special Notes :
649 // Scope : public
650 // Creator : Eric Keiter, SNL
651 // Creation Date : 11/30/08
652 //-----------------------------------------------------------------------------
654 {
655 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
656  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
657  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
658 
666 
674 #endif
675 }
676 
677 //-----------------------------------------------------------------------------
678 // Function : Instance::loadDAEQVector
679 //
680 // Purpose : Loads the Q-vector contributions for a single
681 // diode instance.
682 //
683 // Special Notes : The "Q" vector is part of a standard DAE formalism in
684 // which the system of equations is represented as:
685 //
686 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
687 //
688 // Scope : public
689 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
690 // Creation Date : 01/26/03
691 //-----------------------------------------------------------------------------
693 {
694  // note: the only capacitor goes from the negative to the
695  // positive-prime node, so there is not contribution in this
696  // function to the positive node.
697 
698  // load in the KCL for the negative node:
699  double coef = Qd;
700  (extData.daeQVectorRawPtr)[li_Neg] -= coef;
701 
702  // load in the KCL for the positive prime node:
703  coef *= -1.0; // -Qd
704  (extData.daeQVectorRawPtr)[li_Pri] -= coef;
705 
706  // load the voltage limiter vector.
708  {
709  double Vd_diff = Vd - Vd_orig;
710  double Cd_Jdxp = 0.0;
711  Cd_Jdxp = -( Cd ) * Vd_diff;
712 
713  // Load the dQdxdVp vector
714  (extData.dQdxdVpVectorRawPtr)[li_Neg] += Cd_Jdxp;
715  (extData.dQdxdVpVectorRawPtr)[li_Pri] -= Cd_Jdxp;
716  }
717 
718  if( loadLeadCurrent && (model_.CJO != 0.0))
719  {
721  }
722 
723  return true;
724 }
725 
726 //-----------------------------------------------------------------------------
727 // Function : Instance::loadDAEFVector
728 //
729 // Purpose : Loads the F-vector contributions for a single
730 // diode instance.
731 //
732 // Special Notes :
733 //
734 // Scope : public
735 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
736 // Creation Date : 01/26/03
737 //-----------------------------------------------------------------------------
739 {
740  // 3f5 compatible currents
741  // Including derivation of Vd_diff and Limiting Correction
742  //---------------------------------------------------------
743  double Ir = Gspr * (Vp - Vpp);
744 
745  // load in the KCL for the positive node:
746  double coef = -Ir;
747  (extData.daeFVectorRawPtr)[li_Pos] -= coef;
748 
749  // load in the KCL for the negative node:
750  coef = Id;
751  (extData.daeFVectorRawPtr)[li_Neg] -= coef;
752 
753  // load in the KCL for the positive prime node:
754  coef *= -1;
755  coef += Ir;
756  (extData.daeFVectorRawPtr)[li_Pri] -= coef;
757 
758  // load the voltage limiter vector.
760  {
761  double Vd_diff = Vd - Vd_orig;
762  double Gd_Jdxp = 0.0;
763  Gd_Jdxp = -( Gd ) * Vd_diff;
764 
765  // Load the dFdxdVp vector
766  (extData.dFdxdVpVectorRawPtr)[li_Neg] += Gd_Jdxp;
767  (extData.dFdxdVpVectorRawPtr)[li_Pri] -= Gd_Jdxp;
768  }
769 
770  if( loadLeadCurrent )
771  {
773  }
774 
775  return true;
776 }
777 
778 //-----------------------------------------------------------------------------
779 // Function : Instance::loadDAEdQdx
780 //
781 // Purpose : Loads the Q-vector contributions for a single
782 // diode instance.
783 //
784 // Special Notes : The "Q" vector is part of a standard DAE formalism in
785 // which the system of equations is represented as:
786 //
787 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
788 //
789 // Scope : public
790 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
791 // Creation Date : 03/05/04
792 //-----------------------------------------------------------------------------
794 {
795  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
796 
797 // New Spice3f5 matched conductivities
798 // Only major difference in loads is support for Pos=Pri node when RS=0
799 // For this DAE dQdx load, the capacitance contribution (Gcd) is the
800 // only part used.
801 //---------------------------------------------------------------------
802 
803  dQdx[li_Neg][ANegEquNegNodeOffset] += Cd;
804  dQdx[li_Neg][ANegEquPriNodeOffset] -= Cd;
805 
806  dQdx[li_Pri][APriEquNegNodeOffset] -= Cd;
807  dQdx[li_Pri][APriEquPriNodeOffset] += Cd;
808 
809  return true;
810 }
811 
812 //-----------------------------------------------------------------------------
813 // Function : Instance::loadDAEdFdx ()
814 //
815 // Purpose : Loads the F-vector contributions for a single
816 // diode instance.
817 //
818 // Special Notes :
819 //
820 // Scope : public
821 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
822 // Creation Date : 03/05/04
823 //-----------------------------------------------------------------------------
825 {
826  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
827 
828 // New Spice3f5 matched conductivities
829 // Only major difference in loads is support for Pos=Pri node when RS=0
830 // For this DAE dFdx load, the capacitance contribution (Gcd) is removed.
831 //---------------------------------------------------------------------
832 
833  dFdx[li_Pos][APosEquPosNodeOffset] += Gspr;
834  dFdx[li_Pos][APosEquPriNodeOffset] -= Gspr;
835 
836  dFdx[li_Neg][ANegEquNegNodeOffset] += Gd;
837  dFdx[li_Neg][ANegEquPriNodeOffset] -= Gd;
838 
839  dFdx[li_Pri][APriEquPosNodeOffset] -= Gspr;
840  dFdx[li_Pri][APriEquNegNodeOffset] -= Gd;
841  dFdx[li_Pri][APriEquPriNodeOffset] += Gspr + Gd;
842 
843  return true;
844 }
845 
846 //-----------------------------------------------------------------------------
847 // Function : Instance::updatePrimaryState
848 // Purpose : update primary state for one diode instance
849 // Special Notes :
850 // Scope : public
851 // Creator : Tom Russo, Component Information and Models
852 // Creation Date : 1/10/01
853 //-----------------------------------------------------------------------------
855 {
856  double * stoVec = extData.nextStoVectorRawPtr;
857  stoVec[li_storevd] = Vd;
858 
859  //Qd - capacitor charge generated in updateIntermediateVars
860  bool bsuccess = updateIntermediateVars ();
861 
862  return bsuccess;
863 }
864 
865 //-----------------------------------------------------------------------------
866 // Function : Instance::updateIntermediateVars
867 // Purpose : update intermediate variables for one diode instance
868 // Special Notes :
869 // Scope : public
870 // Creator : Tom Russo, Component Information and Models
871 // Creation Date : 1/10/01
872 //-----------------------------------------------------------------------------
874 {
875  bool bsuccess = true;
876 
877  double * solVec = extData.nextSolVectorRawPtr;
878 
879  //diode parameters
880  double M; // grading parameter
881  double BV; // breakdown voltage
882  double IBV; // reverse breakdown current
883  double NBV; // reverse breakdown ideality factor
884  double IBVL; // low-level reverse breakdown current
885  double NBVL; // low-level reverse breakdown ideality factor
886  double N; // non-ideality factor.
887  double NR; // emission coeff. for ISR.
888  double TT; // transit time.
889  double F2; // capacitive polynomial factor
890  double F3; // capacitive polynomial factor
891  double Inorm; // normal diffusion current
892  double Irec; // recombination current
893  double Kgen; // generation factor
894  double Khi; // high-injection factor
895  double Gd1, DKgen;
896  double Gd2, DKhi;
897 
898  //Model Diode parameters
899  M = model_.M;
900  BV = model_.BV;
901  IBV = model_.IBV;
902  NBV = model_.NBV;
903  IBVL = model_.IBVL;
904  NBVL = model_.NBVL;
905  N = model_.N;
906  NR = model_.NR;
907  TT = model_.TT;
908  F2 = model_.F2;
909  F3 = model_.F3;
910 
911  // obtain voltage drop accross the capacitor:
912  Vp = Vn = Vpp = 0.0;
913  Vpp = solVec[li_Pri];
914  Vn = solVec[li_Neg];
915  Vp = solVec[li_Pos];
916 
917  // Junction Voltage
918  Vd = Vpp - Vn;
919 
920  double Isat = tSatCur * Area;
921  double IsatR = tSatCurR * Area;
922  double Vt = CONSTKoverQ * Temp;
923  double Vte = N * Vt;
924  double VteR = NR * Vt;
925 
926  Gspr = tCOND * Area;
927 
928  Vd_orig = Vd;
929  origFlag = true;
930 
931  // Setup initial junction conditions if UIC enabled
932  //------------------------------------------------
933  if (getSolverState().newtonIter == 0)
934  {
935  newtonIterOld = 0;
936  //Vd_old = Vd;
937  if (getSolverState().initJctFlag && getDeviceOptions().voltageLimiterFlag)
938  {
939  if (InitCondGiven)
940  {
941  Vd = InitCond;
942  origFlag = false;
943  }
944  else if (off)
945  {
946  Vd = 0.0;
947  origFlag = false;
948  }
949  else
950  {
951  if (getSolverState().inputOPFlag)
952  {
953  N_LAS_Vector * flagSolVectorPtr = extData.flagSolVectorPtr;
954  if ((*flagSolVectorPtr)[li_Pos] == 0 ||
955  (*flagSolVectorPtr)[li_Neg] == 0 ||
956  (*flagSolVectorPtr)[li_Pri] == 0)
957  {
958  Vd=tVcrit;
959  origFlag = false;
960  }
961  }
962  else
963  {
964  Vd=tVcrit;
965  origFlag = false;
966  }
967  }
968  }
969 
970  // assume there is no history -- then check if the
971  // state vector can overwrite this
972  Vd_old = Vd;
973 
974  if (!(getSolverState().dcopFlag)||(getSolverState().locaEnabledFlag && getSolverState().dcopFlag))
975  {
977  }
978  }
979  else // just do this whenever it isn't the first iteration:
980  {
982  }
983 
984  // Voltage limiting based on mode of diode
985  //---------------------------------------
987  {
988  int ichk = 0;
989 
990  if (getSolverState().newtonIter >= 0)
991  {
992  //Test if breakdown voltage given or not
993  if (model_.BVGiven && (Vd < Xycemin(0.0, -BV + 10.0 * Vte)))
994  {
995  double Vdtmp = -( BV + Vd );
996  Vdtmp = devSupport.pnjlim(Vdtmp, -(Vd_old+BV), Vte, tVcrit, &ichk);
997  Vd = -(Vdtmp + BV);
998  }
999  else
1000  Vd = devSupport.pnjlim(Vd, Vd_old, Vte, tVcrit, &ichk);
1001 
1002  if (ichk) origFlag = false;
1003  }
1004  }
1005 
1006  // update the "old" newton iteration number.
1007  if (getSolverState().newtonIter != 0 && getSolverState().newtonIter != newtonIterOld)
1008  {
1010  }
1011 
1012 #ifdef Xyce_DEBUG_DEVICE
1013  if (getDeviceOptions().debugLevel>0 && getSolverState().debugTimeFlag)
1014  {
1015  Xyce::dout() << Xyce::section_divider << std::endl;
1016  Xyce::dout() << "Instance::updateIntermediateVars " << getName()<<std::endl;
1017  }
1018 #endif
1019 
1020  // Current and Conductivity
1021  //----------------------------------------------
1022 
1023  int level = model_.getLevel();
1024  if(level == 1)
1025  {
1026  // Using LambertW function
1027  if (lambertWFlag == 1)
1028  {
1029  double RS = model_.RS;
1030  if (Vd >= -3.0 * Vte)
1031  {
1032  lambertWCurrent(Isat, Vte, RS);
1033  }
1034  // linear reverse bias
1035  else if ( !tBrkdwnV || (Vd >= -tBrkdwnV) )
1036  {
1037  lambertWLinearReverseBias(Isat, Vte, RS);
1038  }
1039  // reverse breakdown
1040  else
1041  {
1042  lambertWBreakdownCurrent(Isat, Vte, RS);
1043  }
1044 
1045  double Vrs;
1046  Vrs = (Id + Icd)*RS;
1047  Vc = Vd - Vrs;
1048  }
1049  else if (lambertWFlag == 2)
1050  {
1051  if (Vd >= -3.0 * Vte)
1052  {
1053  lambertWCurrent(Isat, Vte, 1.0e-15);
1054  }
1055  // linear reverse bias
1056  else if ( !tBrkdwnV || (Vd >= -tBrkdwnV) )
1057  {
1058  lambertWLinearReverseBias(Isat, Vte, 1.0e-15);
1059  }
1060  // reverse breakdown
1061  else
1062  {
1063  lambertWBreakdownCurrent(Isat, Vte, 1.0e-15);
1064  }
1065  Vc = Vd;
1066  }
1067 
1068  // Normal exponential
1069  else
1070  {
1071  // Adjustment for linear portion of reverse current
1072  double IRfactor;
1073  //if(Vd >= 0) IRfactor = 1.0; //error? shouldn't this be Vd>=-3*Vte????
1074  if(Vd >= -3.0 * Vte) IRfactor = 1.0; //changing this to be consistent
1075  else IRfactor = tIRF; //with model in reference guide.
1076  Isat *= IRfactor;
1077 
1078  if (Vd >= -3.0 * Vte)
1079  {
1080  double arg1 = Vd / Vte;
1081  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1082  double evd = exp(arg1);
1083 
1084  Id = Isat * (evd - 1.0) + getDeviceOptions().gmin * Vd;
1085  Gd = Isat * evd / Vte + getDeviceOptions().gmin;
1086 #ifdef Xyce_DEBUG_DEVICE
1087  if (getDeviceOptions().debugLevel>0 && getSolverState().debugTimeFlag)
1088  {
1089  Xyce::dout() << "Normal exponential regime." << std::endl;
1090  Xyce::dout() << " Vd = " << Vd << std::endl;
1091  Xyce::dout() << " Vte = " << Vte << std::endl;
1092  Xyce::dout() << " Id = " << Id << std::endl;
1093  Xyce::dout() << " Gd = " << Gd << std::endl;
1094  }
1095 #endif
1096 
1097  }
1098 
1099  // Linear reverse bias
1100  else if(!tBrkdwnV || (Vd >= -tBrkdwnV))
1101  {
1102  double arg = 3.0 * Vte / (Vd * CONSTe);
1103  arg = arg * arg * arg;
1104  Id = -Isat * (1.0 + arg) + getDeviceOptions().gmin * Vd;
1105  Gd = Isat * 3.0 * arg / Vd + getDeviceOptions().gmin;
1106 #ifdef Xyce_DEBUG_DEVICE
1107  if (getDeviceOptions().debugLevel>0 && getSolverState().debugTimeFlag)
1108  {
1109  Xyce::dout() << "Linear reverse bias regime." << std::endl;
1110  Xyce::dout() << " Vd = " << Vd << std::endl;
1111  Xyce::dout() << " tBrkdwnV = " << tBrkdwnV << std::endl;
1112  Xyce::dout() << " Id = " << Id << std::endl;
1113  Xyce::dout() << " Gd = " << Gd << std::endl;
1114  }
1115 #endif
1116  }
1117 
1118  // Reverse breakdown
1119  else
1120  {
1121  double arg1 = -(tBrkdwnV + Vd) / Vte;
1122  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1123  double evrev = exp(arg1);
1124 
1125 #ifdef Xyce_BREAKDOWN_ORIGINAL
1126  Id = -Isat * evrev + getDeviceOptions().gmin * Vd;
1127  Gd = Isat * evrev / Vte + getDeviceOptions().gmin;
1128 #else
1129  //added by K. Santarelli 9/18/07 to account for change in tBrkdwnV
1130  //calculation.
1131  double arg2=3.0*Vte/(CONSTe*tBrkdwnV);
1132  arg2=arg2*arg2*arg2;
1133  double Isat_tBrkdwnV=Isat*(1-arg2);
1134  Id = -Isat_tBrkdwnV * evrev + getDeviceOptions().gmin * Vd;
1135  Gd = Isat_tBrkdwnV * evrev / Vte + getDeviceOptions().gmin;
1136 #endif
1137 
1138 #ifdef Xyce_DEBUG_DEVICE
1139  if (getDeviceOptions().debugLevel>0 && getSolverState().debugTimeFlag)
1140  {
1141  Xyce::dout() << "Reverse breakdown regime." << std::endl;
1142  Xyce::dout() << " Vd = " << Vd << std::endl;
1143  Xyce::dout() << " tBrkdwnV = " << tBrkdwnV << std::endl;
1144  Xyce::dout() << " Id = " << Id << std::endl;
1145  Xyce::dout() << " Gd = " << Gd << std::endl;
1146  }
1147 #endif
1148  }
1149  Vc = Vd;
1150  }
1151 
1152  }
1153  else if(level == 2)
1154  {
1155 #ifdef Xyce_DEBUG_DEVICE
1156  if (getDeviceOptions().debugLevel>0 && getSolverState().debugTimeFlag)
1157  {
1158  Xyce::dout() << " Level 2 diode code " << std::endl;
1159  }
1160 #endif
1161  // Adjustment for linear portion of reverse current
1162  double IRfactor;
1163  //if(Vd >= 0) IRfactor = 1.0; //error? Shouldn't this be Vd >= -3*Vte?
1164  if(Vd >= -3.0*Vte) IRfactor=1.0; //changing it to be consistent with model
1165  else IRfactor = tIRF; //in the reference manual.
1166  Isat *= IRfactor;
1167 
1168  if (Vd >= -3.0 * Vte)
1169  {
1170  double arg1 = Vd / Vte;
1171  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1172  double evd = exp(arg1);
1173  Inorm = Isat * (evd - 1.0) + getDeviceOptions().gmin * Vd;
1174  Gd1 = Isat*evd/Vte + getDeviceOptions().gmin;
1175 
1176  arg1 = Vd / VteR;
1177  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1178  evd = exp(arg1);
1179  Irec = IsatR * (evd - 1.0);
1180  Gd2 = IsatR*evd/VteR;
1181 
1182  Khi = 1;
1183  DKhi = 0;
1184  if(tIKF > 0)
1185  {
1186  Khi = sqrt(tIKF/(tIKF+Inorm));
1187  DKhi = 0.5*Khi*Gd1/(tIKF+Inorm);
1188  }
1189  Kgen = 0;
1190  DKgen = 0;
1191  if(Irec != 0)
1192  {
1193  Kgen = sqrt( pow(((1-Vd/tJctPot)*(1-Vd/tJctPot) + 0.005),M) );
1194  DKgen = -M*(1-Vd/tJctPot)/(tJctPot*Kgen);
1195  }
1196 
1197  Id = Inorm*Khi + Irec*Kgen;
1198  Gd = Gd1*Khi + Inorm*DKhi + Gd2*Kgen + Irec*DKgen;
1199 #ifdef Xyce_DEBUG_DEVICE
1200  if (getDeviceOptions().debugLevel>0 && getSolverState().debugTimeFlag)
1201  {
1202  Xyce::dout() << "L2 Normal exponential regime." << std::endl;
1203  Xyce::dout() << " Vd = " << Vd << std::endl;
1204  Xyce::dout() << " Vte = " << Vte << std::endl;
1205  Xyce::dout() << " Id = " << Id << std::endl;
1206  Xyce::dout() << " Irec= " << Irec << std::endl;
1207  Xyce::dout() << " Gd = " << Gd << std::endl;
1208  Xyce::dout() << " Gd1 = " << Gd1 << std::endl;
1209  Xyce::dout() << " Gd2 = " << Gd2 << std::endl;
1210  Xyce::dout() << " Khi = " << Khi << std::endl;
1211  Xyce::dout() << " Kgen=" << Kgen << std::endl;
1212  Xyce::dout() << "DKgen=" <<DKgen << std::endl;
1213  }
1214 #endif
1215  }
1216 
1217  // Linear reverse bias
1218  else if(!tBrkdwnV || (Vd >= -tBrkdwnV))
1219  {
1220  double arg = 3.0 * Vte / (Vd * CONSTe);
1221  arg = arg * arg * arg;
1222  Id = -Isat * (1.0 + arg) + getDeviceOptions().gmin * Vd;
1223  Gd = Isat * 3.0 * arg / Vd + getDeviceOptions().gmin;
1224 #ifdef Xyce_DEBUG_DEVICE
1225  if (getDeviceOptions().debugLevel>0 && getSolverState().debugTimeFlag)
1226  {
1227  Xyce::dout() << "L2 Linear reverse bias regime." << std::endl;
1228  Xyce::dout() << " Vd = " << Vd << std::endl;
1229  Xyce::dout() << " tBrkdwnV = " << tBrkdwnV << std::endl;
1230  Xyce::dout() << " Id = " << Id << std::endl;
1231  Xyce::dout() << " Gd = " << Gd << std::endl;
1232  }
1233 #endif
1234  }
1235 
1236  // Reverse breakdown
1237  else
1238  {
1239  double arg1 = -(tBrkdwnV + Vd) / Vte;
1240  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1241  double evrev = exp(arg1);
1242 
1243 #ifdef Xyce_BREAKDOWN_ORIGINAL
1244  Id = -Isat * evrev + getDeviceOptions().gmin * Vd;
1245  Gd = Isat * evrev / Vte + getDeviceOptions().gmin;
1246 #else
1247  //added 9/18/07 by K. Santarelli to account for change in tBrkdwnV
1248  //calculation.
1249  double arg2=3.0*Vte/(CONSTe*tBrkdwnV);
1250  arg2=arg2*arg2*arg2;
1251  double Isat_tBrkdwnV=Isat*(1-arg2);
1252  Id = -Isat_tBrkdwnV * evrev + getDeviceOptions().gmin * Vd;
1253  Gd = Isat_tBrkdwnV * evrev / Vte + getDeviceOptions().gmin;
1254 #endif
1255 #ifdef Xyce_DEBUG_DEVICE
1256  if (getDeviceOptions().debugLevel>0 && getSolverState().debugTimeFlag)
1257  {
1258  Xyce::dout() << "L2 Reverse breakdown regime." << std::endl;
1259  Xyce::dout() << " Vd = " << Vd << std::endl;
1260  Xyce::dout() << " tBrkdwnV = " << tBrkdwnV << std::endl;
1261  Xyce::dout() << " Id = " << Id << std::endl;
1262  Xyce::dout() << " Gd = " << Gd << std::endl;
1263  }
1264 #endif
1265  }
1266  Vc = Vd;
1267 
1268  } // level
1269 
1270  // Only compute if Capacitance is non-zero
1271  //---------------------------------------
1272  if (tJctCap != 0.0)
1273  {
1274  // Charge Storage
1275  double Czero = tJctCap * Area;
1276  if (Vc < tDepCap)
1277  {
1278  //double arg = 1.0 - Vd/VJ;
1279  double arg = 1.0 - Vc / tJctPot;
1280  double arg1 = -M * log(arg);
1281  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1282  double sarg = exp(arg1);
1283 
1284  //Qd = TT*Id + VJ*Czero*(1.0-arg*sarg)/(1.0-M);
1285  Qd = TT * Id + tJctPot * Czero * (1.0 - arg * sarg) / (1.0 - M);
1286  Cd = TT * Gd + Czero * sarg;
1287  }
1288  else
1289  {
1290  double Czof2 = Czero / F2;
1291  double MotJctPot = M / tJctPot;
1292 
1293  //Qd = TT*Id + Czero*tF1 + Czof2*(F3*(Vd-tDepCap)+(M/(VJ+VJ))
1294  Qd = TT * Id + Czero * tF1 +
1295  Czof2 * (F3 * (Vc - tDepCap) + (0.5 * MotJctPot) *
1296  (Vc * Vc - tDepCap * tDepCap));
1297  //Cd = TT*Gd + Czof2*(F3+M*Vd/VJ);
1298  Cd = TT * Gd + Czof2 * (F3 + MotJctPot * Vc);
1299  }
1300 #ifdef Xyce_DEBUG_DEVICE
1302  {
1303  Xyce::dout() << "Qd = " << Qd << std::endl;
1304  Xyce::dout() << "Cd = " << Qd << std::endl;
1305  }
1306 #endif
1307  }
1308  else
1309  {
1310  Qd = 0.0;
1311  Cd = 0.0;
1312  }
1313 
1314 #ifdef Xyce_DEBUG_DEVICE
1315  if (getDeviceOptions().debugLevel>0 && getSolverState().debugTimeFlag)
1316  {
1317  Xyce::dout() << Xyce::section_divider << std::endl;
1318  }
1319 #endif
1320 
1321  return bsuccess;
1322 }
1323 
1324 //-----------------------------------------------------------------------------
1325 // Function : Instance::updateTemperature
1326 // Purpose : update intermediate variables for one diode instance
1327 // Special Notes :
1328 // Scope : public
1329 // Creator : Tom Russo, Component Information and Models
1330 // Creation Date : 1/10/01
1331 //-----------------------------------------------------------------------------
1332 bool Instance::updateTemperature( const double & temp )
1333 {
1334 
1335  double vtnom = CONSTKoverQ * model_.TNOM;
1336 
1337  double xfc = log( 1.0 - model_.FC );
1338 
1339  if( temp != -999.0 ) Temp = temp;
1340  double TNOM = model_.TNOM;
1341 
1342  double vt = CONSTKoverQ * Temp;
1343  double fact2 = Temp / CONSTREFTEMP;
1344  double egfet = CONSTEg0 - (CONSTalphaEg*Temp*Temp)/(Temp+CONSTbetaEg);
1345  double arg = -egfet/(2.0*CONSTboltz*Temp) +
1347  double pbfact = -2.0*vt*(1.5*log(fact2)+CONSTQ*arg);
1348  double egfet1 = CONSTEg0 - (CONSTalphaEg*model_.TNOM*model_.TNOM)/
1350  double arg1 = -egfet1/(2.0*CONSTboltz*model_.TNOM) +
1352  double fact1 = model_.TNOM/CONSTREFTEMP;
1353  double pbfact1 = -2.0*vtnom*(1.5*log(fact1)+CONSTQ*arg1);
1354 
1355  double pbo = (model_.VJ-pbfact1)/fact1;
1356  double gmaold = (model_.VJ-pbo)/pbo;
1357 
1358  tJctCap = model_.CJO/
1359  (1.0+model_.M*(4.0e-4*(model_.TNOM-CONSTREFTEMP) -gmaold));
1360 
1361  tJctPot = pbfact+fact2*pbo;
1362 
1363  double gmanew = (tJctPot-pbo)/pbo;
1364 
1365  tJctCap *= 1.0 + model_.M*(4.0e-4*(Temp-CONSTREFTEMP)-gmanew);
1366 
1367  tSatCur = model_.IS*exp(((Temp/model_.TNOM)-1.0)*
1368  model_.EG/(model_.N*vt)+
1369  model_.XTI/model_.N*log(Temp/model_.TNOM));
1370 
1371  tF1 = tJctPot*(1.0-exp((1.0-model_.M)*xfc))/(1.0-model_.M);
1372 
1374 
1375  double vte = model_.N*vt;
1376  double tempBV;
1377 
1378  tVcrit = vte*log(vte/(CONSTroot2*tSatCur));
1379  tRS = model_.RS;
1380  tCOND = model_.COND;
1381  tIRF = model_.IRF*pow(fact2,1.6);
1382 
1383  int level = model_.getLevel();
1384  if(level == 2) // this section is PSPICE compatible
1385  {
1386  tSatCurR = model_.ISR*exp((Temp/TNOM - 1.0)*
1387  model_.EG/(model_.NR*vt)+
1388  model_.XTI/model_.NR*log(Temp/TNOM));
1389 
1390  tIKF = model_.IKF*(1 + model_.TIKF*(Temp-TNOM));
1391 
1392  tempBV = model_.BV*(1 + (Temp-TNOM)*
1393  ( model_.TBV1 + model_.TBV2*(Temp-TNOM) ));
1394 
1395  tRS = model_.RS*(1 + (Temp-TNOM)*
1396  ( model_.TRS1 + model_.TRS2*(Temp-TNOM) ));
1397 
1398  tCOND = 0.0;
1399  if(tRS != 0.0) tCOND = 1.0/tRS;
1400 
1401  tJctPot = (model_.VJ - egfet1)*fact2 - 3*vt*log(fact2) + egfet;
1402 
1403  tJctCap = model_.CJO/(1.0 +
1404  model_.M*(4.0e-4*(Temp-TNOM) + (1-tJctPot/model_.VJ)));
1405  }
1406  else
1407  {
1408  tempBV=model_.BV;
1409  }
1410 
1411 #ifdef Xyce_BREAKDOWN_ORIGINAL
1412  //Changed 9/18/07, K. R. Santarelli. This is the original (broken) version
1413  //of the breakdown voltage computation. It has two known issues:
1414  //
1415  //1. It assumes N (the emission coefficient) is always 1 (division by
1416  // vt instead of vte).
1417  //2. While the for loop terminates due to the fact that it's implemented via
1418  // a counter, the value of xbv does not converge in many cases, so the
1419  // value of xbv upon terminating is often garbage.
1420  //
1421  //For consistency with old, existing simulations, this version of the
1422  //breakdown voltage calculation (along with the appropriate code for
1423  //computing the breakdown current in the level 1 and level 2 models---see
1424  //the appropriate sections of
1425  //Instance::updateIntermediateVars) can be invoked by
1426  //specifiying the CPPFLAG "-DXyce_BREAKDOWN_ORIGINAL" when creating a Xyce
1427  //Build. The default, however, is the code which follows #else.
1428 
1429  double reltol = 1.0e-3;
1430  if( model_.BVGiven )
1431  {
1432  double IRfactor = tIRF;
1433  double cbv = model_.IBV;
1434  double xbv, xcbv;
1435  if( cbv < IRfactor*tSatCur*tempBV/vt )
1436  {
1437  cbv = IRfactor*tSatCur*tempBV/vt;
1438  xbv = tempBV;
1439  }
1440  else
1441  {
1442  double tol = reltol*cbv;
1443  xbv = tempBV-vt*log(1.0+cbv/(IRfactor*tSatCur));
1444  for( int i = 0; i < 25; ++i )
1445  {
1446  xbv = tempBV-vt*log(cbv/(IRfactor*tSatCur)+1.0-xbv/vt);
1447  xcbv = IRfactor*tSatCur*(exp((tempBV-xbv)/vt)-1.0+xbv/vt);
1448  if(fabs(xcbv-cbv)<=tol) break;
1449  }
1450  }
1451  tBrkdwnV = xbv;
1452  }
1453 #else
1454  if( model_.BVGiven)
1455  {
1456  double IRFactor=tIRF;
1457  double cbv = model_.IBV;
1458  double xbv;
1459  double cthreshlow; //lower threshold for IBV
1460  double cthreshhigh; //high threshold for IBV
1461  int iter_count;
1462  const int ITER_COUNT_MAX=8;
1463  double arg2;
1464 
1465  double arg1=3.0*vte/(CONSTe*tempBV);
1466  arg1=arg1*arg1*arg1;
1467  cthreshlow=tSatCur*IRFactor*(1-arg1);
1468  cthreshhigh=tSatCur*IRFactor*(1-1.0/(CONSTe*CONSTe*CONSTe)) *
1469  exp(-1.0*(3.0*vte-tempBV)/vte);
1470 
1471  if(cbv >= cthreshhigh)
1472  { //if IBV is too high, tBrkdwnV will go below 3NVt.
1473  tBrkdwnV=3.0*vte; //Clip tBrkdwnV to 3*N*Vt in this case (and hence
1474  } //clip IBV to cthreshhigh).
1475 
1476 
1477  else if(cbv <= cthreshlow)
1478  { //if IBV is too low, tBrkdwnV will go above
1479  tBrkdwnV=tempBV; //BV. Clip tBrkdwnV to BV in this case (and
1480  } //hence clip IBV to cthreshlow).
1481 
1482 
1483  //If IBV is in an acceptable range, perform a Picard iteration to find
1484  //tBrkdwnV, starting with an initial guess of tBrkdwnV=tempBV, and
1485  //running through the iteration ITER_COUNT_MAX times.
1486 
1487  else
1488  {
1489  xbv=tempBV;
1490  for(iter_count=0; iter_count < ITER_COUNT_MAX; iter_count++)
1491  {
1492  arg2=3.0*vte/(CONSTe*xbv);
1493  arg2=arg2*arg2*arg2;
1494  xbv=tempBV-vte*log(cbv/(tSatCur*IRFactor))+vte *
1495  log(1-arg2);
1496  }
1497  tBrkdwnV=xbv;
1498  }
1499 
1500 //Note that, not only is tBrkdwnV adjusted using this method, but the effective
1501 //value of Is (tSatCur) is adjusted as well. The code used to use Is before,
1502 //but now it will use Is*IRFactor*(1-(3*N*Vt/(e*tBrkdwnV))^3) instead. This is
1503 //reflected in changes made to Instance::updateIntermediateVars
1504 //(for "normal" level 1 and 2 diode models) for the reverse breakdown region.
1505 //Changes have not been made to the associated LambertW functions as of yet
1506 //since there seem to be other issues involved with those functions independent
1507 // of this change.
1508  }
1509 #endif
1510 
1511 
1512 #ifdef Xyce_DEBUG_DEVICE
1513  if (getDeviceOptions().debugLevel>0 && getSolverState().debugTimeFlag)
1514  {
1515  Xyce::dout() << Xyce::section_divider << std::endl;
1516  Xyce::dout() << "Instance::UpdateTemperature" << getName() <<std::endl;
1517  Xyce::dout() << " IS = " << model_.IS << std::endl;
1518  Xyce::dout() << " vtnom = " << vtnom << std::endl;
1519  Xyce::dout() << " xfc = " << xfc << std::endl;
1520  Xyce::dout() << " TNOM = " << TNOM << std::endl;
1521  Xyce::dout() << " vt = " << vt << std::endl;
1522  Xyce::dout() << " fact2 = " << fact2 << std::endl;
1523  Xyce::dout() << " egfet = " << egfet << std::endl;
1524  Xyce::dout() << " arg = " << arg << std::endl;
1525  Xyce::dout() << " pbfact = " << pbfact << std::endl;
1526  Xyce::dout() << " egfet1 = " << egfet1 << std::endl;
1527  Xyce::dout() << " arg1 = " << arg1 << std::endl;
1528  Xyce::dout() << " fact1 = " << fact1 << std::endl;
1529  Xyce::dout() << " pbfact1 = " << pbfact1 << std::endl;
1530  Xyce::dout() << " pbo = " << pbo << std::endl;
1531  Xyce::dout() << " gmaold = " << gmaold << std::endl;
1532  Xyce::dout() << " gmanew = " << gmanew << std::endl;
1533  Xyce::dout() << " tJctCap = " << tJctCap << std::endl;
1534  Xyce::dout() << " tJctPot = " << tJctPot << std::endl;
1535  Xyce::dout() << " tSatCur = " << tSatCur << std::endl;
1536  Xyce::dout() << " tF1 = " << tF1 << std::endl;
1537  Xyce::dout() << " tDepCap = " << tDepCap << std::endl;
1538  Xyce::dout() << " vte = " << vte << std::endl;
1539  Xyce::dout() << " tempBV = " << tempBV << std::endl;
1540  Xyce::dout() << " tVcrit = " << tVcrit << std::endl;
1541  Xyce::dout() << " tRS = " << tRS << std::endl;
1542  Xyce::dout() << " tCOND = " << tCOND << std::endl;
1543  Xyce::dout() << " tIRF = " << tIRF << std::endl;
1544  Xyce::dout() << " tBrkdwnV= " << tBrkdwnV << std::endl;
1545  }
1546 #endif
1547 
1548  return true;
1549 }
1550 
1551 
1552 //-----------------------------------------------------------------------------
1553 // Function : Instance::lambertWCurrent
1554 // Purpose : Determine the diode current using Lambert-W function
1555 // Special Notes :
1556 // Scope : public
1557 // Creator : Nick Johnson, Summer Intern
1558 // Creation Date : 7/5/02
1559 //-----------------------------------------------------------------------------
1560 bool Instance::lambertWCurrent(double Isat, double Vte, double RS)
1561 {
1562  // with capacitor current and using LambertW accros whole model
1563  /* if (Cd != 0.0 && Icd != 0 && (lambertWFlag == 1))
1564  {
1565  double AA = Vte*(1.0 + RS*getSolverState().pdt*Cd);
1566  double XX = Icd - getSolverState().pdt*Qd;
1567  double arg1 = (Vd + RS*Isat - RS*XX)/AA;
1568  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1569  double evd = exp(arg1);
1570  double lambWArg = Isat*RS/AA * evd;
1571  double lambWReturn;
1572  int ierr;
1573  double lambWError;
1574  devSupport.lambertw(lambWArg, lambWReturn, ierr, lambWError);
1575 
1576  #ifdef Xyce_DEBUG_DEVICE
1577  if (getDeviceOptions().debugLevel > 0)
1578  {
1579  if (ierr == 0)
1580  Xyce::dout() << "Safe LambertW return" << std::endl;
1581  else if (ierr == 1)
1582  Xyce::dout() << "LambertW argument not in domain" << std::endl;
1583  else
1584  Xyce::dout() << "Arithmetic problems with LambertW" << std::endl;
1585  }
1586  #endif
1587 
1588  double prefac = AA/RS;
1589  Id = -Isat + prefac*lambWReturn;
1590  Gd = lambWReturn / ((1 + lambWReturn)*RS);
1591 
1592  #ifdef Xyce_DEBUG_DEVICE
1593  if (getDeviceOptions().debugLevel > 0)
1594  {
1595  Xyce::dout() << "lambWArg = " << lambWArg << std::endl;
1596  Xyce::dout() << "lambWError = " << lambWError << std::endl;
1597  Xyce::dout() << "Id = " << Id << std::endl;
1598  Xyce::dout() << "Gd = " << Gd << std::endl;
1599  Xyce::dout() << "Icd = " << Icd << std::endl;
1600  Xyce::dout() << "Cd = " << Cd << std::endl;
1601  Xyce::dout() << "Qd = " << Qd << std::endl;
1602  Xyce::dout() << "AA = " << AA << std::endl;
1603  Xyce::dout() << "XX = " << XX << std::endl;
1604  Xyce::dout() << "Using lambertwCurrent w/ capacitance" << std::endl;
1605  }
1606  #endif
1607  }
1608 
1609  // when capacitor current=0, there is no capacitance, or using LambertW
1610  // only across the diode element
1611  else
1612  { */
1613  double arg1 = (Vd + Isat*RS)/Vte;
1614  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1615  double evd = exp(arg1);
1616  double lambWArg = Isat*RS*evd/Vte;
1617  double lambWReturn;
1618  int ierr;
1619  double lambWError;
1620  devSupport.lambertw(lambWArg, lambWReturn, ierr, lambWError);
1621 
1622  Id = -Isat+Vte*(lambWReturn)/RS;
1623  Gd = lambWReturn / ((1 + lambWReturn)*RS);
1624 
1625  // }
1626 
1627  return true;
1628 }
1629 
1630 //-----------------------------------------------------------------------------
1631 // Function : Instance::lambertWLinearReverseBias
1632 // Purpose : Function to maintain continuity between forward bias and
1633 // breakdown voltages of diode
1634 // Special Notes :
1635 // Scope : public
1636 // Creator : Nick Johnson, Summer Intern
1637 // Creation Date : 7/30/02
1638 //-----------------------------------------------------------------------------
1639 bool Instance::lambertWLinearReverseBias(double Isat, double Vte, double RS)
1640 {
1641  double FF1 = (Vd + tBrkdwnV)/(-3.0 * Vte + tBrkdwnV);
1642  double FF2 = (1/2 - FF1)*(-2);
1643  double arg = Vte/RS;
1644  double arg1 = (Isat/arg - 3);
1645  double arg2 = FF1*arg1;
1646  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg2);
1647  double evd = exp(arg2);
1648  double lambWArg = Isat*evd/arg;
1649  double lambWReturn;
1650  int ierr;
1651  double lambWError;
1652  devSupport.lambertw(lambWArg, lambWReturn, ierr, lambWError);
1653 
1654 #ifdef Xyce_DEBUG_DEVICE
1655  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1656  {
1657  if (ierr == 0)
1658  Xyce::dout() << "Safe LambertW return" << std::endl;
1659  else if (ierr == 1)
1660  Xyce::dout() << "LambertW argument not in domain" << std::endl;
1661  else
1662  Xyce::dout() << "Arithmetic problems with LambertW" << std::endl;
1663  }
1664 #endif
1665 
1666  Id = -Isat*FF1 + FF2*lambWReturn*arg;
1667 
1668  double GdFF1 = 1/(-3.0*Vte + tBrkdwnV);
1669  double GdFF2 = 2 * GdFF1;
1670  double GdW = arg*lambWReturn*GdFF1*arg1/(1 + lambWReturn);
1671  Gd = -Isat*GdFF1 + GdFF2*arg*lambWReturn + FF2*GdW;
1672 
1673 #ifdef Xyce_DEBUG_DEVICE
1675  {
1676  Xyce::dout() << "lambWArg = " << lambWArg << std::endl;
1677  Xyce::dout() << "lambWError = " << lambWError << std::endl;
1678  Xyce::dout() << "lambWReturn= " << lambWReturn << std::endl;
1679  Xyce::dout() << "Id = " << Id << std::endl;
1680  Xyce::dout() << "Gd = " << Gd << std::endl;
1681  Xyce::dout() << "Using lambertwReverseBias" << std::endl;
1682  }
1683 #endif
1684 
1685  return true;
1686 }
1687 
1688 //-----------------------------------------------------------------------------
1689 // Function : Instance::lambertWBreakdownCurrent
1690 // Purpose : Determine the diode breakdown current using Lambert-W function
1691 // Special Notes :
1692 // Scope : public
1693 // Creator : Nick Johnson, Summer Intern
1694 // Creation Date : 7/11/02
1695 //-----------------------------------------------------------------------------
1696 bool Instance::lambertWBreakdownCurrent(double Isat, double Vte, double RS)
1697 {
1698  // with capacitor current and applying LambertW accros whole diode model
1699  /* if (Cd != 0.0 && Icd != 0 && (lambertWFlag == 1))
1700  {
1701  double AA = Vte*(1 + RS*getSolverState().pdt*Cd);
1702  double XX = Icd - getSolverState().pdt*Qd;
1703  double arg1 = (RS*XX - Vd)/AA - tBrkdwnV/Vte;
1704  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1705  double evd = exp(arg1);
1706  double lambWArg = Isat*RS*evd/AA;
1707  double lambWReturn;
1708  int ierr;
1709  double lambWError;
1710  devSupport.lambertw(lambWArg, lambWReturn, ierr, lambWError);
1711 
1712  #ifdef Xyce_DEBUG_DEVICE
1713  if (getDeviceOptions().debugLevel > 0)
1714  {
1715  if (ierr == 0)
1716  Xyce::dout() << "Safe LambertW return" << std::endl;
1717  else if (ierr == 1)
1718  Xyce::dout() << "LambertW argument not in domain" << std::endl;
1719  else
1720  Xyce::dout() << "Arithmetic problems with LambertW" << std::endl;
1721  }
1722  #endif
1723 
1724  Id = -AA*lambWReturn/RS;
1725  Gd = (lambWReturn / (1 + lambWReturn)) * (1/RS);
1726 
1727  #ifdef Xyce_DEBUG_DEVICE
1728  if (getDeviceOptions().debugLevel > 0)
1729  {
1730  Xyce::dout() << "lambWArg = " << lambWArg << std::endl;
1731  Xyce::dout() << "lambWError = " << lambWError << std::endl;
1732  Xyce::dout() << "Id = " << Id << std::endl;
1733  Xyce::dout() << "Gd = " << Gd << std::endl;
1734  Xyce::dout() << "Icd = " << Icd << std::endl;
1735  Xyce::dout() << "Cd = " << Cd << std::endl;
1736  Xyce::dout() << "Qd = " << Qd << std::endl;
1737  Xyce::dout() << "AA = " << AA << std::endl;
1738  Xyce::dout() << "XX = " << XX << std::endl;
1739  Xyce::dout() << "Using lambertwBreakdown w/ capacitance" << std::endl;
1740  }
1741  #endif
1742  }
1743 
1744  // without capacitor current or applying lambertW just accros diode element
1745  else
1746  {*/
1747  double arg1 = (-Vd - tBrkdwnV)/ Vte;
1748  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1749  double evd = exp(arg1);
1750  double lambWArg = Isat*RS*evd/Vte;
1751  double lambWReturn;
1752  int ierr;
1753  double lambWError;
1754  devSupport.lambertw(lambWArg, lambWReturn, ierr, lambWError);
1755 
1756  Id = -Vte*lambWReturn/RS;
1757  Gd = lambWReturn / ((1 + lambWReturn)*RS);
1758 
1759  // }
1760 
1761  return true;
1762 }
1763 
1764 //-----------------------------------------------------------------------------
1765 // Function : Model::processParams
1766 // Purpose :
1767 // Special Notes :
1768 // Scope : public
1769 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1770 // Creation Date : 6/03/02
1771 //-----------------------------------------------------------------------------
1773 {
1774  //limit grading coeff
1775  if( M > 0.9 ) M = 0.9;
1776 
1777  //limit activation energy
1778  if( EG < 0.1 ) EG = 0.1;
1779 
1780  //limit depl cap coeff
1781  if( FC > 0.95 ) FC = 0.95;
1782 
1783  if( RS==0.0 )
1784  COND = 0.0;
1785  else
1786  COND = 1.0/RS;
1787 
1788  double xfc = log(1.0-FC);
1789  F2 = exp((1.0+M)*xfc);
1790  F3 = 1.0-FC*(1.0+M);
1791 
1792  return true;
1793 }
1794 
1795 //----------------------------------------------------------------------------
1796 // Function : Model::processInstanceParams
1797 // Purpose :
1798 // Special Notes :
1799 // Scope : public
1800 // Creator : Dave Shirely, PSSI
1801 // Creation Date : 03/23/06
1802 //----------------------------------------------------------------------------
1804 {
1805 
1806  std::vector<Instance*>::iterator iter;
1807  std::vector<Instance*>::iterator first = instanceContainer.begin();
1808  std::vector<Instance*>::iterator last = instanceContainer.end();
1809 
1810  for (iter=first; iter!=last; ++iter)
1811  {
1812  (*iter)->processParams();
1813  }
1814 
1815  return true;
1816 }
1817 
1818 //-----------------------------------------------------------------------------
1819 // Function : Model::Model
1820 // Purpose : model block constructor
1821 // Special Notes :
1822 // Scope : public
1823 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1824 // Creation Date : 3/16/00
1825 //-----------------------------------------------------------------------------
1827  const Configuration & configuration,
1828  const ModelBlock & MB,
1829  const FactoryBlock & factory_block)
1830  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
1831  IS(1.0e-14),
1832  RS(0.0),
1833  COND(0.0),
1834  N(1.0),
1835  ISR(0.0),
1836  NR(2.0),
1837  IKF(0.0),
1838  TT(0.0),
1839  CJO(0.0),
1840  VJ(1.0),
1841  M(0.5),
1842  EG(1.11),
1843  XTI(3.0),
1844  TIKF(0.0),
1845  TBV1(0.0),
1846  TBV2(0.0),
1847  TRS1(0.0),
1848  TRS2(0.0),
1849  FC(0.5),
1850  BV(1e99),
1851  IBV(1.0e-10),
1852  IRF(1.0),
1853  NBV(1.0),
1854  IBVL(0.0),
1855  NBVL(1.0),
1856  F2(0.0),
1857  F3(0.0),
1858  TNOM(27),
1859  KF(0.0),
1860  AF(1.0),
1861  BVGiven(false)
1862 {
1863 
1864  // Set params to constant default values:
1865  setDefaultParams ();
1866 
1867  // Set params according to .model line and constant defaults from metadata:
1868  setModParams (MB.params);
1869 
1870  // Set any non-constant parameter defaults:
1871  if (!given("TNOM"))
1873 
1874  // Calculate any parameters specified as expressions:
1876 
1877  // calculate dependent (ie computed) params and check for errors:
1878 
1879  // Note: Level 2 only params are: ISR, NR, IKF, NBV, IBVL, NBVL, TIKF, TBV1, TBV2, TRS1, TRS2
1880  if (getLevel() == 1)
1881  {
1882  std::string bad_parameters;
1883 
1884  if (given("ISR"))
1885  bad_parameters += " ISR";
1886  if (given("NR"))
1887  bad_parameters += " NR";
1888  if (given("IKF"))
1889  bad_parameters += " IKF";
1890  if (given("NBV"))
1891  bad_parameters += " NBV";
1892  if (given("IBVL"))
1893  bad_parameters += " IBVL";
1894  if (given("NBVL"))
1895  bad_parameters += " NBVL";
1896  if (given("TIKF"))
1897  bad_parameters += " TIKF";
1898  if (given("TBV1"))
1899  bad_parameters += " TBV1";
1900  if (given("TBV2"))
1901  bad_parameters += " TBV2";
1902  if (given("TRS1"))
1903  bad_parameters += " TRS1";
1904  if (given("TRS2"))
1905  bad_parameters += " TRS2";
1906  if (!bad_parameters.empty())
1907  {
1908  UserError0(*this) << "Illegal parameter(s) given for level 1 diode:" << bad_parameters;
1909  }
1910  }
1911 
1912  processParams ();
1913 }
1914 
1915 
1916 //-----------------------------------------------------------------------------
1917 // Function : Model::~Model
1918 // Purpose : destructor
1919 // Special Notes :
1920 // Scope : public
1921 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1922 // Creation Date : 3/16/00
1923 //-----------------------------------------------------------------------------
1925 {
1926  std::vector<Instance*>::iterator iterI;
1927  std::vector<Instance*>::iterator firstI = instanceContainer.begin ();
1928  std::vector<Instance*>::iterator lastI = instanceContainer.end ();
1929 
1930  // loop over instances:
1931  for (iterI = firstI; iterI != lastI; ++iterI)
1932  {
1933  delete (*iterI);
1934  }
1935 }
1936 
1937 //-----------------------------------------------------------------------------
1938 // Function : Model::printOutInstances
1939 // Purpose : debugging tool.
1940 // Special Notes :
1941 // Scope : public
1942 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1943 // Creation Date : 4/03/00
1944 //-----------------------------------------------------------------------------
1945 
1946 std::ostream &Model::printOutInstances(std::ostream &os) const
1947 {
1948  std::vector<Instance*>::const_iterator iter;
1949  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1950  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1951 
1952  int i;
1953  os << std::endl;
1954  os << " name model name Parameters" << std::endl;
1955  for (i=0, iter=first; iter!=last; ++iter, ++i)
1956  {
1957  os << " " << i << ": " << (*iter)->getName() << " ";
1958  os << getName();
1959 
1960  os << std::endl;
1961  os << "AREA = " << (*iter)->Area << std::endl;
1962  os << " IC = " << (*iter)->InitCond << std::endl;
1963  os << "TEMP = " << (*iter)->Temp << std::endl;
1964  os << " off = " << (*iter)->off << std::endl;
1965 
1966  os << std::endl;
1967  }
1968 
1969  os << std::endl;
1970 
1971  return os;
1972 }
1973 
1974 //-----------------------------------------------------------------------------
1975 // Function : Model::forEachInstance
1976 // Purpose :
1977 // Special Notes :
1978 // Scope : public
1979 // Creator : David Baur
1980 // Creation Date : 2/4/2014
1981 //-----------------------------------------------------------------------------
1982 /// Apply a device instance "op" to all instances associated with this
1983 /// model
1984 ///
1985 /// @param[in] op Operator to apply to all instances.
1986 ///
1987 ///
1988 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1989 {
1990  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1991  op(*it);
1992 }
1993 
1994 
1995 //-----------------------------------------------------------------------------
1996 // Diode Master functions:
1997 //-----------------------------------------------------------------------------
1998 
1999 //-----------------------------------------------------------------------------
2000 // Function : Master::updateState
2001 // Purpose :
2002 // Special Notes :
2003 // Scope : public
2004 // Creator : Eric Keiter, SNL
2005 // Creation Date : 11/26/08
2006 //-----------------------------------------------------------------------------
2007 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
2008 {
2009  bool bsuccess = true;
2010 
2011  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
2012  {
2013  Instance & di = *(*it);
2014 
2015  // save voltage drops
2016  double * stoVec = di.extData.nextStoVectorRawPtr;
2017  stoVec[di.li_storevd] = di.Vd;
2018 
2019  bool btmp = di.updateIntermediateVars ();
2020  bsuccess = bsuccess && btmp;
2021  }
2022 
2023  return bsuccess;
2024 }
2025 
2026 //-----------------------------------------------------------------------------
2027 // Function : Master::loadDAEVectors
2028 // Purpose :
2029 // Special Notes :
2030 // Scope : public
2031 // Creator : Eric Keiter, SNL
2032 // Creation Date : 11/26/08
2033 //-----------------------------------------------------------------------------
2034 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * storeLeadF, double * storeLeadQ)
2035 {
2036  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
2037  {
2038  Instance & di = *(*it);
2039  // load F:
2040  double Ir = di.Gspr * (di.Vp - di.Vpp);
2041 
2042  fVec[di.li_Pos] -= -Ir;
2043  fVec[di.li_Neg] -= di.Id;
2044  fVec[di.li_Pri] -= (-di.Id + Ir);
2045 
2046  // load Q:
2047  qVec[di.li_Neg] -= di.Qd;
2048  qVec[di.li_Pri] -= -di.Qd;
2049 
2050  // voltage limiter vectors.
2052  {
2053  double Vd_diff = di.Vd - di.Vd_orig;
2054  double Cd_Jdxp = -( di.Cd ) * Vd_diff;
2055  double Gd_Jdxp = -( di.Gd ) * Vd_diff;
2056 
2057  double * dFdxdVp = di.extData.dFdxdVpVectorRawPtr;
2058  // dFdxdVp vector
2059  dFdxdVp[di.li_Neg] += Gd_Jdxp;
2060  dFdxdVp[di.li_Pri] -= Gd_Jdxp;
2061 
2062  double * dQdxdVp = di.extData.dQdxdVpVectorRawPtr;
2063  // dQdxdVp vector
2064  dQdxdVp[di.li_Neg] += Cd_Jdxp;
2065  dQdxdVp[di.li_Pri] -= Cd_Jdxp;
2066  }
2067 
2068  if( di.loadLeadCurrent )
2069  {
2070  storeLeadF[di.li_store_dev_i] = di.Id;
2071  if (di.model_.CJO != 0.0)
2072  {
2073  storeLeadQ[di.li_store_dev_i] = di.Qd;
2074  }
2075  }
2076  }
2077  return true;
2078 }
2079 
2080 //-----------------------------------------------------------------------------
2081 // Function : Master::loadDAEMatrices
2082 // Purpose :
2083 // Special Notes :
2084 // Scope : public
2085 // Creator : Eric Keiter, SNL
2086 // Creation Date : 11/26/08
2087 //-----------------------------------------------------------------------------
2088 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
2089 {
2090  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
2091  {
2092  Instance & di = *(*it);
2093 
2094 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
2095  // F-matrix:
2096  *di.fPosEquPosNodePtr += di.Gspr;
2097  *di.fPosEquPriNodePtr -= di.Gspr;
2098  *di.fNegEquNegNodePtr += di.Gd;
2099  *di.fNegEquPriNodePtr -= di.Gd;
2100  *di.fPriEquPosNodePtr -= di.Gspr;
2101  *di.fPriEquNegNodePtr -= di.Gd;
2102  *di.fPriEquPriNodePtr += di.Gspr + di.Gd;
2103 
2104  // Q-matrix:
2105  *di.qNegEquNegNodePtr += di.Cd;
2106  *di.qNegEquPriNodePtr -= di.Cd;
2107  *di.qPriEquNegNodePtr -= di.Cd;
2108  *di.qPriEquPriNodePtr += di.Cd;
2109 #else
2110  // F-matrix:
2111  dFdx[di.li_Pos][di.APosEquPosNodeOffset] += di.Gspr;
2112  dFdx[di.li_Pos][di.APosEquPriNodeOffset] -= di.Gspr;
2113  dFdx[di.li_Neg][di.ANegEquNegNodeOffset] += di.Gd;
2114  dFdx[di.li_Neg][di.ANegEquPriNodeOffset] -= di.Gd;
2115  dFdx[di.li_Pri][di.APriEquPosNodeOffset] -= di.Gspr;
2116  dFdx[di.li_Pri][di.APriEquNegNodeOffset] -= di.Gd;
2117  dFdx[di.li_Pri][di.APriEquPriNodeOffset] += di.Gspr + di.Gd;
2118 
2119  // Q-matrix:
2120  dQdx[di.li_Neg][di.ANegEquNegNodeOffset] += di.Cd;
2121  dQdx[di.li_Neg][di.ANegEquPriNodeOffset] -= di.Cd;
2122  dQdx[di.li_Pri][di.APriEquNegNodeOffset] -= di.Cd;
2123  dQdx[di.li_Pri][di.APriEquPriNodeOffset] += di.Cd;
2124 #endif
2125  }
2126  return true;
2127 }
2128 
2129 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
2130 {
2131 
2132  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
2133 }
2134 
2136 {
2138  .registerDevice("d", 1)
2139  .registerDevice("d", 2)
2140  .registerModelType("d", 1)
2141  .registerModelType("d", 2);
2142 }
2143 
2144 } // namespace Diode
2145 } // namespace Device
2146 } // namespace Xyce