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 -------------------------------------------------------------------------------
11 License
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"
39 #include "symmetryFvPatchFields.H"
40 #include "wallFvPatch.H"
41 #include "polyPatchID.H"
42 #include "fvcMeshPhi.H"
44 #include "EulerDdtScheme.H"
45 #include "CrankNicolsonDdtScheme.H"
46 #include "backwardDdtScheme.H"
47 #include "twoDPointCorrector.H"
48 #include "gravityMeshObject.H"
50 #include "unitConversion.H"
51 #include "foamVtkIndPatchWriter.H"
53 
54 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
55 
56 namespace Foam
57 {
60  (
63  IOobject
64  );
66  (
69  doInit
70  );
71 }
72 
73 
74 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
75 
76 void 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 
132 void 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  (
214  IOobject
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 
258 void 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  (
272  IOobject
273  (
274  "fsNetPhi",
275  aMesh().time().timeName(),
276  aMesh().thisDb(),
279  ),
280  aMesh(),
282  );
283 }
284 
285 
286 void 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 
329 void 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 
391 void 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 
434 void 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  (
448  IOobject
449  (
450  "phis",
451  aMesh().time().timeName(),
452  aMesh().thisDb(),
455  ),
456  linearEdgeInterpolate(Us()) & aMesh().Le()
457  );
458 }
459 
460 
461 void 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  (
475  IOobject
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 
492 void 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  (
506  IOobject
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 
531 void 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  (
545  IOobject
546  (
547  "surfaceTension",
548  aMesh().time().timeName(),
549  aMesh().thisDb(),
552  ),
553  sigma() + surfactant().dSigma(surfactantConcentration())/rho_
554  );
555 }
556 
557 
558 void 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 
577 void 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 
609 void 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 
635  vectorField N
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 
679 void 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 
718  FatalError
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  {
730  FatalError
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 
751 void 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  {
787  FatalError
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 =
808  refCast<velocityMotionSolver>
809  (
810  const_cast<motionSolver&>(motion())
811  );
812 
813  pointVectorField& pointMotionU = vMotion.pointMotionU();
814  pointMotionU.primitiveFieldRef() = Zero;
815 
816  fixedValuePointPatchVectorField& fsPatchPointMeshU =
817  refCast<fixedValuePointPatchVectorField>
818  (
819  const_cast<pointPatchVectorField&>
820  (
821  pointMotionU.boundaryField()[fsPatchIndex()]
822  )
823  );
824 
825  fsPatchPointMeshU == displacement/mesh().time().deltaTValue();
826 
828 }
829 
830 
831 void Foam::interfaceTrackingFvMesh::updateSurfaceFlux()
832 {
833  Phis() = fac::interpolate(Us()) & aMesh().Le();
834 }
835 
836 
837 void 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  (
863  IOobject
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 
909 Foam::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 
923 Foam::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 
960 Foam::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 
988 Foam::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 
1029 void 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 
1043 void 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 
1252 void 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 =
1301  refCast<const processorFaPatch>
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  }
1518  }
1519  }
1520 }
1521 
1522 
1523 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1524 
1525 Foam::interfaceTrackingFvMesh::interfaceTrackingFvMesh
1526 (
1527  const IOobject& io,
1528  const bool doInit
1529 )
1530 :
1531  dynamicMotionSolverFvMesh(io, doInit),
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 /*
1553 Foam::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 
1595 bool 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  {
1697  vectorField N
1698  (
1699  aMesh().boundary()[patchI].ngbPolyPatchFaceNormals()
1700  );
1701 
1702  pUs -= N*(N&pUs);
1703  }
1704  }
1705  }
1706  }
1707 
1708  Us().correctBoundaryConditions();
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 
1724  correctUsBoundaryConditions();
1725 }
1726 
1729 {
1730  return *getObjectPtr<const volVectorField>("U");
1731 }
1732 
1735 {
1736  return *getObjectPtr<const volScalarField>("p");
1737 }
1738 
1739 
1741 {
1742  return *getObjectPtr<const surfaceScalarField>("phi");
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 
1767  const turbulenceModel& turbulence =
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 
1816  meshObjects::gravity::New(mesh().time());
1817 
1818  const turbulenceModel& turbulence =
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();
1900  }
1901 
1902  return *surfactConcPtr_;
1903 }
1904 
1905 
1906 const Foam::areaScalarField&
1908 {
1909  if (!surfactConcPtr_)
1910  {
1911  makeSurfactConc();
1912  }
1913 
1914  return *surfactConcPtr_;
1915 }
1916 
1917 
1920 {
1921  if (!bulkSurfactConcPtr_)
1922  {
1923  makeBulkSurfactConc();
1924  }
1925 
1926  return *bulkSurfactConcPtr_;
1927 }
1928 
1929 
1930 const Foam::volScalarField&
1932 {
1933  if (!bulkSurfactConcPtr_)
1934  {
1935  makeBulkSurfactConc();
1936  }
1937 
1938  return *bulkSurfactConcPtr_;
1939 }
1940 
1941 
1944 {
1945  if (!surfaceTensionPtr_)
1946  {
1947  makeSurfaceTension();
1948  }
1949 
1950  return *surfaceTensionPtr_;
1951 }
1952 
1953 
1954 const Foam::areaScalarField&
1956 {
1957  if (!surfaceTensionPtr_)
1958  {
1959  makeSurfaceTension();
1960  }
1961 
1962  return *surfaceTensionPtr_;
1963 }
1964 
1965 
1968 {
1969  if (!surfactantPtr_)
1970  {
1971  makeSurfactant();
1972  }
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
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 =
2144  refCast<velocityMotionSolver>
2145  (
2146  const_cast<motionSolver&>(motion())
2147  );
2148 
2149  pointVectorField& pointMotionU = vMotion.pointMotionU();
2150  pointMotionU.primitiveFieldRef() = Zero;
2151 
2152  fixedValuePointPatchVectorField& fsPatchPointMeshU =
2153  refCast<fixedValuePointPatchVectorField>
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 =
2176  refCast<velocityMotionSolver>
2177  (
2178  const_cast<motionSolver&>(motion())
2179  );
2180 
2181  pointVectorField& pointMotionU = vMotion.pointMotionU();
2182  pointMotionU.primitiveFieldRef() = Zero;
2183 
2184  fixedValuePointPatchVectorField& fsPatchPointMeshU =
2185  refCast<fixedValuePointPatchVectorField>
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  );
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 // ************************************************************************* //
edgeScalarField & Phis()
Return free-surface fluid flux field.
virtual bool init(const bool doInit)
Initialise all non-demand-driven data.
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:133
faceListList boundary
Write concrete PrimitivePatch faces/points (optionally with fields) as a vtp file or a legacy vtk fil...
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix by subtracting the matrix multiplied by the current fi...
const Type & value() const noexcept
Return const reference to value.
Second-oder Crank-Nicolson implicit ddt using the current and previous time-step fields as well as th...
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:119
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...
vectorField & facesDisplacementDir()
Return reference to control points displacement direction field.
rDeltaTY field()
A list of face labels.
Definition: faceSet.H:47
scalar deltaTValue() const noexcept
Return time step value.
Definition: TimeStateI.H:49
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
virtual bool writeGeometry()
Write vertex topology.
A set of point labels.
Definition: pointSet.H:47
CGAL::indexedCell< K > Cb
const areaScalarField & fsNetPhi() const
Return free-surface net flux.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:130
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:652
const surfaceVectorField & Cf() const
Return face centres as surfaceVectorField.
Virtual base class for velocity motion solver.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
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.
Unit conversion functions.
const Internal & internalField() const noexcept
Return a const-reference to the dimensioned internal field.
Output to file stream as an OSstream, normally using std::ofstream for the actual output...
Definition: OFstream.H:71
tmp< scalarField > freeSurfacePressureJump()
Return free surface pressure jump.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
vectorField & pointsDisplacementDir()
Return reference to point displacement direction field.
tmp< GeometricField< Type, faPatchField, areaMesh > > div(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
Definition: facDiv.C:43
virtual bool update()
Update the mesh for both mesh motion and topology change.
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface...
Definition: boundaryMesh.H:58
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:518
void updateUs()
Update free-surface velocity field.
const labelList & pointLabels() const
Return patch point labels.
Definition: faPatch.C:267
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1774
An indexed form of CGAL::Triangulation_cell_base_3<K> used to keep track of the Delaunay cells (tets)...
Definition: indexedCell.H:64
label nextLabel(const label i) const
Next vertex on face.
Definition: faceI.H:208
const volVectorField & U() const
Return constant reference to velocity field.
Virtual base class for mesh motion solver.
Definition: motionSolver.H:54
void correctUsBoundaryConditions()
Correct surface velocity boundary conditions.
Ignore writing from objectRegistry::writeObject()
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:674
const dimensionSet dimless
Dimensionless.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:229
CGAL::Exact_predicates_exact_constructions_kernel K
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:441
Abstract base class for turbulence models (RAS, LES and laminar).
dimensionedScalar sigma("sigma", dimMass/sqr(dimTime), transportProperties)
faMesh & aMesh()
Return reference to finite area mesh.
dimensionedScalar neg(const dimensionedScalar &ds)
static const word & zeroGradientType() noexcept
The type name for zeroGradient patch fields.
Definition: faPatchField.H:191
Macros for easy insertion into run-time selection tables.
bool get(const label i) const
Return bool value at specified position, always false for out-of-range access.
Definition: UList.H:869
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:400
tmp< faMatrix< Type > > laplacian(const GeometricField< Type, faPatchField, areaMesh > &vf)
Definition: famLaplacian.C:42
label prevLabel(const label i) const
Previous vertex on face.
Definition: faceI.H:214
volScalarField & bulkSurfactantConcentration()
Return volume surfactant concentration field.
word timeName
Definition: getTimeIndex.H:3
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:805
const dimensionSet dimVolume(pow3(dimLength))
Definition: dimensionSets.H:58
auto limits
Definition: setRDeltaT.H:186
zeroField Sp(const Foam::zero, const GeometricField< Type, faPatchField, areaMesh > &)
A no-op source.
virtual bool init(const bool doInit)
Initialise all non-demand-driven data.
label findPatchID(const word &patchName, const bool allowNotFound=true) const
Find patch index given a name, return -1 if not found.
tmp< GeometricField< Type, faePatchField, edgeMesh > > linearEdgeInterpolate(const GeometricField< Type, faPatchField, areaMesh > &vf)
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
dynamicFvMesh & mesh
Type gSum(const FieldField< Field, Type > &f)
dimensionedScalar cos(const dimensionedScalar &ds)
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:611
A class for handling words, derived from Foam::string.
Definition: word.H:63
label nPoints
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
#define DebugInFunction
Report an information message using Foam::Info.
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
areaVectorField & Us()
Return free-surface velocity field.
Us
const auto & io
virtual const pointField & oldPoints() const
Return old points (mesh motion)
Definition: polyMesh.C:1113
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:217
label which(const label vertex) const
Find local vertex on face for the vertex label, same as find()
Definition: faceI.H:196
MinMax< Type > gMinMax(const FieldField< Field, Type > &f)
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]
Definition: readKivaGrid.H:233
label timeIndex() const noexcept
Return the current time index.
Definition: TimeStateI.H:43
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
Second-order backward-differencing ddt using the current and two previous time-step values...
errorManip< error > abort(error &err)
Definition: errorManip.H:139
vectorField & controlPoints()
Return control points.
label find(const T &val) const
Find index of the first occurrence of the value.
Definition: UList.C:160
virtual bool update()
Update the mesh for both mesh motion and topology change.
scalar CoNum
areaScalarField & surfactantConcentration()
Return free-surface surfactant concentration field.
tmp< faMatrix< Type > > ddt(const GeometricField< Type, faPatchField, areaMesh > &vf)
Definition: famDdt.C:41
const uniformDimensionedVectorField & g
dimensionedScalar sin(const dimensionedScalar &ds)
const dimensionSet dimForce
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
tmp< faMatrix< Type > > div(const edgeScalarField &flux, const GeometricField< Type, faPatchField, areaMesh > &vf, const word &name)
Definition: famDiv.C:41
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...
Type gAverage(const FieldField< Field, Type > &f, const label comm)
The global arithmetic average of a FieldField.
Type gMax(const FieldField< Field, Type > &f)
const dimensionSet dimMoles(0, 0, 0, 0, 1, 0, 0)
Definition: dimensionSets.H:53
Info<< "Reading field U\"<< endl;volVectorField U(IOobject("U", runTime.timeName(), mesh, IOobject::MUST_READ, IOobject::AUTO_WRITE), mesh);volScalarField rho(IOobject("rho", runTime.timeName(), mesh, IOobject::NO_READ, IOobject::AUTO_WRITE), thermo.rho());volVectorField rhoU(IOobject("rhoU", runTime.timeName(), mesh, IOobject::NO_READ, IOobject::NO_WRITE), rho *U);volScalarField rhoE(IOobject("rhoE", runTime.timeName(), mesh, IOobject::NO_READ, IOobject::NO_WRITE), rho *(e+0.5 *magSqr(U)));surfaceScalarField pos(IOobject("pos", runTime.timeName(), mesh), mesh, dimensionedScalar("pos", dimless, 1.0));surfaceScalarField neg(IOobject("neg", runTime.timeName(), mesh), mesh, dimensionedScalar("neg", dimless, -1.0));surfaceScalarField phi("phi", fvc::flux(rhoU));Info<< "Creating turbulence model\"<< endl;autoPtr< compressible::turbulenceModel > turbulence(compressible::turbulenceModel::New(rho, U, phi, thermo))
Definition: createFields.H:94
defineTypeNameAndDebug(combustionModel, 0)
const volScalarField & p() const
Return constant reference to pressure field.
static const gravity & New(const word &name, const Time &runTime)
Return named gravity field cached or construct on Time.
tmp< GeometricField< Type, faPatchField, areaMesh > > edgeIntegrate(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
const faBoundaryMesh & boundary() const noexcept
Return constant reference to boundary mesh.
Definition: faMeshI.H:24
const surfaceScalarField & phi() const
Return constant reference to velocity field.
labelList & motionPointsMask()
Return reference to motion points mask field.
const dimensionSet dimDensity
const Vector< label > N(dict.get< Vector< label >>("N"))
Calculate the mesh motion flux and convert fluxes from absolute to relative and back.
const surfactantProperties & surfactant() const
Return surfactant properties.
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field values.
decomposeUsingBbs false
Use bounding boxes (default) or unique decomposition of triangles (i.e. do not duplicate triangles) ...
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:508
U
Definition: pEqn.H:72
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Abstract base class for geometry and/or topology changing fvMesh.
Definition: dynamicFvMesh.H:74
const dimensionedScalar c
Speed of light in a vacuum.
Nothing to be read.
Automatically write from objectRegistry::writeObject()
void writeVTKControlPoints()
Write VTK freeSurface control points.
const dimensionedScalar a0
Bohr radius: default SI units: [m].
Template specialisation for scalar faMatrix.
const std::string patch
OpenFOAM patch number as a std::string.
const motionSolver & motion() const
Return the motionSolver.
tmp< scalarField > freeSurfaceSnGradUn()
Return free surface normal derivative of normal velocity comp.
Legacy ASCII, legacyAsciiFormatter.
bool correctPatchPointNormals(const label patchID) const
Whether point normals should be corrected for a patch.
Definition: faMesh.C:1332
messageStream Info
Information stream (stdout output on master, null elsewhere)
label n
tmp< areaVectorField > surfaceTensionGrad()
Return surface tension gradient.
The dynamicMotionSolverFvMesh.
vtk::vertexWriter writer(edgeCentres, outputOpts,(aMesh.time().globalPath()/outputName), UPstream::parRun())
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition: HashTable.C:141
void writeVTK() const
Write VTK freeSurface mesh.
volScalarField & p
A class for managing temporary objects.
Definition: HashPtrTable.H:50
tmp< vectorField > freeSurfaceSnGradU()
Return free surface normal derivative of velocity.
Basic first-order Euler implicit/explicit ddt using only the current and previous time-step values...
A simple single-phase transport model based on viscosityModel.
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:188
Foam::label startTime
Request registration (bool: true)
A primitive field of type <T> with automated input and output.
volScalarField & nu
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
const volScalarField & p0
Definition: EEqn.H:36
tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > snGrad(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvcSnGrad.C:40
const dimensionSet dimArea(sqr(dimLength))
Definition: dimensionSets.H:57
Namespace for OpenFOAM.
tmp< GeometricField< typename outerProduct< vector, Type >::type, faPatchField, areaMesh >> grad(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
Definition: facGrad.C:51
label timeIndex
Definition: getTimeIndex.H:24
areaScalarField & surfaceTension()
Return surface tension field.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
Processor patch.
The interfaceTrackingFvMesh.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127
const dimensionSet dimVelocity