Xyce  6.1
N_DEV_Reaction.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_Reaction.C,v $
27 //
28 // Purpose : Provide a generic class for reactions using simple
29 // law-of-mass-action kinetics, i.e.:
30 // A+2B+C -> D + 3E + F
31 // implies that the reaction happens at a rate:
32 // reactionRate = k*[A][B]^2[C]
33 // where [X] means "concentration of species X"
34 //
35 //
36 // Special Notes :
37 //
38 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
39 //
40 // Creation Date : 03/20/06
41 //
42 // Revision Information:
43 // ---------------------
44 //
45 // Revision Number: $Revision: 1.19 $
46 //
47 // Revision Date : $Date: 2015/04/08 19:18:22 $
48 //
49 // Current Owner : $Author: tvrusso $
50 //-----------------------------------------------------------------------------
51 
52 #include <Xyce_config.h>
53 
54 // Standard includes
55 #include <vector>
56 #include <N_UTL_Math.h>
57 #include <iostream>
58 
59 // Xyce includes
60 #include <N_UTL_fwd.h>
61 #include <N_UTL_FeatureTest.h>
62 #include <N_DEV_Reaction.h>
63 #include <N_ERH_ErrorMgr.h>
64 
65 #include <iostream>
66 
67 
68 namespace Xyce {
69 namespace Device {
70 
71 //-----------------------------------------------------------------------------
72 // Function : Reaction::Reaction
73 // Purpose : Default constructor
74 // Special Notes :
75 // Scope : public
76 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
77 // Creation Date : 3/20/06
78 //-----------------------------------------------------------------------------
80  : numconcs(0),
81  numconsts(0),
82  theRateConstant(0.0),
83  myRateCalc(0),
84  carrierEmissionIndex(-1),
85  material(0),
86  FADVectorsAllocated(false),
87  carrierBCIndex(-1)
88 {
89  theReactants.resize(0);
90  theProducts.resize(0);
91  concDependency.resize(0);
92  constDependency.resize(0);
93 }
94 
95 //-----------------------------------------------------------------------------
96 // Function : Reaction::Reaction
97 // Purpose : constructor
98 // Special Notes : Used when vector of reactants, products, and rate constant
99 // are available at time of construction
100 // Scope : public
101 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
102 // Creation Date : 3/20/06
103 //-----------------------------------------------------------------------------
104 Reaction::Reaction(std::vector< std::pair<int,double> > & reactants,
105  std::vector< std::pair<int,double> > & products,
106  double rateConstant)
107  :
108  theReactants(reactants),
109  theProducts(products),
110  theRateConstant(rateConstant),
111  numconcs(0),
112  numconsts(0),
113  myRateCalc(0),
114  carrierEmissionIndex(-1),
115  C0(1.0),
116  energy(0.0),
117  material(0),
118  FADVectorsAllocated(false),
119  myReactionName("UNDEFINED"),
120  tolerance(1.e12),
121  charge(1.6021918e-19),
122  peq(charge/(13.1*8.854214871e-14)),
123  unshieldedLength(0.0),
124  latticeConstant(0.0),
125  constCoeff(1.0),
126  Specie1(0),
127  Specie2(0),
128  chargeProduct(0.0),
129  carrierCharge(0),
130  carrierBCIndex(-1)
131 {
132  concDependency.resize(0);
133  constDependency.resize(0);
134 }
135 
136 //-----------------------------------------------------------------------------
137 // Function : Reaction::Reaction
138 // Purpose : copy constructor
139 // Special Notes : Needed because we keep STL vectors of these objects, and
140 // we keep a pointer to the rate constant calculator. Kills
141 // us during all the push_backs without this copy constructor,
142 // as soon as the push starts moving existing objects around.
143 // Scope : public
144 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
145 // Creation Date : 3/20/06
146 //-----------------------------------------------------------------------------
148  :theReactants(right.theReactants),
149  theProducts(right.theProducts),
150  concDependency(right.concDependency),
151  constDependency(right.constDependency),
152  theRateConstant(right.theRateConstant),
153  numconcs(right.numconcs),
154  numconsts(right.numconsts),
155  carrierEmissionIndex(right.carrierEmissionIndex),
156  C0(right.C0),
157  energy(right.energy),
158  material(right.material),
159  FADVectorsAllocated(false),
160  myReactionName(right.myReactionName),
161  tolerance(right.tolerance),
162  charge(right.charge),
163  peq(right.peq),
164  unshieldedLength(right.unshieldedLength),
165  latticeConstant(right.latticeConstant),
166  constCoeff(right.constCoeff),
167  Specie1(right.Specie1),
168  Specie2(right.Specie2),
169  chargeProduct(right.chargeProduct),
170  carrierCharge(right.carrierCharge),
171  carrierBCIndex(right.carrierBCIndex)
172 {
173  if (right.myRateCalc) // Never, ever copy the pointer to the rate calculator!
174  {
175  myRateCalc = right.myRateCalc->Clone();
176  }
177  else
178  {
179  myRateCalc=0;
180  }
181 }
182 
183 
184 //-----------------------------------------------------------------------------
185 // Function : Reaction::operator=
186 // Purpose : assignment operator
187 // Special Notes : Needed because we keep STL vectors of these objects, and
188 // we keep a pointer to the rate constant calculator. Kills
189 // us during all the push_backs without this copy constructor,
190 // as soon as the push starts moving existing objects around.
191 // Scope : public
192 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
193 // Creation Date : 3/20/06
194 //-----------------------------------------------------------------------------
195 Reaction &
197 {
198 
199  if (this == &right) return *this; // assignment to self
200 
201  if (DEBUG_DEVICE)
202  {
203  Xyce::dout() << "We're doing an assignment of reaction! " << std::endl;
204  }
205 
206  // otherwise:
207  theReactants = right.theReactants;
208  theProducts = right.theProducts;
212  numconcs = right.numconcs;
213  numconsts = right.numconsts;
214 
215  if (right.myRateCalc) // Never, ever copy the pointer to the rate calculator!
216  {
217 
218  if (myRateCalc) delete myRateCalc; // we already have one, kill it
219 
220  myRateCalc=right.myRateCalc->Clone();
221  }
222  else
223  {
224  myRateCalc=0;
225  }
226 
227  return *this;
228 
229 }
230 
231 //-----------------------------------------------------------------------------
232 // Function : Reaction::Reaction
233 // Purpose : constructor
234 // Special Notes : Used when vector of reactants, products, and rate constant
235 // are available at time of construction
236 // Scope : public
237 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
238 // Creation Date : 3/20/06
239 //-----------------------------------------------------------------------------
241 {
242  if (myRateCalc)
243  {
244  delete myRateCalc;
245  myRateCalc=0;
246  }
247 }
248 
249 //-----------------------------------------------------------------------------
250 // Function : Reaction::setReactants
251 // Purpose : copy reactant/stoichiometric coefficients into object
252 // Special Notes :
253 // Scope : public
254 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
255 // Creation Date : 3/20/06
256 //-----------------------------------------------------------------------------
257 void Reaction::setReactants(std::vector< std::pair<int,double> > & reactants)
258 {
259  theReactants=reactants;
260 }
261 
262 //-----------------------------------------------------------------------------
263 // Function : Reaction::addReactant
264 // Purpose : add reactant/stoichiometric coefficients to reactants vector
265 // Special Notes :
266 // Scope : public
267 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
268 // Creation Date : 3/20/06
269 //-----------------------------------------------------------------------------
270 void Reaction::addReactant(int species,double stoich)
271 {
272  std::vector<std::pair<int,double> >::iterator iter;
273  std::vector<std::pair<int,double> >::iterator iter_end=theReactants.end();
274  bool foundSpecies=false;
275 
276  // Make sure we only have each that appears on the LHS of a reaction
277  // listed only once. If the user has specified one twice, combine them
278  // into a single term with an augmented stoichiometric coefficient.
279  for (iter=theReactants.begin(); iter != iter_end; iter++)
280  {
281  if (iter->first == species)
282  {
283  iter->second += stoich;
284  foundSpecies=true;
285  break;
286  }
287  }
288  // Only if we didn't find the species in our existing list should we
289  // add a new entry to the vector.
290  if (!foundSpecies)
291  theReactants.push_back(std::pair<int,double>(species,stoich));
292 }
293 
294 
295 //-----------------------------------------------------------------------------
296 // Function : Reaction::addProduct
297 // Purpose : add reactant/stoichiometric coefficients to vector
298 // Special Notes :
299 // Scope : public
300 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
301 // Creation Date : 3/20/06
302 //-----------------------------------------------------------------------------
303 void Reaction::addProduct(int species,double stoich)
304 {
305  std::vector<std::pair<int,double> >::iterator iter;
306  std::vector<std::pair<int,double> >::iterator iter_end=theProducts.end();
307  bool foundSpecies=false;
308 
309  // Make sure we only have each that appears on the RHS of a reaction
310  // listed only once. If the user has specified one twice, combine them
311  // into a single term with an augmented stoichiometric coefficient.
312  for (iter=theProducts.begin(); iter != iter_end; iter++)
313  {
314  if (iter->first == species)
315  {
316  iter->second += stoich;
317  foundSpecies=true;
318  break;
319  }
320  }
321  // Only if we didn't find the species in our existing list should we
322  // add a new entry to the vector.
323  if (!foundSpecies)
324  theProducts.push_back(std::pair<int,double>(species,stoich));
325 }
326 
327 //-----------------------------------------------------------------------------
328 // Function : Reaction::setProducts
329 // Purpose : copy product/stoichiometric coefficients into object
330 // Special Notes :
331 // Scope : public
332 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
333 // Creation Date : 3/20/06
334 //-----------------------------------------------------------------------------
335 void Reaction::setProducts(std::vector< std::pair<int,double> > & products)
336 {
337  theProducts=products;
338 }
339 
340 //-----------------------------------------------------------------------------
341 // Function : Reaction::getRate
342 // Purpose : compute and return the reaction rate. This is normally the
343 // first step of getDdt, but we might need this for
344 // other purposes (e.g. a kludge for getting electron/hole
345 // recombination/regeneration rates even when electrons and
346 // holes are constant species)
347 // Special Notes : It is tacitly assumed that the concentrations and
348 // constants in the provided vector are in an order
349 // consistent with the labeling in the reactants and
350 // products vectors. The contributions to the species
351 // time derivatives are summed into the provided output
352 // vector because it is assumed that there will be a network
353 // of reactions, not just one.
354 // Scope : public
355 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
356 // Creation Date : 3/20/06
357 //-----------------------------------------------------------------------------
358 double Reaction::getRate(std::vector<double> &concentrations,
359  std::vector<double> &constants)
360 {
361  int rSize=theReactants.size();
362  int pSize=theProducts.size();
363  double reactionRate;
364  int i;
365  int species;
366  double stoich;
367  double c;
368 
369 
370  //*************************************************************
371  // The following block is an LCM modification
372  // I'm calling the veriable coefficient version of getRate
373  // to accommodate variable and material dependent coefficients
374  //*************************************************************
375 
376  reactionRate=getRateVC(concentrations,constants);
377 
378  return reactionRate;
379 
380  //*************************************************************
381  // The preceding block is an LCM modification -- Code from
382  // here down is dead and will be removed.
383  //*************************************************************
384 
385  // Reaction rate determined by law of mass action
386  reactionRate=theRateConstant;
387  // product of concentrations of reactants raised to the power of
388  // stoichiometric coefficient
389 
390  for (i=0;i<rSize;++i)
391  {
392  species=theReactants[i].first;
393  stoich=theReactants[i].second;
394 
395  if (species>=0)
396  {
397  c=concentrations[species];
398  }
399  else
400  {
401  c=constants[-(species+1)];
402  }
403 
404  if (stoich != 1.0)
405  {
406  reactionRate *= pow(c,stoich);
407  }
408  else
409  {
410  reactionRate *= c;
411  }
412  }
413 
414  return reactionRate;
415 }
416 
417 //-----------------------------------------------------------------------------
418 // Function : Reaction::getDRateDC
419 // Purpose : return a vector of the derivatives of this reaction's
420 // rate with respect to each species
421 // Special Notes :
422 //
423 // Scope : public
424 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
425 // Creation Date : 9/13/06
426 //-----------------------------------------------------------------------------
427 void Reaction::getDRateDC(std::vector<double> &concentrations,
428  std::vector<double> &constants,
429  std::vector<double> &dratedc)
430 {
431  int cSize=concentrations.size();
432  int rSize=theReactants.size();
433  int species;
434  double stoich,c;
435  int i,j;
436 
437  if (numconcs != cSize)
438  {
439  setDependency(cSize);
440  }
441 
442  // dratedc is the vector of derivatives of the reaction rate w.r.t.
443  // concentrations. Since the reaction rate is just a product of factors
444  // involving individual concentrations, we will just be multiplying in
445  // terms, so we initialize only those that are necessary to theRateConstant.
446  // Only those elements of dratedc that represent concentrations that the
447  // rate depends on will be initialized to non-zero.
448  for (i=0;i<cSize;++i)
449  {
450  if (concDependency[i]==1) // the rxn rate depends on this species
451  {
452  dratedc[i]=theRateConstant;
453  }
454  }
455 
456 
457  // The reaction rate is K*(product as i=0,rSize){[Xi]^{stoich[i]}}
458  // compute dR/dXj
459  for (i=0;i<rSize;++i) // loop over all species on left side of reaction
460  {
461  species=theReactants[i].first;
462  stoich=theReactants[i].second;
463  if (species>=0)
464  {
465  c=concentrations[species];
466  }
467  else
468  {
469  c=constants[-(species+1)];
470  }
471 
472 
473  // for each species in the network, if we depend on that species,
474  // update the product in the dR/dXj
475  if (stoich != 1.0)
476  {
477  for (j=0;j<cSize;++j)
478  {
479  if (concDependency[j] != 0)
480  {
481  if (j==species)
482  {
483  dratedc[j] *= stoich*pow(c,stoich-1.0);
484  }
485  else
486  {
487  dratedc[j] *= pow(c,stoich);
488  }
489  }
490  }
491  }
492  else
493  {
494  for (j=0;j<cSize;++j)
495  {
496  // when j==species we'd just multiply by 1.0
497  if (j!=species && concDependency[j] != 0)
498  {
499  dratedc[j] *= c;
500  }
501  }
502  }
503  }
504 }
505 
506 //-----------------------------------------------------------------------------
507 // Function : Reaction::getDRateDConst
508 // Purpose : return a vector of the derivatives of this reaction's
509 // rate with respect to each constant species
510 //
511 // Special Notes : Very much similar to getDRateDC, but computes
512 // derivative w.r.t. constants. Like getDRateDC, this
513 // will ultimately be used to compute jacobian elements,
514 // but unlike that routine, it will be used to pick out
515 // specific constants for special treatment, and unlike
516 // getDRateDC, it only computes the derivative with respect
517 // to a single constant, not all constants..
518 //
519 // Scope : public
520 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
521 // Creation Date : 10/17/06
522 //-----------------------------------------------------------------------------
523 void Reaction::getDRateDConst(int constNum,
524  std::vector<double> &concentrations,
525  std::vector<double> &constants,
526  double &dratedc)
527 {
528  int cSize=constants.size();
529  int rSize=theReactants.size();
530  int species;
531  double stoich,c;
532  int i,j;
533 
534  if (numconsts != cSize)
535  {
536  setConstDependency(cSize);
537  }
538 
539  if (constDependency[constNum]==0) // the rxn rate does not depend on this
540  //species
541  {
542  dratedc=0.0;
543  }
544  else
545  {
546  dratedc=theRateConstant;
547 
548  // The reaction rate is K*(product as i=0,rSize){[Xi]^{stoich[i]}}
549  // compute dR/dXj
550  for (i=0;i<rSize;++i) // loop over all species on left side of reaction
551  {
552  species=theReactants[i].first;
553  stoich=theReactants[i].second;
554  if (species>=0)
555  {
556  c=concentrations[species];
557  }
558  else
559  {
560  c=constants[-(species+1)];
561  }
562 
563 
564  // for each species in the network, if we depend on that species,
565  // update the product in the dR/dXj
566  if (stoich != 1.0)
567  {
568  if (species < 0 && constNum ==-(species+1)) // this specie is the one
569  // we're differntiating wrt
570  {
571  dratedc *= stoich*pow(c,stoich-1.0);
572  }
573  else
574  {
575  dratedc *= pow(c,stoich);
576  }
577  }
578  else
579  {
580  // when constNum is the specie under consideration we'd multiply by 1.0
581  if (constNum !=-(species+1))
582  {
583  dratedc *= c;
584  }
585  }
586  }
587  }
588 }
589 
590 //-----------------------------------------------------------------------------
591 // Function : Reaction::getDdt
592 // Purpose : sum time derivatives of species into provided vector
593 // Special Notes : It is tacitly assumed that the concentrations and
594 // constants in the provided vector are in an order
595 // consistent with the labeling in the reactants and
596 // products vectors. The contributions to the species
597 // time derivatives are summed into the provided output
598 // vector because it is assumed that there will be a network
599 // of reactions, not just one.
600 // Scope : public
601 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
602 // Creation Date : 3/20/06
603 //-----------------------------------------------------------------------------
604 void Reaction::getDdt(std::vector<double> &concentrations,
605  std::vector<double> &constants,
606  std::vector<double> &ddt)
607 {
608  int rSize=theReactants.size();
609  int pSize=theProducts.size();
610  double reactionRate;
611  int i;
612  int species;
613  double stoich;
614 
615  // Reaction rate determined by law of mass action
616  if(carrierEmissionIndex < 0)
617  {
618  //reactionRate=getRate(concentrations,constants);
619  reactionRate=getRateVC(concentrations,constants);
620  }
621  else
622  {
623  reactionRate=getFDEmissionRate(concentrations,constants);
624  }
625 
626  // Now update time derivatives:
627 
628  for (i=0;i<rSize;++i)
629  {
630  species=theReactants[i].first;
631  stoich=theReactants[i].second;
632  if (species>=0)
633  {
634  ddt[species] -= stoich*reactionRate;
635  }
636  }
637 
638  for (i=0;i<pSize;++i)
639  {
640  species=theProducts[i].first;
641  stoich=theProducts[i].second;
642  if (species>=0)
643  {
644  ddt[species] += stoich*reactionRate;
645  }
646  }
647 }
648 
649 //-----------------------------------------------------------------------------
650 // Function : Reaction::getJac
651 // Purpose : sum derivatives of time derivatives of species with
652 // respect to concentration into provided matrix
653 // Special Notes : It is tacitly assumed that the concentrations and
654 // constants in the provided vector are in an order
655 // consistent with the labeling in the reactants and
656 // products vectors. The contributions to the species
657 // second derivatives are summed into the provided output
658 // vector because it is assumed that there will be a network
659 // of reactions, not just one.
660 //
661 // An implicit assumption here is that the species numbering
662 // does not change through the run --- that is, once we
663 // call this routine with a vector of concentrations, it
664 // is assumed from that point forward that element i of the
665 // vector always refers to the same species in subsequent
666 // calls. If it is necessary to change that over time, the
667 // reaction network will probably have to be reconstructed
668 // and re-initialized.
669 //
670 // Scope : public
671 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
672 // Creation Date : 3/20/06
673 //-----------------------------------------------------------------------------
674 void Reaction::getJac(std::vector<double> &concentrations,
675  std::vector<double> &constants,
676  std::vector<std::vector<double> > &jac)
677 {
678  int cSize=concentrations.size();
679  int constSize=constants.size();
680  int rSize=theReactants.size();
681  int pSize=theProducts.size();
682  int species;
683  double stoich,c;
684  std::vector<double> dratedc(cSize,0.0);
685  int i,j;
686  int FADSize=cSize+constSize;
687 
688  // here is where the assumption of static species numbering is coded.
689  // Should it be necessary to change that assumption, here's where the work
690  // would be needed.
691  //LCM -- This must be modified to use the FADed versions with Fermi-Dirac statistics
692 
693  //allocate FAD arrays once
695  {
696  defects.resize(cSize);
697  carriers.resize(constSize);
698  FADVectorsAllocated = true;
699  }
700 
701  setDependency(cSize);
702  if(carrierEmissionIndex <0)
703  {
704  //getDRateDC(concentrations, constants, dratedc);
705  //The following sets up the FAD types in order to get sensitvities of the FD emission Rxns
706  FDFadType tempdRdCFD;
707  for( i=0 ; i<2 ; ++i)
708  {
709  carriers[i] = constants[i];
710  //carriers[i].diff(i,FADSize);
711  }
712  for( i=0 ; i<cSize ; ++i)
713  {
714  defects[i] = concentrations[i];
715  defects[i].diff(i+2,FADSize);
716  }
717 
718  tempdRdCFD = getRateVC(defects, carriers);
719  for(int j=0 ; j<cSize ; ++j)
720  {
721  dratedc[j] = tempdRdCFD.dx(j+2);
722  }
723  }
724  else
725  {
726  if (numconcs != cSize)
727  {
728  setDependency(cSize);
729  }
730  //The following sets up the FAD types in order to get sensitvities of the FD emission Rxns
731  FDFadType tempdRdCFD;
732  for( i=0 ; i<2 ; ++i)
733  {
734  carriers[i] = constants[i];
735  //carriers[i].diff(i,FADSize);
736  }
737  for( i=0 ; i<cSize ; ++i)
738  {
739  defects[i] = concentrations[i];
740  defects[i].diff(i+2,FADSize);
741  }
742 
743  tempdRdCFD = getFDEmissionRate(defects, carriers);
744  for(int j=0 ; j<cSize ; ++j)
745  {
746  dratedc[j] = tempdRdCFD.dx(j+2);
747  }
748  }
749 
750 
751  /*
752  if(carrierEmissionIndex <0)
753  {
754  getDRateDC(concentrations, constants, dratedc);
755  }
756  else
757  {
758  if (numconcs != cSize)
759  {
760  setDependency(cSize);
761  }
762  //The following sets up the FAD types in order to get sensitvities of the FD emission Rxns
763  FDFadType tempdRdCFD;
764  std::vector<FDFadType> defects(cSize);
765  std::vector<FDFadType> carriers(2);
766  for( i=0 ; i<2 ; ++i)
767  {
768  carriers[i] = constants[i];
769  carriers[i].diff(i,FADSize);
770  }
771  for( i=0 ; i<cSize ; ++i)
772  {
773  defects[i] = concentrations[i];
774  defects[i].diff(i+2,FADSize);
775  }
776 
777  tempdRdCFD = getFDEmissionRate(defects, carriers);
778  for(int j=0 ; j<cSize ; ++j)
779  {
780  dratedc[j] = tempdRdCFD.dx(j+2);
781  }
782  }
783  */
784  // we now know how the reaction rate depends on the various concentrations.
785  // Now we can assemble the jacobian, which is d^2[Xi]/(dt d[Xj])
786 
787 
788  // species on the left of the reaction
789  for (i=0;i<rSize;++i)
790  {
791  species=theReactants[i].first;
792  stoich=theReactants[i].second;
793  if (species>=0)
794  {
795  for (j=0;j<cSize;++j)
796  {
797  if (concDependency[j]!=0)
798  {
799  jac[species][j] -= stoich*dratedc[j];
800  }
801  }
802  }
803  }
804  // species on the right
805  for (i=0;i<pSize;++i)
806  {
807  species=theProducts[i].first;
808  stoich=theProducts[i].second;
809  if (species>=0)
810  {
811  for (j=0;j<cSize;++j)
812  {
813  if (concDependency[j]!=0)
814  {
815  jac[species][j] += stoich*dratedc[j];
816  }
817  }
818  }
819  }
820 
821 }
822 
823 
824 //-----------------------------------------------------------------------------
825 // Function : Reaction::getJac
826 // Purpose : sum derivatives of time derivatives of species with
827 // respect to concentration into provided matrix
828 //
829 // Scope : public
830 // Creator : Lawrence C Musson, SNL, Electrical and Microsystems Modeling
831 // Creation Date : 11/3/14
832 //-----------------------------------------------------------------------------
833  void Reaction::getJacobianVC(std::vector<double> &concentrations,
834  std::vector<double> &constants,
835  std::vector<std::vector<double> > &jac,
836  std::vector<double> &constVec)
837 {
838  int constSize=constants.size();
839  int cSize=concentrations.size();
840  int rSize=theReactants.size();
841  int pSize=theProducts.size();
842  int species;
843  double stoich,c;
844  std::vector<double> dratedc(cSize,0.0);
845  int i,j;
846  std::vector<double> dratedConst(constSize,0.0);
847  int FADSize=cSize+constSize;
848 
849 
850  // here is where the assumption of static species numbering is coded.
851  // Should it be necessary to change that assumption, here's where the work
852  // would be needed.
853 
854  //allocate FAD arrays once
856  {
857  defects.resize(cSize);
858  carriers.resize(constSize);
859  FADVectorsAllocated = true;
860  }
861 
862  setDependency(cSize);
863  if (numconsts != constSize)
864  {
865  setConstDependency(constSize);
866  }
867 
868 
869  if(carrierEmissionIndex <0)
870  {
871  //getDRateDC(concentrations, constants, dratedc);
872  //The following sets up the FAD types in order to get sensitvities of the FD emission Rxns
873  FDFadType tempdRdCFD;
874  for( i=0 ; i<constSize ; ++i)
875  {
876  carriers[i] = constants[i];
877  carriers[i].diff(i,FADSize);
878  }
879  for( i=0 ; i<cSize ; ++i)
880  {
881  defects[i] = concentrations[i];
882  defects[i].diff(i+constSize,FADSize);
883  }
884 
885  tempdRdCFD = getRateVC(defects, carriers);
886  for(int j=0 ; j<cSize ; ++j)
887  {
888  dratedc[j] = tempdRdCFD.dx(j+constSize);
889  }
890  for(int j=0 ; j<constSize ; ++j)
891  dratedConst[j] = tempdRdCFD.dx(j);
892 
893  }
894  else
895  {
896  if (numconcs != cSize)
897  {
898  setDependency(cSize);
899  }
900  //The following sets up the FAD types in order to get sensitvities of the FD emission Rxns
901  FDFadType tempdRdCFD;
902  for( i=0 ; i<constSize ; ++i)
903  {
904  carriers[i] = constants[i];
905  carriers[i].diff(i,FADSize);
906  }
907  for( i=0 ; i<cSize ; ++i)
908  {
909  defects[i] = concentrations[i];
910  defects[i].diff(i+constSize,FADSize);
911  }
912 
913  tempdRdCFD = getFDEmissionRate(defects, carriers);
914  for(int j=0 ; j<cSize ; ++j)
915  {
916  dratedc[j] = tempdRdCFD.dx(j+constSize);
917  }
918  for(int j=0 ; j<constSize ; ++j)
919  dratedConst[j] = tempdRdCFD.dx(j);
920  }
921 
922 
923  // we now know how the reaction rate depends on the various concentrations.
924  // Now we can assemble the jacobian, which is d^2[Xi]/(dt d[Xj])
925 
926 
927  // species on the left of the reaction
928  for (i=0;i<rSize;++i)
929  {
930  species=theReactants[i].first;
931  stoich=theReactants[i].second;
932  if (species>=0)
933  {
934  for (j=0;j<cSize;++j)
935  {
936  jac[species][j] -= stoich*dratedc[j];
937  }
938  }
939  }
940  // species on the right
941  for (i=0;i<pSize;++i)
942  {
943  species=theProducts[i].first;
944  stoich=theProducts[i].second;
945  if (species>=0)
946  {
947  for (j=0;j<cSize;++j)
948  {
949  jac[species][j] += stoich*dratedc[j];
950  }
951  }
952  }
953 
954  // we now know how the reaction rate depends on the various constants
955  // we can assemble the derivatives we need.
956 
957  for(int constIdx=0 ; constIdx<constSize ; ++constIdx)
958  {
959  int offset = constIdx*cSize;
960  // species on the left of the reaction
961  for (i=0;i<rSize;++i)
962  {
963  species=theReactants[i].first;
964  stoich=theReactants[i].second;
965  if (species>=0)
966  constVec[species+offset] -= stoich*dratedConst[constIdx];
967  }
968  // species on the right
969  for (i=0;i<pSize;++i)
970  {
971  species=theProducts[i].first;
972  stoich=theProducts[i].second;
973  if (species>=0)
974  constVec[species+offset] += stoich*dratedConst[constIdx];
975  }
976  }
977 
978 }
979 
980 //-----------------------------------------------------------------------------
981 // Function : Reaction::getDFdConst
982 // Purpose : sum derivatives of time derivatives of species with
983 // respect to concentration into provided vector
984 // Special Notes : It is tacitly assumed that the concentrations and
985 // constants in the provided vector are in an order
986 // consistent with the labeling in the reactants and
987 // products vectors. The contributions to the species
988 // second derivatives are summed into the provided output
989 // vector because it is assumed that there will be a network
990 // of reactions, not just one.
991 //
992 // An implicit assumption here is that the species numbering
993 // does not change through the run --- that is, once we
994 // call this routine with a vector of concentrations, it
995 // is assumed from that point forward that element i of the
996 // vector always refers to the same species in subsequent
997 // calls. If it is necessary to change that over time, the
998 // reaction network will probably have to be reconstructed
999 // and re-initialized.
1000 //
1001 // This method sums into a vector containing the derivatives
1002 // of variable species with respect to the specified constant
1003 // specie. It'll be used as a fragment of a larger jacobian.
1004 //
1005 // Scope : public
1006 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1007 // Creation Date : 3/20/06
1008 //-----------------------------------------------------------------------------
1009 void Reaction::getDFdConst(int constantNumber,
1010  std::vector<double> &concentrations,
1011  std::vector<double> &constants,
1012  std::vector<double> &dFdConst)
1013 {
1014  int constSize=constants.size();
1015  int cSize=concentrations.size();
1016  int rSize=theReactants.size();
1017  int pSize=theProducts.size();
1018  int species;
1019  double stoich,c;
1020  double dratedc;
1021  int i;
1022  int FADSize=cSize+constSize;
1023 
1024  // here is where the assumption of static species numbering is coded.
1025  // Should it be necessary to change that assumption, here's where the work
1026  // would be needed.
1027 
1028  //allocate FAD arrays once
1029  if(!FADVectorsAllocated)
1030  {
1031  defects.resize(cSize);
1032  carriers.resize(constSize);
1033  FADVectorsAllocated = true;
1034  }
1035 
1036  if(carrierEmissionIndex <0)
1037  {
1038  //getDRateDConst(constantNumber,concentrations, constants, dratedc);
1039  //The following sets up the FAD types in order to get sensitvities of the FD emission Rxns
1040 
1041  int cSize = concentrations.size();
1042  if (numconsts != constSize)
1043  {
1044  setConstDependency(constSize);
1045  }
1046 
1047  FDFadType tempdRdCFD;
1048  for( i=0 ; i<2 ; ++i)
1049  {
1050  carriers[i] = constants[i];
1051  carriers[i].diff(i,FADSize);
1052  }
1053  for( i=0 ; i<concentrations.size() ; ++i)
1054  {
1055  defects[i] = concentrations[i];
1056  //defects[i].diff(i+2,FADSize);
1057  }
1058 
1059  tempdRdCFD = getRateVC(defects, carriers);
1060  dratedc = tempdRdCFD.dx(constantNumber);
1061  }
1062  else
1063  {
1064  //The following sets up the FAD types in order to get sensitvities of the FD emission Rxns
1065  int cSize = concentrations.size();
1066  if (numconsts != constSize)
1067  {
1068  setConstDependency(constSize);
1069  }
1070 
1071  FDFadType tempdRdCFD;
1072  for( i=0 ; i<2 ; ++i)
1073  {
1074  carriers[i] = constants[i];
1075  carriers[i].diff(i,FADSize);
1076  }
1077  for( i=0 ; i<cSize ; ++i)
1078  {
1079  defects[i] = concentrations[i];
1080  //defects[i].diff(i+2,FADSize);
1081  }
1082  tempdRdCFD = getFDEmissionRate(defects, carriers);
1083  dratedc = tempdRdCFD.dx(constantNumber);
1084  }
1085 
1086  /*
1087  if(carrierEmissionIndex <0)
1088  {
1089  getDRateDConst(constantNumber,concentrations, constants, dratedc);
1090  //The following sets up the FAD types in order to get sensitvities of the FD emission Rxns
1091  }
1092  else
1093  {
1094  //The following sets up the FAD types in order to get sensitvities of the FD emission Rxns
1095  int cSize = concentrations.size();
1096  if (numconsts != constSize)
1097  {
1098  setConstDependency(constSize);
1099  }
1100 
1101  FDFadType tempdRdCFD;
1102  std::vector<FDFadType> defects(cSize);
1103  std::vector<FDFadType> carriers(2);
1104  for( i=0 ; i<2 ; ++i)
1105  {
1106  carriers[i] = constants[i];
1107  carriers[i].diff(i,FADSize);
1108  }
1109  for( i=0 ; i<cSize ; ++i)
1110  {
1111  defects[i] = concentrations[i];
1112  defects[i].diff(i+2,FADSize);
1113  }
1114  tempdRdCFD = getFDEmissionRate(defects, carriers);
1115  dratedc = tempdRdCFD.dx(constantNumber);
1116  }
1117  */
1118 
1119  // no point going through these loops if this reaction doesn't depend
1120  // on this constant!
1121  if (constDependency[constantNumber] != 0)
1122  {
1123  // we now know how the reaction rate depends on the various constants
1124  // we can assemble the derivatives we need.
1125 
1126  // species on the left of the reaction
1127  for (i=0;i<rSize;++i)
1128  {
1129  species=theReactants[i].first;
1130  stoich=theReactants[i].second;
1131  if (species>=0)
1132  {
1133  dFdConst[species] -= stoich*dratedc;
1134  }
1135  }
1136  // species on the right
1137  for (i=0;i<pSize;++i)
1138  {
1139  species=theProducts[i].first;
1140  stoich=theProducts[i].second;
1141  if (species>=0)
1142  {
1143  dFdConst[species] += stoich*dratedc;
1144  }
1145  }
1146  }
1147 }
1148 
1149 
1150 //-----------------------------------------------------------------------------
1151 // Function : Reaction::setSimpleRateCalculator
1152 // Purpose : set the rate calculator for this reaction to a simple one
1153 // Special Notes :
1154 // Scope : public
1155 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1156 // Creation Date : 8/01/06
1157 //-----------------------------------------------------------------------------
1158 void Reaction::setSimpleRateCalculator(double k_in, double C0, double t0,
1159  double x0)
1160 {
1161  if (myRateCalc) // we already have a calculator set
1162  {
1163  delete myRateCalc; // kill it
1164  myRateCalc=0;
1165  }
1166 
1167  myReactionName = "simplerate";
1168 
1169  myRateCalc = dynamic_cast<RateCalculator *> (new SimpleRateCalculator(k_in, C0, t0, x0));
1170 }
1171 
1172 //-----------------------------------------------------------------------------
1173 // Function : Reaction::setCaptureRateCalculator
1174 // Purpose : set the rate calculator for this reaction to the
1175 // capture rate type (A0+E->AM, for example)
1176 // Special Notes :
1177 // Scope : public
1178 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1179 // Creation Date : 8/01/06
1180 //-----------------------------------------------------------------------------
1181 void Reaction::setCaptureRateCalculator(double sigma, double v,
1182  double C0, double t0, double x0)
1183 {
1184  if (myRateCalc) // we already have a calculator set
1185  {
1186  delete myRateCalc; // kill it
1187  myRateCalc=0;
1188  }
1189 
1190  myReactionName = "capturerate";
1191 
1192  //N.B., it's labeled v (velocity), but really it's the charge of the carrier
1193 
1194  if(v < 0.0)
1195  carrierCharge = -1;
1196  else if(v > 0.0)
1197  carrierCharge = 1;
1198  else
1199  {
1200  Report::UserError() <<"Illegal carrier charge";
1201  }
1202 
1203  myRateCalc = dynamic_cast<RateCalculator *>(new CaptureRateCalculator(sigma, v, C0, t0, x0));
1204 }
1205 
1206 
1207 //-----------------------------------------------------------------------------
1208 // Function : Reaction::setEmissionRateCalculator
1209 // Purpose : set the rate calculator for this reaction to the
1210 // emission rate type (AM->A0+E, for example)
1211 // Special Notes :
1212 // Scope : public
1213 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1214 // Creation Date : 8/01/06
1215 //-----------------------------------------------------------------------------
1216 void Reaction::setEmissionRateCalculator(double sigma, double v,
1217  double N, double Energy,
1218  double C0, double t0, double x0)
1219 {
1220  if (myRateCalc) // we already have a calculator set
1221  {
1222  delete myRateCalc; // kill it
1223  myRateCalc=0;
1224  }
1225 
1226  myReactionName = "emissionrate";
1227 
1228  //N.B., it's labeled v (velocity), but really it's the charge of the carrier
1229 
1230  if(v < 0.0)
1231  carrierCharge = -1;
1232  else if(v > 0.0)
1233  carrierCharge = 1;
1234  else
1235  {
1236  Report::UserError() << "Illegal carrier charge";
1237  }
1238 
1239 
1240  myRateCalc = dynamic_cast<RateCalculator *> (
1241  new EmissionRateCalculator(sigma, v, N, Energy, C0, t0, x0));
1242 }
1243 
1244 //-----------------------------------------------------------------------------
1245 // Function : Reaction::setFDEmissionRateCalculator
1246 // Purpose : set the rate calculator for this reaction to the
1247 // emission rate type (AM->A0+E, for example). This
1248 // include Fermi-Dirac stats
1249 // Special Notes :
1250 // Scope : public
1251 // Creator : Lawrence C Musson
1252 // Creation Date : 06/30/2014
1253 //-----------------------------------------------------------------------------
1254  void Reaction::setFDEmissionRateCalculator(int carrierIndex, double sigma, double Energy,
1255  double v, double C0i, double t0, double x0)
1256 {
1257  if (myRateCalc) // we already have a calculator set
1258  {
1259  delete myRateCalc; // kill it
1260  myRateCalc=0;
1261  }
1262 
1263  //N.B., it's labeled v (velocity), but really it's the charge of the carrier
1264 
1265  if(v < 0.0)
1266  carrierCharge = -1;
1267  else if(v > 0.0)
1268  carrierCharge = 1;
1269  else
1270  {
1271  Report::UserError() << "Illegal carrier charge";
1272  }
1273 
1274  carrierEmissionIndex = carrierIndex; //emitted carrier
1275  C0 = C0i; //concentration
1276  energy = Energy; //emission energy
1277 
1278  myReactionName = "fdemissionrate";
1279 
1280  myRateCalc = dynamic_cast<RateCalculator *> (
1281  new FDEmissionRateCalculator(sigma, Energy, v, C0, t0, x0));
1282 }
1283 
1284 
1285 //-----------------------------------------------------------------------------
1286 // Function : Reaction::setComplexRateCalculator
1287 // Purpose : set the rate calculator for this reaction to the
1288 // complex rate type (A+B->AB, for example)
1289 // Special Notes :
1290 // Scope : public
1291 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1292 // Creation Date : 8/01/06
1293 //-----------------------------------------------------------------------------
1294 void Reaction::setComplexRateCalculator(std::vector<Specie> &V,
1295  std::vector<Specie> &C,
1296  double C0, double t0, double x0)
1297 {
1298  if (myRateCalc) // we already have a calculator set
1299  {
1300  delete myRateCalc; // kill it
1301  myRateCalc=0;
1302  }
1303 
1304  myReactionName = "complexrate";
1305 
1306  //We need to store the reactant list for convenient access
1307 
1308  myRateCalc = dynamic_cast<RateCalculator *> (
1309  new ComplexRateCalculator(V,C,theReactants,C0, t0, x0));
1310 
1311  //The sanity check on this was already handled in the constructor for myRateCalc
1312 
1313  if (theReactants[0].first >= 0)
1314  Specie1 = &(V[theReactants[0].first]);
1315  else
1316  Specie1 = &(C[-(theReactants[0].first+1)]);
1317 
1318  // Handle case where there's only one species with a coefficient of 2.0
1319  if (theReactants.size() == 1)
1320  {
1321  Specie2 = Specie1; // that way we can just treat as A+A instead of 2A
1322  }
1323  else
1324  {
1325  if (theReactants[1].first >= 0)
1326  Specie2 = &(V[theReactants[1].first]);
1327  else
1328  Specie2 = &(C[-(theReactants[1].first+1)]);
1329  }
1330 
1333 
1334 }
1335 
1336 //-----------------------------------------------------------------------------
1337 // Function : Reaction::setComplexRateMultiplierCalculator
1338 // Purpose : set the rate calculator for this reaction to the
1339 // complex rate type (A+B->AB, for example) times
1340 // : the specified multiplier
1341 // Special Notes :
1342 // Scope : public
1343 // Creator : Lawrence C Musson
1344 // Creation Date : 06/26/2014
1345 //-----------------------------------------------------------------------------
1347  std::vector<Specie> &C,
1348  double C0, double t0, double x0,
1349  double multiplier)
1350 {
1351  if (myRateCalc) // we already have a calculator set
1352  {
1353  delete myRateCalc; // kill it
1354  myRateCalc=0;
1355  }
1356 
1357  myReactionName = "complexmultiplierrate";
1358 
1359  myRateCalc = dynamic_cast<RateCalculator *> (
1360  new ComplexRateCalculator(V,C,theReactants,C0, t0, x0));
1361 
1362 
1363  //The sanity check on this was already handled in the constructor for myRateCalc
1364 
1365  if (theReactants[0].first >= 0)
1366  Specie1 = &(V[theReactants[0].first]);
1367  else
1368  Specie1 = &(C[-(theReactants[0].first+1)]);
1369 
1370  // Handle case where there's only one species with a coefficient of 2.0
1371  if (theReactants.size() == 1)
1372  {
1373  Specie2 = Specie1; // that way we can just treat as A+A instead of 2A
1374  }
1375  else
1376  {
1377  if (theReactants[1].first >= 0)
1378  Specie2 = &(V[theReactants[1].first]);
1379  else
1380  Specie2 = &(C[-(theReactants[1].first+1)]);
1381  }
1382 
1385 }
1386 
1387 //-----------------------------------------------------------------------------
1388 // Function : Reaction::setDecomplexRateCalculator
1389 // Purpose : set the rate calculator for this reaction to the
1390 // decomplex rate type (AB->A+B, for example)
1391 // Special Notes :
1392 // Scope : public
1393 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1394 // Creation Date : 8/01/06
1395 //-----------------------------------------------------------------------------
1396 void Reaction::setDecomplexRateCalculator(std::vector<Specie> &V,
1397  std::vector<Specie> &C,
1398  double bindingEnergy,
1399  double gammaAB, double gammaA,
1400  double gammaB, double concSi,
1401  double C0, double t0, double x0)
1402 {
1403  if (myRateCalc) // we already have a calculator set
1404  {
1405  delete myRateCalc; // kill it
1406  myRateCalc=0;
1407  }
1408 
1409  myReactionName = "decomplexrate";
1410 
1411  myRateCalc = dynamic_cast<RateCalculator *> (
1413  bindingEnergy, gammaAB,gammaA,
1414  gammaB, concSi,
1415  C0, t0, x0));
1416 
1417  //The sanity check on this was already handled in the constructor for myRateCalc
1418 
1419  if (theProducts[0].first >= 0)
1420  Specie1 = &(V[theProducts[0].first]);
1421  else
1422  Specie1 = &(C[-(theProducts[0].first+1)]);
1423 
1424  // Handle case where there's only one species with a coefficient of 2.0
1425  if (theProducts.size() == 1)
1426  {
1427  Specie2 = Specie1; // that way we can just treat as A+A instead of 2A
1428  }
1429  else
1430  {
1431  if (theProducts[1].first >= 0)
1432  Specie2 = &(V[theProducts[1].first]);
1433  else
1434  Specie2 = &(C[-(theProducts[1].first+1)]);
1435  }
1436 
1439 
1440 }
1441 
1442 
1443 //-----------------------------------------------------------------------------
1444 // Function : Reaction::setDecomplexRateCalculator
1445 // Purpose : set the rate calculator for this reaction to the
1446 // decomplex rate type (AB->A+B, for example)
1447 // Special Notes :
1448 // Scope : public
1449 // Creator : Lawrence C Musson
1450 // Creation Date : 03/24/2014
1451 //-----------------------------------------------------------------------------
1453  std::vector<Specie> &C, double sigma,
1454  double C0, double t0, double x0)
1455 {
1456  if (myRateCalc) // we already have a calculator set
1457  {
1458  delete myRateCalc; // kill it
1459  myRateCalc=0;
1460  }
1461 
1462  myReactionName = "bouroincorbettholerate";
1463 
1464  myRateCalc = dynamic_cast<RateCalculator *> (
1466  C0, t0, x0));
1467 }
1468 
1469 //-----------------------------------------------------------------------------
1470 // Function : Reaction::setRateConstantFromCalculator
1471 // Purpose : set the rate constant from the temperature using our rate
1472 // calculator
1473 // Special Notes :
1474 // Scope : public
1475 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1476 // Creation Date : 8/01/06
1477 //-----------------------------------------------------------------------------
1479 {
1480  if (myRateCalc) // if we *have* a rate calculator
1481  {
1482  if(material->material=="UNDEFINED" || material->material=="")
1483  {
1484  Report::UserError() << "The bulk material " << material->material << " is unknown";
1485  }
1486 
1489 
1491  }
1492  // otherwise just leave it where it is (which might be 0)
1493 }
1494 
1495 
1496 //-----------------------------------------------------------------------------
1497 // Function : Reaction::setRateConstantFromCalculator
1498 // Purpose : set the rate constant from the temperature using our rate
1499 // calculator
1500 // Special Notes :
1501 // Scope : public
1502 // Creator : Lawrence C Musson, SNL
1503 // Creation Date : 04/17/2014
1504 //-----------------------------------------------------------------------------
1506  std::vector<double> &concs,
1507  std::vector<double> &constant_vec)
1508 {
1509  if (myRateCalc) // if we *have* a rate calculator
1510  {
1511  if(material->material=="UNDEFINED" || material->material=="")
1512  {
1513  Report::UserError() << "The bulk material " << material->material << " is unknown";
1514  }
1515  setRateConstant(myRateCalc->computeRateConstant(T,concs,constant_vec));
1516 
1517  }
1518  // otherwise just leave it where it is (which might be 0)
1519 }
1520 
1521 //-----------------------------------------------------------------------------
1522 // Function : Reaction::scaleRateConstantFromCalculator()
1523 // Purpose : scale the rate constant using values stored in our rate
1524 // calculator
1525 // Special Notes :
1526 // Scope : public
1527 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1528 // Creation Date : 8/01/06
1529 //-----------------------------------------------------------------------------
1531 {
1532  if (myRateCalc) // if we *have* a rate calculator
1533  {
1535  }
1536  // otherwise just leave it where it is
1537 }
1538 
1539 //-----------------------------------------------------------------------------
1540 // Function : Reaction::unscaleRateConstantFromCalculator()
1541 // Purpose : unscale the rate constant using values stored in our rate
1542 // calculator
1543 // Special Notes :
1544 // Scope : public
1545 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1546 // Creation Date : 8/01/06
1547 //-----------------------------------------------------------------------------
1549 {
1550  if (myRateCalc) // if we *have* a rate calculator
1551  {
1553  }
1554  // otherwise just leave it where it is
1555 }
1556 
1557 
1558 //-----------------------------------------------------------------------------
1559 // Function : Reaction::setDependency
1560 // Purpose : Set the vector that denotes which of the cSize species
1561 // that the network tracks are actually used in this one
1562 // reaction as reactants, that is, the species that are
1563 // used in computing the reaction rate.
1564 // Special Notes :
1565 // Scope : private
1566 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1567 // Creation Date : 3/20/06
1568 //-----------------------------------------------------------------------------
1570 {
1571  int rSize=theReactants.size();
1572  int i;
1573  numconcs=cSize;
1574  concDependency.resize(numconcs,0);
1575 
1576  for (i=0;i<rSize;++i)
1577  {
1578  if (theReactants[i].first >= 0)
1579  {
1580  concDependency[theReactants[i].first]=1;
1581  }
1582  }
1583 
1584 }
1585 
1586 //-----------------------------------------------------------------------------
1587 // Function : Reaction::setConstDependency
1588 // Purpose : Set the vector that denotes which of the cSize constant
1589 // species that the network contains are actually used in this
1590 // one reaction as reactants, that is, the species that are
1591 // used in computing the reaction rate.
1592 // Special Notes :
1593 // Scope : private
1594 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1595 // Creation Date : 10/17/06
1596 //-----------------------------------------------------------------------------
1598 {
1599  int rSize=theReactants.size();
1600  int i;
1601  numconsts=cSize;
1602  constDependency.resize(numconsts,0);
1603 
1604  for (i=0;i<rSize;++i)
1605  {
1606  if (theReactants[i].first < 0)
1607  {
1608  constDependency[-(theReactants[i].first+1)]=1;
1609  }
1610  }
1611 }
1612 
1613 //-----------------------------------------------------------------------------
1614 // Function : Reaction::output
1615 // Purpose : Accessor function to set rate constant
1616 // Special Notes :
1617 // Scope : public
1618 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
1619 // Creation Date : 5/27/06
1620 //-----------------------------------------------------------------------------
1621 void Reaction::output
1622  ( const std::vector<Specie> & species, std::ostream & os ) const
1623 {
1624  int i=0;
1625  int isize = theReactants.size();
1626  os << " Rxn: ";
1627  bool firstPrintDone=false;
1628  for (i=0;i<isize;++i)
1629  {
1630  int speciesIndex = theReactants[i].first;
1631  if (speciesIndex >= 0)
1632  {
1633  if (firstPrintDone) os << " + ";
1634  double tmp = theReactants[i].second;
1635  if (tmp > 1.0)
1636  os << " "<<tmp<< " * ";
1637  os.setf(std::ios::right); os.width(3);
1638  os << species[speciesIndex].getName();
1639 
1640  firstPrintDone = true;
1641  }
1642  }
1643 
1644  os << " = ";
1645  isize = theProducts.size();
1646  firstPrintDone=false;
1647  for (i=0;i<isize;++i)
1648  {
1649  int speciesIndex = theProducts[i].first;
1650  if (speciesIndex >= 0)
1651  {
1652  if (firstPrintDone) os << " + ";
1653  double tmp = theProducts[i].second;
1654  if (tmp > 1.0)
1655  os << " " << tmp << " * ";
1656  os.setf(std::ios::right); os.width(3);
1657 
1658  os << species[speciesIndex].getName();
1659  firstPrintDone = true;
1660  }
1661  }
1662 
1663  os << " Rate Constant: ";
1664  os.precision(8); os.setf(std::ios::scientific);
1665  os << theRateConstant;
1666 
1667 #if 0
1668  os << "\n Dependencies:\n";
1669  for (int j=0;j<concDependency.size();++j)
1670  {
1671  os << " " << species[j].getName() << " = " << concDependency[j] << std::endl;
1672  }
1673 #endif
1674  os << std::endl;
1675 
1676 }
1677 
1678 
1679 //-----------------------------------------------------------------------------
1680 // Function : Reaction::setMaterial
1681 // Purpose : Set the bulk material in the reaction object
1682 // Special Notes :
1683 // Scope : public
1684 // Creator : Lawrence C Musson
1685 // Creation Date : 5/27/06
1686 //-----------------------------------------------------------------------------
1687 
1688  void Reaction::setMaterial(MaterialLayer *mat, double Temp)
1689  {
1690  material = mat;
1691 
1692  ExtendedString mN = material->material;
1693  mN.toLower();
1694  material->material = mN;
1695 
1696  if(material->material == "si")
1697  materialEnum = si;
1698  else if(material->material == "gaas")
1699  materialEnum = gaas;
1700 
1701  //now with the material known, we can set some
1702  //material dependent quantities and arrange for
1703  //other, concentration dependent coefficients
1704  //to be set up.
1705 
1706  if (myRateCalc)
1708  }
1709 
1710 
1711 
1712 //-----------------------------------------------------------------------------
1713 // Function : Reaction::setCoefficient
1714 // Purpose : Set the coefficient for the reactions
1715 // Special Notes : This is different than the rate constant. It's most often
1716 // just 1.0. But for some complexing reactions, there are
1717 // concentration dependent values to be used.
1718 // Scope : public
1719 // Creator : Lawrence C Musson
1720 // Creation Date : 5/27/06
1721 //-----------------------------------------------------------------------------
1722 
1723  void Reaction::setCoefficient(double Temp)
1724  {
1725 
1726  //now with the material and reaction type known,
1727  //we can arrange for other, concentration
1728  //dependent coefficients to be set up.
1729 
1730  if(myReactionName == "simplerate")
1731  {
1732  constCoeff = 1.0;
1733  coefficientType = 0;
1734  }
1735  else if(myReactionName == "capturerate")
1736  {
1737  //For this, the coefficient is going to be carrier velocity
1738  if(carrierCharge == 1)
1740  else
1742  coefficientType = 0;
1743  }
1744  else if(myReactionName == "emissionrate")
1745  {
1746  //For this, the coefficient is going to be the product
1747  //of carrier velocity and DOS
1748  if(carrierCharge == 1)
1749  {
1751  constCoeff *= material->Nv;
1752  }
1753  else
1754  {
1756  constCoeff *= material->Nc;
1757  }
1758  coefficientType = 0;
1759  }
1760  else if(myReactionName == "complexrate" || myReactionName == "complexmultiplierrate"
1761  || myReactionName == "decomplexrate")
1762  {
1763  tolerance = 1.e12;
1766  coefficientType = 1;
1767 
1770 
1771  //Need to check if Bourogin Corbett enhanced diffusion is turned on
1773  {
1776  sigmaBC = Specie1->getBCSigma();
1777  if(carrierBCIndex == 0)
1779  else
1781  }
1782  else if(Specie2->getEnhancedDiffusion())
1783  {
1786  sigmaBC = Specie2->getBCSigma();
1787  if(carrierBCIndex == 0)
1789  else
1791  }
1792  else
1793  {
1794  carrierBCIndex = -1;
1795  hopLength = 0.0;
1796  thermalVelocity = 0.0;
1797  }
1798  }
1799  else if(myReactionName == "fdemissionrate")
1800  {
1801  //For this, the coefficient is going to be the product
1802  //of carrier velocity and DOS
1803  if(carrierCharge == 1)
1804  {
1806  }
1807  else
1808  {
1810  }
1811  coefficientType = 0;
1812  }
1813  else
1814  {
1815  //unrecognized reaction name
1816  Report::UserError() << "Unrecognized reaction name in setting rate coefficient creation " << myReactionName;
1817  }
1818 
1819  return;
1820 
1821  }
1822 
1823 } // namespace Device
1824 } // namespace Xyce
Rate constant calculator for Electron or Hole emission reaction.
void setSimpleRateCalculator(double k, double C0, double t0, double x0)
ScalarT getDiffusionCoefficient(ScalarT Temperature)
Definition: N_DEV_Specie.h:129
void setComplexMultiplierRateCalculator(std::vector< Specie > &VariableSpecies, std::vector< Specie > &ConstantSpecies, double C0, double t0, double x0, double multiplier)
Sacado::ELRFad::DFad< double > FDFadType
Pure virtual class to augment a linear system.
Rate constant calculator for Electron or Hole emission reaction.
void unscaleRateConstantFromCalculator()
virtual double rateConstantScaleFactor()=0
return current scale factor for rate constant
double getRate(std::vector< double > &concentrations, std::vector< double > &constants)
std::vector< int > concDependency
std::vector< FDFadType > carriers
void setMaterial(MaterialLayer *material, double Temp)
RetScalarT charge(RetScalarT U, Arg2ScalarT C0, Arg3ScalarT Ud, Arg4ScalarT m, Arg5ScalarT Area)
void getDdt(std::vector< double > &concentrations, std::vector< double > &constants, std::vector< double > &ddt)
void setEmissionRateCalculator(double sigma, double v, double N, double Energy, double C0, double t0, double x0)
virtual double computeRateConstant(double T)=0
return rate constant at given temperature
void getDRateDConst(int constNum, std::vector< double > &concentrations, std::vector< double > &constants, double &dratedc)
void addReactant(int species, double stoich)
void output(const std::vector< Specie > &species, std::ostream &os) const
ScalarT getFDEmissionRate(std::vector< ScalarT > &concentrations, std::vector< ScalarT > &constants)
std::vector< int > constDependency
std::vector< FDFadType > defects
void addProduct(int species, double stoich)
void setRateConstantFromCalculator(double T)
Rate constant calculator for a irreversible two-species complexing reaction.
RateCalculator * myRateCalc
void getJac(std::vector< double > &concentrations, std::vector< double > &constants, std::vector< std::vector< double > > &jac)
void setDecomplexRateCalculator(std::vector< Specie > &VariableSpecies, std::vector< Specie > &ConstantSpecies, double bindingEnergy, double gammaAB, double gammaA, double gammaB, double concSi, double C0, double t0, double x0)
Reaction & operator=(const Reaction &right)
virtual bool isBulkMaterialSet()=0
void setCoefficient(double Temp)
void getDRateDC(std::vector< double > &concentrations, std::vector< double > &constants, std::vector< double > &dratedc)
std::vector< std::pair< int, double > > theReactants
std::vector< std::pair< int, double > > theProducts
void setCaptureRateCalculator(double sigma, double v, double C0, double t0, double x0)
virtual RateCalculator * Clone()=0
create a copy of this calculator
void setRateConstant(double)
void setConstDependency(int cSize)
void setDependency(int cSize)
ScalarT getRateVC(std::vector< ScalarT > &concentrations, std::vector< ScalarT > &constants)
Class for trivial, constant rate constant (independent of temperature)
virtual void setBulkMaterial(std::string material)=0
Abstract interface class for "rate calculator" strategy pattern.
void setFDEmissionRateCalculator(int carrierIndex, double sigma, double Energy, double v, double C0, double t0, double x0)
void setReactants(std::vector< std::pair< int, double > > &products)
MaterialLayer * material
void setBourgoinCorbettHoleRateCalculator(std::vector< Specie > &VariableSpecies, std::vector< Specie > &ConstantSpecies, double sigma, double C0, double t0, double x0)
void setProducts(std::vector< std::pair< int, double > > &products)
void getDFdConst(int constantNumber, std::vector< double > &concentrations, std::vector< double > &constants, std::vector< double > &dFdConst)
Rate constant calculator for Electron or Hole capture reaction.
void getJacobianVC(std::vector< double > &concentrations, std::vector< double > &constants, std::vector< std::vector< double > > &jac, std::vector< double > &constVec)
materialEnum_t materialEnum
void setComplexRateCalculator(std::vector< Specie > &VariableSpecies, std::vector< Specie > &ConstantSpecies, double C0, double t0, double x0)