37 template<
typename Type>
38 Type Foam::isoAdvection::faceValue
40 const GeometricField<Type, fvsPatchField, surfaceMesh>&
f,
46 return f.primitiveField()[facei];
53 const label patchi =
pbm.patchID(facei);
55 if (patchi < 0 || patchi >=
pbm.size())
58 <<
"Cannot find patch for face " << facei
63 const polyPatch&
pp =
pbm[patchi];
64 if (isA<emptyPolyPatch>(
pp) ||
pp.empty())
66 return pTraits<Type>::zero;
69 const label patchFacei =
pp.whichFace(facei);
70 return f.boundaryField()[patchi][patchFacei];
75 template<
typename Type>
76 void Foam::isoAdvection::setFaceValue
78 GeometricField<Type, fvsPatchField, surfaceMesh>&
f,
83 if (mesh_.isInternalFace(facei))
85 f.primitiveFieldRef()[facei] = value;
89 const polyBoundaryMesh&
pbm = mesh_.boundaryMesh();
94 if (patchi < 0 || patchi >=
pbm.
size())
97 <<
"Cannot find patch for face " << facei
102 const polyPatch&
pp =
pbm[patchi];
103 if (isA<emptyPolyPatch>(
pp) ||
pp.empty())
108 const label patchFacei =
pp.whichFace(facei);
109 f.boundaryFieldRef()[patchi][patchFacei] = value;
114 template<
class SpType,
class SuType>
115 void Foam::isoAdvection::limitFluxes
124 const scalar aTol = 100*SMALL;
125 scalar maxAlphaMinus1 =
gMax(alpha1_) - 1;
126 scalar minAlpha =
gMin(alpha1_);
127 const label nOvershoots = 20;
129 const labelList& owner = mesh_.faceOwner();
130 const labelList& neighbour = mesh_.faceNeighbour();
133 <<
"isoAdvection: Before conservative bounding: min(alpha) = " 134 << minAlpha <<
", max(alpha) = 1 + " << maxAlphaMinus1 <<
endl;
138 bitSet needBounding(mesh_.nCells(),
false);
139 needBounding.set(surfCells_);
141 extendMarkedCells(needBounding);
144 for (label
n = 0;
n < nAlphaBounds_;
n++)
146 if (maxAlphaMinus1 > aTol || minAlpha < -aTol)
150 DynamicList<label> correctedFaces(3*nOvershoots);
152 boundFlux(needBounding, dVfcorrectionValues, correctedFaces,
Sp,
Su);
154 correctedFaces.append
156 syncProcPatches(dVfcorrectionValues, phi_,
true)
160 for (
const label facei : correctedFaces)
162 if (alreadyUpdated.insert(facei))
164 checkIfOnProcPatch(facei);
165 const label own = owner[facei];
166 scalar Vown = mesh_.V()[own];
167 if (porosityEnabled_)
169 Vown *= porosityPtr_->primitiveField()[own];
171 alpha1_[own] -= faceValue(dVfcorrectionValues, facei)/Vown;
173 if (mesh_.isInternalFace(facei))
175 const label nei = neighbour[facei];
176 scalar Vnei = mesh_.V()[nei];
177 if (porosityEnabled_)
179 Vnei *= porosityPtr_->primitiveField()[nei];
182 faceValue(dVfcorrectionValues, facei)/Vnei;
186 const scalar corrVf =
187 faceValue(dVf_, facei)
188 + faceValue(dVfcorrectionValues, facei);
190 setFaceValue(dVf_, facei, corrVf);
194 if (!mesh_.isInternalFace(facei))
196 const polyBoundaryMesh& boundaryMesh =
197 mesh_.boundaryMesh();
198 const label patchi = boundaryMesh.patchID(facei);
199 const polyPatch&
pp = boundaryMesh[patchi];
200 const cyclicPolyPatch* cpp = isA<cyclicPolyPatch>(
pp);
201 const label patchFacei =
pp.whichFace(facei);
205 const label neiPatchID(cpp->neighbPolyPatchID());
207 dVf_.boundaryFieldRef();
208 dVfb[neiPatchID][patchFacei] =
209 -dVfb[patchi][patchFacei];
210 const polyPatch& np = boundaryMesh[neiPatchID];
211 const label globalFacei = np.start() + patchFacei;
212 const label neiOwn(owner[globalFacei]);
213 scalar VneiOwn = mesh_.V()[neiOwn];
214 if (porosityEnabled_)
217 porosityPtr_->primitiveField()[neiOwn];
220 faceValue(dVfcorrectionValues, facei)/VneiOwn;
228 syncProcPatches(dVf_, phi_);
235 maxAlphaMinus1 =
gMax(alpha1_) - 1;
236 minAlpha =
gMin(alpha1_);
242 label maxAlphaMinus1 =
max(alpha1_.primitiveField() - 1);
243 scalar minAlpha =
min(alpha1_.primitiveField());
244 label nUndershoots =
sum(
neg0(alpha1_.primitiveField() + aTol));
245 label nOvershoots =
sum(
pos0(alpha1_.primitiveField() - 1 - aTol));
247 Info<<
"After bounding number " <<
n + 1 <<
" of time " 248 << mesh_.time().value() <<
":" <<
nl 249 <<
"nOvershoots = " << nOvershoots <<
" with max(alpha1_-1) = " 250 << maxAlphaMinus1 <<
" and nUndershoots = " << nUndershoots
251 <<
" with min(alpha1_) = " << minAlpha <<
endl;
255 alpha1_.correctBoundaryConditions();
260 template<
class SpType,
class SuType>
261 void Foam::isoAdvection::boundFlux
263 const bitSet& nextToInterface,
265 DynamicList<label>& correctedFaces,
272 const scalar rDeltaT = 1.0/mesh_.time().deltaTValue();
274 correctedFaces.clear();
275 const scalar aTol = 100*SMALL;
278 const scalar dt = mesh_.time().deltaTValue();
280 DynamicList<label> downwindFaces(10);
281 DynamicList<label> facesToPassFluidThrough(downwindFaces.size());
282 DynamicList<scalar> dVfmax(downwindFaces.size());
283 DynamicList<scalar>
phi(downwindFaces.size());
287 for (label celli: nextToInterface)
289 if (alpha1_[celli] < -aTol || alpha1_[celli] > 1 + aTol)
291 scalar Vi = meshV[celli];
292 if (porosityEnabled_)
297 scalar alphaOvershoot =
298 pos0(alpha1_[celli] - 1)*(alpha1_[celli] - 1)
299 +
neg0(alpha1_[celli])*alpha1_[celli];
301 scalar fluidToPassOn = alphaOvershoot*Vi;
302 label nFacesToPassFluidThrough = 1;
304 bool firstLoop =
true;
308 for (label iter=0; iter<10; iter++)
310 if (
mag(alphaOvershoot) < aTol || nFacesToPassFluidThrough == 0)
316 <<
"\n\nBounding cell " << celli
317 <<
" with alpha overshooting " << alphaOvershoot
320 facesToPassFluidThrough.clear();
325 setDownwindFaces(celli, downwindFaces);
328 nFacesToPassFluidThrough = 0;
330 for (
const label facei : downwindFaces)
332 const scalar phif = faceValue(phi_, facei);
335 faceValue(dVf_, facei)
336 + faceValue(dVfcorrectionValues, facei);
338 const scalar maxExtraFaceFluidTrans =
339 mag(
pos0(fluidToPassOn)*phif*dt - dVff);
348 <<
"downwindFace " << facei
349 <<
" has maxExtraFaceFluidTrans = " 350 << maxExtraFaceFluidTrans <<
endl;
352 if (maxExtraFaceFluidTrans/Vi > aTol)
358 facesToPassFluidThrough.append(facei);
360 dVfmax.append(maxExtraFaceFluidTrans);
361 dVftot +=
mag(phif*dt);
366 <<
"\nfacesToPassFluidThrough: " 367 << facesToPassFluidThrough <<
", dVftot = " 368 << dVftot <<
" m3 corresponding to dalpha = " 369 << dVftot/Vi <<
endl;
371 forAll(facesToPassFluidThrough, fi)
373 const label facei = facesToPassFluidThrough[fi];
374 scalar fluidToPassThroughFace =
375 mag(fluidToPassOn)*
mag(
phi[fi]*dt)/dVftot;
377 nFacesToPassFluidThrough +=
378 pos0(dVfmax[fi] - fluidToPassThroughFace);
380 fluidToPassThroughFace =
381 min(fluidToPassThroughFace, dVfmax[fi]);
383 scalar dVff = faceValue(dVfcorrectionValues, facei);
386 sign(
phi[fi])*fluidToPassThroughFace*
sign(fluidToPassOn);
388 setFaceValue(dVfcorrectionValues, facei, dVff);
392 checkIfOnProcPatch(facei);
393 correctedFaces.append(facei);
401 alphaOld[celli]*rDeltaT +
Su[celli]
402 - netFlux(dVf_, celli)/Vi*rDeltaT
403 - netFlux(dVfcorrectionValues, celli)/Vi*rDeltaT
406 (rDeltaT -
Sp[celli]);
409 pos0(alpha1New - 1)*(alpha1New - 1)
410 +
neg0(alpha1New)*alpha1New;
412 fluidToPassOn = alphaOvershoot*Vi;
415 <<
"\nNew alpha for cell " << celli <<
": " 416 << alpha1New <<
endl;
425 template<
class SpType,
class SuType>
431 if (mesh_.topoChanging())
433 setProcessorPatches();
436 scalar advectionStartTime = mesh_.time().elapsedCpuTime();
438 const scalar rDeltaT = 1.0/mesh_.time().deltaTValue();
441 surf_->reconstruct();
443 if (timeIndex_ < mesh_.time().timeIndex())
445 timeIndex_= mesh_.time().timeIndex();
446 surf_->normal().oldTime() = surf_->normal();
447 surf_->centre().oldTime() = surf_->centre();
452 dVf_ = upwind<scalar>(mesh_, phi_).
flux(alpha1_)*mesh_.time().deltaT();
455 timeIntegratedFlux();
460 alpha1In_ *= (mesh_.Vsc0()/mesh_.Vsc());
464 if (porosityEnabled_)
467 alpha1_.primitiveFieldRef() =
469 alpha1_.oldTime().primitiveField()*rDeltaT +
Su.
field()
471 /porosityPtr_->primitiveField()
476 alpha1_.primitiveFieldRef() =
478 alpha1_.oldTime().primitiveField()*rDeltaT
484 alpha1_.correctBoundaryConditions();
489 scalar maxAlphaMinus1 =
gMax(alpha1In_) - 1;
490 scalar minAlpha =
gMin(alpha1In_);
492 Info<<
"isoAdvection: After conservative bounding: min(alpha) = " 493 << minAlpha <<
", max(alpha) = 1 + " << maxAlphaMinus1 <<
endl;
497 applyBruteForceBounding();
502 advectionTime_ += (mesh_.time().elapsedCpuTime() - advectionStartTime);
504 <<
"isoAdvection: time consumption = " 505 << label(100*advectionTime_/(mesh_.time().elapsedCpuTime() + SMALL))
508 alphaPhi_ = dVf_/mesh_.time().deltaT();
dimensionedScalar sign(const dimensionedScalar &ds)
const polyBoundaryMesh & pbm
Surface integrate surfaceField creating a volField. Surface sum a surfaceField creating a volField...
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1)
const GeometricField< Type, PatchField, GeoMesh > & oldTime() const
Return old time field.
const Internal::FieldType & primitiveField() const noexcept
Return a const-reference to the internal field values.
void surfaceIntegrate(Field< Type > &ivf, const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Type gMin(const FieldField< Field, Type > &f)
tmp< surfaceScalarField > flux(const volVectorField &vvf)
Return the face-flux field obtained from the given volVectorField.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
constexpr char nl
The newline '\n' character (0x0a)
Ostream & endl(Ostream &os)
Add newline and flush stream.
const labelList & patchID() const
Per boundary face label the patch index.
GeometricBoundaryField< scalar, fvsPatchField, surfaceMesh > Boundary
Type of boundary fields.
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
#define forAll(list, i)
Loop across all elements in list.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
const dimensionSet dimVolume(pow3(dimLength))
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
#define DebugInFunction
Report an information message using Foam::Info.
label size() const noexcept
The number of entries in the list.
dimensionedScalar neg0(const dimensionedScalar &ds)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
errorManip< error > abort(error &err)
#define DebugInfo
Report an information message using Foam::Info.
dimensionedScalar pos0(const dimensionedScalar &ds)
int debug
Static debugging option.
Type gMax(const FieldField< Field, Type > &f)
zeroField field() const noexcept
Method name compatibility with DimensionedField.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
void advect(const SpType &Sp, const SuType &Su)
Advect the free surface. Updates alpha field, taking into account.
#define addProfilingInFunction(Name)
Define profiling trigger with specified name and description corresponding to the compiler-defined fu...
messageStream Info
Information stream (stdout output on master, null elsewhere)
List< label > labelList
A List of labels.
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())