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 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
1083 {
1084  const Time& time = startIO.time();
1085  IOobject io(startIO);
1086 
1087  // Note: - if name is empty, just check the directory itself
1088  // - check both for isFile and headerOk since the latter does a
1089  // filePath so searches for the file.
1090  // - check for an object with local file scope (so no looking up in
1091  // parent directory in case of parallel)
1092 
1093  if (exists(io))
1094  {
1096  << "Found exact match for \"" << io.name()
1097  << "\" in " << io.instance()/io.local()
1098  << endl;
1099 
1100  return io;
1101  }
1102 
1103  // Handling failures afterwards
1104  const bool exitIfMissing = startIO.isReadRequired();
1105 
1106  enum failureCodes { FAILED_STOPINST = 1, FAILED_CONSTINST = 2 };
1107  int failed(0);
1108 
1109  instantList ts = time.times();
1110 
1111  {
1112  label instIndex = ts.size()-1;
1113 
1114  // Backward search for first time that is <= startValue
1115  for (; instIndex >= 0; --instIndex)
1116  {
1117  if (ts[instIndex].value() <= startValue)
1118  {
1119  break;
1120  }
1121  }
1122 
1123  // Continue (forward) searching from here
1124  for (; instIndex >= 0; --instIndex)
1125  {
1126  io.instance() = ts[instIndex].name();
1127 
1128  // Shortcut: if actual directory is the timeName we've
1129  // already tested it
1130  if
1131  (
1132  io.instance() == startIO.instance()
1133  && io.instance() != stopInstance
1134  )
1135  {
1136  continue;
1137  }
1138 
1139  if (exists(io))
1140  {
1142  << "Found exact match for \"" << io.name()
1143  << "\" in " << io.instance()/io.local()
1144  << endl;
1145 
1146  return io;
1147  }
1148 
1149  // Check if hit minimum instance
1150  if (io.instance() == stopInstance)
1151  {
1153  << "Hit stopInstance " << stopInstance << endl;
1154 
1155  if (exitIfMissing)
1156  {
1157  failed = failureCodes::FAILED_STOPINST;
1158  }
1159  else
1160  {
1161  return io;
1162  }
1163  break;
1164  }
1165  }
1166 
1167 
1168  // times() usually already includes the constant() so would
1169  // have been checked above. However, re-test under these conditions:
1170  // - times() is empty. Sometimes this can happen (e.g. decomposePar
1171  // with collated)
1172  // - times()[0] is not constant
1173  // - Times is empty.
1174  // Sometimes this can happen (eg, decomposePar with collated)
1175  // - Times[0] is not constant
1176  // - The startValue is negative (eg, kivaTest).
1177  // This plays havoc with the reverse search, causing it to miss
1178  // 'constant'
1179 
1180  if
1181  (
1182  !failed
1183  && (ts.empty() || ts[0].name() != time.constant() || startValue < 0)
1184  )
1185  {
1186  io.instance() = time.constant();
1187 
1188  if (exists(io))
1189  {
1191  << "Found constant match for \"" << io.name()
1192  << "\" in " << io.instance()/io.local()
1193  << endl;
1194 
1195  return io;
1196  }
1197  }
1198  }
1199 
1200 
1201  if (!failed && exitIfMissing)
1202  {
1203  failed = failureCodes::FAILED_CONSTINST;
1204  }
1205 
1206  // Handle failures
1207  // ~~~~~~~~~~~~~~~
1208 
1209  if (failed)
1210  {
1211  FatalErrorInFunction << "Cannot find";
1212 
1213  if (!io.name().empty())
1214  {
1215  FatalError
1216  << " file \"" << io.name() << "\" in";
1217  }
1218 
1219  FatalError
1220  << " directory "
1221  << io.local() << " in times "
1222  << startIO.instance() << " down to ";
1223 
1224  if (failed == failureCodes::FAILED_STOPINST)
1225  {
1226  FatalError << stopInstance;
1227  }
1228  else
1229  {
1230  FatalError << "constant";
1231  }
1233  }
1234 
1235  return io;
1236 }
1237 
1238 
1240 (
1241  const objectRegistry& obr,
1242  const fileName& instance,
1243  const fileName& local,
1244  word& newInstance
1245 ) const
1246 {
1247  if (debug)
1248  {
1249  Pout<< "fileOperation::readObjects :"
1250  << " object-path:" << obr.objectPath()
1251  << " instance" << instance
1252  << " local:" << local << endl;
1253  }
1254 
1255  // dbDir() is relative to Time,
1256  // so use dbDir() from self or from parent, but not both!
1257  fileName path;
1258  if (obr.dbDir().empty() || !obr.parent().dbDir().empty())
1259  {
1260  path = obr.path(instance, local);
1261  }
1262  else
1263  {
1264  path = obr.path(instance, obr.dbDir()/local);
1265  }
1266 
1267  newInstance.clear();
1268  fileNameList objectNames;
1269 
1270  if (Foam::isDir(path))
1271  {
1272  newInstance = instance;
1273  objectNames = Foam::readDir(path, fileName::Type::FILE);
1274  }
1275  else
1276  {
1277  // Get processors equivalent of path
1278  fileName procsPath(filePath(path));
1279 
1280  if (!procsPath.empty())
1281  {
1282  newInstance = instance;
1283  objectNames = Foam::readDir(procsPath, fileName::Type::FILE);
1284  }
1285  }
1286  return objectNames;
1287 }
1288 
1289 
1290 Foam::label Foam::fileOperation::nProcs
1291 (
1292  const fileName& dir,
1293  const fileName& local,
1294  const label wanted // expected nProcs. 0 if not supplied
1295 ) const
1296 {
1297  label nProcs = 0;
1298  if (UPstream::master(comm_))
1299  {
1300  fileNameList dirNames(Foam::readDir(dir, fileName::Type::DIRECTORY));
1301 
1302  // E.g. (maybe left over)
1303  // processor0
1304  // processor1
1305  // processors5
1306  // processor90 // gap!
1307  // processors10
1308  //
1309  //- if wanted is 2 then processor0,1 is enough
1310  //- if wanted is not set then return highest valid range
1311  // (processors10 in above case)
1312  //- if wanted cannot be matched (e.g. 37) return 0
1313 
1314  // For marking off contiguous ranges
1315  bitSet foundDirs;
1316  if (wanted > 0)
1317  {
1318  foundDirs.resize(wanted);
1319  }
1320 
1321  // Detect any processorsDDD or processorDDD
1322  label maxProc = -1;
1323  for (const fileName& dirN : dirNames)
1324  {
1325  fileName rp, rd, rl;
1326  procRangeType group;
1327  label rNum;
1328 
1329  const label readProci =
1330  splitProcessorPath(dirN, rp, rd, rl, group, rNum);
1331 
1332  maxProc = max(maxProc, readProci);
1333 
1334  if (rNum > 0) // processorsDDD where DDD>0
1335  {
1336  // Use processors number
1337  maxProc = max(maxProc, rNum-1);
1338  // Mark in cache. TBD separate handling for groups?
1339  foundDirs.set(labelRange(0, rNum));
1340 
1341  if (wanted == rNum)
1342  {
1343  // Exact match of processorsDDD. Direct exit.
1344  maxProc = rNum-1;
1345  foundDirs.resize(rNum);
1346  break;
1347  }
1348  }
1349  else if (readProci >= 0)
1350  {
1351  // Mark in cache
1352  foundDirs.set(readProci);
1353  }
1354  }
1355  nProcs = maxProc+1;
1356 
1357  // Override with any gaps in processorDDD numbering (can never happen
1358  // with collated)
1359  const label gapIndex = foundDirs.find_first_not();
1360  if (gapIndex > 0)
1361  {
1362  nProcs = gapIndex-1;
1363  }
1364 
1365  if (nProcs == 0 && Foam::isDir(dir/processorsBaseDir))
1366  {
1368  << "Defunct collated naming: " << processorsBaseDir << nl
1369  << "Manually rename with the decomposition number. Eg,"
1370  << nl << nl
1371  << " mv processors processors16" << nl << nl
1372  << "...returning 1" << endl;
1373 
1374  nProcs = 1;
1375  }
1376  }
1377  Pstream::broadcast(nProcs, comm_);
1378  return nProcs;
1379 }
1381 
1382 void Foam::fileOperation::flush() const
1383 {
1384  if (debug)
1385  {
1386  Pout<< "fileOperation::flush : clearing processor directories cache"
1387  << endl;
1388  }
1389  procsDirs_.clear();
1390 }
1392 
1394 {
1395  if (debug)
1396  {
1397  Pout<< "fileOperation::sync : parallel synchronisation"
1398  << endl;
1399  }
1400 
1402  (
1404  nProcs_,
1405  procsDirs_
1406  );
1407 }
1408 
1411 (
1412  const IOobject& io,
1413  const word& procsDir
1414 ) const
1415 {
1416  return io.rootPath()/io.time().globalCaseName()/procsDir;
1417 }
1418 
1421 (
1422  const IOobject& io,
1423  const word& instance,
1424  const word& procsDir
1425 ) const
1426 {
1427  return
1428  processorsCasePath(io, procsDir)
1429  /instance
1430  /io.db().dbDir()
1431  /io.local();
1432 }
1433 
1436 (
1437  const fileName& dir,
1438  const word& procsDir
1439 ) const
1440 {
1441  // Check if directory is processorDDD
1442 
1443  const word caseName(dir.name());
1444  if (caseName.starts_with("processor"))
1445  {
1446  // Reject both '^processor$' and '^processors.*$'
1447 
1448  if (!std::isdigit(caseName[9]))
1449  {
1450  WarningInFunction << "Directory " << dir
1451  << " does not end in old-style processorDDD" << endl;
1452  }
1453 
1454  return dir.path()/procsDir;
1455  }
1456 
1457  return fileName();
1458 }
1459 
1462 (
1463  const fileName& objPath,
1464  fileName& path,
1465  fileName& procDir,
1466  fileName& local,
1467 
1469  label& nProcs
1470 )
1471 {
1472  // Return value
1473  label returnProci = -1;
1474 
1475  // Clear out the return parameters
1476 
1477  path.clear();
1478  procDir.clear();
1479  local.clear();
1480  group.clear();
1481 
1482  // Invalidate detected number of processors
1483  nProcs = -1;
1484 
1485  // The local processor group is read as first/last, but stored as
1486  // start/size. Empty with start=0, size=0 if no range is detected
1487 
1488 
1489  // Start of 'processor..' directory name (the procDir)
1490  size_t pos = 0;
1491 
1492  // The slash starting the trailing (local) directory
1493  size_t slashLocal = string::npos;
1494 
1495 
1496  // Search for processor at start of string or after /processor
1497  //
1498  // 'processor(\d+)'
1499  // 'processors(\d+)'
1500  // 'processors(\d+)_(\d+)-(\d+)'
1501 
1502  for
1503  (
1504  /*nil*/;
1505  (pos = objPath.find("processor", pos)) != string::npos;
1506  pos += 9
1507  )
1508  {
1509  if (pos > 0 && objPath[pos-1] != '/')
1510  {
1511  // Not start of string or after /processor
1512  continue;
1513  }
1514 
1515  // The parse point. One past 'processor'
1516  size_t firstp = pos + 9;
1517 
1518  // normal: 'processor(\d+)'
1519  // plural: 'processors(\d+)'
1520 
1521  const bool plural = (objPath[firstp] == 's');
1522 
1523  if (plural)
1524  {
1525  ++firstp; // Skip over the 's'
1526  }
1527  else if (!std::isdigit(objPath[firstp]))
1528  {
1529  // Non-plural version (uncollated) requires digits only
1530  continue;
1531  }
1532 
1533  // The next slash indicates there is a local directory
1534  slashLocal = objPath.find('/', firstp);
1535 
1536  // The last parse point is the slash, or end of string
1537  const size_t lastp =
1538  (slashLocal == string::npos ? objPath.length() : slashLocal);
1539 
1540  if (!std::isdigit(objPath[lastp-1]))
1541  {
1542  // Must end in a digit!
1543  // This traps entries that are too short or look quite wrong
1544  // and avoid a string to int conversion that will fail anyhow
1545  continue;
1546  }
1547 
1548 
1549  // Match: '^processors(\d+)$' -> nProcs
1550 
1551  // Match: '^processors(\d+)_(\d+)-(\d+)$'
1552  // \1 = nProcs
1553  // \2 = beg processor group
1554  // \3 = end processor group (inclusive)
1555 
1556  if (plural)
1557  {
1558  int nProcsRead = 0;
1559 
1560  if
1561  (
1562  parseProcsNumRange
1563  (
1564  objPath.substr(firstp, lastp-firstp),
1565  nProcsRead,
1566  group
1567  )
1568  )
1569  {
1570  // Total number of processors
1571  nProcs = nProcsRead;
1572 
1573  // We are done!
1574  break;
1575  }
1576  }
1577 
1578  // Single
1579  // Match: '^processor(\d+)$' -> proci
1580 
1581  label proci = 0;
1582  if
1583  (
1584  Foam::read(objPath.substr(firstp, lastp-firstp), proci)
1585  && (proci >= 0)
1586  )
1587  {
1588  // Capture value of an individual processor
1589  returnProci = proci;
1590 
1591  // We are done!
1592  break;
1593  }
1594  }
1595 
1596  if (pos != string::npos)
1597  {
1598  // The split succeeded, extract the components.
1599 
1600  // The leading directory
1601  if (pos > 0)
1602  {
1603  path = objPath.substr(0, pos-1);
1604  }
1605 
1606  // The slash starting the trailing (local) directory
1607  if (slashLocal != string::npos)
1608  {
1609  procDir = objPath.substr(pos, slashLocal-pos);
1610  local = objPath.substr(slashLocal+1);
1611  }
1612  else
1613  {
1614  procDir = objPath.substr(pos);
1615  }
1616  }
1617 
1618  return returnProci;
1619 }
1621 
1622 Foam::label Foam::fileOperation::detectProcessorPath(const fileName& fName)
1623 {
1624  fileName path, pDir, local;
1626  label nProcs;
1627  return splitProcessorPath(fName, path, pDir, local, group, nProcs);
1628 }
1629 
1630 
1631 // * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * //
1633 Foam::Ostream& Foam::operator<<
1634 (
1635  Ostream& os,
1636  const InfoProxy<fileOperation>& iproxy
1637 )
1638 {
1639  const auto& fp = *iproxy;
1640 
1641  os << "fileHandler:" << fp.type()
1642  << " nProcs:" << fp.nProcs()
1643  << " comm:" << fp.comm()
1644  << " distributed:" << fp.distributed()
1645  << " ioranks: " << flatOutput(fp.ioRanks())
1646  << " ranks: ";
1647 
1648  if (fp.comm() >= 0)
1649  {
1650  os << flatOutput(UPstream::procID(fp.comm()));
1651  }
1652  os << nl;
1653 
1654  return os;
1655 }
1656 
1657 // ************************************************************************* //
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:504
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
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:160
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:598
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:666
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:1049
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:409
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:1065
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:316
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 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: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 fileName & globalCaseName() const noexcept
Return global case name.
Definition: TimePathsI.H:72
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
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:391
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:197
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:343
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:472
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:43
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:1130
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:1082
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:66
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:435
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:172
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:60
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