timeControl.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2026 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "timeControl.H"
27 #include "PstreamReduceOps.H"
28 
29 // * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * * //
30 
32 Foam::timeControl::timeControlNames_
33 {
34  "timeStep",
35  "writeTime",
36  "outputTime",
37  "adjustableRunTime",
38  "runTime",
39  "runTimes",
40  "clockTime",
41  "cpuTime",
42  "none"
43 };
44 
45 
46 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
47 
48 Foam::label Foam::timeControl::roundDown(const scalar t)
49 {
50  return t < 0 ? label(t) - 1 : label(t);
51 }
52 
53 
54 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
55 
57 (
58  const Time& t,
59  const dictionary& dict,
60  const word& prefix
61 )
62 :
63  time_(t),
64  prefix_(prefix),
65  timeControl_(timeControls::timeStep),
66  startTime_(time_.beginTime().value()),
67  endTime_(vGreat),
68  beginTime_(time_.beginTime().value()),
69  intervalSteps_(0),
70  interval_(-1),
71  timeDelta_(0),
72  executionIndex_(0)
73 {
74  read(dict);
75 }
76 
77 
78 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
79 
81 {}
82 
83 
84 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
85 
87 {
88  dict.readIfPresent("startTime", time().userUnits(), startTime_);
89  dict.readIfPresent("endTime", time().userUnits(), endTime_);
90  dict.readIfPresent("beginTime", time().userUnits(), beginTime_);
91 
92  word controlName(prefix_ + "Control");
93  word intervalName(prefix_ + "Interval");
94 
95  // For backward compatibility support the deprecated 'outputControl' option
96  // now superseded by 'writeControl' for compatibility with Time
97  if (prefix_ == "write" && dict.found("outputControl"))
98  {
100  << "Using deprecated 'outputControl'" << nl
101  << " Please use 'writeControl' with 'writeInterval'"
102  << endl;
103 
104  // Change to the old names for this option
105  controlName = "outputControl";
106  intervalName = "outputInterval";
107  }
108 
109  if (dict.found(controlName))
110  {
111  timeControl_ = timeControlNames_.read(dict.lookup(controlName));
112  }
113  else
114  {
115  timeControl_ = timeControls::timeStep;
116  }
117 
118  switch (timeControl_)
119  {
120  case timeControls::timeStep:
121  {
122  intervalSteps_ = dict.lookupOrDefault<label>(intervalName, 0);
123  break;
124  }
125 
126  case timeControls::writeTime:
127  case timeControls::outputTime:
128  {
129  intervalSteps_ = dict.lookupOrDefault<label>(intervalName, 1);
130  break;
131  }
132 
133  case timeControls::adjustableRunTime:
134  case timeControls::runTime:
135  {
136  interval_ = dict.lookup<scalar>(intervalName, time_.userUnits());
137  executionIndex_ =
138  roundDown
139  (
140  (
141  max(time_.value(), startTime_)
142  - beginTime_
143  - 0.5*time_.deltaTValue()
144  )
145  /interval_
146  );
147  break;
148  }
149 
150  case timeControls::runTimes:
151  {
152  const word timesName(prefix_ + "Times");
153  const word frequenciesName(prefix_ + "Frequencies");
154  const bool repeat = dict.lookupOrDefault(prefix_ + "Repeat", false);
155 
156  timeDelta_ =
158  (
159  "timeDelta",
160  units::none,
161  scalar(1e-3*time_.userDeltaTValue())
162  );
163 
164  if (dict.found(timesName))
165  {
166  times_ = dict.lookup<scalarList>(timesName, units::none);
167  }
168  else if (dict.found(frequenciesName))
169  {
170  List<Pair<scalar>> frequencies(dict.lookup(frequenciesName));
171 
172  const scalar userEndTime =
173  time_.timeToUserTime(time_.endTime().value());
174 
175  if (!repeat)
176  {
177  frequencies.append
178  (
179  {userEndTime, frequencies.last().second()}
180  );
181  }
182 
183  const scalar frequenciesDuration =
184  frequencies.last().first() - frequencies.first().first();
185 
186  DynamicList<scalar> times(1, frequencies[0].first());
187  label i = 0;
188  label repeati = 0;
189  while (times[i] < userEndTime)
190  {
191  for(label pi=0; pi<frequencies.size()-1; pi++)
192  {
193  while
194  (
195  times[i]
196  < frequencies[pi + 1].first()
197  + repeati*frequenciesDuration - timeDelta_
198  )
199  {
200  times(i + 1) = times[i] + frequencies[pi].second();
201  i++;
202  }
203  }
204  repeati++;
205  }
206 
207  times_ = times;
208  }
209  else
210  {
212  << "Undefined " << timesName
213  << " or " << frequenciesName << " for output control: "
214  << timeControlNames_[timeControl_] << nl
215  << exit(FatalError);
216  }
217 
218  forAll(times_, i)
219  {
220  timeIndices_.insert
221  (
222  int64_t((times_[i] + timeDelta_/2.0)/timeDelta_)
223  );
224  }
225 
226  intervalSteps_ = dict.lookupOrDefault<label>(intervalName, 1);
227  break;
228  }
229 
230  case timeControls::clockTime:
231  case timeControls::cpuTime:
232  {
233  interval_ = dict.lookup<scalar>(intervalName, time_.userUnits());
234  break;
235  }
236 
237  case timeControls::none:
238  {
239  break;
240  }
241 
242  default:
243  {
245  << "Undefined output control: "
246  << timeControlNames_[timeControl_] << nl
247  << exit(FatalError);
248  break;
249  }
250  }
251 }
252 
253 
255 {
256  return
257  timeControl_ != timeControls::none
258  && time_.value() >= startTime_ - 0.5*time_.deltaTValue()
259  && time_.value() <= endTime_;
260 }
261 
262 
264 {
265  if (!active())
266  {
267  return false;
268  }
269 
270  switch (timeControl_)
271  {
272  case timeControls::timeStep:
273  {
274  return
275  intervalSteps_ <= 1
276  || time_.timeIndex() % intervalSteps_ == 0;
277  break;
278  }
279 
280  case timeControls::writeTime:
281  case timeControls::outputTime:
282  {
283  if
284  (
285  time_.writeTime()
286  || time_.timeIndex() == time_.startTimeIndex()
287  )
288  {
289  const bool execute =
290  intervalSteps_ <= 1
291  || executionIndex_ % intervalSteps_ == 0;
292  executionIndex_++;
293  return execute;
294  }
295  break;
296  }
297 
298  case timeControls::runTime:
299  case timeControls::adjustableRunTime:
300  {
301  const label executionIndex =
302  roundDown
303  (
304  (
305  time_.value()
306  - beginTime_
307  + 0.5*time_.deltaTValue()
308  )
309  /interval_
310  );
311  if (executionIndex > executionIndex_)
312  {
313  executionIndex_ = executionIndex;
314  return true;
315  }
316  break;
317  }
318 
319  case timeControls::runTimes:
320  {
321  return timeIndices_.found
322  (
323  (time_.userTimeValue() + timeDelta_/2)/timeDelta_
324  );
325  }
326 
327  case timeControls::clockTime:
328  {
329  const label executionIndex = label
330  (
331  returnReduce(label(time_.elapsedClockTime()), maxOp<label>())
332  /interval_
333  );
334  if (executionIndex > executionIndex_)
335  {
336  executionIndex_ = executionIndex;
337  return true;
338  }
339  break;
340  }
341 
342  case timeControls::cpuTime:
343  {
344  const label executionIndex = label
345  (
346  returnReduce(time_.elapsedCpuTime(), maxOp<double>())
347  /interval_
348  );
349  if (executionIndex > executionIndex_)
350  {
351  executionIndex_ = executionIndex;
352  return true;
353  }
354  break;
355  }
356 
357  case timeControls::none:
358  {
359  return false;
360  }
361 
362  default:
363  {
365  << "Undefined output control: "
366  << timeControlNames_[timeControl_] << nl
367  << exit(FatalError);
368  break;
369  }
370  }
371 
372  return false;
373 }
374 
375 
377 {
378  if (time_.value() > endTime_) return vGreat;
379 
380  switch (timeControl_)
381  {
382  case timeControls::timeStep:
383  case timeControls::writeTime:
384  case timeControls::outputTime:
385  case timeControls::runTime:
386  case timeControls::clockTime:
387  case timeControls::cpuTime:
388  case timeControls::none:
389  {
390  return vGreat;
391  break;
392  }
393 
394  case timeControls::adjustableRunTime:
395  {
396  return
397  (executionIndex_ + 1)*interval_
398  - (time_.value() - beginTime_);
399  break;
400  }
401 
402  case timeControls::runTimes:
403  {
404  scalar realTimeToNextAction = vGreat;
405 
406  forAll(times_, i)
407  {
408  if
409  (
410  time_.userTimeToTime(times_[i]) < startTime_
411  || time_.userTimeToTime(times_[i]) > endTime_
412  ) continue;
413 
414  const scalar userTimeToThisAction =
415  times_[i] - time_.userTimeValue();
416 
417  if (userTimeToThisAction > timeDelta_)
418  {
419  realTimeToNextAction =
420  min
421  (
422  realTimeToNextAction,
423  time_.userTimeToTime(userTimeToThisAction)
424  );
425  }
426  }
427 
428  return realTimeToNextAction;
429  break;
430  }
431 
432  default:
433  {
435  << "Undefined output control: "
436  << timeControlNames_[timeControl_] << nl
437  << exit(FatalError);
438  break;
439  }
440  }
441 
442  return vGreat;
443 }
444 
445 
446 // ************************************************************************* //
Inter-processor communication reduction functions.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:55
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:76
T & first()
Return the first element of the list.
Definition: UListI.H:114
T & last()
Return the last element of the list.
Definition: UListI.H:128
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
T lookupOrDefault(const word &, const T &) const
Find and return a T, if not found return the given default.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:669
bool readIfPresent(const word &, T &, bool recursive=false, bool patternMatch=true) const
Find an entry if present, and assign to T.
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:468
timeControls
The time control options.
Definition: timeControl.H:56
void read(const dictionary &)
Read from dictionary.
Definition: timeControl.C:86
~timeControl()
Destructor.
Definition: timeControl.C:80
bool active() const
Returns true the time is within the start to end period.
Definition: timeControl.C:254
scalar timeToNextAction()
Return the time to the next write.
Definition: timeControl.C:376
bool execute()
Flag to indicate whether to execute.
Definition: timeControl.C:263
timeControl(const Time &, const dictionary &, const word &prefix)
Construct from Time object and dictionary.
Definition: timeControl.C:57
A class for handling words, derived from string.
Definition: word.H:63
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
const dimensionSet time
const unitSet none
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
scalar roundDown(const scalar x, const scalar s)
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:49
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
error FatalError
List< Type > repeat(const UList< Type > &a, const UList< Type > &b)
static const char nl
Definition: Ostream.H:297
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
dictionary dict