blockMeshTopology.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) 2011-2024 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 
26 #include "blockMesh.H"
27 #include "blockMeshTools.H"
28 #include "Time.H"
29 #include "preservePatchTypes.H"
30 #include "emptyPolyPatch.H"
31 #include "cyclicPolyPatch.H"
32 
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34 
35 template<class Source>
36 void Foam::blockMesh::checkPatchLabels
37 (
38  const Source& source,
39  const word& patchName,
40  const pointField& points,
41  faceList& patchFaces
42 ) const
43 {
44  forAll(patchFaces, facei)
45  {
46  face& f = patchFaces[facei];
47 
48  // Replace (<block> <face>) face description
49  // with the corresponding block face
50  if (f.size() == 2)
51  {
52  const label bi = f[0];
53  const label fi = f[1];
54 
55  if (bi >= size())
56  {
58  << "Block index out of range for patch face " << f << nl
59  << " Number of blocks = " << size()
60  << ", index = " << f[0] << nl
61  << " on patch " << patchName << ", face " << facei
62  << exit(FatalIOError);
63  }
64  else if (fi >= operator[](bi).blockShape().faces().size())
65  {
67  << "Block face index out of range for patch face " << f
68  << nl
69  << " Number of block faces = "
70  << operator[](bi).blockShape().faces().size()
71  << ", index = " << f[1] << nl
72  << " on patch " << patchName << ", face " << facei
73  << exit(FatalIOError);
74  }
75  else
76  {
77  f = operator[](bi).blockShape().faces()[fi];
78  }
79  }
80  else
81  {
82  forAll(f, fp)
83  {
84  if (f[fp] < 0)
85  {
87  << "Negative point label " << f[fp] << nl
88  << " on patch " << patchName << ", face " << facei
89  << exit(FatalIOError);
90  }
91  else if (f[fp] >= points.size())
92  {
94  << "Point label " << f[fp]
95  << " out of range 0.." << points.size() - 1 << nl
96  << " on patch " << patchName << ", face " << facei
97  << exit(FatalIOError);
98  }
99  }
100  }
101  }
102 }
103 
104 
105 void Foam::blockMesh::readPatches
106 (
107  const dictionary& meshDescription,
108  faceListList& tmpBlocksPatches,
111  wordList& nbrPatchNames
112 )
113 {
114  // Collect all variables
115  dictionary varDict(meshDescription.subOrEmptyDict("namedVertices"));
116  varDict.merge(meshDescription.subOrEmptyDict("namedBlocks"));
117 
118 
119  ITstream& patchStream(meshDescription.lookup("patches"));
120 
121  // Read number of patches in mesh
122  label nPatches = 0;
123 
124  token firstToken(patchStream);
125 
126  if (firstToken.isLabel())
127  {
128  nPatches = firstToken.labelToken();
129 
130  tmpBlocksPatches.setSize(nPatches);
133  nbrPatchNames.setSize(nPatches);
134  }
135  else
136  {
137  patchStream.putBack(firstToken);
138  }
139 
140  // Read beginning of blocks
141  patchStream.readBegin("patches");
142 
143  nPatches = 0;
144 
145  token lastToken(patchStream);
146  while
147  (
148  !(
149  lastToken.isPunctuation()
150  && lastToken.pToken() == token::END_LIST
151  )
152  )
153  {
154  if (tmpBlocksPatches.size() <= nPatches)
155  {
156  tmpBlocksPatches.setSize(nPatches + 1);
159  nbrPatchNames.setSize(nPatches + 1);
160  }
161 
162  patchStream.putBack(lastToken);
163 
164  patchStream
165  >> patchTypes[nPatches]
166  >> patchNames[nPatches];
167 
168  // Read patch faces
169  tmpBlocksPatches[nPatches] = blockMeshTools::read<face>
170  (
171  patchStream,
172  varDict
173  );
174 
175 
176  // Check for multiple patches
177  for (label i = 0; i < nPatches; i++)
178  {
179  if (patchNames[nPatches] == patchNames[i])
180  {
181  FatalIOErrorInFunction(patchStream)
182  << "Duplicate patch " << patchNames[nPatches]
183  << " at line " << patchStream.lineNumber()
184  << exit(FatalIOError);
185  }
186  }
187 
188  checkPatchLabels
189  (
190  patchStream,
192  vertices_,
193  tmpBlocksPatches[nPatches]
194  );
195 
196  nPatches++;
197 
198 
199  // Split old style cyclics
200 
201  if (patchTypes[nPatches-1] == cyclicPolyPatch::typeName)
202  {
203  word halfA = patchNames[nPatches-1] + "_half0";
204  word halfB = patchNames[nPatches-1] + "_half1";
205 
206  FatalIOErrorInFunction(patchStream)
207  << "Old-style cyclic definition."
208  << " Splitting patch "
209  << patchNames[nPatches-1] << " into two halves "
210  << halfA << " and " << halfB << endl
211  << " Alternatively use new 'boundary' dictionary syntax."
212  << exit(FatalIOError);
213 
214  // Add extra patch
215  if (tmpBlocksPatches.size() <= nPatches)
216  {
217  tmpBlocksPatches.setSize(nPatches + 1);
220  nbrPatchNames.setSize(nPatches + 1);
221  }
222 
223  // Update halfA info
224  patchNames[nPatches-1] = halfA;
225  nbrPatchNames[nPatches-1] = halfB;
226 
227  // Update halfB info
229  patchNames[nPatches] = halfB;
230  nbrPatchNames[nPatches] = halfA;
231 
232  // Split faces
233  if ((tmpBlocksPatches[nPatches-1].size() % 2) != 0)
234  {
235  FatalIOErrorInFunction(patchStream)
236  << "Size of cyclic faces is not a multiple of 2 :"
237  << tmpBlocksPatches[nPatches-1]
238  << exit(FatalIOError);
239  }
240  label sz = tmpBlocksPatches[nPatches-1].size()/2;
241  faceList unsplitFaces(tmpBlocksPatches[nPatches-1], true);
242  tmpBlocksPatches[nPatches-1] = faceList
243  (
244  SubList<face>(unsplitFaces, sz)
245  );
246  tmpBlocksPatches[nPatches] = faceList
247  (
248  SubList<face>(unsplitFaces, sz, sz)
249  );
250 
251  nPatches++;
252  }
253 
254  patchStream >> lastToken;
255  }
256  patchStream.putBack(lastToken);
257 
258  // Read end of blocks
259  patchStream.readEnd("patches");
260 }
261 
262 
263 void Foam::blockMesh::readBoundary
264 (
265  const dictionary& meshDescription,
267  faceListList& tmpBlocksPatches,
268  PtrList<dictionary>& patchDicts
269 )
270 {
271  // Collect all variables
272  dictionary varDict(meshDescription.subOrEmptyDict("namedVertices"));
273  varDict.merge(meshDescription.subOrEmptyDict("namedBlocks"));
274 
275 
276  // Read like boundary file
277  const PtrList<entry> patchesInfo
278  (
279  meshDescription.lookupOrDefault("boundary", PtrList<entry>())
280  );
281 
282  patchNames.setSize(patchesInfo.size());
283  tmpBlocksPatches.setSize(patchesInfo.size());
284  patchDicts.setSize(patchesInfo.size());
285 
286  forAll(tmpBlocksPatches, patchi)
287  {
288  const entry& patchInfo = patchesInfo[patchi];
289 
290  if (!patchInfo.isDict())
291  {
292  FatalIOErrorInFunction(meshDescription)
293  << "Entry " << patchInfo << " in boundary section is not a"
294  << " valid dictionary."
295  << exit(FatalIOError);
296  }
297 
298  patchNames[patchi] = patchInfo.keyword();
299 
300  // Construct patch dictionary
301  patchDicts.set(patchi, new dictionary(patchInfo.dict()));
302 
303  // Read block faces
304  tmpBlocksPatches[patchi] = blockMeshTools::read<face>
305  (
306  patchDicts[patchi].lookup("faces"),
307  varDict
308  );
309 
310 
311  checkPatchLabels
312  (
313  patchInfo.dict(),
315  vertices_,
316  tmpBlocksPatches[patchi]
317  );
318  }
319 }
320 
321 
322 void Foam::blockMesh::createCellShapes
323 (
324  cellShapeList& tmpBlockCells
325 )
326 {
327  const blockMesh& blocks = *this;
328 
329  tmpBlockCells.setSize(blocks.size());
330  forAll(blocks, blocki)
331  {
332  tmpBlockCells[blocki] = blocks[blocki].blockShape();
333  }
334 }
335 
336 
337 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
338 
339 void Foam::blockMesh::defaultPatchError
340 (
341  const word& defaultPatchName,
342  const dictionary& meshDescription
343 ) const
344 {
345  // This will be made a fatal error in a future release
346  // to ensure that the defaultPatch is handled explicitly
347  // avoiding common user errors
348  // FatalIOErrorInFunction(meshDescription)
349  IOWarningInFunction(meshDescription)
350  << "The 'defaultPatch' type must be specified"
351  " for the '" << defaultPatchName << "' patch, e.g. for snappyHexMesh"
352  << nl << nl
353  << " defaultPatch\n"
354  " {\n"
355  " name default; // optional\n"
356  " type patch;\n"
357  " }\n\n"
358  << "or for 2D meshes" << nl << nl
359  << " defaultPatch\n"
360  " {\n"
361  " name frontAndBack; // optional\n"
362  " type empty;\n"
363  " }\n"
364  << endl;
365  // << exit(FatalIOError);
366 }
367 
368 
369 Foam::polyMesh* Foam::blockMesh::createTopology
370 (
371  const IOdictionary& meshDescription,
372  const fileName& meshPath,
373  const word& regionName
374 )
375 {
376  checkBlockFaceOrientation = meshDescription.lookupOrDefault<Switch>
377  (
378  "checkBlockFaceOrientation",
379  true
380  );
381 
382  blockList& blocks = *this;
383 
384  word defaultPatchName = "defaultFaces";
385  word defaultPatchType = emptyPolyPatch::typeName;
386  bool defaultPatchTypeSet = false;
387 
388  // Read the names/types for the unassigned patch faces
389  // this is a bit heavy handed (and ugly), but there is currently
390  // no easy way to rename polyMesh patches subsequently
391  if (const dictionary* dictPtr = meshDescription.subDictPtr("defaultPatch"))
392  {
393  dictPtr->readIfPresent("name", defaultPatchName);
394  defaultPatchType = dictPtr->lookup<word>("type");
395  defaultPatchTypeSet = true;
396  }
397 
398  // Optional 'convertToMeters' or 'scale' scaling factor
399  if (!meshDescription.readIfPresent("convertToMeters", scaleFactor_))
400  {
401  meshDescription.readIfPresent("scale", scaleFactor_);
402  }
403 
404  // Read the block edges
405  if (meshDescription.found("edges"))
406  {
407  if (verboseOutput)
408  {
409  Info<< "Creating block edges" << endl;
410  }
411 
412  blockEdgeList edges
413  (
414  meshDescription.lookup("edges"),
415  blockEdge::iNew(meshDescription, geometry_, vertices_)
416  );
417 
418  edges_.transfer(edges);
419  }
420  else if (verboseOutput)
421  {
422  Info<< "No non-linear block edges defined" << endl;
423  }
424 
425 
426  // Read the block faces
427  if (meshDescription.found("faces"))
428  {
429  if (verboseOutput)
430  {
431  Info<< "Creating block faces" << endl;
432  }
433 
434  blockFaceList faces
435  (
436  meshDescription.lookup("faces"),
437  blockFace::iNew(meshDescription, geometry_)
438  );
439 
440  faces_.transfer(faces);
441  }
442  else if (verboseOutput)
443  {
444  Info<< "No non-planar block faces defined" << endl;
445  }
446 
447 
448  // Create the blocks
449  if (verboseOutput)
450  {
451  Info<< "Creating topology blocks" << endl;
452  }
453  {
454  blockList blocks
455  (
456  meshDescription.lookup("blocks"),
457  block::iNew(meshDescription, vertices_, edges_, faces_)
458  );
459 
460  transfer(blocks);
461  }
462 
463 
464 
465  polyMesh* blockMeshPtr = nullptr;
466 
467  // Create the patches
468 
469  if (verboseOutput)
470  {
471  Info<< "Creating topology patches" << endl;
472  }
473 
474  if (meshDescription.found("patches"))
475  {
476  IOWarningInFunction(meshDescription)
477  << "Reading patches section" << nl
478  << " The 'patches' entry is deprecated and has been superseded"
479  << " by the more consistent and general 'boundary' entry."
480  << endl;
481 
482  faceListList tmpBlocksPatches;
485  wordList nbrPatchNames;
486 
487  readPatches
488  (
489  meshDescription,
490  tmpBlocksPatches,
491  patchNames,
492  patchTypes,
493  nbrPatchNames
494  );
495 
496  Info<< nl << "Creating block mesh topology" << endl;
497 
498  cellShapeList tmpBlockCells(blocks.size());
499  createCellShapes(tmpBlockCells);
500 
501  Info<< nl << "Reading physicalType from existing boundary file" << endl;
502 
503  PtrList<dictionary> patchDicts(patchNames.size());
504  word defaultFacesType;
505 
507  (
508  meshDescription.time(),
509  meshPath,
511  patchNames,
512  patchDicts,
513  defaultPatchName,
514  defaultPatchType
515  );
516 
517  // Add cyclic info (might not be present from older file)
519  {
520  if (!patchDicts.set(patchi))
521  {
522  patchDicts.set(patchi, new dictionary());
523  }
524 
525  dictionary& dict = patchDicts[patchi];
526 
527  // Add but not override type
528  if (!dict.found("type"))
529  {
530  dict.add("type", patchTypes[patchi], false);
531  }
532  else if (word(dict.lookup("type")) != patchTypes[patchi])
533  {
534  FatalIOErrorInFunction(meshDescription)
535  << "For patch " << patchNames[patchi]
536  << " overriding type '" << patchTypes[patchi]
537  << "' with '" << word(dict.lookup("type"))
538  << "' (read from boundary file)"
539  << exit(FatalIOError);
540  }
541 
542  // Override neighbourpatch name
543  if (nbrPatchNames[patchi] != word::null)
544  {
545  dict.set("neighbourPatch", nbrPatchNames[patchi]);
546  }
547  }
548 
549  blockMeshPtr = new polyMesh
550  (
551  IOobject
552  (
553  regionName,
554  meshPath,
555  meshDescription.time(),
558  false
559  ),
560  clone(vertices_), // Copy these points, do NOT move
561  tmpBlockCells,
562  tmpBlocksPatches,
563  patchNames,
564  patchDicts,
565  defaultPatchName,
566  defaultPatchType
567  );
568 
569  if
570  (
571  !defaultPatchTypeSet
572  && blockMeshPtr->boundaryMesh().findIndex(defaultPatchName) != -1
573  )
574  {
575  defaultPatchError(defaultPatchName, meshDescription);
576  }
577  }
578  else
579  {
581  faceListList tmpBlocksPatches;
582  PtrList<dictionary> patchDicts;
583 
584  readBoundary
585  (
586  meshDescription,
587  patchNames,
588  tmpBlocksPatches,
589  patchDicts
590  );
591 
592  Info<< nl << "Creating block mesh topology" << endl;
593 
594  cellShapeList tmpBlockCells(blocks.size());
595  createCellShapes(tmpBlockCells);
596 
597  blockMeshPtr = new polyMesh
598  (
599  IOobject
600  (
601  regionName,
602  meshPath,
603  meshDescription.time(),
606  false
607  ),
608  clone(vertices_), // Copy these points, do NOT move
609  tmpBlockCells,
610  tmpBlocksPatches,
611  patchNames,
612  patchDicts,
613  defaultPatchName,
614  defaultPatchType
615  );
616 
617  if
618  (
619  !defaultPatchTypeSet
620  && blockMeshPtr->boundaryMesh().findIndex(defaultPatchName) != -1
621  )
622  {
623  defaultPatchError(defaultPatchName, meshDescription);
624  }
625  }
626 
627  check(*blockMeshPtr, meshDescription);
628 
629  return blockMeshPtr;
630 }
631 
632 
633 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
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
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
const T & operator[](const label) const
Return element const reference.
Definition: UPtrListI.H:105
const blockFaceList & faces() const
Return the curved faces.
Definition: blockMesh.H:267
const pointField & points() const
The points for the entire mesh.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:740
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:1020
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:539
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:273
@ END_LIST
Definition: token.H:110
static const word null
An empty word.
Definition: word.H:77
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
label patchi
const pointField & points
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< cellShape > cellShapeList
List of cellShapes and PtrList of List of cellShape.
Definition: cellShapeList.H:43
List< word > wordList
A List of words.
Definition: fileName.H:54
PtrList< blockFace > blockFaceList
A PtrList of blockFaces.
Definition: blockFaceList.H:45
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:258
const word & regionName(const solver &region)
Definition: solver.H:218
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
PtrList< block > blockList
A PtrList of blocks.
Definition: blockList.H:45
PtrList< blockEdge > blockEdgeList
A PtrList of blockEdges.
Definition: blockEdgeList.H:45
List< faceList > faceListList
Definition: faceListFwd.H:43
T clone(const T &t)
Definition: List.H:55
void preservePatchTypes(const objectRegistry &obr, const word &meshInstance, const fileName &meshDir, const wordList &patchNames, PtrList< dictionary > &patchDicts, const word &defaultFacesName, word &defaultFacesType)
Preserve patch types.
IOerror FatalIOError
List< face > faceList
Definition: faceListFwd.H:41
static const char nl
Definition: Ostream.H:267
preservePatchTypes
wordList patchTypes(nPatches)
wordList patchNames(nPatches)
PtrList< dictionary > patchDicts
Definition: readKivaGrid.H:531
labelList f(nPoints)
word defaultFacesType
Definition: readKivaGrid.H:455
label nPatches
Definition: readKivaGrid.H:396
dictionary dict
word meshPath
Definition: setMeshPath.H:1