powerLawLopesdaCosta.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) 2018 OpenFOAM Foundation
9  Copyright (C) 2020-2022 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 
30 #include "powerLawLopesdaCosta.H"
31 #include "geometricOneField.H"
32 #include "fvMatrices.H"
33 #include "triSurfaceMesh.H"
34 #include "triSurfaceTools.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40  namespace porosityModels
41  {
44  }
45 }
46 
47 
48 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
49 
51 (
52  const word& name,
53  const word& modelType,
54  const fvMesh& mesh,
55  const dictionary& dict
56 )
57 :
58  zoneName_(name + ":porousZone")
59 {
60  const dictionary& coeffs(dict.optionalSubDict(modelType + "Coeffs"));
61 
62  // Vertical direction within porous region
63  vector zDir(coeffs.get<vector>("zDir"));
64 
65  // Span of the search for the cells in the porous region
66  scalar searchSpan(coeffs.get<scalar>("searchSpan"));
67 
68  // Top surface file name defining the extent of the porous region
69  const word topSurfaceFileName(coeffs.get<word>("topSurface"));
70 
71  // List of the ground patches defining the lower surface
72  // of the porous region
73  wordRes groundPatches(coeffs.get<wordRes>("groundPatches"));
74 
75  // Functional form of the porosity surface area per unit volume as a
76  // function of the normalized vertical position
77  autoPtr<Function1<scalar>> SigmaFunc
78  (
79  Function1<scalar>::New("Sigma", dict, &mesh)
80  );
81 
82  // Searchable triSurface for the top of the porous region
83  triSurfaceMesh searchSurf
84  (
85  IOobject
86  (
87  topSurfaceFileName,
88  mesh.time().constant(),
89  "triSurface",
90  mesh.time()
91  )
92  );
93 
94  // Limit the porous cell search to those within the lateral and vertical
95  // extent of the top surface
96 
97  boundBox surfBounds(searchSurf.points());
98  boundBox searchBounds
99  (
100  surfBounds.min() - searchSpan*zDir, surfBounds.max()
101  );
102 
103  const pointField& C = mesh.cellCentres();
104 
105  // List of cells within the porous region
106  labelList porousCells(C.size());
107  label porousCelli = 0;
108 
109  forAll(C, celli)
110  {
111  if (searchBounds.contains(C[celli]))
112  {
113  porousCells[porousCelli++] = celli;
114  }
115  }
116 
117  porousCells.setSize(porousCelli);
118 
119  pointField start(porousCelli);
120  pointField end(porousCelli);
121 
122  forAll(porousCells, porousCelli)
123  {
124  start[porousCelli] = C[porousCells[porousCelli]];
125  end[porousCelli] = start[porousCelli] + searchSpan*zDir;
126  }
127 
128  // Field of distance between the cell centre and the corresponding point
129  // on the porous region top surface
130  scalarField zTop(porousCelli);
131 
132  // Search the porous cells for those with a corresponding point on the
133  // porous region top surface
134  List<pointIndexHit> hitInfo;
135  searchSurf.findLine(start, end, hitInfo);
136 
137  porousCelli = 0;
138 
139  forAll(porousCells, celli)
140  {
141  const pointIndexHit& hit = hitInfo[celli];
142 
143  if (hit.hit())
144  {
145  porousCells[porousCelli] = porousCells[celli];
146 
147  zTop[porousCelli] =
148  (hit.point() - C[porousCells[porousCelli]]) & zDir;
149 
150  porousCelli++;
151  }
152  }
153 
154  // Resize the porous cells list and height field
155  porousCells.setSize(porousCelli);
156  zTop.setSize(porousCelli);
157 
158  // Create a triSurface for the ground patch(s)
159  triSurface groundSurface
160  (
162  (
163  mesh.boundaryMesh(),
164  mesh.boundaryMesh().patchSet(groundPatches),
165  searchBounds
166  )
167  );
168 
169  // Combine the ground triSurfaces across all processors
170  if (Pstream::parRun())
171  {
172  List<List<labelledTri>> groundSurfaceProcTris(Pstream::nProcs());
173  List<pointField> groundSurfaceProcPoints(Pstream::nProcs());
174 
175  groundSurfaceProcTris[Pstream::myProcNo()] = groundSurface;
176  groundSurfaceProcPoints[Pstream::myProcNo()] = groundSurface.points();
177 
178  Pstream::allGatherList(groundSurfaceProcTris);
179  Pstream::allGatherList(groundSurfaceProcPoints);
180 
181  label nTris = 0;
182  forAll(groundSurfaceProcTris, i)
183  {
184  nTris += groundSurfaceProcTris[i].size();
185  }
186 
187  List<labelledTri> groundSurfaceTris(nTris);
188  label trii = 0;
189  label offset = 0;
190  forAll(groundSurfaceProcTris, i)
191  {
192  forAll(groundSurfaceProcTris[i], j)
193  {
194  groundSurfaceTris[trii] = groundSurfaceProcTris[i][j];
195  groundSurfaceTris[trii][0] += offset;
196  groundSurfaceTris[trii][1] += offset;
197  groundSurfaceTris[trii][2] += offset;
198  trii++;
199  }
200  offset += groundSurfaceProcPoints[i].size();
201  }
202 
203  label nPoints = 0;
204  forAll(groundSurfaceProcPoints, i)
205  {
206  nPoints += groundSurfaceProcPoints[i].size();
207  }
208 
209  pointField groundSurfacePoints(nPoints);
210 
211  label pointi = 0;
212  forAll(groundSurfaceProcPoints, i)
213  {
214  forAll(groundSurfaceProcPoints[i], j)
215  {
216  groundSurfacePoints[pointi++] = groundSurfaceProcPoints[i][j];
217  }
218  }
219 
220  groundSurface = triSurface(groundSurfaceTris, groundSurfacePoints);
221  }
222 
223  // Create a searchable triSurface for the ground
224  triSurfaceSearch groundSearch(groundSurface);
225 
226  // Search the porous cells for the corresponding point on the ground
227 
228  start.setSize(porousCelli);
229  end.setSize(porousCelli);
230 
231  forAll(porousCells, porousCelli)
232  {
233  start[porousCelli] = C[porousCells[porousCelli]];
234  end[porousCelli] = start[porousCelli] - searchSpan*zDir;
235  }
236 
237  groundSearch.findLine(start, end, hitInfo);
238 
239  scalarField zBottom(porousCelli);
240 
241  forAll(porousCells, porousCelli)
242  {
243  const pointIndexHit& hit = hitInfo[porousCelli];
244 
245  if (hit.hit())
246  {
247  zBottom[porousCelli] =
248  (C[porousCells[porousCelli]] - hit.point()) & zDir;
249  }
250  }
251 
252  // Create the normalized height field
253  scalarField zNorm(zBottom/(zBottom + zTop));
254 
255  // Create the porosity surface area per unit volume zone field
256  Sigma_ = SigmaFunc->value(zNorm);
257 
258  // Create the porous region cellZone and add to the mesh cellZones
259 
260  cellZoneMesh& cellZones = const_cast<cellZoneMesh&>(mesh.cellZones());
261 
262  label zoneID = cellZones.findZoneID(zoneName_);
263 
264  if (zoneID == -1)
265  {
266  zoneID = cellZones.size();
267  cellZones.setSize(zoneID + 1);
268 
269  cellZones.set
270  (
271  zoneID,
272  new cellZone
273  (
274  zoneName_,
275  porousCells,
276  zoneID,
277  cellZones
278  )
279  );
280  }
281  else
282  {
284  << "Unable to create porous cellZone " << zoneName_
285  << ": zone already exists"
286  << abort(FatalError);
287  }
288 }
289 
290 
291 Foam::porosityModels::powerLawLopesdaCosta::powerLawLopesdaCosta
292 (
293  const word& name,
294  const word& modelType,
295  const fvMesh& mesh,
296  const dictionary& dict,
297  const word& dummyCellZoneName
298 )
299 :
300  powerLawLopesdaCostaZone(name, modelType, mesh, dict),
302  (
303  name,
304  modelType,
305  mesh,
306  dict,
307  powerLawLopesdaCostaZone::zoneName_
308  ),
309  Cd_(coeffs_.get<scalar>("Cd")),
310  C1_(coeffs_.get<scalar>("C1")),
311  rhoName_(coeffs_.getOrDefault<word>("rho", "rho"))
312 {}
313 
314 
315 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
316 
318 {}
319 
320 
321 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
322 
325 {
326  return Sigma_;
327 }
329 
331 {}
332 
333 
335 (
336  const volVectorField& U,
337  const volScalarField& rho,
338  const volScalarField& mu,
339  vectorField& force
340 ) const
341 {
342  scalarField Udiag(U.size(), Zero);
343  const scalarField& V = mesh_.V();
344 
345  apply(Udiag, V, rho, U);
346 
347  force = Udiag*U;
348 }
349 
350 
352 (
354 ) const
355 {
356  const vectorField& U = UEqn.psi();
357  const scalarField& V = mesh_.V();
358  scalarField& Udiag = UEqn.diag();
359 
360  if (UEqn.dimensions() == dimForce)
361  {
362  const volScalarField& rho =
363  mesh_.lookupObject<volScalarField>(rhoName_);
364 
365  apply(Udiag, V, rho, U);
366  }
367  else
368  {
369  apply(Udiag, V, geometricOneField(), U);
370  }
371 }
372 
373 
375 (
377  const volScalarField& rho,
378  const volScalarField& mu
379 ) const
380 {
381  const vectorField& U = UEqn.psi();
382  const scalarField& V = mesh_.V();
383  scalarField& Udiag = UEqn.diag();
384 
385  apply(Udiag, V, rho, U);
386 }
387 
388 
390 (
391  const fvVectorMatrix& UEqn,
392  volTensorField& AU
393 ) const
394 {
395  const vectorField& U = UEqn.psi();
396 
397  if (UEqn.dimensions() == dimForce)
398  {
399  const volScalarField& rho =
400  mesh_.lookupObject<volScalarField>(rhoName_);
401 
402  apply(AU, rho, U);
403  }
404  else
405  {
406  apply(AU, geometricOneField(), U);
407  }
408 }
409 
410 
412 {
413  dict_.writeEntry(name_, os);
414 
415  return true;
416 }
417 
418 
419 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
virtual void findLine(const pointField &start, const pointField &end, List< pointIndexHit > &) const
Find first intersection on segment from start to end.
Top level data entry class for use in dictionaries. Provides a mechanism to specify a variable as a c...
dictionary dict
Graphite solid properties.
Definition: C.H:46
defineTypeNameAndDebug(powerLawLopesdaCosta, 0)
Variant of the power law porosity model with spatially varying drag coefficient.
virtual void correct(fvVectorMatrix &UEqn) const
Add resistance.
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 scalarField & Sigma() const
Return the porosity surface area per unit volume zone field.
addToRunTimeSelectionTable(porosityModel, powerLawLopesdaCosta, mesh)
virtual tmp< pointField > points() const
Get the points that define the surface.
static triSurface triangulate(const polyBoundaryMesh &mBesh, const labelHashSet &includePatches, labelList &faceMap, const bool verbose=false)
Simple triangulation of (selected patches of) boundaryMesh. Needs.
static void apply(bitSet &selection, const Detail::parcelSelection::actionType action, const Predicate &accept, const UList< Type > &list, const AccessOp &aop)
PointIndexHit< point > pointIndexHit
A PointIndexHit with a 3D point.
Definition: pointIndexHit.H:58
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1049
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1074
Macros for easy insertion into run-time selection tables.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
powerLawLopesdaCostaZone(const word &name, const word &modelType, const fvMesh &mesh, const dictionary &dict)
Constructor.
IOoject and searching on triSurface.
static void allGatherList(List< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses linear/tree communication. ...
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1065
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
virtual void calcForce(const volVectorField &U, const volScalarField &rho, const volScalarField &mu, vectorField &force) const
Calculate the porosity force.
dynamicFvMesh & mesh
A class representing the concept of a GeometricField of 1 used to avoid unnecessary manipulations for...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
label findZoneID(const word &zoneName) const
Find zone index by name, return -1 if not found.
Definition: ZoneMesh.C:629
A class for handling words, derived from Foam::string.
Definition: word.H:63
label nPoints
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual void calcTransformModelData()
Transform the model data wrt mesh changes.
A List of wordRe with additional matching capabilities.
Definition: wordRes.H:53
A special matrix type and solver, designed for finite volume solutions of scalar equations. Face addressing is used to make all matrix assembly and solution loops vectorise.
Definition: fvPatchField.H:64
errorManip< error > abort(error &err)
Definition: errorManip.H:139
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
const dimensionSet dimForce
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
OBJstream os(runTime.globalPath()/outputName)
volScalarField & C
scalarField Sigma_
Porosity surface area per unit volume zone field.
const dimensionedScalar mu
Atomic mass unit.
U
Definition: pEqn.H:72
fvVectorMatrix & UEqn
Definition: UEqn.H:13
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
A special matrix type and solver, designed for finite volume solutions of scalar equations.
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
const word zoneName_
Automatically generated zone name for this porous zone.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
ZoneMesh< cellZone, polyMesh > cellZoneMesh
A ZoneMesh with the type cellZone.
Top level model for porosity models.
Definition: porosityModel.H:53
Namespace for OpenFOAM.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127