powerLawLopesdaCosta.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) 2018-2025 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 
27 #include "powerLawLopesdaCosta.H"
28 #include "geometricOneField.H"
29 #include "fvMatrices.H"
31 #include "triSurfaceTools.H"
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
35 namespace Foam
36 {
37  namespace porosityModels
38  {
41  }
42 }
43 
44 
45 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
46 
48 (
49  const word& name,
50  const fvMesh& mesh,
51  const dictionary& dict,
52  const dictionary& coeffDict
53 )
54 :
55  zoneName_(name + ":porousZone")
56 {
57  // Vertical direction within porous region
58  vector zDir(coeffDict.lookup("zDir"));
59 
60  // Span of the search for the cells in the porous region
61  scalar searchSpan(coeffDict.lookup<scalar>("searchSpan"));
62 
63  // Top surface file name defining the extent of the porous region
64  word topSurfaceFileName(coeffDict.lookup("topSurface"));
65 
66  // List of the ground patches defining the lower surface
67  // of the porous region
68  List<wordRe> groundPatches(coeffDict.lookup("groundPatches"));
69 
70  // Functional form of the porosity surface area per unit volume as a
71  // function of the normalised vertical position
73  (
75  (
76  dict.lookupEntryBackwardsCompatible
77  (
78  {"Av", "Sigma"},
79  false,
80  true
81  ).keyword(),
82  dimLength,
84  dict
85  )
86  );
87 
88  // Searchable triSurface for the top of the porous region
90  (
91  IOobject
92  (
93  topSurfaceFileName,
94  mesh.time().constant(),
96  mesh.time()
97  )
98  );
99 
100  // Limit the porous cell search to those within the lateral and vertical
101  // extent of the top surface
102 
103  boundBox surfBounds(searchSurf.points());
104  boundBox searchBounds
105  (
106  surfBounds.min() - searchSpan*zDir, surfBounds.max()
107  );
108 
109  const pointField& C = mesh.cellCentres();
110 
111  // List of cells within the porous region
112  labelList porousCells(C.size());
113  label porousCelli = 0;
114 
115  forAll(C, celli)
116  {
117  if (searchBounds.contains(C[celli]))
118  {
119  porousCells[porousCelli++] = celli;
120  }
121  }
122 
123  porousCells.setSize(porousCelli);
124 
125  pointField start(porousCelli);
126  pointField end(porousCelli);
127 
128  forAll(porousCells, porousCelli)
129  {
130  start[porousCelli] = C[porousCells[porousCelli]];
131  end[porousCelli] = start[porousCelli] + searchSpan*zDir;
132  }
133 
134  // Field of distance between the cell centre and the corresponding point
135  // on the porous region top surface
136  scalarField zTop(porousCelli);
137 
138  // Search the porous cells for those with a corresponding point on the
139  // porous region top surface
140  List<pointIndexHit> hitInfo;
141  searchSurf.findLine(start, end, hitInfo);
142 
143  porousCelli = 0;
144 
145  forAll(porousCells, celli)
146  {
147  const pointIndexHit& hit = hitInfo[celli];
148 
149  if (hit.hit())
150  {
151  porousCells[porousCelli] = porousCells[celli];
152 
153  zTop[porousCelli] =
154  (hit.hitPoint() - C[porousCells[porousCelli]]) & zDir;
155 
156  porousCelli++;
157  }
158  }
159 
160  // Resize the porous cells list and height field
161  porousCells.setSize(porousCelli);
162  zTop.setSize(porousCelli);
163 
164  // Create a triSurface for the ground patch(s)
165  triSurface groundSurface
166  (
168  (
169  mesh.boundaryMesh(),
170  mesh.boundaryMesh().patchSet(groundPatches),
171  searchBounds
172  )
173  );
174 
175  // Combine the ground triSurfaces across all processors
176  if (Pstream::parRun())
177  {
178  List<List<labelledTri>> groundSurfaceProcTris(Pstream::nProcs());
179  List<pointField> groundSurfaceProcPoints(Pstream::nProcs());
180 
181  groundSurfaceProcTris[Pstream::myProcNo()] = groundSurface;
182  groundSurfaceProcPoints[Pstream::myProcNo()] = groundSurface.points();
183 
184  Pstream::gatherList(groundSurfaceProcTris);
185  Pstream::scatterList(groundSurfaceProcTris);
186  Pstream::gatherList(groundSurfaceProcPoints);
187  Pstream::scatterList(groundSurfaceProcPoints);
188 
189  label nTris = 0;
190  forAll(groundSurfaceProcTris, i)
191  {
192  nTris += groundSurfaceProcTris[i].size();
193  }
194 
195  List<labelledTri> groundSurfaceTris(nTris);
196  label trii = 0;
197  label offset = 0;
198  forAll(groundSurfaceProcTris, i)
199  {
200  forAll(groundSurfaceProcTris[i], j)
201  {
202  groundSurfaceTris[trii] = groundSurfaceProcTris[i][j];
203  groundSurfaceTris[trii][0] += offset;
204  groundSurfaceTris[trii][1] += offset;
205  groundSurfaceTris[trii][2] += offset;
206  trii++;
207  }
208  offset += groundSurfaceProcPoints[i].size();
209  }
210 
211  label nPoints = 0;
212  forAll(groundSurfaceProcPoints, i)
213  {
214  nPoints += groundSurfaceProcPoints[i].size();
215  }
216 
217  pointField groundSurfacePoints(nPoints);
218 
219  label pointi = 0;
220  forAll(groundSurfaceProcPoints, i)
221  {
222  forAll(groundSurfaceProcPoints[i], j)
223  {
224  groundSurfacePoints[pointi++] = groundSurfaceProcPoints[i][j];
225  }
226  }
227 
228  groundSurface = triSurface(groundSurfaceTris, groundSurfacePoints);
229  }
230 
231  // Create a searchable triSurface for the ground
232  triSurfaceSearch groundSearch(groundSurface);
233 
234  // Search the porous cells for the corresponding point on the ground
235 
236  start.setSize(porousCelli);
237  end.setSize(porousCelli);
238 
239  forAll(porousCells, porousCelli)
240  {
241  start[porousCelli] = C[porousCells[porousCelli]];
242  end[porousCelli] = start[porousCelli] - searchSpan*zDir;
243  }
244 
245  groundSearch.findLine(start, end, hitInfo);
246 
247  scalarField zBottom(porousCelli);
248 
249  forAll(porousCells, porousCelli)
250  {
251  const pointIndexHit& hit = hitInfo[porousCelli];
252 
253  if (hit.hit())
254  {
255  zBottom[porousCelli] =
256  (C[porousCells[porousCelli]] - hit.hitPoint()) & zDir;
257  }
258  }
259 
260  // Create the normalised height field
261  const scalarField zNorm(zBottom/(zBottom + zTop));
262 
263  // Create the porosity surface area per unit volume zone field
264  Av_ = AvFunc->value(zNorm);
265 
266  // Create the porous region cellZone and add to the mesh cellZones
267  if (!mesh.cellZones().found(zoneName_))
268  {
270  (
271  new cellZone
272  (
273  zoneName_,
274  porousCells,
275  mesh.cellZones()
276  )
277  );
278  }
279  else
280  {
282  << "Unable to create porous cellZone " << zoneName_
283  << ": zone already exists"
284  << abort(FatalError);
285  }
286 }
287 
288 
290 (
291  const word& name,
292  const fvMesh& mesh,
293  const dictionary& dict,
294  const dictionary& coeffDict,
295  const word& dummyCellZoneName
296 )
297 :
298  powerLawLopesdaCostaZone(name, mesh, dict, coeffDict),
300  (
301  name,
302  mesh,
303  dict,
304  coeffDict,
305  powerLawLopesdaCostaZone::zoneName_
306  ),
307  coeffDict_(coeffDict),
308  Cd_(coeffDict.lookup<scalar>("Cd")),
309  C1_(coeffDict.lookup<scalar>("C1")),
310  rhoName_(coeffDict.lookupOrDefault<word>("rho", "rho"))
311 {}
312 
313 
314 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
315 
317 {}
318 
319 
320 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
321 
322 const Foam::scalarField&
324 {
325  return Av_;
326 }
327 
328 
330 {}
331 
332 
334 (
335  const volVectorField& U,
336  const volScalarField& rho,
337  const volScalarField& mu,
338  vectorField& force
339 ) const
340 {
341  scalarField Udiag(U.size(), 0.0);
342  const scalarField& V = mesh_.V();
343 
344  apply(Udiag, V, rho, U);
345 
346  force = Udiag*U;
347 }
348 
349 
351 (
353 ) const
354 {
355  const vectorField& U = UEqn.psi();
356  const scalarField& V = mesh_.V();
357  scalarField& Udiag = UEqn.diag();
358 
359  if (UEqn.dimensions() == dimForce)
360  {
361  const volScalarField& rho =
362  mesh_.lookupObject<volScalarField>(rhoName_);
363 
364  apply(Udiag, V, rho, U);
365  }
366  else
367  {
368  apply(Udiag, V, geometricOneField(), U);
369  }
370 }
371 
372 
374 (
376  const volScalarField& rho,
377  const volScalarField& mu
378 ) const
379 {
380  const vectorField& U = UEqn.psi();
381  const scalarField& V = mesh_.V();
382  scalarField& Udiag = UEqn.diag();
383 
384  apply(Udiag, V, rho, U);
385 }
386 
387 
389 (
390  const fvVectorMatrix& UEqn,
391  volTensorField& AU
392 ) const
393 {
394  const vectorField& U = UEqn.psi();
395 
396  if (UEqn.dimensions() == dimForce)
397  {
398  const volScalarField& rho =
399  mesh_.lookupObject<volScalarField>(rhoName_);
400 
401  apply(AU, rho, U);
402  }
403  else
404  {
405  apply(AU, geometricOneField(), U);
406  }
407 }
408 
409 
410 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
Macros for easy insertion into run-time selection tables.
Graphite solid properties.
Definition: C.H:51
Run-time selectable general function of one variable.
Definition: Function1.H:125
Generic GeometricField class.
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:54
const Point & hitPoint() const
Return hit point.
bool hit() const
Is there a hit.
const Field< PointType > & points() const
Return reference to global points.
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
static const word & constant()
Return constant name.
Definition: TimePaths.H:122
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
const ZoneType & append(ZoneType *) const
Append or update a zone.
Definition: ZoneList.C:214
bool found(const label objectIndex) const
Return true if objectIndex is in any zone.
Definition: ZoneList.C:124
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:59
const point & min() const
Minimum point defining the bounding box.
Definition: boundBoxI.H:60
const point & max() const
Maximum point defining the bounding box.
Definition: boundBoxI.H:66
bool contains(const point &) const
Contains point? (inside or on edge)
Definition: boundBoxI.H:176
Named list of cell indices representing a sub-set of the mesh.
Definition: cellZone.H:61
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:740
A special matrix type and solver, designed for finite volume solutions of scalar equations....
Definition: fvMatrix.H:118
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:96
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:420
A class representing the concept of a GeometricField of 1 used to avoid unnecessary manipulations for...
labelHashSet patchSet(const UList< wordRe > &patchNames, const bool warnNotFound=true, const bool usePatchGroups=true) const
Return the patch set corresponding to the given names.
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:449
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:401
Top level model for porosity models.
Definition: porosityModel.H:57
const word zoneName_
Automatically generated zone name for this porous zone.
const scalarField & Av() const
Return the porosity surface area per unit volume zone field.
powerLawLopesdaCostaZone(const word &name, const fvMesh &mesh, const dictionary &dict, const dictionary &coeffDict)
Constructor.
scalarField Av_
Porosity surface area per unit volume zone field.
Variant of the power law porosity model with spatially varying drag coefficient.
powerLawLopesdaCosta(const word &name, const fvMesh &mesh, const dictionary &dict, const dictionary &coeffDict, const word &cellZoneName)
virtual void calcForce(const volVectorField &U, const volScalarField &rho, const volScalarField &mu, vectorField &force) const
Calculate the porosity force.
virtual void correct(fvVectorMatrix &UEqn) const
Add resistance.
virtual void calcTransformModelData()
Transform the model data wrt mesh changes.
const vectorField & cellCentres() const
static const word & geometryDir()
Return the geometry directory name.
A surface geometry formed of discrete facets, e.g. triangles and/or quadrilaterals,...
virtual void findLine(const pointField &start, const pointField &end, List< pointIndexHit > &) const
Find first intersection on segment from start to end.
virtual tmp< pointField > points() const
Get the points that define the surface.
Helper class to search on triSurface.
void findLine(const pointField &start, const pointField &end, List< pointIndexHit > &info) const
static triSurface triangulate(const polyBoundaryMesh &mBesh, const labelHashSet &includePatches, const bool verbose=false)
Simple triangulation of (selected patches of) boundaryMesh. Needs.
Triangulated surface description with patch information.
Definition: triSurface.H:69
A class for handling words, derived from string.
Definition: word.H:62
fvVectorMatrix & UEqn
Definition: UEqn.H:11
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
A special matrix type and solver, designed for finite volume solutions of scalar equations.
label nPoints
U
Definition: pEqn.H:72
const dimensionedScalar mu
Atomic mass unit.
addToRunTimeSelectionTable(porosityModel, powerLawLopesdaCosta, mesh)
defineTypeNameAndDebug(powerLawLopesdaCosta, 0)
Namespace for OpenFOAM.
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
errorManip< error > abort(error &err)
Definition: errorManip.H:131
const dimensionSet dimLength
const dimensionSet dimForce
const dimensionSet dimVolume
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
error FatalError
const dimensionSet dimArea
void offset(label &lst, const label o)
dictionary dict