loadOrCreateMesh.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-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2026 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 "loadOrCreateMesh.H"
30 #include "faMesh.H"
31 #include "Pstream.H"
32 #include "OSspecific.H"
33 #include "decomposedBlockData.H"
34 #include "IFstream.H"
35 
36 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
37 
38 // Trimmed-down version of lookupAndCacheProcessorsPath
39 // with Foam::exists() check. No caching.
40 
41 // Check for two conditions:
42 // - file has to exist
43 // - if collated the entry has to exist inside the file
44 
45 // Note: bypass fileOperation::filePath(IOobject&) since has problems
46 // with going to a different number of processors
47 // (in collated format). Use file-based searching instead
48 
49 namespace Foam
50 {
51 
52 // If indeed collated format:
53 // Collect block-number in individual filenames
54 // (might differ on different processors)
55 static bool checkFileExistenceCollated
56 (
57  const Foam::fileOperation& handler,
58  const Foam::fileName& fName
59 )
60 {
61  // using namespace Foam;
62 
63  bool found = false;
64  {
65  const auto handlerComm = handler.comm();
66 
67  const auto globalProci = UPstream::myProcNo(UPstream::worldComm);
68  const auto handlerProci = UPstream::myProcNo(handlerComm);
69  const auto nHandlerProcs = UPstream::nProcs(handlerComm);
70 
71  // Determine my local block number
72  label myBlockNumber = -1;
73  {
75  label proci = fileOperation::detectProcessorPath(fName, group);
76 
77  if (proci == -1 && group.empty())
78  {
79  // 'processorsXXX' format so contains all ranks
80  // according to worldComm
81  myBlockNumber = globalProci;
82  }
83  else
84  {
85  // 'processorsXXX_n-m' format so check for relative rank
86  myBlockNumber = handlerProci;
87  }
88  }
89 
90  // // Since we are streaming anyhow, pack as a single tuple:
91  // typedef std::pair<fileName, label> indexedFileNameType;
92  //
93  // // Collect file names, block numbers on master of local communicator
94  // const List<indexedFileNameType> indexedFileNames
95  // (
96  // Pstream::listGatherValues<indexedFileNameType>
97  // (
98  // indexedFileNameType(fName, myBlockNumber),
99  // handlerComm,
100  // UPstream::msgType()
101  // )
102  // );
103 
104  // Collect file names on master of local communicator
105  const fileNameList fNames
106  (
108  (
109  fName,
110  handlerComm,
112  )
113  );
114 
115  // Collect block numbers on master of local communicator
116  const labelList myBlockNumbers
117  (
119  (
120  myBlockNumber,
121  handlerComm,
123  )
124  );
125 
126  // Determine for all whether the filename exists in the collated file.
127  boolList allFound;
128 
129  if (UPstream::master(handlerComm))
130  {
131  allFound.resize(nHandlerProcs, false);
132 
133  // Store nBlocks and index of file that was used for nBlocks
134  label nBlocks = -1, blockRanki = -1;
135 
136  for (label ranki = 0; ranki < nHandlerProcs; ++ranki)
137  {
138  if
139  (
140  blockRanki == -1
141  || (fNames[ranki] != fNames[blockRanki])
142  )
143  {
144  blockRanki = ranki;
145  IFstream is(fNames[ranki]);
146  nBlocks = decomposedBlockData::getNumBlocks(is);
147  }
148 
149  allFound[ranki] = (myBlockNumbers[ranki] < nBlocks);
150  }
151  }
152 
153  // Scatter using the handler communicator
155  (
156  allFound,
157  handlerComm,
159  );
160  }
161 
162  return found;
163 }
164 
165 
166 // Check for availability of specified file
167 static bool checkProcessorFile
168 (
169  const word& name, // eg "faces"
170  const fileName& instance, // eg "constant"
171  const fileName& local, // eg, polyMesh
172  const Time& runTime
173 )
174 {
175  const auto& handler = Foam::fileHandler();
176 
177  const fileName fName
178  (
179  handler.filePath(runTime.path()/instance/local/name)
180  );
181 
182  bool found = handler.isFile(fName);
183 
184  // Assume non-collated (as fallback value) if everyone claims to
185  // have the file. Use master to verify if collated is indeed involved.
186 
187  bool isCollated = false;
188 
190  {
191  // Test for collated format.
192  // Note: can restrict the test to world-master only since even
193  // host-collated will have same file format type for all processors
194 
196  {
197  const auto oldParRun = UPstream::parRun(false);
198 
199  if (IFstream is(fName); is.good())
200  {
201  IOobject io(name, instance, local, runTime);
202  io.readHeader(is);
203 
205  }
206 
207  UPstream::parRun(oldParRun);
208  }
210  }
211 
212  // For collated, check that the corresponding blocks exist
213  if (isCollated)
214  {
215  found = checkFileExistenceCollated(handler, fName);
216  }
217 
218  return found;
219 }
220 
221 
222 // Check for availability of specified file
223 static bool checkProcessorFile
224 (
225  const Time& runTime,
226  const fileName& meshPath,
227  const word& meshFile
228 )
229 {
230  const auto& handler = Foam::fileHandler();
231 
232  const fileName fName
233  (
234  handler.filePath(runTime.path()/meshPath/meshFile)
235  );
236 
237  bool found = handler.isFile(fName);
238 
239  // Assume non-collated (as fallback value) if everyone claims to
240  // have the file. Use master to verify if collated is indeed involved.
241 
242  bool isCollated = false;
243 
245  {
246  // Test for collated format.
247  // Note: can restrict the test to world-master only since even
248  // host-collated will have same file format type for all processors
249 
251  {
252  const auto oldParRun = UPstream::parRun(false);
253 
254  if (IFstream is(fName); is.good())
255  {
256  IOobject io(meshFile, meshPath, runTime);
257  io.readHeader(is);
258 
260  }
261 
262  UPstream::parRun(oldParRun);
263  }
265  }
266 
267  // For collated, check that the corresponding blocks exist
268  if (isCollated)
269  {
270  found = checkFileExistenceCollated(handler, fName);
271  }
272 
273  return found;
274 }
275 
276 } // End namespace Foam
277 
278 
279 // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
280 
282 (
283  const word& name, // eg "faces"
284  const fileName& instance, // eg "constant"
285  const fileName& local, // eg, polyMesh
286  const Time& runTime,
287  const bool verbose
288 )
289 {
290  bool found = checkProcessorFile(name, instance, local, runTime);
291 
292  // Globally consistent information about who has the file
293  bitSet haveFileOnProc = bitSet::allGather(found, UPstream::worldComm);
294 
295  if (verbose)
296  {
297  Info<< "Per processor availability of \""
298  << name << "\" file in " << instance/local << nl
299  << " " << flatOutput(haveFileOnProc) << nl << endl;
300  }
301 
302  return haveFileOnProc;
303 }
304 
305 
307 (
308  const word& name, // eg "faces"
309  const fileName& instance, // eg "constant"
310  const fileName& local, // eg, polyMesh
311  const Time& runTime,
312  const bool verbose
313 )
314 {
315  bool found = checkProcessorFile(name, instance, local, runTime);
316 
317  // Globally consistent information about who has the file
318  boolList haveFileOnProc
319  (
320  UPstream::allGatherValues<bool>(found, UPstream::worldComm)
321  );
322 
323  if (verbose)
324  {
325  Info<< "Per processor availability of \""
326  << name << "\" file in " << instance/local << nl
327  << " " << flatOutput(haveFileOnProc) << nl << endl;
328  }
329 
330  return haveFileOnProc;
331 }
332 
333 
335 (
336  const Time& runTime,
337  const fileName& meshPath,
338  const word& meshFile,
339  const bool verbose
340 )
341 {
342  bool found = checkProcessorFile(runTime, meshPath, meshFile);
343 
344  // Globally consistent information about who has a mesh
345  boolList haveFileOnProc
346  (
347  UPstream::allGatherValues<bool>(found, UPstream::worldComm)
348  );
349 
350  if (verbose)
351  {
352  Info<< "Per processor availability of \""
353  << meshFile << "\" file in " << meshPath << nl
354  << " " << flatOutput(haveFileOnProc) << nl << endl;
355  }
356 
357  return haveFileOnProc;
358 }
359 
360 
361 void Foam::removeProcAddressing(const faMesh& mesh)
362 {
363  IOobject io
364  (
365  "procAddressing",
366  mesh.facesInstance(),
367  faMesh::meshSubDir,
368  mesh.thisDb()
369  );
370 
371  for (const auto prefix : {"boundary", "edge", "face", "point"})
372  {
373  io.rename(prefix + word("ProcAddressing"));
374 
375  const fileName procFile(io.objectPath());
376  Foam::rm(procFile);
377  }
378 }
379 
380 
381 void Foam::removeProcAddressing(const polyMesh& mesh)
382 {
383  IOobject io
384  (
385  "procAddressing",
386  mesh.facesInstance(),
387  polyMesh::meshSubDir,
388  mesh.thisDb()
389  );
390 
391  for (const auto prefix : {"boundary", "cell", "face", "point"})
392  {
393  io.rename(prefix + word("ProcAddressing"));
394 
395  const fileName procFile(io.objectPath());
396  Foam::rm(procFile);
397  }
398 }
399 
400 
402 (
403  const IOobject& io,
404  fileName& facesInstance,
405  fileName& pointsInstance
406 )
407 {
408  const fileName meshSubDir
409  (
410  polyMesh::meshDir(io.name())
411  );
412 
413  if (UPstream::master(UPstream::worldComm))
414  {
415  const auto oldParRun = UPstream::parRun(false);
416  const auto oldNumProcs = fileHandler().nProcs();
417  const auto oldCache = fileOperation::cacheLevel(0);
418 
419  facesInstance = io.time().findInstance
420  (
421  meshSubDir,
422  "faces",
423  IOobjectOption::MUST_READ
424  );
425  pointsInstance = io.time().findInstance
426  (
427  meshSubDir,
428  "points",
429  IOobjectOption::MUST_READ
430  );
431 
432  // Restore old states
433  fileOperation::cacheLevel(oldCache);
434  if (oldParRun)
435  {
436  fileHandler().constCast().nProcs(oldNumProcs);
437  }
438  UPstream::parRun(oldParRun);
439  }
440 
441  // Broadcast information to all
442  Pstream::broadcasts
443  (
444  UPstream::worldComm,
445  facesInstance,
446  pointsInstance
447  );
448 }
449 
450 
451 // ************************************************************************* //
A class for handling file names.
Definition: fileName.H:72
boolList haveMeshFile(const word &name, const fileName &instance, const fileName &local, const Time &runTime, const bool verbose=true)
Check for availability of specified file (on all ranks)
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:153
UPstream::rangeType procRangeType
For addressing a range of processors (an int range)
fileName path() const
The path for the case = rootPath/caseName.
Definition: TimePathsI.H:102
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:518
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1774
static int myProcNo(label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition: UPstream.H:1799
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler()
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:2019
static void broadcast(Type &value, const int communicator=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
static T listScatterValues(const UList< T > &allValues, const int communicator=UPstream::worldComm, const int tag=UPstream::msgType())
Scatter individual values from list locations.
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:1094
virtual bool isFile(const fileName &, const bool checkGzip=true, const bool followLink=true) const =0
Does the name exist as a FILE in the file system?
An encapsulation of filesystem-related operations.
constexpr const char *const group
Group name for atomic constants.
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
void masterMeshInstance(const IOobject &io, fileName &facesInstance, fileName &pointsInstance)
Determine master faces instance.
virtual fileName filePath(const bool checkGlobal, const IOobject &, const word &typeName, const bool search=true) const =0
Search for an object.
bool returnReduceAnd(const bool value, const int communicator=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
const auto & io
Miscellaneous file handling for meshes.
bool local
Definition: EEqn.H:20
static bool isCollatedType(const word &objectType)
True if object type is a known collated type.
bitSet haveProcessorFile(const word &name, const fileName &instance, const fileName &local, const Time &runTime, const bool verbose=true)
Check for availability of specified file (on all ranks)
auto & name
void allGather(Type *allData, int count, MPI_Datatype datatype, const int communicator, UPstream::Request *req=nullptr)
static label getNumBlocks(Istream &is, const label maxNumBlocks=-1)
Extract number of decomposedBlockData block entries, optionally with an upper limit. The input stream should be in a rewound state (or only have read the header) before calling.
static label nProcs(label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1790
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:58
static label detectProcessorPath(const fileName &fName, procRangeType &group, label *numProcs=nullptr)
Detect processor number from &#39;path/processorDDD/abc&#39; or &#39;path/processorsNN/abc&#39;, &#39;path/processorsNN_0...
label comm() const noexcept
Communicator to use.
static List< T > listGatherValues(const T &localValue, const int communicator=UPstream::worldComm, const int tag=UPstream::msgType())
Gather individual values into list locations.
messageStream Info
Information stream (stdout output on master, null elsewhere)
void removeProcAddressing(const faMesh &mesh)
Remove procAddressing.
static bool master(label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1807
List< label > labelList
A List of labels.
Definition: List.H:61
List< fileName > fileNameList
List of fileName.
Definition: fileNameList.H:32
List< bool > boolList
A List of bools.
Definition: List.H:59
bool found
Namespace for OpenFOAM.
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:217
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition: POSIX.C:1410