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 1041935 : Output::validParams()
33 : {
34 : // Get the parameters from the parent object
35 1041935 : InputParameters params = MooseObject::validParams();
36 1041935 : params += SetupInterface::validParams();
37 :
38 : // Displaced Mesh options
39 3125805 : params.addParam<bool>(
40 2083870 : "use_displaced", false, "Enable/disable the use of the displaced mesh for outputting");
41 :
42 : // Output intervals and timing
43 5209675 : params.addRangeCheckedParam<unsigned int>(
44 : "time_step_interval",
45 2083870 : 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 3125805 : params.addParam<Real>(
51 2083870 : "min_simulation_time_interval", 0.0, "The minimum simulation time between output steps");
52 3125805 : params.addParam<Real>("simulation_time_interval",
53 2083870 : std::numeric_limits<Real>::max(),
54 : "The target simulation time interval (in seconds) at which to output");
55 5209675 : params.addRangeCheckedParam<Real>(
56 : "wall_time_interval",
57 2083870 : std::numeric_limits<Real>::max(),
58 : "wall_time_interval > 0",
59 : "The target wall time interval (in seconds) at which to output");
60 4167740 : params.addParam<std::vector<Real>>(
61 : "sync_times", {}, "Times at which the output and solution is forced to occur");
62 4167740 : params.addParam<TimesName>(
63 : "sync_times_object",
64 : "Times object providing the times at which the output and solution is forced to occur");
65 4167740 : params.addParam<bool>("sync_only", false, "Only export results at sync times");
66 4167740 : params.addParam<Real>("start_time", "Time at which this output object begins to operate");
67 4167740 : params.addParam<Real>("end_time", "Time at which this output object stop operating");
68 4167740 : params.addParam<int>("start_step", "Time step at which this output object begins to operate");
69 4167740 : params.addParam<int>("end_step", "Time step at which this output object stop operating");
70 3125805 : params.addParam<Real>(
71 2083870 : "time_tolerance", 1e-14, "Time tolerance utilized checking start and end times");
72 6251610 : params.addDeprecatedParam<FunctionName>(
73 : "output_limiting_function",
74 : "Piecewise base function that sets sync_times",
75 : "Replaced by using the Times system with the sync_times_objects parameter");
76 :
77 : // Update the 'execute_on' input parameter for output
78 1041935 : ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
79 1041935 : exec_enum = Output::getDefaultExecFlagEnum();
80 3125805 : exec_enum = {EXEC_INITIAL, EXEC_TIMESTEP_END};
81 3125805 : params.setDocString("execute_on", exec_enum.getDocString());
82 :
83 : // Add ability to append to the 'execute_on' list
84 3125805 : params.addParam<ExecFlagEnum>("additional_execute_on", exec_enum, exec_enum.getDocString());
85 2083870 : params.set<ExecFlagEnum>("additional_execute_on").clearSetValues();
86 4167740 : params.addParamNamesToGroup("execute_on additional_execute_on", "Execution scheduling");
87 :
88 : // 'Timing' group
89 3125805 : params.addParamNamesToGroup("time_tolerance time_step_interval sync_times sync_times_object "
90 : "sync_only start_time end_time "
91 : "start_step end_step min_simulation_time_interval "
92 : "simulation_time_interval wall_time_interval",
93 : "Timing and frequency of output");
94 :
95 : // Add a private parameter for indicating if it was created with short-cut syntax
96 2083870 : params.addPrivateParam<bool>("_built_by_moose", false);
97 :
98 : // Register this class as base class
99 3125805 : params.declareControllable("enable");
100 1041935 : params.registerBase("Output");
101 :
102 1041935 : return params;
103 1041935 : }
104 :
105 : ExecFlagEnum
106 1111328 : Output::getDefaultExecFlagEnum()
107 : {
108 1111328 : ExecFlagEnum exec_enum = MooseUtils::getDefaultExecFlagEnum();
109 1111328 : exec_enum.addAvailableFlags(EXEC_FAILED);
110 1111328 : return exec_enum;
111 0 : }
112 :
113 297797 : Output::Output(const InputParameters & parameters)
114 : : MooseObject(parameters),
115 : Restartable(this, "Output"),
116 : MeshChangedInterface(parameters),
117 : SetupInterface(this),
118 : FunctionInterface(this),
119 : PostprocessorInterface(this),
120 : VectorPostprocessorInterface(this),
121 : ReporterInterface(this),
122 : PerfGraphInterface(this),
123 297797 : _problem_ptr(getParam<FEProblemBase *>("_fe_problem_base")),
124 297797 : _transient(_problem_ptr->isTransient()),
125 595594 : _use_displaced(getParam<bool>("use_displaced")),
126 297797 : _es_ptr(nullptr),
127 297797 : _mesh_ptr(nullptr),
128 595594 : _execute_on(getParam<ExecFlagEnum>("execute_on")),
129 297797 : _current_execute_flag(EXEC_NONE),
130 297797 : _time(_problem_ptr->time()),
131 297797 : _time_old(_problem_ptr->timeOld()),
132 297797 : _t_step(_problem_ptr->timeStep()),
133 297797 : _dt(_problem_ptr->dt()),
134 297797 : _dt_old(_problem_ptr->dtOld()),
135 297797 : _num(0),
136 297797 : _time_step_interval_set_by_addparam(parameters.isParamSetByAddParam("time_step_interval")),
137 : // If wall_time_interval is user-specified and time_step_interval is not,
138 : // override default value of time_step_interval so output does not occur
139 : // after every time step.
140 297797 : _time_step_interval(
141 595609 : (parameters.isParamSetByUser("wall_time_interval") && _time_step_interval_set_by_addparam)
142 595594 : ? std::numeric_limits<unsigned int>::max()
143 893391 : : getParam<unsigned int>("time_step_interval")),
144 595594 : _min_simulation_time_interval(getParam<Real>("min_simulation_time_interval")),
145 595594 : _simulation_time_interval(getParam<Real>("simulation_time_interval")),
146 595594 : _wall_time_interval(getParam<Real>("wall_time_interval")),
147 595594 : _sync_times(std::set<Real>(getParam<std::vector<Real>>("sync_times").begin(),
148 893391 : getParam<std::vector<Real>>("sync_times").end())),
149 595594 : _sync_times_object(isParamValid("sync_times_object")
150 297814 : ? static_cast<Times *>(&_problem_ptr->getUserObject<Times>(
151 297848 : getParam<TimesName>("sync_times_object")))
152 : : nullptr),
153 893417 : _start_time(isParamValid("start_time") ? getParam<Real>("start_time")
154 297771 : : std::numeric_limits<Real>::lowest()),
155 893417 : _end_time(isParamValid("end_time") ? getParam<Real>("end_time")
156 297771 : : std::numeric_limits<Real>::max()),
157 894169 : _start_step(isParamValid("start_step") ? getParam<int>("start_step")
158 297019 : : std::numeric_limits<int>::lowest()),
159 893417 : _end_step(isParamValid("end_step") ? getParam<int>("end_step")
160 297771 : : std::numeric_limits<int>::max()),
161 595594 : _t_tol(getParam<Real>("time_tolerance")),
162 595594 : _sync_only(getParam<bool>("sync_only")),
163 297797 : _allow_output(true),
164 297797 : _is_advanced(false),
165 297797 : _advanced_execute_on(_execute_on, parameters),
166 297797 : _last_output_simulation_time(declareRestartableData<Real>("last_output_simulation_time",
167 297797 : std::numeric_limits<Real>::lowest())),
168 1191188 : _last_output_wall_time(std::chrono::steady_clock::now())
169 : {
170 297797 : if (_use_displaced)
171 : {
172 155 : std::shared_ptr<DisplacedProblem> dp = _problem_ptr->getDisplacedProblem();
173 155 : if (dp != nullptr)
174 : {
175 147 : _es_ptr = &dp->es();
176 147 : _mesh_ptr = &dp->mesh();
177 : }
178 : else
179 : {
180 8 : mooseWarning(
181 8 : name(),
182 : ": Parameter 'use_displaced' ignored, there is no displaced problem in your simulation.");
183 0 : _es_ptr = &_problem_ptr->es();
184 0 : _mesh_ptr = &_problem_ptr->mesh();
185 : }
186 147 : }
187 : else
188 : {
189 297642 : _es_ptr = &_problem_ptr->es();
190 297642 : _mesh_ptr = &_problem_ptr->mesh();
191 : }
192 :
193 : // Apply the additional output flags
194 893367 : if (isParamValid("additional_execute_on"))
195 : {
196 40 : const ExecFlagEnum & add = getParam<ExecFlagEnum>("additional_execute_on");
197 40 : for (auto & me : add)
198 20 : _execute_on.setAdditionalValue(me);
199 : }
200 :
201 893367 : if (isParamValid("output_limiting_function"))
202 : {
203 26 : const Function & olf = getFunction("output_limiting_function");
204 13 : const PiecewiseBase * pwb_olf = dynamic_cast<const PiecewiseBase *>(&olf);
205 13 : if (pwb_olf == nullptr)
206 0 : mooseError("Function muse have a piecewise base!");
207 :
208 52 : for (auto i = 0; i < pwb_olf->functionSize(); i++)
209 39 : _sync_times.insert(pwb_olf->domain(i));
210 : }
211 :
212 : // Get sync times from Times object if using
213 297789 : if (_sync_times_object)
214 : {
215 85 : if (isParamValid("output_limiting_function") || isParamSetByUser("sync_times"))
216 0 : paramError("sync_times_object",
217 : "Only one method of specifying sync times is supported at a time");
218 : else
219 : // Sync times for the time steppers are taken from the output warehouse. The output warehouse
220 : // takes sync times from the output objects immediately after the object is constructed. Hence
221 : // we must ensure that we set the `_sync_times` in the constructor
222 17 : _sync_times = _sync_times_object->getUniqueTimes();
223 : }
224 297789 : }
225 :
226 : void
227 735729 : Output::solveSetup()
228 : {
229 735729 : }
230 :
231 : void
232 13221604 : Output::outputStep(const ExecFlagType & type)
233 : {
234 : // Output is not allowed
235 13221604 : if (!_allow_output && type != EXEC_FORCED)
236 38428 : return;
237 :
238 : // If recovering disable output of initial condition, it was already output
239 13183176 : if (type == EXEC_INITIAL && _app.isRecovering())
240 0 : return;
241 :
242 : // Return if the current output is not on the desired interval and there is
243 : // no signal to process
244 13183176 : const bool on_interval_or_exec_final = (onInterval() || (type == EXEC_FINAL));
245 : // Sync across processes and only output one time per signal received.
246 13183172 : comm().max(Moose::interrupt_signal_number);
247 13183172 : const bool signal_received = Moose::interrupt_signal_number;
248 13183172 : if (!(on_interval_or_exec_final || signal_received))
249 394733 : return;
250 :
251 : // set current type
252 12788439 : _current_execute_flag = type;
253 :
254 : // Check whether we should output, then do it.
255 12788439 : if (shouldOutput())
256 : {
257 : // store current simulation time
258 4281428 : _last_output_simulation_time = _time;
259 :
260 : // store current wall time of output
261 4281428 : _last_output_wall_time = std::chrono::steady_clock::now();
262 :
263 21407140 : TIME_SECTION("outputStep", 2, "Outputting Step");
264 4281428 : output();
265 4281420 : }
266 :
267 12788431 : _current_execute_flag = EXEC_NONE;
268 : }
269 :
270 : bool
271 13684870 : Output::shouldOutput()
272 : {
273 13684870 : if (_execute_on.isValueSet(_current_execute_flag) || _current_execute_flag == EXEC_FORCED)
274 4225183 : return true;
275 9459687 : return false;
276 : }
277 :
278 : bool
279 19917420 : Output::onInterval()
280 : {
281 : // The output flag to return
282 19917420 : bool output = false;
283 :
284 : // Return true if the current step on the current output interval and within the output time range
285 : // and within the output step range
286 19917420 : if (_time >= _start_time && _time <= _end_time && _t_step >= _start_step &&
287 19596071 : _t_step <= _end_step && (_t_step % _time_step_interval) == 0)
288 19478822 : output = true;
289 :
290 : // Return false if 'sync_only' is set to true
291 19917420 : if (_sync_only)
292 10478 : output = false;
293 :
294 19917420 : if (_sync_times_object)
295 : {
296 372 : const auto & sync_times = _sync_times_object->getUniqueTimes();
297 372 : if (sync_times != _sync_times)
298 4 : mooseError("The provided sync times object has changing time values. Only static time "
299 : "values are supported since time steppers take sync times from the output "
300 : "warehouse which determines its sync times at output construction time.");
301 368 : }
302 :
303 : // If sync times are not skipped, return true if the current time is a sync_time
304 20109212 : for (const auto _sync_time : _sync_times)
305 : {
306 191796 : if (std::abs(_sync_time - _time) < _t_tol)
307 7365 : output = true;
308 : }
309 :
310 : // check if enough simulation time has passed between outputs
311 19917416 : if (_time > _last_output_simulation_time &&
312 8984026 : _last_output_simulation_time + _min_simulation_time_interval > _time + _t_tol)
313 2038 : output = false;
314 :
315 : // check if enough wall time has passed between outputs
316 19917416 : const auto now = std::chrono::steady_clock::now();
317 : // count below returns an interger type, so lets express on a millisecond
318 : // scale and convert to seconds for finer resolution
319 19917416 : _wall_time_since_last_output =
320 19917416 : std::chrono::duration_cast<std::chrono::milliseconds>(now - _last_output_wall_time).count() /
321 : 1000.0;
322 : // Take the maximum wall time since last output accross all processors
323 19917416 : _communicator.max(_wall_time_since_last_output);
324 19917416 : if (_wall_time_since_last_output >= _wall_time_interval)
325 5325 : output = true;
326 :
327 : // Return the output status
328 19917416 : return output;
329 : }
330 :
331 : void
332 50954 : Output::setWallTimeIntervalFromCommandLineParam()
333 : {
334 152862 : if (_app.isParamValid("output_wall_time_interval"))
335 : {
336 110 : _wall_time_interval = _app.getParam<Real>("output_wall_time_interval");
337 :
338 : // If default value of _wall_time_interval was just overriden and user did not
339 : // explicitly specify _time_step_interval, override default value of
340 : // _time_step_interval so output does not occur after every time step
341 55 : if (_time_step_interval_set_by_addparam)
342 55 : _time_step_interval = std::numeric_limits<unsigned int>::max();
343 : }
344 50954 : }
345 :
346 : Real
347 1239858 : Output::time()
348 : {
349 1239858 : if (_transient)
350 1088151 : return _time;
351 : else
352 151707 : return _t_step;
353 : }
354 :
355 : Real
356 8227 : Output::timeOld()
357 : {
358 8227 : if (_transient)
359 8227 : return _time_old;
360 : else
361 0 : return _t_step - 1;
362 : }
363 :
364 : Real
365 259329 : Output::dt()
366 : {
367 259329 : if (_transient)
368 259329 : return _dt;
369 : else
370 0 : return 1;
371 : }
372 :
373 : Real
374 0 : Output::dtOld()
375 : {
376 0 : if (_transient)
377 0 : return _dt_old;
378 : else
379 0 : return 1;
380 : }
381 :
382 : int
383 356539 : Output::timeStep()
384 : {
385 356539 : return _t_step;
386 : }
387 :
388 : const MultiMooseEnum &
389 50 : Output::executeOn() const
390 : {
391 50 : return _execute_on;
392 : }
393 :
394 : bool
395 50 : Output::isAdvanced()
396 : {
397 50 : return _is_advanced;
398 : }
399 :
400 : const OutputOnWarehouse &
401 0 : Output::advancedExecuteOn() const
402 : {
403 0 : mooseError("The output object ", name(), " is not an AdvancedOutput, use isAdvanced() to check.");
404 : return _advanced_execute_on;
405 : }
|