LCOV - code coverage report
Current view: top level - include/executors - Executor.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 34 38 89.5 %
Date: 2025-07-17 01:28:37 Functions: 11 14 78.6 %
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             : #pragma once
      11             : 
      12             : #include "Executioner.h"
      13             : #include "ExecutorInterface.h"
      14             : 
      15             : #include <string>
      16             : 
      17             : class Problem;
      18             : class Executor;
      19             : 
      20             : /// The Executor class directs the execution flow of simulations.  It manages
      21             : /// outputting, time stepping, mesh adaptivity, solve sequencing, multiapp
      22             : /// execution, etc.  Users can compose executor objects in an input file using
      23             : /// the same pattern as with mesh generators.  Subclass here and implement your
      24             : /// own run function if you need special or fancy functionality that
      25             : /// isn't supported by the default executors available.
      26             : class Executor : public Executioner, public ExecutorInterface
      27             : {
      28             : public:
      29             :   /// This object tracks the success/failure state of the executor system as
      30             :   /// execution proceeds in a simulation.  Because executors can be composed into
      31             :   /// trees, result objects are correspondingly composed into trees to track
      32             :   /// simulation progress.  Result objects should generally be created by
      33             :   /// executors calling the Result::newResult() function rather than by using
      34             :   /// the Result constructor directly.
      35             :   struct Result
      36             :   {
      37         110 :     Result() : converged(true), _name("NO_NAME") {}
      38           3 :     Result(const std::string & name) : converged(true), _name(name) {}
      39          40 :     Result(const MooseObject * obj) : converged(true), _name(obj->name()) {}
      40             : 
      41             :     /// whether or not a executor ran its code successfully - only reports
      42             :     /// results from the executor itself.  If a sub/internal executor of a executor
      43             :     /// fails, that sub-executor's result object will have converged=false, while
      44             :     /// the parent may still have converged=truee. Users should use convergedAll
      45             :     /// to recursively determine if there was any descendant executor failure.
      46             :     bool converged = true;
      47             : 
      48             :     /// Optional message detailing why an executor passed or failed (i.e. failed to converge).
      49             :     std::string reason;
      50             : 
      51             :     /// Maps a name/label of a executor's internal/sub executors to the result
      52             :     /// object returned by running each of those internal/sub executors.  This
      53             :     /// member should generally not be accessed directly.  It should generally
      54             :     /// be populated through the record function.  Info contained in these
      55             :     /// results will be included in printouts from the str function.
      56             :     std::map<std::string, Result> subs;
      57             : 
      58             :     /// Prints a full recursive output of this result object - including all
      59             :     /// descendant's results.  If success_msg is true, then all result output
      60             :     /// that contains a message will be printed even if it converged/passed.
      61             :     /// Otherwise, messages will only be printed for unconverged/failed results.
      62             :     std::string
      63           6 :     str(bool success_msg = false, const std::string & indent = "", const std::string & subname = "")
      64             :     {
      65           6 :       std::string s = indent + label(success_msg, subname) + "\n";
      66          10 :       for (auto & entry : subs)
      67           4 :         s += entry.second.str(success_msg, indent + "    ", entry.first);
      68           6 :       return s;
      69           0 :     }
      70             : 
      71             :     /// Marks the result as passing/converged with the given msg text
      72             :     /// describing detail about how things ran.  A result object is in this
      73             :     /// state by default, so it is not necessary to call this function for
      74             :     /// converged/passing scenarios.
      75           1 :     void pass(const std::string & msg, bool overwrite = false)
      76             :     {
      77             :       mooseAssert(converged || overwrite,
      78             :                   "cannot override nonconverged executioner result with a passing one");
      79             :       ((void)(overwrite)); // avoid unused error due to assert
      80           1 :       reason = msg;
      81           1 :       converged = true;
      82           1 :     }
      83             : 
      84             :     /// Marks the result as failing/unconverged with the given msg text
      85             :     /// describing detail about how things ran.
      86           1 :     void fail(const std::string & msg)
      87             :     {
      88           1 :       reason = msg;
      89           1 :       converged = false;
      90           1 :     }
      91             : 
      92             :     /// Records results from sub/internal executors in a executor's result.  When
      93             :     /// child-executors return a result object following their execution, this
      94             :     /// function should be called to add that info into the result hierarchy.
      95             :     /// If the child executor was identified by a label/text from the input file
      96             :     /// (e.g. via sub_solve1=foo_executor) - then "name" should be "sub_solve1".
      97          22 :     bool record(const std::string & name, const Result & r)
      98             :     {
      99          22 :       subs[name] = r;
     100          22 :       return r.convergedAll();
     101             :     }
     102             : 
     103             :     /// Returns false if any single executor in the current hierarchy of results
     104             :     /// (i.e. including all child results accumulated recursively via record)
     105             :     /// had a failed/unconverged return state.  Returns true otherwise.  This
     106             :     /// is how convergence should generally be checked/tracked by executors -
     107             :     /// rather than accessing e.g. the converged member directly.
     108          62 :     bool convergedAll() const
     109             :     {
     110          62 :       if (!converged)
     111           1 :         return false;
     112          81 :       for (auto & entry : subs)
     113          20 :         if (!entry.second.convergedAll())
     114           0 :           return false;
     115          61 :       return true;
     116             :     }
     117             : 
     118             :   private:
     119           6 :     std::string label(bool success_msg, const std::string & subname = "")
     120             :     {
     121             :       std::string state_str =
     122          10 :           success_msg || !converged ? (std::string("(") + (converged ? "pass" : "FAIL") + ")") : "";
     123          12 :       return subname + (subname.empty() ? "" : ":") + _name + state_str +
     124          24 :              ((success_msg || !converged) && !reason.empty() ? ": " + reason : "");
     125           6 :     }
     126             :     std::string _name;
     127             :   };
     128             : 
     129             :   Executor(const InputParameters & parameters);
     130             : 
     131          60 :   virtual ~Executor() {}
     132             : 
     133             :   static InputParameters validParams();
     134             : 
     135             :   /// This is the main function for executors - this is how executors should
     136             :   /// invoke child/sub executors - by calling their exec function.
     137             :   Result exec();
     138             : 
     139           0 :   virtual void execute() override final {}
     140             : 
     141             :   /// Executors need to return a Result object describing how execution went -
     142             :   /// rather than constructing Result objects directly, the newResult function
     143             :   /// should be called to generate new objects.  *DO NOT* catch the result by
     144             :   /// value - if you do, MOOSE cannot track result state for restart capability.
     145             :   /// You must catch result values from this function by reference.
     146          40 :   Result & newResult()
     147             :   {
     148          40 :     _result = Result(this);
     149          40 :     return _result;
     150             :   }
     151             : 
     152             :   /// Whether the executor and all its sub-executors passed / converged
     153           0 :   virtual bool lastSolveConverged() const override { return _result.convergedAll(); }
     154             : 
     155             : protected:
     156             :   /// This function contains the primary execution implementation for a
     157             :   /// executor.  Custom executor behavior should be localized to this function.  If
     158             :   /// you are writing a executor - this is basically where you should put all your
     159             :   /// code.
     160             :   virtual Result run() = 0;
     161             : 
     162             :   /// The execute-on flag to associate with the beginning of this executor's execution.
     163             :   /// This allows the framework and users to trigger other object execution by
     164             :   /// associating other objects with this flag.
     165             :   ExecFlagType _begin_flag;
     166             :   /// The execute-on flag to associate with the end of this executor's execution.
     167             :   /// This allows the framework and users to trigger other object execution by
     168             :   /// associating other objects with this flag.
     169             :   ExecFlagType _end_flag;
     170             : 
     171             : private:
     172             :   /// Stores the result representing the outcome from the run function.  It is
     173             :   /// a local member variable here to facilitate restart capability.
     174             :   Result _result;
     175             : };

Generated by: LCOV version 1.14