fileOperation.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) 2017-2018 OpenFOAM Foundation
9  Copyright (C) 2019-2022 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 "fileOperation.H"
31 #include "regIOobject.H"
32 #include "argList.H"
33 #include "HashSet.H"
34 #include "objectRegistry.H"
35 #include "decomposedBlockData.H"
36 #include "polyMesh.H"
37 #include "registerSwitch.H"
38 #include "Time.H"
39 #include "ITstream.H"
40 #include <cerrno>
41 #include <cinttypes>
42 
43 /* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
44 
45 namespace Foam
46 {
47  defineTypeNameAndDebug(fileOperation, 0);
48  defineRunTimeSelectionTable(fileOperation, word);
49 
51  (
52  debug::optimisationSwitches().getOrAdd<word>
53  (
54  "fileHandler",
55  //Foam::fileOperations::uncollatedFileOperation::typeName,
56  "uncollated",
58  )
59  );
60 }
61 
62 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
63 
66 ({
67  { fileOperation::NOTFOUND, "notFound" },
68  { fileOperation::ABSOLUTE, "absolute" },
69  { fileOperation::OBJECT, "objectPath" },
70  { fileOperation::WRITEOBJECT, "writeObject" },
71  { fileOperation::PROCUNCOLLATED, "uncollatedProc" },
72  { fileOperation::PROCBASEOBJECT, "globalProc" },
73  { fileOperation::PROCOBJECT, "localProc" },
74  { fileOperation::PARENTOBJECT, "parentObjectPath" },
75  { fileOperation::FINDINSTANCE, "findInstance" },
76  { fileOperation::PROCUNCOLLATEDINSTANCE, "uncollatedProcInstance" },
77  { fileOperation::PROCBASEINSTANCE, "globalProcInstance" },
78  { fileOperation::PROCINSTANCE, "localProcInstance" }
79 });
80 
81 
83 
85 
86 
87 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
88 
89 namespace
90 {
91 
92 // Need to parse the numbers
93 // from "processors(\d+)" and
94 // from "processors(\d+)_(\d+)-(\d+)"
95 //
96 // Receive the string matching "^(\d+)(?:_(\d+)-(\d+))?/?$"
97 //
98 // \1 = numProcs
99 // \2 = firstProc
100 // \3 = lastProc
101 //
102 // Return true on success and set parameters numProcs and group (size,start)
103 //
104 // Use low-level C-string to integer parsing to drive the sequence.
105 //
106 // For simplicity, also skip INT_MAX checks everywhere but check for
107 // - (errno) for success
108 // - (nptr == endptr) for leading junk
109 // - (*endptr != endChar) for trailing junk
110 // - skip INT_MAX checks as being too pessimistic
111 
112 static bool parseProcsNumRange
113 (
114  const std::string str,
115  int& numProcs,
117 )
118 {
119  const char * nptr = str.c_str();
120  char *endptr = nullptr;
121 
122  // 1. numProcs
123  errno = 0;
124  intmax_t parsed = std::strtoimax(nptr, &endptr, 10);
125  if (errno || nptr == endptr) return false; // bad parse
126 
127  const int nProcs = int(parsed);
128 
129  // End of string? Then no range and we are done.
130  if (*endptr == '\0')
131  {
132  numProcs = nProcs;
133  return true;
134  }
135 
136  // Parse point at start of range ('_' character)?
137  if (*endptr != '_') return false;
138  nptr = ++endptr;
139 
140 
141  // 2. firstProc
142  errno = 0;
143  parsed = std::strtoimax(nptr, &endptr, 10);
144  if (errno || nptr == endptr) return false; // bad parse
145 
146  const int firstProc = int(parsed);
147 
148  // Parse point at range separator ('-' character)?
149  if (*endptr != '-') return false;
150  nptr = ++endptr;
151 
152 
153  // 3. lastProc
154  errno = 0;
155  parsed = std::strtoimax(nptr, &endptr, 10);
156  if (errno || nptr == endptr) return false; // bad parse
157 
158  const int lastProc = int(parsed);
159 
160 
161  if
162  (
163  // Parse point at end of string
164  (*endptr == '\0')
165 
166  // Input plausibility
167  // Accept nProcs == 0 in case that becomes useful in the future
168  && (nProcs >= 0 && firstProc >= 0 && firstProc <= lastProc)
169  )
170  {
171  numProcs = nProcs;
172 
173  // Convert first/last to start/size
174  group.reset(firstProc, lastProc-firstProc+1);
175 
176  return true;
177  }
178 
179  return false;
180 }
181 
182 } // End anonymous namespace
183 
184 
185 #if 0
186 
187 // Sorting of processor directories
188 #include "stringOpsSort.H"
189 namespace
190 {
191 
192 // Sort processor directory names (natural order)
193 // - not strictly necessary
194 void sortProcessorDirs(Foam::UList<Foam::fileOperation::dirIndex>& dirs)
195 {
196  if (dirs.size() > 1)
197  {
198  std::stable_sort
199  (
200  dirs.begin(),
201  dirs.end(),
202  []
203  (
206  ) -> bool
207  {
208  return
210  (
211  a.first(),
212  b.first()
213  ) < 0;
214  }
215  );
216  }
217 }
218 
219 } // End anonymous namespace
220 #endif
221 
222 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
223 
225 {
226  labelList ranks;
227 
228  ITstream is(Foam::getEnv("FOAM_IORANKS"));
229  if (!is.empty())
230  {
231  is >> ranks;
232  }
234  return ranks;
235 }
236 
237 
240 (
241  const fileNameList& dirEntries,
242  const word& constantName
243 )
244 {
245  // Check for "constant"
246  bool haveConstant = false;
247 
248  if (!constantName.empty())
249  {
250  for (const fileName& dirName : dirEntries)
251  {
252  if (dirName == constantName)
253  {
254  haveConstant = true;
255  break;
256  }
257  }
258  }
259 
260  instantList times(dirEntries.size() + 1);
261  label nTimes = 0;
262 
263  if (haveConstant)
264  {
265  times[nTimes].value() = 0;
266  times[nTimes].name() = constantName;
267  ++nTimes;
268  }
269 
270  // Parse directory entries for scalar values
271  for (const fileName& dirName : dirEntries)
272  {
273  if (readScalar(dirName, times[nTimes].value()))
274  {
275  times[nTimes].name() = dirName;
276  ++nTimes;
277  }
278  }
279 
280  times.resize(nTimes);
281 
282  if (haveConstant)
283  {
284  if (nTimes > 2)
285  {
286  std::sort(&times[1], times.end(), instant::less());
287  }
288  }
289  else if (nTimes > 1)
290  {
291  std::sort(times.begin(), times.end(), instant::less());
292  }
293 
294  return times;
295 }
296 
297 
299 {
300  if (names.empty())
301  {
302  return false;
303  }
304 
305  const auto& object0 = names[0];
306 
307  for (label i = 1; i < names.size(); ++i)
308  {
309  if (object0 != names[i])
310  {
311  return false;
312  }
313  }
314 
315  return true;
316 }
317 
318 
319 bool Foam::fileOperation::uniformFile(const label comm, const fileName& name)
320 {
321  if (!Pstream::parRun())
322  {
323  return true;
324  }
325 
326  fileName masterName(name);
327 
328  Pstream::broadcast(masterName, comm);
330  return returnReduceAnd((masterName == name), comm);
331 }
332 
333 
334 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
335 
337 {
338  if (!monitorPtr_)
339  {
340  monitorPtr_.reset
341  (
342  new fileMonitor
343  (
346  )
347  );
348  }
349  return *monitorPtr_;
350 }
351 
352 
354 (
355  const instantList& extraTimes,
356  const word& constantName,
357  instantList& times
358 )
359 {
360  if (extraTimes.size())
361  {
362  const bool haveConstant =
363  (
364  times.size()
365  && times[0].name() == constantName
366  );
367 
368  const bool haveExtraConstant =
369  (
370  extraTimes.size()
371  && extraTimes[0].name() == constantName
372  );
373 
374  // Combine times
375  instantList combinedTimes(times.size()+extraTimes.size());
376  label sz = 0;
377  label extrai = 0;
378  if (haveExtraConstant)
379  {
380  extrai = 1;
381  if (!haveConstant)
382  {
383  combinedTimes[sz++] = extraTimes[0]; // constant
384  }
385  }
386  forAll(times, i)
387  {
388  combinedTimes[sz++] = times[i];
389  }
390  for (; extrai < extraTimes.size(); extrai++)
391  {
392  combinedTimes[sz++] = extraTimes[extrai];
393  }
394  combinedTimes.setSize(sz);
395  times.transfer(combinedTimes);
396 
397  // Sort
398  if (times.size() > 1)
399  {
400  label starti = 0;
401  if (times[0].name() == constantName)
402  {
403  starti = 1;
404  }
405  std::sort(&times[starti], times.end(), instant::less());
406 
407  // Filter out duplicates
408  label newi = starti+1;
409  for (label i = newi; i < times.size(); i++)
410  {
411  if (times[i].value() != times[i-1].value())
412  {
413  if (newi != i)
414  {
415  times[newi] = times[i];
416  }
417  newi++;
418  }
419  }
421  times.setSize(newi);
422  }
423  }
424 }
425 
426 
427 bool Foam::fileOperation::isFileOrDir(const bool isFile, const fileName& f)
428 {
429  return (isFile ? Foam::isFile(f) : Foam::isDir(f));
430 }
431 
432 
435 (
436  const fileName& fName,
437  const bool syncPar
438 ) const
439 {
440  // If path is local to a processor (e.g. contains 'processor2')
441  // find the corresponding actual processor directory (e.g. 'processors4')
442  // and index (2)
443 
444  fileName path, pDir, local;
445  procRangeType group;
446  label numProcs;
447  const label proci =
448  splitProcessorPath(fName, path, pDir, local, group, numProcs);
449 
450  if (proci != -1)
451  {
452  const fileName procPath(path/pDir);
453 
454  const auto iter = procsDirs_.cfind(procPath);
455 
456  if (iter.found())
457  {
458  return iter.val();
459  }
460 
461  DynamicList<dirIndex> procDirs;
462  fileNameList dirEntries;
463 
464  // Read all directories to see any beginning with processor
465  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
466 
467  // Note: use parallel synchronised reading so cache will be same
468  // order on all processors
469 
470  const bool readDirMasterOnly
471  (
472  Pstream::parRun() && !distributed()
473  &&
474  (
477  )
478  );
479 
480  // The above selection excludes masterUncollated, which uses inotify or
481  // timeStamp but provides its own internals for readDir() anyhow.
482 
483  if (readDirMasterOnly)
484  {
485  // Parallel and non-distributed
486  // Read on master only and send to subProcs
487 
488  if (Pstream::master(comm_))
489  {
490  dirEntries = Foam::readDir(path, fileName::Type::DIRECTORY);
491 
492  DebugInfo
493  << "readDir on master: send " << dirEntries.size()
494  << " names to sub-processes" << endl;
495  }
496 
497  Pstream::broadcast(dirEntries, comm_);
498  }
499  else
500  {
501  // Serial or distributed roots.
502  // Handle readDir() with virtual method
503 
504  if (debug)
505  {
506  Pout<< "readDir without special master/send treatment"
507  << endl;
508  }
509 
510  dirEntries = readDir(path, fileName::Type::DIRECTORY);
511  }
512 
513  // Extract info from processorN or processorsNN
514  // - highest processor number
515  // - directory+offset containing data for proci
516 
517  label nProcs = 0;
518  for (const fileName& dirN : dirEntries)
519  {
520  // Analyse directory name
521  fileName rp, rd, rl;
522  label rNum;
523  const label readProci =
524  splitProcessorPath(dirN, rp, rd, rl, group, rNum);
525 
526  nProcs = max(nProcs, readProci+1);
527 
528  Tuple2<pathType, int> pathTypeIdx(pathType::NOTFOUND, 0);
529 
530  if (proci == readProci)
531  {
532  // Found "processorN"
533  pathTypeIdx.first() = pathType::PROCUNCOLLATED;
534  }
535  else if (rNum != -1)
536  {
537  // "processorsNN" or "processorsNN_start-end"
538  nProcs = max(nProcs, rNum);
539 
540  if (group.empty())
541  {
542  // "processorsNN"
543 
544  if (proci < rNum)
545  {
546  // And it is also in range.
547  // Eg for "processors4": 3 is ok, 10 is not
548 
549  pathTypeIdx.first() = pathType::PROCBASEOBJECT;
550  pathTypeIdx.second() = proci;
551  }
552  }
553  else if (group.found(proci))
554  {
555  // "processorsNN_start-end"
556  // - save the local proc offset
557 
558  pathTypeIdx.first() = pathType::PROCOBJECT;
559  pathTypeIdx.second() = (proci - group.start());
560  }
561  }
562 
563  if (pathTypeIdx.first() != pathType::NOTFOUND)
564  {
565  procDirs.append(dirIndex(dirN, pathTypeIdx));
566  }
567  }
568 
569  // Global check of empty/exists.
570  // 1 : empty directory
571  // 2 : non-empty directory
572  // 3 : mixed empty/non-empty directory (after reduce)
573  // Combines andOp<bool>() and orOp<bool>() in single operation
574 
575  unsigned procDirsStatus = (procDirs.empty() ? 1u : 2u);
576 
577  if (debug)
578  {
579  Pout<< "fileOperation::lookupProcessorsPath " << procPath
580  << " detected:" << procDirs << endl;
581  }
582 
583  if (Pstream::parRun() && (!distributed() || syncPar))
584  {
585  reduce(procDirsStatus, bitOrOp<unsigned>()); // worldComm
586 
587  if (procDirsStatus == 3u)
588  {
589  // Mixed empty/exists for procDirs.
590  // Synthesize missing directory name (consistency in cache
591  // existence).
592  // Cannot reliably synthesize RANK-COLLATED, only COLLATED or
593  // UNCOLLATED.
594  //
595  // RANK-COLLATED should have been read from its corresponding
596  // master anyhow
597 
598  int flavour(pathType::PROCUNCOLLATED);
599  for (const dirIndex& pDir : procDirs)
600  {
601  flavour = max(flavour, int(pDir.second().first()));
602  }
603 
604  reduce(nProcs, maxOp<label>()); // worldComm
605  reduce(flavour, maxOp<int>()); // worldComm
606 
607  if (procDirs.empty())
608  {
609  Tuple2<pathType, int> pathTypeIdx(pathType(flavour), 0);
610 
611  if
612  (
613  pathTypeIdx.first() == pathType::PROCBASEOBJECT
614  && proci < nProcs
615  )
616  {
617  pathTypeIdx.second() = proci;
618 
619  procDirs.append
620  (
621  dirIndex
622  (
623  processorsBaseDir + Foam::name(nProcs),
624  pathTypeIdx
625  )
626  );
627  }
628  else
629  {
630  // - pathType::PROCUNCOLLATED
631  // - poor fallback for pathType::PROCOBJECT
632  // - out-of-range pathType::PROCBASEOBJECT
633 
634  procDirs.append
635  (
636  dirIndex
637  (
638  "processor" + Foam::name(proci),
639  pathTypeIdx
640  )
641  );
642  }
643 
644  if (debug)
645  {
646  Pout<< "fileOperation::lookupProcessorsPath "
647  << procPath
648  << " synthetic:" << procDirs << endl;
649  }
650  }
651  }
652  }
653  else if (!Pstream::parRun())
654  {
655  // Serial: use the number of decompositions (if found)
656  if (nProcs)
657  {
658  const_cast<fileOperation&>(*this).setNProcs(nProcs);
659  }
660  }
661 
662  // Sort processor directory names (natural order)
664 
665  if (procDirsStatus & 2u)
666  {
667  procsDirs_.insert(procPath, procDirs);
668 
669  // Make sure to return a reference
670  return procsDirs_[procPath];
671  }
672  }
673 
674  return refPtr<dirIndexList>::New();
675 }
676 
677 
680 {
681  // Use parallel synchronisation
682  return lookupAndCacheProcessorsPath(fName, true);
683 }
684 
685 
687 {
688  // Generate output filename for object
689  fileName objPath(objectPath(io, word::null));
690 
691  // Test for either directory or a (valid) file & IOobject
692  bool ok;
693  if (io.name().empty())
694  {
695  ok = isDir(objPath);
696  }
697  else
698  {
699  ok =
700  isFile(objPath)
701  && io.typeHeaderOk<IOList<label>>(false);// object with local scope
702  }
703 
704  if (!ok)
705  {
706  // Re-test with searched for objectPath. This is for backwards
707  // compatibility
708  fileName originalPath(filePath(io.objectPath()));
709  if (originalPath != objPath)
710  {
711  // Test for either directory or a (valid) file & IOobject
712  if (io.name().empty())
713  {
714  ok = isDir(originalPath);
715  }
716  else
717  {
718  ok =
719  isFile(originalPath)
720  && io.typeHeaderOk<IOList<label>>(false);
721  }
722  }
723  }
724 
725  return ok;
726 }
727 
728 
729 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
730 
732 (
733  const label comm,
734  const bool distributedRoots
735 )
736 :
737  comm_(comm),
738  distributed_(distributedRoots)
739 {}
740 
741 
744 (
745  const word& handlerType,
746  bool verbose
747 )
748 {
749  if (handlerType.empty())
750  {
752  {
754  << "defaultFileHandler name is undefined" << nl
755  << abort(FatalError);
756  }
757 
759  }
760 
762  << "Constructing fileHandler" << endl;
763 
764  auto* ctorPtr = wordConstructorTable(handlerType);
765 
766  if (!ctorPtr)
767  {
769  (
770  "fileHandler",
771  handlerType,
772  *wordConstructorTablePtr_
773  ) << abort(FatalError);
774  }
776  return autoPtr<fileOperation>(ctorPtr(verbose));
777 }
778 
779 
780 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
781 
782 bool Foam::fileOperation::distributed(bool on) const noexcept
783 {
784  bool old(distributed_);
785  distributed_ = on;
786  return old;
787 }
788 
789 
791 (
792  const IOobject& io,
793  const word& typeName
794 ) const
795 {
796  return io.objectPath();
797 }
798 
799 
801 (
802  const regIOobject& io,
803  IOstreamOption streamOpt,
804  const bool valid
805 ) const
806 {
807  if (valid)
808  {
809  const fileName pathName(io.objectPath());
810 
811  mkDir(pathName.path());
812 
813  autoPtr<OSstream> osPtr(NewOFstream(pathName, streamOpt));
814 
815  if (!osPtr)
816  {
817  return false;
818  }
819 
820  OSstream& os = *osPtr;
821 
822  // Update meta-data for current state
823  const_cast<regIOobject&>(io).updateMetaData();
824 
825  // If any of these fail, return (leave error handling to Ostream class)
826 
827  const bool ok =
828  (
829  os.good()
830  && io.writeHeader(os)
831  && io.writeData(os)
832  );
833 
834  if (ok)
835  {
837  }
838 
839  return ok;
840  }
841  return true;
842 }
843 
844 
846 (
847  const fileName& fName,
848  const bool checkGzip,
849  const bool followLink
850 ) const
851 {
852  if (debug)
853  {
854  Pout<< "fileOperation::filePath :" << " fName:" << fName << endl;
855  }
856 
857  fileName path, pDir, local;
858  procRangeType group;
859  label numProcs;
860  label proci =
861  splitProcessorPath(fName, path, pDir, local, group, numProcs);
862 
863  if (numProcs != -1)
864  {
865  WarningInFunction << "Filename is already adapted:" << fName << endl;
866  }
867 
868  // Give preference to processors variant
869  if (proci != -1)
870  {
871  // Get all processor directories
872  refPtr<dirIndexList> procDirs(lookupProcessorsPath(fName));
873  for (const dirIndex& dirIdx : procDirs())
874  {
875  const fileName& procDir = dirIdx.first();
876 
877  fileName collatedName(path/procDir/local);
878  if (exists(collatedName, checkGzip, followLink))
879  {
880  if (debug)
881  {
882  Pout<< "fileOperation::filePath : " << collatedName << endl;
883  }
884  return collatedName;
885  }
886  }
887  }
888 
889  if (exists(fName, checkGzip, followLink))
890  {
891  if (debug)
892  {
893  Pout<< "fileOperation::filePath : " << fName << endl;
894  }
895  return fName;
896  }
897 
898  if (debug)
899  {
900  Pout<< "fileOperation::filePath : Not found" << endl;
901  }
902 
903  return fileName();
904 }
905 
907 Foam::label Foam::fileOperation::addWatch(const fileName& fName) const
908 {
909  return monitor().addWatch(fName);
910 }
911 
912 
913 bool Foam::fileOperation::removeWatch(const label watchIndex) const
914 {
915  return monitor().removeWatch(watchIndex);
916 }
917 
918 
920 (
921  const labelList& watchIndices,
922  const fileName& fName
923 ) const
924 {
925  forAll(watchIndices, i)
926  {
927  if (getFile(watchIndices[i]) == fName)
928  {
929  return i;
930  }
931  }
932  return -1;
933 }
934 
935 
937 (
938  regIOobject& rio,
939  const fileNameList& files
940 ) const
941 {
942  const labelList& watchIndices = rio.watchIndices();
943 
944  DynamicList<label> newWatchIndices;
945  labelHashSet removedWatches(watchIndices);
946 
947  for (const fileName& f : files)
948  {
949  const label index = findWatch(watchIndices, f);
950 
951  if (index == -1)
952  {
953  newWatchIndices.append(addWatch(f));
954  }
955  else
956  {
957  // Existing watch
958  newWatchIndices.append(watchIndices[index]);
959  removedWatches.erase(index);
960  }
961  }
962 
963  // Remove any unused watches
964  for (const label index : removedWatches)
965  {
966  removeWatch(watchIndices[index]);
967  }
968 
969  rio.watchIndices() = newWatchIndices;
970 }
971 
972 
973 Foam::fileName Foam::fileOperation::getFile(const label watchIndex) const
974 {
975  return monitor().getFile(watchIndex);
976 }
977 
978 
980 (
981  const bool masterOnly,
982  const bool syncPar
983 ) const
984 {
985  monitor().updateStates(masterOnly, Pstream::parRun());
986 }
987 
988 
990 (
991  const label watchFd
992 ) const
993 {
994  return monitor().getState(watchFd);
995 }
996 
997 
998 void Foam::fileOperation::setUnmodified(const label watchFd) const
999 {
1000  monitor().setUnmodified(watchFd);
1001 }
1002 
1003 
1005 (
1006  const fileName& directory,
1007  const word& constantName
1008 ) const
1009 {
1010  if (debug)
1011  {
1012  Pout<< "fileOperation::findTimes : Finding times in directory "
1013  << directory << endl;
1014  }
1015 
1016  // Note: do NOT use master-only reading here (as per lookupProcessorsPath)
1017  // since this routine is called on an individual processorN directory
1018 
1019  // Read directory entries into a list
1020  fileNameList dirEntries(Foam::readDir(directory, fileName::DIRECTORY));
1021  instantList times = sortTimes(dirEntries, constantName);
1022 
1023 
1024  // Get all processor directories
1025  refPtr<dirIndexList> procDirs(lookupProcessorsPath(directory));
1026  for (const dirIndex& dirIdx : procDirs())
1027  {
1028  const fileName& procDir = dirIdx.first();
1029  fileName collDir(processorsPath(directory, procDir));
1030  if (!collDir.empty() && collDir != directory)
1031  {
1032  fileNameList extraEntries
1033  (
1035  (
1036  collDir,
1038  )
1039  );
1040  mergeTimes
1041  (
1042  sortTimes(extraEntries, constantName),
1043  constantName,
1044  times
1045  );
1046  }
1047  }
1048 
1049  if (debug)
1050  {
1051  Pout<< "fileOperation::findTimes : Found times:" << flatOutput(times)
1052  << endl;
1053  }
1054  return times;
1055 }
1056 
1057 
1059 (
1060  const IOobject& startIO,
1061  const scalar startValue,
1062  const word& stopInstance
1063 ) const
1064 {
1065  const Time& time = startIO.time();
1066  IOobject io(startIO);
1067 
1068  // Note: - if name is empty, just check the directory itself
1069  // - check both for isFile and headerOk since the latter does a
1070  // filePath so searches for the file.
1071  // - check for an object with local file scope (so no looking up in
1072  // parent directory in case of parallel)
1073 
1074  if (exists(io))
1075  {
1077  << "Found exact match for \"" << io.name()
1078  << "\" in " << io.instance()/io.local()
1079  << endl;
1080 
1081  return io;
1082  }
1083 
1084  // Handling failures afterwards
1085  const bool exitIfMissing = startIO.isReadRequired();
1086 
1087  enum failureCodes { FAILED_STOPINST = 1, FAILED_CONSTINST = 2 };
1088  int failed(0);
1089 
1090  instantList ts = time.times();
1091 
1092  {
1093  label instIndex = ts.size()-1;
1094 
1095  // Backward search for first time that is <= startValue
1096  for (; instIndex >= 0; --instIndex)
1097  {
1098  if (ts[instIndex].value() <= startValue)
1099  {
1100  break;
1101  }
1102  }
1103 
1104  // Continue (forward) searching from here
1105  for (; instIndex >= 0; --instIndex)
1106  {
1107  io.instance() = ts[instIndex].name();
1108 
1109  // Shortcut: if actual directory is the timeName we've
1110  // already tested it
1111  if
1112  (
1113  io.instance() == startIO.instance()
1114  && io.instance() != stopInstance
1115  )
1116  {
1117  continue;
1118  }
1119 
1120  if (exists(io))
1121  {
1123  << "Found exact match for \"" << io.name()
1124  << "\" in " << io.instance()/io.local()
1125  << endl;
1126 
1127  return io;
1128  }
1129 
1130  // Check if hit minimum instance
1131  if (io.instance() == stopInstance)
1132  {
1134  << "Hit stopInstance " << stopInstance << endl;
1135 
1136  if (exitIfMissing)
1137  {
1138  failed = failureCodes::FAILED_STOPINST;
1139  }
1140  else
1141  {
1142  return io;
1143  }
1144  break;
1145  }
1146  }
1147 
1148 
1149  // times() usually already includes the constant() so would
1150  // have been checked above. However, re-test under these conditions:
1151  // - times() is empty. Sometimes this can happen (e.g. decomposePar
1152  // with collated)
1153  // - times()[0] is not constant
1154  // - Times is empty.
1155  // Sometimes this can happen (eg, decomposePar with collated)
1156  // - Times[0] is not constant
1157  // - The startValue is negative (eg, kivaTest).
1158  // This plays havoc with the reverse search, causing it to miss
1159  // 'constant'
1160 
1161  if
1162  (
1163  !failed
1164  && (ts.empty() || ts[0].name() != time.constant() || startValue < 0)
1165  )
1166  {
1167  io.instance() = time.constant();
1168 
1169  if (exists(io))
1170  {
1172  << "Found constant match for \"" << io.name()
1173  << "\" in " << io.instance()/io.local()
1174  << endl;
1175 
1176  return io;
1177  }
1178  }
1179  }
1180 
1181 
1182  if (!failed && exitIfMissing)
1183  {
1184  failed = failureCodes::FAILED_CONSTINST;
1185  }
1186 
1187  // Handle failures
1188  // ~~~~~~~~~~~~~~~
1189 
1190  if (failed)
1191  {
1192  FatalErrorInFunction << "Cannot find";
1193 
1194  if (!io.name().empty())
1195  {
1196  FatalError
1197  << " file \"" << io.name() << "\" in";
1198  }
1199 
1200  FatalError
1201  << " directory "
1202  << io.local() << " in times "
1203  << startIO.instance() << " down to ";
1204 
1205  if (failed == failureCodes::FAILED_STOPINST)
1206  {
1207  FatalError << stopInstance;
1208  }
1209  else
1210  {
1211  FatalError << "constant";
1212  }
1214  }
1215 
1216  return io;
1217 }
1218 
1219 
1221 (
1222  const objectRegistry& db,
1223  const fileName& instance,
1224  const fileName& local,
1225  word& newInstance
1226 ) const
1227 {
1228  if (debug)
1229  {
1230  Pout<< "fileOperation::readObjects :"
1231  << " db:" << db.objectPath()
1232  << " instance:" << instance << endl;
1233  }
1234 
1235  fileName path(db.path(instance, db.dbDir()/local));
1236 
1237  newInstance.clear();
1238  fileNameList objectNames;
1239 
1240  if (Foam::isDir(path))
1241  {
1242  newInstance = instance;
1243  objectNames = Foam::readDir(path, fileName::FILE);
1244  }
1245  else
1246  {
1247  // Get processors equivalent of path
1248  fileName procsPath(filePath(path));
1249 
1250  if (!procsPath.empty())
1251  {
1252  newInstance = instance;
1253  objectNames = Foam::readDir(procsPath, fileName::FILE);
1254  }
1255  }
1256  return objectNames;
1257 }
1259 
1260 void Foam::fileOperation::setNProcs(const label nProcs)
1261 {}
1262 
1263 
1264 Foam::label Foam::fileOperation::nProcs
1265 (
1266  const fileName& dir,
1267  const fileName& local
1268 ) const
1269 {
1270  label nProcs = 0;
1271  if (Pstream::master(comm_))
1272  {
1273  fileNameList dirNames(Foam::readDir(dir, fileName::Type::DIRECTORY));
1274 
1275  // Detect any processorsDDD or processorDDD
1276  label maxProc = -1;
1277  for (const fileName& dirN : dirNames)
1278  {
1279  fileName rp, rd, rl;
1280  procRangeType group;
1281  label rNum;
1282 
1283  const label readProci =
1284  splitProcessorPath(dirN, rp, rd, rl, group, rNum);
1285 
1286  maxProc = max(maxProc, readProci);
1287  if (rNum != -1)
1288  {
1289  // Direct detection of processorsDDD
1290  maxProc = rNum-1;
1291  break;
1292  }
1293  }
1294  nProcs = maxProc+1;
1295 
1296  if (nProcs == 0 && Foam::isDir(dir/processorsBaseDir))
1297  {
1299  << "Defunct collated naming: " << processorsBaseDir << nl
1300  << "Manually rename with the decomposition number. Eg,"
1301  << nl << nl
1302  << " mv processors processors16" << nl << nl
1303  << "...returning 1" << endl;
1304 
1305  nProcs = 1;
1306  }
1307  }
1308  Pstream::broadcast(nProcs, comm_);
1309  return nProcs;
1310 }
1311 
1312 
1313 void Foam::fileOperation::flush() const
1314 {
1315  if (debug)
1316  {
1317  Pout<< "fileOperation::flush : clearing processor directories cache"
1318  << endl;
1319  }
1320  procsDirs_.clear();
1321 }
1322 
1323 
1325 (
1326  const IOobject& io,
1327  const word& procsDir
1328 ) const
1329 {
1330  return io.rootPath()/io.time().globalCaseName()/procsDir;
1331 }
1332 
1333 
1335 (
1336  const IOobject& io,
1337  const word& instance,
1338  const word& procsDir
1339 ) const
1340 {
1341  return
1342  processorsCasePath(io, procsDir)
1343  /instance
1344  /io.db().dbDir()
1345  /io.local();
1346 }
1347 
1348 
1350 (
1351  const fileName& dir,
1352  const word& procsDir
1353 ) const
1354 {
1355  // Check if directory is processorDDD
1356 
1357  const word caseName(dir.name());
1358  if (caseName.starts_with("processor"))
1359  {
1360  // Reject both '^processor$' and '^processors.*$'
1361 
1362  if (!std::isdigit(caseName[9]))
1363  {
1364  WarningInFunction << "Directory " << dir
1365  << " does not end in old-style processorDDD" << endl;
1366  }
1367 
1368  return dir.path()/procsDir;
1369  }
1370 
1371  return fileName();
1372 }
1373 
1374 
1376 (
1377  const fileName& objPath,
1378  fileName& path,
1379  fileName& procDir,
1380  fileName& local,
1381 
1382  procRangeType& group,
1383  label& nProcs
1384 )
1385 {
1386  // Return value
1387  label returnProci = -1;
1388 
1389  // Clear out the return parameters
1390 
1391  path.clear();
1392  procDir.clear();
1393  local.clear();
1394  group.clear();
1395 
1396  // Invalidate detected number of processors
1397  nProcs = -1;
1398 
1399  // The local processor group is read as first/last, but stored as
1400  // start/size. Empty with start=0, size=0 if no range is detected
1401 
1402 
1403  // Start of 'processor..' directory name (the procDir)
1404  size_t pos = 0;
1405 
1406  // The slash starting the trailing (local) directory
1407  size_t slashLocal = string::npos;
1408 
1409 
1410  // Search for processor at start of string or after /processor
1411  //
1412  // 'processor(\d+)'
1413  // 'processors(\d+)'
1414  // 'processors(\d+)_(\d+)-(\d+)'
1415 
1416  for
1417  (
1418  /*nil*/;
1419  (pos = objPath.find("processor", pos)) != string::npos;
1420  pos += 9
1421  )
1422  {
1423  if (pos > 0 && objPath[pos-1] != '/')
1424  {
1425  // Not start of string or after /processor
1426  continue;
1427  }
1428 
1429  // The parse point. One past 'processor'
1430  size_t firstp = pos + 9;
1431 
1432  // normal: 'processor(\d+)'
1433  // plural: 'processors(\d+)'
1434 
1435  const bool plural = (objPath[firstp] == 's');
1436 
1437  if (plural)
1438  {
1439  ++firstp; // Skip over the 's'
1440  }
1441  else if (!std::isdigit(objPath[firstp]))
1442  {
1443  // Non-plural version (uncollated) requires digits only
1444  continue;
1445  }
1446 
1447  // The next slash indicates there is a local directory
1448  slashLocal = objPath.find('/', firstp);
1449 
1450  // The last parse point is the slash, or end of string
1451  const size_t lastp =
1452  (slashLocal == string::npos ? objPath.length() : slashLocal);
1453 
1454  if (!std::isdigit(objPath[lastp-1]))
1455  {
1456  // Must end in a digit!
1457  // This traps entries that are too short or look quite wrong
1458  // and avoid a string to int conversion that will fail anyhow
1459  continue;
1460  }
1461 
1462 
1463  // Match: '^processors(\d+)$' -> nProcs
1464 
1465  // Match: '^processors(\d+)_(\d+)-(\d+)$'
1466  // \1 = nProcs
1467  // \2 = beg processor group
1468  // \3 = end processor group (inclusive)
1469 
1470  if (plural)
1471  {
1472  int nProcsRead = 0;
1473 
1474  if
1475  (
1476  parseProcsNumRange
1477  (
1478  objPath.substr(firstp, lastp-firstp),
1479  nProcsRead,
1480  group
1481  )
1482  )
1483  {
1484  // Total number of processors
1485  nProcs = nProcsRead;
1486 
1487  // We are done!
1488  break;
1489  }
1490  }
1491 
1492  // Single
1493  // Match: '^processor(\d+)$' -> proci
1494 
1495  label proci = 0;
1496  if
1497  (
1498  Foam::read(objPath.substr(firstp, lastp-firstp), proci)
1499  && (proci >= 0)
1500  )
1501  {
1502  // Capture value of an individual processor
1503  returnProci = proci;
1504 
1505  // We are done!
1506  break;
1507  }
1508  }
1509 
1510  if (pos != string::npos)
1511  {
1512  // The split succeeded, extract the components.
1513 
1514  // The leading directory
1515  if (pos > 0)
1516  {
1517  path = objPath.substr(0, pos-1);
1518  }
1519 
1520  // The slash starting the trailing (local) directory
1521  if (slashLocal != string::npos)
1522  {
1523  procDir = objPath.substr(pos, slashLocal-pos);
1524  local = objPath.substr(slashLocal+1);
1525  }
1526  else
1527  {
1528  procDir = objPath.substr(pos);
1529  }
1530  }
1531 
1532  return returnProci;
1533 }
1534 
1535 
1536 Foam::label Foam::fileOperation::detectProcessorPath(const fileName& fName)
1537 {
1538  fileName path, pDir, local;
1539  procRangeType group;
1540  label nProcs;
1541  return splitProcessorPath(fName, path, pDir, local, group, nProcs);
1542 }
1543 
1544 
1545 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
1546 
1548 {
1549  return autoPtr<fileOperation>
1550  (
1552  );
1553 }
1554 
1555 
1556 // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
1557 
1559 {
1561  {
1562  word handlerType(Foam::getEnv("FOAM_FILEHANDLER"));
1563 
1564  if (handlerType.empty())
1565  {
1566  handlerType = fileOperation::defaultFileHandler;
1567  }
1568 
1570  }
1571 
1573 }
1574 
1575 
1577 Foam::fileHandler(std::nullptr_t)
1578 {
1579  return autoPtr<fileOperation>(fileOperation::fileHandlerPtr_.release());
1580 }
1581 
1582 
1584 Foam::fileHandler(autoPtr<fileOperation>&& newHandler)
1585 {
1586  // - do nothing if newHandler is empty. Does not delete current
1587  // - do nothing if newHandler is identical to current handler
1588 
1589  // Change ownership as atomic operations
1590 
1591  // If newHandler and current handler are actually identical, we
1592  // have a bit problem somewhere else since this means that the pointer
1593  // is managed is done in two places!
1594  // Should flag as a FatalError (in the future), but there may still be
1595  // some place where we would like to fake shared pointers?
1596 
1597  // TBD: add a flush() operation on the old handler first,
1598  // instead of waiting for it to be run on destruction?
1599 
1600  autoPtr<fileOperation> old;
1601 
1602  if
1603  (
1604  newHandler.get() != nullptr
1605  && newHandler.get() != fileOperation::fileHandlerPtr_.get()
1606  )
1607  {
1608  old.reset(newHandler.release());
1610  }
1611 
1612  return old;
1613 }
1614 
1615 
1616 // ************************************************************************* //
static const Enum< pathType > pathTypeNames_
Definition: fileOperation.H:94
static label detectProcessorPath(const fileName &objPath)
Detect processor number from &#39;/aa/bb/processorDDD/cc&#39;.
virtual refPtr< dirIndexList > lookupProcessorsPath(const fileName &objectPath) const
Lookup name of processorsDDD using cache.
List< instant > instantList
List of instants.
Definition: instantList.H:41
fileOperation(const label comm, const bool distributedRoots=false)
Construct from communicator, optionally with distributed roots.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
List< word > names(const UPtrList< T > &list, const UnaryMatchPredicate &matcher)
List of names generated by calling name() for each list item and filtered for matches.
A class for handling file names.
Definition: fileName.H:71
Specialized string sorting.
virtual fileMonitor::fileState getState(const label) const
Get current state of file (using handle)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:132
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
Checking for changes to files.
Definition: fileMonitor.H:62
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition: stringOps.H:55
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:150
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
static refPtr< T > New(Args &&... args)
Construct refPtr with forwarding arguments.
Definition: refPtr.H:186
An interval of (signed) integers defined by a start and a size.
Definition: IntRange.H:59
fileState
Enumeration defining the file state.
Definition: fileMonitor.H:71
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:420
virtual void setUnmodified(const label) const
Set current state of file (using handle) to unmodified.
bool exists(IOobject &io) const
Does IOObject exist. Is either a directory (empty name()) or a file.
virtual fileNameList readObjects(const objectRegistry &db, const fileName &instance, const fileName &local, word &newInstance) const
Search directory for objects. Used in IOobjectList.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:639
autoPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler.
A simple container for options an IOstream can normally have.
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:169
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: POSIX.C:292
#define FatalErrorInLookup(lookupTag, lookupName, lookupTable)
Report an error message using Foam::FatalError.
Definition: error.H:585
static word processorsBaseDir
Return the processors directory name (usually "processors")
fileName processorsPath(const IOobject &, const word &instance, const word &procDir) const
Generate path (like io.path) with provided instance and any.
static bool less(const vector &x, const vector &y)
To compare normals.
bool writeHeader(Ostream &os) const
Write header with current type()
A class for managing references or pointers (no reference counting)
Definition: HashPtrTable.H:49
An encapsulation of filesystem-related operations.
Definition: fileOperation.H:63
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:239
static bool isReadRequired(readOption opt) noexcept
True if (MUST_READ | MUST_READ_IF_MODIFIED) bits are set.
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all processes in communicator.
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:125
refPtr< dirIndexList > lookupAndCacheProcessorsPath(const fileName &objectPath, const bool syncPar) const
Lookup name of processorsDDD using cache.
fileOperation that assumes file operations are local.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
constexpr const char *const group
Group name for atomic constants.
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:813
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
virtual void updateStates(const bool masterOnly, const bool syncPar) const
Update state of all files.
dimensionedScalar pos(const dimensionedScalar &ds)
bool returnReduceAnd(const bool value, const label comm=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
static label splitProcessorPath(const fileName &objectPath, fileName &path, fileName &procDir, fileName &local, procRangeType &group, label &nProcs)
Split objectPath into part before &#39;processor&#39; and part after.
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
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:567
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
virtual fileName filePath(const bool checkGlobal, const IOobject &, const word &typeName, const bool search=true) const =0
Search for an object. checkGlobal : also check undecomposed case.
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
A class for handling words, derived from Foam::string.
Definition: word.H:63
virtual fileName getFile(const label) const
Get name of file being watched (using handle)
#define DebugInFunction
Report an information message using Foam::Info.
virtual IOobject findInstance(const IOobject &io, const scalar startValue, const word &stopInstance) const
Find instance where IOobject is.
virtual instantList findTimes(const fileName &, const word &) const
Get sorted list of times.
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:334
A regular file.
Definition: fileName.H:83
regionProperties rp(runTime)
const objectRegistry & db() const noexcept
Return the local objectRegistry.
Definition: IOobject.C:441
static const word null
An empty word.
Definition: word.H:84
bool exists(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist (as DIRECTORY or FILE) in the file system?
Definition: POSIX.C:788
virtual void addWatches(regIOobject &, const fileNameList &) const
Helper: add watches for list of regIOobjects.
static int compare(const std::string &s1, const std::string &s2)
Natural compare for std::string.
Definition: stringOpsSort.H:71
static instantList sortTimes(const fileNameList &dirEntries, const word &constantName="constant")
Sort directory entries according to time value,.
bool local
Definition: EEqn.H:20
virtual label addWatch(const fileName &) const
Add watching of a file. Returns handle.
String literal.
Definition: keyType.H:82
virtual bool writeObject(const regIOobject &io, IOstreamOption streamOpt=IOstreamOption(), const bool valid=true) const
Writes a regIOobject (so header, contents and divider).
errorManip< error > abort(error &err)
Definition: errorManip.H:139
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition: UListI.H:322
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
bool typeHeaderOk(const bool checkType=true, const bool search=true, const bool verbose=true)
Read header (uses typeFilePath to find file) and check its info.
#define DebugInfo
Report an information message using Foam::Info.
static void mergeTimes(const instantList &extraTimes, const word &constantName, instantList &times)
Merge two times.
static Ostream & writeEndDivider(Ostream &os)
Write the standard end file divider.
const direction noexcept
Definition: Scalar.H:258
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:192
defineRunTimeSelectionTable(reactionRateFlameArea, dictionary)
int debug
Static debugging option.
fileName processorsCasePath(const IOobject &, const word &procDir) const
Generate path (like io.path) from root+casename with any.
OBJstream os(runTime.globalPath()/outputName)
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
defineTypeNameAndDebug(combustionModel, 0)
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:313
fileMonitor & monitor() const
Get or create fileMonitor singleton.
labelList f(nPoints)
static autoPtr< fileOperation > fileHandlerPtr_
Static fileOperation.
static autoPtr< fileOperation > New(const word &handlerType, bool verbose=false)
Select fileHandler-type. Uses defaultFileHandler if the handlerType is empty.
static bool uniformFile(const fileNameList &names)
True if the file names are identical. False on an empty list.
const fileName & instance() const noexcept
Read access to instance path component.
Definition: IOobjectI.H:221
virtual void flush() const
Forcibly wait until all output done. Flush any cached data.
static bool isFileOrDir(const bool isFile, const fileName &)
Helper: check for file (isFile) or directory (!isFile)
const fileName & rootPath() const
Return the Time::rootPath()
Definition: IOobject.C:453
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:830
virtual label nProcs(const fileName &dir, const fileName &local="") const
Get number of processor directories/results. Used for e.g.
static word defaultFileHandler
Name of the default fileHandler.
#define WarningInFunction
Report a warning using Foam::Warning.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
const fileName & globalCaseName() const noexcept
Return global case name.
Definition: TimePathsI.H:49
const Time & time() const
Return Time associated with the objectRegistry.
Definition: IOobject.C:447
bool good() const noexcept
True if next operation might succeed.
Definition: IOstream.H:274
static bool master(const label communicator=worldComm)
Am I the master rank.
Definition: UPstream.H:672
bool distributed() const noexcept
Distributed roots (parallel run)
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
regIOobject is an abstract class derived from IOobject to handle automatic object registration with t...
Definition: regIOobject.H:69
virtual const fileName & dbDir() const
Local directory path of this objectRegistry relative to the time.
dictionary & optimisationSwitches()
The OptimisationSwitches sub-dictionary in the central controlDict(s).
Definition: debug.C:216
iterator end() noexcept
Return an iterator to end traversing the UList.
Definition: UListI.H:343
List< label > labelList
A List of labels.
Definition: List.H:62
static labelList ioRanks()
Retrieve list of IO ranks from FOAM_IORANKS env variable.
const T1 & first() const noexcept
Access the first element.
Definition: Tuple2.H:132
const fileName & local() const noexcept
Read access to local path component.
Definition: IOobjectI.H:233
virtual label findWatch(const labelList &watchIndices, const fileName &) const
Find index (or -1) of file in list of handles.
fileNameList readDir(const fileName &directory, const fileName::Type type=fileName::Type::FILE, const bool filtergz=true, const bool followLink=true)
Read a directory and return the entries as a fileName List.
Definition: POSIX.C:916
List< fileName > fileNameList
A List of fileNames.
Definition: fileNameList.H:54
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:166
virtual fileName objectPath(const IOobject &io, const word &typeName) const
Generate disk file name for object. Opposite of filePath.
virtual void setNProcs(const label nProcs)
Set number of processor directories/results. Only used in.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
virtual bool removeWatch(const label) const
Remove watch on a file (using handle)
Namespace for OpenFOAM.
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225
static autoPtr< fileOperation > NewUncollated()
Static construct the commonly used uncollatedFileOperation.