Memosa-FVM  0.2
FlowModel_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 
7 #ifdef FVM_PARALLEL
8 #include <mpi.h>
9 #endif
10 
11 #include <fstream>
12 #include <sstream>
13 #include <iomanip>
14 #include <limits>
15 
16 #include "NumType.h"
17 #include "Array.h"
18 #include "Field.h"
19 #include "CRConnectivity.h"
20 #include "LinearSystem.h"
21 #include "StorageSite.h"
22 #include "MultiFieldMatrix.h"
23 #include "CRMatrix.h"
24 #include "FluxJacobianMatrix.h"
25 #include "DiagonalMatrix.h"
26 #include "GenericBCS.h"
27 #include "Vector.h"
28 #include "VectorTranspose.h"
32 #include "Underrelaxer.h"
34 #include "AMG.h"
35 #include "Linearizer.h"
36 #include "GradientModel.h"
38 #include "StressTensor.h"
39 
40 template<class T>
41 class FlowModel<T>::Impl
42 {
43 public:
44 
46 
47  typedef Array<T> TArray;
50 
53 
55  typedef typename VVMatrix::DiagArray VVDiagArray;
56 
58  typedef typename PPMatrix::DiagArray PPDiagArray;
60 
61 #ifdef PV_COUPLED
62  typedef CRMatrixRect<VectorT3T,VectorT3,T> PVMatrix;
63  typedef typename PVMatrix::DiagArray PVDiagArray;
64  typedef typename PVMatrix::PairWiseAssembler PVAssembler;
65 
66  typedef CRMatrixRect<VectorT3,T,VectorT3> VPMatrix;
67  typedef typename VPMatrix::DiagArray VPDiagArray;
68  typedef typename VPMatrix::PairWiseAssembler VPAssembler;
69 
70 #endif
71 
74 
77 
79 
82 
83  Impl(const GeomFields& geomFields,
84  FlowFields& thermalFields,
85  const MeshList& meshes):
86  _meshes(meshes),
87  _geomFields(geomFields),
88  _flowFields(thermalFields),
89  _velocityGradientModel(_meshes,_flowFields.velocity,
90  _flowFields.velocityGradient,_geomFields),
91  _pressureGradientModel(_meshes,_flowFields.pressure,
92  _flowFields.pressureGradient,_geomFields),
93  _initialMomentumNorm(),
94  _initialContinuityNorm(),
95  _niters(0)
96  {
97  const int numMeshes = _meshes.size();
98  for (int n=0; n<numMeshes; n++)
99  {
100  const Mesh& mesh = *_meshes[n];
101 
102  FlowVC<T> *vc(new FlowVC<T>());
103  vc->vcType = "flow";
104  _vcMap[mesh.getID()] = vc;
105  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
106  {
107  const FaceGroup& fg = *fgPtr;
108  if (_bcMap.find(fg.id) == _bcMap.end())
109  {
110  FlowBC<T> *bc(new FlowBC<T>());
111 
112  _bcMap[fg.id] = bc;
113  if ((fg.groupType == "wall"))
114  {
115  bc->bcType = "NoSlipWall";
116  }
117  else if ((fg.groupType == "velocity-inlet"))
118  {
119  bc->bcType = "VelocityBoundary";
120  }
121  else if ((fg.groupType == "pressure-inlet") ||
122  (fg.groupType == "pressure-outlet"))
123  {
124  bc->bcType = "PressureBoundary";
125  }
126  else if ((fg.groupType == "symmetry"))
127  {
128  bc->bcType = "Symmetry";
129  }
130  else
131  throw CException("FlowModel: unknown face group type "
132  + fg.groupType);
133  }
134  }
135  /*
136  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
137  {
138  const FaceGroup& fg = *fgPtr;
139  if ((fg.groupType == "ESinterface"))
140  { bc->bcType = "ESInterfaceBC";}
141  }
142  */
143 
144 
145  }
146  }
147 
148  void init()
149  {
150  const int numMeshes = _meshes.size();
151  for (int n=0; n<numMeshes; n++)
152  {
153  const Mesh& mesh = *_meshes[n];
154 
155  const FlowVC<T>& vc = *_vcMap[mesh.getID()];
156 
157  const StorageSite& cells = mesh.getCells();
158  const StorageSite& faces = mesh.getFaces();
159 
160  shared_ptr<VectorT3Array> vCell(new VectorT3Array(cells.getCountLevel1()));
161 
162  VectorT3 initialVelocity;
163  initialVelocity[0] = _options["initialXVelocity"];
164  initialVelocity[1] = _options["initialYVelocity"];
165  initialVelocity[2] = _options["initialZVelocity"];
166  *vCell = initialVelocity;
167 
168  _flowFields.velocity.addArray(cells,vCell);
169 
170  shared_ptr<VectorT3Array> uparallelCell(new VectorT3Array(cells.getCount()));
171  uparallelCell ->zero();
172  _flowFields.uparallel.addArray(cells,uparallelCell);
173 
174  shared_ptr<VectorT3Array> tauCell(new VectorT3Array(faces.getCount()));
175  tauCell ->zero();
176  _flowFields.tau.addArray(faces,tauCell);
177 
178  shared_ptr<VectorT3Array> TauWallCell(new VectorT3Array(faces.getCount()));
179  TauWallCell ->zero();
180  _flowFields.tauwall.addArray(faces,TauWallCell);
181 
182 
183 
184 
185 
186 
187 
188  if (_options.transient)
189  {
190  _flowFields.velocityN1.addArray(cells,
191  dynamic_pointer_cast<ArrayBase>(vCell->newCopy()));
192  if (_options.timeDiscretizationOrder > 1)
193  _flowFields.velocityN2.addArray(cells,
194  dynamic_pointer_cast<ArrayBase>(vCell->newCopy()));
195 
196  }
197 
198  shared_ptr<TArray> pCell(new TArray(cells.getCountLevel1()));
199  shared_ptr<TArray> pFace(new TArray(faces.getCountLevel1()));
200  *pCell = _options["initialPressure"];
201  *pFace = _options["initialPressure"];
202  _flowFields.pressure.addArray(cells,pCell);
203  _flowFields.pressure.addArray(faces,pFace);
204 
205 
206  shared_ptr<TArray> rhoCell(new TArray(cells.getCountLevel1()));
207  *rhoCell = vc["density"];
208  _flowFields.density.addArray(cells,rhoCell);
209 
210  shared_ptr<TArray> muCell(new TArray(cells.getCountLevel1()));
211  *muCell = vc["viscosity"];
212  _flowFields.viscosity.addArray(cells,muCell);
213 
214  shared_ptr<PGradArray> gradp(new PGradArray(cells.getCountLevel1()));
215  gradp->zero();
216  _flowFields.pressureGradient.addArray(cells,gradp);
217 
218  shared_ptr<TArray> ci(new TArray(cells.getCountLevel1()));
219  ci->zero();
220  _flowFields.continuityResidual.addArray(cells,ci);
221 
222  // compute default value of mass flux
223 
224  const VectorT3Array& faceArea =
225  dynamic_cast<const VectorT3Array&>(_geomFields.area[faces]);
226  const VectorT3Array& V = *vCell;
227  const TArray& density = *rhoCell;
228 
229  const CRConnectivity& faceCells = mesh.getAllFaceCells();
230 
231  const int nFaces = faces.getCount();
232 
233  shared_ptr<TArray> mfPtr(new TArray(faces.getCount()));
234  TArray& mf = *mfPtr;
235 
236  for(int f=0; f<nFaces; f++)
237  {
238  const int c0 = faceCells(f,0);
239  const int c1 = faceCells(f,1);
240 
241  mf[f] = 0.5*(density[c0]*dot(V[c0],faceArea[f]) +
242  density[c1]*dot(V[c1],faceArea[f]));
243  }
244  _flowFields.massFlux.addArray(faces,mfPtr);
245 
246  // store momentum flux at interfaces
247  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
248  {
249  const FaceGroup& fg = *fgPtr;
250  const StorageSite& faces = fg.site;
251  shared_ptr<VectorT3Array> momFlux(new VectorT3Array(faces.getCount()));
252  momFlux->zero();
253  _flowFields.momentumFlux.addArray(faces,momFlux);
254 
255  if(fg.groupType == "ESinterface"){
256  cout << "interface init" <<endl;
257  const StorageSite& Intfaces = fg.site;
258 
259  shared_ptr<VectorT3Array> InterfaceVelFace(new VectorT3Array(Intfaces.getCount()));
260  InterfaceVelFace ->zero();
261  _flowFields.InterfaceVelocity.addArray(Intfaces,InterfaceVelFace);
262 
263  shared_ptr<StressTensorArray> InterfaceStressFace(new StressTensorArray(Intfaces.getCount()));
264  InterfaceStressFace ->zero();
265  _flowFields.InterfaceStress.addArray(Intfaces,InterfaceStressFace);
266 
267  shared_ptr<TArray> InterfacePressFace(new TArray(Intfaces.getCount()));
268  *InterfacePressFace = _options["initialPressure"];
269  _flowFields.InterfacePressure.addArray(Intfaces,InterfacePressFace);
270 
271  shared_ptr<TArray> InterfaceDensityFace(new TArray(Intfaces.getCount()));
272  *InterfaceDensityFace =vc["density"];
273  _flowFields.InterfaceDensity.addArray(Intfaces,InterfaceDensityFace);
274 
275 
276  }
277 
278 
279  }
280 
281  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
282  {
283  const FaceGroup& fg = *fgPtr;
284  const StorageSite& faces = fg.site;
285 
286  const FlowBC<T>& bc = *_bcMap[fg.id];
287 
289  bVelocity(bc.getVal("specifiedXVelocity"),
290  bc.getVal("specifiedYVelocity"),
291  bc.getVal("specifiedZVelocity"),
292  faces);
293 
294  const int nFaces = faces.getCount();
295  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
296 
297  if ((bc.bcType == "NoSlipWall") ||
298  (bc.bcType == "SlipJump") ||
299  (bc.bcType == "VelocityBoundary"))
300  {
301  // arrays for this face group
302  TArray& massFlux = dynamic_cast<TArray&>(_flowFields.massFlux[faces]);
303 
304  const VectorT3Array& faceArea =
305  dynamic_cast<const VectorT3Array&>(_geomFields.area[faces]);
306 
307  for(int f=0; f<nFaces; f++)
308  {
309  const int c0 = faceCells(f,0);
310  massFlux[f] = density[c0]*dot(bVelocity[f],faceArea[f]);
311  }
312  }
313  else if (bc.bcType == "SpecifiedPressure")
314  {
315  T bp = bc["specifiedPressure"];
316  TArray& facePressure = dynamic_cast<TArray&>(_flowFields.pressure[faces]);
317  TArray& cellPressure = dynamic_cast<TArray&>(_flowFields.pressure[cells]);
318  for(int f=0; f<nFaces; f++)
319  {
320  const int c1 = faceCells(f,1);
321  facePressure[f] = cellPressure[c1] = bp;
322  }
323  }
324  else if ((bc.bcType == "Symmetry"))
325  {
326  TArray& massFlux = dynamic_cast<TArray&>(_flowFields.massFlux[faces]);
327  massFlux.zero();
328  }
329  shared_ptr<VectorT3Array> momFlux(new VectorT3Array(faces.getCount()));
330  momFlux->zero();
331  _flowFields.momentumFlux.addArray(faces,momFlux);
332 
333 
334 
335  }
336  }
337 
338  computeContinuityResidual();
339  _niters =0;
340  _initialMomentumNorm = MFRPtr();
341  _initialContinuityNorm = MFRPtr();
342  }
343 
344  FlowBCMap& getBCMap() {return _bcMap;}
345  FlowVCMap& getVCMap() {return _vcMap;}
346  FlowModelOptions<T>& getOptions() {return _options;}
347 
348  void updateTime()
349  {
350  const int numMeshes = _meshes.size();
351  for (int n=0; n<numMeshes; n++)
352  {
353  const Mesh& mesh = *_meshes[n];
354 
355  const StorageSite& cells = mesh.getCells();
356  VectorT3Array& v =
357  dynamic_cast<VectorT3Array&>(_flowFields.velocity[cells]);
358  VectorT3Array& vN1 =
359  dynamic_cast<VectorT3Array&>(_flowFields.velocityN1[cells]);
360 
361  if (_options.timeDiscretizationOrder > 1)
362  {
363  VectorT3Array& vN2 =
364  dynamic_cast<VectorT3Array&>(_flowFields.velocityN2[cells]);
365  vN2 = vN1;
366  }
367  vN1 = v;
368  }
369  }
370  const Field& getViscosityField() const
371  {
372  if (_options.turbulent)
373  return _flowFields.totalviscosity;
374  else
375  return _flowFields.viscosity;
376  }
377 
378  void computeIBFaceVelocity(const StorageSite& particles)
379  {
380  typedef CRMatrixTranspose<T,T,T> IMatrix;
381  typedef CRMatrixTranspose<T,VectorT3,VectorT3> IMatrixV3;
382 
383  const VectorT3Array& pV =
384  dynamic_cast<const VectorT3Array&>(_flowFields.velocity[particles]);
385 
386  const int numMeshes = _meshes.size();
387  for (int n=0; n<numMeshes; n++)
388  {
389  const Mesh& mesh = *_meshes[n];
390  if (!mesh.isShell() && mesh.getIBFaces().getCount() > 0){
391 
392  const StorageSite& cells = mesh.getCells();
393  const StorageSite& ibFaces = mesh.getIBFaces();
394 
395  GeomFields::SSPair key1(&ibFaces,&cells);
396  const IMatrix& mIC =
397  dynamic_cast<const IMatrix&>
398  (*_geomFields._interpolationMatrices[key1]);
399 
400  IMatrixV3 mICV(mIC);
401 
402 
403  GeomFields::SSPair key2(&ibFaces,&particles);
404  const IMatrix& mIP =
405  dynamic_cast<const IMatrix&>
406  (*_geomFields._interpolationMatrices[key2]);
407 
408  IMatrixV3 mIPV(mIP);
409 
410 
411  shared_ptr<VectorT3Array> ibV(new VectorT3Array(ibFaces.getCount()));
412 
413  const VectorT3Array& cV =
414  dynamic_cast<const VectorT3Array&>(_flowFields.velocity[cells]);
415 
416 
417  ibV->zero();
418 
419  mICV.multiplyAndAdd(*ibV,cV);
420  mIPV.multiplyAndAdd(*ibV,pV);
421 
422 #if 0
423  ofstream debugFile;
424  stringstream ss(stringstream::in | stringstream::out);
425  ss << MPI::COMM_WORLD.Get_rank();
426  string fname1 = "IBVelocity_proc" + ss.str() + ".dat";
427  debugFile.open(fname1.c_str());
428 
429  //debug use
430  const Array<int>& ibFaceList = mesh.getIBFaceList();
431  const StorageSite& faces = mesh.getFaces();
432  const VectorT3Array& faceCentroid =
433  dynamic_cast<const VectorT3Array&> (_geomFields.coordinate[faces]);
434  const double angV = 1.0;
435  VectorT3 center;
436  center[0]=0.;
437  center[1]=0.;
438  center[2]=0.;
439 
440  for(int f=0; f<ibFaces.getCount();f++){
441  int fID = ibFaceList[f];
442  debugFile << "f=" << f << setw(10) << " fID = " << fID << " faceCentroid = " << faceCentroid[fID] << " ibV = " << (*ibV)[f] << endl;
443  }
444 
445  debugFile.close();
446 #endif
447 
448 
449  _flowFields.velocity.addArray(ibFaces,ibV);
450 
451  }
452  }
453 
454  }
455 
456  map<string,shared_ptr<ArrayBase> >&
458  {
459  _persistenceData.clear();
460 
461  Array<int>* niterArray = new Array<int>(1);
462  (*niterArray)[0] = _niters;
463  _persistenceData["niters"]=shared_ptr<ArrayBase>(niterArray);
464 
465  if (_initialMomentumNorm)
466  {
467  _persistenceData["initialMomentumNorm"] =
468  _initialMomentumNorm->getArrayPtr(_flowFields.velocity);
469  }
470  else
471  {
472  Array<Vector<T,3> >* xArray = new Array<Vector<T,3> >(1);
473  xArray->zero();
474  _persistenceData["initialMomentumNorm"]=shared_ptr<ArrayBase>(xArray);
475 
476  }
477 
478  if (_initialContinuityNorm)
479  {
480  _persistenceData["initialContinuityNorm"] =
481  _initialContinuityNorm->getArrayPtr(_flowFields.pressure);
482  }
483  else
484  {
485  Array<T>* xArray = new Array<T>(1);
486  xArray->zero();
487  _persistenceData["initialContinuityNorm"]=shared_ptr<ArrayBase>(xArray);
488  }
489  return _persistenceData;
490  }
491 
492  void restart()
493  {
494  if (_persistenceData.find("niters") != _persistenceData.end())
495  {
496  shared_ptr<ArrayBase> rp = _persistenceData["niters"];
497  ArrayBase& r = *rp;
498  Array<int>& niterArray = dynamic_cast<Array<int>& >(r);
499  _niters = niterArray[0];
500  }
501 
502  if (_persistenceData.find("initialMomentumNorm") != _persistenceData.end())
503  {
504  shared_ptr<ArrayBase> r = _persistenceData["initialMomentumNorm"];
505  _initialMomentumNorm = MFRPtr(new MultiFieldReduction());
506  _initialMomentumNorm->addArray(_flowFields.velocity,r);
507  }
508 
509  if (_persistenceData.find("initialContinuityNorm") != _persistenceData.end())
510  {
511  shared_ptr<ArrayBase> r = _persistenceData["initialContinuityNorm"];
512  _initialContinuityNorm = MFRPtr(new MultiFieldReduction());
513  _initialContinuityNorm->addArray(_flowFields.pressure,r);
514  }
515 
516  computeContinuityResidual();
517 
518  }
519 
520 
521 
523  {
524  const int numMeshes = _meshes.size();
525  for (int n=0; n<numMeshes; n++)
526  {
527  const Mesh& mesh = *_meshes[n];
528 
529  const StorageSite& cells = mesh.getCells();
530  MultiField::ArrayIndex vIndex(&_flowFields.velocity,&cells);
531 
532  ls.getX().addArray(vIndex,_flowFields.velocity.getArrayPtr(cells));
533 
534  const CRConnectivity& cellCells = mesh.getCellCells();
535 
536  shared_ptr<Matrix> m(new CRMatrix<DiagTensorT3,T,VectorT3>(cellCells));
537 
538  ls.getMatrix().addMatrix(vIndex,vIndex,m);
539 
540  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
541  {
542  const FaceGroup& fg = *fgPtr;
543  const StorageSite& faces = fg.site;
544 
545  MultiField::ArrayIndex fIndex(&_flowFields.momentumFlux,&faces);
546  ls.getX().addArray(fIndex,_flowFields.momentumFlux.getArrayPtr(faces));
547 
548  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
549 
550  shared_ptr<Matrix> mft(new FluxJacobianMatrix<DiagTensorT3,VectorT3>(faceCells));
551  ls.getMatrix().addMatrix(fIndex,vIndex,mft);
552 
553  shared_ptr<Matrix> mff(new DiagonalMatrix<DiagTensorT3,VectorT3>(faces.getCount()));
554  ls.getMatrix().addMatrix(fIndex,fIndex,mff);
555  }
556 
557  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
558  {
559  const FaceGroup& fg = *fgPtr;
560  const StorageSite& faces = fg.site;
561 
562  MultiField::ArrayIndex fIndex(&_flowFields.momentumFlux,&faces);
563  ls.getX().addArray(fIndex,_flowFields.momentumFlux.getArrayPtr(faces));
564 
565  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
566 
567  shared_ptr<Matrix> mft(new FluxJacobianMatrix<DiagTensorT3,VectorT3>(faceCells));
568  ls.getMatrix().addMatrix(fIndex,vIndex,mft);
569 
570  shared_ptr<Matrix> mff(new DiagonalMatrix<DiagTensorT3,VectorT3>(faces.getCount()));
571  ls.getMatrix().addMatrix(fIndex,fIndex,mff);
572  }
573  }
574  }
575 
577  {
578  _velocityGradientModel.compute();
579 
580  DiscrList discretizations;
581  shared_ptr<Discretization>
583  (_meshes,_geomFields,
584  _flowFields.velocity,
585  getViscosityField(),
586  _flowFields.velocityGradient));
587 
588  shared_ptr<Discretization>
590  (_meshes,_geomFields,
591  _flowFields.velocity,
592  _flowFields.massFlux,
593  _flowFields.continuityResidual,
594  _flowFields.velocityGradient));
595 
596  shared_ptr<Discretization>
598  (_meshes,_geomFields,
599  _flowFields,
600  _pressureGradientModel));
601 
602  discretizations.push_back(dd);
603  discretizations.push_back(cd);
604  discretizations.push_back(pd);
605 
606  if (_options.transient)
607  {
608  shared_ptr<Discretization>
610  (_meshes,_geomFields,
611  _flowFields.velocity,
612  _flowFields.velocityN1,
613  _flowFields.velocityN2,
614  _flowFields.density,
615  _options["timeStep"]));
616 
617  discretizations.push_back(td);
618  }
619 
620 
621  shared_ptr<Discretization>
623  (_meshes,_geomFields,_flowFields.velocity));
624 
625  discretizations.push_back(ibm);
626  Linearizer linearizer;
627 
628  linearizer.linearize(discretizations,_meshes,ls.getMatrix(),
629  ls.getX(), ls.getB());
630 
631  const int numMeshes = _meshes.size();
632  for (int n=0; n<numMeshes; n++)
633  {
634  const Mesh& mesh = *_meshes[n];
635 
636  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
637  {
638  const FaceGroup& fg = *fgPtr;
639  const StorageSite& faces = fg.site;
640  const int nFaces = faces.getCount();
641 
642  const FlowBC<T>& bc = *_bcMap[fg.id];
643 
644 
646  _geomFields,
647  _flowFields.velocity,
648  _flowFields.momentumFlux,
649  ls.getMatrix(),
650  ls.getX(),
651  ls.getB());
652 
653  const TArray& massFlux = dynamic_cast<const TArray&>(_flowFields.massFlux[faces]);
654  // const CRConnectivity& faceCells = mesh.getFaceCells(faces);
655 
657  bVelocity(bc.getVal("specifiedXVelocity"),
658  bc.getVal("specifiedYVelocity"),
659  bc.getVal("specifiedZVelocity"),
660  faces);
661 
662  if (bc.bcType == "NoSlipWall")
663  {
664  gbc.applyDirichletBC(bVelocity);
665  }
666  else if (bc.bcType == "SlipJump")
667  {
668  slipJumpMomentumBC(faces,mesh,
669  gbc,
670  bc["accomodationCoefficient"],
671  bVelocity);
672  }
673  else if ((bc.bcType == "VelocityBoundary") ||
674  (bc.bcType == "PressureBoundary"))
675  {
676  for(int f=0; f<nFaces; f++)
677  {
678  if (massFlux[f] > 0.)
679  {
680  gbc.applyExtrapolationBC(f);
681  }
682  else
683  {
684  gbc.applyDirichletBC(f,bVelocity[f]);
685  }
686  }
687  if (bc.bcType == "PressureBoundary")
688  {
689  fixedPressureMomentumBC(faces,mesh,
690  ls.getMatrix(), ls.getX(), ls.getB());
691  }
692  }
693  else if ((bc.bcType == "Symmetry"))
694  {
695  gbc.applySymmetryBC();
696  }
697 
698  else
699  throw CException(bc.bcType + " not implemented for FlowModel");
700  }
701 
702  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
703  {
704  const FaceGroup& fg = *fgPtr;
705  const StorageSite& faces = fg.site;
707  _geomFields,
708  _flowFields.velocity,
709  _flowFields.momentumFlux,
710  ls.getMatrix(), ls.getX(), ls.getB());
711 
712  gbc.applyInterfaceBC();
713  }
714 
715  }
716  DiscrList discretizations2;
717  shared_ptr<Discretization>
719  (_meshes,_flowFields.velocity,
720  _options["momentumURF"]));
721 
722  discretizations2.push_back(ud);
723 
724  linearizer.linearize(discretizations2,_meshes,ls.getMatrix(),
725  ls.getX(), ls.getB());
726 
727  }
728 
729 
731  {
732  LinearSystem ls;
733 
734  initMomentumLinearization(ls);
735  ls.initAssembly();
736  linearizeMomentum(ls);
737  ls.initSolve();
738 
739 
740  // save current velocity for use in continuity discretization
741  _previousVelocity = dynamic_pointer_cast<Field>(_flowFields.velocity.newCopy());
742 
743  //AMG solver(ls);
744  MFRPtr rNorm = _options.getMomentumLinearSolver().solve(ls);
745 
746  if (!_initialMomentumNorm) _initialMomentumNorm = rNorm;
747 
748  _options.getMomentumLinearSolver().cleanup();
749 
750  ls.postSolve();
751 
752  ls.updateSolution();
753 
754  // save the momentum ap coeffficients for use in continuity discretization
755  _momApField = shared_ptr<Field>(new Field("momAp"));
756  const int numMeshes = _meshes.size();
757  for (int n=0; n<numMeshes; n++)
758  {
759  const Mesh& mesh = *_meshes[n];
760 
761  const StorageSite& cells = mesh.getCells();
762  MultiField::ArrayIndex vIndex(&_flowFields.velocity,&cells);
763  const VVMatrix& vvMatrix =
764  dynamic_cast<const VVMatrix&>(ls.getMatrix().getMatrix(vIndex,vIndex));
765  const VVDiagArray& momAp = vvMatrix.getDiag();
766  _momApField->addArray(cells,dynamic_pointer_cast<ArrayBase>(momAp.newCopy()));
767  }
768  _momApField->syncLocal();
769  return rNorm;
770  }
771 
772 
773 
774  void interfaceContinuityBC(const Mesh& mesh,
775  const StorageSite& faces,
776  MultiFieldMatrix& matrix,
777  MultiField& rField)
778  {
779  const StorageSite& cells = mesh.getCells();
780  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
781  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
782 
783  TArray& rCell = dynamic_cast<TArray&>(rField[pIndex]);
784 
785  const int nFaces = faces.getCount();
786 
787  for(int f=0; f<nFaces; f++)
788  {
789  int c0 = faceCells(f,0);
790  int c1 = faceCells(f,1);
791  // either c0 or c1 could be the exterior cell
792  if (c1 >= cells.getSelfCount())
793  {
794  rCell[c1] = 0;
795  }
796  else
797  {
798  rCell[c0] = 0;
799  }
800  }
801  }
802 
803 
804  void correctVelocityBoundary(const Mesh& mesh,
805  const StorageSite& faces,
806  const MultiField& ppField)
807  {
808  const StorageSite& cells = mesh.getCells();
809 
810  const VectorT3Array& faceArea = dynamic_cast<const VectorT3Array&>(_geomFields.area[faces]);
811 
812  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
813 
814  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
815  MultiField::ArrayIndex vIndex(&_flowFields.velocity,&cells);
816  const VVDiagArray& momAp = dynamic_cast<const VVDiagArray&>((*_momApField)[cells]);
817 
818  VectorT3Array& V = dynamic_cast<VectorT3Array&>(_flowFields.velocity[cells]);
819  const TArray& pp = dynamic_cast<const TArray&>(ppField[pIndex]);
820 
821  const int nFaces = faces.getCount();
822  for(int f=0; f<nFaces; f++)
823  {
824  const int c0 = faceCells(f,0);
825  const int c1 = faceCells(f,1);
826 
827  const T ppFace = pp[c1];
828  const VectorT3 ppA = ppFace*faceArea[f];
829 
830  V[c0] += ppA/momAp[c0];
831  }
832  }
833 
834 
836  const MultiField& ppField)
837  {
838  MultiField::ArrayIndex mfIndex(&_flowFields.massFlux,&faces);
839  const TArray& dMassFlux = dynamic_cast<const TArray&>(ppField[mfIndex]);
840  TArray& massFlux = dynamic_cast<TArray&>(_flowFields.massFlux[faces]);
841 
842  const int nFaces = faces.getCount();
843  for(int f=0; f<nFaces; f++)
844  {
845  massFlux[f] -= dMassFlux[f];
846  }
847  }
848 
849  void correctPressure(const Mesh& mesh,
850  const MultiField& xField)
851  {
852  const StorageSite& cells = mesh.getCells();
853  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
854 
855  TArray& p = dynamic_cast<TArray&>(_flowFields.pressure[cells]);
856  const TArray& pp = dynamic_cast<const TArray&>(xField[pIndex]);
857 
858  const T pressureURF(_options["pressureURF"]);
859 
860  const int nCells = cells.getCountLevel1();
861  for(int c=0; c<nCells; c++)
862  {
863  p[c] += pressureURF*(pp[c]-_referencePP);
864  }
865  }
866 
867 
868  void correctVelocityExplicit(const Mesh& mesh,
869  const MultiField& xField)
870  {
871  const StorageSite& cells = mesh.getCells();
872  MultiField::ArrayIndex vIndex(&_flowFields.velocity,&cells);
873 
874  VectorT3Array& V = dynamic_cast<VectorT3Array&>(_flowFields.velocity[cells]);
875  const VectorT3Array& Vp = dynamic_cast<const VectorT3Array&>(xField[vIndex]);
876 
877  const T velocityURF(_options["velocityURF"]);
878 
879  const int nCells = cells.getCountLevel1();
880  for(int c=0; c<nCells; c++)
881  {
882  V[c] += velocityURF*Vp[c];
883  }
884 
885  // boundary
886  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
887  {
888  const FaceGroup& fg = *fgPtr;
889  const StorageSite& faces = fg.site;
890  MultiField::ArrayIndex fluxIndex(&_flowFields.momentumFlux,&faces);
891  VectorT3Array& momFlux =
892  dynamic_cast<VectorT3Array&>(_flowFields.momentumFlux[faces]);
893  const VectorT3Array& dmomFlux =
894  dynamic_cast<const VectorT3Array&>(xField[fluxIndex]);
895 
896  const int nFaces = faces.getCount();
897  for(int f=0; f<nFaces; f++)
898  {
899  momFlux[f] += dmomFlux[f];
900  }
901  }
902  }
903 
904 
905  // set the first cell of the first mesh to be a Dirichlet point
907  MultiField& rField)
908  {
909  const Mesh& mesh = *_meshes[0];
910 
911  const StorageSite& cells = mesh.getCells();
912  const IntArray& ibType = dynamic_cast<const IntArray&>(_geomFields.ibType[cells]);
913 
914  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
915  MultiField::ArrayIndex vIndex(&_flowFields.velocity,&cells);
916 
917  PPMatrix& ppMatrix =
918  dynamic_cast<PPMatrix&>(mfmatrix.getMatrix(pIndex,pIndex));
919 
920  PPDiagArray& ppDiag = ppMatrix.getDiag();
921  PPDiagArray& ppCoeff = ppMatrix.getOffDiag();
922 
923  TArray& rCell = dynamic_cast<TArray&>(rField[pIndex]);
924 
925  const CRConnectivity& cr = ppMatrix.getConnectivity();
926 
927  const Array<int>& row = cr.getRow();
928 
929  const int nCells = cells.getSelfCount();
930 
931 #ifdef FVM_PARALLEL
932  const Array<int>& localToGlobal = mesh.getLocalToGlobal();
933 #endif
934 
935  _globalRefCellID = numeric_limits<int>::max();
936  for ( int n = 0; n < nCells; n++ )
937  {
938  if ( ibType[n] == Mesh::IBTYPE_FLUID )
939  {
940 #ifdef FVM_PARALLEL
941  int glblIndx = localToGlobal[n];
942 #else
943  int glblIndx = n;
944 #endif
945 
946  if ( glblIndx < _globalRefCellID )
947  _globalRefCellID = glblIndx;
948  }
949  }
950 
951 #ifdef FVM_PARALLEL
952  MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &_globalRefCellID, 1, MPI::INT, MPI::MIN);
953 
954 
955  _globalRefProcID = -1;
956  const map<int,int>& globalToLocal = mesh.getGlobalToLocal();
957 
958  if ( globalToLocal.count(_globalRefCellID) > 0 ){
959  _globalRefProcID = MPI::COMM_WORLD.Get_rank();
960  }
961  MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &_globalRefProcID, 1, MPI::INT, MPI::MAX);
962 
963 
964  if ( globalToLocal.count(_globalRefCellID) > 0)
965  {
966  int nc = globalToLocal.find(_globalRefCellID)->second;
967 
968 #else
969  int nc = _globalRefCellID;
970 #endif
971 
972  ppDiag[nc] = -1.;
973  rCell[nc]=0.;
974  for(int nb=row[nc]; nb<row[nc+1]; nb++)
975  ppCoeff[nb] = 0;
976 #ifdef PV_COUPLED
977  if (mfmatrix.hasMatrix(pIndex,vIndex))
978  {
979  PVMatrix& pvMatrix =
980  dynamic_cast<PVMatrix&>(mfmatrix.getMatrix(pIndex,vIndex));
981 
982  PVDiagArray& pvDiag = pvMatrix.getDiag();
983  PVDiagArray& pvCoeff = pvMatrix.getOffDiag();
984 
985  pvDiag[nc] = NumTypeTraits<VectorT3>::getZero();
986  for(int nb=row[nc]; nb<row[nc+1]; nb++)
987  pvCoeff[nb] = NumTypeTraits<VectorT3>::getZero();
988  }
989 #endif
990 
991 #ifdef FVM_PARALLEL
992  }
993 #endif
994  }
995 
996 
997 
999  {
1000  MultiFieldMatrix& matrix = ls.getMatrix();
1001  MultiField& x = ls.getX();
1002  MultiField& b = ls.getB();
1003 
1004 
1005  this->_useReferencePressure = true;
1006  const int numMeshes = _meshes.size();
1007 
1008  T netFlux(0.);
1009 
1010 
1011  _flowFields.pressureGradient.syncLocal();
1012 
1013 
1014  for (int n=0; n<numMeshes; n++)
1015  {
1016  const Mesh& mesh = *_meshes[n];
1017  const StorageSite& cells = mesh.getCells();
1018  const StorageSite& iFaces = mesh.getInteriorFaceGroup().site;
1019 
1020  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
1021 
1022  // interior
1023 
1024  netFlux += discretizeMassFluxInterior(mesh,iFaces,matrix,x,b);
1025 
1026  // interfaces
1027  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
1028  {
1029  const FaceGroup& fg = *fgPtr;
1030  const StorageSite& faces = fg.site;
1031  netFlux += discretizeMassFluxInterior(mesh,faces,matrix,x,b);
1032 
1033  // this just sets the residual for the ghost cell to zero
1034  interfaceContinuityBC(mesh,faces,matrix,b);
1035  }
1036 
1037  // boundaries
1038  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
1039  {
1040  const FaceGroup& fg = *fgPtr;
1041  const StorageSite& faces = fg.site;
1042 
1043  const FlowBC<T>& bc = *_bcMap[fg.id];
1044 
1045  if ((bc.bcType == "NoSlipWall") ||
1046  (bc.bcType == "SlipJump") ||
1047  (bc.bcType == "Symmetry") ||
1048  (bc.bcType == "VelocityBoundary"))
1049  {
1050 
1051  netFlux += fixedFluxContinuityBC(faces,mesh,matrix,x,b,bc);
1052  }
1053  else if (bc.bcType == "PressureBoundary")
1054  {
1055  netFlux += fixedPressureContinuityBC(faces,mesh,matrix,x,b);
1056  this->_useReferencePressure=false;
1057  }
1058  else
1059  throw CException(bc.bcType + " not implemented for FlowModel");
1060 
1061  MultiField::ArrayIndex mfIndex(&_flowFields.massFlux,&faces);
1062  typedef DiagonalMatrix<T,T> FFMatrix;
1063  FFMatrix& dFluxdFlux =
1064  dynamic_cast<FFMatrix&>(matrix.getMatrix(mfIndex,mfIndex));
1065  dFluxdFlux.unitize();
1066  }
1067 
1068  // add additional imbalance to netFlux due to transient term
1069  // when we have deforming mesh
1070  if (_geomFields.volumeN1.hasArray(cells))
1071  {
1072 
1073  // this block computes the net sum of d(rho)/dt over all the cells
1074  const TArray& density =
1075  dynamic_cast<const TArray&>(_flowFields.density[cells]);
1076  const TArray& cellVolume =
1077  dynamic_cast<const TArray&>(_geomFields.volume[cells]);
1078  const int nCells = cells.getSelfCount();
1079  T _dT(_options["timeStep"]);
1080  T onePointFive(1.5);
1081  T two(2.0);
1082  T pointFive(0.5);
1083 
1084  const TArray& cellVolumeN1 =
1085  dynamic_cast<const TArray&>(_geomFields.volumeN1[cells]);
1086 
1087  if (_geomFields.volumeN2.hasArray(cells))
1088  {
1089  // second order time discretization
1090 
1091  const TArray& cellVolumeN2 =
1092  dynamic_cast<const TArray&>(_geomFields.volumeN2[cells]);
1093  for(int c=0; c<nCells; c++)
1094  {
1095  const T rhobydT = density[c]/_dT;
1096  const T term1 = onePointFive*cellVolume[c];
1097  const T term2 = two*cellVolumeN1[c];
1098  const T term3 = pointFive*cellVolumeN2[c];
1099  netFlux -= rhobydT*(term1 - term2 + term3);
1100  }
1101  }
1102  else
1103  {
1104  // first order time discretization
1105  for(int c=0; c<nCells; c++)
1106  {
1107  const T rhobydT = density[c]/_dT;
1108  netFlux -= rhobydT*(cellVolume[c] - cellVolumeN1[c]);
1109  }
1110  }
1111 
1112  // compute the net integral of the grid flux term
1113  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
1114  {
1115  const FaceGroup& fg = *fgPtr;
1116  const StorageSite& faces = fg.site;
1117  const int nFaces = faces.getCount();
1118  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
1119  const VectorT3Array& faceArea =
1120  dynamic_cast<const VectorT3Array&>(_geomFields.area[faces]);
1121  const VectorT3Array& faceVel =
1122  dynamic_cast<const VectorT3Array&>(_geomFields.faceVel[faces]);
1123  for(int f=0; f<nFaces; f++)
1124  {
1125  const int c0 = faceCells(f,0);
1126  netFlux += density[c0]*dot(faceVel[f],faceArea[f]);
1127  }
1128  }
1129  }
1130  }
1131 
1132 
1133  //sum netflux globalally MPI::
1134 #ifdef FVM_PARALLEL
1135  int count = 1;
1136  MPI::COMM_WORLD.Allreduce( MPI::IN_PLACE, &netFlux, count, MPI::DOUBLE, MPI::SUM);
1137 
1138  int useReferencePressureInt = int(this->_useReferencePressure );
1139  MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &useReferencePressureInt, count, MPI::INT, MPI::PROD);
1140  this->_useReferencePressure = bool(useReferencePressureInt);
1141 #endif
1142  //cout << "net boundary flux = " << netFlux << endl;
1143 
1144  if (this->_useReferencePressure)
1145  {
1146  // we have all fixed mass flux boundary problem. In case the
1147  // net mass flux sum over all the boundaries does not add up
1148  // to zero we distribute that over the cells as a volumetric
1149  // as a matching source/sink so that the continuity equation
1150  // can converge to a zero residual. In case of immersed
1151  // boundary problems we need to use only the fluid cells since
1152  // all the other cells will always have zero corrections.
1153 
1154  T volumeSum(0.);
1155 
1156  for (int n=0; n<numMeshes; n++)
1157  {
1158  const Mesh& mesh = *_meshes[n];
1159  const StorageSite& cells = mesh.getCells();
1160  const IntArray& ibType = dynamic_cast<const IntArray&>(_geomFields.ibType[cells]);
1161  const TArray& cellVolume = dynamic_cast<const TArray&>(_geomFields.volume[cells]);
1162  for(int c=0; c<cells.getSelfCount(); c++)
1163  if (ibType[c] == Mesh::IBTYPE_FLUID)
1164  volumeSum += cellVolume[c];
1165  }
1166 
1167 #ifdef FVM_PARALLEL
1168  MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &volumeSum, 1, MPI::DOUBLE, MPI::SUM);
1169 #endif
1170 
1171  netFlux /= volumeSum;
1172 
1173  for (int n=0; n<numMeshes; n++)
1174  {
1175  const Mesh& mesh = *_meshes[n];
1176  const StorageSite& cells = mesh.getCells();
1177  const IntArray& ibType = dynamic_cast<const IntArray&>(_geomFields.ibType[cells]);
1178  const TArray& cellVolume = dynamic_cast<const TArray&>(_geomFields.volume[cells]);
1179 
1180  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
1181  TArray& rCell = dynamic_cast<TArray&>(b[pIndex]);
1182 
1183  for(int c=0; c<cells.getSelfCount(); c++)
1184  {
1185  if (ibType[c] == Mesh::IBTYPE_FLUID)
1186  rCell[c] += netFlux*cellVolume[c];
1187  }
1188  }
1189 
1190  // when all the mass fluxes are specified the continuity
1191  // equation also has an extra degree of freedom. This sets the
1192  // first cell to have a zero correction to account for this.
1193 
1194 
1195  setDirichlet(matrix,b);
1196 
1197  }
1198  }
1199 
1200  void setReferencePP(const MultiField& ppField)
1201  {
1202  if (_useReferencePressure)
1203  {
1204  const Mesh& mesh = *_meshes[0];
1205 
1206  const StorageSite& cells = mesh.getCells();
1207 
1208  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
1209  const TArray& pp = dynamic_cast<const TArray&>(ppField[pIndex]);
1210 
1211 #ifndef FVM_PARALLEL
1212  _referencePP = pp[_globalRefCellID];
1213 #endif
1214 
1215 
1216 #ifdef FVM_PARALLEL
1217  _referencePP = 0.0;
1218  const map<int,int>& globalToLocal = mesh.getGlobalToLocal();
1219  if ( MPI::COMM_WORLD.Get_rank() == _globalRefProcID ){
1220  int localID = globalToLocal.find(_globalRefCellID)->second;
1221  _referencePP = pp[localID];
1222  }
1223 
1224  int count = 1;
1225  MPI::COMM_WORLD.Bcast( &_referencePP, count, MPI::DOUBLE, _globalRefProcID);
1226 
1227 #endif
1228  //broadcast this value (referencePP) to all
1229 
1230  }
1231  else
1232  _referencePP = 0.0;
1233  }
1234 
1236  {
1237  const int numMeshes = _meshes.size();
1238  for (int n=0; n<numMeshes; n++)
1239  {
1240  const Mesh& mesh = *_meshes[n];
1241 
1242  const StorageSite& cells = mesh.getCells();
1243  const StorageSite& faces = mesh.getFaces();
1244 
1245  TArray& r = dynamic_cast<TArray&>(_flowFields.continuityResidual[cells]);
1246  const TArray& massFlux = dynamic_cast<const TArray&>(_flowFields.massFlux[faces]);
1247 
1248  const CRConnectivity& faceCells = mesh.getAllFaceCells();
1249  const int nFaces = faces.getCount();
1250 
1251  r.zero();
1252  for(int f=0; f<nFaces; f++)
1253  {
1254  const int c0 = faceCells(f,0);
1255  const int c1 = faceCells(f,1);
1256 
1257  r[c0] += massFlux[f];
1258  r[c1] -= massFlux[f];
1259  }
1260  }
1261  }
1262 
1264  {
1265  MultiFieldMatrix& matrix = ls.getMatrix();
1266  MultiField& ppField = ls.getDelta();
1267 
1268  setReferencePP(ppField);
1269 
1270  const int numMeshes = _meshes.size();
1271  for (int n=0; n<numMeshes; n++)
1272  {
1273  const Mesh& mesh = *_meshes[n];
1274 
1275  const StorageSite& cells = mesh.getCells();
1276  const StorageSite& iFaces = mesh.getInteriorFaceGroup().site;
1277 
1278  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
1279 
1280  MultiField::ArrayIndex vIndex(&_flowFields.velocity,&cells);
1281  const bool coupled = matrix.hasMatrix(pIndex,vIndex);
1282 
1283  correctPressure(mesh,ppField);
1284 
1285  // interior
1286 
1287  correctMassFluxInterior(mesh,iFaces,matrix,ppField);
1288 
1289  if (coupled)
1290  correctVelocityExplicit(mesh,ppField);
1291  else if (_options.correctVelocity)
1292  correctVelocityInterior(mesh,iFaces,ppField);
1293 
1294  updateFacePressureInterior(mesh,iFaces);
1295 
1296  // interfaces
1297  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
1298  {
1299  const FaceGroup& fg = *fgPtr;
1300  const StorageSite& faces = fg.site;
1301  correctMassFluxInterior(mesh,faces,matrix,ppField);
1302 
1303  if (coupled)
1304  correctVelocityExplicit(mesh,ppField);
1305  else if (_options.correctVelocity)
1306  correctVelocityInterior(mesh,faces,ppField);
1307 
1308  updateFacePressureInterior(mesh,faces);
1309  }
1310 
1311  // boundary
1312  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
1313  {
1314  const FaceGroup& fg = *fgPtr;
1315  const StorageSite& faces = fg.site;
1316  const FlowBC<T>& bc = *_bcMap[fg.id];
1317 
1318  correctMassFluxBoundary(faces,ppField);
1319 
1320  if (!coupled && _options.correctVelocity)
1321  correctVelocityBoundary(mesh,faces,ppField);
1322 
1323  if (bc.bcType == "PressureBoundary")
1324  {
1325  T bp = bc["specifiedPressure"];
1326  pressureBoundaryPostContinuitySolve(faces,mesh,bp);
1327  }
1328 
1329  updateFacePressureBoundary(mesh,faces);
1330  }
1331 
1332  }
1333 
1334  _flowFields.velocity.syncLocal();
1335  _flowFields.pressure.syncLocal();
1336 
1337  computeContinuityResidual();
1338 
1339  }
1340 
1342  {
1343  const int numMeshes = _meshes.size();
1344  for (int n=0; n<numMeshes; n++)
1345  {
1346  const Mesh& mesh = *_meshes[n];
1347 
1348  const StorageSite& cells = mesh.getCells();
1349  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
1350 
1351  ls.getX().addArray(pIndex,_flowFields.pressure.getArrayPtr(cells));
1352 
1353  const CRConnectivity& cellCells = mesh.getCellCells();
1354 
1355  shared_ptr<Matrix> m(new CRMatrix<T,T,T>(cellCells));
1356 
1357  ls.getMatrix().addMatrix(pIndex,pIndex,m);
1358 
1359  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
1360  {
1361  const FaceGroup& fg = *fgPtr;
1362  const StorageSite& faces = fg.site;
1363 
1364  MultiField::ArrayIndex fIndex(&_flowFields.massFlux,&faces);
1365  ls.getX().addArray(fIndex,_flowFields.massFlux.getArrayPtr(faces));
1366 
1367  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
1368 
1369  shared_ptr<Matrix> mft(new FluxJacobianMatrix<T,T>(faceCells));
1370  ls.getMatrix().addMatrix(fIndex,pIndex,mft);
1371 
1372  shared_ptr<Matrix> mff(new DiagonalMatrix<T,T>(faces.getCount()));
1373  ls.getMatrix().addMatrix(fIndex,fIndex,mff);
1374  }
1375  foreach(const FaceGroupPtr fgPtr, mesh.getInterfaceGroups())
1376  {
1377  const FaceGroup& fg = *fgPtr;
1378  const StorageSite& faces = fg.site;
1379 
1380  MultiField::ArrayIndex fIndex(&_flowFields.massFlux,&faces);
1381  ls.getX().addArray(fIndex,_flowFields.massFlux.getArrayPtr(faces));
1382 
1383  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
1384 
1385  shared_ptr<Matrix> mft(new FluxJacobianMatrix<T,T>(faceCells));
1386  ls.getMatrix().addMatrix(fIndex,pIndex,mft);
1387 
1388  shared_ptr<Matrix> mff(new DiagonalMatrix<T,T>(faces.getCount()));
1389  ls.getMatrix().addMatrix(fIndex,fIndex,mff);
1390  }
1391  }
1392  }
1393 
1394  shared_ptr<LinearSystem> discretizeContinuity()
1395  {
1396  shared_ptr<LinearSystem> ls(new LinearSystem());
1397 
1398  initContinuityLinearization(*ls);
1399 
1400  ls->initAssembly();
1401 
1402  linearizeContinuity(*ls);
1403 
1404  ls->initSolve();
1405 
1406  return ls;
1407  }
1408 
1409 
1411  {
1412  shared_ptr<LinearSystem> ls(discretizeContinuity());
1413 
1414  // discard previous velocity
1415  _previousVelocity = shared_ptr<Field>();
1416 
1417  MFRPtr rNorm = _options.getPressureLinearSolver().solve(*ls);
1418 
1419  if (!_initialContinuityNorm) _initialContinuityNorm = rNorm;
1420 
1421  ls->postSolve();
1422  _options.pressureLinearSolver->cleanup();
1423 
1424  postContinuitySolve(*ls);
1425 
1426  // discard the momentum ap coeffficients
1427 
1428  _momApField = shared_ptr<Field>();
1429  return rNorm;
1430  }
1431 
1432 
1433  bool advance(const int niter)
1434  {
1435 
1436  for(int n=0; n<niter; n++)
1437  {
1438  MFRPtr mNorm = solveMomentum();
1439  MFRPtr cNorm = solveContinuity();
1440 
1441  if (_niters < 5)
1442  {
1443  _initialMomentumNorm->setMax(*mNorm);
1444  _initialContinuityNorm->setMax(*cNorm);
1445  }
1446 
1447  MFRPtr mNormRatio((*mNorm)/(*_initialMomentumNorm));
1448  MFRPtr cNormRatio((*cNorm)/(*_initialContinuityNorm));
1449 
1450 #ifdef FVM_PARALLEL
1451  if ( MPI::COMM_WORLD.Get_rank() == 0 ){ // only root process
1452  if (_options.printNormalizedResiduals)
1453  {cout << _niters << ": " << *mNormRatio << ";" << *cNormRatio << endl;}
1454  else{
1455  cout << _niters << ": " << *mNorm << ";" << *cNorm << endl;}}
1456 #endif
1457 
1458 #ifndef FVM_PARALLEL
1459  if (_options.printNormalizedResiduals)
1460  {cout << _niters << ": " << *mNormRatio << ";" << *cNormRatio << endl;}
1461  else
1462  {cout << _niters << ": " << *mNorm << ";" << *cNorm << endl;}
1463 #endif
1464 
1465  _niters++;
1466  if ((*mNormRatio < _options.momentumTolerance) &&
1467  (*cNormRatio < _options.continuityTolerance))
1468  return true;
1469  }
1470  return false;
1471  }
1472 
1473 #ifdef PV_COUPLED
1474  bool advanceCoupled(const int niter)
1475  {
1476  const int numMeshes = _meshes.size();
1477  for(int n=0; n<niter; n++)
1478  {
1479  LinearSystem ls;
1480 
1481  ls.setCoarseningField(_flowFields.pressure);
1482  initMomentumLinearization(ls);
1483  initContinuityLinearization(ls);
1484 
1485  for (int n=0; n<numMeshes; n++)
1486  {
1487  const Mesh& mesh = *_meshes[n];
1488 
1489  const StorageSite& cells = mesh.getCells();
1490  MultiField::ArrayIndex vIndex(&_flowFields.velocity,&cells);
1491  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
1492 
1493  const CRConnectivity& cellCells = mesh.getCellCells();
1494 
1495  shared_ptr<Matrix> mvp(new VPMatrix(cellCells));
1496  ls.getMatrix().addMatrix(vIndex,pIndex,mvp);
1497 
1498  shared_ptr<Matrix> mpv(new PVMatrix(cellCells));
1499  ls.getMatrix().addMatrix(pIndex,vIndex,mpv);
1500  }
1501 
1502  ls.initAssembly();
1503 
1504  linearizeMomentum(ls);
1505 
1506  // save current velocity for use in continuity discretization
1507  _previousVelocity = dynamic_pointer_cast<Field>(_flowFields.velocity.newCopy());
1508 
1509  // save the momentum ap coeffficients for use in continuity discretization
1510  _momApField = shared_ptr<Field>(new Field("momAp"));
1511  for (int n=0; n<numMeshes; n++)
1512  {
1513  const Mesh& mesh = *_meshes[n];
1514 
1515  const StorageSite& cells = mesh.getCells();
1516  MultiField::ArrayIndex vIndex(&_flowFields.velocity,&cells);
1517  const VVMatrix& vvMatrix =
1518  dynamic_cast<const VVMatrix&>(ls.getMatrix().getMatrix(vIndex,vIndex));
1519  const VVDiagArray& momAp = vvMatrix.getDiag();
1520  _momApField->addArray(cells,dynamic_pointer_cast<ArrayBase>(momAp.newCopy()));
1521  }
1522 
1523  linearizeContinuity(ls);
1524 
1525  ls.initSolve();
1526 
1527  MFRPtr rNorm = _options.coupledLinearSolver->solve(ls);
1528 
1529  if (!_initialCoupledNorm) _initialCoupledNorm = rNorm;
1530 
1531  ls.postSolve();
1532 
1533  postContinuitySolve(ls);
1534 
1535  _options.coupledLinearSolver->cleanup();
1536 
1537  if (_niters < 5)
1538  _initialCoupledNorm->setMax(*rNorm);
1539 
1540  MFRPtr normRatio((*rNorm)/(*_initialCoupledNorm));
1541 
1542  if (_options.printNormalizedResiduals)
1543  cout << _niters << ": " << *normRatio << endl;
1544  else
1545  cout << _niters << ": " << *rNorm << endl;
1546 
1547  _niters++;
1548 
1549  _momApField = shared_ptr<Field>();
1550 
1551  if (*normRatio < _options.momentumTolerance)
1552  return true;
1553  }
1554  return false;
1555  }
1556 #endif
1557 
1558 #if !(defined(USING_ATYPE_TANGENT) || defined(USING_ATYPE_PC))
1559 
1560  void dumpContinuityMatrix(const string fileBase)
1561  {
1562  solveMomentum();
1563  shared_ptr<LinearSystem> ls(discretizeContinuity());
1564 
1565  MultiFieldMatrix& matrix = ls->getMatrix();
1566  MultiField& b = ls->getB();
1567 
1568  const Mesh& mesh = *_meshes[0];
1569  const StorageSite& cells = mesh.getCells();
1570 
1571  MultiField::ArrayIndex pIndex(&_flowFields.pressure,&cells);
1572 
1573  PPMatrix& ppMatrix =
1574  dynamic_cast<PPMatrix&>(matrix.getMatrix(pIndex,pIndex));
1575 
1576  PPDiagArray& ppDiag = ppMatrix.getDiag();
1577  PPDiagArray& ppCoeff = ppMatrix.getOffDiag();
1578 
1579  TArray& rCell = dynamic_cast<TArray&>(b[pIndex]);
1580 
1581  const CRConnectivity& cr = ppMatrix.getConnectivity();
1582 
1583  const Array<int>& row = cr.getRow();
1584  const Array<int>& col = cr.getCol();
1585 
1586  const int nCells = cells.getSelfCount();
1587  int nCoeffs = nCells;
1588 
1589  for(int i=0; i<nCells; i++)
1590  for(int jp=row[i]; jp<row[i+1]; jp++)
1591  {
1592  const int j = col[jp];
1593  if (j<nCells) nCoeffs++;
1594  }
1595 
1596  string matFileName = fileBase + ".mat";
1597  FILE *matFile = fopen(matFileName.c_str(),"wb");
1598 
1599  fprintf(matFile,"%%%%MatrixMarket matrix coordinate real general\n");
1600  fprintf(matFile,"%d %d %d\n", nCells,nCells,nCoeffs);
1601 
1602  for(int i=0; i<nCells; i++)
1603  {
1604  fprintf(matFile,"%d %d %lf\n", i+1, i+1, ppDiag[i]);
1605  for(int jp=row[i]; jp<row[i+1]; jp++)
1606  {
1607  const int j = col[jp];
1608  if (j<nCells)
1609  fprintf(matFile,"%d %d %lf\n", i+1, j+1, ppCoeff[jp]);
1610  }
1611  }
1612 
1613  fclose(matFile);
1614 
1615  string rhsFileName = fileBase + ".rhs";
1616  FILE *rhsFile = fopen(rhsFileName.c_str(),"wb");
1617 
1618  for(int i=0; i<nCells; i++)
1619  fprintf(rhsFile,"%lf\n",-rCell[i]);
1620 
1621  fclose(rhsFile);
1622  }
1623 #endif
1624 
1625  void printBCs()
1626  {
1627  foreach(typename FlowBCMap::value_type& pos, _bcMap)
1628  {
1629  cout << "Face Group " << pos.first << ":" << endl;
1630  cout << " bc type " << pos.second->bcType << endl;
1631  foreach(typename FlowBC<T>::value_type& vp, *pos.second)
1632  {
1633  cout << " " << vp.first << " " << vp.second.constant << endl;
1634  }
1635  }
1636  }
1637 
1638  VectorT3 getPressureIntegral(const Mesh& mesh, const int faceGroupId)
1639  {
1641  bool found = false;
1642  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
1643  {
1644  const FaceGroup& fg = *fgPtr;
1645  if (fg.id == faceGroupId)
1646  {
1647  const StorageSite& faces = fg.site;
1648  const VectorT3Array& faceArea =
1649  dynamic_cast<const VectorT3Array&>(_geomFields.area[faces]);
1650  const int nFaces = faces.getCount();
1651  const TArray& facePressure = dynamic_cast<const TArray&>(_flowFields.pressure[faces]);
1652  for(int f=0; f<nFaces; f++)
1653  r += faceArea[f]*facePressure[f];
1654 
1655  found=true;
1656  }
1657  }
1658  if (!found)
1659  throw CException("getPressureIntegral: invalid faceGroupID");
1660  return r;
1661  }
1662 
1664  {
1666  const StorageSite& ibFaces = mesh.getIBFaces();
1667  const StorageSite& faces = mesh.getFaces();
1668  const StorageSite& cells = mesh.getCells();
1669  const Array<int>& ibFaceIndices = mesh.getIBFaceList();
1670  const int nibf = ibFaces.getCount();
1671  const CRConnectivity& faceCells = mesh.getFaceCells(faces);
1672  const IntArray& ibType = dynamic_cast<const IntArray&>(_geomFields.ibType[cells]);
1673  const VectorT3Array& faceArea =
1674  dynamic_cast<const VectorT3Array&>(_geomFields.area[faces]);
1675  const TArray& facePressure = dynamic_cast<const TArray&>(_flowFields.pressure[faces]);
1676 
1677  for ( int f = 0; f < nibf; f ++)
1678  {
1679  const int ibFaceIndex = ibFaceIndices[f];
1680  const int c0 = faceCells(ibFaceIndex,0);
1681 
1682  // need to check whether the face points in or out of the
1683  // fluid cell and adjust sign of area accordingly
1684 
1685  if (ibType[c0] == Mesh::IBTYPE_FLUID)
1686  r += faceArea[ibFaceIndex]*facePressure[ibFaceIndex];
1687  else
1688  r -= faceArea[ibFaceIndex]*facePressure[ibFaceIndex];
1689  }
1690 
1691 #if FVM_PARALLEL
1692  MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, r.getData(), 3, MPI::DOUBLE, MPI::SUM);
1693 #endif
1694 
1695 
1696  return r;
1697  }
1698 
1699 
1700  VectorT3 getMomentumFluxIntegral(const Mesh& mesh, const int faceGroupId)
1701  {
1703  bool found = false;
1704  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
1705  {
1706  const FaceGroup& fg = *fgPtr;
1707  if (fg.id == faceGroupId)
1708  {
1709  const StorageSite& faces = fg.site;
1710  const int nFaces = faces.getCount();
1711  const VectorT3Array& momFlux =
1712  dynamic_cast<const VectorT3Array&>(_flowFields.momentumFlux[faces]);
1713  for(int f=0; f<nFaces; f++)
1714  r += momFlux[f];
1715  found=true;
1716  }
1717  }
1718  if (!found)
1719  throw CException("getMomentumFluxIntegral: invalid faceGroupID");
1720  return r;
1721  }
1722 
1724  {
1726  const StorageSite& cells = mesh.getCells();
1727  const int nCells = cells.getSelfCount();
1728 
1729  const TArray& density =
1730  dynamic_cast<const TArray&>(_flowFields.density[cells]);
1731  const VectorT3Array& v =
1732  dynamic_cast<const VectorT3Array&>(_flowFields.velocity[cells]);
1733  const VectorT3Array& vN1 =
1734  dynamic_cast<const VectorT3Array&>(_flowFields.velocityN1[cells]);
1735 
1736  const TArray& volume =
1737  dynamic_cast<const TArray&>(_geomFields.volume[cells]);
1738 
1739  const T deltaT = _options["timeStep"];
1740 
1741  if (_flowFields.velocityN2.hasArray(cells))
1742  {
1743  // second order
1744  const VectorT3Array& vN2 =
1745  dynamic_cast<const VectorT3Array&>(_flowFields.velocityN2[cells]);
1746  T onePointFive(1.5);
1747  T two(2.0);
1748  T pointFive(0.5);
1749 
1750  for(int c=0; c<nCells; c++)
1751  {
1752  const T rhoVbydT = density[c]*volume[c]/deltaT;
1753  r += rhoVbydT*(onePointFive*v[c]- two*vN1[c]
1754  + pointFive*vN2[c]);
1755  }
1756  }
1757  else
1758  {
1759  for(int c=0; c<nCells; c++)
1760  {
1761  const T rhoVbydT = density[c]*volume[c]/deltaT;
1762  r += rhoVbydT*(v[c]- vN1[c]);
1763  }
1764  }
1765  return r;
1766  }
1767 
1768  boost::shared_ptr<ArrayBase> getStressTensor(const Mesh& mesh, const ArrayBase& gcellIds)
1769  {
1771 
1772  const StorageSite& cells = mesh.getCells();
1773 
1774  const Array<int>& cellIds = dynamic_cast<const Array<int> &>(gcellIds);
1775  const int nCells = cellIds.getLength();
1776 
1777  _velocityGradientModel.compute();
1778 
1779  const VGradArray& vGrad =
1780  dynamic_cast<const VGradArray&>(_flowFields.velocityGradient[cells]);
1781 
1782  const TArray& pCell =
1783  dynamic_cast<const TArray&>(_flowFields.pressure[cells]);
1784 
1785  const TArray& mu = dynamic_cast<const TArray&>(getViscosityField()[cells]);
1786 
1787  boost::shared_ptr<StressTensorArray> stressTensorPtr( new StressTensorArray(nCells));
1788  StressTensorArray& stressTensor = *stressTensorPtr;
1789 
1790  for(int n=0; n<nCells; n++)
1791  {
1792  const int c = cellIds[n];
1793  const VGradType& vg = vGrad[c];
1794  VGradType vgPlusTranspose = vGrad[c];
1795 
1796  for(int i=0;i<3;i++)
1797  for(int j=0;j<3;j++)
1798  vgPlusTranspose[i][j] += vg[j][i];
1799 
1800  stressTensor[n][0] = vgPlusTranspose[0][0]*mu[c] - pCell[c];
1801  stressTensor[n][1] = vgPlusTranspose[1][1]*mu[c] - pCell[c];
1802  stressTensor[n][2] = vgPlusTranspose[2][2]*mu[c] - pCell[c];
1803  stressTensor[n][3] = vgPlusTranspose[0][1]*mu[c];
1804  stressTensor[n][4] = vgPlusTranspose[1][2]*mu[c];
1805  stressTensor[n][5] = vgPlusTranspose[2][0]*mu[c];
1806  }
1807 
1808  return stressTensorPtr;
1809  }
1810 
1811  void ComputeStressTensorES(const StorageSite& solidFaces)
1812  {
1814  const int nSolidFaces = solidFaces.getCount();
1815 
1816 
1817  //interface
1818  VectorT3Array& IntVel =
1819  dynamic_cast<VectorT3Array&>(_flowFields.InterfaceVelocity[solidFaces]);
1820  TArray& IntPress =
1821  dynamic_cast<TArray&>(_flowFields.InterfacePressure[solidFaces]);
1822  TArray& IntDens =
1823  dynamic_cast<TArray&>(_flowFields.InterfaceDensity[solidFaces]);
1824 
1825  //const TArray& mu = dynamic_cast<const TArray&>(getViscosityField()[cells]);
1826  StressTensorArray& stressTensor = dynamic_cast<StressTensorArray &>(_flowFields.InterfaceStress[solidFaces]);
1827 
1828 
1829  const int numMeshes = _meshes.size();
1830 
1831  for (int n=0; n<numMeshes; n++)
1832  {
1833  const Mesh& mesh = *_meshes[n];
1834  const StorageSite& cells = mesh.getCells();
1835  //const int nCells = cells.getCount();
1836 
1837  _velocityGradientModel.compute();
1838 
1839  const VGradArray& vGrad =
1840  dynamic_cast<VGradArray&>(_flowFields.velocityGradient[cells]);
1841  const TArray& pCell =
1842  dynamic_cast<const TArray&>(_flowFields.pressure[cells]);
1843  const TArray& dCell =
1844  dynamic_cast<const TArray&>(_flowFields.density[cells]);
1845  const VectorT3Array& vCell =
1846  dynamic_cast<VectorT3Array&>(_flowFields.velocity[cells]);
1847 
1848 
1849  const CRConnectivity& _faceCells=mesh.getFaceCells(solidFaces);
1850 
1851  for(int f=0; f<nSolidFaces; f++)
1852  {
1853 
1854  const int c0 = _faceCells(f,0);
1855  const int c1 = _faceCells(f,1);
1856 
1857  const VGradType& vg = vGrad[c0];
1858 
1859  VGradType vgPlusTranspose = vGrad[c0];
1860 
1861  for(int i=0;i<3;i++)
1862  for(int j=0;j<3;j++)
1863  vgPlusTranspose[i][j] += vg[j][i];
1864 
1865  stressTensor[f][0] = vgPlusTranspose[0][0];
1866  stressTensor[f][1] = vgPlusTranspose[1][1];
1867  stressTensor[f][3] = vgPlusTranspose[0][1];
1868  stressTensor[f][4] = vgPlusTranspose[1][2];
1869  stressTensor[f][5] = vgPlusTranspose[2][0];
1870 
1871  //copy density pressure and velocity into Interface arrays
1872  IntDens[f]=dCell[c1];
1873  IntPress[f]=pCell[c1];
1874  IntVel[f][0]=vCell[c1][0];
1875  IntVel[f][1]=vCell[c1][1];
1876  IntVel[f][2]=vCell[c1][2];
1877  }
1878  }
1879 
1880 
1881  }
1882 
1883 
1884  void getTraction(const Mesh& mesh)
1885  {
1886  const StorageSite& cells = mesh.getCells();
1887 
1888  const int nCells = cells.getSelfCount();
1889 
1890  shared_ptr<VectorT3Array> tractionXPtr(new VectorT3Array(nCells));
1891  tractionXPtr->zero();
1892  _flowFields.tractionX.addArray(cells,tractionXPtr);
1893  VectorT3Array& tractionX = *tractionXPtr;
1894 
1895  shared_ptr<VectorT3Array> tractionYPtr(new VectorT3Array(nCells));
1896  tractionYPtr->zero();
1897  _flowFields.tractionY.addArray(cells,tractionYPtr);
1898  VectorT3Array& tractionY = *tractionYPtr;
1899 
1900  shared_ptr<VectorT3Array> tractionZPtr(new VectorT3Array(nCells));
1901  tractionZPtr->zero();
1902  _flowFields.tractionZ.addArray(cells,tractionZPtr);
1903  VectorT3Array& tractionZ = *tractionZPtr;
1904 
1905  _velocityGradientModel.compute();
1906 
1907  const VGradArray& vGrad =
1908  dynamic_cast<const VGradArray&>(_flowFields.velocityGradient[cells]);
1909 
1910  const TArray& pCell =
1911  dynamic_cast<const TArray&>(_flowFields.pressure[cells]);
1912 
1913  const TArray& mu = dynamic_cast<const TArray&>(getViscosityField()[cells]);
1914 
1915  for(int n=0; n<nCells; n++)
1916  {
1917  const VGradType& vg = vGrad[n];
1918  VGradType vgPlusTranspose = vGrad[n];
1919 
1920  for(int i=0;i<3;i++)
1921  for(int j=0;j<3;j++)
1922  vgPlusTranspose[i][j] += vg[j][i];
1923 
1924  tractionX[n][0] = vgPlusTranspose[0][0]*mu[n] - pCell[n];
1925  tractionX[n][1] = vgPlusTranspose[0][1]*mu[n];
1926  tractionX[n][2] = vgPlusTranspose[0][2]*mu[n];
1927 
1928  tractionY[n][0] = vgPlusTranspose[1][0]*mu[n];
1929  tractionY[n][1] = vgPlusTranspose[1][1]*mu[n] - pCell[n];
1930  tractionY[n][2] = vgPlusTranspose[1][2]*mu[n];
1931 
1932  tractionZ[n][0] = vgPlusTranspose[2][0]*mu[n];
1933  tractionZ[n][1] = vgPlusTranspose[2][1]*mu[n];
1934  tractionZ[n][2] = vgPlusTranspose[2][2]*mu[n] - pCell[n];
1935  }
1936  }
1937 
1938  void
1939  computeSolidSurfaceForce(const StorageSite& solidFaces, bool perUnitArea)
1940  {
1941  typedef CRMatrixTranspose<T,T,T> IMatrix;
1942 
1943  const int nSolidFaces = solidFaces.getCount();
1944 
1945  _velocityGradientModel.compute();
1946 
1947  boost::shared_ptr<VectorT3Array>
1948  forcePtr( new VectorT3Array(nSolidFaces));
1949  VectorT3Array& force = *forcePtr;
1950 
1951  force.zero();
1952  _flowFields.force.addArray(solidFaces,forcePtr);
1953 
1954  const VectorT3Array& solidFaceArea =
1955  dynamic_cast<const VectorT3Array&>(_geomFields.area[solidFaces]);
1956 
1957  const TArray& solidFaceAreaMag =
1958  dynamic_cast<const TArray&>(_geomFields.areaMag[solidFaces]);
1959 
1960  const int numMeshes = _meshes.size();
1961  for (int n=0; n<numMeshes; n++)
1962  {
1963  const Mesh& mesh = *_meshes[n];
1964  const StorageSite& cells = mesh.getCells();
1965  const VGradArray& vGrad =
1966  dynamic_cast<const VGradArray&>(_flowFields.velocityGradient[cells]);
1967 
1968  const TArray& pCell =
1969  dynamic_cast<const TArray&>(_flowFields.pressure[cells]);
1970 
1971  const TArray& mu =
1972  dynamic_cast<const TArray&>(getViscosityField()[cells]);
1973 
1974  //const FlowVC<T>& vc = *_vcMap[mesh.getID()];
1975 
1976  const CRConnectivity& solidFacesToCells
1977  = mesh.getConnectivity(solidFaces,cells);
1978 
1979  const IntArray& sFCRow = solidFacesToCells.getRow();
1980  const IntArray& sFCCol = solidFacesToCells.getCol();
1981 
1982  GeomFields::SSPair key1(&solidFaces,&cells);
1983  const IMatrix& mIC =
1984  dynamic_cast<const IMatrix&>
1985  (*_geomFields._interpolationMatrices[key1]);
1986 
1987  const Array<T>& iCoeffs = mIC.getCoeff();
1988 
1989  for(int f=0; f<nSolidFaces; f++)
1990  {
1991  StressTensor<T> stress = NumTypeTraits<StressTensor<T> >::getZero();
1992  for(int nc = sFCRow[f]; nc<sFCRow[f+1]; nc++)
1993  {
1994  const int c = sFCCol[nc];
1995  const VGradType& vg = vGrad[c];
1996  VGradType vgPlusTranspose = vGrad[c];
1997 
1998  for(int i=0;i<3;i++)
1999  for(int j=0;j<3;j++)
2000  vgPlusTranspose[i][j] += vg[j][i];
2001 
2002  const T coeff = iCoeffs[nc];
2003 
2004  stress[0] += coeff*(vgPlusTranspose[0][0]*mu[c] - pCell[c]);
2005  stress[1] += coeff*(vgPlusTranspose[1][1]*mu[c] - pCell[c]);
2006  stress[2] += coeff*(vgPlusTranspose[2][2]*mu[c] - pCell[c]);
2007  stress[3] += coeff*(vgPlusTranspose[0][1]*mu[c]);
2008  stress[4] += coeff*(vgPlusTranspose[1][2]*mu[c]);
2009  stress[5] += coeff*(vgPlusTranspose[2][0]*mu[c]);
2010  }
2011 
2012  const VectorT3& Af = solidFaceArea[f];
2013  force[f][0] = Af[0]*stress[0] + Af[1]*stress[3] + Af[2]*stress[5];
2014  force[f][1] = Af[0]*stress[3] + Af[1]*stress[1] + Af[2]*stress[4];
2015  force[f][2] = Af[0]*stress[5] + Af[1]*stress[4] + Af[2]*stress[2];
2016  if (perUnitArea)
2017  {
2018  force[f] /= solidFaceAreaMag[f];
2019  }
2020  }
2021  }
2022  }
2023 
2024 
2026  {
2028  const StorageSite& ibFaces = mesh.getIBFaces();
2029  const StorageSite& faces = mesh.getFaces();
2030  const Array<int>& ibFaceIndices = mesh.getIBFaceList();
2031  const int nibf = ibFaces.getCount();
2032  const VectorT3Array& momFlux =
2033  dynamic_cast<const VectorT3Array&>(_flowFields.momentumFlux[faces]);
2034  for ( int f = 0; f < nibf; f ++){
2035  const int ibFaceIndex = ibFaceIndices[f];
2036  r += momFlux[ibFaceIndex];
2037  }
2038  if (nibf == 0)
2039  throw CException("getMomentumFluxIntegralonIBFaces: no ibFaces found!");
2040  return r;
2041  }
2042 
2043 
2045  {
2046  const int numMeshes = _meshes.size();
2047  for (int n=0; n<numMeshes; n++)
2048  {
2049  const Mesh& mesh = *_meshes[n];
2050  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
2051  {
2052  const FaceGroup& fg = *fgPtr;
2053 
2055 
2056  const StorageSite& faces = fg.site;
2057  const VectorT3Array& faceArea =
2058  dynamic_cast<const VectorT3Array&>(_geomFields.area[faces]);
2059  const int nFaces = faces.getCount();
2060  const TArray& facePressure = dynamic_cast<const TArray&>(_flowFields.pressure[faces]);
2061  for(int f=0; f<nFaces; f++)
2062  r += faceArea[f]*facePressure[f];
2063 
2064  cout << "Mesh " << mesh.getID() << " faceGroup " << fg.id << " : " << r << endl;
2065  }
2066  }
2067  }
2068 
2070  {
2071  const int numMeshes = _meshes.size();
2072  for (int n=0; n<numMeshes; n++)
2073  {
2074  const Mesh& mesh = *_meshes[n];
2075  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
2076  {
2077  const FaceGroup& fg = *fgPtr;
2078 
2080 
2081  const StorageSite& faces = fg.site;
2082  const int nFaces = faces.getCount();
2083  const VectorT3Array& momFlux =
2084  dynamic_cast<const VectorT3Array&>(_flowFields.momentumFlux[faces]);
2085  for(int f=0; f<nFaces; f++)
2086  r += momFlux[f];
2087 
2088  cout << "Mesh " << mesh.getID() << " faceGroup " << fg.id << " : " << r << endl;
2089  }
2090  }
2091  }
2092 
2094  {
2095  const int numMeshes = _meshes.size();
2096  for (int n=0; n<numMeshes; n++)
2097  {
2098  const Mesh& mesh = *_meshes[n];
2099  foreach(const FaceGroupPtr fgPtr, mesh.getBoundaryFaceGroups())
2100  {
2101  const FaceGroup& fg = *fgPtr;
2102 
2103  T r(0.);
2104 
2105  const StorageSite& faces = fg.site;
2106  const int nFaces = faces.getCount();
2107  const TArray& massFlux = dynamic_cast<const TArray&>(_flowFields.massFlux[faces]);
2108  for(int f=0; f<nFaces; f++)
2109  r += massFlux[f];
2110 
2111  cout << "Mesh " << mesh.getID() << " faceGroup " << fg.id << " : " << r << endl;
2112  }
2113  }
2114  }
2115 
2116 #include "FlowModelPressureBC.h"
2117 #include "FlowModelVelocityBC.h"
2118 #include "FlowModelInterior.h"
2119 #include "FlowModelSlipJump.h"
2120 
2121 private:
2127 
2131 
2135  int _niters;
2136 
2137  shared_ptr<Field> _previousVelocity;
2138  shared_ptr<Field> _momApField;
2139 
2144  //AMG _momSolver;
2145  //AMG _continuitySolver;
2146  map<string,shared_ptr<ArrayBase> > _persistenceData;
2147 };
2148 
2149 template<class T>
2151  FlowFields& thermalFields,
2152  const MeshList& meshes) :
2153  Model(meshes),
2154  _impl(new Impl(geomFields,thermalFields,meshes))
2155 {
2156  logCtor();
2157 }
2158 
2159 
2160 template<class T>
2162 {
2163  logDtor();
2164 }
2165 
2166 template<class T>
2167 void
2169 {
2170  _impl->init();
2171 }
2172 
2173 template<class T>
2174 typename FlowModel<T>::FlowBCMap&
2175 FlowModel<T>::getBCMap() {return _impl->getBCMap();}
2176 
2177 template<class T>
2178 typename FlowModel<T>::FlowVCMap&
2179 FlowModel<T>::getVCMap() {return _impl->getVCMap();}
2180 
2181 template<class T>
2183 FlowModel<T>::getOptions() {return _impl->getOptions();}
2184 
2185 
2186 template<class T>
2187 void
2189 {
2190  _impl->printBCs();
2191 }
2192 
2193 template<class T>
2194 bool
2195 FlowModel<T>::advance(const int niter)
2196 {
2197  return _impl->advance(niter);
2198 }
2199 
2200 #ifdef PV_COUPLED
2201 template<class T>
2202 bool
2203 FlowModel<T>::advanceCoupled(const int niter)
2204 {
2205  return _impl->advanceCoupled(niter);
2206 }
2207 #endif
2208 
2209 #if 0
2210 template<class T>
2211 LinearSolver&
2213 {
2214  return _impl->getMomentumSolver();
2215 }
2216 
2217 template<class T>
2218 LinearSolver&
2220 {
2221  return _impl->getContinuitySolver();
2222 }
2223 #endif
2224 
2225 template<class T>
2226 void
2228 {
2229  _impl->updateTime();
2230 }
2231 
2232 template<class T>
2233 void
2235 {
2236  _impl->printPressureIntegrals();
2237 }
2238 
2239 template<class T>
2240 void
2242 {
2243  _impl->printMomentumFluxIntegrals();
2244 }
2245 
2246 template<class T>
2247 void
2249 {
2250  _impl->printMassFluxIntegrals();
2251 }
2252 
2253 template<class T>
2255 FlowModel<T>::getPressureIntegral(const Mesh& mesh, const int faceGroupId)
2256 {
2257  return _impl->getPressureIntegral(mesh,faceGroupId);
2258 }
2259 
2260 template<class T>
2262 FlowModel<T>::getMomentumFluxIntegral(const Mesh& mesh, const int faceGroupId)
2263 {
2264  return _impl->getMomentumFluxIntegral(mesh,faceGroupId);
2265 }
2266 
2267 template<class T>
2270 {
2271  return _impl->getMomentumDerivativeIntegral(mesh);
2272 }
2273 
2274 template<class T>
2277 {
2278  return _impl->getPressureIntegralonIBFaces(mesh);
2279 }
2280 
2281 template<class T>
2284 {
2285  return _impl->getMomentumFluxIntegralonIBFaces(mesh);
2286 }
2287 
2288 template<class T>
2289 void
2291 {
2292  return _impl->computeIBFaceVelocity(particles);
2293 }
2294 
2295 template<class T>
2296 void
2298 {
2299  return _impl->computeSolidSurfaceForce(particles,false);
2300 }
2301 
2302 template<class T>
2303 void
2305 {
2306  return _impl->computeSolidSurfaceForce(particles,true);
2307 }
2308 
2309 
2310 template<class T>
2311 boost::shared_ptr<ArrayBase>
2312 FlowModel<T>::getStressTensor(const Mesh& mesh, const ArrayBase& cellIds)
2313 {
2314  return _impl->getStressTensor(mesh, cellIds);
2315 }
2316 
2317 template<class T>
2318 void
2320 {
2321  return _impl->getTraction(mesh);
2322 }
2323 
2324 template<class T>
2325 void
2327 {
2328  return _impl-> ComputeStressTensorES(particles);
2329 }
2330 template<class T>
2331 map<string,shared_ptr<ArrayBase> >&
2333 {
2334  return _impl->getPersistenceData();
2335 }
2336 
2337 template<class T>
2338 void
2340 {
2341  _impl->restart();
2342 }
2343 
2344 
2345 
2346 
2347 #if !(defined(USING_ATYPE_TANGENT) || defined(USING_ATYPE_PC))
2348 template<class T>
2349 void
2351 {
2352  _impl->dumpContinuityMatrix(fileBase);
2353 }
2354 
2355 #endif
void ComputeStressTensorES(const StorageSite &solidFaces)
virtual map< string, shared_ptr< ArrayBase > > & getPersistenceData()
MFRPtr _initialMomentumNorm
void dumpContinuityMatrix(const string fileBase)
const FaceGroupList & getBoundaryFaceGroups() const
Definition: Mesh.h:187
const Array< int > & getCol() const
void computeSolidSurfaceForce(const StorageSite &solidFaces, bool perUnitArea)
virtual void zero()
Definition: Array.h:281
MFRPtr _initialCoupledNorm
const Array< int > & getRow() const
const FaceGroup & getInteriorFaceGroup() const
Definition: Mesh.h:181
void initAssembly()
void getTraction(const Mesh &mesh)
Matrix & getMatrix(const Index &rowIndex, const Index &colIndex)
shared_ptr< FaceGroup > FaceGroupPtr
Definition: Mesh.h:46
void getTraction(const Mesh &mesh)
int getSelfCount() const
Definition: StorageSite.h:40
const StorageSite & getIBFaces() const
Definition: Mesh.h:111
FlowVCMap & getVCMap()
VectorT3 getPressureIntegralonIBFaces(const Mesh &mesh)
FluxJacobianMatrix< T, T > FMatrix
const CRConnectivity & getConnectivity(const StorageSite &from, const StorageSite &to) const
Definition: Mesh.cpp:416
Gradient< VectorT3 > VGradType
const GeomFields & _geomFields
VectorT3 getMomentumFluxIntegralonIBFaces(const Mesh &mesh)
Array< VectorT3 > VectorT3Array
Vector< T, 3 > getPressureIntegralonIBFaces(const Mesh &mesh)
virtual void restart()
Definition: Mesh.h:28
FlowBCMap & getBCMap()
Definition: FlowBC.h:10
void printPressureIntegrals()
Definition: Field.h:14
string bcType
Definition: FlowBC.h:20
void fixedPressureMomentumBC(const StorageSite &faces, const Mesh &mesh, MultiFieldMatrix &matrix, const MultiField &xField, MultiField &rField)
void setDirichlet(MultiFieldMatrix &mfmatrix, MultiField &rField)
void printMassFluxIntegrals()
shared_ptr< Field > _momApField
bool hasMatrix(const Index &rowIndex, const Index &colIndex) const
VVMatrix::DiagArray VVDiagArray
map< string, shared_ptr< ArrayBase > > _persistenceData
Definition: Model.h:32
void correctVelocityBoundary(const Mesh &mesh, const StorageSite &faces, const MultiField &ppField)
void printBCs()
const Array< int > & getIBFaceList() const
Definition: Mesh.cpp:686
shared_ptr< LinearSystem > discretizeContinuity()
Definition: Mesh.h:49
double max(double x, double y)
Definition: Octree.cpp:18
FlowModelOptions< T > & getOptions()
VectorT3 getMomentumFluxIntegral(const Mesh &mesh, const int faceGroupId)
virtual ~FlowModel()
Array< Diag > & getDiag()
Definition: CRMatrix.h:856
string vcType
Definition: FlowBC.h:33
void updateFacePressureInterior(const Mesh &mesh, const StorageSite &faces, const bool isSymmetry=false)
GradientModel< VectorT3 > _velocityGradientModel
map< int, int > & getGlobalToLocal()
Definition: Mesh.h:243
#define logCtor()
Definition: RLogInterface.h:26
Vector< T, 3 > getPressureIntegral(const Mesh &mesh, const int faceGroupID)
FlowModel(const GeomFields &geomFields, FlowFields &thermalFields, const MeshList &meshes)
void ComputeStressTensorES(const StorageSite &particles)
void printPressureIntegrals()
void postContinuitySolve(LinearSystem &ls)
virtual void init()
virtual const CRConnectivity & getConnectivity() const
Definition: CRMatrix.h:834
string groupType
Definition: Mesh.h:42
MultiField & getDelta()
Definition: LinearSystem.h:34
void correctPressure(const Mesh &mesh, const MultiField &xField)
FloatVal< T > getVal(const string varName) const
Definition: FloatVarDict.h:85
MFRPtr _initialContinuityNorm
FlowVCMap & getVCMap()
bool advance(const int niter)
Array< Vector< double, 3 > > VectorT3Array
Definition: CellMark.cpp:7
map< string, shared_ptr< ArrayBase > > & getPersistenceData()
map< string, shared_ptr< ArrayBase > > _persistenceData
void correctVelocityInterior(const Mesh &mesh, const StorageSite &faces, const MultiField &ppField, const bool isSymmetry=false)
void correctMassFluxBoundary(const StorageSite &faces, const MultiField &ppField)
Array< StressTensorT6 > StressTensorArray
Array< OffDiag > & getOffDiag()
Definition: CRMatrix.h:857
const CRConnectivity & getAllFaceCells() const
Definition: Mesh.cpp:378
Vector< T, 3 > getMomentumFluxIntegral(const Mesh &mesh, const int faceGroupID)
const int id
Definition: Mesh.h:41
void updateSolution()
T discretizeMassFluxInterior(const Mesh &mesh, const StorageSite &faces, MultiFieldMatrix &mfmatrix, const MultiField &xField, MultiField &rField, const bool isSymmetry=false)
void * getData()
Definition: Vector.h:51
boost::shared_ptr< ArrayBase > getStressTensor(const Mesh &mesh, const ArrayBase &gcellIds)
Array< int > & getLocalToGlobal()
Definition: Mesh.h:240
pair< const Field *, const StorageSite * > ArrayIndex
Definition: MultiField.h:21
MFRPtr solveMomentum()
void correctVelocityExplicit(const Mesh &mesh, const MultiField &xField)
void initSolve()
CRMatrix< DiagTensorT3, T, VectorT3 > VVMatrix
boost::shared_ptr< ArrayBase > getStressTensor(const Mesh &mesh, const ArrayBase &cellIds)
PPMatrix::DiagArray PPDiagArray
void printMomentumFluxIntegrals()
vector< shared_ptr< Discretization > > DiscrList
void updateTime()
void initContinuityLinearization(LinearSystem &ls)
Array< T > TArray
DiagonalTensor< T, 3 > DiagTensorT3
Definition: FlowBC.h:24
void linearizeMomentum(LinearSystem &ls)
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 setReferencePP(const MultiField &ppField)
const StorageSite & getCells() const
Definition: Mesh.h:109
StressTensor< T > StressTensorT6
CRMatrix< T, T, T > PPMatrix
void applyInterfaceBC(const int f) const
Definition: GenericBCS.h:325
void correctMassFluxInterior(const Mesh &mesh, const StorageSite &faces, MultiFieldMatrix &mfmatrix, const MultiField &xField)
void computeSolidSurfaceForcePerUnitArea(const StorageSite &particles)
#define logDtor()
Definition: RLogInterface.h:33
void computeContinuityResidual()
void computeSolidSurfaceForce(const StorageSite &particles)
Array< int > IntArray
int getCountLevel1() const
Definition: StorageSite.h:72
VectorT3 getPressureIntegral(const Mesh &mesh, const int faceGroupId)
std::map< int, FlowBC< T > * > FlowBCMap
Definition: FlowModel.h:23
const CRConnectivity & getFaceCells(const StorageSite &site) const
Definition: Mesh.cpp:388
FlowModelOptions< T > _options
void computeIBFaceVelocity(const StorageSite &particles)
void addMatrix(const Index &rowI, const Index &colI, shared_ptr< Matrix > m)
bool isShell() const
Definition: Mesh.h:323
Impl(const GeomFields &geomFields, FlowFields &thermalFields, const MeshList &meshes)
void pressureBoundaryPostContinuitySolve(const StorageSite &faces, const Mesh &mesh, const T bp)
void updateFacePressureBoundary(const Mesh &mesh, const StorageSite &faces)
int getCount() const
Definition: StorageSite.h:39
FlowBCMap & getBCMap()
MultiField & getB()
Definition: LinearSystem.h:33
virtual shared_ptr< IContainer > newCopy() const
Definition: Array.h:483
void slipJumpMomentumBC(const StorageSite &faces, const Mesh &mesh, GenericBCS< VectorT3, DiagTensorT3, T > &gbc, const T accomodationCoefficient, const FloatValEvaluator< VectorT3 > &bVelocity)
void printMassFluxIntegrals()
VectorTranspose< T, 3 > VectorT3T
Array< Gradient< VectorT3 > > VGradArray
shared_ptr< MultiFieldReduction > MFRPtr
shared_ptr< Field > _previousVelocity
Vector< T, 3 > VectorT3
void addArray(const ArrayIndex &aIndex, shared_ptr< ArrayBase > a)
Definition: MultiField.cpp:270
T fixedFluxContinuityBC(const StorageSite &faces, const Mesh &mesh, MultiFieldMatrix &matrix, MultiField &xField, MultiField &rField, const FlowBC< T > &bc)
bool advance(const int niter)
const FaceGroupList & getInterfaceGroups() const
Definition: Mesh.h:190
MultiField & getX()
Definition: LinearSystem.h:32
FlowModelOptions< T > & getOptions()
Vector< T, 3 > getMomentumDerivativeIntegral(const Mesh &mesh)
const Field & getViscosityField() const
FlowFields & _flowFields
VectorT3 getMomentumDerivativeIntegral(const Mesh &mesh)
void linearizeContinuity(LinearSystem &ls)
T dot(const Vector< T, 3 > &a, const Vector< T, 3 > &b)
Definition: Vector.h:253
Vector< T, 3 > getMomentumFluxIntegralonIBFaces(const Mesh &mesh)
MFRPtr solveContinuity()
T fixedPressureContinuityBC(const StorageSite &faces, const Mesh &mesh, MultiFieldMatrix &matrix, const MultiField &xField, MultiField &rField)
static Vector getZero()
Definition: Vector.h:182
Array< PGradType > PGradArray
int getID() const
Definition: Mesh.h:106
void computeIBFaceVelocity(const StorageSite &particles)
GradientModel< T > _pressureGradientModel
void dumpContinuityMatrix(const string fileBase)
Gradient< T > PGradType
virtual void linearize(DiscrList &discretizations, const MeshList &meshes, MultiFieldMatrix &matrix, MultiField &x, MultiField &b)
Definition: Linearizer.cpp:17
void printMomentumFluxIntegrals()
void initMomentumLinearization(LinearSystem &ls)
pair< const StorageSite *, const StorageSite * > SSPair
Definition: GeomFields.h:48
const MeshList _meshes
MultiFieldMatrix & getMatrix()
Definition: LinearSystem.h:37
vector< Mesh * > MeshList
Definition: Mesh.h:439
void interfaceContinuityBC(const Mesh &mesh, const StorageSite &faces, MultiFieldMatrix &matrix, MultiField &rField)
StorageSite site
Definition: Mesh.h:40
int getLength() const
Definition: Array.h:87
PPMatrix::PairWiseAssembler PPAssembler
std::map< int, FlowVC< T > * > FlowVCMap
Definition: FlowModel.h:24
void setCoarseningField(const Field &f)
Definition: LinearSystem.h:48