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