loadOrCreateMesh.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) 2012-2019 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 "loadOrCreateMesh.H"
27 #include "processorPolyPatch.H"
29 #include "Time.H"
30 #include "IOPtrList.H"
31 
32 // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36  defineTemplateTypeNameAndDebug(IOPtrList<entry>, 0);
37 }
38 
39 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
40 
41 // Read mesh if available. Otherwise create empty mesh with same non-proc
42 // patches as proc0 mesh. Requires all processors to have all patches
43 // (and in same order).
45 (
46  const IOobject& io
47 )
48 {
49  fileName meshSubDir;
50 
51  if (io.name() == polyMesh::defaultRegion)
52  {
53  meshSubDir = polyMesh::meshSubDir;
54  }
55  else
56  {
57  meshSubDir = io.name()/polyMesh::meshSubDir;
58  }
59 
60 
61  // Scatter master patches
62  PtrList<entry> patchEntries;
63  if (Pstream::master())
64  {
65  // Read PtrList of dictionary as dictionary.
66  const word oldTypeName = IOPtrList<entry>::typeName;
67  const_cast<word&>(IOPtrList<entry>::typeName) = word::null;
68  IOPtrList<entry> dictList
69  (
70  IOobject
71  (
72  "boundary",
73  io.time().findInstance
74  (
75  meshSubDir,
76  "boundary",
78  ),
79  meshSubDir,
80  io.db(),
83  false
84  )
85  );
86  const_cast<word&>(IOPtrList<entry>::typeName) = oldTypeName;
87  // Fake type back to what was in field
88  const_cast<word&>(dictList.type()) = dictList.headerClassName();
89 
90  patchEntries.transfer(dictList);
91 
92  // Send patches
93  for
94  (
95  int slave=Pstream::firstSlave();
96  slave<=Pstream::lastSlave();
97  slave++
98  )
99  {
100  OPstream toSlave(Pstream::commsTypes::scheduled, slave);
101  toSlave << patchEntries;
102  }
103  }
104  else
105  {
106  // Receive patches
107  IPstream fromMaster
108  (
111  );
112  fromMaster >> patchEntries;
113  }
114 
115 
116 
117  // Check who has a mesh
118  const bool haveMesh = fileHandler().isDir
119  (
120  fileHandler().filePath(io.time().path()/io.instance()/meshSubDir)
121  );
122 
123  if (!haveMesh)
124  {
125  bool oldParRun = Pstream::parRun();
126  Pstream::parRun() = false;
127 
128 
129  // Create dummy mesh. Only used on procs that don't have mesh.
130  IOobject noReadIO(io);
131  noReadIO.readOpt() = IOobject::NO_READ;
132  fvMesh dummyMesh
133  (
134  noReadIO,
135  pointField(),
136  faceList(),
137  labelList(),
138  labelList(),
139  false
140  );
141 
142  // Add patches
143  List<polyPatch*> patches(patchEntries.size());
144  label nPatches = 0;
145 
146  forAll(patchEntries, patchi)
147  {
148  const entry& e = patchEntries[patchi];
149  const word type(e.dict().lookup("type"));
150  const word& name = e.keyword();
151 
152  if
153  (
154  type != processorPolyPatch::typeName
155  && type != processorCyclicPolyPatch::typeName
156  )
157  {
158  dictionary patchDict(e.dict());
159  patchDict.set("nFaces", 0);
160  patchDict.set("startFace", 0);
161 
162  patches[patchi] = polyPatch::New
163  (
164  name,
165  patchDict,
166  nPatches++,
167  dummyMesh.boundaryMesh()
168  ).ptr();
169  }
170  }
171  patches.setSize(nPatches);
172  dummyMesh.addFvPatches(patches, false); // no parallel comms
173 
174  // Add some dummy zones so upon reading it does not read them
175  // from the undecomposed case. Should be done as extra argument to
176  // regIOobject::readStream?
177  List<pointZone*> pz
178  (
179  1,
180  new pointZone
181  (
182  "dummyPointZone",
183  labelList(0),
184  0,
185  dummyMesh.pointZones()
186  )
187  );
188  List<faceZone*> fz
189  (
190  1,
191  new faceZone
192  (
193  "dummyFaceZone",
194  labelList(0),
195  boolList(0),
196  0,
197  dummyMesh.faceZones()
198  )
199  );
200  List<cellZone*> cz
201  (
202  1,
203  new cellZone
204  (
205  "dummyCellZone",
206  labelList(0),
207  0,
208  dummyMesh.cellZones()
209  )
210  );
211  dummyMesh.addZones(pz, fz, cz);
212  // Pout<< "Writing dummy mesh to " << dummyMesh.polyMesh::objectPath()
213  // << endl;
214  dummyMesh.write();
215 
216  Pstream::parRun() = oldParRun;
217  }
218 
219  // Pout<< "Reading mesh from " << io.objectPath() << endl;
220  autoPtr<fvMesh> meshPtr(new fvMesh(io));
221  fvMesh& mesh = meshPtr();
222 
223 
224  // Sync patches
225  // ~~~~~~~~~~~~
226 
227  if (!Pstream::master() && haveMesh)
228  {
229  // Check master names against mine
230 
231  const polyBoundaryMesh& patches = mesh.boundaryMesh();
232 
233  forAll(patchEntries, patchi)
234  {
235  const entry& e = patchEntries[patchi];
236  const word type(e.dict().lookup("type"));
237  const word& name = e.keyword();
238 
239  if (type == processorPolyPatch::typeName)
240  {
241  break;
242  }
243 
244  if (patchi >= patches.size())
245  {
247  << "Non-processor patches not synchronised."
248  << endl
249  << "Processor " << Pstream::myProcNo()
250  << " has only " << patches.size()
251  << " patches, master has "
252  << patchi
253  << exit(FatalError);
254  }
255 
256  if
257  (
258  type != patches[patchi].type()
259  || name != patches[patchi].name()
260  )
261  {
263  << "Non-processor patches not synchronised."
264  << endl
265  << "Master patch " << patchi
266  << " name:" << type
267  << " type:" << type << endl
268  << "Processor " << Pstream::myProcNo()
269  << " patch " << patchi
270  << " has name:" << patches[patchi].name()
271  << " type:" << patches[patchi].type()
272  << exit(FatalError);
273  }
274  }
275  }
276 
277 
278  // Determine zones
279  // ~~~~~~~~~~~~~~~
280 
281  wordList pointZoneNames(mesh.pointZones().names());
282  Pstream::scatter(pointZoneNames);
283  wordList faceZoneNames(mesh.faceZones().names());
284  Pstream::scatter(faceZoneNames);
285  wordList cellZoneNames(mesh.cellZones().names());
286  Pstream::scatter(cellZoneNames);
287 
288  if (!haveMesh)
289  {
290  // Add the zones. Make sure to remove the old dummy ones first
291  mesh.pointZones().clear();
292  mesh.faceZones().clear();
293  mesh.cellZones().clear();
294 
295  List<pointZone*> pz(pointZoneNames.size());
296  forAll(pointZoneNames, i)
297  {
298  pz[i] = new pointZone
299  (
300  pointZoneNames[i],
301  labelList(0),
302  i,
303  mesh.pointZones()
304  );
305  }
306  List<faceZone*> fz(faceZoneNames.size());
307  forAll(faceZoneNames, i)
308  {
309  fz[i] = new faceZone
310  (
311  faceZoneNames[i],
312  labelList(0),
313  boolList(0),
314  i,
315  mesh.faceZones()
316  );
317  }
318  List<cellZone*> cz(cellZoneNames.size());
319  forAll(cellZoneNames, i)
320  {
321  cz[i] = new cellZone
322  (
323  cellZoneNames[i],
324  labelList(0),
325  i,
326  mesh.cellZones()
327  );
328  }
329  mesh.addZones(pz, fz, cz);
330  }
331 
332 
333  if (!haveMesh)
334  {
335  // We created a dummy mesh file above. Delete it.
336  const fileName meshFiles = io.time().path()/io.instance()/meshSubDir;
337  // Pout<< "Removing dummy mesh " << meshFiles << endl;
338  mesh.removeFiles();
339  rmDir(meshFiles);
340  }
341 
342  // Force recreation of globalMeshData.
343  mesh.clearOut();
344  mesh.globalData();
345 
346 
347  // Do some checks.
348 
349  // Check if the boundary definition is unique
350  mesh.boundaryMesh().checkDefinition(true);
351  // Check if the boundary processor patches are correct
352  mesh.boundaryMesh().checkParallelSync(true);
353  // Check names of zones are equal
354  mesh.cellZones().checkDefinition(true);
355  mesh.cellZones().checkParallelSync(true);
356  mesh.faceZones().checkDefinition(true);
357  mesh.faceZones().checkParallelSync(true);
358  mesh.pointZones().checkDefinition(true);
359  mesh.pointZones().checkParallelSync(true);
360 
361  return meshPtr;
362 }
363 
364 
365 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
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
static int masterNo()
Process index of the master.
Definition: UPstream.H:417
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
static int firstSlave()
Process index of first slave.
Definition: UPstream.H:446
static fvMesh * meshPtr
Definition: globalFoam.H:52
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:312
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
List< face > faceList
Definition: faceListFwd.H:43
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:309
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
patches[0]
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Load or create (0 size) a mesh. Used in distributing meshes to a larger number of processors...
static const word null
An empty word.
Definition: word.H:77
List< label > labelList
A List of labels.
Definition: labelList.H:56
const fileOperation & fileHandler()
Get current file handler.
defineTemplateTypeNameAndDebug(IOPtrList< ensightPart >, 0)
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
bool rmDir(const fileName &)
Remove a directory and its contents.
Definition: POSIX.C:1051
autoPtr< fvMesh > loadOrCreateMesh(const IOobject &io)
Load (if it exists) or create zero cell mesh given an IOobject:
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
List< word > wordList
A List of words.
Definition: fileName.H:54
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
label patchi
virtual bool isDir(const fileName &, const bool followLink=true) const =0
Does the name exist as a directory in the file system?
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
static autoPtr< polyPatch > New(const word &patchType, const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm)
Return a pointer to a new patch created on freestore from.
Definition: polyPatchNew.C:32
Namespace for OpenFOAM.
static int lastSlave(const label communicator=0)
Process index of last slave.
Definition: UPstream.H:452