Memosa-FVM  0.2
ElectricModel_impl.h
Go to the documentation of this file.
1 // This file os part of FVM
2 // Copyright (c) 2012 FVM Authors
3 // See LICENSE file for terms.
4 
5 #include "Mesh.h"
6 #include "NumType.h"
7 #include "Array.h"
8 #include "Field.h"
9 #include "CRConnectivity.h"
10 #include "LinearSystem.h"
11 //#include "FieldSet.h"
12 #include "StorageSite.h"
13 #include "MultiFieldMatrix.h"
14 #include "CRMatrix.h"
15 #include "FluxJacobianMatrix.h"
16 #include "DiagonalMatrix.h"
17 #include "GenericBCS.h"
18 #include "Vector.h"
21 #include "DriftDiscretization.h"
24 #include "EmissionDiscretization.h"
25 #include "CaptureDiscretization.h"
28 #include "AMG.h"
29 #include "Linearizer.h"
30 #include "GradientModel.h"
32 #include "SourceDiscretization.h"
33 
34 #include "PhysicsConstant.h"
36 
37 #include "SquareTensor.h"
38 #include "ElecDiagonalTensor.h"
39 //#include "LinearizeDielectric.h"
40 #include "LinearizeInterfaceJump.h"
43 
44 #ifdef FVM_PARALLEL
45 #include <mpi.h>
46 #endif
47 
48 template<class T>
50 {
51 public:
52  typedef Array<T> TArray;
57 
60 
62  //typedef ElecDiagonalTensor<T, 2> TensorNxN;
64 
65  //typedef ElecOffDiagonalTensor<T, 2> OffDiag;
66 
69 
72 
73 
74 
75  Impl(const GeomFields& geomFields,
76  ElectricFields& electricFields,
77  const MeshList& meshes) :
78  _meshes(meshes),
79  _geomFields(geomFields),
80  _electricFields(electricFields),
81  _potentialGradientModel(_meshes,_electricFields.potential,
82  _electricFields.potential_gradient,_geomFields),
83  _chargeGradientModel (_meshes, _electricFields.charge,
84  _electricFields.chargeGradient,_geomFields),
85  _initialElectroStaticsNorm(),
86  _initialChargeTransportNorm(),
87  _niters(0),
88  _avgCharge(0),
89  _tunnelCurrentIn(0),
90  _tunnelCurrentOut(0)
91 
92  {
93  const int numMeshes = _meshes.size();
94  for (int n=0; n<numMeshes; n++)
95  {
96  const Mesh& mesh = *_meshes[n];
97 
98  ElectricVC<T> *vc(new ElectricVC<T>());
99  vc->vcType = "dielectric";
100  _vcMap[mesh.getID()] = vc;
101 
102  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
103  {
104  const FaceGroup& fg = *fgPtr;
105  ElectricBC<T> *bc(new ElectricBC<T>());
106 
107  _bcMap[fg.id] = bc;
108  if (fg.groupType == "wall")
109  {
110  bc->bcType = "SpecifiedPotential";
111  }
112  else if (fg.groupType == "symmetry")
113  {
114  bc->bcType = "Symmetry";
115  }
116  //else
117  // throw CException("ElectricModel: unknown face group type "
118  // + fg.groupType);
119  }
120  }
121  }
122 
123  void init()
124  {
125  const int numMeshes = _meshes.size();
126  for (int n=0; n<numMeshes; n++)
127  {
128  const Mesh& mesh = *_meshes[n];
129 
130  const ElectricVC<T>& vc = *_vcMap[mesh.getID()];
131 
132  const StorageSite& cells = mesh.getCells();
133 
134  const StorageSite& faces = mesh.getFaces();
135 
136  // initialize fields for electrostatics
137 
138  if (_options.electrostatics_enable){
139 
140  const int nCells = cells.getCountLevel1();
141 
142  //initial potential setup
143  shared_ptr<TArray> pCell(new TArray(nCells));
144  *pCell = _options["initialPotential"];
145  _electricFields.potential.addArray(cells,pCell);
146 
147  //dielectric_constant setup
148  shared_ptr<TArray> permCell(new TArray(nCells));
149  *permCell = vc["dielectric_constant"] * E0_SI ;
150  //*permCell = vc["dielectric_constant"];
151  _electricFields.dielectric_constant.addArray(cells,permCell);
152 
153  //total_charge (source in Poisson equation) setup
154  if ( vc.vcType == "dielectric"){
155  shared_ptr<TArray> sdCell(new TArray(nCells));
156  *sdCell = _options["initialTotalCharge"]*-QE;
157  _electricFields.total_charge.addArray(cells,sdCell);
158  }
159  else{
160  shared_ptr<TArray> saCell(new TArray(nCells));
161  saCell->zero();
162  _electricFields.total_charge.addArray(cells,saCell);
163  }
164  //potential gradient setup
165  shared_ptr<PGradArray> gradp(new PGradArray(nCells));
166  gradp->zero();
167  _electricFields.potential_gradient.addArray(cells,gradp);
168 
169  //electric_field setup
170  shared_ptr<VectorT3Array> ef(new VectorT3Array(nCells));
171  ef->zero();
172  _electricFields.electric_field.addArray(cells,ef);
173 
174  //initial potential flux; Note: potential_flux only stored on boundary faces
175  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
176  {
177  const FaceGroup& fg = *fgPtr;
178  const StorageSite& faces = fg.site;
179 
180  shared_ptr<TArray> pFlux(new TArray(faces.getCount()));
181  pFlux->zero();
182  _electricFields.potential_flux.addArray(faces,pFlux);
183 
184  }
185  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
186  {
187  const FaceGroup& fg = *fgPtr;
188  const StorageSite& faces = fg.site;
189 
190  shared_ptr<TArray> pFlux(new TArray(faces.getCount()));
191  pFlux->zero();
192  _electricFields.potential_flux.addArray(faces,pFlux);
193 
194  }
195 
196  //initial species concentration setup for linking to SpeciesModel
197  shared_ptr<TArray> sCCell(new TArray(nCells));
198  sCCell->zero();
199  _electricFields.speciesConcentration.addArray(cells,sCCell);
200 
201  shared_ptr<TArray> lnSCCell(new TArray(nCells));
202  lnSCCell->zero();
203  _electricFields.lnSpeciesConcentration.addArray(cells,lnSCCell);
204 
205  shared_ptr<PGradArray> gradLnSC(new PGradArray(nCells));
206  gradLnSC->zero();
207  _electricFields.lnSpeciesConcentrationGradient.addArray(cells,gradLnSC);
208 
209  }
210 
211  //initilize fields in charge transport models
212  /*
213  regarding multi trapdepth model, assume the number of trapdepth is nTrap
214  index i = 0 to i = nTrap-1 refer to charges in traps
215  index i = nTrap refer to charges in conduction band
216  */
217 
218  if (_options.chargetransport_enable){
219 
220  if ( vc.vcType == "dielectric" ) {
221 
222  const int nCells = cells.getCountLevel1();
223 
224  //conduction_band setup
225  shared_ptr<TArray> cb(new TArray(nCells));
226  cb->zero();
227  _electricFields.conduction_band.addArray(cells,cb);
228 
229  //valence_band setup
230  shared_ptr<TArray> vb(new TArray(nCells));
231  vb->zero();
232  _electricFields.valence_band.addArray(cells, vb);
233 
234  //charge density setup
235  shared_ptr<VectorTNArray> ch(new VectorTNArray (nCells));
236  ch->zero();
237  _electricFields.charge.addArray(cells, ch);
238 
239  if (_options.transient_enable)
240  {
241  _electricFields.chargeN1.addArray(cells,dynamic_pointer_cast<ArrayBase>(ch->newCopy()));
242  if (_options.timeDiscretizationOrder > 1)
243  _electricFields.chargeN2.addArray(cells, dynamic_pointer_cast<ArrayBase>(ch->newCopy()));
244  }
245 
246  //charge velocity
247  shared_ptr<VectorT3Array> vcell(new VectorT3Array(nCells));
248  vcell->zero();
249  _electricFields.electron_velocity.addArray(cells, vcell);
250 
251  //free_electron_capture_cross setup
252  shared_ptr<VectorTNArray> fecr(new VectorTNArray(nCells));
253  fecr->zero();
254  _electricFields.free_electron_capture_cross.addArray(cells, fecr);
255 
256  // convection flux on all faces
257  shared_ptr<TArray> mf (new TArray(faces.getCount()));
258  mf->zero();
259  _electricFields.convectionFlux.addArray(faces, mf);
260 
261  //diffusivity
262  shared_ptr<TArray> diffCell(new TArray(cells.getCountLevel1()));
263  const T diffCoeff = _constants["electron_mobility"] * K_SI * _constants["OP_temperature"] / QE;
264  *diffCell = diffCoeff;
265  _electricFields.diffusivity.addArray(cells,diffCell);
266 
267  //create a zero field
268  shared_ptr<TArray> zeroCell(new TArray(cells.getCountLevel1()));
269  *zeroCell = T(0.0);
270  _electricFields.zero.addArray(cells,zeroCell);
271 
272  //create a one field
273  shared_ptr<TArray> oneCell(new TArray(cells.getCountLevel1()));
274  *oneCell = T(1.0);
275  _electricFields.one.addArray(cells,oneCell);
276 
277  //initial charge gradient array
278  shared_ptr<CGradArray> gradC(new CGradArray(cells.getCountLevel1()));
279  gradC->zero();
280  _electricFields.chargeGradient.addArray(cells,gradC);
281 
282  //initial charge flux
283  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
284  {
285  const FaceGroup& fg = *fgPtr;
286  const StorageSite& faces = fg.site;
287 
288  shared_ptr<VectorTNArray> cFlux(new VectorTNArray(faces.getCount()));
289  cFlux->zero();
290  _electricFields.chargeFlux.addArray(faces,cFlux);
291  }
292  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
293  {
294  const FaceGroup& fg = *fgPtr;
295  const StorageSite& faces = fg.site;
296 
297  shared_ptr<VectorTNArray> cFlux(new VectorTNArray(faces.getCount()));
298  cFlux->zero();
299  _electricFields.chargeFlux.addArray(faces,cFlux);
300  }
301  }
302  }
303  }
304 
305  _electricFields.dielectric_constant.syncLocal();
306  _niters = 0;
307  _initialElectroStaticsNorm = MFRPtr();
308  if (_options.chargetransport_enable)
309  _initialChargeTransportNorm = MFRPtr();
310  }
311 
312 
313 
314 
315  ElectricBCMap& getBCMap() {return _bcMap;}
316 
317  ElectricBC<T>& getBC(const int id) {return *_bcMap[id];}
318 
319  ElectricVCMap& getVCMap() {return _vcMap;}
320 
321  ElectricVC<T>& getVC(const int id) {return *_vcMap[id];}
322 
323  ElectricModelOptions<T>& getOptions() {return _options;}
324 
325  ElectricModelConstants<T>& getConstants() {return _constants;}
326 
327  void updateTime()
328  {
329  const int numMeshes = _meshes.size();
330  for (int n=0; n<numMeshes; n++) {
331 
332  const Mesh& mesh = *_meshes[n];
333  const StorageSite& cells = mesh.getCells();
334  const int nCells = cells.getCountLevel1();
335 
336  VectorTNArray& charge =
337  dynamic_cast<VectorTNArray&>(_electricFields.charge[cells]);
338  VectorTNArray& chargeN1 =
339  dynamic_cast<VectorTNArray&>(_electricFields.chargeN1[cells]);
340  TArray& totalcharge =
341  dynamic_cast<TArray&> (_electricFields.total_charge[cells]);
342 
343  if (_options.timeDiscretizationOrder > 1)
344  {
345  VectorTNArray& chargeN2 =
346  dynamic_cast<VectorTNArray&>(_electricFields.chargeN2[cells]);
347  chargeN2 = chargeN1;
348  }
349  chargeN1 = charge;
350  /*
351  const int nTrap = _constants["nTrap"];
352  for (int c=0; c<nCells; c++){
353  for (int i=0; i<=nTrap; i++){
354  totalcharge[c] += charge[c][i]*-QE;
355  }
356  }
357  */
358  const ElectricVC<T>& vc = *_vcMap[mesh.getID()];
359  if (vc.vcType == "dielectric"){
360  const TArray& cellVolume =
361  dynamic_cast<const TArray&> (_geomFields.volume[cells]);
362  T chargeSum(0);
363  T volumeSum(0);
364  const int nCells = cells.getSelfCount();
365  for (int c=0; c<nCells; c++){
366  volumeSum += cellVolume[c];
367  chargeSum += totalcharge[c]*cellVolume[c];
368  }
369  _avgCharge = chargeSum/volumeSum;
370  }
371  cout << "the avergae charge " << _avgCharge << endl;
372  }
373 
374  }
375 
376 
378  {
379  LinearSystem ls;
380 
381  initElectroStaticsLinearization(ls);
382 
383  ls.initAssembly();
384 
385  linearizeElectroStatics(ls);
386 
387  ls.initSolve();
388 
389  MFRPtr rNorm(_options.getElectroStaticsLinearSolver().solve(ls));
390 
391  if (!_initialElectroStaticsNorm) _initialElectroStaticsNorm = rNorm;
392 
393  _options.getElectroStaticsLinearSolver().cleanup();
394 
395  ls.postSolve();
396 
397  ls.updateSolution();
398 
399  updateElectricField();
400 
401  if (_options.chargetransport_enable){
402 
403  updateElectronVelocity();
404 
405  updateConvectionFlux();
406  }
407 
408  return rNorm;
409 
410  }
411 
413  {
414  LinearSystem ls;
415 
416  initChargeTransportLinearization(ls);
417 
418  ls.initAssembly();
419 
420  linearizeChargeTransport(ls);
421 
422  ls.initSolve();
423 
424  MFRPtr rNorm(_options.getChargeTransportLinearSolver().solve(ls));
425 
426  if (!_initialChargeTransportNorm) _initialChargeTransportNorm = rNorm;
427 
428  _options.getChargeTransportLinearSolver().cleanup();
429 
430  ls.postSolve();
431 
432  ls.updateSolution();
433 
434 
435  return rNorm;
436  }
437 
439  {
440  const int numMeshes = _meshes.size();
441  for (int n=0; n<numMeshes; n++)
442  {
443  const Mesh& mesh = *_meshes[n];
444 
445  const StorageSite& cells = mesh.getCells();
446  MultiField::ArrayIndex tIndex(&_electricFields.potential,&cells);
447 
448  ls.getX().addArray(tIndex,_electricFields.potential.getArrayPtr(cells));
449 
450  const CRConnectivity& cellCells = mesh.getCellCells();
451 
452  shared_ptr<Matrix> m(new CRMatrix<T,T,T>(cellCells));
453 
454  ls.getMatrix().addMatrix(tIndex,tIndex,m);
455 
456  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
457  {
458  const FaceGroup& fg = *fgPtr;
459  const StorageSite& faces = fg.site;
460 
461  MultiField::ArrayIndex fIndex(&_electricFields.potential_flux,&faces);
462  ls.getX().addArray(fIndex,_electricFields.potential_flux.getArrayPtr(faces));
463 
464  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
465 
466  shared_ptr<Matrix> mft(new FluxJacobianMatrix<T,T>(faceCells));
467  ls.getMatrix().addMatrix(fIndex,tIndex,mft);
468 
469  shared_ptr<Matrix> mff(new DiagonalMatrix<T,T>(faces.getCount()));
470  ls.getMatrix().addMatrix(fIndex,fIndex,mff);
471  }
472 
473  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
474  {
475  const FaceGroup& fg = *fgPtr;
476  const StorageSite& faces = fg.site;
477 
478  MultiField::ArrayIndex fIndex(&_electricFields.potential_flux,&faces);
479  ls.getX().addArray(fIndex,_electricFields.potential_flux.getArrayPtr(faces));
480 
481  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
482 
483  shared_ptr<Matrix> mft(new FluxJacobianMatrix<T,T>(faceCells));
484  ls.getMatrix().addMatrix(fIndex,tIndex,mft);
485 
486  shared_ptr<Matrix> mff(new DiagonalMatrix<T,T>(faces.getCount()));
487  ls.getMatrix().addMatrix(fIndex,fIndex,mff);
488  }
489 
490  }
491  }
492 
494  {
495  const int numMeshes = _meshes.size();
496  for (int n=0; n<numMeshes; n++)
497  {
498  const Mesh& mesh = *_meshes[n];
499 
500  //const ElectricVC<T>& vc = *_vcMap[mesh.getID()];
501 
502  //if (vc.vcType == "dielectric"){
503 
504  const StorageSite& cells = mesh.getCells();
505 
506  MultiField::ArrayIndex cIndex(&_electricFields.charge,&cells);
507 
508  ls.getX().addArray(cIndex,_electricFields.charge.getArrayPtr(cells));
509 
510  const CRConnectivity& cellCells = mesh.getCellCells();
511 
512  shared_ptr<Matrix> m(new CRMatrix<TensorNxN,TensorNxN,VectorTN>(cellCells));
513 
514  ls.getMatrix().addMatrix(cIndex,cIndex,m);
515 
516  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
517  {
518  const FaceGroup& fg = *fgPtr;
519  const StorageSite& faces = fg.site;
520 
521  MultiField::ArrayIndex fIndex(&_electricFields.chargeFlux,&faces);
522  ls.getX().addArray(fIndex,_electricFields.chargeFlux.getArrayPtr(faces));
523 
524  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
525 
526  shared_ptr<Matrix> mft(new FluxJacobianMatrix<TensorNxN,VectorTN>(faceCells));
527  ls.getMatrix().addMatrix(fIndex,cIndex,mft);
528 
529  shared_ptr<Matrix> mff(new DiagonalMatrix<TensorNxN,VectorTN>(faces.getCount()));
530  ls.getMatrix().addMatrix(fIndex,fIndex,mff);
531  }
532 
533  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
534  {
535  const FaceGroup& fg = *fgPtr;
536  const StorageSite& faces = fg.site;
537  MultiField::ArrayIndex fIndex(&_electricFields.chargeFlux,&faces);
538  ls.getX().addArray(fIndex,_electricFields.chargeFlux.getArrayPtr(faces));
539 
540  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
541 
542  shared_ptr<Matrix> mft(new FluxJacobianMatrix<TensorNxN,VectorTN>(faceCells));
543  ls.getMatrix().addMatrix(fIndex,cIndex,mft);
544 
545  shared_ptr<Matrix> mff(new DiagonalMatrix<TensorNxN,VectorTN>(faces.getCount()));
546  ls.getMatrix().addMatrix(fIndex,fIndex,mff);
547  }
548  //}
549  }
550  }
551 
553  {
554  _potentialGradientModel.compute();
555 
556  DiscrList discretizations;
557 
558  shared_ptr<Discretization>
559  dd(new DiffusionDiscretization<T,T,T>(_meshes,_geomFields,
560  _electricFields.potential,
561  _electricFields.dielectric_constant,
562  _electricFields.potential_gradient,
563  _constants["dielectric_thickness"]));
564  discretizations.push_back(dd);
565 
566  shared_ptr<Discretization>
568  (_meshes,
569  _geomFields,
570  _electricFields.potential,
571  _electricFields.total_charge
572  ));
573  discretizations.push_back(sd);
574 
575  if(_options.ibm_enable){
576  shared_ptr<Discretization>
578  (_meshes,_geomFields,_electricFields.potential));
579  discretizations.push_back(ibm);
580  }
581 
582  if(_options.ButlerVolmer)
583  {
584  //populate lnSpeciesConc Field
585  for (int n=0; n<_meshes.size(); n++)
586  {
587  const Mesh& mesh = *_meshes[n];
588  const StorageSite& cells = mesh.getCells();
589  const TArray& speciesConc = dynamic_cast<const TArray&>(_electricFields.speciesConcentration[cells]);
590  TArray& lnSpeciesConc = dynamic_cast<TArray&>(_electricFields.lnSpeciesConcentration[cells]);
591  for (int c=0; c<cells.getCount(); c++)
592  {
593  T CellConc = speciesConc[c];
594  if (CellConc <= 0.0)
595  {
596  cout << "Error: Cell Concentration <= 0 MeshID: " << n << " CellNum: " << c << endl;
597  CellConc = 0.01;
598  }
599  lnSpeciesConc[c] = log(CellConc);
600  }
601  }
602 
603  //compute gradient for ln term discretization
604  GradientModel<T> lnSpeciesGradientModel(_meshes,_electricFields.lnSpeciesConcentration,
605  _electricFields.lnSpeciesConcentrationGradient,_geomFields);
606  lnSpeciesGradientModel.compute();
607 
608  //discretize ln term (only affects electrolyte mesh)
609  shared_ptr<Discretization>
611  _electricFields.potential,
612  _electricFields.dielectric_constant,
613  _electricFields.lnSpeciesConcentration,
614  _electricFields.lnSpeciesConcentrationGradient,
615  _options["BatteryElectrolyteMeshID"]));
616  discretizations.push_back(bedd);
617 
618  }
619 
620  Linearizer linearizer;
621 
622  linearizer.linearize(discretizations,_meshes,ls.getMatrix(),
623  ls.getX(), ls.getB());
624 
625 
626 
627 
628  const int numMeshes = _meshes.size();
629 
630  /*linearize shell mesh*/
631  /*
632  for (int n=0; n<numMeshes; n++)
633  {
634  const Mesh& mesh = *_meshes[n];
635  if (mesh.isShell())
636  {
637  LinearizeDielectric<T, T, T> lsm (_geomFields,
638  _electricFields.dielectric_constant,
639  _constants["dielectric_thickness"],
640  _electricFields.potential);
641 
642  lsm.discretize(mesh, ls.getMatrix(), ls.getX(), ls.getB() );
643  }
644  }
645  */
646 
647  /* linearize double shell mesh for interface potential jump*/
648 
649  for (int n=0; n<numMeshes; n++)
650  {
651  const Mesh& mesh = *_meshes[n];
652  if (mesh.isDoubleShell())
653  {
654  const int parentMeshID = mesh.getParentMeshID();
655  const int otherMeshID = mesh.getOtherMeshID();
656  const Mesh& parentMesh = *_meshes[parentMeshID];
657  const Mesh& otherMesh = *_meshes[otherMeshID];
658 
659  if (_options.ButlerVolmer)
660  {
661  bool Cathode = false;
662  bool Anode = false;
663  if (n == _options["ButlerVolmerCathodeShellMeshID"])
664  {
665  Cathode = true;
666  }
667  else if (n == _options["ButlerVolmerAnodeShellMeshID"])
668  {
669  Anode = true;
670  }
671  LinearizePotentialInterface<T, T, T> lbv (_geomFields,
672  _electricFields.potential,
673  _electricFields.speciesConcentration,
674  _options["ButlerVolmerRRConstant"],
675  _options["Interface_A_coeff"],
676  _options["Interface_B_coeff"],
677  Anode,
678  Cathode);
679 
680  lbv.discretize(mesh, parentMesh, otherMesh, ls.getMatrix(), ls.getX(), ls.getB() );
681  }
682  else
683  {
684 
685  LinearizeInterfaceJump<T, T, T> lsm (_options["Interface_A_coeff"],
686  _options["Interface_B_coeff"],
687  _electricFields.potential);
688 
689  lsm.discretize(mesh, parentMesh, otherMesh, ls.getMatrix(), ls.getX(), ls.getB() );
690  }
691  }
692  }
693 
694  /* boundary and interface condition */
695 
696  for (int n=0; n<numMeshes; n++)
697  {
698  const Mesh& mesh = *_meshes[n];
699  const StorageSite& cells = mesh.getCells();
700 
701  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
702  {
703  const FaceGroup& fg = *fgPtr;
704  const StorageSite& faces = fg.site;
705  const int nFaces = faces.getCount();
706  const ElectricBC<T>& bc = *_bcMap[fg.id];
707 
708 
709  GenericBCS<T,T,T> gbc(faces,mesh,
710  _geomFields,
711  _electricFields.potential,
712  _electricFields.potential_flux,
713  ls.getMatrix(), ls.getX(), ls.getB());
714 
715  if (bc.bcType == "SpecifiedPotential")
716  {
717  FloatValEvaluator<T> bT(bc.getVal("specifiedPotential"), faces);
718  for(int f=0; f<nFaces; f++)
719  {
720  gbc.applyDirichletBC(f, bT[f]);
721  }
722  }
723  else if (bc.bcType == "SpecifiedPotentialFlux")
724  {
725  const T specifiedFlux(bc["specifiedPotentialFlux"]);
726  gbc.applyNeumannBC(specifiedFlux);
727  }
728  else if (bc.bcType == "Symmetry")
729  {
730  T zeroFlux(NumTypeTraits<T>::getZero());
731  gbc.applyNeumannBC(zeroFlux);
732  }
733  else if (bc.bcType == "SpecialDielectricBoundary")
734  {
735  FloatValEvaluator<T> bT(bc.getVal("specifiedPotential"), faces);
736  //const T specifiedPotential(bc["specifiedPotential"]);
737  const T dielectric_thickness = _constants["dielectric_thickness"];
738  const T dielectric_constant = _constants["dielectric_constant"] * E0_SI;
739  const T coeff = dielectric_constant / dielectric_thickness;
740  //const T avgCharge = 100/1.60217646e-19*8.854187826e-12*-QE;
741  _avgCharge = -1e4;
742  //const T src = _avgCharge * dielectric_thickness;
743  const T src = 0;
744  for(int f=0; f<nFaces; f++)
745  gbc.applyDielectricInterfaceBC(f, coeff, bT[f], src);
746  }
747  else
748  throw CException(bc.bcType + " not implemented for ElectricModel");
749  }
750 
751  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
752  {
753 
754  const FaceGroup& fg = *fgPtr;
755  const StorageSite& faces = fg.site;
756 
757 
758  GenericBCS<T,T,T> gbc(faces,mesh,
759  _geomFields,
760  _electricFields.potential,
761  _electricFields.potential_flux,
762  ls.getMatrix(), ls.getX(), ls.getB());
763 
764  gbc.applyInterfaceBC();
765  }
766  }
767  }
768 
769 
770 
772  {
773  _chargeGradientModel.compute();
774 
775  DiscrList discretizations;
776 
777  if (_options.tunneling_enable){
778  shared_ptr<Discretization>
780  (_meshes, _geomFields,
781  _electricFields.charge,
782  _electricFields.conduction_band,
783  _constants,
784  _tunnelCurrentIn,
785  _tunnelCurrentOut
786  ));
787  discretizations.push_back(tnd);
788  }
789 
790  if (_options.injection_enable){
791  shared_ptr<Discretization>
793  (_meshes, _geomFields,
794  _electricFields.charge,
795  _electricFields.electric_field,
796  _electricFields.conduction_band,
797  _constants
798  ));
799  discretizations.push_back(inj);
800  }
801 
802  if (_options.emission_enable){
803  shared_ptr<Discretization>
805  (_meshes, _geomFields,
806  _electricFields.charge,
807  _electricFields.electric_field,
808  _constants));
809  discretizations.push_back(em);
810  }
811 
812  if (_options.capture_enable){
813  shared_ptr<Discretization>
815  (_meshes, _geomFields,
816  _electricFields.charge,
817  _electricFields.free_electron_capture_cross,
818  _constants));
819  discretizations.push_back(capt);
820  }
821 
822 
823  if (_options.trapbandtunneling_enable){
824  shared_ptr<Discretization>
826  (_meshes, _geomFields,
827  _electricFields.charge,
828  _electricFields.electric_field,
829  _electricFields.conduction_band,
830  _constants));
831  discretizations.push_back(tbt);
832 
833  }
834 
835 #if 0
836  if (_options.diffusion_enable){
837  shared_ptr<Discretization>
839  (_meshes,_geomFields,
840  _electricFields.charge,
841  _electricFields.diffusivity,
842  _electricFields.chargeGradient));
843  discretizations.push_back(dd);
844  }
845 #endif
846 
847  if (_options.drift_enable){
848  shared_ptr<Discretization>
850  (_meshes,_geomFields,
851  _electricFields.charge,
852  _electricFields.convectionFlux,
853  _constants["nTrap"]));
854  discretizations.push_back(cd);
855  }
856 
857  if (_options.transient_enable)
858  {
859  shared_ptr<Discretization>
861  (_meshes,_geomFields,
862  _electricFields.charge,
863  _electricFields.chargeN1,
864  _electricFields.chargeN2,
865  _electricFields.one,
866  _options["timeStep"]));
867  discretizations.push_back(td);
868  }
869 
870 
871 
872 
873  Linearizer linearizer;
874 
875  linearizer.linearize(discretizations,_meshes,ls.getMatrix(),
876  ls.getX(), ls.getB());
877 
878  if (_options.diffusion_enable || _options.drift_enable){
879  const int numMeshes = _meshes.size();
880  for (int n=0; n<numMeshes; n++)
881  {
882  const Mesh& mesh = *_meshes[n];
883 
884  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
885  {
886  const FaceGroup& fg = *fgPtr;
887  const StorageSite& faces = fg.site;
888 
889  const ElectricBC<T>& bc = *_bcMap[fg.id];
890 
891 
893  _geomFields,
894  _electricFields.charge,
895  _electricFields.chargeFlux,
896  ls.getMatrix(), ls.getX(), ls.getB());
897  //dielectric charging uses fixed zero dirichlet bc
898  VectorTN zero(VectorTN::getZero());;
899 
900  //gbc.applyNonzeroDiagBC();
901  if (bc.bcType == "Symmetry")
902  //gbc.applyExtrapolationBC();
903  gbc.applyDirichletBC(zero);
904  else
905  gbc.applyDirichletBC(zero);
906 
907  }
908 
909  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
910  {
911  const FaceGroup& fg = *fgPtr;
912  const StorageSite& faces = fg.site;
914  _geomFields,
915  _electricFields.charge,
916  _electricFields.chargeFlux,
917  ls.getMatrix(), ls.getX(), ls.getB());
918  gbc.applyInterfaceBC();
919  }
920  }
921  }
922 
923 
924  }
925 
926 
927 
928 
929  bool advance(const int niter)
930  {
931  bool flag1 = false;
932  bool flag2 = false;
933 
934  if(_options.electrostatics_enable){
935 
936  for(int n=0; n<niter; n++)
937  {
938  MFRPtr eNorm = solveElectroStatics();
939 
940  if (_niters < 5)
941  _initialElectroStaticsNorm->setMax(*eNorm);
942 
943  MFRPtr eNormRatio(eNorm->normalize(*_initialElectroStaticsNorm));
944 
945 #ifndef FVM_PARALLEL
946  if (_options.printNormalizedResiduals)
947  cout << _niters << ": " << *eNormRatio << ";" << endl;
948  else
949  cout << _niters << ": " << *eNorm << ";" << endl;
950 #endif
951 
952 #ifdef FVM_PARALLEL
953  if ( MPI::COMM_WORLD.Get_rank() == 0 ){
954  if (_options.printNormalizedResiduals)
955  cout << _niters << ": " << *eNormRatio << ";" << endl;
956  else
957  cout << _niters << ": " << *eNorm << ";" << endl;
958  }
959 #endif
960 
961  if (*eNormRatio < _options.electrostaticsTolerance ) {
962  flag1 = true;
963  break;
964  }
965 
966 
967  }
968  }
969 
970 
971  if(_options.chargetransport_enable){
972  for(int n=0; n<niter; n++)
973  {
974  generateBandDiagram();
975 
976  MFRPtr cNorm = solveChargeTransport();
977 
978  if (_niters < 5)
979  _initialChargeTransportNorm->setMax(*cNorm);
980 
981  MFRPtr cNormRatio((*cNorm)/(*_initialChargeTransportNorm));
982 
983  if (_options.printNormalizedResiduals)
984  cout << _niters << ": " << *cNormRatio << endl;
985  else
986  cout << _niters << ": " << *cNorm << endl;
987 
988  if (*cNormRatio < _options.chargetransportTolerance){
989  flag2 = true;
990  //break;
991  }
992  }
993 
994  }
995  _niters++;
996  return flag1;
997 
998  }
999 
1000  /*** update electric_field from potential_gradient ***/
1002  {
1003  _potentialGradientModel.compute();
1004 
1005  const int numMeshes = _meshes.size();
1006  for (int n=0; n<numMeshes; n++)
1007  {
1008  const Mesh& mesh = *_meshes[n];
1009  const StorageSite& cells = mesh.getCells();
1010  const int nCells = cells.getCountLevel1();
1011  VectorT3Array& electric_field = dynamic_cast<VectorT3Array& > (_electricFields.electric_field[cells]);
1012  const PGradArray& potential_gradient = dynamic_cast<const PGradArray& > (_electricFields.potential_gradient[cells]);
1013 
1014  for(int c=0; c<nCells; c++){
1015  electric_field[c][0] = -potential_gradient[c][0];
1016  electric_field[c][1] = -potential_gradient[c][1];
1017  electric_field[c][2] = -potential_gradient[c][2];
1018  }
1019  }
1020  }
1021 
1022  /*** update electron velocity after electric_field is updated ***/
1024  {
1025  const int numMeshes = _meshes.size();
1026  for (int n=0; n<numMeshes; n++)
1027  {
1028  const Mesh& mesh = *_meshes[n];
1029  const StorageSite& cells = mesh.getCells();
1030  const int nCells = cells.getCountLevel1();
1031  const VectorT3Array& electric_field = dynamic_cast<const VectorT3Array& > (_electricFields.electric_field[cells]);
1032  VectorT3Array& electron_velocity = dynamic_cast<VectorT3Array& > (_electricFields.electron_velocity[cells]);
1033  const T electron_mobility = _constants["electron_mobility"];
1034  const T electron_saturation_velocity = _constants["electron_saturation_velocity"];
1035 
1036  // need to convert to 3D
1037  for(int c=0; c<nCells; c++){
1038  VectorT3 vel = electron_mobility * electric_field[c];
1039  if (mag(vel) < electron_saturation_velocity ){
1040  electron_velocity[c] = - electron_mobility * electric_field[c];
1041  }
1042  else {
1043  electron_velocity[c] = - electron_saturation_velocity * (electric_field[c] / mag(electric_field[c]));
1044  }
1045  }
1046  }
1047 
1048  }
1049 
1051  {
1052  const int numMeshes = _meshes.size();
1053  for (int n=0; n<numMeshes; n++)
1054  {
1055  const Mesh& mesh = *_meshes[n];
1056  const StorageSite& cells = mesh.getCells();
1057  const StorageSite& faces = mesh.getFaces();
1058  const int nFaces = faces.getCount();
1059  const VectorT3Array& vel = dynamic_cast<const VectorT3Array& > (_electricFields.electron_velocity[cells]);
1060  TArray& convFlux = dynamic_cast<TArray&> (_electricFields.convectionFlux[faces]);
1061  const VectorT3Array& faceArea = dynamic_cast<const VectorT3Array&>(_geomFields.area[faces]);
1062  const CRConnectivity& faceCells = mesh.getAllFaceCells();
1063 
1064  for ( int f=0; f<nFaces; f++){
1065  const int c0 = faceCells(f, 0);
1066  const int c1 = faceCells(f, 1);
1067  convFlux[f] = 0.5 * (dot(vel[c0], faceArea[f]) + dot(vel[c1], faceArea[f]));
1068  }
1069 
1070  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
1071  {
1072  const FaceGroup& fg = *fgPtr;
1073  const StorageSite& faces = fg.site;
1074  const int nFaces = faces.getCount();
1075  TArray& convFlux = dynamic_cast<TArray&> (_electricFields.convectionFlux[faces]);
1076  const VectorT3Array& faceArea = dynamic_cast<const VectorT3Array&>(_geomFields.area[faces]);
1077  const CRConnectivity& faceCells = mesh.getAllFaceCells();
1078  const ElectricBC<T>& bc = *_bcMap[fg.id];
1079  if(bc.bcType == "Symmetry")
1080  {
1081  convFlux.zero();
1082  }
1083  else{
1084  for(int f=0; f<nFaces; f++){
1085  const int c0 = faceCells(f,0);
1086  convFlux[f] = dot(vel[c0], faceArea[f]);
1087  }
1088 
1089  }
1090  }
1091  }
1092  }
1093 
1094  /*** Generate Band Diagram after Poisson solve is done ***/
1096  {
1097  const int numMeshes = _meshes.size();
1098  for (int n=0; n<numMeshes; n++)
1099  {
1100  const Mesh& mesh = *_meshes[n];
1101 
1102  const ElectricVC<T>& vc = *_vcMap[mesh.getID()];
1103 
1104  const StorageSite& cells = mesh.getCells();
1105 
1106  const int nCells = cells.getCountLevel1();
1107 
1108  const T& dielectric_ionization = _constants["dielectric_ionization"];
1109  const T& dielectric_bandgap = _constants["dielectric_bandgap"];
1110  const TArray& potential = dynamic_cast<const TArray& > (_electricFields.potential[cells]);
1111 
1112  TArray& conduction_band = dynamic_cast< TArray& > (_electricFields.conduction_band[cells]);
1113  TArray& valence_band = dynamic_cast< TArray& > (_electricFields.valence_band[cells]);
1114  // ??? what is 2 and 4 //
1115  if (vc.vcType == "dielectric"){
1116  for(int c=0; c<nCells; c++){
1117  conduction_band[c] = -(dielectric_ionization + potential[c]);
1118  valence_band[c] = conduction_band[c] - dielectric_bandgap;
1119  }
1120  }
1121  else if (vc.vcType == "air"){
1122  for(int c=0; c<nCells; c++){
1123  conduction_band[c] = -(dielectric_ionization + potential[c]) + 2;
1124  valence_band[c] = conduction_band[c] - dielectric_bandgap - 4;
1125  }
1126  }
1127  else
1128  throw CException(vc.vcType + " not implemented for ElectricModel");
1129  }
1130  }
1131 
1132 
1134  {
1135 
1136  /* this gives the real initial condition for charges */
1137 
1138  const T membrane_workfunction = _constants["membrane_workfunction"];
1139  const T substrate_workfunction = _constants["substrate_workfunction"];
1140  const T dielectric_thickness = _constants["dielectric_thickness"];
1141  const T optical_dielectric_constant = _constants["optical_dielectric_constant"];
1142  const T dielectric_ionization = _constants["dielectric_ionization"];
1143  const T temperature = _constants["OP_temperature"];
1144  const T electron_effmass = _constants["electron_effmass"];
1145  const T poole_frenkel_emission_frequency = _constants["poole_frenkel_emission_frequency"];
1146  const int normal = _constants["normal_direction"];
1147  const int nTrap = _constants["nTrap"];
1148  vector<T> electron_trapdensity = _constants.electron_trapdensity;
1149  vector<T> electron_trapdepth = _constants.electron_trapdepth;
1150 
1151  if (int(electron_trapdensity.size()) != nTrap || int(electron_trapdepth.size()) != nTrap){
1152  throw CException ("wrong trapdepth size!");
1153  }
1154 
1155  T effefield = (membrane_workfunction - substrate_workfunction) / dielectric_thickness;
1156 
1157  T alpha = sqrt(QE / (PI * E0_SI * optical_dielectric_constant));
1158 
1159  const int numMeshes = _meshes.size();
1160 
1161  for (int n=0; n<numMeshes; n++)
1162  {
1163  const Mesh& mesh = *_meshes[n];
1164  const ElectricVC<T>& vc = *_vcMap[mesh.getID()];
1165  if (vc.vcType == "dielectric"){
1166 
1167  const StorageSite& cells = mesh.getCells();
1168  const int nCells = cells.getCountLevel1();
1169 
1170  const VectorT3Array& cellCentroid = dynamic_cast<const VectorT3Array& > (_geomFields.coordinate[cells]);
1171 
1172  VectorTNArray& free_electron_capture_cross = dynamic_cast<VectorTNArray&> (_electricFields.free_electron_capture_cross[cells]);
1173 
1174  VectorTNArray& charge = dynamic_cast<VectorTNArray& > (_electricFields.charge[cells]);
1175 
1176  VectorTNArray& chargeN1 = dynamic_cast<VectorTNArray& > (_electricFields.chargeN1[cells]);
1177 
1178  VectorTNArray* chargeN2 = 0;
1179 
1180  if (_options.timeDiscretizationOrder > 1){
1181  chargeN2 = &(dynamic_cast<VectorTNArray& > (_electricFields.chargeN2[cells]));
1182  }
1183 
1184  for(int c=0; c<nCells; c++)
1185  {
1186 
1187  T fermilevel = -substrate_workfunction+effefield*cellCentroid[c][normal];
1188  T energy(0.);
1189 
1190  for (int i=0; i<nTrap; i++){
1191 
1192  energy = -dielectric_ionization - electron_trapdepth[i];
1193 
1194  charge[c][i] = electron_trapdensity[i] * FermiFunction(energy, fermilevel, temperature);
1195  chargeN1[c][i] = charge[c][i];
1196 
1197  if (_options.timeDiscretizationOrder > 1)
1198  (*chargeN2)[c][i] = charge[c][i];
1199 
1200  energy = -dielectric_ionization;
1201 
1202  charge[c][nTrap] += electron_trapdensity[i] * FermiFunction(energy, fermilevel, temperature);
1203  chargeN1[c][nTrap] = charge[c][nTrap];
1204 
1205 
1206  if (_options.timeDiscretizationOrder > 1)
1207  (*chargeN2)[c][nTrap] = charge[c][nTrap];
1208  }
1209 
1210  for (int i=0; i<nTrap; i++){
1211  T expt = (electron_trapdepth[i] - alpha * sqrt(fabs(effefield))) * QE / (K_SI*temperature);
1212  T beta = exp(-expt);
1213  T velocity = sqrt(8 * K_SI * temperature / (PI * ME * electron_effmass));
1214 
1215  free_electron_capture_cross[c][i] = charge[c][i] * poole_frenkel_emission_frequency * beta;
1216  free_electron_capture_cross[c][i] /= (velocity*(electron_trapdensity[i]-charge[c][i])*charge[c][nTrap]);
1217 
1218  }
1219  }
1220  }
1221  }
1222 
1223  }
1224 
1225 
1227  {
1228  typedef CRMatrixTranspose<T,T,T> IMatrix;
1229 
1230  const TArray& sP =
1231  dynamic_cast<const TArray&>(_electricFields.potential[solid]);
1232 
1233  const int numMeshes = _meshes.size();
1234  for (int n=0; n<numMeshes; n++)
1235  {
1236  const Mesh& mesh = *_meshes[n];
1237  if (!mesh.isShell() && mesh.getIBFaces().getCount() > 0)
1238  {
1239  const StorageSite& cells = mesh.getCells();
1240  const StorageSite& ibFaces = mesh.getIBFaces();
1241 
1242  GeomFields::SSPair key1(&ibFaces,&cells);
1243  const IMatrix& mIC =
1244  dynamic_cast<const IMatrix&>
1245  (*_geomFields._interpolationMatrices[key1]);
1246 
1247  GeomFields::SSPair key2(&ibFaces,&solid);
1248  const IMatrix& mIP =
1249  dynamic_cast<const IMatrix&>
1250  (*_geomFields._interpolationMatrices[key2]);
1251 
1252  shared_ptr<TArray> ibP(new TArray(ibFaces.getCount()));
1253 
1254  const TArray& cP =
1255  dynamic_cast<const TArray&>(_electricFields.potential[cells]);
1256 
1257  //const Array<T>& cellToIBCoeff = mIC.getCoeff();
1258  //const Array<T>& particlesToIBCoeff = mIP.getCoeff();
1259 
1260  ibP->zero();
1261 
1262  mIC.multiplyAndAdd(*ibP,cP);
1263  mIP.multiplyAndAdd(*ibP,sP);
1264 
1265  _electricFields.potential.addArray(ibFaces,ibP);
1266 
1267 
1268  }
1269  }
1270 
1271  }
1272 
1273 
1274  void
1275  computeSolidSurfaceForce(const StorageSite& solidFaces, bool perUnitArea)
1276  {
1277  typedef CRMatrixTranspose<T,T,T> IMatrix;
1278 
1279  const int nSolidFaces = solidFaces.getCount();
1280 
1281  updateElectricField();
1282 
1283  boost::shared_ptr<VectorT3Array>
1284  forcePtr( new VectorT3Array(nSolidFaces));
1285  VectorT3Array& force = *forcePtr;
1286 
1287  force.zero();
1288  _electricFields.force.addArray(solidFaces,forcePtr);
1289 
1290  const VectorT3Array& solidFaceArea =
1291  dynamic_cast<const VectorT3Array&>(_geomFields.area[solidFaces]);
1292 
1293  const TArray& solidFaceAreaMag =
1294  dynamic_cast<const TArray&>(_geomFields.areaMag[solidFaces]);
1295 
1296  //const VectorT3Array& solidFaceCoordinate =
1297  // dynamic_cast<const VectorT3Array&>(_geomFields.coordinate[solidFaces]);
1298 
1299 
1300  const int numMeshes = _meshes.size();
1301  for (int n=0; n<numMeshes; n++)
1302  {
1303  const Mesh& mesh = *_meshes[n];
1304  if (mesh.isShell())
1305  return;
1306  const ElectricVC<T>& vc = *_vcMap[mesh.getID()];
1307  const StorageSite& cells = mesh.getCells();
1308 
1309  const VectorT3Array& electric_field =
1310  dynamic_cast<const VectorT3Array&> (_electricFields.electric_field[cells]);
1311 
1312  const TArray& dielectric_constant =
1313  dynamic_cast<const TArray&>(_electricFields.dielectric_constant[cells]);
1314 
1315  const CRConnectivity& solidFacesToCells
1316  = mesh.getConnectivity(solidFaces,cells);
1317 
1318  const IntArray& sFCRow = solidFacesToCells.getRow();
1319  const IntArray& sFCCol = solidFacesToCells.getCol();
1320 
1321  GeomFields::SSPair key1(&solidFaces,&cells);
1322  const IMatrix& mIC = dynamic_cast<const IMatrix&>
1323  (*_geomFields._interpolationMatrices[key1]);
1324 
1325  const Array<T>& iCoeffs = mIC.getCoeff();
1326 
1327  for(int f=0; f<solidFaces.getCount(); f++)
1328  {
1329  T forceMag(0);
1330  T forceSign(1);
1331  //cout << f << endl;
1332  for(int nc = sFCRow[f]; nc<sFCRow[f+1]; nc++) {
1333  const int c = sFCCol[nc];
1334  const T coeff = iCoeffs[nc];
1335  T efmag = mag(electric_field[c]);
1336 
1337  forceSign = dot(electric_field[c], solidFaceArea[f]);
1338 
1339  if (fabs(forceSign) > 0.0)
1340  forceSign /= fabs(forceSign);
1341  else{
1342  forceSign = 0.0;
1343  }
1344  //T coeff = 0.25;
1345  forceMag += 0.5 * coeff* dielectric_constant[c] * efmag * efmag * forceSign;
1346  //cout << " " << c << " " << efmag << " " << coeff << " " << forceSign << endl;
1347  }
1348  //cout << forceMag << endl;
1349 
1350  const VectorT3& Af = solidFaceArea[f];
1351  force[f] += Af * forceMag;
1352 
1353  if (perUnitArea){
1354  force[f] /= solidFaceAreaMag[f];
1355  }
1356 
1357  }
1358 
1359  }
1360  }
1361 
1362  void printBCs()
1363  {
1364  foreach(typename ElectricBCMap::value_type& pos, _bcMap)
1365  {
1366  cout << "Face Group " << pos.first << ":" << endl;
1367  cout << " bc type " << pos.second->bcType << endl;
1368  foreach(typename ElectricBC<T>::value_type& vp, *pos.second)
1369  {
1370  cout << " " << vp.first << " " << vp.second.constant << endl;
1371  }
1372  }
1373  }
1374 
1375  T getPotentialFluxIntegral(const Mesh& mesh, const int faceGroupId)
1376  {
1377 
1378  T r(0.);
1379  bool found = false;
1380  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
1381  {
1382  const FaceGroup& fg = *fgPtr;
1383  if (fg.id == faceGroupId)
1384  {
1385  const StorageSite& faces = fg.site;
1386  const int nFaces = faces.getCount();
1387  const TArray& potentialFlux =
1388  dynamic_cast<const TArray&>(_electricFields.potential_flux[faces]);
1389  for(int f=0; f<nFaces; f++)
1390  r += potentialFlux[f];
1391  found=true;
1392  }
1393  }
1394 
1395  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
1396  {
1397  const FaceGroup& fg = *fgPtr;
1398  if (fg.id == faceGroupId)
1399  {
1400  const StorageSite& faces = fg.site;
1401  const int nFaces = faces.getCount();
1402  const TArray& potentialFlux =
1403  dynamic_cast<const TArray&>(_electricFields.potential_flux[faces]);
1404  for(int f=0; f<nFaces; f++)
1405  r += potentialFlux[f];
1406  found=true;
1407  }
1408  }
1409 
1410 
1411  if (!found)
1412  throw CException("getPotentialFluxIntegral: invalid faceGroupID");
1413  return r;
1414  }
1415 
1416  map<string,shared_ptr<ArrayBase> >&
1418  {
1419  _persistenceData.clear();
1420 
1421  Array<int>* niterArray = new Array<int>(1);
1422  (*niterArray)[0] = _niters;
1423  _persistenceData["niters"]=shared_ptr<ArrayBase>(niterArray);
1424 
1425  if (_initialElectroStaticsNorm)
1426  {
1427  _persistenceData["initialElectroStaticsNorm"] =
1428  _initialElectroStaticsNorm->getArrayPtr(_electricFields.potential);
1429  }
1430  else
1431  {
1432  Array<T>* xArray = new Array<T>(1);
1433  xArray->zero();
1434  _persistenceData["initialElectroStaticsNorm"]=shared_ptr<ArrayBase>(xArray);
1435  }
1436  return _persistenceData;
1437  }
1438 
1439  void restart()
1440  {
1441  if (_persistenceData.find("niters") != _persistenceData.end())
1442  {
1443  shared_ptr<ArrayBase> rp = _persistenceData["niters"];
1444  ArrayBase& r = *rp;
1445  Array<int>& niterArray = dynamic_cast<Array<int>& >(r);
1446  _niters = niterArray[0];
1447  }
1448  if (_persistenceData.find("initialElectroStaticsNorm") != _persistenceData.end())
1449  {
1450  shared_ptr<ArrayBase> r = _persistenceData["initialElectroStaticsNorm"];
1451  _initialElectroStaticsNorm = MFRPtr(new MultiFieldReduction());
1452  _initialElectroStaticsNorm->addArray(_electricFields.potential,r);
1453  }
1454  }
1455 
1456 
1457  vector<T> getTunnelCurrent(){
1458  vector<T> flux;
1459  flux.push_back(_tunnelCurrentIn);
1460  flux.push_back(_tunnelCurrentOut);
1461  return flux;
1462  }
1463 
1464 
1465 
1466 
1467 
1468 private:
1472 
1475 
1480 
1483  int _niters;
1487 
1488 
1489 
1490  map<string,shared_ptr<ArrayBase> > _persistenceData;
1491 };
1492 
1493 
1494 
1495 template<class T>
1497  ElectricFields& electricFields,
1498  const MeshList& meshes) :
1499  Model(meshes),
1500  _impl(new Impl(geomFields,electricFields,meshes))
1501 {
1502  logCtor();
1503 }
1504 
1505 
1506 template<class T>
1508 {
1509  logDtor();
1510 }
1511 
1512 template<class T>
1513 void
1515 {
1516  _impl->init();
1517 }
1518 
1519 /*
1520 template<class T>
1521 void
1522 ElectricModel<T>::dielectricOneDimModelPrep(const int nXCol, const int nYCol,const int nGrid,
1523  const ElectricModel<T>::VectorD3 corner1_1,
1524  const ElectricModel<T>::VectorD3 corner1_2,
1525  const ElectricModel<T>::VectorD3 corner1_3,
1526  const ElectricModel<T>::VectorD3 corner1_4,
1527  const ElectricModel<T>::VectorD3 corner2_1,
1528  const ElectricModel<T>::VectorD3 corner2_2,
1529  const ElectricModel<T>::VectorD3 corner2_3,
1530  const ElectricModel<T>::VectorD3 corner2_4)
1531 {
1532  _impl->dielectricOneDimModelPrep (nXCol, nYCol, nGrid,
1533  corner1_1, corner1_2, corner1_3, corner1_4,
1534  corner2_1, corner2_2, corner2_3, corner2_4) ;
1535 }
1536 */
1537 
1538 template<class T>
1539 void
1541 {
1542  _impl->updateTime();
1543 }
1544 
1545 template<class T>
1547 ElectricModel<T>::getBCMap() {return _impl->getBCMap();}
1548 
1549 template<class T>
1551 ElectricModel<T>::getBC(const int id) {return _impl->getBC(id);}
1552 
1553 template<class T>
1555 ElectricModel<T>::getVCMap() {return _impl->getVCMap();}
1556 
1557 template<class T>
1559 ElectricModel<T>::getVC(const int id) {return _impl->getVC(id);}
1560 
1561 template<class T>
1563 ElectricModel<T>::getOptions() {return _impl->getOptions();}
1564 
1565 template<class T>
1567 ElectricModel<T>::getConstants() {return _impl->getConstants();}
1568 
1569 template<class T>
1570 void
1572 {
1573  _impl->printBCs();
1574 }
1575 
1576 template<class T>
1577 bool
1579 {
1580  return _impl->advance(niter);
1581 }
1582 
1583 template<class T>
1584 void
1586 {
1587  _impl->calculateEquilibriumParameters();
1588 }
1589 
1590 template<class T>
1591 void
1593 {
1594  _impl->computeIBFacePotential(particles);
1595 }
1596 
1597 template<class T>
1598 void
1600 {
1601  return _impl->computeSolidSurfaceForce(particles,false);
1602 }
1603 
1604 template<class T>
1605 T
1606 ElectricModel<T>::getPotentialFluxIntegral(const Mesh& mesh, const int faceGroupId)
1607 {
1608  return _impl->getPotentialFluxIntegral(mesh, faceGroupId);
1609 }
1610 
1611 template<class T>
1612 void
1614 {
1615  return _impl->computeSolidSurfaceForce(particles,true);
1616 }
1617 
1618 template<class T>
1619 map<string,shared_ptr<ArrayBase> >&
1621 {
1622  return _impl->getPersistenceData();
1623 }
1624 
1625 template<class T>
1626 void
1628 {
1629  _impl->restart();
1630 }
1631 
1632 
1633 template<class T>
1634 vector<T>
1636 {
1637  return _impl->getTunnelCurrent();
1638 }
ElectricModelOptions< T > & getOptions()
const FaceGroupList & getBoundaryFaceGroups() const
Definition: Mesh.h:187
const Array< int > & getCol() const
virtual void zero()
Definition: Array.h:281
bool isDoubleShell() const
Definition: Mesh.h:324
const Array< int > & getRow() const
ElectricFields & _electricFields
void initAssembly()
virtual ~ElectricModel()
shared_ptr< FaceGroup > FaceGroupPtr
Definition: Mesh.h:46
#define PI
Impl(const GeomFields &geomFields, ElectricFields &electricFields, const MeshList &meshes)
Array< TensorNxN > TensorNxNArray
int getSelfCount() const
Definition: StorageSite.h:40
ElectricBCMap & getBCMap()
const StorageSite & getIBFaces() const
Definition: Mesh.h:111
ElectricModelConstants< T > & getConstants()
ElectricVCMap & getVCMap()
const CRConnectivity & getConnectivity(const StorageSite &from, const StorageSite &to) const
Definition: Mesh.cpp:416
bool advance(const int niter)
ElectricModelOptions< T > _options
map< string, shared_ptr< ArrayBase > > _persistenceData
T getPotentialFluxIntegral(const Mesh &mesh, const int faceGroupId)
ElectricVC< T > & getVC(const int id)
GradientModel< VectorTN > _chargeGradientModel
Definition: Mesh.h:28
const GeomFields & _geomFields
const T FermiFunction(const T &energy, const T &fermilevel, const T &temperature)
virtual void init()
#define K_SI
ElectricModelOptions< T > & getOptions()
ElectricVC< T > & getVC(const int id)
Array< VectorTN > VectorTNArray
map< string, shared_ptr< ArrayBase > > _persistenceData
Definition: Model.h:32
ElectricModel(const GeomFields &geomFields, ElectricFields &electricFields, const MeshList &meshes)
Definition: Mesh.h:49
T mag(const Vector< T, 3 > &a)
Definition: Vector.h:260
Array< Gradient< T > > PGradArray
vector< T > getTunnelCurrent()
#define logCtor()
Definition: RLogInterface.h:26
void calculateEquilibriumParameters()
string groupType
Definition: Mesh.h:42
T getPotentialFluxIntegral(const Mesh &mesh, const int faceGroupId)
FloatVal< T > getVal(const string varName) const
Definition: FloatVarDict.h:85
#define ME
int getOtherMeshID() const
Definition: Mesh.h:327
Tangent sqrt(const Tangent &a)
Definition: Tangent.h:317
const CRConnectivity & getAllFaceCells() const
Definition: Mesh.cpp:378
const int id
Definition: Mesh.h:41
ElectricBC< T > & getBC(const int id)
void updateSolution()
void computeIBFacePotential(const StorageSite &solid)
ElectricVCMap & getVCMap()
virtual void restart()
pair< const Field *, const StorageSite * > ArrayIndex
Definition: MultiField.h:21
string vcType
Definition: ElectricBC.h:37
Array< T > TArray
Definition: ElectricModel.h:26
Gradient< VectorTN > CGradType
#define QE
void initSolve()
ElectricBCMap & getBCMap()
vector< shared_ptr< Discretization > > DiscrList
Vector< double, 3 > VectorD3
const StorageSite & getFaces() const
Definition: Mesh.h:108
const MeshList _meshes
Definition: Model.h:29
const CRConnectivity & getCellCells() const
Definition: Mesh.cpp:480
Definition: Model.h:13
void computeIBFacePotential(const StorageSite &solid)
const StorageSite & getCells() const
Definition: Mesh.h:109
GradientModel< T > _potentialGradientModel
void initElectroStaticsLinearization(LinearSystem &ls)
void applyInterfaceBC(const int f) const
Definition: GenericBCS.h:325
void discretize(const Mesh &mesh, const Mesh &parentMesh, const Mesh &otherMesh, MultiFieldMatrix &mfmatrix, MultiField &xField, MultiField &rField)
ElectricModelConstants< T > & getConstants()
void initChargeTransportLinearization(LinearSystem &ls)
#define logDtor()
Definition: RLogInterface.h:33
int getCountLevel1() const
Definition: StorageSite.h:72
Array< VectorT3 > VectorT3Array
Definition: ElectricModel.h:29
const CRConnectivity & getFaceCells(const StorageSite &site) const
Definition: Mesh.cpp:388
std::map< int, ElectricBC< T > * > ElectricBCMap
Definition: ElectricModel.h:23
void computeSolidSurfaceForcePerUnitArea(const StorageSite &particles)
Tangent fabs(const Tangent &a)
Definition: Tangent.h:312
Definition: Array.h:14
int getParentMeshID() const
Definition: Mesh.h:326
void addMatrix(const Index &rowI, const Index &colI, shared_ptr< Matrix > m)
Vector< T, 3 > VectorT3
bool isShell() const
Definition: Mesh.h:323
Array< Gradient< VectorTN > > CGradArray
vector< T > getTunnelCurrent()
string bcType
Definition: ElectricBC.h:27
void computeSolidSurfaceForce(const StorageSite &solidFaces, bool perUnitArea)
std::map< int, ElectricVC< T > * > ElectricVCMap
Definition: ElectricModel.h:24
#define E0_SI
int getCount() const
Definition: StorageSite.h:39
MultiField & getB()
Definition: LinearSystem.h:33
virtual map< string, shared_ptr< ArrayBase > > & getPersistenceData()
shared_ptr< MultiFieldReduction > MFRPtr
void addArray(const ArrayIndex &aIndex, shared_ptr< ArrayBase > a)
Definition: MultiField.cpp:270
void linearizeElectroStatics(LinearSystem &ls)
const FaceGroupList & getInterfaceGroups() const
Definition: Mesh.h:190
ElectricBC< T > & getBC(const int id)
MultiField & getX()
Definition: LinearSystem.h:32
void linearizeChargeTransport(LinearSystem &ls)
Array< VectorT3 > VectorT3Array
bool advance(const int niter)
ElectricModelConstants< T > _constants
T dot(const Vector< T, 3 > &a, const Vector< T, 3 > &b)
Definition: Vector.h:253
void computeSolidSurfaceForce(const StorageSite &particles)
int getID() const
Definition: Mesh.h:106
Vector< T, 3 > VectorTN
map< string, shared_ptr< ArrayBase > > & getPersistenceData()
virtual void linearize(DiscrList &discretizations, const MeshList &meshes, MultiFieldMatrix &matrix, MultiField &x, MultiField &b)
Definition: Linearizer.cpp:17
void discretize(const Mesh &mesh, const Mesh &parentMesh, const Mesh &otherMesh, MultiFieldMatrix &mfmatrix, MultiField &xField, MultiField &rField)
SquareTensor< T, 3 > TensorNxN
pair< const StorageSite *, const StorageSite * > SSPair
Definition: GeomFields.h:48
MultiFieldMatrix & getMatrix()
Definition: LinearSystem.h:37
vector< Mesh * > MeshList
Definition: Mesh.h:439
StorageSite site
Definition: Mesh.h:40