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