Xyce  6.1
N_DEV_MOSFET3.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_MOSFET3.C,v $
27 //
28 // Purpose : Implement the MOSFET Level 3 static model
29 //
30 // Special Notes : BADMOS3 option not supported.
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.257.2.1 $
40 //
41 // Revision Date : $Date: 2015/04/02 18:20:11 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 
49 // ---------- Standard Includes ----------
50 
51 // ---------- Xyce Includes ----------
52 #include <N_DEV_Const.h>
53 #include <N_DEV_DeviceOptions.h>
54 #include <N_DEV_ExternData.h>
55 #include <N_DEV_MOSFET3.h>
56 #include <N_DEV_MatrixLoadData.h>
57 #include <N_DEV_SolverState.h>
58 #include <N_DEV_Message.h>
59 #include <N_DEV_Message.h>
60 #include <N_DEV_Message.h>
61 #include <N_ERH_ErrorMgr.h>
62 
63 #include <N_DEV_MOSFET1.h>
64 
65 #include <N_LAS_Matrix.h>
66 #include <N_LAS_Vector.h>
67 #include <N_UTL_FeatureTest.h>
68 #include <N_UTL_Math.h>
69 #include <N_ANP_NoiseData.h>
70 
71 namespace Xyce {
72 namespace Device {
73 
74 namespace MOSFET3 {
75 
77 {
78  p.addPar ("TEMP",0.0,&MOSFET3::Instance::temp)
79  .setExpressionAccess(ParameterType::TIME_DEP)
80  .setUnit(STANDARD)
81  .setCategory(CAT_NONE)
82  .setDescription("Device temperature"),
83 
84  p.addPar ("L",0.0,&MOSFET3::Instance::l)
85  .setOriginalValueStored(true)
86  .setUnit(U_METER)
87  .setCategory(CAT_GEOMETRY)
88  .setDescription("Channel length");
89 
90  p.addPar ("W",0.0,&MOSFET3::Instance::w)
91  .setOriginalValueStored(true)
92  .setUnit(U_METER)
93  .setCategory(CAT_GEOMETRY)
94  .setDescription("Channel width");
95 
97  .setUnit(U_METER2)
98  .setCategory(CAT_GEOMETRY)
99  .setDescription("Drain diffusion area");
100 
102  .setUnit(U_METER2)
103  .setCategory(CAT_GEOMETRY)
104  .setDescription("Source diffusion area");
105 
107  .setUnit(U_SQUARES)
108  .setCategory(CAT_GEOMETRY)
109  .setDescription("Multiplier for RSH to yield parasitic resistance of drain");
110 
112  .setUnit(U_SQUARES)
113  .setCategory(CAT_GEOMETRY)
114  .setDescription("Multiplier for RSH to yield parasitic resistance of source");
115 
117  .setUnit(U_METER)
118  .setCategory(CAT_GEOMETRY)
119  .setDescription("Drain diffusion perimeter");
120 
122  .setUnit(U_METER)
123  .setCategory(CAT_GEOMETRY)
124  .setDescription("Source diffusion perimeter");
125 
127  .setUnit(U_NONE)
128  .setCategory(CAT_CONTROL)
129  .setDescription("Multiplier for M devices connected in parallel");
130 
131  // Initial conditions
132  p.addPar ("IC1",0.0,&MOSFET3::Instance::icVDS)
133  .setGivenMember(&MOSFET3::Instance::IC_GIVEN)
134  .setUnit(U_VOLT)
135  .setCategory(CAT_INITIAL)
136  .setDescription("Initial condition on Drain-Source voltage");
137 
138  p.addPar ("IC2",0.0,&MOSFET3::Instance::icVGS)
139  .setGivenMember(&MOSFET3::Instance::IC_GIVEN)
140  .setUnit(U_VOLT)
141  .setCategory(CAT_INITIAL)
142  .setDescription("Initial condition on Gate-Source voltage");
143 
144  p.addPar ("IC3",0.0,&MOSFET3::Instance::icVBS)
145  .setGivenMember(&MOSFET3::Instance::IC_GIVEN)
146  .setUnit(U_VOLT)
147  .setCategory(CAT_INITIAL)
148  .setDescription("Initial condition on Bulk-Source voltage");
149 
150  p.makeVector ("IC",3);
151 
152  // Set up non-double precision variables:
153  p.addPar ("OFF",false, &MOSFET3::Instance::OFF)
154  .setUnit(U_LOGIC)
155  .setCategory(CAT_VOLT)
156  .setDescription("Initial condition of no voltage drops across device");
157 }
158 
160 {
161  // Set up double precision variables:
162  p.addPar ("L",1e-4,&MOSFET3::Model::model_l)
163  .setUnit(U_METER)
164  .setCategory(CAT_GEOMETRY)
165  .setDescription("Default channel length");
166 
167  p.addPar ("W",1e-4,&MOSFET3::Model::model_w)
168  .setUnit(U_METER)
169  .setCategory(CAT_GEOMETRY)
170  .setDescription("Default channel width");
171 
172  p.addPar ("VTO",0.0,&MOSFET3::Model::vt0)
173  .setUnit(U_VOLT)
174  .setCategory(CAT_VOLT)
175  .setDescription("Zero-bias threshold voltage");
176 
178  .setUnit(U_AMPVM2)
179  .setCategory(CAT_PROCESS)
180  .setDescription("Transconductance coefficient");
181 
182  p.addPar ("GAMMA",0.0,&MOSFET3::Model::gamma)
183  .setUnit(U_VOLTH)
184  .setCategory(CAT_PROCESS)
185  .setDescription("Bulk threshold parameter");
186 
187  p.addPar ("PHI",0.6,&MOSFET3::Model::phi)
188  .setUnit(U_VOLT)
189  .setCategory(CAT_PROCESS)
190  .setDescription("Surface potential");
191 
193  .setExpressionAccess(ParameterType::MIN_RES)
194  .setUnit(U_OHM)
195  .setCategory(CAT_RES)
196  .setDescription("Drain ohmic resistance");
197 
199  .setExpressionAccess(ParameterType::MIN_RES)
200  .setUnit(U_OHM)
201  .setCategory(CAT_RES)
202  .setDescription("Source ohmic resistance");
203 
204  p.addPar ("CBD",0.0,&MOSFET3::Model::capBD)
205  .setExpressionAccess(ParameterType::MIN_CAP)
206  .setGivenMember(&MOSFET3::Model::capBDGiven)
207  .setUnit(U_FARAD)
208  .setCategory(CAT_CAP)
209  .setDescription("Zero-bias bulk-drain p-n capacitance");
210 
211  p.addPar ("CBS",0.0,&MOSFET3::Model::capBS)
212  .setExpressionAccess(ParameterType::MIN_CAP)
213  .setGivenMember(&MOSFET3::Model::capBSGiven)
214  .setUnit(U_FARAD)
215  .setCategory(CAT_CAP)
216  .setDescription("Zero-bias bulk-source p-n capacitance");
217 
218  p.addPar ("IS",1e-14, &MOSFET3::Model::jctSatCur)
219  .setUnit(U_AMP)
220  .setCategory(CAT_CURRENT)
221  .setDescription("Bulk p-n saturation current");
222 
224  .setUnit(U_VOLT)
225  .setCategory(CAT_VOLT)
226  .setDescription("Bulk p-n bottom potential");
227 
229  .setUnit(U_FARADMM1)
230  .setCategory(CAT_CAP)
231  .setDescription("Gate-source overlap capacitance/channel width");
232 
234  .setUnit(U_FARADMM1)
235  .setCategory(CAT_CAP)
236  .setDescription("Gate-drain overlap capacitance/channel width");
237 
239  .setUnit(U_FARADMM1)
240  .setCategory(CAT_CAP)
241  .setDescription("Gate-bulk overlap capacitance/channel length");
242 
244  .setUnit(U_OHM)
245  .setCategory(CAT_RES)
246  .setDescription("Drain,source diffusion sheet resistance");
247 
249  .setGivenMember(&MOSFET3::Model::bulkCapFactorGiven)
250  .setUnit(U_FARADMM2)
251  .setCategory(CAT_CAP)
252  .setDescription("Bulk p-n zero-bias bottom capacitance/area");
253 
255  .setUnit(U_NONE)
256  .setCategory(CAT_DOPING)
257  .setDescription("Bulk p-n bottom grading coefficient");
258 
261  .setUnit(U_FARADMM2)
262  .setCategory(CAT_CAP)
263  .setDescription("Bulk p-n zero-bias sidewall capacitance/area");
264 
266  .setUnit(U_NONE)
267  .setCategory(CAT_DOPING)
268  .setDescription("Bulk p-n sidewall grading coefficient");
269 
271  .setUnit(U_AMPMM2)
272  .setCategory(CAT_PROCESS)
273  .setDescription("Bulk p-n saturation current density");
274 
275  p.addPar ("TOX",1e-7,&MOSFET3::Model::oxideThickness)
276  .setOriginalValueStored(true)
277  .setUnit(U_METER)
278  .setCategory(CAT_GEOMETRY)
279  .setDescription("Gate oxide thickness");
280 
281  p.addPar ("LD",0.0,&MOSFET3::Model::latDiff)
282  .setUnit(U_METER)
283  .setCategory(CAT_DOPING)
284  .setDescription("Lateral diffusion length");
285 
287  .setUnit(U_CMM2VM1SM1)
289  .setDescription("Surface mobility");
290 
292  .setUnit(U_CMM2VM1SM1)
293  .setCategory(CAT_PROCESS)
294  .setDescription("Surface mobility");
295 
297  .setUnit(U_NONE)
298  .setCategory(CAT_CAP)
299  .setDescription("Bulk p-n forward-bias capacitance coefficient");
300 
302  .setUnit(U_CMM3)
303  .setCategory(CAT_DOPING)
304  .setDescription("Substrate doping density");
305 
307  .setUnit(U_CMM2)
308  .setCategory(CAT_PROCESS)
309  .setDescription("Surface state density");
310 
311  p.addPar ("ETA",0.0,&MOSFET3::Model::eta)
312  .setUnit(U_NONE)
313  .setCategory(CAT_PROCESS)
314  .setDescription("Static feedback");
315 
316  p.addPar ("DELTA",0.0,&MOSFET3::Model::delta)
317  .setUnit(U_NONE)
318  .setCategory(CAT_PROCESS)
319  .setDescription("Width effect on threshold");
320 
322  .setUnit(U_CMM2)
323  .setCategory(CAT_PROCESS)
324  .setDescription("Fast surface state density");
325 
326  p.addPar ("THETA",0.0,&MOSFET3::Model::theta)
327  .setUnit(U_VOLTM1)
328  .setCategory(CAT_PROCESS)
329  .setDescription("Mobility modulation");
330 
331  p.addPar ("VMAX",0.0,&MOSFET3::Model::maxDriftVel)
332  .setUnit(U_MSM1)
333  .setCategory(CAT_PROCESS)
334  .setDescription("Maximum drift velocity");
335 
336  p.addPar ("KAPPA",0.2,&MOSFET3::Model::kappa)
337  .setUnit(U_NONE)
338  .setCategory(CAT_NONE)
339  .setDescription("Saturation field factor");
340 
342  .setUnit(U_METER)
343  .setCategory(CAT_GEOMETRY)
344  .setDescription("Metallurgical junction depth");
345 
346  p.addPar ("TNOM",27.0,&MOSFET3::Model::tnom)
347  .setUnit(STANDARD)
348  .setCategory(CAT_NONE)
349  .setDescription("Parameter measurement temperature");
350 
351  p.addPar ("KF",0.0,&MOSFET3::Model::fNcoef)
352  .setUnit(U_NONE)
353  .setCategory(CAT_FLICKER)
354  .setDescription("Flicker noise coefficient");
355 
356  p.addPar ("AF",1.0,&MOSFET3::Model::fNexp)
357  .setUnit(U_NONE)
358  .setCategory(CAT_FLICKER)
359  .setDescription("Flicker noise exponent");
360 
361  // Set up non-double precision variables:
362  p.addPar ("TPG",1,&MOSFET3::Model::gateType)
363  .setUnit(U_NONE)
364  .setCategory(CAT_MATERIAL)
365  .setDescription("Gate material type (-1 = same as substrate,0 = aluminum,1 = opposite of substrate)");
366 
368 }
369 
370 std::vector< std::vector<int> > Instance::jacStamp_DC_SC;
371 std::vector< std::vector<int> > Instance::jacStamp_DC;
372 std::vector< std::vector<int> > Instance::jacStamp_SC;
373 std::vector< std::vector<int> > Instance::jacStamp;
374 
375 std::vector<int> Instance::jacMap_DC_SC;
376 std::vector<int> Instance::jacMap_DC;
377 std::vector<int> Instance::jacMap_SC;
378 std::vector<int> Instance::jacMap;
379 
380 std::vector< std::vector<int> > Instance::jacMap2_DC_SC;
381 std::vector< std::vector<int> > Instance::jacMap2_DC;
382 std::vector< std::vector<int> > Instance::jacMap2_SC;
383 std::vector< std::vector<int> > Instance::jacMap2;
384 
385 // Class Instance
386 //-----------------------------------------------------------------------------
387 // Function : Instance::processParams
388 // Purpose :
389 // Special Notes :
390 // Scope : public
391 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
392 // Creation Date : 6/03/02
393 //-----------------------------------------------------------------------------
395 {
396 
397  // now set the temperature related stuff
399 
400  return true;
401 }
402 
403 //-----------------------------------------------------------------------------
404 // Function : Instance::Instance
405 // Purpose : instance block constructor
406 // Special Notes :
407 // Scope : public
408 // Creator : Tom Russo, Component Information and Models
409 // Creation Date : 3/21/01
410 //-----------------------------------------------------------------------------
412  const Configuration & configuration,
413  const InstanceBlock & IB,
414  Model & Miter,
415  const FactoryBlock & factory_block)
416  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
417  model_(Miter),
418  dNode(0),
419  gNode(0),
420  sNode(0),
421  bNode(0),
422  dNodePrime(0),
423  sNodePrime(0),
424  l(getDeviceOptions().defl),
425  w(getDeviceOptions().defw),
426  OFF(false),
427  drainArea(getDeviceOptions().defad),
428  sourceArea(getDeviceOptions().defas),
429  drainSquares(1.0),
430  sourceSquares(1.0),
431  drainPerimeter(0.0),
432  sourcePerimeter(0.0),
433  sourceConductance(0.0),
434  drainConductance(0.0),
435  temp(getDeviceOptions().temp.getImmutableValue<double>()),
436  numberParallel(1.0),
437  tTransconductance(0.0),
438  tSurfMob(0.0),
439  tPhi(0.0),
440  tVto(0.0),
441  tSatCur(0.0),
442  tSatCurDens(0.0),
443  tCbd(0.0),
444  tCbs(0.0),
445  tCj(0.0),
446  tCjsw(0.0),
447  tBulkPot(0.0),
448  tDepCap(0.0),
449  tVbi(0.0),
450  icVBS(0.0),
451  icVDS(0.0),
452  icVGS(0.0),
453  von(0.0),
454  vdsat(0.0),
455  sourceVcrit(0.0),
456  drainVcrit(0.0),
457  cd(0.0),
458  cbs(0.0),
459  cbd(0.0),
460  gmbs(0.0),
461  gm(0.0),
462  gds(0.0),
463  gbd(0.0),
464  gbs(0.0),
465  capbd(0.0),
466  capbs(0.0),
467  Cbd(0.0),
468  Cbdsw(0.0),
469  Cbs(0.0),
470  Cbssw(0.0),
471  f2d(0.0),
472  f3d(0.0),
473  f4d(0.0),
474  f2s(0.0),
475  f3s(0.0),
476  f4s(0.0),
477  mode(1),
478  mode_low(0.0),
479  mode_high(0.0),
480  limitedFlag(false),
481  IC_GIVEN(false),
482  Idrain(0.0),
483  Isource(0.0),
484  //calculated quantities
485  EffectiveLength(0),
486  DrainSatCur(0),
487  SourceSatCur(0),
488  GateSourceOverlapCap(0),
489  GateDrainOverlapCap(0),
490  GateBulkOverlapCap(0),
491  OxideCap(0),
492  // local indices
493  li_Drain(-1),
494  li_DrainPrime(-1),
495  li_Source(-1),
496  li_SourcePrime(-1),
497  li_Gate(-1),
498  li_Bulk(-1),
499  // matrix and vector pointers:
500  // jacobian:
501  // drain row
502  ADrainEquDrainNodeOffset(-1),
503  ADrainEquDrainPrimeNodeOffset(-1),
504  // gate row
505  AGateEquGateNodeOffset(-1),
506  AGateEquBulkNodeOffset(-1),
507  AGateEquDrainPrimeNodeOffset(-1),
508  AGateEquSourcePrimeNodeOffset(-1),
509  // source row
510  ASourceEquSourceNodeOffset(-1),
511  ASourceEquSourcePrimeNodeOffset(-1),
512  // bulk row
513  ABulkEquGateNodeOffset(-1),
514  ABulkEquBulkNodeOffset(-1),
515  ABulkEquDrainPrimeNodeOffset(-1),
516  ABulkEquSourcePrimeNodeOffset(-1),
517  // drain' row
518  ADrainPrimeEquDrainNodeOffset(-1),
519  ADrainPrimeEquGateNodeOffset(-1),
520  ADrainPrimeEquBulkNodeOffset(-1),
521  ADrainPrimeEquDrainPrimeNodeOffset(-1),
522  ADrainPrimeEquSourcePrimeNodeOffset(-1),
523  // source' row
524  ASourcePrimeEquGateNodeOffset(-1),
525  ASourcePrimeEquSourceNodeOffset(-1),
526  ASourcePrimeEquBulkNodeOffset(-1),
527  ASourcePrimeEquDrainPrimeNodeOffset(-1),
528  ASourcePrimeEquSourcePrimeNodeOffset(-1),
529 
531  // F-vector pointers:
532  // V_d Row:
533  f_DrainEquDrainNodePtr(0), // a
534  f_DrainEquDrainPrimeNodePtr(0), // b
535  // V_g Row:
536  f_GateEquGateNodePtr(0), // c
537  f_GateEquBulkNodePtr(0), // d
538  f_GateEquDrainPrimeNodePtr(0), // e
539  f_GateEquSourcePrimeNodePtr(0), // f
540  // V_s Row:
541  f_SourceEquSourceNodePtr(0), // g
542  f_SourceEquSourcePrimeNodePtr(0), // h
543  // V_b Row:
544  f_BulkEquGateNodePtr(0), // i
545  f_BulkEquBulkNodePtr(0), // j
546  f_BulkEquDrainPrimeNodePtr(0), // k
547  f_BulkEquSourcePrimeNodePtr(0), // l
548  // V_d' Row:
549  f_DrainPrimeEquDrainNodePtr(0), // m
550  f_DrainPrimeEquGateNodePtr(0), // n
551  f_DrainPrimeEquBulkNodePtr(0), // o
552  f_DrainPrimeEquDrainPrimeNodePtr(0), // p
553  f_DrainPrimeEquSourcePrimeNodePtr(0), // q
554  // V_s' Row:
555  f_SourcePrimeEquGateNodePtr(0), // r
556  f_SourcePrimeEquSourceNodePtr(0), // s
557  f_SourcePrimeEquBulkNodePtr(0), // t
558  f_SourcePrimeEquDrainPrimeNodePtr(0), // u
559  f_SourcePrimeEquSourcePrimeNodePtr(0), // v
560  // Q-vector pointers:
561  // V_d Row:
562  q_DrainEquDrainNodePtr(0), // a
563  q_DrainEquDrainPrimeNodePtr(0), // b
564  // V_g Row:
565  q_GateEquGateNodePtr(0), // c
566  q_GateEquBulkNodePtr(0), // d
567  q_GateEquDrainPrimeNodePtr(0), // e
568  q_GateEquSourcePrimeNodePtr(0), // f
569  // V_s Row:
570  q_SourceEquSourceNodePtr(0), // g
571  q_SourceEquSourcePrimeNodePtr(0), // h
572  // V_b Row:
573  q_BulkEquGateNodePtr(0), // i
574  q_BulkEquBulkNodePtr(0), // j
575  q_BulkEquDrainPrimeNodePtr(0), // k
576  q_BulkEquSourcePrimeNodePtr(0), // l
577  // V_d' Row:
578  q_DrainPrimeEquDrainNodePtr(0), // m
579  q_DrainPrimeEquGateNodePtr(0), // n
580  q_DrainPrimeEquBulkNodePtr(0), // o
581  q_DrainPrimeEquDrainPrimeNodePtr(0), // p
582  q_DrainPrimeEquSourcePrimeNodePtr(0), // q
583  // V_s' Row:
584  q_SourcePrimeEquGateNodePtr(0), // r
585  q_SourcePrimeEquSourceNodePtr(0), // s
586  q_SourcePrimeEquBulkNodePtr(0), // t
587  q_SourcePrimeEquDrainPrimeNodePtr(0), // u
588  q_SourcePrimeEquSourcePrimeNodePtr(0), // v
589 #endif
590 
591  vbd(0.0),
592  vbs(0.0),
593  vgs(0.0),
594  vds(0.0),
595  vbd_old(0.0),
596  vbs_old(0.0),
597  vgs_old(0.0),
598  vds_old(0.0),
599  vbd_orig(0.0),
600  vbs_orig(0.0),
601  vgs_orig(0.0),
602  vds_orig(0.0),
603  capgs(0.0),
604  qgs(0.0),
605  capgd(0.0),
606  qgd(0.0),
607  capgb(0.0),
608  qgb(0.0),
609  qbd(0.0),
610  qbs(0.0),
611  // local indices
612  li_store_vbd(-1),
613  li_store_vbs(-1),
614  li_store_vgs(-1),
615  li_store_vds(-1),
616  li_store_von(-1),
617  li_store_dev_id(-1),
618  li_store_dev_is(-1),
619  li_store_dev_ig(-1),
620  li_store_dev_ib(-1),
621  li_state_qgs(-1),
622  li_state_qgd(-1),
623  li_state_qgb(-1),
624  li_state_capgs(-1),
625  li_state_capgd(-1),
626  li_state_capgb(-1),
627  li_state_qbd(-1),
628  li_state_qbs(-1),
629  blockHomotopyID(0),
630  randomPerturb(0.0)
631 {
632  numIntVars = 2;
633  numExtVars = 4;
634 
635  setNumStoreVars(5);
636  numLeadCurrentStoreVars = 4; // drain, gate, source & base lead currents
637  numStateVars = 8;
638 
639  devConMap.resize(4);
640  devConMap[0] = 1;
641  devConMap[1] = 2;
642  devConMap[2] = 1;
643  devConMap[3] = 3;
644 
646  devSupport.getGainScaleBlockID(getDeviceOptions().numGainScaleBlocks);
647  randomPerturb =
649 
650  if( jacStamp.empty() )
651  {
652  // stamp for RS!=0, RD!=0
653  jacStamp_DC_SC.resize(6);
654  jacStamp_DC_SC[0].resize(2); // Drain row
655  jacStamp_DC_SC[0][0]=0; // d-d
656  jacStamp_DC_SC[0][1]=4; // d-d'
657  jacStamp_DC_SC[1].resize(4); // Gate row
658  jacStamp_DC_SC[1][0]=1; // g-g
659  jacStamp_DC_SC[1][1]=3; // g-b
660  jacStamp_DC_SC[1][2]=4; // g-d'
661  jacStamp_DC_SC[1][3]=5; // g-s'
662  jacStamp_DC_SC[2].resize(2); // Source row
663  jacStamp_DC_SC[2][0]=2; // s-s
664  jacStamp_DC_SC[2][1]=5; // s-s'
665  jacStamp_DC_SC[3].resize(4); // Bulk row
666  jacStamp_DC_SC[3][0]=1; // b-g
667  jacStamp_DC_SC[3][1]=3; // b-b
668  jacStamp_DC_SC[3][2]=4; // b-d'
669  jacStamp_DC_SC[3][3]=5; // b-s'
670  jacStamp_DC_SC[4].resize(5); // Drain' row
671  jacStamp_DC_SC[4][0]=0; // d'-d
672  jacStamp_DC_SC[4][1]=1; // d'-g
673  jacStamp_DC_SC[4][2]=3; // d'-b
674  jacStamp_DC_SC[4][3]=4; // d'-d'
675  jacStamp_DC_SC[4][4]=5; // d'-s'
676  jacStamp_DC_SC[5].resize(5); // Source' row
677  jacStamp_DC_SC[5][0]=1; // s'-g
678  jacStamp_DC_SC[5][1]=2; // s'-s
679  jacStamp_DC_SC[5][2]=3; // s'-b
680  jacStamp_DC_SC[5][3]=4; // s'-d'
681  jacStamp_DC_SC[5][4]=5; // s'-s'
682 
683  jacMap_DC_SC.clear();
685  jacStamp_DC, jacMap_DC, jacMap2_DC, 5, 2, 6);
686 
688  jacStamp_SC, jacMap_SC, jacMap2_SC, 4, 0, 6);
689 
691  jacStamp, jacMap, jacMap2, 4, 0, 6);
692  }
693 
694  // Set params to constant default values:
695  setDefaultParams ();
696 
697  // Set params according to instance line and constant defaults from metadata:
698  setParams (IB.params);
699 
700  // Set any non-constant parameter defaults:
701  if (!given("TEMP"))
702  temp = getDeviceOptions().temp.getImmutableValue<double>();
703  if (!given("L"))
704  l =model_.model_l;
705  if (!given("W"))
706  w = model_.model_w;
707 
708  if (!given("AD"))
710  if (!given("AS"))
712 
713  // Note: processParams needs to be before the drain, source resistance calculations.
714  processParams ();
715 
716  // process source/drain series resistance (from mos1temp)
717  if(model_.drainResistance != 0)
718  {
720  }
721  else if (model_.given("RSH"))
722  {
723  if(model_.sheetResistance != 0)
724  {
727  }
728  else
729  {
730  drainConductance = 0;
731  }
732  }
733  else
734  {
735  drainConductance = 0;
736  }
737  if(model_.sourceResistance != 0)
738  {
740  }
741  else if (model_.given("RSH"))
742  {
743  if(model_.sheetResistance != 0)
744  {
747  }
748  else
749  {
750  sourceConductance = 0;
751  }
752  }
753  else
754  {
755  sourceConductance = 0;
756  }
757 
758  // Calculate any parameters specified as expressions:
759 
761 
762  // calculate dependent (ie computed) params and check for errors:
763 
764  if(l - 2 * model_.latDiff <=0)
765  {
766  UserError0(*this) << "Effective channel length less than zero.";
767  }
768 
774 
775  numIntVars = (((sourceConductance == 0.0)?0:1)+((drainConductance == 0.0) ? 0:1));
776 }
777 
778 //-----------------------------------------------------------------------------
779 // Function : Instance::~Instance
780 // Purpose : destructor
781 // Special Notes :
782 // Scope : public
783 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
784 // Creation Date : 3/16/00
785 //-----------------------------------------------------------------------------
787 {
788 }
789 
790 //-----------------------------------------------------------------------------
791 // Function : Instance::registerLIDs
792 // Purpose :
793 // Special Notes :
794 // Scope : public
795 // Creator : Robert Hoekstra, Computational Sciences
796 // Creation Date : 6/21/02
797 //-----------------------------------------------------------------------------
798 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
799  const std::vector<int> & extLIDVecRef )
800 {
801  numIntVars = (((sourceConductance == 0.0)?0:1)+((drainConductance == 0.0) ? 0:1));
802 
803  AssertLIDs(intLIDVecRef.size() == numIntVars);
804  AssertLIDs(extLIDVecRef.size() == numExtVars);
805 
806  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
807  {
808  Xyce::dout() << section_divider << std::endl;
809  Xyce::dout() << " In Instance::register LIDs\n\n";
810  Xyce::dout() << " name = " << getName() << std::endl;
811  Xyce::dout() << " number of internal variables: " << numIntVars << std::endl;
812  Xyce::dout() << " number of external variables: " << numExtVars << std::endl;
813  }
814 
815  // copy over the global ID lists.
816  intLIDVec = intLIDVecRef;
817  extLIDVec = extLIDVecRef;
818 
819  // now use these lists to obtain the indices into the
820  // linear algebra entities. This assumes an order.
821  // For the matrix indices, first do the rows.
822 
823  li_Drain = extLIDVec[0];
824  li_Gate = extLIDVec[1];
825  li_Source = extLIDVec[2];
826  li_Bulk = extLIDVec[3];
827 
828  int intLoc = 0;
829 
830  if( drainConductance )
831  li_DrainPrime = intLIDVec[intLoc++];
832  else
834 
835  if( sourceConductance )
836  li_SourcePrime = intLIDVec[intLoc];
837  else
839 
840  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
841  {
842  Xyce::dout() << "\n variable local indices:\n";
843  Xyce::dout() << " li_Drain = " << li_Drain << std::endl;
844  Xyce::dout() << " li_DrainPrime = " << li_DrainPrime << std::endl;
845  Xyce::dout() << " li_Source = " << li_Source << std::endl;
846  Xyce::dout() << " li_SourcePrime = " << li_SourcePrime << std::endl;
847  Xyce::dout() << " li_Gate = " << li_Gate << std::endl;
848  Xyce::dout() << " li_Bulk = " << li_Bulk << std::endl;
849 
850  Xyce::dout() << section_divider << std::endl;
851  }
852 
853 }
854 
855 //-----------------------------------------------------------------------------
856 // Function : Instance::loadNodeSymbols
857 // Purpose :
858 // Special Notes :
859 // Scope : public
860 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
861 // Creation Date : 05/13/05
862 //-----------------------------------------------------------------------------
863 void Instance::loadNodeSymbols(Util::SymbolTable &symbol_table) const
864 {
865  if ( li_DrainPrime != li_Drain )
866  addInternalNode(symbol_table, li_DrainPrime, getName(), "drainprime");
867 
868  if ( li_SourcePrime != li_Source )
869  addInternalNode(symbol_table, li_SourcePrime, getName(), "sourceprime");
870 
871  if (loadLeadCurrent)
872  {
873  addStoreNode(symbol_table, li_store_dev_id, getName(), "DEV_ID");
874  addStoreNode(symbol_table, li_store_dev_is, getName(), "DEV_IS");
875  addStoreNode(symbol_table, li_store_dev_ig, getName(), "DEV_IG");
876  addStoreNode(symbol_table, li_store_dev_ib, getName(), "DEV_IB");
877  }
878 }
879 
880 //-----------------------------------------------------------------------------
881 // Function : Instance::registerStateLIDs
882 // Purpose :
883 // Special Notes :
884 // Scope : public
885 // Creator : Robert Hoekstra, Computational Sciences
886 // Creation Date : 6/21/02
887 //-----------------------------------------------------------------------------
888 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
889 {
890  AssertLIDs(staLIDVecRef.size() == numStateVars);
891 
892  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
893  {
894  Xyce::dout() << std::endl;
895  Xyce::dout() << section_divider << std::endl;
896  Xyce::dout() << " In Instance::registerStateLIDs\n\n";
897  Xyce::dout() << " name = " << getName() << std::endl;
898  Xyce::dout() << " Number of State LIDs: " << numStateVars << std::endl;
899  }
900 
901  // Copy over the global ID lists:
902  staLIDVec = staLIDVecRef;
903 
904  int lid=0;
905 
906  li_state_qgs = staLIDVec[lid++];
907  li_state_qgd = staLIDVec[lid++];
908  li_state_qgb = staLIDVec[lid++];
909 
910  li_state_capgs = staLIDVec[lid++];
911  li_state_capgd = staLIDVec[lid++];
912  li_state_capgb = staLIDVec[lid++];
913 
914  li_state_qbd = staLIDVec[lid++];
915  li_state_qbs = staLIDVec[lid++];
916 
917 
918  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
919  {
920  Xyce::dout() << " State local indices:" << std::endl;
921  Xyce::dout() << std::endl;
922  Xyce::dout() << " li_state_qgs = " << li_state_qgs ;
923  Xyce::dout() << " li_state_capgs = " << li_state_capgs;
924  Xyce::dout() << " li_state_capgd = " << li_state_capgd;
925  Xyce::dout() << " li_state_capgb = " << li_state_capgb;
926  Xyce::dout() << " li_state_qgd = " << li_state_qgd;
927  Xyce::dout() << " li_state_qgb = " << li_state_qgb;
928  Xyce::dout() << " li_state_qbs = " << li_state_qbs;
929  Xyce::dout() << " li_state_qbd = " << li_state_qbd;
930  Xyce::dout() << std::endl;
931  Xyce::dout() << section_divider << std::endl;
932  }
933 }
934 
935 //-----------------------------------------------------------------------------
936 // Function : Instance::registerStoreLIDs
937 // Purpose :
938 // Special Notes :
939 // Scope : public
940 // Creator : Eric Keiter, SNL
941 // Creation Date : 12/11/11
942 //-----------------------------------------------------------------------------
943 void Instance::registerStoreLIDs( const std::vector<int> & stoLIDVecRef )
944 {
945  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
946 
947  // Copy over the global ID lists:
948  stoLIDVec = stoLIDVecRef;
949 
950  int lid=0;
951  li_store_vbd = stoLIDVec[lid++];
952  li_store_vbs = stoLIDVec[lid++];
953  li_store_vgs = stoLIDVec[lid++];
954  li_store_vds = stoLIDVec[lid++];
955  li_store_von = stoLIDVec[lid++];
956 
957  if( loadLeadCurrent )
958  {
959  li_store_dev_id = stoLIDVec[lid++];
960  li_store_dev_ig = stoLIDVec[lid++];
961  li_store_dev_is = stoLIDVec[lid++];
962  li_store_dev_ib = stoLIDVec[lid++];
963  }
964 }
965 
966 //-----------------------------------------------------------------------------
967 // Function : Instance::jacobianStamp
968 // Purpose :
969 // Special Notes :
970 // Scope : public
971 // Creator : Robert Hoekstra, Computational Sciences
972 // Creation Date : 9/3/02
973 //-----------------------------------------------------------------------------
974 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
975 {
976  if( drainConductance != 0.0 && sourceConductance != 0.0 )
977  return jacStamp_DC_SC;
978  else if( drainConductance != 0.0 && sourceConductance == 0.0 )
979  return jacStamp_DC;
980  else if( drainConductance == 0.0 && sourceConductance != 0.0 )
981  return jacStamp_SC;
982 
983  return jacStamp;
984 }
985 
986 //-----------------------------------------------------------------------------
987 // Function : Instance::registerJacLIDs
988 // Purpose :
989 // Special Notes :
990 // Scope : public
991 // Creator : Robert Hoekstra, Computational Sciences
992 // Creation Date : 9/3/02
993 //-----------------------------------------------------------------------------
994 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
995 {
996  DeviceInstance::registerJacLIDs( jacLIDVec );
997  std::vector<int> map;
998  std::vector< std::vector<int> > map2;
999 
1000  if (drainConductance != 0.0)
1001  {
1002  if (sourceConductance != 0.0)
1003  {
1004  map = jacMap_DC_SC;
1005  map2 = jacMap2_DC_SC;
1006  }
1007  else
1008  {
1009  map = jacMap_DC;
1010  map2 = jacMap2_DC;
1011  }
1012  }
1013  else
1014  {
1015  if (sourceConductance != 0.0)
1016  {
1017  map = jacMap_SC;
1018  map2 = jacMap2_SC;
1019  }
1020  else
1021  {
1022  map = jacMap;
1023  map2 = jacMap2;
1024  }
1025  }
1026  ADrainEquDrainNodeOffset = jacLIDVec[map[0]][map2[0][0]];
1027  ADrainEquDrainPrimeNodeOffset = jacLIDVec[map[0]][map2[0][1]];
1028 
1029  AGateEquGateNodeOffset = jacLIDVec[map[1]][map2[1][0]];
1030  AGateEquBulkNodeOffset = jacLIDVec[map[1]][map2[1][1]];
1031  AGateEquDrainPrimeNodeOffset = jacLIDVec[map[1]][map2[1][2]];
1032  AGateEquSourcePrimeNodeOffset = jacLIDVec[map[1]][map2[1][3]];
1033 
1034  ASourceEquSourceNodeOffset = jacLIDVec[map[2]][map2[2][0]];
1035  ASourceEquSourcePrimeNodeOffset = jacLIDVec[map[2]][map2[2][1]];
1036 
1037  ABulkEquGateNodeOffset = jacLIDVec[map[3]][map2[3][0]];
1038  ABulkEquBulkNodeOffset = jacLIDVec[map[3]][map2[3][1]];
1039  ABulkEquDrainPrimeNodeOffset = jacLIDVec[map[3]][map2[3][2]];
1040  ABulkEquSourcePrimeNodeOffset = jacLIDVec[map[3]][map2[3][3]];
1041 
1042  ADrainPrimeEquDrainNodeOffset = jacLIDVec[map[4]][map2[4][0]];
1043  ADrainPrimeEquGateNodeOffset = jacLIDVec[map[4]][map2[4][1]];
1044  ADrainPrimeEquBulkNodeOffset = jacLIDVec[map[4]][map2[4][2]];
1045  ADrainPrimeEquDrainPrimeNodeOffset = jacLIDVec[map[4]][map2[4][3]];
1046  ADrainPrimeEquSourcePrimeNodeOffset = jacLIDVec[map[4]][map2[4][4]];
1047 
1048  ASourcePrimeEquGateNodeOffset = jacLIDVec[map[5]][map2[5][0]];
1049  ASourcePrimeEquSourceNodeOffset = jacLIDVec[map[5]][map2[5][1]];
1050  ASourcePrimeEquBulkNodeOffset = jacLIDVec[map[5]][map2[5][2]];
1051  ASourcePrimeEquDrainPrimeNodeOffset = jacLIDVec[map[5]][map2[5][3]];
1052  ASourcePrimeEquSourcePrimeNodeOffset = jacLIDVec[map[5]][map2[5][4]];
1053 }
1054 
1055 //-----------------------------------------------------------------------------
1056 // Function : Instance::setupPointers
1057 // Purpose :
1058 // Special Notes :
1059 // Scope : public
1060 // Creator : Eric Keiter, SNL
1061 // Creation Date : 12/06/08
1062 //-----------------------------------------------------------------------------
1064 {
1065 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1066  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
1067  Linear::Matrix & dQdx = *(extData.dQdxMatrixPtr);
1068 
1069  // F-pointers:
1072 
1077 
1080 
1085 
1091 
1097 
1098  // Q-pointers:
1101 
1106 
1109 
1114 
1120 
1126 #endif
1127 }
1128 
1129 //-----------------------------------------------------------------------------
1130 // Function : Instance::loadDAEQVector
1131 //
1132 // Purpose : Loads the Q-vector contributions for a single
1133 // diode instance.
1134 //
1135 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1136 // which the system of equations is represented as:
1137 //
1138 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1139 //
1140 // This is similar to the loadRHS function, only this function
1141 // only loads capacitor charges, and loads them into the daeQ vector.
1142 //
1143 // Scope : public
1144 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1145 // Creation Date : 03/06/04
1146 //-----------------------------------------------------------------------------
1148 {
1149  double * qVec = extData.daeQVectorRawPtr;
1150  double coef(0.0);
1151 
1152  double Qeqbs(0.0),Qeqbd(0.0),Qeqgb(0.0), Qeqgs(0.0), Qeqgd(0.0);
1153  //double ceqbs,ceqbd,ceqgb, ceqgs, ceqgd; // 3f5 vars
1154  int Dtype=model_.dtype;
1155 
1156  // do the same Dtype corrections on the charges that
1157  // are performed on the currents in the loadRHS function.
1158 
1159  // What is cbs and cbd? They are diode currents (from exponentials),
1160  // so they are left out of this function.
1161  Qeqbs = Dtype*(qbs);
1162  Qeqbd = Dtype*(qbd);
1163  // These need "Dtype" here because we use them later *without*
1164  // Dtype, where SPICE uses it *with*
1165  Qeqgb = Dtype*(qgb);
1166  Qeqgs = Dtype*(qgs);
1167  Qeqgd = Dtype*(qgd);
1168 
1169  // 2 KCL for gate node
1170  coef = (Qeqgs+Qeqgd+Qeqgb);
1171  qVec[li_Gate] += coef*numberParallel;
1172 
1173  // 4 KCL for bulk node
1174  coef = Qeqbs + Qeqbd - Qeqgb;
1175  qVec[li_Bulk] += coef*numberParallel;
1176 
1177  // 5 KCL for drain' node
1178  coef = -(Qeqbd + Qeqgd);
1179  qVec[li_DrainPrime] += coef*numberParallel;
1180 
1181  // 6 KCL for source' node
1182  coef = -(Qeqbs + Qeqgs);
1183  qVec[li_SourcePrime] += coef*numberParallel;
1184 
1185  if( loadLeadCurrent )
1186  {
1187  double * storeLeadQ = extData.storeLeadCurrQCompRawPtr;
1188  storeLeadQ[li_store_dev_id] = (-(Qeqbd + Qeqgd))*numberParallel;
1189  storeLeadQ[li_store_dev_is] = (-(Qeqbs + Qeqgs))*numberParallel;
1190  storeLeadQ[li_store_dev_ig] = (Qeqgs+Qeqgd+Qeqgb)*numberParallel;
1191  storeLeadQ[li_store_dev_ib] = (Qeqbs + Qeqbd - Qeqgb)*numberParallel;
1192  }
1193 
1194  // Same as for the loadRHS function, but with capacitive terms:
1195  // gcgd = Capgd;
1196  // gcgs = Capgs;
1197  // gcgb = Capgb;
1198  // gcbs = capbs;
1199  // gcbd = capbd;
1200  if(!origFlag)
1201  {
1202  // The setup of gcgd, etc. is the same as in the loadDAEdQdxVector
1203  // function.
1204  double gcgd, gcgs, gcgb, gcbs, gcbd;
1206  {
1207  gcgd = Capgd;
1208  gcgs = Capgs;
1209  gcgb = Capgb;
1210  // get at the two parasitic caps the same way
1211  gcbs = capbs;
1212  gcbd = capbd;
1213  }
1214  else
1215  {
1216  gcgd = 0.0; gcgs = 0.0; gcgb = 0.0; gcbs = 0.0; gcbd = 0.0;
1217  }
1218 
1219  // KCL 2
1220  double coef_Jdxp2 = Dtype*(gcgd*(vgd-vgd_orig)+gcgs*(vgs-vgs_orig)+
1221  gcgb*(vgs-vgs_orig-vbs+vbs_orig));
1222 
1223  // 4 KCL for bulk node
1224  double coef_Jdxp4 = Dtype*(
1225  - (gcgb)*(vgs-vgs_orig-vbs+vbs_orig)
1226  + (gcgb)*(vbd-vbd_orig)
1227  + (gcbs)*(vbs-vbs_orig));
1228 
1229  // 5 KCL for drain' node
1230  double coef_Jdxp5 = Dtype*(
1231  -(gcgd)*(vgd-vgd_orig)
1232  -(gcbd)*(vbd-vbd_orig));
1233 
1234  // 6 KCL for source' node
1235  double coef_Jdxp6 = Dtype*(-gcgs*(vgs-vgs_orig)-(gcbs)*(vbs-vbs_orig));
1236 
1237  double * dQdxdVp = extData.dQdxdVpVectorRawPtr;
1238  dQdxdVp[li_Gate ] += coef_Jdxp2*numberParallel;
1239  dQdxdVp[li_Bulk ] += coef_Jdxp4*numberParallel;
1240  dQdxdVp[li_DrainPrime ] += coef_Jdxp5*numberParallel;
1241  dQdxdVp[li_SourcePrime] += coef_Jdxp6*numberParallel;
1242  }
1243 
1244  return true;
1245 }
1246 
1247 //-----------------------------------------------------------------------------
1248 // Function : Instance::loadDAEFVector
1249 //
1250 // Purpose : Loads the F-vector contributions for a single
1251 // diode instance.
1252 //
1253 // Special Notes : See the special notes for loadDAEFVector.
1254 //
1255 // Scope : public
1256 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1257 // Creation Date : 03/06/04
1258 //-----------------------------------------------------------------------------
1260 {
1261  double * fVec = extData.daeFVectorRawPtr;
1262  double coef(0.0);
1263  double ceqbs(0.0),ceqbd(0.0),ceqgb(0.0), ceqgs(0.0), ceqgd(0.0); // 3f5 vars
1264  double gmin1 = getDeviceOptions().gmin;
1265 
1266  int Dtype=model_.dtype;
1267 
1268  // The next few lines are the same as for loadRHS, except
1269  // the capcitor current terms have been set to zero here.
1270  ceqbs = Dtype*(cbs);
1271  ceqbd = Dtype*(cbd);
1272  // These need "Dtype" here because we use them later *without*
1273  // Dtype, where SPICE uses it *with*
1274  ceqgb = 0.0;
1275  ceqgs = 0.0;
1276  ceqgd = 0.0;
1277 
1278  // 1 KCL for drain node
1279  if (drainConductance != 0.0)
1280  {
1281  coef = Idrain;
1282  fVec[li_Drain] += coef*numberParallel;
1283  }
1284 
1285  // 2 KCL for gate node
1286  coef = (ceqgs+ceqgd+ceqgb);
1287  fVec[li_Gate] += coef*numberParallel;
1288 
1289  // 3 KCL for source node
1290  if (sourceConductance != 0.0)
1291  {
1292  coef = Isource;
1293  fVec[li_Source] += coef*numberParallel;
1294  }
1295 
1296  // 4 KCL for bulk node
1297  coef = ceqbs + ceqbd - ceqgb;
1298  fVec[li_Bulk] += coef*numberParallel;
1299 
1300  // 5 KCL for drain' node
1301  coef = -Idrain-(ceqbd - cdreq + ceqgd);
1302  fVec[li_DrainPrime] += coef*numberParallel;
1303 
1304  // 6 KCL for source' node
1305  coef = -Isource-(ceqbs + cdreq + ceqgs);
1306  fVec[li_SourcePrime] += coef*numberParallel;
1307 
1308  // Same as for the loadRHS function, but without capacitive terms:
1309  // gcgd = Capgd;
1310  // gcgs = Capgs;
1311  // gcgb = Capgb;
1312  // gcbs = capbs;
1313  // gcbd = capbd;
1314  if (!origFlag)
1315  {
1316  // 4 KCL for bulk node
1317  double coef_Jdxp4 = Dtype*(
1318  + ((gbd-gmin1))*(vbd-vbd_orig)
1319  + ((gbs-gmin1))*(vbs-vbs_orig));
1320 
1321  // 5 KCL for drain' node
1322  double coef_Jdxp5 = Dtype*(
1323  -((gbd-gmin1))*(vbd-vbd_orig)
1324  +gds*(vds-vds_orig)
1325  +Gm*((mode>0)?(vgs-vgs_orig):(vgd-vgd_orig))
1326  +Gmbs*((mode>0)?(vbs-vbs_orig):(vbd-vbd_orig)));
1327 
1328  // 6 KCL for source' node
1329  double coef_Jdxp6 = Dtype*(
1330  -((gbs-gmin1))*(vbs-vbs_orig)
1331  -gds*(vds-vds_orig)
1332  -Gm*((mode>0)?(vgs-vgs_orig):(vgd-vgd_orig))
1333  -Gmbs*((mode>0)?(vbs-vbs_orig):(vbd-vbd_orig)));
1334 
1335  double * dFdxdVp = extData.dFdxdVpVectorRawPtr;
1336  dFdxdVp[li_Bulk ] += coef_Jdxp4*numberParallel;
1337  dFdxdVp[li_DrainPrime ] += coef_Jdxp5*numberParallel;
1338  dFdxdVp[li_SourcePrime] += coef_Jdxp6*numberParallel;
1339  }
1340 
1341  if( loadLeadCurrent )
1342  {
1343  double * storeLeadF = extData.nextStoVectorRawPtr;
1344  storeLeadF[li_store_dev_id] = (-(ceqbd - cdreq + ceqgd))*numberParallel;
1345  storeLeadF[li_store_dev_is] = (-(ceqbs + cdreq + ceqgs))*numberParallel;
1346  storeLeadF[li_store_dev_ig] = (ceqgs+ceqgd+ceqgb)*numberParallel;
1347  storeLeadF[li_store_dev_ib] = (ceqbs + ceqbd - ceqgb)*numberParallel;
1348  }
1349 
1350  return true;
1351 }
1352 
1353 //-----------------------------------------------------------------------------
1354 // Function : Instance::loadDAEdQdx
1355 //
1356 // Purpose : Loads the Q-vector contributions for a single
1357 // diode instance.
1358 //
1359 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1360 // which the system of equations is represented as:
1361 //
1362 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1363 //
1364 // Scope : public
1365 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1366 // Creation Date : 03/06/04
1367 //-----------------------------------------------------------------------------
1369 {
1370  Linear::Matrix & dQdx = *(extData.dQdxMatrixPtr);
1371 
1372  double gcgd(0.0); // d(cqgd)/dVgd
1373  double gcgs(0.0); // d(cqgs)/dVgs
1374  double gcgb(0.0); // d(cqgb)/dVgb
1375  double gcbs(0.0); // d(cqbs)/dVbs
1376  double gcbd(0.0); // d(cqbd)/dVbd
1377 
1378  // get at the "conductances" for the gate capacitors with this trick
1379  // gcgd = model_.dtype*Capgd;
1380  // gcgs = model_.dtype*Capgs;
1381  // gcgb = model_.dtype*Capgb;
1382  //
1383  // In the loadRHS function, these would all be multiplied by
1384  // getSolverState().pdt. Here, for dQdx, the pdt term is left out.
1385  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
1386  {
1387  gcgd = Capgd;
1388  gcgs = Capgs;
1389  gcgb = Capgb;
1390  // get at the two parasitic caps the same way
1391  gcbs = capbs;
1392  gcbd = capbd;
1393  }
1394 
1395  dQdx[li_Gate][AGateEquGateNodeOffset] += (gcgd+gcgs+gcgb)
1396  *numberParallel;
1400 
1402  dQdx[li_Bulk][ABulkEquBulkNodeOffset] += +(gcbs+gcbd+gcgb)
1403  *numberParallel;
1406  +gcbs*numberParallel;
1407 
1409  -gcgd*numberParallel;
1411  -gcbd*numberParallel;
1413  +(gcbd+gcgd)*numberParallel;
1414 
1416  gcgs*numberParallel;
1418  +gcbs*numberParallel;
1420  +(gcbs+gcgs)*numberParallel;
1421 
1422  return true;
1423 }
1424 
1425 //-----------------------------------------------------------------------------
1426 // Function : Instance::loadDAEdFdx ()
1427 //
1428 // Purpose : Loads the F-vector contributions for a single
1429 // diode instance.
1430 //
1431 // Special Notes :
1432 //
1433 // Scope : public
1434 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1435 // Creation Date : 03/06/04
1436 //-----------------------------------------------------------------------------
1438 {
1439  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
1440 
1445 
1450 
1452  (gbs+gbd)*numberParallel;
1455 
1461  (-gbd+Gmbs)*numberParallel;
1463  (drainConductance+gds+gbd+revsum)*numberParallel;
1465  (-gds-nrmsum)*numberParallel;
1466 
1472  (gbs+Gmbs)*numberParallel;
1474  (gds+revsum)*numberParallel;
1476  (sourceConductance+gds+gbs+nrmsum)*numberParallel;
1477 
1478  return true;
1479 }
1480 
1481 //-----------------------------------------------------------------------------
1482 // Function : Instance::updateIntermediateVars
1483 // Purpose :
1484 // Special Notes :
1485 // Scope : public
1486 // Creator : Tom Russo
1487 // Creation Date : 03/01/01
1488 //-----------------------------------------------------------------------------
1490 {
1491  bool bsuccess = true;
1492  // 3f5 likes to use the same variable names in local variables and in
1493  // structures. Messes with us! Define some local versions with capitals
1494  // instead
1495  double Von;
1496  double Vdsat;
1497  double Beta;
1498  //
1499  double evbs;
1500  double evbd;
1501  double sarg;
1502  double sargsw;
1503  // double vgs1;
1504  // double vgd1;
1505  // double vgb1;
1506  double arg;
1507  int Check = 1;
1508 
1509  double capgs_old;
1510  double capgd_old;
1511  double capgb_old;
1512 
1513  // temporary storage for vgs/vgd/vds so that homotopy doesn't impact
1514  // voltage limiting "jdxp" terms
1515 
1516  double vgs_save;
1517  double vgd_save;
1518  double vds_save;
1519 
1520  // This is one of the vars that are set up at the top of mos3load that
1521  // should *not* be moved to the instance constructor! tTransconductance
1522  // is set by updateTemperature. Perhaps I should remove it from the
1523  // instance variables, too, since now it's pretty much a local thing.
1524  // same goes for the other things that depend on the t* variables!
1525 
1526  if( (tSatCurDens == 0) || (drainArea == 0) || (sourceArea == 0))
1527  {
1528  DrainSatCur = tSatCur;
1530  }
1531  else
1532  {
1535  }
1537 
1538  // don't do this anymore, use the one from the manager
1539  // newtonIter = nlsMgrPtr->getNonLinearIter ();
1540 
1541  // we need our solution variables for any of this stuff
1542 
1549 
1550  // now we need voltage drops
1551  Vddp = Vd - Vdp;
1552  Vssp = Vs - Vsp;
1553  Vbsp = Vb - Vsp;
1554  Vbdp = Vb - Vdp;
1555  Vgsp = Vg - Vsp;
1556  Vgdp = Vg - Vdp;
1557  Vgb = Vg - Vb;
1558  Vdpsp = Vdp - Vsp;
1559 
1560  // Now the things that the 3f5 code really uses (from mos3load's
1561  // "general iteration" part at lines 276-295
1562  vbs = model_.dtype * Vbsp;
1563  vgs = model_.dtype * Vgsp;
1564  vds = model_.dtype * Vdpsp;
1565 
1566  vbd = vbs-vds;
1567  vgd = vgs-vds;
1568 
1569  origFlag = 1;
1570  limitedFlag=false;
1571  vgs_orig = vgs;
1572  vds_orig = vds;
1573  vbs_orig = vbs;
1574  vbd_orig = vbd;
1575  vgd_orig = vgd;
1576 
1577  if (getSolverState().initJctFlag && !OFF && getDeviceOptions().voltageLimiterFlag)
1578  {
1579  if (IC_GIVEN)
1580  {
1581  vds = model_.dtype*icVDS;
1582  vgs = model_.dtype*icVGS;
1583  vbs = model_.dtype*icVBS;
1584  vbd = vbs - vds;
1585  vgd = vgs - vds;
1586  origFlag = false;
1587  }
1588  else
1589  {
1590  if (getSolverState().inputOPFlag)
1591  {
1592  Linear::Vector * flagSolVectorPtr = extData.flagSolVectorPtr;
1593  if ((*flagSolVectorPtr)[li_Drain] == 0 || (*flagSolVectorPtr)[li_Gate] == 0 ||
1594  (*flagSolVectorPtr)[li_Source] == 0 || (*flagSolVectorPtr)[li_SourcePrime] ||
1595  (*flagSolVectorPtr)[li_DrainPrime] || (*flagSolVectorPtr)[li_Bulk] )
1596  {
1597  vbs = -1;
1598  vgs = model_.dtype*tVto;
1599  vds = 0;
1600  vbd = vbs-vds;
1601  vgd = vgs-vds;
1602  }
1603  }
1604  else
1605  {
1606  vbs = -1;
1607  vgs = model_.dtype*tVto;
1608  vds = 0;
1609  vbd = vbs-vds;
1610  vgd = vgs-vds;
1611  }
1612  }
1613  }
1614  else if ((getSolverState().initFixFlag || getSolverState().initJctFlag) && OFF)
1615  {
1616  vbs = vgs = vds = 0;
1617  vbd = vgd = 0;
1618  }
1619 
1620  if (getSolverState().newtonIter == 0)
1621  {
1622 
1623  if (!(getSolverState().dcopFlag)||(getSolverState().locaEnabledFlag && getSolverState().dcopFlag))
1624  {
1629  Von = model_.dtype *
1631  }
1632  else
1633  { // otherwise there is no history
1634  vbs_old = vbs;
1635  vbd_old = vbd;
1636  vgs_old = vgs;
1637  vds_old = vds;
1638  Von = 0.0;
1639  }
1641  }
1642  else
1643  {
1648  Von = model_.dtype *
1651  }
1652 
1653  ////////////////////////////////////////////
1654  // SPICE-type Voltage Limiting
1655  ////////////////////////////////////////////
1657  {
1658  // Do not do limiting if mode initfix and OFF:
1659  if (! (getSolverState().initFixFlag && OFF))
1660  {
1661  if (vds_old >= 0)
1662  {
1663  vgs = devSupport.fetlim( vgs, vgs_old, Von);
1664  vds = vgs - vgd;
1665  vds = devSupport.limvds( vds, vds_old);
1666  vgd = vgs - vds;
1667  }
1668  else
1669  {
1670  vgd = devSupport.fetlim( vgd, vgd_old, Von);
1671  vds = vgs - vgd;
1672  vds = -devSupport.limvds( -vds, -vds_old );
1673  vgs = vgd + vds;
1674  }
1675 
1676  if (vds >= 0.0)
1677  {
1678  vbs = devSupport.pnjlim( vbs, vbs_old, vt, sourceVcrit, &Check);
1679  vbd = vbs - vds;
1680  }
1681  else
1682  {
1683  vbd = devSupport.pnjlim( vbd, vbd_old, vt, drainVcrit, &Check);
1684  vbs = vbd + vds;
1685  }
1686 
1687  // for convergence:
1688  if (Check == 1) limitedFlag=true;
1689 
1690  }
1691  }
1692 
1693  ////
1694  // now all the preliminaries are over - we can start doing the
1695  // real work
1696  ////
1697  vbd = vbs - vds;
1698  vgd = vgs - vds;
1699  Vgb = vgs - vbs;
1700 
1701  // Now set the origFlag
1702  if (vgs_orig != vgs || vds_orig != vds ||
1703  vbs_orig != vbs || vbd_orig != vbd || vgd_orig != vgd) origFlag = 0;
1704 
1705 
1706  ////
1707  // bulk-source and bulk-drain diodes
1708  // here we just evaluate the ideal diode current and the
1709  // corresponding derivative (conductance).
1710  ////
1711  if(vbs <= 0)
1712  {
1713  gbs = SourceSatCur/vt;
1714  gbs += getDeviceOptions().gmin;
1715  cbs = gbs*vbs;
1716  }
1717  else
1718  {
1719  evbs = exp(std::min(CONSTMAX_EXP_ARG,vbs/vt));
1720  gbs = (SourceSatCur*evbs/vt + getDeviceOptions().gmin);
1721  cbs = (SourceSatCur * (evbs-1) + getDeviceOptions().gmin*vbs);
1722  }
1723  if(vbd <= 0)
1724  {
1725  gbd = DrainSatCur/vt;
1726  gbd += getDeviceOptions().gmin;
1727  cbd = gbd *vbd;
1728  }
1729  else
1730  {
1731  evbd = exp(std::min(CONSTMAX_EXP_ARG,vbd/vt));
1732  gbd = (DrainSatCur*evbd/vt + getDeviceOptions().gmin);
1733  cbd = (DrainSatCur *(evbd-1) + getDeviceOptions().gmin*vbd);
1734  }
1735 
1736  // 3f5 does this simple stuff
1737  if (vds >= 0)
1738  mode = 1;
1739  else
1740  mode = -1;
1741 
1742  {
1743  // here 3f5 seems to have inserted a c-translation of a fortran routine
1744  // Sadly, there are GOTO's and labeled statements all over this thing.
1745  // I'll do what I can to eliminate them all, but I'll start by
1746  // leaving it VERBATIM and ugly
1747  //
1748  // evaluate the drain current, its derivatives and the
1749  // charges associated with the gate, channel and bulk for mosfets based on
1750  // semi-empirical equations
1751 
1752  ////
1753  // * subroutine moseq3(vds,vbs,vgs,gm,gds,gmbs,
1754  // * qg,qc,qb,cggb,cgdb,cgsb,cbgb,cbdb,cbsb)
1755  ////
1756 
1757  ////
1758  // * this routine evaluates the drain current, its derivatives and
1759  // * the charges associated with the gate, channel and bulk
1760  // * for mosfets based on semi-empirical equations
1761  ////
1762 
1763  //
1764  // common /mosarg/ vto,beta,gamma,phi,phib,cox,xnsub,xnfs,xd,xj,xld,
1765  // 1 xlamda,uo,uexp,vbp,utra,vmax,xneff,xl,xw,vbi,von,vdsat,qspof,
1766  // 2 beta0,beta1,cdrain,xqco,xqc,fnarrw,fshort,lev
1767  // common /status/ omega,time,delta,delold(7),ag(7),vt,xni,egfet,
1768  // 1 xmu,sfactr,mode,modedc,icalc,initf,method,iord,maxord,noncon,
1769  // 2 iterno,itemno,nosolv,modac,ipiv,ivmflg,ipostp,iscrch,iofile
1770  // common /knstnt/ twopi,xlog2,xlog10,root2,rad,boltz,charge,ctok,
1771  // 1 gmin,reltol,abstol,vntol,trtol,chgtol,eps0,epssil,epsox,
1772  // 2 pivtol,pivrel
1773  //
1774 
1775  // // equivalence (xlamda,alpha),(vbp,theta),(uexp,eta),(utra,xkappa)
1776 
1777  double coeff0 = 0.0631353e0;
1778  double coeff1 = 0.8013292e0;
1779  double coeff2 = -0.01110777e0;
1780  double oneoverxl; // 1/effective length
1781  double eta; // eta from model after length factor */
1782  double phibs; // phi - vbs */
1783  double sqphbs; // square root of phibs */
1784  double dsqdvb; // */
1785  double sqphis; // square root of phi */
1786  double sqphs3; // square root of phi cubed */
1787  double wps;
1788  double oneoverxj; // 1/junction depth */
1789  double xjonxl; // junction depth/effective length */
1790  double djonxj;
1791  double wponxj;
1792  double arga;
1793  double argb;
1794  double argc;
1795  double dwpdvb;
1796  double dadvb;
1797  double dbdvb;
1798  double gammas;
1799  double fbodys;
1800  double fbody;
1801  double onfbdy;
1802  double qbonco;
1803  double vbix;
1804  double wconxj;
1805  double dfsdvb;
1806  double dfbdvb;
1807  double dqbdvb;
1808  double vth;
1809  double dvtdvb;
1810  double csonco;
1811  double cdonco;
1812  double dxndvb;
1813  double dvodvb;
1814  double dvodvd;
1815  double vgsx;
1816  double dvtdvd;
1817  double onfg;
1818  double fgate;
1819  double us;
1820  double dfgdvg;
1821  double dfgdvd;
1822  double dfgdvb;
1823  double dvsdvg;
1824  double dvsdvb;
1825  double dvsdvd;
1826  double xn;
1827  double vdsc;
1828  double onvdsc;
1829  double dvsdga;
1830  double vdsx;
1831  double dcodvb;
1832  double cdnorm;
1833  double cdo;
1834  double cd1;
1835  double fdrain;
1836  double fd2;
1837  double dfddvg;
1838  double dfddvb;
1839  double dfddvd;
1840  double gdsat;
1841  double cdsat;
1842  double gdoncd;
1843  double gdonfd;
1844  double gdonfg;
1845  double dgdvg;
1846  double dgdvd;
1847  double dgdvb;
1848  double emax;
1849  double emongd;
1850  double demdvg;
1851  double demdvd;
1852  double demdvb;
1853  double delxl;
1854  double dldvd;
1855  double dldem;
1856  double ddldvg;
1857  double ddldvd;
1858  double ddldvb;
1859  double dlonxl;
1860  double xlfact;
1861  double diddl;
1862  double gds0;
1863  double emoncd;
1864  double ondvt;
1865  double onxn;
1866  double wfact;
1867  double gms;
1868  double gmw;
1869  double fshort;
1870 
1871 
1872  // Begin block of mosfet continuation code.
1873  // This idea is based, loosely, on a paper by Jaijeet
1874  // Roychowdhury.
1875  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1876  {
1877  Xyce::dout() << "HOMOTOPY INFO: gainscale = "
1878  << getSolverState().gainScale[blockHomotopyID] << std::endl;
1879  Xyce::dout() << "HOMOTOPY INFO: before vds = " << vds << std::endl;
1880  Xyce::dout() << "HOMOTOPY INFO: before vgs = " << vgs << std::endl;
1881  }
1882 
1883  // Save these before allowing homotopy to tweak them. It
1884  // is important to restore them before moving on to
1885  // calculate RHS, because then the Jdxp terms will attempt to force
1886  // the external circuit to make these voltage drops the real thing!
1887  vds_save=vds;
1888  vgs_save=vgs;
1889  vgd_save=vgd;
1890 
1891  if (getSolverState().artParameterFlag)
1892  {
1893  double alpha = getSolverState().gainScale[blockHomotopyID];
1894  if (getDeviceOptions().staggerGainScale)
1895  {
1896  alpha *= (0.3 * randomPerturb + 1.0);
1897  if (alpha > 1.0)
1898  {
1899  alpha = 1.0;
1900  }
1901  }
1902  double vgstConst = getDeviceOptions().vgstConst;
1903  if (getDeviceOptions().randomizeVgstConst)
1904  {
1905  vgstConst *= randomPerturb;
1906  }
1907 
1908  vds = devSupport.contVds (vds, getSolverState().nltermScale, getDeviceOptions().vdsScaleMin);
1909 
1910  if (mode==1)
1911  {
1912  vgs = devSupport.contVgst (vgs, alpha, vgstConst);
1913  }
1914  else
1915  {
1916  vgd = devSupport.contVgst (vgd, alpha, vgstConst);
1917  }
1918  }
1919 
1920  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1921  {
1922  Xyce::dout() << "HOMOTOPY INFO: after vds = " << vds << std::endl;
1923  Xyce::dout() << "HOMOTOPY INFO: after vgs = " << vgs << std::endl;
1924  }
1925  // End of block of mosfet continuation code.
1926 
1927  ////
1928  // bypasses the computation of charges
1929  ////
1930 
1931  ////
1932  // reference cdrain equations to source and
1933  // charge equations to bulk
1934  ////
1935  Vdsat = 0.0;
1936  oneoverxl = 1.0/EffectiveLength;
1937 
1938  // TVR: Massobrio and Antognetti call this "sigma"
1939  eta = model_.eta * 8.15e-22/(model_.oxideCapFactor*
1941  ////
1942  //.....square root term
1943  ////
1944  if ( (mode==1?vbs:vbd) <= 0.0 )
1945  {
1946  if (tPhi > 0)
1947  sqphis = sqrt(tPhi);
1948  else
1949  sqphis = 0;
1950  sqphs3 = tPhi*sqphis;
1951  phibs = tPhi-(mode==1?vbs:vbd);
1952  sqphbs = sqrt(phibs);
1953  dsqdvb = -0.5/sqphbs;
1954  }
1955  else
1956  {
1957  sqphis = sqrt(tPhi);
1958  sqphs3 = tPhi*sqphis;
1959  sqphbs = sqphis/(1.0+(mode==1?vbs:vbd)/
1960  (tPhi+tPhi));
1961  phibs = sqphbs*sqphbs;
1962  dsqdvb = -phibs/(sqphs3+sqphs3);
1963  }
1964  ////
1965  //.....short channel effect factor
1966  ////
1967  if ( (model_.junctionDepth != 0.0) &&
1968  (model_.coeffDepLayWidth != 0.0) )
1969  {
1970  wps = model_.coeffDepLayWidth*sqphbs;
1971  oneoverxj = 1.0/model_.junctionDepth;
1972  xjonxl = model_.junctionDepth*oneoverxl;
1973  djonxj = model_.latDiff*oneoverxj;
1974  wponxj = wps*oneoverxj;
1975  wconxj = coeff0+coeff1*wponxj+coeff2*wponxj*wponxj;
1976  arga = wconxj+djonxj;
1977  argc = wponxj/(1.0+wponxj);
1978  argb = sqrt(1.0-argc*argc);
1979  fshort = 1.0-xjonxl*(arga*argb-djonxj);
1980  dwpdvb = model_.coeffDepLayWidth*dsqdvb;
1981  dadvb = (coeff1+coeff2*(wponxj+wponxj))*dwpdvb*oneoverxj;
1982  dbdvb = -argc*argc*(1.0-argc)*dwpdvb/(argb*wps);
1983  dfsdvb = -xjonxl*(dadvb*argb+arga*dbdvb);
1984  }
1985  else
1986  {
1987  fshort = 1.0;
1988  dfsdvb = 0.0;
1989  }
1990  ////
1991  //.....body effect
1992  //
1993  gammas = model_.gamma*fshort;
1994  fbodys = 0.5*gammas/(sqphbs+sqphbs);
1995  fbody = fbodys+model_.narrowFactor/w;
1996 
1997  onfbdy = 1.0/(1.0+fbody);
1998  dfbdvb = -fbodys*dsqdvb/sqphbs+fbodys*dfsdvb/fshort;
1999  qbonco =gammas*sqphbs+model_.narrowFactor*phibs/w;
2000  dqbdvb = gammas*dsqdvb+model_.gamma*dfsdvb*sqphbs-
2002  ////
2003  //.....static feedback effect
2004  //
2005  vbix = tVbi*model_.dtype-eta*(mode*vds);
2006  ////
2007  //.....threshold voltage
2008  //
2009  vth = vbix+qbonco;
2010  dvtdvd = -eta;
2011  dvtdvb = dqbdvb;
2012  ////
2013  //.....joint weak inversion and strong inversion
2014  //
2015  Von = vth;
2016 
2017  if ( model_.fastSurfaceStateDensity != 0.0 )
2018  {
2020  1e4 *EffectiveLength*w/OxideCap; // 1e4 to convert (cm**2/m**2)
2021  cdonco = qbonco/(phibs+phibs);
2022  xn = 1.0+csonco+cdonco;
2023  Von = vth+vt*xn;
2024  dxndvb = dqbdvb/(phibs+phibs)-qbonco*dsqdvb/(phibs*sqphbs);
2025  dvodvd = dvtdvd;
2026  dvodvb = dvtdvb+vt*dxndvb;
2027  }
2028  else
2029  {
2030  ////
2031  //.....cutoff region
2032  //
2033 
2034  if ( (mode==1?vgs:vgd) <= Von ) {
2035  cdrain = 0.0;
2036  gm = 0.0;
2037  gds = 0.0;
2038  gmbs = 0.0;
2039  goto innerline1000;
2040  }
2041  }
2042  ////
2043  // *.....device is on
2044  ////
2045 
2046  vgsx = std::max((mode==1?vgs:vgd),Von);
2047 
2048  ////
2049  //.....mobility modulation by gate voltage
2050  ////
2051  onfg = 1.0+model_.theta*(vgsx-vth);
2052  fgate = 1.0/onfg;
2053  us = tSurfMob * 1e-4 *fgate; // 1e4 to convert (m**2/cm**2)
2054  dfgdvg = -model_.theta*fgate*fgate;
2055  dfgdvd = -dfgdvg*dvtdvd;
2056  dfgdvb = -dfgdvg*dvtdvb;
2057 
2058  ////
2059  // *.....saturation voltage
2060  ////
2061  Vdsat = (vgsx-vth)*onfbdy;
2062 
2063  if ( model_.maxDriftVel <= 0.0 )
2064  {
2065  dvsdvg = onfbdy;
2066  dvsdvd = -dvsdvg*dvtdvd;
2067  dvsdvb = -dvsdvg*dvtdvb-Vdsat*dfbdvb*onfbdy;
2068  }
2069  else
2070  {
2072  onvdsc = 1.0/vdsc;
2073  arga = (vgsx-vth)*onfbdy;
2074  argb = sqrt(arga*arga+vdsc*vdsc);
2075  Vdsat = arga+vdsc-argb;
2076  dvsdga = (1.0-arga/argb)*onfbdy;
2077  dvsdvg = dvsdga-(1.0-vdsc/argb)*vdsc*dfgdvg*onfg;
2078  dvsdvd = -dvsdvg*dvtdvd;
2079  dvsdvb = -dvsdvg*dvtdvb-arga*dvsdga*dfbdvb;
2080  }
2081  ////
2082  // *.....current factors in linear region
2083  ////
2084  vdsx = std::min((mode*vds),Vdsat);
2085  if ( vdsx == 0.0 ) goto line900;
2086 
2087  cdo = vgsx-vth-0.5*(1.0+fbody)*vdsx;
2088  dcodvb = -dvtdvb-0.5*dfbdvb*vdsx;
2089 
2090  ////
2091  // *.....normalized drain current
2092  ////
2093  cdnorm = cdo*vdsx;
2094 
2095  gm = vdsx;
2096  gds = vgsx-vth-(1.0+fbody+dvtdvd)*vdsx;
2097  gmbs = dcodvb*vdsx;
2098  ////
2099  // *.....drain current without velocity saturation effect
2100  ////
2101  cd1 = Beta*cdnorm;
2102  Beta = Beta*fgate;
2103  cdrain = Beta*cdnorm;
2104  gm = Beta*gm+dfgdvg*cd1;
2105  gds = Beta*gds+dfgdvd*cd1;
2106  gmbs = Beta*gmbs;
2107 
2108  ////
2109  // *.....velocity saturation factor
2110  ////
2111  if ( model_.maxDriftVel != 0.0 )
2112  {
2113  fdrain = 1.0/(1.0+vdsx*onvdsc);
2114  fd2 = fdrain*fdrain;
2115  arga = fd2*vdsx*onvdsc*onfg;
2116  dfddvg = -dfgdvg*arga;
2117  dfddvd = -dfgdvd*arga-fd2*onvdsc;
2118  dfddvb = -dfgdvb*arga;
2119  ////
2120  // *.....drain current
2121  ////
2122  gm = fdrain*gm+dfddvg*cdrain;
2123  gds = fdrain*gds+dfddvd*cdrain;
2124  gmbs = fdrain*gmbs+dfddvb*cdrain;
2125  cdrain = fdrain*cdrain;
2126  Beta = Beta*fdrain;
2127  }
2128 
2129  ////
2130  // *.....channel length modulation
2131  ////
2132  if ( (mode*vds) <= Vdsat ) goto line700;
2133  if ( model_.maxDriftVel <= 0.0 ) goto line510;
2134  if (model_.alpha == 0.0) goto line700;
2135  cdsat = cdrain;
2136  gdsat = cdsat*(1.0-fdrain)*onvdsc;
2137  gdsat = std::max(1.0e-12,gdsat);
2138  gdoncd = gdsat/cdsat;
2139  gdonfd = gdsat/(1.0-fdrain);
2140  gdonfg = gdsat*onfg;
2141  dgdvg = gdoncd*gm-gdonfd*dfddvg+gdonfg*dfgdvg;
2142  dgdvd = gdoncd*gds-gdonfd*dfddvd+gdonfg*dfgdvd;
2143  dgdvb = gdoncd*gmbs-gdonfd*dfddvb+gdonfg*dfgdvb;
2144 
2145  // to have this condition make sense, the option BADMOS3 must be
2146  // recognized on the options line. A problem with the KAPPA parameter
2147  // was detected and fixed in 3f2. BADMOS3 enables the unfixed deal,
2148  // just in case parameter fitting is affected.
2149  // It has never been implemented in Xyce
2150  //#ifdef BADMOS3_IMPLEMENTED
2151  // if (ckt->CKTbadMos3)
2152  // emax = cdsat*oneoverxl/gdsat;
2153  // else
2154  //#endif
2155  emax = model_.kappa * cdsat*oneoverxl/gdsat;
2156  emoncd = emax/cdsat;
2157  emongd = emax/gdsat;
2158  demdvg = emoncd*gm-emongd*dgdvg;
2159  demdvd = emoncd*gds-emongd*dgdvd;
2160  demdvb = emoncd*gmbs-emongd*dgdvb;
2161 
2162  arga = 0.5*emax*model_.alpha;
2163  argc = model_.kappa*model_.alpha;
2164  argb = sqrt(arga*arga+argc*((mode*vds)-Vdsat));
2165  delxl = argb-arga;
2166  dldvd = argc/(argb+argb);
2167  dldem = 0.5*(arga/argb-1.0)*model_.alpha;
2168  ddldvg = dldem*demdvg;
2169  ddldvd = dldem*demdvd-dldvd;
2170  ddldvb = dldem*demdvb;
2171  goto line520;
2172  line510:
2173  delxl = sqrt(model_.kappa*((mode*vds)-Vdsat)*
2174  model_.alpha);
2175  dldvd = 0.5*delxl/((mode*vds)-Vdsat);
2176  ddldvg = 0.0;
2177  ddldvd = -dldvd;
2178  ddldvb = 0.0;
2179  ////
2180  // *.....punch through approximation
2181  ////
2182  line520:
2183  if ( delxl > (0.5*EffectiveLength) )
2184  {
2186  (4.0*delxl));
2187  arga = 4.0*(EffectiveLength-delxl)*(EffectiveLength-delxl)/
2189  ddldvg = ddldvg*arga;
2190  ddldvd = ddldvd*arga;
2191  ddldvb = ddldvb*arga;
2192  dldvd = dldvd*arga;
2193  }
2194  ////
2195  // *.....saturation region
2196  ////
2197  dlonxl = delxl*oneoverxl;
2198  xlfact = 1.0/(1.0-dlonxl);
2199  cdrain = cdrain*xlfact;
2200  diddl = cdrain/(EffectiveLength-delxl);
2201  gm = gm*xlfact+diddl*ddldvg;
2202  gds0 = gds*xlfact+diddl*ddldvd;
2203  gmbs = gmbs*xlfact+diddl*ddldvb;
2204  gm = gm+gds0*dvsdvg;
2205  gmbs = gmbs+gds0*dvsdvb;
2206  gds = gds0*dvsdvd+diddl*dldvd;
2207 
2208  ////
2209  // *.....finish strong inversion case
2210  ////
2211  line700:
2212  if ( (mode==1?vgs:vgd) < Von )
2213  {
2214  ////
2215  // *.....weak inversion
2216  ////
2217  onxn = 1.0/xn;
2218  ondvt = onxn/vt;
2219  wfact = exp( ((mode==1?vgs:vgd)-Von)*ondvt );
2220  cdrain = cdrain*wfact;
2221  gms = gm*wfact;
2222  gmw = cdrain*ondvt;
2223  gm = gmw;
2224 
2225  if ((mode*vds) > Vdsat)
2226  {
2227  gm = gm+gds0*dvsdvg*wfact;
2228  }
2229  gds = gds*wfact+(gms-gmw)*dvodvd;
2230  gmbs = gmbs*wfact+(gms-gmw)*dvodvb-gmw*
2231  ((mode==1?vgs:vgd)-Von)*onxn*dxndvb;
2232  }
2233  ////
2234  // *.....charge computation
2235  ////
2236  goto innerline1000;
2237  ////
2238  // *.....special case of vds = 0.0d0
2239  ////
2240  line900:
2241 
2242  Beta = Beta*fgate;
2243  cdrain = 0.0;
2244  gm = 0.0;
2245  gds = Beta*(vgsx-vth);
2246  gmbs = 0.0;
2247  if ( (model_.fastSurfaceStateDensity != 0.0) &&
2248  ((mode==1?vgs:vgd) < Von) )
2249  {
2250  gds *=exp(((mode==1?vgs:vgd)-Von)/(vt*xn));
2251  }
2252  innerline1000:;
2253  ////
2254  // *.....done
2255  ////
2256  // end of moseq3
2257  ////
2258  }
2259 
2260  // now deal with n vs p polarity
2261 
2262  von = model_.dtype * Von;
2263  vdsat = model_.dtype * Vdsat;
2264 
2265  ////
2266  // * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
2267  ////
2268 
2269  cd = mode * cdrain - cbd;
2270  // in 3f5 this is all in a block conditioned on CKTmode, but since
2271  // it's valid for MODETRAN and MODETRANOP we'll just always do it
2272 
2273  ////
2274  // * now we do the hard part of the bulk-drain and bulk-source
2275  // * diode - we evaluate the non-linear capacitance and
2276  // * charge
2277  // *
2278  // * the basic equations are not hard, but the implementation
2279  // * is somewhat long in an attempt to avoid log/exponential
2280  // * evaluations
2281  ////
2282  ////
2283  // * charge storage elements
2284  // *
2285  // *.. bulk-drain and bulk-source depletion capacitances
2286  ////
2287  // I took out all the CAPBYPASS stuff, and the
2288  // unnecessary curly braces that wind up there if you do
2289 
2290  // can't bypass the diode capacitance calculations
2291  if(Cbs != 0 || Cbssw != 0 )
2292  {
2293  if (vbs < tDepCap)
2294  {
2295  arg=1-vbs/tBulkPot;
2296  ////
2297  // * the following block looks somewhat long and messy,
2298  // * but since most users use the default grading
2299  // * coefficients of .5, and sqrt is MUCH faster than an
2300  // * exp(log()) we use this special case code to buy time.
2301  // * (as much as 10% of total job time!)
2302  ////
2304  {
2305  if(model_.bulkJctBotGradingCoeff == .5)
2306  {
2307  sarg = sargsw = 1/sqrt(arg);
2308  }
2309  else
2310  {
2311  sarg = sargsw = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2312  }
2313  }
2314  else
2315  {
2316  if(model_.bulkJctBotGradingCoeff == .5)
2317  {
2318  sarg = 1/sqrt(arg);
2319  }
2320  else
2321  {
2322  sarg = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2323  }
2325  {
2326  sargsw = 1/sqrt(arg);
2327  }
2328  else
2329  {
2330  sargsw =exp(-model_.bulkJctSideGradingCoeff* log(arg));
2331  }
2332  }
2333  qbs = tBulkPot*(Cbs*(1-arg*sarg)/(1-model_.bulkJctBotGradingCoeff)
2334  +Cbssw*(1-arg*sargsw)/(1-model_.bulkJctSideGradingCoeff));
2335  capbs=Cbs*sarg+ Cbssw*sargsw;
2336 
2337  }
2338  else
2339  {
2340  qbs = f4s + vbs*(f2s+vbs*(f3s/2));
2341  capbs=f2s+f3s*vbs;
2342  }
2343  }
2344  else
2345  {
2346  qbs = 0;
2347  capbs=0;
2348  }
2349 
2350  //// can't bypass the diode capacitance calculations
2351  if(Cbd != 0 || Cbdsw != 0 )
2352  {
2353 
2354  if (vbd < tDepCap)
2355  {
2356  arg=1-vbd/tBulkPot;
2357  ////
2358  // * the following block looks somewhat long and messy,
2359  // * but since most users use the default grading
2360  // * coefficients of .5, and sqrt is MUCH faster than an
2361  // * exp(log()) we use this special case code to buy time.
2362  // * (as much as 10% of total job time!)
2363  ////
2364  if(model_.bulkJctBotGradingCoeff == .5 &&
2366  {
2367  sarg = sargsw = 1/sqrt(arg);
2368  }
2369  else
2370  {
2371  if(model_.bulkJctBotGradingCoeff == .5)
2372  {
2373  sarg = 1/sqrt(arg);
2374  }
2375  else
2376  {
2377  sarg = exp(-model_.bulkJctBotGradingCoeff*log(arg));
2378  }
2380  {
2381  sargsw = 1/sqrt(arg);
2382  }
2383  else
2384  {
2385  sargsw =exp(-model_.bulkJctSideGradingCoeff*log(arg));
2386  }
2387  }
2388  qbd =
2389  tBulkPot*(Cbd*
2390  (1-arg*sarg)
2392  +Cbdsw*
2393  (1-arg*sargsw)
2395  capbd=Cbd*sarg+
2396  Cbdsw*sargsw;
2397  }
2398  else
2399  {
2400  qbd = f4d +
2401  vbd * (f2d + vbd * f3d/2);
2402  capbd=f2d + vbd * f3d;
2403  }
2404  }
2405  else
2406  {
2407  qbd = 0;
2408  capbd = 0;
2409  }
2410 
2411  // Now after a mess of convergence stuff that seems not to apply to us
2412  // 3f5 saves the vbs, vbd, etc. in the state vector (we don't, it gets
2413  // saved in updatePrimaryState)
2414 
2415  // Then 3f5 calculates meyer capacitances, capgs, capgb and capgd
2416  // Careful! They use the local von and vdsat, which haven't got dtype
2417  // multiplying them!
2418 
2419  ////
2420  // * calculate meyer's capacitors
2421  ////
2422  ////
2423  // * new cmeyer - this just evaluates at the current time,
2424  // * expects you to remember values from previous time
2425  // * returns 1/2 of non-constant portion of capacitance
2426  // * you must add in the other half from previous time
2427  // * and the constant part
2428  ////
2429 
2430  if (mode > 0)
2431  {
2432  devSupport.qmeyer (vgs,vgd,Vgb,Von,Vdsat,
2434  }
2435  else
2436  {
2437  devSupport.qmeyer (vgd,vgs,Vgb,Von,Vdsat,
2439  }
2440 
2441 
2442  // vgs1 = vgs_old;
2443  // vgd1 = vgs1 - vds_old;
2444  // vgb1 = vgs1 - vbs_old;
2445 
2446  ////
2447  // TVR: Note! Caution with Capgs vs. capgs. If I used the instance var
2448  // capgs on the left hand side, it's OK as long as we never try to implement
2449  // meyer back averaging, since capgs is going to be recalculated each
2450  // time through. But if we do the averaging, the old one will have the
2451  // constant part and old old part added in, which is not what we wanted.
2452  // So I'll continue 3f5's way of having a local Capgs that's actually used
2453  // for the charge computation, and an instance capgs that's saved as state.
2454  ////
2455 
2456  if((getSolverState().dcopFlag))
2457 // if(!(getSolverState().tranopFlag))
2458  {
2459  Capgs = 2 * capgs + GateSourceOverlapCap ;
2460  Capgd = 2 * capgd + GateDrainOverlapCap ;
2461  Capgb = 2 * capgb + GateBulkOverlapCap ;
2462  }
2463  else
2464  {
2465  capgs_old = (*extData.currStaVectorPtr)[li_state_capgs];
2466  capgd_old = (*extData.currStaVectorPtr)[li_state_capgd];
2467  capgb_old = (*extData.currStaVectorPtr)[li_state_capgb];
2468 
2469  Capgs = ( capgs+
2470  capgs_old +
2472  Capgd = ( capgd+
2473  capgd_old +
2475  Capgb = ( capgb+
2476  capgb_old +
2478  }
2479 
2480  // Eric does this kludge in level 1, so I'll do it to make sure capacitances
2481  // are positive
2482  Capgs *= (Capgs < 0.0)?-1.0:1.0;
2483  Capgd *= (Capgd < 0.0)?-1.0:1.0;
2484  Capgb *= (Capgb < 0.0)?-1.0:1.0;
2485 
2486 
2487  // in the sequel, I'll refer to all derivatives of currents w.r.t. voltages
2488  // as conductances, whether they really are or not.
2489 
2490  // when we get here, cdrain has the channel current
2491  // cbd and cbs have the currents through the diodes
2492  // cd has the drain current minus the diode current and seems only to be used
2493  // for 3f5 convergence stuff
2494  // qbs and qbd have the charges on the parasitic capacitors
2495  // capbs and capbd have the capacitances of the parasitics.
2496 
2497  // none of the charges for the gate capacitors have been calculated yet.
2498  // We've saved the capacitances, so we can get the charges in
2499  // updatePrimaryState later.
2500 
2501  // Conductances:
2502  // gbd: the bulk-drain' conductance without the capacitor components
2503  // We'll need to get the capacitor contribution in the actual load
2504  // using C*dt
2505  // gbs: bulk-source' without capacitor
2506  // gm = derivative of channel current w.r.t. gate-source voltage --- gotta
2507  // account for mode=normal or mode=reverse when using this!
2508  // gmbs = derivative of channel current w.r.t bulk-source voltage
2509  // gds = derivative of channel current w.r.t. drain-source voltage
2510 
2511  // the variables gcgs, gcgb, gcgd should be the conductances for the gate
2512  // capacitors, but we won't do those here (vide supra), we'll do them
2513  // in the jacobian load given the capacitances.
2514 
2515  // Now 3f5 doesn't do the resistor currents in the RHS load, because of
2516  // how they do their numerics. We do, so let's save those here.
2517 
2520 
2521  if (mode >= 0) // Normal mode
2522  {
2523  Gm = gm; // (xnrm-xrev)*gm in 3f5
2524  Gmbs = gmbs; // (xnrm-xrev)*gmbs in 3f5
2525  nrmsum = Gm+Gmbs; // xnrm*(gm+gmbs)
2526  revsum = 0; // xrev*(gm+gmbs)
2528  }
2529  else
2530  {
2531  Gm = -gm;
2532  Gmbs = -gmbs;
2533  nrmsum = 0;
2534  revsum = -(Gm+Gmbs); // because Gm and Gmbs already have - in them!
2535  cdreq = -(model_.dtype)*cdrain;
2536  }
2537 
2538  // It is now essential to restore the vds/vgs/vgd variables that might
2539  // have been tweaked by homotopy, lest they have an effect on RHS
2540  // Jdxp terms.
2541 
2542  vds=vds_save;
2543  vgs=vgs_save;
2544  vgd=vgd_save;
2545 
2546  /// CURRENTS to load into RHS:
2547 
2548  // so at this point:
2549 
2550  // current out of drain is
2551  // Idrain
2552 
2553  // current out of gate:
2554  // dtype*( (deriv of qgs) + (deriv of qgd) + (deriv of qgb))
2555 
2556  // the current *out of* the source should be simply
2557  // Isource.
2558 
2559  // current out of bulk is
2560  // dtype*(deriv of qbd) + dtype*cbd + dtype*cbs + dtype*(deriv of qbs)
2561  // - dtype*(deriv of qgb)
2562 
2563  // current out of drain' is
2564  // -Idrain - dtype*(deriv of qgd) - (deriv of qbd) - dtype*cbd +
2565  // mode*dtype*cdrain
2566 
2567  // the current out of the source' is
2568  // -Isource - dtype*(deriv of qgs) - dtype*cbs - (deriv of qbs) -
2569  // mode*dtype*cdrain
2570 
2571  //////Conductances to load into Jacobian as they relate to things here:
2572  /// all of the places where I say Cap/dt I really mean dtype*Cap/dt for
2573  // the meyer capacitors. No dtype for the parasitics, though
2574 
2575  // 3f5 handles the mode by doing:
2576  // where xnrm=1, xrev=0 if mode>=0, xnrm=0,xrev=1 if mode<0
2577 
2578  // drain-drain = a = drainConductance
2579  // drain-drain' = b = -drainConductance
2580 
2581  // gate-gate = c = "gcgd+gcgs+gcgb" = Capgd/dt+Capgs/dt+Capgb/dt
2582  // gate-bulk = d = -gcgb = -Capgb/dt
2583  // gate-drain' = e = -gcgd = -Capgd/dt
2584  // gate-source' = f = -gcgs = -Capgs/dt
2585 
2586  // source-source = g = sourceConductance
2587  // source-source' = h = -sourceConductance
2588 
2589  // bulk-gate = i = -gcgb = -Capgb/dt
2590  // bulk-bulk = j = gbs+gbd+gcgb+parasitics=gbs+gbd+Capgb/dt+capbs/dt+capbd/dt
2591  // bulk-drain' = k= -gbd-capbd/dt
2592  // bulk-source' = l= -gbs-capbs/dt
2593 
2594  // drain'-drain = m = -drainConductance
2595  // drain'-gate = n = (xnrm-xrev)*gm-Capgd/dt
2596  // drain'-bulk = o = -gbd-capbd/dt+(xnrm-xrev)*gmbs
2597  // drain'-drain' = p = drainConductance+gds+gbd+capbd/dt+
2598  // xrev*(gm+gmbs)+ Capgd/dt
2599  // drain'-source' = q = -gds-xnrm*(gm+gmbs)
2600 
2601  // source'-gate = r = -(xnrm-xrev)*gm-Capgs/dt
2602  // source'-source = s = -sourceConductance
2603  // source'-bulk = t = -gbs-capbs/dt-(xnrm-xrev)*gmbs
2604  // source'-drain' = u= -gds-xrev*(gm+gmbs)
2605  // source'-source' = v = sourceConductance+gds+gbs+capbs/dt+xnrm*(gm+gmbs)+
2606  // Capgs/dt
2607 
2608  return bsuccess;
2609 }
2610 
2611 
2612 //-----------------------------------------------------------------------------
2613 // Function : Instance::updateTemperature
2614 // Purpose :
2615 // Special Notes :
2616 // Scope : public
2617 // Creator : Tom Russo, Component Information and Models
2618 // Creation Date : 02/27/01
2619 //-----------------------------------------------------------------------------
2620 bool Instance::updateTemperature ( const double & temp_tmp)
2621 {
2622  // mos3temp vars
2623  double czbd; // zero voltage bulk-drain capacitance
2624  double czbdsw; // zero voltage bulk-drain sidewall capacitance
2625  double czbs; // zero voltage bulk-source capacitance
2626  double czbssw; // zero voltage bulk-source sidewall capacitance
2627  double arg; // 1 - fc
2628  double sarg; // (1-fc) ^^ (-mj)
2629  double sargsw; // (1-fc) ^^ (-mjsw)
2630  double ratio,ratio4;
2631  double fact2;
2632  double kt;
2633  double egfet;
2634  double pbfact;
2635  double capfact;
2636  double phio;
2637  double pbo;
2638  double gmanew,gmaold;
2639  // end of mos3temp stuff
2640 
2641  double tnom;
2642 
2643  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
2644  {
2645  Xyce::dout() << subsection_divider << std::endl;
2646  Xyce::dout() << " Instance::Begin of updateTemperature. \n";
2647  Xyce::dout() <<" name = " << getName() << std::endl;
2648  Xyce::dout() << std::endl;
2649  }
2650 
2651  // first set the instance temperature to the new temperature:
2652  if (temp_tmp != -999.0) temp = temp_tmp;
2653 
2655  {
2657  }
2658 
2659  tnom = model_.tnom;
2660  ratio = temp/tnom;
2661 
2662  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
2663  {
2664  Xyce::dout() << "Temperature = "<< temp << std::endl;
2665  Xyce::dout() << "tnom = " << tnom << std::endl;
2666  Xyce::dout() << "ratio = " << ratio << std::endl;
2667  }
2668 
2669  vt = temp * CONSTKoverQ;
2670  ratio = temp/tnom;
2671  fact2 = temp/CONSTREFTEMP;
2672  kt = temp * CONSTboltz;
2673  egfet = 1.16-(7.02e-4*temp*temp)/(temp+1108);
2674  arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
2675  pbfact = -2*vt *(1.5*log(fact2)+CONSTQ*arg);
2676 
2677  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
2678  {
2679  Xyce::dout() << "vt = " << vt << std::endl;
2680  Xyce::dout() << "ratio = " << ratio << std::endl;
2681  Xyce::dout() << "fact2 = " << fact2 << std::endl;
2682  Xyce::dout() << "kt = " << kt << std::endl;
2683  Xyce::dout() << "egfet = " << egfet << std::endl;
2684  Xyce::dout() << "arg = " << arg << std::endl;
2685  Xyce::dout() << "pbfact = " << pbfact << std::endl;
2686  }
2687 
2688  // in mos3temp 3f5 does a bunch of parameter defaulting (lines 155-163)
2689  // but we assume that our various parameters have been set already in
2690  // the constructors
2691 
2692  // lines 164-203 of mos3temp moved to instance block constructor
2693 
2694  // Here's the entire guts of the mos3temp instance loop, with obvious
2695  // modifications (here->MOS3 goes away, model->MOS3 turns into model_.)
2696 
2697  ratio4 = ratio * sqrt(ratio);
2699  tSurfMob = model_.surfaceMobility/ratio4;
2700  phio= (model_.phi-model_.pbfact1)/model_.fact1;
2701  tPhi = fact2 * phio + pbfact;
2702  tVbi = model_.vt0 - model_.dtype *
2703  (model_.gamma* sqrt(model_.phi))+.5*(model_.egfet1-egfet)
2704  + model_.dtype*.5* (tPhi-model_.phi);
2705  tVto = tVbi + model_.dtype * model_.gamma * sqrt(tPhi);
2709  gmaold = (model_.bulkJctPotential-pbo)/pbo;
2710  capfact = 1/(1+model_.bulkJctBotGradingCoeff*
2711  (4e-4*(model_.tnom-CONSTREFTEMP)-gmaold));
2712  tCbd = model_.capBD * capfact;
2713  tCbs = model_.capBS * capfact;
2714  tCj = model_.bulkCapFactor * capfact;
2715  capfact = 1/(1+model_.bulkJctSideGradingCoeff*
2716  (4e-4*(model_.tnom-CONSTREFTEMP)-gmaold));
2717  tCjsw = model_.sideWallCapFactor * capfact;
2718  tBulkPot = fact2 * pbo+pbfact;
2719  gmanew = (tBulkPot-pbo)/pbo;
2720  capfact = (1+model_.bulkJctBotGradingCoeff*(4e-4*(temp-CONSTREFTEMP)-gmanew));
2721  tCbd *= capfact;
2722  tCbs *= capfact;
2723  tCj *= capfact;
2724  capfact = (1+model_.bulkJctSideGradingCoeff*(4e-4*(temp-CONSTREFTEMP)-gmanew));
2725  tCjsw *= capfact;
2727 
2728  if( (model_.jctSatCurDensity == 0) || (drainArea == 0) ||
2729  (sourceArea == 0) )
2730  {
2732  vt*log(vt/(CONSTroot2*model_.jctSatCur));
2733  }
2734  else
2735  {
2736  drainVcrit = vt * log( vt / (CONSTroot2 *
2738  sourceVcrit = vt * log( vt / (CONSTroot2 *
2740  }
2741  if(model_.capBDGiven)
2742  {
2743  czbd = tCbd;
2744  }
2745  else
2746  {
2748  {
2749  czbd=tCj*drainArea;
2750  }
2751  else
2752  {
2753  czbd=0;
2754  }
2755  }
2757  {
2758  czbdsw= tCjsw * drainPerimeter;
2759  }
2760  else
2761  {
2762  czbdsw=0;
2763  }
2764  arg = 1-model_.fwdCapDepCoeff;
2765  sarg = exp( (-model_.bulkJctBotGradingCoeff) * log(arg) );
2766  sargsw = exp( (-model_.bulkJctSideGradingCoeff) * log(arg) );
2767  Cbd = czbd;
2768  Cbdsw = czbdsw;
2769 
2770  // The following lines were taken verbatim from the SPICE level 3 mosfet.
2771  // There is a mistake in f3d and f4d, which incorrectly use bulkJctPotential
2772  // instead of tBulkPot. The result of this mistake is to have an incorrect
2773  // discontinuity in the charge calculations --- the derivative of charge
2774  // is right as the voltage drop approaches the discontinuity from either side
2775  // but when numerical differentiation is done to get currents one obtains a
2776  // massive contribution to the right hand side. Since spice never checks
2777  // the RHS residual norm this seems not to have any effect on SPICE, but
2778  // Xyce pukes.
2779  // f2d = czbd*(1-model_.fwdCapDepCoeff*
2780  // (1+model_.bulkJctBotGradingCoeff))* sarg/arg
2781  // + czbdsw*(1-model_.fwdCapDepCoeff*
2782  // (1+model_.bulkJctSideGradingCoeff))*
2783  // sargsw/arg;
2784  // f3d = czbd * model_.bulkJctBotGradingCoeff * sarg/arg/
2785  // model_.bulkJctPotential
2786  // + czbdsw * model_.bulkJctSideGradingCoeff * sargsw/arg /
2787  // model_.bulkJctPotential;
2788  // f4d = czbd*model_.bulkJctPotential*(1-arg*sarg)/
2789  // (1-model_.bulkJctBotGradingCoeff)
2790  // + czbdsw*model_.bulkJctPotential*(1-arg*sargsw)/
2791  // (1-model_.bulkJctSideGradingCoeff)
2792  // -f3d/2*
2793  // (tDepCap*tDepCap)
2794  // -tDepCap * f2d;
2795 
2796  // These lines were taken from the equivalent section of the level 1 mosfet
2797  // and do not have the mistake in the lines above.
2798  f2d = czbd*(1-model_.fwdCapDepCoeff*
2799  (1+model_.bulkJctBotGradingCoeff))* sarg/arg
2800  + czbdsw*(1-model_.fwdCapDepCoeff*
2802  sargsw/arg;
2803  f3d = czbd * model_.bulkJctBotGradingCoeff * sarg/arg/
2804  tBulkPot
2805  + czbdsw * model_.bulkJctSideGradingCoeff * sargsw/arg /
2806  tBulkPot;
2807  f4d = czbd*tBulkPot*(1-arg*sarg)/
2809  + czbdsw*tBulkPot*(1-arg*sargsw)/
2811  -f3d/2*
2812  (tDepCap*tDepCap)
2813  -tDepCap * f2d;
2814  if(model_.capBSGiven)
2815  {
2816  czbs=tCbs;
2817  }
2818  else
2819  {
2821  {
2822  czbs=tCj*sourceArea;
2823  }
2824  else
2825  {
2826  czbs=0;
2827  }
2828  }
2830  {
2831  czbssw = tCjsw * sourcePerimeter;
2832  }
2833  else
2834  {
2835  czbssw=0;
2836  }
2837  arg = 1-model_.fwdCapDepCoeff;
2838  sarg = exp( (-model_.bulkJctBotGradingCoeff) * log(arg) );
2839  sargsw = exp( (-model_.bulkJctSideGradingCoeff) * log(arg) );
2840  Cbs = czbs;
2841  Cbssw = czbssw;
2842 
2843  // See the comments above regarding f3d and f4d --- the same error
2844  // exists in the SPICE mosfet3 code
2845  // f2s = czbs*(1-model_.fwdCapDepCoeff*
2846  // (1+model_.bulkJctBotGradingCoeff))* sarg/arg
2847  // + czbssw*(1-model_.fwdCapDepCoeff*
2848  // (1+model_.bulkJctSideGradingCoeff))*
2849  // sargsw/arg;
2850  // f3s = czbs * model_.bulkJctBotGradingCoeff * sarg/arg/
2851  // model_.bulkJctPotential
2852  // + czbssw * model_.bulkJctSideGradingCoeff * sargsw/arg /
2853  // model_.bulkJctPotential;
2854  // f4s = czbs*model_.bulkJctPotential*(1-arg*sarg)/
2855  // (1-model_.bulkJctBotGradingCoeff)
2856  // + czbssw*model_.bulkJctPotential*(1-arg*sargsw)/
2857  // (1-model_.bulkJctSideGradingCoeff)
2858  // -f3s/2*
2859  // (tBulkPot*tBulkPot)
2860  // -tBulkPot * f2s;
2861 
2862  // so we use these lines from the MOSFET 1 instead.
2863  f2s = czbs*(1-model_.fwdCapDepCoeff*
2864  (1+model_.bulkJctBotGradingCoeff))* sarg/arg
2865  + czbssw*(1-model_.fwdCapDepCoeff*
2867  sargsw/arg;
2868  f3s = czbs * model_.bulkJctBotGradingCoeff * sarg/arg/
2869  tBulkPot
2870  + czbssw * model_.bulkJctSideGradingCoeff * sargsw/arg /
2871  tBulkPot;
2872  f4s = czbs*tBulkPot*(1-arg*sarg)/
2874  + czbssw*tBulkPot*(1-arg*sargsw)/
2876  -f3s/2*
2877  (tDepCap*tDepCap)
2878  -tDepCap * f2s;
2879 
2880  return true;
2881 }
2882 
2883 //-----------------------------------------------------------------------------
2884 // Function : Instance::updatePrimaryState
2885 // Purpose :
2886 // Special Notes :
2887 // Scope : public
2888 // Creator : Tom Russo, Component Information and Models
2889 // Creation Date : 02/28/01
2890 //-----------------------------------------------------------------------------
2892 {
2893  double * staVector = extData.nextStaVectorRawPtr;
2894  double * oldstaVector = extData.currStaVectorRawPtr;
2895  double * stoVector = extData.nextStoVectorRawPtr;
2896  double * oldstoVector = extData.currStoVectorRawPtr;
2897 
2898  double vgs1, vgd1, vbs1,vgb1, vds1;
2899 
2900  bool bsuccess = updateIntermediateVars ();
2901 
2902  // voltage drops:
2903  stoVector[li_store_vbd] = vbd;
2904  stoVector[li_store_vbs] = vbs;
2905  stoVector[li_store_vgs] = vgs;
2906  stoVector[li_store_vds] = vds;
2907  stoVector[li_store_von] = von;
2908 
2909  // now the meyer capacitances
2910  // we didn't calculate these charges in update IntermediateVars
2911  // but we did calculate the voltage drops and capacitances.
2912  // first store the capacitances themselves:
2913  staVector[li_state_capgs] = capgs;
2914  staVector[li_state_capgd] = capgd;
2915  staVector[li_state_capgb] = capgb;
2916 
2917  // now the charges
2918  // BE CAREFUL! We can only do Q=CV for DCOP! Otherwise it's
2919  // supposed to be *INTEGRATED*:
2920  // Q = int(t0,t1)C(V)*dV --- and we approximate that by
2921  // Q(t1)-Q(t0) = CBar*(V(t1)-V(t0)) where CBar is the average.
2922  // Now with Meyer back averaging, Capxx is the average between the last
2923  // time step and this one. So we gotta do the right thing for non-DCOP
2924  // when backaverage is on.
2925 
2926  if((getSolverState().dcopFlag))
2927 // if(!(getSolverState().tranopFlag))
2928  {
2929  qgs = Capgs*vgs;
2930  qgd = Capgd*vgd;
2931  qgb = Capgb*Vgb;
2932  }
2933  else
2934  {
2935  // get the ones from last time step
2936  qgs = oldstaVector[li_state_qgs];
2937  qgd = oldstaVector[li_state_qgd];
2938  qgb = oldstaVector[li_state_qgb];
2939  // get the voltage drops, too
2940  vgs1 = oldstoVector[li_store_vgs];
2941  vbs1 = oldstoVector[li_store_vbs];
2942  vds1 = oldstoVector[li_store_vds];
2943 
2944  vgb1 = vgs1-vbs1;
2945  vgd1 = vgs1-vds1;
2946 
2947  // NOW we can calculate the charge update
2948  qgs += Capgs*(vgs-vgs1);
2949  qgd += Capgd*(vgd-vgd1);
2950  qgb += Capgb*((vgs-vbs)-vgb1);
2951  }
2952 
2953  staVector[li_state_qgs] = qgs;
2954  staVector[li_state_qgd] = qgd;
2955  staVector[li_state_qgb] = qgb;
2956 
2957  // and the diode parasitic capacitors
2958  // these charges were set in updateIntermediateVars
2959  staVector[li_state_qbd] = qbd;
2960  staVector[li_state_qbs] = qbs;
2961 
2962  return bsuccess;
2963 }
2964 
2965 
2966 
2967 //-----------------------------------------------------------------------------
2968 // Function : Xyce::Device::MOSFET3::Instance::getNumNoiseSources
2969 // Purpose :
2970 // Special Notes :
2971 // Scope : public
2972 // Creator : Eric Keiter, SNL
2973 // Creation Date : 12/27/2014
2974 //-----------------------------------------------------------------------------
2976 {
2977  return 4;
2978 }
2979 
2980 //-----------------------------------------------------------------------------
2981 // Function : Xyce::Device::MOSFET3::Instance::setupNoiseSources
2982 // Purpose :
2983 // Special Notes :
2984 // Scope : public
2985 // Creator : Eric Keiter
2986 // Creation Date :
2987 //-----------------------------------------------------------------------------
2989 {
2990  int numSources=4;
2991  noiseData.numSources = numSources;
2992  noiseData.resize(numSources);
2993 
2994  noiseData.deviceName = getName().getEncodedName();
2995 
2996  noiseData.noiseNames[0] = "onoise_" + getName().getEncodedName()+
2997  std::string("_rd"); // noise due to rd
2998  noiseData.noiseNames[1] = "onoise_" + getName().getEncodedName()+
2999  std::string("_rs"); // noise due to rs
3000  noiseData.noiseNames[2] = "onoise_" + getName().getEncodedName()+
3001  std::string("_id"); // noise due to id
3002  noiseData.noiseNames[3] = "onoise_" + getName().getEncodedName()+
3003  std::string("_1overf"); // flicker (1/f) noise
3004 
3005  // RD thermal:
3006  noiseData.li_Pos[0] = li_DrainPrime;
3007  noiseData.li_Neg[0] = li_Drain;
3008 
3009  // RS thermal:
3010  noiseData.li_Pos[1] = li_SourcePrime;
3011  noiseData.li_Neg[1] = li_Source;
3012 
3013  // ID thermal:
3014  noiseData.li_Pos[2] = li_DrainPrime;
3015  noiseData.li_Neg[2] = li_SourcePrime;
3016 
3017  // flicker:
3018  noiseData.li_Pos[3] = li_DrainPrime;
3019  noiseData.li_Neg[3] = li_SourcePrime;
3020 
3021 }
3022 
3023 //-----------------------------------------------------------------------------
3024 // Function : Xyce::Device::MOSFET3::Instance::getNoiseSources
3025 // Purpose :
3026 // Special Notes :
3027 // Scope : public
3028 // Creator : Eric Keiter
3029 // Creation Date :
3030 //-----------------------------------------------------------------------------
3032 {
3033  // thermal noise, RD:
3035  noiseData.noiseDens[0], noiseData.lnNoiseDens[0], THERMNOISE,
3037  temp);
3038 
3039  // thermal noise, RS:
3041  noiseData.noiseDens[1], noiseData.lnNoiseDens[1], THERMNOISE,
3043  temp);
3044 
3045  // thermal noise, ID:
3047  noiseData.noiseDens[2], noiseData.lnNoiseDens[2], THERMNOISE,
3048  (2.0/3.0 * fabs(gm)), temp);
3049 
3050  // flicker noise
3051  noiseData.noiseDens[3] = model_.fNcoef * std::exp(model_.fNexp *
3052  std::log(std::max(fabs(cd),N_MINLOG))) /
3053  (noiseData.freq * w * (l - 2*model_.latDiff) *
3055 
3056  noiseData.lnNoiseDens[3] = std::log(std::max(noiseData.noiseDens[3],N_MINLOG));
3057 }
3058 
3059 // Additional Declarations
3060 
3061 // Class Model
3062 
3063 //-----------------------------------------------------------------------------
3064 // Function : Model::processParams
3065 // Purpose :
3066 // Special Notes :
3067 // Scope : public
3068 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3069 // Creation Date : 6/03/02
3070 //-----------------------------------------------------------------------------
3072 {
3073  double wkfngs;
3074  double wkfng;
3075  double fermig;
3076  double fermis;
3077  double vfb;
3078  double kt1;
3079  double arg1;
3080 
3083  kt1 = CONSTboltz * tnom;
3084  egfet1 = 1.16-(7.02e-4*tnom*tnom)/(tnom+1108);
3085  arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(CONSTREFTEMP+CONSTREFTEMP));
3086  pbfact1 = -2*vtnom *(1.5*log(fact1)+CONSTQ*arg1);
3087 
3088  if(oxideThickness == 0)
3089  {
3090  UserError0(*this) << getName() << " has TOX=0";
3091  }
3092  else
3093  {
3094  oxideCapFactor = 3.9 * 8.854214871e-12/oxideThickness;
3095  }
3096  if(!given("U0") && !given("UO")) surfaceMobility=600;
3097  if(!given("KP"))
3099  if(given("NSUB"))
3100  {
3101  if(substrateDoping*1e6 >1.45e16)
3102  {
3103  if(!given("PHI"))
3104  {
3105  phi = 2*vtnom*
3106  log(substrateDoping*1e6/1.45e16);
3107  phi = std::max(0.1,phi);
3108  }
3109  fermis = dtype * .5 * phi;
3110  wkfng = 3.2;
3111  if(!given("TPG")) gateType=1;
3112  if(gateType != 0)
3113  {
3114  fermig = dtype *gateType*.5*egfet1;
3115  wkfng = 3.25 + .5 * egfet1 - fermig;
3116  }
3117  wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis);
3118  if(!given("GAMMA"))
3119  {
3120  gamma = sqrt(2 * 11.70 * CONSTperm0 *
3121  CONSTQ * substrateDoping*1e6)/
3123  }
3124  if(!given("VTO"))
3125  {
3126  if(!given("NSS"))
3128  vfb = wkfngs - surfaceStateDensity*1e4*CONSTQ/oxideCapFactor;
3129  vt0 = vfb + dtype * (gamma * sqrt(phi)+ phi);
3130  }
3131  else
3132  {
3133  vfb = vt0 - dtype * (gamma*sqrt(phi)+phi);
3134  }
3135  alpha = ((11.7*CONSTperm0)+(11.7*CONSTperm0))/
3136  (CONSTQ*substrateDoping*1e6); //(cm**3/m**3)
3137  coeffDepLayWidth = sqrt(alpha);
3138  }
3139  else
3140  {
3141  UserError0(*this) << "Nsub < Ni";
3142  }
3143  }
3144 
3145  // now model parameter preprocessing
3146  double mpi = M_PI;
3147  narrowFactor = delta * 0.5 * mpi * (11.7*CONSTperm0) /oxideCapFactor ;
3148 
3149  return true;
3150 }
3151 
3152 //----------------------------------------------------------------------------
3153 // Function : Model::processInstanceParams
3154 // Purpose :
3155 // Special Notes :
3156 // Scope : public
3157 // Creator : Dave Shirely, PSSI
3158 // Creation Date : 03/23/06
3159 //----------------------------------------------------------------------------
3161 {
3162  std::vector<Instance*>::iterator iter;
3163  std::vector<Instance*>::iterator first = instanceContainer.begin();
3164  std::vector<Instance*>::iterator last = instanceContainer.end();
3165 
3166  for (iter=first; iter!=last; ++iter)
3167  {
3168  (*iter)->processParams();
3169  }
3170 
3171  return true;
3172 }
3173 
3174 //-----------------------------------------------------------------------------
3175 // Function : Model::Model
3176 // Purpose :
3177 // Special Notes :
3178 // Scope : public
3179 // Creator : Tom Russo, Component Information and Models
3180 // Creation Date : 2/26/01
3181 //-----------------------------------------------------------------------------
3183  const Configuration & configuration,
3184  const ModelBlock & MB,
3185  const FactoryBlock & factory_block)
3186  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
3187  dtype(CONSTNMOS),
3188  tnom(getDeviceOptions().tnom),
3189  latDiff(0.0),
3190  jctSatCurDensity(0.0),
3191  jctSatCur(0.0),
3192  drainResistance(0.0),
3193  sourceResistance(0.0),
3194  sheetResistance(0.0),
3195  transconductance(0.0),
3196  gateSourceOverlapCapFactor(0.0),
3197  gateDrainOverlapCapFactor(0.0),
3198  gateBulkOverlapCapFactor(0.0),
3199  oxideCapFactor(0.0),
3200  vt0(0.0),
3201  capBD(0.0),
3202  capBS(0.0),
3203  bulkCapFactor(0.0),
3204  sideWallCapFactor(0.0),
3205  bulkJctPotential(0.0),
3206  bulkJctBotGradingCoeff(0.0),
3207  bulkJctSideGradingCoeff(0.0),
3208  fwdCapDepCoeff(0.0),
3209  phi(0.0),
3210  gamma(0.0),
3211  substrateDoping(0.0),
3212  gateType(0),
3213  surfaceStateDensity(0.0),
3214  oxideThickness(0.0),
3215  surfaceMobility(0.0),
3216  eta(0.0),
3217  junctionDepth(0.0),
3218  coeffDepLayWidth(0.0),
3219  narrowFactor(0.0),
3220  delta(0.0),
3221  fastSurfaceStateDensity(0.0),
3222  theta(0.0),
3223  maxDriftVel(0.0),
3224  alpha(0.0),
3225  kappa(0.0),
3226  fNcoef(0.0),
3227  fNexp(0.0),
3228  capBDGiven(0),
3229  capBSGiven(0),
3230  bulkCapFactorGiven(0),
3231  sideWallCapFactorGiven(0)
3232 {
3233  if (getType() != "")
3234  {
3235  if (getType() == "NMOS") {
3236  dtype = CONSTNMOS;
3237  }
3238  else if (getType() == "PMOS") {
3239  dtype = CONSTPMOS;
3240  }
3241  else
3242  {
3243  UserError0(*this) << "Could not recognize the type for model " << getName();
3244  }
3245  }
3246 
3247 
3248  // Set params to constant default values:
3249  setDefaultParams ();
3250 
3251  // Set params according to .model line and constant defaults from metadata:
3252  setModParams (MB.params);
3253 
3254  // Set any non-constant parameter defaults:
3255  if (!given("L"))
3257  if (!given("W"))
3259  if (!given("TNOM"))
3261  if (capBD != 0)
3262  capBDGiven = true;
3263  if (capBS != 0)
3264  capBSGiven = true;
3265 
3266  // Calculate any parameters specified as expressions:
3268 
3269  // calculate dependent (ie computed) params and check for errors:
3270  if (given("U0"))
3271  {
3272  if (given("UO"))
3273  UserError0(*this) << "Both uo and u0 have been specified and, which is not allowed";
3274  else
3275  UserWarning0(*this) << "Surface mobility has been specified as u0 instead of uo, uo is the preferred syntax";
3276 
3278  }
3279 
3280  processParams ();
3281 }
3282 
3283 //-----------------------------------------------------------------------------
3284 // Function : Model::~Model
3285 // Purpose : destructor
3286 // Special Notes :
3287 // Scope : public
3288 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3289 // Creation Date : 3/16/00
3290 //-----------------------------------------------------------------------------
3292 {
3293  std::vector<Instance*>::iterator iter;
3294  std::vector<Instance*>::iterator first = instanceContainer.begin();
3295  std::vector<Instance*>::iterator last = instanceContainer.end();
3296 
3297  for (iter=first; iter!=last; ++iter)
3298  {
3299  delete (*iter);
3300  }
3301 
3302 }
3303 
3304 //-----------------------------------------------------------------------------
3305 // Function : Model::printOutInstances
3306 // Purpose : debugging tool.
3307 // Special Notes :
3308 // Scope : public
3309 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3310 // Creation Date : 4/03/00
3311 //-----------------------------------------------------------------------------
3312 std::ostream &Model::printOutInstances(std::ostream &os) const
3313 {
3314  std::vector<Instance*>::const_iterator iter;
3315  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
3316  std::vector<Instance*>::const_iterator last = instanceContainer.end();
3317 
3318  int i;
3319  os << std::endl;
3320  os << " name model name Parameters" << std::endl;
3321  for (i=0, iter=first; iter!=last; ++iter, ++i)
3322  {
3323  os << " " << i << ": " << (*iter)->getName() << "\t";
3324  os << getName();
3325  os << std::endl;
3326  }
3327  os << std::endl;
3328 
3329  return os;
3330 }
3331 
3332 //-----------------------------------------------------------------------------
3333 // Function : Model::forEachInstance
3334 // Purpose :
3335 // Special Notes :
3336 // Scope : public
3337 // Creator : David Baur
3338 // Creation Date : 2/4/2014
3339 //-----------------------------------------------------------------------------
3340 /// Apply a device instance "op" to all instances associated with this
3341 /// model
3342 ///
3343 /// @param[in] op Operator to apply to all instances.
3344 ///
3345 ///
3346 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
3347 {
3348  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
3349  op(*it);
3350 }
3351 
3352 
3353 //-----------------------------------------------------------------------------
3354 // MOSFET3 Master functions:
3355 //-----------------------------------------------------------------------------
3356 
3357 //-----------------------------------------------------------------------------
3358 // Function : Master::updateState
3359 // Purpose :
3360 // Special Notes :
3361 // Scope : public
3362 // Creator : Eric Keiter, SNL
3363 // Creation Date : 11/26/08
3364 //-----------------------------------------------------------------------------
3365 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
3366 {
3367  bool bsuccess = true;
3368 
3369  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3370  {
3371  Instance & mi = *(*it);
3372 
3373  double * oldstaVectorPtr = mi.extData.currStaVectorRawPtr;
3374  double * stoVec = mi.extData.nextStoVectorRawPtr;
3375  double * oldstoVec = mi.extData.currStoVectorRawPtr;
3376 
3377  double vgs1(0.0), vgd1(0.0), vbs1(0.0),vgb1(0.0), vds1(0.0);
3378 
3379  bool btmp = mi.updateIntermediateVars ();
3380  bsuccess = bsuccess && btmp;
3381 
3382  // voltage drops:
3383  stoVec[mi.li_store_vbd] = mi.vbd;
3384  stoVec[mi.li_store_vbs] = mi.vbs;
3385  stoVec[mi.li_store_vgs] = mi.vgs;
3386  stoVec[mi.li_store_vds] = mi.vds;
3387  stoVec[mi.li_store_von] = mi.von;
3388 
3389  // now the meyer capacitances
3390  // we didn't calculate these charges in update IntermediateVars
3391  // but we did calculate the voltage drops and capacitances.
3392  // first store the capacitances themselves:
3393  staVec[mi.li_state_capgs] = mi.capgs;
3394  staVec[mi.li_state_capgd] = mi.capgd;
3395  staVec[mi.li_state_capgb] = mi.capgb;
3396 
3397  // now the charges
3398  // BE CAREFUL! We can only do Q=CV for DCOP! Otherwise it's
3399  // supposed to be *INTEGRATED*:
3400  // Q = int(t0,t1)C(V)*dV --- and we approximate that by
3401  // Q(t1)-Q(t0) = CBar*(V(t1)-V(t0)) where CBar is the average.
3402  // Now with Meyer back averaging, Capxx is the average between the last
3403  // time step and this one. So we gotta do the right thing for non-DCOP
3404  // when backaverage is on.
3405 
3406  if((getSolverState().dcopFlag))
3407 // if(!(getSolverState().tranopFlag))
3408  {
3409  mi.qgs = mi.Capgs*mi.vgs;
3410  mi.qgd = mi.Capgd*mi.vgd;
3411  mi.qgb = mi.Capgb*mi.Vgb;
3412  }
3413  else
3414  {
3415  // get the ones from last time step
3416  mi.qgs = (oldstaVectorPtr)[mi.li_state_qgs];
3417  mi.qgd = (oldstaVectorPtr)[mi.li_state_qgd];
3418  mi.qgb = (oldstaVectorPtr)[mi.li_state_qgb];
3419  // get the voltage drops, too
3420  vgs1 = oldstoVec[mi.li_store_vgs];
3421  vbs1 = oldstoVec[mi.li_store_vbs];
3422  vds1 = oldstoVec[mi.li_store_vds];
3423 
3424  vgb1 = vgs1-vbs1;
3425  vgd1 = vgs1-vds1;
3426 
3427  // NOW we can calculate the charge update
3428  mi.qgs += mi.Capgs*(mi.vgs-vgs1);
3429  mi.qgd += mi.Capgd*(mi.vgd-vgd1);
3430  mi.qgb += mi.Capgb*((mi.vgs-mi.vbs)-vgb1);
3431  }
3432 
3433  staVec[mi.li_state_qgs] = mi.qgs;
3434  staVec[mi.li_state_qgd] = mi.qgd;
3435  staVec[mi.li_state_qgb] = mi.qgb;
3436 
3437  // and the diode parasitic capacitors
3438  // these charges were set in updateIntermediateVars
3439  staVec[mi.li_state_qbd] = mi.qbd;
3440  staVec[mi.li_state_qbs] = mi.qbs;
3441  }
3442 
3443  return bsuccess;
3444 }
3445 
3446 //-----------------------------------------------------------------------------
3447 // Function : Master::loadDAEVectors
3448 // Purpose :
3449 // Special Notes :
3450 // Scope : public
3451 // Creator : Eric Keiter, SNL
3452 // Creation Date : 11/26/08
3453 //-----------------------------------------------------------------------------
3454 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * bVec, double * storeLeadF, double * storeLeadQ, double * leadF, double * leadQ, double * junctionV)
3455 {
3456  double gmin1 = getDeviceOptions().gmin;
3457 
3458  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3459  {
3460  Instance & mi = *(*it);
3461 
3462  int Dtype=mi.getModel().dtype;
3463  double ceqbs(0.0),ceqbd(0.0),ceqgb(0.0), ceqgs(0.0), ceqgd(0.0);
3464  double Qeqbs(0.0),Qeqbd(0.0),Qeqgb(0.0), Qeqgs(0.0), Qeqgd(0.0);
3465  double coef(0.0);
3466 
3467  // F-Vector:
3468  ceqbs = Dtype*(mi.cbs);
3469  ceqbd = Dtype*(mi.cbd);
3470  // These need "Dtype" here because we use them later *without*
3471  // Dtype, where SPICE uses it *with*
3472  ceqgb = 0.0;
3473  ceqgs = 0.0;
3474  ceqgd = 0.0;
3475 
3476  if (mi.drainConductance != 0.0)
3477  {
3478  fVec[mi.li_Drain] += mi.Idrain*mi.numberParallel;
3479  }
3480 
3481  coef = (ceqgs+ceqgd+ceqgb);
3482 
3483  fVec[mi.li_Gate] += coef*mi.numberParallel;
3484 
3485  if (mi.sourceConductance != 0.0)
3486  {
3487  fVec[mi.li_Source] += mi.Isource*mi.numberParallel;
3488  }
3489 
3490  coef = ceqbs + ceqbd - ceqgb;
3491 
3492  fVec[mi.li_Bulk] += coef*mi.numberParallel;
3493 
3494  coef = -mi.Idrain-(ceqbd - mi.cdreq + ceqgd);
3495 
3496  fVec[mi.li_DrainPrime] += coef*mi.numberParallel;
3497 
3498  coef = -mi.Isource-(ceqbs + mi.cdreq + ceqgs);
3499 
3500  fVec[mi.li_SourcePrime] += coef*mi.numberParallel;
3501 
3502  // Q-Vector:
3503  Qeqbs = Dtype*(mi.qbs);
3504  Qeqbd = Dtype*(mi.qbd);
3505  // These need "Dtype" here because we use them later *without*
3506  // Dtype, where SPICE uses it *with*
3507  Qeqgb = Dtype*(mi.qgb);
3508  Qeqgs = Dtype*(mi.qgs);
3509  Qeqgd = Dtype*(mi.qgd);
3510 
3511  coef = (Qeqgs+Qeqgd+Qeqgb);
3512 
3513  qVec[mi.li_Gate] += coef*mi.numberParallel;
3514 
3515  coef = Qeqbs + Qeqbd - Qeqgb;
3516 
3517  qVec[mi.li_Bulk] += coef*mi.numberParallel;
3518 
3519  coef = -(Qeqbd + Qeqgd);
3520 
3521  qVec[mi.li_DrainPrime] += coef*mi.numberParallel;
3522 
3523  coef = -(Qeqbs + Qeqgs);
3524 
3525  qVec[mi.li_SourcePrime] += coef*mi.numberParallel;
3526 
3527  // voltage limiters:
3528  if (!mi.origFlag)
3529  {
3530  // F-limiters:
3531  double coef_Jdxp4 = Dtype*(
3532  + ((mi.gbd-gmin1))*(mi.vbd-mi.vbd_orig)
3533  + ((mi.gbs-gmin1))*(mi.vbs-mi.vbs_orig));
3534 
3535  double coef_Jdxp5 = Dtype*(
3536  -((mi.gbd-gmin1))*(mi.vbd-mi.vbd_orig)
3537  +mi.gds*(mi.vds-mi.vds_orig)
3538  +mi.Gm*((mi.mode>0)?(mi.vgs-mi.vgs_orig):(mi.vgd-mi.vgd_orig))
3539  +mi.Gmbs*((mi.mode>0)?(mi.vbs-mi.vbs_orig):(mi.vbd-mi.vbd_orig)));
3540 
3541  double coef_Jdxp6 = Dtype*(
3542  -((mi.gbs-gmin1))*(mi.vbs-mi.vbs_orig)
3543  -mi.gds*(mi.vds-mi.vds_orig)
3544  -mi.Gm*((mi.mode>0)?(mi.vgs-mi.vgs_orig):(mi.vgd-mi.vgd_orig))
3545  -mi.Gmbs*((mi.mode>0)?(mi.vbs-mi.vbs_orig):(mi.vbd-mi.vbd_orig)));
3546 
3547  double * dFdxdVp = mi.extData.dFdxdVpVectorRawPtr;
3548  dFdxdVp[mi.li_Bulk ] += coef_Jdxp4*mi.numberParallel;
3549  dFdxdVp[mi.li_DrainPrime ] += coef_Jdxp5*mi.numberParallel;
3550  dFdxdVp[mi.li_SourcePrime] += coef_Jdxp6*mi.numberParallel;
3551 
3552  // Q-limiters:
3553  {
3554  double gcgd(0.0), gcgs(0.0), gcgb(0.0), gcbs(0.0), gcbd(0.0);
3555  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3556  {
3557  gcgd = mi.Capgd;
3558  gcgs = mi.Capgs;
3559  gcgb = mi.Capgb;
3560  // get at the two parasitic caps the same way
3561  gcbs = mi.capbs;
3562  gcbd = mi.capbd;
3563  }
3564  else
3565  {
3566  gcgd = 0.0; gcgs = 0.0; gcgb = 0.0; gcbs = 0.0; gcbd = 0.0;
3567  }
3568 
3569  double coef_Jdxp2 =
3570  Dtype*(gcgd*(mi.vgd-mi.vgd_orig)+gcgs*(mi.vgs-mi.vgs_orig)+
3571  gcgb*(mi.vgs-mi.vgs_orig-mi.vbs+mi.vbs_orig));
3572 
3573  double coef_Jdxp4 = Dtype*(
3574  - (gcgb)*(mi.vgs-mi.vgs_orig-mi.vbs+mi.vbs_orig)
3575  + (gcgb)*(mi.vbd-mi.vbd_orig)
3576  + (gcbs)*(mi.vbs-mi.vbs_orig));
3577 
3578  double coef_Jdxp5 = Dtype*(
3579  -(gcgd)*(mi.vgd-mi.vgd_orig)
3580  -(gcbd)*(mi.vbd-mi.vbd_orig));
3581 
3582  // 6 KCL for source' node
3583  double coef_Jdxp6 = Dtype*
3584  (-gcgs*(mi.vgs-mi.vgs_orig)-(gcbs)*(mi.vbs-mi.vbs_orig));
3585 
3586  double * dQdxdVp = mi.extData.dQdxdVpVectorRawPtr;
3587  dQdxdVp[mi.li_Gate ] += coef_Jdxp2*mi.numberParallel;
3588  dQdxdVp[mi.li_Bulk ] += coef_Jdxp4*mi.numberParallel;
3589  dQdxdVp[mi.li_DrainPrime ] += coef_Jdxp5*mi.numberParallel;
3590  dQdxdVp[mi.li_SourcePrime] += coef_Jdxp6*mi.numberParallel;
3591  }
3592  }
3593 
3594  if( mi.loadLeadCurrent )
3595  {
3596  storeLeadF[mi.li_store_dev_id] = (-(ceqbd - mi.cdreq + ceqgd))*mi.numberParallel;
3597  storeLeadQ[mi.li_store_dev_id] = (-(Qeqbd + Qeqgd))*mi.numberParallel;
3598  storeLeadF[mi.li_store_dev_is] = (-(ceqbs + mi.cdreq + ceqgs))*mi.numberParallel;
3599  storeLeadQ[mi.li_store_dev_is] = (-(Qeqbs + Qeqgs))*mi.numberParallel;
3600  storeLeadF[mi.li_store_dev_ig] = (ceqgs+ceqgd+ceqgb)*mi.numberParallel;
3601  storeLeadQ[mi.li_store_dev_ig] = (Qeqgs+Qeqgd+Qeqgb)*mi.numberParallel;
3602  storeLeadF[mi.li_store_dev_ib] = (ceqbs + ceqbd - ceqgb)*mi.numberParallel;
3603  storeLeadQ[mi.li_store_dev_ib] = (Qeqbs + Qeqbd - Qeqgb)*mi.numberParallel;
3604  }
3605  }
3606 
3607  return true;
3608 }
3609 
3610 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
3611 //-----------------------------------------------------------------------------
3612 // Function : Master::loadDAEMatrices
3613 // Purpose :
3614 // Special Notes :
3615 // Scope : public
3616 // Creator : Eric Keiter, SNL
3617 // Creation Date : 11/26/08
3618 //-----------------------------------------------------------------------------
3619 bool Master::loadDAEMatrices (Linear::Matrix & dFdx, Linear::Matrix & dQdx)
3620 {
3621  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
3622  {
3623  Instance & mi = *(*it);
3624 
3625  // F-matrix:
3626 
3627  *mi.f_DrainEquDrainNodePtr +=
3629 
3632 
3633 
3636 
3639 
3640 
3641  *mi.f_BulkEquBulkNodePtr +=
3642  (mi.gbs+mi.gbd)*mi.numberParallel;
3643 
3645 
3647 
3648 
3651 
3653  mi.Gm*mi.numberParallel;
3654 
3656  (-mi.gbd+mi.Gmbs)*mi.numberParallel;
3657 
3659  (mi.drainConductance+mi.gds+mi.gbd+mi.revsum)*mi.numberParallel;
3660 
3662  (-mi.gds-mi.nrmsum)*mi.numberParallel;
3663 
3664 
3666  mi.Gm*mi.numberParallel;
3667 
3670 
3672  (mi.gbs+mi.Gmbs)*mi.numberParallel;
3673 
3675  (mi.gds+mi.revsum)*mi.numberParallel;
3676 
3678  (mi.sourceConductance+mi.gds+mi.gbs+mi.nrmsum)*mi.numberParallel;
3679 
3680  // Q-matrix:
3681  double gcgd(0.0); // d(cqgd)/dVgd
3682  double gcgs(0.0); // d(cqgs)/dVgs
3683  double gcgb(0.0); // d(cqgb)/dVgb
3684  double gcbs(0.0); // d(cqbs)/dVbs
3685  double gcbd(0.0); // d(cqbd)/dVbd
3686 
3687  // get at the "conductances" for the gate capacitors with this trick
3688  // gcgd = model_.dtype*Capgd;
3689  // gcgs = model_.dtype*Capgs;
3690  // gcgb = model_.dtype*Capgb;
3691  //
3692  // In the loadRHS function, these would all be multiplied by
3693  // getSolverState().pdt. Here, for *mi.q_, the pdt term is left out.
3694  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3695  {
3696  gcgd = mi.Capgd;
3697  gcgs = mi.Capgs;
3698  gcgb = mi.Capgb;
3699  // get at the two parasitic caps the same way
3700  gcbs = mi.capbs;
3701  gcbd = mi.capbd;
3702  }
3703 
3704 
3705  *mi.q_GateEquGateNodePtr +=
3706  (gcgd+gcgs+gcgb)*mi.numberParallel;
3707 
3708  *mi.q_GateEquBulkNodePtr -= gcgb*mi.numberParallel;
3709 
3711 
3713 
3714 
3715  *mi.q_BulkEquGateNodePtr -= gcgb*mi.numberParallel;
3716 
3717  *mi.q_BulkEquBulkNodePtr +=
3718  (+gcbs+gcbd+gcgb)*mi.numberParallel;
3719 
3721 
3723  +gcbs*mi.numberParallel;
3724 
3725 
3727  -gcgd*mi.numberParallel;
3728 
3730  -gcbd*mi.numberParallel;
3731 
3733  (+gcbd+gcgd)*mi.numberParallel;
3734 
3735 
3737  gcgs*mi.numberParallel;
3738 
3740  +gcbs*mi.numberParallel;
3741 
3743  (+gcbs+gcgs)*mi.numberParallel;
3744  }
3745  return true;
3746 }
3747 #else
3748 //-----------------------------------------------------------------------------
3749 // Function : Master::loadDAEMatrices
3750 // Purpose :
3751 // Special Notes :
3752 // Scope : public
3753 // Creator : Eric Keiter, SNL
3754 // Creation Date : 11/26/08
3755 //-----------------------------------------------------------------------------
3756 bool Master::loadDAEMatrices (Linear::Matrix & dFdx, Linear::Matrix & dQdx)
3757 {
3758  int sizeInstances = instanceContainer_.size();
3759  for (int i=0; i<sizeInstances; ++i)
3760  {
3761  Instance & mi = *(instanceContainer_.at(i));
3762 
3763  // F-matrix:
3764  dFdx[mi.li_Drain][mi.ADrainEquDrainNodeOffset] +=
3766 
3767  dFdx[mi.li_Drain][mi.ADrainEquDrainPrimeNodeOffset] -=
3769 
3770  dFdx[mi.li_Source][mi.ASourceEquSourceNodeOffset] +=
3772 
3775 
3776  dFdx[mi.li_Bulk][mi.ABulkEquBulkNodeOffset] +=
3777  (mi.gbs+mi.gbd)*mi.numberParallel;
3778 
3781 
3782 
3785 
3787  mi.Gm*mi.numberParallel;
3788 
3790  (-mi.gbd+mi.Gmbs)*mi.numberParallel;
3791 
3793  (mi.drainConductance+mi.gds+mi.gbd+mi.revsum)*mi.numberParallel;
3794 
3796  (-mi.gds-mi.nrmsum)*mi.numberParallel;
3797 
3798 
3800  mi.Gm*mi.numberParallel;
3801 
3804 
3806  (mi.gbs+mi.Gmbs)*mi.numberParallel;
3807 
3809  (mi.gds+mi.revsum)*mi.numberParallel;
3810 
3812  (mi.sourceConductance+mi.gds+mi.gbs+mi.nrmsum)*mi.numberParallel;
3813 
3814  // Q-matrix:
3815  double gcgd(0.0); // d(cqgd)/dVgd
3816  double gcgs(0.0); // d(cqgs)/dVgs
3817  double gcgb(0.0); // d(cqgb)/dVgb
3818  double gcbs(0.0); // d(cqbs)/dVbs
3819  double gcbd(0.0); // d(cqbd)/dVbd
3820 
3821  // get at the "conductances" for the gate capacitors with this trick
3822  // gcgd = model_.dtype*Capgd;
3823  // gcgs = model_.dtype*Capgs;
3824  // gcgb = model_.dtype*Capgb;
3825  //
3826  // In the loadRHS function, these would all be multiplied by
3827  // getSolverState().pdt. Here, for dQdx, the pdt term is left out.
3828  if (getSolverState().tranopFlag || getSolverState().acopFlag || getSolverState().transientFlag)
3829  {
3830  gcgd = mi.Capgd;
3831  gcgs = mi.Capgs;
3832  gcgb = mi.Capgb;
3833  // get at the two parasitic caps the same way
3834  gcbs = mi.capbs;
3835  gcbd = mi.capbd;
3836  }
3837 
3838 
3839  dQdx[mi.li_Gate][mi.AGateEquGateNodeOffset] +=
3840  (gcgd+gcgs+gcgb)*mi.numberParallel;
3841 
3842  dQdx[mi.li_Gate][mi.AGateEquBulkNodeOffset] -= gcgb*mi.numberParallel;
3843  dQdx[mi.li_Gate][mi.AGateEquDrainPrimeNodeOffset] -= gcgd*mi.numberParallel;
3844  dQdx[mi.li_Gate][mi.AGateEquSourcePrimeNodeOffset] -= gcgs*mi.numberParallel;
3845  dQdx[mi.li_Bulk][mi.ABulkEquGateNodeOffset] -= gcgb*mi.numberParallel;
3846  dQdx[mi.li_Bulk][mi.ABulkEquBulkNodeOffset] +=
3847  (+gcbs+gcbd+gcgb)*mi.numberParallel;
3848  dQdx[mi.li_Bulk][mi.ABulkEquDrainPrimeNodeOffset] -= +gcbd*mi.numberParallel;
3849  dQdx[mi.li_Bulk][mi.ABulkEquSourcePrimeNodeOffset] -=
3850  +gcbs*mi.numberParallel;
3852  -gcgd*mi.numberParallel;
3854  -gcbd*mi.numberParallel;
3856  (+gcbd+gcgd)*mi.numberParallel;
3858  gcgs*mi.numberParallel;
3860  +gcbs*mi.numberParallel;
3862  (+gcbs+gcgs)*mi.numberParallel;
3863  }
3864  return true;
3865 }
3866 #endif
3867 
3868 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
3869 {
3870 
3871  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
3872 }
3873 
3875 {
3877  .registerDevice("m", 3)
3878  .registerModelType("pmos", 3)
3879  .registerModelType("nmos", 3);
3880 }
3881 
3882 } // namespace MOSFET3
3883 } // namespace Device
3884 } // namespace Xyce
const InstanceName & getName() const
#define CONSTPMOS
Definition: N_DEV_Const.h:77
static std::vector< std::vector< int > > jacStamp
void registerStoreLIDs(const std::vector< int > &stoLIDVecRef)
static void initThermalModel(ParametricData< T > &parametric_data)
Add the parameter "TEMPMODEL" to the parametric_data.
virtual bool loadDAEMatrices(Linear::Matrix &dFdx, Linear::Matrix &dQdx)
Populates the device's Jacobian object with these pointers.
void loadNodeSymbols(Util::SymbolTable &symbol_table) const
Populates and returns the store name map.
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
static std::vector< std::vector< int > > jacMap2_DC_SC
#define CONSTREFTEMP
Definition: N_DEV_Const.h:56
#define CONSTQ
Definition: N_DEV_Const.h:51
double pnjlim(double vnew, double vold, double vt, double vcrit, int *icheck)
void qmeyer(double vgs, double vgd, double vgb, double von, double vdsat, double &capgs, double &capgd, double &capgb, double phi, double cox)
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
std::vector< Instance * > instanceContainer
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.
static std::vector< std::vector< int > > jacStamp_DC
void registerStateLIDs(const std::vector< int > &staLIDVecRef)
static void loadModelParameters(ParametricData< Model > &model_parameters)
void registerLIDs(const std::vector< int > &intLIDVecRef, const std::vector< int > &extLIDVecRef)
#define CONSTMAX_EXP_ARG
Definition: N_DEV_Const.h:107
void setNumStoreVars(int num_store_vars)
std::vector< double > gainScale
void makeVector(const std::string &cname, int len)
Allows the parameter to be specified as a vector.
Definition: N_DEV_Pars.h:1597
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...
#define AssertLIDs(cmp)
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.
std::vector< int > li_Pos
#define CONSTNMOS
Definition: N_DEV_Const.h:76
Parameter is subject to being set to minimum junction capacitance.
Definition: N_DEV_Pars.h:71
void getNoiseSources(Xyce::Analysis::NoiseData &noiseData)
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
Parameter is subject to being set to minimum lead resistance.
Definition: N_DEV_Pars.h:70
double fetlim(double vnew, double vold, double vto)
InstanceVector::const_iterator getInstanceBegin() const
Returns an iterator to the beginning of the vector of all instances created for this device...
virtual bool updateState(double *solVec, double *staVec, double *stoVec)
Updates the devices state information.
#define N_MINLOG
Definition: N_ANP_NOISE.C:104
double contVgst(double vgst, double alpha, double vgstConst=3.0)
std::vector< Param > params
Parameters from the line.
std::vector< double > noiseDens
static Device * factory(const Configuration &configuration, const FactoryBlock &factory_block)
std::vector< std::string > noiseNames
void setParams(const std::vector< Param > &params)
const std::string & getName() const
bool processParams()
processParams
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
#define CONSTperm0
Definition: N_DEV_Const.h:61
virtual std::ostream & printOutInstances(std::ostream &os) const
const DeviceOptions & getDeviceOptions() const
#define CONSTroot2
Definition: N_DEV_Const.h:50
double limvds(double vnew, double vold)
static Config< T > & addConfiguration()
Adds the device to the Xyce device configuration.
Linear::Matrix * dFdxMatrixPtr
const DeviceOptions & getDeviceOptions() const
Returns the device options given during device construction.
static std::vector< std::vector< int > > jacStamp_DC_SC
bool updateTemperature(const double &temp_tmp)
The Device class is an interface for device implementations.
Definition: N_DEV_Device.h:101
void addStoreNode(Util::SymbolTable &symbol_table, int index, const InstanceName &instance_name, const std::string &lead_name)
static std::vector< std::vector< int > > jacMap2
static std::vector< int > jacMap
Instance(const Configuration &configuration, const InstanceBlock &IB, Model &Miter, const FactoryBlock &factory_block)
const SolverState & solverState_
int getGainScaleBlockID(int numBlocks)
Class Configuration contains device configuration data.
std::vector< double > lnNoiseDens
void setupNoiseSources(Xyce::Analysis::NoiseData &noiseData)
static std::vector< int > jacMap_SC
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
#define M_PI
static std::vector< std::vector< int > > jacStamp_SC
Linear::Vector * nextStoVectorPtr
Linear::Vector * currStaVectorPtr
static std::vector< int > jacMap_DC_SC
#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)
const std::string & getType() const
void registerJacLIDs(const std::vector< std::vector< int > > &jacLIDVec)
double contVds(double vds, double alpha, double min=0.3)
#define CONSTKoverQ
Definition: N_DEV_Const.h:58
Linear::Vector * currStoVectorPtr
static std::vector< int > jacMap_DC
virtual void forEachInstance(DeviceInstanceOp &op) const
Apply a device instance "op" to all instances associated with this model.
const std::vector< std::vector< int > > & jacobianStamp() const
ModelBlock represents a .MODEL line from the netlist.
Manages parameter binding for class C.
Definition: N_DEV_Pars.h:214
InstanceBlock represent a device instance line from the netlist.
static std::vector< std::vector< int > > jacMap2_SC
std::vector< Param > params
Linear::Matrix * dQdxMatrixPtr
static void loadInstanceParameters(ParametricData< Instance > &instance_parameters)
Definition: N_DEV_MOSFET3.C:76
Linear::Vector * flagSolVectorPtr
static std::vector< std::vector< int > > jacMap2_DC
bool processInstanceParams()
processInstanceParams
const SolverState & getSolverState() const
Returns the solver state given during device construction.
void setModParams(const std::vector< Param > &params)
#define CONSTboltz
Definition: N_DEV_Const.h:53