LCOV - code coverage report
Current view: top level - src/userobjects - Terminator.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 76 80 95.0 %
Date: 2025-07-17 01:28:37 Functions: 5 5 100.0 %
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             : #include "libmesh/libmesh_config.h"
      11             : 
      12             : #ifdef LIBMESH_HAVE_FPARSER
      13             : 
      14             : #include "Terminator.h"
      15             : #include "MooseApp.h"
      16             : #include "MooseEnum.h"
      17             : #include "Executioner.h"
      18             : 
      19             : registerMooseObject("MooseApp", Terminator);
      20             : 
      21             : InputParameters
      22       14559 : Terminator::validParams()
      23             : {
      24       14559 :   InputParameters params = GeneralUserObject::validParams();
      25       14559 :   params.addClassDescription("Requests termination of the current solve based on the evaluation of"
      26             :                              " a parsed logical expression of the Postprocessor value(s).");
      27       14559 :   params.addRequiredCustomTypeParam<std::string>(
      28             :       "expression",
      29             :       "FunctionExpression",
      30             :       "FParser expression to process Postprocessor values into a boolean value. "
      31             :       "Termination of the simulation occurs when this returns true.");
      32       14559 :   MooseEnum failModeOption("HARD SOFT NONE", "HARD");
      33       14559 :   params.addParam<MooseEnum>(
      34             :       "fail_mode",
      35             :       failModeOption,
      36             :       "Abort entire simulation (HARD), just the current time step (SOFT), or not at all (NONE).");
      37       14559 :   params.addParam<std::string>("message",
      38             :                                "An optional message to be output instead of the default message "
      39             :                                "when the termination condition is triggered");
      40             : 
      41       14559 :   MooseEnum errorLevel("INFO WARNING ERROR NONE", "INFO");
      42       14559 :   errorLevel.addDocumentation("INFO", "Output an information message once.");
      43       14559 :   errorLevel.addDocumentation("WARNING", "Output a warning message once.");
      44       14559 :   errorLevel.addDocumentation("ERROR",
      45             :                               "Throw a MOOSE error, resulting in the termination of the run.");
      46       14559 :   errorLevel.addDocumentation("NONE", "No message will be printed.");
      47       14559 :   params.addParam<MooseEnum>(
      48             :       "error_level",
      49             :       errorLevel,
      50             :       "The error level for the message. A level of ERROR will always lead to a hard "
      51             :       "termination of the entire simulation.");
      52       29118 :   return params;
      53       14559 : }
      54             : 
      55         150 : Terminator::Terminator(const InputParameters & parameters)
      56             :   : GeneralUserObject(parameters),
      57         150 :     _fail_mode(getParam<MooseEnum>("fail_mode").getEnum<FailMode>()),
      58         150 :     _msg_type(getParam<MooseEnum>("error_level").getEnum<MessageType>()),
      59         150 :     _pp_names(),
      60         150 :     _pp_values(),
      61         150 :     _expression(getParam<std::string>("expression")),
      62         300 :     _fp()
      63             : {
      64             :   // sanity check the parameters
      65         150 :   if (_msg_type == MessageType::ERROR && _fail_mode != FailMode::HARD)
      66           4 :     paramError("error_level",
      67             :                "Setting the error level to ERROR always causes a hard failure, which is "
      68             :                "incompatible with `fail_mode=SOFT or NONE`.");
      69         146 :   if (_msg_type == MessageType::NONE && isParamValid("message"))
      70           4 :     paramError("error_level",
      71             :                "Cannot specify `error_level=NONE` together with the `message` parameter.");
      72         142 :   if (_msg_type == MessageType::NONE && _fail_mode == FailMode::NONE)
      73           0 :     paramWarning("error_level",
      74             :                  "With the current error level and fail mode settings, the terminator will not "
      75             :                  "error or output.");
      76             : 
      77             :   // build the expression object
      78         142 :   if (_fp.ParseAndDeduceVariables(_expression, _pp_names) >= 0)
      79           0 :     mooseError(std::string("Invalid function\n" + _expression + "\nin Terminator.\n") +
      80             :                _fp.ErrorMsg());
      81             : 
      82         142 :   _pp_num = _pp_names.size();
      83         142 :   _pp_values.resize(_pp_num);
      84             : 
      85             :   // get all necessary postprocessors
      86         284 :   for (unsigned int i = 0; i < _pp_num; ++i)
      87         142 :     _pp_values[i] = &getPostprocessorValueByName(_pp_names[i]);
      88             : 
      89         142 :   _params.resize(_pp_num);
      90         142 : }
      91             : 
      92             : void
      93         142 : Terminator::initialSetup()
      94             : {
      95             :   // Check execution schedule of the postprocessors
      96         142 :   if (_fail_mode == FailMode::SOFT || _fail_mode == FailMode::NONE)
      97          92 :     for (const auto i : make_range(_pp_num))
      98             :     // Make sure the postprocessor is executed at least as often
      99             :     {
     100          48 :       const auto & pp_exec = _fe_problem.getUserObjectBase(_pp_names[i], _tid).getExecuteOnEnum();
     101          92 :       for (const auto & flag : getExecuteOnEnum())
     102          48 :         if (!pp_exec.isValueSet(flag) && flag != EXEC_FINAL)
     103           4 :           paramWarning("expression",
     104           4 :                        "Postprocessor '" + _pp_names[i] + "' is not executed on " + flag.name() +
     105             :                            ", which it really should be to serve in the criterion "
     106             :                            "expression for throwing.");
     107             :     }
     108         138 : }
     109             : 
     110             : void
     111         275 : Terminator::handleMessage()
     112             : {
     113         275 :   std::string message;
     114         275 :   if (!isParamValid("message"))
     115             :   {
     116         253 :     message = "Terminator '" + name() + "' is ";
     117         253 :     if (_fail_mode == FailMode::HARD)
     118          11 :       message += "causing the execution to terminate.\n";
     119         242 :     else if (_fail_mode == FailMode::SOFT)
     120         176 :       message += "causing a time step cutback by marking the current step as failed.\n";
     121             :     else
     122          66 :       message += "outputting a message due to the criterion being met";
     123             :   }
     124             :   else
     125          22 :     message = getParam<std::string>("message");
     126             : 
     127         275 :   switch (_msg_type)
     128             :   {
     129         267 :     case MessageType::INFO:
     130         267 :       mooseInfoRepeated(message);
     131         267 :       break;
     132             : 
     133           4 :     case MessageType::WARNING:
     134           4 :       mooseWarning(message);
     135           4 :       break;
     136             : 
     137           4 :     case MessageType::ERROR:
     138           4 :       mooseError(message);
     139             :       break;
     140             : 
     141           0 :     default:
     142           0 :       break;
     143             :   }
     144         271 : }
     145             : 
     146             : void
     147        2419 : Terminator::execute()
     148             : {
     149             :   // copy current Postprocessor values into the FParser parameter buffer
     150        4838 :   for (unsigned int i = 0; i < _pp_num; ++i)
     151        2419 :     _params[i] = *(_pp_values[i]);
     152             : 
     153             :   // request termination of the run or timestep in case the expression evaluates to true
     154        2419 :   if (_fp.Eval(_params.data()) != 0)
     155             :   {
     156         275 :     handleMessage();
     157         271 :     if (_fail_mode == FailMode::HARD)
     158          21 :       _fe_problem.terminateSolve();
     159         250 :     else if (_fail_mode == FailMode::SOFT)
     160             :     {
     161             :       // Within a nonlinear solve, trigger a solve fail
     162         280 :       if (_fe_problem.getCurrentExecuteOnFlag() == EXEC_LINEAR ||
     163          96 :           _fe_problem.getCurrentExecuteOnFlag() == EXEC_NONLINEAR)
     164          88 :         _fe_problem.setFailNextNonlinearConvergenceCheck();
     165             :       // Outside of a solve, trigger a time step fail
     166             :       else
     167          96 :         getMooseApp().getExecutioner()->fixedPointSolve().failStep();
     168             :     }
     169             :   }
     170        2415 : }
     171             : 
     172             : #endif

Generated by: LCOV version 1.14