fieldsDistributorTemplates.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) 2022-2023 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 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
29 
30 template<class GeoField>
32 (
33  const IOobject& io,
34  const typename GeoField::Mesh& mesh,
35  const label idx,
37 )
38 {
39  fields.emplace_set(idx, io, mesh);
40 }
41 
42 
43 template<class Type, template<class> class PatchField, class GeoMesh>
45 (
46  const IOobject& io,
47  const typename GeoMesh::Mesh& mesh,
48  const label idx,
50 )
51 {
52  fields.emplace_set(idx, io, mesh, false); // readOldTime = false
53 }
54 
55 
56 template<class Type, template<class> class PatchField, class GeoMesh>
58 (
59  const typename GeoMesh::Mesh& mesh,
60  const IOobjectList& objects,
62  const bool readOldTime
63 )
64 {
66 
67  // GeoField fields - sorted for consistent order on all processors
68  UPtrList<const IOobject> fieldObjects(objects.sorted<GeoField>());
69 
70  // Construct the fields
71  fields.resize(fieldObjects.size());
72 
73  forAll(fieldObjects, i)
74  {
75  fields.emplace_set(i, fieldObjects[i], mesh, readOldTime);
76  }
77 }
78 
79 
80 template<class Mesh, class GeoField>
82 (
83  const Mesh& mesh,
84  const IOobjectList& objects,
85  PtrList<GeoField>& fields
86 )
87 {
88  // GeoField fields - sorted for consistent order on all processors
89  UPtrList<const IOobject> fieldObjects(objects.sorted<GeoField>());
90 
91  // Construct the fields
92  fields.resize(fieldObjects.size());
93 
94  forAll(fieldObjects, i)
95  {
96  fields.emplace_set(i, fieldObjects[i], mesh);
97  }
98 }
99 
100 
101 template<class BoolListType, class GeoField, class MeshSubsetter>
102 void Foam::fieldsDistributor::readFieldsImpl
103 (
104  refPtr<fileOperation>* readHandlerPtr, // Can be nullptr
105  const BoolListType& haveMeshOnProc,
106  const MeshSubsetter* subsetter,
107  const typename GeoField::Mesh& mesh,
108  IOobjectList& allObjects,
109  PtrList<GeoField>& fields,
110  const bool deregister
111 )
112 {
113  // Get my objects of type
114  IOobjectList objects(allObjects.lookupClass<GeoField>());
115 
116  // Check that we all have all objects
117  wordList objectNames = objects.sortedNames();
118 
119  // Get master names
120  wordList masterNames(objectNames);
121  Pstream::broadcast(masterNames);
122 
123  if
124  (
125  haveMeshOnProc.test(UPstream::myProcNo())
126  && objectNames != masterNames
127  )
128  {
130  << "Objects not synchronised across processors." << nl
131  << "Master has " << flatOutput(masterNames) << nl
132  << "Processor " << UPstream::myProcNo()
133  << " has " << flatOutput(objectNames)
134  << exit(FatalError);
135  }
136 
137  #ifdef FULLDEBUG
138  {
139  // A bit more checking - this may not be strictly correct.
140  // The master must know about everyone, but the others really
141  // only need to know about themselves.
142  // Can broadcast decompose = yes/no from master
143 
144  bitSet localValues(haveMeshOnProc);
145  bitSet masterValues(localValues);
146  Pstream::broadcast(masterValues);
147 
148  localValues ^= masterValues;
149 
150  if (localValues.any())
151  {
153  << "haveMeshOnProc not synchronised across processors." << nl
154  << "Processor " << UPstream::myProcNo()
155  << " differs at these positions: "
156  << flatOutput(localValues.sortedToc()) << nl
157  << exit(FatalError);
158  }
159  }
160  #endif
161 
162 
163  fields.free();
164  fields.resize(masterNames.size());
165 
166  if (fields.empty())
167  {
168  if (deregister)
169  {
170  // Extra safety - remove all such types
171  HashTable<const GeoField*> other
172  (
173  mesh.thisDb().objectRegistry::template lookupClass<GeoField>()
174  );
175 
176  forAllConstIters(other, iter)
177  {
178  GeoField& fld = const_cast<GeoField&>(*iter.val());
179 
180  if (!fld.ownedByRegistry())
181  {
182  fld.checkOut();
183  }
184  }
185  }
186 
187  // Early exit
188  return;
189  }
190 
191 
192  // We are decomposing if none of the subprocs has a mesh
193  bool decompose = true;
194  if (UPstream::master())
195  {
196  for (const int proci : UPstream::subProcs())
197  {
198  if (haveMeshOnProc.test(proci))
199  {
200  decompose = false;
201  break;
202  }
203  }
204  }
205  Pstream::broadcast(decompose);
206 
207 
208  if (decompose && UPstream::master())
209  {
210  const bool oldParRun = UPstream::parRun(false);
211 
212  forAll(masterNames, i)
213  {
214  const word& name = masterNames[i];
215  IOobject& io = *objects[name];
217 
218  // Load field (but not oldTime)
219  readField(io, mesh, i, fields);
220  }
221 
222  UPstream::parRun(oldParRun);
223  }
224  else if
225  (
226  !decompose
227  &&
228  // Has read-handler : use it to decide if reading is possible
229  // No read-handler : decide based on the presence of a mesh
230  (
231  readHandlerPtr
232  ? readHandlerPtr->good()
233  : haveMeshOnProc.test(UPstream::myProcNo())
234  )
235  )
236  {
237  const label oldWorldComm = UPstream::worldComm;
238  refPtr<fileOperation> oldHandler;
239 
240  if (readHandlerPtr)
241  {
242  // Swap read fileHandler for read fields
243  oldHandler = fileOperation::fileHandler(*readHandlerPtr);
245  }
246 
247  forAll(masterNames, i)
248  {
249  const word& name = masterNames[i];
250  IOobject& io = *objects[name];
252 
253  // Load field (but not oldTime)
254  readField(io, mesh, i, fields);
255  }
256 
257  if (readHandlerPtr)
258  {
259  // Restore fileHandler
260  *readHandlerPtr = fileOperation::fileHandler(oldHandler);
261  UPstream::commWorld(oldWorldComm);
262  }
263  }
264 
265 
266  // Missing fields on any processors?
267  // - construct from dictionary
268 
269  PtrList<dictionary> fieldDicts;
270 
271  if (UPstream::master())
272  {
273  // Broadcast zero sized fields everywhere (if needed)
274  // Send like a list of dictionaries
275 
276  OPBstream toProcs(UPstream::masterNo()); // worldComm
277 
278  const label nDicts = (subsetter ? fields.size() : label(0));
279 
280  toProcs << nDicts << token::BEGIN_LIST; // Begin list
281 
282  if (nDicts && subsetter)
283  {
284  // Disable communication for interpolate() method
285  const bool oldParRun = UPstream::parRun(false);
286 
287  for (const auto& fld : fields)
288  {
289  tmp<GeoField> tsubfld = subsetter->interpolate(fld);
290 
291  // Surround each with {} as dictionary entry
292  toProcs.beginBlock();
293  toProcs << tsubfld();
294  toProcs.endBlock();
295  }
296 
297  UPstream::parRun(oldParRun); // Restore state
298  }
299 
300  toProcs << token::END_LIST << token::NL; // End list
301  }
302  else
303  {
304  // Receive the broadcast...
305  IPBstream fromMaster(UPstream::masterNo()); // worldComm
306 
307  // But only consume where needed...
308  if (!haveMeshOnProc.test(UPstream::myProcNo()))
309  {
310  fromMaster >> fieldDicts;
311  }
312  }
313 
314 
315  // Use the received dictionaries (if any) to create missing fields.
316 
317  // Disable communication when constructing from dictionary
318  const bool oldParRun = UPstream::parRun(false);
319 
320  IOobject noreadIO
321  (
322  "none",
323  mesh.time().timeName(),
324  mesh.thisDb(),
328  );
329 
330  forAll(fieldDicts, i)
331  {
332  noreadIO.resetHeader(masterNames[i]);
333 
334  fields.emplace_set(i, noreadIO, mesh, fieldDicts[i]);
335  }
336 
337  UPstream::parRun(oldParRun); // Restore any changes
338 
339 
340  // Finally. Can checkOut of registry as required
341  if (deregister)
342  {
344  for (auto& fld : fields)
345  {
347 
348  // Ensure it is not destroyed by polyMesh deletion
349  fld.checkOut();
350  }
352 
353  // Extra safety - remove all such types
354  HashTable<const GeoField*> other
355  (
356  mesh.thisDb().objectRegistry::template lookupClass<GeoField>()
357  );
358 
359  forAllConstIters(other, iter)
360  {
361  GeoField& fld = const_cast<GeoField&>(*iter.val());
362 
363  if (!fld.ownedByRegistry())
364  {
365  fld.checkOut();
366  }
367  }
368  }
369 }
370 
371 
372 template<class GeoField, class MeshSubsetter>
374 (
375  const bitSet& haveMeshOnProc,
376  const MeshSubsetter* subsetter,
377  const typename GeoField::Mesh& mesh,
378  IOobjectList& allObjects,
379  PtrList<GeoField>& fields,
380  const bool deregister
381 )
382 {
383  readFieldsImpl
384  (
385  nullptr, // readHandler
386  haveMeshOnProc,
387  subsetter,
388 
389  mesh,
390  allObjects,
391  fields,
392  deregister
393  );
394 }
395 
396 
397 template<class GeoField, class MeshSubsetter>
399 (
400  const boolUList& haveMeshOnProc,
401  const MeshSubsetter* subsetter,
402  const typename GeoField::Mesh& mesh,
403  IOobjectList& allObjects,
405  const bool deregister
406 )
407 {
408  readFieldsImpl
409  (
410  nullptr, // readHandler
411  haveMeshOnProc,
412  subsetter,
413 
414  mesh,
415  allObjects,
416  fields,
417  deregister
418  );
419 }
420 
421 
422 template<class GeoField, class MeshSubsetter>
424 (
425  const boolUList& haveMeshOnProc,
426  const typename GeoField::Mesh& mesh,
427  const autoPtr<MeshSubsetter>& subsetter,
428  IOobjectList& allObjects,
430  const bool deregister
431 )
432 {
433  readFieldsImpl
434  (
435  nullptr, // readHandler
436  haveMeshOnProc,
437  subsetter.get(),
438 
439  mesh,
440  allObjects,
441  fields,
442  deregister
443  );
444 }
445 
446 
447 template<class GeoField, class MeshSubsetter>
449 (
450  const boolUList& haveMeshOnProc,
451  refPtr<fileOperation>& readHandler,
452  const typename GeoField::Mesh& mesh,
453  const autoPtr<MeshSubsetter>& subsetter,
454  IOobjectList& allObjects,
456  const bool deregister
457 )
458 {
459  readFieldsImpl
460  (
461  &readHandler,
462  haveMeshOnProc,
463  subsetter.get(),
464 
465  mesh,
466  allObjects,
467  fields,
468  deregister
469  );
470 }
471 
472 
473 // ************************************************************************* //
static void readField(const IOobject &io, const typename GeoField::Mesh &mesh, const label i, PtrList< GeoField > &fields)
Generic mesh-based field reading.
List of IOobjects with searching and retrieving facilities. Implemented as a HashTable, so the various sorted methods should be used if traversing in parallel.
Definition: IOobjectList.H:55
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:578
UPtrList< const IOobject > sorted() const
The sorted list of IOobjects.
Definition: IOobjectList.C:223
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
wordList sortedNames() const
The sorted names of the IOobjects.
Definition: IOobjectList.C:270
Newline [isspace].
Definition: token.H:127
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1004
Begin list [isseparator].
Definition: token.H:158
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler()
Generic GeometricField class.
Definition: areaFieldsFwd.H:50
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:1029
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:362
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:411
A class for managing references or pointers (no reference counting)
Definition: HashPtrTable.H:49
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all processes in communicator.
multivariateSurfaceInterpolationScheme< scalar >::fieldTable fields
Definition: createFields.H:97
virtual const objectRegistry & thisDb() const
Return the object registry - resolve conflict polyMesh/lduMesh.
Definition: fvMesh.H:378
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
writeOption writeOpt() const noexcept
Get the write option.
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
static void readFields(const typename GeoMesh::Mesh &mesh, const IOobjectList &objects, PtrList< GeometricField< Type, PatchField, GeoMesh >> &fields, const bool readOldTime)
Read fields and store on the pointer list.
static constexpr int masterNo() noexcept
Relative rank for the master process - is always 0.
Definition: UPstream.H:1014
End list [isseparator].
Definition: token.H:159
A list of pointers to objects of type <T>, without allocation/deallocation management of the pointers...
Definition: HashTable.H:100
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:99
static word timeName(const scalar t, const int precision=precision_)
Return time name of given scalar time formatted with the given precision.
Definition: Time.C:770
MESH Mesh
Definition: GeoMesh.H:58
static label commWorld() noexcept
Communicator for all ranks (respecting any local worlds)
Definition: UPstream.H:431
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
List< word > wordList
List of word.
Definition: fileName.H:58
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: List.H:55
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1037
Nothing to be read.
Automatically write from objectRegistry::writeObject()
T * get() noexcept
Return pointer to managed object without nullptr checking.
Definition: autoPtr.H:216
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
static const fileOperation & fileHandler()
Return the current file handler. Will create the default file handler if necessary.
Generic mesh wrapper used by volMesh, surfaceMesh, pointMesh etc.
Definition: GeoMesh.H:42
static rangeType subProcs(const label communicator=worldComm)
Range of process indices for sub-processes.
Definition: UPstream.H:1140
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:171
Request registration (bool: true)
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225