50 Foam::isoAdvection::isoAdvection
83 nAlphaBounds_(dict_.lookupOrDefault<
label>(
"nAlphaBounds", 3)),
84 isoFaceTol_(dict_.lookupOrDefault<scalar>(
"isoFaceTol", 1
e-8)),
85 surfCellTol_(dict_.lookupOrDefault<scalar>(
"surfCellTol", 1
e-8)),
86 gradAlphaBasedNormal_(dict_.lookupOrDefault(
"gradAlphaNormal", false)),
87 writeIsoFacesToFile_(dict_.lookupOrDefault(
"writeIsoFaces", false)),
90 surfCells_(
label(0.2*mesh_.nCells())),
91 isoCutCell_(mesh_, ap_),
92 isoCutFace_(mesh_, ap_),
93 cellIsBounded_(mesh_.nCells(), false),
94 checkBounding_(mesh_.nCells(), false),
95 bsFaces_(
label(0.2*mesh_.nBoundaryFaces())),
96 bsx0_(bsFaces_.size()),
97 bsn0_(bsFaces_.size()),
98 bsUn0_(bsFaces_.size()),
99 bsf0_(bsFaces_.size()),
102 procPatchLabels_(mesh_.
boundary().size()),
103 surfaceCellFacesOnProcPatches_(0)
126 surfaceCellFacesOnProcPatches_.resize(
patches.size());
133 isA<processorPolyPatch>(
patches[patchi])
137 procPatchLabels_.
append(patchi);
146 void Foam::isoAdvection::timeIntegratedFlux()
149 const scalar dt = mesh_.time().deltaTValue();
152 interpolationCellPoint<vector> UInterp(U_);
155 label nSurfaceCells = 0;
163 const scalarField& magSfIn = mesh_.magSf().primitiveField();
167 const cellList& cellFaces = mesh_.cells();
168 const labelList& own = mesh_.faceOwner();
169 const labelList& nei = mesh_.faceNeighbour();
175 if (gradAlphaBasedNormal_)
178 normaliseAndSmooth(cellNormals);
187 DynamicList<List<point>> isoFacePts;
193 if (!isASurfaceCell(celli))
continue;
199 surfCells_.append(celli);
200 checkBounding_[celli] =
true;
203 <<
"\n------------ Cell " << celli <<
" with alpha1 = "
204 << alpha1In_[celli] <<
" and 1-alpha1 = "
205 << 1.0 - alpha1In_[celli] <<
" ------------"
208 if (gradAlphaBasedNormal_)
210 vectorField& cellNormalsIn = cellNormals.primitiveFieldRef();
211 setCellVertexValues(celli, cellNormalsIn);
219 label cellStatus = isoCutCell_.vofCutCell
228 if (cellStatus != 0)
continue;
231 const scalar f0(isoCutCell_.isoValue());
232 const point& x0(isoCutCell_.isoFaceCentre());
233 vector n0(isoCutCell_.isoFaceArea());
236 if (writeIsoFacesToFile_ && mesh_.time().writeTime())
238 isoFacePts.append(isoCutCell_.isoFacePoints());
243 const scalar Un0 = UInterp.interpolate(x0, celli) & n0;
246 <<
"calcIsoFace gives initial surface: \nx0 = " << x0
247 <<
", \nn0 = " << n0 <<
", \nf0 = " << f0 <<
", \nUn0 = "
253 const cell& celliFaces = cellFaces[celli];
256 const label facei = celliFaces[fi];
258 if (mesh_.isInternalFace(facei))
260 bool isDownwindFace =
false;
263 if (celli == own[facei])
265 if (phiIn[facei] > 10*SMALL)
267 isDownwindFace =
true;
274 if (phiIn[facei] < -10*SMALL)
276 isDownwindFace =
true;
284 dVfIn[facei] = isoCutFace_.timeIntegratedFaceFlux
314 forAll(nNeighbourCells, ni)
316 checkBounding_[nNeighbourCells[ni]] =
true;
321 bsFaces_.append(facei);
334 const polyBoundaryMesh& boundaryMesh = mesh_.boundaryMesh();
335 const surfaceScalarField::Boundary&
phib = phi_.boundaryField();
336 const surfaceScalarField::Boundary& magSfb = mesh_.magSf().boundaryField();
337 surfaceScalarField::Boundary& dVfb = dVf_.boundaryFieldRef();
338 const label nInternalFaces = mesh_.nInternalFaces();
344 const label facei = bsFaces_[i];
345 const label patchi = boundaryMesh.patchID()[facei - nInternalFaces];
346 const label start = boundaryMesh[patchi].start();
348 if (
phib[patchi].size())
351 const scalar phiP =
phib[patchi][patchFacei];
355 const scalar magSf = magSfb[patchi][patchFacei];
357 dVfb[patchi][patchFacei] = isoCutFace_.timeIntegratedFaceFlux
371 checkIfOnProcPatch(facei);
377 syncProcPatches(dVf_, phi_);
379 writeIsoFaces(isoFacePts);
381 Info<<
"Number of isoAdvector surface cells = "
386 void Foam::isoAdvection::setCellVertexValues
393 const vectorField& cellCentres = mesh_.cellCentres();
396 const point& cellCentre = cellCentres[celli];
400 ap_[
cp[vi]] = (vertex - cellCentre) & cellNormalsIn[celli];
405 void Foam::isoAdvection::normaliseAndSmooth
411 const vectorField& cellCentres = mesh_.cellCentres();
415 cellNIn /= (
mag(cellNIn) + SMALL);
418 vertexN /= (
mag(vertexN) + SMALL);
424 const point& cellCentre = cellCentres[celli];
428 scalar w = 1.0/
mag(vertex - cellCentre);
429 cellNi += w*vertexN[
cp[pointI]];
431 cellNIn[celli] = cellNi/(
mag(cellNi) + SMALL);
436 void Foam::isoAdvection::setDownwindFaces
439 DynamicLabelList& downwindFaces
445 const labelList& own = mesh_.faceOwner();
447 const cell&
c =
cells[celli];
449 downwindFaces.
clear();
455 const label facei =
c[fi];
456 const scalar
phi = faceValue(phi_, facei);
458 if (own[facei] == celli)
462 downwindFaces.append(facei);
465 else if (
phi < -10*SMALL)
467 downwindFaces.append(facei);
471 downwindFaces.shrink();
475 void Foam::isoAdvection::limitFluxes()
480 const scalar dt = mesh_.time().deltaT().value();
483 const scalar aTol = 1.0e-12;
484 scalar maxAlphaMinus1 =
gMax(alphaNew) - 1;
485 scalar minAlpha =
gMin(alphaNew);
486 const label nUndershoots = 20;
487 const label nOvershoots = 20;
488 cellIsBounded_ =
false;
490 Info <<
"isoAdvection: Before conservative bounding: min(alpha) = "
491 << minAlpha <<
", max(alpha) = 1 + " << maxAlphaMinus1 <<
endl;
494 for (
label n = 0;
n < nAlphaBounds_;
n++)
496 if (maxAlphaMinus1 > aTol)
503 DynamicList<label> correctedFaces(3*nOvershoots);
504 boundFromAbove(alpha1In_, dVfcorrected, correctedFaces);
506 forAll(correctedFaces, fi)
508 label facei = correctedFaces[fi];
511 setFaceValue(dVf_, facei, faceValue(dVfcorrected, facei));
514 syncProcPatches(dVf_, phi_);
517 if (minAlpha < -aTol)
533 DynamicList<label> correctedFaces(3*nUndershoots);
534 boundFromAbove(
alpha2, dVfcorrected, correctedFaces);
535 forAll(correctedFaces, fi)
537 label facei = correctedFaces[fi];
540 scalar
phi = faceValue(phi_, facei);
541 scalar dVcorr = faceValue(dVfcorrected, facei);
542 setFaceValue(dVf_, facei,
phi*dt - dVcorr);
545 syncProcPatches(dVf_, phi_);
552 label maxAlphaMinus1 =
max(alphaNew - 1);
553 scalar minAlpha =
min(alphaNew);
556 Info<<
"After bounding number " <<
n + 1 <<
" of time "
557 << mesh_.time().value() <<
":" <<
endl;
558 Info<<
"nOvershoots = " << nOvershoots <<
" with max(alphaNew-1) = "
559 << maxAlphaMinus1 <<
" and nUndershoots = " << nUndershoots
560 <<
" with min(alphaNew) = " << minAlpha <<
endl;
566 void Foam::isoAdvection::boundFromAbove
570 DynamicList<label>& correctedFaces
575 correctedFaces.clear();
576 scalar aTol = 10*SMALL;
579 const scalar dt = mesh_.time().deltaTValue();
581 DynamicList<label> downwindFaces(10);
582 DynamicList<label> facesToPassFluidThrough(downwindFaces.size());
583 DynamicList<scalar> dVfmax(downwindFaces.size());
584 DynamicList<scalar>
phi(downwindFaces.size());
589 if (checkBounding_.test(celli))
591 const scalar Vi = meshV[celli];
592 scalar alpha1New =
alpha1[celli] - netFlux(dVf, celli)/Vi;
593 scalar alphaOvershoot = alpha1New - 1.0;
594 scalar fluidToPassOn = alphaOvershoot*Vi;
595 label nFacesToPassFluidThrough = 1;
597 bool firstLoop =
true;
601 while (alphaOvershoot > aTol && nFacesToPassFluidThrough > 0)
604 <<
"\n\nBounding cell " << celli
605 <<
" with alpha overshooting " << alphaOvershoot
608 facesToPassFluidThrough.clear();
612 cellIsBounded_.set(celli);
615 setDownwindFaces(celli, downwindFaces);
618 nFacesToPassFluidThrough = 0;
622 const label facei = downwindFaces[fi];
623 const scalar phif = faceValue(phi_, facei);
624 const scalar dVff = faceValue(dVf, facei);
625 const scalar maxExtraFaceFluidTrans =
mag(phif*dt - dVff);
634 <<
"downwindFace " << facei
635 <<
" has maxExtraFaceFluidTrans = "
636 << maxExtraFaceFluidTrans <<
endl;
638 if (maxExtraFaceFluidTrans/Vi > aTol)
644 facesToPassFluidThrough.append(facei);
646 dVfmax.append(maxExtraFaceFluidTrans);
647 dVftot +=
mag(phif*dt);
652 <<
"\nfacesToPassFluidThrough: "
653 << facesToPassFluidThrough <<
", dVftot = "
654 << dVftot <<
" m3 corresponding to dalpha = "
655 << dVftot/Vi <<
endl;
657 forAll(facesToPassFluidThrough, fi)
659 const label facei = facesToPassFluidThrough[fi];
660 scalar fluidToPassThroughFace =
661 fluidToPassOn*
mag(
phi[fi]*dt)/dVftot;
663 nFacesToPassFluidThrough +=
664 pos0(dVfmax[fi] - fluidToPassThroughFace);
666 fluidToPassThroughFace =
667 min(fluidToPassThroughFace, dVfmax[fi]);
669 scalar dVff = faceValue(dVf, facei);
670 dVff +=
sign(
phi[fi])*fluidToPassThroughFace;
671 setFaceValue(dVf, facei, dVff);
675 checkIfOnProcPatch(facei);
676 correctedFaces.append(facei);
681 alpha1New =
alpha1[celli] - netFlux(dVf, celli)/Vi;
682 alphaOvershoot = alpha1New - 1.0;
683 fluidToPassOn = alphaOvershoot*Vi;
686 <<
"\nNew alpha for cell " << celli <<
": "
687 << alpha1New <<
endl;
696 Foam::scalar Foam::isoAdvection::netFlux
705 const cell&
c = mesh_.cells()[celli];
708 const labelList& own = mesh_.faceOwner();
712 const label facei =
c[fi];
713 const scalar dVff = faceValue(dVf, facei);
715 if (own[facei] == celli)
729 void Foam::isoAdvection::syncProcPatches
735 const polyBoundaryMesh&
patches = mesh_.boundaryMesh();
742 forAll(procPatchLabels_, i)
744 const label patchi = procPatchLabels_[i];
746 const processorPolyPatch& procPatch =
747 refCast<const processorPolyPatch>(
patches[patchi]);
749 UOPstream toNbr(procPatch.neighbProcNo(), pBufs);
750 const scalarField& pFlux = dVf.boundaryField()[patchi];
752 const List<label>& surfCellFacesOnProcPatch =
753 surfaceCellFacesOnProcPatches_[patchi];
755 const UIndirectList<scalar> dVfPatch
758 surfCellFacesOnProcPatch
761 toNbr << surfCellFacesOnProcPatch << dVfPatch;
764 pBufs.finishedSends();
768 forAll(procPatchLabels_, patchLabeli)
770 const label patchi = procPatchLabels_[patchLabeli];
772 const processorPolyPatch& procPatch =
773 refCast<const processorPolyPatch>(
patches[patchi]);
775 UIPstream fromNeighb(procPatch.neighbProcNo(), pBufs);
777 List<scalar> nbrdVfs;
779 fromNeighb >> faceIDs >> nbrdVfs;
783 Pout<<
"Received at time = " << mesh_.time().value()
784 <<
": surfCellFacesOnProcPatch = " << faceIDs <<
nl
785 <<
"Received at time = " << mesh_.time().value()
786 <<
": dVfPatch = " << nbrdVfs <<
endl;
790 scalarField& localFlux = dVf.boundaryFieldRef()[patchi];
794 const label facei = faceIDs[i];
795 localFlux[facei] = - nbrdVfs[i];
796 if (
debug &&
mag(localFlux[facei] + nbrdVfs[i]) > 10*SMALL)
798 Pout<<
"localFlux[facei] = " << localFlux[facei]
799 <<
" and nbrdVfs[i] = " << nbrdVfs[i]
800 <<
" for facei = " << facei <<
endl;
808 forAll(procPatchLabels_, patchLabeli)
810 const label patchi = procPatchLabels_[patchLabeli];
811 const scalarField& localFlux = dVf.boundaryField()[patchi];
812 Pout<<
"time = " << mesh_.time().value() <<
": localFlux = "
813 << localFlux <<
endl;
818 forAll(surfaceCellFacesOnProcPatches_, patchi)
820 surfaceCellFacesOnProcPatches_[patchi].clear();
826 void Foam::isoAdvection::checkIfOnProcPatch(
const label facei)
828 if (!mesh_.isInternalFace(facei))
830 const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
831 const label patchi = pbm.patchID()[facei - mesh_.nInternalFaces()];
833 if (isA<processorPolyPatch>(pbm[patchi]) && pbm[patchi].size())
835 const label patchFacei = pbm[patchi].whichFace(facei);
836 surfaceCellFacesOnProcPatches_[patchi].append(patchFacei);
846 scalar advectionStartTime = mesh_.time().elapsedCpuTime();
853 timeIntegratedFlux();
858 alpha1In_ *= (mesh_.Vsc0()/mesh_.Vsc());
866 alpha1_.correctBoundaryConditions();
868 scalar maxAlphaMinus1 =
gMax(alpha1In_) - 1;
869 scalar minAlpha =
gMin(alpha1In_);
870 Info <<
"isoAdvection: After conservative bounding: min(alpha) = "
871 << minAlpha <<
", max(alpha) = 1 + " << maxAlphaMinus1 <<
endl;
875 applyBruteForceBounding();
881 advectionTime_ += (mesh_.time().elapsedCpuTime() - advectionStartTime);
882 Info <<
"isoAdvection: time consumption = "
883 <<
label(100*advectionTime_/(mesh_.time().elapsedCpuTime() + SMALL))
890 bool alpha1Changed =
false;
892 scalar snapAlphaTol = dict_.lookupOrDefault<scalar>(
"snapTol", 0);
893 if (snapAlphaTol > 0)
897 *
pos0(alpha1_ - snapAlphaTol)
898 *
neg0(alpha1_ - (1.0 - snapAlphaTol))
899 +
pos0(alpha1_ - (1.0 - snapAlphaTol));
901 alpha1Changed =
true;
904 if (dict_.lookupOrDefault(
"clip",
true))
906 alpha1_ =
min(scalar(1),
max(scalar(0), alpha1_));
907 alpha1Changed =
true;
912 alpha1_.correctBoundaryConditions();
919 if (!mesh_.time().writeTime())
return;
921 if (dict_.lookupOrDefault(
"writeSurfCells",
false))
928 mesh_.time().timeName(),
943 if (!mesh_.time().writeTime())
return;
945 if (dict_.lookupOrDefault(
"writeBoundedCells",
false))
952 mesh_.time().timeName(),
958 for (
const label celli : cellIsBounded_)
974 if (!writeIsoFacesToFile_ || !mesh_.time().writeTime())
return;
979 mesh_.time().globalPath()
981 /
word::printf(
"isoFaces_%012d.obj", mesh_.time().timeIndex())
995 Info<<
nl <<
"isoAdvection: writing iso faces to file: "
996 << os.name() <<
nl <<
endl;
999 forAll(allProcFaces, proci)
1002 allProcFaces[proci];
1008 if (facePts.size() !=
f.size())
1013 os.write(
f, facePts,
false);
1022 Info<<
nl <<
"isoAdvection: writing iso faces to file: "
1023 << os.name() <<
nl <<
endl;
1030 if (facePts.size() !=
f.size())
1035 os.write(
f, facePts,
false);