immersedBoundaryFvPatchField.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | foam-extend: Open Source CFD
4  \\ / O peration | Version: 3.2
5  \\ / A nd | Web: http://www.foam-extend.org
6  \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9  This file is part of foam-extend.
10 
11  foam-extend is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by the
13  Free Software Foundation, either version 3 of the License, or (at your
14  option) any later version.
15 
16  foam-extend is distributed in the hope that it will be useful, but
17  WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
27 #include "fvPatchFieldMapper.H"
28 #include "fvMatrix.H"
29 #include "surfaceWriter.H"
30 
31 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 template<class Type>
41 (
42  "immersedBoundaryNBCIter",
43  5
44 );
45 
46 
47 template<class Type>
48 const Foam::debug::tolerancesSwitch
50 (
51  "immersedBoundaryBCTolerance",
52  0.01
53 );
54 
55 
56 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
57 
58 template<class Type>
60 {
61  // Create IB cell values first
62  Field<Type> ibcv
63  (
64  this->internalField(),
65  ibPatch_.ibCells()
66  );
67 
68  if (this->fixesValue())
69  {
70  ibValue_ = ibPatch_.toIbPoints(refValue_);
71  ibGrad_ = (ibValue_ - ibcv)/ibPatch_.ibDelta();
72 
73  // Reverse normals for external flow
74  if (!ibPatch_.internalFlow())
75  {
76  ibGrad_ *= -1;
77  }
78  }
79  else
80  {
81  ibGrad_ = ibPatch_.toIbPoints(refGrad_);
82 
83  ibValue_ = ibcv + ibGrad_*ibPatch_.ibDelta();
84  }
85 }
86 
87 
88 template<class Type>
91 {
92  // Get addressing
93  const labelList& ibc = ibPatch_.ibCells();
94  const labelListList& ibCellCells = ibPatch_.ibCellCells();
95  const List<List<labelPair> >& ibCellProcCells = ibPatch_.ibCellProcCells();
96  const PtrList<scalarRectangularMatrix>& invMat =
97  ibPatch_.invDirichletMatrices();
98 
99  const vectorField& ibp = ibPatch_.ibPoints();
100 
101  // Note: the algorithm is originally written with inward-facing normals
102  // and subsequently changed: IB surface normals point outwards
103  // HJ, 21/May/2012
104  const vectorField& ibn = ibPatch_.ibNormals();
105 
106  // Collect Dirichlet values from IB triagulation
107  ibValue_ = ibPatch_.toIbPoints(refValue_);
108 
109  // Reset the size and value of snGrad
110  ibGrad_.setSize(ibc.size());
111  ibGrad_ = pTraits<Type>::zero;
112 
113  // Get access to internal field
114  const Field<Type>& psiI = this->internalField();
115 
116  // Collect polynomially interpolated values in IB cells
117  tmp<Field<Type> > tpolyPsi(new Field<Type>(psiI, ibc));
118  Field<Type>& polyPsi = tpolyPsi();
119 
120  const vectorField& C = mesh_.cellCentres();
121 
122  // Dimension the matrix
123  label nCoeffs = 5;
124  if (mesh_.nGeometricD() == 3)
125  {
126  nCoeffs += 4;
127  }
128 
129  label counter = 0;
130  scalarField error(ibc.size(), 0);
131 
132  // Note
133  // In parallel, some processors will have IB cells and others will not.
134  // Therefore, special reduce is needed instead of gMax.
135  // HJ, 7/Dec/2012
136  scalar maxError = 0;
137 
138  do
139  {
140  counter++;
141 
142  // Parallel communication for psi
143  FieldField<Field, Type> procPsi = ibPatch_.sendAndReceive(psiI);
144 
145  // Prepare error normalisation
146  scalar maxMagPolyPsi = 0;
147 
148  forAll (ibc, cellI)
149  {
150  label curCell = ibc[cellI];
151 
152  const labelList& curCells = ibCellCells[cellI];
153 
154  const List<labelPair>& curProcCells = ibCellProcCells[cellI];
155 
156  const scalarRectangularMatrix& curInvMatrix = invMat[cellI];
157 
158  Field<Type> coeffs(nCoeffs, pTraits<Type>::zero);
159  Field<Type> source
160  (
161  curCells.size() + curProcCells.size(),
163  );
164 
165  label pointID = 0;
166  for (label i = 0; i < curCells.size(); i++)
167  {
168  source[pointID++] = psiI[curCells[i]] - ibValue_[cellI];
169  }
170 
171  for (label i = 0; i < curProcCells.size(); i++)
172  {
173  source[pointID++] =
174  procPsi
175  [
176  curProcCells[i].first()
177  ]
178  [
179  curProcCells[i].second()
180  ]
181  - ibValue_[cellI];
182  }
183 
184  for (label i = 0; i < nCoeffs; i++)
185  {
186  for (label j = 0; j < source.size(); j++)
187  {
188  coeffs[i] += curInvMatrix[i][j]*source[j];
189  }
190  }
191 
192  Type oldPolyPsi = polyPsi[cellI];
193 
194  vector R = C[curCell] - ibp[cellI];
195 
196  polyPsi[cellI] =
197  ibValue_[cellI]
198  + coeffs[0]*R.x()
199  + coeffs[1]*R.y()
200  + coeffs[2]*R.x()*R.y()
201  + coeffs[3]*sqr(R.x())
202  + coeffs[4]*sqr(R.y());
203 
204  if (mesh_.nGeometricD() == 3)
205  {
206  polyPsi[cellI] +=
207  coeffs[5]*R.z()
208  + coeffs[6]*R.x()*R.z()
209  + coeffs[7]*R.y()*R.z()
210  + coeffs[8]*sqr(R.z());
211  }
212 
213  // Change of sign of ibn
214  ibGrad_[cellI] =
215  -coeffs[0]*ibn[cellI].x()
216  - coeffs[1]*ibn[cellI].y();
217 
218  if (mesh_.nGeometricD() == 3)
219  {
220  // Change of sign of ibn
221  ibGrad_[cellI] +=
222  -coeffs[5]*ibn[cellI].z();
223  }
224 
225  error[cellI] = mag(polyPsi[cellI] - oldPolyPsi);
226  }
227 
228  // Insert polynomial values into the internal field
229  setIbCellValues(polyPsi);
230 
231  // Parallelisation fixes. HJ, 7/Dec/2012
232 
233  // Reduce max polyPsi
234  if (!polyPsi.empty())
235  {
236  maxMagPolyPsi = max(mag(polyPsi));
237  }
238  else
239  {
240  // No IB cells
241  maxMagPolyPsi = 0;
242  }
243 
244  reduce(maxMagPolyPsi, maxOp<scalar>());
245 
246  error /= maxMagPolyPsi + SMALL;
247 
248  // Reduce max error
249  if (!polyPsi.empty())
250  {
251  maxError = max(error);
252  }
253  else
254  {
255  // No IB cells
256  maxError = 0;
257  }
258 
259  reduce(maxError, maxOp<scalar>());
260  }
261  while (maxError > bcTolerance_ && counter < nBcIter_);
262 
263  if (counter == nBcIter_() && debug)
264  {
265  InfoIn
266  (
267  "template<class Type>\n"
268  "tmp<Foam::Field<Type> >\n"
269  "immersedBoundaryFvPatchField<Type>::"
270  "imposeDirichletCondition() const"
271  ) << this->dimensionedInternalField().name()
272  << " for patch " << this->patch().name()
273  << ", error, max: " << gMax(error)
274  << ", min: " << gMin(error)
275  << ", avg: " << gAverage(error) << endl;
276  }
277 
278  return tpolyPsi;
279 }
280 
281 
282 template<class Type>
285 {
286  // Get addressing
287  const labelList& ibc = ibPatch_.ibCells();
288 
289  const labelListList& ibCellCells = ibPatch_.ibCellCells();
290 
291  const List<List<labelPair> >& ibCellProcCells = ibPatch_.ibCellProcCells();
292 
293  const PtrList<scalarRectangularMatrix>& invMat =
294  ibPatch_.invNeumannMatrices();
295 
296  const vectorField& ibp = ibPatch_.ibPoints();
297 
298  // Collect Neumann values from IB triagulation
299  ibGrad_ = ibPatch_.toIbPoints(refGrad_);
300 
301  // Reset the size and value of
302  ibValue_.setSize(ibc.size());
303  ibValue_ = pTraits<Type>::zero;
304 
305  // Get access to internal field
306  const Field<Type>& psiI = this->internalField();
307 
308  // Collect polynomially interpolated values in IB cells
309  tmp<Field<Type> > tpolyPsi(new Field<Type>(psiI, ibc));
310  Field<Type>& polyPsi = tpolyPsi();
311 
312  const vectorField& C = mesh_.cellCentres();
313 
314  // Dimension the matrix
315  label nCoeffs = 6;
316  if (mesh_.nGeometricD() == 3)
317  {
318  nCoeffs += 4;
319  }
320 
321  label counter = 0;
322  scalarField error(ibc.size(), 0);
323 
324  // Initialise ibCell values using sampling point values to reduce
325  // the number of iterations. HJ, 26/Oct/2012
326  setIbCellValues(ibSamplingPointValue());
327 
328  // Note
329  // In parallel, some processors will have IB cells and others will not.
330  // Therefore, special reduce is needed instead of gMax.
331  // HJ, 7/Dec/2012
332  scalar maxError = 0;
333 
334  do
335  {
336  counter++;
337 
338  // Parallel communication for psi
339  FieldField<Field, Type> procPsi = ibPatch_.sendAndReceive(psiI);
340 
341  // Prepare error normalisation
342  scalar maxMagPolyPsi = 0;
343 
344  forAll (ibc, cellI)
345  {
346  label curCell = ibc[cellI];
347 
348  const labelList& curCells = ibCellCells[cellI];
349  const List<labelPair>& curProcCells = ibCellProcCells[cellI];
350 
351  const scalarRectangularMatrix& curInvMatrix = invMat[cellI];
352 
353  Field<Type> coeffs(nCoeffs, pTraits<Type>::zero);
354  Field<Type> source
355  (
356  curCells.size() + 1 + curProcCells.size(),
358  );
359 
360  label pointID = 0;
361  for (label i = 0; i < curCells.size(); i++)
362  {
363  source[pointID++] = psiI[curCells[i]];
364  }
365 
366  source[pointID++] = ibGrad_[cellI];
367 
368  for (label i = 0; i < curProcCells.size(); i++)
369  {
370  source[pointID++] =
371  procPsi
372  [
373  curProcCells[i].first()
374  ]
375  [
376  curProcCells[i].second()
377  ];
378  }
379 
380  for (label i = 0; i < nCoeffs; i++)
381  {
382  for (label j = 0; j < source.size(); j++)
383  {
384  coeffs[i] += curInvMatrix[i][j]*source[j];
385  }
386  }
387 
388  Type oldPolyPsi = polyPsi[cellI];
389 
390  vector ibR = C[curCell] - ibp[cellI];
391 
392  polyPsi[cellI] =
393  coeffs[0]
394  + coeffs[1]*ibR.x()
395  + coeffs[2]*ibR.y()
396  + coeffs[3]*ibR.x()*ibR.y()
397  + coeffs[4]*sqr(ibR.x())
398  + coeffs[5]*sqr(ibR.y());
399 
400  if (mesh_.nGeometricD() == 3)
401  {
402  polyPsi[cellI] +=
403  coeffs[6]*ibR.z()
404  + coeffs[7]*ibR.x()*ibR.z()
405  + coeffs[8]*ibR.y()*ibR.z()
406  + coeffs[9]*sqr(ibR.z());
407  }
408 
409  ibValue_[cellI] = coeffs[0];
410 
411  error[cellI] = mag(polyPsi[cellI] - oldPolyPsi);
412  }
413 
414  // Insert polynomial values into the internal field
415  setIbCellValues(polyPsi);
416 
417  // Parallelisation fixes. HJ, 7/Dec/2012
418 
419  // Reduce max polyPsi
420  if (!polyPsi.empty())
421  {
422  maxMagPolyPsi = max(mag(polyPsi));
423  }
424  else
425  {
426  // No IB cells
427  maxMagPolyPsi = 0;
428  }
429 
430  reduce(maxMagPolyPsi, maxOp<scalar>());
431 
432  error /= maxMagPolyPsi + SMALL;
433 
434  // Reduce max error
435  if (!polyPsi.empty())
436  {
437  maxError = max(error);
438  }
439  else
440  {
441  // No IB cells
442  maxError = 0;
443  }
444 
445  reduce(maxError, maxOp<scalar>());
446  }
447  while (maxError > bcTolerance_() && counter < nBcIter_());
448 
449  if (counter == nBcIter_() && debug)
450  {
451  InfoIn
452  (
453  "template<class Type>\n"
454  "tmp<Foam::Field<Type> >\n"
455  "immersedBoundaryFvPatchField<Type>::"
456  "imposeNeumannCondition() const"
457  ) << this->dimensionedInternalField().name()
458  << " for patch " << this->patch().name()
459  << ", error, max: " << gMax(error)
460  << ", min: " << gMin(error)
461  << ", avg: " << gAverage(error) << endl;
462  }
463 
464 // Info<< "Neumann condition for " << ibc.size() << " cells of field "
465 // << this->dimensionedInternalField().name() << " = "
466 // << polyPsi
467 // << endl;
468 
469  return tpolyPsi;
470 }
471 
472 
473 template<class Type>
475 {
476  const labelList& dc = ibPatch_.deadCells();
477 
478 // Info<< "Dead condition for " << dc.size() << " cells of field "
479 // << this->dimensionedInternalField().name()
480 // << " set to value " << deadCellValue_
481 // << endl;
482 
483  // Get non-const access to internal field
484  Field<Type>& psiI = const_cast<Field<Type>&>(this->internalField());
485 
486  forAll (dc, dcI)
487  {
488  psiI[dc[dcI]] = deadCellValue_;
489  }
490 }
491 
492 
493 template<class Type>
495 (
496  fvMatrix<Type>& eqn
497 ) const
498 {
499  scalarField& Diag = eqn.diag();
500 
501  const labelList& dce = ibPatch_.deadCellsExt();
502 
503  // Estimate diagonal in live cells
504  scalar liveDiag = 1;
505 
506  if (dce.size() < Diag.size())
507  {
508  liveDiag = gSumMag(Diag)/(Diag.size() - dce.size());
509 
510  // Correct for sign
511  liveDiag *= sign(gMax(Diag));
512  }
513 
514  forAll (dce, cellI)
515  {
516  if (mag(Diag[dce[cellI]]) < SMALL)
517  {
518  Diag[dce[cellI]] = liveDiag;
519  }
520  }
521 }
522 
523 
524 template<class Type>
526 (
527  fvMatrix<Type>& eqn
528 ) const
529 {
530  // Calculate gradient contribution
531  const labelList& ibFaces = ibPatch_.ibFaces();
532  const labelList& ibFaceCells = ibPatch_.ibFaceCells();
533 
534  const scalarField& ibGamma = ibPatch_.gamma().internalField();
535 
536  const unallocLabelList& own = mesh_.owner();
537  const unallocLabelList& nei = mesh_.neighbour();
538 
539  // Get delta coefficients
540  const surfaceScalarField& dc = mesh_.deltaCoeffs();
541  const scalarField& dcI = dc.internalField();
542 
543  if (eqn.symmetric())
544  {
545  scalarField& diag = eqn.diag();
546  scalarField& upper = eqn.upper();
547  Field<Type>& source = eqn.source();
548 
549 // Info<< "Symmetric correctOffDiag for field "
550 // << this->dimensionedInternalField().name() << endl;
551 
552  forAll (ibFaces, faceI)
553  {
554  const label curFace = ibFaces[faceI];
555 
556  if (curFace < nei.size())
557  {
558  // Internal face. One side is an ibCell and another is a
559  // live cell. Add gradient to the source of the live cell
560  // and kill the off-diagonal coefficient
561  if (ibGamma[own[curFace]] > SMALL)
562  {
563  diag[own[curFace]] += upper[curFace];
564 
565  source[own[curFace]] +=
566  upper[curFace]*ibGrad_[ibFaceCells[faceI]]
567  /dcI[curFace];
568  }
569  else
570  {
571  diag[nei[curFace]] += upper[curFace];
572 
573  source[nei[curFace]] -=
574  upper[curFace]*ibGrad_[ibFaceCells[faceI]]
575  /dcI[curFace];
576  }
577 
578  upper[curFace] = 0;
579  }
580  else
581  {
582  // else MPH
583  label patchi = mesh_.boundaryMesh().whichPatch(curFace);
584 
585  if (!eqn.internalCoeffs()[patchi].empty())
586  {
587  label patchFacei =
588  mesh_.boundaryMesh()[patchi].whichFace(curFace);
589 
590  eqn.internalCoeffs()[patchi][patchFacei] =
592 
593  eqn.boundaryCoeffs()[patchi][patchFacei] =
595 
596  // Check if the live cell is on local or neighbour side
597  // HJ, 7/Dec/2012
598  if (ibFaceCells[faceI] > -1)
599  {
600  if (ibGamma[ibFaceCells[faceI]] > SMALL)
601  {
602  source[ibFaceCells[faceI]] +=
603  ibGrad_[ibFaceCells[faceI]]
604  /dc.boundaryField()[patchi][patchFacei];
605  }
606  }
607  }
608  }
609  }
610  }
611  else if (eqn.asymmetric())
612  {
613  scalarField& diag = eqn.diag();
614  scalarField& upper = eqn.upper();
615  scalarField& lower = eqn.lower();
616  Field<Type>& source = eqn.source();
617 
618 // Info<< "Asymmetric correctOffDiag for field "
619 // << this->dimensionedInternalField().name() << endl;
620 
621  forAll (ibFaces, faceI)
622  {
623  const label curFace = ibFaces[faceI];
624 
625  if (curFace < nei.size())
626  {
627  // Internal face. One side is an ibCell and another is a
628  // live cell. Add gradient to the source of the live cell
629  // and kill the off-diagonal coefficient
630  if (ibGamma[own[curFace]] > SMALL)
631  {
632  diag[own[curFace]] += upper[curFace];
633 
634  source[own[curFace]] +=
635  upper[curFace]*ibGrad_[ibFaceCells[faceI]]/dcI[faceI];
636  }
637  else
638  {
639  diag[nei[curFace]] += lower[curFace];
640 
641  source[nei[curFace]] -=
642  lower[curFace]*ibGrad_[ibFaceCells[faceI]]/dcI[faceI];
643  }
644 
645  upper[curFace] = 0;
646  lower[curFace] = 0;
647  }
648  else
649  {
650  // else MPH
651  label patchi = mesh_.boundaryMesh().whichPatch(curFace);
652 
653  if (!eqn.internalCoeffs()[patchi].empty())
654  {
655  label patchFacei =
656  mesh_.boundaryMesh()[patchi].whichFace(curFace);
657 
658  eqn.internalCoeffs()[patchi][patchFacei] =
660 
661  eqn.boundaryCoeffs()[patchi][patchFacei] =
663 
664  // Check if the live cell is on local or neighbour side
665  // HJ, 7/Dec/2012
666  if (ibFaceCells[faceI] > -1)
667  {
668  if (ibGamma[ibFaceCells[faceI]] > SMALL)
669  {
670  source[ibFaceCells[faceI]] +=
671  ibGrad_[ibFaceCells[faceI]]
672  /dc.boundaryField()[patchi][patchFacei];
673  }
674  }
675  }
676  }
677  }
678  }
679 
680  // Note: potentially deal with face flux correction ptr.
681  // HJ, 16/Apr/2012
682 }
683 
684 
685 // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
686 
687 template<class Type>
689 {
690  if
691  (
692  ibPatch_.movingIb()
693  || ibPatch_.boundaryMesh().mesh().moving()
694  )
695  {
696  if
697  (
698  ibUpdateTimeIndex_
699  != ibPatch_.boundaryMesh().mesh().time().timeIndex()
700  )
701  {
702  // Mesh is moving and current time has not been updated
703  return true;
704  }
705  }
706 
707  return false;
708 }
709 
710 
711 template<class Type>
713 {
714  // Motion update, clear data related to immersed boundary points
715  ibValue_.clear();
716  ibGrad_.clear();
717 
718  // Record motion update time
719  ibUpdateTimeIndex_ = ibPatch_.boundaryMesh().mesh().time().timeIndex();
720 }
721 
722 
723 template<class Type>
725 (
726  const Field<Type>& ibcValues
727 ) const
728 {
729  const labelList& ibc = ibPatch_.ibCells();
730 
731  if (ibcValues.size() != ibc.size())
732  {
734  (
735  "template<class Type>\n"
736  "void immersedBoundaryFvPatchField<Type>::setIbCellValues\n"
737  "(\n"
738  " const Field<Type>& ibcValues\n"
739  ") const"
740  ) << "Size of ibcValues field not equal to the number of IB cells."
741  << nl << "ibcValues: " << ibcValues.size()
742  << " ibc: " << ibc.size()
743  << abort(FatalError);
744  }
745 
746  // Get non-const access to internal field
747  Field<Type>& psiI = const_cast<Field<Type>&>(this->internalField());
748 
749  forAll (ibcValues, cellI)
750  {
751  psiI[ibc[cellI]] = ibcValues[cellI];
752  }
753 }
754 
755 
756 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
757 
758 template<class Type>
760 (
761  const fvPatch& p,
763 )
764 :
765  fvPatchField<Type>(p, iF),
766  ibPatch_(refCast<const immersedBoundaryFvPatch>(p)),
767  mesh_(p.boundaryMesh().mesh()),
768  refValue_(ibPatch_.ibMesh().size(), pTraits<Type>::zero),
769  refGrad_(ibPatch_.ibMesh().size(), pTraits<Type>::zero),
770  fixesValue_(false),
771  setDeadCellValue_(false),
772  deadCellValue_(pTraits<Type>::zero),
773  ibValue_(),
774  ibGrad_()
775 {}
776 
777 
778 template<class Type>
780 (
781  const fvPatch& p,
783  const dictionary& dict
784 )
785 :
786  fvPatchField<Type>(p, iF, dict),
787  ibPatch_(refCast<const immersedBoundaryFvPatch>(p)),
788  mesh_(p.boundaryMesh().mesh()),
789  refValue_("refValue", dict, ibPatch_.ibMesh().size()),
790  refGrad_("refGradient", dict, ibPatch_.ibMesh().size()),
791  fixesValue_(dict.lookup("fixesValue")),
792  setDeadCellValue_(dict.lookup("setDeadCellValue")),
793  deadCellValue_(pTraits<Type>(dict.lookup("deadCellValue"))),
794  ibValue_(),
795  ibGrad_()
796 {
797  if (!isType<immersedBoundaryFvPatch>(p))
798  {
800  (
801  "immersedBoundaryFvPatchField<Type>::"
802  "immersedBoundaryFvPatchField\n"
803  "(\n"
804  " const fvPatch& p,\n"
805  " const Field<Type>& field,\n"
806  " const dictionary& dict\n"
807  ")\n",
808  dict
809  ) << "\n patch type '" << p.type()
810  << "' not constraint type '" << typeName << "'"
811  << "\n for patch " << p.name()
812  << " of field " << this->dimensionedInternalField().name()
813  << " in file " << this->dimensionedInternalField().objectPath()
814  << exit(FatalIOError);
815  }
816 }
817 
818 
819 template<class Type>
821 (
823  const fvPatch& p,
825  const fvPatchFieldMapper& mapper
826 )
827 :
828  fvPatchField<Type>(ptf, p, iF, mapper),
829  ibPatch_(refCast<const immersedBoundaryFvPatch>(p)),
830  mesh_(p.boundaryMesh().mesh()),
831  refValue_(ptf.refValue()),
832  refGrad_(ptf.refGrad()),
833  fixesValue_(ptf.fixesValue()),
834  setDeadCellValue_(ptf.setDeadCellValue_),
835  deadCellValue_(ptf.deadCellValue_),
836  ibValue_(),
837  ibGrad_()
838 {
839  // Note: NO MAPPING. Fields are created on the immersed boundary
840  // HJ, 12/Apr/2012
841  if (!isType<immersedBoundaryFvPatch>(p))
842  {
844  (
845  "immersedBoundaryFvPatchField<Type>::"
846  "immersedBoundaryFvPatchField\n"
847  "(\n"
848  " const immersedBoundaryFvPatchField<Type>&,\n"
849  " const fvPatch& p,\n"
850  " const DimensionedField<Type, volMesh>& iF,\n"
851  " const fvPatchFieldMapper& mapper\n"
852  ")\n"
853  ) << "\n patch type '" << p.type()
854  << "' not constraint type '" << typeName << "'"
855  << "\n for patch " << p.name()
856  << " of field " << this->dimensionedInternalField().name()
857  << " in file " << this->dimensionedInternalField().objectPath()
858  << exit(FatalIOError);
859  }
860 }
861 
862 
863 template<class Type>
865 (
867 )
868 :
869  fvPatchField<Type>(ptf),
870  ibPatch_(ptf.ibPatch()),
871  mesh_(ptf.patch().boundaryMesh().mesh()),
872  refValue_(ptf.refValue()),
873  refGrad_(ptf.refGrad()),
874  fixesValue_(ptf.fixesValue()),
875  setDeadCellValue_(ptf.setDeadCellValue_),
876  deadCellValue_(ptf.deadCellValue_),
877  ibValue_(),
878  ibGrad_()
879 {}
880 
881 
882 template<class Type>
884 (
887 )
888 :
889  fvPatchField<Type>(ptf, iF),
890  ibPatch_(ptf.ibPatch()),
891  mesh_(ptf.patch().boundaryMesh().mesh()),
892  refValue_(ptf.refValue()),
893  refGrad_(ptf.refGrad()),
894  fixesValue_(ptf.fixesValue()),
895  setDeadCellValue_(ptf.setDeadCellValue_),
896  deadCellValue_(ptf.deadCellValue_),
897  ibValue_(),
898  ibGrad_()
899 {}
900 
901 
902 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
903 
904 template<class Type>
906 {
907  // Note: on a moving mesh, the intersection has changed and
908  // ibValue and ibGrad fields should be cleared and recalculated.
909  // HJ, 17/Oct/2012
910  if (this->motionUpdateRequired())
911  {
912  motionUpdate();
913  }
914 
915  if (ibValue_.empty())
916  {
917  this->updateIbValues();
918  }
919 
920  return ibValue_;
921 }
922 
923 
924 template<class Type>
926 {
927  // Note: on a moving mesh, the intersection has changed and
928  // ibValue and ibGrad fields should be cleared and recalculated.
929  // HJ, 17/Oct/2012
930  if (this->motionUpdateRequired())
931  {
932  motionUpdate();
933  }
934 
935  if (ibGrad_.empty())
936  {
937  this->updateIbValues();
938  }
939 
940  return ibGrad_;
941 }
942 
943 
944 template<class Type>
946 {
947  // Collect IB cell values
948  tmp<Field<Type> > tibcv
949  (
950  new Field<Type>
951  (
952  this->internalField(),
953  ibPatch_.ibCells()
954  )
955  );
956 
957  return tibcv;
958 }
959 
960 
961 template<class Type>
964 {
965  return ibPatch_.toSamplingPoints(this->internalField());
966 }
967 
968 
969 template<class Type>
971 {
972  return ibPatch_.toTriFaces(this->ibValue());
973 }
974 
975 
976 template<class Type>
978 {
979  return ibPatch_.toTriFaces(this->ibGrad());
980 }
981 
982 
983 template<class Type>
985 {
986  if (this->fixesValue())
987  {
988  this->imposeDirichletCondition();
989  }
990  else
991  {
992  this->imposeNeumannCondition();
993  }
994 
995  // Fix the value in dead cells
996  if (setDeadCellValue_)
997  {
998  this->imposeDeadCondition();
999  }
1000 
1002 }
1003 
1004 
1005 template<class Type>
1008  const Pstream::commsTypes
1009 )
1010 {
1011  this->updateCoeffs();
1012 }
1013 
1014 
1015 template<class Type>
1018  const Pstream::commsTypes
1019 )
1020 {
1021  // Note
1022  // Since the boundary condition is performed by data fitting with the
1023  // internal field, fitting must be performed both on updateCoeffs
1024  // and on evaluate (internal field has changed in the meantime).
1025  // Bug fix, Zeljko Tukovic, 21/Jun/2012
1026 // this->updateCoeffs();
1027 
1029 }
1030 
1031 
1032 template<class Type>
1035  fvMatrix<Type>& eqn
1036 )
1037 {
1038  this->initEvaluate();
1039 
1040  // Build matrix diagonal for cells where it is missing
1041  this->correctDiag(eqn);
1042 
1043  // For Neumann boundary condition, manipulate matrix off-diagonal
1044  if (!this->fixesValue())
1045  {
1046  this->correctOffDiag(eqn);
1047  }
1048 
1049  // Set values in IB cells
1050  Field<Type> polyPsi(eqn.psi(), ibPatch_.ibCells());
1051  eqn.setValues(ibPatch_.ibCells(), polyPsi);
1052 
1053  // Correct equation for dead cells
1054  Field<Type> deadCellsPsi
1055  (
1056  ibPatch_.deadCells().size(),
1057  deadCellValue_
1058  );
1059  eqn.setValues(ibPatch_.deadCells(), deadCellsPsi);
1060 
1062 }
1063 
1064 
1065 template<class Type>
1067 {
1069  refValue_.writeEntry("refValue", os);
1070  refGrad_.writeEntry("refGradient", os);
1071  os.writeKeyword("fixesValue") << fixesValue_ << token::END_STATEMENT << nl;
1072  os.writeKeyword("setDeadCellValue")
1073  << setDeadCellValue_ << token::END_STATEMENT << nl;
1074  os.writeKeyword("deadCellValue")
1075  << deadCellValue_ << token::END_STATEMENT << nl;
1076 
1077  this->writeEntry("value", os);
1078 
1079  // Write immersed boundary data as a vtk file
1080  autoPtr<surfaceWriter<Type> > writerPtr =
1081  surfaceWriter<Type>::New("vtk");
1082 
1083  const triSurface& ts = ibPatch_.ibMesh();
1084 
1085  // Make a face list for writing
1086  faceList f(ts.size());
1087  forAll (ts, faceI)
1088  {
1089  f[faceI] = ts[faceI].triFaceFace();
1090  }
1091 
1092  writerPtr->write
1093  (
1094  this->dimensionedInternalField().path(),
1095  ibPatch_.name(),
1096  ts.points(),
1097  f,
1098  this->dimensionedInternalField().name(),
1099  this->triValue()()
1100  );
1101 }
1102 
1103 
1104 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1105 
1106 } // End namespace Foam
1107 
1108 // ************************************************************************* //
Foam::fvPatchField< Type >
Foam::fvPatchField::write
virtual void write(Ostream &) const
Write.
Definition: fvPatchField.C:349
Foam::immersedBoundaryFvPatchField::manipulateMatrix
virtual void manipulateMatrix(fvMatrix< Type > &matrix)
Manipulate matrix.
Definition: immersedBoundaryFvPatchField.C:1034
Foam::maxOp
Definition: ops.H:172
Foam::token::END_STATEMENT
@ END_STATEMENT
Definition: token.H:99
Foam::fvPatchField::evaluate
virtual void evaluate(const Pstream::commsTypes commsType=Pstream::blocking)
Evaluate the patch field, sets Updated to false.
Definition: fvPatchField.C:318
InfoIn
#define InfoIn(functionName)
Report a information message using Foam::Info.
Definition: messageStream.H:276
Foam::PrimitivePatch::points
const Field< PointType > & points() const
Return reference to global points.
Definition: PrimitivePatchTemplate.H:282
p
p
Definition: pEqn.H:62
Foam::FieldField
Generic field type.
Definition: FieldField.H:51
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:118
Foam::gAverage
Type gAverage(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:571
Foam::diag
void diag(pointPatchField< vector > &, const pointPatchField< tensor > &)
Definition: pointPatchFieldFunctions.H:262
Foam::immersedBoundaryFvPatchField::evaluate
virtual void evaluate(const Pstream::commsTypes commsType=Pstream::blocking)
Evaluate the patch field.
Definition: immersedBoundaryFvPatchField.C:1017
dimensionedInternalField
rDeltaT dimensionedInternalField()
Foam::dictionary::lookup
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:449
Foam::immersedBoundaryFvPatchField::initEvaluate
virtual void initEvaluate(const Pstream::commsTypes commsType=Pstream::blocking)
Initialise the evaluation of the patch field.
Definition: immersedBoundaryFvPatchField.C:1007
Foam::immersedBoundaryFvPatchField::refGrad
virtual Field< Type > & refGrad()
Return access to reference gradient.
Definition: immersedBoundaryFvPatchField.H:258
Foam::GeometricField::boundaryField
GeometricBoundaryField & boundaryField()
Return reference to GeometricBoundaryField.
Definition: GeometricField.C:735
Foam::fvMatrix::internalCoeffs
FieldField< Field, Type > & internalCoeffs()
fvBoundary scalar field containing pseudo-matrix coeffs
Definition: fvMatrix.H:303
Foam::FatalIOError
IOerror FatalIOError
fvMatrix.H
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
fvPatchFieldMapper.H
Foam::immersedBoundaryFvPatchField::ibValue
const Field< Type > & ibValue() const
Return fields on intersection points interacting with the IB.
Definition: immersedBoundaryFvPatchField.C:905
surfaceWriter.H
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
Foam::fvBoundaryMesh::mesh
const fvMesh & mesh() const
Return the mesh reference.
Definition: fvBoundaryMesh.H:99
Foam::sign
dimensionedScalar sign(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:179
Foam::fvMatrix::psi
const GeometricField< Type, fvPatchField, volMesh > & psi() const
Definition: fvMatrix.H:281
Foam::fileName::name
word name() const
Return file name (part beyond last /)
Definition: fileName.C:212
Foam::fvPatch::boundaryMesh
const fvBoundaryMesh & boundaryMesh() const
Return boundaryMesh reference.
Definition: fvPatch.H:185
Foam::immersedBoundaryFvPatchField::motionUpdateRequired
bool motionUpdateRequired() const
Does immersed boundary patch field need motion update?
Definition: immersedBoundaryFvPatchField.C:688
Foam::immersedBoundaryFvPatchField::immersedBoundaryFvPatchField
immersedBoundaryFvPatchField(const fvPatch &, const DimensionedField< Type, volMesh > &)
Construct from patch and internal field.
Definition: immersedBoundaryFvPatchField.C:760
Foam::immersedBoundaryFvPatchField::refValue
virtual Field< Type > & refValue()
Return access to reference value.
Definition: immersedBoundaryFvPatchField.H:246
Foam::immersedBoundaryFvPatchField::imposeDeadCondition
void imposeDeadCondition()
Impose condition in dead cells.
Definition: immersedBoundaryFvPatchField.C:474
Foam::immersedBoundaryFvPatchField::updateCoeffs
void updateCoeffs()
Update the coefficients associated with the patch field.
Definition: immersedBoundaryFvPatchField.C:984
Foam::immersedBoundaryFvPatchField::updateIbValues
void updateIbValues() const
Update IB value and gradient.
Definition: immersedBoundaryFvPatchField.C:59
Foam::debug::optimisationSwitch
int optimisationSwitch(const char *name, const int defaultValue=0)
Lookup optimisation switch or add default value.
Definition: debug.C:182
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:43
Foam::fvMatrix::setValues
void setValues(const labelUList &cells, const UList< Type > &values)
Set solution in given cells to the specified values.
R
#define R(A, B, C, D, E, F, K, M)
immersedBoundaryFvPatchField.H
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::Field< Type >
Foam::triSurface
Triangulated surface description with patch information.
Definition: triSurface.H:57
Foam::immersedBoundaryFvPatchField::ibPatch
const immersedBoundaryFvPatch & ibPatch() const
Return reference to immersed boundary patch.
Definition: immersedBoundaryFvPatchField.H:235
Foam::immersedBoundaryFvPatchField::ibGrad
const Field< Type > & ibGrad() const
Return IB surface-normal gradient.
Definition: immersedBoundaryFvPatchField.C:925
Foam::immersedBoundaryFvPatchField::fixesValue
virtual bool fixesValue() const
Return true if this patch field fixes a value.
Definition: immersedBoundaryFvPatchField.H:270
Foam::immersedBoundaryFvPatchField::correctOffDiag
void correctOffDiag(fvMatrix< Type > &eqn) const
Impose fixed gradient condition by manipulating matrix.
Definition: immersedBoundaryFvPatchField.C:526
Foam::nl
static const char nl
Definition: Ostream.H:260
Foam::immersedBoundaryFvPatchField::imposeDirichletCondition
tmp< Field< Type > > imposeDirichletCondition() const
Impose Dirichlet BC at IB cells and return corrected cells values.
Definition: immersedBoundaryFvPatchField.C:90
Foam::immersedBoundaryFvPatchField::ibCellValue
tmp< Field< Type > > ibCellValue() const
Return IB cell field.
Definition: immersedBoundaryFvPatchField.C:945
Foam::immersedBoundaryFvPatchField::deadCellValue_
Type deadCellValue_
Dead cell value.
Definition: immersedBoundaryFvPatchField.H:86
Foam::immersedBoundaryFvPatchField::ibSamplingPointValue
tmp< Field< Type > > ibSamplingPointValue() const
Return IB sample point field.
Definition: immersedBoundaryFvPatchField.C:963
Foam::immersedBoundaryFvPatchField::write
virtual void write(Ostream &) const
Write.
Definition: immersedBoundaryFvPatchField.C:1066
Foam::fvPatch
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:61
FatalIOErrorIn
#define FatalIOErrorIn(functionName, ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:324
Foam::GeometricField::internalField
InternalField & internalField()
Return internal field.
Definition: GeometricField.C:724
Foam::immersedBoundaryFvPatchField::triGrad
tmp< Field< Type > > triGrad() const
Return IB surface-normal gradient.
Definition: immersedBoundaryFvPatchField.C:977
Foam::PtrList
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: List.H:61
Foam::RectangularMatrix< scalar >
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::Vector::x
const Cmpt & x() const
Definition: VectorI.H:65
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:137
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::immersedBoundaryFvPatchField::bcTolerance_
static const debug::tolerancesSwitch bcTolerance_
Boundary condition update tolerance.
Definition: immersedBoundaryFvPatchField.H:162
Foam::Vector::z
const Cmpt & z() const
Definition: VectorI.H:77
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:131
Foam::fvPatchField::manipulateMatrix
virtual void manipulateMatrix(fvMatrix< Type > &matrix)
Manipulate matrix.
Definition: fvPatchField.C:331
Foam::gSumMag
scalar gSumMag(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:565
Foam::fvPatchField::updateCoeffs
virtual void updateCoeffs()
Update the coefficients associated with the patch field.
Definition: fvPatchField.C:296
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::fvMatrix::boundaryCoeffs
FieldField< Field, Type > & boundaryCoeffs()
fvBoundary scalar field containing pseudo-matrix coeffs
Definition: fvMatrix.H:310
Foam::immersedBoundaryFvPatchField::setDeadCellValue_
Switch setDeadCellValue_
Set dead cell value.
Definition: immersedBoundaryFvPatchField.H:83
internalField
conserve internalField()+
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::immersedBoundaryFvPatchField::nBcIter_
static const debug::optimisationSwitch nBcIter_
Number of boundary condition update iterations.
Definition: immersedBoundaryFvPatchField.H:159
Foam::autoPtr
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:117
Foam::immersedBoundaryFvPatchField::correctDiag
void correctDiag(fvMatrix< Type > &eqn) const
Check and correct zero diagonal in dead cells.
Definition: immersedBoundaryFvPatchField.C:495
Foam::UPstream::commsTypes
commsTypes
Types of communications.
Definition: UPstream.H:64
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:49
f
labelList f(nPoints)
Foam::surfaceWriter::New
static autoPtr< surfaceWriter > New(const word &writeType)
Return a reference to the selected surfaceWriter.
Definition: surfaceWriter.C:55
Foam::Vector< scalar >
Foam::immersedBoundaryFvPatchField::setIbCellValues
virtual void setIbCellValues(const Field< Type > &) const
Set IB cell values.
Definition: immersedBoundaryFvPatchField.C:725
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
Foam::pTraits
Traits class for primitives.
Definition: pTraits.H:50
Foam::fvMatrix::source
Field< Type > & source()
Definition: fvMatrix.H:291
Foam::Ostream::writeKeyword
Ostream & writeKeyword(const keyType &)
Write the keyword followed by an appropriate indentation.
Definition: Ostream.C:59
Foam::UList
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:60
patchi
label patchi
Definition: getPatchFieldScalar.H:1
Foam::immersedBoundaryFvPatchField
Foam::immersedBoundaryFvPatchField.
Definition: immersedBoundaryFvPatchField.H:53
path
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
Foam::fvMatrix< Type >
Foam::immersedBoundaryFvPatchField::imposeNeumannCondition
tmp< Field< Type > > imposeNeumannCondition() const
Impose Neumann BC at IB cells and return corrected cells values.
Definition: immersedBoundaryFvPatchField.C:284
Foam::Vector::y
const Cmpt & y() const
Definition: VectorI.H:71
FatalErrorIn
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:313
Foam::fvPatchFieldMapper
Foam::fvPatchFieldMapper.
Definition: fvPatchFieldMapper.H:45
Foam::fvPatchField< Type >::patch
const fvPatch & patch() const
Return patch.
Definition: fvPatchField.H:300
Foam::immersedBoundaryFvPatchField::triValue
tmp< Field< Type > > triValue() const
Return fields on triangular faces.
Definition: immersedBoundaryFvPatchField.C:970
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:53
Foam::gMin
Type gMin(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:563
Foam::UList::size
label size() const
Return the number of elements in the UList.
Definition: UListI.H:299
Foam::C
Graphite solid properties.
Definition: C.H:57
Foam::GeometricField
Generic GeometricField class.
Definition: surfaceFieldsFwd.H:52
Foam::immersedBoundaryFvPatchField::motionUpdate
virtual void motionUpdate() const
Execute immersed boundary patch field motion update.
Definition: immersedBoundaryFvPatchField.C:712
Foam::error
Class to handle errors and exceptions in a simple, consistent stream-based manner.
Definition: error.H:66
Foam::gMax
Type gMax(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:562
Foam::DimensionedField
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
Definition: DimensionedField.H:51