LCOV - code coverage report
Current view: top level - src/outputs - Output.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 175 189 92.6 %
Date: 2026-05-29 20:35:17 Functions: 14 16 87.5 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.14