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