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 : }