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-2021 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 "demandDrivenData.H"
51 #include "unitConversion.H"
52 #include "foamVtkIndPatchWriter.H"
54 
55 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
56 
57 namespace Foam
58 {
61  (
64  IOobject
65  );
67  (
70  doInit
71  );
72 }
73 
74 
75 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
76 
77 void Foam::interfaceTrackingFvMesh::initializeData()
78 {
79  // Set free surface patch index
80  {
81  const word fsPatchName(motion().get<word>("fsPatchName"));
82 
83  polyPatchID patch(fsPatchName, this->boundaryMesh());
84 
85  if (!patch.active())
86  {
88  << "Patch name " << fsPatchName << " not found."
89  << abort(FatalError);
90  }
91 
92  fsPatchIndex_ = patch.index();
93  }
94 
95  // Set point normal correction for finite area mesh
96  if (!pointNormalsCorrectionPatches_.empty())
97  {
99 
100  for (const word& patchName : pointNormalsCorrectionPatches_)
101  {
102  label patchID = aMesh().boundary().findPatchID(patchName);
103 
104  if (patchID == -1)
105  {
107  << "Patch name '" << patchName
108  << "' for point normals correction does not exist"
109  << abort(FatalError);
110  }
111 
112  correction[patchID] = true;
113  }
114  }
115 
116  // Read motion direction
117  if (!normalMotionDir_)
118  {
119  motionDir_ = normalised(motion().get<vector>("motionDir"));
120  }
121 
122  // Check if contact angle is defined
123  makeContactAngle();
124 
126  (
127  "nonReflectingFreeSurfacePatches",
128  nonReflectingFreeSurfacePatches_
129  );
130 }
131 
132 
133 void Foam::interfaceTrackingFvMesh::makeUs() const
134 {
136  << "making free-surface velocity field" << nl;
137 
138  if (UsPtr_)
139  {
141  << "free-surface velocity field already exists"
142  << abort(FatalError);
143  }
144 
145  wordList patchFieldTypes
146  (
147  aMesh().boundary().size(),
149  );
150 
151  forAll(aMesh().boundary(), patchI)
152  {
153  if
154  (
155  aMesh().boundary()[patchI].type()
156  == wedgeFaPatch::typeName
157  )
158  {
159  patchFieldTypes[patchI] =
160  wedgeFaPatchVectorField::typeName;
161  }
162  else
163  {
164  label ngbPolyPatchID =
165  aMesh().boundary()[patchI].ngbPolyPatchIndex();
166 
167  if (ngbPolyPatchID != -1)
168  {
169  if
170  (
171  mesh().boundary()[ngbPolyPatchID].type()
172  == wallFvPatch::typeName
173  )
174  {
175  patchFieldTypes[patchI] =
176  slipFaPatchVectorField::typeName;
177  }
178  }
179  }
180  }
181 
182  for (const word& patchName : fixedFreeSurfacePatches_)
183  {
184  const label fixedPatchID =
185  aMesh().boundary().findPatchID(patchName);
186 
187  if (fixedPatchID == -1)
188  {
190  << "Wrong faPatch name '" << patchName
191  << "' in the fixedFreeSurfacePatches list"
192  << " defined in the dynamicMeshDict dictionary"
193  << abort(FatalError);
194  }
195 
196  label ngbPolyPatchID =
197  aMesh().boundary()[fixedPatchID].ngbPolyPatchIndex();
198 
199  if (ngbPolyPatchID != -1)
200  {
201  if
202  (
203  mesh().boundary()[ngbPolyPatchID].type()
204  == wallFvPatch::typeName
205  )
206  {
207  patchFieldTypes[fixedPatchID] =
208  fixedValueFaPatchVectorField::typeName;
209  }
210  }
211  }
212 
213  UsPtr_ = new areaVectorField
214  (
215  IOobject
216  (
217  "Us",
218  aMesh().time().timeName(),
219  aMesh().thisDb(),
222  ),
223  aMesh(),
225  patchFieldTypes
226  );
227 
228  for (const word& patchName : fixedFreeSurfacePatches_)
229  {
230  const label fixedPatchID = aMesh().boundary().findPatchID(patchName);
231 
232  if (fixedPatchID == -1)
233  {
235  << "Wrong faPatch name '" << patchName
236  << "' in the fixedFreeSurfacePatches list"
237  << " defined in the dynamicMeshDict dictionary"
238  << abort(FatalError);
239  }
240 
241  label ngbPolyPatchID =
242  aMesh().boundary()[fixedPatchID].ngbPolyPatchIndex();
243 
244  if (ngbPolyPatchID != -1)
245  {
246  if
247  (
248  mesh().boundary()[ngbPolyPatchID].type()
249  == wallFvPatch::typeName
250  )
251  {
252  UsPtr_->boundaryFieldRef()[fixedPatchID] == Zero;
253  }
254  }
255  }
256 }
257 
258 
259 void Foam::interfaceTrackingFvMesh::makeFsNetPhi() const
260 {
262  << "making free-surface net flux" << nl;
263 
264  if (fsNetPhiPtr_)
265  {
267  << "free-surface net flux already exists"
268  << abort(FatalError);
269  }
270 
271  fsNetPhiPtr_ = new areaScalarField
272  (
273  IOobject
274  (
275  "fsNetPhi",
276  aMesh().time().timeName(),
277  aMesh().thisDb(),
280  ),
281  aMesh(),
283  );
284 }
285 
286 
287 void Foam::interfaceTrackingFvMesh::makeControlPoints()
288 {
290  << "making control points" << nl;
291 
292  if (controlPointsPtr_)
293  {
295  << "control points already exists"
296  << abort(FatalError);
297  }
298 
299  IOobject pointsIO
300  (
301  "controlPoints",
302  mesh().time().timeName(),
303  mesh(),
307  );
308 
309  if (pointsIO.typeHeaderOk<vectorIOField>())
310  {
311  Info<< "Reading control points" << endl;
312  controlPointsPtr_ = new vectorIOField(pointsIO);
313  }
314  else
315  {
316  pointsIO.readOpt(IOobject::NO_READ);
317 
318  Info<< "Creating new control points" << endl;
319  controlPointsPtr_ = new vectorIOField
320  (
321  pointsIO,
322  aMesh().areaCentres().internalField()
323  );
324 
325  initializeControlPointsPosition();
326  }
327 }
328 
329 
330 void Foam::interfaceTrackingFvMesh::makeMotionPointsMask()
331 {
333  << "making motion points mask" << nl;
334 
335  if (motionPointsMaskPtr_)
336  {
338  << "motion points mask already exists"
339  << abort(FatalError);
340  }
341 
342  motionPointsMaskPtr_ = new labelList
343  (
344  mesh().boundaryMesh()[fsPatchIndex()].nPoints(),
345  1
346  );
347 
348  // Mark free surface boundary points
349  // that belong to processor patches
350  forAll(aMesh().boundary(), patchI)
351  {
352  if
353  (
354  aMesh().boundary()[patchI].type()
355  == processorFaPatch::typeName
356  )
357  {
358  const labelList& patchPoints =
359  aMesh().boundary()[patchI].pointLabels();
360 
361  forAll(patchPoints, pointI)
362  {
363  motionPointsMask()[patchPoints[pointI]] = -1;
364  }
365  }
366  }
367 
368  // Mark fixed free surface boundary points
369  for (const word& patchName : fixedFreeSurfacePatches_)
370  {
371  const label fixedPatchID = aMesh().boundary().findPatchID(patchName);
372 
373  if (fixedPatchID == -1)
374  {
376  << "Wrong faPatch name in the fixedFreeSurfacePatches list"
377  << " defined in the dynamicMeshDict dictionary"
378  << abort(FatalError);
379  }
380 
381  const labelList& patchPoints =
382  aMesh().boundary()[fixedPatchID].pointLabels();
383 
384  forAll(patchPoints, pointI)
385  {
386  motionPointsMask()[patchPoints[pointI]] = 0;
387  }
388  }
389 }
390 
391 
392 void Foam::interfaceTrackingFvMesh::makeDirections()
393 {
395  << "make displacement directions for points and control points" << nl;
396 
397  if (pointsDisplacementDirPtr_ || facesDisplacementDirPtr_)
398  {
400  << "points, control points displacement directions already exist"
401  << abort(FatalError);
402  }
403 
404  pointsDisplacementDirPtr_ =
405  new vectorField
406  (
407  mesh().boundaryMesh()[fsPatchIndex()].nPoints(),
408  Zero
409  );
410 
411  facesDisplacementDirPtr_ =
412  new vectorField
413  (
414  mesh().boundaryMesh()[fsPatchIndex()].size(),
415  Zero
416  );
417 
418  if (!normalMotionDir())
419  {
420  if (mag(motionDir_) < SMALL)
421  {
423  << "Zero motion direction"
424  << abort(FatalError);
425  }
426 
427  facesDisplacementDir() = motionDir_;
428  pointsDisplacementDir() = motionDir_;
429  }
430 
431  updateDisplacementDirections();
432 }
433 
434 
435 void Foam::interfaceTrackingFvMesh::makePhis()
436 {
438  << "making free-surface flux" << nl;
439 
440  if (phisPtr_)
441  {
443  << "free-surface flux already exists"
444  << abort(FatalError);
445  }
446 
447  phisPtr_ = new edgeScalarField
448  (
449  IOobject
450  (
451  "phis",
452  aMesh().time().timeName(),
453  aMesh().thisDb(),
456  ),
457  linearEdgeInterpolate(Us()) & aMesh().Le()
458  );
459 }
460 
461 
462 void Foam::interfaceTrackingFvMesh::makeSurfactConc() const
463 {
465  << "making free-surface surfactant concentration field" << nl;
466 
467  if (surfactConcPtr_)
468  {
470  << "free-surface surfactant concentration field already exists"
471  << abort(FatalError);
472  }
473 
474  surfactConcPtr_ = new areaScalarField
475  (
476  IOobject
477  (
478  "Cs",
479  mesh().time().timeName
480  (
481  mesh().time().startTime().value()
482  ),
483  // mesh().time().timeName(),
484  aMesh().thisDb(),
487  ),
488  aMesh()
489  );
490 }
491 
492 
493 void Foam::interfaceTrackingFvMesh::makeBulkSurfactConc() const
494 {
496  << "making volume surfactant concentration field" << nl;
497 
498  if (bulkSurfactConcPtr_)
499  {
501  << "volume surfactant concentration field already exists"
502  << abort(FatalError);
503  }
504 
505  bulkSurfactConcPtr_ = new volScalarField
506  (
507  IOobject
508  (
509  "C",
510  mesh().time().timeName
511  (
512  mesh().time().startTime().value()
513  ),
514  // mesh().time().timeName(),
515  mesh(),
518  ),
519  mesh()
520  );
521  volScalarField& bulkSurfactConc = *bulkSurfactConcPtr_;
522 
523  if (mesh().time().timeIndex()-1 == 0)
524  {
525  // Initialize uniform volume surfactant concentration
526  bulkSurfactConc = surfactant().bulkConc();
527  bulkSurfactConc.correctBoundaryConditions();
528  }
529 }
530 
531 
532 void Foam::interfaceTrackingFvMesh::makeSurfaceTension() const
533 {
535  << "making surface tension field" << nl;
536 
537  if (surfaceTensionPtr_)
538  {
540  << "surface tension field already exists"
541  << abort(FatalError);
542  }
543 
544  surfaceTensionPtr_ = new areaScalarField
545  (
546  IOobject
547  (
548  "surfaceTension",
549  aMesh().time().timeName(),
550  aMesh().thisDb(),
553  ),
554  sigma() + surfactant().dSigma(surfactantConcentration())/rho_
555  );
556 }
557 
558 
559 void Foam::interfaceTrackingFvMesh::makeSurfactant() const
560 {
562  << "making surfactant properties" << nl;
563 
564  if (surfactantPtr_)
565  {
567  << "surfactant properties already exists"
568  << abort(FatalError);
569  }
570 
571  const dictionary& surfactProp =
572  motion().subDict("surfactantProperties");
573 
574  surfactantPtr_ = new surfactantProperties(surfactProp);
575 }
576 
577 
578 void Foam::interfaceTrackingFvMesh::makeContactAngle()
579 {
581  << "making contact angle field" << nl;
582 
583  if (contactAnglePtr_)
584  {
586  << "contact angle already exists"
587  << abort(FatalError);
588  }
589 
590  // Check if contactAngle is defined
591  IOobject contactAngleHeader
592  (
593  "contactAngle",
594  aMesh().time().timeName(),
595  aMesh().thisDb(),
598  );
599 
600  if (contactAngleHeader.typeHeaderOk<areaScalarField>())
601  {
602  Info<< "Reading contact angle field" << endl;
603 
604  contactAnglePtr_ = new 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  const labelList& eFaces =
737  aMesh().boundary()[fixedPatchID].edgeFaces();
738 
739  forAll(eFaces, edgeI)
740  {
741  deltaH[eFaces[edgeI]] *= 2.0;
742  }
743  }
744 
745  controlPoints() += facesDisplacementDir()*deltaH;
746  }
747 }
748 
749 
750 void Foam::interfaceTrackingFvMesh::smoothFreeSurfaceMesh()
751 {
752  Info<< "Smoothing free surface mesh" << endl;
753 
754  controlPoints() = aMesh().areaCentres().internalField();
755 
756  pointField displacement(pointDisplacement());
757 
758  const faceList& faces = aMesh().faces();
759  const pointField& points = aMesh().points();
760 
761  pointField newPoints(points + displacement);
762 
763  scalarField sweptVol(faces.size(), Zero);
764  forAll(faces, faceI)
765  {
766  sweptVol[faceI] = -faces[faceI].sweptVol(points, newPoints);
767  }
768 
769  vectorField faceArea(faces.size(), Zero);
770  forAll(faceArea, faceI)
771  {
772  faceArea[faceI] = faces[faceI].unitNormal(newPoints);
773  }
774 
775  scalarField deltaHf
776  (
777  sweptVol/(faceArea & facesDisplacementDir())
778  );
779 
780  for (const word& patchName : fixedFreeSurfacePatches_)
781  {
782  label fixedPatchID = aMesh().boundary().findPatchID(patchName);
783 
784  if (fixedPatchID == -1)
785  {
786  FatalError
787  << "Wrong faPatch name fixedFreeSurfacePatches list"
788  << " defined in the dynamicMeshDict dictionary"
789  << abort(FatalError);
790  }
791 
792  const labelList& eFaces =
793  aMesh().boundary()[fixedPatchID].edgeFaces();
794 
795  forAll(eFaces, edgeI)
796  {
797  deltaHf[eFaces[edgeI]] *= 2.0;
798  }
799  }
800 
801  controlPoints() += facesDisplacementDir()*deltaHf;
802 
803  displacement = pointDisplacement();
804 
805  velocityMotionSolver& vMotion =
806  refCast<velocityMotionSolver>
807  (
808  const_cast<motionSolver&>(motion())
809  );
810 
811  pointVectorField& pointMotionU = vMotion.pointMotionU();
812  pointMotionU.primitiveFieldRef() = Zero;
813 
814  fixedValuePointPatchVectorField& fsPatchPointMeshU =
815  refCast<fixedValuePointPatchVectorField>
816  (
817  const_cast<pointPatchVectorField&>
818  (
819  pointMotionU.boundaryField()[fsPatchIndex()]
820  )
821  );
822 
823  fsPatchPointMeshU == displacement/mesh().time().deltaTValue();
824 
826 }
827 
828 
829 void Foam::interfaceTrackingFvMesh::updateSurfaceFlux()
830 {
831  Phis() = fac::interpolate(Us()) & aMesh().Le();
832 }
833 
834 
835 void Foam::interfaceTrackingFvMesh::updateSurfactantConcentration()
836 {
837  if (!pureFreeSurface())
838  {
839  Info<< "Correct surfactant concentration" << endl << flush;
840 
841  updateSurfaceFlux();
842 
843  // Crate and solve the surfactanta transport equation
844  faScalarMatrix CsEqn
845  (
846  fam::ddt(surfactantConcentration())
847  + fam::div(Phis(), surfactantConcentration())
849  (
850  surfactant().diffusion(),
851  surfactantConcentration()
852  )
853  );
854 
855  if (surfactant().soluble())
856  {
857  #include "solveBulkSurfactant.H"
858 
860  (
861  IOobject
862  (
863  "Cb",
864  aMesh().time().timeName(),
865  aMesh().thisDb(),
868  ),
869  aMesh(),
872  );
873 
874  Cb.ref().field() =
875  bulkSurfactantConcentration().boundaryField()[fsPatchIndex()];
876  Cb.correctBoundaryConditions();
877 
878  CsEqn +=
879  fam::Sp
880  (
881  surfactant().adsorptionCoeff()*Cb
882  + surfactant().adsorptionCoeff()
883  *surfactant().desorptionCoeff(),
884  surfactantConcentration()
885  )
886  - surfactant().adsorptionCoeff()
887  *Cb*surfactant().saturatedConc();
888  }
889 
890  CsEqn.solve();
891 
892  // Info<< "Correct surface tension" << endl;
893 
894  surfaceTension() =
895  sigma() + surfactant().dSigma(surfactantConcentration())/rho_;
896 
897  if (neg(min(surfaceTension().internalField().field())))
898  {
900  << "Surface tension is negative"
901  << abort(FatalError);
902  }
903  }
904 }
905 
906 
907 Foam::vector Foam::interfaceTrackingFvMesh::totalPressureForce() const
908 {
909  const scalarField& S = aMesh().S();
910 
911  const vectorField& n = aMesh().faceAreaNormals().internalField();
912 
913  const scalarField& P = p().boundaryField()[fsPatchIndex()];
914 
915  vectorField pressureForces(S*P*n);
916 
917  return gSum(pressureForces);
918 }
919 
920 
921 Foam::vector Foam::interfaceTrackingFvMesh::totalViscousForce() const
922 {
923  const auto& turbulence =
924  mesh().lookupObject<turbulenceModel>("turbulenceProperties");
925 
926  scalarField nu(turbulence.nuEff(fsPatchIndex()));
927 
928  // const singlePhaseTransportModel& properties =
929  // mesh().lookupObject<singlePhaseTransportModel>
930  // (
931  // "transportProperties"
932  // );
933 
934  // dimensionedScalar nu("nu", properties);
935 
936  const scalarField& S = aMesh().S();
937  const vectorField& n = aMesh().faceAreaNormals().internalField();
938 
939  vectorField nGradU
940  (
941  U().boundaryField()[fsPatchIndex()].snGrad()
942  );
943 
944  vectorField viscousForces
945  (
946  - nu*S
947  *(
948  nGradU
949  + (fac::grad(Us())().internalField()&n)
950  - (n*fac::div(Us())().internalField())
951  )
952  );
953 
954  return gSum(viscousForces);
955 }
956 
957 
958 Foam::vector Foam::interfaceTrackingFvMesh::totalSurfaceTensionForce() const
959 {
960  const scalarField& S = aMesh().S();
961 
962  const vectorField& n = aMesh().faceAreaNormals().internalField();
963 
964  const scalarField& K = aMesh().faceCurvatures().internalField();
965 
966  vectorField surfTensionForces(n.size(), Zero);
967 
968  if (pureFreeSurface())
969  {
970  surfTensionForces =
971  S*sigma().value()
973  (
974  aMesh().Le()*aMesh().edgeLengthCorrection()
975  )().internalField();
976  }
977  else
978  {
979  surfTensionForces = surfaceTension().internalField().field()*K*S*n;
980  }
981 
982  return gSum(surfTensionForces);
983 }
984 
985 
986 Foam::scalar Foam::interfaceTrackingFvMesh::maxCourantNumber()
987 {
988  scalar CoNum = 0;
989 
990  if (pureFreeSurface())
991  {
992  const scalarField& dE = aMesh().lPN();
993 
994  CoNum = gMax
995  (
996  mesh().time().deltaTValue()/
997  sqrt
998  (
999  Foam::pow(dE, 3.0)/2.0/M_PI/(sigma().value() + SMALL)
1000  )
1001  );
1002  }
1003  else
1004  {
1005  scalarField sigmaE
1006  (
1007  linearEdgeInterpolate(surfaceTension())().internalField().field()
1008  + SMALL
1009  );
1010 
1011  const scalarField& dE = aMesh().lPN();
1012 
1013  CoNum = gMax
1014  (
1015  mesh().time().deltaTValue()/
1016  sqrt
1017  (
1018  Foam::pow(dE, 3.0)/2.0/M_PI/sigmaE
1019  )
1020  );
1021  }
1022 
1023  return CoNum;
1024 }
1025 
1026 
1027 void Foam::interfaceTrackingFvMesh::updateProperties()
1028 {
1029  const singlePhaseTransportModel& properties =
1031  (
1032  "transportProperties"
1033  );
1034 
1035  rho_ = dimensionedScalar("rho", properties);
1036 
1037  sigma0_ = dimensionedScalar("sigma", properties)/rho_;
1038 }
1039 
1040 
1041 void Foam::interfaceTrackingFvMesh::correctPointDisplacement
1042 (
1043  const scalarField& sweptVolCorr,
1044  vectorField& displacement
1045 )
1046 {
1047  const labelListList& pFaces =
1048  aMesh().patch().pointFaces();
1049 
1050  const faceList& faces =
1051  aMesh().patch().localFaces();
1052 
1053  const pointField& points =
1054  aMesh().patch().localPoints();
1055 
1056  for (const word& patchName : fixedFreeSurfacePatches_)
1057  {
1058  label fixedPatchID = aMesh().boundary().findPatchID(patchName);
1059 
1060  const labelList& pLabels =
1061  aMesh().boundary()[fixedPatchID].pointLabels();
1062 
1063  const labelList& eFaces =
1064  aMesh().boundary()[fixedPatchID].edgeFaces();
1065 
1067 
1068  forAll(eFaces, edgeI)
1069  {
1070  label curFace = eFaces[edgeI];
1071 
1072  const labelList& curPoints = faces[curFace];
1073 
1074  forAll(curPoints, pointI)
1075  {
1076  label curPoint = curPoints[pointI];
1077  label index = pLabels.find(curPoint);
1078 
1079  if (index == -1)
1080  {
1081  pointSet.insert(curPoint);
1082  }
1083  }
1084  }
1085 
1086  labelList corrPoints = pointSet.toc();
1087 
1088  labelListList corrPointFaces(corrPoints.size());
1089 
1090  forAll(corrPoints, pointI)
1091  {
1092  label curPoint = corrPoints[pointI];
1093 
1095 
1096  forAll(pFaces[curPoint], faceI)
1097  {
1098  label curFace = pFaces[curPoint][faceI];
1099 
1100  label index = eFaces.find(curFace);
1101 
1102  if (index != -1)
1103  {
1104  faceSet.insert(curFace);
1105  }
1106  }
1107 
1108  corrPointFaces[pointI] = faceSet.toc();
1109  }
1110 
1111  forAll(corrPoints, pointI)
1112  {
1113  label curPoint = corrPoints[pointI];
1114 
1115  scalar curDisp = 0;
1116 
1117  const labelList& curPointFaces = corrPointFaces[pointI];
1118 
1119  forAll(curPointFaces, faceI)
1120  {
1121  const face& curFace = faces[curPointFaces[faceI]];
1122 
1123  label ptInFace = curFace.which(curPoint);
1124  label next = curFace.nextLabel(ptInFace);
1125  label prev = curFace.prevLabel(ptInFace);
1126 
1127  vector a = points[next] - points[curPoint];
1128  vector b = points[prev] - points[curPoint];
1129  const vector& c = pointsDisplacementDir()[curPoint];
1130 
1131  curDisp += 2*sweptVolCorr[curPointFaces[faceI]]/((a^b)&c);
1132  }
1133 
1134  curDisp /= curPointFaces.size();
1135 
1136  displacement[curPoint] =
1137  curDisp*pointsDisplacementDir()[curPoint];
1138  }
1139  }
1140 
1141 
1142  for (const word& patchName : nonReflectingFreeSurfacePatches_)
1143  {
1144  label nonReflectingPatchID =
1145  aMesh().boundary().findPatchID(patchName);
1146 
1147  const labelList& pLabels =
1148  aMesh().boundary()[nonReflectingPatchID].pointLabels();
1149 
1150  const labelList& eFaces =
1151  aMesh().boundary()[nonReflectingPatchID].edgeFaces();
1152 
1153  labelList corrPoints = pLabels;
1154 
1155  labelListList corrPointFaces(corrPoints.size());
1156 
1157  forAll(corrPoints, pointI)
1158  {
1159  label curPoint = corrPoints[pointI];
1160 
1162 
1163  forAll(pFaces[curPoint], faceI)
1164  {
1165  label curFace = pFaces[curPoint][faceI];
1166 
1167  label index = eFaces.find(curFace);
1168 
1169  if (index != -1)
1170  {
1171  faceSet.insert(curFace);
1172  }
1173  }
1174 
1175  corrPointFaces[pointI] = faceSet.toc();
1176  }
1177 
1178 
1179  forAll(corrPoints, pointI)
1180  {
1181  label curPoint = corrPoints[pointI];
1182 
1183  scalar curDisp = 0;
1184 
1185  const labelList& curPointFaces = corrPointFaces[pointI];
1186 
1187  forAll(curPointFaces, faceI)
1188  {
1189  const face& curFace = faces[curPointFaces[faceI]];
1190 
1191  label ptInFace = curFace.which(curPoint);
1192  label next = curFace.nextLabel(ptInFace);
1193  label prev = curFace.prevLabel(ptInFace);
1194 
1195  label p0 = -1;
1196  label p1 = -1;
1197  label p2 = -1;
1198 
1199  if (corrPoints.find(next) == -1)
1200  {
1201  p0 = curPoint;
1202  p1 = next;
1203  p2 = curFace.nextLabel(curFace.which(next));
1204  }
1205  else
1206  {
1207  p0 = curFace.prevLabel(curFace.which(prev));
1208  p1 = prev;
1209  p2 = curPoint;
1210  }
1211 
1212  vector a0 = points[p1] - points[p0];
1213  vector b0 = points[p2] - points[p1];
1214  vector c0 = displacement[p1];
1215 
1216  scalar V0 = mag((a0^b0)&c0)/2;
1217 
1218  scalar DV = sweptVolCorr[curPointFaces[faceI]] - V0;
1219 
1220  if (corrPoints.find(prev) != -1)
1221  {
1222  vector a = points[curPoint] - points[prev];
1223  vector b =
1224  (points[next] + displacement[next])
1225  - points[curPoint];
1226  const vector& c = pointsDisplacementDir()[curPoint];
1227 
1228  curDisp += 2*DV/((a^b)&c);
1229  }
1230  else
1231  {
1232  vector a = points[curPoint]
1233  - (points[prev] + displacement[prev]);
1234  vector b = points[next] - points[curPoint];
1235  const vector& c = pointsDisplacementDir()[curPoint];
1236 
1237  curDisp += 2*DV/((a^b)&c);
1238  }
1239  }
1240 
1241  curDisp /= curPointFaces.size();
1242 
1243  displacement[curPoint] =
1244  curDisp*pointsDisplacementDir()[curPoint];
1245  }
1246  }
1247 }
1248 
1249 
1250 void Foam::interfaceTrackingFvMesh::correctContactLinePointNormals()
1251 {
1252  // Correct normals for contact line points
1253  // according to specified contact angle
1254 
1255  vectorField& N =
1256  const_cast<vectorField&>
1257  (
1258  aMesh().pointAreaNormals()
1259  );
1260 
1261  if (contactAnglePtr_ && correctContactLineNormals())
1262  {
1263  Info<< "Correcting contact line normals" << endl;
1264 
1265  vectorField oldPoints(aMesh().nPoints(), Zero);
1266 
1267  const labelList& meshPoints = aMesh().patch().meshPoints();
1268 
1269  forAll(oldPoints, ptI)
1270  {
1271  oldPoints[ptI] =
1272  mesh().oldPoints()[meshPoints[ptI]];
1273  }
1274 
1275 // # include "createTangentField.H"
1276  areaVectorField tangent
1277  (
1278  IOobject
1279  (
1280  "tangent",
1281  aMesh().time().timeName(),
1282  aMesh().thisDb(),
1285  ),
1286  aMesh(),
1288  );
1289 
1290  if (Pstream::parRun())
1291  {
1292  const labelListList& edgeFaces = aMesh().patch().edgeFaces();
1293  const labelListList& pointEdges = aMesh().patch().pointEdges();
1294  const labelListList& pointFaces = aMesh().patch().pointFaces();
1295  const edgeList& edges = aMesh().edges();
1296 
1297  forAll(aMesh().boundary(), patchI)
1298  {
1299  if
1300  (
1301  aMesh().boundary()[patchI].type()
1302  == processorFaPatch::typeName
1303  )
1304  {
1305  const processorFaPatch& procPatch =
1306  refCast<const processorFaPatch>
1307  (
1308  aMesh().boundary()[patchI]
1309  );
1310 
1311  const labelList& patchPointLabels =
1312  procPatch.pointLabels();
1313 
1314  forAll(patchPointLabels, pointI)
1315  {
1316  label curPoint = patchPointLabels[pointI];
1317 
1318  // Check if processor point is boundary point
1319 
1320  label patchID = -1;
1321  label edgeID = -1;
1322 
1323  const labelList& curPointEdges = pointEdges[curPoint];
1324 
1325  forAll(curPointEdges, edgeI)
1326  {
1327  label curEdge = curPointEdges[edgeI];
1328 
1329  if (edgeFaces[curEdge].size() == 1)
1330  {
1331  forAll(aMesh().boundary(), pI)
1332  {
1333  const labelList& curEdges =
1334  aMesh().boundary()[pI];
1335 
1336  label index = curEdges.find(curEdge);
1337 
1338  if (index != -1)
1339  {
1340  if
1341  (
1342  aMesh().boundary()[pI].type()
1343  != processorFaPatch::typeName
1344  )
1345  {
1346  patchID = pI;
1347  edgeID = index;
1348  break;
1349  }
1350  }
1351  }
1352  }
1353  }
1354 
1355  if (patchID != -1)
1356  {
1357  label curEdge =
1358  aMesh().boundary()[patchID].start() + edgeID;
1359 
1360  vector t = edges[curEdge].vec(oldPoints);
1361  t /= mag(t) + SMALL;
1362 
1363  const labelList& curPointFaces =
1364  pointFaces[curPoint];
1365 
1366  forAll(curPointFaces, fI)
1367  {
1368  tangent.ref().field()[curPointFaces[fI]] = t;
1369  }
1370  }
1371  }
1372  }
1373  }
1374 
1375  tangent.correctBoundaryConditions();
1376  }
1377 
1378  forAll(aMesh().boundary(), patchI)
1379  {
1380  label ngbPolyPatchID =
1381  aMesh().boundary()[patchI].ngbPolyPatchIndex();
1382 
1383  if (ngbPolyPatchID != -1)
1384  {
1385  if
1386  (
1387  mesh().boundary()[ngbPolyPatchID].type()
1388  == wallFvPatch::typeName
1389  )
1390  {
1391  const scalar rotAngle = degToRad
1392  (
1393  gAverage
1394  (
1395  90
1396  - contactAnglePtr_->boundaryField()[patchI]
1397  )
1398  );
1399 
1400  vectorField ngbN
1401  (
1402  aMesh().boundary()[patchI].ngbPolyPatchPointNormals()
1403  );
1404 
1405  const labelList& patchPoints =
1406  aMesh().boundary()[patchI].pointLabels();
1407 
1408  vectorField pN(N, patchPoints);
1409 
1410  vectorField rotationAxis(ngbN^pN);
1411  rotationAxis /= mag(rotationAxis) + SMALL;
1412 
1413 
1414  // Calc rotation axis using edge vectors
1415 
1416  const edgeList& edges = aMesh().edges();
1417 
1418  const labelListList& pointEdges =
1419  aMesh().boundary()[patchI].pointEdges();
1420 
1421  forAll(pointEdges, pointI)
1422  {
1423  vector rotAx = Zero;
1424 
1425  forAll(pointEdges[pointI], eI)
1426  {
1427  label curEdge =
1428  aMesh().boundary()[patchI].start()
1429  + pointEdges[pointI][eI];
1430 
1431  vector e = edges[curEdge].vec(oldPoints);
1432 
1433  e *= (e&rotationAxis[pointI])
1434  /mag(e&rotationAxis[pointI]);
1435 
1436  e /= mag(e) + SMALL;
1437 
1438  rotAx += e;
1439  }
1440 
1441  if (pointEdges[pointI].size() == 1)
1442  {
1443  label curPoint = patchPoints[pointI];
1444 
1445  const labelListList& ptEdges =
1446  aMesh().patch().pointEdges();
1447  const labelList& curPointEdges =
1448  ptEdges[curPoint];
1449 
1450  label procPatchID = -1;
1451  label edgeID = -1;
1452 
1453  const labelListList& edgeFaces =
1454  aMesh().patch().edgeFaces();
1455 
1456  forAll(curPointEdges, edgeI)
1457  {
1458  label curEdge = curPointEdges[edgeI];
1459 
1460  if (edgeFaces[curEdge].size() == 1)
1461  {
1462  forAll(aMesh().boundary(), pI)
1463  {
1464  const labelList& curEdges =
1465  aMesh().boundary()[pI];
1466 
1467  label index =
1468  curEdges.find(curEdge);
1469 
1470  if (index != -1)
1471  {
1472  if
1473  (
1474  aMesh().boundary()[pI].type()
1475  == processorFaPatch::typeName
1476  )
1477  {
1478  procPatchID = pI;
1479  edgeID = index;
1480  break;
1481  }
1482  }
1483  }
1484  }
1485  }
1486 
1487  if (procPatchID != -1)
1488  {
1489  vector t =
1490  tangent.boundaryField()[procPatchID]
1491  .patchNeighbourField()()[edgeID];
1492 
1493  t *= (t&rotationAxis[pointI])
1494  /(mag(t&rotationAxis[pointI]) + SMALL);
1495 
1496  t /= mag(t) + SMALL;
1497 
1498  rotAx += t;
1499  }
1500  }
1501 
1502  rotationAxis[pointI] = rotAx/(mag(rotAx) + SMALL);
1503  }
1504 
1505  // Rodrigues' rotation formula
1506  ngbN = ngbN*cos(rotAngle)
1507  + rotationAxis*(rotationAxis & ngbN)*(1 - cos(rotAngle))
1508  + (rotationAxis^ngbN)*sin(rotAngle);
1509 
1510  // Info<< aMesh().boundary()[patchI].name() << endl;
1511  forAll(patchPoints, pointI)
1512  {
1513  N[patchPoints[pointI]] -=
1514  ngbN[pointI]*(ngbN[pointI]&N[patchPoints[pointI]]);
1515 
1516  N[patchPoints[pointI]] /=
1517  mag(N[patchPoints[pointI]]) + SMALL;
1518 
1519  // Info<< N[patchPoints[pointI]] << endl;
1520  }
1521  }
1522  }
1523  }
1524  }
1525 }
1526 
1527 
1528 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1529 
1530 Foam::interfaceTrackingFvMesh::interfaceTrackingFvMesh
1531 (
1532  const IOobject& io,
1533  const bool doInit
1534 )
1535 :
1536  dynamicMotionSolverFvMesh(io, doInit),
1537  aMeshPtr_(nullptr),
1538  fsPatchIndex_(-1),
1539  fixedFreeSurfacePatches_(),
1540  nonReflectingFreeSurfacePatches_(),
1541  pointNormalsCorrectionPatches_(),
1542  normalMotionDir_(false),
1543  motionDir_(Zero),
1544  smoothing_(false),
1545  pureFreeSurface_(true),
1546  rigidFreeSurface_(false),
1547  correctContactLineNormals_(false),
1548  sigma0_("zero", dimForce/dimLength/dimDensity, Zero),
1549  rho_("one", dimDensity, 1.0),
1550  timeIndex_(-1),
1551  UsPtr_(nullptr),
1552  controlPointsPtr_(nullptr),
1553  motionPointsMaskPtr_(nullptr),
1554  pointsDisplacementDirPtr_(nullptr),
1555  facesDisplacementDirPtr_(nullptr),
1556  fsNetPhiPtr_(nullptr),
1557  phisPtr_(nullptr),
1558  surfactConcPtr_(nullptr),
1559  bulkSurfactConcPtr_(nullptr),
1560  surfaceTensionPtr_(nullptr),
1561  surfactantPtr_(nullptr),
1562  contactAnglePtr_(nullptr)
1563 {
1564  if (doInit)
1565  {
1566  init(false); // do not initialise lower levels
1567  }
1568 }
1569 
1570 /*
1571 Foam::interfaceTrackingFvMesh::interfaceTrackingFvMesh
1572 (
1573  const IOobject& io,
1574  pointField&& points,
1575  faceList&& faces,
1576  labelList&& allOwner,
1577  labelList&& allNeighbour,
1578  const bool syncPar
1579 )
1580 :
1581  dynamicMotionSolverFvMesh
1582  (
1583  io,
1584  std::move(points),
1585  std::move(faces),
1586  std::move(allOwner),
1587  std::move(allNeighbour),
1588  syncPar
1589  ),
1590  aMeshPtr_(new faMesh(*this)),
1591  fsPatchIndex_(-1),
1592  fixedFreeSurfacePatches_(),
1593  nonReflectingFreeSurfacePatches_(),
1594  pointNormalsCorrectionPatches_(),
1595  normalMotionDir_(false),
1596  motionDir_(Zero),
1597  smoothing_(false),
1598  pureFreeSurface_(true),
1599  sigma0_("zero", dimForce/dimLength/dimDensity, Zero),
1600  rho_("one", dimDensity, 1.0),
1601  timeIndex_(-1),
1602  UsPtr_(nullptr),
1603  controlPointsPtr_(nullptr),
1604  motionPointsMaskPtr_(nullptr),
1605  pointsDisplacementDirPtr_(nullptr),
1606  facesDisplacementDirPtr_(nullptr),
1607  fsNetPhiPtr_(nullptr),
1608  phisPtr_(nullptr),
1609  surfactConcPtr_(nullptr),
1610  bulkSurfactConcPtr_(nullptr),
1611  surfaceTensionPtr_(nullptr),
1612  surfactantPtr_(nullptr),
1613  contactAnglePtr_(nullptr)
1614 {}
1615 */
1616 
1617 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1618 
1620 {
1621  deleteDemandDrivenData(UsPtr_);
1622  deleteDemandDrivenData(controlPointsPtr_);
1623  deleteDemandDrivenData(motionPointsMaskPtr_);
1624  deleteDemandDrivenData(pointsDisplacementDirPtr_);
1625  deleteDemandDrivenData(facesDisplacementDirPtr_);
1626  deleteDemandDrivenData(fsNetPhiPtr_);
1627  deleteDemandDrivenData(phisPtr_);
1628  deleteDemandDrivenData(surfactConcPtr_);
1629  deleteDemandDrivenData(bulkSurfactConcPtr_);
1630  deleteDemandDrivenData(surfaceTensionPtr_);
1631  deleteDemandDrivenData(surfactantPtr_);
1632  deleteDemandDrivenData(contactAnglePtr_);
1633 }
1634 
1635 
1636 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1637 
1638 bool Foam::interfaceTrackingFvMesh::init(const bool doInit)
1639 {
1640  if (doInit)
1641  {
1643  }
1644 
1645  aMeshPtr_.reset(new faMesh(*this));
1646 
1647  // Set motion-based data
1648  fixedFreeSurfacePatches_ =
1649  motion().get<wordList>("fixedFreeSurfacePatches");
1650 
1651  pointNormalsCorrectionPatches_ =
1652  motion().get<wordList>("pointNormalsCorrectionPatches");
1653 
1654  normalMotionDir_ = motion().get<bool>("normalMotionDir");
1655  smoothing_ = motion().getOrDefault("smoothing", false);
1656  pureFreeSurface_ = motion().getOrDefault("pureFreeSurface", true);
1658  initializeData();
1659 
1660  return true;
1661 }
1662 
1663 
1665 {
1666  if (!UsPtr_)
1667  {
1668  makeUs();
1669  }
1670 
1671  return *UsPtr_;
1672 }
1673 
1674 
1676 {
1677  if (!UsPtr_)
1678  {
1679  makeUs();
1680  }
1681 
1682  return *UsPtr_;
1683 }
1684 
1685 
1687 {
1688  if (!fsNetPhiPtr_)
1689  {
1690  makeFsNetPhi();
1691  }
1692 
1693  return *fsNetPhiPtr_;
1694 }
1695 
1696 
1698 {
1699  if (!fsNetPhiPtr_)
1700  {
1701  makeFsNetPhi();
1702  }
1703 
1704  return *fsNetPhiPtr_;
1705 }
1706 
1707 
1709 {
1710  forAll(Us().boundaryField(), patchI)
1711  {
1712  if
1713  (
1714  Us().boundaryField()[patchI].type()
1715  == calculatedFaPatchVectorField::typeName
1716  )
1717  {
1718  vectorField& pUs = Us().boundaryFieldRef()[patchI];
1719 
1720  pUs = Us().boundaryField()[patchI].patchInternalField();
1721 
1722  label ngbPolyPatchID =
1723  aMesh().boundary()[patchI].ngbPolyPatchIndex();
1724 
1725  if (ngbPolyPatchID != -1)
1726  {
1727  if
1728  (
1729  (
1730  U().boundaryField()[ngbPolyPatchID].type()
1731  == slipFvPatchVectorField::typeName
1732  )
1733  ||
1734  (
1735  U().boundaryField()[ngbPolyPatchID].type()
1736  == symmetryFvPatchVectorField::typeName
1737  )
1738  )
1739  {
1740  vectorField N
1741  (
1742  aMesh().boundary()[patchI].ngbPolyPatchFaceNormals()
1743  );
1744 
1745  pUs -= N*(N&pUs);
1746  }
1747  }
1748  }
1749  }
1750 
1751  Us().correctBoundaryConditions();
1752 }
1753 
1754 
1756 {
1757  // Info<< "Update Us" << endl;
1758 
1759  Us().ref().field() = U().boundaryField()[fsPatchIndex()];
1760 
1761  // // Correct normal component of free-surface velocity
1762  // const vectorField& nA = aMesh().faceAreaNormals().internalField();
1763  // vectorField UnFs = nA*phi().boundaryField()[fsPatchIndex()]
1764  // /mesh().boundary()[fsPatchIndex()].magSf();
1765  // Us().ref().field() += UnFs - nA*(nA&Us().internalField());
1766 
1767  correctUsBoundaryConditions();
1768 }
1769 
1772 {
1773  return *getObjectPtr<const volVectorField>("U");
1774 }
1775 
1778 {
1779  return *getObjectPtr<const volScalarField>("p");
1780 }
1781 
1782 
1784 {
1785  return *getObjectPtr<const surfaceScalarField>("phi");
1786 }
1787 
1788 
1791 {
1792  auto tSnGradU = tmp<vectorField>::New(aMesh().nFaces(), Zero);
1793  auto& SnGradU = tSnGradU.ref();
1794 
1795  const vectorField& nA = aMesh().faceAreaNormals().internalField();
1796 
1797  areaScalarField divUs
1798  (
1799  fac::div(Us())
1800  - aMesh().faceCurvatures()*(aMesh().faceAreaNormals()&Us())
1801  );
1802 
1803  areaTensorField gradUs(fac::grad(Us()));
1804 
1805  // Remove component of gradient normal to surface (area)
1806  const areaVectorField& n = aMesh().faceAreaNormals();
1807  gradUs -= n*(n & gradUs);
1808  gradUs.correctBoundaryConditions();
1809 
1810  const turbulenceModel& turbulence =
1811  mesh().lookupObject<turbulenceModel>("turbulenceProperties");
1812 
1813  scalarField nu(turbulence.nuEff(fsPatchIndex()));
1814 
1815  vectorField tangentialSurfaceTensionForce(nA.size(), Zero);
1816 
1817  if (!pureFreeSurface() && max(nu) > SMALL)
1818  {
1819  tangentialSurfaceTensionForce =
1820  surfaceTensionGrad()().internalField();
1821  }
1822 
1823  SnGradU =
1824  tangentialSurfaceTensionForce/(nu + SMALL)
1825  - nA*divUs.internalField()
1826  - (gradUs.internalField()&nA);
1827 
1828  return tSnGradU;
1829 }
1830 
1831 
1834 {
1835  auto tSnGradUn = tmp<scalarField>::New(aMesh().nFaces(), Zero);
1836  auto& SnGradUn = tSnGradUn.ref();
1837 
1838  areaScalarField divUs
1839  (
1840  fac::div(Us())
1841  - aMesh().faceCurvatures()*(aMesh().faceAreaNormals()&Us())
1842  );
1843 
1844  SnGradUn = -divUs.internalField();
1845 
1846  return tSnGradUn;
1847 }
1848 
1849 
1852 {
1853  auto tPressureJump = tmp<scalarField>::New(aMesh().nFaces(), Zero);
1854  auto& pressureJump = tPressureJump.ref();
1855 
1856  const scalarField& K = aMesh().faceCurvatures().internalField();
1857 
1859  meshObjects::gravity::New(mesh().time());
1860 
1861  const turbulenceModel& turbulence =
1862  mesh().lookupObject<turbulenceModel>("turbulenceProperties");
1863 
1864  scalarField nu(turbulence.nuEff(fsPatchIndex()));
1865 
1866  pressureJump =
1867  - (g.value() & mesh().Cf().boundaryField()[fsPatchIndex()])
1868  + 2.0*nu*freeSurfaceSnGradUn();
1869 
1870  if (pureFreeSurface())
1871  {
1872  pressureJump -= sigma().value()*K;
1873  }
1874  else
1875  {
1876  pressureJump -= surfaceTension().internalField()*K;
1877  }
1878 
1879  return tPressureJump;
1880 }
1881 
1882 
1884 {
1885  if (!controlPointsPtr_)
1886  {
1887  makeControlPoints();
1888  }
1889 
1890  return *controlPointsPtr_;
1891 }
1892 
1893 
1895 {
1896  if (!motionPointsMaskPtr_)
1897  {
1898  makeMotionPointsMask();
1899  }
1900 
1901  return *motionPointsMaskPtr_;
1902 }
1903 
1904 
1906 {
1907  if (!pointsDisplacementDirPtr_)
1908  {
1909  makeDirections();
1910  }
1911 
1912  return *pointsDisplacementDirPtr_;
1913 }
1914 
1915 
1917 {
1918  if (!facesDisplacementDirPtr_)
1919  {
1920  makeDirections();
1921  }
1922 
1923  return *facesDisplacementDirPtr_;
1924 }
1925 
1926 
1928 {
1929  if (!phisPtr_)
1930  {
1931  makePhis();
1932  }
1933 
1934  return *phisPtr_;
1935 }
1936 
1939 {
1940  if (!surfactConcPtr_)
1941  {
1942  makeSurfactConc();
1943  }
1944 
1945  return *surfactConcPtr_;
1946 }
1947 
1948 
1949 const Foam::areaScalarField&
1951 {
1952  if (!surfactConcPtr_)
1953  {
1954  makeSurfactConc();
1955  }
1956 
1957  return *surfactConcPtr_;
1958 }
1959 
1960 
1963 {
1964  if (!bulkSurfactConcPtr_)
1965  {
1966  makeBulkSurfactConc();
1967  }
1968 
1969  return *bulkSurfactConcPtr_;
1970 }
1971 
1972 
1973 const Foam::volScalarField&
1975 {
1976  if (!bulkSurfactConcPtr_)
1977  {
1978  makeBulkSurfactConc();
1979  }
1980 
1981  return *bulkSurfactConcPtr_;
1982 }
1983 
1984 
1987 {
1988  if (!surfaceTensionPtr_)
1989  {
1990  makeSurfaceTension();
1991  }
1992 
1993  return *surfaceTensionPtr_;
1994 }
1995 
1996 
1997 const Foam::areaScalarField&
1999 {
2000  if (!surfaceTensionPtr_)
2001  {
2002  makeSurfaceTension();
2003  }
2004 
2005  return *surfaceTensionPtr_;
2006 }
2007 
2008 
2011 {
2012  if (!surfactantPtr_)
2013  {
2014  makeSurfactant();
2015  }
2016 
2017  return *surfactantPtr_;
2018 }
2019 
2020 
2023 {
2024  auto tgrad = tmp<areaVectorField>::New
2025  (
2026  IOobject
2027  (
2028  "surfaceTensionGrad",
2029  aMesh().time().timeName(),
2030  aMesh().thisDb(),
2033  ),
2034  fac::grad(surfaceTension())
2035  // (-fac::grad(surfactantConcentration()/rho_)*
2036  // surfactant().surfactR()*surfactant().surfactT()/
2037  // (1.0 - surfactantConcentration()/
2038  // surfactant().surfactSaturatedConc()))()
2039  );
2040  auto& grad = tgrad.ref();
2041 
2042  // Remove component of gradient normal to surface (area)
2043  const areaVectorField& n = aMesh().faceAreaNormals();
2044  grad -= n*(n & grad);
2045  grad.correctBoundaryConditions();
2046 
2047  return tgrad;
2048 }
2049 
2050 
2052 {
2053  if (timeIndex_ != mesh().time().timeIndex())
2054  {
2055  if (smoothing_ && !rigidFreeSurface_)
2056  {
2057  smoothFreeSurfaceMesh();
2058  clearControlPoints();
2059  }
2060 
2061  updateDisplacementDirections();
2062 
2063  updateProperties();
2064 
2065  Info<< "Maximal capillary Courant number: "
2066  << maxCourantNumber() << endl;
2067 
2068  const scalarField& K = aMesh().faceCurvatures().internalField();
2069 
2070  Info<< "Free surface curvature: min = " << gMin(K)
2071  << ", max = " << gMax(K) << ", average = " << gAverage(K) << nl;
2072 
2073  timeIndex_ = mesh().time().timeIndex();
2074  }
2075 
2076  if (!rigidFreeSurface_)
2077  {
2078  // This is currently relaltive flux
2079  scalarField sweptVolCorr =
2080  phi().boundaryField()[fsPatchIndex()];
2081 
2082  // Info<< "Free surface flux: sum local = "
2083  // << gSum(mag(sweptVolCorr))
2084  // << ", global = " << gSum(sweptVolCorr) << endl;
2085 
2086  // if (mesh().moving())
2087  // {
2088  // sweptVolCorr -=
2089  // fvc::meshPhi(U())().boundaryField()[fsPatchIndex()];
2090  // }
2091 
2092  Info<< "Free surface continuity error : sum local = "
2093  << gSum(mag(sweptVolCorr)) << ", global = " << gSum(sweptVolCorr)
2094  << endl;
2095 
2096  // For postprocessing
2097  fsNetPhi().ref().field() = sweptVolCorr;
2098 
2099  word ddtScheme
2100  (
2101  mesh().ddtScheme
2102  (
2103  "ddt(" + U().name() + ')'
2104  )
2105  );
2106 
2107  if
2108  (
2109  ddtScheme
2111  )
2112  {
2113  sweptVolCorr *= (1.0/2.0)*mesh().time().deltaTValue();
2114  }
2115  else if
2116  (
2117  ddtScheme
2119  )
2120  {
2121  sweptVolCorr *= mesh().time().deltaTValue();
2122  }
2123  else if
2124  (
2125  ddtScheme
2127  )
2128  {
2129  if (mesh().time().timeIndex() == 1)
2130  {
2131  sweptVolCorr *= mesh().time().deltaTValue();
2132  }
2133  else
2134  {
2135  sweptVolCorr *= (2.0/3.0)*mesh().time().deltaTValue();
2136  }
2137  }
2138  else
2139  {
2141  << "Unsupported temporal differencing scheme : "
2142  << ddtScheme << nl
2143  << abort(FatalError);
2144  }
2145 
2146  const scalarField& Sf = aMesh().S();
2147  const vectorField& Nf = aMesh().faceAreaNormals().internalField();
2148 
2149  scalarField deltaHf
2150  (
2151  sweptVolCorr/(Sf*(Nf & facesDisplacementDir()))
2152  );
2153 
2154  for (const word& patchName : fixedFreeSurfacePatches_)
2155  {
2156  label fixedPatchID =
2157  aMesh().boundary().findPatchID(patchName);
2158 
2159  if (fixedPatchID == -1)
2160  {
2162  << "Wrong faPatch name '" << patchName
2163  << "'in the fixedFreeSurfacePatches list"
2164  << " defined in dynamicMeshDict dictionary"
2165  << abort(FatalError);
2166  }
2167 
2168  const labelList& eFaces =
2169  aMesh().boundary()[fixedPatchID].edgeFaces();
2170 
2171  forAll(eFaces, edgeI)
2172  {
2173  deltaHf[eFaces[edgeI]] *= 2.0;
2174  }
2175  }
2176 
2177  controlPoints() += facesDisplacementDir()*deltaHf;
2178 
2179  pointField displacement(pointDisplacement());
2180  correctPointDisplacement(sweptVolCorr, displacement);
2181 
2182  velocityMotionSolver& vMotion =
2183  refCast<velocityMotionSolver>
2184  (
2185  const_cast<motionSolver&>(motion())
2186  );
2187 
2188  pointVectorField& pointMotionU = vMotion.pointMotionU();
2189  pointMotionU.primitiveFieldRef() = Zero;
2190 
2191  fixedValuePointPatchVectorField& fsPatchPointMeshU =
2192  refCast<fixedValuePointPatchVectorField>
2193  (
2194  const_cast<pointPatchVectorField&>
2195  (
2196  pointMotionU.boundaryField()[fsPatchIndex()]
2197  )
2198  );
2199 
2200  fsPatchPointMeshU == displacement/mesh().time().deltaTValue();
2201 
2203 
2204  correctContactLinePointNormals();
2205  }
2206  else
2207  {
2208  vectorField displacement
2209  (
2210  mesh().boundaryMesh()[fsPatchIndex()].nPoints(),
2211  Zero
2212  );
2213 
2214  velocityMotionSolver& vMotion =
2215  refCast<velocityMotionSolver>
2216  (
2217  const_cast<motionSolver&>(motion())
2218  );
2219 
2220  pointVectorField& pointMotionU = vMotion.pointMotionU();
2221  pointMotionU.primitiveFieldRef() = Zero;
2222 
2223  fixedValuePointPatchVectorField& fsPatchPointMeshU =
2224  refCast<fixedValuePointPatchVectorField>
2225  (
2226  const_cast<pointPatchVectorField&>
2227  (
2228  pointMotionU.boundaryField()[fsPatchIndex()]
2229  )
2230  );
2231 
2232  fsPatchPointMeshU == displacement/mesh().time().deltaTValue();
2233 
2235  }
2236 
2237  updateUs();
2239  updateSurfactantConcentration();
2240 
2241  return true;
2242 }
2243 
2244 
2246 {
2248  (
2249  aMesh().patch(),
2251  mesh().time().timePath()/"freeSurface",
2252  false // serial only
2253  );
2255 }
2256 
2257 
2259 {
2260  // Write control points into VTK
2261  OFstream os
2262  (
2263  mesh().time().timePath()/"freeSurfaceControlPoints.vtk"
2264  );
2265 
2266  Info<< "Writing free surface control points to " << os.name() << nl;
2267 
2268  os << "# vtk DataFile Version 2.0" << nl
2269  << "freeSurfaceControlPoints" << nl
2270  << "ASCII" << nl
2271  << "DATASET POLYDATA" << nl;
2272 
2273  const label nPoints = controlPoints().size();
2274 
2275  os << "POINTS " << nPoints << " float" << nl;
2276  for (const point& p : controlPoints())
2277  {
2278  os << float(p.x()) << ' '
2279  << float(p.y()) << ' '
2280  << float(p.z()) << nl;
2281  }
2282 
2283  os << "VERTICES " << nPoints << ' ' << 2*nPoints << nl;
2284  for (label id = 0; id < nPoints; ++id)
2285  {
2286  os << 1 << ' ' << id << nl;
2287  }
2288 }
2289 
2290 
2291 // ************************************************************************* //
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:116
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)
A set of point labels.
Definition: pointSet.H:47
CGAL::indexedCell< K > Cb
vtk::lineWriter writer(edgeCentres, edgeList::null(), fileName(aMesh.time().globalPath()/"finiteArea-edgesCentres"))
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:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
const surfaceVectorField & Cf() const
Return face centres as surfaceVectorField.
Type gMin(const FieldField< Field, Type > &f)
virtual const fileName & name() const override
Read/write access to the name of the stream.
Definition: OSstream.H:134
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:531
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:1061
An indexed form of CGAL::Triangulation_cell_base_3<K> used to keep track of the Delaunay cells (tets)...
Definition: indexedCell.H:62
label nextLabel(const label i) const
Next vertex on face.
Definition: faceI.H:183
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type get(const label i) const
Return bool value at specified position, always false for out-of-range access.
Definition: UList.H:791
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:232
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.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
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:189
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:72
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:799
const dimensionSet dimVolume(pow3(dimLength))
Definition: dimensionSets.H:58
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:609
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.
areaVectorField & Us()
Return free-surface velocity field.
Us
virtual const pointField & oldPoints() const
Return old points (mesh motion)
Definition: polyMesh.C:1128
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
label which(const label vertex) const
Find local vertex on face for the vertex label, same as find()
Definition: faceI.H:171
label timeIndex() const noexcept
Return the current time index.
Definition: TimeStateI.H:43
GeometricField< scalar, faePatchField, edgeMesh > edgeScalarField
Definition: edgeFieldsFwd.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:173
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 gMax(const FieldField< Field, Type > &f)
OBJstream os(runTime.globalPath()/outputName)
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.
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];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } 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};const 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< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
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)
Template functions to aid in the implementation of demand driven data.
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field values.
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:521
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.
Type gAverage(const FieldField< Field, Type > &f)
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.
void correctBoundaryConditions()
Correct boundary field.
Legacy ASCII, legacyAsciiFormatter.
bool correctPatchPointNormals(const label patchID) const
Whether point normals should be corrected for a patch.
Definition: faMesh.C:1336
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual bool writeGeometry()
Write patch topology.
label n
Field< vector > vectorField
Specialisation of Field<T> for vector.
tmp< areaVectorField > surfaceTensionGrad()
Return surface tension gradient.
The dynamicMotionSolverFvMesh.
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition: HashTable.C:148
void writeVTK() const
Write VTK freeSurface mesh.
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
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.
void deleteDemandDrivenData(DataPtr &dataPtr)
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:180
Foam::label startTime
Request registration (bool: true)
GeometricField< vector, faPatchField, areaMesh > areaVectorField
Definition: areaFieldsFwd.H:76
A primitive field of type <T> with automated input and output.
IOField< vector > vectorIOField
IO for a Field of vector.
Definition: vectorIOField.H:32
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.
GeometricField< scalar, faPatchField, areaMesh > areaScalarField
Definition: areaFieldsFwd.H:72
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127
const dimensionSet dimVelocity