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 683736 : Output::validParams()
33 : {
34 : // Get the parameters from the parent object
35 683736 : InputParameters params = MooseObject::validParams();
36 683736 : params += SetupInterface::validParams();
37 :
38 : // Displaced Mesh options
39 2051208 : params.addParam<bool>(
40 1367472 : "use_displaced", false, "Enable/disable the use of the displaced mesh for outputting");
41 :
42 : // Output intervals and timing
43 3418680 : params.addRangeCheckedParam<unsigned int>(
44 : "time_step_interval",
45 1367472 : 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 2051208 : params.addParam<Real>(
51 1367472 : "min_simulation_time_interval", 0.0, "The minimum simulation time between output steps");
52 3418680 : params.addRangeCheckedParam<Real>(
53 : "wall_time_interval",
54 1367472 : std::numeric_limits<Real>::max(),
55 : "wall_time_interval > 0",
56 : "The target wall time interval (in seconds) at which to output");
57 2734944 : params.setDocUnit("wall_time_interval", "seconds");
58 2734944 : params.addParam<std::vector<Real>>(
59 : "sync_times", {}, "Times at which the output and solution is forced to occur");
60 2734944 : params.addParam<TimesName>(
61 : "sync_times_object",
62 : "Times object providing the times at which the output and solution is forced to occur");
63 2734944 : params.addParam<bool>("sync_only", false, "Only export results at sync times");
64 2734944 : params.addParam<Real>("start_time", "Time at which this output object begins to operate");
65 2734944 : params.addParam<Real>("end_time", "Time at which this output object stop operating");
66 2734944 : params.addParam<int>("start_step", "Time step at which this output object begins to operate");
67 2734944 : params.addParam<int>("end_step", "Time step at which this output object stop operating");
68 2051208 : params.addParam<Real>(
69 1367472 : "time_tolerance", 1e-14, "Time tolerance utilized checking start and end times");
70 4102416 : 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 683736 : ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
77 683736 : exec_enum = Output::getDefaultExecFlagEnum();
78 2051208 : exec_enum = {EXEC_INITIAL, EXEC_TIMESTEP_END};
79 2051208 : params.setDocString("execute_on", exec_enum.getDocString());
80 :
81 : // Add ability to append to the 'execute_on' list
82 2051208 : params.addParam<ExecFlagEnum>("additional_execute_on", exec_enum, exec_enum.getDocString());
83 1367472 : params.set<ExecFlagEnum>("additional_execute_on").clearSetValues();
84 2734944 : params.addParamNamesToGroup("execute_on additional_execute_on", "Execution scheduling");
85 :
86 : // 'Timing' group
87 2051208 : 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 1367472 : params.addPrivateParam<bool>("_built_by_moose", false);
95 :
96 : // Register this class as base class
97 2051208 : params.declareControllable("enable");
98 683736 : params.registerBase("Output");
99 :
100 683736 : return params;
101 683736 : }
102 :
103 : ExecFlagEnum
104 750687 : Output::getDefaultExecFlagEnum()
105 : {
106 750687 : ExecFlagEnum exec_enum = MooseUtils::getDefaultExecFlagEnum();
107 750687 : exec_enum.addAvailableFlags(EXEC_FAILED);
108 750687 : return exec_enum;
109 0 : }
110 :
111 289006 : 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 289006 : _problem_ptr(getParam<FEProblemBase *>("_fe_problem_base")),
122 289006 : _transient(_problem_ptr->isTransient()),
123 578012 : _use_displaced(getParam<bool>("use_displaced")),
124 289006 : _es_ptr(nullptr),
125 289006 : _mesh_ptr(nullptr),
126 578012 : _execute_on(getParam<ExecFlagEnum>("execute_on")),
127 289006 : _current_execute_flag(EXEC_NONE),
128 289006 : _time(_problem_ptr->time()),
129 289006 : _time_old(_problem_ptr->timeOld()),
130 289006 : _t_step(_problem_ptr->timeStep()),
131 289006 : _dt(_problem_ptr->dt()),
132 289006 : _dt_old(_problem_ptr->dtOld()),
133 289006 : _num(0),
134 289006 : _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 289006 : _time_step_interval(
139 578019 : (parameters.isParamSetByUser("wall_time_interval") && _time_step_interval_set_by_addparam)
140 578012 : ? std::numeric_limits<unsigned int>::max()
141 867018 : : getParam<unsigned int>("time_step_interval")),
142 578012 : _min_simulation_time_interval(getParam<Real>("min_simulation_time_interval")),
143 578012 : _wall_time_interval(getParam<Real>("wall_time_interval")),
144 578012 : _sync_times(std::set<Real>(getParam<std::vector<Real>>("sync_times").begin(),
145 867018 : getParam<std::vector<Real>>("sync_times").end())),
146 578012 : _sync_times_object(isParamValid("sync_times_object")
147 289021 : ? static_cast<Times *>(&_problem_ptr->getUserObject<Times>(
148 289051 : getParam<TimesName>("sync_times_object")))
149 : : nullptr),
150 867032 : _start_time(isParamValid("start_time") ? getParam<Real>("start_time")
151 288992 : : std::numeric_limits<Real>::lowest()),
152 867032 : _end_time(isParamValid("end_time") ? getParam<Real>("end_time")
153 288992 : : std::numeric_limits<Real>::max()),
154 867734 : _start_step(isParamValid("start_step") ? getParam<int>("start_step")
155 288290 : : std::numeric_limits<int>::lowest()),
156 867042 : _end_step(isParamValid("end_step") ? getParam<int>("end_step")
157 288982 : : std::numeric_limits<int>::max()),
158 578012 : _t_tol(getParam<Real>("time_tolerance")),
159 578012 : _sync_only(getParam<bool>("sync_only")),
160 289006 : _allow_output(true),
161 289006 : _is_advanced(false),
162 289006 : _advanced_execute_on(_execute_on, parameters),
163 289006 : _last_output_simulation_time(declareRestartableData<Real>("last_output_simulation_time",
164 289006 : std::numeric_limits<Real>::lowest())),
165 1156024 : _last_output_wall_time(std::chrono::steady_clock::now())
166 : {
167 289006 : 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 288877 : _es_ptr = &_problem_ptr->es();
187 288877 : _mesh_ptr = &_problem_ptr->mesh();
188 : }
189 :
190 : // Apply the additional output flags
191 867000 : 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 867000 : 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 289000 : 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 289000 : }
222 :
223 : void
224 683652 : Output::solveSetup()
225 : {
226 683652 : }
227 :
228 : void
229 12220582 : Output::outputStep(const ExecFlagType & type)
230 : {
231 : // Output is not allowed
232 12220582 : if (!_allow_output && type != EXEC_FORCED)
233 3446186 : return;
234 :
235 : // If recovering disable output of initial condition, it was already output
236 12186359 : 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 12186359 : 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 12186356 : int signal_number = Moose::interrupt_signal_number;
244 12186356 : comm().max(signal_number);
245 : // Do not write back zero because the handler may have set the latch after the copy.
246 12186356 : if (signal_number)
247 571 : Moose::interrupt_signal_number = signal_number;
248 12186356 : const bool signal_received = signal_number;
249 12186356 : if (!(on_interval_or_exec_final || signal_received))
250 3411963 : return;
251 :
252 : // set current type
253 8774393 : _current_execute_flag = type;
254 :
255 : // Check whether we should output, then do it.
256 8774393 : if (shouldOutput())
257 : {
258 : // store current simulation time
259 3340486 : _last_output_simulation_time = _time;
260 :
261 : // store current wall time of output
262 3340486 : _last_output_wall_time = std::chrono::steady_clock::now();
263 :
264 16702430 : TIME_SECTION("outputStep", 2, "Outputting Step");
265 3340486 : output();
266 3340480 : }
267 :
268 8774387 : _current_execute_flag = EXEC_NONE;
269 : }
270 :
271 : bool
272 9575817 : Output::shouldOutput()
273 : {
274 9575817 : if (_execute_on.isValueSet(_current_execute_flag) || _current_execute_flag == EXEC_FORCED)
275 3105748 : return true;
276 6470069 : return false;
277 : }
278 :
279 : bool
280 17783562 : Output::onInterval()
281 : {
282 : // The output flag to return
283 17783562 : 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 17783562 : if (_time >= _start_time && _time <= _end_time && _t_step >= _start_step &&
288 17481941 : _t_step <= _end_step && (_t_step % _time_step_interval) == 0)
289 14292252 : output = true;
290 :
291 : // Return false if 'sync_only' is set to true
292 17783562 : if (_sync_only)
293 9575 : output = false;
294 :
295 17783562 : 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 17783559 : if (_time > _last_output_simulation_time &&
309 8814557 : _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 17900162 : 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 17783559 : 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 17783559 : _wall_time_since_last_output =
324 17783559 : 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 17783559 : _communicator.max(_wall_time_since_last_output);
328 17783559 : if (_wall_time_since_last_output >= _wall_time_interval)
329 3442 : output = true;
330 :
331 : // Return the output status
332 17783559 : return output;
333 : }
334 :
335 : void
336 49023 : Output::setWallTimeIntervalFromCommandLineParam()
337 : {
338 147069 : 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 49023 : }
349 :
350 : Real
351 1122682 : Output::time()
352 : {
353 1122682 : if (_transient)
354 986041 : return _time;
355 : else
356 136641 : 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 240061 : Output::dt()
370 : {
371 240061 : if (_transient)
372 240061 : 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 332091 : Output::timeStep()
388 : {
389 332091 : 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 : }
|