FIREMeshReader.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) 2016-2021 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 "FIREMeshReader.H"
29#include "wallPolyPatch.H"
30#include "ListOps.H"
31#include "IFstream.H"
32
33
34// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35
37(
38 ISstream& is,
39 const scalar scaleFactor
40)
41{
42 const label n = FIRECore::readPoints(is, points_);
43 // the above has FatalError if there are no points
44
45 Info<< "Number of points = " << n << endl;
46 if (scaleFactor > 1.0 + SMALL || scaleFactor < 1.0 - SMALL)
47 {
48 points_ *= scaleFactor;
49 }
50}
51
52
54{
55 const label nFaces = getFireLabel(is);
56 Info<< "Number of faces = " << nFaces << endl;
57 meshFaces_.setSize(nFaces);
58
59 if (nFaces > 0)
60 {
61 forAll(meshFaces_, faceI)
62 {
63 const label size = getFireLabel(is);
64
65 face& f = meshFaces_[faceI];
66 f.setSize(size);
67 forAll(f, fp)
68 {
69 f[fp] = getFireLabel(is);
70 }
71
72 // flip in-place
73 f.flip();
74 }
75 }
76 else
77 {
79 << "no faces in file " << is.name()
80 << abort(FatalError);
81 }
82}
83
84
86{
87 const label nCells = getFireLabel(is);
88 Info<< "Number of cells = " << nCells << endl;
89
90 owner_.setSize(meshFaces_.size());
91 neigh_.setSize(meshFaces_.size());
92
93 owner_ = -1;
94 neigh_ = -1;
95
96 if (nCells > 0)
97 {
98 for (label cellI = 0; cellI < nCells; ++cellI)
99 {
100 const label nface = getFireLabel(is);
101
102 for (label i = 0; i < nface; ++i)
103 {
104 const label faceI = getFireLabel(is);
105
106 if (owner_[faceI] == -1)
107 {
108 owner_[faceI] = cellI;
109 }
110 else if (neigh_[faceI] == -1)
111 {
112 neigh_[faceI] = cellI;
113 }
114 else
115 {
116 Warning
117 << "bad cell connectivity for face " << faceI
118 << " on cell " << cellI
119 << endl;
120 }
121 }
122 }
123 }
124 else
125 {
127 << "no cells in file " << is.name()
128 << abort(FatalError);
129 }
130
131 cellTableId_.setSize(nCells);
132 cellTableId_ = -1;
133}
134
135
137{
138 const label nSelect = getFireLabel(is);
139 Info<< "Number of select = " << nSelect << endl;
140
141 label nCellSelections = 0;
142 label nFaceSelections = 0;
143
144 faceZoneId_.setSize(meshFaces_.size());
145 faceZoneId_ = -1;
146
147 DynamicList<word> faceNames(32);
148
149 for (label selI = 0; selI < nSelect; ++selI)
150 {
151 std::string name = getFireString(is);
152 const label selType = getFireLabel(is);
153 const label count = getFireLabel(is);
154
155 if (selType == FIRECore::cellSelection)
156 {
157 // index starting at 1
158 const label selId = ++nCellSelections;
159
160 cellTable_.setName(selId, word::validate(name, true));
161 cellTable_.setMaterial(selId, "fluid");
162
163 for (label i = 0; i < count; ++i)
164 {
165 const label cellId = getFireLabel(is);
166
167 cellTableId_[cellId] = selId;
168 }
169 }
170 else if (selType == FIRECore::faceSelection)
171 {
172 // index starting at 0
173 const label selId = nFaceSelections++;
174
175 faceNames.append(word::validate(name, true));
176
177 for (label i = 0; i < count; ++i)
178 {
179 const label faceId = getFireLabel(is);
180
181 faceZoneId_[faceId] = selId;
182 }
183 }
184 else
185 {
186 // discard other selection types (eg, nodes)
187 for (label i = 0; i < count; ++i)
188 {
189 getFireLabel(is);
190 }
191 }
192 }
193
194 Info<< nFaceSelections << " face selections" << endl;
195 Info<< nCellSelections << " cell selections" << endl;
196
197 // add extra for missed boundary faces
198 faceNames.append("__MISSED_FACES__");
199 faceNames_.transfer(faceNames);
200}
201
202
204{
205 nInternalFaces_ = 0;
206
207 // pass 1:
208 // count internal faces and also swap owner <-> neigh as required
209 forAll(meshFaces_, faceI)
210 {
211 if (neigh_[faceI] != -1)
212 {
213 ++nInternalFaces_;
214
215 if (owner_[faceI] > neigh_[faceI])
216 {
217 std::swap(owner_[faceI], neigh_[faceI]);
218 }
219 }
220 }
221
222 label posInternal = 0;
223 label posExternal = nInternalFaces_;
224
225 labelList oldToNew(meshFaces_.size(), -1);
226
227 // pass 2:
228 // mapping to ensure proper division of internal / external
229 forAll(meshFaces_, faceI)
230 {
231 if (neigh_[faceI] == -1)
232 {
233 oldToNew[faceI] = posExternal++;
234 }
235 else
236 {
237 oldToNew[faceI] = posInternal++;
238 }
239 }
240
241 inplaceReorder(oldToNew, meshFaces_);
242 inplaceReorder(oldToNew, owner_);
243 inplaceReorder(oldToNew, neigh_);
244 inplaceReorder(oldToNew, faceZoneId_);
245
246 // Determine the patch sizes
247 // - faceNames_ already has extra place for missed faces
248 const label zoneMissed = faceNames_.size() - 1;
249 patchSizes_.setSize(faceNames_.size());
250 patchSizes_ = 0;
251
252 patchStarts_.setSize(patchSizes_.size());
253 patchStarts_ = 0;
254
255 for (label faceI = nInternalFaces_; faceI < meshFaces_.size(); ++faceI)
256 {
257 label zoneI = faceZoneId_[faceI];
258 if (zoneI == -1)
259 {
260 ++patchSizes_[zoneMissed];
261 }
262 else
263 {
264 ++patchSizes_[zoneI];
265 }
266 }
267
268 if (patchSizes_[zoneMissed])
269 {
270 Info<<"collecting " << patchSizes_[zoneMissed]
271 << " missed boundary faces to final patch" << endl;
272 }
273
274 oldToNew = -1;
275
276 // calculate the patch starts
277 {
278 label pos = nInternalFaces_;
279
280 forAll(patchStarts_, patchI)
281 {
282 patchStarts_[patchI] = pos;
283 pos += patchSizes_[patchI];
284 }
285
286 forAll(patchSizes_, patchI)
287 {
288 patchSizes_[patchI] = 0;
289 }
290 }
291
292 // reordering
293 for (label faceI = nInternalFaces_; faceI < meshFaces_.size(); ++faceI)
294 {
295 label patchI = faceZoneId_[faceI];
296 if (patchI == -1)
297 {
298 oldToNew[faceI] =
299 patchStarts_[zoneMissed] + patchSizes_[zoneMissed];
300 ++patchSizes_[zoneMissed];
301 }
302 else
303 {
304 oldToNew[faceI] = patchStarts_[patchI] + patchSizes_[patchI];
305 ++patchSizes_[patchI];
306 }
307 }
308
309 // discard old information
310 faceZoneId_.clear();
311
312 inplaceReorder(oldToNew, meshFaces_);
313 inplaceReorder(oldToNew, owner_);
314 inplaceReorder(oldToNew, neigh_);
315
316 //--- neigh_.setSize(nInternalFaces_);
317
318 // finally reduce to the number of patches actually used
319 patchNames_.setSize(patchSizes_.size());
320 oldToNew = -1;
321
322 label nPatches = 0;
323 forAll(patchSizes_, patchI)
324 {
325 if (patchSizes_[patchI])
326 {
327 patchNames_[nPatches] = faceNames_[patchI];
328
329 oldToNew[patchI] = nPatches;
330 ++nPatches;
331 }
332 }
333
334 inplaceReorder(oldToNew, patchStarts_);
335 inplaceReorder(oldToNew, patchSizes_);
336
337 patchStarts_.setSize(nPatches);
338 patchSizes_.setSize(nPatches);
339 patchNames_.setSize(nPatches);
340}
341
342
344{
345 // create patches
346 List<polyPatch*> newPatches(patchSizes_.size());
347
348 label meshFaceI = nInternalFaces_;
349
350 forAll(patchStarts_, patchI)
351 {
352 Info<< "patch " << patchI
353 << " (start: " << meshFaceI << " size: " << patchSizes_[patchI]
354 << ") name: " << patchNames_[patchI]
355 << endl;
356
357 // don't know anything better - just make it a wall
358 newPatches[patchI] = new polyPatch
359 (
360 patchNames_[patchI],
361 patchSizes_[patchI],
362 meshFaceI,
363 patchI,
364 mesh.boundaryMesh(),
366 );
367
368 meshFaceI += patchSizes_[patchI];
369 }
370
371 mesh.addPatches(newPatches);
372}
373
374
375// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
376
378{
380
381 const word ext(geometryFile_.ext());
382
383 bool supported = FIRECore::file3dExtensions.found(ext);
384
385 if (supported)
386 {
388 if (fireFileType == FIRECore::POLY_ASCII)
389 {
390 fmt = IOstream::ASCII;
391 }
392 else if (fireFileType == FIRECore::POLY_BINARY)
393 {
394 fmt = IOstream::BINARY;
395 }
396 else
397 {
398 // compressed or something
399 supported = false;
400 }
401 }
402
403 if (!supported)
404 {
406 << "File-type '" << ext
407 << "' is not supported for reading as a FIRE mesh." << nl
408 << "If it is a compressed file, use gunzip first."
409 << abort(FatalError);
410 }
411
412 IFstream is(geometryFile_, fmt);
413
414 readPoints(is, scaleFactor);
415 readFaces(is);
416 readCells(is);
417 readSelections(is);
418
419 return true;
420}
421
423(
424 const objectRegistry& registry
425)
426{
427 readGeometry(scaleFactor_);
428 reorganize();
429
430 Info<< "Creating a polyMesh" << endl;
431
433 (
435 (
437 "constant",
438 registry,
441 ),
442 std::move(points_),
443 std::move(meshFaces_),
444 std::move(owner_),
445 std::move(neigh_)
446 );
448
449 // adding patches also checks the mesh
450 addPatches(mesh);
451
452 cellTable_.addCellZones(mesh, cellTableId_);
453
454 // addFaceZones(mesh);
455
456 return meshPtr;
457}
458
459// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
460
462(
463 const fileName& name,
464 const scalar scaleFactor
465)
466:
467 meshReader(name, scaleFactor),
468 owner_(),
469 neigh_(),
470 faceZoneId_(),
471 faceNames_()
472{}
473
474
475// ************************************************************************* //
Various functions to operate on Lists.
label n
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
bool found(const word &enumName) const
True if there is an enumeration corresponding to the given name.
Definition: EnumI.H:103
Input from file stream, using an ISstream.
Definition: IFstream.H:57
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
streamFormat
Data format (ascii | binary)
Generic input stream using a standard (STL) stream.
Definition: ISstream.H:58
virtual const fileName & name() const
Return the name of the stream.
Definition: ISstream.H:113
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
Face selection method for createBaffles.
Definition: faceSelection.H:59
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
static const Enum< fileExt3d > file3dExtensions
Definition: FIRECore.H:106
fileExt3d
Enumeration defining the file extensions for 3D types.
Definition: FIRECore.H:87
static label readPoints(ISstream &, pointField &)
Read points.
Definition: FIRECore.C:48
Read AVL/FIRE fpma, fpmb files.
void readFaces(ISstream &)
Read points from file.
void readCells(ISstream &)
Read cell connectivities from file.
void readSelections(ISstream &)
Read cell/face selections from file.
void addPatches(polyMesh &) const
virtual bool readGeometry(const scalar scaleFactor=1.0)
Read the mesh from the file(s)
void readPoints(ISstream &, const scalar scaleFactor=1.0)
Read points from file.
A class for handling file names.
Definition: fileName.H:76
virtual void validate()
Validate the turbulence fields after construction.
Definition: kkLOmega.C:597
This class supports creating polyMeshes with baffles.
Definition: meshReader.H:69
pointField points_
Points supporting the mesh.
Definition: meshReader.H:216
Registry of regIOobjects.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:321
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:75
A class for handling words, derived from Foam::string.
Definition: word.H:68
dynamicFvMesh & mesh
Foam::autoPtr< Foam::dynamicFvMesh > meshPtr
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
const labelList nFaces(UPstream::listGatherValues< label >(aMesh.nFaces()))
const label nPatches
label cellId
label faceId(-1)
dimensionedScalar pos(const dimensionedScalar &ds)
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
void inplaceReorder(const labelUList &oldToNew, ListType &input, const bool prune=false)
Inplace reorder the elements of a list.
errorManip< error > abort(error &err)
Definition: errorManip.H:144
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
messageStream Warning
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
labelList f(nPoints)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333