diff --git a/applications/utilities/miscellaneous/foamRestoreFields/Make/files b/applications/utilities/miscellaneous/foamRestoreFields/Make/files new file mode 100644 index 0000000000000000000000000000000000000000..cf5d388c247e4ef7e6eda7766873c087e537d401 --- /dev/null +++ b/applications/utilities/miscellaneous/foamRestoreFields/Make/files @@ -0,0 +1,3 @@ +foamRestoreFields.C + +EXE = $(FOAM_APPBIN)/foamRestoreFields diff --git a/applications/utilities/miscellaneous/foamRestoreFields/Make/options b/applications/utilities/miscellaneous/foamRestoreFields/Make/options new file mode 100644 index 0000000000000000000000000000000000000000..18e6fe47afacb902cddccf82632772447704fd88 --- /dev/null +++ b/applications/utilities/miscellaneous/foamRestoreFields/Make/options @@ -0,0 +1,2 @@ +/* EXE_INC = */ +/* EXE_LIBS = */ diff --git a/applications/utilities/miscellaneous/foamRestoreFields/foamRestoreFields.C b/applications/utilities/miscellaneous/foamRestoreFields/foamRestoreFields.C new file mode 100644 index 0000000000000000000000000000000000000000..a8205f625b79992cd88808a7f5412bcb403e356c --- /dev/null +++ b/applications/utilities/miscellaneous/foamRestoreFields/foamRestoreFields.C @@ -0,0 +1,399 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "profiling.H" +#include "timeSelector.H" +#include "Enum.H" +#include "Time.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 +wordList getFiles(const fileName& dir, const word& instance) +{ + return ListOps::create<word> + ( + Foam::readDir(dir/instance, fileName::FILE), + [](const fileName& f){ return f.name(); } + ); +} + + +// 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 (dryrun) + { + Info<< "dry-run: " << dirName << nl; + } + else if (verbose) + { + Info<< "directory " << dirName << 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. The fields are " + "selected\n" + "automatically or can be specified as optional command arguments.\n" + ); + + profiling::disable(); // Disable profiling (and its output) + argList::noJobInfo(); + argList::noFunctionObjects(); + 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" + ); + + // Non-mandatory arguments + argList::addArgument("fieldName ... fieldName"); + + timeSelector::addOptions(true, true); + #include "setRootCaseNonMandatoryArgs.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; + instantList times; + + 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 times from "processor0/" only + times = timeSelector::select + ( + Time + ( + Time::controlDictName, + args.rootPath(), + args.caseName()/"processor0" + ).times(), + args + ); + } + else + { + if (Pstream::master()) + { + times = timeSelector::select + ( + Time(Time::controlDictName, args).times(), + args + ); + } + + Pstream::scatter(times); + } + + + if (times.empty()) + { + Info<< "no times selected" << nl; + } + + for (const instant& inst : times) + { + Info<< "\nTime = " << inst.name() << nl; + + label count = 0; + + if (nProcs) + { + const wordHashSet files + ( + getFiles(args.path()/"processor0", inst.name()) + ); + + for (label proci=0; proci < nProcs; ++proci) + { + count += restoreFields + ( + method, + args.path()/("processor" + Foam::name(proci))/inst.name(), + files, + targetNames + ); + } + } + else + { + wordList files; + if (Pstream::master()) + { + files = getFiles(args.path(), inst.name()); + } + Pstream::scatter(files); + + count += restoreFields + ( + method, + args.path()/inst.name(), + wordHashSet(files), + targetNames + ); + } + + if (dryrun) + { + Info<< "dry-run: "; + } + Info<< "moved " << count << " files" << nl; + } + + Info<< "\nEnd\n" << endl; + return 0; +} + + +// ************************************************************************* //