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

Generated by: LCOV version 1.14