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