https://mooseframework.inl.gov
PhysicsBase.C
Go to the documentation of this file.
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 #include "PhysicsBase.h"
11 #include "MooseUtils.h"
12 #include "FEProblemBase.h"
13 
14 #include "NonlinearSystemBase.h"
15 #include "AuxiliarySystem.h"
16 #include "BlockRestrictable.h"
17 #include "ActionComponent.h"
18 #include "InitialConditionBase.h"
19 #include "FVInitialConditionBase.h"
20 #include "MooseVariableScalar.h"
21 #include "LinearSystem.h"
22 
25 {
27  params.addClassDescription("Creates all the objects necessary to solve a particular physics");
28 
29  params.addParam<std::vector<SubdomainName>>(
30  "block", {}, "Blocks (subdomains) that this Physics is active on.");
31 
32  MooseEnum transient_options("true false same_as_problem", "same_as_problem");
33  params.addParam<MooseEnum>(
34  "transient", transient_options, "Whether the physics is to be solved as a transient");
35 
36  params.addParam<bool>("verbose", false, "Flag to facilitate debugging a Physics");
37 
38  // Numerical solve parameters
39  params.addParam<std::vector<SolverSystemName>>(
40  "system_names",
41  {"nl0"},
42  "Name of the solver system(s) for the variables. If a single name is specified, "
43  "that system is used for all solver variables.");
44  MooseEnum pc_options("default defer", "defer");
45  params.addParam<MooseEnum>("preconditioning",
46  pc_options,
47  "Which preconditioning to use/add for this Physics, or whether to "
48  "defer to the Preconditioning block, or another Physics");
49 
50  // Restart parameters
51  params.addParam<bool>("initialize_variables_from_mesh_file",
52  false,
53  "Determines if the variables that are added by the action are initialized"
54  "from the mesh file (only for Exodus format)");
55  params.addParam<std::string>(
56  "initial_from_file_timestep",
57  "LATEST",
58  "Gives the time step number (or \"LATEST\") for which to read the Exodus solution");
59  params.addParamNamesToGroup("initialize_variables_from_mesh_file initial_from_file_timestep",
60  "Restart from Exodus");
61 
62  // Options to turn off tasks
63  params.addParam<bool>("dont_create_solver_variables",
64  false,
65  "Whether to skip the 'add_variable'/'add_variables_physics' task(s)");
66  params.addParam<bool>(
67  "dont_create_ics", false, "Whether to skip the 'add_ic'/'add_fv_ic/add_ics_physics' task(s)");
68  params.addParam<bool>(
69  "dont_create_kernels", false, "Whether to skip the 'add_kernel' task for each kernel type");
70  params.addParam<bool>("dont_create_bcs",
71  false,
72  "Whether to skip the 'add_bc' task for each boundary condition type");
73  params.addParam<bool>("dont_create_functions", false, "Whether to skip the 'add_function' task");
74  params.addParam<bool>(
75  "dont_create_aux_variables", false, "Whether to skip the 'add_aux_variable' task");
76  params.addParam<bool>(
77  "dont_create_aux_kernels", false, "Whether to skip the 'add_aux_kernel' task");
78  params.addParam<bool>(
79  "dont_create_materials",
80  false,
81  "Whether to skip the 'add_material'/'add_materials_physics' task(s) for each material type");
82  params.addParam<bool>(
83  "dont_create_user_objects",
84  false,
85  "Whether to skip the 'add_user_object' task. This does not apply to UserObject derived "
86  "classes being created on a different task (for example: postprocessors, VPPs, correctors)");
87  params.addParam<bool>(
88  "dont_create_correctors", false, "Whether to skip the 'add_correctors' task");
89  params.addParam<bool>(
90  "dont_create_postprocessors", false, "Whether to skip the 'add_postprocessors' task");
91  params.addParam<bool>("dont_create_vectorpostprocessors",
92  false,
93  "Whether to skip the 'add_vectorpostprocessors' task");
94  params.addParamNamesToGroup(
95  "dont_create_solver_variables dont_create_ics dont_create_kernels dont_create_bcs "
96  "dont_create_functions dont_create_aux_variables dont_create_aux_kernels "
97  "dont_create_materials dont_create_user_objects dont_create_correctors "
98  "dont_create_postprocessors dont_create_vectorpostprocessors",
99  "Reduce Physics object creation");
100 
101  params.addParamNamesToGroup("active inactive", "Advanced");
102  params.addParamNamesToGroup("preconditioning system_names", "Numerical scheme");
103  return params;
104 }
105 
107  : Action(parameters),
109  _system_names(getParam<std::vector<SolverSystemName>>("system_names")),
110  _verbose(getParam<bool>("verbose")),
111  _preconditioning(getParam<MooseEnum>("preconditioning")),
112  _blocks(getParam<std::vector<SubdomainName>>("block")),
113  _is_transient(getParam<MooseEnum>("transient"))
114 {
115  checkSecondParamSetOnlyIfFirstOneTrue("initialize_variables_from_mesh_file",
116  "initial_from_file_timestep");
118  addRequiredPhysicsTask("init_physics");
119  addRequiredPhysicsTask("copy_vars_physics");
120  addRequiredPhysicsTask("check_integrity_early_physics");
121 }
122 
123 void
125 {
126  mooseDoOnce(checkRequiredTasks());
127 
128  // Lets a derived Physics class implement additional tasks
130 
131  // Initialization and variables
132  if (_current_task == "init_physics")
134  else if ((_current_task == "add_variable" || _current_task == "add_variables_physics") &&
135  !getParam<bool>("dont_create_solver_variables"))
137  else if ((_current_task == "add_ic" || _current_task == "add_fv_ic" ||
138  _current_task == "add_ics_physics") &&
139  !getParam<bool>("dont_create_ics"))
141 
142  // Kernels
143  else if (_current_task == "add_kernel" && !getParam<bool>("dont_create_kernels"))
144  addFEKernels();
145  else if (_current_task == "add_nodal_kernel" && !getParam<bool>("dont_create_kernels"))
146  addNodalKernels();
147  else if ((_current_task == "add_fv_kernel" || _current_task == "add_linear_fv_kernel") &&
148  !getParam<bool>("dont_create_kernels"))
149  addFVKernels();
150  else if (_current_task == "add_dirac_kernel" && !getParam<bool>("dont_create_kernels"))
151  addDiracKernels();
152  else if (_current_task == "add_dg_kernel" && !getParam<bool>("dont_create_kernels"))
153  addDGKernels();
154  else if (_current_task == "add_scalar_kernel" && !getParam<bool>("dont_create_kernels"))
156  else if (_current_task == "add_interface_kernel" && !getParam<bool>("dont_create_kernels"))
158  else if (_current_task == "add_fv_ik" && !getParam<bool>("dont_create_kernels"))
160 
161  // Boundary conditions
162  else if (_current_task == "add_bc" && !getParam<bool>("dont_create_bcs"))
163  addFEBCs();
164  else if (_current_task == "add_nodal_bc" && !getParam<bool>("dont_create_bcs"))
165  addNodalBCs();
166  else if ((_current_task == "add_fv_bc" || _current_task == "add_linear_fv_bc") &&
167  !getParam<bool>("dont_create_bcs"))
168  addFVBCs();
169  else if (_current_task == "add_periodic_bc" && !getParam<bool>("dont_create_bcs"))
170  addPeriodicBCs();
171 
172  // Auxiliary quantities
173  else if (_current_task == "add_function" && !getParam<bool>("dont_create_functions"))
174  addFunctions();
175  else if (_current_task == "add_aux_variable" && !getParam<bool>("dont_create_aux_variables"))
177  else if (_current_task == "add_aux_kernel" && !getParam<bool>("dont_create_aux_kernels"))
179  else if ((_current_task == "add_material" || _current_task == "add_materials_physics") &&
180  !getParam<bool>("dont_create_materials"))
181  addMaterials();
182  else if (_current_task == "add_functor_material" && !getParam<bool>("dont_create_materials"))
184 
185  // Multiapp
186  else if (_current_task == "add_multi_app")
187  addMultiApps();
188  else if (_current_task == "add_transfer")
189  addTransfers();
190 
191  // User objects and output
192  else if (_current_task == "add_user_object" && !getParam<bool>("dont_create_user_objects"))
193  addUserObjects();
194  else if (_current_task == "add_corrector" && !getParam<bool>("dont_create_correctors"))
195  addCorrectors();
196  else if (_current_task == "add_postprocessor" && !getParam<bool>("dont_create_postprocessors"))
198  else if (_current_task == "add_vector_postprocessor" &&
199  !getParam<bool>("dont_create_vectorpostprocessors"))
201  else if (_current_task == "add_reporter")
202  addReporters();
203  else if (_current_task == "add_output")
204  addOutputs();
205 
206  // Equation solver-related tasks
207  else if (_current_task == "add_preconditioning")
209  else if (_current_task == "add_executioner")
210  addExecutioner();
211  else if (_current_task == "add_executor")
212  addExecutors();
213 
214  // Checks
215  else if (_current_task == "check_integrity_early_physics")
217  else if (_current_task == "check_integrity")
218  checkIntegrity();
219 
220  // Exodus restart capabilities
221  if (_current_task == "copy_vars_physics")
222  {
224  if (_aux_var_names.size() > 0)
226  }
227 }
228 
229 void
231 {
232  if (getParam<bool>("initialize_variables_from_mesh_file"))
234 
235  checkSecondParamSetOnlyIfFirstOneTrue("initialize_variables_from_mesh_file",
236  "initial_from_file_timestep");
237 }
238 
239 bool
241 {
242  mooseAssert(_problem, "We don't have a problem yet");
243  if (_is_transient == "true")
244  return true;
245  else if (_is_transient == "false")
246  return false;
247  else
248  return getProblem().isTransient();
249 }
250 
251 unsigned int
253 {
254  mooseAssert(_mesh, "We dont have a mesh yet");
255  mooseAssert(_dim < 4, "Dimension has not been set yet");
256  return _dim;
257 }
258 
259 std::set<SubdomainID>
260 PhysicsBase::getSubdomainIDs(const std::set<SubdomainName> & blocks) const
261 {
262  const bool not_block_restricted =
263  (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") != blocks.end()) ||
265  mooseAssert(_mesh, "Should have a mesh");
266  // use a set for simplicity. Note that subdomain names are unique, except maybe the empty one,
267  // which cannot be specified by the user to the Physics.
268  // MooseMesh::getSubdomainIDs cannot deal with the 'ANY_BLOCK_ID' name
269  std::set<SubdomainID> block_ids_set =
270  not_block_restricted ? _mesh->meshSubdomains() : _mesh->getSubdomainIDs(blocks);
271  return block_ids_set;
272 }
273 
274 std::vector<std::string>
275 PhysicsBase::getSubdomainNamesAndIDs(const std::set<SubdomainID> & blocks) const
276 {
277  mooseAssert(_mesh, "Should have a mesh");
278  std::vector<std::string> sub_names_ids;
279  sub_names_ids.reserve(blocks.size());
280  for (const auto bid : blocks)
281  {
282  const auto bname = _mesh->getSubdomainName(bid);
283  sub_names_ids.push_back((bname.empty() ? "(unnamed)" : bname) + " (" + std::to_string(bid) +
284  ")");
285  }
286  return sub_names_ids;
287 }
288 
289 void
290 PhysicsBase::addBlocks(const std::vector<SubdomainName> & blocks)
291 {
292  if (blocks.size())
293  {
294  _blocks.insert(_blocks.end(), blocks.begin(), blocks.end());
295  _dim = _mesh->getBlocksMaxDimension(_blocks);
296  }
297 }
298 
299 void
300 PhysicsBase::addBlocksById(const std::vector<SubdomainID> & block_ids)
301 {
302  if (block_ids.size())
303  {
304  for (const auto bid : block_ids)
305  _blocks.push_back(_mesh->getSubdomainName(bid));
306  _dim = _mesh->getBlocksMaxDimension(_blocks);
307  }
308 }
309 
310 void
312 {
313  for (const auto & block : component.blocks())
314  _blocks.push_back(block);
315 }
316 
317 void
319 {
321  Action::addRelationshipManagers(input_rm_type, params);
322 }
323 
324 const ActionComponent &
325 PhysicsBase::getActionComponent(const ComponentName & comp_name) const
326 {
327  return _awh.getAction<ActionComponent>(comp_name);
328 }
329 
330 void
332 {
333  // Annoying edge case. We cannot use ANY_BLOCK_ID for kernels and variables since errors got
334  // added downstream for using it, we cannot leave it empty as that sets all objects to not live
335  // on any block
336  if (isParamSetByUser("block") && _blocks.empty())
337  paramError("block",
338  "Empty block restriction is not supported. Comment out the Physics if you are "
339  "trying to disable it.");
340 
341  // Components should have added their blocks already.
342  if (_blocks.empty())
343  _blocks.push_back("ANY_BLOCK_ID");
344 
345  mooseAssert(_mesh, "We should have a mesh to find the dimension");
346  if (_blocks.size())
347  _dim = _mesh->getBlocksMaxDimension(_blocks);
348  else
349  _dim = _mesh->dimension();
350 
351  // Forward physics verbosity to problem to output the setup
352  if (_verbose)
354 
355  // If the derived physics need additional initialization very early on
357 
358  // Check that the systems exist in the Problem
359  // TODO: try to add the systems to the problem from here instead
360  // NOTE: this must be performed after the "Additional" initialization because the list
361  // of systems might have been adjusted once the dimension of the Physics is known
362  const auto & problem_nl_systems = getProblem().getNonlinearSystemNames();
363  const auto & problem_lin_systems = getProblem().getLinearSystemNames();
364  for (const auto & sys_name : _system_names)
365  if (std::find(problem_nl_systems.begin(), problem_nl_systems.end(), sys_name) ==
366  problem_nl_systems.end() &&
367  std::find(problem_lin_systems.begin(), problem_lin_systems.end(), sys_name) ==
368  problem_lin_systems.end() &&
369  solverVariableNames().size())
370  mooseError("System '", sys_name, "' is not found in the Problem");
371 
372  // Cache system number as it makes some logic easier
373  for (const auto & sys_name : _system_names)
374  _system_numbers.push_back(getProblem().solverSysNum(sys_name));
375 }
376 
377 void
379 {
380  if (_is_transient == "true" && !getProblem().isTransient())
381  paramError("transient", "We cannot solve a physics as transient in a steady problem");
382 
383  // Check that there is a system for each variable
384  if (_system_names.size() != 1 && _system_names.size() != _solver_var_names.size())
385  paramError("system_names",
386  "There should be one system name per solver variable (potentially repeated), or a "
387  "single system name for all variables. Currently you have '" +
388  std::to_string(_system_names.size()) + "' systems specified for '" +
389  std::to_string(_solver_var_names.size()) + "' solver variables.");
390 
391  // Check that each variable is present in the expected system
392  unsigned int var_i = 0;
393  for (const auto & var_name : _solver_var_names)
394  {
395  const auto & sys_name = _system_names.size() == 1 ? _system_names[0] : _system_names[var_i++];
396  if (!_problem->getSolverSystem(_problem->solverSysNum(sys_name)).hasVariable(var_name) &&
397  !_problem->getSolverSystem(_problem->solverSysNum(sys_name)).hasScalarVariable(var_name))
398  paramError("system_names",
399  "We expected system '" + sys_name + "' to contain variable '" + var_name +
400  "' but it did not. Make sure the system names closely match the ordering of "
401  "the variables in the Physics.");
402  }
403 }
404 
405 void
406 PhysicsBase::copyVariablesFromMesh(const std::vector<VariableName> & variables_to_copy,
407  bool are_solver_var)
408 {
409  if (getParam<bool>("initialize_variables_from_mesh_file"))
410  {
411  mooseInfoRepeated("Adding Exodus restart for " + std::to_string(variables_to_copy.size()) +
412  " variables: " + Moose::stringify(variables_to_copy));
413  // TODO Check that the variable types and orders are actually supported for exodus restart
414  for (const auto i : index_range(variables_to_copy))
415  {
416  SystemBase & system = are_solver_var ? getProblem().getSystemBase(_system_numbers.size() == 1
417  ? _system_numbers[0]
418  : _system_numbers[i])
420  const auto & var_name = variables_to_copy[i];
421  system.addVariableToCopy(
422  var_name, var_name, getParam<std::string>("initial_from_file_timestep"));
423  }
424  }
425 }
426 
427 bool
428 PhysicsBase::variableExists(const VariableName & var_name, bool error_if_aux) const
429 {
430  if (error_if_aux && _problem->getAuxiliarySystem().hasVariable(var_name))
431  mooseError("Variable '",
432  var_name,
433  "' is supposed to be nonlinear for physics '",
434  name(),
435  "' but it is already defined as auxiliary");
436  else
437  return _problem->hasVariable(var_name);
438 }
439 
440 bool
441 PhysicsBase::solverVariableExists(const VariableName & var_name) const
442 {
443  return _problem->hasSolverVariable(var_name);
444 }
445 
446 const SolverSystemName &
447 PhysicsBase::getSolverSystem(unsigned int variable_index) const
448 {
449  mooseAssert(!_system_names.empty(), "We should have a solver system name");
450  if (_system_names.size() == 1)
451  return _system_names[0];
452  else
453  // We trust that the system names and the variable names match one-to-one as it is enforced by
454  // the checkIntegrityEarly() routine.
455  return _system_names[variable_index];
456 }
457 
458 const SolverSystemName &
459 PhysicsBase::getSolverSystem(const VariableName & var_name) const
460 {
461  mooseAssert(!_system_names.empty(), "We should have a solver system name");
462  // No need to look if only one system for the Physics
463  if (_system_names.size() == 1)
464  return _system_names[0];
465 
466  // We trust that the system names and the variable names match one-to-one as it is enforced by
467  // the checkIntegrityEarly() routine.
468  for (const auto variable_index : index_range(_solver_var_names))
469  if (var_name == _solver_var_names[variable_index])
470  return _system_names[variable_index];
471  mooseError("Variable '", var_name, "' was not found within the Physics solver variables.");
472 }
473 
474 void
476 {
477  const auto registered_tasks = _action_factory.getTasksByAction(type());
478 
479  // Check for missing tasks
480  for (const auto & required_task : _required_tasks)
481  if (!registered_tasks.count(required_task))
482  mooseWarning("Task '" + required_task +
483  "' has been declared as required by a Physics parent class of derived class '" +
484  type() +
485  "' but this task is not registered to the derived class. Registered tasks for "
486  "this Physics are: " +
487  Moose::stringify(registered_tasks));
488 }
489 
490 void
491 PhysicsBase::assignBlocks(InputParameters & params, const std::vector<SubdomainName> & blocks) const
492 {
493  // We only set the blocks if we don't have `ANY_BLOCK_ID` defined because the subproblem
494  // (through the mesh) errors out if we use this keyword during the addVariable/Kernel
495  // functions
496  if (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") == blocks.end())
497  params.set<std::vector<SubdomainName>>("block") = blocks;
498  if (blocks.empty())
499  mooseInfoRepeated("Empty block restriction assigned to an object created by Physics '" +
500  name() + "'.\n Did you mean to do this?");
501 }
502 
503 bool
504 PhysicsBase::checkBlockRestrictionIdentical(const std::string & object_name,
505  const std::vector<SubdomainName> & blocks,
506  bool error_if_not_identical) const
507 {
508  // If identical, we can return fast
509  if (_blocks == blocks)
510  return true;
511  // If one is block restricted to anywhere and the other is block restricted to anywhere manually
512  if ((std::find(_blocks.begin(), _blocks.end(), "ANY_BLOCK_ID") != _blocks.end() &&
513  allMeshBlocks(blocks)) ||
514  (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") != blocks.end() &&
516  return true;
517 
518  // Copy, sort and unique is the only way to check that they are actually the same
519  auto copy_blocks = _blocks;
520  auto copy_blocks_other = blocks;
521  std::sort(copy_blocks.begin(), copy_blocks.end());
522  copy_blocks.erase(unique(copy_blocks.begin(), copy_blocks.end()), copy_blocks.end());
523  std::sort(copy_blocks_other.begin(), copy_blocks_other.end());
524  copy_blocks_other.erase(unique(copy_blocks_other.begin(), copy_blocks_other.end()),
525  copy_blocks_other.end());
526 
527  if (copy_blocks == copy_blocks_other)
528  return true;
529  std::vector<SubdomainName> diff;
530  std::set_difference(copy_blocks.begin(),
531  copy_blocks.end(),
532  copy_blocks_other.begin(),
533  copy_blocks_other.end(),
534  std::inserter(diff, diff.begin()));
535  if (error_if_not_identical)
536  mooseError("Physics '",
537  name(),
538  "' and object '",
539  object_name,
540  "' have different block restrictions.\nPhysics: ",
542  "\nObject: ",
544  "\nDifference: ",
545  Moose::stringify(diff));
546  else
547  return false;
548 }
549 
550 bool
551 PhysicsBase::hasBlocks(const std::vector<SubdomainName> & blocks) const
552 {
553  mooseAssert(_blocks.size(), "hasBlocks called before blocks were initialized");
554  return std::all_of(blocks.begin(),
555  blocks.end(),
556  [this](const SubdomainName & block)
557  { return std::find(_blocks.begin(), _blocks.end(), block) != _blocks.end(); });
558 }
559 
560 bool
561 PhysicsBase::allMeshBlocks(const std::vector<SubdomainName> & blocks) const
562 {
563  mooseAssert(_mesh, "The mesh should exist already");
564  // Try to return faster without examining every single block
565  if (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") != blocks.end())
566  return true;
567  else if (blocks.size() != _mesh->meshSubdomains().size())
568  return false;
569 
570  for (const auto mesh_block : _mesh->meshSubdomains())
571  {
572  const auto & subdomain_name = _mesh->getSubdomainName(mesh_block);
573  // Check subdomain name
574  if (!subdomain_name.empty() &&
575  std::find(blocks.begin(), blocks.end(), subdomain_name) == blocks.end())
576  return false;
577  // no subdomain name, check the IDs being used as names instead
578  else if (std::find(blocks.begin(), blocks.end(), std::to_string(mesh_block)) == blocks.end())
579  return false;
580  }
581  return true;
582 }
583 
584 bool
585 PhysicsBase::allMeshBlocks(const std::set<SubdomainName> & blocks) const
586 {
587  std::vector<SubdomainName> blocks_vec(blocks.begin(), blocks.end());
588  return allMeshBlocks(blocks_vec);
589 }
590 
591 void
593  const std::vector<std::pair<MooseEnumItem, std::string>> & petsc_pair_options)
594 {
595  Moose::PetscSupport::PetscOptions & po = _problem->getPetscOptions();
596  for (const auto solver_sys_num : _system_numbers)
598  petsc_pair_options,
599  _problem->mesh().dimension(),
600  _problem->getSolverSystem(solver_sys_num).prefix(),
601  *this,
602  po);
603 }
604 
605 bool
606 PhysicsBase::isVariableFV(const VariableName & var_name) const
607 {
608  const auto var = &_problem->getVariable(0, var_name);
609  return var->isFV();
610 }
611 
612 bool
613 PhysicsBase::isVariableScalar(const VariableName & var_name) const
614 {
615  return _problem->hasScalarVariable(var_name);
616 }
617 
618 bool
619 PhysicsBase::shouldCreateVariable(const VariableName & var_name,
620  const std::vector<SubdomainName> & blocks,
621  const bool error_if_aux)
622 {
623  if (!variableExists(var_name, error_if_aux))
624  return true;
625  // check block restriction
626  auto & var = _problem->getVariable(0, var_name);
627  const bool not_block_restricted =
628  (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") != blocks.end()) ||
630  if (!var.blockRestricted() || (!not_block_restricted && var.hasBlocks(blocks)))
631  return false;
632 
633  // This is an edge case, which might warrant a warning
634  if (allMeshBlocks(var.blocks()) && not_block_restricted)
635  return false;
636  else
637  mooseError("Variable '" + var_name + "' already exists with subdomain restriction '" +
638  Moose::stringify(var.blocks()) + "' which does not include the subdomains '" +
639  Moose::stringify(blocks) + "', required for this Physics.");
640 }
641 
642 bool
643 PhysicsBase::shouldCreateIC(const VariableName & var_name,
644  const std::vector<SubdomainName> & blocks,
645  const bool ic_is_default_ic,
646  const bool error_if_already_defined) const
647 {
648  // Handle recover
649  if (ic_is_default_ic && (_app.isRestarting() || _app.isRecovering()))
650  return false;
651  // do not set initial conditions if we are loading fields from the mesh file
652  if (getParam<bool>("initialize_variables_from_mesh_file"))
653  return false;
654  // Different type of ICs, not block restrictable
655  mooseAssert(!isVariableScalar(var_name), "shouldCreateIC not implemented for scalar variables");
656 
657  // Process the desired block restriction into a set of subdomain IDs
658  std::set<SubdomainName> blocks_set(blocks.begin(), blocks.end());
659  const auto blocks_ids_set = getSubdomainIDs(blocks_set);
660 
661  // Check whether there are any ICs for this variable already in the problem
662  std::set<SubdomainID> blocks_ids_covered;
663  bool has_all_blocks;
664  if (isVariableFV(var_name))
665  {
666  has_all_blocks = _problem->getFVInitialConditionWarehouse().hasObjectsForVariableAndBlocks(
667  var_name, blocks_ids_set, blocks_ids_covered, /*tid =*/0);
668  // FV variables can be initialized by non-FV ICs
669  std::set<SubdomainID> blocks_ids_covered_fe;
670  const bool has_all_blocks_from_feics =
671  _problem->getInitialConditionWarehouse().hasObjectsForVariableAndBlocks(
672  var_name, blocks_ids_set, blocks_ids_covered_fe, /*tid =*/0);
673  // Note we are missing the case with complete but split coverage
674  has_all_blocks = has_all_blocks || has_all_blocks_from_feics;
675  blocks_ids_covered.insert(blocks_ids_covered_fe.begin(), blocks_ids_covered_fe.end());
676  }
677  else
678  has_all_blocks = _problem->getInitialConditionWarehouse().hasObjectsForVariableAndBlocks(
679  var_name, blocks_ids_set, blocks_ids_covered, /*tid =*/0);
680 
681  const bool has_some_blocks = !blocks_ids_covered.empty();
682  if (!has_some_blocks)
683  return true;
684 
685  if (has_all_blocks)
686  {
687  if (error_if_already_defined)
688  mooseError("ICs for variable '" + var_name + "' have already been defined for blocks '" +
689  Moose::stringify(blocks) + "'.");
690  else
691  return false;
692  }
693 
694  // Partial overlap between Physics is not implemented.
695  mooseError("There is a partial overlap between the subdomains covered by pre-existing initial "
696  "conditions (ICs), defined on blocks (ids): " +
697  Moose::stringify(getSubdomainNamesAndIDs(blocks_ids_covered)) +
698  "\n and a newly created IC for variable '" + var_name +
699  "', to be defined on blocks: " + Moose::stringify(blocks) +
700  ".\nWe should be creating the Physics' IC only for non-covered blocks. This is not "
701  "implemented at this time.");
702 }
703 
704 bool
705 PhysicsBase::shouldCreateTimeDerivative(const VariableName & var_name,
706  const std::vector<SubdomainName> & blocks,
707  const bool error_if_already_defined) const
708 {
709  // Follow the transient setting of the Physics
710  if (!isTransient())
711  return false;
712 
713  // Variable is either nonlinear (FV/FE), nodal nonlinear (field of ODEs), linear, or scalar.
714  // The warehouses hosting the time kernels are different for each of these types
715  // Different type of time derivatives, not block restrictable
716  mooseAssert(!isVariableScalar(var_name),
717  "shouldCreateTimeDerivative not implemented for scalar variables");
718  mooseAssert(!_problem->hasAuxiliaryVariable(var_name),
719  "Should not be called with auxiliary variables");
720 
721  // Get solver system type
722  const auto var = &_problem->getVariable(0, var_name);
723  const auto var_id = var->number();
724  const auto sys_num = var->sys().number();
725  const auto time_vector_tag =
726  (sys_num < _problem->numNonlinearSystems())
727  ? var->sys().timeVectorTag()
728  // this is not quite correct. Many kernels can contribute to RHS time vector on paper
729  : dynamic_cast<LinearSystem *>(&var->sys())->rightHandSideTimeVectorTag();
730 
731  // We just use the warehouse, it should cover every time derivative object type
732  bool all_blocks_covered = true;
733  std::set<SubdomainID> blocks_ids_covered;
734  // we examine subdomain by subdomain, because mutiple kernels could be covering every block in
735  // the 'blocks' parameter
736  for (const auto & block : blocks)
737  {
738  std::vector<MooseObject *> time_kernels;
739  if (block != "ANY_BLOCK_ID")
740  {
741  const auto bid = _mesh->getSubdomainID(block);
742  _problem->theWarehouse()
743  .query()
744  .template condition<AttribSysNum>(sys_num)
745  .template condition<AttribVar>(var_id)
746  .template condition<AttribSubdomains>(bid)
747  // we use the time tag as a proxy for time derivatives
748  .template condition<AttribVectorTags>(time_vector_tag)
749  .queryInto(time_kernels);
750  }
751  else
752  _problem->theWarehouse()
753  .query()
754  .template condition<AttribSysNum>(sys_num)
755  .template condition<AttribVar>(var_id)
756  // we use the time tag as a proxy for time derivatives
757  .template condition<AttribVectorTags>(time_vector_tag)
758  .queryInto(time_kernels);
759 
760  if (time_kernels.size())
761  {
762  if (block == "ANY_BLOCK_ID")
763  {
764  for (const auto & time_kernel : time_kernels)
765  if (const auto blk = dynamic_cast<BlockRestrictable *>(time_kernel))
766  blocks_ids_covered.insert(blk->blockIDs().begin(), blk->blockIDs().end());
767  }
768  else
769  blocks_ids_covered.insert(_mesh->getSubdomainID(block));
770  }
771  else
772  all_blocks_covered = false;
773  }
774 
775  // From the set of covered blocks, see if the blocks we needed are found
776  if (all_blocks_covered)
777  {
778  std::set<SubdomainName> blocks_set(blocks.begin(), blocks.end());
779  const auto blocks_ids = getSubdomainIDs(blocks_set);
780  if (blocks_ids != blocks_ids_covered)
781  all_blocks_covered = false;
782  }
783  const bool has_some_blocks = !blocks_ids_covered.empty();
784  if (!has_some_blocks)
785  return true;
786  if (all_blocks_covered)
787  {
788  if (error_if_already_defined)
789  mooseError("A time kernel for variable '" + var_name +
790  "' has already been defined on blocks '" + Moose::stringify(blocks) + "'.");
791  else
792  return false;
793  }
794 
795  // Partial overlap between Physics is not implemented.
796  mooseError("There is a partial overlap between the subdomains covered by pre-existing time "
797  "derivative kernel(s), defined on blocks (ids): " +
798  Moose::stringify(getSubdomainNamesAndIDs(blocks_ids_covered)) +
799  "\nand a newly created time derivative kernel for variable " + var_name +
800  ", to be defined on blocks: " + Moose::stringify(blocks) +
801  ".\nWe should be creating the Physics' time derivative only for non-covered "
802  "blocks. This is not implemented at this time.");
803 }
804 
805 void
806 PhysicsBase::reportPotentiallyMissedParameters(const std::vector<std::string> & param_names,
807  const std::string & object_type,
808  const std::string & object_name) const
809 {
810  std::vector<std::string> defaults_unused;
811  std::vector<std::string> user_values_unused;
812  for (const auto & param : param_names)
813  {
814  if (isParamSetByUser(param))
815  user_values_unused.push_back(param);
816  else if (isParamValid(param))
817  defaults_unused.push_back(param);
818  }
819  const std::string object_name_string =
820  object_name.empty() ? "" : ("and name '" + object_name + "' ");
821 
822  if (defaults_unused.size() && _verbose)
823  mooseInfoRepeated("Defaults for parameters '" + Moose::stringify(defaults_unused) +
824  "' for object of type '" + object_type + "' " + object_name_string +
825  "were not used because the object was not created by this Physics.");
826  if (user_values_unused.size())
827  {
829  mooseWarning(
830  "User-specifed values for parameters '" + Moose::stringify(user_values_unused) +
831  "' for object of type '" + object_type + "' " + object_name_string +
832  "were not used because the corresponding object was not created by this Physics.");
833  else if (_app.unusedFlagIsError())
834  mooseError("User-specified values for parameters '" + Moose::stringify(user_values_unused) +
835  "' for object of type '" + object_type + "' " + object_name_string +
836  "were not used because the corresponding object was not created by this Physics.");
837  }
838 }
const T & getAction(const std::string &name) const
Retrieve an action with its name and the desired type.
const std::vector< VariableName > & auxVariableNames() const
Return the list of aux variables in this physics.
Definition: PhysicsBase.h:106
const std::vector< NonlinearSystemName > & getNonlinearSystemNames() const
virtual void act() override final
Forwards from the action tasks to the implemented addXYZ() in the derived classes If you need more th...
Definition: PhysicsBase.C:124
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:40
virtual InputParameters getAdditionalRMParams() const
Provide additional parameters for the relationship managers.
Definition: PhysicsBase.h:38
void assignBlocks(InputParameters &params, const std::vector< SubdomainName > &blocks) const
Set the blocks parameter to the input parameters of an object this Physics will create.
Definition: PhysicsBase.C:491
virtual void addInitialConditions()
Definition: PhysicsBase.h:294
bool shouldCreateVariable(const VariableName &var_name, const std::vector< SubdomainName > &blocks, const bool error_if_aux)
Returns whether this Physics should create the variable.
Definition: PhysicsBase.C:619
std::vector< VariableName > _aux_var_names
Vector of the aux variables in the Physics.
Definition: PhysicsBase.h:333
virtual void addFVInterfaceKernels()
Definition: PhysicsBase.h:302
virtual void addPreconditioning()
Definition: PhysicsBase.h:319
MooseEnum _is_transient
Whether the physics is to be solved as a transient.
Definition: PhysicsBase.h:328
RelationshipManagerType
Main types of Relationship Managers.
Definition: MooseTypes.h:1012
ActionWarehouse & _awh
Reference to ActionWarehouse where we store object build by actions.
Definition: Action.h:169
void initializePhysics()
Process some parameters that require the problem to be created. Executed on init_physics.
Definition: PhysicsBase.C:331
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseBase.h:467
void addRequiredPhysicsTask(const std::string &task)
Add a new required task for all physics deriving from this class NOTE: This does not register the tas...
Definition: PhysicsBase.h:164
void addPetscPairsToPetscOptions(const std::vector< std::pair< MooseEnumItem, std::string >> &petsc_pair_options)
Process the given petsc option pairs into the system solver settings.
Definition: PhysicsBase.C:592
char ** blocks
void addPetscPairsToPetscOptions(const std::vector< std::pair< MooseEnumItem, std::string >> &petsc_pair_options, const unsigned int mesh_dimension, std::string prefix, const ParallelParamObject &param_object, PetscOptions &petsc_options)
Populate name and value pairs in a given PetscOptions object using vectors of input arguments...
Definition: PetscSupport.C:831
virtual void checkIntegrity() const
Additional checks performed near the end of the setup phase.
Definition: PhysicsBase.h:257
Base class to help creating an entire physics.
Definition: PhysicsBase.h:30
virtual void checkIntegrityEarly() const
Additional checks performed once the executioner / executor has been created.
Definition: PhysicsBase.C:378
std::set< std::string > getTasksByAction(const std::string &action) const
virtual void addMultiApps()
Definition: PhysicsBase.h:313
ActionFactory & _action_factory
Builds Actions.
virtual void addAuxiliaryKernels()
Definition: PhysicsBase.h:308
A struct for storing the various types of petsc options and values.
Definition: PetscSupport.h:44
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
virtual void addPeriodicBCs()
Definition: PhysicsBase.h:306
const std::vector< SubdomainName > & blocks() const
Return the blocks this physics is defined on.
Definition: PhysicsBase.h:60
void reportPotentiallyMissedParameters(const std::vector< std::string > &param_names, const std::string &object_type, const std::string &object_name="") const
When this is called, we are knowingly not using the value of these parameters.
Definition: PhysicsBase.C:806
void mooseInfoRepeated(Args &&... args)
Emit an informational message with the given stringified, concatenated args.
Definition: MooseError.h:409
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
virtual void addVariableToCopy(const std::string &dest_name, const std::string &source_name, const std::string &timestep)
Add info about variable that will be copied.
Definition: SystemBase.C:1176
bool solverVariableExists(const VariableName &var_name) const
Check whether a variable already exists and is a solver variable.
Definition: PhysicsBase.C:441
const bool _verbose
Whether to output additional information.
Definition: PhysicsBase.h:266
Base class for components that are defined using an action.
bool shouldCreateIC(const VariableName &var_name, const std::vector< SubdomainName > &blocks, const bool ic_is_default_ic, const bool error_if_already_defined) const
Returns whether this Physics should create the variable.
Definition: PhysicsBase.C:643
bool shouldCreateTimeDerivative(const VariableName &var_name, const std::vector< SubdomainName > &blocks, const bool error_if_already_defined) const
Returns whether this Physics should create the variable.
Definition: PhysicsBase.C:705
Base class for a system (of equations)
Definition: SystemBase.h:85
bool isRestarting() const
Whether or not this is a "restart" calculation.
Definition: MooseApp.C:1499
bool allMeshBlocks(const std::vector< SubdomainName > &blocks) const
Check if a vector contains all the mesh blocks.
Definition: PhysicsBase.C:561
std::vector< SubdomainName > _blocks
Keep track of the subdomains the Physics is defined on.
Definition: PhysicsBase.h:273
Base class for actions.
Definition: Action.h:34
unsigned int dimension() const
Return the maximum dimension of the blocks the Physics is active on.
Definition: PhysicsBase.C:252
virtual void addFVBCs()
Definition: PhysicsBase.h:304
void addBlocks(const std::vector< SubdomainName > &blocks)
Add new blocks to the Physics.
Definition: PhysicsBase.C:290
Utility class to help check parameters.
virtual FEProblemBase & getProblem()
Get the problem for this physics Useful to add objects to the simulation.
Definition: PhysicsBase.h:118
void mooseWarning(Args &&... args) const
const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:103
static InputParameters validParams()
Definition: Action.C:26
virtual void addNodalBCs()
Definition: PhysicsBase.h:305
const SolverSystemName & getSolverSystem(unsigned int variable_index) const
Get the solver system for this variable index.
Definition: PhysicsBase.C:447
virtual void addNodalKernels()
Definition: PhysicsBase.h:297
virtual void addDGKernels()
Definition: PhysicsBase.h:299
bool unusedFlagIsError() const
Returns whether the flag for unused parameters is set to throw an error.
Definition: MooseApp.h:1094
virtual void addMaterials()
Definition: PhysicsBase.h:309
std::set< std::string > _required_tasks
Manually keeps track of the tasks required by each physics as tasks cannot be inherited.
Definition: PhysicsBase.h:340
void setExodusFileRestart(bool flag)
Set the flag to indicate whether or not we need to use a separate Exodus reader to read the mesh BEFO...
Definition: MooseApp.h:429
bool isVariableScalar(const VariableName &var_name) const
Whether the variable is a scalar variable (global single scalar, not a field)
Definition: PhysicsBase.C:613
PhysicsBase(const InputParameters &parameters)
Definition: PhysicsBase.C:106
void copyVariablesFromMesh(const std::vector< VariableName > &variables_to_copy, bool are_nonlinear=true)
Copy nonlinear or aux variables from the mesh file.
Definition: PhysicsBase.C:406
unsigned int _dim
Dimension of the physics, which we expect for now to be the dimension of the mesh NOTE: this is not k...
Definition: PhysicsBase.h:337
virtual void addReporters()
Definition: PhysicsBase.h:317
bool isVariableFV(const VariableName &var_name) const
Whether the variable is a finite volume variable.
Definition: PhysicsBase.C:606
std::vector< std::string > getSubdomainNamesAndIDs(const std::set< SubdomainID > &blocks) const
Get the vector of subdomain names and ids for the incoming set of subdomain IDs.
Definition: PhysicsBase.C:275
const std::string & type() const
Get the type of this class.
Definition: MooseBase.h:93
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:54
const std::string & _current_task
The current action (even though we have separate instances for each action)
Definition: Action.h:172
virtual const SystemBase & systemBaseAuxiliary() const override
Return the auxiliary system object as a base class reference.
virtual void addPostprocessors()
Definition: PhysicsBase.h:315
virtual void addFunctions()
Definition: PhysicsBase.h:307
virtual void addFEBCs()
Definition: PhysicsBase.h:303
MooseApp & _app
The MOOSE application this is associated with.
Definition: MooseBase.h:385
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
virtual void addSolverVariables()
The default implementation of these routines will do nothing as we do not expect all Physics to be de...
Definition: PhysicsBase.h:292
virtual void addExecutioner()
Definition: PhysicsBase.h:320
bool hasBlocks(const std::vector< SubdomainName > &blocks) const
Whether the Physics is defined on those blocks.
Definition: PhysicsBase.C:551
const std::vector< LinearSystemName > & getLinearSystemNames() const
const std::vector< VariableName > & solverVariableNames() const
Return the list of solver (nonlinear + linear) variables in this physics.
Definition: PhysicsBase.h:104
bool variableExists(const VariableName &var_name, bool error_if_aux) const
Check whether a variable already exists.
Definition: PhysicsBase.C:428
bool checkBlockRestrictionIdentical(const std::string &object_name, const std::vector< SubdomainName > &blocks, const bool error_if_not_identical=true) const
Check if an external object has the same block restriction.
Definition: PhysicsBase.C:504
virtual void addFVKernels()
Definition: PhysicsBase.h:296
static InputParameters validParams()
Definition: PhysicsBase.C:24
virtual const SystemBase & getSystemBase(const unsigned int sys_num) const
Get constant reference to a system in this problem.
std::shared_ptr< MooseMesh > & _mesh
Definition: Action.h:174
std::vector< VariableName > _solver_var_names
Vector of the solver variables (nonlinear and linear) in the Physics.
Definition: PhysicsBase.h:331
std::set< SubdomainID > getSubdomainIDs(const std::set< SubdomainName > &blocks) const
Get the set of subdomain ids for the incoming vector of subdomain names.
Definition: PhysicsBase.C:260
virtual void addComponent(const ActionComponent &component)
Most basic way of adding a component: simply adding the blocks to the block restriction of the Physic...
Definition: PhysicsBase.C:311
virtual void addFEKernels()
Definition: PhysicsBase.h:295
virtual void addUserObjects()
Definition: PhysicsBase.h:311
virtual void addRelationshipManagers(Moose::RelationshipManagerType input_rm_type) override
Method to add a relationship manager for the objects being added to the system.
Definition: PhysicsBase.C:318
bool unusedFlagIsWarning() const
Returns whether the flag for unused parameters is set to throw a warning only.
Definition: MooseApp.h:1091
virtual void actOnAdditionalTasks()
Routine to add additional setup work on additional registered tasks to a Physics. ...
Definition: PhysicsBase.h:49
void addBlocksById(const std::vector< SubdomainID > &block_ids)
Definition: PhysicsBase.C:300
void prepareCopyVariablesFromMesh() const
Tell the app if we want to use Exodus restart.
Definition: PhysicsBase.C:230
const std::vector< SubdomainName > & blocks() const
Returns the subdomains for the component mesh, if any.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:281
virtual void addOutputs()
Definition: PhysicsBase.h:318
bool addRelationshipManagers(Moose::RelationshipManagerType when_type, const InputParameters &moose_object_pars)
Method to add a relationship manager for the objects being added to the system.
Definition: Action.C:131
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
std::shared_ptr< FEProblemBase > & _problem
Convenience reference to a problem this action works on.
Definition: Action.h:178
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
Linear system to be solved.
Definition: LinearSystem.h:39
virtual void addDiracKernels()
Definition: PhysicsBase.h:298
virtual void addVectorPostprocessors()
Definition: PhysicsBase.h:316
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:209
virtual void addExecutors()
Definition: PhysicsBase.h:321
virtual bool isTransient() const override
virtual void addInterfaceKernels()
Definition: PhysicsBase.h:301
virtual void addFunctorMaterials()
Definition: PhysicsBase.h:310
const ActionComponent & getActionComponent(const ComponentName &comp_name) const
Get a component with the requested name.
Definition: PhysicsBase.C:325
void checkSecondParamSetOnlyIfFirstOneTrue(const std::string &param1, const std::string &param2) const
Check that a parameter is set only if the first one is set to true.
std::vector< unsigned int > _system_numbers
System numbers for the system(s) owning the solver variables.
Definition: PhysicsBase.h:263
virtual void addTransfers()
Definition: PhysicsBase.h:314
bool isRecovering() const
Whether or not this is a "recover" calculation.
Definition: MooseApp.C:1493
virtual void addCorrectors()
Definition: PhysicsBase.h:312
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
Definition: MooseBase.h:215
void setVerboseProblem(bool verbose)
Make the problem be verbose.
auto index_range(const T &sizable)
std::vector< SolverSystemName > _system_names
System names for the system(s) owning the solver variables.
Definition: PhysicsBase.h:260
bool isTransient() const
Return whether the Physics is solved using a transient.
Definition: PhysicsBase.C:240
virtual void addAuxiliaryVariables()
Definition: PhysicsBase.h:293
virtual void initializePhysicsAdditional()
Additional initialization work that should happen very early, as soon as the problem is created...
Definition: PhysicsBase.h:284
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...
virtual void addScalarKernels()
Definition: PhysicsBase.h:300
void checkRequiredTasks() const
Check the list of required tasks for missing tasks.
Definition: PhysicsBase.C:475