1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
28 #include "freeSurface.H"
30 #include "volFields.H"
31 #include "transformField.H"
33 #include "emptyFaPatch.H"
34 #include "wedgeFaPatch.H"
35 #include "wallFvPatch.H"
37 #include "EulerDdtScheme.H"
38 #include "CrankNicolsonDdtScheme.H"
39 #include "backwardDdtScheme.H"
41 #include "tetFemMatrices.H"
42 #include "tetPointFields.H"
43 #include "faceTetPolyPatch.H"
44 #include "tetPolyPatchInterpolation.H"
45 #include "fixedValueTetPolyPatchFields.H"
46 #include "fixedValuePointPatchFields.H"
47 #include "twoDPointCorrector.H"
49 #include "slipFvPatchFields.H"
50 #include "symmetryFvPatchFields.H"
51 #include "fixedGradientFvPatchFields.H"
52 #include "zeroGradientCorrectedFvPatchFields.H"
53 #include "fixedGradientCorrectedFvPatchFields.H"
54 #include "fixedValueCorrectedFvPatchFields.H"
56 #include "primitivePatchInterpolation.H"
58 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
63 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
65 defineTypeNameAndDebug(freeSurface, 0);
68 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
70 void freeSurface::clearOut()
72 deleteDemandDrivenData(interpolatorABPtr_);
73 deleteDemandDrivenData(interpolatorBAPtr_);
74 deleteDemandDrivenData(controlPointsPtr_);
75 deleteDemandDrivenData(motionPointsMaskPtr_);
76 deleteDemandDrivenData(pointsDisplacementDirPtr_);
77 deleteDemandDrivenData(facesDisplacementDirPtr_);
78 deleteDemandDrivenData(totalDisplacementPtr_);
79 deleteDemandDrivenData(aMeshPtr_);
80 deleteDemandDrivenData(UsPtr_);
81 deleteDemandDrivenData(phisPtr_);
82 deleteDemandDrivenData(surfactConcPtr_);
83 deleteDemandDrivenData(surfaceTensionPtr_);
84 deleteDemandDrivenData(surfactantPtr_);
85 deleteDemandDrivenData(fluidIndicatorPtr_);
88 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
90 freeSurface::freeSurface
93 const volScalarField& rho,
96 const surfaceScalarField& sfPhi
103 "freeSurfaceProperties",
104 Ub.mesh().time().constant(),
115 curTimeIndex_(Ub.mesh().time().timeIndex()),
118 this->lookup("twoFluids")
122 this->lookup("normalMotionDir")
127 this->lookup("cleanInterface")
133 this->lookup("muFluidA")
137 this->lookup("muFluidB")
141 this->lookup("rhoFluidA")
145 this->lookup("rhoFluidB")
147 g_(this->lookup("g")),
148 cleanInterfaceSurfTension_
150 this->lookup("surfaceTension")
152 fixedFreeSurfacePatches_
154 this->lookup("fixedFreeSurfacePatches")
156 pointNormalsCorrectionPatches_
158 this->lookup("pointNormalsCorrectionPatches")
162 readInt(this->lookup("nFreeSurfaceCorrectors"))
165 interpolatorABPtr_(NULL),
166 interpolatorBAPtr_(NULL),
167 controlPointsPtr_(NULL),
168 motionPointsMaskPtr_(NULL),
169 pointsDisplacementDirPtr_(NULL),
170 facesDisplacementDirPtr_(NULL),
171 totalDisplacementPtr_(NULL),
175 surfactConcPtr_(NULL),
176 surfaceTensionPtr_(NULL),
177 surfactantPtr_(NULL),
178 fluidIndicatorPtr_(NULL)
180 //Read motion direction
181 if (!normalMotionDir_)
183 motionDir_ = vector(this->lookup("motionDir"));
184 motionDir_ /= mag(motionDir_) + SMALL;
187 // Set point normal correction patches
188 boolList& correction = aMesh().correctPatchPointNormals();
190 forAll(pointNormalsCorrectionPatches_, patchI)
192 word patchName = pointNormalsCorrectionPatches_[patchI];
194 label patchID = aMesh().boundary().findPatchID(patchName);
200 "freeSurface::freeSurface(...)"
201 ) << "Patch name for point normals correction does not exist"
202 << abort(FatalError);
205 correction[patchID] = true;
209 aMesh().movePoints();
212 // Detect the free surface patch
213 forAll (mesh().boundary(), patchI)
215 if(mesh().boundary()[patchI].name() == "freeSurface")
219 Info<< "Found free surface patch. ID: " << aPatchID_
226 FatalErrorIn("freeSurface::freeSurface(...)")
227 << "Free surface patch not defined. Please make sure that "
228 << " the free surface patches is named as freeSurface"
229 << abort(FatalError);
233 // Detect the free surface shadow patch
236 forAll (mesh().boundary(), patchI)
238 if(mesh().boundary()[patchI].name() == "freeSurfaceShadow")
242 Info<< "Found free surface shadow patch. ID: "
243 << bPatchID_ << endl;
249 FatalErrorIn("freeSurface::freeSurface(...)")
250 << "Free surface shadow patch not defined. "
251 << "Please make sure that the free surface shadow patch "
252 << "is named as freeSurfaceShadow."
253 << abort(FatalError);
258 // Mark free surface boundary points
259 // which belonge to processor patches
260 forAll(aMesh().boundary(), patchI)
264 aMesh().boundary()[patchI].type()
265 == processorFaPatch::typeName
268 const labelList& patchPoints =
269 aMesh().boundary()[patchI].pointLabels();
271 forAll(patchPoints, pointI)
273 motionPointsMask()[patchPoints[pointI]] = -1;
279 // Mark fixed free surface boundary points
280 forAll(fixedFreeSurfacePatches_, patchI)
283 aMesh().boundary().findPatchID
285 fixedFreeSurfacePatches_[patchI]
288 if(fixedPatchID == -1)
290 FatalErrorIn("freeSurface::freeSurface(...)")
291 << "Wrong faPatch name in the fixedFreeSurfacePatches list"
292 << " defined in the freeSurfaceProperties dictionary"
293 << abort(FatalError);
296 const labelList& patchPoints =
297 aMesh().boundary()[fixedPatchID].pointLabels();
299 forAll(patchPoints, pointI)
301 motionPointsMask()[patchPoints[pointI]] = 0;
306 // Mark free-surface boundary point
307 // at the axis of 2-D axisymmetic cases
308 forAll(aMesh().boundary(), patchI)
312 aMesh().boundary()[patchI].type()
313 == wedgeFaPatch::typeName
316 const wedgeFaPatch& wedgePatch =
317 refCast<const wedgeFaPatch>(aMesh().boundary()[patchI]);
319 if(wedgePatch.axisPoint() > -1)
321 motionPointsMask()[wedgePatch.axisPoint()] = 0;
323 Info << "Axis point: "
324 << wedgePatch.axisPoint()
326 << aMesh().points()[wedgePatch.axisPoint()] << endl;
332 // Read free-surface points total displacement if present
333 readTotalDisplacement();
336 // Read control points positions if present
340 // Check if smoothing switch is set
341 if (this->found("smoothing"))
343 smoothing_ = Switch(this->lookup("smoothing"));
348 // * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * * //
350 freeSurface::~freeSurface()
356 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
358 void freeSurface::updateDisplacementDirections()
360 if(normalMotionDir())
362 // Update point displacement correction
363 pointsDisplacementDir() = aMesh().pointAreaNormals();
365 // Correcte point displacement direction
366 // at the "centerline" symmetryPlane which represents the axis
367 // of an axisymmetric case
368 forAll(aMesh().boundary(), patchI)
370 if(aMesh().boundary()[patchI].type() == wedgeFaPatch::typeName)
372 const wedgeFaPatch& wedgePatch =
373 refCast<const wedgeFaPatch>(aMesh().boundary()[patchI]);
375 vector axis = wedgePatch.axis();
377 label centerLinePatchID =
378 aMesh().boundary().findPatchID("centerline");
380 if(centerLinePatchID != -1)
382 const labelList& pointLabels =
383 aMesh().boundary()[centerLinePatchID].pointLabels();
385 forAll(pointLabels, pointI)
388 pointsDisplacementDir()[pointLabels[pointI]];
390 dir = (dir&axis)*axis;
393 pointsDisplacementDir()[pointLabels[pointI]] = dir;
398 Info << "Warning: centerline polyPatch does not exist. "
399 << "Free surface points displacement directions "
400 << "will not be corrected at the axis (centerline)"
408 // Update face displacement direction
409 facesDisplacementDir() =
410 aMesh().faceAreaNormals().internalField();
412 // Correction of control points postion
413 const vectorField& Cf = aMesh().areaCentres().internalField();
416 facesDisplacementDir()
417 *(facesDisplacementDir()&(controlPoints() - Cf))
423 bool freeSurface::predictPoints()
429 controlPoints() = aMesh().areaCentres().internalField();
430 movePoints(scalarField(controlPoints().size(), 0));
431 movePoints(-fvc::meshPhi(rho(),U())().boundaryField()[aPatchID()]);
437 freeSurfCorr<nFreeSurfCorr_;
441 movePoints(phi_.boundaryField()[aPatchID()]);
448 bool freeSurface::correctPoints()
453 freeSurfCorr<nFreeSurfCorr_;
457 movePoints(phi_.boundaryField()[aPatchID()]);
464 bool freeSurface::movePoints(const scalarField& interfacePhi)
466 pointField newMeshPoints = mesh().points();
468 scalarField sweptVolCorr =
470 - fvc::meshPhi(rho(),U())().boundaryField()[aPatchID()];
474 mesh().schemesDict().ddtScheme
476 "ddt(" + rho().name() + ',' + U().name()+')'
483 == fv::CrankNicolsonDdtScheme<vector>::typeName
486 sweptVolCorr *= (1.0/2.0)*DB().deltaT().value();
491 == fv::EulerDdtScheme<vector>::typeName
494 sweptVolCorr *= DB().deltaT().value();
499 == fv::backwardDdtScheme<vector>::typeName
502 if (DB().timeIndex() == 1)
504 sweptVolCorr *= DB().deltaT().value();
508 sweptVolCorr *= (2.0/3.0)*DB().deltaT().value();
513 FatalErrorIn("freeSurface::movePoints()")
514 << "Unsupported temporal differencing scheme : "
516 << abort(FatalError);
519 const scalarField& Sf = aMesh().S();
520 const vectorField& Nf = aMesh().faceAreaNormals().internalField();
523 sweptVolCorr/(Sf*(Nf & facesDisplacementDir()));
525 pointField displacement = pointDisplacement(deltaH);
528 // Move only free-surface points
530 const labelList& meshPointsA =
531 mesh().boundaryMesh()[aPatchID()].meshPoints();
533 forAll (displacement, pointI)
535 newMeshPoints[meshPointsA[pointI]] += displacement[pointI];
540 const labelList& meshPointsB =
541 mesh().boundaryMesh()[bPatchID_].meshPoints();
543 pointField displacementB =
544 interpolatorAB().pointInterpolate
549 forAll (displacementB, pointI)
551 newMeshPoints[meshPointsB[pointI]] += displacementB[pointI];
555 // Update total displacement field
557 if(totalDisplacementPtr_ && (curTimeIndex_ < DB().timeIndex()))
559 FatalErrorIn("freeSurface::movePoints()")
560 << "Total displacement of free surface points "
561 << "from previous time step is not absorbed by the mesh."
562 << abort(FatalError);
564 else if (curTimeIndex_ < DB().timeIndex())
566 totalDisplacement() = displacement;
568 curTimeIndex_ = DB().timeIndex();
572 totalDisplacement() += displacement;
575 twoDPointCorrector twoDPointCorr(mesh());
577 twoDPointCorr.correctPoints(newMeshPoints);
579 mesh().movePoints(newMeshPoints);
581 // faMesh motion is done automatically, using meshObject
583 // aMesh().movePoints(mesh().points());
586 // Move correctedFvPatchField fvSubMeshes
588 forAll(U().boundaryField(), patchI)
593 U().boundaryField()[patchI].type()
594 == fixedGradientCorrectedFvPatchField<vector>::typeName
598 U().boundaryField()[patchI].type()
599 == fixedValueCorrectedFvPatchField<vector>::typeName
603 U().boundaryField()[patchI].type()
604 == zeroGradientCorrectedFvPatchField<vector>::typeName
608 correctedFvPatchField<vector>& pU =
609 refCast<correctedFvPatchField<vector> >
611 U().boundaryField()[patchI]
614 pU.movePatchSubMesh();
618 forAll(p().boundaryField(), patchI)
623 p().boundaryField()[patchI].type()
624 == fixedGradientCorrectedFvPatchField<scalar>::typeName
628 p().boundaryField()[patchI].type()
629 == fixedValueCorrectedFvPatchField<scalar>::typeName
633 p().boundaryField()[patchI].type()
634 == zeroGradientCorrectedFvPatchField<scalar>::typeName
638 correctedFvPatchField<scalar>& pP =
639 refCast<correctedFvPatchField<scalar> >
641 p().boundaryField()[patchI]
644 pP.movePatchSubMesh();
652 bool freeSurface::moveMeshPointsForOldFreeSurfDisplacement()
654 if(totalDisplacementPtr_)
656 pointField newPoints = mesh().points();
658 const labelList& meshPointsA =
659 mesh().boundaryMesh()[aPatchID()].meshPoints();
661 forAll (totalDisplacement(), pointI)
663 newPoints[meshPointsA[pointI]] -= totalDisplacement()[pointI];
667 // Check mesh motion solver type
668 bool feMotionSolver =
669 mesh().objectRegistry::foundObject<tetPointVectorField>
673 bool fvMotionSolver =
674 mesh().objectRegistry::foundObject<pointVectorField>
681 tetPointVectorField& motionU =
682 const_cast<tetPointVectorField&>
684 mesh().objectRegistry::
685 lookupObject<tetPointVectorField>
691 fixedValueTetPolyPatchVectorField& motionUaPatch =
692 refCast<fixedValueTetPolyPatchVectorField>
694 motionU.boundaryField()[aPatchID()]
697 tetPolyPatchInterpolation tppiAPatch
699 refCast<const faceTetPolyPatch>
701 motionUaPatch.patch()
706 tppiAPatch.pointToPointInterpolate
708 totalDisplacement()/DB().deltaT().value()
713 const labelList& meshPointsB =
714 mesh().boundaryMesh()[bPatchID()].meshPoints();
716 pointField totDisplacementB =
717 interpolatorAB().pointInterpolate
722 forAll (totDisplacementB, pointI)
724 newPoints[meshPointsB[pointI]] -=
725 totDisplacementB[pointI];
728 fixedValueTetPolyPatchVectorField& motionUbPatch =
729 refCast<fixedValueTetPolyPatchVectorField>
731 motionU.boundaryField()[bPatchID()]
734 tetPolyPatchInterpolation tppiBPatch
736 refCast<const faceTetPolyPatch>(motionUbPatch.patch())
740 tppiBPatch.pointToPointInterpolate
742 totDisplacementB/DB().deltaT().value()
746 else if (fvMotionSolver)
748 pointVectorField& motionU =
749 const_cast<pointVectorField&>
751 mesh().objectRegistry::
752 lookupObject<pointVectorField>
758 fixedValuePointPatchVectorField& motionUaPatch =
759 refCast<fixedValuePointPatchVectorField>
761 motionU.boundaryField()[aPatchID()]
765 totalDisplacement()/DB().deltaT().value();
769 const labelList& meshPointsB =
770 mesh().boundaryMesh()[bPatchID()].meshPoints();
772 pointField totDisplacementB =
773 interpolatorAB().pointInterpolate
778 forAll (totDisplacementB, pointI)
780 newPoints[meshPointsB[pointI]] -=
781 totDisplacementB[pointI];
784 fixedValuePointPatchVectorField& motionUbPatch =
785 refCast<fixedValuePointPatchVectorField>
787 motionU.boundaryField()[bPatchID()]
791 totDisplacementB/DB().deltaT().value();
795 twoDPointCorrector twoDPointCorr(mesh());
797 twoDPointCorr.correctPoints(newPoints);
799 mesh().movePoints(newPoints);
801 deleteDemandDrivenData(totalDisplacementPtr_);
805 // faMesh motion is done automatically, using meshObject
807 // aMesh().movePoints(mesh().points());
809 // Move correctedFvPatchField fvSubMeshes
811 forAll(U().boundaryField(), patchI)
816 U().boundaryField()[patchI].type()
817 == fixedGradientCorrectedFvPatchField<vector>::typeName
821 U().boundaryField()[patchI].type()
822 == fixedValueCorrectedFvPatchField<vector>::typeName
826 U().boundaryField()[patchI].type()
827 == zeroGradientCorrectedFvPatchField<vector>::typeName
831 correctedFvPatchField<vector>& aU =
832 refCast<correctedFvPatchField<vector> >
834 U().boundaryField()[patchI]
837 aU.movePatchSubMesh();
841 forAll(p().boundaryField(), patchI)
846 p().boundaryField()[patchI].type()
847 == fixedGradientCorrectedFvPatchField<scalar>::typeName
851 p().boundaryField()[patchI].type()
852 == fixedValueCorrectedFvPatchField<scalar>::typeName
856 p().boundaryField()[patchI].type()
857 == zeroGradientCorrectedFvPatchField<scalar>::typeName
861 correctedFvPatchField<scalar>& aP =
862 refCast<correctedFvPatchField<scalar> >
864 p().boundaryField()[patchI]
867 aP.movePatchSubMesh();
876 bool freeSurface::moveMeshPoints()
878 scalarField sweptVolCorr =
879 phi_.boundaryField()[aPatchID()]
880 - fvc::meshPhi(rho(),U())().boundaryField()[aPatchID()];
884 mesh().schemesDict().ddtScheme
886 "ddt(" + rho().name() + ',' + U().name()+')'
893 == fv::CrankNicolsonDdtScheme<vector>::typeName
896 sweptVolCorr *= (1.0/2.0)*DB().deltaT().value();
901 == fv::EulerDdtScheme<vector>::typeName
904 sweptVolCorr *= DB().deltaT().value();
909 == fv::backwardDdtScheme<vector>::typeName
912 sweptVolCorr *= (2.0/3.0)*DB().deltaT().value();
916 FatalErrorIn("freeSurface::movePoints()")
917 << "Unsupported temporal differencing scheme : "
919 << abort(FatalError);
923 const scalarField& Sf = aMesh().S();
924 const vectorField& Nf = aMesh().faceAreaNormals().internalField();
927 sweptVolCorr/(Sf*(Nf & facesDisplacementDir()));
930 pointField displacement = pointDisplacement(deltaH);
933 //-- Set mesh motion boundary conditions
935 tetPointVectorField& motionU =
936 const_cast<tetPointVectorField&>
938 mesh().objectRegistry::
939 lookupObject<tetPointVectorField>
945 fixedValueTetPolyPatchVectorField& motionUaPatch =
946 refCast<fixedValueTetPolyPatchVectorField>
948 motionU.boundaryField()[aPatchID()]
951 tetPolyPatchInterpolation tppiAPatch
953 refCast<const faceTetPolyPatch>
955 motionUaPatch.patch()
960 tppiAPatch.pointToPointInterpolate
962 displacement/DB().deltaT().value()
967 fixedValueTetPolyPatchVectorField& motionUbPatch =
968 refCast<fixedValueTetPolyPatchVectorField>
970 motionU.boundaryField()[bPatchID()]
973 tetPolyPatchInterpolation tppiBPatch
975 refCast<const faceTetPolyPatch>(motionUbPatch.patch())
979 tppiBPatch.pointToPointInterpolate
981 interpolatorAB().pointInterpolate
983 displacement/DB().deltaT().value()
990 // faMesh motion is done automatically, using meshObject
992 // aMesh().movePoints(mesh().points());
995 // Move correctedFvPatchField fvSubMeshes
997 forAll(U().boundaryField(), patchI)
1002 U().boundaryField()[patchI].type()
1003 == fixedGradientCorrectedFvPatchField<vector>::typeName
1007 U().boundaryField()[patchI].type()
1008 == fixedValueCorrectedFvPatchField<vector>::typeName
1012 U().boundaryField()[patchI].type()
1013 == zeroGradientCorrectedFvPatchField<vector>::typeName
1017 correctedFvPatchField<vector>& aU =
1018 refCast<correctedFvPatchField<vector> >
1020 U().boundaryField()[patchI]
1023 aU.movePatchSubMesh();
1027 forAll(p().boundaryField(), patchI)
1032 p().boundaryField()[patchI].type()
1033 == fixedGradientCorrectedFvPatchField<scalar>::typeName
1037 p().boundaryField()[patchI].type()
1038 == fixedValueCorrectedFvPatchField<scalar>::typeName
1042 p().boundaryField()[patchI].type()
1043 == zeroGradientCorrectedFvPatchField<scalar>::typeName
1047 correctedFvPatchField<scalar>& aP =
1048 refCast<correctedFvPatchField<scalar> >
1050 p().boundaryField()[patchI]
1053 aP.movePatchSubMesh();
1061 void freeSurface::updateBoundaryConditions()
1064 updateSurfactantConcentration();
1069 void freeSurface::updateVelocity()
1073 vectorField nA = mesh().boundary()[aPatchID()].nf();
1075 vectorField nB = mesh().boundary()[bPatchID()].nf();
1077 scalarField DnB = interpolatorBA().faceInterpolate
1079 mesh().boundary()[bPatchID()].deltaCoeffs()
1082 scalarField DnA = mesh().boundary()[aPatchID()].deltaCoeffs();
1086 U().boundaryField()[aPatchID()].patchInternalField();
1090 U().boundaryField()[aPatchID()].type()
1091 == fixedGradientCorrectedFvPatchField<vector>::typeName
1094 fixedGradientCorrectedFvPatchField<vector>& aU =
1095 refCast<fixedGradientCorrectedFvPatchField<vector> >
1097 U().boundaryField()[aPatchID()]
1100 UtPA += aU.corrVecGrad();
1103 UtPA -= nA*(nA & UtPA);
1106 vectorField UtPB = interpolatorBA().faceInterpolate
1108 U().boundaryField()[bPatchID()].patchInternalField()
1113 U().boundaryField()[bPatchID()].type()
1114 == fixedValueCorrectedFvPatchField<vector>::typeName
1117 fixedValueCorrectedFvPatchField<vector>& bU =
1118 refCast<fixedValueCorrectedFvPatchField<vector> >
1120 U().boundaryField()[bPatchID()]
1123 UtPB += interpolatorBA().faceInterpolate(bU.corrVecGrad());
1126 UtPB -= nA*(nA & UtPB);
1128 vectorField UtFs = muFluidA().value()*DnA*UtPA
1129 + muFluidB().value()*DnB*UtPB;
1132 nA*phi_.boundaryField()[aPatchID()]
1133 /mesh().boundary()[aPatchID()].magSf();
1135 Us().internalField() += UnFs - nA*(nA&Us().internalField());
1136 correctUsBoundaryConditions();
1138 UtFs -= (muFluidA().value() - muFluidB().value())*
1139 (fac::grad(Us())&aMesh().faceAreaNormals())().internalField();
1142 vectorField tangentialSurfaceTensionForce(nA.size(), vector::zero);
1144 if(!cleanInterface())
1146 tangentialSurfaceTensionForce =
1147 surfaceTensionGrad()().internalField();
1151 vectorField surfaceTensionForce =
1152 cleanInterfaceSurfTension().value()
1155 aMesh().Le()*aMesh().edgeLengthCorrection()
1156 )().internalField();
1158 tangentialSurfaceTensionForce =
1160 - cleanInterfaceSurfTension().value()
1161 *aMesh().faceCurvatures().internalField()*nA;
1164 UtFs += tangentialSurfaceTensionForce;
1166 UtFs /= muFluidA().value()*DnA + muFluidB().value()*DnB + VSMALL;
1168 Us().internalField() = UnFs + UtFs;
1169 correctUsBoundaryConditions();
1171 // Store old-time velocity field U()
1174 U().boundaryField()[bPatchID()] ==
1175 interpolatorAB().faceInterpolate(UtFs)
1176 + nB*fvc::meshPhi(rho(),U())().boundaryField()[bPatchID()]/
1177 mesh().boundary()[bPatchID()].magSf();
1181 p().boundaryField()[bPatchID()].type()
1182 == fixedGradientFvPatchField<scalar>::typeName
1185 fixedGradientFvPatchField<scalar>& pB =
1186 refCast<fixedGradientFvPatchField<scalar> >
1188 p().boundaryField()[bPatchID()]
1192 - rhoFluidB().value()
1194 nB&fvc::ddt(U())().boundaryField()[bPatchID()]
1199 // Update fixedGradient boundary condition on patch A
1201 vectorField nGradU =
1202 muFluidB().value()*(UtPB - UtFs)*DnA
1203 + tangentialSurfaceTensionForce
1204 - muFluidA().value()*nA*fac::div(Us())().internalField()
1205 + (muFluidB().value() - muFluidA().value())
1206 *(fac::grad(Us())().internalField()&nA);
1208 nGradU /= muFluidA().value() + VSMALL;
1212 U().boundaryField()[aPatchID()].type()
1213 == fixedGradientCorrectedFvPatchField<vector>::typeName
1216 fixedGradientCorrectedFvPatchField<vector>& aU =
1217 refCast<fixedGradientCorrectedFvPatchField<vector> >
1219 U().boundaryField()[aPatchID()]
1222 aU.gradient() = nGradU;
1226 U().boundaryField()[aPatchID()].type()
1227 == fixedGradientFvPatchField<vector>::typeName
1230 fixedGradientFvPatchField<vector>& aU =
1231 refCast<fixedGradientFvPatchField<vector> >
1233 U().boundaryField()[aPatchID()]
1236 aU.gradient() = nGradU;
1240 FatalErrorIn("freeSurface::updateVelocity()")
1241 << "Bounary condition on " << U().name()
1242 << " for freeSurface patch is "
1243 << U().boundaryField()[aPatchID()].type()
1245 << fixedGradientCorrectedFvPatchField<vector>::typeName
1247 << fixedGradientFvPatchField<vector>::typeName
1248 << abort(FatalError);
1253 vectorField nA = aMesh().faceAreaNormals().internalField();
1256 nA*phi_.boundaryField()[aPatchID()]
1257 /mesh().boundary()[aPatchID()].magSf();
1259 // Correct normal component of free-surface velocity
1260 Us().internalField() += UnFs - nA*(nA&Us().internalField());
1261 correctUsBoundaryConditions();
1263 vectorField tangentialSurfaceTensionForce(nA.size(), vector::zero);
1265 if(!cleanInterface())
1267 tangentialSurfaceTensionForce =
1268 surfaceTensionGrad()().internalField();
1272 vectorField surfaceTensionForce =
1273 cleanInterfaceSurfTension().value()
1276 aMesh().Le()*aMesh().edgeLengthCorrection()
1277 )().internalField();
1279 tangentialSurfaceTensionForce =
1281 - cleanInterfaceSurfTension().value()
1282 *aMesh().faceCurvatures().internalField()*nA;
1284 if (muFluidA().value() < SMALL)
1286 tangentialSurfaceTensionForce = vector::zero;
1290 vectorField tnGradU =
1291 tangentialSurfaceTensionForce/(muFluidA().value() + VSMALL)
1292 - (fac::grad(Us())&aMesh().faceAreaNormals())().internalField();
1295 U().boundaryField()[aPatchID()].patchInternalField();
1296 UtPA -= nA*(nA & UtPA);
1298 scalarField DnA = mesh().boundary()[aPatchID()].deltaCoeffs();
1300 vectorField UtFs = UtPA + tnGradU/DnA;
1302 Us().internalField() = UtFs + UnFs;
1303 correctUsBoundaryConditions();
1305 vectorField nGradU =
1306 tangentialSurfaceTensionForce/(muFluidA().value() + VSMALL)
1307 - nA*fac::div(Us())().internalField()
1308 - (fac::grad(Us())().internalField()&nA);
1312 U().boundaryField()[aPatchID()].type()
1313 == fixedGradientCorrectedFvPatchField<vector>::typeName
1316 fixedGradientCorrectedFvPatchField<vector>& aU =
1317 refCast<fixedGradientCorrectedFvPatchField<vector> >
1319 U().boundaryField()[aPatchID()]
1322 aU.gradient() = nGradU;
1326 U().boundaryField()[aPatchID()].type()
1327 == fixedGradientFvPatchField<vector>::typeName
1330 fixedGradientFvPatchField<vector>& aU =
1331 refCast<fixedGradientFvPatchField<vector> >
1333 U().boundaryField()[aPatchID()]
1336 aU.gradient() = nGradU;
1340 FatalErrorIn("freeSurface::updateVelocity()")
1341 << "Bounary condition on " << U().name()
1342 << " for freeSurface patch is "
1343 << U().boundaryField()[aPatchID()].type()
1345 << fixedGradientCorrectedFvPatchField<vector>::typeName
1347 << fixedGradientFvPatchField<vector>::typeName
1348 << abort(FatalError);
1354 void freeSurface::updatePressure()
1356 // Correct pressure boundary condition at the free-surface
1358 vectorField nA = mesh().boundary()[aPatchID()].nf();
1363 interpolatorBA().faceInterpolate
1365 p().boundaryField()[bPatchID()]
1368 const scalarField& K = aMesh().faceCurvatures().internalField();
1370 Info << "Free surface curvature: min = " << gMin(K)
1371 << ", max = " << gMax(K)
1372 << ", average = " << gAverage(K) << endl << flush;
1374 if(cleanInterface())
1376 // pA -= cleanInterfaceSurfTension().value()*(K - gAverage(K));
1377 pA -= cleanInterfaceSurfTension().value()*K;
1381 scalarField surfTensionK =
1382 surfaceTension().internalField()*K;
1384 pA -= surfTensionK - gAverage(surfTensionK);
1387 pA -= 2.0*(muFluidA().value() - muFluidB().value())
1388 *fac::div(Us())().internalField();
1390 // vector R0 = gAverage(mesh().C().boundaryField()[aPatchID()]);
1391 vector R0 = vector::zero;
1393 pA -= (rhoFluidA().value() - rhoFluidB().value())*
1397 mesh().C().boundaryField()[aPatchID()]
1402 p().boundaryField()[aPatchID()] == pA;
1406 // vector R0 = gAverage(mesh().C().boundaryField()[aPatchID()]);
1407 vector R0 = vector::zero;
1410 - rhoFluidA().value()*
1414 mesh().C().boundaryField()[aPatchID()]
1419 const scalarField& K = aMesh().faceCurvatures().internalField();
1421 Info << "Free surface curvature: min = " << gMin(K)
1422 << ", max = " << gMax(K) << ", average = " << gAverage(K)
1425 if(cleanInterface())
1427 // pA -= cleanInterfaceSurfTension().value()*(K - gAverage(K));
1428 pA -= cleanInterfaceSurfTension().value()*K;
1432 scalarField surfTensionK =
1433 surfaceTension().internalField()*K;
1435 pA -= surfTensionK - gAverage(surfTensionK);
1438 pA -= 2.0*muFluidA().value()*fac::div(Us())().internalField();
1440 p().boundaryField()[aPatchID()] == pA;
1444 // Set modified pressure at patches with fixed apsolute
1447 // vector R0 = gAverage(mesh().C().boundaryField()[aPatchID()]);
1448 vector R0 = vector::zero;
1450 for (int patchI=0; patchI < p().boundaryField().size(); patchI++)
1454 p().boundaryField()[patchI].type()
1455 == fixedValueFvPatchScalarField::typeName
1458 if (patchI != aPatchID())
1460 p().boundaryField()[patchI] ==
1461 - rho().boundaryField()[patchI]
1462 *(g_.value()&(mesh().C().boundaryField()[patchI] - R0));
1469 void freeSurface::updateSurfaceFlux()
1471 Phis() = fac::interpolate(Us()) & aMesh().Le();
1475 void freeSurface::updateSurfactantConcentration()
1477 if(!cleanInterface())
1479 Info << "Correct surfactant concentration" << endl << flush;
1481 updateSurfaceFlux();
1483 // Crate and solve the surfactanta transport equation
1484 faScalarMatrix CsEqn
1486 fam::ddt(surfactantConcentration())
1487 + fam::div(Phis(), surfactantConcentration())
1490 surfactant().surfactDiffusion(),
1491 surfactantConcentration()
1496 if(surfactant().soluble())
1498 const scalarField& C =
1499 mesh().boundary()[aPatchID()]
1500 .lookupPatchField<volScalarField, scalar>("C");
1513 dimensioned<scalar>("Cb", dimMoles/dimVolume, 0),
1514 zeroGradientFaPatchScalarField::typeName
1517 Cb.internalField() = C;
1518 Cb.correctBoundaryConditions();
1523 surfactant().surfactAdsorptionCoeff()*Cb
1524 + surfactant().surfactAdsorptionCoeff()
1525 *surfactant().surfactDesorptionCoeff(),
1526 surfactantConcentration()
1528 - surfactant().surfactAdsorptionCoeff()
1529 *Cb*surfactant().surfactSaturatedConc();
1534 Info << "Correct surface tension" << endl;
1537 cleanInterfaceSurfTension()
1538 + surfactant().surfactR()
1539 *surfactant().surfactT()
1540 *surfactant().surfactSaturatedConc()
1541 *log(1.0 - surfactantConcentration()
1542 /surfactant().surfactSaturatedConc());
1544 if(neg(min(surfaceTension().internalField())))
1548 "void freeSurface::correctSurfactantConcentration()"
1549 ) << "Surface tension is negative"
1550 << abort(FatalError);
1556 void freeSurface::correctUsBoundaryConditions()
1558 forAll(Us().boundaryField(), patchI)
1562 Us().boundaryField()[patchI].type()
1563 == calculatedFaPatchVectorField::typeName
1566 vectorField& pUs = Us().boundaryField()[patchI];
1568 pUs = Us().boundaryField()[patchI].patchInternalField();
1570 label ngbPolyPatchID =
1571 aMesh().boundary()[patchI].ngbPolyPatchIndex();
1573 if(ngbPolyPatchID != -1)
1578 isA<slipFvPatchVectorField>
1580 U().boundaryField()[ngbPolyPatchID]
1585 isA<symmetryFvPatchVectorField>
1587 U().boundaryField()[ngbPolyPatchID]
1593 aMesh().boundary()[patchI].ngbPolyPatchFaceNormals();
1601 Us().correctBoundaryConditions();
1605 vector freeSurface::totalPressureForce() const
1607 const scalarField& S = aMesh().S();
1609 const vectorField& n = aMesh().faceAreaNormals().internalField();
1611 const scalarField& P = p().boundaryField()[aPatchID()];
1613 vectorField pressureForces = S*P*n;
1615 return gSum(pressureForces);
1619 vector freeSurface::totalViscousForce() const
1621 const scalarField& S = aMesh().S();
1622 const vectorField& n = aMesh().faceAreaNormals().internalField();
1624 vectorField nGradU =
1625 U().boundaryField()[aPatchID()].snGrad();
1627 vectorField viscousForces =
1628 - muFluidA().value()*S
1631 + (fac::grad(Us())().internalField()&n)
1632 - (n*fac::div(Us())().internalField())
1635 return gSum(viscousForces);
1639 vector freeSurface::totalSurfaceTensionForce() const
1641 const scalarField& S = aMesh().S();
1643 const vectorField& n = aMesh().faceAreaNormals().internalField();
1645 const scalarField& K = aMesh().faceCurvatures().internalField();
1647 vectorField surfTensionForces(n.size(), vector::zero);
1649 if(cleanInterface())
1652 S*cleanInterfaceSurfTension().value()
1655 aMesh().Le()*aMesh().edgeLengthCorrection()
1656 )().internalField();
1660 surfTensionForces *= surfaceTension().internalField()*K;
1663 return gSum(surfTensionForces);
1667 void freeSurface::initializeControlPointsPosition()
1669 scalarField deltaH = scalarField(aMesh().nFaces(), 0.0);
1671 pointField displacement = pointDisplacement(deltaH);
1673 const faceList& faces = aMesh().faces();
1674 const pointField& points = aMesh().points();
1677 pointField newPoints = points + displacement;
1679 scalarField sweptVol(faces.size(), 0.0);
1681 forAll(faces, faceI)
1683 sweptVol[faceI] = -faces[faceI].sweptVol(points, newPoints);
1686 vectorField faceArea(faces.size(), vector::zero);
1688 forAll (faceArea, faceI)
1690 faceArea[faceI] = faces[faceI].normal(newPoints);
1693 forAll(deltaH, faceI)
1695 deltaH[faceI] = sweptVol[faceI]/
1696 (faceArea[faceI] & facesDisplacementDir()[faceI]);
1699 displacement = pointDisplacement(deltaH);
1703 scalar freeSurface::maxCourantNumber()
1707 if(cleanInterface())
1709 const scalarField& dE =aMesh().lPN();
1713 DB().deltaT().value()/
1716 rhoFluidA().value()*dE*dE*dE/
1717 2.0/M_PI/(cleanInterfaceSurfTension().value() + SMALL)
1723 scalarField sigmaE =
1724 linearEdgeInterpolate(surfaceTension())().internalField()
1727 const scalarField& dE =aMesh().lPN();
1731 DB().deltaT().value()/
1734 rhoFluidA().value()*dE*dE*dE/
1744 void freeSurface::updateProperties()
1746 muFluidA_ = dimensionedScalar(this->lookup("muFluidA"));
1748 muFluidB_ = dimensionedScalar(this->lookup("muFluidB"));
1750 rhoFluidA_ = dimensionedScalar(this->lookup("rhoFluidA"));
1752 rhoFluidB_ = dimensionedScalar(this->lookup("rhoFluidB"));
1754 g_ = dimensionedVector(this->lookup("g"));
1756 cleanInterfaceSurfTension_ =
1757 dimensionedScalar(this->lookup("surfaceTension"));
1761 void freeSurface::writeVTK() const
1763 aMesh().patch().writeVTK
1765 DB().timePath()/"freeSurface",
1767 aMesh().patch().points()
1772 void freeSurface::writeVTKControlPoints()
1774 // Write patch and points into VTK
1775 fileName name(DB().timePath()/"freeSurfaceControlPoints");
1776 OFstream mps(name + ".vtk");
1778 mps << "# vtk DataFile Version 2.0" << nl
1779 << name << ".vtk" << nl
1781 << "DATASET POLYDATA" << nl
1782 << "POINTS " << controlPoints().size() << " float" << nl;
1784 forAll(controlPoints(), pointI)
1786 mps << controlPoints()[pointI].x() << ' '
1787 << controlPoints()[pointI].y() << ' '
1788 << controlPoints()[pointI].z() << nl;
1792 mps << "VERTICES " << controlPoints().size() << ' '
1793 << controlPoints().size()*2 << nl;
1795 forAll(controlPoints(), pointI)
1797 mps << 1 << ' ' << pointI << nl;
1802 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1804 } // End namespace Foam
1806 // ************************************************************************* //