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-2020 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 
69 using namespace Foam;
70 
71 // Many ways to name processor directories
72 //
73 // Uncollated | "processor0", "processor1" ...
74 // Collated (old) | "processors"
75 // Collated (new) | "processors<N>"
76 // Host collated | "processors<N>_<low>-<high>"
77 
78 const regExp matcher("processors?[0-9]+(_[0-9]+-[0-9]+)?");
79 
80 bool isProcessorDir(const string& dir)
81 {
82  return
83  (
84  dir.starts_with("processor")
85  && (dir == "processors" || matcher.match(dir))
86  );
87 }
88 
89 
90 //- The known and support types of operations
91 enum restoreMethod
92 {
93  MEAN,
94  ORIG
95 };
96 
97 
98 static const Enum<restoreMethod> methodNames
99 {
100  { restoreMethod::MEAN, "mean" },
101  { restoreMethod::ORIG, "orig" },
102 };
103 
104 
105 static const Enum<restoreMethod> methodEndings
106 {
107  { restoreMethod::MEAN, "Mean" },
108  { restoreMethod::ORIG, ".orig" },
109 };
110 
111 
112 // Files in given directory at time instant
113 inline wordList getFiles(const fileName& dir, const word& instance)
114 {
115  return ListOps::create<word>
116  (
117  Foam::readDir(dir/instance, fileName::FILE),
119  );
120 }
121 
122 
123 // Command-line options: -dry-run, -verbose
124 bool dryrun = false, verbose = false;
125 
126 
127 // Use predefined method to walk the directory and rename the files.
128 //
129 // If no target names are specified, the existing files are scanned for
130 // candidates.
131 label restoreFields
132 (
133  const restoreMethod method,
134  const fileName& dirName,
135  const wordHashSet& existingFiles,
136  const wordList& targetNames
137 )
138 {
139  // The file ending to search for.
140  const word ending(methodEndings[method]);
141 
142  // The backup ending for existing (if any)
143  word bak;
144 
145  switch (method)
146  {
147  case restoreMethod::MEAN:
148  bak = methodEndings[restoreMethod::ORIG];
149  break;
150 
151  default:
152  break;
153  }
154 
155  wordHashSet targets(targetNames);
156 
157  if (targets.empty())
158  {
159  // No target names specified - scan existing files for candidates.
160 
161  for (word f : existingFiles) // Operate on a copy
162  {
163  // Eg, check for "UMean" and save as "U"
164  if (f.removeEnd(ending) && f.size())
165  {
166  targets.insert(f);
167  }
168  }
169  }
170 
171  if (verbose)
172  {
173  Info<< "directory " << dirName.name() << nl;
174  }
175 
176  // Count of files moved, including backups
177  label count = 0;
178 
179  for (const word& dst : targets)
180  {
181  const word src(dst + ending);
182 
183  if (!existingFiles.found(src))
184  {
185  continue;
186  }
187 
188  if (bak.size() && existingFiles.found(dst))
189  {
190  if (dryrun || Foam::mv(dirName/dst, dirName/dst + bak))
191  {
192  Info<< " mv " << dst << " " << word(dst + bak) << nl;
193  ++count;
194  }
195  }
196 
197  if (dryrun || Foam::mv(dirName/src, dirName/dst))
198  {
199  Info<< " mv " << src << " " << dst << nl;
200  ++count;
201  }
202  }
203 
204  return count;
205 }
206 
207 
208 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
209 
210 int main(int argc, char *argv[])
211 {
213  (
214  "Restore field names by removing the ending. Fields are selected"
215  " automatically or can be specified as optional command arguments"
216  );
217 
218  profiling::disable(); // Disable profiling (and its output)
220  argList::noFunctionObjects(); // Never use function objects
222  (
223  "method",
224  "name",
225  "The restore method (mean|orig) [MANDATORY]. "
226  "With <mean> renames files ending with 'Mean' "
227  "(with backup of existing as '.orig'). "
228  "With <orig> renames files ending with '.orig'"
229  );
231  (
232  "processor",
233  "In serial mode use times from processor0/ directory, but operate on "
234  "processor\\d+ directories"
235  );
237  (
238  "dry-run",
239  "Report action without moving/renaming"
240  );
242  (
243  "verbose",
244  "Additional verbosity"
245  );
246 
247  // Arguments are optional (non-mandatory)
249  argList::addArgument("fieldName ... fieldName");
250 
251  timeSelector::addOptions(true, true); // constant(true), zero(true)
252 
253  #include "setRootCase.H"
254 
255  dryrun = args.found("dry-run");
256  verbose = args.found("verbose");
257 
258 
259  // Construct time
260  // ~~~~~~~~~~~~~~
261 
262  restoreMethod method = restoreMethod::ORIG;
263  {
264  word methodName;
265 
266  if
267  (
268  args.readIfPresent("method", methodName)
269  && methodNames.found(methodName)
270  )
271  {
272  method = methodNames[methodName];
273  }
274  else
275  {
276  Info<< "Unspecified or unknown method name" << nl
277  << "Valid methods: "
278  << flatOutput(methodNames.sortedToc()) << nl
279  << "... stopping" << nl << nl;
280  return 1;
281  }
282  }
283 
284  // Optional base or target field names (eg, 'U', 'T' etc)
285  wordList targetNames;
286  if (args.size() > 1)
287  {
288  targetNames.resize(args.size()-1);
289  wordHashSet uniq;
290 
291  for (label argi=1; argi < args.size(); ++argi)
292  {
293  if (uniq.insert(args[argi]))
294  {
295  targetNames[uniq.size()-1] = args[argi];
296  }
297  }
298 
299  targetNames.resize(uniq.size());
300 
301  if (verbose)
302  {
303  Info<< nl
304  << "using method=" << methodNames[method] << nl
305  << "with fields " << flatOutput(targetNames) << nl;
306  }
307  }
308  else if (verbose)
309  {
310  Info<< nl
311  << "using method=" << methodNames[method] << nl
312  << "autodetect fields" << nl;
313  }
314 
315 
316  // Get times list from the master processor and subset based on
317  // command-line options
318 
319  label nProcs = 0;
320  autoPtr<TimePaths> timePaths;
321 
322  if (args.found("processor") && !Pstream::parRun())
323  {
324  // Determine the processor count
325  nProcs = fileHandler().nProcs(args.path());
326 
327  if (!nProcs)
328  {
330  << "No processor* directories found"
331  << exit(FatalError);
332  }
333 
334  // Obtain time directory names from "processor0/" only
335  timePaths = autoPtr<TimePaths>::New
336  (
337  args.rootPath(),
338  args.caseName()/"processor0"
339  );
340  }
341  else
342  {
343  timePaths = autoPtr<TimePaths>::New
344  (
345  args.rootPath(),
346  args.caseName()
347  );
348  }
349 
350  const instantList timeDirs(timeSelector::select(timePaths->times(), args));
351 
352  fileNameList procDirs;
353  label leadProcIdx = -1;
354 
355  if (timeDirs.empty())
356  {
357  Info<< "No times selected" << nl;
358  }
359  else if (nProcs)
360  {
361  procDirs =
363  (
364  args.path(),
366  false, // No gzip anyhow
367  false // Do not follow linkts
368  );
369 
370  inplaceSubsetList(procDirs, isProcessorDir);
371 
372  // Perhaps not needed
373  Foam::sort(procDirs, stringOps::natural_sort());
374 
375  // Decide who will be the "leading" processor for obtaining names
376  // - processor0
377  // - processors<N>
378  // - processors<N>_0-<high>
379 
380  // Uncollated
381  leadProcIdx = procDirs.find("processor0");
382 
383  if (!procDirs.empty())
384  {
385  if (leadProcIdx < 0)
386  {
387  // Collated (old)
388  leadProcIdx = procDirs.find("processors");
389  }
390 
391  if (leadProcIdx < 0)
392  {
393  // Collated (new)
394  leadProcIdx = procDirs.find("processors" + Foam::name(nProcs));
395  }
396 
397  if (leadProcIdx < 0)
398  {
399  // Host-collated
400  const std::string prefix
401  (
402  "processors" + Foam::name(nProcs) + "_0-"
403  );
404 
405  forAll(procDirs, idx)
406  {
407  if (procDirs[idx].starts_with(prefix))
408  {
409  leadProcIdx = idx;
410  break;
411  }
412  }
413  }
414 
415  // Just default to anything (safety)
416  if (leadProcIdx < 0)
417  {
418  leadProcIdx = 0;
419  }
420  }
421  }
422 
423 
424  for (const instant& t : timeDirs)
425  {
426  const word& timeName = t.name();
427 
428  Info<< "\nTime = " << timeName << nl;
429 
430  label count = 0;
431  wordList files;
432 
433  if (nProcs)
434  {
435  if (leadProcIdx >= 0)
436  {
437  files = getFiles(args.path()/procDirs[leadProcIdx], timeName);
438  }
439 
440  for (const fileName& procDir : procDirs)
441  {
442  count += restoreFields
443  (
444  method,
445  args.path()/procDir/timeName,
446  wordHashSet(files),
447  targetNames
448  );
449  }
450  }
451  else
452  {
453  if (Pstream::master())
454  {
455  files = getFiles(args.path(), timeName);
456  }
457  Pstream::scatter(files);
458 
459  count += restoreFields
460  (
461  method,
462  args.path()/timeName,
463  wordHashSet(files),
464  targetNames
465  );
466  }
467 
468  if (dryrun)
469  {
470  Info<< "dry-run: ";
471  }
472  Info<< "moved " << count << " files" << nl;
473  }
474 
475  Info<< "\nEnd\n" << endl;
476  return 0;
477 }
478 
479 
480 // ************************************************************************* //
Foam::autoPtr::New
static autoPtr< T > New(Args &&... args)
Construct autoPtr of T with forwarding arguments.
profiling.H
Foam::HashTable::size
label size() const noexcept
The number of elements in table.
Definition: HashTableI.H:52
Foam::Enum
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: IOstreamOption.H:57
Foam::fileName::FILE
A file.
Definition: fileName.H:79
Foam::inplaceSubsetList
void inplaceSubsetList(ListType &input, const UnaryPredicate &pred, const bool invert=false)
Inplace subset of the list when predicate is true.
Definition: ListOpsTemplates.C:701
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
TimePaths.H
Foam::string::starts_with
bool starts_with(const std::string &s) const
True if string starts with the given prefix (cf. C++20)
Definition: string.H:299
Foam::fileName::name
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:209
Foam::UPstream::parRun
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:415
Foam::argList::addNote
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:413
Foam::timeSelector::select
instantList select(const instantList &times) const
Select a list of Time values that are within the ranges.
Definition: timeSelector.C:95
Foam::Pstream::scatter
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
Definition: gatherScatter.C:150
Foam::fileHandler
const fileOperation & fileHandler()
Get current file handler.
Definition: fileOperation.C:1170
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::HashSet< word >
Foam::argList::readIfPresent
bool readIfPresent(const word &optName, T &val) const
Read a value from the named option if present.
Definition: argListI.H:302
Foam::argList::noMandatoryArgs
static void noMandatoryArgs()
Flag command arguments as being optional (non-mandatory)
Definition: argList.C:430
Foam::argList::rootPath
const fileName & rootPath() const
Return root path.
Definition: argListI.H:63
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::argList::addArgument
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:302
Foam::argList::noFunctionObjects
static void noFunctionObjects(bool addWithOption=false)
Remove '-noFunctionObjects' option and ignore any occurrences.
Definition: argList.C:454
Foam::string::match
bool match(const std::string &text) const
Test for equality.
Definition: stringI.H:260
Foam::argList::noJobInfo
static void noJobInfo()
Suppress JobInfo, overriding controlDict setting.
Definition: argList.C:474
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::fileOperation::nProcs
virtual label nProcs(const fileName &dir, const fileName &local="") const
Get number of processor directories/results. Used for e.g.
Definition: fileOperation.C:915
argList.H
Foam::sort
void sort(UList< T > &a)
Definition: UList.C:254
Foam::TimePaths::times
instantList times() const
Search the case for valid time directories.
Definition: TimePaths.C:149
Foam::nameOp
Extract name (as a word) from an object, typically using its name() method.
Definition: word.H:238
Foam::regExpCxx
Wrapper around C++11 regular expressions.
Definition: regExpCxx.H:72
Foam::List::resize
void resize(const label newSize)
Adjust allocated size of list.
Definition: ListI.H:139
timeName
word timeName
Definition: getTimeIndex.H:3
Foam::argList::path
fileName path() const
Return the full path to the (processor local) case.
Definition: argListI.H:81
Foam::FatalError
error FatalError
Foam::mv
bool mv(const fileName &src, const fileName &dst, const bool followLink=false)
Rename src to dst.
Definition: MSwindows.C:929
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::profiling::disable
static void disable()
Disallow profiling by forcing the InfoSwitch off.
Definition: profiling.C:118
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::UPstream::master
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:439
Foam::argList::addBoolOption
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:325
Foam::autoPtr
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: HashPtrTable.H:53
setRootCase.H
Foam::argList::size
label size() const noexcept
The number of arguments.
Definition: argListI.H:127
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:372
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::flatOutput
FlatOutput< Container > flatOutput(const Container &obj, label len=0)
Global flatOutput function.
Definition: FlatOutput.H:85
f
labelList f(nPoints)
Foam::BitOps::count
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:74
Foam::timeSelector::addOptions
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
Definition: timeSelector.C:108
Foam::List< word >
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:181
Foam::fileName::DIRECTORY
A directory.
Definition: fileName.H:80
timeSelector.H
Foam::stringOps::natural_sort
Encapsulation of natural order sorting for algorithms.
Definition: stringOpsSort.H:62
Foam::wordHashSet
HashSet< word > wordHashSet
A HashSet with word keys.
Definition: HashSet.H:407
Foam::argList::caseName
const fileName & caseName() const
Return case name (parallel run) or global case (serial run)
Definition: argListI.H:69
ListOps.H
Various functions to operate on Lists.
Foam::instant
An instant of time. Contains the time value and name.
Definition: instant.H:52
Foam::argList::addOption
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:336
args
Foam::argList args(argc, argv)
stringOps.H
Foam::readDir
fileNameList readDir(const fileName &directory, const fileName::Type type=fileName::FILE, const bool filtergz=true, const bool followLink=true)
Read a directory and return the entries as a fileName List.
Definition: MSwindows.C:707
Foam::argList::found
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:157
autoPtr.H
Enum.H