loopControl.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2017-2021 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "loopControl.H"
29 #include "fvSolution.H"
30 #include "solutionControl.H"
31 
32 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
33 
34 void Foam::loopControl::clear()
35 {
36  total_ = 0;
37  interval_ = 0;
38 
40  onLoop_.clear();
42  onEnd_.clear();
43 
44  converged_ = false;
45 }
46 
47 
48 void Foam::loopControl::read(const dictionary& dict)
49 {
50  clear();
51 
52  bool enabled = dict.getOrDefault("enabled", true);
53 
54  if (enabled)
55  {
56  scalar timeStart;
57  if (dict.readIfPresent("timeStart", timeStart))
58  {
59  timeStart = time_.userTimeToTime(timeStart);
60 
61  enabled =
62  (
63  enabled
64  && time_.value() >= (timeStart - 0.5*time_.deltaTValue())
65  );
66  }
67 
68  scalar timeEnd;
69  if (dict.readIfPresent("timeEnd", timeEnd))
70  {
71  timeEnd = time_.userTimeToTime(timeEnd);
72 
73  enabled =
74  (
75  enabled
76  && time_.value() <= (timeEnd + 0.5*time_.deltaTValue())
77  );
78  }
79  }
80 
81  if (!enabled)
82  {
83  return;
84  }
85 
86  dict.readIfPresent("iterations", total_);
87  dict.readIfPresent("interval", interval_);
88 
89  convergenceDict_ = dict.subOrEmptyDict("convergence");
90 
91  dict.readIfPresent("onLoop", onLoop_);
92  dict.readIfPresent("onConverged", onConverged_);
93  dict.readIfPresent("onEnd", onEnd_);
94 }
95 
96 
97 bool Foam::loopControl::checkConverged() const
98 {
99  if (convergenceDict_.empty())
100  {
101  return false;
102  }
103 
104  HashTable<const fvMesh*> meshes = time_.lookupClass<const fvMesh>();
105 
106  bool achieved = true;
107  bool checked = false; // safety that some checks were indeed performed
108 
109  forAllConstIters(meshes, meshIter)
110  {
111  const fvMesh& regionMesh = *(meshIter.val());
112 
113  const dictionary& solverDict = regionMesh.solverPerformanceDict();
114  for (const entry& dataDictEntry : solverDict)
115  {
116  const word& variableName = dataDictEntry.keyword();
117 
118  const scalar absTol =
119  convergenceDict_.getOrDefault<scalar>(variableName, -1);
120 
121  if (absTol > 0)
122  {
123  // Treat like a SIMPLE control
124 
125  Pair<scalar> residuals =
127  (
128  regionMesh,
129  dataDictEntry
130  );
131 
132  checked = true;
133  achieved = achieved && (residuals.first() < absTol);
134  }
135  }
136  }
137 
138  return checked && achieved;
139 }
140 
141 
142 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
143 
144 Foam::loopControl::loopControl
145 (
146  Time& runTime,
147  const label nCycles,
148  const word& loopName
149 )
150 :
151  subLoopTime(runTime, nCycles),
152  name_(loopName),
153  interval_(0),
154  convergenceDict_(),
155  onLoop_(),
156  onConverged_(),
157  onEnd_(),
158  converged_(false)
159 {}
160 
161 
162 Foam::loopControl::loopControl
163 (
164  Time& runTime,
165  const dictionary& algorithmDict,
166  const word& dictName
167 )
168 :
170 {
171  // The loop sub-dictionary
172  const dictionary* dictptr = algorithmDict.findDict(dictName);
173 
174  if (dictptr)
175  {
176  // Info<< dictName << *dictptr << endl;
177  read(*dictptr);
178  }
179 }
180 
181 
182 Foam::loopControl::loopControl
183 (
184  Time& runTime,
185  const word& algorithmName,
186  const word& dictName
187 )
188 :
189  loopControl(runTime, 0, dictName)
190 {
191  fvSolution fvsol(time_);
192 
193  // Eg, PIMPLE or SIMPLE from <system/fvSolution>
194  const dictionary* dictptr = fvsol.solutionDict().findDict(algorithmName);
195 
196  if (dictptr)
197  {
198  // The loop sub-dictionary
199  dictptr = dictptr->findDict(dictName);
200 
201  if (dictptr)
202  {
203  // Info<< dictName << *dictptr << endl;
204  read(*dictptr);
205  }
206  }
207 }
208 
209 
210 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
211 
213 {
214  stop();
215 }
216 
217 
218 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
219 
221 {
222  bool active = (index_ < total_); // as per status()
223 
224  if (active)
225  {
226  operator++();
227 
228  converged_ = checkConverged();
229 
230  if (converged_)
231  {
232  time_.functionObjects().execute(onConverged_, index_);
233  stop();
234  return false;
235  }
236  else if
237  (
238  interval_ && !(index_ % interval_)
239  && !onLoop_.empty()
240  )
241  {
242  time_.functionObjects().execute(onLoop_, index_);
243  }
244  }
245  else if (index_)
246  {
247  // Not active, the loop condition has now exiting on the last subloop
248 
249  if (!converged_ && !onEnd_.empty())
250  {
251  time_.functionObjects().execute(onEnd_, index_);
252  }
253  }
255  return active;
256 }
257 
258 
259 // * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * * //
260 
261 Foam::Ostream& Foam::operator<<(Ostream& os, const loopControl& ctrl)
262 {
263  os << ctrl.name() << ": ";
264  if (ctrl.nCycles() && ctrl.index() <= ctrl.nCycles())
265  {
266  os << ctrl.index() << '/' << ctrl.nCycles();
267  }
268  else
269  {
270  os << "off";
271  }
272 
273  return os;
274 }
275 
276 
277 // ************************************************************************* //
dictionary dict
A class for managing sub-loops referencing Time.
Definition: subLoopTime.H:49
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
const word dictName("faMeshDefinition")
engineTime & runTime
wordRes onLoop_
Function object names to fire during the loop (at executeInterval)
Definition: loopControl.H:190
label total_
The total number of cycles in the sub-cycle.
Definition: subLoopTime.H:78
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
bool loop()
True if looping is active, increments the index and executes the onLoop and onConverged functions...
Definition: loopControl.C:213
static Pair< scalar > maxResidual(const fvMesh &fvmesh, const entry &dataDictEntry)
Extract maximum residual for the solver performance entry, provided the corresponding volume field is...
wordRes onEnd_
Function object names to fire when the loop exits without convergence.
Definition: loopControl.H:201
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:109
A class for handling words, derived from Foam::string.
Definition: word.H:63
Foam::PtrList< Foam::fvMesh > meshes(regionNames.size())
patchWriters clear()
wordRes onConverged_
Function object names to fire on convergence.
Definition: loopControl.H:195
label interval_
The interval to execute onLoop function-objects.
Definition: loopControl.H:180
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:55
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
OBJstream os(runTime.globalPath()/outputName)
dictionary subOrEmptyDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX, const bool mandatory=false) const
Find and return a sub-dictionary as a copy, otherwise return an empty dictionary. ...
Definition: dictionary.C:533
bool converged_
Convergence tests passed.
Definition: loopControl.H:206
virtual const fileName & name() const
Read/write access to the name of the stream.
Definition: OSstream.H:128
Ostream & operator<<(Ostream &, const boundaryPatch &p)
Write boundaryPatch as dictionary entries (without surrounding braces)
Definition: boundaryPatch.C:76
dictionary convergenceDict_
Dictionary for checking convergence (all regions)
Definition: loopControl.H:185
~loopControl()
Destructor.
Definition: loopControl.C:205
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T, or return the given default value. FatalIOError if it is found and the number of...
void clear()
Clear the dictionary.
Definition: dictionary.C:856
A class for managing arbitrary loops with the ability to invoke function object execution.
Definition: loopControl.H:136
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
const dictionary * findDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary pointer if present (and a sub-dictionary) otherwise return nullptr...
Definition: dictionaryI.H:120