diff --git a/src/finiteVolume/Make/files b/src/finiteVolume/Make/files index db88df52ae7abd5bd5f9f49e836c00cc74db6c03..e7023dea211fa34aad9980e68153641fa7c9545d 100644 --- a/src/finiteVolume/Make/files +++ b/src/finiteVolume/Make/files @@ -425,6 +425,7 @@ $(coupling)/externalFileCoupler.C solutionControl = $(general)/solutionControl $(solutionControl)/solutionControl/solutionControl.C +$(solutionControl)/loopControl/loopControl.C $(solutionControl)/simpleControl/simpleControl.C $(solutionControl)/pimpleControl/pimpleControl.C $(solutionControl)/pisoControl/pisoControl.C diff --git a/src/finiteVolume/cfdTools/general/solutionControl/loopControl/fvSolution b/src/finiteVolume/cfdTools/general/solutionControl/loopControl/fvSolution new file mode 100644 index 0000000000000000000000000000000000000000..19d8b0fe0b132a7cad73c67ba050df55c0c0d164 --- /dev/null +++ b/src/finiteVolume/cfdTools/general/solutionControl/loopControl/fvSolution @@ -0,0 +1,47 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: plus | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object fvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + +SIMPLE +{ + energyCoupling + { + // (Max) number of loops + iterations 200; + + // The interval to execute onLoop function-objects + interval 0; + + // Convergence criteria to terminate loop + convergence + { + "h" 1e-3; + } + + // Names of function objects to fire with execute(int) when looping + onLoop ( ); + + // Names of function objects to fire with execute(int) when converged + onConverged ( ); + + // Names of function objects to fire with execute(int) when loop ends + // without convergence + onEnd ( ); + } +} + + +// ************************************************************************* // diff --git a/src/finiteVolume/cfdTools/general/solutionControl/loopControl/loopControl.C b/src/finiteVolume/cfdTools/general/solutionControl/loopControl/loopControl.C new file mode 100644 index 0000000000000000000000000000000000000000..f4531243686f3f9e9513f8745c7c0beffdfddc94 --- /dev/null +++ b/src/finiteVolume/cfdTools/general/solutionControl/loopControl/loopControl.C @@ -0,0 +1,280 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2017 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "loopControl.H" +#include "fvSolution.H" +#include "wordRes.H" +#include "solutionControl.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::loopControl::clear() +{ + total_ = 0; + interval_ = 0; + + convergenceDict_.clear(); + onLoop_.clear(); + onConverged_.clear(); + onEnd_.clear(); + + converged_ = false; +} + + +void Foam::loopControl::read(const dictionary& dict) +{ + clear(); + + bool enabled = dict.lookupOrDefault("enabled", true); + + if (enabled) + { + scalar timeStart; + if (dict.readIfPresent("timeStart", timeStart)) + { + timeStart = time_.userTimeToTime(timeStart); + + enabled = + ( + enabled + && time_.value() >= (timeStart - 0.5*time_.deltaTValue()) + ); + } + + scalar timeEnd; + if (dict.readIfPresent("timeEnd", timeEnd)) + { + timeEnd = time_.userTimeToTime(timeEnd); + + enabled = + ( + enabled + && time_.value() <= (timeEnd + 0.5*time_.deltaTValue()) + ); + } + } + + if (!enabled) + { + return; + } + + dict.readIfPresent("iterations", total_); + dict.readIfPresent("interval", interval_); + + convergenceDict_ = dict.subOrEmptyDict("convergence"); + + dict.readIfPresent("onLoop", onLoop_); + dict.readIfPresent("onConverged", onConverged_); + dict.readIfPresent("onEnd", onEnd_); +} + + +bool Foam::loopControl::checkConverged() const +{ + if (convergenceDict_.empty()) + { + return false; + } + + HashTable<const fvMesh*> meshes = time_.lookupClass<const fvMesh>(); + + bool achieved = true; + bool checked = false; // safety that some checks were indeed performed + + forAllConstIters(meshes, meshIter) + { + const fvMesh& regionMesh = *(meshIter.object()); + + const dictionary& solverDict = regionMesh.solverPerformanceDict(); + + forAllConstIters(solverDict, iter) + { + const entry& dataDictEntry = *iter; + + const word& variableName = dataDictEntry.keyword(); + + const scalar absTol = + convergenceDict_.lookupOrDefault<scalar>(variableName, -1); + + if (absTol > 0) + { + // Treat like a SIMPLE control + + Pair<scalar> residuals = + solutionControl::maxResidual + ( + regionMesh, + dataDictEntry + ); + + checked = true; + achieved = achieved && (residuals.first() < absTol); + } + } + } + + return checked && achieved; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::loopControl::loopControl +( + Time& runTime, + const label nCycles, + const word& loopName +) +: + subLoopTime(runTime, nCycles), + name_(loopName), + interval_(0), + convergenceDict_(), + onLoop_(), + onConverged_(), + onEnd_(), + converged_(false) +{} + + +Foam::loopControl::loopControl +( + Time& runTime, + const dictionary& algorithmDict, + const word& dictName +) +: + loopControl(runTime, 0, dictName) +{ + // The loop sub-dictionary + const dictionary* dictptr = algorithmDict.subDictPtr(dictName); + + if (dictptr) + { + // Info<< dictName << *dictptr << endl; + read(*dictptr); + } +} + + +Foam::loopControl::loopControl +( + Time& runTime, + const word& algorithmName, + const word& dictName +) +: + loopControl(runTime, 0, dictName) +{ + fvSolution fvsol(time_); + + // Eg, PIMPLE or SIMPLE from <system/fvSolution> + const dictionary* dictptr = + fvsol.solutionDict().subDictPtr(algorithmName); + + if (dictptr) + { + // The loop sub-dictionary + dictptr = dictptr->subDictPtr(dictName); + + if (dictptr) + { + // Info<< dictName << *dictptr << endl; + read(*dictptr); + } + } +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::loopControl::~loopControl() +{ + stop(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::loopControl::loop() +{ + bool active = (index_ < total_); // as per status() + + if (active) + { + operator++(); + + converged_ = checkConverged(); + + if (converged_) + { + time_.functionObjects().execute(onConverged_, index_); + stop(); + return false; + } + else if + ( + interval_ && !(index_ % interval_) + && !onLoop_.empty() + ) + { + time_.functionObjects().execute(onLoop_, index_); + } + } + else if (index_) + { + // Not active, the loop condition has now exiting on the last subloop + + if (!converged_ && !onEnd_.empty()) + { + time_.functionObjects().execute(onEnd_, index_); + } + } + + return active; +} + + +// * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * * // + +Foam::Ostream& Foam::operator<<(Ostream& os, const loopControl& ctrl) +{ + os << ctrl.name() << ": "; + if (ctrl.nCycles() && ctrl.index() <= ctrl.nCycles()) + { + os << ctrl.index() << '/' << ctrl.nCycles(); + } + else + { + os << "off"; + } + + return os; +} + + +// ************************************************************************* // diff --git a/src/finiteVolume/cfdTools/general/solutionControl/loopControl/loopControl.H b/src/finiteVolume/cfdTools/general/solutionControl/loopControl/loopControl.H new file mode 100644 index 0000000000000000000000000000000000000000..ced72d57e3035d5d644c7d548062d47f65622e51 --- /dev/null +++ b/src/finiteVolume/cfdTools/general/solutionControl/loopControl/loopControl.H @@ -0,0 +1,227 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2017 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::loopControl + +Description + A class for managing arbitrary loops with the ability to invoke + function object execution. + +Usage + Examples of function object specification: + \verbatim + SIMPLE + { + energyCoupling + { + iterations 100; + onLoop (); + onConverged ( externalCoupled "loopThings.*" ); + + convergence + { + "h" 1e-3; + } + } + } + + Where the loop entries comprise: + \table + Property | Description | Required | Default + enabled | active/deactive loop | no | true + iteration | times to loop | no | 0 + timeStart | begin time for loop activation | no | -VGREAT + timeEnd | end time of loop activation | no | VGREAT + interval | sub-interval to execute onLoop | no | 0 + onLoop | function object names to call at executeInterval | no + onConverged | function object names to call when converged | no + onEnd | function object names to call when loop ends | no + convergence | dictionary of convergence values to check | no + \endtable + + The function object names listed by \c onLoop, \c onConverged, \c onEnd + must implement an \c execute(int) method. + If the time controls \c timeStart or \c timeEnd are used for the loop, + these values are only inspected upon creation, not during execution. + +SeeAlso + fvSolution + +SourceFiles + loopControl.C + +\*---------------------------------------------------------------------------*/ + +#ifndef loopControl_H +#define loopControl_H + +#include "subLoopTime.H" +#include "dictionary.H" +#include "wordReList.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class loopControl Declaration +\*---------------------------------------------------------------------------*/ + +class loopControl +: + public subLoopTime +{ + // Private Member Functions + + //- Reset + void clear(); + + //- Read settings from dictionary + void read(const dictionary& dict); + + //- Execute specified function names + bool checkConverged() const; + + //- Disallow default bitwise copy construct + loopControl(const loopControl&) = delete; + + //- Disallow default bitwise assignment + void operator=(const loopControl&) = delete; + +protected: + + // Protected data + + //- Name of the loop control (the lookup dictionary name). + word name_; + + //- The interval to execute onLoop function-objects + label interval_; + + //- Dictionary for checking convergence (all regions) + dictionary convergenceDict_; + + //- Function object names to fire during the loop (at executeInterval) + List<wordRe> onLoop_; + + //- Function object names to fire on convergence + List<wordRe> onConverged_; + + //- Function object names to fire when the loop exits without + //- convergence + List<wordRe> onEnd_; + + //- Convergence tests passed + bool converged_; + +public: + + // Constructors + + //- Construct from time with fixed number of cycles + // \param runTime the top-level time + // \param nCycles the number of times to loop + // \param loopName the name of the loop + loopControl + ( + Time& runTime, + const label nCycles, + const word& dictName = "loop" + ); + + //- Construct from fvSolution dictionary based on time and the name + //- of the controlling algorithm + // \param runTime the top-level time + // \param algorithmName the name of the fvSolution dictionary, + // typically PIMPLE or SIMPLE + // \param dictName the name of the control dictionary + loopControl + ( + Time& runTime, + const word& algorithmName, + const word& dictName = "loop" + ); + + //- Construct from fvSolution dictionary based on time and the name + //- of the controlling algorithm + // \param runTime the top-level time + // \param algorithmDict the fvSolution algorithm dictionary, + // typically PIMPLE or SIMPLE + // \param dictName the name of the control dictionary + loopControl + ( + Time& runTime, + const dictionary& algorithmDict, + const word& dictName = "loop" + ); + + + //- Destructor + ~loopControl(); + + + // Member Functions + + //- Name of the loop control + inline const word& name() const + { + return name_; + } + + //- The interval to execute onLoop function-objects + inline label interval() const + { + return interval_; + } + + //- True if looping is active, increments the index and executes + //- the onLoop and onConverged functions. + // Example usage, + // \code + // while (control.loop()) + // { + // solve; + // } + // \endcode + bool loop(); + + + // IOstream operators + + //- Write name and state (on/off, index/total) to Ostream + friend Ostream& operator<<(Ostream& os, const loopControl& ctrl); + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* //