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-2025 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 Members * * * * * * * * * * * * * * //
47 
49 {
50  return
51  time_.value() >= startTime_ - 0.5*time_.deltaTValue()
52  && time_.value() <= endTime_;
53 }
54 
55 
56 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
57 
59 (
60  const Time& t,
61  const dictionary& dict,
62  const word& prefix
63 )
64 :
65  time_(t),
66  prefix_(prefix),
67  timeControl_(timeControls::timeStep),
68  startTime_(time_.beginTime().value()),
69  endTime_(vGreat),
70  intervalSteps_(0),
71  interval_(-1),
72  timeDelta_(0),
73  executionIndex_(0)
74 {
75  read(dict);
76 }
77 
78 
79 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
80 
82 {}
83 
84 
85 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
86 
88 {
89  dict.readIfPresent("startTime", time().userUnits(), startTime_);
90  dict.readIfPresent("endTime", time().userUnits(), endTime_);
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::clockTime:
134  case timeControls::runTime:
135  case timeControls::cpuTime:
136  case timeControls::adjustableRunTime:
137  {
138  interval_ = dict.lookup<scalar>(intervalName, time_.userUnits());
139 
140  if (timeControl_ == timeControls::adjustableRunTime)
141  {
142  executionIndex_ = max
143  (
144  label
145  (
146  ((time_.value() - startTime_) + 0.5*time_.deltaTValue())
147  /interval_
148  ),
149  0
150  );
151 
152  if
153  (
154  executionIndex_ == 0
155  && startTime_ != time_.beginTime().value()
156  )
157  {
158  executionIndex_ = -1;
159  }
160  }
161 
162  break;
163  }
164 
165  case timeControls::runTimes:
166  {
167  const word timesName(prefix_ + "Times");
168  const word frequenciesName(prefix_ + "Frequencies");
169  const bool repeat = dict.lookupOrDefault(prefix_ + "Repeat", false);
170 
171  timeDelta_ =
173  (
174  "timeDelta",
175  unitNone,
176  1e-3*time_.userDeltaTValue()
177  );
178 
179  if (dict.found(timesName))
180  {
181  times_ = dict.lookup<scalarList>(timesName, unitNone);
182  }
183  else if (dict.found(frequenciesName))
184  {
185  List<Pair<scalar>> frequencies(dict.lookup(frequenciesName));
186 
187  const scalar userEndTime =
188  time_.timeToUserTime(time_.endTime().value());
189 
190  if (!repeat)
191  {
192  frequencies.append
193  (
194  {userEndTime, frequencies.last().second()}
195  );
196  }
197 
198  const scalar frequenciesDuration =
199  frequencies.last().first() - frequencies.first().first();
200 
201  DynamicList<scalar> times(1, frequencies[0].first());
202  label i = 0;
203  label repeati = 0;
204  while (times[i] < userEndTime)
205  {
206  for(label pi=0; pi<frequencies.size()-1; pi++)
207  {
208  while
209  (
210  times[i]
211  < frequencies[pi + 1].first()
212  + repeati*frequenciesDuration - timeDelta_
213  )
214  {
215  times(i + 1) = times[i] + frequencies[pi].second();
216  i++;
217  }
218  }
219  repeati++;
220  }
221 
222  times_ = times;
223  }
224  else
225  {
227  << "Undefined " << timesName
228  << " or " << frequenciesName << " for output control: "
229  << timeControlNames_[timeControl_] << nl
230  << exit(FatalError);
231  }
232 
233  forAll(times_, i)
234  {
235  timeIndices_.insert
236  (
237  int64_t((times_[i] + timeDelta_/2.0)/timeDelta_)
238  );
239  }
240 
241  intervalSteps_ = dict.lookupOrDefault<label>(intervalName, 1);
242  break;
243  }
244 
245  default:
246  {
247  break;
248  }
249  }
250 }
251 
252 
254 {
255  if (!active())
256  {
257  return false;
258  }
259 
260  switch (timeControl_)
261  {
262  case timeControls::timeStep:
263  {
264  return
265  (
266  (intervalSteps_ <= 1)
267  || !(time_.timeIndex() % intervalSteps_)
268  );
269  break;
270  }
271 
272  case timeControls::writeTime:
273  case timeControls::outputTime:
274  {
275  if (time_.writeTime())
276  {
277  executionIndex_++;
278  return !(executionIndex_ % intervalSteps_);
279  }
280  break;
281  }
282 
283  case timeControls::runTime:
284  case timeControls::adjustableRunTime:
285  {
286  const label executionIndex = label
287  (
288  ((time_.value() - startTime_) + 0.5*time_.deltaTValue())
289  /interval_
290  );
291 
292  if (executionIndex > executionIndex_)
293  {
294  executionIndex_ = executionIndex;
295  return true;
296  }
297  break;
298  }
299 
300  case timeControls::runTimes:
301  {
302  return timeIndices_.found
303  (
304  (time_.userTimeValue() + timeDelta_/2)/timeDelta_
305  );
306 
307  break;
308  }
309 
310  case timeControls::cpuTime:
311  {
312  const label executionIndex = label
313  (
314  returnReduce(time_.elapsedCpuTime(), maxOp<double>())
315  /interval_
316  );
317  if (executionIndex > executionIndex_)
318  {
319  executionIndex_ = executionIndex;
320  return true;
321  }
322  break;
323  }
324 
325  case timeControls::clockTime:
326  {
327  const label executionIndex = label
328  (
329  returnReduce(label(time_.elapsedClockTime()), maxOp<label>())
330  /interval_
331  );
332  if (executionIndex > executionIndex_)
333  {
334  executionIndex_ = executionIndex;
335  return true;
336  }
337  break;
338  }
339 
340  case timeControls::none:
341  {
342  return false;
343  }
344 
345  default:
346  {
348  << "Undefined output control: "
349  << timeControlNames_[timeControl_] << nl
350  << exit(FatalError);
351  break;
352  }
353  }
354 
355  return false;
356 }
357 
358 
360 {
361  switch (timeControl_)
362  {
363  case timeControls::timeStep:
364  case timeControls::writeTime:
365  case timeControls::outputTime:
366  case timeControls::runTime:
367  case timeControls::cpuTime:
368  case timeControls::clockTime:
369  case timeControls::none:
370  {
371  return vGreat;
372  break;
373  }
374 
375  case timeControls::adjustableRunTime:
376  {
377  if (time_.value() < startTime_)
378  {
379  return startTime_ - time_.value();
380  }
381  else if (time_.value() > endTime_)
382  {
383  return vGreat;
384  }
385  else
386  {
387  return max
388  (
389  0,
390  (executionIndex_ + 1)*interval_
391  - (time_.value() - startTime_)
392  );
393  }
394  break;
395  }
396 
397  case timeControls::runTimes:
398  {
399  scalar realTimeToNextAction = vGreat;
400 
401  forAll(times_, i)
402  {
403  const scalar userTimeToThisAction =
404  times_[i] - time_.userTimeValue();
405 
406  if (userTimeToThisAction > timeDelta_)
407  {
408  realTimeToNextAction =
409  min
410  (
411  realTimeToNextAction,
412  time_.userTimeToTime(userTimeToThisAction)
413  );
414  }
415  }
416 
417  return realTimeToNextAction;
418  break;
419  }
420 
421  default:
422  {
424  << "Undefined output control: "
425  << timeControlNames_[timeControl_] << nl
426  << exit(FatalError);
427  break;
428  }
429  }
430 
431  return vGreat;
432 }
433 
434 
435 // ************************************************************************* //
Inter-processor communication reduction functions.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
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
scalar deltaTValue() const
Return time step value.
Definition: TimeStateI.H:34
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
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:740
T lookupOrDefault(const word &, const T &, const bool writeDefault=writeOptionalEntries > 0) const
Find and return a T, if not found return the given default.
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:539
const Type & value() const
Return const reference to value.
timeControls
The time control options.
Definition: timeControl.H:56
void read(const dictionary &)
Read from dictionary.
Definition: timeControl.C:87
~timeControl()
Destructor.
Definition: timeControl.C:81
bool active() const
Returns true the time is within the start to end period.
Definition: timeControl.C:48
scalar timeToNextAction()
Return the time to the next write.
Definition: timeControl.C:359
bool execute()
Flag to indicate whether to execute.
Definition: timeControl.C:253
timeControl(const Time &, const dictionary &, const word &prefix)
Construct from Time object and dictionary.
Definition: timeControl.C:59
A class for handling words, derived from string.
Definition: word.H:62
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
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:258
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:49
const unitConversion unitNone
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
error FatalError
List< Type > repeat(const UList< Type > &a, const UList< Type > &b)
static const char nl
Definition: Ostream.H:267
dictionary dict