diff --git a/.gitignore b/.gitignore index b426cd4ee..88b59834b 100644 --- a/.gitignore +++ b/.gitignore @@ -181,4 +181,12 @@ src/lduSolvers/amg/amgPolicy/samgPolicy.H src/lduSolvers/amg/amgPolicy/aamgPolicy.C src/lduSolvers/amg/amgPolicy/aamgPolicy.H +# The following files are blacklisted because of a DMCA complaint by ANSYS. +src/lduSolvers/tools/PriorityArray.C +src/lduSolvers/tools/PriorityArray.H +src/lduSolvers/amg/amgPolicy/samgPolicy.C +src/lduSolvers/amg/amgPolicy/samgPolicy.H +src/lduSolvers/amg/amgPolicy/aamgPolicy.C +src/lduSolvers/amg/amgPolicy/aamgPolicy.H + # end-of-file diff --git a/applications/solvers/multiSolver/multiSolverDemo/Make/files b/applications/solvers/multiSolver/multiSolverDemo/Make/files new file mode 100644 index 000000000..be56142a9 --- /dev/null +++ b/applications/solvers/multiSolver/multiSolverDemo/Make/files @@ -0,0 +1,3 @@ +multiSolverDemo.C + +EXE = $(FOAM_APPBIN)/multiSolverDemo diff --git a/applications/solvers/multiSolver/multiSolverDemo/Make/options b/applications/solvers/multiSolver/multiSolverDemo/Make/options new file mode 100644 index 000000000..19bacb224 --- /dev/null +++ b/applications/solvers/multiSolver/multiSolverDemo/Make/options @@ -0,0 +1,9 @@ +EXE_INC = \ + -I$(LIB_SRC)/finiteVolume/lnInclude \ + -I$(LIB_SRC)/multiSolver/lnInclude \ + -I$(LIB_SRC)/multiSolver/multiSolver + +EXE_LIBS = \ + -lfiniteVolume \ + -L$(FOAM_USER_LIBBIN) \ + -lmultiSolver diff --git a/applications/solvers/multiSolver/multiSolverDemo/createFields_icoFoam.H b/applications/solvers/multiSolver/multiSolverDemo/createFields_icoFoam.H new file mode 100644 index 000000000..6a7d6b9a8 --- /dev/null +++ b/applications/solvers/multiSolver/multiSolverDemo/createFields_icoFoam.H @@ -0,0 +1,55 @@ + Info<< "Reading transportProperties\n" << endl; + + IOdictionary transportProperties + ( + IOobject + ( + "transportProperties", + runTime.constant(), + mesh, + IOobject::MUST_READ, + IOobject::NO_WRITE + ) + ); + + dimensionedScalar nu + ( + transportProperties.lookup("nu") + ); + + Info<< "Reading field p\n" << endl; + volScalarField p + ( + IOobject + ( + "p", + runTime.timeName(), + mesh, + IOobject::MUST_READ, + IOobject::AUTO_WRITE + ), + mesh + ); + + + Info<< "Reading field U\n" << endl; + volVectorField U + ( + IOobject + ( + "U", + runTime.timeName(), + mesh, + IOobject::MUST_READ, + IOobject::AUTO_WRITE + ), + mesh + ); + + +# include "createPhi.H" + + + label pRefCell = 0; + scalar pRefValue = 0.0; + setRefCell(p, mesh.solutionDict().subDict("PISO"), pRefCell, pRefValue); diff --git a/applications/solvers/multiSolver/multiSolverDemo/createFields_scalarTransportFoam.H b/applications/solvers/multiSolver/multiSolverDemo/createFields_scalarTransportFoam.H new file mode 100644 index 000000000..5eb6c116f --- /dev/null +++ b/applications/solvers/multiSolver/multiSolverDemo/createFields_scalarTransportFoam.H @@ -0,0 +1,55 @@ + Info<< "Reading field T\n" << endl; + + volScalarField T + ( + IOobject + ( + "T", + runTime.timeName(), + mesh, + IOobject::MUST_READ, + IOobject::AUTO_WRITE + ), + mesh + ); + + + Info<< "Reading field U\n" << endl; + + volVectorField U + ( + IOobject + ( + "U", + runTime.timeName(), + mesh, + IOobject::MUST_READ, + IOobject::AUTO_WRITE + ), + mesh + ); + + + Info<< "Reading transportProperties\n" << endl; + + IOdictionary transportProperties + ( + IOobject + ( + "transportProperties", + runTime.constant(), + mesh, + IOobject::MUST_READ, + IOobject::NO_WRITE + ) + ); + + Info<< "Reading diffusivity D\n" << endl; + + dimensionedScalar DT + ( + transportProperties.lookup("DT") + ); + +# include "createPhi.H" + diff --git a/applications/solvers/multiSolver/multiSolverDemo/multiSolverDemo.C b/applications/solvers/multiSolver/multiSolverDemo/multiSolverDemo.C new file mode 100644 index 000000000..c12a074ab --- /dev/null +++ b/applications/solvers/multiSolver/multiSolverDemo/multiSolverDemo.C @@ -0,0 +1,86 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Application + multiSolverDemo + +Description + Demonstration multiSolver-enabled application. + +Author + David L. F. Gaden + +\*---------------------------------------------------------------------------*/ + +#include "fvCFD.H" +#include "multiSolver.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +int main(int argc, char *argv[]) +{ + +# include "setRootCase.H" + +# include "createMultiSolver.H" + +// * * * * * * * * * * * * * * * * icoFoam1 * * * * * * * * * * * * * * * * // + + Info << "*** Switching to icoFoam1 ***\n" << endl; + solverDomain = "icoFoam1"; +# include "setSolverDomain.H" + +# include "solverIcoFoam.H" + +// * * * * * * * * * * * * * scalarTransportFoam * * * * * * * * * * * * * * // + + Info << "*** Switching to scalarTransportFoam ***\n" << endl; + solverDomain = "scalarTransportFoam"; +# include "setSolverDomain.H" + +# include "solverScalarTransportFoam.H" + + multiRun++; + +// * * * * * * * * * * * * * * * * icoFoam2 * * * * * * * * * * * * * * * * // + + Info << "*** Switching to icoFoam2 ***\n" << endl; + solverDomain = "icoFoam2"; +# include "setSolverDomain.H" + +# include "solverIcoFoam.H" + +// * * * * * * * * * * * * * scalarTransportFoam * * * * * * * * * * * * * * // + + Info << "*** Switching to scalarTransportFoam ***\n" << endl; + solverDomain = "scalarTransportFoam"; +# include "setSolverDomain.H" + +# include "solverScalarTransportFoam.H" + +# include "endMultiSolver.H" + return(0); +} + +// ************************************************************************* // diff --git a/applications/solvers/multiSolver/multiSolverDemo/solverIcoFoam.H b/applications/solvers/multiSolver/multiSolverDemo/solverIcoFoam.H new file mode 100644 index 000000000..f62ba240e --- /dev/null +++ b/applications/solvers/multiSolver/multiSolverDemo/solverIcoFoam.H @@ -0,0 +1,69 @@ + +# include "createTime.H" +# include "createMesh.H" +# include "createFields_icoFoam.H" +# include "initContinuityErrs.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + Info<< "\nStarting time loop\n" << endl; + + for (runTime++; !runTime.end(); runTime++) + { + Info<< "Time = " << runTime.timeName() << nl << endl; + +# include "readPISOControls.H" +# include "CourantNo.H" + + fvVectorMatrix UEqn + ( + fvm::ddt(U) + + fvm::div(phi, U) + - fvm::laplacian(nu, U) + ); + + solve(UEqn == -fvc::grad(p)); + + // --- PISO loop + + for (int corr=0; corrsetSize(++nSuperLoops); + ptrSuperLoops->operator[](nSuperLoops - 1) + = nextOption.labelToken(); + break; + } + if (nextOption.isWord()) + { + ptrSolverDomains->setSize(++nSolverDomains); + ptrSolverDomains->operator[](nSolverDomains - 1) + = nextOption.wordToken(); + } + else + { + // not word, not label, fail + FatalErrorIn("multiSolver::parseOptions") + << "Expecting word or label. Neither found at position " + << nSolverDomains - 1 << " in " << options + << abort(FatalError); + } + } + + // Get superLoopList + while (not optionsStream.eof()) + { + token nextOption(optionsStream); + if (nextOption.isLabel()) + { + ptrSuperLoops->setSize(++nSuperLoops); + ptrSuperLoops->operator[](nSuperLoops - 1) + = nextOption.labelToken(); + } + else if (nSuperLoops > 0) + { + // might be a range -> label : label + + if (nextOption.isPunctuation()) + { + token::punctuationToken p(nextOption.pToken()); + if (p == token::COLON) + { + token nextNextOption(optionsStream); + if (nextNextOption.isLabel()) + { + label toValue(nextNextOption.labelToken()); + label fromValue + ( + ptrSuperLoops->operator[](nSuperLoops - 1) + ); + + if (toValue > fromValue) + { + // correct range format + for (label i = fromValue + 1; i <= toValue; i++) + { + ptrSuperLoops->setSize(++nSuperLoops); + ptrSuperLoops->operator[](nSuperLoops - 1) = i; + } + } + else + { + // greater than / less than, range + FatalErrorIn("multiSolver::parseOptions") + << "superLoop range incorrect order. 'from : " + << "to' where 'from' should be less than " + << "'to'. Values read are '" << fromValue + << " : " << toValue + << abort(FatalError); + } + } + else + { + // nextNext not label + FatalErrorIn("multiSolver::parseOptions") + << "Incorrect syntax. Expecting label after ':' " + << "in " << options + << abort(FatalError); + } + } + else + { + // non : punctuation + FatalErrorIn("multiSolver::parseOptions") + << "Incorrect syntax. Expecting label, word, or ':' " + << "in " << options + << abort(FatalError); + } + } + else + { + // not punctuation + FatalErrorIn("multiSolver::parseOptions") + << "Incorrect syntax. Expecting label, word, or ':' " + << "in " << options + << abort(FatalError); + } + } + else + { + // not label, not word + FatalErrorIn("multiSolver::parseOptions") + << "Incorrect syntax. Expecting label, word, or ':' " + << "in " << options + << abort(FatalError); + } + } +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +int main(int argc, char *argv[]) +{ + argList::validOptions.insert("list",""); + argList::validOptions.insert + ( + "load","<[solverDomainName] [superLoopNumber(s)]>" + ); + argList::validOptions.insert + ( + "purge","<[solverDomainName] [superLoopNumber(s)]>" + ); + argList::validOptions.insert("set",""); + argList::validOptions.insert("preDecompose", ""); + argList::validOptions.insert("postDecompose", ""); + argList::validOptions.insert("preReconstruct", ""); + argList::validOptions.insert("postReconstruct", ""); + + argList::validOptions.insert("global",""); + argList::validOptions.insert("local",""); + + // default behaviour is purge the case/[time] directory before '-load' + // command. '-noPurge' prevents this. Allows for more complicated + // load data selections by executing multiSolver several times + argList::validOptions.insert("noPurge",""); + + // default behaviour is: if there is only one solverDomain specified, use + // setSolverDomain() on it. Same as multiSolver -set solverDomain. + // '-noSet' prevents this. + argList::validOptions.insert("noSet",""); + + // default behaviour is: if there are storeFields defined, when loading, it + // will copy the store fields into every time instance where they are + // absent. '-noStore' will prevent this. + argList::validOptions.insert("noStore",""); + +# include "setRootCase.H" + + enum commandType + { + list, + load, + purge, + set, + preDecompose, + postDecompose, + preReconstruct, + postReconstruct + }; + commandType command; + string options; + bool global = false; + bool local = false; + bool all = false; + bool root = false; + bool noPurge = false; + bool noSet = false; + bool noStore = false; + label nCommands(0); + + // Read arguments + if (args.optionFound("list")) + { + nCommands++; + command = list; + } + if (args.optionFound("load")) + { + nCommands++; + command = load; + options = args.options()["load"]; + } + if (args.optionFound("purge")) + { + nCommands++; + command = purge; + options = args.options()["purge"]; + } + if (args.optionFound("set")) + { + nCommands++; + command = set; + options = args.options()["set"]; + } + if (args.optionFound("preDecompose")) + { + nCommands++; + command = preDecompose; + } + if (args.optionFound("postDecompose")) + { + nCommands++; + command = postDecompose; + } + if (args.optionFound("preReconstruct")) + { + nCommands++; + command = preReconstruct; + } + if (args.optionFound("postReconstruct")) + { + nCommands++; + command = postReconstruct; + } + if (args.optionFound("global")) + { + global = true; + } + if (args.optionFound("local")) + { + local = true; + } + if (args.optionFound("noPurge")) + { + noPurge = true; + } + if (args.optionFound("noSet")) + { + noSet = true; + } + if (args.optionFound("noStore")) + { + noStore = true; + } + + // Error checking + if (nCommands == 0) + { + FatalErrorIn("multiSolver::main") + << "multiSolver - nothing to do. Use 'multiSolver -help' for assistance." + << abort(FatalError); + } + else if (nCommands > 1) + { + FatalErrorIn("multiSolver::main") + << "More than one command found. Use only one of:" + << "\n\t-list" + << "\n\t-purge" + << "\n\t-set" + << "\n\t-preDecompose" + << "\n\t-postDecompose" + << "\n\t-preReconstruct" + << "\n\t-postReconstruct\n" + << abort(FatalError); + } + if (global && local) + { + FatalErrorIn("multiSolver::main") + << "Options global and local both specified. Use only one or " + << "none." + << abort(FatalError); + } + if ((command != load) && (noPurge || noSet || noStore)) + { + FatalErrorIn("multiSolver::main") + << "'noPurge', 'noSet' and 'noStore' can only be used with the " + << "'-load' command." + << abort(FatalError); + } + + multiSolver multiRun + ( + Foam::multiSolver::multiControlDictName, + args.rootPath(), + args.caseName() + ); + + const IOdictionary& mcd(multiRun.multiControlDict()); + wordList solverDomains(0); + labelList superLoops(0); + if + ( + (command != list) + && (command != preDecompose) + && (command != postDecompose) + && (command != preReconstruct) + && (command != postReconstruct) + ) + { + parseOptions(&solverDomains, &superLoops, options); + } + + // Special words - all, root + if (solverDomains.size() == 1) + { + if (solverDomains[0] == "all") + { + all = true; + } + else if (solverDomains[0] == "root") + { + root = true; + } + } + + // More error checking + if (root && ((command == load) || (command == set))) + { + FatalErrorIn("multiSolver::main") + << "'root' is not a valid option with '-load' or '-set'" + << abort(FatalError); + } + if (all && (command == set)) + { + FatalErrorIn("multiSolver::main") + << "'all' is not a valid option with '-set'" + << abort(FatalError); + } + if ((command == set) && ((solverDomains.size() > 1) || superLoops.size())) + { + FatalErrorIn("multiSolver::main") + << "'-set' can only have a single solverDomain name as an option." + << abort(FatalError); + } + if (all && superLoops.size()) + { + FatalErrorIn("multiSolver::main") + << "'all' cannot be followed by superLoop numbers. To specify " + << "a superLoop range for all solverDomains, omit the solverDomain" + << " name entirely. e.g. multiSolver -load '0:4 6'" + << abort(FatalError); + } + if (root && superLoops.size()) + { + FatalErrorIn("multiSolver::main") + << "'root' cannot be followed by superLoop numbers. 'root' refers" + << " to case/[time] directories. There are no superLoops here." + << abort(FatalError); + } + + // Check for correct solverDomain names + if + ( + !all + && !root + && (command != list) + && (command != preDecompose) + && (command != postDecompose) + && (command != preReconstruct) + && (command != postReconstruct) + ) + { + forAll(solverDomains, i) + { + if (solverDomains[i] == "default") + { + // default not permitted + FatalErrorIn("multiSolver::main") + << "'default' is not a permitted solverDomain name." + << abort(FatalError); + } + if (!mcd.subDict("solverDomains").found(solverDomains[i])) + { + // Incorrect solver domain name + FatalErrorIn("multiSolver::main") + << "solverDomainName " << solverDomains[i] << " is not " + << "found." + << abort(FatalError); + } + } + } + + // Load specified timeClusterLists + timeClusterList tclSource(0); + + if (all) + { + // read all + tclSource = multiRun.readAllTimes(); + forAll(tclSource, i) + { + if (tclSource[i].superLoop() == -1) + { + tclSource[i].times().clear(); + } + } + tclSource.purgeEmpties(); + } + else if + ( + !superLoops.size() + && (command != set) + && (command != list) + && (command != preDecompose) + && (command != postDecompose) + && (command != preReconstruct) + && (command != postReconstruct) + ) + { + // no superLoops specified - read entire solverDomains + forAll (solverDomains, sd) + { + tclSource.append + ( + multiRun.readSolverDomainTimes(solverDomains[sd]) + ); + } + } + else if + ( + !root + && (command != set) + && (command != list) + && (command != preDecompose) + && (command != postDecompose) + && (command != preReconstruct) + && (command != postReconstruct) + ) + { + // read individual superLoops + if (!solverDomains.size()) + { + solverDomains = mcd.subDict("solverDomains").toc(); + } + forAll(superLoops, sl) + { + forAll(solverDomains, sd) + { + if (solverDomains[sd] == "default") continue; + tclSource.append + ( + multiRun.readSuperLoopTimes + ( + solverDomains[sd], + superLoops[sl] + ) + ); + } + } + } + + if (tclSource.size()) + { + if (!tclSource.purgeEmpties()) + { + FatalErrorIn("multiSolver::main") + << "No data found with specified parameters." + << abort(FatalError); + } + } + + switch (command) + { + case list: + { + Info << "Listing available data:\n" << endl; + Info << "superLoops by solverDomain:" << endl; + solverDomains = mcd.subDict("solverDomains").toc(); + fileName listPath + ( + multiRun.multiDictRegistry().path()/"multiSolver" + ); + + forAll(solverDomains, i) + { + if (solverDomains[i] == "default") continue; + Info << solverDomains[i] << ":" << endl; + Info << multiRun.findSuperLoops(listPath/solverDomains[i]) + << endl; + } + Info << endl; + break; + } + case load: + { + // Default behaviour - use local time unless overlapping, then use + // global time; if global overlaps, fail. -local and -global force + // the behaviour + bool localOverlap(!multiRun.nonOverlapping(tclSource, false)); + bool globalOverlap(!multiRun.nonOverlapping(tclSource, true)); + if (local && localOverlap) + { + FatalErrorIn("multiSolver::main") + << "'-local' option used for data with overlapping local " + << "values. Try using a single solverDomain / superLoop, " + << "or leave '-local' off." + << abort(FatalError); + } + if (globalOverlap) + { + FatalErrorIn("multiSolver::main") + << "globalTime values are overlapping. This should not " + << "happen. Ensure you have not specified the same " + << "solverDomain and/or superLoop more than once. If " + << "that fails, try using 'multiSolver -purge all' and " + << "rerunning the simulation. If the problem persists, " + << "it is a bug." + << abort(FatalError); + } + + if (!noPurge) + { + Info << "Purging existing time directories in case root" + << endl; + multiRun.purgeTimeDirs(multiRun.multiDictRegistry().path()); + } + + Info << "Loading data from multiSolver directories to case root" + << endl; + if + ( + !multiRun.loadTimeClusterList + ( + tclSource, + global || localOverlap, + !noStore + ) + ) + { + FatalErrorIn("multiRun::main") + << "loadTimeClusterList failed. timeClusterList contents: " + << tclSource + << abort(FatalError); + } + break; + } + case purge: + if (root) + { + Info << "Purging time directories from case root" << endl; + multiRun.purgeTimeDirs(multiRun.multiDictRegistry().path()); + } + else + { + Info << "Purging time directories from multiSolver directories" + << endl; + forAll(tclSource, i) + { + // do not purge 'initial' directory, even if specified + if (tclSource[i].superLoop() < 0) continue; + fileName purgePath + ( + multiRun.findInstancePath(tclSource[i], 0).path() + ); + rmDir(purgePath); + } + } + break; + case set: + // do nothing here + break; + case preDecompose: + { + Info << "Performing preDecompose" << endl; + multiRun.preCondition(); + break; + } + case postDecompose: + { + Info << "Performing postDecompose" << endl; + + fileNameList dirEntries + ( + readDir + ( + multiRun.multiDictRegistry().path(), fileName::DIRECTORY + ) + ); + + forAll(dirEntries, de) + { + if (dirEntries[de](9) == "processor") + { + Info << "Reading " << dirEntries[de] << endl; + + multiRun.postCondition + ( + dirEntries[de] + ); + + // Copy system to processorN + cp + ( + multiRun.multiDictRegistry().path() + /multiRun.multiDictRegistry().system(), + multiRun.multiDictRegistry().path()/dirEntries[de] + ); + + // Copy constant/files to processorN/constant + fileNameList constantContents + ( + readDir + ( + multiRun.multiDictRegistry().path() + /multiRun.multiDictRegistry().constant(), + fileName::FILE + ) + ); + forAll(constantContents, cc) + { + cp + ( + multiRun.multiDictRegistry().path() + /multiRun.multiDictRegistry().constant() + /constantContents[cc], + multiRun.multiDictRegistry().path()/dirEntries[de] + /multiRun.multiDictRegistry().constant() + ); + } + + // Copy constant/directories to processorN/constant + constantContents = readDir + ( + multiRun.multiDictRegistry().path() + /multiRun.multiDictRegistry().constant(), + fileName::DIRECTORY + ); + forAll(constantContents, cc) + { + // Ingore mesh directory + if (constantContents[cc] == "polyMesh") + { + continue; + } + cp + ( + multiRun.multiDictRegistry().path() + /multiRun.multiDictRegistry().constant() + /constantContents[cc], + multiRun.multiDictRegistry().path()/dirEntries[de] + /multiRun.multiDictRegistry().constant() + ); + } + } + } + multiRun.purgeTimeDirs(multiRun.multiDictRegistry().path()); + break; + } + case preReconstruct: + { + Info << "Performing preReconstruct" << endl; + fileNameList dirEntries + ( + readDir + ( + multiRun.multiDictRegistry().path(), fileName::DIRECTORY + ) + ); + + forAll(dirEntries, de) + { + if (dirEntries[de](9) == "processor") + { + Info << "Reading " << dirEntries[de] << endl; + multiRun.preCondition + ( + dirEntries[de] + ); + // Fix missing 0.00000e+00 directory if it exists + mkDir + ( + multiRun.multiDictRegistry().path()/dirEntries[de]/"0" + ); + } + } + break; + } + case postReconstruct: + { + Info << "Performing postReconstruct" << endl; + + Info << "Reading preconditioned time directories" << endl; + multiRun.postCondition(); + + Info << "Purging preconditioned time directories" + << endl; + + // Clean up extra time directories + fileNameList dirEntries + ( + readDir + ( + multiRun.multiDictRegistry().path(), fileName::DIRECTORY + ) + ); + + forAll(dirEntries, de) + { + if (dirEntries[de](9) == "processor") + { + multiRun.purgeTimeDirs + ( + multiRun.multiDictRegistry().path()/dirEntries[de] + ); + } + } + break; + } + } + + // Execute set command - either from an explicit '-set' or from a '-load' + // with only one solverDomain as an option + + if + ( + (command == set) + || ( + (command == load) + && (solverDomains.size() == 1) + && (!all) + ) + ) + { + Info << "Changing to " << solverDomains[0] << " settings." << endl; + multiRun.setSolverDomainPostProcessing(solverDomains[0]); + } + + Info << "\nCommand completed successfully.\n" << endl; + return(0); +} + +// ************************************************************************* // diff --git a/src/Allwmake b/src/Allwmake index 6fe5e2ba5..e2e483751 100755 --- a/src/Allwmake +++ b/src/Allwmake @@ -22,6 +22,8 @@ Pstream/Allwmake wmake libo OSspecific/$WM_OSTYPE wmake libso OpenFOAM +wmake libso multiSolver + # Decomposition methods needed by meshTools decompositionMethods/AllwmakeLnInclude decompositionMethods/Allwmake diff --git a/src/multiSolver/Make/files b/src/multiSolver/Make/files new file mode 100644 index 000000000..eb2f99562 --- /dev/null +++ b/src/multiSolver/Make/files @@ -0,0 +1,6 @@ +dummyControlDict/dummyControlDict.C +multiSolver/multiSolver.C +timeCluster/timeCluster.C +timeCluster/timeClusterList.C + +LIB = $(FOAM_LIBBIN)/libmultiSolver diff --git a/src/multiSolver/Make/options b/src/multiSolver/Make/options new file mode 100644 index 000000000..082a5e7a2 --- /dev/null +++ b/src/multiSolver/Make/options @@ -0,0 +1,6 @@ +EXE_INC = \ + -I$(LIB_SRC)/finiteVolume/lnInclude \ + -Ituple2Lists + +LIB_LIBS = \ + -lfiniteVolume diff --git a/src/multiSolver/dummyControlDict/dummyControlDict.C b/src/multiSolver/dummyControlDict/dummyControlDict.C new file mode 100644 index 000000000..48c8cf6ab --- /dev/null +++ b/src/multiSolver/dummyControlDict/dummyControlDict.C @@ -0,0 +1,111 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "dummyControlDict.H" +#include "IFstream.H" + +// * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(dummyControlDict, 0); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::dummyControlDict::dummyControlDict() +{ + this->set("deltaT", 1); + this->set("writeFrequency", 1); +} + + +Foam::dummyControlDict::dummyControlDict(const fileName& mcdFile) +{ + this->set("deltaT", 1); + this->set("writeFrequency", 1); + + IFstream mcdStream(mcdFile); + if (!mcdStream.good()) + { + FatalErrorIn("dummyControlDict::dummyControlDict") + << "Cannot find the multiControlDict file " << mcdFile << "." + << abort(FatalError); + } + dictionary mcdDict(mcdStream); + if (mcdDict.subDict("multiSolverControl").found("timeFormat")) + { + word tf(mcdDict.subDict("multiSolverControl").lookup("timeFormat")); + this->set("timeFormat", tf); + } + if (mcdDict.subDict("multiSolverControl").found("timePrecision")) + { + label tp + ( + readLabel + ( + mcdDict.subDict("multiSolverControl").lookup("timePrecision") + ) + ); + this->set("timePrecision", tp); + } +} + + +Foam::dummyControlDict::dummyControlDict(const dictionary& mcdDict) +{ + this->set("deltaT", 1); + this->set("writeFrequency", 1); + + if (mcdDict.subDict("multiSolverControl").found("timeFormat")) + { + word tf(mcdDict.subDict("multiSolverControl").lookup("timeFormat")); + this->set("timeFormat", tf); + } + if (mcdDict.subDict("multiSolverControl").found("timePrecision")) + { + label tp + ( + readLabel + ( + mcdDict.subDict("multiSolverControl").lookup("timePrecision") + ) + ); + this->set("timePrecision", tp); + } +} + + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::dummyControlDict::~dummyControlDict() +{} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + diff --git a/src/multiSolver/dummyControlDict/dummyControlDict.H b/src/multiSolver/dummyControlDict/dummyControlDict.H new file mode 100644 index 000000000..93d241859 --- /dev/null +++ b/src/multiSolver/dummyControlDict/dummyControlDict.H @@ -0,0 +1,92 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::dummyControlDict + +Description + This class is a workaround that allows a class to have its own independent + objectRegistry. That requires the creation of a new Time object, which + requires a controlDict for construction. dummyControlDict creates a dummy + controlDict to feed the new Time object. The only dictionary values it + handles are deltaT, writeFrequency, and optionally, the Time class statics, + format and precision. + +SourceFiles + dummyControlDict.C + +Author + David L. F. Gaden + +\*---------------------------------------------------------------------------*/ + +#ifndef dummyControlDict_H +#define dummyControlDict_H + +#include "dictionary.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class dummyControlDict Declaration +\*---------------------------------------------------------------------------*/ + +class dummyControlDict +: + public dictionary +{ + +public: + + TypeName("dummyControlDict"); + + + // Constructors + + //- Construct, creating the bare minimum controlDict + dummyControlDict(); + + //- Construct, reading the multiControlDict data from a file + explicit dummyControlDict(const fileName&); + + //- Construct given the multiControlDict dictionary + explicit dummyControlDict(const dictionary&); + + + // Destructor + virtual ~dummyControlDict(); + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif diff --git a/src/multiSolver/include/createMultiSolver.H b/src/multiSolver/include/createMultiSolver.H new file mode 100644 index 000000000..f7772375b --- /dev/null +++ b/src/multiSolver/include/createMultiSolver.H @@ -0,0 +1,12 @@ + word solverDomain; + + multiSolver multiRun + ( + multiSolver::multiControlDictName, + args.rootPath(), + args.caseName() + ); + + while (multiRun.run()) + { // While brace + { // dummy brace diff --git a/src/multiSolver/include/endMultiSolver.H b/src/multiSolver/include/endMultiSolver.H new file mode 100644 index 000000000..3ca84c21f --- /dev/null +++ b/src/multiSolver/include/endMultiSolver.H @@ -0,0 +1,3 @@ + } // previous solver domain goes out of scope + multiRun++; + } // end While loop diff --git a/src/multiSolver/include/setSolverDomain.H b/src/multiSolver/include/setSolverDomain.H new file mode 100644 index 000000000..52b2a5a33 --- /dev/null +++ b/src/multiSolver/include/setSolverDomain.H @@ -0,0 +1,10 @@ + } // previous solver domain goes out of scope + multiRun.setSolverDomain(solverDomain); + +// Clear defines that may interfere with other solver domains +#undef createPhi_H +#undef createPhiV_H +#undef initContinuityErrs_H + + if (multiRun.run()) + { // next solver domain comes into scope diff --git a/src/multiSolver/multiSolver/multiSolver.C b/src/multiSolver/multiSolver/multiSolver.C new file mode 100644 index 000000000..989a31577 --- /dev/null +++ b/src/multiSolver/multiSolver/multiSolver.C @@ -0,0 +1,1402 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "multiSolver.H" +#include "tuple2Lists.H" +#include "OFstream.H" +#include "Pstream.H" + +// * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(multiSolver, 0); +} + + +template<> +const char* Foam::NamedEnum::names[] = +{ + "firstTime", + "firstTimeInStartDomain", + "firstTimeInStartDomainInStartSuperLoop", + "startTime", + "startTimeInStartDomain", + "startTimeInStartDomainInStartSuperLoop", + "latestTime", + "latestTimeInStartDomain", + "latestTimeInStartDomainInStartSuperLoop" +}; + +const Foam::NamedEnum + Foam::multiSolver::initialStartFromControlsNames_; + + +template<> +const char* Foam::NamedEnum::names[] = +{ + "endTime", + "endTimeInEndDomain", + "endTimeInEndDomainInEndSuperLoop", + "endSuperLoop", + "writeNow", + "noWriteNow", + "nextWrite" +}; + +const Foam::NamedEnum + Foam::multiSolver::finalStopAtControlsNames_; + + +template<> +const char* Foam::NamedEnum::names[] = +{ + "firstTime", + "startTime", + "latestTimeThisDomain", + "latestTimeAllDomains" +}; + +const Foam::NamedEnum + Foam::multiSolver::startFromControlsNames_; + + +template<> +const char* Foam::NamedEnum::names[] = +{ + "endTime", + "noWriteNow", + "writeNow", + "nextWrite", + "iterations", + "solverSignal", + "elapsedTime" +}; + +const Foam::NamedEnum + Foam::multiSolver::stopAtControlsNames_; + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::word Foam::multiSolver::multiControlDictName("multiControlDict"); + + +void Foam::multiSolver::setUpParallel() +{ + if (Pstream::master()) + { + fileNameList roots(Pstream::nProcs()); + + roots[0] = multiDictRegistry_.rootPath(); + manageLocalRoot_ = true; + + // Receive from slaves + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + slave++ + ) + { + IPstream fromSlave(Pstream::blocking, slave); + roots[slave] = fileName(fromSlave); + } + + // Distribute + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + slave++ + ) + { + OPstream toSlave(Pstream::blocking, slave); + if (roots[slave] != roots[slave - 1]) + { + toSlave << true; + } + else + { + toSlave << false; + } + } + } + else + { + // Send to master + { + OPstream toMaster(Pstream::blocking, Pstream::masterNo()); + toMaster << fileName(multiDictRegistry_.rootPath()); + } + // Receive from master + { + IPstream fromMaster(Pstream::blocking, Pstream::masterNo()); + manageLocalRoot_ = readBool(fromMaster); + } + } +} + + +void Foam::multiSolver::synchronizeParallel() const +{ + if (Pstream::master()) + { + // Give go signal + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + slave++ + ) + { + OPstream toSlave(Pstream::blocking, slave); + toSlave << true; + } + } + else + { + // Recieve go signal + { + IPstream fromMaster(Pstream::blocking, Pstream::masterNo()); + bool okayToGo(readBool(fromMaster)); + } + } +} + + +Foam::word Foam::multiSolver::setLocalEndTime() +{ + word stopAtSetting("endTime"); + switch (stopAt_) + { + case msaEndTime: + // do nothing + break; + case msaNoWriteNow: + stopAtSetting = "noWriteNow"; + finished_ = true; + break; + case msaWriteNow: + stopAtSetting = "writeNow"; + finished_ = true; + break; + case msaNextWrite: + stopAtSetting = "nextWrite"; + finished_ = true; + break; + case msaIterations: + endTime_ = deltaT_ * iterations_ + startTime_; + break; + case msaSolverSignal: + endTime_ = VGREAT; + break; + case msaElapsedTime: + endTime_ = startTime_ + elapsedTime_; + break; + } + + // Modify endTime_ if it exceeds finalEndTime + switch (finalStopAt_) + { + case mfsEndTime: + if ((endTime_ + globalTimeOffset_) >= finalEndTime_) + { + endTime_ = finalEndTime_ - globalTimeOffset_; + finished_ = true; + if ((startTime_ + globalTimeOffset_) >= finalEndTime_) + { + // Initialized beyond end + stopAtSetting = "noWriteNow"; + } + } + + break; + case mfsEndTimeInEndDomain: + if + ( + (currentSolverDomain_ == endDomain_) + && (endTime_ >= finalEndTime_) + ) + { + endTime_ = finalEndTime_; + finished_ = true; + if (startTime_ >= finalEndTime_) + { + // Initialized beyond end + stopAtSetting = "noWriteNow"; + } + } + break; + case mfsEndTimeInEndDomainInEndSuperLoop: + if (currentSolverDomain_ == endDomain_) + { + if + ( + (superLoop_ >= endSuperLoop_) + && (endTime_ >= finalEndTime_) + ) + { + endTime_ = finalEndTime_; + finished_ = true; + if (startTime_ > finalEndTime_) + { + // Initialized beyond end + stopAtSetting = "noWriteNow"; + } + } + } + // Cannot check for beyond end initialization with superLoops + // because operator++ allows the superLoop to increment by more + // than 1 + break; + case mfsEndSuperLoop: + if (superLoop_ > endSuperLoop_) + { + stopAtSetting = "noWriteNow"; + finished_ = true; + } + break; + case mfsWriteNow: + finished_ = true; + stopAtSetting = "writeNow"; + break; + case mfsNoWriteNow: + finished_ = true; + stopAtSetting = "noWriteNow"; + break; + case mfsNextWrite: + stopAtSetting = "nextWrite"; + finished_ = true; + break; + } + return stopAtSetting; +} + +void Foam::multiSolver::checkTimeDirectories() const +{ + forAll(prefixes_, i) + { + if (prefixes_[i] == "default") continue; + if ((prefixes_[i] == "all") || (prefixes_[i] == "root")) + { + FatalErrorIn("multiSolver::checkTimeDirectories") + << "'all' or 'root' solverDomain name found in " + << "multiControlDict. These two names are prohibitted." + << abort(FatalError); + } + fileName checkMe + ( + multiDictRegistry_.path()/"multiSolver"/prefixes_[i]/"initial/0" + ); + if + ( + !exists(checkMe) + ) + { + FatalErrorIn("multiSolver::checkTimeDirectories") + << "Initial time directory missing for solver domain [" + << prefixes_[i] << "]. Expecting " << checkMe + << abort(FatalError); + } + } +} + + +void Foam::multiSolver::swapDictionaries(const word& solverDomainName) +{ + forAll(multiDicts_, i) + { + IOdictionary newMultiDict + ( + IOobject + ( + multiDicts_[i].lookup("dictionaryName"), + multiDicts_[i].instance(), + multiDicts_[i].local(), + multiDictRegistry_, + IOobject::NO_READ, + IOobject::AUTO_WRITE, + false + ) + ); + if (multiDicts_[i].subDict("multiSolver").found("default")) + { + newMultiDict.merge + ( + multiDicts_[i].subDict("multiSolver").subDict("default") + ); + } + + if (multiDicts_[i].subDict("multiSolver").found(solverDomainName)) + { + if (multiDicts_[i].subDict("multiSolver") + .subDict(solverDomainName).found("sameAs")) + { + word sameAsSolverDomain(multiDicts_[i].subDict("multiSolver") + .subDict(solverDomainName).lookup("sameAs")); + if (multiControlDict_.subDict("solverDomains") + .found(sameAsSolverDomain)) + { + newMultiDict.merge + ( + multiDicts_[i].subDict("multiSolver") + .subDict(sameAsSolverDomain) + ); + } + else + { + FatalIOErrorIn + ( + "multiSolver::swapDictionaries", multiDicts_[i] + ) + << "'sameAs' solverDomain name " << sameAsSolverDomain + << " not found." + << exit(FatalIOError); + } + } + else + newMultiDict.merge + ( + multiDicts_[i].subDict("multiSolver").subDict(solverDomainName) + ); + } + + newMultiDict.regIOobject::write(); + } +} + + +void Foam::multiSolver::swapBoundaryConditions +( + const fileName& dataSourcePath, + const word& intoSolverDomain +) +{ + fileName bcFilePath + ( + multiDictRegistry_.path()/"multiSolver"/intoSolverDomain/"initial/0" + ); + + fileName dataSourceInitialConditions + ( + multiDictRegistry_.path()/"multiSolver"/currentSolverDomain_ + /"initial/0" + ); + + instantList il(Time::findTimes(dataSourcePath.path())); + + fileName firstDataSourcePath + ( + dataSourcePath.path()/il[Time::findClosestTimeIndex(il,-1.0)].name() + ); + + fileNameList dirEntries + ( + readDir(dataSourcePath, fileName::FILE) + ); + + word headerClassName; + forAll(dirEntries, i) + { + // Ignore this file if it isn't in case/prefix/initial/0 + if (!exists(bcFilePath/dirEntries[i])) continue; + + IFstream bc(bcFilePath/dirEntries[i]); + IFstream data(dataSourcePath/dirEntries[i]); + + // Find the headerClassName for pseudo regIOobject::write later + while (!bc.eof()) + { + token nextToken(bc); + if (nextToken.isWord() && nextToken.wordToken() == "class") + { + break; + } + } + headerClassName = word(token(bc).wordToken()); + bc.rewind(); + + dictionary bcDict(bc); + dictionary dataDict(data); + + if + ( + !bcDict.found("dimensions") + || !bcDict.found("internalField") + || !bcDict.found("boundaryField") + || !dataDict.found("dimensions") + || !dataDict.found("internalField") + || !dataDict.found("boundaryField") + ) + { + // Data source or BC source not a proper geometricField file + continue; + } + + dimensionSet bcDims(bcDict.lookup("dimensions")); + dimensionSet dataDims(dataDict.lookup("dimensions")); + + if ((bcDims != dataDims) && dimensionSet::debug) + { + FatalErrorIn("multiSolver::swapBoundaryConditions") + << "Dimensions do not match in geometricFields with the same " + << "name. Solver domain [" << intoSolverDomain << "] has " + << bcDims << " and the previous domain has " << dataDims << "." + << abort(FatalError); + } + + dictionary outputDict(bcDict); + + outputDict.set("internalField", dataDict.lookup("internalField")); + + wordList dataPatches(dataDict.subDict("boundaryField").toc()); + wordList bcPatches(bcDict.subDict("boundaryField").toc()); + sort(dataPatches); + sort(bcPatches); + + if (dataPatches.size() != bcPatches.size()) + { + FatalErrorIn("multiSolver::swapBoundaryConditions") + << "Boundary fields do not match. Solver domain [" + << intoSolverDomain << "] has " << bcPatches.size() << " patches " + << "and the previous domain has " << dataPatches.size() << "." + << abort(FatalError); + } + + forAll(dataPatches, j) + { + if (dataPatches[j] != bcPatches[j]) + { + FatalErrorIn("multiSolver::swapBoundaryConditions") + << "Boundary fields do not match. Solver domain [" + << intoSolverDomain << "] has:" << bcPatches << " patches " + << "and the previous domain has:" << dataPatches << "." + << abort(FatalError); + } + if (exists(firstDataSourcePath/dirEntries[i])) + { + IFstream firstDataStream(firstDataSourcePath/dirEntries[i]); + dictionary firstDict(firstDataStream); + + // Check for 'multiSolverRemembering' entries, copy them from + // the earliest time (this superLoop) to the outputDict + if + ( + firstDict.subDict("boundaryField") + .subDict(bcPatches[j]).found("multiSolverRemembering") + ) + { + wordList msr + ( + firstDict.subDict("boundaryField") + .subDict(bcPatches[j]) + .lookup("multiSolverRemembering") + ); + forAll(msr, k) + { + if (!firstDict.found(msr[k])) + { + FatalIOErrorIn + ( + "multiSolver::swapBoundaryConditions", + firstDict + ) + << "'multiSolverRemember' word '" << msr[k] + << "' missing from boundary patch '" + << dataPatches[j] << "' while switching to " + << currentSolverDomain_ << ". This may be " + << "the result of manual editting datafiles " + << "or data corruption. If the problem " + << "persists, this is a bug." + << exit(FatalIOError); + } + + outputDict.subDict("boundaryField") + .subDict(bcPatches[j]).set + ( + msr[k], + firstDict.subDict("boundaryField") + .subDict(bcPatches[j]).lookup(msr[k]) + ); + } + outputDict.subDict("boundaryField") + .subDict(bcPatches[j]).set + ( + "multiSolverRemembering", + msr + ); + } + + // Check for "multiSolverRemember" fields, copy them from + // latestTime to outputDict, append their names to multiSolver- + // Remembering + if (exists(dataSourceInitialConditions/dirEntries[i])) + { + IFstream ic(dataSourceInitialConditions/dirEntries[i]); + dictionary icDict(ic); + if + ( + icDict.subDict("boundaryField") + .subDict(bcPatches[j]).found("multiSolverRemember") + ) + { + wordList remember + ( + icDict + .subDict("boundaryField") + .subDict(bcPatches[j]) + .lookup("multiSolverRemember") + ); + + forAll(remember, k) + { + if (!dataDict.found(remember[k])) + { + FatalIOErrorIn + ( + "multiSolver::swapBoundaryConditions", + dataDict + ) + << "'multiSolverRemember' wordList found, " + << "but keyword '" << remember[k] << "' not" + << "present in dictionary for " + << dirEntries[i] + << exit(FatalIOError); + } + + outputDict + .subDict("boundaryField") + .subDict(bcPatches[j]).set + ( + remember[j], + dataDict.subDict("boundaryField") + .subDict(bcPatches[j]).lookup(remember[k]) + ); + } + + wordList remembering(remember); + + if + ( + firstDict.subDict("boundaryField") + .subDict(bcPatches[j]) + .found("multiSolverRemembering") + ) + { + wordList msr + ( + firstDict.subDict("boundaryField") + .subDict(bcPatches[j]) + .lookup("multiSolverRemembering") + ); + remembering.setSize(remember.size() + msr.size()); + forAll(msr, l) + { + remembering[remember.size() + l] = msr[l]; + } + } + + outputDict + .subDict("boundaryField") + .subDict(bcPatches[j]).set + ( + "multiSolverRemembering", + remembering + ); + } + } + } // End multiSolverRemember implementation + } // end cycle through patches + + // Here we are cheating a regIOobject::write from a non regIOobject. + // This allows us to change the header as we want. * High maintenance* + OFstream os + ( + multiDictRegistry_.path()/ + multiDictRegistry_.timeName()/ + dirEntries[i] + ); + IOobject::writeBanner(os); + os << "FoamFile\n{\n" + << " version " << os.version() << ";\n" + << " format " << os.format() << ";\n" + << " class " << headerClassName << ";\n"; + + os << " object " << dirEntries[i] << ";\n" + << "}" << nl; + + IOobject::writeDivider(os); + os << endl; + outputDict.write(os); + } // end cycle through files +} + + +void Foam::multiSolver::readAllMultiDicts() +{ + fileName systemPath + ( + multiDictRegistry_.path()/multiDictRegistry_.system() + ); + fileName constantPath + ( + multiDictRegistry_.path()/multiDictRegistry_.constant() + ); + + label done(0); + while (done <= 0) + { + readMultiDictDirectory(systemPath); + readMultiDictDirectory(constantPath); + + // Sub directories under system + fileNameList dirEntries + ( + readDir(systemPath, fileName::DIRECTORY) + ); + + forAll(dirEntries, i) + { + readMultiDictDirectory + ( + systemPath/dirEntries[i], + dirEntries[i] + ); + } + + // Sub directories under constant + dirEntries = readDir + ( + constantPath, + fileName::DIRECTORY + ); + + forAll(dirEntries, i) + { + readMultiDictDirectory + ( + constantPath/dirEntries[i], + dirEntries[i] + ); + } + + // Add local root for parallel runs and repeat + if (manageLocalRoot_) + { + if (done == 0) + { + systemPath = + multiDictRegistry_.path().path() + /multiDictRegistry_.system(); + constantPath = + multiDictRegistry_.path().path() + /multiDictRegistry_.constant(); + done = -1; + } + else + { + done = 1; + } + } + else + { + done = 1; + } + } +} + + +void Foam::multiSolver::readMultiDictDirectory +( + const fileName& sourcePath, + const word& local +) +{ + fileNameList dirEntries(readDir(sourcePath, fileName::FILE)); + forAll(dirEntries, i) + { + if + ( + (dirEntries[i](5) == "multi") + && (dirEntries[i] != multiControlDictName) + && (dirEntries[i] != "multiSolverTime") + ) + { + IFstream is(sourcePath/dirEntries[i]); + dictionary candidate(is); + + if + ( + candidate.found("dictionaryName") + && candidate.found("multiSolver") + ) + { + multiDicts_.setSize(multiDicts_.size() + 1); + multiDicts_.set + ( + multiDicts_.size() - 1, + new IOdictionary + ( + IOobject + ( + dirEntries[i], + sourcePath.name(), + local, + multiDictRegistry_, + IOobject::MUST_READ, + IOobject::NO_WRITE + ) + ) + ); + } + } + } +} + + +void Foam::multiSolver::readIfModified() +{ + if (multiDictsRunTimeModifiable_) + { + multiDictRegistry_.readModifiedObjects(); + setMultiSolverControls(); + } +} + + +Foam::timeCluster Foam::multiSolver::parseConditionedFile +( + const word& pcFile, + const instant& inst +) const +{ + // solverDomain@superLoop@globalOffset@preConName +# ifdef FULLDEBUG + if (!pcFile.size()) + { + FatalErrorIn("multiSolver::parseConditionedFile") + << "Empty preConditioned fileName." + << abort(FatalError); + } +# endif + + // Find first @ + string::size_type first = pcFile.find("@"); +# ifdef FULLDEBUG + if (first == string::npos) + { + FatalErrorIn("multiSolver::parseConditionedFile") + << "Bad preConditioned fileName: " << pcFile + << abort(FatalError); + } +# endif + + // Find second @ + string::size_type second = pcFile(first + 1, pcFile.size() - first - 1) + .find("@"); +# ifdef FULLDEBUG + if (second == string::npos) + { + FatalErrorIn("multiSolver::parseConditionedFile") + << "Bad preConditioned fileName: " << pcFile + << abort(FatalError); + } +# endif + + // Find third @ + string::size_type third = pcFile + ( + first + second + 2, + pcFile.size() - first - second - 2 + ).find("@"); + +# ifdef FULLDEBUG + if + ( + third == string::npos + || pcFile.size() == first + second + third + 3 + ) + { + FatalErrorIn("multiSolver::parseConditionedFile") + << "Bad preConditioned fileName: " << pcFile + << abort(FatalError); + } +# endif + + word solverDomain + ( + pcFile(first) + ); + + IStringStream superLoopStream(pcFile(first + 1, second)); + token superLoopToken(superLoopStream); + +# ifdef FULLDEBUG + if (!superLoopToken.isLabel() || !superLoopStream.eof()) + { + FatalErrorIn("multiSolver::parseConditionedFile") + << "Bad preConditioned fileName: " << pcFile + << abort(FatalError); + } +# endif + + label superLoop + ( + superLoopToken.labelToken() + ); + + IStringStream globalOffsetStream(pcFile(first + second + 2, third)); + token globalOffsetToken(globalOffsetStream); + +# ifdef FULLDEBUG + if (!globalOffsetToken.isNumber() || !globalOffsetStream.eof()) + { + FatalErrorIn("multiSolver::parseConditionedFile") + << "Bad preConditioned fileName: " << pcFile + << abort(FatalError); + } +# endif + + scalar globalOffset + ( + globalOffsetToken.number() + ); + + word preConName + ( + pcFile + ( + first + second + third + 3, + pcFile.size() - first - second - third - 3 + ) + ); + + return timeCluster + ( + instantList(1, inst), + globalOffset, + superLoop, + solverDomain, + preConName + ); +} + + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::multiSolver::multiSolver +( + const dictionary& dict, + const fileName& rootPath, + const fileName& caseName, + const word& systemName, + const word& constantName +) +: + dcd_(dict), + + multiDictRegistry_ + ( + dcd_, + rootPath, + caseName, + systemName, + constantName + ), + + multiControlDict_ + ( + IOobject + ( + multiControlDictName, + multiDictRegistry_.system(), + multiDictRegistry_, + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ), + dict + ), +#include "multiSolverInit.H" +{ + if (Pstream::parRun()) + { + setUpParallel(); + } + readAllMultiDicts(); + checkTimeDirectories(); + setMultiSolverControls(); +} + + +Foam::multiSolver::multiSolver +( + const word& multiControlDictName, + const fileName& rootPath, + const fileName& caseName, + const word& systemName, + const word& constantName +) +: + dcd_(rootPath/caseName/systemName/multiControlDictName), + + multiDictRegistry_ + ( + dcd_, + rootPath, + caseName, + systemName, + constantName + ), + + multiControlDict_ + ( + IOobject + ( + multiControlDictName, + multiDictRegistry_.system(), + multiDictRegistry_, + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ) + ), +#include "multiSolverInit.H" +{ + if (Pstream::parRun()) + { + setUpParallel(); + } + readAllMultiDicts(); + checkTimeDirectories(); + setMultiSolverControls(); +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::multiSolver::~multiSolver() +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::multiSolver::preCondition(const word& processor) +{ + fileName path(multiDictRegistry_.path()); + if (processor.size()) + { + path = path/processor; + } + + // Remove existing time directories from root + purgeTimeDirs(path); + + //Read all data in path/multiSolver + timeClusterList tclSource + ( + readAllTimes(processor) + ); + tclSource.purgeEmpties(); + forAll(tclSource, tc) + { + forAll(tclSource[tc], inst) + { + fileName sourcePath; + fileName destPath; + + // Destination path goes to -1 for initial conditions because + // reconstructPar omits 0 + if (tclSource[tc].superLoop() == -1) + { + sourcePath = path/"multiSolver" + /tclSource[tc].solverDomainName() + /"initial/0"; + destPath = path/"-1"; + } + else + { + sourcePath = path/"multiSolver" + /tclSource[tc].solverDomainName() + /name(tclSource[tc].superLoop()) + /tclSource[tc][inst].name(); + destPath = path/tclSource[tc][inst].name(); + } + mkDir(destPath); + + fileNameList rootFiles + ( + readDir(sourcePath, fileName::FILE) + ); + forAll(rootFiles, rf) + { + cp + ( + sourcePath/rootFiles[rf], + destPath/tclSource[tc].solverDomainName() + + "@" + name(tclSource[tc].superLoop()) + + "@" + name(tclSource[tc].globalOffset()) + + "@" + rootFiles[rf] + ); + } + + fileNameList subDirs + ( + readDir(sourcePath, fileName::DIRECTORY) + ); + + forAll(subDirs, sd) + { + mkDir(destPath/subDirs[sd]); + + fileNameList subDirFiles + ( + readDir(sourcePath/subDirs[sd], fileName::FILE) + ); + forAll(subDirFiles, sdf) + { + cp + ( + sourcePath/subDirs[sd]/subDirFiles[sdf], + destPath/subDirs[sd]/tclSource[tc].solverDomainName() + + "@" + name(tclSource[tc].superLoop()) + + "@" + subDirFiles[sdf] + + "@" + name(tclSource[tc].globalOffset()) + ); + } // end forAll(subDirFiles, sdf) + } // end forAll(subDirs, sd) + } // end forAll instants + } // end forAll timeClusters + if (tclSource.size()) + { + setSolverDomainPostProcessing(tclSource[0].solverDomainName()); + } +} + + +void Foam::multiSolver::postCondition(const word& processor) +{ + fileName path(multiDictRegistry_.path()); + if (processor.size()) + { + path = path/processor; + } + + timeClusterList purgeMe(readAllTimes(processor)); + purgeMe.purgeEmpties(); + + // Purge these directories + forAll(purgeMe, i) + { + fileName purgePath + ( + findInstancePath(purgeMe[i], 0).path() + ); + rmDir(purgePath); + } + + instantList times(Time::findTimes(path)); + + forAll(times, t) + { + // Ignore "constant" if it exists + if (times[t].name() == "constant") + { + continue; + } + fileName sourcePath + ( + path/times[t].name() + ); + + // If timeFormat is not general, it will miss the -1 initial directory + if (!exists(sourcePath)) + { + if (times[t].value() == -1) + { + sourcePath = path/"-1"; + } + else + { + continue; + } + } + + // Root files first + fileNameList rootFiles + ( + readDir(sourcePath, fileName::FILE) + ); + forAll(rootFiles, rf) + { + timeCluster tcSubject + ( + parseConditionedFile(rootFiles[rf], times[t]) + ); + + fileName destPath; + if (tcSubject.superLoop() == -1) + { + destPath = path/"multiSolver" + /tcSubject.solverDomainName() + /"initial/0"; + } + else + { + destPath = path/"multiSolver" + /tcSubject.solverDomainName() + /name(tcSubject.superLoop()) + /times[t].name(); + } + mkDir(destPath); + + // Create multiSolverTime dictionary if it doesn't exist + if + ( + !exists(destPath.path()/"multiSolverTime") + && (tcSubject.superLoop() != -1) + ) + { + IOdictionary multiSolverTime + ( + IOobject + ( + "multiSolverTime", + multiDictRegistry_.constant(), + multiDictRegistry_, + IOobject::NO_READ, + IOobject::AUTO_WRITE, + false + ) + ); + multiSolverTime.set("globalOffset", tcSubject.globalOffset()); + + // Write multiSolverTime to the case/constant directory, then + // move to destination path + multiSolverTime.regIOobject::write(); + mv + ( + multiDictRegistry_.constantPath()/"multiSolverTime", + destPath.path() + ); + } + cp + ( + sourcePath/rootFiles[rf], + destPath/tcSubject.preConName() + ); + } // end forAll(rootFiles, rf) + + // Subdirectories now + fileNameList subDirs + ( + readDir(sourcePath, fileName::DIRECTORY) + ); + + forAll(subDirs, sd) + { + fileNameList subDirFiles + ( + readDir(sourcePath/subDirs[sd], fileName::FILE) + ); + forAll(subDirFiles, sdf) + { + timeCluster tcSubject + ( + parseConditionedFile(subDirFiles[sdf], times[t]) + ); + fileName destPath; + if (tcSubject.superLoop() == -1) + { + destPath = sourcePath.path()/"multiSolver" + /tcSubject.solverDomainName() + /"initial/0"/subDirs[sd]; + } + else + { + destPath = sourcePath.path()/"multiSolver" + /tcSubject.solverDomainName() + /name(tcSubject.superLoop()) + /times[t].name() + /subDirs[sd]; + } + mkDir(destPath); + cp + ( + sourcePath/subDirs[sd]/subDirFiles[sdf], + destPath/subDirs[sd]/tcSubject.preConName() + ); + } // end forAll(subDirFiles, sdf) + } // end forAll(subDirs, sd) + } // end forAll(rootDirs, rd) + + // Delete root time directories + purgeTimeDirs(path); +} + + +void Foam::multiSolver::setSolverDomain(const Foam::word& solverDomainName) +{ + if (run()) + { + if (currentSolverDomain_ == "default") + { + setInitialSolverDomain(solverDomainName); + } + else + { + setNextSolverDomain(solverDomainName); + } + } + if (Pstream::parRun()) + { + synchronizeParallel(); + } +} + + +void Foam::multiSolver::setSolverDomainPostProcessing +( + const Foam::word& solverDomainName +) +{ + if (!solverDomains_.found(solverDomainName)) + { + FatalErrorIn("multiSolver::setInitialSolverDomain") + << "Initial solverDomainName '" << solverDomainName << "' does" + << " not exist in multiSolver dictionary. Found entries are: " + << solverDomains_.toc() + << abort(FatalError); + } + + currentSolverDomain_ = solverDomainName; + + setSolverDomainControls(currentSolverDomain_); + + // startTime is set to the earliest in case/[time] + instantList il(multiDictRegistry_.times()); + label first(Time::findClosestTimeIndex(il,-1.0)); + + startTime_ = il[first].value(); + + word stopAtSetting("endTime"); + + // Build the new controlDict + IOdictionary newControlDict + ( + IOobject + ( + Time::controlDictName, + multiDictRegistry_.system(), + multiDictRegistry_, + IOobject::NO_READ, + IOobject::AUTO_WRITE, + false + ), + currentSolverDomainDict_ + ); + + // Remove multiSolver-specific values from dictionary + newControlDict.remove("startFrom"); + newControlDict.remove("startTime"); + newControlDict.remove("stopAt"); + newControlDict.remove("endTime"); + newControlDict.remove("iterations"); + newControlDict.remove("purgeWriteSuperLoops"); + newControlDict.remove("timeFormat"); + newControlDict.remove("timePrecision"); + newControlDict.remove("storeFields"); + newControlDict.remove("elapsedTime"); + + // Add values to obtain the desired behaviour + newControlDict.set("startFrom", "startTime"); + newControlDict.set("startTime", startTime_); + newControlDict.set("stopAt", stopAtSetting); + newControlDict.set("endTime", endTime_); + if (multiSolverControl_.found("timeFormat")) + { + newControlDict.set + ( + "timeFormat", + word(multiSolverControl_.lookup("timeFormat")) + ); + } + if (multiSolverControl_.found("timePrecision")) + { + newControlDict.set + ( + "timePrecision", + readScalar(multiSolverControl_.lookup("timePrecision")) + ); + } + + // Write the dictionary to the case directory + newControlDict.regIOobject::write(); + + swapDictionaries(currentSolverDomain_); +} + + +Foam::multiSolver& Foam::multiSolver::operator++() +{ + superLoop_++; + noSaveSinceSuperLoopIncrement_ = true; + return *this; +} + + +Foam::multiSolver& Foam::multiSolver::operator++(int) +{ + return operator++(); +} + + +bool Foam::multiSolver::run() const +{ + // If case/[time] are present, run must continue to next 'setSolverDomain' + // so that they are archived properly. + instantList il(Time::findTimes(multiDictRegistry_.path())); + return !(finished_ && (il.size() == 1)); +} + + +bool Foam::multiSolver::end() const +{ + // If case/[time] are present, run must continue to next 'setSolverDomain' + // so that they are archived properly. + instantList il(Time::findTimes(multiDictRegistry_.path())); + return (finished_ && (il.size() == 1)); +} + +#include "multiSolverSetControls.C" +#include "multiSolverSetInitialSolverDomain.C" +#include "multiSolverSetNextSolverDomain.C" +#include "multiSolverTimeFunctions.C" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + diff --git a/src/multiSolver/multiSolver/multiSolver.H b/src/multiSolver/multiSolver/multiSolver.H new file mode 100644 index 000000000..77e14b544 --- /dev/null +++ b/src/multiSolver/multiSolver/multiSolver.H @@ -0,0 +1,562 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::multiSolver + +Description + Manages multiple solvers within one master-solver. Allows for multiple + definitions of time. Works by changing the case directory as required by + each solver. + +SourceFiles + multiSolverI.H + multiSolver.C + multiSolverSetControls.C + multiSolverSetInitialSolverDomain.C + multiSolverSetNextSolverDomain.C + multiSolverTimeFunctions.C + +Author + David L. F. Gaden +\*---------------------------------------------------------------------------*/ + +#ifndef multiSolver_H +#define multiSolver_H + +#include "Time.H" +#include "dummyControlDict.H" +#include "timeClusterList.H" +#include "IFstream.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class multiSolver Declaration +\*---------------------------------------------------------------------------*/ + +class multiSolver +{ + + // Private data + + // A dummy controlDict, required to initialize multiDictRegistry + dummyControlDict dcd_; + + // A mini-objectRegistry for the dictionaries - done this way to allow + // run-time modification of dictionaries + Time multiDictRegistry_; + + // Main control dictionary for multiSolver + IOdictionary multiControlDict_; + + // All multiDicts contained in the case directory + PtrList multiDicts_; + + // Reference to multiSolverControl subdictionary in multiControlDict + dictionary& multiSolverControl_; + + // Reference to solverDomains subdictionary in multiControlDict + dictionary& solverDomains_; + + // Current solverDomain dictionary + dictionary currentSolverDomainDict_; + + // List of all the solver domain prefixes + wordList prefixes_; + + // True when the end condition has been met + bool finished_; + + // True when superLoop++ just happened, but the previous solverDomain + // has not yet been saved (to prevent the first solverDomain from + // saving to the *next* superLoop. + bool noSaveSinceSuperLoopIncrement_; + + // True if this is the lowest number on a local shared drive - parallel + // only. + bool manageLocalRoot_; + + + // Private member functions + + // Set manageLocalRoot_ flags on all processors (parallel only) + void setUpParallel(); + + // Ensure all processors are synchronized (parallel only) + void synchronizeParallel() const; + + // Load initial data and controls + // *** Located in multiSolverSetInitialSolverDomain.C *** + void setInitialSolverDomain(const word& solverDomainName); + + // Load data and controls of a subsequent solver domain + // *** Located in multiSolverSetNextSolverDomain.C *** + void setNextSolverDomain(const word& solverDomainName); + + // Sets controls from the multiSolverControl subdictionary in the + // multiControlDict + // *** Located in multiSolverSetControls.C *** + void setMultiSolverControls(); + + // Sets controls from the solverDomains subdictionary in the + // multiControlDict + // *** Located in multiSolverSetControls.C *** + void setSolverDomainControls(const word& solverDomainName); + + // Use stopAt and finalStopAt settings to determine the endTime for + // the current solverDomain. Returns the controlDict's stopAt word, + // which may differ from that in multiControlDict. Sets finished_ to + // true if the end condition will be met. + word setLocalEndTime(); + + // Looks for case/multiSolver/solverDomain/initial/0. Fail if missing. + void checkTimeDirectories() const; + + // Change all catalogued multiDicts to another solverDomain + void swapDictionaries(const word& solverDomainName); + + // When setting up for a different solverDomain, the boundary + // conditions are allowed to change. This function copies all valid + // case/intoSolverDomain/inital/0 files, and overwrites the + // internalField with those found in the corresponding file in + // dataSourcePath. The result is placed in case/[time]. + void swapBoundaryConditions + ( + const fileName& dataSourcePath, + const word& intoSolverDomain + ); + + // Read multiDict files into the multiDictRegistry. Loads: + // - case/system/multi* + // - case/system/[local]/multi*, where [local] is anything + // - case/constant/multi* + // - case/constant/[local]/multi* + void readAllMultiDicts(); + + // Scan a directory for multi*; read them into the multiDictRegistry + void readMultiDictDirectory + ( + const fileName& sourcePath, + const word& local = word::null + ); + + // Rereads modified dictionaries and sets the controls + void readIfModified(); + + // Converts a fileName with the naming convention: + // solverDomain@superLoop@globalOffset@fileName + // to a timeCluster + timeCluster parseConditionedFile + ( + const word& pcFile, + const instant& inst + ) const; + + +public: + + // multiSolverControl enumerations + + //- Read initial data control options + enum initialStartFromControls + { + misFirstTime, + misFirstTimeInStartDomain, + misFirstTimeInStartDomainInStartSuperLoop, + misStartTime, + misStartTimeInStartDomain, + misStartTimeInStartDomainInStartSuperLoop, + misLatestTime, + misLatestTimeInStartDomain, + misLatestTimeInStartDomainInStartSuperLoop + }; + + //- Final stop at control options + enum finalStopAtControls + { + mfsEndTime, + mfsEndTimeInEndDomain, + mfsEndTimeInEndDomainInEndSuperLoop, + mfsEndSuperLoop, + mfsWriteNow, + mfsNoWriteNow, + mfsNextWrite + }; + + // solverDomains enumerations + + //- Time value start from control options + enum startFromControls + { + mtsFirstTime, + mtsStartTime, + mtsLatestTimeThisDomain, + mtsLatestTimeAllDomains + }; + + //- Stop at control options + enum stopAtControls + { + msaEndTime, + msaNoWriteNow, + msaWriteNow, + msaNextWrite, + msaIterations, + msaSolverSignal, + msaElapsedTime + }; + +protected: + + // multiSolverControl data + + label superLoop_; + + word currentSolverDomain_; + + static const NamedEnum + initialStartFromControlsNames_; + initialStartFromControls initialStartFrom_; + + scalar initialStartTime_; + + word startDomain_; + + label startSuperLoop_; + + static const NamedEnum + finalStopAtControlsNames_; + finalStopAtControls finalStopAt_; + + word endDomain_; + + scalar finalEndTime_; + + label endSuperLoop_; + + bool multiDictsRunTimeModifiable_; + + scalar globalTimeOffset_; + + + // solverDomains data + // This data is transient, changing between solver domains + + static const NamedEnum + startFromControlsNames_; + startFromControls startFrom_; + + scalar startTime_; + + static const NamedEnum stopAtControlsNames_; + stopAtControls stopAt_; + + scalar endTime_; + + label purgeWriteSuperLoops_; + + scalar deltaT_; + + label iterations_; + + scalar elapsedTime_; + + wordList storeFields_; + +public: + + TypeName("multiSolver"); + + //- The default multiSolver dictionary name + static word multiControlDictName; + +/* Not implemented yet + //- Indicates whether the 'solverSignal' option for the finalStopAt setting + // in the multiControlDict is permitted. Default false. Set this to true + // in the global space of a solver that does support solverSignal. + static bool supportsSolverSignal; +*/ + + // Constructors + + //- Construct given the multiControlDict + multiSolver + ( + const dictionary& dict, + const fileName& rootPath, + const fileName& caseName, + const word& systemName = "system", + const word& constantName = "constant" + ); + + //- Construct reading the multiControlDict from file + multiSolver + ( + const word& multiControlDictName, + const fileName& rootPath, + const fileName& caseName, + const word& systemName = "system", + const word& constantName = "constant" + ); + + + // Destructor + virtual ~multiSolver(); + + + // Member functions + + // Access + + // Database + + inline const Time& multiDictRegistry() const; + + inline const IOdictionary multiControlDict() const; + + + // multiSolverControl data + + inline const label& superLoop() const; + + inline const word& currentSolverDomain() const; + + inline const initialStartFromControls& initialStartFrom() const; + + inline const word& startDomain() const; + + inline const scalar& initialStartTime() const; + + inline const finalStopAtControls& finalStopAt() const; + + inline const word& endDomain() const; + + inline const scalar& finalEndTime() const; + + inline const label& startSuperLoop() const; + + inline const label& endSuperLoop() const; + + inline const bool& multiDictsRunTimeModifiable() const; + + inline const scalar& globalTimeOffset() const; + + // Write permission + inline scalar& globalTimeOffset(); + + // solverDomains data + inline const startFromControls& startFrom() const; + + inline const stopAtControls& stopAt() const; + + inline const scalar& startTime() const; + + inline const scalar& endTime() const; + + inline const label& iterations() const; + + inline const scalar& elapsedTime() const; + + inline const wordList& storeFields() const; + + inline const label& purgeWriteSuperLoops() const; + + inline const scalar& deltaT() const; + + + // Solver (and pre/post-processor) interface functions + + // Pre-condition the directory for decomposePar or reconstructPar + void preCondition(const word& processor = word::null); + + // Post-condition the directory after decomposePar or + // reconstructPar + void postCondition(const word& processor = word::null); + + // Switch to another solver domain + void setSolverDomain(const word& solverDomainName); + + // Switch to another solver domain for post-processing only + void setSolverDomainPostProcessing(const word& solverDomainName); + + // Stop the run at the next setSolverDomain + inline void setFinished(); + + // Increment the superLoop (prefix) + multiSolver& operator++(); + + // Increment the superLoop (postfix) + multiSolver& operator++(int); + + + // Check + + //- Return true if run should continue + bool run() const; + + //- Return true if end of run + bool end() const; + + + // Time functions + // The multiSolver time directory structure should have the form: + // case + // '-multiSolver + // |-prefix1 {solverDomain} + // | |-initial {initial directory, superLoop -1} + // | |-0 {superLoop} + // | |-1 {superLoop} + // | | '-multiSolverTime {auto-generated dictionary} + // | '-2, etc.. + // |-prefix2, etc.. + // + // *** All time functions are located in *** + // *** multiSolverTimeFunctions.C *** + + // Create a list of all superLoops in a directory, (usually in + // case/prefix). Only looks for integer directory names, does not + // check for valid time subdirectories. + static labelList findSuperLoops(const fileName& path); + + // Find the closest global time to a given value in a + // timeClusterList. Assumes timeClusters do not overlap global time + // values (as they shouldn't). If exact is true, this function + // throws a FatalError when no exact match is found. + static timeCluster findClosestGlobalTime + ( + const scalar value, + const timeClusterList& tcl, + const bool& exact = false + ); + + // Find the closest local time to a given value in a + // timeClusterList. Unlike global times, local times can overlap. + // If overlaps exist, it uses only the latest superloop. If exact + // is true, this function throws a FatalError when no exact match + // is found. + static timeCluster findClosestLocalTime + ( + const scalar value, + const timeClusterList& tcl, + const bool& exact = false + ); + + // Find the latest global time + static timeCluster findLatestGlobalTime + ( + const timeClusterList& tcl + ); + + // Find the latest global time + static timeCluster findLatestLocalTime + ( + const timeClusterList& tcl + ); + + // Find the path to a specific entry in a time cluster + fileName findInstancePath + ( + const timeCluster& tc, + const label& index + ) const; + + // Find the largest superLoop + static label findMaxSuperLoopValue(const timeClusterList& tcl); + + // Find the timeClusterList index for the timeClusterList that has + // the largest superLoop + static labelList findMaxSuperLoopIndices(const timeClusterList& tcl); + + // Checks if any of the time ranges overlap one another in a + // timeClusterList. (If startTime = previous end, this is okay.) + // True means they do not overlap. + static bool nonOverlapping + ( + const timeClusterList& tcl, + const bool useGlobalTime = false + ); + + // Maps the time directories in a single superLoop directory + // Include a processor name, and it uses the processorN directory + timeCluster readSuperLoopTimes + ( + const word& solverDomain, + const label superLoop, + const word& processor = word::null + ) const; + + // Maps the time directories in a single solverDomain + // Include a processor name, and it uses the processorN directory + timeClusterList readSolverDomainTimes + ( + const word& solverDomain, + const word processor = word::null + ) const; + + // Create a snapshot of all the multiSolver time directories + // Give it a processor name, and it searches instead in the + // processor directory + timeClusterList readAllTimes + ( + const word processor = word::null + ) const; + + // Move or copy all output time directories that are catalogued by + // a timeClusterList to case/[timeValue] format. Returns false if + // time values overlap when forced to useGlobalTime. + // loadStoreFields will copy storeFields into every time folder + // even though they do not change. + bool loadTimeClusterList + ( + const timeClusterList& tcl, + const bool useGlobalTime = true, + const bool loadStoreFields = true + ) const; + + // Move all the time directories from sourcePath to archivePath + static void archiveTimeDirs + ( + const fileName& sourcePath, + const fileName& archivePath, + const label& purgeWrite + ); + + // Delete all time directories in path, do not delete "constant" + static void purgeTimeDirs(const fileName& path); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "multiSolverI.H" + +#endif diff --git a/src/multiSolver/multiSolver/multiSolverI.H b/src/multiSolver/multiSolver/multiSolverI.H new file mode 100644 index 000000000..9d515ed70 --- /dev/null +++ b/src/multiSolver/multiSolver/multiSolverI.H @@ -0,0 +1,182 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +inline const Time& multiSolver::multiDictRegistry() const +{ + return multiDictRegistry_; +} + + +inline const IOdictionary multiSolver::multiControlDict() const +{ + return multiControlDict_; +} + + +inline const label& multiSolver::superLoop() const +{ + return superLoop_; +} + + +inline const word& multiSolver::currentSolverDomain() const +{ + return currentSolverDomain_; +} + + +inline const multiSolver::initialStartFromControls& multiSolver::initialStartFrom() const +{ + return initialStartFrom_; +} + + +inline const word& multiSolver::startDomain() const +{ + return startDomain_; +} + + +inline const scalar& multiSolver::initialStartTime() const +{ + return initialStartTime_; +} + + +inline const multiSolver::finalStopAtControls& multiSolver::finalStopAt() const +{ + return finalStopAt_; +} + + +inline const word& multiSolver::endDomain() const +{ + return endDomain_; +} + + +inline const scalar& multiSolver::finalEndTime() const +{ + return finalEndTime_; +} + + +inline const label& multiSolver::startSuperLoop() const +{ + return startSuperLoop_; +} + + +inline const label& multiSolver::endSuperLoop() const +{ + return endSuperLoop_; +} + + +inline const bool& multiSolver::multiDictsRunTimeModifiable() const +{ + return multiDictsRunTimeModifiable_; +} + + +inline const scalar& multiSolver::globalTimeOffset() const +{ + return globalTimeOffset_; +} + + +inline scalar& multiSolver::globalTimeOffset() +{ + return globalTimeOffset_; +} + + +inline const multiSolver::startFromControls& multiSolver::startFrom() const +{ + return startFrom_; +} + +inline const multiSolver::stopAtControls& multiSolver::stopAt() const +{ + return stopAt_; +} + + +inline const scalar& multiSolver::startTime() const +{ + return startTime_; +} + +inline const scalar& multiSolver::endTime() const +{ + return endTime_; +} + + +inline const label& multiSolver::iterations() const +{ + return iterations_; +} + + +inline const scalar& multiSolver::elapsedTime() const +{ + return elapsedTime_; +} + + +inline const wordList& multiSolver::storeFields() const +{ + return storeFields_; +} + + +inline const label& multiSolver::purgeWriteSuperLoops() const +{ + return purgeWriteSuperLoops_; +} + + +inline const scalar& multiSolver::deltaT() const +{ + return deltaT_; +} + + +void Foam::multiSolver::setFinished() +{ + finished_ = true; +} + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/multiSolver/multiSolver/multiSolverInit.H b/src/multiSolver/multiSolver/multiSolverInit.H new file mode 100644 index 000000000..5a08332b0 --- /dev/null +++ b/src/multiSolver/multiSolver/multiSolverInit.H @@ -0,0 +1,39 @@ +// Common elements in the constructor initialization list for multiSolver + + multiDicts_(NULL), + + multiSolverControl_(multiControlDict_.subDict("multiSolverControl")), + solverDomains_(multiControlDict_.subDict("solverDomains")), + currentSolverDomainDict_(), + prefixes_(solverDomains_.toc()), + finished_(false), + noSaveSinceSuperLoopIncrement_(false), + manageLocalRoot_(false), + + superLoop_(0), + currentSolverDomain_("default"), + + initialStartFrom_(misLatestTime), +// startDomain_, + initialStartTime_(0), + startSuperLoop_(0), + finalStopAt_(mfsEndTime), +// endDomain_, + finalEndTime_(0), + + endSuperLoop_(0), + + multiDictsRunTimeModifiable_(true), + + globalTimeOffset_(0), + + purgeWriteSuperLoops_(prefixes_.size()), + +// timeValueStartFrom_, +// scalar startTime_, +// stopAtControls stopAt_, +// scalar endTime_, +// label endIterations_ + + storeFields_(0) + diff --git a/src/multiSolver/multiSolver/multiSolverSetControls.C b/src/multiSolver/multiSolver/multiSolverSetControls.C new file mode 100644 index 000000000..0a8d557f3 --- /dev/null +++ b/src/multiSolver/multiSolver/multiSolverSetControls.C @@ -0,0 +1,359 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + + +void Foam::multiSolver::setMultiSolverControls() +{ + initialStartFrom_ = misLatestTime; + if (multiSolverControl_.found("initialStartFrom")) + { + initialStartFrom_ = initialStartFromControlsNames_.read + ( + multiSolverControl_.lookup("initialStartFrom") + ); + } + + if (multiSolverControl_.found("startTime")) + { + initialStartTime_ = readScalar(multiSolverControl_.lookup("startTime")); + if (initialStartTime_ < 0) + { + FatalErrorIn("multiSolver::setMultiSolverControls") + << "'startTime' in multiControlDict/multiSolverControl cannot " + << "be negative." + << abort(FatalError); + } + } + else if + ( + (initialStartFrom_ == misStartTime) + || (initialStartFrom_ == misStartTimeInStartDomain) + || (initialStartFrom_ == misStartTimeInStartDomainInStartSuperLoop) + ) + { + FatalIOErrorIn + ( + "multiSolver::setMultiSolverControls", multiSolverControl_ + ) + << "'startTime' is required in multiControlDict/multiSolverControl " + << "if 'initialStartFrom' is set to 'startTime', " + << "'startTimeInStartDomain', or " + << "'startTimeInStartDomainInStartStuperLoop'" + << exit(FatalIOError); + } + + if (multiSolverControl_.found("startDomain")) + { + startDomain_ = word(multiSolverControl_.lookup("startDomain")); + } + else if + ( + (initialStartFrom_ == misFirstTimeInStartDomain) + || (initialStartFrom_ == misFirstTimeInStartDomainInStartSuperLoop) + || (initialStartFrom_ == misStartTimeInStartDomain) + || (initialStartFrom_ == misStartTimeInStartDomainInStartSuperLoop) + || (initialStartFrom_ == misLatestTimeInStartDomain) + || (initialStartFrom_ == misLatestTimeInStartDomainInStartSuperLoop) + ) + { + FatalIOErrorIn("multiSolver::setMultiSolverControls", multiSolverControl_) + << "'startDomain' is required in " + << "multiControlDict/multiSolverControl if 'initialStartFrom' is " + << "set to 'firstTimeInStartDomain', " + << "'firstTimeInStartDomainInStartSuperLoop', " + << "'startTimeInStartDomain', " + << "'startTimeInStartDomainInStartSuperLoop', " + << "'latestTimeInStartDomain', or " + << "'latestTimeInStartDomainInStartSuperLoop'." + << abort(FatalError); + } + + finalStopAt_ = mfsEndTime; + if (multiSolverControl_.found("finalStopAt")) + { + finalStopAt_ = finalStopAtControlsNames_.read + ( + multiSolverControl_.lookup("finalStopAt") + ); + } + + if (multiSolverControl_.found("endDomain")) + { + endDomain_ = word(multiSolverControl_.lookup("endDomain")); + } + else if + ( + (finalStopAt_ == mfsEndTimeInEndDomain) + || (finalStopAt_ == mfsEndTimeInEndDomainInEndSuperLoop) + ) + { + FatalErrorIn("multiSolver::setMultiSolverControls") + << "endTime is required in multiControlDict/multiSolverControl if " + << "finalStopAt is set to 'endTimeInEndDomain', or " + << "'endTimeInEndDomainInEndSuperLoop'." + << abort(FatalError); + } + + if (multiSolverControl_.found("endTime")) + { + finalEndTime_ = + readScalar(multiSolverControl_.lookup("endTime")); + } + else if + ( + (finalStopAt_ == mfsEndTime) + || (finalStopAt_ == mfsEndTimeInEndDomain) + || (finalStopAt_ == mfsEndTimeInEndDomainInEndSuperLoop) + ) + { + FatalErrorIn("multiSolver::setMultiSolverControls") + << "'endTime' is required in " + << "multiControlDict/multiSolverControl if 'finalStopAt' is set to " + << "'endTime', 'endTimeInEndDomain', or " + << "'endTimeInEndDomainInEndSuperLoop'." + << abort(FatalError); + } + + if (multiSolverControl_.found("startSuperLoop")) + { + startSuperLoop_ = + readLabel(multiSolverControl_.lookup("startSuperLoop")); + } + else if + ( + (initialStartFrom_ == misFirstTimeInStartDomainInStartSuperLoop) + || (initialStartFrom_ == misStartTimeInStartDomainInStartSuperLoop) + || (initialStartFrom_ == misLatestTimeInStartDomainInStartSuperLoop) + ) + { + FatalErrorIn("multiSolver::setMultiSolverControls") + << "'startSuperLoop' is required in " + << "multiControlDict/multiSolverControl if 'initialStartFrom' is " + << "set to 'firstTimeInStartDomainInSuperLoop', " + << "'startTimeInStartDomainInStartSuperLoop', or " + << "'latestTimeInStartDomainInStartSuperLoop'." + << abort(FatalError); + } + + if (multiSolverControl_.found("endSuperLoop")) + { + endSuperLoop_ = + readLabel(multiSolverControl_.lookup("endSuperLoop")); + } + else if + ( + (finalStopAt_ == mfsEndSuperLoop) + || (finalStopAt_ == mfsEndTimeInEndDomainInEndSuperLoop) + ) + { + FatalErrorIn("multiSolver::setMultiSolverControls") + << "'endSuperLoops' is required in " + << "multiControlDict/multiSolverControl if 'finalStopAt' is set to " + << "'endSuperLoop' or 'endTimeInEndDomainInEndSuperLoop'." + << abort(FatalError); + } + + multiDictsRunTimeModifiable_ = true; + if (multiSolverControl_.found("multiDictsRunTimeModifiable")) + { + multiDictsRunTimeModifiable_ = + multiSolverControl_.lookup("multiDictsRunTimeModifiable"); + } + + prefixes_.clear(); + prefixes_ = solverDomains_.toc(); + if + ( + (prefixes_.size() == 0) + || ((prefixes_.size() == 1) && (prefixes_[0] == "default")) + ) + { + FatalErrorIn("multiSolver::setMultiSolverControls") + << "No solver domains found in multiControlDict. Expecting " + << "subdictionary solverDomains to contain at least one entry " + << "other than 'default'." + << abort(FatalError); + } + + dictionary solverDomainsDefault + ( + solverDomains_.found("default") + ? solverDomains_.subDict("default") + : dictionary() + ); +} + + +void Foam::multiSolver::setSolverDomainControls(const word& solverDomainName) +{ + currentSolverDomainDict_.clear(); + if (solverDomains_.found("default")) + { + currentSolverDomainDict_.merge(solverDomains_.subDict("default")); + } + currentSolverDomainDict_.merge(solverDomains_.subDict(solverDomainName)); + + startFrom_ = mtsLatestTimeAllDomains; + if (currentSolverDomainDict_.found("startFrom")) + { + startFrom_ = startFromControlsNames_.read + ( + currentSolverDomainDict_.lookup("startFrom") + ); + } + + if (currentSolverDomainDict_.found("startTime")) + { + startTime_ = readScalar(currentSolverDomainDict_.lookup("startTime")); + if (startTime_ < 0) + { + FatalErrorIn("multiSolver::setSolverDomainControls") + << "'startTime' in multiControlDict/solverDomains/" + << solverDomainName << " cannot be negative." + << abort(FatalError); + } + } + else if (startFrom_ == mtsStartTime) + { + FatalErrorIn("multiSolver::setSolverDomainControls") + << "'startTime' not defined in solverDomain '" << solverDomainName + << "' or 'default'. startTime is required when startFrom " + << "is set to 'startTime'." + << abort(FatalError); + } + + stopAt_ = msaEndTime; + if (currentSolverDomainDict_.found("stopAt")) + { + stopAt_ = stopAtControlsNames_.read + ( + currentSolverDomainDict_.lookup("stopAt") + ); + if + ( + (stopAt_ == msaIterations) + && (currentSolverDomainDict_.found("adjustTimeStep")) + && ( + readBool(currentSolverDomainDict_.lookup + ("adjustTimeStep")) == true + ) + ) + { + FatalErrorIn("multiSolver::setSolverDomainControls") + << "'stopAt' in multiControlDict/sovlerDomains cannot be set " + << "to 'iterations' when 'adjustTimeStep' is 'true'." + << abort(FatalError); + } + } + + endTime_ = 0; + if (currentSolverDomainDict_.found("endTime")) + { + endTime_ = readScalar(currentSolverDomainDict_.lookup("endTime")); + } + + if (currentSolverDomainDict_.found("iterations")) + { + iterations_ = readLabel + ( + currentSolverDomainDict_.lookup("iterations") + ); + } + else if (stopAt_ == msaIterations) + { + FatalErrorIn("multiSolver::setSolverDomainControls") + << "'iterations' not defined in solverDomain '" + << solverDomainName << "' or 'default'. iterations is required " + << "when stopAt is set to iterations." + << abort(FatalError); + } + + if (currentSolverDomainDict_.found("elapsedTime")) + { + elapsedTime_ = readScalar(currentSolverDomainDict_.lookup("elapsedTime")); + } + else if (stopAt_ == msaElapsedTime) + { + FatalErrorIn("multiSolver::setSolverDomainControls") + << "'elapsedTime' not defined in solverDomain '" + << solverDomainName << "' or 'default'. elapsedTime is required " + << "when stopAt is set to elapsedTime." + << abort(FatalError); + } + + if (currentSolverDomainDict_.found("storeFields")) + { + storeFields_ = wordList + ( + currentSolverDomainDict_.lookup("storeFields") + ); + } + + purgeWriteSuperLoops_ = 0; + if (currentSolverDomainDict_.found("purgeWriteSuperLoops")) + { + purgeWriteSuperLoops_ = readLabel + ( + currentSolverDomainDict_.lookup("purgeWriteSuperLoops") + ); + } + + if (currentSolverDomainDict_.found("deltaT")) + { + deltaT_ = readScalar + ( + currentSolverDomainDict_.lookup("deltaT") + ); + } + else + { + FatalErrorIn("multiSolver::setSolverDomainControls") + << "'deltaT' not defined in solverDomain '" + << solverDomainName << "' or 'default'. deltaT is required." + << abort(FatalError); + } + + if + ( + currentSolverDomainDict_.found("timeFormat") + || currentSolverDomainDict_.found("timePrecision") + ) + { + WarningIn("multiSolver::setSolverDomainControls") + << "Dictionary entry 'timeFormat' or 'timePrecision' found in " + << "multiControlDict/solverDomain subdictionaries and will be " + << "ignored. This setting must be applied universally in " + << "multiControlDict/multiSolverControl." + << endl; + } +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + diff --git a/src/multiSolver/multiSolver/multiSolverSetInitialSolverDomain.C b/src/multiSolver/multiSolver/multiSolverSetInitialSolverDomain.C new file mode 100644 index 000000000..0e815c5d9 --- /dev/null +++ b/src/multiSolver/multiSolver/multiSolverSetInitialSolverDomain.C @@ -0,0 +1,265 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + + +void Foam::multiSolver::setInitialSolverDomain(const word& solverDomainName) +{ + + if (!solverDomains_.found(solverDomainName)) + { + FatalErrorIn("multiSolver::setInitialSolverDomain") + << "Initial solverDomainName '" << solverDomainName << "' does" + << " not exist in multiSolver dictionary. Found entries are: " + << solverDomains_.toc() + << abort(FatalError); + } + + currentSolverDomain_ = solverDomainName; + + setSolverDomainControls(currentSolverDomain_); + + // Purge all time directories from case directory root + purgeTimeDirs(multiDictRegistry_.path()); + + // Read initial settings and determine data source (from which path the + // initial data is copied, the starting superLoop_, and the current + // globalTime (used to determine globalOffset). Rules that are applied: + // + // 1. superLoop_ = data source superLoop + // a. unless data source solverDomain != currentSolverDomain_, in + // which case, superLoop_ = data source superLoop + 1 + // 2. globalTime = data source globalTime. globalTime does not increment + // when swapping solver domains. + // 3. startTime = data source local time + // a. unless data source solverDomain != currentSolverDomain_, in + // which case, startTime is dictated by the solverDomains + // subdictionary. + // 4. endTime is determined by the solverDomains subdictionary + // a. unless the finalStopAt trumps it + timeCluster tcSource; + switch (initialStartFrom_) + { + case misFirstTime: + tcSource = findClosestGlobalTime + ( + 0, readSuperLoopTimes(currentSolverDomain_, -1) + ); + break; + case misFirstTimeInStartDomain: + tcSource = findClosestGlobalTime + ( + 0, readSuperLoopTimes(startDomain_, -1) + ); + break; + case misFirstTimeInStartDomainInStartSuperLoop: + tcSource = findClosestGlobalTime + ( + 0, readSuperLoopTimes(startDomain_, startSuperLoop_) + ); + break; + case misStartTime: + if (initialStartTime_ == 0) + { + tcSource = findClosestGlobalTime + ( + initialStartTime_, + readSuperLoopTimes(currentSolverDomain_, -1) + ); + } + else + { + tcSource = findClosestGlobalTime + ( + initialStartTime_, readAllTimes() + ); + } + break; + case misStartTimeInStartDomain: + tcSource = findClosestLocalTime + ( + initialStartTime_, readSolverDomainTimes(startDomain_) + ); + break; + case misStartTimeInStartDomainInStartSuperLoop: + tcSource = findClosestLocalTime + ( + initialStartTime_, + readSuperLoopTimes(startDomain_, startSuperLoop_) + ); + break; + case misLatestTime: + tcSource = findLatestGlobalTime(readAllTimes()); + break; + case misLatestTimeInStartDomain: + tcSource = findLatestLocalTime(readSolverDomainTimes(startDomain_)); + break; + case misLatestTimeInStartDomainInStartSuperLoop: + tcSource = findLatestLocalTime + ( + readSuperLoopTimes(startDomain_, startSuperLoop_) + ); + break; + } + + if (!tcSource.times().size()) + { + // No relevant data found, set to initial conditions + tcSource = timeCluster + ( + Time::findTimes + ( + multiDictRegistry_.path()/"multiSolver"/currentSolverDomain_ + /"initial" + ), + 0, + -1, // superLoop of -1 signifies "initial" directory + currentSolverDomain_ + ); + } + + fileName sourcePath(findInstancePath(tcSource, 0)); + superLoop_ = tcSource.superLoop(); + // If starting from initial conditions, superLoop_ = -1 + if (superLoop_ < 0) superLoop_ = 0; + scalar globalTime(tcSource.globalValue(0)); + scalar localStartTime(tcSource.localValue(0)); + + // Now to apply the exceptions if currentSolverDomain_ != data source + // solverDomain (see long comment above). + if (sourcePath.path().path().name() != currentSolverDomain_) + { + superLoop_++; + + switch (startFrom_) + { + case mtsFirstTime: + localStartTime = 0; + break; + case mtsStartTime: + localStartTime = startTime_; + break; + case mtsLatestTimeThisDomain: + { + timeCluster tcTemp + ( + findLatestLocalTime + ( + readSolverDomainTimes(currentSolverDomain_) + ) + ); + localStartTime = tcTemp.localValue(0); + } + break; + case mtsLatestTimeAllDomains: + localStartTime = globalTime; + break; + } + } + + startTime_ = localStartTime; + + globalTimeOffset_ = globalTime - startTime_; + + // Give multiDictRegistry a time value (required for regIOobject::write() + // to case/[timeValue] + multiDictRegistry_.setTime(startTime_, 0); + + // Copy the source data to case/[localTime] + cp(sourcePath, multiDictRegistry_.path()); + mv + ( + multiDictRegistry_.path()/sourcePath.name(), + multiDictRegistry_.path()/Time::timeName(startTime_) + ); + + // If the source data was in a different domain, swap the boundary conditions + if (sourcePath.path().path().name() != currentSolverDomain_) + { + swapBoundaryConditions + ( + multiDictRegistry_.path()/Time::timeName(startTime_), + currentSolverDomain_ + ); + } + + // Determine localEndTime and stopAtSetting + word stopAtSetting(setLocalEndTime()); + + // Build the new controlDict + IOdictionary newControlDict + ( + IOobject + ( + Time::controlDictName, + multiDictRegistry_.system(), + multiDictRegistry_, + IOobject::NO_READ, + IOobject::AUTO_WRITE, + false + ), + currentSolverDomainDict_ + ); + + // Remove multiSolver-specific values from dictionary + newControlDict.remove("startFrom"); + newControlDict.remove("startTime"); + newControlDict.remove("stopAt"); + newControlDict.remove("endTime"); + newControlDict.remove("iterations"); + newControlDict.remove("purgeWriteSuperLoops"); + newControlDict.remove("timeFormat"); + newControlDict.remove("timePrecision"); + newControlDict.remove("storeFields"); + newControlDict.remove("elapsedTime"); + + // Add values to obtain the desired behaviour + newControlDict.set("startFrom", "startTime"); + newControlDict.set("startTime", startTime_); + newControlDict.set("stopAt", stopAtSetting); + newControlDict.set("endTime", endTime_); + if (multiSolverControl_.found("timeFormat")) + { + newControlDict.set + ( + "timeFormat", + word(multiSolverControl_.lookup("timeFormat")) + ); + } + if (multiSolverControl_.found("timePrecision")) + { + newControlDict.set + ( + "timePrecision", + readScalar(multiSolverControl_.lookup("timePrecision")) + ); + } + + // Write the dictionary to the case directory + newControlDict.regIOobject::write(); + + swapDictionaries(currentSolverDomain_); +} + diff --git a/src/multiSolver/multiSolver/multiSolverSetNextSolverDomain.C b/src/multiSolver/multiSolver/multiSolverSetNextSolverDomain.C new file mode 100644 index 000000000..562e07af0 --- /dev/null +++ b/src/multiSolver/multiSolver/multiSolverSetNextSolverDomain.C @@ -0,0 +1,277 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + + +void Foam::multiSolver::setNextSolverDomain(const word& solverDomainName) +{ + if (!solverDomains_.found(solverDomainName)) + { + FatalErrorIn("multiSolver::setNextSolverDomain") + << "Next solverDomainName '" << solverDomainName << "' does" + << " not exist in multiSolver dictionary. Found entries are: " + << solverDomains_.toc() + << abort(FatalError); + } + + readIfModified(); + + // Check if superLoop was just incremented to prevent saving the initial + // solverDomain data to the *next* superLoop + label saveToSuperLoop(superLoop_); + if (noSaveSinceSuperLoopIncrement_) + { + saveToSuperLoop--; + } + + // Create archive path + fileName archivePath + ( + multiDictRegistry_.path()/"multiSolver"/currentSolverDomain_/name + ( + saveToSuperLoop + ) + ); + + // Move all case/[time] to case/multiSolver/prefix/superloop/time + archiveTimeDirs + ( + multiDictRegistry_.path(), + archivePath, + purgeWriteSuperLoops_ + ); + + // Create multiSolverTime dictionary + IOdictionary multiSolverTime + ( + IOobject + ( + "multiSolverTime", + multiDictRegistry_.constant(), + multiDictRegistry_, + IOobject::NO_READ, + IOobject::AUTO_WRITE, + false + ) + ); + multiSolverTime.set("globalOffset", globalTimeOffset_); + + // Write multiSolverTime to the case/constant directory, then move to + // archivePath + multiSolverTime.regIOobject::write(); + mv(multiDictRegistry_.constantPath()/"multiSolverTime", archivePath); + + // tcSource is where the latest data has been moved to + timeCluster tcSource + ( + findLatestLocalTime + ( + readSuperLoopTimes(currentSolverDomain_, saveToSuperLoop) + ) + ); + + // Copy previous solverDomain data for use later (needed for storeFields) + wordList previousStoreFields(storeFields_); + word previousSolverDomain = currentSolverDomain_; + + // Change all solverDomain data to the new solverDomain + currentSolverDomain_ = solverDomainName; + setSolverDomainControls(currentSolverDomain_); + + fileName sourcePath(findInstancePath(tcSource, 0)); + scalar globalTime(tcSource.globalValue(0)); + scalar localStartTime(0); + + switch (startFrom_) + { + case mtsFirstTime: + localStartTime = 0; + break; + case mtsStartTime: + localStartTime = startTime_; + break; + case mtsLatestTimeThisDomain: + { + timeCluster tcTemp + ( + findLatestLocalTime + ( + readSolverDomainTimes(currentSolverDomain_) + ) + ); + localStartTime = tcTemp.localValue(0); + } + break; + case mtsLatestTimeAllDomains: + localStartTime = globalTime; + break; + } + + startTime_ = localStartTime; + globalTimeOffset_ = globalTime - startTime_; + + // Give multiDictRegistry a time value (required for regIOobject::write() + // to case/[timeValue] + multiDictRegistry_.setTime(startTime_, 0); + + word stopAtSetting("endTime"); + + if (!finished_) + { + // Copy the source data to case/[localTime] + cp(sourcePath, multiDictRegistry_.path()); + mv + ( + multiDictRegistry_.path()/sourcePath.name(), + multiDictRegistry_.path()/Time::timeName(startTime_) + ); + + // Copy the previous domain's storeFields from its first timestep to + // current time directory + if (previousStoreFields.size()) + { + fileName storedSourcePath + ( + findInstancePath + ( + findClosestLocalTime + ( + 0, + readSuperLoopTimes + ( + previousSolverDomain, + saveToSuperLoop + ) + ), + 0 + ) + ); + + forAll (previousStoreFields, i) + { + // Copy the stored fields to case/[localTime]. + if (exists(storedSourcePath/previousStoreFields[i])) + { + fileName storedSource(storedSourcePath/previousStoreFields[i]); + + cp + ( + storedSource, + multiDictRegistry_.path()/Time::timeName(startTime_) + /previousStoreFields[i] + ); + } + else + { + FatalErrorIn("multiSolver::setNextSolverDomain") + << "Attempting to copy stored field " + << previousStoreFields[i] << " from " + << previousSolverDomain << " to " + << currentSolverDomain_ << " in superLoop " + << saveToSuperLoop << ". File not found. This may occur " + << "if " << previousSolverDomain << " is the first " + << "solverDomain to be initialized, and you did not put " + << "the stored fields into its 0/0 directory." + << abort(FatalError); + } + } + } + + swapBoundaryConditions + ( + multiDictRegistry_.path()/Time::timeName(startTime_), + currentSolverDomain_ + ); + + // Determine localEndTime and stopAtSetting + stopAtSetting = setLocalEndTime(); + } + else //finished_ + { + stopAtSetting = "noWriteNow"; + } + + // Build the new controlDict + IOdictionary newControlDict + ( + IOobject + ( + Time::controlDictName, + multiDictRegistry_.system(), + multiDictRegistry_, + IOobject::NO_READ, + IOobject::AUTO_WRITE, + false + ), + currentSolverDomainDict_ + ); + + // Remove multiSolver-specific values from dictionary + newControlDict.remove("startFrom"); + newControlDict.remove("startTime"); + newControlDict.remove("stopAt"); + newControlDict.remove("endTime"); + newControlDict.remove("iterations"); + newControlDict.remove("purgeWriteSuperLoops"); + newControlDict.remove("timeFormat"); + newControlDict.remove("timePrecision"); + newControlDict.remove("storeFields"); + newControlDict.remove("elapsedTime"); + + // Add values to obtain the desired behaviour + newControlDict.set("startFrom", "startTime"); + newControlDict.set("startTime", startTime_); + newControlDict.set("stopAt", stopAtSetting); + newControlDict.set("endTime", endTime_); + if (multiSolverControl_.found("timeFormat")) + { + newControlDict.set + ( + "timeFormat", + word(multiSolverControl_.lookup("timeFormat")) + ); + } + if (multiSolverControl_.found("timePrecision")) + { + newControlDict.set + ( + "timePrecision", + readScalar(multiSolverControl_.lookup("timePrecision")) + ); + } + + // Write the dictionary to the case directory + newControlDict.regIOobject::write(); + + // Change all the dictionaries + swapDictionaries(currentSolverDomain_); + + // Remove noSaves flag + if (noSaveSinceSuperLoopIncrement_) + { + noSaveSinceSuperLoopIncrement_ = false; + } +} + diff --git a/src/multiSolver/multiSolver/multiSolverTimeFunctions.C b/src/multiSolver/multiSolver/multiSolverTimeFunctions.C new file mode 100644 index 000000000..22a4e5511 --- /dev/null +++ b/src/multiSolver/multiSolver/multiSolverTimeFunctions.C @@ -0,0 +1,758 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + + +Foam::labelList Foam::multiSolver::findSuperLoops(const fileName& path) +{ + fileNameList dirEntries(readDir(path, fileName::DIRECTORY)); + + labelList superLoopList(dirEntries.size()); + label nSuperLoops(0); + + // Loop through dirEntries, checking for valid integers, sort entries + forAll(dirEntries, de) + { + // Check if directory is "initial" + if (dirEntries[de] == "initial") + { + superLoopList[nSuperLoops++] = -1; + continue; + } + + IStringStream superLoopStream(dirEntries[de]); + token superLoopToken(superLoopStream); + + // Check if directory is an integer + if (superLoopToken.isLabel() && superLoopStream.eof()) + { + superLoopList[nSuperLoops++] = superLoopToken.labelToken(); + } + } + superLoopList.setSize(nSuperLoops); + sort(superLoopList); + return superLoopList; +} + + +Foam::timeCluster Foam::multiSolver::findClosestGlobalTime +( + const Foam::scalar value, + const Foam::timeClusterList& tcl, + const bool& exact +) +{ + scalar maxDiff(-VGREAT); + scalar minDiff(VGREAT); + label underShoot(-1); + label best(-1); + label initial(-1); + + // Find closest global minimum that does not exceed value + forAll(tcl, i) + { + if (!tcl[i].times().size()) continue; + scalar diff(tcl[i].globalMinValue() - value); + if ((diff <= 0) && (diff >= maxDiff)) + { + // "initial" directory may be a duplicate match - others take + // priority. + if ((tcl[i].superLoop() < 0) && (diff > maxDiff)) + { + initial = i; + } + else + { + initial = -1; + best = i; + } + maxDiff = diff; + } + else if ((diff > 0) && (diff < minDiff)) + { + // This is in case all timeClusters exceed value - then we have to + // return the closest minValue + minDiff = diff; + underShoot = i; + } + } + + if (initial != -1) + { + // "initial" directory is the only match + best = initial; + } + + if (best == -1) + { + if (minDiff != -1) + { + // All timeClusters exceed value, return closest minValue + best = underShoot; + } + else + { + + FatalErrorIn("multiSolver::findClosestGlobalTime") + << "The timeClusterList passed to this function has no non-" + << "empty instantLists. Use timeClusterList::purgeEmpties " + << "and check its return value to prevent this." + << abort(FatalError); + } + } + + label timeIndex + ( + Time::findClosestTimeIndex + ( + tcl[best].times(), value - tcl[best].globalOffset() + ) + ); + + if (exact && (maxDiff < -VSMALL)) + { + FatalErrorIn("multiSolver::findClosestGlobalTime") + << "No exact match found for global time = " << value + << abort(FatalError); + } + + return tcl[best](timeIndex); +} + + +Foam::timeCluster Foam::multiSolver::findClosestLocalTime +( + const Foam::scalar value, + const Foam::timeClusterList& tcl, + const bool& exact +) +{ + scalar maxDiff(-VGREAT); + scalar minDiff(VGREAT); + label underShoot(-1); + label best(-1); + label initial(-1); + timeClusterList tclDummy; + const timeClusterList * tclPtr; + + if (nonOverlapping(tcl)) + { + tclPtr = & tcl; + } + else + { + tclDummy = tcl.selectiveSubList(findMaxSuperLoopIndices(tcl)); + tclPtr = & tclDummy; + } + + for (label i = 0; i < tclPtr->size(); i++) + { + if (!tclPtr->operator[](i).times().size()) continue; + scalar diff(tclPtr->operator[](i).localMinValue() - value); + + if ((diff <= 0) && (diff >= maxDiff)) + { + // "initial" directory may be a duplicate match - others take + // priority. + + if ((tclPtr->operator[](i).superLoop() < 0) && (diff > maxDiff)) + { + initial = i; + } + else + { + initial = -1; + best = i; + } + maxDiff = diff; + } + else if ((diff > 0) && (diff < minDiff)) + { + // This is in case all timeClusters exceed value - then we have to + // return the closest minValue + minDiff = diff; + underShoot = i; + } + } + + if (initial != -1) + { + // "initial" directory is the only match + best = initial; + } + + if (best == -1) + { + if (minDiff != -1) + { + // All timeClusters exceed value, return closest minValue + best = underShoot; + } + else + { + + FatalErrorIn("multiSolver::findClosestLocalTime") + << "The timeClusterList passed to this function has no non-" + << "empty instantLists. Use timeClusterList::purgeEmpties " + << "and check its return value to prevent this." + << abort(FatalError); + } + } + + label timeIndex + ( + Time::findClosestTimeIndex + ( + tclPtr->operator[](best).times(), value + ) + ); + + if (exact && (maxDiff < -VSMALL)) + { + FatalErrorIn("multiSolver::findClosestLocalTime") + << "No exact match found for local time = " << value + << abort(FatalError); + } + + return tclPtr->operator[](best)(timeIndex); +} + + +Foam::timeCluster Foam::multiSolver::findLatestGlobalTime +( + const Foam::timeClusterList& tcl +) +{ + timeCluster bestMax(0); + + timeCluster currentMax; + + forAll(tcl, i) + { + if (tcl[i].times().size() == 0) continue; + + currentMax = tcl[i](tcl[i].globalMaxIndex()); + if + ( + (currentMax.globalValue(0) > bestMax.globalValue(0)) + || ( + (currentMax.globalValue(0) == bestMax.globalValue(0)) + && (currentMax.superLoop() != -1) + ) + ) + { + bestMax = currentMax; + } + } + + if (bestMax.solverDomainName() == word::null) + { + FatalErrorIn("multiSolver::findLatestGlobalTime") + << "The timeClusterList passed to this function has no non-empty " + << "instantLists. Use timeClusterList::purgeEmpties and check its" + << " return value to prevent this." + << abort(FatalError); + } + return bestMax; +} + + +Foam::timeCluster Foam::multiSolver::findLatestLocalTime +( + const Foam::timeClusterList& tcl +) +{ + timeClusterList dummyTcl; + const timeClusterList * tclPtr; + timeCluster bestMax(0); + timeCluster currentMax; + + if (nonOverlapping(tcl)) + { + tclPtr = & tcl; + } + else + { + dummyTcl = tcl.selectiveSubList(findMaxSuperLoopIndices(tcl)); + tclPtr = & dummyTcl; + } + + for (label i = 0; i < tclPtr->size(); i++) + { + if (tclPtr->operator[](i).times().size() == 0) continue; + + currentMax = + tclPtr->operator[](i)(tclPtr->operator[](i).localMaxIndex()); + + if + ( + (currentMax.localValue(0) > bestMax.localValue(0)) + || ( + (currentMax.localValue(0) == bestMax.localValue(0)) + && (currentMax.superLoop() != -1) + ) + ) + { + bestMax = currentMax; + } + } + + if (bestMax.solverDomainName() == word::null) + { + FatalErrorIn("multiSolver::findLatestLocalTime") + << "The timeClusterList passed to this function has no non-empty " + << "instantLists. Use timeClusterList::purgeEmpties and check its" + << " return value to prevent this." + << abort(FatalError); + } + + return bestMax; +} + + +Foam::fileName Foam::multiSolver::findInstancePath +( + const timeCluster& tc, + const label& index +) const +{ + if (!tc.times().size()) + { + FatalErrorIn("multiSolver::findInstancePath") + << "The timeClusterList passed to this function has no non-empty " + << "instantLists. Use timeClusterList::purgeEmpties and check its" + << " return value to prevent this." + << abort(FatalError); + } + if (tc.superLoop() < 0) + { + // Initial directory + return fileName + ( + multiDictRegistry_.path()/"multiSolver"/tc.solverDomainName() + /"initial"/tc[index].name() + ); + } + else + { + return fileName + ( + multiDictRegistry_.path()/"multiSolver"/tc.solverDomainName() + /name(tc.superLoop())/tc[index].name() + ); + } +} + + +Foam::label Foam::multiSolver::findMaxSuperLoopValue(const timeClusterList& tcl) +{ + if (!tcl.size()) + { + FatalErrorIn("multiSolver::findMaxSuperLoopValue") + << "The timeClusterList passed to this function is empty. Use " + << "timeClusterList::purgeEmpties and check its return value to " + << "prevent this." + << abort(FatalError); + } + return tcl[findMaxSuperLoopIndices(tcl)[0]].superLoop(); +} + + +Foam::labelList Foam::multiSolver::findMaxSuperLoopIndices(const timeClusterList& tcl) +{ + label currentMax(-2); + labelList bestIndices(0); + label maxesFound(0); + + forAll(tcl, i) + { + if (!tcl[i].times().size()) continue; + if (currentMax == tcl[i].superLoop()) + { + bestIndices.setSize(++maxesFound); + bestIndices[maxesFound - 1] = i; + } + else if (currentMax < tcl[i].superLoop()) + { + currentMax = tcl[i].superLoop(); + maxesFound = 1; + bestIndices.setSize(1); + bestIndices[0] = i; + } + } + + if (bestIndices.size() == 0) + { + FatalErrorIn("multiSolver::findMaxSuperLoopIndices") + << "The timeClusterList passed to this function is empty. Use " + << "timeClusterList::purgeEmpties and check its return value to " + << "prevent this." + << abort(FatalError); + } + return bestIndices; +} + + +bool Foam::multiSolver::nonOverlapping +( + + const Foam::timeClusterList& tcl, + const bool useGlobalTime +) +{ + // see tuple2Lists.H + scalarScalarList range(tcl.size()); + + if (useGlobalTime) + { + forAll(tcl, i) + { + if (!tcl[i].times().size()) + { + range[i].first() = 0; + range[i].second() = 0; + } + else + { + range[i].first() = tcl[i].globalMinValue(); + range[i].second() = tcl[i].globalMaxValue(); + } + } + } + else + { + forAll(tcl, i) + { + if (!tcl[i].times().size()) + { + range[i].first() = 0; + range[i].second() = 0; + } + else + { + range[i].first() = tcl[i].localMinValue(); + range[i].second() = tcl[i].localMaxValue(); + } + } + } + sortTuple2ListBy1stThen2nd(range); + + for (label i = 0; i < (range.size() - 1); i++) + { + // Using '-SMALL' below is a temporary bug fix + if (range[i + 1].first() - range[i].second() < -SMALL) + { + // timeClusters overlap + return false; + } + } + return true; +} + + +Foam::timeCluster Foam::multiSolver::readSuperLoopTimes +( + const Foam::word& solverDomain, + const Foam::label superLoop, + const Foam::word& processor +) const +{ + fileName currentPath; + if (processor.size()) + { + currentPath = multiDictRegistry_.path()/processor; + } + else + { + currentPath = multiDictRegistry_.path(); + } + if (superLoop < 0) + { + currentPath = currentPath/"multiSolver"/solverDomain + /"initial"; + } + else + { + currentPath = currentPath/"multiSolver"/solverDomain + /name(superLoop); + } + + fileName mstFileName + ( + currentPath/"multiSolverTime" + ); + IFstream mstFile(mstFileName); + + bool mstFileGood(false); + scalar globalOffset(0); + + if (mstFile.good()) + { + dictionary mstDict(mstFile); + if (mstDict.found("globalOffset")) + { + globalOffset = + readScalar(mstDict.lookup("globalOffset")); + mstFileGood = true; + } + } + + if ((!mstFileGood) && (superLoop != -1)) + { + WarningIn("multiSolver::readSuperLoopTimes") + << "Bad or missing multiSolverTime dictionary (auto-" + << "generated) in case/multiSolver/" << solverDomain + << "/" << superLoop << ". Assuming globalOffset = 0" + << endl; + } + timeCluster tc + ( + Time::findTimes(currentPath), + globalOffset, + superLoop, + solverDomain + ); + return tc; +} + + +Foam::timeClusterList Foam::multiSolver::readSolverDomainTimes +( + const word& solverDomain, + const word processor +) const +{ + timeClusterList tcl(0); + label nTimeClusters(0); + + fileName locale; + if (processor.size()) + { + locale = processor/"multiSolver"; + } + else + { + locale = "multiSolver"; + } + fileName currentPath + ( + multiDictRegistry_.path()/locale/solverDomain + ); + + labelList superLoopList(multiSolver::findSuperLoops(currentPath)); + + // Loop through superLoopList, check for valid data, store in tcl + forAll(superLoopList, sl) + { + timeCluster tc + ( + readSuperLoopTimes(solverDomain, superLoopList[sl], processor) + ); + + // If there are no time directories, ignore this superLoop + if (tc.times().size() == 0) continue; + + // Store timeCluster + tcl.setSize(++nTimeClusters); + tcl[nTimeClusters - 1] = tc; + } + return tcl; +} + + +Foam::timeClusterList Foam::multiSolver::readAllTimes +( + const word processor +) const +{ + timeClusterList tcl(0); + + // Loop through solverDomains + forAll(prefixes_, pf) + { + if (prefixes_[pf] == "default") continue; + + timeClusterList tclIn(readSolverDomainTimes(prefixes_[pf], processor)); + tcl.append(tclIn); + } + return tcl; +} + + +bool Foam::multiSolver::loadTimeClusterList +( + const Foam::timeClusterList& tcl, + const bool useGlobalTime, + const bool loadStoreFields +) const +{ + if (!nonOverlapping(tcl, useGlobalTime)) return false; + + wordList storeFields; + + forAll(tcl, i) + { + fileName currentPath + ( + findInstancePath(tcl[i], 0).path() + ); + + instantList il(Time::findTimes(currentPath)); + fileName storeFieldsPath + ( + currentPath/il[Time::findClosestTimeIndex(il, -1.0)].name() + ); + + if + ( + loadStoreFields + && solverDomains_ + .subDict(tcl[i].solverDomainName()) + .found("storeFields") + ) + { + storeFields = wordList(solverDomains_ + .subDict(tcl[i].solverDomainName()) + .lookup("storeFields")); + } + else + { + storeFields.clear(); + } + + forAll(tcl[i].times(), j) + { + fileName storeFieldsDestination + ( + multiDictRegistry_.path()/tcl[i].times()[j].name() + ); + + cp + ( + currentPath/tcl[i].times()[j].name(), + multiDictRegistry_.path() + ); + if (useGlobalTime) + { + storeFieldsDestination = multiDictRegistry_.path()/ + Time::timeName + ( + tcl[i].globalValue(j) + ); + + mv + ( + multiDictRegistry_.path()/tcl[i].times()[j].name(), + storeFieldsDestination + ); + } + if + ( + loadStoreFields + && (storeFieldsPath != storeFieldsDestination) + ) + { + forAll(storeFields, j) + { + cp + ( + storeFieldsPath/storeFields[j], + storeFieldsDestination + ); + } + } + } // end cycle through instants + } // end cycle through timeClusters + return true; +} + + +void Foam::multiSolver::archiveTimeDirs +( + const Foam::fileName& sourcePath, + const Foam::fileName& archivePath, + const Foam::label& purgeWrite +) +{ + if (archivePath.name() == "initial") + { + FatalErrorIn("multiSolver::archiveTimeDirs") + << "Attempting to archive to the 'initial' directory. This is " + << "not permitted. sourcePath = " << sourcePath << ", archivePath" + << " = " << archivePath + << abort(FatalError); + } + if (exists(archivePath)) + { + purgeTimeDirs(archivePath); + } + + mkDir(archivePath); + + // Perform purgeWrite of superLoop directories + if (purgeWrite) + { + labelList allSL(findSuperLoops(archivePath.path())); + label currentSL(atoi(archivePath.name().c_str())); + + sort(allSL); + label i = 0; + while (allSL[i] < currentSL) + { + i++; + } + + for (label j = 1; j <= (i - purgeWrite); j++) + { + rmDir(archivePath.path()/name(allSL[j])); + } + } + + instantList timeDirs(Time::findTimes(sourcePath)); + + forAll(timeDirs, i) + { + if (timeDirs[i].name() == "constant") continue; + mv(sourcePath/timeDirs[i].name(), archivePath/timeDirs[i].name()); + } +} + +void Foam::multiSolver::purgeTimeDirs(const Foam::fileName& path) +{ + instantList timeDirs(Time::findTimes(path)); + + forAll(timeDirs, i) + { + if (timeDirs[i].name() == "constant") continue; + rmDir(path/timeDirs[i].name()); + } +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + diff --git a/src/multiSolver/timeCluster/timeCluster.C b/src/multiSolver/timeCluster/timeCluster.C new file mode 100644 index 000000000..56120bb68 --- /dev/null +++ b/src/multiSolver/timeCluster/timeCluster.C @@ -0,0 +1,243 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "timeClusterList.H" +#include "Time.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +const char* const Foam::timeCluster::typeName = "timeCluster"; + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::timeCluster::timeCluster() +{} + + +Foam::timeCluster::timeCluster +( + const instantList& times, + const scalar globalOffset, + const label superLoop, + const word& solverDomainName, + const word& preConName +) +: + instantList(times), + globalOffset_(globalOffset), + superLoop_(superLoop), + solverDomainName_(solverDomainName), + preConName_(preConName) +{} + +Foam::timeCluster::timeCluster +( + const timeCluster& tc, + const label index +) +: + instantList(1, tc[index]), + globalOffset_(tc.globalOffset_), + superLoop_(tc.superLoop_), + solverDomainName_(tc.solverDomainName_), + preConName_(tc.preConName_) +{} + + +Foam::timeCluster::timeCluster(const Foam::scalar t) +: + instantList(1, instant(0)), + globalOffset_(0), + superLoop_(0), + solverDomainName_(word::null), + preConName_(word::null) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::scalar Foam::timeCluster::globalValue(const label& index) const +{ + return this->operator[](index).value() + globalOffset_; +} + +Foam::scalar Foam::timeCluster::globalMinValue() const +{ + return this->localMinValue() + globalOffset_; +} + + +Foam::scalar Foam::timeCluster::globalMaxValue() const +{ + return this->localMaxValue() + globalOffset_; +} + + +Foam::label Foam::timeCluster::globalMinIndex() const +{ + return this->localMinIndex(); +} + + +Foam::label Foam::timeCluster::globalMaxIndex() const +{ + return this->localMaxIndex(); +} + + +Foam::scalar Foam::timeCluster::globalFindClosestTimeValue +( + const scalar timeValue +) const +{ + return this->operator[] + ( + Foam::Time::findClosestTimeIndex + ( + this->times(), timeValue - globalOffset_ + ) + ).value() + globalOffset_; +} + + +Foam::label Foam::timeCluster::globalFindClosestTimeIndex +( + const scalar timeValue +) const +{ + return Foam::Time::findClosestTimeIndex + ( + this->times(), timeValue - globalOffset_ + ); +} + + +Foam::scalar Foam::timeCluster::localValue(const label& index) const +{ + return this->operator[](index).value(); +} + + +Foam::scalar Foam::timeCluster::localMinValue() const +{ + return this->operator[](this->localMinIndex()).value(); +} + + +Foam::scalar Foam::timeCluster::localMaxValue() const +{ + return this->operator[](this->localMaxIndex()).value(); +} + + +Foam::label Foam::timeCluster::localMinIndex() const +{ + label bestIndex(0); + scalar min(VGREAT); + forAll(*this, i) + { + if (this->operator[](i).value() < min) + { + min = this->operator[](i).value(); + bestIndex = i; + } + } + return bestIndex; +} + + +Foam::label Foam::timeCluster::localMaxIndex() const +{ + label bestIndex(0); + scalar max(0); + forAll(*this, i) + { + if (this->operator[](i).value() > max) + { + max = this->operator[](i).value(); + bestIndex = i; + } + } + return bestIndex; +} + + +Foam::scalar Foam::timeCluster::localFindClosestTimeValue +( + const scalar timeValue +) const +{ + return this->operator[] + ( + Foam::Time::findClosestTimeIndex + ( + this->times(), timeValue + ) + ).value(); +} + + +Foam::label Foam::timeCluster::localFindClosestTimeIndex +( + const scalar timeValue +) const +{ + return Foam::Time::findClosestTimeIndex + ( + this->times(), timeValue + ); +} + + +Foam::timeCluster Foam::timeCluster::operator()(const Foam::label index) const +{ + return timeCluster(*this, index); +} + + +// * * * * * * * * * * * * * Friend IOstream Operators * * * * * * * * * * * // + +Foam::Istream& Foam::operator>>(Istream& is, timeCluster& I) +{ + return is >> I.globalOffset_ + >> I.superLoop_ + >> I.solverDomainName_ + >> I.preConName_ + >> I.times(); +} + + +Foam::Ostream& Foam::operator<<(Ostream& os, const timeCluster& I) +{ + return os << "/* globalOffset: */\t" << I.globalOffset_ << nl + << "/* superLoop: */\t" << I.superLoop_ << nl + << "/* solverDomain: */\t" << I.solverDomainName_ << nl + << "/* preConName: */\t" << I.preConName_ << nl + << "/* Instant list: */\t" << I.times(); +} + + +// ************************************************************************* // diff --git a/src/multiSolver/timeCluster/timeCluster.H b/src/multiSolver/timeCluster/timeCluster.H new file mode 100644 index 000000000..e333d66e2 --- /dev/null +++ b/src/multiSolver/timeCluster/timeCluster.H @@ -0,0 +1,233 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::timeCluster + +Description + A cluster of time instances, used with multiSolver. Catalogues all the + time directories within a superLoop, within a solverDomain. A single + time cluster describes what would be analogous to all the time directories + for a solver that does not use multiSolver. + +SourceFiles + timeCluster.C + +Author + David L. F. Gaden + +\*---------------------------------------------------------------------------*/ + +#ifndef timeCluster_H +#define timeCluster_H + +#include "word.H" +#include "scalar.H" +#include "instantList.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration of friend functions and operators + +class timeCluster; + +// Friend IOstream Operators + +Istream& operator>>(Istream&, timeCluster&); +Ostream& operator<<(Ostream&, const timeCluster&); + + +/*---------------------------------------------------------------------------*\ + Class timeCluster Declaration +\*---------------------------------------------------------------------------*/ + +class timeCluster +: + public instantList +{ + // Private data + + scalar globalOffset_; + label superLoop_; + word solverDomainName_; + + // PreConditioned file name - used only for pre and post conditioning + // a data set for parallel runs + word preConName_; + +public: + + // Public classes + + //- Less function class used in sorting timeClusters + class less + { + public: + + bool operator()(const timeCluster& one, const timeCluster& two) const + { + return one.globalMinValue() < two.globalMinValue(); + } + }; + + + // Static data members + + static const char* const typeName; + + + // Constructors + + //- Construct null + timeCluster(); + + //- Construct from components + timeCluster + ( + const instantList& times, + const scalar globalOffset, + const label superLoop, + const word& solverDomainName, + const word& preConName = word::null + ); + + //- Construct given a timeCluster and an index + // This creates a 'timeCluster' that holds a single instant + // in time, whose other values match those of tc. + timeCluster + ( + const timeCluster& tc, + const label index + ); + + //- Construct a time cluster given a scalar value. This constructs + // a timeCluster with a single instant of time at value t, and whose + // other values are zero or empty. + explicit timeCluster(const scalar t); + + // Member Functions + + // Access + + //- Times + inline const instantList& times() const; + + inline instantList& times(); + + //- Global offset + inline scalar globalOffset() const; + + inline scalar& globalOffset(); + + //- SuperLoop + inline label superLoop() const; + + inline label& superLoop(); + + //- Solver domain name + inline const word& solverDomainName() const; + + inline word& solverDomainName(); + + //- Solver domain name + inline const word& preConName() const; + + inline word& preConName(); + + // Derived values + + //- Global value at index + scalar globalValue(const label& index) const; + + //- Search for and return global min value. If empty, + // returns VGREAT. + scalar globalMinValue() const; + + //- Search for and return global max value. If empty, + // returns 0. + scalar globalMaxValue() const; + + //- Search for and return index of global min value + label globalMinIndex() const; + + //- Search for and return index of global max value + label globalMaxIndex() const; + + //- Global closest time + scalar globalFindClosestTimeValue(const scalar) const; + + //- Global closest time index + label globalFindClosestTimeIndex(const scalar) const; + + //- Local value at index + scalar localValue(const label& index) const; + + //- Search for and return local min value + scalar localMinValue() const; + + //- Search for and return local max value + scalar localMaxValue() const; + + //- Search for and return index of global min value. If empty, + // returns VGREAT + label localMinIndex() const; + + //- Search for and return index of global max value. If empty, + // returns 0. + label localMaxIndex() const; + + //-Local closest time + scalar localFindClosestTimeValue(const scalar) const; + + //-Local closest time index + label localFindClosestTimeIndex(const scalar) const; + + // Operators + + //- Chip off a single instant given an index, return as timeCluster + // This retains superLoop, solverDomain, etc.. with a timevalue + timeCluster operator()(const label index) const; + + + // Friend IOstream Operators + + friend Istream& operator>>(Istream&, timeCluster&); + friend Ostream& operator<<(Ostream&, const timeCluster&); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "timeClusterI.H" + +#endif + +// ************************************************************************* // diff --git a/src/multiSolver/timeCluster/timeClusterI.H b/src/multiSolver/timeCluster/timeClusterI.H new file mode 100644 index 000000000..1fbb528c5 --- /dev/null +++ b/src/multiSolver/timeCluster/timeClusterI.H @@ -0,0 +1,88 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +inline const instantList& timeCluster::times() const +{ + const instantList& times(*this); + return times; +} + +inline instantList& timeCluster::times() +{ + instantList& times(*this); + return times; +} + +inline scalar timeCluster::globalOffset() const +{ + return globalOffset_; +} + +inline scalar& timeCluster::globalOffset() +{ + return globalOffset_; +} + +inline label timeCluster::superLoop() const +{ + return superLoop_; +} + +inline label& timeCluster::superLoop() +{ + return superLoop_; +} + +inline const word& timeCluster::solverDomainName() const +{ + return solverDomainName_; +} + +inline word& timeCluster::solverDomainName() +{ + return solverDomainName_; +} + +inline const word& timeCluster::preConName() const +{ + return preConName_; +} + +inline word& timeCluster::preConName() +{ + return preConName_; +} + + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/multiSolver/timeCluster/timeClusterList.C b/src/multiSolver/timeCluster/timeClusterList.C new file mode 100644 index 000000000..21432b722 --- /dev/null +++ b/src/multiSolver/timeCluster/timeClusterList.C @@ -0,0 +1,156 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "timeClusterList.H" +#include "Time.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +const char* const Foam::timeClusterList::typeName = "timeClusterList"; + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::timeClusterList::timeClusterList() +: + List() +{} + + +Foam::timeClusterList::timeClusterList(const Foam::label size) +: + List(size) +{} + + +Foam::timeClusterList::timeClusterList(const timeCluster& tcIn) +: + List(1, tcIn) +{} + + +Foam::timeClusterList::timeClusterList(const Foam::label size, const Foam::timeCluster& tcIn) +: + List(size, tcIn) +{} + + +Foam::timeClusterList::timeClusterList(const labelList& subIndices, const timeClusterList& tclIn) +: + List(subIndices.size()) +{ + forAll(subIndices, i) + { + this->operator[](i) = tclIn[subIndices[i]]; + } +} + + +Foam::timeClusterList::timeClusterList(Foam::Istream& is) +: + List(is) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::timeClusterList::globalSort() +{ + Foam::sort(*this, timeCluster::less()); +} + +void Foam::timeClusterList::append(const timeClusterList& tclIn) +{ + label wasSize = this->size(); + this->setSize(tclIn.size() + this->size()); + + for (label i = 0; i < tclIn.size(); i++) + { + this->operator[](i + wasSize) = tclIn[i]; + } +} + + +void Foam::timeClusterList::append(const timeCluster& tcIn) +{ + label wasSize = this->size(); + this->setSize(this->size() + 1); + + this->operator[](wasSize) = tcIn; +} + + +bool Foam::timeClusterList::purgeEmpties() +{ + if (!this->size()) return false; + + label empties(0); + for (label i = 0; i < this->size(); i++) + { + if (!this->operator[](i).times().size()) + { + empties++; + continue; + } + if (empties) + { + this->operator[](i - empties) = this->operator[](i); + } + } + if (empties) + { + this->setSize(this->size() - empties); + } + if (!this->size()) return false; + return true; +} + +Foam::timeClusterList Foam::timeClusterList::selectiveSubList +( + const labelList& indices +) const +{ + timeClusterList tcl(indices.size()); + + forAll(indices, i) + { + if (indices[i] > this->size()) + { + FatalErrorIn("timeClusterList::selectiveSubList") + << "Out of range index passed to this function. Indices " + << "passed are: \n" << indices << "\nFailure at index " << i + << ", with value " << indices[i] << ".\n This timeClusterList " + << "has size " << this->size() << "." + << abort(FatalError); + } + + tcl[i] = this->operator[](indices[i]); + } + return tcl; +} + + + +// ************************************************************************* // diff --git a/src/multiSolver/timeCluster/timeClusterList.H b/src/multiSolver/timeCluster/timeClusterList.H new file mode 100644 index 000000000..8a2c13038 --- /dev/null +++ b/src/multiSolver/timeCluster/timeClusterList.H @@ -0,0 +1,110 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::timeClusterList + +Description + List of timeClusters with some additional functions + +SourceFiles + timeClusterList.C + +\*---------------------------------------------------------------------------*/ + +#ifndef timeClusterList_H +#define timeClusterList_H + +#include "timeCluster.H" +#include "labelList.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class timeClusterList Declaration +\*---------------------------------------------------------------------------*/ + +class timeClusterList +: + public List +{ + +public: + + // Static data members + + static const char* const typeName; + + // Constructors + + //- Null constructor + timeClusterList(); + + //- Construct with given size. + explicit timeClusterList(const label); + + //- Construct from a timeCluster. + timeClusterList(const timeCluster&); + + //- Construct with given size and value for all elements. + timeClusterList(const label, const timeCluster&); + + //- Construct as a sublist of another timeClusterList. This is not + // like the SubList in that this is not a new class, rather it is only + // producing a new copy that contains the specified entries. + timeClusterList(const labelList&, const timeClusterList&); + + //- Construct from Istream. + timeClusterList(Istream&); + + // Member functions + + //- Sort by global time + void globalSort(); + + //- Append another timeClusterList on the end of this one + void append(const timeClusterList& tclIn); + + //- Append a timeCluster on the end of this list + void append(const timeCluster& tcIn); + + //- Remove timeClusters with empty instantLists return false if all are + // empty + bool purgeEmpties(); + + //- Return a sublist using the specified indexes + timeClusterList selectiveSubList(const labelList&) const; + +}; + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/multiSolver/tuple2Lists/tuple2Lists.H b/src/multiSolver/tuple2Lists/tuple2Lists.H new file mode 100644 index 000000000..5bb14c517 --- /dev/null +++ b/src/multiSolver/tuple2Lists/tuple2Lists.H @@ -0,0 +1,113 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright held by original author + \\/ 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 2 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, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Typedef + Foam::tuple2List + +Description + List of paired values, with sorting capability + +Author + David L. F. Gaden + +\*---------------------------------------------------------------------------*/ + +#ifndef tuple2Lists_H +#define tuple2Lists_H + +#include "Tuple2.H" +#include "List.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + typedef List > labelLabelList; + typedef List > labelScalarList; + typedef List > scalarLabelList; + typedef List > scalarScalarList; + +template +bool lessFirst(Tuple2 t1, Tuple2 t2) +{ + return (t1.first() < t2.first()); +} + +template +bool lessFirstSecond(Tuple2 t1, Tuple2 t2) +{ + return + ( + (t1.first() < t2.first()) + || ((t1.first() == t2.first()) && (t1.second() < t2.second())) + ); +} + +template +bool lessSecond(Tuple2 t1, Tuple2 t2) +{ + return (t1.second() < t2.second()); +} + +template +bool lessSecondFirst(Tuple2 t1, Tuple2 t2) +{ + return + ( + (t2.first() < t1.first()) + || ((t2.first() == t1.first()) && (t2.second() < t1.second())) + ); +} + +template +void sortTuple2ListBy1st(List >& t2l) +{ + sort(t2l, lessFirst); +} + +template +void sortTuple2ListBy2nd(List >& t2l) +{ + sort(t2l, lessSecond); +} + +template +void sortTuple2ListBy1stThen2nd(List >& t2l) +{ + sort(t2l, lessFirstSecond); +} + +template +void sortTuple2ListBy2ndThen1st(List >& t2l) +{ + sort(t2l, lessSecondFirst); +} + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/multiTransportProperties b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/multiTransportProperties new file mode 100644 index 000000000..0599658c6 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/multiTransportProperties @@ -0,0 +1,32 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5-dev | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object multiTransportProperties; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +dictionaryName transportProperties; + +multiSolver +{ + scalarTransportFoam + { + DT DT [0 2 -1 0 0 0 0] 0.0; + } + icoFoam1 + { + nu nu [0 2 -1 0 0 0 0] 0.01; + } + icoFoam2 + { + nu nu [0 2 -1 0 0 0 0] 0.01; + } +} diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/polyMesh/blockMeshDict b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/polyMesh/blockMeshDict new file mode 100644 index 000000000..a60e689e8 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/polyMesh/blockMeshDict @@ -0,0 +1,90 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5 | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +convertToMeters 0.1; + +vertices +( + (0 0 0) + (1.5 0 0) + (1.5 1 0) + (0 1 0) + (2.5 0 0) + (4 0 0) + (4 1 0) + (2.5 1 0) + (1.5 2.5 0) + (2.5 2.5 0) + + (0 0 0.1) + (1.5 0 0.1) + (1.5 1 0.1) + (0 1 0.1) + (2.5 0 0.1) + (4 0 0.1) + (4 1 0.1) + (2.5 1 0.1) + (1.5 2.5 0.1) + (2.5 2.5 0.1) + +); + +blocks +( + hex (0 1 2 3 10 11 12 13) (20 20 1) simpleGrading (1 1 1) + hex (1 4 7 2 11 14 17 12) (20 20 1) simpleGrading (1 1 1) + hex (4 5 6 7 14 15 16 17) (20 20 1) simpleGrading (1 1 1) + hex (2 7 9 8 12 17 19 18) (20 20 1) simpleGrading (1 1 1) +); + +edges +( +); + +patches +( + wall steetWalls + ( + (1 0 10 11) + (4 1 11 14) + (5 4 14 15) + (2 3 13 12) + (6 7 17 16) + ) + wall branchWalls + ( + (8 2 12 18) + (7 9 19 17) + ) + patch westStreet + ( + (3 0 10 13) + ) + patch eastStreet + ( + (5 6 16 15) + ) + patch northBranch + ( + (9 8 18 19) + ) +); + +mergePatchPairs +( +); + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/polyMesh/boundary b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/polyMesh/boundary new file mode 100644 index 000000000..78f5dbbec --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/polyMesh/boundary @@ -0,0 +1,58 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5-dev | +| \\ / A nd | Revision: exported | +| \\/ M anipulation | Web: http://www.OpenFOAM.org | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class polyBoundaryMesh; + location "constant/polyMesh"; + object boundary; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +6 +( + steetWalls + { + type wall; + nFaces 100; + startFace 3100; + } + branchWalls + { + type wall; + nFaces 40; + startFace 3200; + } + westStreet + { + type patch; + nFaces 20; + startFace 3240; + } + eastStreet + { + type patch; + nFaces 20; + startFace 3260; + } + northBranch + { + type patch; + nFaces 20; + startFace 3280; + } + defaultFaces + { + type empty; + nFaces 3200; + startFace 3300; + } +) + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/transportProperties b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/transportProperties new file mode 100644 index 000000000..3172e58df --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/constant/transportProperties @@ -0,0 +1,21 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.7.1 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object transportProperties; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +nu nu [ 0 2 -1 0 0 0 0 ] 0.01; + + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam1/initial/0/T b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam1/initial/0/T new file mode 100644 index 000000000..664e75477 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam1/initial/0/T @@ -0,0 +1,50 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5 | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object p; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 0 0 1 0 0 0]; + +internalField uniform 0; + +boundaryField +{ + steetWalls + { + type zeroGradient; + } + branchWalls + { + type zeroGradient; + } + westStreet + { + type zeroGradient; + } + eastStreet + { + type zeroGradient; + } + northBranch // inlet + { + type fixedValue; + value uniform 1; + } + defaultFaces + { + type empty; + } +} + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam1/initial/0/U b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam1/initial/0/U new file mode 100644 index 000000000..3c3f5d721 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam1/initial/0/U @@ -0,0 +1,53 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5 | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volVectorField; + object U; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 1 -1 0 0 0 0]; + +internalField uniform (0 0 0); + +boundaryField +{ + steetWalls + { + type fixedValue; + value uniform (0 0 0); + } + branchWalls + { + type fixedValue; + value uniform (0 0 0); + } + westStreet // closed + { + type fixedValue; + value uniform (0 0 0); + } + eastStreet // outlet + { + type zeroGradient; + } + northBranch // inlet + { + type fixedValue; + value uniform (0 -1 0); + } + defaultFaces + { + type empty; + } +} + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam1/initial/0/p b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam1/initial/0/p new file mode 100644 index 000000000..5c502aada --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam1/initial/0/p @@ -0,0 +1,50 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5 | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object p; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 2 -2 0 0 0 0]; + +internalField uniform 0; + +boundaryField +{ + steetWalls + { + type zeroGradient; + } + branchWalls + { + type zeroGradient; + } + westStreet // closed + { + type zeroGradient; + } + eastStreet // outlet + { + type fixedValue; + value uniform 0; + } + northBranch // inlet + { + type zeroGradient; + } + defaultFaces + { + type empty; + } +} + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam2/initial/0/T b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam2/initial/0/T new file mode 100644 index 000000000..807d685ae --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam2/initial/0/T @@ -0,0 +1,50 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5 | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object p; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 0 0 1 0 0 0]; + +internalField uniform 0; + +boundaryField +{ + steetWalls + { + type zeroGradient; + } + branchWalls + { + type zeroGradient; + } + westStreet + { + type zeroGradient; + } + eastStreet + { + type zeroGradient; + } + northBranch + { + type fixedValue; + value uniform 1; + } + defaultFaces + { + type empty; + } +} + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam2/initial/0/U b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam2/initial/0/U new file mode 100644 index 000000000..e172533fc --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam2/initial/0/U @@ -0,0 +1,52 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5 | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volVectorField; + object U; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 1 -1 0 0 0 0]; + +internalField uniform (0 0 0); + +boundaryField +{ + steetWalls + { + type fixedValue; + value uniform (0 0 0); + } + branchWalls + { + type fixedValue; + value uniform (0 0 0); + } + westStreet // outlet + { + type zeroGradient; + } + eastStreet // inlet + { + type fixedValue; + value uniform (-1 0 0); + } + northBranch // outlet + { + type zeroGradient; + } + defaultFaces + { + type empty; + } +} + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam2/initial/0/p b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam2/initial/0/p new file mode 100644 index 000000000..1e9db6433 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/icoFoam2/initial/0/p @@ -0,0 +1,51 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5 | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object p; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 2 -2 0 0 0 0]; + +internalField uniform 0; + +boundaryField +{ + steetWalls + { + type zeroGradient; + } + branchWalls + { + type zeroGradient; + } + westStreet // outlet + { + type fixedValue; + value uniform 0; + } + eastStreet // inlet + { + type zeroGradient; + } + northBranch // outlet + { + type fixedValue; + value uniform 0; + } + defaultFaces + { + type empty; + } +} + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/scalarTransportFoam/initial/0/T b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/scalarTransportFoam/initial/0/T new file mode 100644 index 000000000..664e75477 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/scalarTransportFoam/initial/0/T @@ -0,0 +1,50 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5 | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object p; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 0 0 1 0 0 0]; + +internalField uniform 0; + +boundaryField +{ + steetWalls + { + type zeroGradient; + } + branchWalls + { + type zeroGradient; + } + westStreet + { + type zeroGradient; + } + eastStreet + { + type zeroGradient; + } + northBranch // inlet + { + type fixedValue; + value uniform 1; + } + defaultFaces + { + type empty; + } +} + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/scalarTransportFoam/initial/0/U b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/scalarTransportFoam/initial/0/U new file mode 100644 index 000000000..9a06af3c1 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/multiSolver/scalarTransportFoam/initial/0/U @@ -0,0 +1,52 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5 | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volVectorField; + object U; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 1 -1 0 0 0 0]; + +internalField uniform (0 0 0); + +boundaryField +{ + steetWalls + { + type fixedValue; + value uniform (0 0 0); + } + branchWalls + { + type fixedValue; + value uniform (0 0 0); + } + westStreet // outlet + { + type zeroGradient; + } + eastStreet // closed + { + type zeroGradient; + } + northBranch // inlet + { + type fixedValue; + value uniform (0 -1 0); + } + defaultFaces + { + type empty; + } +} + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/controlDict b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/controlDict new file mode 100644 index 000000000..e6dddb44c --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/controlDict @@ -0,0 +1,47 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.7.1 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object controlDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +writeFormat ascii; + +writePrecision 6; + +writeCompression uncompressed; + +runTimeModifiable yes; + +application icoFoam; + +deltaT 0.01; + +writeControl timeStep; + +writeInterval 1; + +startFrom startTime; + +startTime 0.1; + +stopAt endTime; + +endTime 0.1; + +timeFormat scientific; + +timePrecision 6; + + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/fvSchemes b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/fvSchemes new file mode 100644 index 000000000..3a9c54797 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/fvSchemes @@ -0,0 +1,60 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.7.1 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSchemes; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +ddtSchemes +{ + default Euler; +} + +gradSchemes +{ + default Gauss linear; + grad(p) Gauss linear; +} + +divSchemes +{ + default none; + div(phi,U) Gauss linear; +} + +laplacianSchemes +{ + default none; + laplacian(nu,U) Gauss linear corrected; + laplacian((1|A(U)),p) Gauss linear corrected; +} + +interpolationSchemes +{ + default linear; + interpolate(HbyA) linear; +} + +snGradSchemes +{ + default corrected; +} + +fluxRequired +{ + default no; + p ; +} + + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/fvSolution b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/fvSolution new file mode 100644 index 000000000..2e430db2b --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/fvSolution @@ -0,0 +1,45 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.7.1 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solvers +{ + p + { + solver PCG; + preconditioner DIC; + tolerance 1e-06; + relTol 0; + } + U + { + solver PBiCG; + preconditioner DILU; + tolerance 1e-05; + relTol 0; + } +} + +PISO +{ + nCorrectors 2; + nNonOrthogonalCorrectors 0; + pRefCell 0; + pRefValue 0; +} + + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/multiControlDict b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/multiControlDict new file mode 100644 index 000000000..a3e116162 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/multiControlDict @@ -0,0 +1,70 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5-dev | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object multiSolverDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +multiSolverControl +{ + initialStartFrom startTime; + startTime 0; + finalStopAt endSuperLoop; + endSuperLoop 3; + timeFormat scientific; + timePrecision 6; +} + +solverDomains +{ + icoFoam1 + { + application icoFoam; + startFrom startTime; + startTime 0; + stopAt endTime; + endTime 0.1; + deltaT 0.01; + writeControl timeStep; + writeInterval 1; + storeFields ( T ); + } + icoFoam2 + { + application icoFoam; + startFrom startTime; + startTime 0; + stopAt endTime; + endTime 0.1; + deltaT 0.01; + writeControl timeStep; + writeInterval 1; + storeFields ( T ); + } + scalarTransportFoam + { + application scalarTransportFoam; + startFrom latestTimeAllDomains; + stopAt elapsedTime; + elapsedTime 1; + deltaT 0.1; + writeControl timeStep; + writeInterval 1; + storeFields ( p ); + } + default + { + writeFormat ascii; + writePrecision 6; + writeCompression uncompressed; + runTimeModifiable yes; + } +} diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/multiFvSchemes b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/multiFvSchemes new file mode 100644 index 000000000..36ca427a5 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/multiFvSchemes @@ -0,0 +1,150 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5-dev | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object multiFvSchemes; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +dictionaryName fvSchemes; + +multiSolver +{ + icoFoam1 + { + ddtSchemes + { + default Euler; + } + + gradSchemes + { + default Gauss linear; + grad(p) Gauss linear; + } + + divSchemes + { + default none; + div(phi,U) Gauss linear; + } + + laplacianSchemes + { + default none; + laplacian(nu,U) Gauss linear corrected; + laplacian((1|A(U)),p) Gauss linear corrected; + } + + interpolationSchemes + { + default linear; + interpolate(HbyA) linear; + } + + snGradSchemes + { + default corrected; + } + + fluxRequired + { + default no; + p; + } + } + + icoFoam2 + { + ddtSchemes + { + default Euler; + } + + gradSchemes + { + default Gauss linear; + grad(p) Gauss linear; + } + + divSchemes + { + default none; + div(phi,U) Gauss linear; + } + + laplacianSchemes + { + default none; + laplacian(nu,U) Gauss linear corrected; + laplacian((1|A(U)),p) Gauss linear corrected; + } + + interpolationSchemes + { + default linear; + interpolate(HbyA) linear; + } + + snGradSchemes + { + default corrected; + } + + fluxRequired + { + default no; + p; + } + } + + scalarTransportFoam + { + ddtSchemes + { + default none; + ddt(T) Euler; + } + + gradSchemes + { + default Gauss linear; + } + + divSchemes + { + default none; + div(phi,T) Gauss upwind; + } + + laplacianSchemes + { + default none; + laplacian(DT,T) Gauss linear corrected; + } + + interpolationSchemes + { + default linear; + } + + snGradSchemes + { + default corrected; + } + + fluxRequired + { + default no; + } + } +} + +// ************************************************************************* // diff --git a/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/multiFvSolution b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/multiFvSolution new file mode 100644 index 000000000..133de7424 --- /dev/null +++ b/tutorials/multiSolver/multiSolverDemo/teeFitting2d/system/multiFvSolution @@ -0,0 +1,100 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 1.5-dev | +| \\ / A nd | Web: http://www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object multiFvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +dictionaryName fvSolution; + +multiSolver +{ + icoFoam1 + { + solvers + { + p + { + solver PCG; + preconditioner DIC; + tolerance 1e-06; + relTol 0; + }; + + U + { + solver PBiCG; + preconditioner DILU; + tolerance 1e-05; + relTol 0; + }; + } + + PISO + { + nCorrectors 2; + nNonOrthogonalCorrectors 0; + pRefCell 0; + pRefValue 0; + } + } + + icoFoam2 + { + solvers + { + p + { + solver PCG; + preconditioner DIC; + tolerance 1e-06; + relTol 0; + }; + + U + { + solver PBiCG; + preconditioner DILU; + tolerance 1e-05; + relTol 0; + }; + } + + PISO + { + nCorrectors 2; + nNonOrthogonalCorrectors 0; + pRefCell 0; + pRefValue 0; + } + } + + scalarTransportFoam + { + solvers + { + T + { + solver PBiCG; + preconditioner DILU; + tolerance 1e-05; + relTol 0; + }; + } + + SIMPLE + { + nNonOrthogonalCorrectors 0; + } + } +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //