Line data Source code
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 :
10 : // Standard includes
11 : #include <cmath>
12 : #include <limits>
13 :
14 : // MOOSE includes
15 : #include "Output.h"
16 : #include "FEProblem.h"
17 : #include "DisplacedProblem.h"
18 : #include "MooseApp.h"
19 : #include "Postprocessor.h"
20 : #include "Restartable.h"
21 : #include "FileMesh.h"
22 : #include "MooseUtils.h"
23 : #include "MooseApp.h"
24 : #include "Console.h"
25 : #include "Function.h"
26 : #include "PiecewiseLinear.h"
27 : #include "Times.h"
28 :
29 : #include "libmesh/equation_systems.h"
30 :
31 : InputParameters
32 686794 : Output::validParams()
33 : {
34 : // Get the parameters from the parent object
35 686794 : InputParameters params = MooseObject::validParams();
36 686794 : params += SetupInterface::validParams();
37 :
38 : // Displaced Mesh options
39 2060382 : params.addParam<bool>(
40 1373588 : "use_displaced", false, "Enable/disable the use of the displaced mesh for outputting");
41 :
42 : // Output intervals and timing
43 3433970 : params.addRangeCheckedParam<unsigned int>(
44 : "time_step_interval",
45 1373588 : 1,
46 : "time_step_interval > 0",
47 : "The interval (number of time steps) at which output occurs. "
48 : "Unless explicitly set, the default value of this parameter is set "
49 : "to infinity if the wall_time_interval is explicitly set.");
50 2060382 : params.addParam<Real>(
51 1373588 : "min_simulation_time_interval", 0.0, "The minimum simulation time between output steps");
52 3433970 : params.addRangeCheckedParam<Real>(
53 : "wall_time_interval",
54 1373588 : std::numeric_limits<Real>::max(),
55 : "wall_time_interval > 0",
56 : "The target wall time interval (in seconds) at which to output");
57 2747176 : params.setDocUnit("wall_time_interval", "seconds");
58 2747176 : params.addParam<std::vector<Real>>(
59 : "sync_times", {}, "Times at which the output and solution is forced to occur");
60 2747176 : params.addParam<TimesName>(
61 : "sync_times_object",
62 : "Times object providing the times at which the output and solution is forced to occur");
63 2747176 : params.addParam<bool>("sync_only", false, "Only export results at sync times");
64 2747176 : params.addParam<Real>("start_time", "Time at which this output object begins to operate");
65 2747176 : params.addParam<Real>("end_time", "Time at which this output object stop operating");
66 2747176 : params.addParam<int>("start_step", "Time step at which this output object begins to operate");
67 2747176 : params.addParam<int>("end_step", "Time step at which this output object stop operating");
68 2060382 : params.addParam<Real>(
69 1373588 : "time_tolerance", 1e-14, "Time tolerance utilized checking start and end times");
70 4120764 : params.addDeprecatedParam<FunctionName>(
71 : "output_limiting_function",
72 : "Piecewise base function that sets sync_times",
73 : "Replaced by using the Times system with the sync_times_objects parameter");
74 :
75 : // Update the 'execute_on' input parameter for output
76 686794 : ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
77 686794 : exec_enum = Output::getDefaultExecFlagEnum();
78 2060382 : exec_enum = {EXEC_INITIAL, EXEC_TIMESTEP_END};
79 2060382 : params.setDocString("execute_on", exec_enum.getDocString());
80 :
81 : // Add ability to append to the 'execute_on' list
82 2060382 : params.addParam<ExecFlagEnum>("additional_execute_on", exec_enum, exec_enum.getDocString());
83 1373588 : params.set<ExecFlagEnum>("additional_execute_on").clearSetValues();
84 2747176 : params.addParamNamesToGroup("execute_on additional_execute_on", "Execution scheduling");
85 :
86 : // 'Timing' group
87 2060382 : params.addParamNamesToGroup("time_tolerance time_step_interval sync_times sync_times_object "
88 : "sync_only start_time end_time "
89 : "start_step end_step min_simulation_time_interval "
90 : "wall_time_interval",
91 : "Timing and frequency of output");
92 :
93 : // Add a private parameter for indicating if it was created with short-cut syntax
94 1373588 : params.addPrivateParam<bool>("_built_by_moose", false);
95 :
96 : // Register this class as base class
97 2060382 : params.declareControllable("enable");
98 686794 : params.registerBase("Output");
99 :
100 686794 : return params;
101 686794 : }
102 :
103 : ExecFlagEnum
104 754086 : Output::getDefaultExecFlagEnum()
105 : {
106 754086 : ExecFlagEnum exec_enum = MooseUtils::getDefaultExecFlagEnum();
107 754086 : exec_enum.addAvailableFlags(EXEC_FAILED);
108 754086 : return exec_enum;
109 0 : }
110 :
111 290535 : Output::Output(const InputParameters & parameters)
112 : : MooseObject(parameters),
113 : Restartable(this, "Output"),
114 : MeshChangedInterface(parameters),
115 : SetupInterface(this),
116 : FunctionInterface(this),
117 : PostprocessorInterface(this),
118 : VectorPostprocessorInterface(this),
119 : ReporterInterface(this),
120 : PerfGraphInterface(this),
121 290535 : _problem_ptr(getParam<FEProblemBase *>("_fe_problem_base")),
122 290535 : _transient(_problem_ptr->isTransient()),
123 581070 : _use_displaced(getParam<bool>("use_displaced")),
124 290535 : _es_ptr(nullptr),
125 290535 : _mesh_ptr(nullptr),
126 581070 : _execute_on(getParam<ExecFlagEnum>("execute_on")),
127 290535 : _current_execute_flag(EXEC_NONE),
128 290535 : _time(_problem_ptr->time()),
129 290535 : _time_old(_problem_ptr->timeOld()),
130 290535 : _t_step(_problem_ptr->timeStep()),
131 290535 : _dt(_problem_ptr->dt()),
132 290535 : _dt_old(_problem_ptr->dtOld()),
133 290535 : _num(0),
134 290535 : _time_step_interval_set_by_addparam(parameters.isParamSetByAddParam("time_step_interval")),
135 : // If wall_time_interval is user-specified and time_step_interval is not,
136 : // override default value of time_step_interval so output does not occur
137 : // after every time step.
138 290535 : _time_step_interval(
139 581077 : (parameters.isParamSetByUser("wall_time_interval") && _time_step_interval_set_by_addparam)
140 581070 : ? std::numeric_limits<unsigned int>::max()
141 871605 : : getParam<unsigned int>("time_step_interval")),
142 581070 : _min_simulation_time_interval(getParam<Real>("min_simulation_time_interval")),
143 581070 : _wall_time_interval(getParam<Real>("wall_time_interval")),
144 581070 : _sync_times(std::set<Real>(getParam<std::vector<Real>>("sync_times").begin(),
145 871605 : getParam<std::vector<Real>>("sync_times").end())),
146 581070 : _sync_times_object(isParamValid("sync_times_object")
147 290550 : ? static_cast<Times *>(&_problem_ptr->getUserObject<Times>(
148 290580 : getParam<TimesName>("sync_times_object")))
149 : : nullptr),
150 871619 : _start_time(isParamValid("start_time") ? getParam<Real>("start_time")
151 290521 : : std::numeric_limits<Real>::lowest()),
152 871619 : _end_time(isParamValid("end_time") ? getParam<Real>("end_time")
153 290521 : : std::numeric_limits<Real>::max()),
154 872321 : _start_step(isParamValid("start_step") ? getParam<int>("start_step")
155 289819 : : std::numeric_limits<int>::lowest()),
156 871629 : _end_step(isParamValid("end_step") ? getParam<int>("end_step")
157 290511 : : std::numeric_limits<int>::max()),
158 581070 : _t_tol(getParam<Real>("time_tolerance")),
159 581070 : _sync_only(getParam<bool>("sync_only")),
160 290535 : _allow_output(true),
161 290535 : _is_advanced(false),
162 290535 : _advanced_execute_on(_execute_on, parameters),
163 290535 : _last_output_simulation_time(declareRestartableData<Real>("last_output_simulation_time",
164 290535 : std::numeric_limits<Real>::lowest())),
165 1162140 : _last_output_wall_time(std::chrono::steady_clock::now())
166 : {
167 290535 : if (_use_displaced)
168 : {
169 129 : std::shared_ptr<DisplacedProblem> dp = _problem_ptr->getDisplacedProblem();
170 129 : if (dp != nullptr)
171 : {
172 123 : _es_ptr = &dp->es();
173 123 : _mesh_ptr = &dp->mesh();
174 : }
175 : else
176 : {
177 6 : mooseWarning(
178 6 : name(),
179 : ": Parameter 'use_displaced' ignored, there is no displaced problem in your simulation.");
180 0 : _es_ptr = &_problem_ptr->es();
181 0 : _mesh_ptr = &_problem_ptr->mesh();
182 : }
183 123 : }
184 : else
185 : {
186 290406 : _es_ptr = &_problem_ptr->es();
187 290406 : _mesh_ptr = &_problem_ptr->mesh();
188 : }
189 :
190 : // Apply the additional output flags
191 871587 : if (isParamValid("additional_execute_on"))
192 : {
193 36 : const ExecFlagEnum & add = getParam<ExecFlagEnum>("additional_execute_on");
194 36 : for (auto & me : add)
195 18 : _execute_on.setAdditionalValue(me);
196 : }
197 :
198 871587 : if (isParamValid("output_limiting_function"))
199 : {
200 24 : const Function & olf = getFunction("output_limiting_function");
201 12 : const PiecewiseBase * pwb_olf = dynamic_cast<const PiecewiseBase *>(&olf);
202 12 : if (pwb_olf == nullptr)
203 0 : mooseError("Function muse have a piecewise base!");
204 :
205 48 : for (auto i = 0; i < pwb_olf->functionSize(); i++)
206 36 : _sync_times.insert(pwb_olf->domain(i));
207 : }
208 :
209 : // Get sync times from Times object if using
210 290529 : if (_sync_times_object)
211 : {
212 75 : if (isParamValid("output_limiting_function") || isParamSetByUser("sync_times"))
213 0 : paramError("sync_times_object",
214 : "Only one method of specifying sync times is supported at a time");
215 : else
216 : // Sync times for the time steppers are taken from the output warehouse. The output warehouse
217 : // takes sync times from the output objects immediately after the object is constructed. Hence
218 : // we must ensure that we set the `_sync_times` in the constructor
219 15 : _sync_times = _sync_times_object->getUniqueTimes();
220 : }
221 290529 : }
222 :
223 : void
224 684428 : Output::solveSetup()
225 : {
226 684428 : }
227 :
228 : void
229 12232779 : Output::outputStep(const ExecFlagType & type)
230 : {
231 : // Output is not allowed
232 12232779 : if (!_allow_output && type != EXEC_FORCED)
233 3448711 : return;
234 :
235 : // If recovering disable output of initial condition, it was already output
236 12198556 : if (type == EXEC_INITIAL && _app.isRecovering())
237 0 : return;
238 :
239 : // Return if the current output is not on the desired interval and there is
240 : // no signal to process
241 12198556 : const bool on_interval_or_exec_final = (onInterval() || (type == EXEC_FINAL));
242 : // Reduce a copy so MPI cannot overwrite a signal received during the collective.
243 12198553 : int signal_number = Moose::interrupt_signal_number;
244 12198553 : comm().max(signal_number);
245 : // Do not write back zero because the handler may have set the latch after the copy.
246 12198553 : if (signal_number)
247 568 : Moose::interrupt_signal_number = signal_number;
248 12198553 : const bool signal_received = signal_number;
249 12198553 : if (!(on_interval_or_exec_final || signal_received))
250 3414488 : return;
251 :
252 : // set current type
253 8784065 : _current_execute_flag = type;
254 :
255 : // Check whether we should output, then do it.
256 8784065 : if (shouldOutput())
257 : {
258 : // store current simulation time
259 3343292 : _last_output_simulation_time = _time;
260 :
261 : // store current wall time of output
262 3343292 : _last_output_wall_time = std::chrono::steady_clock::now();
263 :
264 16716460 : TIME_SECTION("outputStep", 2, "Outputting Step");
265 3343292 : output();
266 3343286 : }
267 :
268 8784059 : _current_execute_flag = EXEC_NONE;
269 : }
270 :
271 : bool
272 9584953 : Output::shouldOutput()
273 : {
274 9584953 : if (_execute_on.isValueSet(_current_execute_flag) || _current_execute_flag == EXEC_FORCED)
275 3107866 : return true;
276 6477087 : return false;
277 : }
278 :
279 : bool
280 17799921 : Output::onInterval()
281 : {
282 : // The output flag to return
283 17799921 : bool output = false;
284 :
285 : // Return true if the current step on the current output interval and within the output time range
286 : // and within the output step range
287 17799921 : if (_time >= _start_time && _time <= _end_time && _t_step >= _start_step &&
288 17498300 : _t_step <= _end_step && (_t_step % _time_step_interval) == 0)
289 14305876 : output = true;
290 :
291 : // Return false if 'sync_only' is set to true
292 17799921 : if (_sync_only)
293 9575 : output = false;
294 :
295 17799921 : if (_sync_times_object)
296 : {
297 339 : const auto & sync_times = _sync_times_object->getUniqueTimes();
298 339 : if (sync_times != _sync_times)
299 3 : mooseError("The provided sync times object has changing time values. Only static time "
300 : "values are supported since time steppers take sync times from the output "
301 : "warehouse which determines its sync times at output construction time.");
302 336 : }
303 :
304 : // We make sync times have precendence over the other criteria by convention, since they already
305 : // take precedence over start/end step, start/end time, step frequency etc.
306 : //
307 : // Check if enough simulation time has passed between outputs
308 17799918 : if (_time > _last_output_simulation_time &&
309 8825099 : _last_output_simulation_time + _min_simulation_time_interval > _time + _t_tol)
310 1860 : output = false;
311 :
312 : // If sync times are not skipped, return true if the current time is a sync_time
313 17916521 : for (const auto _sync_time : _sync_times)
314 : {
315 116603 : if (std::abs(_sync_time - _time) < _t_tol)
316 5350 : output = true;
317 : }
318 :
319 : // check if enough wall time has passed between outputs
320 17799918 : const auto now = std::chrono::steady_clock::now();
321 : // count below returns an interger type, so lets express on a millisecond
322 : // scale and convert to seconds for finer resolution
323 17799918 : _wall_time_since_last_output =
324 17799918 : std::chrono::duration_cast<std::chrono::milliseconds>(now - _last_output_wall_time).count() /
325 : 1000.0;
326 : // Take the maximum wall time since last output accross all processors
327 17799918 : _communicator.max(_wall_time_since_last_output);
328 17799918 : if (_wall_time_since_last_output >= _wall_time_interval)
329 3338 : output = true;
330 :
331 : // Return the output status
332 17799918 : return output;
333 : }
334 :
335 : void
336 49364 : Output::setWallTimeIntervalFromCommandLineParam()
337 : {
338 148092 : if (_app.isParamValid("output_wall_time_interval"))
339 : {
340 50 : _wall_time_interval = _app.getParam<Real>("output_wall_time_interval");
341 :
342 : // If default value of _wall_time_interval was just overriden and user did not
343 : // explicitly specify _time_step_interval, override default value of
344 : // _time_step_interval so output does not occur after every time step
345 25 : if (_time_step_interval_set_by_addparam)
346 25 : _time_step_interval = std::numeric_limits<unsigned int>::max();
347 : }
348 49364 : }
349 :
350 : Real
351 1123617 : Output::time()
352 : {
353 1123617 : if (_transient)
354 986223 : return _time;
355 : else
356 137394 : return _t_step;
357 : }
358 :
359 : Real
360 7374 : Output::timeOld()
361 : {
362 7374 : if (_transient)
363 7374 : return _time_old;
364 : else
365 0 : return _t_step - 1;
366 : }
367 :
368 : Real
369 240281 : Output::dt()
370 : {
371 240281 : if (_transient)
372 240281 : return _dt;
373 : else
374 0 : return 1;
375 : }
376 :
377 : Real
378 0 : Output::dtOld()
379 : {
380 0 : if (_transient)
381 0 : return _dt_old;
382 : else
383 0 : return 1;
384 : }
385 :
386 : int
387 332769 : Output::timeStep()
388 : {
389 332769 : return _t_step;
390 : }
391 :
392 : const MultiMooseEnum &
393 45 : Output::executeOn() const
394 : {
395 45 : return _execute_on;
396 : }
397 :
398 : bool
399 45 : Output::isAdvanced()
400 : {
401 45 : return _is_advanced;
402 : }
403 :
404 : const OutputOnWarehouse &
405 0 : Output::advancedExecuteOn() const
406 : {
407 0 : mooseError("The output object ", name(), " is not an AdvancedOutput, use isAdvanced() to check.");
408 : return _advanced_execute_on;
409 : }
|