foamRestoreFields.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) 2018-2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 Application
27  foamRestoreFields
28 
29 Group
30  grpMiscUtilities
31 
32 Description
33  Adjust (restore) field names by removing the ending.
34  The fields are selected automatically or can be specified as optional
35  command arguments.
36 
37  The operation 'mean' renames files ending with 'Mean' and makes
38  a backup of existing names, using the '.orig' ending.
39 
40  The operation 'orig' renames files ending with '.orig'.
41 
42 Usage
43  \b foamRestoreFields [OPTION]
44 
45  Options:
46  - \par -method mean | orig
47  The renaming method.
48 
49  - \par -processor
50  Use processor directories, taking information from processor0/
51 
52  - \par -dry-run
53  Test without actually moving/renaming files.
54 
55  - \par -verbose
56  Additional verbosity.
57 
58 \*---------------------------------------------------------------------------*/
59 
60 #include "argList.H"
61 #include "autoPtr.H"
62 #include "profiling.H"
63 #include "timeSelector.H"
64 #include "Enum.H"
65 #include "TimePaths.H"
66 #include "ListOps.H"
67 #include "stringOps.H"
68 #include "regionProperties.H"
69 #include "polyMesh.H"
70 #include "Time.H"
71 
72 using namespace Foam;
73 
74 // Many ways to name processor directories
75 //
76 // Uncollated | "processor0", "processor1" ...
77 // Collated | "processors<N>"
78 // Host collated | "processors<N>_<low>-<high>"
79 
80 const regExp matcher("processors?[0-9]+(_[0-9]+-[0-9]+)?");
81 
82 bool isProcessorDir(const string& dir)
83 {
84  return (dir.starts_with("processor") && matcher.match(dir));
85 }
86 
87 
88 //- The known and support types of operations
89 enum restoreMethod
90 {
91  MEAN,
92  ORIG
93 };
94 
95 
96 static const Enum<restoreMethod> methodNames
97 {
98  { restoreMethod::MEAN, "mean" },
99  { restoreMethod::ORIG, "orig" },
100 };
101 
102 
103 static const Enum<restoreMethod> methodEndings
104 {
105  { restoreMethod::MEAN, "Mean" },
106  { restoreMethod::ORIG, ".orig" },
107 };
108 
109 
110 // Files in given directory at time instant
111 inline wordList getFiles(const fileName& dir, const word& instance)
112 {
113  return ListOps::create<word>
114  (
115  Foam::readDir(dir/instance, fileName::FILE),
117  );
118 }
119 
120 
121 // Command-line options: -dry-run, -verbose
122 bool dryrun = false, verbose = false;
123 
124 
125 // Use predefined method to walk the directory and rename the files.
126 //
127 // If no target names are specified, the existing files are scanned for
128 // candidates.
129 label restoreFields
130 (
131  const restoreMethod method,
132  const fileName& dirName,
133  const wordHashSet& existingFiles,
134  const wordList& targetNames
135 )
136 {
137  // The file ending to search for.
138  const word ending(methodEndings[method]);
139 
140  // The backup ending for existing (if any)
141  word bak;
142 
143  switch (method)
144  {
145  case restoreMethod::MEAN:
146  bak = methodEndings[restoreMethod::ORIG];
147  break;
148 
149  default:
150  break;
151  }
152 
153  wordHashSet targets(targetNames);
154 
155  if (targets.empty())
156  {
157  // No target names specified - scan existing files for candidates.
158 
159  for (word f : existingFiles) // Operate on a copy
160  {
161  // Eg, check for "UMean" and save as "U"
162  if (f.removeEnd(ending) && f.size())
163  {
164  targets.insert(f);
165  }
166  }
167  }
168 
169  if (verbose)
170  {
171  Info<< "directory " << dirName.name() << nl;
172  }
173 
174  // Count of files moved, including backups
175  label count = 0;
176 
177  for (const word& dst : targets)
178  {
179  const word src(dst + ending);
180 
181  if (!existingFiles.found(src))
182  {
183  continue;
184  }
185 
186  if (bak.size() && existingFiles.found(dst))
187  {
188  if (dryrun || Foam::mv(dirName/dst, dirName/dst + bak))
189  {
190  Info<< " mv " << dst << " " << word(dst + bak) << nl;
191  ++count;
192  }
193  }
194 
195  if (dryrun || Foam::mv(dirName/src, dirName/dst))
196  {
197  Info<< " mv " << src << " " << dst << nl;
198  ++count;
199  }
200  }
201 
202  return count;
203 }
204 
205 
206 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
207 
208 int main(int argc, char *argv[])
209 {
211  (
212  "Restore field names by removing the ending. Fields are selected"
213  " automatically or can be specified as optional command arguments"
214  );
215 
216  profiling::disable(); // Disable profiling (and its output)
218  argList::noFunctionObjects(); // Never use function objects
220  (
221  "method",
222  "name",
223  "The restore method (mean|orig) [MANDATORY]. "
224  "With <mean> renames files ending with 'Mean' "
225  "(with backup of existing as '.orig'). "
226  "With <orig> renames files ending with '.orig'"
227  );
229  (
230  "processor",
231  "In serial mode use times from processor0/ directory, but operate on "
232  "processor\\d+ directories"
233  );
235  (
236  "Report action without moving/renaming"
237  );
239 
240  // Arguments are optional (non-mandatory)
242  argList::addArgument("fieldName ... fieldName");
243 
244  timeSelector::addOptions(true, true); // constant(true), zero(true)
245 
246  #include "addAllRegionOptions.H"
247  #include "setRootCase.H"
248 
249  wordList regionNames0;
250  {
251  // Dummy time just for the database to read regionProperties
252 
253  autoPtr<Time> dummyTimePtr(Time::New(args));
254 
255  const auto& runTime = *dummyTimePtr;
256 
257  // Handle -allRegions, -regions, -region
258  #include "getAllRegionOptions.H"
259 
260  regionNames0 = std::move(regionNames);
261  }
262 
263  dryrun = args.dryRun();
264  verbose = args.verbose();
265 
266 
267  // Construct time
268  // ~~~~~~~~~~~~~~
269 
270  restoreMethod method = restoreMethod::ORIG;
271  {
272  word methodName;
273 
274  if
275  (
276  args.readIfPresent("method", methodName)
277  && methodNames.found(methodName)
278  )
279  {
280  method = methodNames[methodName];
281  }
282  else
283  {
284  Info<< "Unspecified or unknown method name" << nl
285  << "Valid methods: "
286  << flatOutput(methodNames.sortedToc()) << nl
287  << "... stopping" << nl << nl;
288  return 1;
289  }
290  }
291 
292  // Optional base or target field names (eg, 'U', 'T' etc)
293  wordList targetNames;
294  if (args.size() > 1)
295  {
296  targetNames.resize(args.size()-1);
297  wordHashSet uniq;
298 
299  for (label argi=1; argi < args.size(); ++argi)
300  {
301  if (uniq.insert(args[argi]))
302  {
303  targetNames[uniq.size()-1] = args[argi];
304  }
305  }
306 
307  targetNames.resize(uniq.size());
308 
309  if (verbose)
310  {
311  Info<< nl
312  << "using method=" << methodNames[method] << nl
313  << "with fields " << flatOutput(targetNames) << nl;
314  }
315  }
316  else if (verbose)
317  {
318  Info<< nl
319  << "using method=" << methodNames[method] << nl
320  << "autodetect fields" << nl;
321  }
322 
323 
324  // Get times list from the master processor and subset based on
325  // command-line options
326 
327  label nProcs = 0;
328  autoPtr<TimePaths> timePaths;
329 
330  if (args.found("processor") && !Pstream::parRun())
331  {
332  // Determine the processor count
333  nProcs = fileHandler().nProcs(args.path());
334 
335  if (!nProcs)
336  {
338  << "No processor* directories found"
339  << exit(FatalError);
340  }
341 
342  // Obtain time directory names from "processor0/" only
343  timePaths = autoPtr<TimePaths>::New
344  (
345  args.rootPath(),
346  args.caseName()/"processor0"
347  );
348  }
349  else
350  {
351  timePaths = autoPtr<TimePaths>::New
352  (
353  args.rootPath(),
354  args.caseName()
355  );
356  }
357 
358  const instantList timeDirs(timeSelector::select(timePaths->times(), args));
359 
360  fileNameList procDirs;
361  label leadProcIdx = -1;
362 
363  if (timeDirs.empty())
364  {
365  Info<< "No times selected" << nl;
366  }
367  else if (nProcs)
368  {
369  procDirs =
371  (
372  args.path(),
374  false, // No gzip anyhow
375  false // Do not follow linkts
376  );
377 
378  inplaceSubsetList(procDirs, isProcessorDir);
379 
380  // Perhaps not needed
381  Foam::sort(procDirs, stringOps::natural_sort());
382 
383  // Decide who will be the "leading" processor for obtaining names
384  // - processor0
385  // - processors<N>
386  // - processors<N>_0-<high>
387 
388  // Uncollated
389  leadProcIdx = procDirs.find("processor0");
390 
391  if (!procDirs.empty())
392  {
393  if (leadProcIdx < 0)
394  {
395  // Collated
396  leadProcIdx = procDirs.find("processors" + Foam::name(nProcs));
397  }
398 
399  if (leadProcIdx < 0)
400  {
401  // Host-collated
402  const std::string prefix
403  (
404  "processors" + Foam::name(nProcs) + "_0-"
405  );
406 
407  forAll(procDirs, idx)
408  {
409  if (procDirs[idx].starts_with(prefix))
410  {
411  leadProcIdx = idx;
412  break;
413  }
414  }
415  }
416 
417  // Just default to anything (safety)
418  if (leadProcIdx < 0)
419  {
420  leadProcIdx = 0;
421  }
422  }
423  }
424 
425 
426  for (const instant& t : timeDirs)
427  {
428  const word& timeName = t.name();
429 
430  Info<< "\nTime = " << timeName << nl;
431 
432  for (const word& regionName : regionNames0)
433  {
435 
436  if (regionNames0.size() > 1)
437  {
438  Info<< "region = " << regionName << nl;
439  }
440 
441  label count = 0;
442  wordList files;
443 
444  if (nProcs)
445  {
446  if (leadProcIdx >= 0)
447  {
448  files =
449  getFiles
450  (
451  args.path()/procDirs[leadProcIdx],
453  );
454  }
455 
456  for (const fileName& procDir : procDirs)
457  {
458  count += restoreFields
459  (
460  method,
461  args.path()/procDir/timeName/regionDir,
462  wordHashSet(files),
463  targetNames
464  );
465  }
466  }
467  else
468  {
469  if (Pstream::master())
470  {
471  files = getFiles(args.path(), timeName/regionDir);
472  }
473  Pstream::broadcast(files);
474 
475  count += restoreFields
476  (
477  method,
479  wordHashSet(files),
480  targetNames
481  );
482  }
483 
484  if (dryrun)
485  {
486  Info<< "dry-run: ";
487  }
488  Info<< "moved " << count << " files" << nl;
489  }
490  }
491  Info<< "\nEnd\n" << endl;
492  return 0;
493 }
494 
495 
496 // ************************************************************************* //
static void noJobInfo()
Suppress JobInfo, overriding controlDict setting.
Definition: argList.C:567
static void noFunctionObjects(bool addWithOption=false)
Remove &#39;-noFunctionObjects&#39; option and ignore any occurrences.
Definition: argList.C:547
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:462
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
bool mv(const fileName &src, const fileName &dst, const bool followLink=false)
Rename src to dst.
Definition: POSIX.C:1324
A class for handling file names.
Definition: fileName.H:72
static void noMandatoryArgs()
Flag command arguments as being optional (non-mandatory)
Definition: argList.C:479
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
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
const word & regionName() const
The mesh region name or word::null if polyMesh::defaultRegion.
Definition: polyMesh.C:847
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
engineTime & runTime
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
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: TimeNew.C:26
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:374
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler()
wordList regionNames
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:232
instantList select(const instantList &times) const
Select a list of Time values that are within the ranges.
Definition: timeSelector.C:88
static void disable() noexcept
Disallow profiling - turns the InfoSwitch off.
Definition: profiling.C:113
void inplaceSubsetList(ListType &input, const UnaryPredicate &pred, const bool invert=false)
Inplace subset of the list when predicate is true.
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...
Extract name (as a word) from an object, typically using its name() method.
Definition: word.H:340
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:358
word timeName
Definition: getTimeIndex.H:3
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
A class for handling words, derived from Foam::string.
Definition: word.H:63
static void addDryRunOption(const string &usage, bool advanced=false)
Enable a &#39;dry-run&#39; bool option, with usage information.
Definition: argList.C:504
int dryRun() const noexcept
Return the dry-run flag.
Definition: argListI.H:109
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:296
A regular file.
Definition: fileName.H:84
label size() const noexcept
The number of arguments.
Definition: argListI.H:139
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition: argList.C:385
HashSet< word, Hash< word > > wordHashSet
A HashSet of words, uses string hasher.
Definition: HashSet.H:73
const fileName & caseName() const noexcept
Return case name (parallel run) or global case (serial run)
Definition: argListI.H:62
label find(const T &val) const
Find index of the first occurrence of the value.
Definition: UList.C:173
static void addVerboseOption(const string &usage="", bool advanced=false)
Enable a &#39;verbose&#39; bool option, with usage information.
Definition: argList.C:520
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:192
const fileName & rootPath() const noexcept
Return root path.
Definition: argListI.H:56
labelList f(nPoints)
Encapsulation of natural order sorting for algorithms.
Definition: stringOpsSort.H:63
fileName path() const
Return the full path to the (processor local) case.
Definition: argListI.H:74
An instant of time. Contains the time value and name. Uses Foam::Time when formatting the name...
Definition: instant.H:53
Wrapper around POSIX extended regular expressions with some additional prefix-handling. The prefix-handling is loosely oriented on PCRE regular expressions and provides a simple means of tuning the expressions.
Definition: regExpPosix.H:80
bool starts_with(char c) const
True if string starts with given character (cf. C++20)
Definition: string.H:435
instantList times() const
Search the case for valid time directories.
Definition: TimePaths.C:118
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: error.H:64
Foam::word regionName(args.getOrDefault< word >("region", Foam::polyMesh::defaultRegion))
const word & regionDir
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1094
Required Classes.
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:351
messageStream Info
Information stream (stdout output on master, null elsewhere)
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
bool readIfPresent(const word &optName, T &val) const
Read a value from the named option if present.
Definition: argListI.H:316
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
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
Foam::argList args(argc, argv)
int verbose() const noexcept
Return the verbose flag.
Definition: argListI.H:121
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:171
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
Definition: timeSelector.C:101
Namespace for OpenFOAM.
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225