isothermalFilm.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2023 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "isothermalFilm.H"
27 #include "filmWallPolyPatch.H"
28 #include "filmSurfacePolyPatch.H"
29 #include "mappedPatchBase.H"
32 #include "constantSurfaceTension.H"
33 #include "fvcVolumeIntegrate.H"
34 #include "fvcDdt.H"
35 #include "fvcDiv.H"
36 #include "fvcFlux.H"
37 #include "fvcSurfaceIntegrate.H"
39 
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 
42 namespace Foam
43 {
44 namespace solvers
45 {
48 }
49 }
50 
51 
52 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
53 
55 {
56  maxCo =
57  runTime.controlDict().lookupOrDefault<scalar>("maxCo", 1.0);
58 
59  maxDeltaT_ =
60  runTime.controlDict().lookupOrDefault<scalar>("maxDeltaT", vGreat);
61 }
62 
63 
64 void Foam::solvers::isothermalFilm::correctCoNum()
65 {
66  const scalarField sumPhi(fvc::surfaceSum(mag(phi))().primitiveField());
67 
68  CoNum = 0.5*gMax(sumPhi/mesh.V().field())*runTime.deltaTValue();
69 
70  const scalar meanCoNum =
71  0.5*(gSum(sumPhi)/gSum(mesh.V().field()))*runTime.deltaTValue();
72 
73  Info<< "Courant Number mean: " << meanCoNum
74  << " max: " << CoNum << endl;
75 }
76 
77 
78 void Foam::solvers::isothermalFilm::continuityErrors()
79 {
80  const dimensionedScalar mass = fvc::domainIntegrate(rho()*delta()*magSf);
81 
82  correctContinuityError();
83 
84  if (mass.value() > small)
85  {
86  const volScalarField::Internal massContErr
87  (
88  runTime.deltaT()*magSf*contErr()
89  );
90 
91  const scalar sumLocalContErr =
92  (fvc::domainIntegrate(mag(massContErr))/mass).value();
93 
94  const scalar globalContErr =
95  (fvc::domainIntegrate(massContErr)/mass).value();
96 
97  Info<< "time step continuity errors : sum local = " << sumLocalContErr
98  << ", global = " << globalContErr;
99 
100  if (pimple.finalPisoIter() && pimple.finalIter())
101  {
103 
104  Info<< ", cumulative = " << cumulativeContErr;
105  }
106 
107  Info<< endl;
108  }
109 }
110 
111 
112 // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
113 
114 bool Foam::solvers::isothermalFilm::initFilmMesh()
115 {
116  // Search for film wall patches
117 
118  label nWallFaces = 0;
119  DynamicList<label> wallPatchIDs_;
120 
121  const polyBoundaryMesh& bm = mesh.boundaryMesh();
122 
123  forAll(bm, patchi)
124  {
125  const polyPatch& p = bm[patchi];
126 
127  if (isA<filmWallPolyPatch>(p))
128  {
129  wallPatchIDs_.append(patchi);
130  nWallFaces += p.faceCells().size();
131  }
132  }
133 
134  if (nWallFaces != mesh.nCells())
135  {
137  << "The number of film wall faces in the mesh "
138  << nWallFaces
139  << " is not equal to the number of cells "
140  << mesh.nCells()
141  << exit(FatalError);
142  }
143 
144  if (returnReduce(nWallFaces, sumOp<label>()) == 0)
145  {
147  << "There are no filmWall faces in the mesh"
148  << exit(FatalError);
149  }
150 
151  wallPatchIDs.transfer(wallPatchIDs_);
152 
153 
154  // Search for film surface patch
155  surfacePatchID = -1;
156 
157  forAll(bm, patchi)
158  {
159  const polyPatch& p = bm[patchi];
160 
161  if (isA<filmSurfacePolyPatch>(p))
162  {
163  if (surfacePatchID == -1)
164  {
165  surfacePatchID = patchi;
166  }
167  else
168  {
170  << "More than one filmSurface patch defined: "
171  << surfacePatchID << " and " << patchi
172  << exit(FatalError);
173  }
174  }
175  }
176 
177  if (surfacePatchID == -1)
178  {
179  Info<< "The filmSurface patch is not defined"
180  << endl;
181  }
182 
183 
184  // Calculate film specific mesh geometry from the film wall patches
185 
186  forAll(wallPatchIDs, i)
187  {
188  const label patchi = wallPatchIDs[i];
189  const polyPatch& wallp = bm[patchi];
190  const labelList& fCells = wallp.faceCells();
191 
192  UIndirectList<vector>(nHat_, fCells) = wallp.faceNormals();
193  UIndirectList<scalar>(magSf_, fCells) = wallp.magFaceAreas();
194  }
195 
196  nHat_.correctBoundaryConditions();
197 
198  VbyA_.primitiveFieldRef() = mesh.V()/magSf_;
199  VbyA_.correctBoundaryConditions();
200 
201  return true;
202 }
203 
204 
205 Foam::wordList Foam::solvers::isothermalFilm::alphaTypes() const
206 {
207  wordList alphaTypes(delta_.boundaryField().types());
208 
209  forAll(delta_.boundaryField(), patchi)
210  {
211  if (!delta_.boundaryField()[patchi].assignable())
212  {
213  alphaTypes[patchi] = fixedValueFvPatchScalarField::typeName;
214  }
215  }
216 
217  forAll(wallPatchIDs, i)
218  {
219  alphaTypes[wallPatchIDs[i]] = alphaOneFvPatchScalarField::typeName;
220  }
221 
222  if (surfacePatchID != -1)
223  {
224  alphaTypes[surfacePatchID] = alphaOneFvPatchScalarField::typeName;
225  }
226 
227  return alphaTypes;
228 }
229 
230 
231 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
232 
234 (
235  fvMesh& mesh,
236  autoPtr<rhoThermo> thermoPtr
237 )
238 :
239  solver(mesh),
240 
241  CoNum(0),
243 
244  thermoPtr_(thermoPtr),
245  thermo_(thermoPtr_()),
246 
247  p(thermo_.p()),
248 
249  nHat_
250  (
251  IOobject
252  (
253  "nHat",
254  runTime.name(),
255  mesh
256  ),
257  mesh,
260  ),
261 
262  magSf_
263  (
264  IOobject
265  (
266  "magSf",
267  runTime.name(),
268  mesh
269  ),
270  mesh,
272  ),
273 
274  VbyA_
275  (
276  IOobject
277  (
278  "VbyA",
279  runTime.name(),
280  mesh
281  ),
282  mesh,
285  ),
286 
287  initialised_(initFilmMesh()),
288 
289  delta_
290  (
291  IOobject
292  (
293  "delta",
294  runTime.name(),
295  mesh,
296  IOobject::MUST_READ,
297  IOobject::AUTO_WRITE
298  ),
299  mesh
300  ),
301 
302  alpha_
303  (
304  IOobject
305  (
306  "alpha",
307  runTime.name(),
308  mesh,
309  IOobject::READ_IF_PRESENT,
310  IOobject::AUTO_WRITE
311  ),
312  delta_/VbyA_,
313  alphaTypes()
314  ),
315 
316  deltaWet("deltaWet", dimLength, thermo_.properties()),
317 
318  U_
319  (
320  IOobject
321  (
322  "U",
323  runTime.name(),
324  mesh,
325  IOobject::MUST_READ,
326  IOobject::AUTO_WRITE
327  ),
328  mesh
329  ),
330 
331  alphaRhoPhi_
332  (
333  IOobject
334  (
335  "alphaRhoPhi",
336  runTime.name(),
337  mesh,
338  IOobject::READ_IF_PRESENT,
339  IOobject::AUTO_WRITE
340  ),
341  fvc::flux(alpha_*thermo_.rho()*U_)
342  ),
343 
344  phi_
345  (
346  IOobject
347  (
348  "phi",
349  runTime.name(),
350  mesh,
351  IOobject::READ_IF_PRESENT,
352  IOobject::AUTO_WRITE
353  ),
354  fvc::flux(U_)
355  ),
356 
357  surfaceTension(surfaceTensionModel::New(thermo_.properties(), mesh)),
358  thermocapillary(!isType<surfaceTensionModels::constant>(surfaceTension())),
359 
360  g
361  (
362  IOobject
363  (
364  "g",
365  runTime.constant(),
366  mesh,
367  IOobject::MUST_READ,
368  IOobject::NO_WRITE
369  )
370  ),
371 
372  nHat(nHat_),
373  magSf(magSf_),
374  VbyA(VbyA_),
375  delta(delta_),
376  alpha(alpha_),
377  thermo(thermo_),
378  rho(thermo_.rho()),
379  U(U_),
380  alphaRhoPhi(alphaRhoPhi_),
381  phi(phi_),
382 
383  momentumTransport
384  (
385  filmCompressible::momentumTransportModel::New
386  (
387  alpha,
388  thermo.rho(),
389  U,
390  alphaRhoPhi,
391  phi,
392  thermo
393  )
394  )
395 {
396  // Read the controls
397  readControls();
398 
400  momentumTransport->validate();
401 }
402 
403 
405 :
406  isothermalFilm(mesh, rhoThermo::New(mesh))
407 {}
408 
409 
410 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
411 
413 {}
414 
415 
416 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
417 
419 {
420  return mesh.boundary()[surfacePatchID];
421 }
422 
423 
426 {
427  return refCast<const mappedPatchBase>(surfacePatch().patch());
428 }
429 
430 
432 {
433  scalar deltaT = min(fvModels().maxDeltaT(), maxDeltaT_);
434 
435  if (CoNum > small)
436  {
437  deltaT = min(deltaT, maxCo/CoNum*runTime.deltaTValue());
438  }
439 
440  return deltaT;
441 }
442 
443 
445 {
446  readControls();
447  correctCoNum();
448 }
449 
450 
452 {}
453 
454 
456 {
457  thermo_.correct();
458 }
459 
460 
462 {
463  correctAlpha();
464 }
465 
466 
468 {
469  if (pimple.correctTransport())
470  {
471  momentumTransport->correct();
472  }
473 }
474 
475 
477 {}
478 
479 
480 // ************************************************************************* //
scalar delta
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Macros for easy insertion into run-time selection tables.
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
static const char *const typeName
Definition: Field.H:105
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
const word & name() const
Return name.
Definition: IOobject.H:310
const dictionary & controlDict() const
Return the control dict.
Definition: Time.H:265
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
const Type & value() const
Return const reference to value.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:101
const fvSchemes & schemes() const
Return the fvSchemes.
Definition: fvMesh.C:1748
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:64
void setFluxRequired(const word &name) const
Definition: fvSchemes.C:503
Engine which provides mapping between two patches.
Abstract base class for turbulence models (RAS, LES and laminar).
Base-class for fluid thermodynamic properties based on density.
Definition: rhoThermo.H:55
Abstract base class for run-time selectable region solvers.
Definition: solver.H:55
const Time & runTime
Time.
Definition: solver.H:97
const fvMesh & mesh
Region mesh.
Definition: solver.H:94
Solver module for flow of compressible isothermal liquid films.
virtual void thermophysicalPredictor()
Construct and solve the energy equation,.
isothermalFilm(fvMesh &mesh, autoPtr< rhoThermo >)
Construct from region mesh and thermophysical properties.
virtual void postSolve()
Called after the PIMPLE loop at the end of the time-step.
autoPtr< filmCompressible::momentumTransportModel > momentumTransport
Pointer to the momentum transport model.
const volScalarField & alpha
Film volume fraction in the cell layer.
const mappedPatchBase & surfacePatchMap() const
Return the film surface patch region-region map.
virtual void moveMesh()
Called at the start of the PIMPLE loop to move the mesh.
virtual scalar maxDeltaT() const
Return the current maximum time-step for stable solution.
virtual void pressureCorrector()
Construct and solve the pressure equation in the PISO loop.
virtual void postCorrector()
Correct the momentum and thermophysical transport modelling.
const fvPatch & surfacePatch() const
Return the film surface patch.
void readControls()
Read controls.
virtual void preSolve()
Called at the start of the time-step, before the PIMPLE loop.
virtual ~isothermalFilm()
Destructor.
'Patch' on surface as subset of triSurface.
Definition: surfacePatch.H:61
Abstract base-class for surface tension models which return the surface tension coefficient field.
This boundary condition applies a zero-gradient condition from the patch internal field onto the patc...
scalar CoNum
scalar meanCoNum
Foam::fvModels & fvModels(Foam::fvModels::New(mesh))
pimpleControl pimple(mesh)
scalar maxDeltaT
scalar maxCo
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
Calculate the first temporal derivative.
Calculate the divergence of the given field.
Calculate the face-flux of the given field.
Surface integrate surfaceField creating a volField. Surface sum a surfaceField creating a volField.
Volume integrate volField creating a volField.
label patchi
scalar cumulativeContErr
label nWallFaces(0)
U
Definition: pEqn.H:72
volScalarField alpha(IOobject("alpha", runTime.name(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE), lambda *max(Ua &U, zeroSensitivity))
tmp< VolField< Type > > surfaceSum(const SurfaceField< Type > &ssf)
dimensioned< Type > domainIntegrate(const VolField< Type > &vf)
addToRunTimeSelectionTable(solver, compressibleMultiphaseVoF, fvMesh)
defineTypeNameAndDebug(compressibleMultiphaseVoF, 0)
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
List< word > wordList
A List of words.
Definition: fileName.H:54
Type gSum(const FieldField< Field, Type > &f)
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
const dimensionSet dimless
bool isType(const Type &t)
Check the typeid.
Definition: typeInfo.H:131
messageStream Info
const dimensionSet dimLength
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
dimensioned< scalar > mag(const dimensioned< Type > &)
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
error FatalError
const dimensionSet dimArea
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Type gMax(const FieldField< Field, Type > &f)
volScalarField & p
fluidMulticomponentThermo & thermo
Definition: createFields.H:31
scalar sumLocalContErr
Definition: volContinuity.H:9
scalar globalContErr
Definition: volContinuity.H:12