Xyce  6.1
N_DEV_RxnSet.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_RxnSet.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL
33 //
34 // Creation Date : 02/09/08
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.58.2.1 $
40 // Revision Date : $Date: 2015/04/02 18:20:09 $
41 //
42 // Current Owner : $Author: tvrusso $
43 //-------------------------------------------------------------------------
44 
45 #include <Xyce_config.h>
46 
47 // ---------- Standard Includes ----------
48 #include <iostream>
49 #include <iomanip>
50 #include <N_UTL_Math.h>
51 #include <cstdio>
52 
53 // ---------- Xyce Includes ----------
54 #include <N_DEV_Const.h>
55 #include <N_DEV_DeviceOptions.h>
56 #include <N_DEV_DeviceMaster.h>
57 #include <N_DEV_ExternData.h>
58 #include <N_DEV_MatrixLoadData.h>
59 #include <N_DEV_Message.h>
60 #include <N_DEV_Region.h>
61 #include <N_DEV_RegionData.h>
62 #include <N_DEV_SolverState.h>
63 #include <N_DEV_SpecieSource.h>
64 
65 #include <N_LAS_Matrix.h>
66 #include <N_LAS_MultiVector.h>
67 #include <N_LAS_Vector.h>
68 
69 #include <N_DEV_RxnSet.h>
70 #include <N_DEV_ReactionNetwork.h>
71 
72 #include <N_UTL_Expression.h>
73 #include <N_UTL_BreakPoint.h>
74 
75 namespace Xyce {
76 namespace Device {
77 
78 namespace RxnSet {
79 
81 {
82  p.addPar("TEMP",0.0,&RxnSet::Instance::TEMP)
83  .setExpressionAccess(ParameterType::TIME_DEP)
84  .setUnit(STANDARD)
85  .setDescription("Temperature");
86 
87  p.addPar("X0",1.0e-7,&RxnSet::Instance::x0_user)
88  .setUnit(U_NONE)
89  .setCategory(CAT_SCALING)
90  .setDescription("Length Scalar.");
91 
92  p.addPar("C0",1.0e+12,&RxnSet::Instance::C0_user)
93  .setUnit(U_NONE)
94  .setCategory(CAT_SCALING)
95  .setDescription("Concentration Scalar.");
96 
97  p.addPar("t0",1.0e-6,&RxnSet::Instance::t0_user)
98  .setUnit(U_NONE)
99  .setCategory(CAT_SCALING)
100  .setDescription("Time Scalar.");
101 
102  p.addPar("outputXscalar",1.0,&RxnSet::Instance::outputXscalar)
103  .setUnit(U_NONE)
104  .setCategory(CAT_OUTPUT)
105  .setDescription("Scalar for X axis in tecplot file (default unit is cm)");
106 
107  p.addPar("OUTPUTINTERVAL",0.0,&RxnSet::Instance::outputInterval)
108  .setUnit(U_NONE)
109  .setCategory(CAT_OUTPUT)
110  .setDescription("Output Interval(sec)");
111 
113  .setUnit(U_LOGIC)
114  .setCategory(CAT_NONE)
115  .setDescription("Flag for processing chemistry file only once,then copied to other mesh points.");
116 
118  .setUnit(U_LOGIC)
119  .setCategory(CAT_SCALING)
120  .setDescription("Flag for applying scaling to the reaction equations.");
121 
122  p.addPar("DIFFUSION",false,&RxnSet::Instance::diffusionFlag)
123  .setGivenMember(&RxnSet::Instance::diffusionFlagGiven)
124  .setUnit(U_LOGIC)
125  .setCategory(CAT_NONE)
126  .setDescription("Flag for enabling lattice defect diffusion.");
127 
128  p.addPar("TRANSPORT",false,&RxnSet::Instance::transportFlag)
129  .setGivenMember(&RxnSet::Instance::transportFlagGiven)
130  .setUnit(U_LOGIC)
131  .setCategory(CAT_NONE)
132  .setDescription("Flag for enabling lattice defect diffusion. Identical to DIFFUSION flag,above. Do not set both!");
133 
134  p.addPar("EXCLUDENOSOURCE",true,&RxnSet::Instance::excludeNoSourceRegionsFlag)
136  .setUnit(U_LOGIC)
137  .setCategory(CAT_NONE)
138  .setDescription("Flag for excluding regions that are outside of source region from computing defect reaction equations. This is a speed optimization. Turning it on will NOT change the answer");
139 
140  p.addPar("COLUMNREORDER",false,&RxnSet::Instance::columnReorderingFlag)
141  .setUnit(U_LOGIC)
142  .setCategory(CAT_NONE)
143  .setDescription("Debug Flag for turning on/off column reordering.");
144 
145  p.addPar("OUTPUTREGION",1,&RxnSet::Instance::outputRegion)
146  .setCategory(CAT_OUTPUT);
147 
148  p.addPar("TECPLOTLEVEL",0,&RxnSet::Instance::tecplotLevel)
149  .setCategory(CAT_OUTPUT)
150  .setDescription("Integer number to determine type of tecplot output. 0=no output. 1=single time-dependent file,with each time step in a different zone.");
151 
152  p.addPar("DIRICHLETBC",false,&RxnSet::Instance::dirichletBCFlag)
153  .setUnit(U_LOGIC)
154  .setCategory(CAT_BOUNDARYCONDITIONS)
155  .setDescription("Flag for using Dirichlet boundary conditions.");
156 }
157 
159 {
160  p.addPar("TNOM",0.0,&RxnSet::Model::TNOM)
161  .setUnit(U_DEGC)
162  .setCategory(CAT_UNKNOWN)
163  .setDescription("Parameter measurement temperature");
164 
165  // rxn stuff:
166  p.addPar("XLO",1.0e-5,&RxnSet::Model::xlo)
167  .setUnit(U_CM)
168  .setCategory(CAT_UNKNOWN)
169  .setDescription("Left edge of integration volume.");
170 
171  p.addPar("XHI",3.0e-4,&RxnSet::Model::xhi)
172  .setUnit(U_CM)
173  .setCategory(CAT_UNKNOWN)
174  .setDescription("Right edge of integration volume");
175 
176  p.addPar("XLO_SOURCE",1.0e-5,&RxnSet::Model::xlo_source)
177  .setGivenMember(&RxnSet::Model::xlo_sourceGiven)
178  .setUnit(U_CM)
179  .setCategory(CAT_UNKNOWN)
180  .setDescription("Left edge of source region");
181 
182  p.addPar("XHI_SOURCE",3.0e-4,&RxnSet::Model::xhi_source)
183  .setGivenMember(&RxnSet::Model::xhi_sourceGiven)
184  .setUnit(U_CM)
185  .setCategory(CAT_UNKNOWN)
186  .setDescription("Right edge of source region");
187 
188  p.addPar("MASTERSOURCE",0.0,&RxnSet::Model::masterSource)
189  .setExpressionAccess(ParameterType::TIME_DEP)
190  .setUnit(STANDARD)
191  .setCategory(CAT_NONE)
192  .setDescription("");
193 
194  p.addPar("REACTION_FILE",std::string("NOFILE"),&RxnSet::Model::rxnFileName)
195  .setUnit(U_NONE)
196  .setCategory(CAT_NONE)
197  .setDescription("Name of the reaction file");
198 
199  p.addPar("NUMBER_REGIONS",0,&RxnSet::Model::userNumRegions)
200  .setUnit(U_NONE)
201  .setCategory(CAT_NONE)
202  .setDescription("Number of mesh points.");
203 
205 
207 
209 
211 
213 }
214 
215 //-----------------------------------------------------------------------------
216 // Function : Instance::processParams
217 // Purpose :
218 // Special Notes :
219 // Scope : public
220 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
221 // Creation Date : 02/09/08
222 //-----------------------------------------------------------------------------
224 {
226  return true;
227 }
228 
229 //----------------------------------------------------------------------------
230 // Function : Instance::Instance
231 // Purpose : instance block constructor
232 // Special Notes :
233 // Scope : public
234 // Creator : Eric R. Keiter
235 // Creation Date : 02/09/08
236 //----------------------------------------------------------------------------
237 
239  const Configuration & configuration,
240  const InstanceBlock & IB,
241  Model & it_MB,
242  const FactoryBlock & factory_block)
243  : DevicePDEInstance(IB,configuration.getInstanceParameters(), factory_block),
244  model_(it_MB),
245  reactionFileCopyFlag(false),
246  haveAnyReactions(false),
247  useScaledVariablesFlag(true),
248  useDopingArrayData(false),
249  outputInterval(0.0),
250  outputIndex(0),
251  lastOutputTime(-10.0),
252  outputRegion(0),
253  tecplotLevel(0),
254  callsOTEC(0),
255  callsOTECcarrier(0),
256  TEMP(300.0),
257 
258  li_Pos(-1),
259  li_Neg(-1),
260 
261  outputXscalar(1.0),
262  excludeNoSourceRegionsFlag(true),
263  excludeNoSourceRegionsFlagGiven(false),
264  transportFlagGiven(false),
265  transportFlag(false),
266  diffusionFlagGiven(false),
267  diffusionFlag(false),
268  dirichletBCFlag(false),
269  columnReorderingFlag(false),
270  xloIndex(-1),
271  xhiIndex(-1)
272 {
273  numIntVars = 0;
274  numExtVars = 2;
275  numStateVars = 10;
276 
277  devConMap.resize(2);
278  devConMap[0] = 1;
279  devConMap[1] = 1;
280 
281  // Set params to constant default values:
282  setDefaultParams ();
283 
284  // Set params according to instance line and constant defaults from metadata:
285  setParams (IB.params);
286 
287  // Set any non-constant parameter defaults:
288  if (!given("TEMP"))
289  TEMP = getDeviceOptions().temp.getImmutableValue<double>();
290 
291 
293  {
295  }
296 
297  if (diffusionFlagGiven && transportFlagGiven) // both given
298  {
299  Report::UserWarning() << "Both transportFlag and diffusionFlag set in " << getName() << ". Using transportFlag";
300  }
301 
302  // Calculate any parameters specified as expressions:
304 
305  setupScalingVars ();
306 
307  // Handle the reactions.
308  setupMeshUniform ();
309  allocateRegions ();
310  scaleMesh ();
311 
312  // Do the rest of the defect chemistry setup, which is independent of whether
313  // or not the model or instance spefication has been used.
315 
316  int numRegions=regVec.size();
317 
318  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
319  {
320  std::vector<RegionData*> & rdVec1 = model_.regionDataVec;
321  if (!(rdVec1.empty()))
322  {
323  Xyce::dout() << "Model Region Data vector:" << std::endl;
324  for (int ireg=0;ireg<numRegions;++ireg)
325  {
326  RegionData & rd = *(rdVec1[ireg]);
327  Xyce::dout() << ireg << ": "<< rd;
328  }
329  }
330  }
331 
332  // calculate dependent (ie computed) params:
333  processParams ();
334  setupFluxVec ();
335  setupJacStamp ();
336 }
337 
338 //-----------------------------------------------------------------------------
339 // Function : Instance::setupMeshUniform
340 // Purpose : Sets up xVec and dxVec (unscaled).
341 // Special Notes :
342 // Scope : public
343 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
344 // Creation Date : 10/27/08
345 //-----------------------------------------------------------------------------
347 {
348  if ( model_.userNumRegions > 0)
349  {
350  int size = model_.userNumRegions;
351  double xmin = model_.xlo;
352  double xmax = model_.xhi;
353 
354  double dn = static_cast<double>(size-1);
355  double dx = (xmax-xmin)/dn;
356  double xtmp = xmin;
357 
358  xVec.resize(size,0.0);
359  dxVec.resize(size,0.0);
360 
361  xloStencilVec.resize(size,0);
362  xhiStencilVec.resize(size,0);
363 
364  int i=0;
365  for (; i<size;++i)
366  {
367  xVec[i] = xtmp;
368  xtmp += dx;
369  }
370 
371  for (i=0;i<size-1;++i)
372  {
373  dxVec[i] = xVec[i+1]-xVec[i];
374  }
375 
376  if (size-2 >= 0)
377  {
378  dxVec[size-1] = dxVec[size-2];
379  }
380 
381  // set up the edge indices
382  xloIndex=0;
383  xhiIndex=size-1;
384  }
385  else
386  {
387  // no-op
388  }
389 }
390 
391 //-----------------------------------------------------------------------------
392 // Function : Instance::allocateRegions
393 // Purpose :
394 // Special Notes :
395 // Scope : public
396 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
397 // Creation Date : 11/03/08
398 //-----------------------------------------------------------------------------
400 {
401  std::map<std::string, DopeInfo *> diMap = model_.dopeInfoMap;
402 
403  if ( model_.userNumRegions > 0 && model_.rxnFileName != "NOFILE" )
404  {
405  //setupDopingArrays();
406  useDopingArrayData = true;
407 
408  // Now set up corresponding region Data classes, to match the region classes.
409  // mesh stuff will be fixed later also:
410  int numReg = model_.userNumRegions;
411 
412  std::vector<RegionData*> * rdVecPtr(0);
413  rdVecPtr = &(model_.regionDataVec);
414  // if (*rdVecPtr) is not empty, then the contents came from the input file and
415  // should be deleted, as this specification overrides.
416  (*rdVecPtr).clear();
417  int iReg=0;
418  for (iReg=0;iReg!=numReg;++iReg)
419  {
420  RegionData * regDataPtr = new RegionData ();
421  {
422  std::ostringstream oss;
423  oss << getName() << "_" << std::setw(3) << std::setfill('0') << iReg;
424  regDataPtr->name = oss.str();
425  }
426 
427  {
428  std::ostringstream oss;
429  oss << outputName << "_" << std::setw(3) << std::setfill('0') << iReg;
430  regDataPtr->outName = oss.str();
431  }
432 
433  regDataPtr->xloc = xVec[iReg];
434  regDataPtr->reactionFile = model_.rxnFileName;
435 
436  (*rdVecPtr).push_back(regDataPtr);
437  }
438 
440  {
441  // Allocate a single reaction network class, and use it to parse the reactions
442  // file. This reaction network will then be copied into each reaction region
443  // as it is constructed.
444  ReactionNetwork tmpReactions1;
445  ReactionNetwork tmpReactions2;
446 
447  tmpReactions1.setApplySources(true);
449 
450  tmpReactions2.setApplySources(false);
452 
453  // Now that the region data class have been set up, allocate the regions.
454  for (iReg=0;iReg!=numReg;++iReg)
455  {
456  Region * regPtr;
457  bool sourceOn(true);
458  sourceOn = (xVec[iReg] >= model_.xlo_source) &&
459  (xVec[iReg] <= model_.xhi_source);
460 
461  if (sourceOn)
462  {
463  regPtr = new Region(*((*rdVecPtr)[iReg]),
464  getDeviceOptions(), getSolverState(), tmpReactions1);
465  }
466  else
467  {
468  // if no source and transport is off, then no point in
469  // solving reaction network at this mesh cell.
470  if (transportFlag)
471  {
472  regPtr = new Region(*((*rdVecPtr)[iReg]),
473  getDeviceOptions(), getSolverState(), tmpReactions2);
474  }
475  else
476  {
477  ((*rdVecPtr)[iReg])->doNothing=true;
478 
479  regPtr = new Region(*((*rdVecPtr)[iReg]),
480  getDeviceOptions(), getSolverState(), tmpReactions2);
481  }
482  }
483  regVec.push_back(regPtr);
484  }
485  }
486  else
487  {
488  // Now that the region data class have been set up, allocate the regions.
489  for (iReg=0;iReg!=numReg;++iReg)
490  {
491  bool sourceOn(true);
492  sourceOn = (xVec[iReg] >= model_.xlo_source) &&
493  (xVec[iReg] <= model_.xhi_source);
494 
496  {
497  if (!transportFlag && !sourceOn)
498  {
499  ((*rdVecPtr)[iReg])->doNothing=true;
500  }
501  }
502 
503  Region * regPtr = new Region(netlistLocation(), *((*rdVecPtr)[iReg]),
504  getDeviceOptions(), getSolverState(), sourceOn);
505 
506  regVec.push_back(regPtr);
507  }
508  }
509  }
510 }
511 
512 //-----------------------------------------------------------------------------
513 // Function : Instance::setupScalingVars
514 // Purpose :
515 // Special Notes :
516 // Scope : public
517 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
518 // Creation Date : 03/04/08
519 //-----------------------------------------------------------------------------
521 {
522  scalingVars.t0 = 1.0e-6; // time scaling (s)
523  scalingVars.C0 = 1.0e+12; // concentration scaling (cm^-3);
524  scalingVars.x0 = 1.0e-7; // distance scaling (cm)
525 
526  // time scaling (s)
527  if (given("t0"))
528  {
530  }
531 
532  // concentration scaling (cm^-3);
533  if (given("C0"))
534  {
536  }
537 
538  // distance scaling (cm)
539  if (given("X0"))
540  {
542  }
543 
544  double rx0 = 1.0/scalingVars.x0;
545 
546  // area scaling (cm^2)
548 
549  // diffusion coefficient scaling (cm^2/s)
550  //scalingVars.D0 = scalingVars.t0*rx0*rx0;
552 
553  // recombination rate scaling (cm^-3/s)
554  //scalingVars.R0 = scalingVars.D0*scalingVars.C0/(scalingVars.x0*scalingVars.x0);
556 
558 
559  // rate constant scaling. k0 = 1/(C0*t0) = cm^3/sec
563 }
564 
565 //-----------------------------------------------------------------------------
566 // Function : Instance::initializeChemistry
567 //
568 // Purpose : This function takes care of some of the initial setup for
569 // defect chemistry. It is independent of the model or
570 // instance specification for the chemistry, and thus gets
571 // its own function. The other functions are
572 // setupUserSpecifiedRegions (for instance based).
573 //
574 // Special Notes :
575 // Scope : public
576 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
577 // Creation Date : 03/02/08
578 //-----------------------------------------------------------------------------
580 {
581  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
582  {
583  // debug outputs. Check what is in the defect map.
584  std::map<std::string, SpecieSource *>::iterator itSource = model_.defectSourceMap.begin();
585  std::map<std::string, SpecieSource *>::iterator itSourceEnd = model_.defectSourceMap.end ();
586 
587  Xyce::dout() << Xyce::section_divider << std::endl;
588  Xyce::dout() << "Instance::initializeChemistry ():" << std::endl;
589  for (; itSource!=itSourceEnd; ++itSource)
590  {
591  std::string speciesName (itSource->first);
592  Xyce::dout() << "speciesName = " << speciesName << std::endl;
593  }
594  Xyce::dout() << Xyce::section_divider << std::endl;
595  }
596 
597  std::vector<RegionData*> * rdVecPtr(0);
598  rdVecPtr = &(model_.regionDataVec);
599 
601 
602  int numRegions=regVec.size();
603  for (int ireg=0;ireg<numRegions;++ireg)
604  {
605  regVec[ireg]->initializeReactionNetwork(scalingVars,model_.materialVec[0],TEMP);
606 
607  if (useDopingArrayData)
608  {
609  std::map<std::string, DopeInfo *> diMap = model_.dopeInfoMap;
610  if (!(diMap.empty()))
611  {
612  // Push in some initial values for various species.
613  // This includes doping species like boron- (BM) as well as E and H.
614  std::map<std::string, DopeInfo *>::iterator iter;
615  std::map<std::string, DopeInfo *>::iterator start = diMap.begin();
616  std::map<std::string, DopeInfo *>::iterator end = diMap.end();
617 
618  for ( iter = start; iter != end; ++iter )
619  {
620  DopeInfo & di = *(iter->second);
621 
622  bool reactantExist = false;
623  reactantExist = regVec[ireg]->reactantExist(di.speciesName);
624 
625  if (reactantExist)
626  {
627  double dopeValue = di.splintDopeVec[ireg];
628  regVec[ireg]->setInitialCondition(di.speciesName, dopeValue);
629  }
630  }
631  }
632  else
633  {
634 #if 0
635  // This is the original doping/carrier intialization.
636  // It is hardwired to boron and phosphorus, so
637  // it should be phased out and/or deprecated.
638 
639  if (regVec[ireg]->reactantExist("BM"))
640  {
641  regVec[ireg]->setInitialCondition("BM", (*rdVecPtr)[ireg]->Boron_Concentration);
642  }
643 
644  if (regVec[ireg]->reactantExist("PP"))
645  {
646  regVec[ireg]->setInitialCondition("PP", (*rdVecPtr)[ireg]->Phosphorus_Concentration);
647  }
648 #endif
649  }
650 
651  if (model_.given("MASTERSOURCE"))
652  {
653  bool sourceOn(true);
654  double xlos = model_.xlo_source *(useScaledVariablesFlag?(1.0/scalingVars.x0):1.0);
655  double xhis = model_.xhi_source *(useScaledVariablesFlag?(1.0/scalingVars.x0):1.0);
656 
657  sourceOn = (xVec[ireg] >= xlos) && (xVec[ireg] <= xhis);
658 
659  if (sourceOn)
660  {
661  std::map<std::string,SpecieSource *>::iterator itSource = model_.defectSourceMap.begin();
662  std::map<std::string,SpecieSource *>::iterator itSourceEnd = model_.defectSourceMap.end ();
663 
664  for (; itSource!=itSourceEnd; ++itSource)
665  {
666  std::string speciesName (itSource->first);
667  regVec[ireg]->addMasterSource(speciesName);
668  }
669  }
670  }
671 
673  {
674  regVec[ireg]->scaleVariables ();
675  }
676  }
677  }
678 }
679 
680 //-----------------------------------------------------------------------------
681 // Function : Instance::setupJacStamp
682 // Purpose :
683 // Special Notes :
684 //
685 //
686 // Scope : public
687 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
688 // Creation Date : 02/09/08
689 //-----------------------------------------------------------------------------
691 {
692  // Now it's time to do the jacobian stamp.
693  // Set up full jacstamp
694  int localPosIndex = 0;
695  int localNegIndex = 1;
696  int indexCounter=localNegIndex+1;
697 
698  jacStamp.resize(2);
699 
700  jacStamp[localPosIndex].resize(2); // Base'
701  jacStamp[localPosIndex][localPosIndex] = localPosIndex; // B'-B' (0)
702  jacStamp[localPosIndex][localNegIndex] = localNegIndex; // B'-E' (1)
703 
704  jacStamp[localNegIndex].resize(2); // Emitter'
705  jacStamp[localNegIndex][localPosIndex] = localPosIndex; // E'-B' (0)
706  jacStamp[localNegIndex][localNegIndex] = localNegIndex; // E'-E' (1)
707 
708  // Rxn model blocks are next.
709  regLastIndexVec.resize(regVec.size(), -1); // index at the end of the stamp.
710  regFirstReactantIndexVec.resize(regVec.size(), -1); // index of first reactant
711  regNumSpecieVec.resize(regVec.size(), 0);
712 
713  int ireg=0;
714 
715  // Call each region to have it augment its share of the jacstamp.
716  int numRegions=regVec.size();
717  for (ireg=0;ireg<numRegions;++ireg)
718  {
719  int concentrationSize = regVec[ireg]->getNumSpecies();
720  if (concentrationSize != 0)
721  {
722  // communicate down to the region the voltage inputs indices.
723  std::vector<int> voltageNodeColDep(2,-1);
724  voltageNodeColDep[0]=localPosIndex; // pos (previously base) voltage
725  voltageNodeColDep[1]=localNegIndex; // neg (perviously emitter) voltage
726 
727  int firstReactant=-1;
728  int lastIndex=-1;
729  regVec[ireg]->setupJacStamp(jacStamp,voltageNodeColDep, firstReactant, lastIndex);
730  regFirstReactantIndexVec[ireg] = firstReactant;
731  regLastIndexVec[ireg] = lastIndex;
732 
733  numIntVars += regVec[ireg]->getNumIntVars();
734  numStateVars += concentrationSize;
735  }
736  }
737 
738  // Do diffusion. for all mobile species.
739  int numSpecies = thVec.size();
740  int isp=0;
741 
742  for (ireg=0;ireg<numRegions;++ireg)
743  {
744  if (!(regVec[ireg]->getDoNothingFlag()) )
745  {
746  regNumSpecieVec[ireg] = numSpecies;
747  }
748  else
749  {
750  regNumSpecieVec[ireg] = 0;
751  }
752  if (DEBUG_DEVICE)
753  {
754  Xyce::dout() << regVec[ireg]->getName ()
755  << " numSpecies = " << regNumSpecieVec[ireg] << std::endl;
756  }
757  }
758 
759  if (transportFlag && numRegions > 1)
760  {
761  for (isp=0;isp<numSpecies;++isp)
762  {
763  if (!(thVec[isp].transportFlag)) continue;
764 
765  // If this is the base or emitter, then add a single column to the stamp.
766  // Otherwise, if this is the BE point (in the middle) then add 2 columns,
767  // for 2 neighbors.
768  for (ireg=0;ireg<numRegions;++ireg)
769  {
770  int row = regFirstReactantIndexVec[ireg] + isp;
771  if (row < 0) continue;
772 
773  int rowSize = jacStamp[row].size();
774  if (ireg==0)
775  {
776  int col = regFirstReactantIndexVec[1] + isp;
777  jacStamp[row].resize(rowSize+1);
778  jacStamp[row][rowSize] = col;
779  }
780  else if (ireg==numRegions-1)
781  {
782  int col = regFirstReactantIndexVec[numRegions-2] + isp;
783  jacStamp[row].resize(rowSize+1);
784  jacStamp[row][rowSize] = col;
785  }
786  else
787  {
788  int col1 = regFirstReactantIndexVec[ireg+1] + isp;
789  int col2 = regFirstReactantIndexVec[ireg-1] + isp;
790  jacStamp[row].resize(rowSize+2);
791  jacStamp[row][rowSize ] = col1;
792  jacStamp[row][rowSize+1] = col2;
793  }
794  }
795  }
796  }
797 
798  // Just put in a dense-ish row for these terms for now.
799  // These represent the dependence of generation-recombination
800  // currents, calculated from regions, on the species
801  // densities of those same regions.
802  {
803  //
804  // do the base-prime row and the emit-prime row.
805  int posRow = 0;
806  int posSize = jacStamp[posRow].size();
807  int negRow = 1;
808  int negSize = jacStamp[negRow].size();
809  for (ireg=0;ireg<numRegions;++ireg)
810  {
811  int posIndex = regFirstReactantIndexVec[ireg];
812  int numSpecie = regNumSpecieVec[ireg];
813 
814  if (posIndex != -1)
815  {
816  int posRowSize = jacStamp[posRow].size();
817  jacStamp[posRow].resize(posRowSize+numSpecie);
818 
819  int negRowSize = jacStamp[negRow].size();
820  jacStamp[negRow].resize(negRowSize+numSpecie);
821 
822  for (isp=0;isp<numSpecie;++isp)
823  {
824  int icol = posRowSize+isp;
825  jacStamp[posRow][icol] = posIndex+isp ;
826 
827  icol = negRowSize+isp;
828  jacStamp[negRow][icol] = posIndex+isp ;
829  }
830  }
831  }
832  }
833 
834  // set up normal jacMap for when all resistances nonzero
835  // If nothing is remapped, this amounts to a null operation when the
836  // map is used later. The maps become important when we start
837  // remapping nodes because of zero lead resistances
838  jacMap.clear();
839  jacMap2.clear();
840  jacMap.resize(jacStamp.size());
841  jacMap2.resize(jacStamp.size());
842 
843  // This is only done once per model, and size is small --- not gonna
844  // bother with temporary vars just to keep the .size() call out of the
845  // loops
846 
847  int mapSize = jacMap.size();
848  for (int i=0;i<mapSize;++i)
849  {
850  jacMap[i]=i;
851  jacMap2[i].resize(jacStamp[i].size());
852  for (int j=0;j<jacStamp[i].size();++j)
853  {
854  jacMap2[i][j] = j;
855  }
856  }
857 
858  // Now fix the ordering of the columns in the jacStamp. If the columns in each row
859  // are not in ascending order, then the jacStampMap calls below (for removing
860  // variables) will not work correctly.
861  //
862  // ERK: 01/13/10: this flag doesn't appear to be needed for this model,
863  // as this model doesn't contain any optional prime nodes. This block
864  // of code was copied over from another model, which *does* need it.
865  // As such, the columnReorderFlag is "false" by default, whereas it is
866  // "true" in the orginal device from which this was copied.
868  {
869  std::vector< std::vector<int> > tempStamp_eric;
870  std::vector< std::vector<int> > tempMap2_eric;
871  jacStampMap_fixOrder(jacStamp, jacMap2, tempStamp_eric, tempMap2_eric);
872  jacStamp = tempStamp_eric;
873  jacMap2 = tempMap2_eric;
874  }
875 
876  // Now we have to selectively map away bits and pieces of the
877  // jacobian stamp based on absent resistances
878  if (DEBUG_DEVICE && isActive(Diag::DEVICE_JACSTAMP) && getSolverState().debugTimeFlag)
879  {
880  Xyce::dout() << "jacStamp Before removing terminal nodes:"<<std::endl;
882  Xyce::dout() << "jacMap2 Before removing terminal nodes:"<<std::endl;
884  }
885 }
886 
887 //-----------------------------------------------------------------------------
888 // Function : Instance::scaleMesh
889 // Purpose :
890 // Special Notes : This should be called after the doping-profile based
891 // regions are set up.
892 //
893 // Scope : public
894 // Creator : Eric Keiter, SNL
895 // Creation Date : 10/27/08
896 //-----------------------------------------------------------------------------
898 {
899  std::vector<RegionData*> * rdVecPtr(0);
900  rdVecPtr = &(model_.regionDataVec);
901  int i=0;
902  int size = (*rdVecPtr).size();
904  {
905  for (i=0;i<size;++i)
906  {
907  xVec[i] *= (1.0/scalingVars.x0);
908  }
909  }
910 
911  for (i=0;i<size-1;++i)
912  {
913  dxVec[i] = xVec[i+1]-xVec[i];
914  }
915 
916  if (size-2 >= 0)
917  {
918  dxVec[size-1] = dxVec[size-2];
919  }
920 
921  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
922  {
923  for (i=0;i<size;++i)
924  {
925  Xyce::dout() << "Scaled Mesh: xVec["<<i<<"] = " << xVec[i] << std::endl;
926  }
927  Xyce::dout() << std::endl;
928  for (i=0;i<size-1;++i)
929  {
930  Xyce::dout() << "Scaled Mesh: dxVec["<<i<<"] = " << dxVec[i] << std::endl;
931  }
932  Xyce::dout() << std::endl;
933  }
934 
935 }
936 
937 //-----------------------------------------------------------------------------
938 // Function : Instance::setupFluxVec
939 // Purpose :
940 // Special Notes :
941 // Scope : public
942 // Creator : Eric Keiter, SNL
943 // Creation Date : 10/27/08
944 //-----------------------------------------------------------------------------
946 {
947  std::vector<RegionData*> * rdVecPtr(0);
948  rdVecPtr = &(model_.regionDataVec);
949  if ( !((*rdVecPtr).empty()) )
950  {
951  // do all the mobile species
952  int numSpecies = thVec.size();
953  int isp=0;
954  int size = (*rdVecPtr).size();
955  for (isp=0;isp<numSpecies;++isp)
956  {
957  thVec[isp].fluxVec.resize(size-1,0.0);
958  }
959  }
960 }
961 
962 //-----------------------------------------------------------------------------
963 // Function : Instance::outputPlotFiles
964 // Purpose :
965 // Special Notes :
966 // Scope : public
967 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
968 // Creation Date : 02/09/08
969 //-----------------------------------------------------------------------------
971 {
972  bool bsuccess = true;
973  bool bs1 = true;
974  bool skipOutput = false;
975 
976  // If using output interval, check if enough time has passed to do
977  // another output. (only applies for transient - not DCOP).
978  if ( !(getSolverState().dcopFlag) && !(getSolverState().forceFinalOutput) && given("OUTPUTINTERVAL") )
979  {
980  double outMult = static_cast<double> (outputIndex);
981  double nextOutputTime = outMult * outputInterval;
982 
983  if (nextOutputTime > getSolverState().currTime)
984  {
985  skipOutput = true;
986  }
987  }
988 
989  // If this is a "forced" final output, make sure that it didn't already output.
990  // This can happen if the output interval is an exact multiple of the
991  // total simulation time.
993  getSolverState().currTime==lastOutputTime) skipOutput=true;
994 
995  if (skipOutput) return bsuccess;
996  ++outputIndex;
998 
999 
1000  // output individual tecplot files for each region.
1001  // These are time-dependent files, with no spatial depedence.
1002  int numRegions = regVec.size();
1003  if ( (tecplotLevel==2 && numRegions > 1) || (tecplotLevel==1 && numRegions==1) )
1004  {
1005  for (int ireg=0;ireg<numRegions;++ireg)
1006  {
1007  if (regVec[ireg]->haveAnyReactions())
1008  {
1009  bs1 = regVec[ireg]->outputTecplot ();
1010  bsuccess = bsuccess && bs1;
1011  }
1012  }
1013  }
1014 
1015  // output a single, spatially-dependent file(s).
1016  // Don't bother if there's only one (or less) regions.
1017  if (tecplotLevel==1 && numRegions > 1)
1018  {
1019  bs1 = outputTecplot ();
1020  bsuccess = bsuccess && bs1;
1021  }
1022  else if (tecplotLevel==3 && numRegions > 1)
1023  {
1024  bs1 = output2DTecplot ();
1025  bsuccess = bsuccess && bs1;
1026  }
1027 
1028  if (tecplotLevel > 0 && given("OUTPUTREGION"))
1029  {
1030  int numRegions = regVec.size();
1031  if (outputRegion < numRegions && outputRegion >= 0)
1032  {
1034  {
1035  bs1 = regVec[outputRegion]->outputTecplot ();
1036  bsuccess = bsuccess && bs1;
1037  }
1038  }
1039  }
1040 
1041  return bsuccess;
1042 }
1043 
1044 //-----------------------------------------------------------------------------
1045 // Function : Instance::outputTecplot
1046 // Purpose :
1047 // Special Notes :
1048 // Scope : public
1049 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1050 // Creation Date : 02/09/08
1051 //-----------------------------------------------------------------------------
1053 {
1054  bool bsuccess = true;
1055 
1056  int i(0);
1057  int NX = regVec.size();
1058 
1059  char filename[256];
1060  for(i=0;i<256;++i) filename[i] = static_cast<char>(0);
1061 
1062  sprintf(filename,"%s.dat",outputName.c_str());
1063  double time = getSolverState().currTime;
1064  FILE *fp1(NULL);
1065 
1066  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1067  {
1068  Xyce::dout() << " Instance::outputTecplot. filename = " << std::string(filename) <<std::endl;
1069  }
1070 
1071  if (callsOTEC <= 0)
1072  {
1073  fp1 = fopen(filename,"w");
1074  fprintf(fp1,
1075  " TITLE = \"Spatially Dependent defect data for compact rxn device: %s time = %20.12e seconds.\",\n",
1076  outputName.c_str(),time);
1077  }
1078  else
1079  {
1080  fp1 = fopen(filename,"a");
1081  }
1082 
1083  int rSize=(regVec[0])->getNumSpecies();
1084  int cSize=(regVec[0])->getNumConstants();
1085 
1086  if (callsOTEC <= 0)
1087  {
1088  fprintf(fp1,"%s","\tVARIABLES = \"X \",\n");
1089 
1090  Region & reg = (*(regVec[0]));
1091  for (int iconst=0;iconst<cSize;++iconst)
1092  {
1093  fprintf(fp1, "\t \"%s \",\n" , ( reg.getConstantsName(iconst)).c_str());
1094  }
1095 
1096  for (int ispec=0;ispec<rSize;++ispec)
1097  {
1098  fprintf(fp1,"\t \"%s \",\n", ( reg.getSpeciesName(ispec)).c_str());
1099  }
1100  }
1101 
1102  fprintf(fp1,"\tDATASETAUXDATA %s\n", tecplotTimeDateStamp().c_str() );
1103  fprintf(fp1,"\tZONE F=POINT,I=%d", NX);
1104 
1105  if (getSolverState().dcopFlag)
1106  {
1107  fprintf(fp1," T = \"DCOP step = %d\" \n", callsOTEC);
1108  }
1109  else
1110  {
1111  fprintf(fp1," T = \"time step = %d, time=%20.12e\" AUXDATA time = \"%20.12e seconds\" \n", callsOTEC , time, time);
1112  }
1113 
1114  std::vector<RegionData*> * rdVecPtr(0);
1115  rdVecPtr = &(model_.regionDataVec);
1116 
1117  if (NX <= 1)
1118  {
1119  fprintf(fp1," %20.12e", time);
1120  }
1121 
1122  int numprint=0;
1123  for (i=0;i<NX;++i)
1124  {
1125  double val(0.0);
1126  val = ((*rdVecPtr)[i])->xloc * outputXscalar;
1127  fprintf(fp1," %20.12e", val);
1128 
1129  Region & reg = (*(regVec[i]));
1130 
1131  for (int iconst=0;iconst<cSize;++iconst)
1132  {
1133  val = reg.getConstantsVal(iconst) ;
1134  fprintf(fp1," %20.12e", val);
1135 
1136  if (numprint >= 6)
1137  {
1138  fprintf(fp1,"%s","\n"); numprint = 0;
1139  }
1140  else
1141  {
1142  numprint++;
1143  }
1144  }
1145 
1146  for (int ispec=0;ispec<rSize;++ispec)
1147  {
1148  val = 0.0;
1149  if (reg.haveAnyReactions())
1150  {
1151  val = reg.getSpeciesVal(ispec);
1152  }
1153  fprintf(fp1," %20.12e", val);
1154 
1155  if (numprint >= 6)
1156  {
1157  fprintf(fp1,"%s","\n"); numprint = 0;
1158  }
1159  else
1160  {
1161  numprint++;
1162  }
1163  }
1164  }
1165 
1166  fprintf(fp1,"%s","\n");
1167 
1168  ++callsOTEC;
1169  fclose(fp1);
1170 
1171  return bsuccess;
1172 }
1173 
1174 //-----------------------------------------------------------------------------
1175 // Function : Instance::output2DTecplot
1176 // Purpose :
1177 // Special Notes :
1178 // Scope : public
1179 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1180 // Creation Date : 10/14/09
1181 //-----------------------------------------------------------------------------
1183 {
1184  bool bsuccess = true;
1185 
1186  int i(0);
1187  int NX = regVec.size();
1188 
1189  char filename[256];
1190  for(i=0;i<256;++i) filename[i] = static_cast<char>(0);
1191 
1192  sprintf(filename,"%s.dat",outputName.c_str());
1193  double time = getSolverState().currTime;
1194  FILE *fp1(NULL);
1195 
1196  if (callsOTEC <= 0)
1197  {
1198  fp1 = fopen(filename,"w");
1199  fprintf(fp1,
1200  " TITLE = \"Spatially Dependent defect data for compact rxn device: %s time = %20.12e seconds.\",\n",
1201  outputName.c_str(),time);
1202  }
1203  else
1204  {
1205  fp1 = fopen(filename,"a");
1206  }
1207 
1208  int rSize=(regVec[0])->getNumSpecies();
1209  int cSize=(regVec[0])->getNumConstants();
1210 
1211  if (callsOTEC <= 0)
1212  {
1213  fprintf(fp1,"%s","\tVARIABLES = \"X \",\n");
1214  fprintf(fp1,"%s","\t \"Time(sec) \",\n");
1215 
1216  Region & reg = (*(regVec[0]));
1217  for (int iconst=0;iconst<cSize;++iconst)
1218  {
1219  fprintf(fp1, "\t \"%s \",\n" , ( reg.getConstantsName(iconst)).c_str());
1220  }
1221 
1222  for (int ispec=0;ispec<rSize;++ispec)
1223  {
1224  fprintf(fp1,"\t \"%s \",\n", ( reg.getSpeciesName(ispec)).c_str());
1225  }
1226 
1227  fprintf(fp1,"\tZONE F=POINT,I=%d", NX);
1228  }
1229 
1230  fprintf(fp1,"%s"," \n");
1231 
1232  std::vector<RegionData*> * rdVecPtr(0);
1233  rdVecPtr = &(model_.regionDataVec);
1234 
1235  if (NX <= 1)
1236  {
1237  fprintf(fp1," %20.12e", time);
1238  }
1239 
1240  int numprint=0;
1241  for (i=0;i<NX;++i)
1242  {
1243  double val(0.0);
1244  val = ((*rdVecPtr)[i])->xloc;
1245  fprintf(fp1," %20.12e", val);
1246 
1247  fprintf(fp1," %20.12e", time);
1248 
1249  Region & reg = (*(regVec[i]));
1250 
1251  for (int iconst=0;iconst<cSize;++iconst)
1252  {
1253  val = reg.getConstantsVal(iconst) ;
1254  fprintf(fp1," %20.12e", val);
1255 
1256  if (numprint >= 6)
1257  {
1258  fprintf(fp1,"%s","\n"); numprint = 0;
1259  }
1260  else
1261  {
1262  numprint++;
1263  }
1264  }
1265 
1266  for (int ispec=0;ispec<rSize;++ispec)
1267  {
1268  val = reg.getSpeciesVal(ispec);
1269  fprintf(fp1," %20.12e", val);
1270 
1271  if (numprint >= 6)
1272  {
1273  fprintf(fp1,"%s","\n"); numprint = 0;
1274  }
1275  else
1276  {
1277  numprint++;
1278  }
1279  }
1280  }
1281 
1282  fprintf(fp1,"%s","\n");
1283 
1284  ++callsOTEC;
1285  fclose(fp1);
1286 
1287  return bsuccess;
1288 }
1289 
1290 //-----------------------------------------------------------------------------
1291 // Function : Instance::outputCarrierDensities
1292 // Purpose :
1293 // Special Notes :
1294 // Scope : public
1295 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1296 // Creation Date : 02/09/08
1297 //-----------------------------------------------------------------------------
1299 {
1300  bool bsuccess = true;
1301 
1302  int i(0);
1303  int NX = regVec.size();
1304  char filename[256]; for(i=0;i<256;++i) filename[i] = static_cast<char>(0);
1305  sprintf(filename,"%scarrier.dat",outputName.c_str());
1306 
1307  FILE *fp1(NULL);
1308  fp1 = fopen(filename,"w");
1309  int cSize=(regVec[0])->getNumConstants();
1310 
1311  std::vector<RegionData*> * rdVecPtr(0);
1312  rdVecPtr = &(model_.regionDataVec);
1313 
1314  for (i=0;i<NX;++i)
1315  {
1316  double val(0.0);
1317  val = ((*rdVecPtr)[i])->xloc;
1318  fprintf(fp1," %20.12e", val);
1319 
1320  Region & reg = (*(regVec[i]));
1321 
1322  for (int iconst=0;iconst<cSize;++iconst)
1323  {
1324  val = reg.getConstantsVal(iconst) ;
1325  fprintf(fp1," %20.12e", val);
1326  }
1327  fprintf(fp1,"%s","\n");
1328  }
1329 
1330  ++callsOTECcarrier;
1331  fclose(fp1);
1332 
1333  return bsuccess;
1334 }
1335 
1336 //-----------------------------------------------------------------------------
1337 // Function : Instance::~Instance
1338 // Purpose : destructor
1339 // Special Notes :
1340 // Scope : public
1341 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1342 // Creation Date : 02/09/08
1343 //-----------------------------------------------------------------------------
1345 {
1346  if (!(regVec.empty()))
1347  {
1348  int size = regVec.size();
1349  int i=0;
1350  for (i=0;i<size;++i)
1351  {
1352  if (regVec[i] != 0)
1353  {
1354  delete regVec[i];
1355  regVec[i] = 0;
1356  }
1357  }
1358  }
1359 
1360  // Loop over the dopeInfoMap (if it is not empty) and delete its contents.
1361  if (!(dopeInfoMap.empty()))
1362  {
1363  std::map<std::string,DopeInfo *>::iterator iter;
1364  std::map<std::string,DopeInfo *>::iterator begin = dopeInfoMap.begin();
1365  std::map<std::string,DopeInfo *>::iterator end = dopeInfoMap.end ();
1366 
1367  for(iter=begin;iter!=end;++iter)
1368  {
1369  if (iter->second != 0) delete iter->second;
1370  }
1371  }
1372 
1373  regVec.clear();
1374  dopeInfoMap.clear();
1375 }
1376 
1377 //-----------------------------------------------------------------------------
1378 // Function : Instance::registerLIDs
1379 // Purpose :
1380 // Special Notes :
1381 // Scope : public
1382 // Creator : Eric R. Keiter, SNL
1383 // Creation Date : 02/09/08
1384 //-----------------------------------------------------------------------------
1385 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
1386  const std::vector<int> & extLIDVecRef )
1387 {
1388  AssertLIDs(intLIDVecRef.size() == numIntVars);
1389  AssertLIDs(extLIDVecRef.size() == numExtVars);
1390 
1391  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1392  {
1393  Xyce::dout() << section_divider << std::endl;
1394  Xyce::dout() << " Instance::registerLIDs" <<std::endl;
1395  Xyce::dout() << " name = " << getName() << std::endl;
1396  Xyce::dout() << " number of internal variables: " << numIntVars << std::endl;
1397  Xyce::dout() << " number of external variables: " << numExtVars << std::endl;
1398  Xyce::dout() << " numIntVars = " << numIntVars << std::endl;
1399  Xyce::dout() << " numExtVars = " << numExtVars << std::endl;
1400  }
1401 
1402  // Copy over the global ID lists.
1403  intLIDVec = intLIDVecRef;
1404  extLIDVec = extLIDVecRef;
1405 
1406  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1407  {
1408  Xyce::dout() << " Internal LID List" << std::endl;
1409  for( int i = 0; i < intLIDVec.size(); ++i )
1410  Xyce::dout() << " " << intLIDVec[i] << std::endl;
1411  Xyce::dout() << " External LID List" << std::endl;
1412  for( int i = 0; i < extLIDVec.size(); ++i )
1413  Xyce::dout() << " " << extLIDVec[i] << std::endl;
1414  }
1415 
1416  // Use these lists to obtain the indices into the linear algebra entities.
1417  // First do external variables:
1418  int extIndex = 0;
1419  int intIndex = 0;
1420 
1421  li_Pos = extLIDVec[extIndex++];
1422  li_Neg = extLIDVec[extIndex++];
1423 
1424  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1425  {
1426  Xyce::dout() << " li_Pos = " << li_Pos << std::endl;
1427  Xyce::dout() << " li_Neg = " << li_Neg << std::endl;
1428  }
1429 
1430  // Register the LIDs for each reaction region.
1431  int numRegions = regVec.size();
1432  for (int ireg=0;ireg<numRegions;++ireg)
1433  {
1434  regVec[ireg]->registerLIDs(intLIDVec, extLIDVec,intIndex);
1435  }
1436 
1437  // Do diffusion. for all mobile species.
1438  int i=0;
1439  int ispec=0;
1440  int numSpecies = thVec.size();
1441  int size = regVec.size();
1442 
1443  if (transportFlag)
1444  {
1445  for (ispec=0;ispec<numSpecies;++ispec)
1446  {
1447  std::string speciesName = regVec[0]->getSpeciesName(ispec);
1448  thVec[ispec].specie_id.resize(size,-1);
1449  for (i=0;i<size;++i)
1450  {
1451  thVec[ispec].specie_id[i] = (regVec[i])->getSpeciesLID (speciesName);
1452  }
1453  }
1454  }
1455 
1456  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1457  {
1458  Xyce::dout() << section_divider << std::endl;
1459  }
1460 
1461 }
1462 
1463 //-----------------------------------------------------------------------------
1464 // Function : Instance::loadNodeSymbols
1465 // Purpose :
1466 // Special Notes :
1467 // Scope : public
1468 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
1469 // Creation Date : 05/13/05
1470 //-----------------------------------------------------------------------------
1471 void Instance::loadNodeSymbols(Util::SymbolTable &symbol_table) const
1472 {
1473  // If we have internal nodes, then we need to do this for debugging set up the internal name map
1474  for (std::vector<Region *>::const_iterator it = regVec.begin(), end = regVec.end(); it != end; ++it)
1475  (*it)->loadNodeSymbols(symbol_table, *this);
1476 }
1477 
1478 //-----------------------------------------------------------------------------
1479 // Function : Instance::registerStateLIDs
1480 // Purpose :
1481 // Special Notes :
1482 // Scope : public
1483 // Creator : Eric R. Keiter, SNL
1484 // Creation Date : 02/09/08
1485 //-----------------------------------------------------------------------------
1486 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
1487 {
1488  AssertLIDs(staLIDVecRef.size() == numStateVars);
1489 
1490  // Copy over the global ID lists:
1491  staLIDVec = staLIDVecRef;
1492 
1493  int i=0;
1494 
1495  int numRegions = regVec.size();
1496  for (int ireg=0;ireg<numRegions;++ireg)
1497  {
1498  regVec[ireg]->registerStateLIDs(staLIDVec,i);
1499  }
1500 }
1501 
1502 //-----------------------------------------------------------------------------
1503 // Function : Instance::getDepSolnVars
1504 // Purpose :
1505 // Special Notes :
1506 // Scope : public
1507 // Creator : Rob Hoekstra, SNL, Parallel Computational Sciences
1508 // Creation Date : 06/06/01
1509 //-----------------------------------------------------------------------------
1510 const std::vector<std::string> & Instance::getDepSolnVars()
1511 {
1513 }
1514 
1515 //-----------------------------------------------------------------------------
1516 // Function : Instance::jacobianStamp
1517 // Purpose :
1518 // Special Notes :
1519 // Scope : public
1520 // Creator : Eric R. Keiter, SNL
1521 // Creation Date : 02/09/08
1522 //-----------------------------------------------------------------------------
1523 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
1524 {
1525  return jacStamp;
1526 }
1527 
1528 //-----------------------------------------------------------------------------
1529 // Function : Instance::registerJacLIDs
1530 // Purpose :
1531 // Special Notes :
1532 // Scope : public
1533 // Creator : Eric R. Keiter, SNL
1534 // Creation Date : 02/09/08
1535 //-----------------------------------------------------------------------------
1536 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
1537 {
1538  DeviceInstance::registerJacLIDs( jacLIDVec );
1539 
1540  std::vector<int> &map=jacMap;
1541  std::vector< std::vector<int> > &map2=jacMap2;
1542  int posI = 0;
1543  int negI = 1;
1544 
1545  APosEquPosNodeOffset = jacLIDVec[map[posI]][map2[posI][posI]];
1546  APosEquNegNodeOffset = jacLIDVec[map[posI]][map2[posI][negI]];
1547 
1548  ANegEquPosNodeOffset = jacLIDVec[map[negI]][map2[negI][posI]];
1549  ANegEquNegNodeOffset = jacLIDVec[map[negI]][map2[negI][negI]];
1550 
1551  // Do the reaction species block
1552  int numRegions = regVec.size();
1553  for (int ireg=0;ireg<numRegions;++ireg)
1554  {
1555  regVec[ireg]->registerJacLIDs(jacLIDVec, jacMap, jacMap2);
1556  }
1557 
1558 
1559 #if 0
1560  // For now diffusion can only be set up in the jacobian matrix
1561  // via setRow function calls.
1562 
1563  // If this is the base or emitter, then add a single column to the stamp.
1564  // Otherwise, if this is the BE point (in the middle) then add 2 columns,
1565  // for 2 neighbors.
1566  for (int ireg=0;ireg<numRegions;++ireg)
1567  {
1568  int row = regPosIndexVec[ireg] + regV0subIndexVec[ireg];
1569  if (row < 0) continue;
1570 
1571  int rowSize = jacStamp[row].size();
1572  if (ireg==0)
1573  {
1574  int col = regPosIndexVec[1] + regV0subIndexVec[1];
1575  jacStamp[row].resize(rowSize+1);
1576  jacStamp[row][rowSize] = col;
1577  }
1578  else if (ireg==numRegions-1)
1579  {
1580  int col = regPosIndexVec[numRegions-2] + regV0subIndexVec[numRegions-2];
1581  jacStamp[row].resize(rowSize+1);
1582  jacStamp[row][rowSize] = col;
1583  }
1584  else
1585  {
1586  int col1 = regPosIndexVec[ireg+1] + regV0subIndexVec[ireg+1];
1587  int col2 = regPosIndexVec[ireg-1] + regV0subIndexVec[ireg-1];
1588  jacStamp[row].resize(rowSize+2);
1589  jacStamp[row][rowSize+1] = col1;
1590  jacStamp[row][rowSize+2] = col2;
1591  }
1592  }
1593 #endif
1594 
1595  for (int iReg=0;iReg<numRegions;++iReg)
1596  {
1597  if (regVec[iReg]->haveAnyReactions())
1598  {
1599  haveAnyReactions=true;
1600  }
1601  }
1602 
1603 }
1604 
1605 //-----------------------------------------------------------------------------
1606 // Function : Instance::setupPointers()
1607 //
1608 // Purpose : Sets up raw pointers for optimized matrix loads.
1609 //
1610 // Special Notes : ERK: This function is primarily concerned with determining
1611 // matrix pointers associated with coupling the reaction model
1612 // to the terminal nodes. I've had a lot of difficulty
1613 // getting the LID offsets correct for those terms. To preserve
1614 // load speed, I've decided to go directly to raw pointers
1615 // for those terms.
1616 //
1617 // Scope : public
1618 // Creator : Eric R. Keiter, SNL
1619 // Creation Date : 05/18/10
1620 //-----------------------------------------------------------------------------
1622 {
1623  int numRegions = regVec.size();
1624 
1625  Linear::Matrix & dFdxMat = *(extData.dFdxMatrixPtr);
1626 
1627  APosEqu_SpeciesPtr.resize(numRegions);
1628  ANegEqu_SpeciesPtr.resize(numRegions);
1629 
1630  APosEqu_ConstPtr.resize(numRegions);
1631  ANegEqu_ConstPtr.resize(numRegions);
1632 
1633  for (int ireg=0;ireg<numRegions;++ireg)
1634  {
1635  Linear::Matrix & dFdx = *(extData.dFdxMatrixPtr);
1636  Linear::Matrix & dQdx = *(extData.dQdxMatrixPtr);
1637  regVec[ireg]->setupPointers (dFdx,dQdx);
1638  }
1639 
1640 }
1641 
1642 //-----------------------------------------------------------------------------
1643 // Function : Instance::updateTemperature
1644 // Purpose :
1645 // Special Notes :
1646 // Scope : public
1647 // Creator : Eric R. Keiter, SNL
1648 // Creation Date : 02/09/08
1649 //-----------------------------------------------------------------------------
1650 bool Instance::updateTemperature( const double & temp )
1651 {
1652 
1653  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1654  {
1655  Xyce::dout() << "Start Instance::updateTemperature" << std::endl;
1656  Xyce::dout() << "temp = "<<temp << std::endl;
1657  }
1658  if( temp != -999.0 ) TEMP = temp;
1659 
1661  {
1662  // some params may have changed during interpolation
1664  }
1665 
1666  //Generation of temperature based factors
1667  double TNOM = model_.TNOM;
1668 
1669  // update the rate constants for the defect reactions
1670  int numRegions = regVec.size();
1671  for (int i=0;i<numRegions;++i)
1672  {
1673  regVec[i]->setRateConstants(TEMP);
1674  }
1675 
1676  // all Species diffusion:
1677  if (thVec.empty() && !(regVec.empty()) )
1678  {
1679  int numSpecies = regVec[0]->getNumSpecies();
1680  thVec.reserve(numSpecies);
1681  for (int ispec=0;ispec<numSpecies;++ispec)
1682  {
1683  std::string speciesName = regVec[0]->getSpeciesName(ispec);
1684 
1685  double Dtmp = (regVec[0])->getDiffusionCoefficient (ispec,TEMP);
1686 
1687  thVec.push_back(TransportHelper(Dtmp,speciesName));
1688 
1689  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1690  {
1692  {
1693  Xyce::dout() << "Vacancy Diffusion: scaling=TRUE ";
1694  Xyce::dout() << "D_"<<speciesName<<" = " << Dtmp << std::endl;
1695  }
1696  else
1697  {
1698  Xyce::dout() << "Vacancy Diffusion: scaling=FALSE ";
1699  Xyce::dout() << "D_"<<speciesName<<" = " << Dtmp << std::endl;
1700  }
1701  }
1702  }
1703 
1704  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1705  {
1706  for (int ispec=0;ispec<numSpecies;++ispec)
1707  {
1708  Xyce::dout() << "Vacancy Diffusion: D_" << thVec[ispec].name << " transportFlag = ";
1709  if (thVec[ispec].transportFlag) Xyce::dout() << "TRUE";
1710  else Xyce::dout() << "FALSE";
1711  Xyce::dout() << std::endl;
1712  }
1713  }
1714 
1715  }
1716 
1717  return true;
1718 }
1719 
1720 //-----------------------------------------------------------------------------
1721 // Function : Instance::loadErrorWeightMask
1722 //
1723 // Purpose : Loads the zero elements of the device mask
1724 //
1725 // Special Notes : elements of the error vector associated with zero
1726 // elements of the mask will not be included in weighted
1727 // norms by the time integrator.
1728 //
1729 // Scope : public
1730 // Creator : Eric R. Keiter, SNL, Electrical and Microsystems Modeling
1731 // Creation Date : 02/09/08
1732 //-----------------------------------------------------------------------------
1734 {
1735  Linear::Vector & maskVector = *(extData.deviceErrorWeightMask_);
1736 
1737  int numRegions = regVec.size();
1738  if (numRegions > 0)
1739  {
1740  for (int ireg=0;ireg<numRegions;++ireg)
1741  {
1742  regVec[ireg]->loadErrorWeightMask (maskVector);
1743  }
1744  }
1745 }
1746 
1747 //-----------------------------------------------------------------------------
1748 // Function : Instance::loadDAEQVector
1749 //
1750 // Purpose : Loads the Q-vector contributions for a single
1751 // instance.
1752 //
1753 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1754 // which the system of equations is represented as:
1755 //
1756 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1757 //
1758 // Scope : public
1759 // Creator : Eric R. Keiter, SNL
1760 // Creation Date : 02/09/08
1761 //-----------------------------------------------------------------------------
1763 {
1764  double * daeQVec = extData.daeQVectorRawPtr;
1765  double * dQdxdVp = extData.dQdxdVpVectorRawPtr;
1766 
1767  // Do the reaction terms. There will be no voltage limiting
1768  // contributions here.
1769  int numRegions = regVec.size();
1770  for (int ireg=0;ireg<numRegions;++ireg)
1771  {
1772  regVec[ireg]->loadDAEQVector (daeQVec);
1773  }
1774 
1775  return true;
1776 }
1777 
1778 //-----------------------------------------------------------------------------
1779 // Function : Instance::loadDAEFVector
1780 //
1781 // Purpose : Loads the F-vector contributions for a single
1782 // instance.
1783 //
1784 // Special Notes :
1785 //
1786 // Scope : public
1787 // Creator : Eric R. Keiter, SNL
1788 // Creation Date : 02/09/08
1789 //-----------------------------------------------------------------------------
1791 {
1792  double * daeFVec = extData.daeFVectorRawPtr;
1793  double * dFdxdVp = extData.dFdxdVpVectorRawPtr;
1794  double * solVector = extData.nextSolVectorRawPtr;
1795 
1796  double vbe_diff = 0.0;
1797 
1798  // Now do the reaction terms. There will be no voltage limiting
1799  // contributions here.
1800  int numRegions = regVec.size();
1801  for (int ireg=0;ireg<numRegions;++ireg)
1802  {
1803  // Internal reaction terms are handled by the region class.
1804  regVec[ireg]->loadDAEFVector (daeFVec);
1805  regVec[ireg]->loadDAEdFdxdV(dFdxdVp, vbe_diff);
1806  }
1807 
1808  if (transportFlag)
1809  {
1810  if (!getSolverState().dcopFlag)
1811  {
1812  int numSpecies = thVec.size();
1813  int isp=0;
1814  for (isp=0;isp<numSpecies;++isp)
1815  {
1816  if (!(thVec[isp].transportFlag)) continue;
1817 
1818  int i=0;
1819  int size = regVec.size();
1820 
1821  std::vector<int> & specie_id = thVec[isp].specie_id;
1822 
1823  double dx1 = dxVec[0];
1824  double xloVal = (thVec[isp].fluxVec[0]-thVec[isp].flux_bc1)/dx1;
1825  daeFVec[specie_id[0]] += xloVal;
1826 
1827  for (i=1;i<size-1;++i)
1828  {
1829  double fluxDif = (thVec[isp].fluxVec[i]-thVec[isp].fluxVec[i-1]);
1830  double aveDx = (dxVec[i-1]+dxVec[i])*0.5;
1831  daeFVec[specie_id[i]] += (fluxDif)/aveDx;
1832  }
1833 
1834  double dx2 = dxVec[size-2];
1835  double xhiVal = (thVec[isp].flux_bc2-thVec[isp].fluxVec[size-2])/dx2;
1836  daeFVec[specie_id[size-1]] += xhiVal;
1837  } // end of species loop.
1838  }
1839  }
1840 
1841  return true;
1842 }
1843 
1844 //-----------------------------------------------------------------------------
1845 // Function : Instance::loadDAEdQdx
1846 //
1847 // Purpose : Loads the Q-vector contributions for a single
1848 // instance.
1849 //
1850 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1851 // which the system of equations is represented as:
1852 //
1853 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1854 //
1855 // Scope : public
1856 // Creator : Eric R. Keiter, SNL
1857 // Creation Date : 02/09/08
1858 //-----------------------------------------------------------------------------
1860 {
1861  bool bsuccess = true;
1862  bool tmpBool = true;
1863  Linear::Matrix & dQdxMat = *(extData.dQdxMatrixPtr);
1864 
1865  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1866  {
1867  Xyce::dout() << subsection_divider << std::endl;
1868  Xyce::dout() << "Rxn dQdx load:" << std::endl;
1869  Xyce::dout() << " name = " << getName() << std::endl;
1870  }
1871 
1872  tmpBool = loadQMatrix (dQdxMat);
1873  bsuccess = bsuccess && tmpBool;
1874 
1875  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1876  Xyce::dout() << subsection_divider << std::endl;
1877 
1878  return bsuccess;
1879 }
1880 
1881 //-----------------------------------------------------------------------------
1882 // Function : Instance::loadQMatrix
1883 //
1884 // Purpose : Loads the Q-vector contributions for a single
1885 // instance.
1886 //
1887 // Special Notes : See the special notes for loadDAEdQdxMatrix
1888 //
1889 // Scope : public
1890 // Creator : Eric R. Keiter, SNL
1891 // Creation Date : 10/19/08
1892 //-----------------------------------------------------------------------------
1893 bool Instance::loadQMatrix (Linear::Matrix & dQdxMat)
1894 {
1895  bool bsuccess = true;
1896 
1897  // Finally, we need to add in the block of jacobian entries for the
1898  // reactions
1899  int numRegions = regVec.size();
1900  for (int ireg=0;ireg<numRegions;++ireg)
1901  {
1902  regVec[ireg]->loadDAEdQdx (dQdxMat);
1903  }
1904  return bsuccess;
1905 }
1906 
1907 //-----------------------------------------------------------------------------
1908 // Function : Instance::loadDAEdFdx ()
1909 //
1910 // Purpose : Loads the F-vector contributions for a single
1911 // instance.
1912 //
1913 // Special Notes : This is an algebraic constaint.
1914 //
1915 // Scope : public
1916 // Creator : Eric R. Keiter, SNL
1917 // Creation Date : 02/09/08
1918 //-----------------------------------------------------------------------------
1920 {
1921  bool bsuccess = true;
1922  bool tmpBool = true;
1923 
1924  Linear::Matrix & dFdxMat = *(extData.dFdxMatrixPtr);
1925 
1926  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1927  {
1928  Xyce::dout() << subsection_divider << std::endl;
1929  Xyce::dout() << "Rxn dFdx load:" << std::endl;
1930  Xyce::dout() << " name = " << getName() << std::endl;
1931  }
1932 
1933  tmpBool = loadFMatrix (dFdxMat);
1934  bsuccess = bsuccess && tmpBool;
1935 
1936  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1937  {
1938  Xyce::dout() << subsection_divider << std::endl;
1939  }
1940 
1941  return bsuccess;
1942 }
1943 
1944 //-----------------------------------------------------------------------------
1945 // Function : Instance::loadFMatrix
1946 //
1947 // Purpose : Loads the F-vector contributions for a single
1948 // instance.
1949 //
1950 // Special Notes : See the special notes for loadDAEdFdxMatrix
1951 //
1952 // Scope : public
1953 // Creator : Eric R. Keiter, SNL
1954 // Creation Date : 10/19/08
1955 //-----------------------------------------------------------------------------
1956 bool Instance::loadFMatrix (Linear::Matrix & dFdxMat)
1957 {
1958  bool bsuccess=true;
1959 
1960  // Finally, we need to add in the block of jacobian entries for the
1961  // reactions
1962  int numRegions = regVec.size();
1963  int cSize(0);
1964  int rSize(0);
1965  if (numRegions > 0)
1966  {
1967  cSize = (regVec[0])->getNumConstants();
1968  rSize = (regVec[0])->getNumSpecies();
1969  for (int ireg=0;ireg<numRegions;++ireg)
1970  {
1971  regVec[ireg]->loadDAEdFdx(dFdxMat);
1972  }
1973  if (cols.size() < rSize) cols.resize(rSize,0);
1974  if (vals.size() < cols.size()) vals.resize(cols.size(),0.0);
1975  }
1976 
1977  // This set of loads should be updated to use the bracket operators.
1978  if (transportFlag)
1979  {
1980  if (!getSolverState().dcopFlag)
1981  {
1982  int numSpecies = thVec.size();
1983  int isp=0;
1984  for (isp=0;isp<numSpecies;++isp)
1985  {
1986  if (!(thVec[isp].transportFlag)) continue;
1987 
1988  int i=0;
1989  int size = regVec.size();
1990 
1991  double DiffC = thVec[isp].D_specie;
1992  std::vector<int> & specie_id = thVec[isp].specie_id;
1993 
1994  for (i=0;i<size;++i)
1995  {
1996  int row = specie_id[i];
1997  if (i==0)
1998  {
1999  double aveDx = (dxVec[i]);
2000  double coef = DiffC/(aveDx*dxVec[i]);
2001  int count = 2;
2002 
2003  cols[0] = specie_id[i ]; vals[0] = thVec[isp].bcScale1 * coef;
2004  cols[1] = specie_id[i+1]; vals[1] =-coef;
2005 
2006  bool bs1 = dFdxMat.sumIntoLocalRow (row, count, &vals[0], &cols[0]);
2007  }
2008  else if (i==(size-1))
2009  {
2010  double aveDx = (dxVec[i-1]);
2011  double coef = DiffC/(aveDx*dxVec[i-1]);
2012  int count = 2;
2013  cols[0] = specie_id[i-1]; vals[0] =-coef;
2014  cols[1] = specie_id[i ]; vals[1] = thVec[isp].bcScale2 * coef;
2015 
2016  bool bs1 = dFdxMat.sumIntoLocalRow (row, count, &vals[0], &cols[0]);
2017  }
2018  else
2019  {
2020  double aveDx = 0.5*(dxVec[i-1] + dxVec[i]);
2021  double coef1 = DiffC/(aveDx*dxVec[i-1]);
2022  double coef2 = DiffC/(aveDx*dxVec[i ]);
2023  double coefSum = coef1+coef2;
2024  int count = 3;
2025 
2026  cols[0] = specie_id[i-1]; vals[0] =-coef1;
2027  cols[1] = specie_id[i ]; vals[1] = coefSum;
2028  cols[2] = specie_id[i+1]; vals[2] =-coef2;
2029 
2030  bool bs1 = dFdxMat.sumIntoLocalRow (row, count, &vals[0], &cols[0]);
2031  }
2032  } // for loop over regions
2033  } // for loop over species.
2034  }
2035  }
2036 
2037  return bsuccess;
2038 }
2039 
2040 //-----------------------------------------------------------------------------
2041 // Function : Instance::updatePrimaryState
2042 // Purpose :
2043 // Special Notes :
2044 // Scope : public
2045 // Creator : Eric R. Keiter, SNL
2046 // Creation Date : 02/09/08
2047 //-----------------------------------------------------------------------------
2049 {
2050  bool bsuccess = true;
2051 
2052  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
2053  {
2054  Xyce::dout() << subsection_divider << std::endl;
2055  Xyce::dout() << " Start Instance::updatePrimaryState\n";
2056  Xyce::dout() << " name = " << getName() << std::endl;
2057  }
2058 
2059  // Do the bulk of the work in updateIntermediateVars:
2061 
2062  // From this point onward, the function does nothing if running MPDE.
2063  double * staVector = extData.nextStaVectorRawPtr;
2064  double * currStaVector = extData.currStaVectorRawPtr;
2065 
2066  // We need time derivatives of concentrations from time integrator to
2067  // calculate RHS for old DAE, so save the concentrations in state.
2068  int numRegions = regVec.size();
2069  for (int ireg=0;ireg<numRegions;++ireg)
2070  {
2071  if (regVec[ireg]->haveAnyReactions())
2072  {
2073  int rSize = regVec[ireg]->getNumSpecies();
2074  for (int i=0;i<rSize;++i)
2075  {
2076  staVector[regVec[ireg]->getStateConcentrationLID(i)] = regVec[ireg]->getStateConcentration(i);
2077  }
2078  }
2079  }
2080 
2081  // if this is the first newton step of the first time step
2082  // of the transient simulation, we need to enforce that the
2083  // time derivatives w.r.t. charge are zero. This is to maintain 3f5
2084  // compatibility. ERK.
2085 
2086  if (!(getSolverState().dcopFlag) && (getSolverState().initTranFlag) && getSolverState().newtonIter==0)
2087  {
2088  // Also need to force these derivatives to be zero
2089  numRegions = regVec.size();
2090  for (int ireg=0;ireg<numRegions;++ireg)
2091  {
2092  if (regVec[ireg]->haveAnyReactions())
2093  {
2094  int rSize = regVec[ireg]->getNumSpecies();
2095  for (int i=0;i<rSize;++i)
2096  {
2097  currStaVector[regVec[ireg]->getStateConcentrationLID(i)] = regVec[ireg]->getStateConcentration(i);
2098  }
2099  }
2100  }
2101  }
2102 
2103  return bsuccess;
2104 }
2105 
2106 //-----------------------------------------------------------------------------
2107 // Function : Instance::updateSecondaryState
2108 // Purpose :
2109 // Special Notes :
2110 // Scope : public
2111 // Creator : Eric R. Keiter, SNL
2112 // Creation Date : 02/09/08
2113 //-----------------------------------------------------------------------------
2115 {
2116  double * staDeriv = extData.nextStaDerivVectorRawPtr;
2117 
2118  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
2119  {
2120  Xyce::dout() << subsection_divider << std::endl;
2121  Xyce::dout() << " Start Instance::updateSecondaryState\n";
2122  Xyce::dout() << " name = " << getName() << std::endl;
2123  }
2124 
2125  // We need time derivatives of concentrations from time integrator
2126  int numRegions = regVec.size();
2127  for (int ireg=0;ireg<numRegions;++ireg)
2128  {
2129  regVec[ireg]->updateSecondaryState (staDeriv);
2130  }
2131 
2132  return true;
2133 }
2134 
2135 //-----------------------------------------------------------------------------
2136 // Function : Instance::updateIntermediateVars
2137 // Purpose :
2138 // Special Notes :
2139 // Scope : public
2140 // Creator : Eric R. Keiter
2141 // Creation Date : 02/09/08
2142 //-----------------------------------------------------------------------------
2144 {
2145  double * solVec = extData.nextSolVectorRawPtr;
2146  double * oldSolVec = extData.currSolVectorRawPtr;
2147 
2148  double * staVec = extData.nextStaVectorRawPtr;
2149  double * currStaVec = extData.currStaVectorRawPtr;
2150 
2151  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
2152  {
2153  Xyce::dout() << subsection_divider << std::endl;
2154  Xyce::dout() << " In Instance::updateIntermediateVars" << std::endl;
2155  Xyce::dout() << " name = " << getName() << std::endl;
2156  }
2157 
2158  // Reset this to show we're starting from the originals
2159  origFlag = true;
2160 
2161  double time=getSolverState().currTime;
2162 
2163  // For reaction kinetics, all we have to do here is copy the concentrations
2164  // out of the solution vector and into the temp storage
2165  int numRegions = regVec.size();
2166  for (int ireg=0;ireg<numRegions;++ireg)
2167  {
2168  regVec[ireg]->setMasterSourceValue(model_.masterSource);
2169  regVec[ireg]->updateIntermediateVars (solVec, oldSolVec, time);
2170  }
2171 
2172 
2173  int numSpecies = thVec.size();
2174  int isp=0;
2175  if (transportFlag)
2176  {
2177  for (isp=0;isp<numSpecies;++isp)
2178  {
2179  if (!(thVec[isp].transportFlag)) continue;
2180 
2181  int i=0;
2182  int size = thVec[isp].fluxVec.size(); // = numRegions-1
2183  double DiffC = thVec[isp].D_specie;
2184  for (i=0;i<size;++i)
2185  {
2186  double n2 = solVec[thVec[isp].specie_id[i ]];
2187  double n1 = solVec[thVec[isp].specie_id[i+1]];
2188 
2189  thVec[isp].fluxVec[i] = DiffC*(n2-n1)/dxVec[i];
2190  }
2191 
2192  // this imposes a direchlet BC (n=0) condition on all species at the ends.
2193  if (dirichletBCFlag)
2194  {
2195  double n1(0.0); // i+1
2196  double n2(0.0); // i
2197 
2198  n1 = solVec[thVec[isp].specie_id[0]];
2199  n2 = 0.0; // i=-1
2200  thVec[isp].flux_bc1 = DiffC*(n2-n1)/dxVec[0];
2201 
2202  n1 = 0.0; // i=max. Remember "size" here is # fluxes, not # regions (=fluxes+1).
2203  n2 = solVec[thVec[isp].specie_id[size]];
2204  thVec[isp].flux_bc2 = DiffC*(n2-n1)/dxVec[size];
2205 
2206  thVec[isp].bcScale1=2.0;
2207  thVec[isp].bcScale2=2.0;
2208  }
2209  else
2210  {
2211  thVec[isp].flux_bc1 = 0.0;
2212  thVec[isp].flux_bc2 = 0.0;
2213  }
2214  }
2215  }
2216 
2217  return true;
2218 }
2219 
2220 
2221 //-----------------------------------------------------------------------------
2222 // Function : Instance::getInstanceBreakPoints
2223 // Purpose : This function adds break points to a vector of breakpoints.
2224 //
2225 // It does not bother to check them in any way, or put them
2226 // in order. It only adds them in.
2227 //
2228 // Special Notes : Breakpoints other than those from the photocurrent
2229 // in this device are all generated by the reaction network
2230 //
2231 // Scope : public
2232 // Creator : Eric R. Keiter, SNL, Electrical and Microsystems Modeling
2233 // Creation Date : 02/09/08
2234 //-----------------------------------------------------------------------------
2236  std::vector<Util::BreakPoint> &breakPointTimes)
2237 {
2238  int numRegions = regVec.size();
2239  double junk;
2240  for (int ireg=0;ireg<numRegions;++ireg)
2241  {
2242  regVec[ireg]->setSimTime(getSolverState().currTime);
2243  junk=regVec[ireg]->getBreakTime();
2244  breakPointTimes.push_back(junk);
2245  }
2246  return true;
2247 }
2248 
2249 
2250 //-----------------------------------------------------------------------------
2251 // Function : Instance::resolveMaterialModel
2252 // Purpose :
2253 // Special Notes :
2254 // Scope : public
2255 // Creator : Lawrence C Musson
2256 // Creation Date : 01/12/15
2257 //-----------------------------------------------------------------------------
2259 {
2260  if(model_.materialVec.size() == 0)
2261  {
2262  Report::UserWarning0() << "No material layer defined in the device, defaulting to silicon.\n"
2263  << "A simple material model (and the default inserted here) looks like:\n"
2264  << " + layer = {name = DeviceMaterial\n"
2265  << " + material = si\n"
2266  << " + ConductionBandDOS = 2.86e19\n"
2267  << " + ValenceBandDOS = 2.66e19}";
2268 
2269  MaterialLayer *m = new MaterialLayer("si",1.0,1.0);
2270  model_.materialVec.push_back(m);
2271  }
2272 }
2273 
2274 
2275 //-----------------------------------------------------------------------------
2276 // Function : Model::constructComposite
2277 // Purpose :
2278 // Special Notes :
2279 // Scope : public
2280 // Creator : Eric Keiter, SNL
2281 // Creation Date : 02/09/08
2282 //-----------------------------------------------------------------------------
2283 CompositeParam *Model::constructComposite(const std::string & cName, const std::string & pName)
2284 {
2285  if (cName == "DOPINGPROFILES" || cName == "REGION")
2286  {
2287  DopeInfo *doping = new DopeInfo();
2288  dopeInfoMap[pName] = doping;
2289  return (static_cast<CompositeParam *> (doping));
2290  }
2291  else if (cName == "SOURCELIST")
2292  {
2293  SpecieSource *sources = new SpecieSource();
2294  defectSourceMap[pName] = sources;
2295  return (static_cast<CompositeParam *> (sources));
2296  }
2297  if (cName == "LAYER")
2298  {
2299  layerCompositeSpecified = true;
2300  MaterialLayer *n = new MaterialLayer();
2301  materialVec.push_back(n);
2302  return (static_cast<CompositeParam *> (n));
2303  }
2304  else
2305  {
2306  Report::UserError() << "Unrecognized composite name " << cName;
2307  }
2308 
2309  return NULL;
2310 }
2311 
2312 //-----------------------------------------------------------------------------
2313 // Function : Model::processParams
2314 // Purpose :
2315 // Special Notes :
2316 // Scope : public
2317 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2318 // Creation Date : 02/09/08
2319 //-----------------------------------------------------------------------------
2321 {
2322  return true;
2323 }
2324 
2325 //----------------------------------------------------------------------------
2326 // Function : Model::processInstanceParams
2327 // Purpose :
2328 // Special Notes :
2329 // Scope : public
2330 // Creator : Eric R. Keiter, SNL
2331 // Creation Date : 02/09/08
2332 //----------------------------------------------------------------------------
2334 {
2335 
2336  std::vector<Instance*>::iterator iter;
2337  std::vector<Instance*>::iterator first = instanceContainer.begin();
2338  std::vector<Instance*>::iterator last = instanceContainer.end();
2339 
2340  for (iter=first; iter!=last; ++iter)
2341  {
2342  (*iter)->processParams();
2343  }
2344 
2345  return true;
2346 }
2347 
2348 //-----------------------------------------------------------------------------
2349 // Function : Model::Model
2350 // Purpose : modelblock constructor
2351 // Special Notes :
2352 // Scope : public
2353 // Creator :
2354 // Creation Date : 02/09/08
2355 //-----------------------------------------------------------------------------
2357  const Configuration & configuration,
2358  const ModelBlock & MB,
2359  const FactoryBlock & factory_block)
2360  : DevicePDEModel(MB,configuration.getModelParameters(), factory_block),
2361  TNOM(300.0),
2362 
2363  userNumRegions(0),
2364  rxnFileName("NOFILE"),
2365  xlo(1.0e-5),
2366  xhi(3.0e-4),
2367 
2368  xlo_source(1.0e-5),
2369  xhi_source(3.0e-4),
2370  xlo_sourceGiven(false),
2371  xhi_sourceGiven(false),
2372 
2373  masterSource(0.0)
2374 {
2375 
2376  // Set params to constant default values:
2377  setDefaultParams ();
2378 
2379  // Set params according to .model line and constant defaults from metadata:
2380  setModParams (MB.params);
2381 
2382  // Set any non-constant parameter defaults:
2383  if (!given("TNOM"))
2385 
2386  // if the specification makes no sense, then turn it off:
2387  if (xlo_source >= xhi_source)
2388  {
2389  xlo_sourceGiven = false;
2390  xhi_sourceGiven = false;
2391  UserWarning(*this) << "XLO_SOURCE >= XHI_SOURCE. Ignoring, and using a spatially uniform source";
2392  }
2393 
2394  // If the source region was not specified(or turned off), make sure it
2395  // extends through the entire integration volume:
2396  if (!xlo_sourceGiven)
2397  {
2398  xlo_source = xlo;
2399  }
2400 
2401  if (!xhi_sourceGiven)
2402  {
2403  xhi_source = xhi;
2404  }
2405 
2406  // Calculate any parameters specified as expressions:
2407 
2409 
2410  // calculate dependent (ie computed) params and check for errors:
2411 
2412  processParams ();
2413 }
2414 
2415 //-----------------------------------------------------------------------------
2416 // Function : Model::~Model
2417 // Purpose : destructor
2418 // Special Notes :
2419 // Scope : public
2420 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2421 // Creation Date : 02/09/08
2422 //-----------------------------------------------------------------------------
2424 {
2425  std::vector<Instance*>::iterator iter;
2426  std::vector<Instance*>::iterator first = instanceContainer.begin();
2427  std::vector<Instance*>::iterator last = instanceContainer.end();
2428 
2429  for (iter=first; iter!=last; ++iter)
2430  {
2431  delete (*iter);
2432  }
2433 
2434  if (!(regionDataVec.empty()))
2435  {
2436  int size = regionDataVec.size();
2437  int i=0;
2438  for (i=0;i<size;++i)
2439  {
2440  if (regionDataVec[i] != 0)
2441  {
2442  delete regionDataVec[i];
2443  regionDataVec[i] = 0;
2444  }
2445  }
2446  }
2447 
2448  // Loop over the dopeInfoMap (if it is not empty) and delete its contents.
2449  if (!(dopeInfoMap.empty()))
2450  {
2451  std::map<std::string,DopeInfo *>::iterator iter;
2452  std::map<std::string,DopeInfo *>::iterator begin = dopeInfoMap.begin();
2453  std::map<std::string,DopeInfo *>::iterator end = dopeInfoMap.end ();
2454 
2455  for(iter=begin;iter!=end;++iter)
2456  {
2457  if (iter->second != 0) delete iter->second;
2458  }
2459  }
2460 
2461  // Do the same for the defect source map.
2462  if (!(defectSourceMap.empty()))
2463  {
2464  std::map<std::string,SpecieSource *>::iterator iter;
2465  std::map<std::string,SpecieSource *>::iterator begin = defectSourceMap.begin();
2466  std::map<std::string,SpecieSource *>::iterator end = defectSourceMap.end ();
2467 
2468  for(iter=begin;iter!=end;++iter)
2469  {
2470  if (iter->second != 0)
2471  {
2472  delete iter->second;
2473  iter->second=0;
2474  }
2475  }
2476  defectSourceMap.clear();
2477  }
2478 
2479  // Release the memory in the material vector
2480  if (!(materialVec.empty()))
2481  {
2482  for(int i=0 ; i<materialVec.size() ; ++i)
2483  {
2484  if (materialVec[i] != 0)
2485  {
2486  delete materialVec[i];
2487  materialVec[i]=NULL;
2488  }
2489  }
2490  materialVec.clear();
2491  }
2492 
2493 }
2494 
2495 //-----------------------------------------------------------------------------
2496 // Function : Model::printOutInstances
2497 // Purpose : debugging tool.
2498 // Special Notes :
2499 // Scope : public
2500 // Creator :
2501 // Creation Date : 02/09/08
2502 //-----------------------------------------------------------------------------
2503 std::ostream &Model::printOutInstances(std::ostream &os) const
2504 {
2505  std::vector<Instance*>::const_iterator iter;
2506  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
2507  std::vector<Instance*>::const_iterator last = instanceContainer.end();
2508 
2509  int i;
2510  os << " name model name Parameters" << std::endl;
2511  for (i = 0, iter = first; iter != last; ++iter, ++i)
2512  {
2513  os << " " << i << ": " << (*iter)->getName() << " ";
2514  os << getName();
2515 
2516  os << std::endl;
2517  os << " TEMP = " << (*iter)->TEMP << std::endl;
2518 
2519  os << std::endl;
2520  }
2521 
2522  os << std::endl;
2523 
2524  return os;
2525 }
2526 
2527 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */ {
2528  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
2529  op(*it);
2530 }
2531 
2532 
2533 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
2534 {
2535 
2536  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
2537 }
2538 
2540 {
2542  .registerDevice("rxn", 1)
2543  .registerModelType("rxn", 1);
2544 }
2545 
2546 } // namespace RxnSet
2547 } // namespace Device
2548 } // namespace Xyce
const InstanceName & getName() const
std::vector< double > xVec
Definition: N_DEV_RxnSet.h:226
std::vector< MaterialLayer * > materialVec
Definition: N_DEV_RxnSet.h:340
std::vector< std::vector< double * > > APosEqu_ConstPtr
Definition: N_DEV_RxnSet.h:222
std::vector< std::vector< int > > jacStamp
Definition: N_DEV_RxnSet.h:243
static void initThermalModel(ParametricData< T > &parametric_data)
Add the parameter "TEMPMODEL" to the parametric_data.
bool loadQMatrix(Linear::Matrix &dQdxMat)
std::vector< std::vector< double * > > APosEqu_SpeciesPtr
Definition: N_DEV_RxnSet.h:219
static ParametricData< MaterialLayer > & getParametricData()
const SolverState & solverState_
static Device * factory(const Configuration &configuration, const FactoryBlock &factory_block)
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 ParametricData< DopeInfo > & getParametricData()
double getSpeciesVal(int i)
Definition: N_DEV_Region.h:400
void loadNodeSymbols(Util::SymbolTable &symbol_table) const
Populates and returns the store name map.
std::vector< double > & vals
bool given(const std::string &parameter_name) const
Pure virtual class to augment a linear system.
Parameter may be specified as time dependent expression from netlist.
Definition: N_DEV_Pars.h:67
void registerLIDs(const std::vector< int > &intLIDVecRef, const std::vector< int > &extLIDVecRef)
bool processInstanceParams()
processInstanceParams
void registerJacLIDs(const std::vector< std::vector< int > > &jacLIDVec)
std::vector< int > regFirstReactantIndexVec
Definition: N_DEV_RxnSet.h:212
#define AssertLIDs(cmp)
virtual std::ostream & printOutInstances(std::ostream &os) const
void jacStampMap_fixOrder(const JacobianStamp &stamp_parent, JacobianStamp &map2_parent, JacobianStamp &stamp, JacobianStamp &map2)
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
std::map< std::string, SpecieSource * > defectSourceMap
Definition: N_DEV_RxnSet.h:334
std::vector< std::vector< double * > > ANegEqu_ConstPtr
Definition: N_DEV_RxnSet.h:223
const std::vector< std::string > & getDepSolnVars()
static ParametricData< SpecieSource > & getParametricData()
std::vector< RegionData * > regionDataVec
Definition: N_DEV_RxnSet.h:332
std::vector< Param > params
Parameters from the line.
std::vector< int > xhiStencilVec
Definition: N_DEV_RxnSet.h:230
void setParams(const std::vector< Param > &params)
const std::string & getName() const
CompositeParam * constructComposite(const std::string &cName, const std::string &pName)
const std::vector< std::vector< int > > & jacobianStamp() const
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
bool loadFMatrix(Linear::Matrix &dFdxMat)
const DeviceOptions & getDeviceOptions() const
std::vector< std::vector< int > > jacMap2
Definition: N_DEV_RxnSet.h:245
void addComposite(const char *comp_name, const ParametricData< U > &composite_pars, std::map< std::string, U * > V::*composite_map)
Adds a composite parameter to the parameter map.
Definition: N_DEV_Pars.h:1553
std::vector< std::vector< double * > > ANegEqu_SpeciesPtr
Definition: N_DEV_RxnSet.h:220
std::vector< Instance * > instanceContainer
Definition: N_DEV_RxnSet.h:310
std::vector< int > xloStencilVec
Definition: N_DEV_RxnSet.h:229
const DeviceOptions & deviceOptions_
Linear::Vector * deviceErrorWeightMask_
const std::string & getSpeciesName(int i)
Definition: N_DEV_Region.h:374
static Config< T > & addConfiguration()
Adds the device to the Xyce device configuration.
static void loadModelParameters(ParametricData< Model > &model_parameters)
Definition: N_DEV_RxnSet.C:158
Linear::Matrix * dFdxMatrixPtr
bool processParams()
processParams
The Device class is an interface for device implementations.
Definition: N_DEV_Device.h:101
std::map< std::string, DopeInfo * > dopeInfoMap
Class Configuration contains device configuration data.
void outputJacStamp(const JacobianStamp &jac)
Instance(const Configuration &configuration, const InstanceBlock &IB, Model &it_MB, const FactoryBlock &factory_block)
Definition: N_DEV_RxnSet.C:238
const SolverState & getSolverState() const
virtual void forEachInstance(DeviceInstanceOp &op) const
std::map< std::string, DopeInfo * > dopeInfoMap
const NetlistLocation & netlistLocation() const
std::vector< double > dxVec
Definition: N_DEV_RxnSet.h:227
static void loadInstanceParameters(ParametricData< Instance > &instance_parameters)
Definition: N_DEV_RxnSet.C:80
void registerStateLIDs(const std::vector< int > &stateLIDVecRef)
std::vector< TransportHelper > thVec
Definition: N_DEV_RxnSet.h:232
std::vector< int > regLastIndexVec
Definition: N_DEV_RxnSet.h:211
std::vector< Region * > regVec
Definition: N_DEV_RxnSet.h:209
double getConstantsVal(int i)
Definition: N_DEV_Region.h:413
bool getInstanceBreakPoints(std::vector< Util::BreakPoint > &breakPointTimes)
std::vector< double > splintDopeVec
const std::string & getConstantsName(int i)
Definition: N_DEV_Region.h:387
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.
std::vector< int > regNumSpecieVec
Definition: N_DEV_RxnSet.h:213
std::vector< Param > params
Linear::Matrix * dQdxMatrixPtr
void setReactionNetworkFromFile(const NetlistLocation &netlist_location, const std::string &fileName)
CompositeParam is the base class for classes that wish to only manage the processing of parameter dat...
virtual const std::vector< std::string > & getDepSolnVars()
void setModParams(const std::vector< Param > &params)
bool updateTemperature(const double &temp=-999.0)