Skip to content
Snippets Groups Projects
Commit 96ed3638 authored by Mark OLESEN's avatar Mark OLESEN
Browse files

ENH: basic support for generic solution loop-control

parent 610c2909
Branches
Tags
No related merge requests found
......@@ -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
......
/*--------------------------------*- 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 ( );
}
}
// ************************************************************************* //
/*---------------------------------------------------------------------------*\
========= |
\\ / 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;
}
// ************************************************************************* //
/*---------------------------------------------------------------------------*\
========= |
\\ / 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
// ************************************************************************* //
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment