Xyce  6.1
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-2015 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.322 $
40 //
41 // Revision Date : $Date: 2015/09/09 19:26:08 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 #include <Xyce_config.h>
46 
47 // ---------- Standard Includes ----------
48 #include <N_UTL_Math.h>
49 
50 // ---------- Xyce Includes ----------
51 #include <N_DEV_Const.h>
52 #include <N_DEV_DeviceOptions.h>
53 #include <N_DEV_Diode.h>
54 #include <N_DEV_ExternData.h>
55 #include <N_DEV_MatrixLoadData.h>
56 #include <N_DEV_SolverState.h>
57 #include <N_DEV_Message.h>
58 #include <N_ERH_ErrorMgr.h>
59 
60 #include <N_LAS_Matrix.h>
61 #include <N_LAS_Vector.h>
62 #include <N_UTL_FeatureTest.h>
63 #include <N_UTL_ExtendedString.h>
64 #include <N_ANP_NoiseData.h>
65 
66 namespace Xyce {
67 namespace Device {
68 namespace Diode {
69 
71 {
72  p.addPar ("AREA", 1.0, &Diode::Instance::Area)
73  .setCategory(CAT_GEOMETRY)
74  .setDescription("Area scaling value (scales IS, ISR, IKF, RS, CJ0, and IBV)");
75 
76  p.addPar ("IC", 0.0, &Diode::Instance::InitCond)
77  .setGivenMember(&Diode::Instance::InitCondGiven)
78  .setCategory(CAT_NONE);
79 
80  p.addPar ("TEMP", 0.0, &Diode::Instance::Temp)
81  .setExpressionAccess(ParameterType::TIME_DEP)
82  .setDescription("Device temperature");
83 
84  p.addPar ("OFF", 0, &Diode::Instance::off)
85  .setUnit(U_LOGIC)
86  .setCategory(CAT_CONTROL)
87  .setDescription("Initial voltage drop across device set to zero");
88  p.addPar ("LAMBERTW", 0, &Diode::Instance::lambertWFlag)
89  .setUnit(U_LOGIC)
90  .setCategory(CAT_CONTROL)
91  .setDescription("Option to solve diode equations with the Lambert-W function");
92 }
93 
95 {
96  p.addPar ("IS", 1.0e-14, &Diode::Model::IS)
97  .setUnit(U_AMP)
98  .setCategory(CAT_CURRENT)
99  .setDescription("Saturation current")
100  .setAnalyticSensitivityAvailable(true)
101  .setSensitivityFunctor(&diodeSens);
102 
103  // synonym for IS
104  p.addPar ("JS", 1.0e-14, &Diode::Model::IS)
105  .setUnit(U_AMP)
106  .setCategory(CAT_CURRENT)
107  .setDescription("Saturation current")
108  .setAnalyticSensitivityAvailable(true)
109  .setSensitivityFunctor(&diodeSens);
110 
111  p.addPar ("RS", 0.0, &Diode::Model::RS)
112  .setExpressionAccess(ParameterType::MIN_RES)
113  .setUnit(U_OHM)
114  .setCategory(CAT_RES)
115  .setDescription("Parasitic resistance")
116  .setAnalyticSensitivityAvailable(true)
117  .setSensitivityFunctor(&diodeSens);
118 
119  p.addPar ("N", 1.0, &Diode::Model::N)
120  .setCategory(CAT_PROCESS)
121  .setOriginalValueStored(true)
122  .setDescription("Emission coefficient")
123  .setAnalyticSensitivityAvailable(true)
124  .setSensitivityFunctor(&diodeSens);
125 
126  p.addPar ("ISR", 0.0, &Diode::Model::ISR)
127  .setUnit(U_AMP)
128  .setCategory(CAT_CURRENT)
129  .setDescription("Recombination current parameter (level 2)")
130  .setAnalyticSensitivityAvailable(true)
131  .setSensitivityFunctor(&diodeSens);
132 
133  p.addPar ("NR", 2.0, &Diode::Model::NR)
134  .setCategory(CAT_NONE)
135  .setDescription("Emission coefficient for ISR (level 2)")
136  .setAnalyticSensitivityAvailable(true)
137  .setSensitivityFunctor(&diodeSens);
138 
139  p.addPar ("IKF", 0.0, &Diode::Model::IKF)
140  .setUnit(U_AMP)
141  .setCategory(CAT_CURRENT)
142  .setDescription("High-injection \"knee\" current (level 2)")
143  .setAnalyticSensitivityAvailable(true)
144  .setSensitivityFunctor(&diodeSens);
145 
146  p.addPar ("TT", 0.0, &Diode::Model::TT)
147  .setUnit(U_SECOND)
148  .setCategory(CAT_PROCESS)
149  .setDescription("Transit time")
150  .setAnalyticSensitivityAvailable(true)
151  .setSensitivityFunctor(&diodeSens);
152 
153  p.addPar ("CJO", 0.0, &Diode::Model::CJO)
154  .setExpressionAccess(ParameterType::MIN_CAP)
155  .setUnit(U_FARAD)
156  .setCategory(CAT_CAP)
157  .setDescription("Zero-bias p-n depletion capacitance")
158  .setAnalyticSensitivityAvailable(true)
159  .setSensitivityFunctor(&diodeSens);
160 
161  // synonyms for CJO
162  p.addPar ("CJ", 0.0, &Diode::Model::CJO)
163  .setExpressionAccess(ParameterType::MIN_CAP)
164  .setUnit(U_FARAD)
165  .setCategory(CAT_CAP)
166  .setDescription("Zero-bias p-n depletion capacitance")
167  .setAnalyticSensitivityAvailable(true)
168  .setSensitivityFunctor(&diodeSens);
169 
170  p.addPar ("CJ0", 0.0, &Diode::Model::CJO)
171  .setExpressionAccess(ParameterType::MIN_CAP)
172  .setUnit(U_FARAD)
173  .setCategory(CAT_CAP)
174  .setDescription("Zero-bias p-n depletion capacitance")
175  .setAnalyticSensitivityAvailable(true)
176  .setSensitivityFunctor(&diodeSens);
177 
178  p.addPar ("VJ", 1.0, &Diode::Model::VJ)
179  .setUnit(U_VOLT)
180  .setCategory(CAT_VOLT)
181  .setDescription("Potential for p-n junction")
182  .setAnalyticSensitivityAvailable(true)
183  .setSensitivityFunctor(&diodeSens);
184 
185  p.addPar ("M", 0.5, &Diode::Model::M)
186  .setCategory(CAT_PROCESS)
187  .setDescription("Grading parameter for p-n junction")
188  .setAnalyticSensitivityAvailable(true)
189  .setSensitivityFunctor(&diodeSens);
190 
191  p.addPar ("EG", 1.11, &Diode::Model::EG)
192  .setUnit(U_EV)
193  .setCategory(CAT_PROCESS)
194  .setDescription("Bandgap voltage (barrier height)")
195  .setAnalyticSensitivityAvailable(true)
196  .setSensitivityFunctor(&diodeSens);
197 
198  p.addPar ("XTI", 3.0, &Diode::Model::XTI)
199  .setCategory(CAT_TEMP)
200  .setDescription("IS temperature exponent")
201  .setAnalyticSensitivityAvailable(true)
202  .setSensitivityFunctor(&diodeSens);
203 
204  p.addPar ("TIKF", 0.0, &Diode::Model::TIKF)
205  .setUnit(U_DEGCM1)
206  .setCategory(CAT_TEMP)
207  .setDescription("IKF temperature coefficient (linear) (level 2)")
208  .setAnalyticSensitivityAvailable(true)
209  .setSensitivityFunctor(&diodeSens);
210 ////
211  p.addPar ("TBV1", 0.0, &Diode::Model::TBV1)
212  .setUnit(U_DEGCM1)
213  .setCategory(CAT_TEMP)
214  .setDescription("BV temperature coefficient (linear) (level 2)");
215 
216  p.addPar ("TBV2", 0.0, &Diode::Model::TBV2)
217  .setUnit(U_DEGCM2)
218  .setCategory(CAT_TEMP)
219  .setDescription("BV temperature coefficient (quadratic) (level 2)");
220 
221  p.addPar ("TRS1", 0.0, &Diode::Model::TRS1)
222  .setUnit(U_DEGCM1)
223  .setCategory(CAT_TEMP)
224  .setDescription("RS temperature coefficient (linear) (level 2)");
225 
226  p.addPar ("TRS2", 0.0, &Diode::Model::TRS2)
227  .setUnit(U_DEGCM2)
228  .setCategory(CAT_TEMP)
229  .setDescription("RS temperature coefficient (quadratic) (level 2)");
230 ////
231  p.addPar ("FC", 0.5, &Diode::Model::FC)
232  .setCategory(CAT_CAP)
233  .setDescription("Forward-bias depletion capacitance coefficient")
234  .setAnalyticSensitivityAvailable(true)
235  .setSensitivityFunctor(&diodeSens);
236 
237  p.addPar ("BV", 1E99, &Diode::Model::BV)
238  .setGivenMember(&Diode::Model::BVGiven)
239  .setUnit(U_VOLT)
240  .setCategory(CAT_VOLT)
241  .setDescription("Reverse breakdown \"knee\" voltage")
242  .setAnalyticSensitivityAvailable(true)
243  .setSensitivityFunctor(&diodeSens);
244 
245  // synonym for BV
246  p.addPar ("VB", 1E99, &Diode::Model::BV)
247  .setGivenMember(&Diode::Model::BVGiven)
248  .setUnit(U_VOLT)
249  .setCategory(CAT_VOLT)
250  .setDescription("Reverse breakdown \"knee\" voltage")
251  .setAnalyticSensitivityAvailable(true)
252  .setSensitivityFunctor(&diodeSens);
253 
254  p.addPar ("IBV", 1.0e-3, &Diode::Model::IBV)
255  .setUnit(U_AMP)
256  .setCategory(CAT_CURRENT)
257  .setDescription("Reverse breakdown \"knee\" current")
258  .setAnalyticSensitivityAvailable(true)
259  .setSensitivityFunctor(&diodeSens);
260 
261  p.addPar ("IRF", 1.0, &Diode::Model::IRF)
262  .setCategory(CAT_CURRENT)
263  .setDescription("Reverse current fitting factor")
264  .setAnalyticSensitivityAvailable(true)
265  .setSensitivityFunctor(&diodeSens);
266 
267  p.addPar ("NBV", 1.0, &Diode::Model::NBV)
268  .setCategory(CAT_PROCESS)
269  .setDescription("Reverse breakdown ideality factor (level 2)")
270  .setAnalyticSensitivityAvailable(true)
271  .setSensitivityFunctor(&diodeSens);
272 
273  p.addPar ("IBVL", 0.0, &Diode::Model::IBVL)
274  .setUnit(U_AMP)
275  .setCategory(CAT_CURRENT)
276  .setDescription("Low-level reverse breakdown \"knee\" current (level 2)")
277  .setAnalyticSensitivityAvailable(true)
278  .setSensitivityFunctor(&diodeSens);
279 
280  p.addPar ("NBVL", 1.0, &Diode::Model::NBVL)
281  .setCategory(CAT_PROCESS)
282  .setDescription("Low-level reverse breakdown ideality factor (level 2)")
283  .setAnalyticSensitivityAvailable(true)
284  .setSensitivityFunctor(&diodeSens);
285 
286  p.addPar ("TNOM", 0.0, &Diode::Model::TNOM)
287  .setCategory(CAT_NONE)
288  .setDescription("")
289  .setAnalyticSensitivityAvailable(true)
290  .setSensitivityFunctor(&diodeSens);
291 
292  p.addPar ("KF", 0.0, &Diode::Model::KF)
293  .setCategory(CAT_FLICKER)
294  .setDescription("Flicker noise coefficient")
295  .setAnalyticSensitivityAvailable(true)
296  .setSensitivityFunctor(&diodeSens);
297 
298  p.addPar ("AF", 1.0, &Diode::Model::AF)
299  .setCategory(CAT_FLICKER)
300  .setDescription("Flicker noise exponent")
301  .setAnalyticSensitivityAvailable(true)
302  .setSensitivityFunctor(&diodeSens);
303 }
304 
305 
306 
307 std::vector< std::vector<int> > Instance::jacStamp_RS;
308 std::vector< std::vector<int> > Instance::jacStamp;
309 
310 std::vector<int> Instance::jacMap_RS;
311 std::vector<int> Instance::jacMap;
312 
313 std::vector< std::vector<int> > Instance::jacMap2_RS;
314 std::vector< std::vector<int> > Instance::jacMap2;
315 
316 //-----------------------------------------------------------------------------
317 // Function : Instance::processParams
318 // Purpose :
319 // Special Notes :
320 // Scope : public
321 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
322 // Creation Date : 6/03/02
323 //-----------------------------------------------------------------------------
325 {
326  // Set any non-constant parameter defaults:
327  if (!given("LAMBERTW"))
329  if (!given("TEMP"))
330  Temp = getDeviceOptions().temp.getImmutableValue<double>();
331  if ( (model_.RS == 0.0) && (lambertWFlag == 1) )
332  model_.RS =1.0e-12;
333 
335  return true;
336 }
337 
338 //-----------------------------------------------------------------------------
339 // Function : Instance::Instance
340 // Purpose : "instance block" constructor
341 // Special Notes :
342 // Scope : public
343 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
344 // Creation Date : 3/16/00
345 //-----------------------------------------------------------------------------
347  const Configuration & configuration,
348  const InstanceBlock & instance_block,
349  Model & model,
350  const FactoryBlock & factory_block)
351  : DeviceInstance(instance_block, configuration.getInstanceParameters(), factory_block),
352  model_(model),
353  off(0),
354  Area(1.0),
355  InitCond(0.0),
356  Temp(getDeviceOptions().temp.getImmutableValue<double>()),
357  lambertWFlag(0),
358  InitCondGiven(false),
359  tJctPot(0.0),
360  tJctCap(0.0),
361  tDepCap(0.0),
362  tSatCur(0.0),
363  tVcrit(0.0),
364  tF1(0.0),
365  tBrkdwnV(0.0),
366  tSatCurR(0.0),
367  tIKF(0.0),
368  tRS(0.0),
369  tIRF(1.0),
370  Id(0.0),
371  Gd(0.0),
372  Cd(0.0),
373  Gcd(0.0),
374  Icd(0.0),
375  Qd(0.0),
376  Gspr(0.0),
377  Vpp(0.0),
378  Vp(0.0),
379  Vn(0.0),
380  Vc(0.0),
381  Vd(0.0),
382  Vd_old(0.0),
383  Vd_orig(0.0),
384  li_Pos(-1),
385  li_Neg(-1),
386  li_Pri(-1),
387  APosEquPosNodeOffset(-1),
388  APosEquPriNodeOffset(-1),
389  ANegEquNegNodeOffset(-1),
390  ANegEquPriNodeOffset(-1),
391  APriEquPosNodeOffset(-1),
392  APriEquNegNodeOffset(-1),
393  APriEquPriNodeOffset(-1),
395  fPosEquPosNodePtr(0),
396  fPosEquPriNodePtr(0),
397  fNegEquNegNodePtr(0),
398  fNegEquPriNodePtr(0),
399  fPriEquPosNodePtr(0),
400  fPriEquNegNodePtr(0),
401  fPriEquPriNodePtr(0),
402  qPosEquPosNodePtr(0),
403  qPosEquPriNodePtr(0),
404  qNegEquNegNodePtr(0),
405  qNegEquPriNodePtr(0),
406  qPriEquPosNodePtr(0),
407  qPriEquNegNodePtr(0),
408  qPriEquPriNodePtr(0),
409 #endif
410  li_storevd(-1),
411  li_store_dev_i(-1),
412  li_branch_data(-1)
413 {
414  numIntVars = 1;
415  numExtVars = 2;
416  numStateVars = 0;
417  setNumStoreVars(1);
418  numLeadCurrentStoreVars = 1; // lead current DEV_I
419  setNumBranchDataVars(0); // by default don't allocate space in branch vectors
420  numBranchDataVarsIfAllocated = 1; // this is the space to allocate if lead current or power is needed.
421 
422  if( jacStamp.empty() )
423  {
424  jacStamp_RS.resize(3);
425  jacStamp_RS[0].resize(2);
426  jacStamp_RS[0][0]=0;
427  jacStamp_RS[0][1]=2;
428  jacStamp_RS[1].resize(2);
429  jacStamp_RS[1][0]=1;
430  jacStamp_RS[1][1]=2;
431  jacStamp_RS[2].resize(3);
432  jacStamp_RS[2][0]=0;
433  jacStamp_RS[2][1]=1;
434  jacStamp_RS[2][2]=2;
435 
436  jacMap_RS.clear();
438  jacStamp, jacMap, jacMap2, 2, 0, 3);
439 
440  }
441 
442  // Set params to constant default values:
443  setDefaultParams ();
444 
445  // Set params according to instance line and constant defaults from metadata:
446  setParams (instance_block.params);
447 
448  // Calculate any parameters specified as expressions:
450 
451  // calculate dependent (ie computed) params and check for errors:
452  processParams ();
453 
454  if ( (model_.RS == 0.0) || (lambertWFlag == 1) )
455  numIntVars = 0;
456  if ( model_.CJO == 0.0 )
457  numStateVars = 1;
458 }
459 
460 //-----------------------------------------------------------------------------
461 // Function : Instance::~Instance
462 // Purpose : destructor
463 // Special Notes :
464 // Scope : public
465 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
466 // Creation Date : 3/16/00
467 //-----------------------------------------------------------------------------
469 {
470 }
471 
472 // Additional Declarations
473 //-----------------------------------------------------------------------------
474 // Function : Instance::registerLIDs
475 // Purpose : function for registering, and setting up, local ID's.
476 // Special Notes :
477 // Scope : public
478 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
479 // Creation Date : 6/20/02
480 //-----------------------------------------------------------------------------
481 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
482  const std::vector<int> & extLIDVecRef)
483 {
484  AssertLIDs(intLIDVecRef.size() == numIntVars);
485  AssertLIDs(extLIDVecRef.size() == numExtVars);
486 
487  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
488  {
489  Xyce::dout() << std::endl << section_divider << std::endl;
490  Xyce::dout() << "In Instance::register LIDs\n\n";
491  Xyce::dout() << "name = " << getName() << std::endl;
492  Xyce::dout() << "number of internal variables: " << numIntVars << std::endl;
493  Xyce::dout() << "number of external variables: " << numExtVars << std::endl;
494  }
495 
496  // copy over the global ID lists.
497  intLIDVec = intLIDVecRef;
498  extLIDVec = extLIDVecRef;
499 
500  // Now use these lists to obtain the indices into the linear algebra
501  // entities. This assumes an order.
502 
503  li_Pos = extLIDVec[0];
504  li_Neg = extLIDVec[1];
505 
506  //Setup of Pri node indices
507  //If RS=0, Pri=Pos Node
508  //--------------------------
509  if( model_.RS && (lambertWFlag != 1) )
510  li_Pri = intLIDVec[0];
511  else
512  li_Pri = li_Pos;
513 
514  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
515  {
516  Xyce::dout() << "\nSolution and RHS variables:\n";
517  Xyce::dout() << "\nli_Pos = ";
518  Xyce::dout().width(4);
519  Xyce::dout() << li_Pos << std::endl;
520 
521  Xyce::dout() << "\nli_Neg = ";
522  Xyce::dout().width(4);
523  Xyce::dout() << li_Neg << std::endl;
524 
525  Xyce::dout() << "\nli_Pri = ";
526  Xyce::dout().width(4);
527  Xyce::dout() << li_Pri << std::endl;
528 
529  }
530 
531 
532 
533  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
534  {
535  Xyce::dout() << "\nEnd of Instance::register LIDs\n";
536  Xyce::dout() << section_divider << std::endl;
537  }
538 }
539 
540 //-----------------------------------------------------------------------------
541 // Function : Instance::loadNodeSymbols
542 // Purpose :
543 // Special Notes :
544 // Scope : public
545 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
546 // Creation Date : 05/13/05
547 //-----------------------------------------------------------------------------
548 void Instance::loadNodeSymbols(Util::SymbolTable &symbol_table) const
549 {
550  if (li_Pos != li_Pri)
551  addInternalNode(symbol_table, li_Pri, getName(), "internal");
552 
553  addStoreNode(symbol_table, li_storevd, getName(), "vd");
554 
555  if (loadLeadCurrent)
556  {
557  addStoreNode(symbol_table, li_store_dev_i, getName(), "DEV_I");
558  addBranchDataNode( symbol_table, li_branch_data, getName(), "BRANCH_D");
559  }
560 }
561 
562 //-----------------------------------------------------------------------------
563 // Function : Instance::registerStateLIDs
564 // Purpose :
565 // Special Notes :
566 // Scope : public
567 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
568 // Creation Date : 6/20/02
569 //-----------------------------------------------------------------------------
570 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
571 {
572  AssertLIDs(staLIDVecRef.size() == numStateVars);
573 
574  // copy over the global ID lists:
575  staLIDVec = staLIDVecRef;
576 }
577 
578 //-----------------------------------------------------------------------------
579 // Function : Instance::registerStoreLIDs
580 // Purpose :
581 // Special Notes :
582 // Scope : public
583 // Creator : Eric Keiter
584 // Creation Date :
585 //-----------------------------------------------------------------------------
587  const std::vector<int> & stoLIDVecRef )
588 {
589  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
590 
591 // copy over the global ID lists:
592  stoLIDVec = stoLIDVecRef;
593  li_storevd = stoLIDVec[0];
594  if( loadLeadCurrent )
595  {
596  li_store_dev_i = stoLIDVec[1];
597  }
598 
599  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
600  {
601  Xyce::dout() << "li_storevd = " << li_storevd;
602  }
603 
604 }
605 
606 //-----------------------------------------------------------------------------
607 // Function : Instance::registerBranchDataLIDs
608 // Purpose :
609 // Special Notes :
610 // Scope : public
611 // Creator : Richard Schiek, Electrical Systems Modeling
612 // Creation Date : 12/18/2012
613 //-----------------------------------------------------------------------------
614 /// In addition to state vector, Xyce maintains a separate datastructure
615 /// called a "branch data" vector. As with other such vectors, the device
616 /// declares at construction time how many branch vector entries it needs,
617 /// and later Topology assigns locations for devices, returning LIDs.
618 ///
619 /// These LIDs are stored in this method for later use.
620 ///
621 
622 void Instance::registerBranchDataLIDs(const std::vector<int> & branchLIDVecRef)
623 {
624  AssertLIDs(branchLIDVecRef.size() == getNumBranchDataVars());
625 
626  if (loadLeadCurrent)
627  {
628  li_branch_data= branchLIDVecRef[0];
629  }
630 }
631 
632 
633 //-----------------------------------------------------------------------------
634 // Function : Instance::jacobianStamp
635 // Purpose :
636 // Special Notes :
637 // Scope : public
638 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
639 // Creation Date : 9/2/02
640 //-----------------------------------------------------------------------------
641 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
642 {
643  if( model_.RS && (lambertWFlag != 1) )
644  return jacStamp_RS;
645  else
646  return jacStamp;
647 }
648 
649 //-----------------------------------------------------------------------------
650 // Function : Instance::registerJacLIDs
651 // Purpose :
652 // Special Notes :
653 // Scope : public
654 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
655 // Creation Date : 9/2/02
656 //-----------------------------------------------------------------------------
657 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
658 {
659  DeviceInstance::registerJacLIDs( jacLIDVec );
660  std::vector<int> map;
661  std::vector< std::vector<int> > map2;
662 
663  if( model_.RS && (lambertWFlag != 1) )
664  {
665  map = jacMap_RS;
666  map2 = jacMap2_RS;
667  }
668  else
669  {
670  map = jacMap;
671  map2 = jacMap2;
672  }
673 
674  APosEquPosNodeOffset = jacLIDVec[map[0]][map2[0][0]];
675  APosEquPriNodeOffset = jacLIDVec[map[0]][map2[0][1]];
676 
677  ANegEquNegNodeOffset = jacLIDVec[map[1]][map2[1][0]];
678  ANegEquPriNodeOffset = jacLIDVec[map[1]][map2[1][1]];
679 
680  APriEquPosNodeOffset = jacLIDVec[map[2]][map2[2][0]];
681  APriEquNegNodeOffset = jacLIDVec[map[2]][map2[2][1]];
682  APriEquPriNodeOffset = jacLIDVec[map[2]][map2[2][2]];
683 
684 }
685 
686 //-----------------------------------------------------------------------------
687 // Function : Instance::setupPointers
688 // Purpose :
689 // Special Notes :
690 // Scope : public
691 // Creator : Eric Keiter, SNL
692 // Creation Date : 11/30/08
693 //-----------------------------------------------------------------------------
695 {
696 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
697  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
698  Linear::Matrix & dQdx = *(extData.dQdxMatrixPtr);
699 
707 
715 #endif
716 }
717 
718 //-----------------------------------------------------------------------------
719 // Function : Instance::loadDAEQVector
720 //
721 // Purpose : Loads the Q-vector contributions for a single
722 // diode instance.
723 //
724 // Special Notes : The "Q" vector is part of a standard DAE formalism in
725 // which the system of equations is represented as:
726 //
727 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
728 //
729 // Scope : public
730 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
731 // Creation Date : 01/26/03
732 //-----------------------------------------------------------------------------
734 {
735  // note: the only capacitor goes from the negative to the
736  // positive-prime node, so there is not contribution in this
737  // function to the positive node.
738 
739  // load in the KCL for the negative node:
740  double coef = Qd;
741  (extData.daeQVectorRawPtr)[li_Neg] -= coef;
742 
743  // load in the KCL for the positive prime node:
744  coef *= -1.0; // -Qd
745  (extData.daeQVectorRawPtr)[li_Pri] -= coef;
746 
747  // load the voltage limiter vector.
749  {
750  double Vd_diff = Vd - Vd_orig;
751  double Cd_Jdxp = 0.0;
752  Cd_Jdxp = -( Cd ) * Vd_diff;
753 
754  // Load the dQdxdVp vector
755  (extData.dQdxdVpVectorRawPtr)[li_Neg] += Cd_Jdxp;
756  (extData.dQdxdVpVectorRawPtr)[li_Pri] -= Cd_Jdxp;
757  }
758 
759  if( loadLeadCurrent && (model_.CJO != 0.0))
760  {
763  }
764 
765  return true;
766 }
767 
768 //-----------------------------------------------------------------------------
769 // Function : Instance::loadDAEFVector
770 //
771 // Purpose : Loads the F-vector contributions for a single
772 // diode instance.
773 //
774 // Special Notes :
775 //
776 // Scope : public
777 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
778 // Creation Date : 01/26/03
779 //-----------------------------------------------------------------------------
781 {
782  // 3f5 compatible currents
783  // Including derivation of Vd_diff and Limiting Correction
784  //---------------------------------------------------------
785  double Ir = Gspr * (Vp - Vpp);
786 
787  // load in the KCL for the positive node:
788  double coef = -Ir;
789  (extData.daeFVectorRawPtr)[li_Pos] -= coef;
790 
791  // load in the KCL for the negative node:
792  coef = Id;
793  (extData.daeFVectorRawPtr)[li_Neg] -= coef;
794 
795  // load in the KCL for the positive prime node:
796  coef *= -1;
797  coef += Ir;
798  (extData.daeFVectorRawPtr)[li_Pri] -= coef;
799 
800  // load the voltage limiter vector.
802  {
803  double Vd_diff = Vd - Vd_orig;
804  double Gd_Jdxp = 0.0;
805  Gd_Jdxp = -( Gd ) * Vd_diff;
806 
807  // Load the dFdxdVp vector
808  (extData.dFdxdVpVectorRawPtr)[li_Neg] += Gd_Jdxp;
809  (extData.dFdxdVpVectorRawPtr)[li_Pri] -= Gd_Jdxp;
810  }
811 
812  if( loadLeadCurrent )
813  {
817  }
818 
819  return true;
820 }
821 
822 //-----------------------------------------------------------------------------
823 // Function : Instance::loadDAEdQdx
824 //
825 // Purpose : Loads the Q-vector contributions for a single
826 // diode instance.
827 //
828 // Special Notes : The "Q" vector is part of a standard DAE formalism in
829 // which the system of equations is represented as:
830 //
831 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
832 //
833 // Scope : public
834 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
835 // Creation Date : 03/05/04
836 //-----------------------------------------------------------------------------
838 {
839  Linear::Matrix & dQdx = *(extData.dQdxMatrixPtr);
840 
841 // New Spice3f5 matched conductivities
842 // Only major difference in loads is support for Pos=Pri node when RS=0
843 // For this DAE dQdx load, the capacitance contribution (Gcd) is the
844 // only part used.
845 //---------------------------------------------------------------------
846 
847  dQdx[li_Neg][ANegEquNegNodeOffset] += Cd;
848  dQdx[li_Neg][ANegEquPriNodeOffset] -= Cd;
849 
850  dQdx[li_Pri][APriEquNegNodeOffset] -= Cd;
851  dQdx[li_Pri][APriEquPriNodeOffset] += Cd;
852 
853  return true;
854 }
855 
856 //-----------------------------------------------------------------------------
857 // Function : Instance::loadDAEdFdx ()
858 //
859 // Purpose : Loads the F-vector contributions for a single
860 // diode instance.
861 //
862 // Special Notes :
863 //
864 // Scope : public
865 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
866 // Creation Date : 03/05/04
867 //-----------------------------------------------------------------------------
869 {
870  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
871 
872 // New Spice3f5 matched conductivities
873 // Only major difference in loads is support for Pos=Pri node when RS=0
874 // For this DAE dFdx load, the capacitance contribution (Gcd) is removed.
875 //---------------------------------------------------------------------
876 
877  dFdx[li_Pos][APosEquPosNodeOffset] += Gspr;
878  dFdx[li_Pos][APosEquPriNodeOffset] -= Gspr;
879 
880  dFdx[li_Neg][ANegEquNegNodeOffset] += Gd;
881  dFdx[li_Neg][ANegEquPriNodeOffset] -= Gd;
882 
883  dFdx[li_Pri][APriEquPosNodeOffset] -= Gspr;
884  dFdx[li_Pri][APriEquNegNodeOffset] -= Gd;
885  dFdx[li_Pri][APriEquPriNodeOffset] += Gspr + Gd;
886 
887  return true;
888 }
889 
890 //-----------------------------------------------------------------------------
891 // Function : Instance::updatePrimaryState
892 // Purpose : update primary state for one diode instance
893 // Special Notes :
894 // Scope : public
895 // Creator : Tom Russo, Component Information and Models
896 // Creation Date : 1/10/01
897 //-----------------------------------------------------------------------------
899 {
900  double * stoVec = extData.nextStoVectorRawPtr;
901  bool bsuccess = updateIntermediateVars ();
902  stoVec[li_storevd] = Vd;
903  return bsuccess;
904 }
905 
906 
907 //-----------------------------------------------------------------------------
908 // Function : Xyce::Device::Diode::Instance::getNumNoiseSources
909 // Purpose :
910 // Special Notes :
911 // Scope : public
912 // Creator : Eric Keiter, SNL
913 // Creation Date : 12/27/2014
914 //-----------------------------------------------------------------------------
916 {
917  return 3;
918 }
919 
920 //-----------------------------------------------------------------------------
921 // Function : Xyce::Device::Diode::Instance::setupNoiseSources
922 // Purpose :
923 // Special Notes :
924 // Scope : public
925 // Creator : Eric Keiter
926 // Creation Date :
927 //-----------------------------------------------------------------------------
929 {
930  int numSources=3;
931  noiseData.numSources = numSources;
932  noiseData.resize(numSources);
933 
934  noiseData.deviceName = getName().getEncodedName();
935 
936  noiseData.noiseNames[0] = "onoise_" + getName().getEncodedName()+
937  std::string("_rs"); // noise due to rs
938  noiseData.noiseNames[1] = "onoise_" + getName().getEncodedName()+
939  std::string("_id"); // noise due to id
940  noiseData.noiseNames[2] = "onoise_" + getName().getEncodedName()+
941  std::string("_1overf"); // flicker (1/f) noise
942 
943  noiseData.li_Pos[0] = li_Pri;
944  noiseData.li_Neg[0] = li_Pos;
945 
946  noiseData.li_Pos[1] = li_Pri;
947  noiseData.li_Neg[1] = li_Neg;
948 
949  noiseData.li_Pos[2] = li_Pri;
950  noiseData.li_Neg[2] = li_Neg;
951 }
952 
953 //-----------------------------------------------------------------------------
954 // Function : Xyce::Device::Diode::Instance::getNoiseSources
955 // Purpose :
956 // Special Notes :
957 // Scope : public
958 // Creator : Eric Keiter
959 // Creation Date :
960 //-----------------------------------------------------------------------------
962 {
963  // thermal noise from RS
965  noiseData.noiseDens[0], noiseData.lnNoiseDens[0],
966  THERMNOISE, Gspr, Temp);
967 
968  // shot noise from the diode depletion region
970  noiseData.noiseDens[1], noiseData.lnNoiseDens[1],
971  SHOTNOISE, Id, Temp);
972 
973  // flicker noise
974  noiseData.noiseDens[2] = model_.KF * std::exp(model_.AF * std::log(std::max(fabs(Id),N_MINLOG))) / noiseData.freq;
975  noiseData.lnNoiseDens[2] = std::log(std::max(noiseData.noiseDens[2],N_MINLOG));
976 }
977 
978 //-----------------------------------------------------------------------------
979 // Function : Instance::updateIntermediateVars
980 // Purpose : update intermediate variables for one diode instance
981 // Special Notes :
982 // Scope : public
983 // Creator : Tom Russo, Component Information and Models
984 // Creation Date : 1/10/01
985 //-----------------------------------------------------------------------------
987 {
988  bool bsuccess = true;
989 
990  double * solVec = extData.nextSolVectorRawPtr;
991 
992  //diode parameters
993  double M; // grading parameter
994  double BV; // breakdown voltage
995  double IBV; // reverse breakdown current
996  double NBV; // reverse breakdown ideality factor
997  double IBVL; // low-level reverse breakdown current
998  double NBVL; // low-level reverse breakdown ideality factor
999  double N; // non-ideality factor.
1000  double NR; // emission coeff. for ISR.
1001  double TT; // transit time.
1002  double F2; // capacitive polynomial factor
1003  double F3; // capacitive polynomial factor
1004  double Inorm; // normal diffusion current
1005  double Irec; // recombination current
1006  double Kgen; // generation factor
1007  double Khi; // high-injection factor
1008  double Gd1, DKgen;
1009  double Gd2, DKhi;
1010 
1011  //Model Diode parameters
1012  M = model_.M;
1013  BV = model_.BV;
1014  IBV = model_.IBV;
1015  NBV = model_.NBV;
1016  IBVL = model_.IBVL;
1017  NBVL = model_.NBVL;
1018  N = model_.N;
1019  NR = model_.NR;
1020  TT = model_.TT;
1021  F2 = model_.F2;
1022  F3 = model_.F3;
1023 
1024  // obtain voltage drop accross the capacitor:
1025  Vp = Vn = Vpp = 0.0;
1026  Vpp = solVec[li_Pri];
1027  Vn = solVec[li_Neg];
1028  Vp = solVec[li_Pos];
1029 
1030  // Junction Voltage
1031  Vd = Vpp - Vn;
1032 
1033  double Isat = tSatCur * Area;
1034  double IsatR = tSatCurR * Area;
1035  double Vt = CONSTKoverQ * Temp;
1036  double Vte = N * Vt;
1037  double VteR = NR * Vt;
1038 
1039  Gspr = tCOND * Area;
1040 
1041  Vd_orig = Vd;
1042  origFlag = true;
1043 
1044  // Setup initial junction conditions if UIC enabled
1045  //------------------------------------------------
1046  if (getSolverState().newtonIter == 0)
1047  {
1048  //Vd_old = Vd;
1049  if (getSolverState().initJctFlag_ && getDeviceOptions().voltageLimiterFlag)
1050  {
1051  if (InitCondGiven)
1052  {
1053  Vd = InitCond;
1054  origFlag = false;
1055  }
1056  else if (off)
1057  {
1058  Vd = 0.0;
1059  origFlag = false;
1060  }
1061  else
1062  {
1063  if (getSolverState().inputOPFlag)
1064  {
1065  Linear::Vector * flagSolVectorPtr = extData.flagSolVectorPtr;
1066  if ((*flagSolVectorPtr)[li_Pos] == 0 ||
1067  (*flagSolVectorPtr)[li_Neg] == 0 ||
1068  (*flagSolVectorPtr)[li_Pri] == 0)
1069  {
1070  Vd=tVcrit;
1071  origFlag = false;
1072  }
1073  }
1074  else
1075  {
1076  Vd=tVcrit;
1077  origFlag = false;
1078  }
1079  }
1080  }
1081 
1082  // assume there is no history -- then check if the
1083  // state vector can overwrite this
1084  Vd_old = Vd;
1085 
1086  if (!(getSolverState().dcopFlag)||(getSolverState().locaEnabledFlag && getSolverState().dcopFlag))
1087  {
1089  }
1090  }
1091  else // just do this whenever it isn't the first iteration:
1092  {
1094  }
1095 
1096  // Voltage limiting based on mode of diode
1097  //---------------------------------------
1099  {
1100  int ichk = 0;
1101 
1102  if (getSolverState().newtonIter >= 0)
1103  {
1104  //Test if breakdown voltage given or not
1105  if (model_.BVGiven && (Vd < Xycemin(0.0, -BV + 10.0 * Vte)))
1106  {
1107  double Vdtmp = -( BV + Vd );
1108  Vdtmp = devSupport.pnjlim(Vdtmp, -(Vd_old+BV), Vte, tVcrit, &ichk);
1109  Vd = -(Vdtmp + BV);
1110  }
1111  else
1112  Vd = devSupport.pnjlim(Vd, Vd_old, Vte, tVcrit, &ichk);
1113 
1114  if (ichk) origFlag = false;
1115  }
1116  }
1117 
1118  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1119  {
1120  Xyce::dout() << Xyce::section_divider << std::endl;
1121  Xyce::dout() << "Instance::updateIntermediateVars " << getName()<<std::endl;
1122  }
1123 
1124  // Current and Conductivity
1125  //----------------------------------------------
1126 
1127  int level = model_.getLevel();
1128  if(level == 1)
1129  {
1130  // Using LambertW function
1131  if (lambertWFlag == 1)
1132  {
1133  double RS = model_.RS;
1134  if (Vd >= -3.0 * Vte)
1135  {
1136  lambertWCurrent(Isat, Vte, RS);
1137  }
1138  // linear reverse bias
1139  else if ( !tBrkdwnV || (Vd >= -tBrkdwnV) )
1140  {
1141  lambertWLinearReverseBias(Isat, Vte, RS);
1142  }
1143  // reverse breakdown
1144  else
1145  {
1146  lambertWBreakdownCurrent(Isat, Vte, RS);
1147  }
1148 
1149  double Vrs;
1150  Vrs = (Id + Icd)*RS;
1151  Vc = Vd - Vrs;
1152  }
1153  else if (lambertWFlag == 2)
1154  {
1155  if (Vd >= -3.0 * Vte)
1156  {
1157  lambertWCurrent(Isat, Vte, 1.0e-15);
1158  }
1159  // linear reverse bias
1160  else if ( !tBrkdwnV || (Vd >= -tBrkdwnV) )
1161  {
1162  lambertWLinearReverseBias(Isat, Vte, 1.0e-15);
1163  }
1164  // reverse breakdown
1165  else
1166  {
1167  lambertWBreakdownCurrent(Isat, Vte, 1.0e-15);
1168  }
1169  Vc = Vd;
1170  }
1171 
1172  // Normal exponential
1173  else
1174  {
1175  // Adjustment for linear portion of reverse current
1176  double IRfactor;
1177  //if(Vd >= 0) IRfactor = 1.0; //error? shouldn't this be Vd>=-3*Vte????
1178  if(Vd >= -3.0 * Vte) IRfactor = 1.0; //changing this to be consistent
1179  else IRfactor = tIRF; //with model in reference guide.
1180  Isat *= IRfactor;
1181 
1182  if (Vd >= -3.0 * Vte)
1183  {
1184  double arg1 = Vd / Vte;
1185  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1186  double evd = exp(arg1);
1187 
1188  Id = Isat * (evd - 1.0) + getDeviceOptions().gmin * Vd;
1189  Gd = Isat * evd / Vte + getDeviceOptions().gmin;
1190  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1191  {
1192  Xyce::dout() << "Normal exponential regime." << std::endl;
1193  Xyce::dout() << " Vd = " << Vd << std::endl;
1194  Xyce::dout() << " Vte = " << Vte << std::endl;
1195  Xyce::dout() << " Id = " << Id << std::endl;
1196  Xyce::dout() << " Gd = " << Gd << std::endl;
1197  }
1198 
1199  }
1200 
1201  // Linear reverse bias
1202  else if(!tBrkdwnV || (Vd >= -tBrkdwnV))
1203  {
1204  double arg = 3.0 * Vte / (Vd * CONSTe);
1205  arg = arg * arg * arg;
1206  Id = -Isat * (1.0 + arg) + getDeviceOptions().gmin * Vd;
1207  Gd = Isat * 3.0 * arg / Vd + getDeviceOptions().gmin;
1208  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1209  {
1210  Xyce::dout() << "Linear reverse bias regime." << std::endl;
1211  Xyce::dout() << " Vd = " << Vd << std::endl;
1212  Xyce::dout() << " tBrkdwnV = " << tBrkdwnV << std::endl;
1213  Xyce::dout() << " Id = " << Id << std::endl;
1214  Xyce::dout() << " Gd = " << Gd << std::endl;
1215  }
1216  }
1217 
1218  // Reverse breakdown
1219  else
1220  {
1221  double arg1 = -(tBrkdwnV + Vd) / Vte;
1222  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1223  double evrev = exp(arg1);
1224 
1225 #ifdef Xyce_BREAKDOWN_ORIGINAL
1226  Id = -Isat * evrev + getDeviceOptions().gmin * Vd;
1227  Gd = Isat * evrev / Vte + getDeviceOptions().gmin;
1228 #else
1229  //added by K. Santarelli 9/18/07 to account for change in tBrkdwnV
1230  //calculation.
1231  double arg2=3.0*Vte/(CONSTe*tBrkdwnV);
1232  arg2=arg2*arg2*arg2;
1233  double Isat_tBrkdwnV=Isat*(1-arg2);
1234  Id = -Isat_tBrkdwnV * evrev + getDeviceOptions().gmin * Vd;
1235  Gd = Isat_tBrkdwnV * evrev / Vte + getDeviceOptions().gmin;
1236 #endif
1237 
1238  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1239  {
1240  Xyce::dout() << "Reverse breakdown regime." << std::endl;
1241  Xyce::dout() << " Vd = " << Vd << std::endl;
1242  Xyce::dout() << " tBrkdwnV = " << tBrkdwnV << std::endl;
1243  Xyce::dout() << " Id = " << Id << std::endl;
1244  Xyce::dout() << " Gd = " << Gd << std::endl;
1245  }
1246  }
1247  Vc = Vd;
1248  }
1249 
1250  }
1251  else if(level == 2)
1252  {
1253  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1254  {
1255  Xyce::dout() << " Level 2 diode code " << std::endl;
1256  }
1257  // Adjustment for linear portion of reverse current
1258  double IRfactor;
1259  //if(Vd >= 0) IRfactor = 1.0; //error? Shouldn't this be Vd >= -3*Vte?
1260  if(Vd >= -3.0*Vte) IRfactor=1.0; //changing it to be consistent with model
1261  else IRfactor = tIRF; //in the reference manual.
1262  Isat *= IRfactor;
1263 
1264  if (Vd >= -3.0 * Vte)
1265  {
1266  double arg1 = Vd / Vte;
1267  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1268  double evd = exp(arg1);
1269  Inorm = Isat * (evd - 1.0) + getDeviceOptions().gmin * Vd;
1270  Gd1 = Isat*evd/Vte + getDeviceOptions().gmin;
1271 
1272  arg1 = Vd / VteR;
1273  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1274  evd = exp(arg1);
1275  Irec = IsatR * (evd - 1.0);
1276  Gd2 = IsatR*evd/VteR;
1277 
1278  Khi = 1;
1279  DKhi = 0;
1280  if(tIKF > 0)
1281  {
1282  Khi = sqrt(tIKF/(tIKF+Inorm));
1283  DKhi = 0.5*Khi*Gd1/(tIKF+Inorm);
1284  }
1285  Kgen = 0;
1286  DKgen = 0;
1287  if(Irec != 0)
1288  {
1289  Kgen = sqrt( pow(((1-Vd/tJctPot)*(1-Vd/tJctPot) + 0.005),M) );
1290  DKgen = -M*(1-Vd/tJctPot)/(tJctPot*Kgen);
1291  }
1292 
1293  Id = Inorm*Khi + Irec*Kgen;
1294  Gd = Gd1*Khi + Inorm*DKhi + Gd2*Kgen + Irec*DKgen;
1295  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1296  {
1297  Xyce::dout() << "L2 Normal exponential regime." << std::endl;
1298  Xyce::dout() << " Vd = " << Vd << std::endl;
1299  Xyce::dout() << " Vte = " << Vte << std::endl;
1300  Xyce::dout() << " Id = " << Id << std::endl;
1301  Xyce::dout() << " Irec= " << Irec << std::endl;
1302  Xyce::dout() << " Gd = " << Gd << std::endl;
1303  Xyce::dout() << " Gd1 = " << Gd1 << std::endl;
1304  Xyce::dout() << " Gd2 = " << Gd2 << std::endl;
1305  Xyce::dout() << " Khi = " << Khi << std::endl;
1306  Xyce::dout() << " Kgen=" << Kgen << std::endl;
1307  Xyce::dout() << "DKgen=" <<DKgen << std::endl;
1308  }
1309  }
1310 
1311  // Linear reverse bias
1312  else if(!tBrkdwnV || (Vd >= -tBrkdwnV))
1313  {
1314  double arg = 3.0 * Vte / (Vd * CONSTe);
1315  arg = arg * arg * arg;
1316  Id = -Isat * (1.0 + arg) + getDeviceOptions().gmin * Vd;
1317  Gd = Isat * 3.0 * arg / Vd + getDeviceOptions().gmin;
1318  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1319  {
1320  Xyce::dout() << "L2 Linear reverse bias regime." << std::endl;
1321  Xyce::dout() << " Vd = " << Vd << std::endl;
1322  Xyce::dout() << " tBrkdwnV = " << tBrkdwnV << std::endl;
1323  Xyce::dout() << " Id = " << Id << std::endl;
1324  Xyce::dout() << " Gd = " << Gd << std::endl;
1325  }
1326  }
1327 
1328  // Reverse breakdown
1329  else
1330  {
1331  double arg1 = -(tBrkdwnV + Vd) / Vte;
1332  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1333  double evrev = exp(arg1);
1334 
1335 #ifdef Xyce_BREAKDOWN_ORIGINAL
1336  Id = -Isat * evrev + getDeviceOptions().gmin * Vd;
1337  Gd = Isat * evrev / Vte + getDeviceOptions().gmin;
1338 #else
1339  //added 9/18/07 by K. Santarelli to account for change in tBrkdwnV
1340  //calculation.
1341  double arg2=3.0*Vte/(CONSTe*tBrkdwnV);
1342  arg2=arg2*arg2*arg2;
1343  double Isat_tBrkdwnV=Isat*(1-arg2);
1344  Id = -Isat_tBrkdwnV * evrev + getDeviceOptions().gmin * Vd;
1345  Gd = Isat_tBrkdwnV * evrev / Vte + getDeviceOptions().gmin;
1346 #endif
1347  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1348  {
1349  Xyce::dout() << "L2 Reverse breakdown regime." << std::endl;
1350  Xyce::dout() << " Vd = " << Vd << std::endl;
1351  Xyce::dout() << " tBrkdwnV = " << tBrkdwnV << std::endl;
1352  Xyce::dout() << " Id = " << Id << std::endl;
1353  Xyce::dout() << " Gd = " << Gd << std::endl;
1354  }
1355  }
1356  Vc = Vd;
1357 
1358  } // level
1359 
1360  // Only compute if Capacitance is non-zero
1361  //---------------------------------------
1362  if (tJctCap != 0.0)
1363  {
1364  // Charge Storage
1365  double Czero = tJctCap * Area;
1366  if (Vc < tDepCap)
1367  {
1368  //double arg = 1.0 - Vd/VJ;
1369  double arg = 1.0 - Vc / tJctPot;
1370  double arg1 = -M * log(arg);
1371  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1372  double sarg = exp(arg1);
1373 
1374  //Qd = TT*Id + VJ*Czero*(1.0-arg*sarg)/(1.0-M);
1375  Qd = TT * Id + tJctPot * Czero * (1.0 - arg * sarg) / (1.0 - M);
1376  Cd = TT * Gd + Czero * sarg;
1377  }
1378  else
1379  {
1380  double Czof2 = Czero / F2;
1381  double MotJctPot = M / tJctPot;
1382 
1383  //Qd = TT*Id + Czero*tF1 + Czof2*(F3*(Vd-tDepCap)+(M/(VJ+VJ))
1384  Qd = TT * Id + Czero * tF1 +
1385  Czof2 * (F3 * (Vc - tDepCap) + (0.5 * MotJctPot) *
1386  (Vc * Vc - tDepCap * tDepCap));
1387  //Cd = TT*Gd + Czof2*(F3+M*Vd/VJ);
1388  Cd = TT * Gd + Czof2 * (F3 + MotJctPot * Vc);
1389  }
1390  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1391  {
1392  Xyce::dout() << "Qd = " << Qd << std::endl;
1393  Xyce::dout() << "Cd = " << Qd << std::endl;
1394  }
1395  }
1396  else
1397  {
1398  Qd = 0.0;
1399  Cd = 0.0;
1400  }
1401 
1402  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1403  {
1404  Xyce::dout() << Xyce::section_divider << std::endl;
1405  }
1406 
1407  return bsuccess;
1408 }
1409 
1410 //-----------------------------------------------------------------------------
1411 // Function : Instance::updateTemperature
1412 // Purpose : update intermediate variables for one diode instance
1413 // Special Notes :
1414 // Scope : public
1415 // Creator : Tom Russo, Component Information and Models
1416 // Creation Date : 1/10/01
1417 //-----------------------------------------------------------------------------
1418 bool Instance::updateTemperature( const double & temp )
1419 {
1420 
1421  double vtnom = CONSTKoverQ * model_.TNOM;
1422 
1423  double xfc = log( 1.0 - model_.FC );
1424 
1425  if( temp != -999.0 ) Temp = temp;
1426  double TNOM = model_.TNOM;
1427 
1428  double vt = CONSTKoverQ * Temp;
1429  double fact2 = Temp / CONSTREFTEMP;
1430  double egfet = CONSTEg0 - (CONSTalphaEg*Temp*Temp)/(Temp+CONSTbetaEg);
1431  double arg = -egfet/(2.0*CONSTboltz*Temp) +
1433  double pbfact = -2.0*vt*(1.5*log(fact2)+CONSTQ*arg);
1434  double egfet1 = CONSTEg0 - (CONSTalphaEg*model_.TNOM*model_.TNOM)/
1436  double arg1 = -egfet1/(2.0*CONSTboltz*model_.TNOM) +
1438  double fact1 = model_.TNOM/CONSTREFTEMP;
1439  double pbfact1 = -2.0*vtnom*(1.5*log(fact1)+CONSTQ*arg1);
1440 
1441  double pbo = (model_.VJ-pbfact1)/fact1;
1442  double gmaold = (model_.VJ-pbo)/pbo;
1443 
1444  tJctCap = model_.CJO/
1445  (1.0+model_.M*(4.0e-4*(model_.TNOM-CONSTREFTEMP) -gmaold));
1446 
1447  tJctPot = pbfact+fact2*pbo;
1448 
1449  double gmanew = (tJctPot-pbo)/pbo;
1450 
1451  tJctCap *= 1.0 + model_.M*(4.0e-4*(Temp-CONSTREFTEMP)-gmanew);
1452 
1453  tSatCur = model_.IS*exp(((Temp/model_.TNOM)-1.0)*
1454  model_.EG/(model_.N*vt)+
1455  model_.XTI/model_.N*log(Temp/model_.TNOM));
1456 
1457  tF1 = tJctPot*(1.0-exp((1.0-model_.M)*xfc))/(1.0-model_.M);
1458 
1460 
1461  double vte = model_.N*vt;
1462  double tempBV;
1463 
1464  tVcrit = vte*log(vte/(CONSTroot2*tSatCur));
1465  tRS = model_.RS;
1466  tCOND = model_.COND;
1467  tIRF = model_.IRF*pow(fact2,1.6);
1468 
1469  int level = model_.getLevel();
1470  if(level == 2) // this section is PSPICE compatible
1471  {
1472  tSatCurR = model_.ISR*exp((Temp/TNOM - 1.0)*
1473  model_.EG/(model_.NR*vt)+
1474  model_.XTI/model_.NR*log(Temp/TNOM));
1475 
1476  tIKF = model_.IKF*(1 + model_.TIKF*(Temp-TNOM));
1477 
1478  tempBV = model_.BV*(1 + (Temp-TNOM)*
1479  ( model_.TBV1 + model_.TBV2*(Temp-TNOM) ));
1480 
1481  tRS = model_.RS*(1 + (Temp-TNOM)*
1482  ( model_.TRS1 + model_.TRS2*(Temp-TNOM) ));
1483 
1484  tCOND = 0.0;
1485  if(tRS != 0.0) tCOND = 1.0/tRS;
1486 
1487  tJctPot = (model_.VJ - egfet1)*fact2 - 3*vt*log(fact2) + egfet;
1488 
1489  tJctCap = model_.CJO/(1.0 +
1490  model_.M*(4.0e-4*(Temp-TNOM) + (1-tJctPot/model_.VJ)));
1491  }
1492  else
1493  {
1494  tempBV=model_.BV;
1495  }
1496 
1497 #ifdef Xyce_BREAKDOWN_ORIGINAL
1498  //Changed 9/18/07, K. R. Santarelli. This is the original (broken) version
1499  //of the breakdown voltage computation. It has two known issues:
1500  //
1501  //1. It assumes N (the emission coefficient) is always 1 (division by
1502  // vt instead of vte).
1503  //2. While the for loop terminates due to the fact that it's implemented via
1504  // a counter, the value of xbv does not converge in many cases, so the
1505  // value of xbv upon terminating is often garbage.
1506  //
1507  //For consistency with old, existing simulations, this version of the
1508  //breakdown voltage calculation (along with the appropriate code for
1509  //computing the breakdown current in the level 1 and level 2 models---see
1510  //the appropriate sections of
1511  //Instance::updateIntermediateVars) can be invoked by
1512  //specifiying the CPPFLAG "-DXyce_BREAKDOWN_ORIGINAL" when creating a Xyce
1513  //Build. The default, however, is the code which follows #else.
1514 
1515  double reltol = 1.0e-3;
1516  if( model_.BVGiven )
1517  {
1518  double IRfactor = tIRF;
1519  double cbv = model_.IBV;
1520  double xbv, xcbv;
1521  if( cbv < IRfactor*tSatCur*tempBV/vt )
1522  {
1523  cbv = IRfactor*tSatCur*tempBV/vt;
1524  xbv = tempBV;
1525  }
1526  else
1527  {
1528  double tol = reltol*cbv;
1529  xbv = tempBV-vt*log(1.0+cbv/(IRfactor*tSatCur));
1530  for( int i = 0; i < 25; ++i )
1531  {
1532  xbv = tempBV-vt*log(cbv/(IRfactor*tSatCur)+1.0-xbv/vt);
1533  xcbv = IRfactor*tSatCur*(exp((tempBV-xbv)/vt)-1.0+xbv/vt);
1534  if(fabs(xcbv-cbv)<=tol) break;
1535  }
1536  }
1537  tBrkdwnV = xbv;
1538  }
1539 #else
1540  if( model_.BVGiven)
1541  {
1542  double IRFactor=tIRF;
1543  double cbv = model_.IBV;
1544  double xbv;
1545  double cthreshlow; //lower threshold for IBV
1546  double cthreshhigh; //high threshold for IBV
1547  int iter_count;
1548  const int ITER_COUNT_MAX=8;
1549  double arg2;
1550 
1551  double arg1=3.0*vte/(CONSTe*tempBV);
1552  arg1=arg1*arg1*arg1;
1553  cthreshlow=tSatCur*IRFactor*(1-arg1);
1554  cthreshhigh=tSatCur*IRFactor*(1-1.0/(CONSTe*CONSTe*CONSTe)) *
1555  exp(-1.0*(3.0*vte-tempBV)/vte);
1556 
1557  if(cbv >= cthreshhigh)
1558  { //if IBV is too high, tBrkdwnV will go below 3NVt.
1559  tBrkdwnV=3.0*vte; //Clip tBrkdwnV to 3*N*Vt in this case (and hence
1560  } //clip IBV to cthreshhigh).
1561 
1562 
1563  else if(cbv <= cthreshlow)
1564  { //if IBV is too low, tBrkdwnV will go above
1565  tBrkdwnV=tempBV; //BV. Clip tBrkdwnV to BV in this case (and
1566  } //hence clip IBV to cthreshlow).
1567 
1568 
1569  //If IBV is in an acceptable range, perform a Picard iteration to find
1570  //tBrkdwnV, starting with an initial guess of tBrkdwnV=tempBV, and
1571  //running through the iteration ITER_COUNT_MAX times.
1572 
1573  else
1574  {
1575  xbv=tempBV;
1576  for(iter_count=0; iter_count < ITER_COUNT_MAX; iter_count++)
1577  {
1578  arg2=3.0*vte/(CONSTe*xbv);
1579  arg2=arg2*arg2*arg2;
1580  xbv=tempBV-vte*log(cbv/(tSatCur*IRFactor))+vte *
1581  log(1-arg2);
1582  }
1583  tBrkdwnV=xbv;
1584  }
1585 
1586 //Note that, not only is tBrkdwnV adjusted using this method, but the effective
1587 //value of Is (tSatCur) is adjusted as well. The code used to use Is before,
1588 //but now it will use Is*IRFactor*(1-(3*N*Vt/(e*tBrkdwnV))^3) instead. This is
1589 //reflected in changes made to Instance::updateIntermediateVars
1590 //(for "normal" level 1 and 2 diode models) for the reverse breakdown region.
1591 //Changes have not been made to the associated LambertW functions as of yet
1592 //since there seem to be other issues involved with those functions independent
1593 // of this change.
1594  }
1595 #endif
1596 
1597 
1598  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1599  {
1600  Xyce::dout() << Xyce::section_divider << std::endl;
1601  Xyce::dout() << "Instance::UpdateTemperature" << getName() <<std::endl;
1602  Xyce::dout() << " IS = " << model_.IS << std::endl;
1603  Xyce::dout() << " vtnom = " << vtnom << std::endl;
1604  Xyce::dout() << " xfc = " << xfc << std::endl;
1605  Xyce::dout() << " TNOM = " << TNOM << std::endl;
1606  Xyce::dout() << " vt = " << vt << std::endl;
1607  Xyce::dout() << " fact2 = " << fact2 << std::endl;
1608  Xyce::dout() << " egfet = " << egfet << std::endl;
1609  Xyce::dout() << " arg = " << arg << std::endl;
1610  Xyce::dout() << " pbfact = " << pbfact << std::endl;
1611  Xyce::dout() << " egfet1 = " << egfet1 << std::endl;
1612  Xyce::dout() << " arg1 = " << arg1 << std::endl;
1613  Xyce::dout() << " fact1 = " << fact1 << std::endl;
1614  Xyce::dout() << " pbfact1 = " << pbfact1 << std::endl;
1615  Xyce::dout() << " pbo = " << pbo << std::endl;
1616  Xyce::dout() << " gmaold = " << gmaold << std::endl;
1617  Xyce::dout() << " gmanew = " << gmanew << std::endl;
1618  Xyce::dout() << " tJctCap = " << tJctCap << std::endl;
1619  Xyce::dout() << " tJctPot = " << tJctPot << std::endl;
1620  Xyce::dout() << " tSatCur = " << tSatCur << std::endl;
1621  Xyce::dout() << " tF1 = " << tF1 << std::endl;
1622  Xyce::dout() << " tDepCap = " << tDepCap << std::endl;
1623  Xyce::dout() << " vte = " << vte << std::endl;
1624  Xyce::dout() << " tempBV = " << tempBV << std::endl;
1625  Xyce::dout() << " tVcrit = " << tVcrit << std::endl;
1626  Xyce::dout() << " tRS = " << tRS << std::endl;
1627  Xyce::dout() << " tCOND = " << tCOND << std::endl;
1628  Xyce::dout() << " tIRF = " << tIRF << std::endl;
1629  Xyce::dout() << " tBrkdwnV= " << tBrkdwnV << std::endl;
1630  }
1631 
1632  return true;
1633 }
1634 
1635 
1636 //-----------------------------------------------------------------------------
1637 // Function : Instance::lambertWCurrent
1638 // Purpose : Determine the diode current using Lambert-W function
1639 // Special Notes :
1640 // Scope : public
1641 // Creator : Nick Johnson, Summer Intern
1642 // Creation Date : 7/5/02
1643 //-----------------------------------------------------------------------------
1644 bool Instance::lambertWCurrent(double Isat, double Vte, double RS)
1645 {
1646  // with capacitor current and using LambertW accros whole model
1647  /* if (Cd != 0.0 && Icd != 0 && (lambertWFlag == 1))
1648  {
1649  double AA = Vte*(1.0 + RS*getSolverState().pdt*Cd);
1650  double XX = Icd - getSolverState().pdt*Qd;
1651  double arg1 = (Vd + RS*Isat - RS*XX)/AA;
1652  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1653  double evd = exp(arg1);
1654  double lambWArg = Isat*RS/AA * evd;
1655  double lambWReturn;
1656  int ierr;
1657  double lambWError;
1658  devSupport.lambertw(lambWArg, lambWReturn, ierr, lambWError);
1659 
1660  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1661  {
1662  if (ierr == 0)
1663  Xyce::dout() << "Safe LambertW return" << std::endl;
1664  else if (ierr == 1)
1665  Xyce::dout() << "LambertW argument not in domain" << std::endl;
1666  else
1667  Xyce::dout() << "Arithmetic problems with LambertW" << std::endl;
1668  }
1669 
1670  double prefac = AA/RS;
1671  Id = -Isat + prefac*lambWReturn;
1672  Gd = lambWReturn / ((1 + lambWReturn)*RS);
1673 
1674  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1675  {
1676  Xyce::dout() << "lambWArg = " << lambWArg << std::endl;
1677  Xyce::dout() << "lambWError = " << lambWError << std::endl;
1678  Xyce::dout() << "Id = " << Id << std::endl;
1679  Xyce::dout() << "Gd = " << Gd << std::endl;
1680  Xyce::dout() << "Icd = " << Icd << std::endl;
1681  Xyce::dout() << "Cd = " << Cd << std::endl;
1682  Xyce::dout() << "Qd = " << Qd << std::endl;
1683  Xyce::dout() << "AA = " << AA << std::endl;
1684  Xyce::dout() << "XX = " << XX << std::endl;
1685  Xyce::dout() << "Using lambertwCurrent w/ capacitance" << std::endl;
1686  }
1687  #endif
1688  }
1689 
1690  // when capacitor current=0, there is no capacitance, or using LambertW
1691  // only across the diode element
1692  else
1693  { */
1694  double arg1 = (Vd + Isat*RS)/Vte;
1695  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1696  double evd = exp(arg1);
1697  double lambWArg = Isat*RS*evd/Vte;
1698  double lambWReturn;
1699  int ierr;
1700  double lambWError;
1701  devSupport.lambertw(lambWArg, lambWReturn, ierr, lambWError);
1702 
1703  Id = -Isat+Vte*(lambWReturn)/RS;
1704  Gd = lambWReturn / ((1 + lambWReturn)*RS);
1705 
1706  // }
1707 
1708  return true;
1709 }
1710 
1711 //-----------------------------------------------------------------------------
1712 // Function : Instance::lambertWLinearReverseBias
1713 // Purpose : Function to maintain continuity between forward bias and
1714 // breakdown voltages of diode
1715 // Special Notes :
1716 // Scope : public
1717 // Creator : Nick Johnson, Summer Intern
1718 // Creation Date : 7/30/02
1719 //-----------------------------------------------------------------------------
1720 bool Instance::lambertWLinearReverseBias(double Isat, double Vte, double RS)
1721 {
1722  double FF1 = (Vd + tBrkdwnV)/(-3.0 * Vte + tBrkdwnV);
1723  double FF2 = (1/2 - FF1)*(-2);
1724  double arg = Vte/RS;
1725  double arg1 = (Isat/arg - 3);
1726  double arg2 = FF1*arg1;
1727  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg2);
1728  double evd = exp(arg2);
1729  double lambWArg = Isat*evd/arg;
1730  double lambWReturn;
1731  int ierr;
1732  double lambWError;
1733  devSupport.lambertw(lambWArg, lambWReturn, ierr, lambWError);
1734 
1735  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1736  {
1737  if (ierr == 0)
1738  Xyce::dout() << "Safe LambertW return" << std::endl;
1739  else if (ierr == 1)
1740  Xyce::dout() << "LambertW argument not in domain" << std::endl;
1741  else
1742  Xyce::dout() << "Arithmetic problems with LambertW" << std::endl;
1743  }
1744 
1745  Id = -Isat*FF1 + FF2*lambWReturn*arg;
1746 
1747  double GdFF1 = 1/(-3.0*Vte + tBrkdwnV);
1748  double GdFF2 = 2 * GdFF1;
1749  double GdW = arg*lambWReturn*GdFF1*arg1/(1 + lambWReturn);
1750  Gd = -Isat*GdFF1 + GdFF2*arg*lambWReturn + FF2*GdW;
1751 
1752  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1753  {
1754  Xyce::dout() << "lambWArg = " << lambWArg << std::endl;
1755  Xyce::dout() << "lambWError = " << lambWError << std::endl;
1756  Xyce::dout() << "lambWReturn= " << lambWReturn << std::endl;
1757  Xyce::dout() << "Id = " << Id << std::endl;
1758  Xyce::dout() << "Gd = " << Gd << std::endl;
1759  Xyce::dout() << "Using lambertwReverseBias" << std::endl;
1760  }
1761 
1762  return true;
1763 }
1764 
1765 //-----------------------------------------------------------------------------
1766 // Function : Instance::lambertWBreakdownCurrent
1767 // Purpose : Determine the diode breakdown current using Lambert-W function
1768 // Special Notes :
1769 // Scope : public
1770 // Creator : Nick Johnson, Summer Intern
1771 // Creation Date : 7/11/02
1772 //-----------------------------------------------------------------------------
1773 bool Instance::lambertWBreakdownCurrent(double Isat, double Vte, double RS)
1774 {
1775  // with capacitor current and applying LambertW accros whole diode model
1776  /* if (Cd != 0.0 && Icd != 0 && (lambertWFlag == 1))
1777  {
1778  double AA = Vte*(1 + RS*getSolverState().pdt*Cd);
1779  double XX = Icd - getSolverState().pdt*Qd;
1780  double arg1 = (RS*XX - Vd)/AA - tBrkdwnV/Vte;
1781  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1782  double evd = exp(arg1);
1783  double lambWArg = Isat*RS*evd/AA;
1784  double lambWReturn;
1785  int ierr;
1786  double lambWError;
1787  devSupport.lambertw(lambWArg, lambWReturn, ierr, lambWError);
1788 
1789  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1790  {
1791  if (ierr == 0)
1792  Xyce::dout() << "Safe LambertW return" << std::endl;
1793  else if (ierr == 1)
1794  Xyce::dout() << "LambertW argument not in domain" << std::endl;
1795  else
1796  Xyce::dout() << "Arithmetic problems with LambertW" << std::endl;
1797  }
1798  #endif
1799 
1800  Id = -AA*lambWReturn/RS;
1801  Gd = (lambWReturn / (1 + lambWReturn)) * (1/RS);
1802 
1803  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1804  {
1805  Xyce::dout() << "lambWArg = " << lambWArg << std::endl;
1806  Xyce::dout() << "lambWError = " << lambWError << std::endl;
1807  Xyce::dout() << "Id = " << Id << std::endl;
1808  Xyce::dout() << "Gd = " << Gd << std::endl;
1809  Xyce::dout() << "Icd = " << Icd << std::endl;
1810  Xyce::dout() << "Cd = " << Cd << std::endl;
1811  Xyce::dout() << "Qd = " << Qd << std::endl;
1812  Xyce::dout() << "AA = " << AA << std::endl;
1813  Xyce::dout() << "XX = " << XX << std::endl;
1814  Xyce::dout() << "Using lambertwBreakdown w/ capacitance" << std::endl;
1815  }
1816  #endif
1817  }
1818 
1819  // without capacitor current or applying lambertW just accros diode element
1820  else
1821  {*/
1822  double arg1 = (-Vd - tBrkdwnV)/ Vte;
1823  arg1 = Xycemin(CONSTMAX_EXP_ARG, arg1);
1824  double evd = exp(arg1);
1825  double lambWArg = Isat*RS*evd/Vte;
1826  double lambWReturn;
1827  int ierr;
1828  double lambWError;
1829  devSupport.lambertw(lambWArg, lambWReturn, ierr, lambWError);
1830 
1831  Id = -Vte*lambWReturn/RS;
1832  Gd = lambWReturn / ((1 + lambWReturn)*RS);
1833 
1834  // }
1835 
1836  return true;
1837 }
1838 
1839 //-----------------------------------------------------------------------------
1840 // Function : Model::processParams
1841 // Purpose :
1842 // Special Notes :
1843 // Scope : public
1844 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1845 // Creation Date : 6/03/02
1846 //-----------------------------------------------------------------------------
1848 {
1849  //limit grading coeff
1850  if( M > 0.9 ) M = 0.9;
1851 
1852  //limit activation energy
1853  if( EG < 0.1 ) EG = 0.1;
1854 
1855  //limit depl cap coeff
1856  if( FC > 0.95 ) FC = 0.95;
1857 
1858  if( RS==0.0 )
1859  COND = 0.0;
1860  else
1861  COND = 1.0/RS;
1862 
1863  double xfc = log(1.0-FC);
1864  F2 = exp((1.0+M)*xfc);
1865  F3 = 1.0-FC*(1.0+M);
1866 
1867  return true;
1868 }
1869 
1870 //----------------------------------------------------------------------------
1871 // Function : Model::processInstanceParams
1872 // Purpose :
1873 // Special Notes :
1874 // Scope : public
1875 // Creator : Dave Shirely, PSSI
1876 // Creation Date : 03/23/06
1877 //----------------------------------------------------------------------------
1879 {
1880 
1881  std::vector<Instance*>::iterator iter;
1882  std::vector<Instance*>::iterator first = instanceContainer.begin();
1883  std::vector<Instance*>::iterator last = instanceContainer.end();
1884 
1885  for (iter=first; iter!=last; ++iter)
1886  {
1887  (*iter)->processParams();
1888  }
1889 
1890  return true;
1891 }
1892 
1893 //-----------------------------------------------------------------------------
1894 // Function : Model::Model
1895 // Purpose : model block constructor
1896 // Special Notes :
1897 // Scope : public
1898 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1899 // Creation Date : 3/16/00
1900 //-----------------------------------------------------------------------------
1902  const Configuration & configuration,
1903  const ModelBlock & MB,
1904  const FactoryBlock & factory_block)
1905  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
1906  IS(1.0e-14),
1907  RS(0.0),
1908  COND(0.0),
1909  N(1.0),
1910  ISR(0.0),
1911  NR(2.0),
1912  IKF(0.0),
1913  TT(0.0),
1914  CJO(0.0),
1915  VJ(1.0),
1916  M(0.5),
1917  EG(1.11),
1918  XTI(3.0),
1919  TIKF(0.0),
1920  TBV1(0.0),
1921  TBV2(0.0),
1922  TRS1(0.0),
1923  TRS2(0.0),
1924  FC(0.5),
1925  BV(1e99),
1926  IBV(1.0e-10),
1927  IRF(1.0),
1928  NBV(1.0),
1929  IBVL(0.0),
1930  NBVL(1.0),
1931  F2(0.0),
1932  F3(0.0),
1933  TNOM(27),
1934  KF(0.0),
1935  AF(1.0),
1936  BVGiven(false)
1937 {
1938 
1939  // Set params to constant default values:
1940  setDefaultParams ();
1941 
1942  // Set params according to .model line and constant defaults from metadata:
1943  setModParams (MB.params);
1944 
1945  // Set any non-constant parameter defaults:
1946  if (!given("TNOM"))
1948 
1949  // Calculate any parameters specified as expressions:
1951 
1952  // calculate dependent (ie computed) params and check for errors:
1953 
1954  // Note: Level 2 only params are: ISR, NR, IKF, NBV, IBVL, NBVL, TIKF, TBV1, TBV2, TRS1, TRS2
1955  if (getLevel() == 1)
1956  {
1957  std::string bad_parameters;
1958 
1959  if (given("ISR"))
1960  bad_parameters += " ISR";
1961  if (given("NR"))
1962  bad_parameters += " NR";
1963  if (given("IKF"))
1964  bad_parameters += " IKF";
1965  if (given("NBV"))
1966  bad_parameters += " NBV";
1967  if (given("IBVL"))
1968  bad_parameters += " IBVL";
1969  if (given("NBVL"))
1970  bad_parameters += " NBVL";
1971  if (given("TIKF"))
1972  bad_parameters += " TIKF";
1973  if (given("TBV1"))
1974  bad_parameters += " TBV1";
1975  if (given("TBV2"))
1976  bad_parameters += " TBV2";
1977  if (given("TRS1"))
1978  bad_parameters += " TRS1";
1979  if (given("TRS2"))
1980  bad_parameters += " TRS2";
1981  if (!bad_parameters.empty())
1982  {
1983  UserError0(*this) << "Illegal parameter(s) given for level 1 diode:" << bad_parameters;
1984  }
1985  }
1986 
1987  processParams ();
1988 }
1989 
1990 
1991 //-----------------------------------------------------------------------------
1992 // Function : Model::~Model
1993 // Purpose : destructor
1994 // Special Notes :
1995 // Scope : public
1996 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1997 // Creation Date : 3/16/00
1998 //-----------------------------------------------------------------------------
2000 {
2001  std::vector<Instance*>::iterator iterI;
2002  std::vector<Instance*>::iterator firstI = instanceContainer.begin ();
2003  std::vector<Instance*>::iterator lastI = instanceContainer.end ();
2004 
2005  // loop over instances:
2006  for (iterI = firstI; iterI != lastI; ++iterI)
2007  {
2008  delete (*iterI);
2009  }
2010 }
2011 
2012 //-----------------------------------------------------------------------------
2013 // Function : Model::printOutInstances
2014 // Purpose : debugging tool.
2015 // Special Notes :
2016 // Scope : public
2017 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2018 // Creation Date : 4/03/00
2019 //-----------------------------------------------------------------------------
2020 
2021 std::ostream &Model::printOutInstances(std::ostream &os) const
2022 {
2023  std::vector<Instance*>::const_iterator iter;
2024  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
2025  std::vector<Instance*>::const_iterator last = instanceContainer.end();
2026 
2027  int i;
2028  os << std::endl;
2029  os << " name model name Parameters" << std::endl;
2030  for (i=0, iter=first; iter!=last; ++iter, ++i)
2031  {
2032  os << " " << i << ": " << (*iter)->getName() << " ";
2033  os << getName();
2034 
2035  os << std::endl;
2036  os << "AREA = " << (*iter)->Area << std::endl;
2037  os << " IC = " << (*iter)->InitCond << std::endl;
2038  os << "TEMP = " << (*iter)->Temp << std::endl;
2039  os << " off = " << (*iter)->off << std::endl;
2040 
2041  os << std::endl;
2042  }
2043 
2044  os << std::endl;
2045 
2046  return os;
2047 }
2048 
2049 //-----------------------------------------------------------------------------
2050 // Function : Model::forEachInstance
2051 // Purpose :
2052 // Special Notes :
2053 // Scope : public
2054 // Creator : David Baur
2055 // Creation Date : 2/4/2014
2056 //-----------------------------------------------------------------------------
2057 /// Apply a device instance "op" to all instances associated with this
2058 /// model
2059 ///
2060 /// @param[in] op Operator to apply to all instances.
2061 ///
2062 ///
2063 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
2064 {
2065  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
2066  op(*it);
2067 }
2068 
2069 
2070 //-----------------------------------------------------------------------------
2071 // Diode Master functions:
2072 //-----------------------------------------------------------------------------
2073 
2074 //-----------------------------------------------------------------------------
2075 // Function : Master::updateState
2076 // Purpose :
2077 // Special Notes :
2078 // Scope : public
2079 // Creator : Eric Keiter, SNL
2080 // Creation Date : 11/26/08
2081 //-----------------------------------------------------------------------------
2082 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
2083 {
2084  bool bsuccess = true;
2085 
2086  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
2087  {
2088  Instance & di = *(*it);
2089  bool btmp = di.updateIntermediateVars ();
2090  stoVec[di.li_storevd] = di.Vd;
2091  bsuccess = bsuccess && btmp;
2092  }
2093 
2094  return bsuccess;
2095 }
2096 
2097 //-----------------------------------------------------------------------------
2098 // Function : Master::loadDAEVectors
2099 // Purpose :
2100 // Special Notes :
2101 // Scope : public
2102 // Creator : Eric Keiter, SNL
2103 // Creation Date : 11/26/08
2104 //-----------------------------------------------------------------------------
2105 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * bVec, double * storeLeadF, double * storeLeadQ, double * leadF, double * leadQ, double * junctionV)
2106 {
2107  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
2108  {
2109  Instance & di = *(*it);
2110  // load F:
2111  double Ir = di.Gspr * (di.Vp - di.Vpp);
2112 
2113  fVec[di.li_Pos] -= -Ir;
2114  fVec[di.li_Neg] -= di.Id;
2115  fVec[di.li_Pri] -= (-di.Id + Ir);
2116 
2117  // load Q:
2118  qVec[di.li_Neg] -= di.Qd;
2119  qVec[di.li_Pri] -= -di.Qd;
2120 
2121  // voltage limiter vectors.
2123  {
2124  double Vd_diff = di.Vd - di.Vd_orig;
2125  double Cd_Jdxp = -( di.Cd ) * Vd_diff;
2126  double Gd_Jdxp = -( di.Gd ) * Vd_diff;
2127 
2128  double * dFdxdVp = di.extData.dFdxdVpVectorRawPtr;
2129  // dFdxdVp vector
2130  dFdxdVp[di.li_Neg] += Gd_Jdxp;
2131  dFdxdVp[di.li_Pri] -= Gd_Jdxp;
2132 
2133  double * dQdxdVp = di.extData.dQdxdVpVectorRawPtr;
2134  // dQdxdVp vector
2135  dQdxdVp[di.li_Neg] += Cd_Jdxp;
2136  dQdxdVp[di.li_Pri] -= Cd_Jdxp;
2137  }
2138 
2139  if( di.loadLeadCurrent )
2140  {
2141  storeLeadF[di.li_store_dev_i] = di.Id;
2142  if (di.model_.CJO != 0.0)
2143  {
2144  storeLeadQ[di.li_store_dev_i] = di.Qd;
2145  leadQ[di.li_branch_data] = di.Qd;
2146  }
2147  leadF[di.li_branch_data] = di.Id;
2148  junctionV[di.li_branch_data] = solVec[di.li_Pos] - solVec[di.li_Neg];
2149 
2150  }
2151  }
2152  return true;
2153 }
2154 
2155 //-----------------------------------------------------------------------------
2156 // Function : Master::loadDAEMatrices
2157 // Purpose :
2158 // Special Notes :
2159 // Scope : public
2160 // Creator : Eric Keiter, SNL
2161 // Creation Date : 11/26/08
2162 //-----------------------------------------------------------------------------
2163 bool Master::loadDAEMatrices (Linear::Matrix & dFdx, Linear::Matrix & dQdx)
2164 {
2165  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
2166  {
2167  Instance & di = *(*it);
2168 
2169 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
2170  // F-matrix:
2171  *di.fPosEquPosNodePtr += di.Gspr;
2172  *di.fPosEquPriNodePtr -= di.Gspr;
2173  *di.fNegEquNegNodePtr += di.Gd;
2174  *di.fNegEquPriNodePtr -= di.Gd;
2175  *di.fPriEquPosNodePtr -= di.Gspr;
2176  *di.fPriEquNegNodePtr -= di.Gd;
2177  *di.fPriEquPriNodePtr += di.Gspr + di.Gd;
2178 
2179  // Q-matrix:
2180  *di.qNegEquNegNodePtr += di.Cd;
2181  *di.qNegEquPriNodePtr -= di.Cd;
2182  *di.qPriEquNegNodePtr -= di.Cd;
2183  *di.qPriEquPriNodePtr += di.Cd;
2184 #else
2185  // F-matrix:
2186  dFdx[di.li_Pos][di.APosEquPosNodeOffset] += di.Gspr;
2187  dFdx[di.li_Pos][di.APosEquPriNodeOffset] -= di.Gspr;
2188  dFdx[di.li_Neg][di.ANegEquNegNodeOffset] += di.Gd;
2189  dFdx[di.li_Neg][di.ANegEquPriNodeOffset] -= di.Gd;
2190  dFdx[di.li_Pri][di.APriEquPosNodeOffset] -= di.Gspr;
2191  dFdx[di.li_Pri][di.APriEquNegNodeOffset] -= di.Gd;
2192  dFdx[di.li_Pri][di.APriEquPriNodeOffset] += di.Gspr + di.Gd;
2193 
2194  // Q-matrix:
2195  dQdx[di.li_Neg][di.ANegEquNegNodeOffset] += di.Cd;
2196  dQdx[di.li_Neg][di.ANegEquPriNodeOffset] -= di.Cd;
2197  dQdx[di.li_Pri][di.APriEquNegNodeOffset] -= di.Cd;
2198  dQdx[di.li_Pri][di.APriEquPriNodeOffset] += di.Cd;
2199 #endif
2200  }
2201  return true;
2202 }
2203 
2204 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
2205 {
2206 
2207  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
2208 }
2209 
2211 {
2213  .registerDevice("d", 1)
2214  .registerDevice("d", 2)
2215  .registerModelType("d", 1)
2216  .registerModelType("d", 2);
2217 }
2218 
2219 //-----------------------------------------------------------------------------
2220 // sensitivity related code.
2221 //
2222 // This is not the final implementation, as it is too klunky. But, it works
2223 // for now as a preliminary experiment.
2224 
2225 
2226 //-----------------------------------------------------------------------------
2227 // Function : processParams
2228 // Purpose : patterned after the model version of this function.
2229 // Special Notes :
2230 // Scope : public
2231 // Creator :
2232 // Creation Date :
2233 //-----------------------------------------------------------------------------
2234 template <typename ScalarT>
2236  ScalarT & M,
2237  ScalarT & EG,
2238  ScalarT & FC,
2239  const ScalarT & RS,
2240  ScalarT & COND,
2241  ScalarT & F2,
2242  ScalarT & F3
2243  )
2244 {
2245  //limit grading coeff
2246  if( M > 0.9 ) M = 0.9;
2247 
2248  //limit activation energy
2249  if( EG < 0.1 ) EG = 0.1;
2250 
2251  //limit depl cap coeff
2252  if( FC > 0.95 ) FC = 0.95;
2253 
2254  if( RS==0.0 )
2255  COND = 0.0;
2256  else
2257  COND = 1.0/RS;
2258 
2259  ScalarT xfc = log(1.0-FC);
2260  F2 = exp((1.0+M)*xfc);
2261  F3 = 1.0-FC*(1.0+M);
2262 
2263  return true;
2264 }
2265 
2266 //-----------------------------------------------------------------------------
2267 // Function : updateTemperature
2268 // Purpose :
2269 // Special Notes :
2270 // Scope : public
2271 // Creator :
2272 // Creation Date :
2273 //-----------------------------------------------------------------------------
2274 template <typename ScalarT>
2275 bool updateTemperature
2276  (
2277  const double & temp,
2278 
2279  // instance variables/params:
2280  ScalarT & Temp,
2281  ScalarT & tJctCap,
2282  ScalarT & tJctPot,
2283  ScalarT & tDepCap,
2284  ScalarT & tF1,
2285  ScalarT & tSatCur,
2286  ScalarT & tSatCurR,
2287  ScalarT & tVcrit,
2288  ScalarT & tRS,
2289  ScalarT & tCOND,
2290  ScalarT & tIRF,
2291  ScalarT & tIKF,
2292  ScalarT & tBrkdwnV,
2293 
2294  // model variables/params:
2295  const ScalarT & TNOM,
2296  const ScalarT & VJ,
2297  const ScalarT & CJO,
2298  const ScalarT & M,
2299  const ScalarT & N,
2300  const ScalarT & IS,
2301  const ScalarT & EG,
2302  const ScalarT & XTI,
2303  const ScalarT & RS,
2304  const ScalarT & COND,
2305  const ScalarT & IRF,
2306  const ScalarT & NR,
2307  const ScalarT & IKF,
2308  const ScalarT & TIKF,
2309  const ScalarT & ISR,
2310  const ScalarT & IBV,
2311  const ScalarT & BV,
2312 
2313  const bool & BVGiven,
2314 
2315  const ScalarT & TBV1,
2316  const ScalarT & TBV2,
2317  const ScalarT & TRS1,
2318  const ScalarT & TRS2,
2319  const ScalarT & FC,
2320 
2321  const int level
2322 
2323  )
2324 {
2325  ScalarT KoverQ = static_cast<ScalarT>(CONSTKoverQ);
2326  ScalarT REFTEMP = static_cast<ScalarT>(CONSTREFTEMP);
2327  ScalarT Eg0 = static_cast<ScalarT>(CONSTEg0);
2328  ScalarT alphaEg = static_cast<ScalarT>(CONSTalphaEg);
2329  ScalarT betaEg = static_cast<ScalarT>(CONSTbetaEg);
2330  ScalarT boltz = static_cast<ScalarT>(CONSTboltz);
2331  ScalarT Q = static_cast<ScalarT>(CONSTQ);
2332  ScalarT Eg300 = static_cast<ScalarT>(CONSTEg300);
2333  ScalarT root2 = static_cast<ScalarT>(CONSTroot2);
2334  ScalarT e = static_cast<ScalarT>(CONSTe);
2335 
2336  ScalarT vtnom = KoverQ * TNOM;
2337 
2338  ScalarT xfc = log( 1.0 - FC );
2339 
2340  if( temp != -999.0 ) Temp = temp;
2341  //double TNOM = TNOM;
2342 
2343  ScalarT vt = KoverQ * Temp;
2344  ScalarT fact2 = Temp / REFTEMP;
2345  ScalarT egfet = Eg0 - (alphaEg*Temp*Temp)/(Temp+betaEg);
2346  ScalarT arg = -egfet/(2.0*boltz*Temp) +
2347  Eg300/(boltz*(REFTEMP+REFTEMP));
2348  ScalarT pbfact = -2.0*vt*(1.5*log(fact2)+Q*arg);
2349  ScalarT egfet1 = Eg0 - (alphaEg*TNOM*TNOM)/
2350  (TNOM+betaEg);
2351  ScalarT arg1 = -egfet1/(2.0*boltz*TNOM) +
2352  Eg300/(2.0*boltz*REFTEMP);
2353  ScalarT fact1 = TNOM/REFTEMP;
2354  ScalarT pbfact1 = -2.0*vtnom*(1.5*log(fact1)+Q*arg1);
2355 
2356  ScalarT pbo = (VJ-pbfact1)/fact1;
2357  ScalarT gmaold = (VJ-pbo)/pbo;
2358 
2359  tJctCap = CJO/
2360  (1.0+M*(4.0e-4*(TNOM-REFTEMP) -gmaold));
2361 
2362  tJctPot = pbfact+fact2*pbo;
2363 
2364  ScalarT gmanew = (tJctPot-pbo)/pbo;
2365 
2366  tJctCap *= 1.0 + M*(4.0e-4*(Temp-REFTEMP)-gmanew);
2367 
2368  tSatCur = IS*exp(((Temp/TNOM)-1.0)*
2369  EG/(N*vt)+
2370  XTI/N*log(Temp/TNOM));
2371 
2372  tF1 = tJctPot*(1.0-exp((1.0-M)*xfc))/(1.0-M);
2373 
2374  tDepCap = FC*tJctPot;
2375 
2376  ScalarT vte = N*vt;
2377  ScalarT tempBV;
2378 
2379  tVcrit = vte*log(vte/(root2*tSatCur));
2380  tRS = RS;
2381  tCOND = COND;
2382  tIRF = IRF*pow(fact2,1.6);
2383 
2384  //int level = getLevel();
2385  if(level == 2) // this section is PSPICE compatible
2386  {
2387  tSatCurR = ISR*exp((Temp/TNOM - 1.0)*
2388  EG/(NR*vt)+
2389  XTI/NR*log(Temp/TNOM));
2390 
2391  tIKF = IKF*(1 + TIKF*(Temp-TNOM));
2392 
2393  tempBV = BV*(1 + (Temp-TNOM)*
2394  ( TBV1 + TBV2*(Temp-TNOM) ));
2395 
2396  tRS = RS*(1 + (Temp-TNOM)*
2397  ( TRS1 + TRS2*(Temp-TNOM) ));
2398 
2399  tCOND = 0.0;
2400  if(tRS != 0.0) tCOND = 1.0/tRS;
2401 
2402  tJctPot = (VJ - egfet1)*fact2 - 3*vt*log(fact2) + egfet;
2403 
2404  tJctCap = CJO/(1.0 +
2405  M*(4.0e-4*(Temp-TNOM) + (1-tJctPot/VJ)));
2406  }
2407  else
2408  {
2409  tempBV=BV;
2410  }
2411 
2412 #ifdef Xyce_BREAKDOWN_ORIGINAL
2413  //Changed 9/18/07, K. R. Santarelli. This is the original (broken) version
2414  //of the breakdown voltage computation. It has two known issues:
2415  //
2416  //1. It assumes N (the emission coefficient) is always 1 (division by
2417  // vt instead of vte).
2418  //2. While the for loop terminates due to the fact that it's implemented via
2419  // a counter, the value of xbv does not converge in many cases, so the
2420  // value of xbv upon terminating is often garbage.
2421  //
2422  //For consistency with old, existing simulations, this version of the
2423  //breakdown voltage calculation (along with the appropriate code for
2424  //computing the breakdown current in the level 1 and level 2 models---see
2425  //the appropriate sections of
2426  //Instance::updateIntermediateVars) can be invoked by
2427  //specifiying the CPPFLAG "-DXyce_BREAKDOWN_ORIGINAL" when creating a Xyce
2428  //Build. The default, however, is the code which follows #else.
2429 
2430  double reltol = 1.0e-3;
2431  if( BVGiven )
2432  {
2433  double IRfactor = tIRF;
2434  double cbv = IBV;
2435  double xbv, xcbv;
2436  if( cbv < IRfactor*tSatCur*tempBV/vt )
2437  {
2438  cbv = IRfactor*tSatCur*tempBV/vt;
2439  xbv = tempBV;
2440  }
2441  else
2442  {
2443  double tol = reltol*cbv;
2444  xbv = tempBV-vt*log(1.0+cbv/(IRfactor*tSatCur));
2445  for( int i = 0; i < 25; ++i )
2446  {
2447  xbv = tempBV-vt*log(cbv/(IRfactor*tSatCur)+1.0-xbv/vt);
2448  xcbv = IRfactor*tSatCur*(exp((tempBV-xbv)/vt)-1.0+xbv/vt);
2449  if(fabs(xcbv-cbv)<=tol) break;
2450  }
2451  }
2452  tBrkdwnV = xbv;
2453  }
2454 #else
2455  if( BVGiven)
2456  {
2457  ScalarT IRFactor=tIRF;
2458  ScalarT cbv = IBV;
2459  ScalarT xbv;
2460  ScalarT cthreshlow; //lower threshold for IBV
2461  ScalarT cthreshhigh; //high threshold for IBV
2462  int iter_count;
2463  const int ITER_COUNT_MAX=8;
2464  ScalarT arg2;
2465 
2466  ScalarT arg1=3.0*vte/(e*tempBV);
2467  arg1=arg1*arg1*arg1;
2468  cthreshlow=tSatCur*IRFactor*(1-arg1);
2469  cthreshhigh=tSatCur*IRFactor*(1-1.0/(e*e*e)) *
2470  exp(-1.0*(3.0*vte-tempBV)/vte);
2471 
2472  if(cbv >= cthreshhigh)
2473  { //if IBV is too high, tBrkdwnV will go below 3NVt.
2474  tBrkdwnV=3.0*vte; //Clip tBrkdwnV to 3*N*Vt in this case (and hence
2475  } //clip IBV to cthreshhigh).
2476 
2477 
2478  else if(cbv <= cthreshlow)
2479  { //if IBV is too low, tBrkdwnV will go above
2480  tBrkdwnV=tempBV; //BV. Clip tBrkdwnV to BV in this case (and
2481  } //hence clip IBV to cthreshlow).
2482 
2483 
2484  //If IBV is in an acceptable range, perform a Picard iteration to find
2485  //tBrkdwnV, starting with an initial guess of tBrkdwnV=tempBV, and
2486  //running through the iteration ITER_COUNT_MAX times.
2487 
2488  else
2489  {
2490  xbv=tempBV;
2491  for(iter_count=0; iter_count < ITER_COUNT_MAX; iter_count++)
2492  {
2493  arg2=3.0*vte/(e*xbv);
2494  arg2=arg2*arg2*arg2;
2495  xbv=tempBV-vte*log(cbv/(tSatCur*IRFactor))+vte *
2496  log(1-arg2);
2497  }
2498  tBrkdwnV=xbv;
2499  }
2500 
2501 //Note that, not only is tBrkdwnV adjusted using this method, but the effective
2502 //value of Is (tSatCur) is adjusted as well. The code used to use Is before,
2503 //but now it will use Is*IRFactor*(1-(3*N*Vt/(e*tBrkdwnV))^3) instead. This is
2504 //reflected in changes made to Instance::updateIntermediateVars
2505 //(for "normal" level 1 and 2 diode models) for the reverse breakdown region.
2506 //Changes have not been made to the associated LambertW functions as of yet
2507 //since there seem to be other issues involved with those functions independent
2508 // of this change.
2509  }
2510 #endif
2511 
2512  return true;
2513 }
2514 
2515 
2516 //-----------------------------------------------------------------------------
2517 // Function : updateIntermediateVars
2518 // Purpose : update intermediate variables for one diode instance
2519 // Special Notes :
2520 // Scope : public
2521 // Creator :
2522 // Creation Date :
2523 //-----------------------------------------------------------------------------
2524 template <typename ScalarT>
2526 
2527  // inputs:
2528  const ScalarT & Vp,
2529  const ScalarT & Vpp,
2530  const ScalarT & Vn,
2531  const ScalarT & Vd,
2532 
2533  // instance params:
2534  const ScalarT & Temp,
2535  const ScalarT & tJctCap,
2536  const ScalarT & tJctPot,
2537  const ScalarT & tDepCap,
2538  const ScalarT & tF1,
2539  const ScalarT & tSatCur,
2540  const ScalarT & tSatCurR,
2541  const ScalarT & tVcrit,
2542  const ScalarT & tRS,
2543  const ScalarT & tCOND,
2544  const ScalarT & tIRF,
2545  const ScalarT & tIKF,
2546  const ScalarT & tBrkdwnV,
2547 
2548  // instance variables:
2549  const ScalarT & Area,
2550  const int & lambertWFlag,
2551  const double & gmin,
2552 
2553  // model params:
2554  const ScalarT M , // grading parameter
2555  const ScalarT BV , // breakdown voltage
2556  const ScalarT IBV , // reverse breakdown current
2557  const ScalarT NBV , // reverse breakdown ideality factor
2558  const ScalarT IBVL, // low-level reverse breakdown current
2559  const ScalarT NBVL, // low-level reverse breakdown ideality factor
2560  const ScalarT N , // non-ideality factor.
2561  const ScalarT NR , // emission coeff. for ISR.
2562  const ScalarT TT , // transit time.
2563  const ScalarT F2 , // capacitive polynomial factor
2564  const ScalarT F3 , // capacitive polynomial factor
2565 
2566  const int level,
2567 
2568  // outputs:
2569  ScalarT & Id,
2570  ScalarT & Gd,
2571  ScalarT & Qd,
2572  ScalarT & Cd,
2573  ScalarT & Gspr
2574 
2575  )
2576 {
2577  bool bsuccess = true;
2578 
2579 
2580 
2581  ScalarT Inorm; // normal diffusion current
2582  ScalarT Irec; // recombination current
2583  ScalarT Kgen; // generation factor
2584  ScalarT Khi; // high-injection factor
2585  ScalarT Gd1, DKgen;
2586  ScalarT Gd2, DKhi;
2587 
2588  ScalarT Vc;
2589 
2590  ScalarT Icd = 0.0;// NOT USED, must be deprecated.
2591 
2592  ScalarT Isat = tSatCur * Area;
2593  ScalarT IsatR = tSatCurR * Area;
2594  ScalarT KoverQ = static_cast<ScalarT>(CONSTKoverQ);
2595  ScalarT Vt = KoverQ * Temp;
2596  ScalarT Vte = N * Vt;
2597  ScalarT VteR = NR * Vt;
2598 
2599  Gspr = tCOND * Area;
2600 
2601  // Current and Conductivity
2602  //----------------------------------------------
2603 
2604  if(level == 1)
2605  {
2606  // Adjustment for linear portion of reverse current
2607  ScalarT IRfactor;
2608  //if(Vd >= 0) IRfactor = 1.0; //error? shouldn't this be Vd>=-3*Vte????
2609  if(Vd >= -3.0 * Vte) IRfactor = 1.0; //changing this to be consistent
2610  else IRfactor = tIRF; //with model in reference guide.
2611  Isat *= IRfactor;
2612 
2613  if (Vd >= -3.0 * Vte)
2614  {
2615  ScalarT arg1 = Vd / Vte;
2616  arg1 = Xycemin(static_cast<fadType>(CONSTMAX_EXP_ARG), arg1);
2617  ScalarT evd = exp(arg1);
2618 
2619  Id = Isat * (evd - 1.0) + gmin * Vd;
2620  Gd = Isat * evd / Vte + gmin;
2621  }
2622  // Linear reverse bias
2623  else if(!tBrkdwnV || (Vd >= -tBrkdwnV))
2624  {
2625  ScalarT arg = 3.0 * Vte / (Vd * CONSTe);
2626  arg = arg * arg * arg;
2627  Id = -Isat * (1.0 + arg) + gmin * Vd;
2628  Gd = Isat * 3.0 * arg / Vd + gmin;
2629  }
2630  // Reverse breakdown
2631  else
2632  {
2633  ScalarT arg1 = -(tBrkdwnV + Vd) / Vte;
2634  arg1 = Xycemin(static_cast<fadType>(CONSTMAX_EXP_ARG), arg1);
2635  ScalarT evrev = exp(arg1);
2636 
2637 #ifdef Xyce_BREAKDOWN_ORIGINAL
2638  Id = -Isat * evrev + gmin * Vd;
2639  Gd = Isat * evrev / Vte + gmin;
2640 #else
2641  //added by K. Santarelli 9/18/07 to account for change in tBrkdwnV
2642  //calculation.
2643  ScalarT arg2=3.0*Vte/(CONSTe*tBrkdwnV);
2644  arg2=arg2*arg2*arg2;
2645  ScalarT Isat_tBrkdwnV=Isat*(1-arg2);
2646  Id = -Isat_tBrkdwnV * evrev + gmin * Vd;
2647  Gd = Isat_tBrkdwnV * evrev / Vte + gmin;
2648 #endif
2649  }
2650  Vc = Vd;
2651  }
2652  else if(level == 2)
2653  {
2654  // Adjustment for linear portion of reverse current
2655  ScalarT IRfactor;
2656  //if(Vd >= 0) IRfactor = 1.0; //error? Shouldn't this be Vd >= -3*Vte?
2657  if(Vd >= -3.0*Vte) IRfactor=1.0; //changing it to be consistent with model
2658  else IRfactor = tIRF; //in the reference manual.
2659  Isat *= IRfactor;
2660 
2661  if (Vd >= -3.0 * Vte)
2662  {
2663  ScalarT arg1 = Vd / Vte;
2664  arg1 = Xycemin(static_cast<fadType>(CONSTMAX_EXP_ARG), arg1);
2665  ScalarT evd = exp(arg1);
2666  Inorm = Isat * (evd - 1.0) + gmin * Vd;
2667  Gd1 = Isat*evd/Vte + gmin;
2668 
2669  arg1 = Vd / VteR;
2670  arg1 = Xycemin(static_cast<fadType>(CONSTMAX_EXP_ARG), arg1);
2671  evd = exp(arg1);
2672  Irec = IsatR * (evd - 1.0);
2673  Gd2 = IsatR*evd/VteR;
2674 
2675  Khi = 1;
2676  DKhi = 0;
2677  if(tIKF > 0)
2678  {
2679  Khi = sqrt(tIKF/(tIKF+Inorm));
2680  DKhi = 0.5*Khi*Gd1/(tIKF+Inorm);
2681  }
2682  Kgen = 0;
2683  DKgen = 0;
2684  if(Irec != 0)
2685  {
2686  Kgen = sqrt( pow(((1-Vd/tJctPot)*(1-Vd/tJctPot) + 0.005),M) );
2687  DKgen = -M*(1-Vd/tJctPot)/(tJctPot*Kgen);
2688  }
2689 
2690  Id = Inorm*Khi + Irec*Kgen;
2691  Gd = Gd1*Khi + Inorm*DKhi + Gd2*Kgen + Irec*DKgen;
2692  }
2693  // Linear reverse bias
2694  else if(!tBrkdwnV || (Vd >= -tBrkdwnV))
2695  {
2696  ScalarT arg = 3.0 * Vte / (Vd * CONSTe);
2697  arg = arg * arg * arg;
2698  Id = -Isat * (1.0 + arg) + gmin * Vd;
2699  Gd = Isat * 3.0 * arg / Vd + gmin;
2700  }
2701  // Reverse breakdown
2702  else
2703  {
2704  ScalarT arg1 = -(tBrkdwnV + Vd) / Vte;
2705  arg1 = Xycemin(static_cast<fadType>(CONSTMAX_EXP_ARG), arg1);
2706  ScalarT evrev = exp(arg1);
2707 
2708 #ifdef Xyce_BREAKDOWN_ORIGINAL
2709  Id = -Isat * evrev + gmin * Vd;
2710  Gd = Isat * evrev / Vte + gmin;
2711 #else
2712  //added 9/18/07 by K. Santarelli to account for change in tBrkdwnV
2713  //calculation.
2714  ScalarT arg2=3.0*Vte/(CONSTe*tBrkdwnV);
2715  arg2=arg2*arg2*arg2;
2716  ScalarT Isat_tBrkdwnV=Isat*(1-arg2);
2717  Id = -Isat_tBrkdwnV * evrev + gmin * Vd;
2718  Gd = Isat_tBrkdwnV * evrev / Vte + gmin;
2719 #endif
2720  }
2721  Vc = Vd;
2722  } // level
2723 
2724  // Only compute if Capacitance is non-zero
2725  //---------------------------------------
2726  if (tJctCap != 0.0)
2727  {
2728  // Charge Storage
2729  ScalarT Czero = tJctCap * Area;
2730  if (Vc < tDepCap)
2731  {
2732  //ScalarT arg = 1.0 - Vd/VJ;
2733  ScalarT arg = 1.0 - Vc / tJctPot;
2734  ScalarT arg1 = -M * log(arg);
2735  arg1 = Xycemin(static_cast<fadType>(CONSTMAX_EXP_ARG), arg1);
2736  ScalarT sarg = exp(arg1);
2737 
2738  //Qd = TT*Id + VJ*Czero*(1.0-arg*sarg)/(1.0-M);
2739  Qd = TT * Id + tJctPot * Czero * (1.0 - arg * sarg) / (1.0 - M);
2740  Cd = TT * Gd + Czero * sarg;
2741  }
2742  else
2743  {
2744  ScalarT Czof2 = Czero / F2;
2745  ScalarT MotJctPot = M / tJctPot;
2746 
2747  //Qd = TT*Id + Czero*tF1 + Czof2*(F3*(Vd-tDepCap)+(M/(VJ+VJ))
2748  Qd = TT * Id + Czero * tF1 +
2749  Czof2 * (F3 * (Vc - tDepCap) + (0.5 * MotJctPot) *
2750  (Vc * Vc - tDepCap * tDepCap));
2751  //Cd = TT*Gd + Czof2*(F3+M*Vd/VJ);
2752  Cd = TT * Gd + Czof2 * (F3 + MotJctPot * Vc);
2753  }
2754  }
2755  else
2756  {
2757  Qd = 0.0;
2758  Cd = 0.0;
2759  }
2760 
2761  return bsuccess;
2762 }
2763 
2764 //-----------------------------------------------------------------------------
2765 // Function : applyLimiters
2766 // Purpose :
2767 // Special Notes :
2768 // Scope : public
2769 // Creator :
2770 // Creation Date :
2771 //-----------------------------------------------------------------------------
2772 template <typename ScalarT>
2773 bool applyLimiters
2774 (
2775  DeviceSupport & devSupport,
2776 
2777  // inputs:
2778  const ScalarT & Vp,
2779  const ScalarT & Vpp,
2780  const ScalarT & Vn,
2781 
2782  // parameters:
2783  const ScalarT & tVcrit,
2784  const ScalarT & Vte,
2785  const ScalarT & BV,
2786 
2787  // output and book-keeping
2788  ScalarT & Vd,
2789  ScalarT & Vd_orig,
2790  ScalarT & Vd_old,
2791 
2792  const ScalarT & currVd_old, // (extData.currStoVectorRawPtr)[li_storevd];
2793  const ScalarT & nextVd_old, // (extData.nextStoVectorRawPtr)[li_storevd];
2794 
2795  const double InitCond,
2796  const bool InitCondGiven,
2797  const bool BVGiven,
2798  const int off, // instance variable
2799  bool & origFlag, // instance variable
2800  const bool dotICapplies, // check all the "flagSol". if any == 1, then true
2801 
2802  // solver state variables:
2803  const int & newtonIter,
2804  const bool initJctFlag,
2805  const bool voltageLimiterFlag,
2806  const bool dcopFlag,
2807  const bool locaEnabledFlag
2808  )
2809 {
2810  // Junction Voltage
2811  Vd = Vpp - Vn;
2812  Vd_orig = Vd;
2813  origFlag = true;
2814 
2815  // Setup initial junction conditions if UIC enabled
2816  //------------------------------------------------
2817  if (newtonIter == 0)
2818  {
2819  if (initJctFlag && voltageLimiterFlag && !dotICapplies)
2820  {
2821  if (InitCondGiven)
2822  {
2823  Vd = InitCond;
2824  origFlag = false;
2825  }
2826  else if (off)
2827  {
2828  Vd = 0.0;
2829  origFlag = false;
2830  }
2831  else
2832  {
2833  Vd=tVcrit;
2834  origFlag = false;
2835  }
2836  }
2837 
2838  // assume there is no history -- then check if the
2839  // state vector can overwrite this
2840  Vd_old = Vd;
2841 
2842  if (!(dcopFlag)|| (locaEnabledFlag && dcopFlag))
2843  {
2844  Vd_old = currVd_old;
2845  }
2846  }
2847  else // just do this whenever it isn't the first iteration:
2848  {
2849  Vd_old = nextVd_old;
2850  }
2851 
2852  // Voltage limiting based on mode of diode
2853  //---------------------------------------
2854  if (voltageLimiterFlag)
2855  {
2856  int ichk = 0;
2857 
2858  if (newtonIter >= 0)
2859  {
2860  //Test if breakdown voltage given or not
2861  if (BVGiven && (Vd < Xycemin(0.0, -BV + 10.0 * Vte)))
2862  {
2863  double Vdtmp = -( BV + Vd );
2864  Vdtmp = devSupport.pnjlim(Vdtmp, -(Vd_old+BV), Vte, tVcrit, &ichk);
2865  Vd = -(Vdtmp + BV);
2866  }
2867  else
2868  Vd = devSupport.pnjlim(Vd, Vd_old, Vte, tVcrit, &ichk);
2869 
2870  if (ichk) origFlag = false;
2871  }
2872  }
2873 
2874  return true;
2875 }
2876 
2877 //-----------------------------------------------------------------------------
2878 // Function : diodeSensitivity::operator
2879 // Purpose : produces df/dp and dq/dp, where p= any diode parameter.
2880 // Special Notes :
2881 // Scope : public
2882 // Creator : Eric Keiter, SNL
2883 // Creation Date : 7/18/2014
2884 //-----------------------------------------------------------------------------
2886  const ParameterBase &entity,
2887  const std::string &name,
2888  std::vector<double> & dfdp,
2889  std::vector<double> & dqdp,
2890  std::vector<double> & dbdp,
2891  std::vector<int> & Findices,
2892  std::vector<int> & Qindices,
2893  std::vector<int> & Bindices
2894  ) const
2895 {
2896  const ParameterBase * e1 = &entity;
2897  const Model & mod = *(dynamic_cast<const Model *> (e1));
2898 
2899  int sizeInstance = mod.instanceContainer.size();
2900 
2901  dfdp.resize(3*sizeInstance);
2902  dqdp.resize(3*sizeInstance);
2903  Findices.resize(3*sizeInstance);
2904  Qindices.resize(3*sizeInstance);
2905 
2906  // model params:
2907  fadType TNOM = mod.TNOM;
2908  fadType VJ = mod.VJ;
2909  fadType CJO = mod.CJO;
2910  fadType M = mod.M;
2911  fadType N = mod.N;
2912  fadType IS = mod.IS;
2913  fadType EG = mod.EG;
2914  fadType XTI = mod.XTI;
2915  fadType RS = mod.RS;
2916  fadType COND = mod.COND;
2917  fadType IRF = mod.IRF;
2918  fadType NR = mod.NR;
2919  fadType IKF = mod.IKF;
2920  fadType TIKF = mod.TIKF;
2921  fadType ISR = mod.ISR;
2922  fadType IBV = mod.IBV;
2923  fadType IBVL = mod.IBVL;
2924  fadType NBV = mod.NBV;
2925  fadType NBVL = mod.NBVL;
2926  fadType BV = mod.BV;
2927  fadType TT = mod.TT;
2928  fadType F2 = mod.F2;
2929  fadType F3 = mod.F3;
2930 
2931  fadType TBV1 = mod.TBV1;
2932  fadType TBV2 = mod.TBV2;
2933  fadType TRS1 = mod.TRS1;
2934  fadType TRS2 = mod.TRS2;
2935  fadType FC = mod.FC;
2936  fadType KF = mod.KF;
2937  fadType AF = mod.AF;
2938 
2939  std::string paramName = ExtendedString( name ).toUpper();
2940 
2941  if (paramName=="VJ") { VJ.diff(0,1); }
2942  else if (paramName=="CJO") { CJO.diff(0,1); }
2943  else if (paramName=="CJ") { CJO.diff(0,1); } // CJ is a synonym for CJO
2944  else if (paramName=="CJ0") { CJO.diff(0,1); } // CJ0 is a synonym for CJO
2945  else if (paramName=="M") { M.diff(0,1); }
2946  else if (paramName=="N") { N.diff(0,1); }
2947  else if (paramName=="IS") { IS.diff(0,1); }
2948  else if (paramName=="JS") { IS.diff(0,1); } // JS is a synonym for IS
2949  else if (paramName=="EG") { EG.diff(0,1); }
2950  else if (paramName=="XTI") { XTI.diff(0,1); }
2951  else if (paramName=="RS") { RS.diff(0,1); }
2952  else if (paramName=="COND") { COND.diff(0,1); }
2953  else if (paramName=="IRF") { IRF.diff(0,1); }
2954  else if (paramName=="NR") { NR.diff(0,1); }
2955  else if (paramName=="IKF") { IKF.diff(0,1); }
2956  else if (paramName=="TIKF") { TIKF.diff(0,1); }
2957  else if (paramName=="ISR") { ISR.diff(0,1); }
2958  else if (paramName=="IBV") { IBV.diff(0,1); }
2959  else if (paramName=="IBVL") { IBVL.diff(0,1); }
2960  else if (paramName=="NBV") { NBV.diff(0,1); }
2961  else if (paramName=="NBVL") { NBVL.diff(0,1); }
2962  else if (paramName=="BV") { BV.diff(0,1); }
2963  else if (paramName=="VB") { BV.diff(0,1); } // VB is a synonym for BV
2964  else if (paramName=="TT") { TT.diff(0,1); }
2965  else if (paramName=="FC") { FC.diff(0,1); }
2966  else if (paramName=="KF") { KF.diff(0,1); }
2967  else if (paramName=="AF") { AF.diff(0,1); }
2968  else if (paramName=="TNOM") { TNOM.diff(0,1); }
2969 
2970  else if (paramName=="TBV1") { TBV1.diff(0,1); }
2971  else if (paramName=="TBV2") { TBV2.diff(0,1); }
2972  else if (paramName=="TRS1") { TRS1.diff(0,1); }
2973  else if (paramName=="TRS2") { TRS2.diff(0,1); }
2974 
2975  processParams( M, EG, FC, RS, COND, F2, F3);
2976 
2977  int inst=0;
2978 
2979  for (std::vector<Instance *>::const_iterator in = mod.instanceContainer.begin();
2980  in != mod.instanceContainer.end(); ++in, ++inst)
2981  {
2982  double * solVec = (*in)->extData.nextSolVectorRawPtr;
2983 
2984  fadType Vpp = solVec[(*in)->li_Pri];
2985  fadType Vn = solVec[(*in)->li_Neg];
2986  fadType Vp = solVec[(*in)->li_Pos];
2987  fadType Vd = Vpp - Vn;
2988 
2989  // instance variables:
2990  fadType tJctCap = 0.0;
2991  fadType tJctPot = 0.0;
2992  fadType tDepCap = 0.0;
2993  fadType tF1 = 0.0;
2994  fadType tSatCur = 0.0;
2995  fadType tSatCurR = 0.0;
2996  fadType tVcrit = 0.0;
2997  fadType tRS = 0.0;
2998  fadType tCOND = 0.0;
2999  fadType tIRF = 0.0;
3000  fadType tIKF = 0.0;
3001  fadType tBrkdwnV = 0.0;
3002 
3003  // instance parameters:
3004  fadType Temp = (*in)->Temp;
3005  fadType Area = (*in)->Area;
3006 
3008  (*in)->Temp,
3009  Temp, tJctCap, tJctPot, tDepCap, tF1, tSatCur, tSatCurR,
3010  tVcrit, tRS, tCOND, tIRF, tIKF, tBrkdwnV,
3011  TNOM, VJ, CJO, M, N, IS, EG, XTI, RS, COND, IRF,
3012  NR, IKF, TIKF, ISR, IBV, BV,
3013  mod.BVGiven,
3014  TBV1, TBV2, TRS1, TRS2, FC,
3015  mod.getLevel()
3016  );
3017 
3018  fadType Id = 0.0;
3019  fadType Gd = 0.0;
3020  fadType Qd = 0.0;
3021  fadType Cd = 0.0;
3022  fadType Gspr = 0.0;
3023 
3025  // inputs:
3026  Vp, Vpp, Vn, Vd,
3027  // instance params:
3028  Temp, tJctCap, tJctPot, tDepCap, tF1,
3029  tSatCur, tSatCurR, tVcrit, tRS, tCOND,
3030  tIRF, tIKF, tBrkdwnV,
3031  // instance variables:
3032  Area, (*in)->lambertWFlag, (*in)->getDeviceOptions().gmin,
3033  // model params:
3034  M, BV, IBV, NBV, IBVL, NBVL, N, NR, TT, F2, F3,
3035  mod.getLevel(),
3036  // outputs:
3037  Id, Gd, Qd, Cd, Gspr
3038  );
3039 
3040  int iPos=0+inst*3;
3041  int iNeg=1+inst*3;
3042  int iPri=2+inst*3;
3043 
3044  fadType Ir = Gspr * (Vp - Vpp);
3045  dfdp[iPos] -= -Ir.dx(0);
3046  dfdp[iNeg] -= Id.dx(0);
3047  dfdp[iPri] -= (-Id.dx(0) + Ir.dx(0));
3048 
3049  dqdp[iPos] = 0.0;
3050  dqdp[iNeg] -= Qd.dx(0);
3051  dqdp[iPri] -= -Qd.dx(0);
3052 
3053  Findices[iPos] = (*in)->li_Pos;
3054  Findices[iNeg] = (*in)->li_Neg;
3055  Findices[iPri] = (*in)->li_Pri;
3056 
3057  Qindices[iPos] = (*in)->li_Pos;
3058  Qindices[iNeg] = (*in)->li_Neg;
3059  Qindices[iPri] = (*in)->li_Pri;
3060  }
3061 }
3062 
3063 } // namespace Diode
3064 } // namespace Device
3065 } // namespace Xyce
const InstanceName & getName() const
static std::vector< int > jacMap
Definition: N_DEV_Diode.h:346
static std::vector< int > jacMap_RS
Definition: N_DEV_Diode.h:345
const DeviceOptions & deviceOptions_
Descriptor & addPar(const char *parName, T default_value, T U::*varPtr)
Adds the parameter description to the parameter map.
Definition: N_DEV_Pars.h:1429
#define CONSTEg0
Definition: N_DEV_Const.h:73
bool lambertWBreakdownCurrent(double Isat, double Vte, double RS)
Definition: N_DEV_Diode.C:1773
#define CONSTQ
Definition: N_DEV_Const.h:51
#define CONSTREFTEMP
Definition: N_DEV_Const.h:56
static std::vector< std::vector< int > > jacStamp_RS
Definition: N_DEV_Diode.h:342
double pnjlim(double vnew, double vold, double vt, double vcrit, int *icheck)
bool given(const std::string &parameter_name) const
Pure virtual class to augment a linear system.
Parameter may be specified as time dependent expression from netlist.
Definition: N_DEV_Pars.h:67
void addInternalNode(Util::SymbolTable &symbol_table, int index, const InstanceName &instance_name, const std::string &lead_name)
const std::string & getEncodedName() const
Return the instance name encoded as: [s:]*xname [s:]*Ytype!name [s:]*Utype!name!count.
void registerLIDs(const std::vector< int > &intLIDVecRef, const std::vector< int > &extLIDVecRef)
Definition: N_DEV_Diode.C:481
void registerStateLIDs(const std::vector< int > &staLIDVecRef)
Definition: N_DEV_Diode.C:570
Sacado::Fad::SFad< double, 1 > fadType
Definition: N_DEV_Diode.h:65
#define CONSTMAX_EXP_ARG
Definition: N_DEV_Const.h:110
void setNumStoreVars(int num_store_vars)
void addBranchDataNode(Util::SymbolTable &symbol_table, int index, const InstanceName &instance_name, const std::string &lead_name)
std::vector< int > li_Neg
InstanceVector::const_iterator getInstanceEnd() const
Returns an iterator to the ending of the vector of all instances created for this device...
Base class for all parameters.
Definition: N_DEV_Pars.h:169
#define AssertLIDs(cmp)
std::vector< int > li_Pos
Parameter is subject to being set to minimum junction capacitance.
Definition: N_DEV_Pars.h:71
RetScalarT Vt(Arg1ScalarT U, Arg2ScalarT Ud)
#define CONSTe
Definition: N_DEV_Const.h:60
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
virtual void operator()(const ParameterBase &entity, const std::string &param, std::vector< double > &dfdp, std::vector< double > &dqdp, std::vector< double > &dbdp, std::vector< int > &Findices, std::vector< int > &Qindices, std::vector< int > &Bindices) const
Definition: N_DEV_Diode.C:2885
Parameter is subject to being set to minimum lead resistance.
Definition: N_DEV_Pars.h:70
bool processParams(ScalarT &M, ScalarT &EG, ScalarT &FC, const ScalarT &RS, ScalarT &COND, ScalarT &F2, ScalarT &F3)
Definition: N_DEV_Diode.C:2235
Instance(const Configuration &configuration, const InstanceBlock &instance_block, Model &model, const FactoryBlock &factory_block)
Definition: N_DEV_Diode.C:346
double tnom
nominal temperature for device params.
InstanceVector::const_iterator getInstanceBegin() const
Returns an iterator to the beginning of the vector of all instances created for this device...
#define N_MINLOG
Definition: N_ANP_NOISE.C:108
static void loadModelParameters(ParametricData< Model > &model_parameters)
Definition: N_DEV_Diode.C:94
std::vector< Param > params
Parameters from the line.
std::vector< double > noiseDens
void registerBranchDataLIDs(const std::vector< int > &branchLIDVecRef)
In addition to state vector, Xyce maintains a separate datastructure called a "branch data" vector...
Definition: N_DEV_Diode.C:622
std::vector< std::string > noiseNames
std::vector< Instance * > instanceContainer
Definition: N_DEV_Diode.h:489
void setParams(const std::vector< Param > &params)
const std::string & getName() const
static diodeSensitivity diodeSens
Definition: N_DEV_Diode.h:97
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
bool updateTemperature(const double &temp=-999.0)
Definition: N_DEV_Diode.C:1418
void getNoiseSources(Xyce::Analysis::NoiseData &noiseData)
Definition: N_DEV_Diode.C:961
const DeviceOptions & getDeviceOptions() const
#define CONSTroot2
Definition: N_DEV_Const.h:50
bool processInstanceParams()
processInstanceParams
Definition: N_DEV_Diode.C:1878
static Config< T > & addConfiguration()
Adds the device to the Xyce device configuration.
static std::vector< std::vector< int > > jacStamp
Definition: N_DEV_Diode.h:343
Linear::Matrix * dFdxMatrixPtr
const DeviceOptions & getDeviceOptions() const
Returns the device options given during device construction.
The Device class is an interface for device implementations.
Definition: N_DEV_Device.h:101
void loadNodeSymbols(Util::SymbolTable &symbol_table) const
Populates and returns the store name map.
Definition: N_DEV_Diode.C:548
bool processParams()
processParams
Definition: N_DEV_Diode.C:1847
void addStoreNode(Util::SymbolTable &symbol_table, int index, const InstanceName &instance_name, const std::string &lead_name)
const std::vector< std::vector< int > > & jacobianStamp() const
Definition: N_DEV_Diode.C:641
bool lambertWLinearReverseBias(double Isat, double Vte, double RS)
Definition: N_DEV_Diode.C:1720
virtual std::ostream & printOutInstances(std::ostream &os) const
Definition: N_DEV_Diode.C:2021
const SolverState & solverState_
void setupNoiseSources(Xyce::Analysis::NoiseData &noiseData)
Definition: N_DEV_Diode.C:928
Class Configuration contains device configuration data.
static std::vector< std::vector< int > > jacMap2_RS
Definition: N_DEV_Diode.h:348
std::vector< double > lnNoiseDens
bool updateIntermediateVars(const ScalarT &Vp, const ScalarT &Vpp, const ScalarT &Vn, const ScalarT &Vd, const ScalarT &Temp, const ScalarT &tJctCap, const ScalarT &tJctPot, const ScalarT &tDepCap, const ScalarT &tF1, const ScalarT &tSatCur, const ScalarT &tSatCurR, const ScalarT &tVcrit, const ScalarT &tRS, const ScalarT &tCOND, const ScalarT &tIRF, const ScalarT &tIKF, const ScalarT &tBrkdwnV, const ScalarT &Area, const int &lambertWFlag, const double &gmin, const ScalarT M, const ScalarT BV, const ScalarT IBV, const ScalarT NBV, const ScalarT IBVL, const ScalarT NBVL, const ScalarT N, const ScalarT NR, const ScalarT TT, const ScalarT F2, const ScalarT F3, const int level, ScalarT &Id, ScalarT &Gd, ScalarT &Qd, ScalarT &Cd, ScalarT &Gspr)
Definition: N_DEV_Diode.C:2525
#define M
static Device * factory(const Configuration &configuration, const FactoryBlock &factory_block)
Definition: N_DEV_Diode.C:2204
void jacStampMap(const JacobianStamp &stamp_parent, IdVector &map_parent, JacobianStamp &map2_parent, JacobianStamp &stamp, IdVector &map, JacobianStamp &map2, int from, int to, int original_size)
const SolverState & getSolverState() const
void lambertw(double x, double &w, int &ierr, double &xi)
#define CONSTbetaEg
Definition: N_DEV_Const.h:75
virtual bool loadDAEMatrices(Linear::Matrix &dFdx, Linear::Matrix &dQdx)
Populates the device's Jacobian object with these pointers.
Definition: N_DEV_Diode.C:2163
void setNumBranchDataVars(int num_branch_data_vars)
virtual bool updateState(double *solVec, double *staVec, double *stoVec)
Updates the devices state information.
Definition: N_DEV_Diode.C:2082
#define Xyce_NONPOINTER_MATRIX_LOAD
Definition: N_DEV_Bsrc.C:97
void noiseSupport(double &noise, double &lnNoise, const int type, const double param, const double temp)
double gmin
minimum allowed conductance.
#define RS
static void loadInstanceParameters(ParametricData< Instance > &instance_parameters)
Definition: N_DEV_Diode.C:70
#define CONSTKoverQ
Definition: N_DEV_Const.h:58
static std::vector< std::vector< int > > jacMap2
Definition: N_DEV_Diode.h:349
ModelBlock represents a .MODEL line from the netlist.
bool lambertWCurrent(double Isat, double Vte, double RS)
Definition: N_DEV_Diode.C:1644
#define CONSTalphaEg
Definition: N_DEV_Const.h:74
Manages parameter binding for class C.
Definition: N_DEV_Pars.h:214
InstanceBlock represent a device instance line from the netlist.
Util::Param temp
operating temperature of ckt.
std::vector< Param > params
void registerJacLIDs(const std::vector< std::vector< int > > &jacLIDVec)
Definition: N_DEV_Diode.C:657
Linear::Matrix * dQdxMatrixPtr
#define CONSTEg300
Definition: N_DEV_Const.h:72
bool applyLimiters(DeviceSupport &devSupport, const ScalarT &Vp, const ScalarT &Vpp, const ScalarT &Vn, const ScalarT &tVcrit, ScalarT &Vd, ScalarT &Vd_orig, ScalarT &Vd_old, const ScalarT &currVd_old, const ScalarT &nextVd_old, const double InitCond, const bool InitCondGiven, const bool BVGiven, const int off, bool &origFlag, const bool dotICapplies, const int &newtonIter, const bool initJctFlag, const bool voltageLimiterFlag, const bool dcopFlag, const bool locaEnabledFlag)
virtual void forEachInstance(DeviceInstanceOp &op) const
Apply a device instance "op" to all instances associated with this model.
Definition: N_DEV_Diode.C:2063
int li_branch_data
Index for Lead Current and junction voltage (for power calculations)
Definition: N_DEV_Diode.h:406
ScalarT Xycemin(ScalarT f1, ScalarT f2)
Definition: N_DEV_Diode.h:74
Linear::Vector * flagSolVectorPtr
void setModParams(const std::vector< Param > &params)
virtual bool loadDAEVectors(double *solVec, double *fVec, double *qVec, double *bVec, double *storeLeadF, double *storeLeadQ, double *leadF, double *leadQ, double *junctionV)
Populates the device's ExternData object with these pointers.
Definition: N_DEV_Diode.C:2105
bool updateTemperature( ScalarT &Temp, ScalarT &tJctCap, ScalarT &tJctPot, ScalarT &tDepCap, ScalarT &tF1, ScalarT &tSatCur, ScalarT &tSatCurR, ScalarT &tVcrit, ScalarT &tRS, ScalarT &tCOND, ScalarT &tIRF, ScalarT &tIKF, ScalarT &tBrkdwnV, const ScalarT &TNOM, const ScalarT &VJ, const ScalarT &CJO, const ScalarT &M, const ScalarT &N, const ScalarT &IS, const ScalarT &EG, const ScalarT &XTI, const ScalarT &RS, const ScalarT &COND, const ScalarT &IRF, const ScalarT &NR, const ScalarT &IKF, const ScalarT &TIKF, const ScalarT &ISR, const ScalarT &IBV, const ScalarT &BV, const bool &BVGiven, const ScalarT &TBV1, const ScalarT &TBV2, const ScalarT &TRS1, const ScalarT &TRS2, const ScalarT &FC, const int level)
#define CONSTboltz
Definition: N_DEV_Const.h:53
void registerStoreLIDs(const std::vector< int > &stoLIDVecRef)
Definition: N_DEV_Diode.C:586