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  "Additional verbosity"
241  );
242 
243  // Arguments are optional (non-mandatory)
245  argList::addArgument("fieldName ... fieldName");
246 
247  timeSelector::addOptions(true, true); // constant(true), zero(true)
248 
249  #include "addAllRegionOptions.H"
250  #include "setRootCase.H"
251 
252  wordList regionNames0;
253  {
254  // Dummy time just for the database to read regionProperties
255 
256  autoPtr<Time> dummyTimePtr(Time::New(args));
257 
258  const auto& runTime = *dummyTimePtr;
259 
260  // Handle -allRegions, -regions, -region
261  #include "getAllRegionOptions.H"
262 
263  regionNames0 = std::move(regionNames);
264  }
265 
266  dryrun = args.dryRun();
267  verbose = args.verbose();
268 
269 
270  // Construct time
271  // ~~~~~~~~~~~~~~
272 
273  restoreMethod method = restoreMethod::ORIG;
274  {
275  word methodName;
276 
277  if
278  (
279  args.readIfPresent("method", methodName)
280  && methodNames.found(methodName)
281  )
282  {
283  method = methodNames[methodName];
284  }
285  else
286  {
287  Info<< "Unspecified or unknown method name" << nl
288  << "Valid methods: "
289  << flatOutput(methodNames.sortedToc()) << nl
290  << "... stopping" << nl << nl;
291  return 1;
292  }
293  }
294 
295  // Optional base or target field names (eg, 'U', 'T' etc)
296  wordList targetNames;
297  if (args.size() > 1)
298  {
299  targetNames.resize(args.size()-1);
300  wordHashSet uniq;
301 
302  for (label argi=1; argi < args.size(); ++argi)
303  {
304  if (uniq.insert(args[argi]))
305  {
306  targetNames[uniq.size()-1] = args[argi];
307  }
308  }
309 
310  targetNames.resize(uniq.size());
311 
312  if (verbose)
313  {
314  Info<< nl
315  << "using method=" << methodNames[method] << nl
316  << "with fields " << flatOutput(targetNames) << nl;
317  }
318  }
319  else if (verbose)
320  {
321  Info<< nl
322  << "using method=" << methodNames[method] << nl
323  << "autodetect fields" << nl;
324  }
325 
326 
327  // Get times list from the master processor and subset based on
328  // command-line options
329 
330  label nProcs = 0;
331  autoPtr<TimePaths> timePaths;
332 
333  if (args.found("processor") && !Pstream::parRun())
334  {
335  // Determine the processor count
336  nProcs = fileHandler().nProcs(args.path());
337 
338  if (!nProcs)
339  {
341  << "No processor* directories found"
342  << exit(FatalError);
343  }
344 
345  // Obtain time directory names from "processor0/" only
346  timePaths = autoPtr<TimePaths>::New
347  (
348  args.rootPath(),
349  args.caseName()/"processor0"
350  );
351  }
352  else
353  {
354  timePaths = autoPtr<TimePaths>::New
355  (
356  args.rootPath(),
357  args.caseName()
358  );
359  }
360 
361  const instantList timeDirs(timeSelector::select(timePaths->times(), args));
362 
363  fileNameList procDirs;
364  label leadProcIdx = -1;
365 
366  if (timeDirs.empty())
367  {
368  Info<< "No times selected" << nl;
369  }
370  else if (nProcs)
371  {
372  procDirs =
374  (
375  args.path(),
377  false, // No gzip anyhow
378  false // Do not follow linkts
379  );
380 
381  inplaceSubsetList(procDirs, isProcessorDir);
382 
383  // Perhaps not needed
384  Foam::sort(procDirs, stringOps::natural_sort());
385 
386  // Decide who will be the "leading" processor for obtaining names
387  // - processor0
388  // - processors<N>
389  // - processors<N>_0-<high>
390 
391  // Uncollated
392  leadProcIdx = procDirs.find("processor0");
393 
394  if (!procDirs.empty())
395  {
396  if (leadProcIdx < 0)
397  {
398  // Collated
399  leadProcIdx = procDirs.find("processors" + Foam::name(nProcs));
400  }
401 
402  if (leadProcIdx < 0)
403  {
404  // Host-collated
405  const std::string prefix
406  (
407  "processors" + Foam::name(nProcs) + "_0-"
408  );
409 
410  forAll(procDirs, idx)
411  {
412  if (procDirs[idx].starts_with(prefix))
413  {
414  leadProcIdx = idx;
415  break;
416  }
417  }
418  }
419 
420  // Just default to anything (safety)
421  if (leadProcIdx < 0)
422  {
423  leadProcIdx = 0;
424  }
425  }
426  }
427 
428 
429  for (const instant& t : timeDirs)
430  {
431  const word& timeName = t.name();
432 
433  Info<< "\nTime = " << timeName << nl;
434 
435  for (const word& regionName : regionNames0)
436  {
438 
439  if (regionNames0.size() > 1)
440  {
441  Info<< "region = " << regionName << nl;
442  }
443 
444  label count = 0;
445  wordList files;
446 
447  if (nProcs)
448  {
449  if (leadProcIdx >= 0)
450  {
451  files =
452  getFiles
453  (
454  args.path()/procDirs[leadProcIdx],
456  );
457  }
458 
459  for (const fileName& procDir : procDirs)
460  {
461  count += restoreFields
462  (
463  method,
464  args.path()/procDir/timeName/regionDir,
465  wordHashSet(files),
466  targetNames
467  );
468  }
469  }
470  else
471  {
472  if (Pstream::master())
473  {
474  files = getFiles(args.path(), timeName/regionDir);
475  }
476  Pstream::broadcast(files);
477 
478  count += restoreFields
479  (
480  method,
482  wordHashSet(files),
483  targetNames
484  );
485  }
486 
487  if (dryrun)
488  {
489  Info<< "dry-run: ";
490  }
491  Info<< "moved " << count << " files" << nl;
492  }
493  }
494  Info<< "\nEnd\n" << endl;
495  return 0;
496 }
497 
498 
499 // ************************************************************************* //
static void noJobInfo()
Suppress JobInfo, overriding controlDict setting.
Definition: argList.C:534
static void noFunctionObjects(bool addWithOption=false)
Remove &#39;-noFunctionObjects&#39; option and ignore any occurrences.
Definition: argList.C:514
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:453
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
bool mv(const fileName &src, const fileName &dst, const bool followLink=false)
Rename src to dst.
Definition: POSIX.C:1277
A class for handling file names.
Definition: fileName.H:71
static void noMandatoryArgs()
Flag command arguments as being optional (non-mandatory)
Definition: argList.C:470
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:132
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
label find(const T &val, label pos=0) const
Find index of the first occurrence of the value.
Definition: UList.C:204
const word & regionName() const
The mesh region name or word::null if polyMesh::defaultRegion.
Definition: polyMesh.C:841
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:420
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:639
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:697
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:365
autoPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler.
label size() const noexcept
The number of elements in table.
Definition: HashTableI.H:45
wordList regionNames
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:227
instantList select(const instantList &times) const
Select a list of Time values that are within the ranges.
Definition: timeSelector.C:88
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 processes in communicator.
Extract name (as a word) from an object, typically using its name() method.
Definition: word.H:340
static void disable()
Disallow profiling by forcing the InfoSwitch off.
Definition: profiling.C:110
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
word timeName
Definition: getTimeIndex.H:3
Foam::word regionName(Foam::polyMesh::defaultRegion)
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 INVALID.
Definition: exprTraits.C:52
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:495
int dryRun() const noexcept
Return the dry-run flag.
Definition: argListI.H:109
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:334
A regular file.
Definition: fileName.H:83
static void addVerboseOption(const string &usage, bool advanced=false)
Enable a &#39;verbose&#39; bool option, with usage information.
Definition: argList.C:505
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:376
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
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:414
instantList times() const
Search the case for valid time directories.
Definition: TimePaths.C:142
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
const word & regionDir
static bool master(const label communicator=worldComm)
Am I the master rank.
Definition: UPstream.H:672
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:342
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:916
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