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-2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
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;
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  polyPatchList 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.set
359  (
360  patchI,
361  new polyPatch
362  (
363  patchNames_[patchI],
364  patchSizes_[patchI],
365  meshFaceI,
366  patchI,
367  mesh.boundaryMesh(),
368  word::null
369  )
370  );
371 
372  meshFaceI += patchSizes_[patchI];
373  }
374 
375  mesh.addPatches(newPatches);
376 }
377 
378 
379 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
380 
381 bool Foam::fileFormats::FIREMeshReader::readGeometry(const scalar scaleFactor)
382 {
384 
385  const word ext(geometryFile_.ext());
386 
387  bool supported = FIRECore::file3dExtensions.found(ext);
388 
389  if (supported)
390  {
392  if (fireFileType == FIRECore::POLY_ASCII)
393  {
394  fmt = IOstreamOption::ASCII;
395  }
396  else if (fireFileType == FIRECore::POLY_BINARY)
397  {
399  }
400  else
401  {
402  // compressed or something
403  supported = false;
404  }
405  }
406 
407  if (!supported)
408  {
410  << "File-type '" << ext
411  << "' is not supported for reading as a FIRE mesh." << nl
412  << "If it is a compressed file, use gunzip first."
413  << abort(FatalError);
414  }
415 
416  IFstream is(geometryFile_, fmt);
417 
418  readPoints(is, scaleFactor);
419  readFaces(is);
420  readCells(is);
421  readSelections(is);
423  return true;
424 }
425 
427 (
428  const objectRegistry& registry
429 )
430 {
431  readGeometry(scaleFactor_);
432  reorganize();
433 
434  Info<< "Creating a polyMesh" << endl;
435 
437  (
438  IOobject
439  (
441  "constant",
442  registry,
445  ),
446  std::move(points_),
447  std::move(meshFaces_),
448  std::move(owner_),
449  std::move(neigh_)
450  );
451  polyMesh& mesh = *meshPtr;
452 
453  // adding patches also checks the mesh
454  addPatches(mesh);
455 
456  cellTable_.addCellZones(mesh, cellTableId_);
457 
458  // addFaceZones(mesh);
459 
460  return meshPtr;
461 }
462 
463 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
464 
466 (
467  const fileName& name,
468  const scalar scaleFactor
469 )
470 :
471  meshReader(name, scaleFactor),
472  owner_(),
473  neigh_(),
474  faceZoneId_(),
475  faceNames_()
476 {}
477 
478 
479 // ************************************************************************* //
label nPatches
Definition: readKivaGrid.H:396
static word validate(const std::string &s, const bool prefix=false)
Construct validated word (no invalid characters).
Definition: word.C:39
fileExt3d
Enumeration defining the file extensions for 3D types.
Definition: FIRECore.H:87
label faceId(-1)
A class for handling file names.
Definition: fileName.H:72
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
bool found(const word &key) const
Same as contains()
Definition: Enum.H:474
void readSelections(ISstream &)
Read cell/face selections from file.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
void inplaceReorder(const labelUList &oldToNew, ListType &input, const bool prune=false)
Inplace reorder the elements of a list.
"ascii" (normal default)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
void readPoints(ISstream &, const scalar scaleFactor=1.0)
Read points from file.
void readFaces(ISstream &)
Read points from file.
pointField points_
Points supporting the mesh.
Definition: meshReader.H:271
FIREMeshReader(const FIREMeshReader &)=delete
No copy construct.
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
dimensionedScalar pos(const dimensionedScalar &ds)
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
static label readPoints(ISstream &, pointField &)
Read points.
Definition: FIRECore.C:41
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
Foam::autoPtr< Foam::dynamicFvMesh > meshPtr
A class for handling words, derived from Foam::string.
Definition: word.H:63
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:405
void addPatches(polyMesh &) const
static const word null
An empty word.
Definition: word.H:84
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:584
virtual const fileName & name() const override
The name of the input serial stream. (eg, the name of the Fstream file name)
Definition: ISstream.H:141
errorManip< error > abort(error &err)
Definition: errorManip.H:139
labelList f(nPoints)
messageStream Warning
Warning stream (stdout output on master, null elsewhere), with additional &#39;FOAM Warning&#39; header text...
virtual autoPtr< polyMesh > mesh(const objectRegistry &)
Create and return polyMesh.
Generic input stream using a standard (STL) stream.
Definition: ISstream.H:51
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: List.H:55
label cellId
Nothing to be read.
Automatically write from objectRegistry::writeObject()
streamFormat
Data format (ascii | binary)
messageStream Info
Information stream (stdout output on master, null elsewhere)
label n
static const Enum< fileExt3d > file3dExtensions
Definition: FIRECore.H:111
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
void readCells(ISstream &)
Read cell connectivities from file.
Registry of regIOobjects.
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
This class supports creating polyMeshes with baffles.
Definition: meshReader.H:64
virtual bool readGeometry(const scalar scaleFactor=1.0)
Read the mesh from the file(s)