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"
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_ = new 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_ = new 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 controlPointsHeader
299  (
300  "controlPoints",
301  mesh().time().timeName(),
302  mesh(),
304  );
305 
306  if (controlPointsHeader.typeHeaderOk<vectorIOField>())
307  {
308  Info<< "Reading control points" << endl;
309  controlPointsPtr_ =
310  new vectorIOField
311  (
312  IOobject
313  (
314  "controlPoints",
315  mesh().time().timeName(),
316  mesh(),
319  )
320  );
321  }
322  else
323  {
324  Info<< "Creating new control points" << endl;
325  controlPointsPtr_ =
326  new vectorIOField
327  (
328  IOobject
329  (
330  "controlPoints",
331  mesh().time().timeName(),
332  mesh(),
335  ),
336  aMesh().areaCentres().internalField()
337  );
338 
339  initializeControlPointsPosition();
340  }
341 }
342 
343 
344 void Foam::interfaceTrackingFvMesh::makeMotionPointsMask()
345 {
347  << "making motion points mask" << nl;
348 
349  if (motionPointsMaskPtr_)
350  {
352  << "motion points mask already exists"
353  << abort(FatalError);
354  }
355 
356  motionPointsMaskPtr_ = new labelList
357  (
358  mesh().boundaryMesh()[fsPatchIndex()].nPoints(),
359  1
360  );
361 
362  // Mark free surface boundary points
363  // that belong to processor patches
364  forAll(aMesh().boundary(), patchI)
365  {
366  if
367  (
368  aMesh().boundary()[patchI].type()
369  == processorFaPatch::typeName
370  )
371  {
372  const labelList& patchPoints =
373  aMesh().boundary()[patchI].pointLabels();
374 
375  forAll(patchPoints, pointI)
376  {
377  motionPointsMask()[patchPoints[pointI]] = -1;
378  }
379  }
380  }
381 
382  // Mark fixed free surface boundary points
383  for (const word& patchName : fixedFreeSurfacePatches_)
384  {
385  const label fixedPatchID = aMesh().boundary().findPatchID(patchName);
386 
387  if (fixedPatchID == -1)
388  {
390  << "Wrong faPatch name in the fixedFreeSurfacePatches list"
391  << " defined in the dynamicMeshDict dictionary"
392  << abort(FatalError);
393  }
394 
395  const labelList& patchPoints =
396  aMesh().boundary()[fixedPatchID].pointLabels();
397 
398  forAll(patchPoints, pointI)
399  {
400  motionPointsMask()[patchPoints[pointI]] = 0;
401  }
402  }
403 }
404 
405 
406 void Foam::interfaceTrackingFvMesh::makeDirections()
407 {
409  << "make displacement directions for points and control points" << nl;
410 
411  if (pointsDisplacementDirPtr_ || facesDisplacementDirPtr_)
412  {
414  << "points, control points displacement directions already exist"
415  << abort(FatalError);
416  }
417 
418  pointsDisplacementDirPtr_ =
419  new vectorField
420  (
421  mesh().boundaryMesh()[fsPatchIndex()].nPoints(),
422  Zero
423  );
424 
425  facesDisplacementDirPtr_ =
426  new vectorField
427  (
428  mesh().boundaryMesh()[fsPatchIndex()].size(),
429  Zero
430  );
431 
432  if (!normalMotionDir())
433  {
434  if (mag(motionDir_) < SMALL)
435  {
437  << "Zero motion direction"
438  << abort(FatalError);
439  }
440 
441  facesDisplacementDir() = motionDir_;
442  pointsDisplacementDir() = motionDir_;
443  }
444 
445  updateDisplacementDirections();
446 }
447 
448 
449 void Foam::interfaceTrackingFvMesh::makePhis()
450 {
452  << "making free-surface flux" << nl;
453 
454  if (phisPtr_)
455  {
457  << "free-surface flux already exists"
458  << abort(FatalError);
459  }
460 
461  phisPtr_ = new edgeScalarField
462  (
463  IOobject
464  (
465  "phis",
466  aMesh().time().timeName(),
467  aMesh().thisDb(),
470  ),
471  linearEdgeInterpolate(Us()) & aMesh().Le()
472  );
473 }
474 
475 
476 void Foam::interfaceTrackingFvMesh::makeSurfactConc() const
477 {
479  << "making free-surface surfactant concentration field" << nl;
480 
481  if (surfactConcPtr_)
482  {
484  << "free-surface surfactant concentration field already exists"
485  << abort(FatalError);
486  }
487 
488  surfactConcPtr_ = new areaScalarField
489  (
490  IOobject
491  (
492  "Cs",
493  mesh().time().timeName
494  (
495  mesh().time().startTime().value()
496  ),
497  // mesh().time().timeName(),
498  aMesh().thisDb(),
501  ),
502  aMesh()
503  );
504 }
505 
506 
507 void Foam::interfaceTrackingFvMesh::makeBulkSurfactConc() const
508 {
510  << "making volume surfactant concentration field" << nl;
511 
512  if (bulkSurfactConcPtr_)
513  {
515  << "volume surfactant concentration field already exists"
516  << abort(FatalError);
517  }
518 
519  bulkSurfactConcPtr_ = new volScalarField
520  (
521  IOobject
522  (
523  "C",
524  mesh().time().timeName
525  (
526  mesh().time().startTime().value()
527  ),
528  // mesh().time().timeName(),
529  aMesh().thisDb(),
532  ),
533  mesh()
534  );
535  volScalarField& bulkSurfactConc = *bulkSurfactConcPtr_;
536 
537  if (mesh().time().timeIndex()-1 == 0)
538  {
539  // Initialize uniform volume surfactant concentration
540  bulkSurfactConc = surfactant().bulkConc();
541  bulkSurfactConc.correctBoundaryConditions();
542  }
543 }
544 
545 
546 void Foam::interfaceTrackingFvMesh::makeSurfaceTension() const
547 {
549  << "making surface tension field" << nl;
550 
551  if (surfaceTensionPtr_)
552  {
554  << "surface tension field already exists"
555  << abort(FatalError);
556  }
557 
558  surfaceTensionPtr_ = new areaScalarField
559  (
560  IOobject
561  (
562  "surfaceTension",
563  aMesh().time().timeName(),
564  aMesh().thisDb(),
567  ),
568  sigma() + surfactant().dSigma(surfactantConcentration())/rho_
569  );
570 }
571 
572 
573 void Foam::interfaceTrackingFvMesh::makeSurfactant() const
574 {
576  << "making surfactant properties" << nl;
577 
578  if (surfactantPtr_)
579  {
581  << "surfactant properties already exists"
582  << abort(FatalError);
583  }
584 
585  const dictionary& surfactProp =
586  motion().subDict("surfactantProperties");
587 
588  surfactantPtr_ = new surfactantProperties(surfactProp);
589 }
590 
591 
592 void Foam::interfaceTrackingFvMesh::makeContactAngle()
593 {
595  << "making contact angle field" << nl;
596 
597  if (contactAnglePtr_)
598  {
600  << "contact angle already exists"
601  << abort(FatalError);
602  }
603 
604  // Check if contactAngle is defined
605  IOobject contactAngleHeader
606  (
607  "contactAngle",
608  aMesh().time().timeName(),
609  aMesh().thisDb(),
612  );
613 
614  if (contactAngleHeader.typeHeaderOk<areaScalarField>())
615  {
616  Info<< "Reading contact angle field" << endl;
617 
618  contactAnglePtr_ = new areaScalarField(contactAngleHeader, aMesh());
619  }
620 }
621 
622 
623 void Foam::interfaceTrackingFvMesh::updateDisplacementDirections()
624 {
625  if (normalMotionDir())
626  {
627  // Update point displacement direction
628  pointsDisplacementDir() = aMesh().pointAreaNormals();
629 
630  // Correct point displacement direction at contact line
631  forAll(aMesh().boundary(), patchI)
632  {
633  if (contactAnglePtr_)
634  {
635  label ngbPolyPatchID =
636  aMesh().boundary()[patchI].ngbPolyPatchIndex();
637 
638  if (ngbPolyPatchID != -1)
639  {
640  if
641  (
642  mesh().boundary()[ngbPolyPatchID].type()
643  == wallFvPatch::typeName
644  )
645  {
646  labelList patchPoints =
647  aMesh().boundary()[patchI].pointLabels();
648 
649  vectorField N
650  (
651  aMesh().boundary()[patchI]
652  .ngbPolyPatchPointNormals()
653  );
654 
655  forAll(patchPoints, pointI)
656  {
657  pointsDisplacementDir()[patchPoints[pointI]] -=
658  N[pointI]
659  *(
660  N[pointI]
661  & pointsDisplacementDir()[patchPoints[pointI]]
662  );
663 
664  pointsDisplacementDir()[patchPoints[pointI]] /=
665  mag
666  (
667  pointsDisplacementDir()
668  [
669  patchPoints[pointI]
670  ]
671  ) + SMALL;
672  }
673  }
674  }
675  }
676  }
677 
678  // Update face displacement direction
679  facesDisplacementDir() =
680  aMesh().faceAreaNormals().internalField();
681 
682  // Correction of control points position
683  const vectorField& Cf = aMesh().areaCentres().internalField();
684 
685  controlPoints() =
686  facesDisplacementDir()
687  *(facesDisplacementDir()&(controlPoints() - Cf))
688  + Cf;
689  }
690 }
691 
692 
693 void Foam::interfaceTrackingFvMesh::initializeControlPointsPosition()
694 {
695  {
696  const faceList& faces = aMesh().faces();
697  const pointField& points = aMesh().points();
698 
699  pointField displacement(pointDisplacement());
700  scalarField sweptVolCorr(faces.size(), Zero);
701  correctPointDisplacement(sweptVolCorr, displacement);
702 
703  pointField newPoints(points + displacement);
704 
705  scalarField sweptVol(faces.size(), Zero);
706 
707  forAll(faces, faceI)
708  {
709  sweptVol[faceI] = -faces[faceI].sweptVol(points, newPoints);
710  }
711 
712  vectorField faceArea(faces.size(), Zero);
713 
714  forAll(faceArea, faceI)
715  {
716  faceArea[faceI] = faces[faceI].unitNormal(newPoints);
717  }
718 
719  scalarField deltaH = scalarField(aMesh().nFaces(), Zero);
720 
721  forAll(deltaH, faceI)
722  {
723  deltaH[faceI] = sweptVol[faceI]/
724  ((faceArea[faceI] & facesDisplacementDir()[faceI]) + SMALL);
725 
726  if (mag(faceArea[faceI] & facesDisplacementDir()[faceI]) < SMALL)
727  {
728  // Info<< (faceArea[faceI] & facesDisplacementDir()[faceI])
729  // << ", " << faceArea[faceI]
730  // << ", " << facesDisplacementDir()[faceI] << endl;
731 
732  FatalError
733  << "Something is wrong with specified motion direction"
734  << abort(FatalError);
735  }
736  }
737 
738  for (const word& patchName : fixedFreeSurfacePatches_)
739  {
740  label fixedPatchID = aMesh().boundary().findPatchID(patchName);
741 
742  if (fixedPatchID == -1)
743  {
744  FatalError
745  << "Wrong faPatch name in the fixedFreeSurfacePatches list"
746  << " defined in the freeSurfaceProperties dictionary"
747  << abort(FatalError);
748  }
749 
750  const labelList& eFaces =
751  aMesh().boundary()[fixedPatchID].edgeFaces();
752 
753  forAll(eFaces, edgeI)
754  {
755  deltaH[eFaces[edgeI]] *= 2.0;
756  }
757  }
758 
759  controlPoints() += facesDisplacementDir()*deltaH;
760  }
761 }
762 
763 
764 void Foam::interfaceTrackingFvMesh::smoothFreeSurfaceMesh()
765 {
766  Info<< "Smoothing free surface mesh" << endl;
767 
768  controlPoints() = aMesh().areaCentres().internalField();
769 
770  pointField displacement(pointDisplacement());
771 
772  const faceList& faces = aMesh().faces();
773  const pointField& points = aMesh().points();
774 
775  pointField newPoints(points + displacement);
776 
777  scalarField sweptVol(faces.size(), Zero);
778  forAll(faces, faceI)
779  {
780  sweptVol[faceI] = -faces[faceI].sweptVol(points, newPoints);
781  }
782 
783  vectorField faceArea(faces.size(), Zero);
784  forAll(faceArea, faceI)
785  {
786  faceArea[faceI] = faces[faceI].unitNormal(newPoints);
787  }
788 
789  scalarField deltaHf
790  (
791  sweptVol/(faceArea & facesDisplacementDir())
792  );
793 
794  for (const word& patchName : fixedFreeSurfacePatches_)
795  {
796  label fixedPatchID = aMesh().boundary().findPatchID(patchName);
797 
798  if (fixedPatchID == -1)
799  {
800  FatalError
801  << "Wrong faPatch name fixedFreeSurfacePatches list"
802  << " defined in the dynamicMeshDict dictionary"
803  << abort(FatalError);
804  }
805 
806  const labelList& eFaces =
807  aMesh().boundary()[fixedPatchID].edgeFaces();
808 
809  forAll(eFaces, edgeI)
810  {
811  deltaHf[eFaces[edgeI]] *= 2.0;
812  }
813  }
814 
815  controlPoints() += facesDisplacementDir()*deltaHf;
816 
817  displacement = pointDisplacement();
818 
819  velocityMotionSolver& vMotion =
820  refCast<velocityMotionSolver>
821  (
822  const_cast<motionSolver&>(motion())
823  );
824 
825  pointVectorField& pointMotionU = vMotion.pointMotionU();
826  pointMotionU.primitiveFieldRef() = Zero;
827 
828  fixedValuePointPatchVectorField& fsPatchPointMeshU =
829  refCast<fixedValuePointPatchVectorField>
830  (
831  const_cast<pointPatchVectorField&>
832  (
833  pointMotionU.boundaryField()[fsPatchIndex()]
834  )
835  );
836 
837  fsPatchPointMeshU == displacement/mesh().time().deltaTValue();
838 
840 }
841 
842 
843 void Foam::interfaceTrackingFvMesh::updateSurfaceFlux()
844 {
845  Phis() = fac::interpolate(Us()) & aMesh().Le();
846 }
847 
848 
849 void Foam::interfaceTrackingFvMesh::updateSurfactantConcentration()
850 {
851  if (!pureFreeSurface())
852  {
853  Info<< "Correct surfactant concentration" << endl << flush;
854 
855  updateSurfaceFlux();
856 
857  // Crate and solve the surfactanta transport equation
858  faScalarMatrix CsEqn
859  (
860  fam::ddt(surfactantConcentration())
861  + fam::div(Phis(), surfactantConcentration())
863  (
864  surfactant().diffusion(),
865  surfactantConcentration()
866  )
867  );
868 
869  if (surfactant().soluble())
870  {
871  #include "solveBulkSurfactant.H"
872 
874  (
875  IOobject
876  (
877  "Cb",
878  aMesh().time().timeName(),
879  aMesh().thisDb(),
882  ),
883  aMesh(),
886  );
887 
888  Cb.ref().field() =
889  bulkSurfactantConcentration().boundaryField()[fsPatchIndex()];
890  Cb.correctBoundaryConditions();
891 
892  CsEqn +=
893  fam::Sp
894  (
895  surfactant().adsorptionCoeff()*Cb
896  + surfactant().adsorptionCoeff()
897  *surfactant().desorptionCoeff(),
898  surfactantConcentration()
899  )
900  - surfactant().adsorptionCoeff()
901  *Cb*surfactant().saturatedConc();
902  }
903 
904  CsEqn.solve();
905 
906  // Info<< "Correct surface tension" << endl;
907 
908  surfaceTension() =
909  sigma() + surfactant().dSigma(surfactantConcentration())/rho_;
910 
911  if (neg(min(surfaceTension().internalField().field())))
912  {
914  << "Surface tension is negative"
915  << abort(FatalError);
916  }
917  }
918 }
919 
920 
921 Foam::vector Foam::interfaceTrackingFvMesh::totalPressureForce() const
922 {
923  const scalarField& S = aMesh().S();
924 
925  const vectorField& n = aMesh().faceAreaNormals().internalField();
926 
927  const scalarField& P = p().boundaryField()[fsPatchIndex()];
928 
929  vectorField pressureForces(S*P*n);
930 
931  return gSum(pressureForces);
932 }
933 
934 
935 Foam::vector Foam::interfaceTrackingFvMesh::totalViscousForce() const
936 {
937  const auto& turbulence =
938  mesh().lookupObject<turbulenceModel>("turbulenceProperties");
939 
940  scalarField nu(turbulence.nuEff(fsPatchIndex()));
941 
942  // const singlePhaseTransportModel& properties =
943  // mesh().lookupObject<singlePhaseTransportModel>
944  // (
945  // "transportProperties"
946  // );
947 
948  // dimensionedScalar nu("nu", properties);
949 
950  const scalarField& S = aMesh().S();
951  const vectorField& n = aMesh().faceAreaNormals().internalField();
952 
953  vectorField nGradU
954  (
955  U().boundaryField()[fsPatchIndex()].snGrad()
956  );
957 
958  vectorField viscousForces
959  (
960  - nu*S
961  *(
962  nGradU
963  + (fac::grad(Us())().internalField()&n)
964  - (n*fac::div(Us())().internalField())
965  )
966  );
967 
968  return gSum(viscousForces);
969 }
970 
971 
972 Foam::vector Foam::interfaceTrackingFvMesh::totalSurfaceTensionForce() const
973 {
974  const scalarField& S = aMesh().S();
975 
976  const vectorField& n = aMesh().faceAreaNormals().internalField();
977 
978  const scalarField& K = aMesh().faceCurvatures().internalField();
979 
980  vectorField surfTensionForces(n.size(), Zero);
981 
982  if (pureFreeSurface())
983  {
984  surfTensionForces =
985  S*sigma().value()
987  (
988  aMesh().Le()*aMesh().edgeLengthCorrection()
989  )().internalField();
990  }
991  else
992  {
993  surfTensionForces = surfaceTension().internalField().field()*K*S*n;
994  }
995 
996  return gSum(surfTensionForces);
997 }
998 
999 
1000 Foam::scalar Foam::interfaceTrackingFvMesh::maxCourantNumber()
1001 {
1002  scalar CoNum = 0;
1003 
1004  if (pureFreeSurface())
1005  {
1006  const scalarField& dE = aMesh().lPN();
1007 
1008  CoNum = gMax
1009  (
1010  mesh().time().deltaTValue()/
1011  sqrt
1012  (
1013  Foam::pow(dE, 3.0)/2.0/M_PI/(sigma().value() + SMALL)
1014  )
1015  );
1016  }
1017  else
1018  {
1019  scalarField sigmaE
1020  (
1021  linearEdgeInterpolate(surfaceTension())().internalField().field()
1022  + SMALL
1023  );
1024 
1025  const scalarField& dE = aMesh().lPN();
1026 
1027  CoNum = gMax
1028  (
1029  mesh().time().deltaTValue()/
1030  sqrt
1031  (
1032  Foam::pow(dE, 3.0)/2.0/M_PI/sigmaE
1033  )
1034  );
1035  }
1036 
1037  return CoNum;
1038 }
1039 
1040 
1041 void Foam::interfaceTrackingFvMesh::updateProperties()
1042 {
1043  const singlePhaseTransportModel& properties =
1045  (
1046  "transportProperties"
1047  );
1048 
1049  rho_ = dimensionedScalar("rho", properties);
1050 
1051  sigma0_ = dimensionedScalar("sigma", properties)/rho_;
1052 }
1053 
1054 
1055 void Foam::interfaceTrackingFvMesh::correctPointDisplacement
1056 (
1057  const scalarField& sweptVolCorr,
1058  vectorField& displacement
1059 )
1060 {
1061  const labelListList& pFaces =
1062  aMesh().patch().pointFaces();
1063 
1064  const faceList& faces =
1065  aMesh().patch().localFaces();
1066 
1067  const pointField& points =
1068  aMesh().patch().localPoints();
1069 
1070  for (const word& patchName : fixedFreeSurfacePatches_)
1071  {
1072  label fixedPatchID = aMesh().boundary().findPatchID(patchName);
1073 
1074  const labelList& pLabels =
1075  aMesh().boundary()[fixedPatchID].pointLabels();
1076 
1077  const labelList& eFaces =
1078  aMesh().boundary()[fixedPatchID].edgeFaces();
1079 
1081 
1082  forAll(eFaces, edgeI)
1083  {
1084  label curFace = eFaces[edgeI];
1085 
1086  const labelList& curPoints = faces[curFace];
1087 
1088  forAll(curPoints, pointI)
1089  {
1090  label curPoint = curPoints[pointI];
1091  label index = pLabels.find(curPoint);
1092 
1093  if (index == -1)
1094  {
1095  pointSet.insert(curPoint);
1096  }
1097  }
1098  }
1099 
1100  labelList corrPoints = pointSet.toc();
1101 
1102  labelListList corrPointFaces(corrPoints.size());
1103 
1104  forAll(corrPoints, pointI)
1105  {
1106  label curPoint = corrPoints[pointI];
1107 
1109 
1110  forAll(pFaces[curPoint], faceI)
1111  {
1112  label curFace = pFaces[curPoint][faceI];
1113 
1114  label index = eFaces.find(curFace);
1115 
1116  if (index != -1)
1117  {
1118  faceSet.insert(curFace);
1119  }
1120  }
1121 
1122  corrPointFaces[pointI] = faceSet.toc();
1123  }
1124 
1125  forAll(corrPoints, pointI)
1126  {
1127  label curPoint = corrPoints[pointI];
1128 
1129  scalar curDisp = 0;
1130 
1131  const labelList& curPointFaces = corrPointFaces[pointI];
1132 
1133  forAll(curPointFaces, faceI)
1134  {
1135  const face& curFace = faces[curPointFaces[faceI]];
1136 
1137  label ptInFace = curFace.which(curPoint);
1138  label next = curFace.nextLabel(ptInFace);
1139  label prev = curFace.prevLabel(ptInFace);
1140 
1141  vector a = points[next] - points[curPoint];
1142  vector b = points[prev] - points[curPoint];
1143  const vector& c = pointsDisplacementDir()[curPoint];
1144 
1145  curDisp += 2*sweptVolCorr[curPointFaces[faceI]]/((a^b)&c);
1146  }
1147 
1148  curDisp /= curPointFaces.size();
1149 
1150  displacement[curPoint] =
1151  curDisp*pointsDisplacementDir()[curPoint];
1152  }
1153  }
1154 
1155 
1156  for (const word& patchName : nonReflectingFreeSurfacePatches_)
1157  {
1158  label nonReflectingPatchID =
1159  aMesh().boundary().findPatchID(patchName);
1160 
1161  const labelList& pLabels =
1162  aMesh().boundary()[nonReflectingPatchID].pointLabels();
1163 
1164  const labelList& eFaces =
1165  aMesh().boundary()[nonReflectingPatchID].edgeFaces();
1166 
1167  labelList corrPoints = pLabels;
1168 
1169  labelListList corrPointFaces(corrPoints.size());
1170 
1171  forAll(corrPoints, pointI)
1172  {
1173  label curPoint = corrPoints[pointI];
1174 
1176 
1177  forAll(pFaces[curPoint], faceI)
1178  {
1179  label curFace = pFaces[curPoint][faceI];
1180 
1181  label index = eFaces.find(curFace);
1182 
1183  if (index != -1)
1184  {
1185  faceSet.insert(curFace);
1186  }
1187  }
1188 
1189  corrPointFaces[pointI] = faceSet.toc();
1190  }
1191 
1192 
1193  forAll(corrPoints, pointI)
1194  {
1195  label curPoint = corrPoints[pointI];
1196 
1197  scalar curDisp = 0;
1198 
1199  const labelList& curPointFaces = corrPointFaces[pointI];
1200 
1201  forAll(curPointFaces, faceI)
1202  {
1203  const face& curFace = faces[curPointFaces[faceI]];
1204 
1205  label ptInFace = curFace.which(curPoint);
1206  label next = curFace.nextLabel(ptInFace);
1207  label prev = curFace.prevLabel(ptInFace);
1208 
1209  label p0 = -1;
1210  label p1 = -1;
1211  label p2 = -1;
1212 
1213  if (corrPoints.find(next) == -1)
1214  {
1215  p0 = curPoint;
1216  p1 = next;
1217  p2 = curFace.nextLabel(curFace.which(next));
1218  }
1219  else
1220  {
1221  p0 = curFace.prevLabel(curFace.which(prev));
1222  p1 = prev;
1223  p2 = curPoint;
1224  }
1225 
1226  vector a0 = points[p1] - points[p0];
1227  vector b0 = points[p2] - points[p1];
1228  vector c0 = displacement[p1];
1229 
1230  scalar V0 = mag((a0^b0)&c0)/2;
1231 
1232  scalar DV = sweptVolCorr[curPointFaces[faceI]] - V0;
1233 
1234  if (corrPoints.find(prev) != -1)
1235  {
1236  vector a = points[curPoint] - points[prev];
1237  vector b =
1238  (points[next] + displacement[next])
1239  - points[curPoint];
1240  const vector& c = pointsDisplacementDir()[curPoint];
1241 
1242  curDisp += 2*DV/((a^b)&c);
1243  }
1244  else
1245  {
1246  vector a = points[curPoint]
1247  - (points[prev] + displacement[prev]);
1248  vector b = points[next] - points[curPoint];
1249  const vector& c = pointsDisplacementDir()[curPoint];
1250 
1251  curDisp += 2*DV/((a^b)&c);
1252  }
1253  }
1254 
1255  curDisp /= curPointFaces.size();
1256 
1257  displacement[curPoint] =
1258  curDisp*pointsDisplacementDir()[curPoint];
1259  }
1260  }
1261 }
1262 
1263 
1264 void Foam::interfaceTrackingFvMesh::correctContactLinePointNormals()
1265 {
1266  // Correct normals for contact line points
1267  // according to specified contact angle
1268 
1269  vectorField& N =
1270  const_cast<vectorField&>
1271  (
1272  aMesh().pointAreaNormals()
1273  );
1274 
1275  if (contactAnglePtr_ && correctContactLineNormals())
1276  {
1277  Info<< "Correcting contact line normals" << endl;
1278 
1279  vectorField oldPoints(aMesh().nPoints(), Zero);
1280 
1281  const labelList& meshPoints = aMesh().patch().meshPoints();
1282 
1283  forAll(oldPoints, ptI)
1284  {
1285  oldPoints[ptI] =
1286  mesh().oldPoints()[meshPoints[ptI]];
1287  }
1288 
1289 // # include "createTangentField.H"
1290  areaVectorField tangent
1291  (
1292  IOobject
1293  (
1294  "tangent",
1295  aMesh().time().timeName(),
1296  aMesh().thisDb(),
1299  ),
1300  aMesh(),
1302  );
1303 
1304  if (Pstream::parRun())
1305  {
1306  const labelListList& edgeFaces = aMesh().patch().edgeFaces();
1307  const labelListList& pointEdges = aMesh().patch().pointEdges();
1308  const labelListList& pointFaces = aMesh().patch().pointFaces();
1309  const edgeList& edges = aMesh().edges();
1310 
1311  forAll(aMesh().boundary(), patchI)
1312  {
1313  if
1314  (
1315  aMesh().boundary()[patchI].type()
1316  == processorFaPatch::typeName
1317  )
1318  {
1319  const processorFaPatch& procPatch =
1320  refCast<const processorFaPatch>
1321  (
1322  aMesh().boundary()[patchI]
1323  );
1324 
1325  const labelList& patchPointLabels =
1326  procPatch.pointLabels();
1327 
1328  forAll(patchPointLabels, pointI)
1329  {
1330  label curPoint = patchPointLabels[pointI];
1331 
1332  // Check if processor point is boundary point
1333 
1334  label patchID = -1;
1335  label edgeID = -1;
1336 
1337  const labelList& curPointEdges = pointEdges[curPoint];
1338 
1339  forAll(curPointEdges, edgeI)
1340  {
1341  label curEdge = curPointEdges[edgeI];
1342 
1343  if (edgeFaces[curEdge].size() == 1)
1344  {
1345  forAll(aMesh().boundary(), pI)
1346  {
1347  const labelList& curEdges =
1348  aMesh().boundary()[pI];
1349 
1350  label index = curEdges.find(curEdge);
1351 
1352  if (index != -1)
1353  {
1354  if
1355  (
1356  aMesh().boundary()[pI].type()
1357  != processorFaPatch::typeName
1358  )
1359  {
1360  patchID = pI;
1361  edgeID = index;
1362  break;
1363  }
1364  }
1365  }
1366  }
1367  }
1368 
1369  if (patchID != -1)
1370  {
1371  label curEdge =
1372  aMesh().boundary()[patchID].start() + edgeID;
1373 
1374  vector t = edges[curEdge].vec(oldPoints);
1375  t /= mag(t) + SMALL;
1376 
1377  const labelList& curPointFaces =
1378  pointFaces[curPoint];
1379 
1380  forAll(curPointFaces, fI)
1381  {
1382  tangent.ref().field()[curPointFaces[fI]] = t;
1383  }
1384  }
1385  }
1386  }
1387  }
1388 
1389  tangent.correctBoundaryConditions();
1390  }
1391 
1392  forAll(aMesh().boundary(), patchI)
1393  {
1394  label ngbPolyPatchID =
1395  aMesh().boundary()[patchI].ngbPolyPatchIndex();
1396 
1397  if (ngbPolyPatchID != -1)
1398  {
1399  if
1400  (
1401  mesh().boundary()[ngbPolyPatchID].type()
1402  == wallFvPatch::typeName
1403  )
1404  {
1405  const scalar rotAngle = degToRad
1406  (
1407  gAverage
1408  (
1409  90
1410  - contactAnglePtr_->boundaryField()[patchI]
1411  )
1412  );
1413 
1414  vectorField ngbN
1415  (
1416  aMesh().boundary()[patchI].ngbPolyPatchPointNormals()
1417  );
1418 
1419  const labelList& patchPoints =
1420  aMesh().boundary()[patchI].pointLabels();
1421 
1422  vectorField pN(N, patchPoints);
1423 
1424  vectorField rotationAxis(ngbN^pN);
1425  rotationAxis /= mag(rotationAxis) + SMALL;
1426 
1427 
1428  // Calc rotation axis using edge vectors
1429 
1430  const edgeList& edges = aMesh().edges();
1431 
1432  const labelListList& pointEdges =
1433  aMesh().boundary()[patchI].pointEdges();
1434 
1435  forAll(pointEdges, pointI)
1436  {
1437  vector rotAx = Zero;
1438 
1439  forAll(pointEdges[pointI], eI)
1440  {
1441  label curEdge =
1442  aMesh().boundary()[patchI].start()
1443  + pointEdges[pointI][eI];
1444 
1445  vector e = edges[curEdge].vec(oldPoints);
1446 
1447  e *= (e&rotationAxis[pointI])
1448  /mag(e&rotationAxis[pointI]);
1449 
1450  e /= mag(e) + SMALL;
1451 
1452  rotAx += e;
1453  }
1454 
1455  if (pointEdges[pointI].size() == 1)
1456  {
1457  label curPoint = patchPoints[pointI];
1458 
1459  const labelListList& ptEdges =
1460  aMesh().patch().pointEdges();
1461  const labelList& curPointEdges =
1462  ptEdges[curPoint];
1463 
1464  label procPatchID = -1;
1465  label edgeID = -1;
1466 
1467  const labelListList& edgeFaces =
1468  aMesh().patch().edgeFaces();
1469 
1470  forAll(curPointEdges, edgeI)
1471  {
1472  label curEdge = curPointEdges[edgeI];
1473 
1474  if (edgeFaces[curEdge].size() == 1)
1475  {
1476  forAll(aMesh().boundary(), pI)
1477  {
1478  const labelList& curEdges =
1479  aMesh().boundary()[pI];
1480 
1481  label index =
1482  curEdges.find(curEdge);
1483 
1484  if (index != -1)
1485  {
1486  if
1487  (
1488  aMesh().boundary()[pI].type()
1489  == processorFaPatch::typeName
1490  )
1491  {
1492  procPatchID = pI;
1493  edgeID = index;
1494  break;
1495  }
1496  }
1497  }
1498  }
1499  }
1500 
1501  if (procPatchID != -1)
1502  {
1503  vector t =
1504  tangent.boundaryField()[procPatchID]
1505  .patchNeighbourField()()[edgeID];
1506 
1507  t *= (t&rotationAxis[pointI])
1508  /(mag(t&rotationAxis[pointI]) + SMALL);
1509 
1510  t /= mag(t) + SMALL;
1511 
1512  rotAx += t;
1513  }
1514  }
1515 
1516  rotationAxis[pointI] = rotAx/(mag(rotAx) + SMALL);
1517  }
1518 
1519  // Rodrigues' rotation formula
1520  ngbN = ngbN*cos(rotAngle)
1521  + rotationAxis*(rotationAxis & ngbN)*(1 - cos(rotAngle))
1522  + (rotationAxis^ngbN)*sin(rotAngle);
1523 
1524  // Info<< aMesh().boundary()[patchI].name() << endl;
1525  forAll(patchPoints, pointI)
1526  {
1527  N[patchPoints[pointI]] -=
1528  ngbN[pointI]*(ngbN[pointI]&N[patchPoints[pointI]]);
1529 
1530  N[patchPoints[pointI]] /=
1531  mag(N[patchPoints[pointI]]) + SMALL;
1532 
1533  // Info<< N[patchPoints[pointI]] << endl;
1534  }
1535  }
1536  }
1537  }
1538  }
1539 }
1540 
1541 
1542 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1543 
1544 Foam::interfaceTrackingFvMesh::interfaceTrackingFvMesh
1545 (
1546  const IOobject& io,
1547  const bool doInit
1548 )
1549 :
1550  dynamicMotionSolverFvMesh(io, doInit),
1551  aMeshPtr_(nullptr),
1552  fsPatchIndex_(-1),
1553  fixedFreeSurfacePatches_(),
1554  nonReflectingFreeSurfacePatches_(),
1555  pointNormalsCorrectionPatches_(),
1556  normalMotionDir_(false),
1557  motionDir_(Zero),
1558  smoothing_(false),
1559  pureFreeSurface_(true),
1560  rigidFreeSurface_(false),
1561  correctContactLineNormals_(false),
1562  sigma0_("zero", dimForce/dimLength/dimDensity, Zero),
1563  rho_("one", dimDensity, 1.0),
1564  timeIndex_(-1),
1565  UsPtr_(nullptr),
1566  controlPointsPtr_(nullptr),
1567  motionPointsMaskPtr_(nullptr),
1568  pointsDisplacementDirPtr_(nullptr),
1569  facesDisplacementDirPtr_(nullptr),
1570  fsNetPhiPtr_(nullptr),
1571  phisPtr_(nullptr),
1572  surfactConcPtr_(nullptr),
1573  bulkSurfactConcPtr_(nullptr),
1574  surfaceTensionPtr_(nullptr),
1575  surfactantPtr_(nullptr),
1576  contactAnglePtr_(nullptr)
1577 {
1578  if (doInit)
1579  {
1580  init(false); // do not initialise lower levels
1581  }
1582 }
1583 
1584 /*
1585 Foam::interfaceTrackingFvMesh::interfaceTrackingFvMesh
1586 (
1587  const IOobject& io,
1588  pointField&& points,
1589  faceList&& faces,
1590  labelList&& allOwner,
1591  labelList&& allNeighbour,
1592  const bool syncPar
1593 )
1594 :
1595  dynamicMotionSolverFvMesh
1596  (
1597  io,
1598  std::move(points),
1599  std::move(faces),
1600  std::move(allOwner),
1601  std::move(allNeighbour),
1602  syncPar
1603  ),
1604  aMeshPtr_(new faMesh(*this)),
1605  fsPatchIndex_(-1),
1606  fixedFreeSurfacePatches_(),
1607  nonReflectingFreeSurfacePatches_(),
1608  pointNormalsCorrectionPatches_(),
1609  normalMotionDir_(false),
1610  motionDir_(Zero),
1611  smoothing_(false),
1612  pureFreeSurface_(true),
1613  sigma0_("zero", dimForce/dimLength/dimDensity, Zero),
1614  rho_("one", dimDensity, 1.0),
1615  timeIndex_(-1),
1616  UsPtr_(nullptr),
1617  controlPointsPtr_(nullptr),
1618  motionPointsMaskPtr_(nullptr),
1619  pointsDisplacementDirPtr_(nullptr),
1620  facesDisplacementDirPtr_(nullptr),
1621  fsNetPhiPtr_(nullptr),
1622  phisPtr_(nullptr),
1623  surfactConcPtr_(nullptr),
1624  bulkSurfactConcPtr_(nullptr),
1625  surfaceTensionPtr_(nullptr),
1626  surfactantPtr_(nullptr),
1627  contactAnglePtr_(nullptr)
1628 {}
1629 */
1630 
1631 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1632 
1634 {
1635  deleteDemandDrivenData(UsPtr_);
1636  deleteDemandDrivenData(controlPointsPtr_);
1637  deleteDemandDrivenData(motionPointsMaskPtr_);
1638  deleteDemandDrivenData(pointsDisplacementDirPtr_);
1639  deleteDemandDrivenData(facesDisplacementDirPtr_);
1640  deleteDemandDrivenData(fsNetPhiPtr_);
1641  deleteDemandDrivenData(phisPtr_);
1642  deleteDemandDrivenData(surfactConcPtr_);
1643  deleteDemandDrivenData(bulkSurfactConcPtr_);
1644  deleteDemandDrivenData(surfaceTensionPtr_);
1645  deleteDemandDrivenData(surfactantPtr_);
1646  deleteDemandDrivenData(contactAnglePtr_);
1647 }
1648 
1649 
1650 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1651 
1652 bool Foam::interfaceTrackingFvMesh::init(const bool doInit)
1653 {
1654  if (doInit)
1655  {
1657  }
1658 
1659  aMeshPtr_.reset(new faMesh(*this));
1660 
1661  // Set motion-based data
1662  fixedFreeSurfacePatches_ =
1663  motion().get<wordList>("fixedFreeSurfacePatches");
1664 
1665  pointNormalsCorrectionPatches_ =
1666  motion().get<wordList>("pointNormalsCorrectionPatches");
1667 
1668  normalMotionDir_ = motion().get<bool>("normalMotionDir");
1669  smoothing_ = motion().getOrDefault("smoothing", false);
1670  pureFreeSurface_ = motion().getOrDefault("pureFreeSurface", true);
1672  initializeData();
1673 
1674  return true;
1675 }
1676 
1677 
1679 {
1680  if (!UsPtr_)
1681  {
1682  makeUs();
1683  }
1684 
1685  return *UsPtr_;
1686 }
1687 
1688 
1690 {
1691  if (!UsPtr_)
1692  {
1693  makeUs();
1694  }
1695 
1696  return *UsPtr_;
1697 }
1698 
1699 
1701 {
1702  if (!fsNetPhiPtr_)
1703  {
1704  makeFsNetPhi();
1705  }
1706 
1707  return *fsNetPhiPtr_;
1708 }
1709 
1710 
1712 {
1713  if (!fsNetPhiPtr_)
1714  {
1715  makeFsNetPhi();
1716  }
1717 
1718  return *fsNetPhiPtr_;
1719 }
1720 
1721 
1723 {
1724  forAll(Us().boundaryField(), patchI)
1725  {
1726  if
1727  (
1728  Us().boundaryField()[patchI].type()
1729  == calculatedFaPatchVectorField::typeName
1730  )
1731  {
1732  vectorField& pUs = Us().boundaryFieldRef()[patchI];
1733 
1734  pUs = Us().boundaryField()[patchI].patchInternalField();
1735 
1736  label ngbPolyPatchID =
1737  aMesh().boundary()[patchI].ngbPolyPatchIndex();
1738 
1739  if (ngbPolyPatchID != -1)
1740  {
1741  if
1742  (
1743  (
1744  U().boundaryField()[ngbPolyPatchID].type()
1745  == slipFvPatchVectorField::typeName
1746  )
1747  ||
1748  (
1749  U().boundaryField()[ngbPolyPatchID].type()
1750  == symmetryFvPatchVectorField::typeName
1751  )
1752  )
1753  {
1754  vectorField N
1755  (
1756  aMesh().boundary()[patchI].ngbPolyPatchFaceNormals()
1757  );
1758 
1759  pUs -= N*(N&pUs);
1760  }
1761  }
1762  }
1763  }
1764 
1765  Us().correctBoundaryConditions();
1766 }
1767 
1768 
1770 {
1771  // Info<< "Update Us" << endl;
1772 
1773  Us().ref().field() = U().boundaryField()[fsPatchIndex()];
1774 
1775  // // Correct normal component of free-surface velocity
1776  // const vectorField& nA = aMesh().faceAreaNormals().internalField();
1777  // vectorField UnFs = nA*phi().boundaryField()[fsPatchIndex()]
1778  // /mesh().boundary()[fsPatchIndex()].magSf();
1779  // Us().ref().field() += UnFs - nA*(nA&Us().internalField());
1780 
1781  correctUsBoundaryConditions();
1782 }
1783 
1786 {
1787  return *getObjectPtr<const volVectorField>("U");
1788 }
1789 
1792 {
1793  return *getObjectPtr<const volScalarField>("p");
1794 }
1795 
1796 
1798 {
1799  return *getObjectPtr<const surfaceScalarField>("phi");
1800 }
1801 
1802 
1805 {
1806  auto tSnGradU = tmp<vectorField>::New(aMesh().nFaces(), Zero);
1807  auto& SnGradU = tSnGradU.ref();
1808 
1809  const vectorField& nA = aMesh().faceAreaNormals().internalField();
1810 
1811  areaScalarField divUs
1812  (
1813  fac::div(Us())
1814  - aMesh().faceCurvatures()*(aMesh().faceAreaNormals()&Us())
1815  );
1816 
1817  areaTensorField gradUs(fac::grad(Us()));
1818 
1819  // Remove component of gradient normal to surface (area)
1820  const areaVectorField& n = aMesh().faceAreaNormals();
1821  gradUs -= n*(n & gradUs);
1822  gradUs.correctBoundaryConditions();
1823 
1824  const turbulenceModel& turbulence =
1825  mesh().lookupObject<turbulenceModel>("turbulenceProperties");
1826 
1827  scalarField nu(turbulence.nuEff(fsPatchIndex()));
1828 
1829  vectorField tangentialSurfaceTensionForce(nA.size(), Zero);
1830 
1831  if (!pureFreeSurface() && max(nu) > SMALL)
1832  {
1833  tangentialSurfaceTensionForce =
1834  surfaceTensionGrad()().internalField();
1835  }
1836 
1837  SnGradU =
1838  tangentialSurfaceTensionForce/(nu + SMALL)
1839  - nA*divUs.internalField()
1840  - (gradUs.internalField()&nA);
1841 
1842  return tSnGradU;
1843 }
1844 
1845 
1848 {
1849  auto tSnGradUn = tmp<scalarField>::New(aMesh().nFaces(), Zero);
1850  auto& SnGradUn = tSnGradUn.ref();
1851 
1852  areaScalarField divUs
1853  (
1854  fac::div(Us())
1855  - aMesh().faceCurvatures()*(aMesh().faceAreaNormals()&Us())
1856  );
1857 
1858  SnGradUn = -divUs.internalField();
1859 
1860  return tSnGradUn;
1861 }
1862 
1863 
1866 {
1867  auto tPressureJump = tmp<scalarField>::New(aMesh().nFaces(), Zero);
1868  auto& pressureJump = tPressureJump.ref();
1869 
1870  const scalarField& K = aMesh().faceCurvatures().internalField();
1871 
1873  meshObjects::gravity::New(mesh().time());
1874 
1875  const turbulenceModel& turbulence =
1876  mesh().lookupObject<turbulenceModel>("turbulenceProperties");
1877 
1878  scalarField nu(turbulence.nuEff(fsPatchIndex()));
1879 
1880  pressureJump =
1881  - (g.value() & mesh().Cf().boundaryField()[fsPatchIndex()])
1882  + 2.0*nu*freeSurfaceSnGradUn();
1883 
1884  if (pureFreeSurface())
1885  {
1886  pressureJump -= sigma().value()*K;
1887  }
1888  else
1889  {
1890  pressureJump -= surfaceTension().internalField()*K;
1891  }
1892 
1893  return tPressureJump;
1894 }
1895 
1896 
1898 {
1899  if (!controlPointsPtr_)
1900  {
1901  makeControlPoints();
1902  }
1903 
1904  return *controlPointsPtr_;
1905 }
1906 
1907 
1909 {
1910  if (!motionPointsMaskPtr_)
1911  {
1912  makeMotionPointsMask();
1913  }
1914 
1915  return *motionPointsMaskPtr_;
1916 }
1917 
1918 
1920 {
1921  if (!pointsDisplacementDirPtr_)
1922  {
1923  makeDirections();
1924  }
1925 
1926  return *pointsDisplacementDirPtr_;
1927 }
1928 
1929 
1931 {
1932  if (!facesDisplacementDirPtr_)
1933  {
1934  makeDirections();
1935  }
1936 
1937  return *facesDisplacementDirPtr_;
1938 }
1939 
1940 
1942 {
1943  if (!phisPtr_)
1944  {
1945  makePhis();
1946  }
1947 
1948  return *phisPtr_;
1949 }
1950 
1953 {
1954  if (!surfactConcPtr_)
1955  {
1956  makeSurfactConc();
1957  }
1958 
1959  return *surfactConcPtr_;
1960 }
1961 
1962 
1963 const Foam::areaScalarField&
1965 {
1966  if (!surfactConcPtr_)
1967  {
1968  makeSurfactConc();
1969  }
1970 
1971  return *surfactConcPtr_;
1972 }
1973 
1974 
1977 {
1978  if (!bulkSurfactConcPtr_)
1979  {
1980  makeBulkSurfactConc();
1981  }
1982 
1983  return *bulkSurfactConcPtr_;
1984 }
1985 
1986 
1987 const Foam::volScalarField&
1989 {
1990  if (!bulkSurfactConcPtr_)
1991  {
1992  makeBulkSurfactConc();
1993  }
1994 
1995  return *bulkSurfactConcPtr_;
1996 }
1997 
1998 
2001 {
2002  if (!surfaceTensionPtr_)
2003  {
2004  makeSurfaceTension();
2005  }
2006 
2007  return *surfaceTensionPtr_;
2008 }
2009 
2010 
2011 const Foam::areaScalarField&
2013 {
2014  if (!surfaceTensionPtr_)
2015  {
2016  makeSurfaceTension();
2017  }
2018 
2019  return *surfaceTensionPtr_;
2020 }
2021 
2022 
2025 {
2026  if (!surfactantPtr_)
2027  {
2028  makeSurfactant();
2029  }
2030 
2031  return *surfactantPtr_;
2032 }
2033 
2034 
2037 {
2038  auto tgrad = tmp<areaVectorField>::New
2039  (
2040  IOobject
2041  (
2042  "surfaceTensionGrad",
2043  aMesh().time().timeName(),
2044  aMesh().thisDb(),
2047  ),
2048  fac::grad(surfaceTension())
2049  // (-fac::grad(surfactantConcentration()/rho_)*
2050  // surfactant().surfactR()*surfactant().surfactT()/
2051  // (1.0 - surfactantConcentration()/
2052  // surfactant().surfactSaturatedConc()))()
2053  );
2054  auto& grad = tgrad.ref();
2055 
2056  // Remove component of gradient normal to surface (area)
2057  const areaVectorField& n = aMesh().faceAreaNormals();
2058  grad -= n*(n & grad);
2059  grad.correctBoundaryConditions();
2060 
2061  return tgrad;
2062 }
2063 
2064 
2066 {
2067  if (timeIndex_ != mesh().time().timeIndex())
2068  {
2069  if (smoothing_ && !rigidFreeSurface_)
2070  {
2071  smoothFreeSurfaceMesh();
2072  clearControlPoints();
2073  }
2074 
2075  updateDisplacementDirections();
2076 
2077  updateProperties();
2078 
2079  Info<< "Maximal capillary Courant number: "
2080  << maxCourantNumber() << endl;
2081 
2082  const scalarField& K = aMesh().faceCurvatures().internalField();
2083 
2084  Info<< "Free surface curvature: min = " << gMin(K)
2085  << ", max = " << gMax(K) << ", average = " << gAverage(K) << nl;
2086 
2087  timeIndex_ = mesh().time().timeIndex();
2088  }
2089 
2090  if (!rigidFreeSurface_)
2091  {
2092  // This is currently relaltive flux
2093  scalarField sweptVolCorr =
2094  phi().boundaryField()[fsPatchIndex()];
2095 
2096  // Info<< "Free surface flux: sum local = "
2097  // << gSum(mag(sweptVolCorr))
2098  // << ", global = " << gSum(sweptVolCorr) << endl;
2099 
2100  // if (mesh().moving())
2101  // {
2102  // sweptVolCorr -=
2103  // fvc::meshPhi(U())().boundaryField()[fsPatchIndex()];
2104  // }
2105 
2106  Info<< "Free surface continuity error : sum local = "
2107  << gSum(mag(sweptVolCorr)) << ", global = " << gSum(sweptVolCorr)
2108  << endl;
2109 
2110  // For postprocessing
2111  fsNetPhi().ref().field() = sweptVolCorr;
2112 
2113  word ddtScheme
2114  (
2115  mesh().ddtScheme
2116  (
2117  "ddt(" + U().name() + ')'
2118  )
2119  );
2120 
2121  if
2122  (
2123  ddtScheme
2125  )
2126  {
2127  sweptVolCorr *= (1.0/2.0)*mesh().time().deltaTValue();
2128  }
2129  else if
2130  (
2131  ddtScheme
2133  )
2134  {
2135  sweptVolCorr *= mesh().time().deltaTValue();
2136  }
2137  else if
2138  (
2139  ddtScheme
2141  )
2142  {
2143  if (mesh().time().timeIndex() == 1)
2144  {
2145  sweptVolCorr *= mesh().time().deltaTValue();
2146  }
2147  else
2148  {
2149  sweptVolCorr *= (2.0/3.0)*mesh().time().deltaTValue();
2150  }
2151  }
2152  else
2153  {
2155  << "Unsupported temporal differencing scheme : "
2156  << ddtScheme << nl
2157  << abort(FatalError);
2158  }
2159 
2160  const scalarField& Sf = aMesh().S();
2161  const vectorField& Nf = aMesh().faceAreaNormals().internalField();
2162 
2163  scalarField deltaHf
2164  (
2165  sweptVolCorr/(Sf*(Nf & facesDisplacementDir()))
2166  );
2167 
2168  for (const word& patchName : fixedFreeSurfacePatches_)
2169  {
2170  label fixedPatchID =
2171  aMesh().boundary().findPatchID(patchName);
2172 
2173  if (fixedPatchID == -1)
2174  {
2176  << "Wrong faPatch name '" << patchName
2177  << "'in the fixedFreeSurfacePatches list"
2178  << " defined in dynamicMeshDict dictionary"
2179  << abort(FatalError);
2180  }
2181 
2182  const labelList& eFaces =
2183  aMesh().boundary()[fixedPatchID].edgeFaces();
2184 
2185  forAll(eFaces, edgeI)
2186  {
2187  deltaHf[eFaces[edgeI]] *= 2.0;
2188  }
2189  }
2190 
2191  controlPoints() += facesDisplacementDir()*deltaHf;
2192 
2193  pointField displacement(pointDisplacement());
2194  correctPointDisplacement(sweptVolCorr, displacement);
2195 
2196  velocityMotionSolver& vMotion =
2197  refCast<velocityMotionSolver>
2198  (
2199  const_cast<motionSolver&>(motion())
2200  );
2201 
2202  pointVectorField& pointMotionU = vMotion.pointMotionU();
2203  pointMotionU.primitiveFieldRef() = Zero;
2204 
2205  fixedValuePointPatchVectorField& fsPatchPointMeshU =
2206  refCast<fixedValuePointPatchVectorField>
2207  (
2208  const_cast<pointPatchVectorField&>
2209  (
2210  pointMotionU.boundaryField()[fsPatchIndex()]
2211  )
2212  );
2213 
2214  fsPatchPointMeshU == displacement/mesh().time().deltaTValue();
2215 
2217 
2218  correctContactLinePointNormals();
2219  }
2220  else
2221  {
2222  vectorField displacement
2223  (
2224  mesh().boundaryMesh()[fsPatchIndex()].nPoints(),
2225  Zero
2226  );
2227 
2228  velocityMotionSolver& vMotion =
2229  refCast<velocityMotionSolver>
2230  (
2231  const_cast<motionSolver&>(motion())
2232  );
2233 
2234  pointVectorField& pointMotionU = vMotion.pointMotionU();
2235  pointMotionU.primitiveFieldRef() = Zero;
2236 
2237  fixedValuePointPatchVectorField& fsPatchPointMeshU =
2238  refCast<fixedValuePointPatchVectorField>
2239  (
2240  const_cast<pointPatchVectorField&>
2241  (
2242  pointMotionU.boundaryField()[fsPatchIndex()]
2243  )
2244  );
2245 
2246  fsPatchPointMeshU == displacement/mesh().time().deltaTValue();
2247 
2249  }
2250 
2251  updateUs();
2253  updateSurfactantConcentration();
2254 
2255  return true;
2256 }
2257 
2258 
2260 {
2262  (
2263  aMesh().patch(),
2265  mesh().time().timePath()/"freeSurface",
2266  false // serial only
2267  );
2269 }
2270 
2271 
2273 {
2274  // Write control points into VTK
2275  OFstream os
2276  (
2277  mesh().time().timePath()/"freeSurfaceControlPoints.vtk"
2278  );
2279 
2280  Info<< "Writing free surface control points to " << os.name() << nl;
2281 
2282  os << "# vtk DataFile Version 2.0" << nl
2283  << "freeSurfaceControlPoints" << nl
2284  << "ASCII" << nl
2285  << "DATASET POLYDATA" << nl;
2286 
2287  const label nPoints = controlPoints().size();
2288 
2289  os << "POINTS " << nPoints << " float" << nl;
2290  for (const point& p : controlPoints())
2291  {
2292  os << float(p.x()) << ' '
2293  << float(p.y()) << ' '
2294  << float(p.z()) << nl;
2295  }
2296 
2297  os << "VERTICES " << nPoints << ' ' << 2*nPoints << nl;
2298  for (label id = 0; id < nPoints; ++id)
2299  {
2300  os << 1 << ' ' << id << nl;
2301  }
2302 }
2303 
2304 
2305 // ************************************************************************* //
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:87
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:598
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:128
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, using an OSstream.
Definition: OFstream.H:49
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:276
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1049
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:782
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:81
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:608
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:46
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:31
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:1117
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:124
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:172
Foam::label startTime
GeometricField< vector, faPatchField, areaMesh > areaVectorField
Definition: areaFieldsFwd.H:81
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:80
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127
const dimensionSet dimVelocity