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