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