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, false),
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  if (dict.found("value"))
114  {
116  (
117  Field<Type>("value", dict, p.size())
118  );
119  }
120  else
121  {
122  Field<Type>::operator=(this->patchInternalField());
123  }
124 }
125 
126 
127 template<class Type>
129 (
130  const oversetFvPatchField<Type>& ptf
131 )
132 :
133  coupledFvPatchField<Type>(ptf),
134  oversetPatch_(ptf.oversetPatch_),
135  setHoleCellValue_(ptf.setHoleCellValue_),
136  fluxCorrection_(ptf.fluxCorrection_),
137  interpolateHoleCellValue_(ptf.interpolateHoleCellValue_),
138  holeCellValue_(ptf.holeCellValue_),
139  fringeUpperCoeffs_(ptf.fringeUpperCoeffs_),
140  fringeLowerCoeffs_(ptf.fringeLowerCoeffs_),
141  fringeFaces_(ptf.fringeFaces_),
142  zoneId_(ptf.zoneId_)
143 {}
144 
145 
146 template<class Type>
148 (
149  const oversetFvPatchField<Type>& ptf,
151 )
152 :
153  coupledFvPatchField<Type>(ptf, iF),
154  oversetPatch_(ptf.oversetPatch_),
155  setHoleCellValue_(ptf.setHoleCellValue_),
156  fluxCorrection_(ptf.fluxCorrection_),
157  interpolateHoleCellValue_(ptf.interpolateHoleCellValue_),
158  holeCellValue_(ptf.holeCellValue_),
159  fringeUpperCoeffs_(ptf.fringeUpperCoeffs_),
160  fringeLowerCoeffs_(ptf.fringeLowerCoeffs_),
161  fringeFaces_(ptf.fringeFaces_),
162  zoneId_(ptf.zoneId_)
163 {}
164 
165 
166 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
167 
168 template<class Type>
170 (
171  const fvMatrix<Type>& matrix
172 )
173 {
174  const fvMesh& mesh = this->internalField().mesh();
175 
178  const labelList& zoneID = overlap.zoneID();
179  const labelUList& own = mesh.owner();
180  const labelUList& nei = mesh.neighbour();
181 
183 
184  label fringesFaces = 0;
185 
186  forAll(own, facei)
187  {
188  const label zonei = zoneID[own[facei]];
189 
190  const label ownType = cellTypes[own[facei]];
191  const label neiType = cellTypes[nei[facei]];
192 
193  const bool ownCalc =
194  (ownType == cellCellStencil::CALCULATED)
195  && (neiType == cellCellStencil::INTERPOLATED);
196 
197  const bool neiCalc =
198  (ownType == cellCellStencil::INTERPOLATED)
199  && (neiType == cellCellStencil::CALCULATED);
200 
201  const bool ownNei = (ownCalc || neiCalc);
202 
203  if
204  (
205  (ownNei && (zonei == zoneId_)) || (ownNei && (zoneId_ == -1))
206  )
207  {
208  fringesFaces++;
209  }
210  }
211 
212  const fvPatchList& patches = mesh.boundary();
213 
214  labelList neiCellTypes;
216  {
217  forAll(patches, patchi)
218  {
219  const fvPatch& curPatch = patches[patchi];
220 
221  const labelUList& fc = curPatch.faceCells();
222 
223  const label start = curPatch.start();
224 
225  forAll(fc, i)
226  {
227  const label facei = start + i;
228  const label celli = fc[i];
229  const label ownType = cellTypes[celli];
230  const label neiType = neiCellTypes[facei-mesh.nInternalFaces()];
231 
232  const label zonei = zoneID[celli];
233 
234  const bool ownCalc =
235  (ownType == cellCellStencil::CALCULATED)
236  && (neiType == cellCellStencil::INTERPOLATED);
237 
238 
239  if (ownCalc && (zonei == zoneId_))
240  {
241  fringesFaces++;
242  }
243  }
244  }
245  }
246  fringeUpperCoeffs_.setSize(fringesFaces, Zero);
247  fringeLowerCoeffs_.setSize(fringesFaces, Zero);
248  fringeFaces_.setSize(fringesFaces, -1);
249 
250  const scalarField& upper = matrix.upper();
251  const scalarField& lower = matrix.lower();
252 
253  fringesFaces = 0;
254  forAll(own, facei)
255  {
256  const label zonei = zoneID[own[facei]];
257 
258  const label ownType = cellTypes[own[facei]];
259  const label neiType = cellTypes[nei[facei]];
260 
261  const bool ownCalc =
262  (ownType == cellCellStencil::CALCULATED)
263  && (neiType == cellCellStencil::INTERPOLATED);
264 
265  const bool neiCalc =
266  (ownType == cellCellStencil::INTERPOLATED)
267  && (neiType == cellCellStencil::CALCULATED);
268 
269  const bool ownNei = (ownCalc || neiCalc);
270 
271  if
272  (
273  (ownNei && (zonei == zoneId_)) || (ownNei && (zoneId_ == -1))
274  )
275  {
276  fringeUpperCoeffs_[fringesFaces] = upper[facei];
277  fringeLowerCoeffs_[fringesFaces] = lower[facei];
278  fringeFaces_[fringesFaces] = facei;
279  fringesFaces++;
280  }
281  }
282 
283  forAll(boundaryMesh, patchi)
284  {
285  const polyPatch& p = boundaryMesh[patchi];
286 
287  if (isA<coupledPolyPatch>(p))
288  {
289  const labelUList& fc = p.faceCells();
290  const label start = p.start();
291 
292  forAll(fc, i)
293  {
294  const label facei = start + i;
295  const label celli = fc[i];
296  const label ownType = cellTypes[celli];
297  const label neiType = neiCellTypes[facei-mesh.nInternalFaces()];
298 
299  const label zonei = zoneID[celli];
300 
301  const bool ownCalc =
302  (ownType == cellCellStencil::CALCULATED)
303  && (neiType == cellCellStencil::INTERPOLATED);
304 
305  const bool neiCalc =
306  (neiType == cellCellStencil::CALCULATED)
307  && (ownType == cellCellStencil::INTERPOLATED);
308 
309  if ((ownCalc||neiCalc) && (zonei == zoneId_))
310  {
311  fringeLowerCoeffs_[fringesFaces] =
312  component
313  (
314  matrix.internalCoeffs()[patchi][facei],
315  0
316  );
317 
318  fringeUpperCoeffs_[fringesFaces] =
319  component
320  (
321  matrix.boundaryCoeffs()[patchi][facei],
322  0
323  );
324 
325  fringeFaces_[fringesFaces] = facei;
326 
327  fringesFaces++;
328  }
329  }
330  }
331  }
332 }
333 
334 
335 template<class Type>
337 (
338  const fvMatrix<Type>& matrix,
339  const surfaceScalarField& phi
340 ) const
341 {
342  scalar massIn = 0;
343  scalar phiIn = 0;
344 
345  const Field<Type>& psi = matrix.psi();
346 
347  const scalarField& upper = matrix.upper();
348  const scalarField& lower = matrix.lower();
349 
350  if (this->oversetPatch_.master())
351  {
352  const fvMesh& mesh = this->internalField().mesh();
353  const cellCellStencilObject& overlap = Stencil::New(mesh);
355  const labelList& zoneID = overlap.zoneID();
356 
357  // Check all faces on the outside of interpolated cells
358  const labelUList& own = mesh.owner();
359  const labelUList& nei = mesh.neighbour();
360 
361  label fringesFaces = 0;
362  forAll(own, facei)
363  {
364  const label zonei = zoneID[own[facei]];
365 
366  const label ownType = cellTypes[own[facei]];
367  const label neiType = cellTypes[nei[facei]];
368 
369  const bool ownCalc =
370  (ownType == cellCellStencil::CALCULATED)
371  && (neiType == cellCellStencil::INTERPOLATED);
372 
373  const bool neiCalc =
374  (ownType == cellCellStencil::INTERPOLATED)
375  && (neiType == cellCellStencil::CALCULATED);
376 
377  const bool ownNei = (ownCalc || neiCalc);
378 
379  if
380  (
381  (ownNei && (zonei == zoneId_)) || (ownNei && (zoneId_ == -1))
382  )
383  {
384  const label fringei = fringeFaces_[fringesFaces];
385 
386  // Get fringe upper/lower coeffs
387  //const scalar& ufc = fringeUpperCoeffs_[fringesFaces];
388  //const scalar& lfc = fringeLowerCoeffs_[fringesFaces];
389 
390  const scalar& ufc = upper[fringei];
391  const scalar& lfc = lower[fringei];
392 
393  const Type curFlux =
394  ufc*psi[nei[fringei]] - lfc*psi[own[fringei]];
395 
396  if (neiCalc)
397  {
398  phiIn -= phi[fringei];
399  massIn -= curFlux;
400  }
401  else
402  {
403  phiIn += phi[fringei];
404  massIn += curFlux;
405  }
406  fringesFaces++;
407  }
408  }
409  }
410 
411  reduce(massIn, sumOp<scalar>());
412  reduce(phiIn, sumOp<scalar>());
413 
414  Info << " gSum(phi) on fringes " << phiIn << endl;
415  Info << " gSum(p.flux) on fringes " << massIn << endl;
416 }
417 
418 
419 template<class Type>
421 (
423  const lduAddressing& lduAddr,
424  solveScalarField& result
425 ) const
426 {
427  const fvMesh& mesh = this->internalField().mesh();
428 
431  const labelList& zoneID = overlap.zoneID();
432 
433  // Pass-1: accumulate all fluxes, calculate correction factor
434 
435  scalarField interpolatedCoeffs(fringeUpperCoeffs_.size(), Zero);
436 
437  // Options for scaling corrections
438  scalar massIn = 0;
439  scalar offDiagCoeffs = 0;
440  labelField facePerCell(cellTypes.size(), 0);
441 
442  // Check all faces on the outside of interpolated cells
443  const labelUList& own = mesh.owner();
444  const labelUList& nei = mesh.neighbour();
445 
446  label fringesFaces = 0;
447  {
448  forAll(own, facei)
449  {
450  const label zonei = zoneID[own[facei]];
451 
452  const label ownType = cellTypes[own[facei]];
453  const label neiType = cellTypes[nei[facei]];
454 
455  const bool ownCalc =
456  (ownType == cellCellStencil::CALCULATED)
457  && (neiType == cellCellStencil::INTERPOLATED);
458 
459  const bool neiCalc =
460  (ownType == cellCellStencil::INTERPOLATED)
461  && (neiType == cellCellStencil::CALCULATED);
462 
463  const bool ownNei = (ownCalc || neiCalc);
464 
465  if
466  (
467  (ownNei && (zonei == zoneId_)) || (ownNei && (zoneId_ == -1))
468  )
469  {
470  // Get fringe upper/lower coeffs
471  const scalar& ufc = fringeUpperCoeffs_[fringesFaces];
472  const scalar& lfc = fringeLowerCoeffs_[fringesFaces];
473 
474  const scalar curFlux =
475  ufc*psi[nei[facei]] - lfc*psi[own[facei]];
476 
477  if (neiCalc) // interpolated is owner
478  {
479  massIn -= curFlux;
480  offDiagCoeffs += lfc;
481  facePerCell[own[facei]]++;
482  }
483  else
484  {
485  massIn += curFlux;
486  offDiagCoeffs += ufc;
487  facePerCell[nei[facei]]++;
488  }
489  fringesFaces++;
490  }
491  }
492  }
493 
494  scalarField weights(facePerCell.size(), scalar(1));
495  forAll (weights, celli)
496  {
497  if (facePerCell[celli] > 1)
498  {
499  weights[celli] = scalar(1)/facePerCell[celli];
500  }
501  }
502 
503  // Check all coupled faces on the outside of interpolated cells
504  labelList neiCellTypes;
506 
507  const fvPatchList& boundaryMesh = mesh.boundary();
508 
509  forAll(boundaryMesh, patchi)
510  {
511  const polyPatch& p = mesh.boundaryMesh()[patchi];
512 
513  if (isA<coupledPolyPatch>(p))
514  {
515  const auto& coupledPatch = refCast<const coupledPolyPatch>(p);
516 
517  const labelUList& fc = p.faceCells();
518  const label start = p.start();
519 
520  forAll(fc, i)
521  {
522  const label facei = start + i;
523  const label celli = fc[i];
524  const label ownType = cellTypes[celli];
525  const label neiType = neiCellTypes[facei-mesh.nInternalFaces()];
526 
527  const label zonei = zoneID[celli];
528 
529  const bool ownCalc =
530  (ownType == cellCellStencil::CALCULATED)
531  && (neiType == cellCellStencil::INTERPOLATED);
532 
533  const bool neiCalc =
534  (neiType == cellCellStencil::CALCULATED)
535  && (ownType == cellCellStencil::INTERPOLATED);
536 
537  if ((ownCalc||neiCalc) && (zonei == zoneId_))
538  {
539  const scalar psiOwn = psi[celli];
540  const scalar& lfc = fringeLowerCoeffs_[fringesFaces];
541  const scalar curFlux = lfc*psiOwn;
542 
543  if (ownCalc)
544  {
545  massIn -= curFlux;
546 
547  if (coupledPatch.owner())
548  {
549  offDiagCoeffs -= lfc;
550  }
551 
552  fringesFaces++;
553  }
554  else
555  {
556  massIn += curFlux;
557 
558  if (coupledPatch.owner())
559  {
560  offDiagCoeffs -= lfc;
561  }
562 
563  fringesFaces++;
564  }
565  }
566  }
567  }
568  }
569 
570  reduce(massIn, sumOp<scalar>());
571  reduce(offDiagCoeffs, sumOp<scalar>());
572 
573  scalar psiCorr = -massIn/offDiagCoeffs;
574 
575  forAll (cellTypes, celli)
576  {
577  const bool bInter = (cellTypes[celli] == cellCellStencil::INTERPOLATED);
578  const label zonei = zoneID[celli];
579  if
580  (
581  (bInter && (zonei == zoneId_)) ||(bInter && (zoneId_ == -1))
582  )
583  {
584  psi[celli] += psiCorr;
585  }
586  }
587 }
588 
589 
590 template<class Type>
592 patchNeighbourField() const
593 {
594  return tmp<Field<Type>>
595  (
596  new Field<Type>(this->size(), Zero)
597  );
598 }
599 
600 
601 template<class Type>
603 (
604  const Pstream::commsTypes commsType
605 )
606 {
607  if (this->oversetPatch_.master())
608  {
609  // Trigger interpolation
610  const fvMesh& mesh = this->internalField().mesh();
612  const word& fldName = this->internalField().name();
613 
614  if (&mesh.lduAddr() != &mesh.fvMesh::lduAddr())
615  {
616  // Running extended addressing. Flux correction already done
617  // in the linear solver (through the initUpdateInterfaceMatrix
618  // method below)
619  if (debug)
620  {
621  Info<< "Skipping overset interpolation for solved-for field "
622  << fldName << endl;
623  }
624  }
625  else if (!fvSchemes.found("oversetInterpolation"))
626  {
627  IOWarningInFunction(fvSchemes)
628  << "Missing required dictionary entry"
629  << " 'oversetInterpolation'"
630  << ". Skipping overset interpolation for field "
631  << fldName << endl;
632  }
633  else if (fvSchemes.found("oversetInterpolationRequired"))
634  {
635  // Backwards compatibility mode: only interpolate what is
636  // explicitly mentioned
637 
638  if (fvSchemes.found("oversetInterpolationSuppressed"))
639  {
640  FatalIOErrorInFunction(fvSchemes)
641  << "Cannot have both dictionary entry"
642  << " 'oversetInterpolationSuppresed' and "
643  << " 'oversetInterpolationRequired' for field "
644  << fldName << exit(FatalIOError);
645  }
646  const dictionary& intDict = fvSchemes.subDict
647  (
648  "oversetInterpolationRequired"
649  );
650  if (intDict.found(fldName))
651  {
652  if (debug)
653  {
654  Info<< "Interpolating field " << fldName << endl;
655  }
656 
657  // Interpolate without bc update (since would trigger infinite
658  // recursion back to oversetFvPatchField<Type>::evaluate)
659  // The only problem is bcs that use the new cell values
660  // (e.g. zeroGradient, processor). These need to appear -after-
661  // the 'overset' bc.
663  (
664  const_cast<Field<Type>&>
665  (
666  this->primitiveField()
667  )
668  );
669  }
670  else if (debug)
671  {
672  Info<< "Skipping overset interpolation for field "
673  << fldName << endl;
674  }
675  }
676  else
677  {
678  const dictionary* dictPtr
679  (
680  fvSchemes.findDict("oversetInterpolationSuppressed")
681  );
682 
683  const wordHashSet& suppress =
684  Stencil::New(mesh).nonInterpolatedFields();
685 
686  bool skipInterpolate = suppress.found(fldName);
687 
688  if (dictPtr)
689  {
690  skipInterpolate =
691  skipInterpolate
692  || dictPtr->found(fldName);
693  }
694 
695  if (skipInterpolate)
696  {
697  if (debug)
698  {
699  Info<< "Skipping suppressed overset interpolation"
700  << " for field " << fldName << endl;
701  }
702  }
703  else
704  {
705  if (debug)
706  {
707  Info<< "Interpolating non-suppressed field " << fldName
708  << endl;
709  }
710 
711  // Interpolate without bc update (since would trigger infinite
712  // recursion back to oversetFvPatchField<Type>::evaluate)
713  // The only problem is bcs that use the new cell values
714  // (e.g. zeroGradient, processor). These need to appear -after-
715  // the 'overset' bc.
716 
717  const cellCellStencil& overlap = Stencil::New(mesh);
718 
719  Field<Type>& fld =
720  const_cast<Field<Type>&>(this->primitiveField());
721 
722  // tbd: different weights for different variables ...
724  (
725  fld,
726  mesh,
727  overlap,
729  );
730 
731  if (this->setHoleCellValue_)
732  {
733  const labelUList& types = overlap.cellTypes();
734  label nConstrained = 0;
735  forAll(types, celli)
736  {
737  const label cType = types[celli];
738  if
739  (
740  cType == cellCellStencil::HOLE
741  || cType == cellCellStencil::SPECIAL
742  )
743  {
744  fld[celli] = this->holeCellValue_;
745  nConstrained++;
746  }
747  }
748 
749  if (debug)
750  {
751  Pout<< FUNCTION_NAME << " field:" << fldName
752  << " patch:" << this->oversetPatch_.name()
753  << " set:" << nConstrained << " cells to:"
754  << this->holeCellValue_ << endl;
755  }
756  }
757  }
758  }
759  }
762 }
763 
764 
765 template<class Type>
767 (
768  fvMatrix<Type>& matrix
769 )
770 {
771  if (this->manipulatedMatrix())
772  {
773  return;
774  }
775 
776  const oversetFvPatch& ovp = this->oversetPatch_;
777 
778  if (ovp.master())
779  {
780  if (fluxCorrection_ || (debug & 2))
781  {
782  storeFringeCoefficients(matrix);
783  }
784 
785  // Trigger interpolation
786  const fvMesh& mesh = this->internalField().mesh();
787  const word& fldName = this->internalField().name();
788 
789  // Try to find out if the solve routine comes from the unadapted mesh
790  // TBD. This should be cleaner.
791  if (&mesh.lduAddr() == &mesh.fvMesh::lduAddr())
792  {
793  return;
794  }
795 
796  if (debug)
797  {
798  Pout<< FUNCTION_NAME << " field:" << fldName
799  << " patch:" << ovp.name() << endl;
800  }
801 
802 
803  // Calculate stabilised diagonal as normalisation for interpolation
804  const scalarField norm
805  (
806  dynamic_cast<const oversetFvMeshBase&>(mesh).normalisation(matrix)
807  );
808 
809  const cellCellStencil& overlap = Stencil::New(mesh);
810  const labelUList& types = overlap.cellTypes();
811  const labelListList& stencil = overlap.cellStencil();
812 
813  dynamic_cast<const oversetFvMeshBase&>(mesh).addInterpolation
814  (
815  matrix,
816  norm,
817  this->setHoleCellValue_,
818  this->holeCellValue_
819  );
820 
821  if (debug)
822  {
823  pointField allCs(mesh.cellCentres());
824  const mapDistribute& map = overlap.cellInterpolationMap();
825  map.distribute(allCs, false, UPstream::msgType()+1);
826 
827  // Make sure we don't interpolate from a hole
828 
829  scalarField marker(this->primitiveField().size(), 0);
830  forAll(types, celli)
831  {
832  if (types[celli] == cellCellStencil::HOLE)
833  {
834  marker[celli] = 1.0;
835  }
836  }
838  (
839  marker,
840  mesh,
841  overlap,
843  );
844 
845  forAll(marker, celli)
846  {
847  if
848  (
849  types[celli] == cellCellStencil::INTERPOLATED
850  && marker[celli] > SMALL
851  )
852  {
854  << " field:" << fldName
855  << " patch:" << ovp.name()
856  << " found:" << celli
857  << " at:" << mesh.cellCentres()[celli]
858  << " donorSlots:" << stencil[celli]
859  << " at:"
860  << UIndirectList<point>(allCs, stencil[celli])
861  << " amount-of-hole:" << marker[celli]
862  << endl;
863  }
864  }
865 
866  // Make sure we don't have matrix coefficients for interpolated
867  // or hole cells
868 
869  const lduAddressing& addr = mesh.lduAddr();
870  const labelUList& upperAddr = addr.upperAddr();
871  const labelUList& lowerAddr = addr.lowerAddr();
872  const scalarField& lower = matrix.lower();
873  const scalarField& upper = matrix.upper();
874 
875  forAll(lowerAddr, facei)
876  {
877  const label l = lowerAddr[facei];
878  const bool lHole = (types[l] == cellCellStencil::HOLE);
879  const label u = upperAddr[facei];
880  const bool uHole = (types[u] == cellCellStencil::HOLE);
881 
882  if
883  (
884  (lHole && upper[facei] != 0.0)
885  || (uHole && lower[facei] != 0.0)
886  )
887  {
889  << "Hole-neighbouring face:" << facei
890  << " lower:" << l
891  << " type:" << types[l]
892  << " coeff:" << lower[facei]
893  << " upper:" << upperAddr[facei]
894  << " type:" << types[u]
895  << " coeff:" << upper[facei]
896  << exit(FatalError);
897  }
898 
899 
900  // Empty donor list: treat like hole but still allow to
901  // influence neighbouring domains
902  const bool lEmpty =
903  (
905  && stencil[l].empty()
906  );
907  const bool uEmpty =
908  (
910  && stencil[u].empty()
911  );
912 
913  if
914  (
915  (lEmpty && upper[facei] != 0.0)
916  || (uEmpty && lower[facei] != 0.0)
917  )
918  {
920  << "Still connected face:" << facei << " lower:" << l
921  << " type:" << types[l]
922  << " coeff:" << lower[facei]
923  << " upper:" << u
924  << " type:" << types[u]
925  << " coeff:" << upper[facei]
926  << exit(FatalError);
927  }
928  }
929 
930  forAll(matrix.internalCoeffs(), patchi)
931  {
932  const labelUList& fc = addr.patchAddr(patchi);
933  const Field<Type>& bouCoeffs = matrix.boundaryCoeffs()[patchi];
934 
935  forAll(fc, i)
936  {
937  const label celli = fc[i];
938  const bool lHole = (types[celli] == cellCellStencil::HOLE);
939 
940  if (lHole && bouCoeffs[i] != pTraits<Type>::zero)
941  {
943  << "Patch:" << patchi
944  << " patchFace:" << i
945  << " lower:" << celli
946  << " type:" << types[celli]
947  << " bouCoeff:" << bouCoeffs[i]
948  << exit(FatalError);
949  }
950 
951  // Check whether this is influenced by neighbouring domains
952  const bool lEmpty =
953  (
954  types[celli] == cellCellStencil::INTERPOLATED
955  && stencil[celli].empty()
956  );
957 
958  if (lEmpty && bouCoeffs[i] != pTraits<Type>::zero)
959  {
961  << "Patch:" << patchi
962  << " patchFace:" << i
963  << " lower:" << celli
964  << " type:" << types[celli]
965  << " bouCoeff:" << bouCoeffs[i]
966  << exit(FatalError);
967  }
968  }
969  }
970 
971 
972  // Make sure that diagonal is non-zero. Note: should add
973  // boundaryCoeff ...
974  const FieldField<Field, Type>& internalCoeffs =
975  matrix.internalCoeffs();
976 
977  for (direction cmpt=0; cmpt<pTraits<Type>::nComponents; ++cmpt)
978  {
979  // Replacement for m.addBoundaryDiag(norm, cmpt);
980  scalarField diag(matrix.diag());
981  forAll(internalCoeffs, patchi)
982  {
983  const labelUList& fc = addr.patchAddr(patchi);
984  const Field<Type>& intCoeffs = internalCoeffs[patchi];
985  const scalarField cmptCoeffs(intCoeffs.component(cmpt));
986  forAll(fc, i)
987  {
988  diag[fc[i]] += cmptCoeffs[i];
989  }
990  }
991 
992  forAll(diag, celli)
993  {
994  if (mag(diag[celli]) < SMALL)
995  {
997  << "Patch:" << ovp.name()
998  << " cell:" << celli
999  << " at:" << mesh.cellCentres()[celli]
1000  << " diag:" << diag[celli]
1001  << exit(FatalError);
1002  }
1003  }
1004  }
1005  }
1006  }
1009 }
1010 
1011 
1012 template<class Type>
1014 (
1015  solveScalarField& result,
1016  const bool add,
1017  const lduAddressing& lduAddr,
1018  const label interfacei,
1019  const solveScalarField& psiInternal,
1020  const scalarField& coeffs,
1021  const direction cmpt,
1022  const Pstream::commsTypes commsType
1023 ) const
1024 {
1025 }
1026 
1027 
1028 template<class Type>
1030 (
1031  solveScalarField& result,
1032  const bool add,
1033  const lduAddressing& lduAddr,
1034  const label patchId,
1035  const solveScalarField& psiInternal,
1036  const scalarField& coeffs,
1037  const direction,
1038  const Pstream::commsTypes commsType
1039 ) const
1040 {
1041  auto& psi = const_cast<solveScalarField&>(psiInternal);
1042 
1043  if (fluxCorrection_ && this->oversetPatch_.master())
1044  {
1045  adjustPsi(psi, lduAddr, result);
1046  }
1047 }
1048 
1049 
1050 template<class Type>
1051 void Foam::oversetFvPatchField<Type>::write(Ostream& os) const
1052 {
1054 
1055  if (this->setHoleCellValue_)
1056  {
1057  os.writeEntry("setHoleCellValue", setHoleCellValue_);
1058  os.writeEntry("holeCellValue", holeCellValue_);
1060  (
1061  "interpolateHoleCellValue",
1062  false,
1063  interpolateHoleCellValue_
1064  );
1065  }
1067  (
1068  "fluxCorrection",
1069  false,
1070  fluxCorrection_
1071  );
1073  (
1074  "zone",
1075  label(-1),
1076  zoneId_
1077  );
1078 }
1079 
1080 
1081 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:584
label patchId(-1)
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:51
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
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
Types of communications.
Definition: UPstream.H:66
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:120
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
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 data using default commsType.
static const Type & New(const Mesh &mesh, Args &&... args)
Get existing or create a new MeshObject.
Definition: MeshObject.C:41
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) that generates FatalError on failed casts, uses the virtual type() me...
Definition: typeInfo.H:151
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:487
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:68
virtual tmp< Field< Type > > patchNeighbourField() const
Return neighbour field. Dummy.
A traits class, which is primarily used for primitives.
Definition: pTraits.H:50
Patch for indicating interpolated boundaries (in overset meshes).
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:312
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:806
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:424
scalarField & upper()
Definition: lduMatrix.C:207
static void interpolate(Field< T > &psi, const fvMesh &mesh, const cellCellStencil &overlap, const List< scalarList > &wghts)
Interpolation of acceptor cells from donor cells.
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:453
UList< label > labelUList
A UList of labels.
Definition: UList.H:80
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:100
const labelUList & neighbour() const
Internal face neighbour.
Definition: fvMesh.H:545
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
virtual void write(Ostream &) const
Write.
void diag(pointPatchField< vector > &, const pointPatchField< tensor > &)
friend Ostream & operator(Ostream &, const Field< Type > &)
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:289
dynamicFvMesh & mesh
virtual const labelListList & cellStencil() const
Per interpolated cell the neighbour cells (in terms of slots as.
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:711
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:303
const dictionary & schemesDict() const
The current schemes dictionary, respects the "select" keyword.
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:327
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
void operator=(const Field< Type > &)
Copy assignment.
Definition: Field.C:671
const labelUList & owner() const
Internal face owner. Note bypassing virtual mechanism so.
Definition: fvMesh.H:537
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:607
scalarField & lower()
Definition: lduMatrix.C:178
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:79
virtual const mapDistribute & cellInterpolationMap() const
Return a communication schedule.
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 FieldField< Field, Type > & internalCoeffs() const noexcept
fvBoundary scalar field containing pseudo-matrix coeffs for internal cells
Definition: fvMatrix.H:548
#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:566
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:196
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:57
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:120
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:705
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:157