- for some special cases we wish to mark command-line arguments as being optional, in order to do our own treatment. For example, when an arbitrary number of arguments should be allowed. Now tag this situation with argList::noMandatoryArgs(). The argList::argsMandatory() query can then be used in any further logic, including the standard default argument checking. - with the new default check, can consolidate the special-purpose "setRootCaseNonMandatoryArgs.H" into the regular "setRootCase.H" - revert to a simple "setRootCase.H" and move all the listing related bits to a "setRootCaseLists.H" file. This leaves the information available for solvers, or whoever else wishes, without being introduced everywhere. - add include guards and scoping to the listing files and rename to something less generic. listOptions.H -> setRootCaseListOptions.H listOutput.H -> setRootCaseListOutput.H
392 lines
9.4 KiB
C
392 lines
9.4 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration |
|
|
\\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
|
|
\\/ M anipulation |
|
|
-------------------------------------------------------------------------------
|
|
License
|
|
This file is part of OpenFOAM.
|
|
|
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Application
|
|
foamRestoreFields
|
|
|
|
Group
|
|
grpMiscUtilities
|
|
|
|
Description
|
|
Restore field names by removing the ending.
|
|
The fields are selected automatically or can be specified as optional
|
|
command arguments.
|
|
|
|
The operation 'mean' renames files ending with 'Mean' and makes
|
|
a backup of existing names, using the '.orig' ending.
|
|
|
|
The operation 'orig' renames files ending with '.orig'.
|
|
|
|
Usage
|
|
\b foamRestoreFields [OPTION]
|
|
|
|
Options:
|
|
- \par -method mean | orig
|
|
The renaming method.
|
|
|
|
- \par -processor
|
|
Use processor directories, taking information from processor0/
|
|
|
|
- \par -dry-run
|
|
Test without actually moving/renaming files.
|
|
|
|
- \par -verbose
|
|
Additional verbosity.
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#include "argList.H"
|
|
#include "autoPtr.H"
|
|
#include "profiling.H"
|
|
#include "timeSelector.H"
|
|
#include "Enum.H"
|
|
#include "TimePaths.H"
|
|
|
|
using namespace Foam;
|
|
|
|
//- The known and support types of operations
|
|
enum restoreMethod
|
|
{
|
|
MEAN,
|
|
ORIG
|
|
};
|
|
|
|
|
|
static const Enum<restoreMethod> methodNames
|
|
{
|
|
{ restoreMethod::MEAN, "mean" },
|
|
{ restoreMethod::ORIG, "orig" },
|
|
};
|
|
|
|
|
|
static const Enum<restoreMethod> methodEndings
|
|
{
|
|
{ restoreMethod::MEAN, "Mean" },
|
|
{ restoreMethod::ORIG, ".orig" },
|
|
};
|
|
|
|
|
|
// Files in given directory at time instant
|
|
inline wordList getFiles(const fileName& dir, const word& instance)
|
|
{
|
|
return ListOps::create<word>
|
|
(
|
|
Foam::readDir(dir/instance, fileName::FILE),
|
|
nameOp<fileName>()
|
|
);
|
|
}
|
|
|
|
|
|
// Command-line options: -dry-run, -verbose
|
|
bool dryrun = false, verbose = false;
|
|
|
|
|
|
// Use predefined method to walk the directory and rename the files.
|
|
//
|
|
// If no target names are specified, the existing files are scanned for
|
|
// candidates.
|
|
label restoreFields
|
|
(
|
|
const restoreMethod method,
|
|
const fileName& dirName,
|
|
const wordHashSet& existingFiles,
|
|
const wordList& targetNames
|
|
)
|
|
{
|
|
// The file ending to search for.
|
|
const word ending(methodEndings[method]);
|
|
|
|
// The backup ending for existing (if any)
|
|
word bak;
|
|
|
|
switch (method)
|
|
{
|
|
case restoreMethod::MEAN:
|
|
bak = methodEndings[restoreMethod::ORIG];
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
wordHashSet targets(targetNames);
|
|
|
|
if (targets.empty())
|
|
{
|
|
// No target names specified - scan existing files for candidates.
|
|
|
|
for (word f : existingFiles) // Operate on a copy
|
|
{
|
|
// Eg, check for "UMean" and save as "U"
|
|
if (f.removeEnd(ending) && f.size())
|
|
{
|
|
targets.insert(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (verbose)
|
|
{
|
|
Info<< "directory " << dirName.name() << nl;
|
|
}
|
|
|
|
// Count of files moved, including backups
|
|
label count = 0;
|
|
|
|
for (const word& dst : targets)
|
|
{
|
|
const word src(dst + ending);
|
|
|
|
if (!existingFiles.found(src))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (bak.size() && existingFiles.found(dst))
|
|
{
|
|
if (dryrun || Foam::mv(dirName/dst, dirName/dst + bak))
|
|
{
|
|
Info<< " mv " << dst << " " << word(dst + bak) << nl;
|
|
++count;
|
|
}
|
|
}
|
|
|
|
if (dryrun || Foam::mv(dirName/src, dirName/dst))
|
|
{
|
|
Info<< " mv " << src << " " << dst << nl;
|
|
++count;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
argList::addNote
|
|
(
|
|
"Restore field names by removing the ending. Fields are selected"
|
|
" automatically or can be specified as optional command arguments"
|
|
);
|
|
|
|
profiling::disable(); // Disable profiling (and its output)
|
|
argList::noJobInfo();
|
|
argList::noFunctionObjects(); // Never use function objects
|
|
argList::addOption
|
|
(
|
|
"method",
|
|
"name",
|
|
"The restore method (mean|orig) [MANDATORY]. "
|
|
"With <mean> renames files ending with 'Mean' "
|
|
"(with backup of existing as '.orig'). "
|
|
"With <orig> renames files ending with '.orig'"
|
|
);
|
|
argList::addBoolOption
|
|
(
|
|
"processor",
|
|
"In serial mode use times from processor0/ directory, but operate on "
|
|
"processor\\d+ directories"
|
|
);
|
|
argList::addBoolOption
|
|
(
|
|
"dry-run",
|
|
"Report action without moving/renaming"
|
|
);
|
|
argList::addBoolOption
|
|
(
|
|
"verbose",
|
|
"Additional verbosity"
|
|
);
|
|
|
|
// Arguments are optional (non-mandatory)
|
|
argList::noMandatoryArgs();
|
|
argList::addArgument("fieldName ... fieldName");
|
|
|
|
timeSelector::addOptions(true, true); // constant(true), zero(true)
|
|
|
|
#include "setRootCase.H"
|
|
|
|
dryrun = args.found("dry-run");
|
|
verbose = args.found("verbose");
|
|
|
|
|
|
// Construct time
|
|
// ~~~~~~~~~~~~~~
|
|
|
|
restoreMethod method = restoreMethod::ORIG;
|
|
{
|
|
word methodName;
|
|
|
|
if
|
|
(
|
|
args.readIfPresent("method", methodName)
|
|
&& methodNames.found(methodName)
|
|
)
|
|
{
|
|
method = methodNames[methodName];
|
|
}
|
|
else
|
|
{
|
|
Info<< "Unspecified or unknown method name" << nl
|
|
<< "Valid methods: "
|
|
<< flatOutput(methodNames.sortedToc()) << nl
|
|
<< "... stopping" << nl << nl;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Optional base or target field names (eg, 'U', 'T' etc)
|
|
wordList targetNames;
|
|
if (args.size() > 1)
|
|
{
|
|
targetNames.resize(args.size()-1);
|
|
wordHashSet uniq;
|
|
|
|
for (label argi=1; argi < args.size(); ++argi)
|
|
{
|
|
if (uniq.insert(args[argi]))
|
|
{
|
|
targetNames[uniq.size()-1] = args[argi];
|
|
}
|
|
}
|
|
|
|
targetNames.resize(uniq.size());
|
|
|
|
if (verbose)
|
|
{
|
|
Info<< nl
|
|
<< "using method=" << methodNames[method] << nl
|
|
<< "with fields " << flatOutput(targetNames) << nl;
|
|
}
|
|
}
|
|
else if (verbose)
|
|
{
|
|
Info<< nl
|
|
<< "using method=" << methodNames[method] << nl
|
|
<< "autodetect fields" << nl;
|
|
}
|
|
|
|
|
|
// Get times list from the master processor and subset based on
|
|
// command-line options
|
|
|
|
label nProcs = 0;
|
|
autoPtr<TimePaths> timePaths;
|
|
|
|
if (args.found("processor") && !Pstream::parRun())
|
|
{
|
|
// Determine the processor count
|
|
nProcs = fileHandler().nProcs(args.path());
|
|
|
|
if (!nProcs)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "No processor* directories found"
|
|
<< exit(FatalError);
|
|
}
|
|
|
|
// Obtain time directory names from "processor0/" only
|
|
|
|
timePaths = autoPtr<TimePaths>::New
|
|
(
|
|
args.rootPath(),
|
|
args.caseName()/"processor0"
|
|
);
|
|
}
|
|
else
|
|
{
|
|
timePaths = autoPtr<TimePaths>::New
|
|
(
|
|
args.rootPath(),
|
|
args.caseName()
|
|
);
|
|
}
|
|
|
|
const instantList timeDirs(timeSelector::select(timePaths->times(), args));
|
|
|
|
if (timeDirs.empty())
|
|
{
|
|
Info<< "no times selected" << nl;
|
|
}
|
|
|
|
for (const instant& t : timeDirs)
|
|
{
|
|
const word& timeName = t.name();
|
|
|
|
Info<< "\nTime = " << timeName << nl;
|
|
|
|
label count = 0;
|
|
|
|
if (nProcs)
|
|
{
|
|
const wordHashSet files
|
|
(
|
|
getFiles(args.path()/"processor0", timeName)
|
|
);
|
|
|
|
for (label proci=0; proci < nProcs; ++proci)
|
|
{
|
|
count += restoreFields
|
|
(
|
|
method,
|
|
args.path()/("processor" + Foam::name(proci))/timeName,
|
|
files,
|
|
targetNames
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wordList files;
|
|
if (Pstream::master())
|
|
{
|
|
files = getFiles(args.path(), timeName);
|
|
}
|
|
Pstream::scatter(files);
|
|
|
|
count += restoreFields
|
|
(
|
|
method,
|
|
args.path()/timeName,
|
|
wordHashSet(files),
|
|
targetNames
|
|
);
|
|
}
|
|
|
|
if (dryrun)
|
|
{
|
|
Info<< "dry-run: ";
|
|
}
|
|
Info<< "moved " << count << " files" << nl;
|
|
}
|
|
|
|
Info<< "\nEnd\n" << endl;
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|