LCOV - code coverage report
Current view: top level - include/physics - PhysicsBase.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33416 (b10b36) with base 9fbd27 Lines: 17 49 34.7 %
Date: 2026-07-23 16:15:30 Functions: 13 45 28.9 %
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 "Action.h"
      13             : #include "ActionWarehouse.h"
      14             : #include "InputParametersChecksUtils.h"
      15             : #include "ActionComponent.h"
      16             : 
      17             : // We include these headers for all the derived classes that will be building objects
      18             : #include "FEProblemBase.h"
      19             : #include "Factory.h"
      20             : #include "MultiMooseEnum.h"
      21             : 
      22             : #define registerPhysicsBaseTasks(app_name, derived_name)                                           \
      23             :   registerMooseAction(app_name, derived_name, "init_physics");                                     \
      24             :   registerMooseAction(app_name, derived_name, "copy_vars_physics");                                \
      25             :   registerMooseAction(app_name, derived_name, "check_integrity_early_physics")
      26             : 
      27             : /**
      28             :  * Base class to help creating an entire physics
      29             :  */
      30             : class PhysicsBase : public Action, public InputParametersChecksUtils<PhysicsBase>
      31             : {
      32             : public:
      33             :   static InputParameters validParams();
      34             : 
      35             :   PhysicsBase(const InputParameters & parameters);
      36             : 
      37             :   /// Provide additional parameters for the relationship managers
      38         455 :   virtual InputParameters getAdditionalRMParams() const { return emptyInputParameters(); };
      39             : 
      40             :   // Responding to tasks //
      41             :   /// Forwards from the action tasks to the implemented addXYZ() in the derived classes
      42             :   /// If you need more than these:
      43             :   /// - register your action to the new task using
      44             :   ///   registerMooseAction("AppName", ActionClass, "task_name");
      45             :   /// - override actOnAdditionalTasks and add your additional work there
      46             :   virtual void act() override final;
      47             : 
      48             :   /// Routine to add additional setup work on additional registered tasks to a Physics
      49          72 :   virtual void actOnAdditionalTasks() {}
      50             : 
      51             :   // Block restriction //
      52             :   /**
      53             :    * @brief Add new blocks to the Physics
      54             :    * @param blocks list of blocks to add to the physics
      55             :    */
      56             :   void addBlocks(const std::vector<SubdomainName> & blocks);
      57             :   void addBlocksById(const std::vector<SubdomainID> & block_ids);
      58             : 
      59             :   /// Return the blocks this physics is defined on
      60             :   const std::vector<SubdomainName> & blocks() const { return _blocks; }
      61             : 
      62             :   /**
      63             :    * @brief Check if an external object has the same block restriction
      64             :    * @param object_name name of the object to check the block restriction of
      65             :    * @param blocks the blocks for this object
      66             :    * @param error_if_not_identical whether to error if the block restrictions dont match
      67             :    */
      68             :   bool checkBlockRestrictionIdentical(const std::string & object_name,
      69             :                                       const std::vector<SubdomainName> & blocks,
      70             :                                       const bool error_if_not_identical = true) const;
      71             : 
      72             :   /**
      73             :    * Whether the Physics is defined on those blocks
      74             :    * @param blocks the blocks to check
      75             :    */
      76             :   bool hasBlocks(const std::vector<SubdomainName> & blocks) const;
      77             : 
      78             :   // Coupling with Physics //
      79             :   /**
      80             :    * @brief Get a Physics from the ActionWarehouse with the requested type and name
      81             :    * @param phys_name name of the Physics to retrieve
      82             :    * @param allow_fail whether to allow returning a nullptr if the physics does not exist
      83             :    */
      84             :   template <typename T>
      85             :   const T * getCoupledPhysics(const PhysicsName & phys_name, const bool allow_fail = false) const;
      86             :   /// Get all Physics from the ActionWarehouse with the requested type
      87             :   template <typename T>
      88             :   const std::vector<T *> getCoupledPhysics(const bool allow_fail = false) const;
      89             : 
      90             :   /// Return the maximum dimension of the blocks the Physics is active on
      91             :   unsigned int dimension() const;
      92             : 
      93             :   // Coupling with Components //
      94             :   /// Get a component with the requested name
      95             :   const ActionComponent & getActionComponent(const ComponentName & comp_name) const;
      96             :   /// Check that the component is of the desired type
      97             :   template <typename T>
      98             :   void checkComponentType(const ActionComponent & component) const;
      99             :   /// Most basic way of adding a component: simply adding the blocks to the block
     100             :   /// restriction of the Physics. More complex behavior should be implemented by overriding
     101             :   virtual void addComponent(const ActionComponent & component);
     102             : 
     103             :   /// Return the list of solver (nonlinear + linear) variables in this physics
     104         482 :   const std::vector<VariableName> & solverVariableNames() const { return _solver_var_names; };
     105             :   /// Return the list of aux variables in this physics
     106         240 :   const std::vector<VariableName> & auxVariableNames() const { return _aux_var_names; };
     107             : 
     108             :   /**
     109             :    * @brief Return the names of the UserObjects this Physics adds to the problem.
     110             :    *
     111             :    * A Physics that adds a UserObject that another object may reference in its constructor must
     112             :    * declare that UserObject's name here so the construction order can be resolved regardless of
     113             :    * input file order. This is consulted before the 'add_user_object' task runs, so it must be
     114             :    * computable without adding the objects (i.e. from the Physics name, blocks and variables, all
     115             :    * known after init_physics). The default is empty: a Physics that adds no such UserObject need
     116             :    * not override.
     117             :    */
     118           0 :   virtual std::vector<UserObjectName> getSuppliedUserObjects() const { return {}; }
     119             : 
     120             : protected:
     121             :   /// Return whether the Physics is solved using a transient
     122             :   bool isTransient() const;
     123             : 
     124             :   /// Get the factory for this physics
     125             :   /// The factory lets you get the parameters for objects
     126        2343 :   Factory & getFactory() { return _factory; }
     127         273 :   Factory & getFactory() const { return _factory; }
     128             :   /// Get the problem for this physics
     129             :   /// Useful to add objects to the simulation
     130        3758 :   virtual FEProblemBase & getProblem()
     131             :   {
     132             :     mooseAssert(_problem, "Requesting the problem too early");
     133        3758 :     return *_problem;
     134             :   }
     135         219 :   virtual const FEProblemBase & getProblem() const
     136             :   {
     137             :     mooseAssert(_problem, "Requesting the problem too early");
     138         219 :     return *_problem;
     139             :   }
     140             : 
     141             :   /// Tell the app if we want to use Exodus restart
     142             :   void prepareCopyVariablesFromMesh() const;
     143             :   /**
     144             :    * Copy nonlinear or aux variables from the mesh file
     145             :    *
     146             :    * @param variables_to_copy  Nonlinear or aux (not a mix) variables
     147             :    * @param are_nonlinear  True if \c variables_to_copy are nonlinear; else, aux
     148             :    */
     149             :   void copyVariablesFromMesh(const std::vector<VariableName> & variables_to_copy,
     150             :                              bool are_nonlinear = true);
     151             : 
     152             :   /// Use prefix() to disambiguate names
     153        1599 :   std::string prefix() const { return name() + "_"; }
     154             : 
     155             :   /**
     156             :    * @brief Add a UserObject supplied by this Physics to the problem.
     157             :    *
     158             :    * Forwards to FEProblemBase::addUserObject. Use this instead of getProblem().addUserObject() so
     159             :    * that any UserObject this Physics supplies is (in a debug build) checked to have been declared
     160             :    * in getSuppliedUserObjects(), keeping the declaration and the construction consistent.
     161             :    */
     162             :   void
     163             :   addUserObject(const std::string & uo_type, const std::string & uo_name, InputParameters & params);
     164             : 
     165             :   /// Keep track of the name of the solver variable defined in the Physics
     166         260 :   void saveSolverVariableName(const VariableName & var_name)
     167             :   {
     168         260 :     _solver_var_names.push_back(var_name);
     169         260 :   }
     170             :   /// Keep track of the name of an aux variable defined in the Physics
     171             :   void saveAuxVariableName(const VariableName & var_name) { _aux_var_names.push_back(var_name); }
     172             : 
     173             :   /// Check whether a variable already exists
     174             :   bool variableExists(const VariableName & var_name, bool error_if_aux) const;
     175             :   /// Check whether a variable already exists and is a solver variable
     176             :   bool solverVariableExists(const VariableName & var_name) const;
     177             : 
     178             :   /// Get the solver system for this variable index. The index should be the index of the variable in solver
     179             :   /// var_names (currently _solver_var_names) vector
     180             :   const SolverSystemName & getSolverSystem(unsigned int variable_index) const;
     181             :   /// Get the solver system for this variable name
     182             :   const SolverSystemName & getSolverSystem(const VariableName & variable_name) const;
     183             : 
     184             :   /// Add a new required task for all physics deriving from this class
     185             :   /// NOTE: This does not register the task, you still need to call registerMooseAction
     186        1596 :   void addRequiredPhysicsTask(const std::string & task) { _required_tasks.insert(task); }
     187             : 
     188             :   /**
     189             :    * @brief Set the blocks parameter to the input parameters of an object this Physics will create
     190             :    * @param params the parameters of the object
     191             :    * @param blocks the blocks to set as the parameter
     192             :    */
     193             :   void assignBlocks(InputParameters & params, const std::vector<SubdomainName> & blocks) const;
     194             :   /**
     195             :    * @brief Check if a vector contains all the mesh blocks
     196             :    * @param blocks the vector blocks to check for whether it contains every block in the mesh
     197             :    */
     198             :   bool allMeshBlocks(const std::vector<SubdomainName> & blocks) const;
     199             :   bool allMeshBlocks(const std::set<SubdomainName> & blocks) const;
     200             :   // These APIs can deal with ANY_BLOCK_ID or ids with no names. They will be slower than the
     201             :   // MooseMeshUtils' APIs, but are more convenient for setup purposes
     202             :   /// Get the set of subdomain ids for the incoming vector of subdomain names
     203             :   std::set<SubdomainID> getSubdomainIDs(const std::set<SubdomainName> & blocks) const;
     204             :   /// Get the vector of subdomain names and ids for the incoming set of subdomain IDs
     205             :   std::vector<std::string> getSubdomainNamesAndIDs(const std::set<SubdomainID> & blocks) const;
     206             : 
     207             :   /**
     208             :    * Process the given petsc option pairs into the system solver settings
     209             :    */
     210             :   void addPetscPairsToPetscOptions(
     211             :       const std::vector<std::pair<MooseEnumItem, std::string>> & petsc_pair_options);
     212             : 
     213             :   // Helpers to check on variable types
     214             :   /// Whether the variable is a finite volume variable
     215             :   bool isVariableFV(const VariableName & var_name) const;
     216             :   /// Whether the variable is a scalar variable (global single scalar, not a field)
     217             :   bool isVariableScalar(const VariableName & var_name) const;
     218             : 
     219             :   // Routines to help with deciding when to create objects
     220             :   /**
     221             :    * Returns whether this Physics should create the variable. Will return false if the variable
     222             :    * already exists and has the necessary block restriction.
     223             :    * @param var_name name of the variable
     224             :    * @param blocks block restriction to use. If empty, no block restriction
     225             :    * @param error_if_aux error if the variable is auxiliary
     226             :    */
     227             :   bool shouldCreateVariable(const VariableName & var_name,
     228             :                             const std::vector<SubdomainName> & blocks,
     229             :                             const bool error_if_aux);
     230             : 
     231             :   /**
     232             :    * Returns whether this Physics should create the variable. Will return false if the initial
     233             :    * condition already exists and has the necessary block restriction.
     234             :    * @param var_name name of the variable
     235             :    * @param blocks block restriction to use. If empty, no block restriction
     236             :    * @param ic_is_default_ic whether this IC is from a default parameter, and therefore should be
     237             :    * skipped when recovering/restarting
     238             :    * @param error_if_already_defined two ICs cannot be defined on the same subdomain, so if this is
     239             :    * set to true, any overlap between the subdomains of two ICs for the same variable will cause an
     240             :    * error. If set to false, the existing ICs will take priority, and this routine will return
     241             :    * false. Setting 'error_if_already_defined' to '!ic_is_default_ic' is a good idea if it is ok to
     242             :    * overwrite the default IC value of the Physics.
     243             :    */
     244             :   bool shouldCreateIC(const VariableName & var_name,
     245             :                       const std::vector<SubdomainName> & blocks,
     246             :                       const bool ic_is_default_ic,
     247             :                       const bool error_if_already_defined) const;
     248             : 
     249             :   /**
     250             :    * Returns whether this Physics should create the variable. Will return false if the time
     251             :    * derivative kernel already exists and has the necessary block restriction.
     252             :    * @param var_name name of the variable
     253             :    * @param blocks block restriction to use. If empty, no block restriction
     254             :    * @param error_if_already_defined two time derivatives can be defined on the same subdomain, but
     255             :    * it is usually not correct. So if this is set to true, any overlap between the subdomains of two
     256             :    * time derivatives for the same variable will cause an error. If set to false, the existing time
     257             :    * derivative will be deemed as sufficient, and this routine will return false.
     258             :    */
     259             :   bool shouldCreateTimeDerivative(const VariableName & var_name,
     260             :                                   const std::vector<SubdomainName> & blocks,
     261             :                                   const bool error_if_already_defined) const;
     262             : 
     263             :   // Other conceivable "shouldCreate" routines for things that are unique to a variable
     264             :   // - shouldCreateTimeIntegrator
     265             :   // - shouldCreatePredictor/Corrector
     266             : 
     267             :   /**
     268             :    * When this is called, we are knowingly not using the value of these parameters. This routine
     269             :    * checks whether these parameters simply have defaults or were passed by the user
     270             :    * @param param_names the parameters we are ignoring
     271             :    * @param object_type the type of the object we are not building (thus ignoring the parameters)
     272             :    * @param object_name the name of the object we are not building
     273             :    */
     274             :   void reportPotentiallyMissedParameters(const std::vector<std::string> & param_names,
     275             :                                          const std::string & object_type,
     276             :                                          const std::string & object_name = "") const;
     277             : 
     278             :   /// Additional checks performed near the end of the setup phase
     279           0 :   virtual void checkIntegrity() const {}
     280             : 
     281             :   /// System names for the system(s) owning the solver variables
     282             :   std::vector<SolverSystemName> _system_names;
     283             : 
     284             :   /// System numbers for the system(s) owning the solver variables
     285             :   std::vector<unsigned int> _system_numbers;
     286             : 
     287             :   /// Whether to output additional information
     288             :   const bool _verbose;
     289             : 
     290             :   /// Whether to add a default preconditioning.
     291             :   /// The implementation of the default is defined by the derived class
     292             :   const MooseEnum & _preconditioning;
     293             : 
     294             :   /// Keep track of the subdomains the Physics is defined on
     295             :   std::vector<SubdomainName> _blocks;
     296             : 
     297             : private:
     298             :   /// Gathers additional parameters for the relationship managers from the Physics
     299             :   /// then calls the parent Action::addRelationshipManagers with those parameters
     300             :   using Action::addRelationshipManagers;
     301             :   virtual void addRelationshipManagers(Moose::RelationshipManagerType input_rm_type) override;
     302             : 
     303             :   /// Process some parameters that require the problem to be created. Executed on init_physics
     304             :   void initializePhysics();
     305             :   /// Additional initialization work that should happen very early, as soon as the problem is created
     306         170 :   virtual void initializePhysicsAdditional() {}
     307             :   /// Additional checks performed once the executioner / executor has been created
     308             :   virtual void checkIntegrityEarly() const;
     309             : 
     310             :   /// The default implementation of these routines will do nothing as we do not expect all Physics
     311             :   /// to be defining an object of every type
     312             :   /// We keep these private as we don't want a derived class to call a do-nothing implementation
     313             :   /// If they call a parent class implementation, it must have been re-defined as protected
     314           0 :   virtual void addSolverVariables() {}
     315           0 :   virtual void addAuxiliaryVariables() {}
     316           3 :   virtual void addInitialConditions() {}
     317           0 :   virtual void addFEKernels() {}
     318           0 :   virtual void addFVKernels() {}
     319           0 :   virtual void addFVInterpolationMethods() {}
     320           0 :   virtual void addNodalKernels() {}
     321           0 :   virtual void addDiracKernels() {}
     322           0 :   virtual void addDGKernels() {}
     323           0 :   virtual void addScalarKernels() {}
     324           0 :   virtual void addInterfaceKernels() {}
     325           0 :   virtual void addFVInterfaceKernels() {}
     326           0 :   virtual void addFEBCs() {}
     327           0 :   virtual void addFVBCs() {}
     328           0 :   virtual void addNodalBCs() {}
     329           0 :   virtual void addPeriodicBCs() {}
     330           0 :   virtual void addFunctions() {}
     331           0 :   virtual void addAuxiliaryKernels() {}
     332           0 :   virtual void addMaterials() {}
     333           0 :   virtual void addFunctorMaterials() {}
     334           0 :   virtual void addUserObjects() {}
     335           0 :   virtual void addCorrectors() {}
     336           0 :   virtual void addMultiApps() {}
     337           0 :   virtual void addTransfers() {}
     338           0 :   virtual void addPostprocessors() {}
     339           0 :   virtual void addVectorPostprocessors() {}
     340           0 :   virtual void addReporters() {}
     341           0 :   virtual void addOutputs() {}
     342           0 :   virtual void addPreconditioning() {}
     343           0 :   virtual void addExecutioner() {}
     344           0 :   virtual void addExecutors() {}
     345             : 
     346             :   /// Check the list of required tasks for missing tasks
     347             :   void checkRequiredTasks() const;
     348             : 
     349             :   /// Whether the physics is to be solved as a transient. It can be advantageous to solve
     350             :   /// some physics directly to steady state
     351             :   MooseEnum _is_transient;
     352             : 
     353             :   /// Vector of the solver variables (nonlinear and linear) in the Physics
     354             :   std::vector<VariableName> _solver_var_names;
     355             :   /// Vector of the aux variables in the Physics
     356             :   std::vector<VariableName> _aux_var_names;
     357             : 
     358             :   /// Dimension of the physics, which we expect for now to be the dimension of the mesh
     359             :   /// NOTE: this is not known at construction time, only after initializePhysics which is a huge bummer
     360             :   unsigned int _dim = libMesh::invalid_uint;
     361             : 
     362             :   /// Manually keeps track of the tasks required by each physics as tasks cannot be inherited
     363             :   std::set<std::string> _required_tasks;
     364             : };
     365             : 
     366             : template <typename T>
     367             : const T *
     368             : PhysicsBase::getCoupledPhysics(const PhysicsName & phys_name, const bool allow_fail) const
     369             : {
     370             :   constexpr bool is_physics = std::is_base_of<PhysicsBase, T>::value;
     371             :   libmesh_ignore(is_physics);
     372             :   mooseAssert(is_physics, "Must be a PhysicsBase to be retrieved by getCoupledPhysics");
     373             :   const auto all_T_physics = _awh.getActions<T>();
     374             :   for (const auto * const physics : all_T_physics)
     375             :   {
     376             :     if (physics->name() == phys_name)
     377             :       return physics;
     378             :   }
     379             :   if (!allow_fail)
     380             :     mooseError("Requested Physics '",
     381             :                phys_name,
     382             :                "' does not exist or is not of type '",
     383             :                MooseUtils::prettyCppType<T>(),
     384             :                "'");
     385             :   else
     386             :     return nullptr;
     387             : }
     388             : 
     389             : template <typename T>
     390             : const std::vector<T *>
     391             : PhysicsBase::getCoupledPhysics(const bool allow_fail) const
     392             : {
     393             :   constexpr bool is_physics = std::is_base_of<PhysicsBase, T>::value;
     394             :   libmesh_ignore(is_physics);
     395             :   mooseAssert(is_physics, "Must be a PhysicsBase to be retrieved by getCoupledPhysics");
     396             :   const auto all_T_physics = _awh.getActions<T>();
     397             :   if (!allow_fail && all_T_physics.empty())
     398             :     mooseError("No Physics of requested type '", MooseUtils::prettyCppType<T>(), "'");
     399             :   else
     400             :     return all_T_physics;
     401             : }
     402             : 
     403             : template <typename T>
     404             : void
     405             : PhysicsBase::checkComponentType(const ActionComponent & component) const
     406             : {
     407             :   if (!dynamic_cast<const T *>(&component))
     408             :     mooseError("Component '" + component.name() + "' must be of type '" +
     409             :                MooseUtils::prettyCppType<T>() + "'.\nIt is currently of type '" + component.type() +
     410             :                "'");
     411             : }

Generated by: LCOV version 1.14