Loading...
Searching...
No Matches
interfaceTrackingFvMesh.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) 2019 Zeljko Tukovic, FSB Zagreb.
9 Copyright (C) 2020-2024 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
31#include "motionSolver.H"
32#include "volFields.H"
33#include "processorFaPatch.H"
34#include "wedgeFaPatch.H"
35#include "wedgeFaPatchFields.H"
36#include "slipFaPatchFields.H"
38#include "slipFvPatchFields.H"
40#include "wallFvPatch.H"
41#include "polyPatchID.H"
42#include "fvcMeshPhi.H"
44#include "EulerDdtScheme.H"
46#include "backwardDdtScheme.H"
47#include "twoDPointCorrector.H"
48#include "gravityMeshObject.H"
50#include "unitConversion.H"
53
54// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
55
56namespace Foam
57{
60 (
64 );
66 (
69 doInit
70 );
71}
72
73
74// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
75
76void Foam::interfaceTrackingFvMesh::initializeData()
77{
78 // Set free surface patch index
79 {
80 const word fsPatchName(motion().get<word>("fsPatchName"));
81
82 polyPatchID patch(fsPatchName, this->boundaryMesh());
83
84 if (!patch.active())
85 {
87 << "Patch name " << fsPatchName << " not found."
88 << abort(FatalError);
89 }
90
91 fsPatchIndex_ = patch.index();
92 }
93
94 // Set point normal correction for finite area mesh
95 if (!pointNormalsCorrectionPatches_.empty())
96 {
98
99 for (const word& patchName : pointNormalsCorrectionPatches_)
100 {
101 label patchID = aMesh().boundary().findPatchID(patchName);
102
103 if (patchID == -1)
104 {
106 << "Patch name '" << patchName
107 << "' for point normals correction does not exist"
108 << abort(FatalError);
109 }
110
111 correction[patchID] = true;
112 }
113 }
114
115 // Read motion direction
116 if (!normalMotionDir_)
117 {
118 motionDir_ = normalised(motion().get<vector>("motionDir"));
119 }
120
121 // Check if contact angle is defined
122 makeContactAngle();
123
125 (
126 "nonReflectingFreeSurfacePatches",
127 nonReflectingFreeSurfacePatches_
128 );
129}
130
131
132void Foam::interfaceTrackingFvMesh::makeUs() const
133{
135 << "making free-surface velocity field" << nl;
136
137 if (UsPtr_)
138 {
140 << "free-surface velocity field already exists"
141 << abort(FatalError);
142 }
143
144 wordList patchFieldTypes
145 (
146 aMesh().boundary().size(),
148 );
149
150 forAll(aMesh().boundary(), patchI)
151 {
152 if
153 (
154 aMesh().boundary()[patchI].type()
155 == wedgeFaPatch::typeName
156 )
157 {
158 patchFieldTypes[patchI] =
159 wedgeFaPatchVectorField::typeName;
160 }
161 else
162 {
163 label ngbPolyPatchID =
164 aMesh().boundary()[patchI].ngbPolyPatchIndex();
165
166 if (ngbPolyPatchID != -1)
167 {
168 if
169 (
170 mesh().boundary()[ngbPolyPatchID].type()
171 == wallFvPatch::typeName
172 )
173 {
174 patchFieldTypes[patchI] =
175 slipFaPatchVectorField::typeName;
176 }
177 }
178 }
179 }
180
181 for (const word& patchName : fixedFreeSurfacePatches_)
182 {
183 const label fixedPatchID =
184 aMesh().boundary().findPatchID(patchName);
185
186 if (fixedPatchID == -1)
187 {
189 << "Wrong faPatch name '" << patchName
190 << "' in the fixedFreeSurfacePatches list"
191 << " defined in the dynamicMeshDict dictionary"
192 << abort(FatalError);
193 }
194
195 label ngbPolyPatchID =
196 aMesh().boundary()[fixedPatchID].ngbPolyPatchIndex();
197
198 if (ngbPolyPatchID != -1)
199 {
200 if
201 (
202 mesh().boundary()[ngbPolyPatchID].type()
203 == wallFvPatch::typeName
204 )
205 {
206 patchFieldTypes[fixedPatchID] =
207 fixedValueFaPatchVectorField::typeName;
208 }
209 }
210 }
211
212 UsPtr_ = std::make_unique<areaVectorField>
213 (
215 (
216 "Us",
217 aMesh().time().timeName(),
218 aMesh().thisDb(),
221 ),
222 aMesh(),
224 patchFieldTypes
225 );
226
227 for (const word& patchName : fixedFreeSurfacePatches_)
228 {
229 const label fixedPatchID = aMesh().boundary().findPatchID(patchName);
230
231 if (fixedPatchID == -1)
232 {
234 << "Wrong faPatch name '" << patchName
235 << "' in the fixedFreeSurfacePatches list"
236 << " defined in the dynamicMeshDict dictionary"
237 << abort(FatalError);
238 }
239
240 label ngbPolyPatchID =
241 aMesh().boundary()[fixedPatchID].ngbPolyPatchIndex();
242
243 if (ngbPolyPatchID != -1)
244 {
245 if
246 (
247 mesh().boundary()[ngbPolyPatchID].type()
248 == wallFvPatch::typeName
249 )
250 {
251 UsPtr_->boundaryFieldRef()[fixedPatchID] == Zero;
252 }
253 }
254 }
255}
256
257
258void Foam::interfaceTrackingFvMesh::makeFsNetPhi() const
259{
261 << "making free-surface net flux" << nl;
262
263 if (fsNetPhiPtr_)
264 {
266 << "free-surface net flux already exists"
267 << abort(FatalError);
268 }
269
270 fsNetPhiPtr_ = std::make_unique<areaScalarField>
271 (
273 (
274 "fsNetPhi",
275 aMesh().time().timeName(),
276 aMesh().thisDb(),
279 ),
280 aMesh(),
282 );
283}
284
285
286void Foam::interfaceTrackingFvMesh::makeControlPoints()
287{
289 << "making control points" << nl;
290
291 if (controlPointsPtr_)
292 {
294 << "control points already exists"
295 << abort(FatalError);
296 }
297
298 IOobject pointsIO
299 (
300 "controlPoints",
301 mesh().time().timeName(),
302 mesh(),
306 );
307
308 if (pointsIO.typeHeaderOk<vectorIOField>())
309 {
310 Info<< "Reading control points" << endl;
311 controlPointsPtr_ = std::make_unique<vectorIOField>(pointsIO);
312 }
313 else
314 {
315 pointsIO.readOpt(IOobject::NO_READ);
316
317 Info<< "Creating new control points" << endl;
318 controlPointsPtr_ = std::make_unique<vectorIOField>
319 (
320 pointsIO,
321 aMesh().areaCentres().internalField()
322 );
323
324 initializeControlPointsPosition();
325 }
326}
327
328
329void Foam::interfaceTrackingFvMesh::makeMotionPointsMask()
330{
332 << "making motion points mask" << nl;
333
334 if (motionPointsMaskPtr_)
335 {
337 << "motion points mask already exists"
338 << abort(FatalError);
339 }
340
341 motionPointsMaskPtr_ = std::make_unique<labelList>
342 (
343 mesh().boundaryMesh()[fsPatchIndex()].nPoints(),
344 1
345 );
346
347 // Mark free surface boundary points
348 // that belong to processor patches
349 forAll(aMesh().boundary(), patchI)
350 {
351 if
352 (
353 aMesh().boundary()[patchI].type()
354 == processorFaPatch::typeName
355 )
356 {
357 const labelList& patchPoints =
358 aMesh().boundary()[patchI].pointLabels();
359
360 forAll(patchPoints, pointI)
361 {
362 motionPointsMask()[patchPoints[pointI]] = -1;
363 }
364 }
365 }
366
367 // Mark fixed free surface boundary points
368 for (const word& patchName : fixedFreeSurfacePatches_)
369 {
370 const label fixedPatchID = aMesh().boundary().findPatchID(patchName);
371
372 if (fixedPatchID == -1)
373 {
375 << "Wrong faPatch name in the fixedFreeSurfacePatches list"
376 << " defined in the dynamicMeshDict dictionary"
377 << abort(FatalError);
378 }
379
380 const labelList& patchPoints =
381 aMesh().boundary()[fixedPatchID].pointLabels();
382
383 forAll(patchPoints, pointI)
384 {
385 motionPointsMask()[patchPoints[pointI]] = 0;
386 }
387 }
388}
389
390
391void Foam::interfaceTrackingFvMesh::makeDirections()
392{
394 << "make displacement directions for points and control points" << nl;
395
396 if (pointsDisplacementDirPtr_ || facesDisplacementDirPtr_)
397 {
399 << "points, control points displacement directions already exist"
400 << abort(FatalError);
401 }
402
403 pointsDisplacementDirPtr_ =
404 std::make_unique<vectorField>
405 (
406 mesh().boundaryMesh()[fsPatchIndex()].nPoints(),
407 Zero
408 );
409
410 facesDisplacementDirPtr_ =
411 std::make_unique<vectorField>
412 (
413 mesh().boundaryMesh()[fsPatchIndex()].size(),
414 Zero
415 );
416
417 if (!normalMotionDir())
418 {
419 if (mag(motionDir_) < SMALL)
420 {
422 << "Zero motion direction"
423 << abort(FatalError);
424 }
425
426 facesDisplacementDir() = motionDir_;
427 pointsDisplacementDir() = motionDir_;
428 }
429
430 updateDisplacementDirections();
431}
432
433
434void Foam::interfaceTrackingFvMesh::makePhis()
435{
437 << "making free-surface flux" << nl;
438
439 if (phisPtr_)
440 {
442 << "free-surface flux already exists"
443 << abort(FatalError);
444 }
445
446 phisPtr_ = std::make_unique<edgeScalarField>
447 (
449 (
450 "phis",
451 aMesh().time().timeName(),
452 aMesh().thisDb(),
455 ),
456 linearEdgeInterpolate(Us()) & aMesh().Le()
457 );
458}
459
460
461void Foam::interfaceTrackingFvMesh::makeSurfactConc() const
462{
464 << "making free-surface surfactant concentration field" << nl;
465
466 if (surfactConcPtr_)
467 {
469 << "free-surface surfactant concentration field already exists"
470 << abort(FatalError);
471 }
472
473 surfactConcPtr_ = std::make_unique<areaScalarField>
474 (
476 (
477 "Cs",
478 mesh().time().timeName
479 (
480 mesh().time().startTime().value()
481 ),
482 // mesh().time().timeName(),
483 aMesh().thisDb(),
486 ),
487 aMesh()
488 );
489}
490
491
492void Foam::interfaceTrackingFvMesh::makeBulkSurfactConc() const
493{
495 << "making volume surfactant concentration field" << nl;
496
497 if (bulkSurfactConcPtr_)
498 {
500 << "volume surfactant concentration field already exists"
501 << abort(FatalError);
502 }
503
504 bulkSurfactConcPtr_ = std::make_unique<volScalarField>
505 (
507 (
508 "C",
509 mesh().time().timeName
510 (
511 mesh().time().startTime().value()
512 ),
513 // mesh().time().timeName(),
514 mesh(),
517 ),
518 mesh()
519 );
520 auto& bulkSurfactConc = *bulkSurfactConcPtr_;
521
522 if (mesh().time().timeIndex()-1 == 0)
523 {
524 // Initialize uniform volume surfactant concentration
525 bulkSurfactConc = surfactant().bulkConc();
526 bulkSurfactConc.correctBoundaryConditions();
527 }
528}
529
530
531void Foam::interfaceTrackingFvMesh::makeSurfaceTension() const
532{
534 << "making surface tension field" << nl;
535
536 if (surfaceTensionPtr_)
537 {
539 << "surface tension field already exists"
540 << abort(FatalError);
541 }
542
543 surfaceTensionPtr_ = std::make_unique<areaScalarField>
544 (
546 (
547 "surfaceTension",
548 aMesh().time().timeName(),
549 aMesh().thisDb(),
552 ),
553 sigma() + surfactant().dSigma(surfactantConcentration())/rho_
554 );
555}
556
557
558void Foam::interfaceTrackingFvMesh::makeSurfactant() const
559{
561 << "making surfactant properties" << nl;
562
563 if (surfactantPtr_)
564 {
566 << "surfactant properties already exists"
567 << abort(FatalError);
568 }
569
570 const dictionary& surfactProp =
571 motion().subDict("surfactantProperties");
572
573 surfactantPtr_ = std::make_unique<surfactantProperties>(surfactProp);
574}
575
576
577void Foam::interfaceTrackingFvMesh::makeContactAngle()
578{
580 << "making contact angle field" << nl;
581
582 if (contactAnglePtr_)
583 {
585 << "contact angle already exists"
586 << abort(FatalError);
587 }
588
589 // Check if contactAngle is defined
590 IOobject contactAngleHeader
591 (
592 "contactAngle",
593 aMesh().time().timeName(),
594 aMesh().thisDb(),
597 );
598
599 if (contactAngleHeader.typeHeaderOk<areaScalarField>())
600 {
601 Info<< "Reading contact angle field" << endl;
602
603 contactAnglePtr_ =
604 std::make_unique<areaScalarField>(contactAngleHeader, aMesh());
605 }
606}
607
608
609void Foam::interfaceTrackingFvMesh::updateDisplacementDirections()
610{
611 if (normalMotionDir())
612 {
613 // Update point displacement direction
614 pointsDisplacementDir() = aMesh().pointAreaNormals();
615
616 // Correct point displacement direction at contact line
617 forAll(aMesh().boundary(), patchI)
618 {
619 if (contactAnglePtr_)
620 {
621 label ngbPolyPatchID =
622 aMesh().boundary()[patchI].ngbPolyPatchIndex();
623
624 if (ngbPolyPatchID != -1)
625 {
626 if
627 (
628 mesh().boundary()[ngbPolyPatchID].type()
629 == wallFvPatch::typeName
630 )
631 {
632 labelList patchPoints =
633 aMesh().boundary()[patchI].pointLabels();
634
636 (
637 aMesh().boundary()[patchI]
638 .ngbPolyPatchPointNormals()
639 );
640
641 forAll(patchPoints, pointI)
642 {
643 pointsDisplacementDir()[patchPoints[pointI]] -=
644 N[pointI]
645 *(
646 N[pointI]
647 & pointsDisplacementDir()[patchPoints[pointI]]
648 );
649
650 pointsDisplacementDir()[patchPoints[pointI]] /=
651 mag
652 (
653 pointsDisplacementDir()
654 [
655 patchPoints[pointI]
656 ]
657 ) + SMALL;
658 }
659 }
660 }
661 }
662 }
663
664 // Update face displacement direction
665 facesDisplacementDir() =
666 aMesh().faceAreaNormals().internalField();
667
668 // Correction of control points position
669 const vectorField& Cf = aMesh().areaCentres().internalField();
670
671 controlPoints() =
672 facesDisplacementDir()
673 *(facesDisplacementDir()&(controlPoints() - Cf))
674 + Cf;
675 }
676}
677
678
679void Foam::interfaceTrackingFvMesh::initializeControlPointsPosition()
680{
681 {
682 const faceList& faces = aMesh().faces();
683 const pointField& points = aMesh().points();
684
685 pointField displacement(pointDisplacement());
686 scalarField sweptVolCorr(faces.size(), Zero);
687 correctPointDisplacement(sweptVolCorr, displacement);
688
689 pointField newPoints(points + displacement);
690
691 scalarField sweptVol(faces.size(), Zero);
692
693 forAll(faces, faceI)
694 {
695 sweptVol[faceI] = -faces[faceI].sweptVol(points, newPoints);
696 }
697
698 vectorField faceArea(faces.size(), Zero);
699
700 forAll(faceArea, faceI)
701 {
702 faceArea[faceI] = faces[faceI].unitNormal(newPoints);
703 }
704
705 scalarField deltaH = scalarField(aMesh().nFaces(), Zero);
706
707 forAll(deltaH, faceI)
708 {
709 deltaH[faceI] = sweptVol[faceI]/
710 ((faceArea[faceI] & facesDisplacementDir()[faceI]) + SMALL);
711
712 if (mag(faceArea[faceI] & facesDisplacementDir()[faceI]) < SMALL)
713 {
714 // Info<< (faceArea[faceI] & facesDisplacementDir()[faceI])
715 // << ", " << faceArea[faceI]
716 // << ", " << facesDisplacementDir()[faceI] << endl;
717
719 << "Something is wrong with specified motion direction"
720 << abort(FatalError);
721 }
722 }
723
724 for (const word& patchName : fixedFreeSurfacePatches_)
725 {
726 label fixedPatchID = aMesh().boundary().findPatchID(patchName);
727
728 if (fixedPatchID == -1)
729 {
731 << "Wrong faPatch name in the fixedFreeSurfacePatches list"
732 << " defined in the freeSurfaceProperties dictionary"
733 << abort(FatalError);
734 }
735
736 for
737 (
738 const label facei
739 : aMesh().boundary()[fixedPatchID].edgeFaces()
740 )
741 {
742 deltaH[facei] *= 2.0;
743 }
744 }
745
746 controlPoints() += facesDisplacementDir()*deltaH;
747 }
748}
749
750
751void Foam::interfaceTrackingFvMesh::smoothFreeSurfaceMesh()
752{
753 Info<< "Smoothing free surface mesh" << endl;
754
755 controlPoints() = aMesh().areaCentres().internalField();
756
757 pointField displacement(pointDisplacement());
758
759 const faceList& faces = aMesh().faces();
760 const pointField& points = aMesh().points();
761
762 pointField newPoints(points + displacement);
763
764 scalarField sweptVol(faces.size(), Zero);
765 forAll(faces, faceI)
766 {
767 sweptVol[faceI] = -faces[faceI].sweptVol(points, newPoints);
768 }
769
770 vectorField faceArea(faces.size(), Zero);
771 forAll(faceArea, faceI)
772 {
773 faceArea[faceI] = faces[faceI].unitNormal(newPoints);
774 }
775
776 scalarField deltaHf
777 (
778 sweptVol/(faceArea & facesDisplacementDir())
779 );
780
781 for (const word& patchName : fixedFreeSurfacePatches_)
782 {
783 label fixedPatchID = aMesh().boundary().findPatchID(patchName);
784
785 if (fixedPatchID == -1)
786 {
788 << "Wrong faPatch name fixedFreeSurfacePatches list"
789 << " defined in the dynamicMeshDict dictionary"
790 << abort(FatalError);
791 }
792
793 for
794 (
795 const label facei
796 : aMesh().boundary()[fixedPatchID].edgeFaces()
797 )
798 {
799 deltaHf[facei] *= 2.0;
800 }
801 }
802
803 controlPoints() += facesDisplacementDir()*deltaHf;
804
805 displacement = pointDisplacement();
806
807 velocityMotionSolver& vMotion =
809 (
810 const_cast<motionSolver&>(motion())
811 );
812
813 pointVectorField& pointMotionU = vMotion.pointMotionU();
814 pointMotionU.primitiveFieldRef() = Zero;
815
816 fixedValuePointPatchVectorField& fsPatchPointMeshU =
818 (
819 const_cast<pointPatchVectorField&>
820 (
821 pointMotionU.boundaryField()[fsPatchIndex()]
822 )
823 );
824
825 fsPatchPointMeshU == displacement/mesh().time().deltaTValue();
826
828}
829
830
831void Foam::interfaceTrackingFvMesh::updateSurfaceFlux()
832{
833 Phis() = fac::interpolate(Us()) & aMesh().Le();
834}
835
836
837void Foam::interfaceTrackingFvMesh::updateSurfactantConcentration()
838{
839 if (!pureFreeSurface())
840 {
841 Info<< "Correct surfactant concentration" << endl << flush;
842
843 updateSurfaceFlux();
844
845 // Crate and solve the surfactanta transport equation
846 faScalarMatrix CsEqn
847 (
848 fam::ddt(surfactantConcentration())
849 + fam::div(Phis(), surfactantConcentration())
851 (
852 surfactant().diffusion(),
853 surfactantConcentration()
854 )
855 );
856
857 if (surfactant().soluble())
858 {
859 #include "solveBulkSurfactant.H"
860
862 (
864 (
865 "Cb",
866 aMesh().time().timeName(),
867 aMesh().thisDb(),
870 ),
871 aMesh(),
874 );
875
876 Cb.ref().field() =
877 bulkSurfactantConcentration().boundaryField()[fsPatchIndex()];
878 Cb.correctBoundaryConditions();
879
880 CsEqn +=
881 fam::Sp
882 (
883 surfactant().adsorptionCoeff()*Cb
884 + surfactant().adsorptionCoeff()
885 *surfactant().desorptionCoeff(),
886 surfactantConcentration()
887 )
888 - surfactant().adsorptionCoeff()
889 *Cb*surfactant().saturatedConc();
890 }
891
892 CsEqn.solve();
893
894 // Info<< "Correct surface tension" << endl;
895
896 surfaceTension() =
897 sigma() + surfactant().dSigma(surfactantConcentration())/rho_;
898
899 if (neg(min(surfaceTension().internalField().field())))
900 {
902 << "Surface tension is negative"
903 << abort(FatalError);
904 }
905 }
906}
907
908
909Foam::vector Foam::interfaceTrackingFvMesh::totalPressureForce() const
910{
911 const scalarField& S = aMesh().S();
912
913 const vectorField& n = aMesh().faceAreaNormals().internalField();
914
915 const scalarField& P = p().boundaryField()[fsPatchIndex()];
916
917 vectorField pressureForces(S*P*n);
918
919 return gSum(pressureForces);
920}
921
922
923Foam::vector Foam::interfaceTrackingFvMesh::totalViscousForce() const
924{
925 const auto& turbulence =
926 mesh().lookupObject<turbulenceModel>("turbulenceProperties");
927
928 scalarField nu(turbulence.nuEff(fsPatchIndex()));
929
930 // const singlePhaseTransportModel& properties =
931 // mesh().lookupObject<singlePhaseTransportModel>
932 // (
933 // "transportProperties"
934 // );
935
936 // dimensionedScalar nu("nu", properties);
937
938 const scalarField& S = aMesh().S();
939 const vectorField& n = aMesh().faceAreaNormals().internalField();
940
941 vectorField nGradU
942 (
943 U().boundaryField()[fsPatchIndex()].snGrad()
944 );
945
946 vectorField viscousForces
947 (
948 - nu*S
949 *(
950 nGradU
951 + (fac::grad(Us())().internalField()&n)
952 - (n*fac::div(Us())().internalField())
953 )
954 );
955
956 return gSum(viscousForces);
957}
958
959
960Foam::vector Foam::interfaceTrackingFvMesh::totalSurfaceTensionForce() const
961{
962 const scalarField& S = aMesh().S();
963
964 const vectorField& n = aMesh().faceAreaNormals().internalField();
965
966 const scalarField& K = aMesh().faceCurvatures().internalField();
967
968 vectorField surfTensionForces(n.size(), Zero);
969
970 if (pureFreeSurface())
971 {
972 surfTensionForces =
973 S*sigma().value()
975 (
976 aMesh().Le()*aMesh().edgeLengthCorrection()
977 )().internalField();
978 }
979 else
980 {
981 surfTensionForces = surfaceTension().internalField().field()*K*S*n;
982 }
983
984 return gSum(surfTensionForces);
985}
986
987
988Foam::scalar Foam::interfaceTrackingFvMesh::maxCourantNumber()
989{
990 scalar CoNum = 0;
991
992 if (pureFreeSurface())
993 {
994 const scalarField& dE = aMesh().lPN();
995
996 CoNum = gMax
997 (
998 mesh().time().deltaTValue()/
999 sqrt
1000 (
1001 Foam::pow(dE, 3.0)/2.0/M_PI/(sigma().value() + SMALL)
1002 )
1003 );
1004 }
1005 else
1006 {
1007 scalarField sigmaE
1008 (
1009 linearEdgeInterpolate(surfaceTension())().internalField().field()
1010 + SMALL
1011 );
1012
1013 const scalarField& dE = aMesh().lPN();
1014
1015 CoNum = gMax
1016 (
1017 mesh().time().deltaTValue()/
1018 sqrt
1019 (
1020 Foam::pow(dE, 3.0)/2.0/M_PI/sigmaE
1021 )
1022 );
1023 }
1024
1025 return CoNum;
1026}
1027
1028
1029void Foam::interfaceTrackingFvMesh::updateProperties()
1030{
1031 const singlePhaseTransportModel& properties =
1033 (
1034 "transportProperties"
1035 );
1036
1037 rho_ = dimensionedScalar("rho", properties);
1038
1039 sigma0_ = dimensionedScalar("sigma", properties)/rho_;
1040}
1041
1042
1043void Foam::interfaceTrackingFvMesh::correctPointDisplacement
1044(
1045 const scalarField& sweptVolCorr,
1046 vectorField& displacement
1047)
1048{
1049 const labelListList& pFaces =
1050 aMesh().patch().pointFaces();
1051
1052 const faceList& faces =
1053 aMesh().patch().localFaces();
1054
1055 const pointField& points =
1056 aMesh().patch().localPoints();
1057
1058 for (const word& patchName : fixedFreeSurfacePatches_)
1059 {
1060 label fixedPatchID = aMesh().boundary().findPatchID(patchName);
1061
1062 const labelList& pLabels =
1063 aMesh().boundary()[fixedPatchID].pointLabels();
1064
1065 const labelUList& eFaces =
1066 aMesh().boundary()[fixedPatchID].edgeFaces();
1067
1069
1070 forAll(eFaces, edgeI)
1071 {
1072 label curFace = eFaces[edgeI];
1073
1074 const labelList& curPoints = faces[curFace];
1075
1076 forAll(curPoints, pointI)
1077 {
1078 label curPoint = curPoints[pointI];
1079 label index = pLabels.find(curPoint);
1080
1081 if (index == -1)
1082 {
1083 pointSet.insert(curPoint);
1084 }
1085 }
1086 }
1087
1088 labelList corrPoints = pointSet.toc();
1089
1090 labelListList corrPointFaces(corrPoints.size());
1091
1092 forAll(corrPoints, pointI)
1093 {
1094 label curPoint = corrPoints[pointI];
1095
1097
1098 forAll(pFaces[curPoint], faceI)
1099 {
1100 label curFace = pFaces[curPoint][faceI];
1101
1102 label index = eFaces.find(curFace);
1103
1104 if (index != -1)
1105 {
1106 faceSet.insert(curFace);
1107 }
1108 }
1109
1110 corrPointFaces[pointI] = faceSet.toc();
1111 }
1112
1113 forAll(corrPoints, pointI)
1114 {
1115 label curPoint = corrPoints[pointI];
1116
1117 scalar curDisp = 0;
1118
1119 const labelList& curPointFaces = corrPointFaces[pointI];
1120
1121 forAll(curPointFaces, faceI)
1122 {
1123 const face& curFace = faces[curPointFaces[faceI]];
1124
1125 label ptInFace = curFace.which(curPoint);
1126 label next = curFace.nextLabel(ptInFace);
1127 label prev = curFace.prevLabel(ptInFace);
1128
1129 vector a = points[next] - points[curPoint];
1130 vector b = points[prev] - points[curPoint];
1131 const vector& c = pointsDisplacementDir()[curPoint];
1132
1133 curDisp += 2*sweptVolCorr[curPointFaces[faceI]]/((a^b)&c);
1134 }
1135
1136 curDisp /= curPointFaces.size();
1137
1138 displacement[curPoint] =
1139 curDisp*pointsDisplacementDir()[curPoint];
1140 }
1141 }
1142
1143
1144 for (const word& patchName : nonReflectingFreeSurfacePatches_)
1145 {
1146 label nonReflectingPatchID =
1147 aMesh().boundary().findPatchID(patchName);
1148
1149 const labelList& pLabels =
1150 aMesh().boundary()[nonReflectingPatchID].pointLabels();
1151
1152 const labelUList& eFaces =
1153 aMesh().boundary()[nonReflectingPatchID].edgeFaces();
1154
1155 labelList corrPoints = pLabels;
1156
1157 labelListList corrPointFaces(corrPoints.size());
1158
1159 forAll(corrPoints, pointI)
1160 {
1161 label curPoint = corrPoints[pointI];
1162
1164
1165 forAll(pFaces[curPoint], faceI)
1166 {
1167 label curFace = pFaces[curPoint][faceI];
1168
1169 label index = eFaces.find(curFace);
1170
1171 if (index != -1)
1172 {
1173 faceSet.insert(curFace);
1174 }
1175 }
1176
1177 corrPointFaces[pointI] = faceSet.toc();
1178 }
1179
1180
1181 forAll(corrPoints, pointI)
1182 {
1183 label curPoint = corrPoints[pointI];
1184
1185 scalar curDisp = 0;
1186
1187 const labelList& curPointFaces = corrPointFaces[pointI];
1188
1189 forAll(curPointFaces, faceI)
1190 {
1191 const face& curFace = faces[curPointFaces[faceI]];
1192
1193 label ptInFace = curFace.which(curPoint);
1194 label next = curFace.nextLabel(ptInFace);
1195 label prev = curFace.prevLabel(ptInFace);
1196
1197 label p0 = -1;
1198 label p1 = -1;
1199 label p2 = -1;
1200
1201 if (corrPoints.find(next) == -1)
1202 {
1203 p0 = curPoint;
1204 p1 = next;
1205 p2 = curFace.nextLabel(curFace.which(next));
1206 }
1207 else
1208 {
1209 p0 = curFace.prevLabel(curFace.which(prev));
1210 p1 = prev;
1211 p2 = curPoint;
1212 }
1213
1214 vector a0 = points[p1] - points[p0];
1215 vector b0 = points[p2] - points[p1];
1216 vector c0 = displacement[p1];
1217
1218 scalar V0 = mag((a0^b0)&c0)/2;
1219
1220 scalar DV = sweptVolCorr[curPointFaces[faceI]] - V0;
1221
1222 if (corrPoints.find(prev) != -1)
1223 {
1224 vector a = points[curPoint] - points[prev];
1225 vector b =
1226 (points[next] + displacement[next])
1227 - points[curPoint];
1228 const vector& c = pointsDisplacementDir()[curPoint];
1229
1230 curDisp += 2*DV/((a^b)&c);
1231 }
1232 else
1233 {
1234 vector a = points[curPoint]
1235 - (points[prev] + displacement[prev]);
1236 vector b = points[next] - points[curPoint];
1237 const vector& c = pointsDisplacementDir()[curPoint];
1238
1239 curDisp += 2*DV/((a^b)&c);
1240 }
1241 }
1242
1243 curDisp /= curPointFaces.size();
1244
1245 displacement[curPoint] =
1246 curDisp*pointsDisplacementDir()[curPoint];
1247 }
1248 }
1249}
1250
1251
1252void Foam::interfaceTrackingFvMesh::correctContactLinePointNormals()
1253{
1254 // Correct normals for contact line points
1255 // according to specified contact angle
1256
1257 vectorField& N =
1258 const_cast<vectorField&>
1259 (
1260 aMesh().pointAreaNormals()
1261 );
1262
1263 if (contactAnglePtr_ && correctContactLineNormals())
1264 {
1265 Info<< "Correcting contact line normals" << endl;
1266
1267 vectorField oldPoints(aMesh().nPoints(), Zero);
1268
1269 const labelList& meshPoints = aMesh().patch().meshPoints();
1270
1271 forAll(oldPoints, ptI)
1272 {
1273 oldPoints[ptI] =
1274 mesh().oldPoints()[meshPoints[ptI]];
1275 }
1276
1277// # include "createTangentField.H"
1278 areaVectorField tangent
1279 (
1280 aMesh().thisDb().newIOobject("tangent"),
1281 aMesh(),
1283 );
1284
1285 if (Pstream::parRun())
1286 {
1287 const labelListList& edgeFaces = aMesh().patch().edgeFaces();
1288 const labelListList& pointEdges = aMesh().patch().pointEdges();
1289 const labelListList& pointFaces = aMesh().patch().pointFaces();
1290 const edgeList& edges = aMesh().edges();
1291
1292 forAll(aMesh().boundary(), patchI)
1293 {
1294 if
1295 (
1296 aMesh().boundary()[patchI].type()
1297 == processorFaPatch::typeName
1298 )
1299 {
1300 const processorFaPatch& procPatch =
1302 (
1303 aMesh().boundary()[patchI]
1304 );
1305
1306 const labelList& patchPointLabels =
1307 procPatch.pointLabels();
1308
1309 forAll(patchPointLabels, pointI)
1310 {
1311 label curPoint = patchPointLabels[pointI];
1312
1313 // Check if processor point is boundary point
1314
1315 label patchID = -1;
1316 label edgeID = -1;
1317
1318 const labelList& curPointEdges = pointEdges[curPoint];
1319
1320 forAll(curPointEdges, edgeI)
1321 {
1322 label curEdge = curPointEdges[edgeI];
1323
1324 if (edgeFaces[curEdge].size() == 1)
1325 {
1326 forAll(aMesh().boundary(), pI)
1327 {
1328 const labelList& curEdges =
1329 aMesh().boundary()[pI];
1330
1331 label index = curEdges.find(curEdge);
1332
1333 if (index != -1)
1334 {
1335 if
1336 (
1337 aMesh().boundary()[pI].type()
1338 != processorFaPatch::typeName
1339 )
1340 {
1341 patchID = pI;
1342 edgeID = index;
1343 break;
1344 }
1345 }
1346 }
1347 }
1348 }
1349
1350 if (patchID != -1)
1351 {
1352 label curEdge =
1353 aMesh().boundary()[patchID].start() + edgeID;
1354
1355 vector t = edges[curEdge].vec(oldPoints);
1356 t /= mag(t) + SMALL;
1357
1358 const labelList& curPointFaces =
1359 pointFaces[curPoint];
1360
1361 forAll(curPointFaces, fI)
1362 {
1363 tangent.ref().field()[curPointFaces[fI]] = t;
1364 }
1365 }
1366 }
1367 }
1368 }
1369
1370 tangent.correctBoundaryConditions();
1371 }
1372
1373 forAll(aMesh().boundary(), patchI)
1374 {
1375 label ngbPolyPatchID =
1376 aMesh().boundary()[patchI].ngbPolyPatchIndex();
1377
1378 if (ngbPolyPatchID != -1)
1379 {
1380 if
1381 (
1382 mesh().boundary()[ngbPolyPatchID].type()
1383 == wallFvPatch::typeName
1384 )
1385 {
1386 const scalar rotAngle = degToRad
1387 (
1388 gAverage
1389 (
1390 90
1391 - contactAnglePtr_->boundaryField()[patchI]
1392 )
1393 );
1394
1395 vectorField ngbN
1396 (
1397 aMesh().boundary()[patchI].ngbPolyPatchPointNormals()
1398 );
1399
1400 const labelList& patchPoints =
1401 aMesh().boundary()[patchI].pointLabels();
1402
1403 vectorField pN(N, patchPoints);
1404
1405 vectorField rotationAxis(ngbN^pN);
1406 rotationAxis /= mag(rotationAxis) + SMALL;
1407
1408
1409 // Calc rotation axis using edge vectors
1410
1411 const edgeList& edges = aMesh().edges();
1412
1413 const labelListList& pointEdges =
1414 aMesh().boundary()[patchI].pointEdges();
1415
1416 forAll(pointEdges, pointI)
1417 {
1418 vector rotAx = Zero;
1419
1420 forAll(pointEdges[pointI], eI)
1421 {
1422 label curEdge =
1423 aMesh().boundary()[patchI].start()
1424 + pointEdges[pointI][eI];
1425
1426 vector e = edges[curEdge].vec(oldPoints);
1427
1428 e *= (e&rotationAxis[pointI])
1429 /mag(e&rotationAxis[pointI]);
1430
1431 e /= mag(e) + SMALL;
1432
1433 rotAx += e;
1434 }
1435
1436 if (pointEdges[pointI].size() == 1)
1437 {
1438 label curPoint = patchPoints[pointI];
1439
1440 const labelListList& ptEdges =
1441 aMesh().patch().pointEdges();
1442 const labelList& curPointEdges =
1443 ptEdges[curPoint];
1444
1445 label procPatchID = -1;
1446 label edgeID = -1;
1447
1448 const labelListList& edgeFaces =
1449 aMesh().patch().edgeFaces();
1450
1451 forAll(curPointEdges, edgeI)
1452 {
1453 label curEdge = curPointEdges[edgeI];
1454
1455 if (edgeFaces[curEdge].size() == 1)
1456 {
1457 forAll(aMesh().boundary(), pI)
1458 {
1459 const labelList& curEdges =
1460 aMesh().boundary()[pI];
1461
1462 label index =
1463 curEdges.find(curEdge);
1464
1465 if (index != -1)
1466 {
1467 if
1468 (
1469 aMesh().boundary()[pI].type()
1470 == processorFaPatch::typeName
1471 )
1472 {
1473 procPatchID = pI;
1474 edgeID = index;
1475 break;
1476 }
1477 }
1478 }
1479 }
1480 }
1481
1482 if (procPatchID != -1)
1483 {
1484 vector t =
1485 tangent.boundaryField()[procPatchID]
1486 .patchNeighbourField()()[edgeID];
1487
1488 t *= (t&rotationAxis[pointI])
1489 /(mag(t&rotationAxis[pointI]) + SMALL);
1490
1491 t /= mag(t) + SMALL;
1492
1493 rotAx += t;
1494 }
1495 }
1496
1497 rotationAxis[pointI] = rotAx/(mag(rotAx) + SMALL);
1498 }
1499
1500 // Rodrigues' rotation formula
1501 ngbN = ngbN*cos(rotAngle)
1502 + rotationAxis*(rotationAxis & ngbN)*(1 - cos(rotAngle))
1503 + (rotationAxis^ngbN)*sin(rotAngle);
1504
1505 // Info<< aMesh().boundary()[patchI].name() << endl;
1506 forAll(patchPoints, pointI)
1507 {
1508 N[patchPoints[pointI]] -=
1509 ngbN[pointI]*(ngbN[pointI]&N[patchPoints[pointI]]);
1510
1511 N[patchPoints[pointI]] /=
1512 mag(N[patchPoints[pointI]]) + SMALL;
1513
1514 // Info<< N[patchPoints[pointI]] << endl;
1515 }
1516 }
1517 }
1519 }
1520}
1521
1522
1523// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1524
1525Foam::interfaceTrackingFvMesh::interfaceTrackingFvMesh
1526(
1527 const IOobject& io,
1528 const bool doInit
1529)
1530:
1532 fsPatchIndex_(-1),
1533 fixedFreeSurfacePatches_(),
1534 nonReflectingFreeSurfacePatches_(),
1535 pointNormalsCorrectionPatches_(),
1536 normalMotionDir_(false),
1537 motionDir_(Zero),
1538 smoothing_(false),
1539 pureFreeSurface_(true),
1540 rigidFreeSurface_(false),
1541 correctContactLineNormals_(false),
1542 sigma0_("zero", dimForce/dimLength/dimDensity, Zero),
1543 rho_("one", dimDensity, 1.0),
1544 timeIndex_(-1)
1545{
1546 if (doInit)
1547 {
1548 init(false); // do not initialise lower levels
1549 }
1550}
1551
1552/*
1553Foam::interfaceTrackingFvMesh::interfaceTrackingFvMesh
1554(
1555 const IOobject& io,
1556 pointField&& points,
1557 faceList&& faces,
1558 labelList&& allOwner,
1559 labelList&& allNeighbour,
1560 const bool syncPar
1561)
1562:
1563 dynamicMotionSolverFvMesh
1564 (
1565 io,
1566 std::move(points),
1567 std::move(faces),
1568 std::move(allOwner),
1569 std::move(allNeighbour),
1570 syncPar
1571 ),
1572 aMeshPtr_(new faMesh(*this)),
1573 fsPatchIndex_(-1),
1574 fixedFreeSurfacePatches_(),
1575 nonReflectingFreeSurfacePatches_(),
1576 pointNormalsCorrectionPatches_(),
1577 normalMotionDir_(false),
1578 motionDir_(Zero),
1579 smoothing_(false),
1580 pureFreeSurface_(true),
1581 sigma0_("zero", dimForce/dimLength/dimDensity, Zero),
1582 rho_("one", dimDensity, 1.0),
1583 timeIndex_(-1)
1584{}
1585*/
1586
1587// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1590{}
1591
1592
1593// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1594
1595bool Foam::interfaceTrackingFvMesh::init(const bool doInit)
1596{
1597 if (doInit)
1598 {
1600 }
1601
1602 aMeshPtr_.reset(new faMesh(*this));
1603
1604 // Set motion-based data
1605 fixedFreeSurfacePatches_ =
1606 motion().get<wordList>("fixedFreeSurfacePatches");
1607
1608 pointNormalsCorrectionPatches_ =
1609 motion().get<wordList>("pointNormalsCorrectionPatches");
1610
1611 normalMotionDir_ = motion().get<bool>("normalMotionDir");
1612 smoothing_ = motion().getOrDefault("smoothing", false);
1613 pureFreeSurface_ = motion().getOrDefault("pureFreeSurface", true);
1615 initializeData();
1616
1617 return true;
1618}
1619
1620
1622{
1623 if (!UsPtr_)
1624 {
1625 makeUs();
1626 }
1627
1628 return *UsPtr_;
1629}
1630
1631
1633{
1634 if (!UsPtr_)
1635 {
1636 makeUs();
1637 }
1638
1639 return *UsPtr_;
1640}
1641
1642
1644{
1645 if (!fsNetPhiPtr_)
1646 {
1647 makeFsNetPhi();
1648 }
1649
1650 return *fsNetPhiPtr_;
1651}
1652
1653
1655{
1656 if (!fsNetPhiPtr_)
1657 {
1658 makeFsNetPhi();
1659 }
1660
1661 return *fsNetPhiPtr_;
1662}
1663
1664
1666{
1667 forAll(Us().boundaryField(), patchI)
1668 {
1669 if
1670 (
1671 Us().boundaryField()[patchI].type()
1672 == calculatedFaPatchVectorField::typeName
1673 )
1674 {
1675 vectorField& pUs = Us().boundaryFieldRef()[patchI];
1676
1677 pUs = Us().boundaryField()[patchI].patchInternalField();
1678
1679 label ngbPolyPatchID =
1680 aMesh().boundary()[patchI].ngbPolyPatchIndex();
1681
1682 if (ngbPolyPatchID != -1)
1683 {
1684 if
1685 (
1686 (
1687 U().boundaryField()[ngbPolyPatchID].type()
1688 == slipFvPatchVectorField::typeName
1689 )
1690 ||
1691 (
1692 U().boundaryField()[ngbPolyPatchID].type()
1693 == symmetryFvPatchVectorField::typeName
1694 )
1695 )
1696 {
1698 (
1699 aMesh().boundary()[patchI].ngbPolyPatchFaceNormals()
1700 );
1701
1702 pUs -= N*(N&pUs);
1703 }
1704 }
1706 }
1707
1709}
1710
1711
1713{
1714 // Info<< "Update Us" << endl;
1715
1716 Us().ref().field() = U().boundaryField()[fsPatchIndex()];
1717
1718 // // Correct normal component of free-surface velocity
1719 // const vectorField& nA = aMesh().faceAreaNormals().internalField();
1720 // vectorField UnFs = nA*phi().boundaryField()[fsPatchIndex()]
1721 // /mesh().boundary()[fsPatchIndex()].magSf();
1722 // Us().ref().field() += UnFs - nA*(nA&Us().internalField());
1723
1725}
1726
1731}
1732
1737}
1738
1739
1741{
1743}
1744
1745
1748{
1749 auto tSnGradU = tmp<vectorField>::New(aMesh().nFaces(), Zero);
1750 auto& SnGradU = tSnGradU.ref();
1751
1752 const vectorField& nA = aMesh().faceAreaNormals().internalField();
1753
1754 areaScalarField divUs
1755 (
1756 fac::div(Us())
1757 - aMesh().faceCurvatures()*(aMesh().faceAreaNormals()&Us())
1758 );
1759
1760 areaTensorField gradUs(fac::grad(Us()));
1761
1762 // Remove component of gradient normal to surface (area)
1763 const areaVectorField& n = aMesh().faceAreaNormals();
1764 gradUs -= n*(n & gradUs);
1765 gradUs.correctBoundaryConditions();
1766
1768 mesh().lookupObject<turbulenceModel>("turbulenceProperties");
1769
1770 scalarField nu(turbulence.nuEff(fsPatchIndex()));
1771
1772 vectorField tangentialSurfaceTensionForce(nA.size(), Zero);
1773
1774 if (!pureFreeSurface() && max(nu) > SMALL)
1775 {
1776 tangentialSurfaceTensionForce =
1777 surfaceTensionGrad()().internalField();
1778 }
1779
1780 SnGradU =
1781 tangentialSurfaceTensionForce/(nu + SMALL)
1782 - nA*divUs.internalField()
1783 - (gradUs.internalField()&nA);
1784
1785 return tSnGradU;
1786}
1787
1788
1791{
1792 auto tSnGradUn = tmp<scalarField>::New(aMesh().nFaces(), Zero);
1793 auto& SnGradUn = tSnGradUn.ref();
1794
1795 areaScalarField divUs
1796 (
1797 fac::div(Us())
1798 - aMesh().faceCurvatures()*(aMesh().faceAreaNormals()&Us())
1799 );
1800
1801 SnGradUn = -divUs.internalField();
1802
1803 return tSnGradUn;
1804}
1805
1806
1809{
1810 auto tPressureJump = tmp<scalarField>::New(aMesh().nFaces(), Zero);
1811 auto& pressureJump = tPressureJump.ref();
1812
1813 const scalarField& K = aMesh().faceCurvatures().internalField();
1814
1817
1819 mesh().lookupObject<turbulenceModel>("turbulenceProperties");
1820
1821 scalarField nu(turbulence.nuEff(fsPatchIndex()));
1822
1823 pressureJump =
1824 - (g.value() & mesh().Cf().boundaryField()[fsPatchIndex()])
1825 + 2.0*nu*freeSurfaceSnGradUn();
1826
1827 if (pureFreeSurface())
1828 {
1829 pressureJump -= sigma().value()*K;
1830 }
1831 else
1832 {
1833 pressureJump -= surfaceTension().internalField()*K;
1834 }
1835
1836 return tPressureJump;
1837}
1838
1839
1841{
1842 if (!controlPointsPtr_)
1843 {
1844 makeControlPoints();
1845 }
1846
1847 return *controlPointsPtr_;
1848}
1849
1850
1852{
1853 if (!motionPointsMaskPtr_)
1854 {
1855 makeMotionPointsMask();
1856 }
1857
1858 return *motionPointsMaskPtr_;
1859}
1860
1861
1863{
1864 if (!pointsDisplacementDirPtr_)
1865 {
1866 makeDirections();
1867 }
1868
1869 return *pointsDisplacementDirPtr_;
1870}
1871
1872
1874{
1875 if (!facesDisplacementDirPtr_)
1876 {
1877 makeDirections();
1878 }
1879
1880 return *facesDisplacementDirPtr_;
1881}
1882
1883
1885{
1886 if (!phisPtr_)
1887 {
1888 makePhis();
1889 }
1890
1891 return *phisPtr_;
1892}
1893
1896{
1897 if (!surfactConcPtr_)
1898 {
1899 makeSurfactConc();
1901
1902 return *surfactConcPtr_;
1903}
1904
1905
1908{
1909 if (!surfactConcPtr_)
1910 {
1911 makeSurfactConc();
1913
1914 return *surfactConcPtr_;
1915}
1916
1917
1920{
1921 if (!bulkSurfactConcPtr_)
1922 {
1923 makeBulkSurfactConc();
1925
1926 return *bulkSurfactConcPtr_;
1927}
1928
1929
1932{
1933 if (!bulkSurfactConcPtr_)
1934 {
1935 makeBulkSurfactConc();
1937
1938 return *bulkSurfactConcPtr_;
1939}
1940
1941
1944{
1945 if (!surfaceTensionPtr_)
1946 {
1947 makeSurfaceTension();
1949
1950 return *surfaceTensionPtr_;
1951}
1952
1953
1956{
1957 if (!surfaceTensionPtr_)
1958 {
1959 makeSurfaceTension();
1961
1962 return *surfaceTensionPtr_;
1963}
1964
1965
1968{
1969 if (!surfactantPtr_)
1970 {
1971 makeSurfactant();
1973
1974 return *surfactantPtr_;
1975}
1976
1977
1980{
1981 auto tgrad = tmp<areaVectorField>::New
1982 (
1983 IOobject
1984 (
1985 "surfaceTensionGrad",
1986 aMesh().time().timeName(),
1987 aMesh().thisDb(),
1990 ),
1991 fac::grad(surfaceTension())
1992 // (-fac::grad(surfactantConcentration()/rho_)*
1993 // surfactant().surfactR()*surfactant().surfactT()/
1994 // (1.0 - surfactantConcentration()/
1995 // surfactant().surfactSaturatedConc()))()
1996 );
1997 auto& grad = tgrad.ref();
1998
1999 // Remove component of gradient normal to surface (area)
2000 const areaVectorField& n = aMesh().faceAreaNormals();
2001 grad -= n*(n & grad);
2002 grad.correctBoundaryConditions();
2003
2004 return tgrad;
2005}
2006
2007
2009{
2010 if (timeIndex_ != mesh().time().timeIndex())
2011 {
2012 if (smoothing_ && !rigidFreeSurface_)
2013 {
2014 smoothFreeSurfaceMesh();
2015 clearControlPoints();
2016 }
2017
2018 updateDisplacementDirections();
2019
2020 updateProperties();
2021
2022 Info<< "Maximal capillary Courant number: "
2023 << maxCourantNumber() << endl;
2024
2025 const scalarField& K = aMesh().faceCurvatures().internalField();
2026
2027 auto limits = gMinMax(K);
2028
2029 Info<< "Free surface curvature: min = " << limits.min()
2030 << ", max = " << limits.max()
2031 << ", average = " << gAverage(K) << nl;
2032
2033 timeIndex_ = mesh().time().timeIndex();
2034 }
2035
2036 if (!rigidFreeSurface_)
2037 {
2038 // This is currently relaltive flux
2039 scalarField sweptVolCorr =
2040 phi().boundaryField()[fsPatchIndex()];
2041
2042 // Info<< "Free surface flux: sum local = "
2043 // << gSum(mag(sweptVolCorr))
2044 // << ", global = " << gSum(sweptVolCorr) << endl;
2045
2046 // if (mesh().moving())
2047 // {
2048 // sweptVolCorr -=
2049 // fvc::meshPhi(U())().boundaryField()[fsPatchIndex()];
2050 // }
2051
2052 Info<< "Free surface continuity error : sum local = "
2053 << gSum(mag(sweptVolCorr)) << ", global = " << gSum(sweptVolCorr)
2054 << endl;
2055
2056 // For postprocessing
2057 fsNetPhi().ref().field() = sweptVolCorr;
2058
2059 word ddtScheme
2060 (
2061 mesh().ddtScheme
2062 (
2063 "ddt(" + U().name() + ')'
2064 )
2065 );
2066
2067 if
2068 (
2069 ddtScheme
2070 == fv::CrankNicolsonDdtScheme<vector>::typeName
2071 )
2072 {
2073 sweptVolCorr *= (1.0/2.0)*mesh().time().deltaTValue();
2074 }
2075 else if
2076 (
2077 ddtScheme
2079 )
2080 {
2081 sweptVolCorr *= mesh().time().deltaTValue();
2082 }
2083 else if
2084 (
2085 ddtScheme
2087 )
2088 {
2089 if (mesh().time().timeIndex() == 1)
2090 {
2091 sweptVolCorr *= mesh().time().deltaTValue();
2092 }
2093 else
2094 {
2095 sweptVolCorr *= (2.0/3.0)*mesh().time().deltaTValue();
2096 }
2097 }
2098 else
2099 {
2101 << "Unsupported temporal differencing scheme : "
2102 << ddtScheme << nl
2103 << abort(FatalError);
2104 }
2105
2106 const scalarField& Sf = aMesh().S();
2107 const vectorField& Nf = aMesh().faceAreaNormals().internalField();
2108
2109 scalarField deltaHf
2110 (
2111 sweptVolCorr/(Sf*(Nf & facesDisplacementDir()))
2112 );
2113
2114 for (const word& patchName : fixedFreeSurfacePatches_)
2115 {
2116 label fixedPatchID =
2117 aMesh().boundary().findPatchID(patchName);
2118
2119 if (fixedPatchID == -1)
2120 {
2122 << "Wrong faPatch name '" << patchName
2123 << "'in the fixedFreeSurfacePatches list"
2124 << " defined in dynamicMeshDict dictionary"
2125 << abort(FatalError);
2126 }
2127
2128 for
2129 (
2130 const label facei
2131 : aMesh().boundary()[fixedPatchID].edgeFaces()
2132 )
2133 {
2134 deltaHf[facei] *= 2.0;
2135 }
2136 }
2137
2138 controlPoints() += facesDisplacementDir()*deltaHf;
2139
2140 pointField displacement(pointDisplacement());
2141 correctPointDisplacement(sweptVolCorr, displacement);
2142
2143 velocityMotionSolver& vMotion =
2145 (
2146 const_cast<motionSolver&>(motion())
2147 );
2148
2149 pointVectorField& pointMotionU = vMotion.pointMotionU();
2150 pointMotionU.primitiveFieldRef() = Zero;
2151
2152 fixedValuePointPatchVectorField& fsPatchPointMeshU =
2154 (
2155 const_cast<pointPatchVectorField&>
2156 (
2157 pointMotionU.boundaryField()[fsPatchIndex()]
2158 )
2159 );
2160
2161 fsPatchPointMeshU == displacement/mesh().time().deltaTValue();
2162
2164
2165 correctContactLinePointNormals();
2166 }
2167 else
2168 {
2169 vectorField displacement
2170 (
2171 mesh().boundaryMesh()[fsPatchIndex()].nPoints(),
2172 Zero
2173 );
2174
2175 velocityMotionSolver& vMotion =
2177 (
2178 const_cast<motionSolver&>(motion())
2179 );
2180
2181 pointVectorField& pointMotionU = vMotion.pointMotionU();
2182 pointMotionU.primitiveFieldRef() = Zero;
2183
2184 fixedValuePointPatchVectorField& fsPatchPointMeshU =
2186 (
2187 const_cast<pointPatchVectorField&>
2188 (
2189 pointMotionU.boundaryField()[fsPatchIndex()]
2190 )
2191 );
2192
2193 fsPatchPointMeshU == displacement/mesh().time().deltaTValue();
2194
2196 }
2197
2198 updateUs();
2200 updateSurfactantConcentration();
2201
2202 return true;
2203}
2204
2205
2207{
2209 (
2210 aMesh().patch(),
2212 mesh().time().timePath()/"freeSurface",
2213 false // serial only
2214 );
2215 writer.writeGeometry();
2216}
2217
2218
2220{
2221 // Write control points into VTK
2222 OFstream os
2223 (
2224 mesh().time().timePath()/"freeSurfaceControlPoints.vtk"
2225 );
2226
2227 Info<< "Writing free surface control points to " << os.name() << nl;
2228
2229 os << "# vtk DataFile Version 2.0" << nl
2230 << "freeSurfaceControlPoints" << nl
2231 << "ASCII" << nl
2232 << "DATASET POLYDATA" << nl;
2233
2234 const label nPoints = controlPoints().size();
2235
2236 os << "POINTS " << nPoints << " float" << nl;
2237 for (const point& p : controlPoints())
2238 {
2239 os << float(p.x()) << ' '
2240 << float(p.y()) << ' '
2241 << float(p.z()) << nl;
2242 }
2243
2244 os << "VERTICES " << nPoints << ' ' << 2*nPoints << nl;
2245 for (label id = 0; id < nPoints; ++id)
2246 {
2247 os << 1 << ' ' << id << nl;
2248 }
2249}
2250
2251
2252// ************************************************************************* //
CGAL::Exact_predicates_exact_constructions_kernel K
CGAL::indexedCell< K > Cb
label n
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
vtk::lineWriter writer(edgeCentres, edgeList::null(), fileName(aMesh.time().globalPath()/(vtkBaseFileName+"-edgesCentres")))
Foam::label startTime
const uniformDimensionedVectorField & g
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field values.
const Internal & internalField() const noexcept
Return a const-reference to the dimensioned internal field.
void correctBoundaryConditions()
Correct boundary field.
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition HashSet.H:229
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition HashTable.C:141
@ REGISTER
Request registration (bool: true).
@ NO_READ
Nothing to be read.
@ MUST_READ
Reading required.
@ NO_WRITE
Ignore writing from objectRegistry::writeObject().
@ AUTO_WRITE
Automatically write from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
Output to file stream as an OSstream, normally using std::ofstream for the actual output.
Definition OFstream.H:75
label timeIndex() const noexcept
Return the current time index.
Definition TimeStateI.H:43
scalar deltaTValue() const noexcept
Return time step value.
Definition TimeStateI.H:49
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
label find(const T &val) const
Find index of the first occurrence of the value.
Definition UList.C:160
static bool parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
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.
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition dictionary.C:441
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
Generic dimensioned Type class.
const Type & value() const noexcept
Return const reference to value.
Abstract base class for geometry and/or topology changing fvMesh.
The dynamicMotionSolverFvMesh.
virtual bool init(const bool doInit)
Initialise all non-demand-driven data.
virtual bool update()
Update the mesh for both mesh motion and topology change.
const motionSolver & motion() const
Return the motionSolver.
label findPatchID(const word &patchName, const bool allowNotFound=true) const
Find patch index given a name, return -1 if not found.
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition faMesh.H:140
const faBoundaryMesh & boundary() const noexcept
Return constant reference to boundary mesh.
Definition faMeshI.H:24
bool correctPatchPointNormals(const label patchID) const
Whether point normals should be corrected for a patch.
Definition faMesh.C:1342
static const word & zeroGradientType() noexcept
The type name for zeroGradient patch fields.
const labelList & pointLabels() const
Return patch point labels.
Definition faPatch.C:267
A list of face labels.
Definition faceSet.H:50
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
label which(const label vertex) const
Find local vertex on face for the vertex label, same as find().
Definition faceI.H:196
label nextLabel(const label i) const
Next vertex on face.
Definition faceI.H:208
label prevLabel(const label i) const
Previous vertex on face.
Definition faceI.H:214
virtual const objectRegistry & thisDb() const
Return the object registry - resolve conflict polyMesh/lduMesh.
Definition fvMesh.H:376
const Time & time() const
Return the top-level database.
Definition fvMesh.H:360
const surfaceVectorField & Cf() const
Return face centres as surfaceVectorField.
const surfaceVectorField & Sf() const
Return cell face area vectors.
Second-oder Crank-Nicolson implicit ddt using the current and previous time-step fields as well as th...
Basic first-order Euler implicit/explicit ddt using only the current and previous time-step values.
Second-order backward-differencing ddt using the current and two previous time-step values.
The interfaceTrackingFvMesh.
vectorField & controlPoints()
Return control points.
void correctUsBoundaryConditions()
Correct surface velocity boundary conditions.
Switch pureFreeSurface() const noexcept
Pure free-surface.
areaVectorField & Us()
Return free-surface velocity field.
const areaScalarField & fsNetPhi() const
Return free-surface net flux.
const surfaceScalarField & phi() const
Return constant reference to velocity field.
tmp< scalarField > freeSurfaceSnGradUn()
Return free surface normal derivative of normal velocity comp.
vectorField & pointsDisplacementDir()
Return reference to point displacement direction field.
virtual bool init(const bool doInit)
Initialise all non-demand-driven data.
const volVectorField & U() const
Return constant reference to velocity field.
void writeVTK() const
Write VTK freeSurface mesh.
void updateUs()
Update free-surface velocity field.
areaScalarField & surfaceTension()
Return surface tension field.
vectorField & facesDisplacementDir()
Return reference to control points displacement direction field.
void writeVTKControlPoints()
Write VTK freeSurface control points.
faMesh & aMesh()
Return reference to finite area mesh.
virtual bool update()
Update the mesh for both mesh motion and topology change.
tmp< areaVectorField > surfaceTensionGrad()
Return surface tension gradient.
labelList & motionPointsMask()
Return reference to motion points mask field.
volScalarField & bulkSurfactantConcentration()
Return volume surfactant concentration field.
const volScalarField & p() const
Return constant reference to pressure field.
const surfactantProperties & surfactant() const
Return surfactant properties.
areaScalarField & surfactantConcentration()
Return free-surface surfactant concentration field.
edgeScalarField & Phis()
Return free-surface fluid flux field.
tmp< scalarField > freeSurfacePressureJump()
Return free surface pressure jump.
tmp< vectorField > freeSurfaceSnGradU()
Return free surface normal derivative of velocity.
void clearControlPoints()
Clear control points.
static const gravity & New(const word &name, const Time &runTime)
Return named gravity field cached or construct on Time.
Virtual base class for mesh motion solver.
const Type & lookupObject(const word &name, const bool recursive=false) const
Lookup and return const reference to the object of the given Type. Fatal if not found or the wrong ty...
Type * getObjectPtr(const word &name, const bool recursive=false) const
Return non-const pointer to the object of the given Type, using a const-cast to have it behave like a...
A set of point labels.
Definition pointSet.H:50
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
virtual const pointField & oldPoints() const
Return old points (mesh motion).
Definition polyMesh.C:1113
label nFaces() const noexcept
Number of mesh faces.
const labelListList & edgeFaces() const
ITstream & ddtScheme(const word &name) const
Get ddt scheme for given name, or default.
A simple single-phase transport model based on viscosityModel.
A class for managing temporary objects.
Definition tmp.H:75
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition tmp.H:215
Abstract base class for turbulence models (RAS, LES and laminar).
Virtual base class for velocity motion solver.
pointVectorField & pointMotionU()
Return reference to the point motion velocity field.
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
U
Definition pEqn.H:72
volScalarField & p
rDeltaTY field()
auto limits
Definition setRDeltaT.H:186
const volScalarField & p0
Definition EEqn.H:36
faceListList boundary
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
OBJstream os(runTime.globalPath()/outputName)
const auto & io
Calculate the mesh motion flux and convert fluxes from absolute to relative and back.
auto & name
const pointField & points
label nPoints
word timeName
Definition getTimeIndex.H:3
#define DebugInFunction
Report an information message using Foam::Info.
const dimensionedScalar a0
Bohr radius: default SI units: [m].
const dimensionedScalar c
Speed of light in a vacuum.
static tmp< GeometricField< Type, faePatchField, edgeMesh > > interpolate(const GeometricField< Type, faPatchField, areaMesh > &tvf, const edgeScalarField &faceFlux, Istream &schemeData)
Interpolate field onto faces using scheme given by Istream.
tmp< GeometricField< Type, faPatchField, areaMesh > > div(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
Definition facDiv.C:43
tmp< GeometricField< Type, faPatchField, areaMesh > > edgeIntegrate(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
tmp< GeometricField< typename outerProduct< vector, Type >::type, faPatchField, areaMesh > > grad(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
Definition facGrad.C:51
tmp< faMatrix< Type > > div(const edgeScalarField &flux, const GeometricField< Type, faPatchField, areaMesh > &vf, const word &name)
Definition famDiv.C:41
tmp< faMatrix< Type > > laplacian(const GeometricField< Type, faPatchField, areaMesh > &vf)
tmp< faMatrix< Type > > ddt(const GeometricField< Type, faPatchField, areaMesh > &vf)
Definition famDdt.C:41
zeroField Sp(const Foam::zero, const GeometricField< Type, faPatchField, areaMesh > &)
A no-op source.
const std::string patch
OpenFOAM patch number as a std::string.
tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > snGrad(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition fvcSnGrad.C:40
@ LEGACY_ASCII
Legacy ASCII, legacyAsciiFormatter.
Definition foamVtkCore.H:94
GenericPatchWriter< uindirectPrimitivePatch > uindirectPatchWriter
Write uindirectPrimitivePatch faces/points (optionally with fields) as a vtp file or a legacy vtk fil...
Namespace for OpenFOAM.
List< edge > edgeList
List of edge.
Definition edgeList.H:32
Type gAverage(const FieldField< Field, Type > &f, const label comm)
The global arithmetic average of a FieldField.
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
List< word > wordList
List of word.
Definition fileName.H:60
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
Type gSum(const FieldField< Field, Type > &f)
GeometricField< vector, fvPatchField, volMesh > volVectorField
const dimensionSet dimless
Dimensionless.
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
List< label > labelList
A List of labels.
Definition List.H:62
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition HashSet.H:85
GeometricField< scalar, fvPatchField, volMesh > volScalarField
const dimensionSet dimMoles(0, 0, 0, 0, 1, 0, 0)
const dimensionSet dimArea(sqr(dimLength))
dimensionedScalar sin(const dimensionedScalar &ds)
const dimensionSet dimVelocity
tmp< GeometricField< Type, faePatchField, edgeMesh > > linearEdgeInterpolate(const GeometricField< Type, faPatchField, areaMesh > &vf)
faMatrix< scalar > faScalarMatrix
Definition faMatrices.H:46
messageStream Info
Information stream (stdout output on master, null elsewhere).
GeometricField< tensor, faPatchField, areaMesh > areaTensorField
List< face > faceList
List of faces.
Definition faceListFwd.H:41
GeometricField< vector, pointPatchField, pointMesh > pointVectorField
DynamicID< polyBoundaryMesh > polyPatchID
Foam::polyPatchID.
Definition polyPatchID.H:34
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition POSIX.C:801
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
constexpr scalar degToRad() noexcept
Multiplication factor for degrees to radians conversion.
GeometricField< vector, faPatchField, areaMesh > areaVectorField
GeometricField< scalar, faePatchField, edgeMesh > edgeScalarField
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
UniformDimensionedField< vector > uniformDimensionedVectorField
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
GeometricField< scalar, faPatchField, areaMesh > areaScalarField
errorManip< error > abort(error &err)
Definition errorManip.H:139
const dimensionSet dimForce
Field< vector > vectorField
Specialisation of Field<T> for vector.
pointPatchField< vector > pointPatchVectorField
vector point
Point is a vector.
Definition point.H:37
dimensionedScalar neg(const dimensionedScalar &ds)
List< bool > boolList
A List of bools.
Definition List.H:60
MinMax< Type > gMinMax(const FieldField< Field, Type > &f)
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix by subtracting the matrix multiplied by the current fi...
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
const dimensionSet dimVolume(pow3(dimLength))
vectorField pointField
pointField is a vectorField.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Vector< scalar > vector
Definition vector.H:57
const dimensionSet dimDensity
UList< label > labelUList
A UList of labels.
Definition UList.H:75
IOField< vector > vectorIOField
IO for a Field of vector.
Type gMax(const FieldField< Field, Type > &f)
Ostream & flush(Ostream &os)
Flush stream.
Definition Ostream.H:509
dimensionedScalar cos(const dimensionedScalar &ds)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
label timeIndex
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} pointMap[start]=pointMap[end]=Foam::min(start, end);} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};constexpr label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< DynamicList< face > > pFaces[nBCs]
volScalarField & nu
volScalarField & b
volScalarField & e
dimensionedScalar sigma("sigma", dimMass/sqr(dimTime), transportProperties)
scalar CoNum
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
Unit conversion functions.
const Vector< label > N(dict.get< Vector< label > >("N"))