LCOV - code coverage report
Current view: top level - src/outputs - Output.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 181 195 92.8 %
Date: 2025-07-17 01:28:37 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      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             : }

Generated by: LCOV version 1.14