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 675100 : Output::validParams()
33 : {
34 : // Get the parameters from the parent object
35 675100 : InputParameters params = MooseObject::validParams();
36 675100 : params += SetupInterface::validParams();
37 :
38 : // Displaced Mesh options
39 2025300 : params.addParam<bool>(
40 1350200 : "use_displaced", false, "Enable/disable the use of the displaced mesh for outputting");
41 :
42 : // Output intervals and timing
43 3375500 : params.addRangeCheckedParam<unsigned int>(
44 : "time_step_interval",
45 1350200 : 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 2025300 : params.addParam<Real>(
51 1350200 : "min_simulation_time_interval", 0.0, "The minimum simulation time between output steps");
52 3375500 : params.addRangeCheckedParam<Real>(
53 : "wall_time_interval",
54 1350200 : std::numeric_limits<Real>::max(),
55 : "wall_time_interval > 0",
56 : "The target wall time interval (in seconds) at which to output");
57 2700400 : params.setDocUnit("wall_time_interval", "seconds");
58 2700400 : params.addParam<std::vector<Real>>(
59 : "sync_times", {}, "Times at which the output and solution is forced to occur");
60 2700400 : params.addParam<TimesName>(
61 : "sync_times_object",
62 : "Times object providing the times at which the output and solution is forced to occur");
63 2700400 : params.addParam<bool>("sync_only", false, "Only export results at sync times");
64 2700400 : params.addParam<Real>("start_time", "Time at which this output object begins to operate");
65 2700400 : params.addParam<Real>("end_time", "Time at which this output object stop operating");
66 2700400 : params.addParam<int>("start_step", "Time step at which this output object begins to operate");
67 2700400 : params.addParam<int>("end_step", "Time step at which this output object stop operating");
68 2025300 : params.addParam<Real>(
69 1350200 : "time_tolerance", 1e-14, "Time tolerance utilized checking start and end times");
70 4050600 : 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 675100 : ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
77 675100 : exec_enum = Output::getDefaultExecFlagEnum();
78 2025300 : exec_enum = {EXEC_INITIAL, EXEC_TIMESTEP_END};
79 2025300 : params.setDocString("execute_on", exec_enum.getDocString());
80 :
81 : // Add ability to append to the 'execute_on' list
82 2025300 : params.addParam<ExecFlagEnum>("additional_execute_on", exec_enum, exec_enum.getDocString());
83 1350200 : params.set<ExecFlagEnum>("additional_execute_on").clearSetValues();
84 2700400 : params.addParamNamesToGroup("execute_on additional_execute_on", "Execution scheduling");
85 :
86 : // 'Timing' group
87 2025300 : 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 1350200 : params.addPrivateParam<bool>("_built_by_moose", false);
95 :
96 : // Register this class as base class
97 2025300 : params.declareControllable("enable");
98 675100 : params.registerBase("Output");
99 :
100 675100 : return params;
101 675100 : }
102 :
103 : ExecFlagEnum
104 741181 : Output::getDefaultExecFlagEnum()
105 : {
106 741181 : ExecFlagEnum exec_enum = MooseUtils::getDefaultExecFlagEnum();
107 741181 : exec_enum.addAvailableFlags(EXEC_FAILED);
108 741181 : return exec_enum;
109 0 : }
110 :
111 285103 : 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 285103 : _problem_ptr(getParam<FEProblemBase *>("_fe_problem_base")),
122 285103 : _transient(_problem_ptr->isTransient()),
123 570206 : _use_displaced(getParam<bool>("use_displaced")),
124 285103 : _es_ptr(nullptr),
125 285103 : _mesh_ptr(nullptr),
126 570206 : _execute_on(getParam<ExecFlagEnum>("execute_on")),
127 285103 : _current_execute_flag(EXEC_NONE),
128 285103 : _time(_problem_ptr->time()),
129 285103 : _time_old(_problem_ptr->timeOld()),
130 285103 : _t_step(_problem_ptr->timeStep()),
131 285103 : _dt(_problem_ptr->dt()),
132 285103 : _dt_old(_problem_ptr->dtOld()),
133 285103 : _num(0),
134 285103 : _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 285103 : _time_step_interval(
139 570213 : (parameters.isParamSetByUser("wall_time_interval") && _time_step_interval_set_by_addparam)
140 570206 : ? std::numeric_limits<unsigned int>::max()
141 855309 : : getParam<unsigned int>("time_step_interval")),
142 570206 : _min_simulation_time_interval(getParam<Real>("min_simulation_time_interval")),
143 570206 : _wall_time_interval(getParam<Real>("wall_time_interval")),
144 570206 : _sync_times(std::set<Real>(getParam<std::vector<Real>>("sync_times").begin(),
145 855309 : getParam<std::vector<Real>>("sync_times").end())),
146 570206 : _sync_times_object(isParamValid("sync_times_object")
147 285118 : ? static_cast<Times *>(&_problem_ptr->getUserObject<Times>(
148 285148 : getParam<TimesName>("sync_times_object")))
149 : : nullptr),
150 855323 : _start_time(isParamValid("start_time") ? getParam<Real>("start_time")
151 285089 : : std::numeric_limits<Real>::lowest()),
152 855323 : _end_time(isParamValid("end_time") ? getParam<Real>("end_time")
153 285089 : : std::numeric_limits<Real>::max()),
154 856025 : _start_step(isParamValid("start_step") ? getParam<int>("start_step")
155 284387 : : std::numeric_limits<int>::lowest()),
156 855333 : _end_step(isParamValid("end_step") ? getParam<int>("end_step")
157 285079 : : std::numeric_limits<int>::max()),
158 570206 : _t_tol(getParam<Real>("time_tolerance")),
159 570206 : _sync_only(getParam<bool>("sync_only")),
160 285103 : _allow_output(true),
161 285103 : _is_advanced(false),
162 285103 : _advanced_execute_on(_execute_on, parameters),
163 285103 : _last_output_simulation_time(declareRestartableData<Real>("last_output_simulation_time",
164 285103 : std::numeric_limits<Real>::lowest())),
165 1140412 : _last_output_wall_time(std::chrono::steady_clock::now())
166 : {
167 285103 : 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 284974 : _es_ptr = &_problem_ptr->es();
187 284974 : _mesh_ptr = &_problem_ptr->mesh();
188 : }
189 :
190 : // Apply the additional output flags
191 855291 : 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 855291 : 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 285097 : 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 285097 : }
222 :
223 : void
224 675444 : Output::solveSetup()
225 : {
226 675444 : }
227 :
228 : void
229 12171966 : Output::outputStep(const ExecFlagType & type)
230 : {
231 : // Output is not allowed
232 12171966 : if (!_allow_output && type != EXEC_FORCED)
233 34943 : return;
234 :
235 : // If recovering disable output of initial condition, it was already output
236 12137023 : 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 12137023 : const bool on_interval_or_exec_final = (onInterval() || (type == EXEC_FINAL));
242 : // Sync across processes and only output one time per signal received.
243 12137020 : comm().max(Moose::interrupt_signal_number);
244 12137020 : const bool signal_received = Moose::interrupt_signal_number;
245 12137020 : if (!(on_interval_or_exec_final || signal_received))
246 3407355 : return;
247 :
248 : // set current type
249 8729665 : _current_execute_flag = type;
250 :
251 : // Check whether we should output, then do it.
252 8729665 : if (shouldOutput())
253 : {
254 : // store current simulation time
255 3320482 : _last_output_simulation_time = _time;
256 :
257 : // store current wall time of output
258 3320482 : _last_output_wall_time = std::chrono::steady_clock::now();
259 :
260 16602410 : TIME_SECTION("outputStep", 2, "Outputting Step");
261 3320482 : output();
262 3320476 : }
263 :
264 8729659 : _current_execute_flag = EXEC_NONE;
265 : }
266 :
267 : bool
268 9545124 : Output::shouldOutput()
269 : {
270 9545124 : if (_execute_on.isValueSet(_current_execute_flag) || _current_execute_flag == EXEC_FORCED)
271 3092632 : return true;
272 6452492 : return false;
273 : }
274 :
275 : bool
276 17711789 : Output::onInterval()
277 : {
278 : // The output flag to return
279 17711789 : bool output = false;
280 :
281 : // Return true if the current step on the current output interval and within the output time range
282 : // and within the output step range
283 17711789 : if (_time >= _start_time && _time <= _end_time && _t_step >= _start_step &&
284 17410170 : _t_step <= _end_step && (_t_step % _time_step_interval) == 0)
285 14225991 : output = true;
286 :
287 : // Return false if 'sync_only' is set to true
288 17711789 : if (_sync_only)
289 9575 : output = false;
290 :
291 17711789 : if (_sync_times_object)
292 : {
293 339 : const auto & sync_times = _sync_times_object->getUniqueTimes();
294 339 : if (sync_times != _sync_times)
295 3 : mooseError("The provided sync times object has changing time values. Only static time "
296 : "values are supported since time steppers take sync times from the output "
297 : "warehouse which determines its sync times at output construction time.");
298 336 : }
299 :
300 : // We make sync times have precendence over the other criteria by convention, since they already
301 : // take precedence over start/end step, start/end time, step frequency etc.
302 : //
303 : // Check if enough simulation time has passed between outputs
304 17711786 : if (_time > _last_output_simulation_time &&
305 8782984 : _last_output_simulation_time + _min_simulation_time_interval > _time + _t_tol)
306 1860 : output = false;
307 :
308 : // If sync times are not skipped, return true if the current time is a sync_time
309 17828416 : for (const auto _sync_time : _sync_times)
310 : {
311 116630 : if (std::abs(_sync_time - _time) < _t_tol)
312 5356 : output = true;
313 : }
314 :
315 : // check if enough wall time has passed between outputs
316 17711786 : 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 17711786 : _wall_time_since_last_output =
320 17711786 : 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 17711786 : _communicator.max(_wall_time_since_last_output);
324 17711786 : if (_wall_time_since_last_output >= _wall_time_interval)
325 3280 : output = true;
326 :
327 : // Return the output status
328 17711786 : return output;
329 : }
330 :
331 : void
332 48324 : Output::setWallTimeIntervalFromCommandLineParam()
333 : {
334 144972 : if (_app.isParamValid("output_wall_time_interval"))
335 : {
336 50 : _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 25 : if (_time_step_interval_set_by_addparam)
342 25 : _time_step_interval = std::numeric_limits<unsigned int>::max();
343 : }
344 48324 : }
345 :
346 : Real
347 1093274 : Output::time()
348 : {
349 1093274 : if (_transient)
350 960152 : return _time;
351 : else
352 133122 : return _t_step;
353 : }
354 :
355 : Real
356 7327 : Output::timeOld()
357 : {
358 7327 : if (_transient)
359 7327 : return _time_old;
360 : else
361 0 : return _t_step - 1;
362 : }
363 :
364 : Real
365 235887 : Output::dt()
366 : {
367 235887 : if (_transient)
368 235887 : 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 326245 : Output::timeStep()
384 : {
385 326245 : return _t_step;
386 : }
387 :
388 : const MultiMooseEnum &
389 45 : Output::executeOn() const
390 : {
391 45 : return _execute_on;
392 : }
393 :
394 : bool
395 45 : Output::isAdvanced()
396 : {
397 45 : 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 : }
|