LCOV - code coverage report
Current view: top level - include/physics - PhysicsBase.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 16 47 34.0 %
Date: 2026-05-29 20:35:17 Functions: 12 43 27.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         401 :   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           0 :   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         464 :   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             : protected:
     109             :   /// Return whether the Physics is solved using a transient
     110             :   bool isTransient() const;
     111             : 
     112             :   /// Get the factory for this physics
     113             :   /// The factory lets you get the parameters for objects
     114        2325 :   Factory & getFactory() { return _factory; }
     115         273 :   Factory & getFactory() const { return _factory; }
     116             :   /// Get the problem for this physics
     117             :   /// Useful to add objects to the simulation
     118        3686 :   virtual FEProblemBase & getProblem()
     119             :   {
     120             :     mooseAssert(_problem, "Requesting the problem too early");
     121        3686 :     return *_problem;
     122             :   }
     123         219 :   virtual const FEProblemBase & getProblem() const
     124             :   {
     125             :     mooseAssert(_problem, "Requesting the problem too early");
     126         219 :     return *_problem;
     127             :   }
     128             : 
     129             :   /// Tell the app if we want to use Exodus restart
     130             :   void prepareCopyVariablesFromMesh() const;
     131             :   /**
     132             :    * Copy nonlinear or aux variables from the mesh file
     133             :    *
     134             :    * @param variables_to_copy  Nonlinear or aux (not a mix) variables
     135             :    * @param are_nonlinear  True if \c variables_to_copy are nonlinear; else, aux
     136             :    */
     137             :   void copyVariablesFromMesh(const std::vector<VariableName> & variables_to_copy,
     138             :                              bool are_nonlinear = true);
     139             : 
     140             :   /// Use prefix() to disambiguate names
     141        1599 :   std::string prefix() const { return name() + "_"; }
     142             : 
     143             :   /// Keep track of the name of the solver variable defined in the Physics
     144         260 :   void saveSolverVariableName(const VariableName & var_name)
     145             :   {
     146         260 :     _solver_var_names.push_back(var_name);
     147         260 :   }
     148             :   /// Keep track of the name of an aux variable defined in the Physics
     149             :   void saveAuxVariableName(const VariableName & var_name) { _aux_var_names.push_back(var_name); }
     150             : 
     151             :   /// Check whether a variable already exists
     152             :   bool variableExists(const VariableName & var_name, bool error_if_aux) const;
     153             :   /// Check whether a variable already exists and is a solver variable
     154             :   bool solverVariableExists(const VariableName & var_name) const;
     155             : 
     156             :   /// Get the solver system for this variable index. The index should be the index of the variable in solver
     157             :   /// var_names (currently _solver_var_names) vector
     158             :   const SolverSystemName & getSolverSystem(unsigned int variable_index) const;
     159             :   /// Get the solver system for this variable name
     160             :   const SolverSystemName & getSolverSystem(const VariableName & variable_name) const;
     161             : 
     162             :   /// Add a new required task for all physics deriving from this class
     163             :   /// NOTE: This does not register the task, you still need to call registerMooseAction
     164        1542 :   void addRequiredPhysicsTask(const std::string & task) { _required_tasks.insert(task); }
     165             : 
     166             :   /**
     167             :    * @brief Set the blocks parameter to the input parameters of an object this Physics will create
     168             :    * @param params the parameters of the object
     169             :    * @param blocks the blocks to set as the parameter
     170             :    */
     171             :   void assignBlocks(InputParameters & params, const std::vector<SubdomainName> & blocks) const;
     172             :   /**
     173             :    * @brief Check if a vector contains all the mesh blocks
     174             :    * @param blocks the vector blocks to check for whether it contains every block in the mesh
     175             :    */
     176             :   bool allMeshBlocks(const std::vector<SubdomainName> & blocks) const;
     177             :   bool allMeshBlocks(const std::set<SubdomainName> & blocks) const;
     178             :   // These APIs can deal with ANY_BLOCK_ID or ids with no names. They will be slower than the
     179             :   // MooseMeshUtils' APIs, but are more convenient for setup purposes
     180             :   /// Get the set of subdomain ids for the incoming vector of subdomain names
     181             :   std::set<SubdomainID> getSubdomainIDs(const std::set<SubdomainName> & blocks) const;
     182             :   /// Get the vector of subdomain names and ids for the incoming set of subdomain IDs
     183             :   std::vector<std::string> getSubdomainNamesAndIDs(const std::set<SubdomainID> & blocks) const;
     184             : 
     185             :   /**
     186             :    * Process the given petsc option pairs into the system solver settings
     187             :    */
     188             :   void addPetscPairsToPetscOptions(
     189             :       const std::vector<std::pair<MooseEnumItem, std::string>> & petsc_pair_options);
     190             : 
     191             :   // Helpers to check on variable types
     192             :   /// Whether the variable is a finite volume variable
     193             :   bool isVariableFV(const VariableName & var_name) const;
     194             :   /// Whether the variable is a scalar variable (global single scalar, not a field)
     195             :   bool isVariableScalar(const VariableName & var_name) const;
     196             : 
     197             :   // Routines to help with deciding when to create objects
     198             :   /**
     199             :    * Returns whether this Physics should create the variable. Will return false if the variable
     200             :    * already exists and has the necessary block restriction.
     201             :    * @param var_name name of the variable
     202             :    * @param blocks block restriction to use. If empty, no block restriction
     203             :    * @param error_if_aux error if the variable is auxiliary
     204             :    */
     205             :   bool shouldCreateVariable(const VariableName & var_name,
     206             :                             const std::vector<SubdomainName> & blocks,
     207             :                             const bool error_if_aux);
     208             : 
     209             :   /**
     210             :    * Returns whether this Physics should create the variable. Will return false if the initial
     211             :    * condition already exists and has the necessary block restriction.
     212             :    * @param var_name name of the variable
     213             :    * @param blocks block restriction to use. If empty, no block restriction
     214             :    * @param ic_is_default_ic whether this IC is from a default parameter, and therefore should be
     215             :    * skipped when recovering/restarting
     216             :    * @param error_if_already_defined two ICs cannot be defined on the same subdomain, so if this is
     217             :    * set to true, any overlap between the subdomains of two ICs for the same variable will cause an
     218             :    * error. If set to false, the existing ICs will take priority, and this routine will return
     219             :    * false. Setting 'error_if_already_defined' to '!ic_is_default_ic' is a good idea if it is ok to
     220             :    * overwrite the default IC value of the Physics.
     221             :    */
     222             :   bool shouldCreateIC(const VariableName & var_name,
     223             :                       const std::vector<SubdomainName> & blocks,
     224             :                       const bool ic_is_default_ic,
     225             :                       const bool error_if_already_defined) const;
     226             : 
     227             :   /**
     228             :    * Returns whether this Physics should create the variable. Will return false if the time
     229             :    * derivative kernel already exists and has the necessary block restriction.
     230             :    * @param var_name name of the variable
     231             :    * @param blocks block restriction to use. If empty, no block restriction
     232             :    * @param error_if_already_defined two time derivatives can be defined on the same subdomain, but
     233             :    * it is usually not correct. So if this is set to true, any overlap between the subdomains of two
     234             :    * time derivatives for the same variable will cause an error. If set to false, the existing time
     235             :    * derivative will be deemed as sufficient, and this routine will return false.
     236             :    */
     237             :   bool shouldCreateTimeDerivative(const VariableName & var_name,
     238             :                                   const std::vector<SubdomainName> & blocks,
     239             :                                   const bool error_if_already_defined) const;
     240             : 
     241             :   // Other conceivable "shouldCreate" routines for things that are unique to a variable
     242             :   // - shouldCreateTimeIntegrator
     243             :   // - shouldCreatePredictor/Corrector
     244             : 
     245             :   /**
     246             :    * When this is called, we are knowingly not using the value of these parameters. This routine
     247             :    * checks whether these parameters simply have defaults or were passed by the user
     248             :    * @param param_names the parameters we are ignoring
     249             :    * @param object_type the type of the object we are not building (thus ignoring the parameters)
     250             :    * @param object_name the name of the object we are not building
     251             :    */
     252             :   void reportPotentiallyMissedParameters(const std::vector<std::string> & param_names,
     253             :                                          const std::string & object_type,
     254             :                                          const std::string & object_name = "") const;
     255             : 
     256             :   /// Additional checks performed near the end of the setup phase
     257           0 :   virtual void checkIntegrity() const {}
     258             : 
     259             :   /// System names for the system(s) owning the solver variables
     260             :   std::vector<SolverSystemName> _system_names;
     261             : 
     262             :   /// System numbers for the system(s) owning the solver variables
     263             :   std::vector<unsigned int> _system_numbers;
     264             : 
     265             :   /// Whether to output additional information
     266             :   const bool _verbose;
     267             : 
     268             :   /// Whether to add a default preconditioning.
     269             :   /// The implementation of the default is defined by the derived class
     270             :   const MooseEnum & _preconditioning;
     271             : 
     272             :   /// Keep track of the subdomains the Physics is defined on
     273             :   std::vector<SubdomainName> _blocks;
     274             : 
     275             : private:
     276             :   /// Gathers additional parameters for the relationship managers from the Physics
     277             :   /// then calls the parent Action::addRelationshipManagers with those parameters
     278             :   using Action::addRelationshipManagers;
     279             :   virtual void addRelationshipManagers(Moose::RelationshipManagerType input_rm_type) override;
     280             : 
     281             :   /// Process some parameters that require the problem to be created. Executed on init_physics
     282             :   void initializePhysics();
     283             :   /// Additional initialization work that should happen very early, as soon as the problem is created
     284         152 :   virtual void initializePhysicsAdditional() {}
     285             :   /// Additional checks performed once the executioner / executor has been created
     286             :   virtual void checkIntegrityEarly() const;
     287             : 
     288             :   /// The default implementation of these routines will do nothing as we do not expect all Physics
     289             :   /// to be defining an object of every type
     290             :   /// We keep these private as we don't want a derived class to call a do-nothing implementation
     291             :   /// If they call a parent class implementation, it must have been re-defined as protected
     292           0 :   virtual void addSolverVariables() {}
     293           0 :   virtual void addAuxiliaryVariables() {}
     294           3 :   virtual void addInitialConditions() {}
     295           0 :   virtual void addFEKernels() {}
     296           0 :   virtual void addFVKernels() {}
     297           0 :   virtual void addNodalKernels() {}
     298           0 :   virtual void addDiracKernels() {}
     299           0 :   virtual void addDGKernels() {}
     300           0 :   virtual void addScalarKernels() {}
     301           0 :   virtual void addInterfaceKernels() {}
     302           0 :   virtual void addFVInterfaceKernels() {}
     303           0 :   virtual void addFEBCs() {}
     304           0 :   virtual void addFVBCs() {}
     305           0 :   virtual void addNodalBCs() {}
     306           0 :   virtual void addPeriodicBCs() {}
     307           0 :   virtual void addFunctions() {}
     308           0 :   virtual void addAuxiliaryKernels() {}
     309           0 :   virtual void addMaterials() {}
     310           0 :   virtual void addFunctorMaterials() {}
     311           0 :   virtual void addUserObjects() {}
     312           0 :   virtual void addCorrectors() {}
     313           0 :   virtual void addMultiApps() {}
     314           0 :   virtual void addTransfers() {}
     315           0 :   virtual void addPostprocessors() {}
     316           0 :   virtual void addVectorPostprocessors() {}
     317           0 :   virtual void addReporters() {}
     318           0 :   virtual void addOutputs() {}
     319           0 :   virtual void addPreconditioning() {}
     320           0 :   virtual void addExecutioner() {}
     321           0 :   virtual void addExecutors() {}
     322             : 
     323             :   /// Check the list of required tasks for missing tasks
     324             :   void checkRequiredTasks() const;
     325             : 
     326             :   /// Whether the physics is to be solved as a transient. It can be advantageous to solve
     327             :   /// some physics directly to steady state
     328             :   MooseEnum _is_transient;
     329             : 
     330             :   /// Vector of the solver variables (nonlinear and linear) in the Physics
     331             :   std::vector<VariableName> _solver_var_names;
     332             :   /// Vector of the aux variables in the Physics
     333             :   std::vector<VariableName> _aux_var_names;
     334             : 
     335             :   /// Dimension of the physics, which we expect for now to be the dimension of the mesh
     336             :   /// NOTE: this is not known at construction time, only after initializePhysics which is a huge bummer
     337             :   unsigned int _dim = libMesh::invalid_uint;
     338             : 
     339             :   /// Manually keeps track of the tasks required by each physics as tasks cannot be inherited
     340             :   std::set<std::string> _required_tasks;
     341             : };
     342             : 
     343             : template <typename T>
     344             : const T *
     345             : PhysicsBase::getCoupledPhysics(const PhysicsName & phys_name, const bool allow_fail) const
     346             : {
     347             :   constexpr bool is_physics = std::is_base_of<PhysicsBase, T>::value;
     348             :   libmesh_ignore(is_physics);
     349             :   mooseAssert(is_physics, "Must be a PhysicsBase to be retrieved by getCoupledPhysics");
     350             :   const auto all_T_physics = _awh.getActions<T>();
     351             :   for (const auto * const physics : all_T_physics)
     352             :   {
     353             :     if (physics->name() == phys_name)
     354             :       return physics;
     355             :   }
     356             :   if (!allow_fail)
     357             :     mooseError("Requested Physics '",
     358             :                phys_name,
     359             :                "' does not exist or is not of type '",
     360             :                MooseUtils::prettyCppType<T>(),
     361             :                "'");
     362             :   else
     363             :     return nullptr;
     364             : }
     365             : 
     366             : template <typename T>
     367             : const std::vector<T *>
     368             : PhysicsBase::getCoupledPhysics(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             :   if (!allow_fail && all_T_physics.empty())
     375             :     mooseError("No Physics of requested type '", MooseUtils::prettyCppType<T>(), "'");
     376             :   else
     377             :     return all_T_physics;
     378             : }
     379             : 
     380             : template <typename T>
     381             : void
     382             : PhysicsBase::checkComponentType(const ActionComponent & component) const
     383             : {
     384             :   if (!dynamic_cast<const T *>(&component))
     385             :     mooseError("Component '" + component.name() + "' must be of type '" +
     386             :                MooseUtils::prettyCppType<T>() + "'.\nIt is currently of type '" + component.type() +
     387             :                "'");
     388             : }

Generated by: LCOV version 1.14