faMeshTools.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) 2012-2016 OpenFOAM Foundation
9  Copyright (C) 2015-2024 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 
29 #include "faMeshTools.H"
30 #include "faBoundaryMeshEntries.H"
31 #include "areaFields.H"
32 #include "edgeFields.H"
33 #include "fileOperation.H"
34 #include "BitOps.H"
35 #include "polyMesh.H"
36 #include "processorFaPatch.H"
37 
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
39 
41 {
42  auto& obr = const_cast<objectRegistry&>(mesh.thisDb());
43 
44  // Checkout by name (casting ambiguity)
45  obr.checkOut(faMesh::typeName);
46  obr.checkOut("faBoundaryMesh");
47  obr.checkOut("faSchemes");
48  obr.checkOut("faSolution");
49 }
50 
51 
53 {
54  (void)mesh.globalData();
55 
56  (void)mesh.Le();
57  (void)mesh.magLe();
58  (void)mesh.areaCentres();
59  (void)mesh.edgeCentres();
60 
61  (void)mesh.faceAreaNormals();
62  (void)mesh.edgeAreaNormals();
63  (void)mesh.pointAreaNormals();
64  (void)mesh.faceCurvatures();
65  (void)mesh.edgeTransformTensors();
66 
67  mesh.syncGeom();
68 }
69 
70 
73 (
74  const IOobject& io,
75  const polyMesh& pMesh,
76  const bool masterOnlyReading,
77  const bool verbose
78 )
79 {
80  // The mesh directory (assuming single area region), relative to Time
81  const fileName meshSubDir
82  (
84  );
85 
86 
87  fileName facesInstance;
88 
89  // Patch types
90  // ~~~~~~~~~~~
91  // Read and scatter master patches (without reading master mesh!)
92 
93  PtrList<entry> patchEntries;
94  if (UPstream::master())
95  {
96  const bool oldParRun = UPstream::parRun(false);
97 
98  facesInstance = io.time().findInstance
99  (
100  meshSubDir,
101  "faceLabels",
103  );
104 
105  patchEntries = faBoundaryMeshEntries
106  (
107  IOobject
108  (
109  "faBoundary",
110  facesInstance,
111  meshSubDir,
112  io.time(),
116  )
117  );
118 
119  UPstream::parRun(oldParRun);
120  }
121 
122  // Broadcast information to all
124  (
126  patchEntries,
127  facesInstance
128  );
129 
130 
131  // Dummy meshes
132  // ~~~~~~~~~~~~
133 
134  // Fake read-if-present behaviour to obtain the faceLabels
135 
136  IOobject meshIO(io);
137  meshIO.instance() = facesInstance;
138  meshIO.readOpt(IOobject::READ_IF_PRESENT);
139 
140  // For mesh components (faceLabels, ...)
141  IOobject cmptIO(io.time(), "faceLabels", meshSubDir);
142  cmptIO.instance() = facesInstance;
143  cmptIO.readOpt(IOobject::MUST_READ);
144  cmptIO.writeOpt(IOobject::NO_WRITE);
145  cmptIO.registerObject(IOobject::NO_REGISTER);
146 
147 
148  // Check who has a mesh
149 
150  const fileName meshDir = io.time().path()/facesInstance/meshSubDir;
151  bool haveMesh = isDir(meshDir);
152  if (masterOnlyReading && !UPstream::master())
153  {
154  haveMesh = false;
155  meshIO.readOpt(IOobject::NO_READ);
156  }
157 
158  if (!haveMesh)
159  {
160  cmptIO.readOpt(IOobject::NO_READ);
161  }
162 
163 
164  // Read mesh
165  // ~~~~~~~~~
166  // Now all processors use supplied points,faces etc
167  // Note: solution, schemes are also using the supplied IOobject so
168  // on slave will be NO_READ, on master READ_IF_PRESENT. This will
169  // conflict with e.g. timeStampMaster reading so switch off.
170 
171  const auto oldCheckType = IOobject::fileModificationChecking;
173 
174 
175  // faceLabels
176  cmptIO.rename("faceLabels");
177  labelIOList faceLabels(cmptIO);
178 
179 
181  (
182  pMesh,
183  std::move(faceLabels),
184  meshIO
185  );
186  auto& mesh = *meshPtr;
187 
188  IOobject::fileModificationChecking = oldCheckType;
189 
190 
191  // Some processors without patches? - add patches
192 
194  {
195  // Use patchEntries, which were read on master and broadcast
196 
197  faPatchList patches(patchEntries.size());
198  label nPatches = 0;
199 
200  const bool isEmptyMesh = (mesh.faceLabels().empty());
201 
202  forAll(patchEntries, patchi)
203  {
204  const entry& e = patchEntries[patchi];
205  const word type(e.dict().get<word>("type"));
206  const word& name = e.keyword();
207 
208  if
209  (
210  type == processorFaPatch::typeName
211  )
212  {
213  // Stop at the first processor patch.
214  // - logic will not work with inter-mixed proc-patches anyhow
215  break;
216  }
217  else
218  {
219  dictionary patchDict(e.dict());
220 
221  if (isEmptyMesh)
222  {
223  patchDict.set("edgeLabels", labelList());
224  }
225 
226  patches.set
227  (
228  patchi,
230  (
231  name,
232  patchDict,
233  nPatches++,
234  mesh.boundary()
235  )
236  );
237  }
238  }
239 
241  mesh.addFaPatches(patches, false); // No parallel comms
242  }
243 
244  // Recreate basic geometry, globalMeshData etc.
245  mesh.init(false);
246  (void)mesh.globalData();
247 
248  return meshPtr;
249 }
250 
251 
253 Foam::faMeshTools::loadOrCreateMeshImpl
254 (
255  const IOobject& io,
256  refPtr<fileOperation>* readHandlerPtr, // Can be nullptr
257  const polyMesh& pMesh,
258  const bool decompose,
259  const bool verbose
260 )
261 {
262  // The mesh directory (assuming single area region), relative to Time
263  const fileName meshSubDir
264  (
266  );
267 
268 
269  // Patch types
270  // ~~~~~~~~~~~
271  // Read and scatter master patches (without reading master mesh!)
272 
273  PtrList<entry> patchEntries;
274  if (UPstream::master())
275  {
276  const bool oldParRun = UPstream::parRun(false);
277  const label oldNumProcs = fileHandler().nProcs();
278  const int oldCache = fileOperation::cacheLevel(0);
279 
280  patchEntries = faBoundaryMeshEntries
281  (
282  IOobject
283  (
284  "faBoundary",
285  io.instance(),
286  meshSubDir,
287  io.time(),
291  )
292  );
293 
294  fileOperation::cacheLevel(oldCache);
295  if (oldParRun)
296  {
297  const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
298  }
299  UPstream::parRun(oldParRun);
300  }
301 
302  // Broadcast: send patches to all
304 
305 
306  // Check who has or needs a mesh.
307  bool haveLocalMesh = false;
308 
309  if (readHandlerPtr)
310  {
311  // Non-null reference when a mesh exists on given processor
312  haveLocalMesh = (*readHandlerPtr).good();
313  }
314  else
315  {
316  // No file handler.
317  // For 'decompose', only need mesh on master.
318  // Otherwise check for presence of the "faceLabels" file
319 
320  haveLocalMesh =
321  (
322  decompose
323  ? UPstream::master()
324  : fileHandler().isFile
325  (
326  fileHandler().filePath
327  (
328  io.time().path()/io.instance()/meshSubDir/"faceLabels"
329  )
330  )
331  );
332  }
333 
334 
335  // Globally consistent information about who has a mesh
336  boolList haveMesh
337  (
338  UPstream::allGatherValues<bool>(haveLocalMesh)
339  );
340 
341 
342  autoPtr<faMesh> meshPtr;
343 
344  if (!haveLocalMesh)
345  {
346  // No local mesh - need to synthesize one
347 
348  const bool oldParRun = UPstream::parRun(false);
349  const label oldNumProcs = fileHandler().nProcs();
350  const int oldCache = fileOperation::cacheLevel(0);
351 
352  // Create dummy mesh - on procs that don't already have a mesh
353  meshPtr.reset
354  (
355  new faMesh
356  (
357  pMesh,
358  labelList(), // Similar to Foam::zero{}
360  )
361  );
362  faMesh& mesh = *meshPtr;
363 
364  // Add patches
365  faPatchList patches(patchEntries.size());
366  label nPatches = 0;
367 
368  forAll(patchEntries, patchi)
369  {
370  const entry& e = patchEntries[patchi];
371  const word type(e.dict().get<word>("type"));
372  const word& name = e.keyword();
373 
374  if
375  (
376  type == processorFaPatch::typeName
377  )
378  {
379  // Stop at the first processor patch.
380  // - logic will not work with inter-mixed proc-patches anyhow
381  break;
382  }
383  else
384  {
385  dictionary patchDict(e.dict());
386  patchDict.set("edgeLabels", labelList());
387 
388  patches.set
389  (
390  patchi,
392  (
393  name,
394  patchDict,
395  nPatches++,
396  mesh.boundary()
397  )
398  );
399  }
400  }
402  mesh.addFaPatches(patches, false); // No parallel comms
403 
404  if (!readHandlerPtr)
405  {
406  // The 'old' way of doing things.
407  // Write the dummy mesh to disk for subsequent re-reading.
408  //
409  // This is not particularly elegant.
410 
411  // Bad hack, but the underlying polyMesh is NO_WRITE
412  // so it does not create the faMesh subDir for us...
413  Foam::mkDir(mesh.boundary().path());
414 
415  //Pout<< "Writing dummy mesh to " << mesh.boundary().path() << nl;
416  mesh.write();
417 
418  // Discard - it will be re-read later
419  meshPtr.reset(nullptr);
420  }
421 
422  fileOperation::cacheLevel(oldCache);
423  if (oldParRun)
424  {
425  const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
426  }
427  UPstream::parRun(oldParRun); // Restore parallel state
428  }
429  else if (readHandlerPtr && haveLocalMesh)
430  {
431  const labelList meshProcIds(BitOps::sortedToc(haveMesh));
432 
433  UPstream::communicator newCommunicator;
434  const label oldWorldComm = UPstream::commWorld();
435 
436  auto& readHandler = *readHandlerPtr;
437  auto oldHandler = fileOperation::fileHandler(readHandler);
438 
439  // With IO ranks the communicator of the fileOperation will
440  // only include the ranks for the current IO rank.
441  // Instead allocate a new communicator for everyone with a mesh
442 
443  const auto& handlerProcIds = UPstream::procID(fileHandler().comm());
444 
445  // Comparing global ranks in the communicator.
446  // Use std::equal for the List<label> vs List<int> comparison
447 
448  if
449  (
450  meshProcIds.size() == handlerProcIds.size()
451  && std::equal
452  (
453  meshProcIds.cbegin(),
454  meshProcIds.cend(),
455  handlerProcIds.cbegin()
456  )
457  )
458  {
459  // Can use the handler communicator as is.
461  }
462  else if
463  (
464  UPstream::nProcs(fileHandler().comm())
466  )
467  {
468  // Need a new communicator for the fileHandler.
469 
470  // Warning: MS-MPI currently uses MPI_Comm_create() instead of
471  // MPI_Comm_create_group() so it will block here!
472 
473  newCommunicator.reset(UPstream::worldComm, meshProcIds);
474  UPstream::commWorld(newCommunicator.comm());
475  }
476 
477  // Load but do not initialise
478  meshPtr = autoPtr<faMesh>::New(pMesh, false);
479 
480  readHandler = fileOperation::fileHandler(oldHandler);
481  UPstream::commWorld(oldWorldComm);
482 
483  // Reset mesh communicator to the real world comm
484  meshPtr().comm() = UPstream::commWorld();
485  }
486 
487 
488  if (!meshPtr)
489  {
490  // Using the 'old' way of doing things (writing to disk and re-reading).
491 
492  // Read mesh from disk
493  //
494  // Now all processors have a (possibly zero size) mesh so can
495  // read in parallel
496 
498  // Load but do not initialise
499  meshPtr = autoPtr<faMesh>::New(pMesh, false);
500  }
501 
502  faMesh& mesh = meshPtr();
503 
504  // Check patches
505  // ~~~~~~~~~~~~~
506 
507  #if 0
508  if (!UPstream::master() && haveLocalMesh)
509  {
510  // Check master names against mine
511 
512  const faBoundaryMesh& patches = mesh.boundary();
513 
514  forAll(patchEntries, patchi)
515  {
516  const entry& e = patchEntries[patchi];
517  const word type(e.dict().get<word>("type"));
518  const word& name = e.keyword();
519 
520  if
521  (
522  type == processorFaPatch::typeName
523  )
524  {
525  break;
526  }
527 
528  if (patchi >= patches.size())
529  {
531  << "Non-processor patches not synchronised." << endl
532  << "Processor " << UPstream::myProcNo()
533  << " has only " << patches.size()
534  << " patches, master has "
535  << patchi
536  << exit(FatalError);
537  }
538 
539  if
540  (
541  type != patches[patchi].type()
542  || name != patches[patchi].name()
543  )
544  {
546  << "Non-processor patches not synchronised." << endl
547  << "Master patch " << patchi
548  << " name:" << type
549  << " type:" << type << endl
550  << "Processor " << UPstream::myProcNo()
551  << " patch " << patchi
552  << " has name:" << patches[patchi].name()
553  << " type:" << patches[patchi].type()
554  << exit(FatalError);
555  }
556  }
557  }
558  #endif
559 
560 
561  // Recreate basic geometry, globalMeshData etc.
562  mesh.init(false);
563  (void)mesh.globalData();
564 
569 
570  // Do some checks.
571 
572  // Check if the boundary definition is unique
573  // and processor patches are correct
574  mesh.boundary().checkDefinition(verbose);
575  mesh.boundary().checkParallelSync(verbose);
577  return meshPtr;
578 }
579 
580 
583 (
584  const IOobject& io,
585  const polyMesh& pMesh,
586  const bool decompose,
587  const bool verbose
588 )
589 {
590  return faMeshTools::loadOrCreateMeshImpl
591  (
592  io,
593  nullptr, // fileOperation (ignore)
594  pMesh,
595  decompose,
596  verbose
597  );
598 }
599 
600 
603 (
604  const IOobject& io,
605  const polyMesh& pMesh,
606  refPtr<fileOperation>& readHandler,
607  const bool verbose
608 )
609 {
610  return faMeshTools::loadOrCreateMeshImpl
611  (
612  io,
613  &readHandler,
614  pMesh,
615  false, // decompose (ignored)
616  verbose
617  );
618 }
619 
620 
621 // ************************************************************************* //
label nPatches
Definition: readKivaGrid.H:396
PtrList< faPatch > faPatchList
Store lists of faPatch as a PtrList.
Definition: faPatch.H:59
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:133
static autoPtr< faMesh > newMesh(const IOobject &io, const polyMesh &pMesh, const bool masterOnlyReading, const bool verbose=false)
Read mesh or create dummy mesh (0 faces, >0 patches).
Definition: faMeshTools.C:66
static autoPtr< faPatch > New(const word &name, const dictionary &dict, const label index, const faBoundaryMesh &bm)
Return pointer to a new patch created on freestore from dictionary.
Definition: faPatchNew.C:28
fileName path() const
Return path = rootPath/caseName. Same as TimePaths::path()
Definition: Time.H:503
A class for handling file names.
Definition: fileName.H:72
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
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:608
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:195
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1061
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler()
virtual bool init(const bool doInit)
Initialise all non-demand-driven data.
Definition: dynamicFvMesh.C:84
bool checkOut(regIOobject *io) const
Remove a regIOobject from registry and free memory if the object is ownedByRegistry. A nullptr is ignored.
Ignore writing from objectRegistry::writeObject()
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:1086
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:421
labelList faceLabels(nFaceLabels)
A class for managing references or pointers (no reference counting)
Definition: HashPtrTable.H:49
bool equal(const Matrix< Form1, Type > &A, const Matrix< Form2, Type > &B, const bool verbose=false, const label maxDiffs=10, const scalar relTol=1e-5, const scalar absTol=1e-8)
Compare matrix elements for absolute or relative equality.
Definition: MatrixTools.C:27
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:860
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
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:1077
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
IOList< label > labelIOList
IO for a List of label.
Definition: labelIOList.H:32
dynamicFvMesh & mesh
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:614
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
word findInstance(const fileName &directory, const word &name=word::null, IOobjectOption::readOption rOpt=IOobjectOption::MUST_READ, const word &stopInstance=word::null, const bool constant_fallback=true) const
Return time instance (location) of directory containing the file name (eg, used in reading mesh data)...
Definition: Time.C:725
Foam::autoPtr< Foam::dynamicFvMesh > meshPtr
fileName meshDir() const
Return the local mesh directory (dbDir()/meshSubDir)
Definition: faMesh.C:1016
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
Reading is optional [identical to LAZY_READ].
static const word null
An empty word.
Definition: word.H:84
const globalMeshData & globalData() const
Return parallel info (demand-driven)
Definition: polyMesh.C:1311
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie...
Definition: PtrList.H:159
virtual bool write(const bool writeOnProc=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1113
const Time & time() const noexcept
Return Time associated with the objectRegistry.
Definition: IOobject.C:456
bool empty() const noexcept
True if the hash table is empty.
Definition: HashTable.H:353
static int cacheLevel() noexcept
Return cache level.
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:351
static label commWorld() noexcept
Communicator for all ranks (respecting any local worlds)
Definition: UPstream.H:441
void resize(const label newLen)
Adjust size of PtrList.
Definition: PtrList.C:95
const fileName & instance() const noexcept
Read access to instance path component.
Definition: IOobjectI.H:266
static autoPtr< faMesh > loadOrCreateMesh(const IOobject &io, const polyMesh &pMesh, const bool decompose, const bool verbose=false)
Definition: faMeshTools.C:576
static void broadcasts(const label comm, Type &arg1, Args &&... args)
Broadcast multiple items to all communicator ranks. Does nothing in non-parallel. ...
Read and store dictionary entries for finite-area boundary patches. The object is *never* registered ...
bool isFile(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist as a FILE in the file system?
Definition: POSIX.C:877
bool empty() const noexcept
True if the list is empty (ie, size() is zero)
Definition: UPtrListI.H:99
static void unregisterMesh(const faMesh &mesh)
Unregister the faMesh from its associated polyMesh to prevent triggering on polyMesh changes etc...
Definition: faMeshTools.C:33
static List< int > & procID(const label communicator)
The list of ranks within a given communicator.
Definition: UPstream.H:1142
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1094
const polyBoundaryMesh & patches
Nothing to be read.
Automatically write from objectRegistry::writeObject()
List< label > sortedToc(const UList< bool > &bools)
Return the (sorted) values corresponding to &#39;true&#39; entries.
Definition: BitOps.C:195
const fvBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition: fvMesh.H:395
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
static const fileOperation & fileHandler()
Return the current file handler. Will create the default file handler if necessary.
List< label > labelList
A List of labels.
Definition: List.H:62
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
Registry of regIOobjects.
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
List< bool > boolList
A List of bools.
Definition: List.H:60
static void forceDemandDriven(faMesh &mesh)
Force creation of everything that might vaguely be used by patches.
Definition: faMeshTools.C:45
Do not request registration (bool: false)