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-2024 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 int Foam::fileOperation::nProcsFilter_(-1);
84 
85 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
86 
87 namespace
88 {
89 
90 // Need to parse the numbers
91 // from "processors(\d+)" and
92 // from "processors(\d+)_(\d+)-(\d+)"
93 //
94 // Receive the string matching "^(\d+)(?:_(\d+)-(\d+))?/?$"
95 //
96 // \1 = numProcs
97 // \2 = firstProc
98 // \3 = lastProc
99 //
100 // Return true on success and set parameters numProcs and group (size,start)
101 //
102 // Use low-level C-string to integer parsing to drive the sequence.
103 //
104 // For simplicity, also skip INT_MAX checks everywhere but check for
105 // - (errno) for success
106 // - (nptr == endptr) for leading junk
107 // - (*endptr != endChar) for trailing junk
108 // - skip INT_MAX checks as being too pessimistic
109 
110 static bool parseProcsNumRange
111 (
112  const std::string str,
113  int& numProcs,
115 )
116 {
117  const char * nptr = str.c_str();
118  char *endptr = nullptr;
119 
120  // 1. numProcs
121  errno = 0;
122  intmax_t parsed = std::strtoimax(nptr, &endptr, 10);
123  if (errno || nptr == endptr) return false; // bad parse
124 
125  const int nProcs = int(parsed);
126 
127  // End of string? Then no range and we are done.
128  if (*endptr == '\0')
129  {
130  numProcs = nProcs;
131  return true;
132  }
133 
134  // Parse point at start of range ('_' character)?
135  if (*endptr != '_') return false;
136  nptr = ++endptr;
137 
138 
139  // 2. firstProc
140  errno = 0;
141  parsed = std::strtoimax(nptr, &endptr, 10);
142  if (errno || nptr == endptr) return false; // bad parse
143 
144  const int firstProc = int(parsed);
145 
146  // Parse point at range separator ('-' character)?
147  if (*endptr != '-') return false;
148  nptr = ++endptr;
149 
150 
151  // 3. lastProc
152  errno = 0;
153  parsed = std::strtoimax(nptr, &endptr, 10);
154  if (errno || nptr == endptr) return false; // bad parse
155 
156  const int lastProc = int(parsed);
157 
158 
159  if
160  (
161  // Parse point at end of string
162  (*endptr == '\0')
163 
164  // Input plausibility
165  // Accept nProcs == 0 in case that becomes useful in the future
166  && (nProcs >= 0 && firstProc >= 0 && firstProc <= lastProc)
167  )
168  {
169  numProcs = nProcs;
170 
171  // Convert first/last to start/size
172  group.reset(firstProc, lastProc-firstProc+1);
173 
174  return true;
175  }
176 
177  return false;
178 }
179 
180 } // End anonymous namespace
181 
182 
183 // Sorting of processor directories
184 #include "stringOpsSort.H"
185 namespace
186 {
187 
188 // Sort processor directory names (natural order)
189 // - not strictly necessary
190 void sortProcessorDirs(Foam::UList<Foam::fileOperation::dirIndex>& dirs)
191 {
192  if (dirs.size() > 1)
193  {
194  std::stable_sort
195  (
196  dirs.begin(),
197  dirs.end(),
198  []
199  (
202  ) -> bool
203  {
204  return
206  (
207  a.first(),
208  b.first()
209  ) < 0;
210  }
211  );
212  }
213 }
214 
215 } // End anonymous namespace
216 
218 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
219 
222 (
223  const fileNameList& dirEntries,
224  const word& constantName
225 )
226 {
227  // Check for "constant"
228  bool haveConstant = false;
229 
230  if (!constantName.empty())
231  {
232  for (const fileName& dirName : dirEntries)
233  {
234  if (dirName == constantName)
235  {
236  haveConstant = true;
237  break;
238  }
239  }
240  }
241 
242  instantList times(dirEntries.size() + 1);
243  label nTimes = 0;
244 
245  if (haveConstant)
246  {
247  times[nTimes].value() = 0;
248  times[nTimes].name() = constantName;
249  ++nTimes;
250  }
251 
252  // Parse directory entries for scalar values
253  for (const fileName& dirName : dirEntries)
254  {
255  if (readScalar(dirName, times[nTimes].value()))
256  {
257  times[nTimes].name() = dirName;
258  ++nTimes;
259  }
260  }
261 
262  times.resize(nTimes);
263 
264  if (haveConstant)
265  {
266  if (nTimes > 2)
267  {
268  std::sort(&times[1], times.end(), instant::less());
269  }
270  }
271  else if (nTimes > 1)
272  {
273  std::sort(times.begin(), times.end(), instant::less());
274  }
276  return times;
277 }
278 
279 
281 {
282  if (names.empty())
283  {
284  return false;
285  }
286 
287  const auto& object0 = names[0];
288 
289  for (label i = 1; i < names.size(); ++i)
290  {
291  if (object0 != names[i])
292  {
293  return false;
294  }
295  }
297  return true;
298 }
299 
300 
301 bool Foam::fileOperation::uniformFile(const label comm, const fileName& name)
302 {
303  if (!UPstream::parRun())
304  {
305  return true;
306  }
307 
308  fileName masterName(name);
309 
310  Pstream::broadcast(masterName, comm);
311 
312  return returnReduceAnd((masterName == name), comm);
313 }
314 
315 
316 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
317 
319 {
320  if (!monitorPtr_)
321  {
322  monitorPtr_.reset
323  (
324  new fileMonitor
325  (
328  )
329  );
330  }
331  return *monitorPtr_;
332 }
333 
334 
336 (
337  const instantList& extraTimes,
338  const word& constantName,
339  instantList& times
340 )
341 {
342  if (extraTimes.size())
343  {
344  const bool haveConstant =
345  (
346  times.size()
347  && times[0].name() == constantName
348  );
349 
350  const bool haveExtraConstant =
351  (
352  extraTimes.size()
353  && extraTimes[0].name() == constantName
354  );
355 
356  // Combine times
357  instantList combinedTimes(times.size()+extraTimes.size());
358  label sz = 0;
359  label extrai = 0;
360  if (haveExtraConstant)
361  {
362  extrai = 1;
363  if (!haveConstant)
364  {
365  combinedTimes[sz++] = extraTimes[0]; // constant
366  }
367  }
368  forAll(times, i)
369  {
370  combinedTimes[sz++] = times[i];
371  }
372  for (; extrai < extraTimes.size(); extrai++)
373  {
374  combinedTimes[sz++] = extraTimes[extrai];
375  }
376  combinedTimes.setSize(sz);
377  times.transfer(combinedTimes);
378 
379  // Sort
380  if (times.size() > 1)
381  {
382  label starti = 0;
383  if (times[0].name() == constantName)
384  {
385  starti = 1;
386  }
387  std::sort(&times[starti], times.end(), instant::less());
388 
389  // Filter out duplicates
390  label newi = starti+1;
391  for (label i = newi; i < times.size(); i++)
392  {
393  if (times[i].value() != times[i-1].value())
394  {
395  if (newi != i)
396  {
397  times[newi] = times[i];
398  }
399  newi++;
400  }
401  }
402 
403  times.setSize(newi);
404  }
405  }
406 }
407 
408 
409 bool Foam::fileOperation::isFileOrDir(const bool isFile, const fileName& f)
410 {
411  return (isFile ? Foam::isFile(f) : Foam::isDir(f));
412 }
413 
414 
417 (
418  const fileName& fName,
419  const bool syncPar
420 ) const
421 {
422  // If path is local to a processor (e.g. contains 'processor2')
423  // find the corresponding actual processor directory (e.g. 'processors4')
424  // and index (2)
425 
426  // Behaviour affected by
427  // - UPstream::parRun()
428  // - syncPar : usually true, only uncollated does false. Determines
429  // if directory status gets synchronised
430  // - distributed() : different processors have different roots
431  // - fileModificationChecking : (uncollated only) do IO on master only
432  // - nProcsFilter_ : if set to
433  // 0 : accept any directory (e.g. for redistributePar where we don't
434  // know yet number of read/write procs)
435  // -1 : accept only processorsDDD where DDD is nProcs(worldComm)
436  // >0 : accept the exact mentioned number of prcessors
437 
438 
439  // Collated : check whether/how to filter processorsXXX directory names
440  const label targetNProcs
441  (
442  (UPstream::parRun() && nProcsFilter_ < 0)
444  : nProcsFilter_
445  );
446 
447 
448  fileName path, pDir, local;
449  procRangeType group;
450  label numProcs;
451  const label proci =
452  splitProcessorPath(fName, path, pDir, local, group, numProcs);
453 
454  if (proci != -1)
455  {
456  const fileName procPath(path/pDir);
457 
458  if (cacheLevel() > 0)
459  {
460  const auto iter = procsDirs_.cfind(procPath);
461 
462  if (iter.good())
463  {
464  return iter.val();
465  }
466  }
467 
468  DynamicList<dirIndex> procDirs;
469  fileNameList dirEntries;
470 
471  // Read all directories to see any beginning with processor
472  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
473 
474  // Note: use parallel synchronised reading so cache will be same
475  // order on all processors
476 
477  const bool readDirMasterOnly
478  (
479  UPstream::parRun() && !distributed()
480  &&
481  (
484  )
485  );
486 
487  // The above selection excludes masterUncollated, which uses inotify or
488  // timeStamp but provides its own internals for readDir() anyhow.
489 
490  if (readDirMasterOnly)
491  {
492  // Parallel and non-distributed
493  // Read on master only and send to subProcs
494 
496  {
497  dirEntries = Foam::readDir(path, fileName::Type::DIRECTORY);
498 
499  DebugInfo
500  << "readDir on master: send " << dirEntries.size()
501  << " names to sub-processes" << endl;
502  }
503 
505  }
506  else
507  {
508  // Serial or distributed roots.
509  // Handle readDir() with virtual method
510 
511  if (debug)
512  {
513  Pout<< "readDir without special master/send treatment"
514  << endl;
515  }
516 
517  dirEntries = readDir(path, fileName::Type::DIRECTORY);
518  }
519 
520  // Extract info from processorN or processorsNN
521  // - highest processor number
522  // - directory+offset containing data for proci
523 
524  label nProcs = 0;
525  for (const fileName& dirN : dirEntries)
526  {
527  // Analyse directory name
528  fileName rp, rd, rl;
529  label rNum;
530  const label readProci =
531  splitProcessorPath(dirN, rp, rd, rl, group, rNum);
532 
533  nProcs = max(nProcs, readProci+1);
534 
535  Tuple2<pathType, int> pathTypeIdx(pathType::NOTFOUND, 0);
536 
537  if (proci == readProci)
538  {
539  // Found "processorN"
540  pathTypeIdx.first() = pathType::PROCUNCOLLATED;
541  }
542  else if (rNum != -1)
543  {
544  if (targetNProcs > 1 && (targetNProcs != rNum))
545  {
546  // Current directory can never contain wanted proc
547  //Pout<< "For fName:" << fName
548  // << "Ignoring directory " << dirN
549  // << " since parsed rNum:" << rNum
550  // << " targetNProcs:" << targetNProcs
551  // << endl;
552  //error::printStack(Pout);
553 
554  continue;
555  }
556 
557  // "processorsNN" or "processorsNN_start-end"
558  nProcs = max(nProcs, rNum);
559 
560  if (group.empty())
561  {
562  // "processorsNN"
563 
564  if (proci < rNum || (nProcsFilter_ == 0))
565  {
566  // And it is also in range.
567  // Eg for "processors4": 3 is ok, 10 is not
568 
569  pathTypeIdx.first() = pathType::PROCBASEOBJECT;
570  pathTypeIdx.second() = proci;
571  }
572  }
573  else if (group.contains(proci) || (nProcsFilter_ == 0))
574  {
575  // "processorsNN_start-end"
576  // - save the local proc offset
577 
578  pathTypeIdx.first() = pathType::PROCOBJECT;
579  pathTypeIdx.second() = (proci - group.start());
580  }
581  }
582 
583  if (pathTypeIdx.first() != pathType::NOTFOUND)
584  {
585  procDirs.append(dirIndex(dirN, pathTypeIdx));
586  }
587  }
588 
589  // Sort processor directory names (natural order)
590  sortProcessorDirs(procDirs);
591 
592 
593  // Global check of empty/exists.
594  // 1 : empty directory
595  // 2 : non-empty directory
596  // 3 : mixed empty/non-empty directory (after reduce)
597  // Combines andOp<bool>() and orOp<bool>() in single operation
598 
599  unsigned int procDirsStatus = (procDirs.empty() ? 1u : 2u);
600 
601  if (debug)
602  {
603  Pout<< "fileOperation::lookupProcessorsPath " << procPath
604  << " detected:" << flatOutput(procDirs) << endl;
605  }
606 
607  if (UPstream::parRun() && (!distributed() || syncPar))
608  {
609  reduce(procDirsStatus, bitOrOp<unsigned int>()); // worldComm
610 
611  if (procDirsStatus == 3u)
612  {
613  // Mixed empty/exists for procDirs.
614  // Synthesize missing directory name (consistency in cache
615  // existence).
616  // Cannot reliably synthesize RANK-COLLATED, only COLLATED or
617  // UNCOLLATED.
618  //
619  // RANK-COLLATED should have been read from its corresponding
620  // master anyhow
621 
622  int flavour(pathType::PROCUNCOLLATED);
623  for (const dirIndex& pDir : procDirs)
624  {
625  flavour = max(flavour, int(pDir.second().first()));
626  }
627 
628  reduce(nProcs, maxOp<label>()); // worldComm
629  reduce(flavour, maxOp<int>()); // worldComm
630 
631  if (procDirs.empty())
632  {
633  Tuple2<pathType, int> pathTypeIdx(pathType(flavour), 0);
634 
635  if
636  (
637  pathTypeIdx.first() == pathType::PROCBASEOBJECT
638  // Do not restrict to currently used processors
639  // && proci < nProcs
640  )
641  {
642  pathTypeIdx.second() = proci;
643 
644  procDirs.append
645  (
646  dirIndex
647  (
648  processorsBaseDir + Foam::name(nProcs),
649  pathTypeIdx
650  )
651  );
652  }
653  else
654  {
655  // - pathType::PROCUNCOLLATED
656  // - poor fallback for pathType::PROCOBJECT
657  // - out-of-range pathType::PROCBASEOBJECT
658 
659  procDirs.append
660  (
661  dirIndex
662  (
663  "processor" + Foam::name(proci),
664  pathTypeIdx
665  )
666  );
667  }
668 
669  if (debug)
670  {
671  Pout<< "fileOperation::lookupProcessorsPath "
672  << procPath
673  << " synthetic:" << procDirs << endl;
674  }
675  }
676  }
677  }
678  else if (!UPstream::parRun())
679  {
680  // Serial: use the number of decompositions (if found)
681  if (nProcs)
682  {
683  const_cast<fileOperation&>(*this).nProcs(nProcs);
684  }
685  }
686 
687  if (procDirsStatus & 2u)
688  {
689  if (cacheLevel() > 0)
690  {
691  procsDirs_.insert(procPath, procDirs);
692 
693  // Make sure to return a reference
694  return procsDirs_[procPath];
695  }
696  else
697  {
698  return refPtr<dirIndexList>::New(procDirs);
699  }
700  }
701  }
702 
704 }
705 
706 
709 {
710  return lookupAndCacheProcessorsPath(fName, true);
711 }
712 
713 
715 {
716  // Generate output filename for object
717  fileName objPath(objectPath(io, word::null));
718 
719  // Test for either directory or a (valid) file & IOobject
720  bool ok;
721  if (io.name().empty())
722  {
723  ok = isDir(objPath);
724  }
725  else
726  {
727  ok =
728  (
729  isFile(objPath)
730  // object with local scope
731  && io.typeHeaderOk<labelIOList>(false)
732  );
733  }
734 
735  if (!ok)
736  {
737  // Re-test with searched for objectPath. This is for backwards
738  // compatibility
739  fileName originalPath(filePath(io.objectPath()));
740  if (originalPath != objPath)
741  {
742  // Test for either directory or a (valid) file & IOobject
743  if (io.name().empty())
744  {
745  ok = isDir(originalPath);
746  }
747  else
748  {
749  ok =
750  (
751  isFile(originalPath)
752  // object with local scope
753  && io.typeHeaderOk<labelIOList>(false)
754  );
755  }
756  }
757  }
758 
759  return ok;
760 }
762 
763 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
764 
766 (
767  const Tuple2<label, labelList>& commAndIORanks,
768  const bool distributedRoots
769 )
770 :
771  comm_(commAndIORanks.first()),
772  nProcs_(UPstream::nProcs(UPstream::worldComm)),
773  distributed_(distributedRoots),
774  ioRanks_(commAndIORanks.second())
775 {}
776 
777 
779 (
780  const label comm,
781  const labelUList& ioRanks,
782  const bool distributedRoots
783 )
784 :
785  comm_(comm),
786  nProcs_(UPstream::nProcs(UPstream::worldComm)),
787  distributed_(distributedRoots),
788  ioRanks_(ioRanks)
789 {}
791 
792 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
793 
795 (
796  const IOobject& io,
797  const word& typeName
798 ) const
799 {
800  return io.objectPath();
801 }
802 
803 
805 (
806  const regIOobject& io,
807  IOstreamOption streamOpt,
808  const bool writeOnProc
809 ) const
810 {
811  if (writeOnProc)
812  {
813  const fileName pathName(io.objectPath());
814 
815  mkDir(pathName.path());
816 
817  autoPtr<OSstream> osPtr(NewOFstream(pathName, streamOpt));
818 
819  if (!osPtr)
820  {
821  return false;
822  }
823 
824  OSstream& os = *osPtr;
825 
826  // Update meta-data for current state
827  const_cast<regIOobject&>(io).updateMetaData();
828 
829  // If any of these fail, return (leave error handling to Ostream class)
830 
831  const bool ok =
832  (
833  os.good()
834  && io.writeHeader(os)
835  && io.writeData(os)
836  );
837 
838  if (ok)
839  {
841  }
842 
843  return ok;
844  }
845  return true;
846 }
847 
848 
850 (
851  const fileName& fName,
852  const bool checkGzip,
853  const bool followLink
854 ) const
855 {
856  if (debug)
857  {
858  Pout<< "fileOperation::filePath :" << " fName:" << fName << endl;
859  }
860 
861  fileName path, pDir, local;
862  procRangeType group;
863  label numProcs;
864  label proci =
865  splitProcessorPath(fName, path, pDir, local, group, numProcs);
866 
867  if (numProcs != -1)
868  {
869  WarningInFunction << "Filename is already adapted:" << fName << endl;
870  }
871 
872  // Give preference to processors variant
873  fileName foundName;
874  if (proci != -1)
875  {
876  // Get all processor directories
877  refPtr<dirIndexList> procDirs(lookupProcessorsPath(fName));
878  for (const dirIndex& dirIdx : procDirs())
879  {
880  const fileName& procDir = dirIdx.first();
881 
882  fileName collatedName(path/procDir/local);
883  if (exists(collatedName, checkGzip, followLink))
884  {
885  if (debug)
886  {
887  Pout<< "fileOperation::filePath : " << collatedName << endl;
888  }
889  foundName = collatedName;
890  }
891  }
892  }
893 
894  //if (returnReduceOr(foundName.empty())) // worldComm
895  if (foundName.empty())
896  {
897  // There is at least one processor that cannot find the processors
898  // directory. Re-do with straight supplied filename
899  if (exists(fName, checkGzip, followLink))
900  {
901  if (foundName.empty())
902  {
903  foundName = fName;
904  }
905  }
906  }
907 
908  if (!foundName.empty())
909  {
910  if (debug)
911  {
912  Pout<< "fileOperation::filePath : " << foundName << endl;
913  }
914  }
915  else
916  {
917  if (debug)
918  {
919  Pout<< "fileOperation::filePath : Not found" << endl;
920  }
921  }
922  return foundName;
923 }
924 
925 
926 Foam::label Foam::fileOperation::addWatch(const fileName& fName) const
927 {
928  return monitor().addWatch(fName);
929 }
930 
931 
932 bool Foam::fileOperation::removeWatch(const label watchIndex) const
933 {
934  return monitor().removeWatch(watchIndex);
935 }
936 
937 
939 (
940  const labelList& watchIndices,
941  const fileName& fName
942 ) const
943 {
944  forAll(watchIndices, i)
945  {
946  if (getFile(watchIndices[i]) == fName)
947  {
948  return i;
949  }
950  }
951  return -1;
952 }
953 
954 
956 (
957  regIOobject& rio,
958  const fileNameList& files
959 ) const
960 {
961  const labelList& watchIndices = rio.watchIndices();
962 
963  DynamicList<label> newWatchIndices;
964  labelHashSet removedWatches(watchIndices);
965 
966  for (const fileName& f : files)
967  {
968  const label index = findWatch(watchIndices, f);
969 
970  if (index == -1)
971  {
972  newWatchIndices.append(addWatch(f));
973  }
974  else
975  {
976  // Existing watch
977  newWatchIndices.append(watchIndices[index]);
978  removedWatches.erase(index);
979  }
980  }
981 
982  // Remove any unused watches
983  for (const label index : removedWatches)
984  {
985  removeWatch(watchIndices[index]);
986  }
988  rio.watchIndices() = newWatchIndices;
989 }
990 
991 
992 Foam::fileName Foam::fileOperation::getFile(const label watchIndex) const
993 {
994  return monitor().getFile(watchIndex);
995 }
996 
997 
999 (
1000  const bool masterOnly,
1001  const bool syncPar
1002 ) const
1003 {
1004  monitor().updateStates(masterOnly, UPstream::parRun());
1005 }
1006 
1007 
1009 (
1010  const label watchFd
1011 ) const
1013  return monitor().getState(watchFd);
1014 }
1015 
1016 
1017 void Foam::fileOperation::setUnmodified(const label watchFd) const
1018 {
1019  monitor().setUnmodified(watchFd);
1020 }
1021 
1022 
1024 (
1025  const fileName& directory,
1026  const word& constantName
1027 ) const
1028 {
1029  if (debug)
1030  {
1031  Pout<< "fileOperation::findTimes : Finding times in directory "
1032  << directory << endl;
1033  }
1034 
1035  // Note: do NOT use master-only reading here (as per lookupProcessorsPath)
1036  // since this routine is called on an individual processorN directory
1037 
1038  // Read directory entries into a list
1039  fileNameList dirEntries(Foam::readDir(directory, fileName::DIRECTORY));
1040  instantList times = sortTimes(dirEntries, constantName);
1041 
1042 
1043  // Get all processor directories
1044  refPtr<dirIndexList> procDirs(lookupProcessorsPath(directory));
1045  for (const dirIndex& dirIdx : procDirs())
1046  {
1047  const fileName& procDir = dirIdx.first();
1048  fileName collDir(processorsPath(directory, procDir));
1049  if (!collDir.empty() && collDir != directory)
1050  {
1051  fileNameList extraEntries
1052  (
1054  (
1055  collDir,
1057  )
1058  );
1059  mergeTimes
1060  (
1061  sortTimes(extraEntries, constantName),
1062  constantName,
1063  times
1064  );
1065  }
1066  }
1067 
1068  if (debug)
1069  {
1070  Pout<< "fileOperation::findTimes : Found times:" << flatOutput(times)
1071  << endl;
1072  }
1073  return times;
1074 }
1075 
1076 
1078 (
1079  const IOobject& startIO,
1080  const scalar startValue,
1081  const word& stopInstance,
1082  const bool constant_fallback
1083 ) const
1084 {
1085  const Time& time = startIO.time();
1086  IOobject io(startIO);
1087 
1088  // Note: - if name is empty, just check the directory itself
1089  // - check both for isFile and headerOk since the latter does a
1090  // filePath so searches for the file.
1091  // - check for an object with local file scope (so no looking up in
1092  // parent directory in case of parallel)
1093 
1094  if (exists(io))
1095  {
1097  << "Found exact match for \"" << io.name()
1098  << "\" in " << io.instance()/io.local()
1099  << endl;
1100 
1101  return io;
1102  }
1103 
1104  // Handling failures afterwards
1105  const bool exitIfMissing = startIO.isReadRequired();
1106 
1107  enum failureCodes { FAILED_STOPINST = 1, FAILED_CONSTINST = 2 };
1108  int failed(0);
1109 
1110  instantList ts = time.times();
1111 
1112  {
1113  label instIndex = ts.size()-1;
1114 
1115  // Backward search for first time that is <= startValue
1116  for (; instIndex >= 0; --instIndex)
1117  {
1118  if (ts[instIndex].value() <= startValue)
1119  {
1120  break;
1121  }
1122  }
1123 
1124  // Continue (forward) searching from here
1125  for (; instIndex >= 0; --instIndex)
1126  {
1127  io.instance() = ts[instIndex].name();
1128 
1129  // Shortcut: if actual directory is the timeName we've
1130  // already tested it
1131  if
1132  (
1133  io.instance() == startIO.instance()
1134  && io.instance() != stopInstance
1135  )
1136  {
1137  continue;
1138  }
1139 
1140  if (exists(io))
1141  {
1143  << "Found exact match for \"" << io.name()
1144  << "\" in " << io.instance()/io.local()
1145  << endl;
1146 
1147  return io;
1148  }
1149 
1150  // Check if hit minimum instance
1151  if (io.instance() == stopInstance)
1152  {
1154  << "Hit stopInstance " << stopInstance << endl;
1155 
1156  if (exitIfMissing)
1157  {
1158  failed = failureCodes::FAILED_STOPINST;
1159  }
1160  else
1161  {
1162  // At the stopInstance
1163  return io;
1164  }
1165  break;
1166  }
1167  }
1168 
1169 
1170  // times() usually already includes the constant() so would
1171  // have been checked above. However, re-test under these conditions:
1172  // - times() is empty. Sometimes this can happen (e.g. decomposePar
1173  // with collated)
1174  // - times()[0] is not constant
1175  // - Times is empty.
1176  // Sometimes this can happen (eg, decomposePar with collated)
1177  // - Times[0] is not constant
1178  // - The startValue is negative (eg, kivaTest).
1179  // This plays havoc with the reverse search, causing it to miss
1180  // 'constant'
1181 
1182  if
1183  (
1184  !failed
1185  && (ts.empty() || ts[0].name() != time.constant() || startValue < 0)
1186  )
1187  {
1188  io.instance() = time.constant();
1189 
1190  if (exists(io))
1191  {
1193  << "Found constant match for \"" << io.name()
1194  << "\" in " << io.instance()/io.local()
1195  << endl;
1196 
1197  return io;
1198  }
1199  }
1200  }
1201 
1202 
1203  if (!failed)
1204  {
1205  if (exitIfMissing)
1206  {
1207  failed = failureCodes::FAILED_CONSTINST;
1208  }
1209  else if (constant_fallback)
1210  {
1211  io.instance() = time.constant();
1212  }
1213  else
1214  {
1215  io.instance().clear();
1216  }
1217  }
1218 
1219 
1220  // Handle failures
1221  // ~~~~~~~~~~~~~~~
1222 
1223  if (failed)
1224  {
1225  FatalErrorInFunction << "Cannot find";
1226 
1227  if (!io.name().empty())
1228  {
1229  FatalError
1230  << " file \"" << io.name() << "\" in";
1231  }
1232 
1233  FatalError
1234  << " directory "
1235  << io.local() << " in times "
1236  << startIO.instance() << " down to ";
1237 
1238  if (failed == failureCodes::FAILED_STOPINST)
1239  {
1240  FatalError << stopInstance;
1241  }
1242  else // FAILED_CONSTINST
1243  {
1244  FatalError << "constant";
1245  }
1247  }
1248 
1249  return io;
1250 }
1251 
1252 
1254 (
1255  const objectRegistry& obr,
1256  const fileName& instance,
1257  const fileName& local,
1258  word& newInstance
1259 ) const
1260 {
1261  if (debug)
1262  {
1263  Pout<< "fileOperation::readObjects :"
1264  << " object-path:" << obr.objectPath()
1265  << " instance" << instance
1266  << " local:" << local << endl;
1267  }
1268 
1269  // dbDir() is relative to Time,
1270  // so use dbDir() from self or from parent, but not both!
1271  fileName path;
1272  if (obr.dbDir().empty() || !obr.parent().dbDir().empty())
1273  {
1274  path = obr.path(instance, local);
1275  }
1276  else
1277  {
1278  path = obr.path(instance, obr.dbDir()/local);
1279  }
1280 
1281  newInstance.clear();
1282  fileNameList objectNames;
1283 
1284  if (Foam::isDir(path))
1285  {
1286  newInstance = instance;
1287  objectNames = Foam::readDir(path, fileName::Type::FILE);
1288  }
1289  else
1290  {
1291  // Get processors equivalent of path
1292  fileName procsPath(filePath(path));
1293 
1294  if (!procsPath.empty())
1295  {
1296  newInstance = instance;
1297  objectNames = Foam::readDir(procsPath, fileName::Type::FILE);
1298  }
1299  }
1300  return objectNames;
1301 }
1302 
1303 
1304 Foam::label Foam::fileOperation::nProcs
1305 (
1306  const fileName& dir,
1307  const fileName& local,
1308  const label wanted // expected nProcs. 0 if not supplied
1309 ) const
1310 {
1311  label nProcs = 0;
1312  if (UPstream::master(comm_))
1313  {
1314  fileNameList dirNames(Foam::readDir(dir, fileName::Type::DIRECTORY));
1315 
1316  // E.g. (maybe left over)
1317  // processor0
1318  // processor1
1319  // processors5
1320  // processor90 // gap!
1321  // processors10
1322  //
1323  //- if wanted is 2 then processor0,1 is enough
1324  //- if wanted is not set then return highest valid range
1325  // (processors10 in above case)
1326  //- if wanted cannot be matched (e.g. 37) return 0
1327 
1328  // For marking off contiguous ranges
1329  bitSet foundDirs;
1330  if (wanted > 0)
1331  {
1332  foundDirs.resize(wanted);
1333  }
1334 
1335  // Detect any processorsDDD or processorDDD
1336  label maxProc = -1;
1337  for (const fileName& dirN : dirNames)
1338  {
1339  fileName rp, rd, rl;
1340  procRangeType group;
1341  label rNum;
1342 
1343  const label readProci =
1344  splitProcessorPath(dirN, rp, rd, rl, group, rNum);
1345 
1346  maxProc = max(maxProc, readProci);
1347 
1348  if (rNum > 0) // processorsDDD where DDD>0
1349  {
1350  // Use processors number
1351  maxProc = max(maxProc, rNum-1);
1352  // Mark in cache. TBD separate handling for groups?
1353  foundDirs.set(labelRange(0, rNum));
1354 
1355  if (wanted == rNum)
1356  {
1357  // Exact match of processorsDDD. Direct exit.
1358  maxProc = rNum-1;
1359  foundDirs.resize(rNum);
1360  break;
1361  }
1362  }
1363  else if (readProci >= 0)
1364  {
1365  // Mark in cache
1366  foundDirs.set(readProci);
1367  }
1368  }
1369  nProcs = maxProc+1;
1370 
1371  // Override with any gaps in processorDDD numbering (can never happen
1372  // with collated)
1373  const label gapIndex = foundDirs.find_first_not();
1374  if (gapIndex > 0)
1375  {
1376  nProcs = gapIndex-1;
1377  }
1378 
1379  if (nProcs == 0 && Foam::isDir(dir/processorsBaseDir))
1380  {
1382  << "Defunct collated naming: " << processorsBaseDir << nl
1383  << "Manually rename with the decomposition number. Eg,"
1384  << nl << nl
1385  << " mv processors processors16" << nl << nl
1386  << "...returning 1" << endl;
1387 
1388  nProcs = 1;
1389  }
1390  }
1391  Pstream::broadcast(nProcs, comm_);
1392  return nProcs;
1393 }
1395 
1396 void Foam::fileOperation::flush() const
1397 {
1398  if (debug)
1399  {
1400  Pout<< "fileOperation::flush : clearing processor directories cache"
1401  << endl;
1402  }
1403  procsDirs_.clear();
1404 }
1406 
1408 {
1409  if (debug)
1410  {
1411  Pout<< "fileOperation::sync : parallel synchronisation"
1412  << endl;
1413  }
1414 
1416  (
1418  nProcs_,
1419  procsDirs_
1420  );
1421 }
1422 
1425 (
1426  const IOobject& io,
1427  const word& procsDir
1428 ) const
1429 {
1430  return io.rootPath()/io.globalCaseName()/procsDir;
1431 }
1432 
1435 (
1436  const IOobject& io,
1437  const word& instance,
1438  const word& procsDir
1439 ) const
1440 {
1441  return
1442  processorsCasePath(io, procsDir)
1443  /instance
1444  /io.db().dbDir()
1445  /io.local();
1446 }
1447 
1450 (
1451  const fileName& dir,
1452  const word& procsDir
1453 ) const
1454 {
1455  // Check if directory is processorDDD
1456 
1457  const word caseName(dir.name());
1458  if (caseName.starts_with("processor"))
1459  {
1460  // Reject both '^processor$' and '^processors.*$'
1461 
1462  if (!std::isdigit(caseName[9]))
1463  {
1464  WarningInFunction << "Directory " << dir
1465  << " does not end in old-style processorDDD" << endl;
1466  }
1467 
1468  return dir.path()/procsDir;
1469  }
1470 
1471  return fileName();
1472 }
1473 
1476 (
1477  const fileName& objPath,
1478  fileName& path,
1479  fileName& procDir,
1480  fileName& local,
1481 
1483  label& nProcs
1484 )
1485 {
1486  // Return value
1487  label returnProci = -1;
1488 
1489  // Clear out the return parameters
1490 
1491  path.clear();
1492  procDir.clear();
1493  local.clear();
1494  group.clear();
1495 
1496  // Invalidate detected number of processors
1497  nProcs = -1;
1498 
1499  // The local processor group is read as first/last, but stored as
1500  // start/size. Empty with start=0, size=0 if no range is detected
1501 
1502 
1503  // Start of 'processor..' directory name (the procDir)
1504  size_t pos = 0;
1505 
1506  // The slash starting the trailing (local) directory
1507  size_t slashLocal = string::npos;
1508 
1509 
1510  // Search for processor at start of string or after /processor
1511  //
1512  // 'processor(\d+)'
1513  // 'processors(\d+)'
1514  // 'processors(\d+)_(\d+)-(\d+)'
1515 
1516  for
1517  (
1518  /*nil*/;
1519  (pos = objPath.find("processor", pos)) != string::npos;
1520  pos += 9
1521  )
1522  {
1523  if (pos > 0 && objPath[pos-1] != '/')
1524  {
1525  // Not start of string or after /processor
1526  continue;
1527  }
1528 
1529  // The parse point. One past 'processor'
1530  size_t firstp = pos + 9;
1531 
1532  // normal: 'processor(\d+)'
1533  // plural: 'processors(\d+)'
1534 
1535  const bool plural = (objPath[firstp] == 's');
1536 
1537  if (plural)
1538  {
1539  ++firstp; // Skip over the 's'
1540  }
1541  else if (!std::isdigit(objPath[firstp]))
1542  {
1543  // Non-plural version (uncollated) requires digits only
1544  continue;
1545  }
1546 
1547  // The next slash indicates there is a local directory
1548  slashLocal = objPath.find('/', firstp);
1549 
1550  // The last parse point is the slash, or end of string
1551  const size_t lastp =
1552  (slashLocal == string::npos ? objPath.length() : slashLocal);
1553 
1554  if (!std::isdigit(objPath[lastp-1]))
1555  {
1556  // Must end in a digit!
1557  // This traps entries that are too short or look quite wrong
1558  // and avoid a string to int conversion that will fail anyhow
1559  continue;
1560  }
1561 
1562 
1563  // Match: '^processors(\d+)$' -> nProcs
1564 
1565  // Match: '^processors(\d+)_(\d+)-(\d+)$'
1566  // \1 = nProcs
1567  // \2 = beg processor group
1568  // \3 = end processor group (inclusive)
1569 
1570  if (plural)
1571  {
1572  int nProcsRead = 0;
1573 
1574  if
1575  (
1576  parseProcsNumRange
1577  (
1578  objPath.substr(firstp, lastp-firstp),
1579  nProcsRead,
1580  group
1581  )
1582  )
1583  {
1584  // Total number of processors
1585  nProcs = nProcsRead;
1586 
1587  // We are done!
1588  break;
1589  }
1590  }
1591 
1592  // Single
1593  // Match: '^processor(\d+)$' -> proci
1594 
1595  label proci = 0;
1596  if
1597  (
1598  Foam::read(objPath.substr(firstp, lastp-firstp), proci)
1599  && (proci >= 0)
1600  )
1601  {
1602  // Capture value of an individual processor
1603  returnProci = proci;
1604 
1605  // We are done!
1606  break;
1607  }
1608  }
1609 
1610  if (pos != string::npos)
1611  {
1612  // The split succeeded, extract the components.
1613 
1614  // The leading directory
1615  if (pos > 0)
1616  {
1617  path = objPath.substr(0, pos-1);
1618  }
1619 
1620  // The slash starting the trailing (local) directory
1621  if (slashLocal != string::npos)
1622  {
1623  procDir = objPath.substr(pos, slashLocal-pos);
1624  local = objPath.substr(slashLocal+1);
1625  }
1626  else
1627  {
1628  procDir = objPath.substr(pos);
1629  }
1630  }
1631 
1632  return returnProci;
1633 }
1635 
1636 Foam::label Foam::fileOperation::detectProcessorPath(const fileName& fName)
1637 {
1638  fileName path, pDir, local;
1640  label nProcs;
1641  return splitProcessorPath(fName, path, pDir, local, group, nProcs);
1642 }
1643 
1644 
1645 // * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * //
1647 Foam::Ostream& Foam::operator<<
1648 (
1649  Ostream& os,
1650  const InfoProxy<fileOperation>& iproxy
1651 )
1652 {
1653  const auto& fp = *iproxy;
1654 
1655  os << "fileHandler:" << fp.type()
1656  << " nProcs:" << fp.nProcs()
1657  << " comm:" << fp.comm()
1658  << " distributed:" << fp.distributed()
1659  << " ioranks: " << flatOutput(fp.ioRanks())
1660  << " ranks: ";
1661 
1662  if (fp.comm() >= 0)
1663  {
1664  os << flatOutput(UPstream::procID(fp.comm()));
1665  }
1666  os << nl;
1667 
1668  return os;
1669 }
1670 
1671 // ************************************************************************* //
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.
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
static std::string::size_type length(const char *s)
Length of the character sequence (with nullptr protection)
Definition: string.H:258
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:498
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:72
virtual IOobject findInstance(const IOobject &io, const scalar startValue, const word &stopInstance, const bool constant_fallback=true) const
Find time instance where IOobject is located. The name of the IOobject can be empty, in which case only the IOobject::local() is checked. Does not search beyond stopInstance (if set) or constant.
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:153
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:326
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
Checking for changes to files.
Definition: fileMonitor.H:61
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
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:195
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:70
A range or interval of labels defined by a start and a size.
Definition: labelRange.H:52
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:675
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:531
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1061
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:421
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
label find_first_not() const
Locate the first bit that is unset.
Definition: bitSetI.H:289
An encapsulation of filesystem-related operations.
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:284
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 communicator ranks. Does nothing in non-paral...
fileName path() const
The complete path for the object (with instance, local,...).
Definition: IOobject.C:480
void resize(const label numElem, const unsigned int val=0u)
Reset addressable list size, does not shrink the allocated size.
Definition: PackedListI.H:455
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:421
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)
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1077
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:320
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 expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
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 instantList findTimes(const fileName &, const word &) const
Get sorted list of times.
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:296
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:450
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
const fileName & globalCaseName() const noexcept
Return the Time::globalCaseName()
Definition: IOobject.C:474
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:584
String literal.
Definition: keyType.H:82
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition: UListI.H:392
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
bool typeHeaderOk(const bool checkType=true, const bool search=true, const bool verbose=true)
Read header (respects is_globalIOobject trait) 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:456
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:56
const labelList & watchIndices() const noexcept
Read access to file-monitoring handles.
Definition: regIOobjectI.H:206
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:112
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:351
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:266
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 communicator ranks. Does nothing in non-parallel. ...
bool erase(const iterator &iter)
Erase an entry specified by given iterator.
Definition: HashTable.C:496
static bool isFileOrDir(const bool isFile, const fileName &)
Helper: check for file (isFile) or directory (!isFile)
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
const fileName & rootPath() const noexcept
Return the Time::rootPath()
Definition: IOobject.C:462
A helper class for outputting values to Ostream.
Definition: ensightCells.H:44
instantList times() const
Search the case for valid time directories.
Definition: TimePaths.C:118
static word defaultFileHandler
Name of the default fileHandler.
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
#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...
Definition: error.H:64
static List< int > & procID(const label communicator)
The list of ranks within a given communicator.
Definition: UPstream.H:1142
const objectRegistry & parent() const noexcept
Return the parent objectRegistry.
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:1094
regIOobject is an abstract class derived from IOobject to handle automatic object registration with t...
Definition: regIOobject.H:68
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:436
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
List< instant > instantList
List of instants.
Definition: instantList.H:41
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:278
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:180
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:65
void reduce(T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) using linear/tree communication schedule.
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