fileOperationNew.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 #include "fileOperation.H"
29 #include "dummyFileOperation.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 Foam::refPtr<Foam::fileOperation> Foam::fileOperation::dummyHandlerPtr_;
35 
37 
38 
39 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
40 
42 {
43  if (!dummyHandlerPtr_)
44  {
45  // verbose = false
46  dummyHandlerPtr_.reset(new fileOperations::dummyFileOperation(false));
47  }
48 
49  return dummyHandlerPtr_;
50 }
51 
52 
54 {
56  {
57  word handlerType(Foam::getEnv("FOAM_FILEHANDLER"));
58 
59  if (handlerType.empty())
60  {
61  handlerType = defaultFileHandler;
62  }
63 
65  }
66 
68 }
69 
70 
73 {
74  return refPtr<fileOperation>(std::move(fileHandlerPtr_));
75 }
76 
77 
80 {
81  // - do nothing if newHandler is empty. Does not delete current
82  // - do nothing if newHandler is identical to current handler
83 
84  // Change ownership as atomic operations
85 
86  // If newHandler and current handler are actually identical, we
87  // have a bit problem somewhere else since this means that the pointer
88  // is managed is done in two places!
89  // Should flag as a FatalError (in the future), but there may still be
90  // some place where we would like to fake shared pointers?
91 
92  // TBD: add a flush() operation on the old handler first,
93  // instead of waiting for it to be run on destruction?
94 
96 
97  if
98  (
99  newHandler.get() != nullptr
100  && newHandler.get() != fileOperation::fileHandlerPtr_.get()
101  )
102  {
103  old.swap(newHandler);
105  }
106 
107  return old;
108 }
109 
110 
112 Foam::fileOperation::fileHandler(autoPtr<fileOperation>&& newHandler)
113 {
114  // Same logic as refPtr version
115 
116  refPtr<fileOperation> old;
117 
118  if
119  (
120  newHandler.get() != nullptr
121  && newHandler.get() != fileOperation::fileHandlerPtr_.get()
122  )
123  {
124  old.reset(newHandler.release());
126  }
127 
128  return old;
129 }
130 
131 
134 {
135  return fileOperation::fileHandler(newHandler);
136 }
137 
138 
140 {
142  (
143  new fileOperations::uncollatedFileOperation(false) // verbose = false
144  );
145 }
146 
147 
148 // * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
149 
152 (
153  const word& handlerType,
154  bool verbose
155 )
156 {
157  if (handlerType.empty())
158  {
160  {
162  << "Default file-handler name is undefined" << nl
163  << abort(FatalError);
164  }
165 
166  // Forward to self
168  }
169 
171  << "Constructing fileHandler: " << handlerType << endl;
172 
173  auto* ctorPtr = wordConstructorTable(handlerType);
174 
175  if (!ctorPtr)
176  {
178  (
179  "fileHandler",
180  handlerType,
181  *wordConstructorTablePtr_
182  ) << abort(FatalError);
183  }
185  return autoPtr<fileOperation>(ctorPtr(verbose));
186 }
187 
188 
191 (
192  const word& handlerType,
193  const Tuple2<label, labelList>& commAndIORanks,
194  const bool distributedRoots,
195  bool verbose
196 )
197 {
198  if (handlerType.empty())
199  {
201  {
203  << "defaultFileHandler name is undefined" << nl
204  << abort(FatalError);
205  }
206 
207  // Forward to self
208  return fileOperation::New
209  (
211  commAndIORanks,
212  distributedRoots,
213  verbose
214  );
215  }
216 
218  << "Constructing fileHandler: " << handlerType << endl;
219 
220  auto* ctorPtr = commConstructorTable(handlerType);
221 
222  if (!ctorPtr)
223  {
225  (
226  "fileHandler",
227  handlerType,
228  *commConstructorTablePtr_
229  ) << abort(FatalError);
230  }
231 
232  return autoPtr<fileOperation>
233  (
234  ctorPtr(commAndIORanks, distributedRoots, verbose)
235  );
236 }
237 
238 
239 
240 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
242 namespace Foam
243 {
244 
245 // From boolUList/bitSet to list of labels,
246 // always include rank 0 and constrain by numProcs
247 template<class BoolListType>
248 static labelList getSelectedProcs(const BoolListType& useProc)
249 {
250  labelList ranks;
251 
252  if
253  (
255  || useProc.test(UPstream::myProcNo(UPstream::worldComm))
256  )
257  {
259 
260  for (const int proci : UPstream::allProcs(UPstream::worldComm))
261  {
262  // Always include the master rank
263  if (!proci || useProc.test(proci))
264  {
265  subProcs.push_back(proci);
266  }
267  }
268 
269  ranks.transfer(subProcs);
270  }
271 
272  return ranks;
273 }
274 
275 } // End namespace Foam
276 
277 
278 // * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
279 
281 Foam::fileOperation::New_impl
282 (
283  const fileOperation& origHandler,
284  const labelUList& subProcs, // in worldComm
285  bool verbose
286 )
287 {
288  autoPtr<fileOperation> newHandler;
289 
290  // NB: input must include master!
291 
292  const label myProci = UPstream::myProcNo(UPstream::worldComm);
293  const label numProcs = UPstream::nProcs(UPstream::worldComm);
294 
295  if (subProcs.contains(myProci))
296  {
297  // Retaining the original IO ranks if possible
298 
299  // Retain the original IO ranks that coincide with the new subset.
300  // This may still need more attention...
301 
302  const labelUList& origIOranks = origHandler.ioRanks();
303  DynamicList<label> subIORanks(origIOranks.size());
304 
305  for (const label proci : subProcs)
306  {
307  if (origIOranks.contains(proci))
308  {
309  subIORanks.push_back(proci);
310  }
311  }
312 
313  // Default starting point
314  Tuple2<label, labelList> commAndIORanks
315  (
317  subIORanks
318  );
319 
320  // TBD: special handling for uncollated
321  // if (origHandler.comm() == UPstream::commSelf())
322  // {
323  // commAndIORanks.first() = UPstream::commSelf();
324  // }
325 
326  const bool hasIOranks = (commAndIORanks.second().size() > 1);
327 
328  if
329  (
331  && (hasIOranks || (subProcs.size() != numProcs))
332  )
333  {
334  // Without any IO range, restrict to overall proc range
335  // since we don't necessarily trust the input...
336  labelRange siblingRange(numProcs);
337 
338  if (hasIOranks)
339  {
340  // Multiple masters: ranks included in my IO range
341  siblingRange = fileOperation::subRanks(commAndIORanks.second());
342  }
343 
344  // Restrict to siblings within the IO range or proc range
345  labelList siblings;
346  if (siblingRange.size())
347  {
348  auto& dynSiblings = subIORanks;
349  dynSiblings.clear();
350 
351  for (const label proci : subProcs)
352  {
353  if (siblingRange.contains(proci))
354  {
355  dynSiblings.push_back(proci);
356  }
357  }
358 
359  siblings.transfer(dynSiblings);
360  }
361 
362  // Warning: MS-MPI currently uses MPI_Comm_create() instead of
363  // MPI_Comm_create_group() so it will block there!
364 
365  commAndIORanks.first() = UPstream::allocateCommunicator
366  (
368  siblings
369  );
370  }
371 
372 
373  // Allocate new handler with same type and similar IO ranks
374  // but with different sub-ranks (and communicator)
375 
376 
377  // Temporarily override world comm to get through the initialisation
378  // (e.g. fileOperation::printRanks() which uses worldComm)
379  const label oldWorldComm = UPstream::commWorld(commAndIORanks.first());
380 
381  newHandler = fileOperation::New
382  (
383  origHandler.type(),
384  commAndIORanks,
385  origHandler.distributed(),
386  verbose
387  );
388 
389  UPstream::commWorld(oldWorldComm);
390 
391  if (newHandler)
392  {
393  // Make sure that the output format uses the correct number of
394  // 'active' ranks (instead of that of the origHandler)
395  newHandler->nProcs(subProcs.size());
396  newHandler->storeComm();
397  }
398  }
400  return newHandler;
401 }
402 
403 
406 (
407  const fileOperation& origHandler,
408  const boolUList& useProc, // in worldComm
409  bool verbose
410 )
411 {
412  const labelList subProcs = getSelectedProcs(useProc);
414  return New_impl(origHandler, subProcs, verbose);
415 }
416 
417 
420 (
421  const fileOperation& origHandler,
422  const bitSet& useProc, // in worldComm
423  bool verbose
424 )
425 {
426  const labelList subProcs = getSelectedProcs(useProc);
427 
428  return New_impl(origHandler, subProcs, verbose);
429 }
430 
431 
432 // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
433 
435 Foam::fileHandler(autoPtr<fileOperation>&& newHandler)
436 {
437  refPtr<fileOperation> oldHandler
438  (
439  fileOperation::fileHandler(std::move(newHandler))
440  );
441 
442  autoPtr<fileOperation> old;
443 
444  // Can return as autoPtr if handler was also a pointer (not a reference)
445  if (oldHandler.is_pointer())
446  {
447  old.reset(oldHandler.release());
448  }
449 
450  return old;
451 }
452 
453 
454 // ************************************************************************* //
static refPtr< fileOperation > fileHandlerPtr_
The currently active file handler. Avoid accessing directly.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
static labelList getSelectedProcs(const BoolListType &useProc)
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:326
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:598
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition: stringOps.H:54
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition: UPstream.H:1176
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
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:1049
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler()
static refPtr< fileOperation > null()
Reference to a dummy file handler.
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: POSIX.C:339
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:1074
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:409
#define FatalErrorInLookup(lookupTag, lookupName, lookupTable)
Report an error message using Foam::FatalError.
Definition: error.H:605
An encapsulation of filesystem-related operations.
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
fileOperation that assumes file operations are local.
Dummy fileOperation, to be used as a placeholder for interfaces taking a reference to a fileOperation...
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:1065
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:137
A class for handling words, derived from Foam::string.
Definition: word.H:63
#define DebugInFunction
Report an information message using Foam::Info.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
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:105
T * get() noexcept
Return pointer without nullptr checking.
Definition: refPtr.H:249
static autoPtr< fileOperation > New(const word &handlerType, bool verbose=false)
Select fileHandler-type. Uses defaultFileHandler if the handlerType is empty.
void push_back(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:555
static label commWorld() noexcept
Communicator for all ranks (respecting any local worlds)
Definition: UPstream.H:429
static labelRange subRanks(const labelUList &mainIOranks)
Get (contiguous) range/bounds of ranks addressed within the given main io-ranks.
T * release() noexcept
Release ownership and return the pointer. A no-op for reference objects (returns nullptr).
Definition: refPtrI.H:266
static word defaultFileHandler
Name of the default fileHandler.
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
const T2 & second() const noexcept
Access the second element.
Definition: Tuple2.H:142
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1082
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.
List< label > labelList
A List of labels.
Definition: List.H:62
const T1 & first() const noexcept
Access the first element.
Definition: Tuple2.H:132
void swap(refPtr< T > &other) noexcept
Swaps the managed object with other.
Definition: refPtrI.H:430
static label allocateCommunicator(const label parent, const labelRange &subRanks, const bool withComponents=true)
Allocate new communicator with contiguous sub-ranks on the parent communicator.
Definition: UPstream.C:258
Namespace for OpenFOAM.
void reset(T *p=nullptr) noexcept
Delete managed pointer and set to new given pointer.
Definition: refPtrI.H:314
static autoPtr< fileOperation > NewUncollated()
The commonly used uncollatedFileOperation.