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_interpolation_method_physics" &&
144  !getParam<bool>("dont_create_kernels"))
146  else if (_current_task == "add_kernel" && !getParam<bool>("dont_create_kernels"))
147  addFEKernels();
148  else if (_current_task == "add_nodal_kernel" && !getParam<bool>("dont_create_kernels"))
149  addNodalKernels();
150  else if ((_current_task == "add_fv_kernel" || _current_task == "add_linear_fv_kernel") &&
151  !getParam<bool>("dont_create_kernels"))
152  addFVKernels();
153  else if (_current_task == "add_dirac_kernel" && !getParam<bool>("dont_create_kernels"))
154  addDiracKernels();
155  else if (_current_task == "add_dg_kernel" && !getParam<bool>("dont_create_kernels"))
156  addDGKernels();
157  else if (_current_task == "add_scalar_kernel" && !getParam<bool>("dont_create_kernels"))
159  else if (_current_task == "add_interface_kernel" && !getParam<bool>("dont_create_kernels"))
161  else if (_current_task == "add_fv_ik" && !getParam<bool>("dont_create_kernels"))
163 
164  // Boundary conditions
165  else if (_current_task == "add_bc" && !getParam<bool>("dont_create_bcs"))
166  addFEBCs();
167  else if (_current_task == "add_nodal_bc" && !getParam<bool>("dont_create_bcs"))
168  addNodalBCs();
169  else if ((_current_task == "add_fv_bc" || _current_task == "add_linear_fv_bc") &&
170  !getParam<bool>("dont_create_bcs"))
171  addFVBCs();
172  else if (_current_task == "add_periodic_bc" && !getParam<bool>("dont_create_bcs"))
173  addPeriodicBCs();
174 
175  // Auxiliary quantities
176  else if (_current_task == "add_function" && !getParam<bool>("dont_create_functions"))
177  addFunctions();
178  else if (_current_task == "add_aux_variable" && !getParam<bool>("dont_create_aux_variables"))
180  else if (_current_task == "add_aux_kernel" && !getParam<bool>("dont_create_aux_kernels"))
182  else if ((_current_task == "add_material" || _current_task == "add_materials_physics") &&
183  !getParam<bool>("dont_create_materials"))
184  addMaterials();
185  else if (_current_task == "add_functor_material" && !getParam<bool>("dont_create_materials"))
187 
188  // Multiapp
189  else if (_current_task == "add_multi_app")
190  addMultiApps();
191  else if (_current_task == "add_transfer")
192  addTransfers();
193 
194  // User objects and output
195  else if (_current_task == "add_user_object" && !getParam<bool>("dont_create_user_objects"))
196  addUserObjects();
197  else if (_current_task == "add_corrector" && !getParam<bool>("dont_create_correctors"))
198  addCorrectors();
199  else if (_current_task == "add_postprocessor" && !getParam<bool>("dont_create_postprocessors"))
201  else if (_current_task == "add_vector_postprocessor" &&
202  !getParam<bool>("dont_create_vectorpostprocessors"))
204  else if (_current_task == "add_reporter")
205  addReporters();
206  else if (_current_task == "add_output")
207  addOutputs();
208 
209  // Equation solver-related tasks
210  else if (_current_task == "add_preconditioning")
212  else if (_current_task == "add_executioner")
213  addExecutioner();
214  else if (_current_task == "add_executor")
215  addExecutors();
216 
217  // Checks
218  else if (_current_task == "check_integrity_early_physics")
220  else if (_current_task == "check_integrity")
221  checkIntegrity();
222 
223  // Exodus restart capabilities
224  if (_current_task == "copy_vars_physics")
225  {
227  if (_aux_var_names.size() > 0)
229  }
230 }
231 
232 void
233 PhysicsBase::addUserObject(const std::string & uo_type,
234  const std::string & uo_name,
235  InputParameters & params)
236 {
237  mooseAssert(
238  [&]()
239  {
240  const auto supplied = getSuppliedUserObjects();
241  return std::find(supplied.begin(), supplied.end(), uo_name) != supplied.end();
242  }(),
243  "The UserObject '" + uo_name + "' added by Physics '" + name() +
244  "' was not declared in getSuppliedUserObjects(). Declare it there so its construction "
245  "order can be resolved.");
246  getProblem().addUserObject(uo_type, uo_name, params);
247 }
248 
249 void
251 {
252  if (getParam<bool>("initialize_variables_from_mesh_file"))
254 
255  checkSecondParamSetOnlyIfFirstOneTrue("initialize_variables_from_mesh_file",
256  "initial_from_file_timestep");
257 }
258 
259 bool
261 {
262  mooseAssert(_problem, "We don't have a problem yet");
263  if (_is_transient == "true")
264  return true;
265  else if (_is_transient == "false")
266  return false;
267  else
268  return getProblem().isTransient();
269 }
270 
271 unsigned int
273 {
274  mooseAssert(_mesh, "We dont have a mesh yet");
275  mooseAssert(_dim < 4, "Dimension has not been set yet");
276  return _dim;
277 }
278 
279 std::set<SubdomainID>
280 PhysicsBase::getSubdomainIDs(const std::set<SubdomainName> & blocks) const
281 {
282  const bool not_block_restricted =
283  (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") != blocks.end()) ||
285  mooseAssert(_mesh, "Should have a mesh");
286  // use a set for simplicity. Note that subdomain names are unique, except maybe the empty one,
287  // which cannot be specified by the user to the Physics.
288  // MooseMesh::getSubdomainIDs cannot deal with the 'ANY_BLOCK_ID' name
289  std::set<SubdomainID> block_ids_set =
290  not_block_restricted ? _mesh->meshSubdomains() : _mesh->getSubdomainIDs(blocks);
291  return block_ids_set;
292 }
293 
294 std::vector<std::string>
295 PhysicsBase::getSubdomainNamesAndIDs(const std::set<SubdomainID> & blocks) const
296 {
297  mooseAssert(_mesh, "Should have a mesh");
298  std::vector<std::string> sub_names_ids;
299  sub_names_ids.reserve(blocks.size());
300  for (const auto bid : blocks)
301  {
302  const auto bname = _mesh->getSubdomainName(bid);
303  sub_names_ids.push_back((bname.empty() ? "(unnamed)" : bname) + " (" + std::to_string(bid) +
304  ")");
305  }
306  return sub_names_ids;
307 }
308 
309 void
310 PhysicsBase::addBlocks(const std::vector<SubdomainName> & blocks)
311 {
312  if (blocks.size())
313  {
314  _blocks.insert(_blocks.end(), blocks.begin(), blocks.end());
315  _dim = _mesh->getBlocksMaxDimension(_blocks);
316  }
317 }
318 
319 void
320 PhysicsBase::addBlocksById(const std::vector<SubdomainID> & block_ids)
321 {
322  if (block_ids.size())
323  {
324  for (const auto bid : block_ids)
325  _blocks.push_back(_mesh->getSubdomainName(bid));
326  _dim = _mesh->getBlocksMaxDimension(_blocks);
327  }
328 }
329 
330 void
332 {
333  for (const auto & block : component.blocks())
334  _blocks.push_back(block);
335 }
336 
337 void
339 {
341  Action::addRelationshipManagers(input_rm_type, params);
342 }
343 
344 const ActionComponent &
345 PhysicsBase::getActionComponent(const ComponentName & comp_name) const
346 {
347  return _awh.getAction<ActionComponent>(comp_name);
348 }
349 
350 void
352 {
353  // Annoying edge case. We cannot use ANY_BLOCK_ID for kernels and variables since errors got
354  // added downstream for using it, we cannot leave it empty as that sets all objects to not live
355  // on any block
356  if (isParamSetByUser("block") && _blocks.empty())
357  paramError("block",
358  "Empty block restriction is not supported. Comment out the Physics if you are "
359  "trying to disable it.");
360 
361  // Components should have added their blocks already.
362  if (_blocks.empty())
363  _blocks.push_back("ANY_BLOCK_ID");
364 
365  mooseAssert(_mesh, "We should have a mesh to find the dimension");
366  if (_blocks.size())
367  _dim = _mesh->getBlocksMaxDimension(_blocks);
368  else
369  _dim = _mesh->dimension();
370 
371  // Forward physics verbosity to problem to output the setup
372  if (_verbose)
374 
375  // If the derived physics need additional initialization very early on
377 
378  // Check that the systems exist in the Problem
379  // TODO: try to add the systems to the problem from here instead
380  // NOTE: this must be performed after the "Additional" initialization because the list
381  // of systems might have been adjusted once the dimension of the Physics is known
382  const auto & problem_nl_systems = getProblem().getNonlinearSystemNames();
383  const auto & problem_lin_systems = getProblem().getLinearSystemNames();
384  for (const auto & sys_name : _system_names)
385  if (std::find(problem_nl_systems.begin(), problem_nl_systems.end(), sys_name) ==
386  problem_nl_systems.end() &&
387  std::find(problem_lin_systems.begin(), problem_lin_systems.end(), sys_name) ==
388  problem_lin_systems.end() &&
389  solverVariableNames().size())
390  mooseError("System '", sys_name, "' is not found in the Problem");
391 
392  // Cache system number as it makes some logic easier
393  for (const auto & sys_name : _system_names)
394  _system_numbers.push_back(getProblem().solverSysNum(sys_name));
395 }
396 
397 void
399 {
400  if (_is_transient == "true" && !getProblem().isTransient())
401  paramError("transient", "We cannot solve a physics as transient in a steady problem");
402 
403  // Check that there is a system for each variable
404  if (_system_names.size() != 1 && _system_names.size() != _solver_var_names.size())
405  paramError("system_names",
406  "There should be one system name per solver variable (potentially repeated), or a "
407  "single system name for all variables. Currently you have '" +
408  std::to_string(_system_names.size()) + "' systems specified for '" +
409  std::to_string(_solver_var_names.size()) + "' solver variables.");
410 
411  // Check that each variable is present in the expected system
412  unsigned int var_i = 0;
413  for (const auto & var_name : _solver_var_names)
414  {
415  const auto & sys_name = _system_names.size() == 1 ? _system_names[0] : _system_names[var_i++];
416  if (!_problem->getSolverSystem(_problem->solverSysNum(sys_name)).hasVariable(var_name) &&
417  !_problem->getSolverSystem(_problem->solverSysNum(sys_name)).hasScalarVariable(var_name))
418  paramError("system_names",
419  "We expected system '" + sys_name + "' to contain variable '" + var_name +
420  "' but it did not. Make sure the system names closely match the ordering of "
421  "the variables in the Physics.");
422  }
423 }
424 
425 void
426 PhysicsBase::copyVariablesFromMesh(const std::vector<VariableName> & variables_to_copy,
427  bool are_solver_var)
428 {
429  if (getParam<bool>("initialize_variables_from_mesh_file"))
430  {
431  mooseInfoRepeated("Adding Exodus restart for " + std::to_string(variables_to_copy.size()) +
432  " variables: " + Moose::stringify(variables_to_copy));
433  // TODO Check that the variable types and orders are actually supported for exodus restart
434  for (const auto i : index_range(variables_to_copy))
435  {
436  SystemBase & system = are_solver_var ? getProblem().getSystemBase(_system_numbers.size() == 1
437  ? _system_numbers[0]
438  : _system_numbers[i])
440  const auto & var_name = variables_to_copy[i];
441  system.addVariableToCopy(
442  var_name, var_name, getParam<std::string>("initial_from_file_timestep"));
443  }
444  }
445 }
446 
447 bool
448 PhysicsBase::variableExists(const VariableName & var_name, bool error_if_aux) const
449 {
450  if (error_if_aux && _problem->getAuxiliarySystem().hasVariable(var_name))
451  mooseError("Variable '",
452  var_name,
453  "' is supposed to be nonlinear for physics '",
454  name(),
455  "' but it is already defined as auxiliary");
456  else
457  return _problem->hasVariable(var_name);
458 }
459 
460 bool
461 PhysicsBase::solverVariableExists(const VariableName & var_name) const
462 {
463  return _problem->hasSolverVariable(var_name);
464 }
465 
466 const SolverSystemName &
467 PhysicsBase::getSolverSystem(unsigned int variable_index) const
468 {
469  mooseAssert(!_system_names.empty(), "We should have a solver system name");
470  if (_system_names.size() == 1)
471  return _system_names[0];
472  else
473  // We trust that the system names and the variable names match one-to-one as it is enforced by
474  // the checkIntegrityEarly() routine.
475  return _system_names[variable_index];
476 }
477 
478 const SolverSystemName &
479 PhysicsBase::getSolverSystem(const VariableName & var_name) const
480 {
481  mooseAssert(!_system_names.empty(), "We should have a solver system name");
482  // No need to look if only one system for the Physics
483  if (_system_names.size() == 1)
484  return _system_names[0];
485 
486  // We trust that the system names and the variable names match one-to-one as it is enforced by
487  // the checkIntegrityEarly() routine.
488  for (const auto variable_index : index_range(_solver_var_names))
489  if (var_name == _solver_var_names[variable_index])
490  return _system_names[variable_index];
491  mooseError("Variable '", var_name, "' was not found within the Physics solver variables.");
492 }
493 
494 void
496 {
497  const auto registered_tasks = _action_factory.getTasksByAction(type());
498 
499  // Check for missing tasks
500  for (const auto & required_task : _required_tasks)
501  if (!registered_tasks.count(required_task))
502  mooseWarning("Task '" + required_task +
503  "' has been declared as required by a Physics parent class of derived class '" +
504  type() +
505  "' but this task is not registered to the derived class. Registered tasks for "
506  "this Physics are: " +
507  Moose::stringify(registered_tasks));
508 }
509 
510 void
511 PhysicsBase::assignBlocks(InputParameters & params, const std::vector<SubdomainName> & blocks) const
512 {
513  // We only set the blocks if we don't have `ANY_BLOCK_ID` defined because the subproblem
514  // (through the mesh) errors out if we use this keyword during the addVariable/Kernel
515  // functions
516  if (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") == blocks.end())
517  params.set<std::vector<SubdomainName>>("block") = blocks;
518  if (blocks.empty())
519  mooseInfoRepeated("Empty block restriction assigned to an object created by Physics '" +
520  name() + "'.\n Did you mean to do this?");
521 }
522 
523 bool
524 PhysicsBase::checkBlockRestrictionIdentical(const std::string & object_name,
525  const std::vector<SubdomainName> & blocks,
526  bool error_if_not_identical) const
527 {
528  // If identical, we can return fast
529  if (_blocks == blocks)
530  return true;
531  // If one is block restricted to anywhere and the other is block restricted to anywhere manually
532  if ((std::find(_blocks.begin(), _blocks.end(), "ANY_BLOCK_ID") != _blocks.end() &&
533  allMeshBlocks(blocks)) ||
534  (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") != blocks.end() &&
536  return true;
537 
538  // Copy, sort and unique is the only way to check that they are actually the same
539  auto copy_blocks = _blocks;
540  auto copy_blocks_other = blocks;
541  std::sort(copy_blocks.begin(), copy_blocks.end());
542  copy_blocks.erase(unique(copy_blocks.begin(), copy_blocks.end()), copy_blocks.end());
543  std::sort(copy_blocks_other.begin(), copy_blocks_other.end());
544  copy_blocks_other.erase(unique(copy_blocks_other.begin(), copy_blocks_other.end()),
545  copy_blocks_other.end());
546 
547  if (copy_blocks == copy_blocks_other)
548  return true;
549  std::vector<SubdomainName> diff;
550  std::set_difference(copy_blocks.begin(),
551  copy_blocks.end(),
552  copy_blocks_other.begin(),
553  copy_blocks_other.end(),
554  std::inserter(diff, diff.begin()));
555  if (error_if_not_identical)
556  mooseError("Physics '",
557  name(),
558  "' and object '",
559  object_name,
560  "' have different block restrictions.\nPhysics: ",
562  "\nObject: ",
564  "\nDifference: ",
565  Moose::stringify(diff));
566  else
567  return false;
568 }
569 
570 bool
571 PhysicsBase::hasBlocks(const std::vector<SubdomainName> & blocks) const
572 {
573  mooseAssert(_blocks.size(), "hasBlocks called before blocks were initialized");
574  return std::all_of(blocks.begin(),
575  blocks.end(),
576  [this](const SubdomainName & block)
577  { return std::find(_blocks.begin(), _blocks.end(), block) != _blocks.end(); });
578 }
579 
580 bool
581 PhysicsBase::allMeshBlocks(const std::vector<SubdomainName> & blocks) const
582 {
583  mooseAssert(_mesh, "The mesh should exist already");
584  // Try to return faster without examining every single block
585  if (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") != blocks.end())
586  return true;
587  else if (blocks.size() != _mesh->meshSubdomains().size())
588  return false;
589 
590  for (const auto mesh_block : _mesh->meshSubdomains())
591  {
592  const auto & subdomain_name = _mesh->getSubdomainName(mesh_block);
593  // Check subdomain name
594  if (!subdomain_name.empty() &&
595  std::find(blocks.begin(), blocks.end(), subdomain_name) == blocks.end())
596  return false;
597  // no subdomain name, check the IDs being used as names instead
598  else if (std::find(blocks.begin(), blocks.end(), std::to_string(mesh_block)) == blocks.end())
599  return false;
600  }
601  return true;
602 }
603 
604 bool
605 PhysicsBase::allMeshBlocks(const std::set<SubdomainName> & blocks) const
606 {
607  std::vector<SubdomainName> blocks_vec(blocks.begin(), blocks.end());
608  return allMeshBlocks(blocks_vec);
609 }
610 
611 void
613  const std::vector<std::pair<MooseEnumItem, std::string>> & petsc_pair_options)
614 {
615  Moose::PetscSupport::PetscOptions & po = _problem->getPetscOptions();
616  for (const auto solver_sys_num : _system_numbers)
618  petsc_pair_options,
619  _problem->mesh().dimension(),
620  _problem->getSolverSystem(solver_sys_num).prefix(),
621  *this,
622  po);
623 }
624 
625 bool
626 PhysicsBase::isVariableFV(const VariableName & var_name) const
627 {
628  const auto var = &_problem->getVariable(0, var_name);
629  return var->isFV();
630 }
631 
632 bool
633 PhysicsBase::isVariableScalar(const VariableName & var_name) const
634 {
635  return _problem->hasScalarVariable(var_name);
636 }
637 
638 bool
639 PhysicsBase::shouldCreateVariable(const VariableName & var_name,
640  const std::vector<SubdomainName> & blocks,
641  const bool error_if_aux)
642 {
643  if (!variableExists(var_name, error_if_aux))
644  return true;
645  // check block restriction
646  auto & var = _problem->getVariable(0, var_name);
647  const bool not_block_restricted =
648  (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") != blocks.end()) ||
650  if (!var.blockRestricted() || (!not_block_restricted && var.hasBlocks(blocks)))
651  return false;
652 
653  // This is an edge case, which might warrant a warning
654  if (allMeshBlocks(var.blocks()) && not_block_restricted)
655  return false;
656  else
657  mooseError("Variable '" + var_name + "' already exists with subdomain restriction '" +
658  Moose::stringify(var.blocks()) + "' which does not include the subdomains '" +
659  Moose::stringify(blocks) + "', required for this Physics.");
660 }
661 
662 bool
663 PhysicsBase::shouldCreateIC(const VariableName & var_name,
664  const std::vector<SubdomainName> & blocks,
665  const bool ic_is_default_ic,
666  const bool error_if_already_defined) const
667 {
668  // Handle recover
669  if (ic_is_default_ic && (_app.isRestarting() || _app.isRecovering()))
670  return false;
671  // do not set initial conditions if we are loading fields from the mesh file
672  if (getParam<bool>("initialize_variables_from_mesh_file"))
673  return false;
674  // Different type of ICs, not block restrictable
675  mooseAssert(!isVariableScalar(var_name), "shouldCreateIC not implemented for scalar variables");
676 
677  // Process the desired block restriction into a set of subdomain IDs
678  std::set<SubdomainName> blocks_set(blocks.begin(), blocks.end());
679  const auto blocks_ids_set = getSubdomainIDs(blocks_set);
680 
681  // Check whether there are any ICs for this variable already in the problem
682  std::set<SubdomainID> blocks_ids_covered;
683  bool has_all_blocks;
684  if (isVariableFV(var_name))
685  {
686  has_all_blocks = _problem->getFVInitialConditionWarehouse().hasObjectsForVariableAndBlocks(
687  var_name, blocks_ids_set, blocks_ids_covered, /*tid =*/0);
688  // FV variables can be initialized by non-FV ICs
689  std::set<SubdomainID> blocks_ids_covered_fe;
690  const bool has_all_blocks_from_feics =
691  _problem->getInitialConditionWarehouse().hasObjectsForVariableAndBlocks(
692  var_name, blocks_ids_set, blocks_ids_covered_fe, /*tid =*/0);
693  // Note we are missing the case with complete but split coverage
694  has_all_blocks = has_all_blocks || has_all_blocks_from_feics;
695  blocks_ids_covered.insert(blocks_ids_covered_fe.begin(), blocks_ids_covered_fe.end());
696  }
697  else
698  has_all_blocks = _problem->getInitialConditionWarehouse().hasObjectsForVariableAndBlocks(
699  var_name, blocks_ids_set, blocks_ids_covered, /*tid =*/0);
700 
701  const bool has_some_blocks = !blocks_ids_covered.empty();
702  if (!has_some_blocks)
703  return true;
704 
705  if (has_all_blocks)
706  {
707  if (error_if_already_defined)
708  mooseError("ICs for variable '" + var_name + "' have already been defined for blocks '" +
709  Moose::stringify(blocks) + "'.");
710  else
711  return false;
712  }
713 
714  // Partial overlap between Physics is not implemented.
715  mooseError("There is a partial overlap between the subdomains covered by pre-existing initial "
716  "conditions (ICs), defined on blocks (ids): " +
717  Moose::stringify(getSubdomainNamesAndIDs(blocks_ids_covered)) +
718  "\n and a newly created IC for variable '" + var_name +
719  "', to be defined on blocks: " + Moose::stringify(blocks) +
720  ".\nWe should be creating the Physics' IC only for non-covered blocks. This is not "
721  "implemented at this time.");
722 }
723 
724 bool
725 PhysicsBase::shouldCreateTimeDerivative(const VariableName & var_name,
726  const std::vector<SubdomainName> & blocks,
727  const bool error_if_already_defined) const
728 {
729  // Follow the transient setting of the Physics
730  if (!isTransient())
731  return false;
732 
733  // Variable is either nonlinear (FV/FE), nodal nonlinear (field of ODEs), linear, or scalar.
734  // The warehouses hosting the time kernels are different for each of these types
735  // Different type of time derivatives, not block restrictable
736  mooseAssert(!isVariableScalar(var_name),
737  "shouldCreateTimeDerivative not implemented for scalar variables");
738  mooseAssert(!_problem->hasAuxiliaryVariable(var_name),
739  "Should not be called with auxiliary variables");
740 
741  // Get solver system type
742  const auto var = &_problem->getVariable(0, var_name);
743  const auto var_id = var->number();
744  const auto sys_num = var->sys().number();
745  const auto time_vector_tag =
746  (sys_num < _problem->numNonlinearSystems())
747  ? var->sys().timeVectorTag()
748  // this is not quite correct. Many kernels can contribute to RHS time vector on paper
749  : dynamic_cast<LinearSystem *>(&var->sys())->rightHandSideTimeVectorTag();
750 
751  // We just use the warehouse, it should cover every time derivative object type
752  bool all_blocks_covered = true;
753  std::set<SubdomainID> blocks_ids_covered;
754  // we examine subdomain by subdomain, because mutiple kernels could be covering every block in
755  // the 'blocks' parameter
756  for (const auto & block : blocks)
757  {
758  std::vector<MooseObject *> time_kernels;
759  if (block != "ANY_BLOCK_ID")
760  {
761  const auto bid = _mesh->getSubdomainID(block);
762  _problem->theWarehouse()
763  .query()
764  .template condition<AttribSysNum>(sys_num)
765  .template condition<AttribVar>(var_id)
766  .template condition<AttribSubdomains>(bid)
767  // we use the time tag as a proxy for time derivatives
768  .template condition<AttribVectorTags>(time_vector_tag)
769  .queryInto(time_kernels);
770  }
771  else
772  _problem->theWarehouse()
773  .query()
774  .template condition<AttribSysNum>(sys_num)
775  .template condition<AttribVar>(var_id)
776  // we use the time tag as a proxy for time derivatives
777  .template condition<AttribVectorTags>(time_vector_tag)
778  .queryInto(time_kernels);
779 
780  if (time_kernels.size())
781  {
782  if (block == "ANY_BLOCK_ID")
783  {
784  for (const auto & time_kernel : time_kernels)
785  if (const auto blk = dynamic_cast<BlockRestrictable *>(time_kernel))
786  blocks_ids_covered.insert(blk->blockIDs().begin(), blk->blockIDs().end());
787  }
788  else
789  blocks_ids_covered.insert(_mesh->getSubdomainID(block));
790  }
791  else
792  all_blocks_covered = false;
793  }
794 
795  // From the set of covered blocks, see if the blocks we needed are found
796  if (all_blocks_covered)
797  {
798  std::set<SubdomainName> blocks_set(blocks.begin(), blocks.end());
799  const auto blocks_ids = getSubdomainIDs(blocks_set);
800  if (blocks_ids != blocks_ids_covered)
801  all_blocks_covered = false;
802  }
803  const bool has_some_blocks = !blocks_ids_covered.empty();
804  if (!has_some_blocks)
805  return true;
806  if (all_blocks_covered)
807  {
808  if (error_if_already_defined)
809  mooseError("A time kernel for variable '" + var_name +
810  "' has already been defined on blocks '" + Moose::stringify(blocks) + "'.");
811  else
812  return false;
813  }
814 
815  // Partial overlap between Physics is not implemented.
816  mooseError("There is a partial overlap between the subdomains covered by pre-existing time "
817  "derivative kernel(s), defined on blocks (ids): " +
818  Moose::stringify(getSubdomainNamesAndIDs(blocks_ids_covered)) +
819  "\nand a newly created time derivative kernel for variable " + var_name +
820  ", to be defined on blocks: " + Moose::stringify(blocks) +
821  ".\nWe should be creating the Physics' time derivative only for non-covered "
822  "blocks. This is not implemented at this time.");
823 }
824 
825 void
826 PhysicsBase::reportPotentiallyMissedParameters(const std::vector<std::string> & param_names,
827  const std::string & object_type,
828  const std::string & object_name) const
829 {
830  std::vector<std::string> defaults_unused;
831  std::vector<std::string> user_values_unused;
832  for (const auto & param : param_names)
833  {
834  if (isParamSetByUser(param))
835  user_values_unused.push_back(param);
836  else if (isParamValid(param))
837  defaults_unused.push_back(param);
838  }
839  const std::string object_name_string =
840  object_name.empty() ? "" : ("and name '" + object_name + "' ");
841 
842  if (defaults_unused.size() && _verbose)
843  mooseInfoRepeated("Defaults for parameters '" + Moose::stringify(defaults_unused) +
844  "' for object of type '" + object_type + "' " + object_name_string +
845  "were not used because the object was not created by this Physics.");
846  if (user_values_unused.size())
847  {
849  mooseWarning(
850  "User-specifed values for parameters '" + Moose::stringify(user_values_unused) +
851  "' for object of type '" + object_type + "' " + object_name_string +
852  "were not used because the corresponding object was not created by this Physics.");
853  else if (_app.unusedFlagIsError())
854  mooseError("User-specified values for parameters '" + Moose::stringify(user_values_unused) +
855  "' for object of type '" + object_type + "' " + object_name_string +
856  "were not used because the corresponding object was not created by this Physics.");
857  }
858 }
const T & getAction(const std::string &name) const
Retrieve an action with its name and the desired type.
void addUserObject(const std::string &uo_type, const std::string &uo_name, InputParameters &params)
Add a UserObject supplied by this Physics to the problem.
Definition: PhysicsBase.C:233
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:511
virtual void addInitialConditions()
Definition: PhysicsBase.h:316
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:639
std::vector< VariableName > _aux_var_names
Vector of the aux variables in the Physics.
Definition: PhysicsBase.h:356
virtual void addFVInterfaceKernels()
Definition: PhysicsBase.h:325
virtual void addPreconditioning()
Definition: PhysicsBase.h:342
MooseEnum _is_transient
Whether the physics is to be solved as a transient.
Definition: PhysicsBase.h:351
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:351
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:457
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:186
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:612
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:279
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:398
std::set< std::string > getTasksByAction(const std::string &action) const
virtual void addMultiApps()
Definition: PhysicsBase.h:336
ActionFactory & _action_factory
Builds Actions.
virtual void addAuxiliaryKernels()
Definition: PhysicsBase.h:331
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:329
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:826
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:461
const bool _verbose
Whether to output additional information.
Definition: PhysicsBase.h:288
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:663
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:725
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:1675
bool allMeshBlocks(const std::vector< SubdomainName > &blocks) const
Check if a vector contains all the mesh blocks.
Definition: PhysicsBase.C:581
std::vector< SubdomainName > _blocks
Keep track of the subdomains the Physics is defined on.
Definition: PhysicsBase.h:295
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:272
virtual void addFVBCs()
Definition: PhysicsBase.h:327
void addBlocks(const std::vector< SubdomainName > &blocks)
Add new blocks to the Physics.
Definition: PhysicsBase.C:310
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:130
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:328
const SolverSystemName & getSolverSystem(unsigned int variable_index) const
Get the solver system for this variable index.
Definition: PhysicsBase.C:467
virtual void addNodalKernels()
Definition: PhysicsBase.h:320
virtual void addDGKernels()
Definition: PhysicsBase.h:322
bool unusedFlagIsError() const
Returns whether the flag for unused parameters is set to throw an error.
Definition: MooseApp.h:1120
virtual void addMaterials()
Definition: PhysicsBase.h:332
std::set< std::string > _required_tasks
Manually keeps track of the tasks required by each physics as tasks cannot be inherited.
Definition: PhysicsBase.h:363
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:430
bool isVariableScalar(const VariableName &var_name) const
Whether the variable is a scalar variable (global single scalar, not a field)
Definition: PhysicsBase.C:633
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:426
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:360
virtual void addReporters()
Definition: PhysicsBase.h:340
bool isVariableFV(const VariableName &var_name) const
Whether the variable is a finite volume variable.
Definition: PhysicsBase.C:626
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:295
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:338
virtual void addFunctions()
Definition: PhysicsBase.h:330
virtual void addFEBCs()
Definition: PhysicsBase.h:326
MooseApp & _app
The MOOSE application this is associated with.
Definition: MooseBase.h:375
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:314
virtual void addExecutioner()
Definition: PhysicsBase.h:343
bool hasBlocks(const std::vector< SubdomainName > &blocks) const
Whether the Physics is defined on those blocks.
Definition: PhysicsBase.C:571
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:448
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:524
virtual void addFVKernels()
Definition: PhysicsBase.h:318
static InputParameters validParams()
Definition: PhysicsBase.C:24
virtual std::vector< UserObjectName > getSuppliedUserObjects() const
Return the names of the UserObjects this Physics adds to the problem.
Definition: PhysicsBase.h:118
virtual void addFVInterpolationMethods()
Definition: PhysicsBase.h:319
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:354
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:280
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:331
virtual void addFEKernels()
Definition: PhysicsBase.h:317
virtual void addUserObjects()
Definition: PhysicsBase.h:334
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:338
bool unusedFlagIsWarning() const
Returns whether the flag for unused parameters is set to throw a warning only.
Definition: MooseApp.h:1117
virtual void actOnAdditionalTasks()
Routine to add additional setup work on additional registered tasks to a Physics. ...
Definition: PhysicsBase.h:49
virtual std::vector< std::shared_ptr< UserObject > > addUserObject(const std::string &user_object_name, const std::string &name, InputParameters &parameters)
void addBlocksById(const std::vector< SubdomainID > &block_ids)
Definition: PhysicsBase.C:320
void prepareCopyVariablesFromMesh() const
Tell the app if we want to use Exodus restart.
Definition: PhysicsBase.C:250
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:271
virtual void addOutputs()
Definition: PhysicsBase.h:341
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:48
virtual void addDiracKernels()
Definition: PhysicsBase.h:321
virtual void addVectorPostprocessors()
Definition: PhysicsBase.h:339
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:199
virtual void addExecutors()
Definition: PhysicsBase.h:344
virtual bool isTransient() const override
virtual void addInterfaceKernels()
Definition: PhysicsBase.h:324
virtual void addFunctorMaterials()
Definition: PhysicsBase.h:333
const ActionComponent & getActionComponent(const ComponentName &comp_name) const
Get a component with the requested name.
Definition: PhysicsBase.C:345
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:285
virtual void addTransfers()
Definition: PhysicsBase.h:337
bool isRecovering() const
Whether or not this is a "recover" calculation.
Definition: MooseApp.C:1669
virtual void addCorrectors()
Definition: PhysicsBase.h:335
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:205
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:282
bool isTransient() const
Return whether the Physics is solved using a transient.
Definition: PhysicsBase.C:260
virtual void addAuxiliaryVariables()
Definition: PhysicsBase.h:315
virtual void initializePhysicsAdditional()
Additional initialization work that should happen very early, as soon as the problem is created...
Definition: PhysicsBase.h:306
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:323
void checkRequiredTasks() const
Check the list of required tasks for missing tasks.
Definition: PhysicsBase.C:495