oversetFvPatchField.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2016-2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "volFields.H"
29 #include "cellCellStencil.H"
30 #include "cellCellStencilObject.H"
32 #include "syncTools.H"
33 
34 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
35 
36 template<class Type>
38 (
39  const fvPatch& p,
41 )
42 :
43  coupledFvPatchField<Type>(p, iF),
44  oversetPatch_(refCast<const oversetFvPatch>(p)),
45  setHoleCellValue_(false),
46  fluxCorrection_(false),
47  interpolateHoleCellValue_(false),
48  holeCellValue_(pTraits<Type>::min),
49  fringeUpperCoeffs_(),
50  fringeLowerCoeffs_(),
51  fringeFaces_(),
52  zoneId_(-1)
53 {}
54 
55 
56 template<class Type>
58 (
59  const oversetFvPatchField<Type>& ptf,
60  const fvPatch& p,
62  const fvPatchFieldMapper& mapper
63 )
64 :
65  coupledFvPatchField<Type>(ptf, p, iF, mapper),
66  oversetPatch_(refCast<const oversetFvPatch>(p)),
67  setHoleCellValue_(ptf.setHoleCellValue_),
68  fluxCorrection_(ptf.fluxCorrection_),
69  interpolateHoleCellValue_(ptf.interpolateHoleCellValue_),
70  holeCellValue_(ptf.holeCellValue_),
71  fringeUpperCoeffs_(ptf.fringeUpperCoeffs_),
72  fringeLowerCoeffs_(ptf.fringeLowerCoeffs_),
73  fringeFaces_(ptf.fringeFaces_),
74  zoneId_(ptf.zoneId_)
75 {}
76 
77 
78 template<class Type>
80 (
81  const fvPatch& p,
83  const dictionary& dict
84 )
85 :
86  coupledFvPatchField<Type>(p, iF, dict, IOobjectOption::NO_READ),
87  oversetPatch_(refCast<const oversetFvPatch>(p, dict)),
88  setHoleCellValue_(dict.getOrDefault("setHoleCellValue", false)),
89  fluxCorrection_
90  (
91  dict.getOrDefaultCompat
92  (
93  "fluxCorrection",
94  {{"massCorrection", 2206}},
95  false
96  )
97  ),
98  interpolateHoleCellValue_
99  (
100  dict.getOrDefault("interpolateHoleCellValue", false)
101  ),
102  holeCellValue_
103  (
104  setHoleCellValue_
105  ? dict.get<Type>("holeCellValue")
107  ),
108  fringeUpperCoeffs_(),
109  fringeLowerCoeffs_(),
110  fringeFaces_(),
111  zoneId_(dict.getOrDefault<label>("zone", -1))
112 {
113  // Use 'value' supplied, or set to internal field
114  if (!this->readValueEntry(dict))
115  {
117  }
118 }
119 
120 
121 template<class Type>
123 (
124  const oversetFvPatchField<Type>& ptf
125 )
126 :
127  coupledFvPatchField<Type>(ptf),
128  oversetPatch_(ptf.oversetPatch_),
129  setHoleCellValue_(ptf.setHoleCellValue_),
130  fluxCorrection_(ptf.fluxCorrection_),
131  interpolateHoleCellValue_(ptf.interpolateHoleCellValue_),
132  holeCellValue_(ptf.holeCellValue_),
133  fringeUpperCoeffs_(ptf.fringeUpperCoeffs_),
134  fringeLowerCoeffs_(ptf.fringeLowerCoeffs_),
135  fringeFaces_(ptf.fringeFaces_),
136  zoneId_(ptf.zoneId_)
137 {}
138 
139 
140 template<class Type>
142 (
143  const oversetFvPatchField<Type>& ptf,
145 )
146 :
147  coupledFvPatchField<Type>(ptf, iF),
148  oversetPatch_(ptf.oversetPatch_),
149  setHoleCellValue_(ptf.setHoleCellValue_),
150  fluxCorrection_(ptf.fluxCorrection_),
151  interpolateHoleCellValue_(ptf.interpolateHoleCellValue_),
152  holeCellValue_(ptf.holeCellValue_),
153  fringeUpperCoeffs_(ptf.fringeUpperCoeffs_),
154  fringeLowerCoeffs_(ptf.fringeLowerCoeffs_),
155  fringeFaces_(ptf.fringeFaces_),
156  zoneId_(ptf.zoneId_)
157 {}
158 
159 
160 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
161 
162 template<class Type>
164 (
165  const fvMatrix<Type>& matrix
166 )
167 {
168  const fvMesh& mesh = this->internalField().mesh();
169 
172  const labelList& zoneID = overlap.zoneID();
173  const labelUList& own = mesh.owner();
174  const labelUList& nei = mesh.neighbour();
175 
177 
178  label fringesFaces = 0;
179 
180  forAll(own, facei)
181  {
182  const label zonei = zoneID[own[facei]];
183 
184  const label ownType = cellTypes[own[facei]];
185  const label neiType = cellTypes[nei[facei]];
186 
187  const bool ownCalc =
188  (ownType == cellCellStencil::CALCULATED)
189  && (neiType == cellCellStencil::INTERPOLATED);
190 
191  const bool neiCalc =
192  (ownType == cellCellStencil::INTERPOLATED)
193  && (neiType == cellCellStencil::CALCULATED);
194 
195  const bool ownNei = (ownCalc || neiCalc);
196 
197  if
198  (
199  (ownNei && (zonei == zoneId_)) || (ownNei && (zoneId_ == -1))
200  )
201  {
202  fringesFaces++;
203  }
204  }
205 
206  const fvPatchList& patches = mesh.boundary();
207 
208  labelList neiCellTypes;
210  {
211  forAll(patches, patchi)
212  {
213  const fvPatch& curPatch = patches[patchi];
214 
215  const labelUList& fc = curPatch.faceCells();
216 
217  const label start = curPatch.start();
218 
219  forAll(fc, i)
220  {
221  const label facei = start + i;
222  const label celli = fc[i];
223  const label ownType = cellTypes[celli];
224  const label neiType = neiCellTypes[facei-mesh.nInternalFaces()];
225 
226  const label zonei = zoneID[celli];
227 
228  const bool ownCalc =
229  (ownType == cellCellStencil::CALCULATED)
230  && (neiType == cellCellStencil::INTERPOLATED);
231 
232 
233  if (ownCalc && (zonei == zoneId_))
234  {
235  fringesFaces++;
236  }
237  }
238  }
239  }
240  fringeUpperCoeffs_.setSize(fringesFaces, Zero);
241  fringeLowerCoeffs_.setSize(fringesFaces, Zero);
242  fringeFaces_.setSize(fringesFaces, -1);
243 
244  const scalarField& upper = matrix.upper();
245  const scalarField& lower = matrix.lower();
246 
247  fringesFaces = 0;
248  forAll(own, facei)
249  {
250  const label zonei = zoneID[own[facei]];
251 
252  const label ownType = cellTypes[own[facei]];
253  const label neiType = cellTypes[nei[facei]];
254 
255  const bool ownCalc =
256  (ownType == cellCellStencil::CALCULATED)
257  && (neiType == cellCellStencil::INTERPOLATED);
258 
259  const bool neiCalc =
260  (ownType == cellCellStencil::INTERPOLATED)
261  && (neiType == cellCellStencil::CALCULATED);
262 
263  const bool ownNei = (ownCalc || neiCalc);
264 
265  if
266  (
267  (ownNei && (zonei == zoneId_)) || (ownNei && (zoneId_ == -1))
268  )
269  {
270  fringeUpperCoeffs_[fringesFaces] = upper[facei];
271  fringeLowerCoeffs_[fringesFaces] = lower[facei];
272  fringeFaces_[fringesFaces] = facei;
273  fringesFaces++;
274  }
275  }
276 
277  forAll(boundaryMesh, patchi)
278  {
279  const polyPatch& p = boundaryMesh[patchi];
280 
281  if (isA<coupledPolyPatch>(p))
282  {
283  const labelUList& fc = p.faceCells();
284  const label start = p.start();
285 
286  forAll(fc, i)
287  {
288  const label facei = start + i;
289  const label celli = fc[i];
290  const label ownType = cellTypes[celli];
291  const label neiType = neiCellTypes[facei-mesh.nInternalFaces()];
292 
293  const label zonei = zoneID[celli];
294 
295  const bool ownCalc =
296  (ownType == cellCellStencil::CALCULATED)
297  && (neiType == cellCellStencil::INTERPOLATED);
298 
299  const bool neiCalc =
300  (neiType == cellCellStencil::CALCULATED)
301  && (ownType == cellCellStencil::INTERPOLATED);
302 
303  if ((ownCalc||neiCalc) && (zonei == zoneId_))
304  {
305  fringeLowerCoeffs_[fringesFaces] =
306  component
307  (
308  matrix.internalCoeffs()[patchi][facei],
309  0
310  );
311 
312  fringeUpperCoeffs_[fringesFaces] =
313  component
314  (
315  matrix.boundaryCoeffs()[patchi][facei],
316  0
317  );
318 
319  fringeFaces_[fringesFaces] = facei;
320 
321  fringesFaces++;
322  }
323  }
324  }
325  }
326 }
327 
328 
329 template<class Type>
331 (
332  const fvMatrix<Type>& matrix,
333  const surfaceScalarField& phi
334 ) const
335 {
336  scalar massIn = 0;
337  scalar phiIn = 0;
338 
339  const Field<Type>& psi = matrix.psi();
340 
341  const scalarField& upper = matrix.upper();
342  const scalarField& lower = matrix.lower();
343 
344  if (this->oversetPatch_.master())
345  {
346  const fvMesh& mesh = this->internalField().mesh();
347  const cellCellStencilObject& overlap = Stencil::New(mesh);
349  const labelList& zoneID = overlap.zoneID();
350 
351  // Check all faces on the outside of interpolated cells
352  const labelUList& own = mesh.owner();
353  const labelUList& nei = mesh.neighbour();
354 
355  label fringesFaces = 0;
356  forAll(own, facei)
357  {
358  const label zonei = zoneID[own[facei]];
359 
360  const label ownType = cellTypes[own[facei]];
361  const label neiType = cellTypes[nei[facei]];
362 
363  const bool ownCalc =
364  (ownType == cellCellStencil::CALCULATED)
365  && (neiType == cellCellStencil::INTERPOLATED);
366 
367  const bool neiCalc =
368  (ownType == cellCellStencil::INTERPOLATED)
369  && (neiType == cellCellStencil::CALCULATED);
370 
371  const bool ownNei = (ownCalc || neiCalc);
372 
373  if
374  (
375  (ownNei && (zonei == zoneId_)) || (ownNei && (zoneId_ == -1))
376  )
377  {
378  const label fringei = fringeFaces_[fringesFaces];
379 
380  // Get fringe upper/lower coeffs
381  //const scalar& ufc = fringeUpperCoeffs_[fringesFaces];
382  //const scalar& lfc = fringeLowerCoeffs_[fringesFaces];
383 
384  const scalar& ufc = upper[fringei];
385  const scalar& lfc = lower[fringei];
386 
387  const Type curFlux =
388  ufc*psi[nei[fringei]] - lfc*psi[own[fringei]];
389 
390  if (neiCalc)
391  {
392  phiIn -= phi[fringei];
393  massIn -= curFlux;
394  }
395  else
396  {
397  phiIn += phi[fringei];
398  massIn += curFlux;
399  }
400  fringesFaces++;
401  }
402  }
403  }
404 
405  reduce(massIn, sumOp<scalar>());
406  reduce(phiIn, sumOp<scalar>());
407 
408  Info << " gSum(phi) on fringes " << phiIn << endl;
409  Info << " gSum(p.flux) on fringes " << massIn << endl;
410 }
411 
412 
413 template<class Type>
415 (
417  const lduAddressing& lduAddr,
418  solveScalarField& result
419 ) const
420 {
421  const fvMesh& mesh = this->internalField().mesh();
422 
425  const labelList& zoneID = overlap.zoneID();
426 
427  // Pass-1: accumulate all fluxes, calculate correction factor
428 
429  scalarField interpolatedCoeffs(fringeUpperCoeffs_.size(), Zero);
430 
431  // Options for scaling corrections
432  scalar massIn = 0;
433  scalar offDiagCoeffs = 0;
434  labelField facePerCell(cellTypes.size(), 0);
435 
436  // Check all faces on the outside of interpolated cells
437  const labelUList& own = mesh.owner();
438  const labelUList& nei = mesh.neighbour();
439 
440  label fringesFaces = 0;
441  {
442  forAll(own, facei)
443  {
444  const label zonei = zoneID[own[facei]];
445 
446  const label ownType = cellTypes[own[facei]];
447  const label neiType = cellTypes[nei[facei]];
448 
449  const bool ownCalc =
450  (ownType == cellCellStencil::CALCULATED)
451  && (neiType == cellCellStencil::INTERPOLATED);
452 
453  const bool neiCalc =
454  (ownType == cellCellStencil::INTERPOLATED)
455  && (neiType == cellCellStencil::CALCULATED);
456 
457  const bool ownNei = (ownCalc || neiCalc);
458 
459  if
460  (
461  (ownNei && (zonei == zoneId_)) || (ownNei && (zoneId_ == -1))
462  )
463  {
464  // Get fringe upper/lower coeffs
465  const scalar& ufc = fringeUpperCoeffs_[fringesFaces];
466  const scalar& lfc = fringeLowerCoeffs_[fringesFaces];
467 
468  const scalar curFlux =
469  ufc*psi[nei[facei]] - lfc*psi[own[facei]];
470 
471  if (neiCalc) // interpolated is owner
472  {
473  massIn -= curFlux;
474  offDiagCoeffs += lfc;
475  facePerCell[own[facei]]++;
476  }
477  else
478  {
479  massIn += curFlux;
480  offDiagCoeffs += ufc;
481  facePerCell[nei[facei]]++;
482  }
483  fringesFaces++;
484  }
485  }
486  }
487 
488  scalarField weights(facePerCell.size(), scalar(1));
489  forAll (weights, celli)
490  {
491  if (facePerCell[celli] > 1)
492  {
493  weights[celli] = scalar(1)/facePerCell[celli];
494  }
495  }
496 
497  // Check all coupled faces on the outside of interpolated cells
498  labelList neiCellTypes;
500 
501  const fvPatchList& boundaryMesh = mesh.boundary();
502 
503  forAll(boundaryMesh, patchi)
504  {
505  const polyPatch& p = mesh.boundaryMesh()[patchi];
506 
507  if (isA<coupledPolyPatch>(p))
508  {
509  const auto& coupledPatch = refCast<const coupledPolyPatch>(p);
510 
511  const labelUList& fc = p.faceCells();
512  const label start = p.start();
513 
514  forAll(fc, i)
515  {
516  const label facei = start + i;
517  const label celli = fc[i];
518  const label ownType = cellTypes[celli];
519  const label neiType = neiCellTypes[facei-mesh.nInternalFaces()];
520 
521  const label zonei = zoneID[celli];
522 
523  const bool ownCalc =
524  (ownType == cellCellStencil::CALCULATED)
525  && (neiType == cellCellStencil::INTERPOLATED);
526 
527  const bool neiCalc =
528  (neiType == cellCellStencil::CALCULATED)
529  && (ownType == cellCellStencil::INTERPOLATED);
530 
531  if ((ownCalc||neiCalc) && (zonei == zoneId_))
532  {
533  const scalar psiOwn = psi[celli];
534  const scalar& lfc = fringeLowerCoeffs_[fringesFaces];
535  const scalar curFlux = lfc*psiOwn;
536 
537  if (ownCalc)
538  {
539  massIn -= curFlux;
540 
541  if (coupledPatch.owner())
542  {
543  offDiagCoeffs -= lfc;
544  }
545 
546  fringesFaces++;
547  }
548  else
549  {
550  massIn += curFlux;
551 
552  if (coupledPatch.owner())
553  {
554  offDiagCoeffs -= lfc;
555  }
556 
557  fringesFaces++;
558  }
559  }
560  }
561  }
562  }
563 
564  reduce(massIn, sumOp<scalar>());
565  reduce(offDiagCoeffs, sumOp<scalar>());
566 
567  scalar psiCorr = -massIn/offDiagCoeffs;
568 
569  forAll (cellTypes, celli)
570  {
571  const bool bInter = (cellTypes[celli] == cellCellStencil::INTERPOLATED);
572  const label zonei = zoneID[celli];
573  if
574  (
575  (bInter && (zonei == zoneId_)) ||(bInter && (zoneId_ == -1))
576  )
577  {
578  psi[celli] += psiCorr;
579  }
580  }
581 }
582 
583 
584 template<class Type>
586 patchNeighbourField() const
587 {
588  return tmp<Field<Type>>
589  (
590  new Field<Type>(this->size(), Zero)
591  );
592 }
593 
594 
595 template<class Type>
597 (
598  const Pstream::commsTypes commsType
599 )
600 {
601  if (this->oversetPatch_.master())
602  {
603  // Trigger interpolation
604  const fvMesh& mesh = this->internalField().mesh();
606  const word& fldName = this->internalField().name();
607 
608  if (&mesh.lduAddr() != &mesh.fvMesh::lduAddr())
609  {
610  // Running extended addressing. Flux correction already done
611  // in the linear solver (through the initUpdateInterfaceMatrix
612  // method below)
613  if (debug)
614  {
615  Info<< "Skipping overset interpolation for solved-for field "
616  << fldName << endl;
617  }
618  }
619  else if (!fvSchemes.found("oversetInterpolation"))
620  {
621  IOWarningInFunction(fvSchemes)
622  << "Missing required dictionary entry"
623  << " 'oversetInterpolation'"
624  << ". Skipping overset interpolation for field "
625  << fldName << endl;
626  }
627  else if (fvSchemes.found("oversetInterpolationRequired"))
628  {
629  // Backwards compatibility mode: only interpolate what is
630  // explicitly mentioned
631 
632  if (fvSchemes.found("oversetInterpolationSuppressed"))
633  {
634  FatalIOErrorInFunction(fvSchemes)
635  << "Cannot have both dictionary entry"
636  << " 'oversetInterpolationSuppresed' and "
637  << " 'oversetInterpolationRequired' for field "
638  << fldName << exit(FatalIOError);
639  }
640  const dictionary& intDict = fvSchemes.subDict
641  (
642  "oversetInterpolationRequired"
643  );
644  if (intDict.found(fldName))
645  {
646  if (debug)
647  {
648  Info<< "Interpolating field " << fldName << endl;
649  }
650 
651  // Interpolate without bc update (since would trigger infinite
652  // recursion back to oversetFvPatchField<Type>::evaluate)
653  // The only problem is bcs that use the new cell values
654  // (e.g. zeroGradient, processor). These need to appear -after-
655  // the 'overset' bc.
657  (
658  const_cast<Field<Type>&>
659  (
660  this->primitiveField()
661  )
662  );
663  }
664  else if (debug)
665  {
666  Info<< "Skipping overset interpolation for field "
667  << fldName << endl;
668  }
669  }
670  else
671  {
672  const dictionary* dictPtr
673  (
674  fvSchemes.findDict("oversetInterpolationSuppressed")
675  );
676 
677  const wordHashSet& suppress =
678  Stencil::New(mesh).nonInterpolatedFields();
679 
680  bool skipInterpolate = suppress.found(fldName);
681 
682  if (dictPtr)
683  {
684  skipInterpolate =
685  skipInterpolate
686  || dictPtr->found(fldName);
687  }
688 
689  if (skipInterpolate)
690  {
691  if (debug)
692  {
693  Info<< "Skipping suppressed overset interpolation"
694  << " for field " << fldName << endl;
695  }
696  }
697  else
698  {
699  if (debug)
700  {
701  Info<< "Interpolating non-suppressed field " << fldName
702  << endl;
703  }
704 
705  // Interpolate without bc update (since would trigger infinite
706  // recursion back to oversetFvPatchField<Type>::evaluate)
707  // The only problem is bcs that use the new cell values
708  // (e.g. zeroGradient, processor). These need to appear -after-
709  // the 'overset' bc.
710 
711  const cellCellStencil& overlap = Stencil::New(mesh);
712 
713  Field<Type>& fld =
714  const_cast<Field<Type>&>(this->primitiveField());
715 
716  // tbd: different weights for different variables ...
718  (
719  fld,
720  mesh,
721  overlap,
723  );
724 
725  if (this->setHoleCellValue_)
726  {
727  const labelUList& types = overlap.cellTypes();
728  label nConstrained = 0;
729  forAll(types, celli)
730  {
731  const label cType = types[celli];
732  if
733  (
734  cType == cellCellStencil::HOLE
735  || cType == cellCellStencil::SPECIAL
736  )
737  {
738  fld[celli] = this->holeCellValue_;
739  nConstrained++;
740  }
741  }
742 
743  if (debug)
744  {
745  Pout<< FUNCTION_NAME << " field:" << fldName
746  << " patch:" << this->oversetPatch_.name()
747  << " set:" << nConstrained << " cells to:"
748  << this->holeCellValue_ << endl;
749  }
750  }
751  }
752  }
753  }
756 }
757 
758 
759 template<class Type>
761 (
762  fvMatrix<Type>& matrix
763 )
764 {
765  if (this->manipulatedMatrix())
766  {
767  return;
768  }
769 
770  const oversetFvPatch& ovp = this->oversetPatch_;
771 
772  if (ovp.master())
773  {
774  if (fluxCorrection_ || (debug & 2))
775  {
776  storeFringeCoefficients(matrix);
777  }
778 
779  // Trigger interpolation
780  const fvMesh& mesh = this->internalField().mesh();
781  const word& fldName = this->internalField().name();
782 
783  // Try to find out if the solve routine comes from the unadapted mesh
784  // TBD. This should be cleaner.
785  if (&mesh.lduAddr() == &mesh.fvMesh::lduAddr())
786  {
787  return;
788  }
789 
790  if (debug)
791  {
792  Pout<< FUNCTION_NAME << " field:" << fldName
793  << " patch:" << ovp.name() << endl;
794  }
795 
796 
797  // Calculate stabilised diagonal as normalisation for interpolation
798  const scalarField norm
799  (
800  dynamic_cast<const oversetFvMeshBase&>(mesh).normalisation(matrix)
801  );
802 
803  const cellCellStencil& overlap = Stencil::New(mesh);
804  const labelUList& types = overlap.cellTypes();
805  const labelListList& stencil = overlap.cellStencil();
806 
807  dynamic_cast<const oversetFvMeshBase&>(mesh).addInterpolation
808  (
809  matrix,
810  norm,
811  this->setHoleCellValue_,
812  this->holeCellValue_
813  );
814 
815  if (debug)
816  {
817  pointField allCs(mesh.cellCentres());
818  const mapDistribute& map = overlap.cellInterpolationMap();
819  map.distribute(allCs, false, UPstream::msgType()+1);
820 
821  // Make sure we don't interpolate from a hole
822 
823  scalarField marker(this->primitiveField().size(), 0);
824  forAll(types, celli)
825  {
826  if (types[celli] == cellCellStencil::HOLE)
827  {
828  marker[celli] = 1.0;
829  }
830  }
832  (
833  marker,
834  mesh,
835  overlap,
837  );
838 
839  forAll(marker, celli)
840  {
841  if
842  (
843  types[celli] == cellCellStencil::INTERPOLATED
844  && marker[celli] > SMALL
845  )
846  {
848  << " field:" << fldName
849  << " patch:" << ovp.name()
850  << " found:" << celli
851  << " at:" << mesh.cellCentres()[celli]
852  << " donorSlots:" << stencil[celli]
853  << " at:"
854  << UIndirectList<point>(allCs, stencil[celli])
855  << " amount-of-hole:" << marker[celli]
856  << endl;
857  }
858  }
859 
860  // Make sure we don't have matrix coefficients for interpolated
861  // or hole cells
862 
863  const lduAddressing& addr = mesh.lduAddr();
864  const labelUList& upperAddr = addr.upperAddr();
865  const labelUList& lowerAddr = addr.lowerAddr();
866  const scalarField& lower = matrix.lower();
867  const scalarField& upper = matrix.upper();
868 
869  forAll(lowerAddr, facei)
870  {
871  const label l = lowerAddr[facei];
872  const bool lHole = (types[l] == cellCellStencil::HOLE);
873  const label u = upperAddr[facei];
874  const bool uHole = (types[u] == cellCellStencil::HOLE);
875 
876  if
877  (
878  (lHole && upper[facei] != 0.0)
879  || (uHole && lower[facei] != 0.0)
880  )
881  {
883  << "Hole-neighbouring face:" << facei
884  << " lower:" << l
885  << " type:" << types[l]
886  << " coeff:" << lower[facei]
887  << " upper:" << upperAddr[facei]
888  << " type:" << types[u]
889  << " coeff:" << upper[facei]
890  << exit(FatalError);
891  }
892 
893 
894  // Empty donor list: treat like hole but still allow to
895  // influence neighbouring domains
896  const bool lEmpty =
897  (
899  && stencil[l].empty()
900  );
901  const bool uEmpty =
902  (
904  && stencil[u].empty()
905  );
906 
907  if
908  (
909  (lEmpty && upper[facei] != 0.0)
910  || (uEmpty && lower[facei] != 0.0)
911  )
912  {
914  << "Still connected face:" << facei << " lower:" << l
915  << " type:" << types[l]
916  << " coeff:" << lower[facei]
917  << " upper:" << u
918  << " type:" << types[u]
919  << " coeff:" << upper[facei]
920  << exit(FatalError);
921  }
922  }
923 
924  forAll(matrix.internalCoeffs(), patchi)
925  {
926  const labelUList& fc = addr.patchAddr(patchi);
927  const Field<Type>& bouCoeffs = matrix.boundaryCoeffs()[patchi];
928 
929  forAll(fc, i)
930  {
931  const label celli = fc[i];
932  const bool lHole = (types[celli] == cellCellStencil::HOLE);
933 
934  if (lHole && bouCoeffs[i] != pTraits<Type>::zero)
935  {
937  << "Patch:" << patchi
938  << " patchFace:" << i
939  << " lower:" << celli
940  << " type:" << types[celli]
941  << " bouCoeff:" << bouCoeffs[i]
942  << exit(FatalError);
943  }
944 
945  // Check whether this is influenced by neighbouring domains
946  const bool lEmpty =
947  (
948  types[celli] == cellCellStencil::INTERPOLATED
949  && stencil[celli].empty()
950  );
951 
952  if (lEmpty && bouCoeffs[i] != pTraits<Type>::zero)
953  {
955  << "Patch:" << patchi
956  << " patchFace:" << i
957  << " lower:" << celli
958  << " type:" << types[celli]
959  << " bouCoeff:" << bouCoeffs[i]
960  << exit(FatalError);
961  }
962  }
963  }
964 
965 
966  // Make sure that diagonal is non-zero. Note: should add
967  // boundaryCoeff ...
968  const FieldField<Field, Type>& internalCoeffs =
969  matrix.internalCoeffs();
970 
971  for (direction cmpt=0; cmpt<pTraits<Type>::nComponents; ++cmpt)
972  {
973  // Replacement for m.addBoundaryDiag(norm, cmpt);
974  scalarField diag(matrix.diag());
975  forAll(internalCoeffs, patchi)
976  {
977  const labelUList& fc = addr.patchAddr(patchi);
978  const Field<Type>& intCoeffs = internalCoeffs[patchi];
979  const scalarField cmptCoeffs(intCoeffs.component(cmpt));
980  forAll(fc, i)
981  {
982  diag[fc[i]] += cmptCoeffs[i];
983  }
984  }
985 
986  forAll(diag, celli)
987  {
988  if (mag(diag[celli]) < SMALL)
989  {
991  << "Patch:" << ovp.name()
992  << " cell:" << celli
993  << " at:" << mesh.cellCentres()[celli]
994  << " diag:" << diag[celli]
995  << exit(FatalError);
996  }
997  }
998  }
999  }
1000  }
1003 }
1004 
1005 
1006 template<class Type>
1008 (
1009  solveScalarField& result,
1010  const bool add,
1011  const lduAddressing& lduAddr,
1012  const label interfacei,
1013  const solveScalarField& psiInternal,
1014  const scalarField& coeffs,
1015  const direction cmpt,
1016  const Pstream::commsTypes commsType
1017 ) const
1018 {
1019 }
1020 
1021 
1022 template<class Type>
1024 (
1025  solveScalarField& result,
1026  const bool add,
1027  const lduAddressing& lduAddr,
1028  const label patchId,
1029  const solveScalarField& psiInternal,
1030  const scalarField& coeffs,
1031  const direction,
1032  const Pstream::commsTypes commsType
1033 ) const
1034 {
1035  auto& psi = const_cast<solveScalarField&>(psiInternal);
1036 
1037  if (fluxCorrection_ && this->oversetPatch_.master())
1038  {
1039  adjustPsi(psi, lduAddr, result);
1040  }
1041 }
1042 
1043 
1044 template<class Type>
1045 void Foam::oversetFvPatchField<Type>::write(Ostream& os) const
1046 {
1048 
1049  if (this->setHoleCellValue_)
1050  {
1051  os.writeEntry("setHoleCellValue", setHoleCellValue_);
1052  os.writeEntry("holeCellValue", holeCellValue_);
1054  (
1055  "interpolateHoleCellValue",
1056  false,
1057  interpolateHoleCellValue_
1058  );
1059  }
1061  (
1062  "fluxCorrection",
1063  false,
1064  fluxCorrection_
1065  );
1067  (
1068  "zone",
1069  label(-1),
1070  zoneId_
1071  );
1072 }
1073 
1074 
1075 // ************************************************************************* //
label patchId(-1)
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
uint8_t direction
Definition: direction.H:46
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
commsTypes
Communications types.
Definition: UPstream.H:72
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
void fringeFlux(const fvMatrix< Type > &m, const surfaceScalarField &phi) const
Calculate patch flux (helper function). Requires.
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute List data using default commsType, default flip/negate operator.
static const Type & New(const Mesh &mesh, Args &&... args)
Get existing or create a new MeshObject. Registered with typeName.
Definition: MeshObject.C:53
virtual void updateInterfaceMatrix(solveScalarField &result, const bool add, const lduAddressing &lduAddr, const label patchId, const solveScalarField &psiInternal, const scalarField &coeffs, const direction, const Pstream::commsTypes commsType) const
Update result field based on interface functionality.
Type & refCast(U &obj)
A dynamic_cast (for references). Generates a FatalError on failed casts and uses the virtual type() m...
Definition: typeInfo.H:159
virtual void initEvaluate(const Pstream::commsTypes commsType)
Initialise the evaluation of the patch field.
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface...
Definition: boundaryMesh.H:58
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:70
virtual tmp< Field< Type > > patchNeighbourField() const
Return neighbour field. Dummy.
A traits class, which is primarily used for primitives and vector-space.
Definition: pTraits.H:75
Patch for indicating interpolated boundaries (in overset meshes).
void extrapolateInternal()
Assign the patch field from the internal field.
Definition: fvPatchField.C:62
string upper(const std::string &s)
Return string copy transformed with std::toupper on each character.
Definition: stringOps.C:1187
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:321
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1229
::Foam::direction nComponents(const expressions::valueTypeCode) noexcept
The number of components associated with given valueTypeCode.
Definition: exprTraits.C:40
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T. FatalIOError if not found, or if the number of tokens is incorrect.
virtual void interpolate(volScalarField &) const
Interpolate interpolationCells only.
Definition: fvMesh.H:459
scalarField & upper()
Definition: lduMatrix.C:208
static void interpolate(Field< T > &psi, const fvMesh &mesh, const cellCellStencil &overlap, const List< scalarList > &wghts)
Interpolation of acceptor cells from donor cells.
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
virtual void initEvaluate(const Pstream::commsTypes commsType)
Initialise the evaluation of the patch field.
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:441
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
virtual const labelUList & cellTypes() const
Return the cell type list.
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:104
const labelUList & neighbour() const
Internal face neighbour.
Definition: fvMesh.H:580
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
virtual void write(Ostream &) const
Write.
void diag(pointPatchField< vector > &, const pointPatchField< tensor > &)
void storeFringeCoefficients(const fvMatrix< Type > &matrix)
Store fringe coefficients and faces.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
void setSize(const label n)
Alias for resize()
Definition: List.H:316
dynamicFvMesh & mesh
virtual const labelListList & cellStencil() const
Per interpolated cell the neighbour cells (in terms of slots as.
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:608
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual const lduAddressing & lduAddr() const
Return ldu addressing.
Definition: fvMesh.C:741
A FieldMapper for finite-volume patch fields.
const cellCellStencilObject & overlap
Definition: correctPhi.H:57
virtual const List< scalarList > & cellInterpolationWeights() const
Weights for cellStencil.
A special matrix type and solver, designed for finite volume solutions of scalar equations. Face addressing is used to make all matrix assembly and solution loops vectorise.
Definition: fvPatchField.H:64
virtual void manipulateMatrix(fvMatrix< Type > &matrix)
Manipulate matrix.
Definition: fvPatchField.C:342
const dictionary & schemesDict() const
The entire dictionary or the optional "select" sub-dictionary.
virtual void initInterfaceMatrixUpdate(Field< Type > &, const bool add, const lduAddressing &, const label interfacei, const Field< Type > &, const scalarField &, const Pstream::commsTypes commsType) const
Initialise neighbour matrix update.
label nInternalFaces() const noexcept
Number of internal faces.
HashSet< word, Hash< word > > wordHashSet
A HashSet of words, uses string hasher.
Definition: HashSet.H:73
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
const vectorField & cellCentres() const
Ostream & writeEntryIfDifferent(const word &key, const T &value1, const T &value2)
Write a keyword/value entry only when the two values differ.
Definition: Ostream.H:336
Abstract base class for coupled patches.
const labelList & cellTypes
Definition: setCellMask.H:27
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
oversetFvPatchField(const fvPatch &, const DimensionedField< Type, volMesh > &)
Construct from patch and internal field.
void adjustPsi(solveScalarField &psi, const lduAddressing &lduAddr, solveScalarField &result) const
Adjust psi for mass correction. Requires storeFringeCoefficients.
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
const labelUList & owner() const
Internal face owner. Note bypassing virtual mechanism so.
Definition: fvMesh.H:572
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
static void swapBoundaryCellList(const polyMesh &mesh, const UList< T > &cellData, List< T > &neighbourCellData)
Swap to obtain neighbour cell values for all boundary faces.
string lower(const std::string &s)
Return string copy transformed with std::tolower on each character.
Definition: stringOps.C:1171
#define WarningInFunction
Report a warning using Foam::Warning.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:627
scalarField & lower()
Definition: lduMatrix.C:179
Selector class for finite volume differencing schemes. fvMesh is derived from fvSchemes so that all f...
Definition: fvSchemes.H:51
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
virtual const mapDistribute & cellInterpolationMap() const
Return a communication schedule.
A simple container of IOobject preferences. Can also be used for general handling of read/no-read/rea...
const polyBoundaryMesh & patches
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
Definition: areaFieldsFwd.H:42
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
messageStream Info
Information stream (stdout output on master, null elsewhere)
const fvBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition: fvMesh.H:395
const FieldField< Field, Type > & internalCoeffs() const noexcept
fvBoundary scalar field containing pseudo-matrix coeffs for internal cells
Definition: fvMatrix.H:547
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
const volScalarField & psi
The class contains the addressing required by the lduMatrix: upper, lower and losort.
const FieldField< Field, Type > & boundaryCoeffs() const noexcept
fvBoundary scalar field containing pseudo-matrix coeffs for boundary cells
Definition: fvMatrix.H:565
virtual void manipulateMatrix(fvMatrix< Type > &matrix)
Manipulate matrix.
virtual void write(Ostream &os) const
Write.
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T, or return the given default value. FatalIOError if it is found and the number of...
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
A class for managing temporary objects.
Definition: HashPtrTable.H:50
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
scalarField & diag()
Definition: lduMatrix.C:197
static const labelIOList & zoneID(const fvMesh &)
Helper: get reference to registered zoneID. Loads volScalarField.
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
PtrList< fvPatch > fvPatchList
Store lists of fvPatch as a PtrList.
Definition: fvPatch.H:59
Boundary condition for use on overset patches. To be run in combination with special dynamicFvMesh ty...
const dictionary * findDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary pointer if present (and a sub-dictionary) otherwise return nullptr...
Definition: dictionaryI.H:124
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127