columnFvMesh.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-2022 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
28#include "columnFvMesh.H"
30#include "IOobjectList.H"
31#include "fieldDictionary.H"
32#include "vectorIOField.H"
33#include "emptyPolyPatch.H"
34#include "topoSet.H"
36
37// * * * * * * * * * * * * * * * Static Members * * * * * * * * * * * * * * //
38
39namespace Foam
40{
41namespace simplifiedMeshes
42{
45
47 (
50 time
51 );
52}
53}
54
55
56// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
57
58bool Foam::simplifiedMeshes::columnFvMeshInfo::setPatchEntries
59(
60 const Time& runTime
61)
62{
63 IOobject boundaryIO
64 (
65 "boundary",
68 runTime,
71 false
72 );
73
74 const wordHashSet constraintPatches(polyPatch::constraintTypes());
75
76 if (boundaryIO.typeHeaderOk<polyBoundaryMesh>(true))
77 {
78 polyBoundaryMeshEntries allPatchEntries(boundaryIO);
79
80 Info<< "Creating simplified mesh using " << allPatchEntries.path()
81 << endl;
82
83 for (const entry& e : allPatchEntries)
84 {
85 const word type(e.dict().get<word>("type"));
86
87 if (!constraintPatches.found(type))
88 {
89 if (e.dict().get<label>("nFaces"))
90 {
92 }
93 patchEntries_.add(e.keyword(), e.dict());
94 }
95 }
96
97 return true;
98 }
99 else
100 {
101 // No boundary file - try reading from a field
102 IOobjectList objects
103 (
104 runTime,
107 );
108
109 if (objects.empty())
110 {
111 // No fields - cannot create a mesh
112 return false;
113 }
114
115 const IOobject& io = *objects.begin()();
116
117 if (io.instance() == runTime.constant())
118 {
120 << "No time directories found for field reading"
121 << exit(FatalError);
122 }
123
124 const fieldDictionary fieldDict(io, io.headerClassName());
125
126 Info<< "Creating simplified mesh from field "
127 << fieldDict.objectPath()
128 << endl;
129
131 << "All boundaries will be approximated using wall-type patches. "
132 << "This may cause your" << nl
133 << " final case to run differently. "
134 << "Create your mesh first for improved performance"
135 << endl;
136
137 const dictionary& boundaryFieldDict =
138 fieldDict.subDict("boundaryField");
139
140 for (const entry& e : boundaryFieldDict)
141 {
142 const word type(e.dict().get<word>("type"));
143
145 {
146 if (!constraintPatches.found(type))
147 {
149 dictionary simplifiedEntries;
150 simplifiedEntries.add("startFace", 0);
151 simplifiedEntries.add("nFaces", 1);
152 simplifiedEntries.add("type", "wall"); // default to wall
153
154 patchEntries_.add(e.keyword(), simplifiedEntries);
155 }
156 }
157 else
158 {
159 Info<< "Ignoring unknown patch type " << type << endl;
160 }
161 }
162
163 return false;
164 }
165}
166
167
169{
170 DebugInfo << "Constructing 1-D mesh" << nl << endl;
171
172 // Read patches - filter out proc patches for parallel runs
173 createFromMesh_ = setPatchEntries(runTime);
174
175 const label nPatch = patchEntries_.size();
176
177 DebugPout << "Read " << nPatch << " patches" << endl;
178
179 /*
180 3 ---- 7
181 f5 |\ |\ f2
182 | | 2 ---- 6 \
183 | 0 |--- 4 | \
184 | \| \| f3
185 f4 1 ---- 5
186
187 f0 ----- f1
188 */
189
190 // Create mesh with nPatchWithFace hex cells
191 // - hex face 1: set internal face to link to next hex cell
192 // - hex face 2,3,4,5: set to boundary condition
193 //
194 // TODO: Coupled patches:
195 // - separated/collocated cyclic - faces 2 and 3
196 // - rotational cyclic - convert to separated and warn not handled?
197 // - proc patches - faces need to be collocated?
198
199 points1D_.setSize(nPatchWithFace_*4 + 4);
200 faces1D_.setSize(nPatchWithFace_*5 + 1);
201
202 owner1D_.setSize(faces1D_.size(), label(-1));
203 neighbour1D_.setSize(owner1D_.size(), label(-1));
204
205 vector dx(Zero);
206 {
207 // Determine the mesh bounds
208 IOobject pointsIO
209 (
210 "points",
211 localInstance_,
213 runTime,
216 false
217 );
218
219 scalar dxi = 0;
220 scalar dyi = 0;
221 scalar dzi = 0;
222 point origin(Zero);
223
224 if (pointsIO.typeHeaderOk<vectorIOField>(true))
225 {
226 const pointIOField meshPoints(pointsIO);
227
228 boundBox meshBb(meshPoints, true);
229
230 Info<< "Mesh bounds: " << meshBb << endl;
231
232 origin = meshBb.min();
233 vector span = meshBb.span();
234 dxi = span.x()/scalar(nPatchWithFace_);
235 dyi = span.y();
236 dzi = span.z();
237 }
238 else
239 {
240 scalar Lref = GREAT;
241 origin = point(-Lref, -Lref, -Lref);
242 dxi = 2.0*Lref/scalar(nPatchWithFace_);
243 dyi = Lref;
244 dzi = Lref;
245 }
246
247 dx = vector(dxi, 0, 0);
248 const vector dy(0, dyi, 0);
249 const vector dz(0, 0, dzi);
250
251 // End face
252 points1D_[0] = origin;
253 points1D_[1] = origin + dy;
254 points1D_[2] = origin + dy + dz;
255 points1D_[3] = origin + dz;
256 }
257
258 label n = 4;
259 for (label i = 1; i <= nPatchWithFace_; ++i)
260 {
261 const vector idx(i*dx);
262 points1D_[i*n] = points1D_[0] + idx;
263 points1D_[i*n + 1] = points1D_[1] + idx;
264 points1D_[i*n + 2] = points1D_[2] + idx;
265 points1D_[i*n + 3] = points1D_[3] + idx;
266 }
267
268 if (debug) Pout<< "points:" << points1D_ << endl;
269
270 label facei = 0;
271
272 // Internal faces first
273 for (label i = 0; i < nPatchWithFace_ - 1; ++i)
274 {
275 label o = i*4;
276 faces1D_[facei] = face({4 + o, 5 + o, 6 + o, 7 + o});
277 owner1D_[facei] = i;
278 neighbour1D_[facei] = i + 1;
279 ++facei;
280 }
281
282 // Boundary conditions
283 for (label i = 0; i < nPatchWithFace_; ++i)
284 {
285 label o = i*4;
286 faces1D_[facei] = face({0 + o, 4 + o, 7 + o, 3 + o});
287 owner1D_[facei] = i;
288 ++facei;
289
290 faces1D_[facei] = face({0 + o, 1 + o, 5 + o, 4 + o});
291 owner1D_[facei] = i;
292 ++facei;
293
294 faces1D_[facei] = face({1 + o, 2 + o, 6 + o, 5 + o});
295 owner1D_[facei] = i;
296 ++facei;
297
298 faces1D_[facei] = face({3 + o, 7 + o, 6 + o, 2 + o});
299 owner1D_[facei] = i;
300 ++facei;
301 }
302 {
303 // End caps
304 faces1D_[facei] = face({0, 3, 2, 1});
305 owner1D_[facei] = 0;
306 ++facei;
307
308 label o = 4*nPatchWithFace_;
309 faces1D_[facei] = face({0 + o, 1 + o, 2 + o, 3 + o});
310 owner1D_[facei] = nPatchWithFace_ - 1;
311 ++facei;
312 }
313
315 << "faces:" << faces1D_ << nl
316 << "owner:" << owner1D_ << nl
317 << "neighbour:" << neighbour1D_
318 << endl;
319}
320
321
322// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
323
325(
326 fvMesh& mesh
327) const
328{
329 const label nPatch = patchEntries_.size();
330
331 List<polyPatch*> patches(nPatch + 1);
332
333 label nInternalFace = nPatchWithFace_ - 1;
334 label startFace = nInternalFace;
335 label entryi = 0;
336 for (const entry& e : patchEntries_)
337 {
338 // Re-create boundary types, but reset nFaces and startFace settings
339 dictionary patchDict = e.dict();
340 const word& patchName = e.keyword();
341
342 DebugPout << "Setting " << patchName << endl;
343
344 label nFaces0 = patchDict.get<label>("nFaces");
345
346 if (nFaces0)
347 {
348 // Only set to 4 faces if there were faces in the original patch
349 nFaces0 = 4;
350 patchDict.set("nFaces", nFaces0);
351 }
352
353 patchDict.set("startFace", startFace);
354 patches[entryi] =
356 (
357 patchName,
358 patchDict,
359 entryi,
360 mesh.boundaryMesh()
361 ).ptr();
362
363 ++entryi;
364 startFace += nFaces0;
365 }
366
367 patches.last() = new emptyPolyPatch
368 (
369 typeName + ":default", // name
370 2, // number of faces
371 nInternalFace + 4*nPatchWithFace_, // start face
372 nPatch - 1, // index in boundary list
373 mesh.boundaryMesh(), // polyBoundaryMesh
374 emptyPolyPatch::typeName // patchType
375 );
376
377 mesh.addFvPatches(patches);
378
379 if (debug)
380 {
381 Pout<< "patches:" << nl << mesh.boundaryMesh() << endl;
382 }
383}
384
385
387{
388 if (createFromMesh_)
389 {
390 // Initialise the zones
391 initialiseZone<pointZoneMesh>
392 (
393 "point",
394 localInstance_,
395 mesh.pointZones()
396 );
397 initialiseZone<faceZoneMesh>("face", localInstance_, mesh.faceZones());
398 initialiseZone<cellZoneMesh>("cell", localInstance_, mesh.cellZones());
399 }
400}
401
402
403// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
404
406(
407 const Time& runTime,
408 const word& regionName
409)
410:
411 regionName_(regionName),
412 localInstance_
413 (
414 runTime.findInstance
415 (
416 polyMesh::regionName(regionName_)/polyMesh::meshSubDir,
417 "boundary",
418 IOobject::READ_IF_PRESENT
419 )
420 ),
421 createFromMesh_(false),
422 points1D_(),
423 faces1D_(),
424 owner1D_(),
425 neighbour1D_(),
426 patchEntries_(),
427 nPatchWithFace_(0)
428{
429 initialise(runTime);
430
431 // Dummy zones and sets created on demand
432 // Note: zones can be updated post-construction
435}
436
437
439(
440 const Time& runTime,
441 const word& regionName
442)
443:
446 (
448 (
451 runTime,
452 IOobject::NO_READ, // Do not read any existing mesh
453 IOobject::NO_WRITE
454 ),
455 std::move(points1D_),
456 std::move(faces1D_),
457 std::move(owner1D_),
458 std::move(neighbour1D_)
459 )
460{
461 // Workaround to read fvSchemes and fvSolution after setting NO_READ
462 // when creating the mesh
463 {
468 }
469
470 // Add the patches
471 addLocalPatches(*this);
472
473 // Add the zones if constructed from mesh
474 initialiseZones(*this);
475
476 if (debug)
477 {
480 }
481}
482
483
484// ************************************************************************* //
label n
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
const word & headerClassName() const noexcept
Return name of the class name read from header.
Definition: IOobjectI.H:83
readOption readOpt() const noexcept
The read option.
Definition: IOobjectI.H:164
const fileName & instance() const noexcept
Read access to instance path component.
Definition: IOobjectI.H:196
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
virtual bool read()
Re-read model coefficients if they have changed.
const word & constant() const
Return constant name.
Definition: TimePathsI.H:96
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:80
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
static word timeName(const scalar t, const int precision=precision_)
Definition: Time.C:780
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type get(const label i) const
Definition: UList.H:528
static int disallowGenericZones
Debug switch to disallow the use of generic zones.
Definition: ZoneMesh.H:106
static int debug
Debug switch.
Definition: data.H:77
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:640
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition: dictionary.C:780
Empty front and back plane patch. Used for 2-D geometries.
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:70
virtual bool write()
Write the output fields.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:91
constant condensation/saturation model.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
void setInstance(const fileName &instance, const IOobject::writeOption wOpt=IOobject::AUTO_WRITE)
Set the instance for mesh files.
Definition: polyMeshIO.C:36
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:324
const word & regionName() const
The mesh region name or word::null if polyMesh::defaultRegion.
Definition: polyMesh.C:854
static wordList constraintTypes()
Return a list of all the constraint patch types.
Definition: polyPatch.C:287
Functions to generate simplified finite volume meshes.
static bool fvPatchFieldExists(const word &patchType)
dictionary patchEntries_
Dictionary of patch information.
Definition: columnFvMesh.H:105
label nPatchWithFace_
Number of patches with at least 1 local face.
Definition: columnFvMesh.H:108
const word regionName_
Region of existing mesh.
Definition: columnFvMesh.H:78
const word localInstance_
Location of existing mesh (if present)
Definition: columnFvMesh.H:81
void addLocalPatches(fvMesh &mesh) const
Add the patches to the mesh.
Definition: columnFvMesh.C:325
void initialiseZones(fvMesh &mesh)
Initialise zones if constructed from mesh.
Definition: columnFvMesh.C:386
Generates a 1D column representation of a mesh based on an existing mesh and/or fields.
Definition: columnFvMesh.H:138
static int disallowGenericSets
Debug switch to disallow the use of generic sets.
Definition: topoSet.H:120
void initialise()
Initialise integral-scale box properties.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
engineTime & runTime
Foam::word regionName(Foam::polyMesh::defaultRegion)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
#define DebugInfo
Report an information message using Foam::Info.
#define WarningInFunction
Report a warning using Foam::Warning.
#define DebugPout
Report an information message using Foam::Pout.
Namespace for OpenFOAM.
messageStream Info
Information stream (stdout output on master, null elsewhere)
vector point
Point is a vector.
Definition: point.H:43
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:598
IOField< vector > vectorIOField
vectorField with IO.
Definition: vectorIOField.H:44
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
vectorIOField pointIOField
pointIOField is a vectorIOField.
Definition: pointIOField.H:44
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
HashSet< word, Hash< word > > wordHashSet
A HashSet of words, uses string hasher.
Definition: HashSet.H:82
error FatalError
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Vector< scalar > vector
Definition: vector.H:61
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
List< treeBoundBox > meshBb(1, treeBoundBox(boundBox(coarseMesh.points(), false)).extend(rndGen, 1e-3))
volScalarField & e
Definition: createFields.H:11
static const char *const typeName
The type name used in ensight case files.