https://mooseframework.inl.gov
TimeSequenceStepperBase.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
11 #include "FEProblem.h"
12 #include "Transient.h"
13 
14 #include <algorithm>
15 #include <functional>
16 
19 {
21  params.addParam<bool>(
22  "use_last_dt_after_last_t",
23  false,
24  "If true, uses the final time step size for times after the last time in the sequence, "
25  "instead of taking a single step directly to the simulation end time");
26  params.addParam<bool>(
27  "use_last_t_for_end_time", false, "Use last time in sequence as 'end_time' in Executioner.");
28  return params;
29 }
30 
32  : TimeStepper(parameters),
33  _use_last_dt_after_last_t(getParam<bool>("use_last_dt_after_last_t")),
34  _current_step(declareRestartableData<unsigned int>("current_step", 0)),
35  _time_sequence(declareRestartableData<std::vector<Real>>("time_sequence")),
36  _set_end_time(getParam<bool>("use_last_t_for_end_time"))
37 {
38 }
39 
40 void
41 TimeSequenceStepperBase::setupSequence(const std::vector<Real> & times)
42 {
43  // In case of half transient, transient's end time needs to be reset to
44  // be able to imprint TimeSequenceStepperBase's end time
47 
48  // When restarting or recovering, we reload _time_sequence as restartable data
49  if (_time_sequence.empty() || (!_app.isRestarting() && !_app.isRecovering()))
50  updateSequence(times);
51  else if (_app.isRecovering())
52  mooseAssert(_current_step < _time_sequence.size() &&
54  (_current_step + 1 == _time_sequence.size() ||
56  "The recovered current step must identify the last reached sequence time");
57  else
58  {
59  if (!MooseUtils::absoluteFuzzyEqual(_executioner.getStartTime(), _time_sequence[0]))
60  mooseError("Timesequencestepper does not allow the start time to be modified.");
61 
62  auto current_input_sequence = buildSequence(times);
63  // Count the leading sequence entries already reached at the current time. Entries no greater
64  // than _time + _timestep_tolerance are complete, so this count is also the index of the first
65  // future entry, or sequence.size() if every entry is complete.
66  const auto completed_prefix_size = [this](const auto & sequence)
67  {
68  return std::distance(sequence.begin(),
69  std::find_if(sequence.begin(),
70  sequence.end(),
71  [this](const auto sequence_time)
72  { return sequence_time - _time > _timestep_tolerance; }));
73  };
74 
75  const auto saved_prefix_size = completed_prefix_size(_time_sequence);
76  const auto current_prefix_size = completed_prefix_size(current_input_sequence);
77  if (current_prefix_size != saved_prefix_size)
78  mooseError("The timesequence provided in the restart file must be identical to "
79  "the one in the old file through the restart time, but it contains ",
80  current_prefix_size,
81  " completed value(s) instead of ",
82  saved_prefix_size,
83  ".");
84 
85  for (const auto j : make_range(saved_prefix_size))
86  if (!MooseUtils::absoluteFuzzyEqual(current_input_sequence[j], _time_sequence[j]))
87  mooseError("The timesequence provided in the restart file must be identical to "
88  "the one in the old file through the restart time, but entry ",
89  j + 1,
90  " is ",
91  current_input_sequence[j],
92  " in the restart input and ",
93  _time_sequence[j],
94  " in the restarted input.");
95 
96  _time_sequence = std::move(current_input_sequence);
98  }
99 
100  // Set end time to last time in sequence if requested
101  if (_set_end_time)
102  {
103  auto & end_time = _executioner.endTime();
104  end_time = _time_sequence.back();
105  }
106 
108  {
109  unsigned int half = (_time_sequence.size() - 1) / 2;
111  }
112 }
113 
114 std::vector<Real>
115 TimeSequenceStepperBase::buildSequence(const std::vector<Real> & times) const
116 {
117  const Real start_time = _executioner.getStartTime();
118  const Real end_time = _executioner.endTime();
119 
120  // make sure time sequence is in strictly ascending order
121  if (!std::is_sorted(times.begin(), times.end(), std::less_equal<Real>()))
122  paramError("time_sequence", "Time points must be in strictly ascending order.");
123 
124  std::vector<Real> sequence{start_time};
125  for (const auto time : times)
126  if (time > start_time && time <= end_time)
127  sequence.push_back(time);
128 
129  // Always append end_time as a sentinel, even when it duplicates the last supplied time.
130  if (!_set_end_time)
131  sequence.push_back(end_time);
132 
133  return sequence;
134 }
135 
136 void
137 TimeSequenceStepperBase::updateSequence(const std::vector<Real> & times)
138 {
139  _time_sequence = buildSequence(times);
141 }
142 
143 void
145 {
146  _time_sequence.clear();
147 }
148 
149 bool
150 TimeSequenceStepperBase::advanceToFutureTime(Real time, Real tolerance, Real & next_time)
151 {
152  refreshSequence();
153  const auto first_future = findFirstFutureTime(time, tolerance);
154  if (first_future == _time_sequence.cend())
155  return false;
156 
157  next_time = *first_future;
158  return true;
159 }
160 
161 std::vector<Real>::const_iterator
162 TimeSequenceStepperBase::findFirstFutureTime(Real time, Real tolerance) const
163 {
164  return std::partition_point(_time_sequence.begin(),
165  _time_sequence.end(),
166  [time, tolerance](const auto sequence_time)
167  { return sequence_time - time <= tolerance; });
168 }
169 
170 void
172 {
173  const auto first_future = findFirstFutureTime(time, tolerance);
174  _current_step =
175  first_future == _time_sequence.cbegin()
176  ? 0
177  : static_cast<unsigned int>(std::distance(_time_sequence.cbegin(), first_future) - 1);
178 }
179 
180 Real
182 {
183  refreshSequence();
184  mooseAssert(_current_step + 1 < _time_sequence.size(),
185  "The time sequence must contain a future time");
186  return _time_sequence[_current_step + 1];
187 }
188 
189 void
191 {
193  refreshSequence();
194  while (_current_step + 1 < _time_sequence.size() &&
197 }
198 
199 Real
201 {
202  return computeDT();
203 }
204 
205 Real
207 {
208  refreshSequence();
209  mooseAssert(_current_step + 1 < _time_sequence.size(),
210  "The time sequence must contain a future time");
211  const auto next_time = _time_sequence[_current_step + 1];
212 
214  {
215  // last *provided* time value index; actual last index corresponds to end time
216  const auto last_t_index = _time_sequence.size() - 2;
217  if (_current_step + 1 > last_t_index)
218  return _time_sequence[last_t_index] - _time_sequence[last_t_index - 1];
219  }
220 
221  return next_time - _time;
222 }
TransientBase & _executioner
Reference to transient executioner.
Definition: TimeStepper.h:126
static InputParameters validParams()
Definition: TimeStepper.C:16
Real & _timestep_tolerance
Definition: TimeStepper.h:138
std::vector< Real > buildSequence(const std::vector< Real > &times) const
Build the canonical time sequence for the current start and end times.
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseBase.h:457
virtual void refreshSequence()
Re-read a time sequence source that can change during the simulation.
unsigned int & _current_step
the step that the time stepper is currently at
Base class for time stepping.
Definition: TimeStepper.h:22
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
TimeSequenceStepperBase(const InputParameters &parameters)
Real getStartTime() const
Return the start time.
void synchronizeCurrentStep(Real time, Real tolerance)
Set the current sequence position from time.
void setupSequence(const std::vector< Real > &times)
bool advanceToFutureTime(Real time, Real tolerance, Real &next_time)
Return the first sequence time that has not yet been reached, if any.
std::vector< Real >::const_iterator findFirstFutureTime(Real time, Real tolerance) const
Find the first sequence time greater than time by more than tolerance.
bool isRestarting() const
Whether or not this is a "restart" calculation.
Definition: MooseApp.C:1675
const bool _set_end_time
Whether to use the last t in sequence as Executioner end_time.
virtual void acceptStep()
This gets called when time step is accepted.
Definition: TimeStepper.C:176
virtual Real getNextTimeInSequence()
Get the next time in the input time sequence.
std::vector< Real > & _time_sequence
stores the sequence of time points
bool testCheckpointHalfTransient() const
Whether or not this simulation should only run half its transient (useful for testing recovery) ...
Definition: MooseApp.h:524
constexpr bool is_sorted()
Check if the given index sequence is sorted ()internal function)
MooseApp & _app
The MOOSE application this is associated with.
Definition: MooseBase.h:375
virtual Real computeDT() override
Computes time step size after the initial time step.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Real & endTime()
Get a modifiable reference to the end time.
virtual Real computeInitialDT() override
Computes time step size for the initial time step.
static InputParameters validParams()
const bool _use_last_dt_after_last_t
Whether to use the final dt past the last t in sequence.
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:271
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
virtual void acceptStep() override
This gets called when time step is accepted.
bool isRecovering() const
Whether or not this is a "recover" calculation.
Definition: MooseApp.C:1669
void ErrorVector unsigned int
Real & _time
Values from executioner.
Definition: TimeStepper.h:129
void updateSequence(const std::vector< Real > &times)