https://mooseframework.inl.gov
Simulation.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 "Simulation.h"
11 #include "FEProblemBase.h"
12 #include "AddVariableAction.h"
13 #include "MooseObjectAction.h"
14 #include "Transient.h"
15 #include "HeatConductionModel.h"
16 #include "HeatStructureInterface.h"
17 #include "FlowChannelBase.h"
18 #include "FlowJunction.h"
19 
20 #include "ClosuresBase.h"
21 #include "FluidProperties.h"
22 #include "THMControl.h"
23 #include "TerminateControl.h"
24 #include "THMMesh.h"
25 #include "RelationshipManager.h"
26 #include "NonlinearSystemBase.h"
27 #include "TimeIntegrator.h"
28 #include "ExplicitTimeIntegrator.h"
29 #include "ExplicitEuler.h"
30 #include "ExplicitRK2.h"
31 #include "ExplicitTVDRK2.h"
32 
33 #include "libmesh/string_to_enum.h"
34 
35 using namespace libMesh;
36 
37 std::map<VariableName, int> Simulation::_component_variable_order_map;
38 
39 void
40 Simulation::setComponentVariableOrder(const VariableName & var, int index)
41 {
42  _component_variable_order_map[var] = index;
43 }
44 
46  : ParallelObject(fe_problem.comm()),
47  LoggingInterface(_log),
48  _thm_mesh(*static_cast<THMMesh *>(pars.get<MooseMesh *>("mesh"))),
49  _fe_problem(fe_problem),
50  _thm_app(static_cast<ThermalHydraulicsApp &>(*pars.get<MooseApp *>("_moose_app"))),
51  _thm_factory(_thm_app.getFactory()),
52  _thm_pars(pars),
53  _flow_fe_type(FEType(CONSTANT, MONOMIAL)),
54  _implicit_time_integration(true),
55  _check_jacobian(false),
56  _output_vector_velocity(true),
57  _zero(0)
58 {
59  bool second_order_mesh = pars.get<bool>("2nd_order_mesh");
61  second_order_mesh ? FEType(SECOND, LAGRANGE) : FEType(FIRST, LAGRANGE);
62 }
63 
65 {
66  for (auto && k : _control_data)
67  delete k.second;
68 }
69 
70 void
71 Simulation::augmentSparsity(const dof_id_type & elem_id1, const dof_id_type & elem_id2)
72 {
73  auto it = _sparsity_elem_augmentation.find(elem_id1);
74  if (it == _sparsity_elem_augmentation.end())
76  {elem_id1, std::vector<dof_id_type>()});
77  it->second.push_back(elem_id2);
78 
79  it = _sparsity_elem_augmentation.find(elem_id2);
80  if (it == _sparsity_elem_augmentation.end())
82  {elem_id2, std::vector<dof_id_type>()});
83  it->second.push_back(elem_id1);
84 }
85 
86 void
88 {
89  if (_components.size() == 0)
90  return;
91 
92  // build mesh
93  for (auto && comp : _components)
94  comp->executeSetupMesh();
95 }
96 
97 void
99 {
100  if (_components.size() == 0)
101  return;
102 
103  Order order = CONSTANT;
104  unsigned int n_flow_channels = 0;
105  unsigned int n_heat_structures = 0;
106 
107  for (auto && comp : _components)
108  {
109  auto flow_channel = dynamic_cast<FlowChannelBase *>(comp.get());
110  if (flow_channel != nullptr)
111  n_flow_channels++;
112 
113  auto hs_interface = dynamic_cast<HeatStructureInterface *>(comp.get());
114  if (hs_interface)
115  n_heat_structures++;
116  }
117 
118  if (n_flow_channels > 0)
119  {
120  const FEType & fe_type = getFlowFEType();
121  if (fe_type.default_quadrature_order() > order)
122  order = fe_type.default_quadrature_order();
123  }
124  if (n_heat_structures > 0)
125  {
126  const FEType & fe_type = HeatConductionModel::feType();
127  if (fe_type.default_quadrature_order() > order)
128  order = fe_type.default_quadrature_order();
129  }
130 
131  _fe_problem.createQRules(QGAUSS, order, order, order);
132 }
133 
134 void
136 {
137  // sort the components using dependency resolver
139  for (const auto & comp : _components)
140  {
141  dependency_resolver.addNode(comp);
142  for (const auto & dep : comp->getDependencies())
143  if (hasComponent(dep))
144  dependency_resolver.addEdge(_comp_by_name[dep], comp);
145  }
146 
147  _components = dependency_resolver.dfs();
148 }
149 
150 void
152 {
153  // initialize components
154  for (auto && comp : _components)
155  comp->executeInit();
156 
157  // perform secondary initialization, which relies on init() being called
158  // already for all components
159  for (auto && comp : _components)
160  comp->executeInitSecondary();
161 }
162 
163 void
165 {
166  // loop over junctions and boundaries (non-geometrical components)
167  for (const auto & component : _components)
168  {
169  const auto flow_connection =
170  MooseSharedNamespace::dynamic_pointer_cast<Component1DConnection>(component);
171  if (flow_connection)
172  {
173  // create vector of names of this component and its connected flow channels, and then sort
174  // them
175  std::vector<std::string> names = flow_connection->getConnectedComponentNames();
176  names.push_back(component->name());
177  std::sort(names.begin(), names.end());
178 
179  // pick first name alphabetically to be the proposed loop name
180  std::string proposed_loop_name = names[0];
181 
182  for (const std::string & name : names)
183  {
184  // if the name is not yet in the map
186  // just add the new map key; nothing else needs updating
187  _component_name_to_loop_name[name] = proposed_loop_name;
188  else
189  {
190  // compare to the existing loop name for this component to make sure the
191  // proposed loop name is first alphabetically
192  const std::string current_loop_name = _component_name_to_loop_name[name];
193  // if proposed loop name comes later, change map values of the current
194  // loop name to be the proposed name, and then update the proposed name
195  // to be the current name
196  if (proposed_loop_name > current_loop_name)
197  {
198  for (auto && entry : _component_name_to_loop_name)
199  if (entry.second == proposed_loop_name)
200  entry.second = current_loop_name;
201  proposed_loop_name = current_loop_name;
202  }
203  // if proposed loop name comes earlier, change map values of the current
204  // loop name to be the proposed name
205  else if (proposed_loop_name < current_loop_name)
206  {
207  for (auto && entry : _component_name_to_loop_name)
208  if (entry.second == current_loop_name)
209  entry.second = proposed_loop_name;
210  }
211  }
212  }
213  }
214  }
215 
216  // get the list of loops
217  std::vector<std::string> loops;
218  for (const auto & entry : _component_name_to_loop_name)
219  if (std::find(loops.begin(), loops.end(), entry.second) == loops.end())
220  loops.push_back(entry.second);
221 
222  // fill the map of loop name to model ID
223  for (const auto & loop : loops)
224  {
225  // find a flow channel in this loop and get its model ID
226  THM::FlowModelID model_id;
227  bool found_model_id = false;
228  for (const auto & component : _components)
229  {
230  const auto flow_chan_base_component =
231  MooseSharedNamespace::dynamic_pointer_cast<FlowChannelBase>(component);
232  if (flow_chan_base_component && (_component_name_to_loop_name[component->name()] == loop))
233  {
234  model_id = flow_chan_base_component->getFlowModelID();
235  found_model_id = true;
236  break;
237  }
238  }
239  // set the value in the map or throw an error
240  if (found_model_id)
241  _loop_name_to_model_id[loop] = model_id;
242  else
243  logError("No FlowChannelBase-derived components were found in loop '", loop, "'");
244  }
245 }
246 
247 void
249 {
250  // get the list of loops
251  std::vector<std::string> loops;
252  for (auto && entry : _component_name_to_loop_name)
253  if (std::find(loops.begin(), loops.end(), entry.second) == loops.end())
254  loops.push_back(entry.second);
255 
256  // for each loop
257  Moose::out << "\nListing of component loops:" << std::endl;
258  for (unsigned int i = 0; i < loops.size(); i++)
259  {
260  Moose::out << "\n Loop " << i + 1 << ":" << std::endl;
261 
262  // print out each component in the loop
263  for (auto && entry : _component_name_to_loop_name)
264  if (entry.second == loops[i])
265  Moose::out << " " << entry.first << std::endl;
266  }
267  Moose::out << std::endl;
268 }
269 
270 void
271 Simulation::addSimVariable(bool nl, const VariableName & name, FEType fe_type, Real scaling_factor)
272 {
274 
275  if (fe_type.family != SCALAR)
276  mooseError("This method should only be used for scalar variables.");
277 
278  if (_vars.find(name) == _vars.end()) // variable is new
279  {
280  VariableInfo vi;
281  InputParameters & params = vi._params;
282 
283  vi._nl = nl;
284  vi._var_type = "MooseVariableScalar";
285  params = _thm_factory.getValidParams(vi._var_type);
286 
288  family = Utility::enum_to_string(fe_type.family);
289  params.set<MooseEnum>("family") = family;
290 
292  order = Utility::enum_to_string<Order>(fe_type.order);
293  params.set<MooseEnum>("order") = order;
294 
295  if (nl)
296  params.set<std::vector<Real>>("scaling") = {scaling_factor};
297  else if (!MooseUtils::absoluteFuzzyEqual(scaling_factor, 1.0))
298  mooseError("Aux variables cannot be provided a residual scaling factor.");
299 
300  _vars[name] = vi;
301  }
302  else
303  // One of the two cases is true:
304  // - This variable was previously added as a scalar variable, and scalar
305  // variables should not be added more than once, since there is no block
306  // restriction to extend, as there is in the field variable version of this
307  // method.
308  // - This variable was previously added as a field variable, and a variable
309  // may have only one type (this method is used for scalar variables only).
310  mooseError("The variable '", name, "' was already added.");
311 }
312 
313 void
315  const VariableName & name,
316  FEType fe_type,
317  const std::vector<SubdomainName> & subdomain_names,
318  Real scaling_factor)
319 {
321 
322  if (fe_type.family == SCALAR)
324  "The version of Simulation::addSimVariable() with subdomain names can no longer be used "
325  "with scalar variables since scalar variables cannot be block-restricted. Use the version "
326  "of Simulation::addSimVariable() without subdomain names instead.");
327 
328 #ifdef DEBUG
329  for (const auto & subdomain_name : subdomain_names)
330  mooseAssert(subdomain_name != "ANY_BLOCK_ID",
331  "'ANY_BLOCK_ID' cannot be used for adding field variables in components.");
332 #endif
333 
334  if (_vars.find(name) == _vars.end()) // variable is new
335  {
336  VariableInfo vi;
337  InputParameters & params = vi._params;
338 
339  vi._nl = nl;
340  vi._var_type = "MooseVariable";
341  params = _thm_factory.getValidParams(vi._var_type);
342  params.set<std::vector<SubdomainName>>("block") = subdomain_names;
343 
345  family = Utility::enum_to_string(fe_type.family);
346  params.set<MooseEnum>("family") = family;
347 
349  order = Utility::enum_to_string<Order>(fe_type.order);
350  params.set<MooseEnum>("order") = order;
351 
352  if (nl)
353  params.set<std::vector<Real>>("scaling") = {scaling_factor};
354  else if (!MooseUtils::absoluteFuzzyEqual(scaling_factor, 1.0))
355  mooseError("Aux variables cannot be provided a residual scaling factor.");
356 
357  _vars[name] = vi;
358  }
359  else // variable was previously added
360  {
361  VariableInfo & vi = _vars[name];
362  InputParameters & params = vi._params;
363 
364  if (vi._nl != nl)
365  mooseError("The variable '",
366  name,
367  "' has already been added in a different system (nonlinear or aux).");
368 
369  if (vi._var_type != "MooseVariable")
370  mooseError("The variable '",
371  name,
372  "' has already been added with a different type than 'MooseVariable'.");
373 
375  family = Utility::enum_to_string(fe_type.family);
376  if (!params.get<MooseEnum>("family").compareCurrent(family))
377  mooseError("The variable '", name, "' has already been added with a different FE family.");
378 
380  order = Utility::enum_to_string<Order>(fe_type.order);
381  if (!params.get<MooseEnum>("order").compareCurrent(order))
382  mooseError("The variable '", name, "' has already been added with a different FE order.");
383 
384  // If already block-restricted, extend the block restriction
385  if (params.isParamValid("block"))
386  {
387  auto blocks = params.get<std::vector<SubdomainName>>("block");
388  for (const auto & subdomain_name : subdomain_names)
389  if (std::find(blocks.begin(), blocks.end(), subdomain_name) == blocks.end())
390  blocks.push_back(subdomain_name);
391  params.set<std::vector<SubdomainName>>("block") = blocks;
392  }
393  else
394  params.set<std::vector<SubdomainName>>("block") = subdomain_names;
395 
396  if (params.isParamValid("scaling"))
397  if (!MooseUtils::absoluteFuzzyEqual(params.get<std::vector<Real>>("scaling")[0],
398  scaling_factor))
399  mooseError(
400  "The variable '", name, "' has already been added with a different scaling factor.");
401  }
402 }
403 
404 void
406  const std::string & var_type,
407  const VariableName & name,
408  const InputParameters & params)
409 {
411 
412  if (_vars.find(name) == _vars.end()) // variable is new
413  {
414  VariableInfo vi;
415  vi._nl = nl;
416  vi._var_type = var_type;
417  vi._params = params;
418 
419  _vars[name] = vi;
420  }
421  else // variable was previously added
422  {
423  VariableInfo & vi = _vars[name];
424  InputParameters & vi_params = vi._params;
425 
426  if (vi._nl != nl)
427  mooseError("The variable '",
428  name,
429  "' has already been added in a different system (nonlinear or aux).");
430 
431  if (vi._var_type != var_type)
432  mooseError("The variable '",
433  name,
434  "' has already been added with a different type than '",
435  var_type,
436  "'.");
437 
438  // Check that all valid parameters (other than 'block') are consistent
439  for (auto it = params.begin(); it != params.end(); it++)
440  {
441  const std::string param_name = it->first;
442  if (param_name == "block")
443  {
444  if (vi_params.isParamValid("block"))
445  {
446  auto blocks = vi_params.get<std::vector<SubdomainName>>("block");
447  const auto new_blocks = params.get<std::vector<SubdomainName>>("block");
448  for (const auto & subdomain_name : new_blocks)
449  if (std::find(blocks.begin(), blocks.end(), subdomain_name) == blocks.end())
450  blocks.push_back(subdomain_name);
451  vi_params.set<std::vector<SubdomainName>>("block") = blocks;
452  }
453  else
454  mooseError("The variable '", name, "' was added previously without block restriction.");
455  }
456  else if (params.isParamValid(param_name))
457  {
458  if (vi_params.isParamValid(param_name))
459  {
460  if (params.rawParamVal(param_name) != vi_params.rawParamVal(param_name))
461  mooseError("The variable '",
462  name,
463  "' was added previously with a different value for the parameter '",
464  param_name,
465  "'.");
466  }
467  else
468  mooseError("The variable '",
469  name,
470  "' was added previously without the parameter '",
471  param_name,
472  "'.");
473  }
474  }
475  }
476 }
477 
478 void
479 Simulation::checkVariableNameLength(const std::string & name) const
480 {
481  if (name.size() > THM::MAX_VARIABLE_LENGTH)
482  mooseError(
483  "Variable name '", name, "' is too long. The limit is ", THM::MAX_VARIABLE_LENGTH, ".");
484 }
485 
486 void
487 Simulation::addControl(const std::string & type, const std::string & name, InputParameters params)
488 {
489  params.addPrivateParam<FEProblemBase *>("_fe_problem_base", &_fe_problem);
490  std::shared_ptr<Control> control = _thm_factory.create<Control>(type, name, params);
492 }
493 
494 void
495 Simulation::addSimInitialCondition(const std::string & type,
496  const std::string & name,
497  InputParameters params)
498 {
500  return;
501 
502  if (_ics.find(name) == _ics.end())
503  {
504  ICInfo ic(type, params);
505  _ics[name] = ic;
506  }
507  else
508  mooseError("Initial condition with name '", name, "' already exists.");
509 }
510 
511 void
512 Simulation::addConstantIC(const VariableName & var_name,
513  Real value,
514  const std::vector<SubdomainName> & block_names)
515 {
517  return;
518 
519  std::string blk_str = block_names[0];
520  for (unsigned int i = 1; i < block_names.size(); i++)
521  blk_str += ":" + block_names[i];
522 
523  std::string class_name = "ConstantIC";
524  InputParameters params = _thm_factory.getValidParams(class_name);
525  params.set<VariableName>("variable") = var_name;
526  params.set<Real>("value") = value;
527  params.set<std::vector<SubdomainName>>("block") = block_names;
528  addSimInitialCondition(class_name, genName(var_name, blk_str, "ic"), params);
529 }
530 
531 void
532 Simulation::addFunctionIC(const VariableName & var_name,
533  const std::string & func_name,
534  const std::vector<SubdomainName> & block_names)
535 {
537  return;
538 
539  std::string blk_str = block_names[0];
540  for (unsigned int i = 1; i < block_names.size(); i++)
541  blk_str += ":" + block_names[i];
542 
543  std::string class_name = "FunctionIC";
544  InputParameters params = _thm_factory.getValidParams(class_name);
545  params.set<VariableName>("variable") = var_name;
546  params.set<std::vector<SubdomainName>>("block") = block_names;
547  params.set<FunctionName>("function") = func_name;
548  addSimInitialCondition(class_name, genName(var_name, blk_str, "ic"), params);
549 }
550 
551 void
552 Simulation::addConstantScalarIC(const VariableName & var_name, Real value)
553 {
555  return;
556 
557  std::string class_name = "ScalarConstantIC";
558  InputParameters params = _thm_factory.getValidParams(class_name);
559  params.set<VariableName>("variable") = var_name;
560  params.set<Real>("value") = value;
561  addSimInitialCondition(class_name, genName(var_name, "ic"), params);
562 }
563 
564 void
565 Simulation::addComponentScalarIC(const VariableName & var_name, const std::vector<Real> & value)
566 {
568  return;
569 
570  std::string class_name = "ScalarComponentIC";
571  InputParameters params = _thm_factory.getValidParams(class_name);
572  params.set<VariableName>("variable") = var_name;
573  params.set<std::vector<Real>>("values") = value;
574  addSimInitialCondition(class_name, genName(var_name, "ic"), params);
575 }
576 
577 std::vector<VariableName>
579 {
580  // Check that no index in order map is used more than once.
581  // Also, convert the map to a vector of pairs to be sorted.
582  std::set<int> indices;
583  std::vector<std::pair<VariableName, int>> registered_var_index_pairs;
584  for (const auto & var_and_index : _component_variable_order_map)
585  {
586  registered_var_index_pairs.push_back(var_and_index);
587 
588  const auto ind = var_and_index.second;
589  auto insert_return = indices.insert(ind);
590  if (!insert_return.second)
591  mooseError("The index ", ind, " was used for multiple component variables.");
592  }
593 
594  // Collect all of the added variable names into an unsorted vector.
595  std::vector<VariableName> vars_unsorted;
596  for (const auto & var_and_data : _vars)
597  vars_unsorted.push_back(var_and_data.first);
598 
599  // The sorting works as follows. For those variables that are listed in
600  // _component_variable_order_map, these are ordered before those that are not,
601  // in the order of their indices in the map. Those not in the map are sorted
602  // alphabetically.
603 
604  // Sort registered_var_index_pairs by value (index)
605  std::sort(registered_var_index_pairs.begin(),
606  registered_var_index_pairs.end(),
607  [](const std::pair<VariableName, int> & a, const std::pair<VariableName, int> & b)
608  { return a.second < b.second; });
609 
610  // Loop over the ordered, registered variable names and add a variable to the
611  // sorted list if in vars_unsorted. When this happens, delete the element from
612  // vars_unsorted, leaving only unregistered variable names after the loop.
613  std::vector<VariableName> vars_sorted;
614  for (const auto & var_index_pair : registered_var_index_pairs)
615  {
616  const auto & var = var_index_pair.first;
617  if (std::find(vars_unsorted.begin(), vars_unsorted.end(), var) != vars_unsorted.end())
618  {
619  vars_sorted.push_back(var);
620  vars_unsorted.erase(std::remove(vars_unsorted.begin(), vars_unsorted.end(), var),
621  vars_unsorted.end());
622  }
623  }
624 
625  // Sort the remaining (unregistered) variables alphabetically and then add
626  // them to the end of the full list.
627  std::sort(vars_unsorted.begin(), vars_unsorted.end());
628  vars_sorted.insert(vars_sorted.end(), vars_unsorted.begin(), vars_unsorted.end());
629 
630  return vars_sorted;
631 }
632 
633 void
635 {
636  TransientBase * trex = dynamic_cast<TransientBase *>(getApp().getExecutioner());
637  if (trex)
638  {
639  Moose::TimeIntegratorType ti_type = trex->getTimeScheme();
640  // This is only needed for the listed time integrators that are using the original approach to
641  // explicit integration in MOOSE. Currently, the new time integrators like
642  // ActuallyExplicitEuler do not need the implicit flag to be set.
643  if (ti_type == Moose::TI_EXPLICIT_TVD_RK_2 || ti_type == Moose::TI_EXPLICIT_MIDPOINT ||
644  ti_type == Moose::TI_EXPLICIT_EULER)
646  }
647 
648  if (_components.size() == 0)
649  return;
650 
651  // Cache the variables that components request to add
652  for (auto && comp : _components)
653  comp->addVariables();
654 
655  // Sort the variables for a consistent ordering
656  const auto var_names = sortAddedComponentVariables();
657 
658  // Report the ordering if the executioner is verbose
659  if (_fe_problem.getParam<MooseEnum>("verbose_setup") != "false")
660  {
661  std::stringstream ss;
662  ss << "The system ordering of variables added by Components is as follows:\n";
663  for (const auto & var : var_names)
664  ss << " " << var << "\n";
665  mooseInfo(ss.str());
666  }
667 
668  // Add the variables to the problem
669  for (const auto & name : var_names)
670  {
671  VariableInfo & vi = _vars[name];
672 
673  if (vi._nl)
675  else
677  }
678 
681  else
683 }
684 
685 void
687 {
688  const UserObjectName suo_name = genName("thm", "suo");
689  {
690  const std::string class_name = "SolutionUserObject";
691  InputParameters params = _thm_factory.getValidParams(class_name);
692  params.set<MeshFileName>("mesh") = _thm_pars.get<FileName>("initial_from_file");
693  params.set<std::string>("timestep") = _thm_pars.get<std::string>("initial_from_file_timestep");
694  _fe_problem.addUserObject(class_name, suo_name, params);
695  }
696 
697  for (auto && v : _vars)
698  {
699  const VariableName & var_name = v.first;
700  const VariableInfo & vi = v.second;
701 
702  if (vi._var_type == "MooseVariableScalar")
703  {
704  std::string class_name = "ScalarSolutionIC";
705  InputParameters params = _thm_factory.getValidParams(class_name);
706  params.set<VariableName>("variable") = var_name;
707  params.set<VariableName>("from_variable") = var_name;
708  params.set<UserObjectName>("solution_uo") = suo_name;
709  _fe_problem.addInitialCondition(class_name, genName(var_name, "ic"), params);
710  }
711  else
712  {
713  std::string class_name = "SolutionIC";
714  InputParameters params = _thm_factory.getValidParams(class_name);
715  params.set<VariableName>("variable") = var_name;
716  params.set<VariableName>("from_variable") = var_name;
717  params.set<UserObjectName>("solution_uo") = suo_name;
718  if (vi._params.isParamValid("block"))
719  params.set<std::vector<SubdomainName>>("block") =
720  vi._params.get<std::vector<SubdomainName>>("block");
721  _fe_problem.addInitialCondition(class_name, genName(var_name, "ic"), params);
722  }
723  }
724 }
725 
726 void
728 {
729  for (auto && i : _ics)
730  {
731  const std::string & name = i.first;
732  ICInfo & ic = i.second;
734  }
735 }
736 
737 void
739 {
740  for (auto && comp : _components)
741  comp->addMooseObjects();
742 }
743 
744 void
746 {
747  {
748  const std::string class_name = "AugmentSparsityBetweenElements";
749  auto params = _thm_factory.getValidParams(class_name);
750  params.set<Moose::RelationshipManagerType>("rm_type") =
753  params.set<std::string>("for_whom") = _fe_problem.name();
754  params.set<MooseMesh *>("mesh") = &_thm_mesh;
755  params.set<std::map<dof_id_type, std::vector<dof_id_type>> *>("_elem_map") =
757  auto rm =
758  _thm_factory.create<RelationshipManager>(class_name, "thm:sparsity_btw_elems", params);
760  _thm_factory.releaseSharedObjects(*rm);
761  }
762 
763  for (auto && comp : _components)
764  comp->addRelationshipManagers(Moose::RelationshipManagerType::COUPLING |
767 }
768 
769 void
771 {
772  MultiMooseEnum coord_types("XYZ RZ RSPHERICAL");
773  std::vector<SubdomainName> blocks;
774 
775  for (auto && comp : _components)
776  {
777  if (comp->parent() == nullptr)
778  {
779  const auto & subdomains = comp->getSubdomainNames();
780  const auto & coord_sys = comp->getCoordSysTypes();
781 
782  for (unsigned int i = 0; i < subdomains.size(); i++)
783  {
784  blocks.push_back(subdomains[i]);
785  // coord_types.push_back("XYZ");
786  coord_types.setAdditionalValue(coord_sys[i] == Moose::COORD_RZ ? "RZ" : "XYZ");
787  }
788  }
789  }
790  _fe_problem.setCoordSystem(blocks, coord_types);
791 
792  // RZ geometries are always aligned with x-axis
793  MooseEnum rz_coord_axis("X=0 Y=1", "X");
794  _fe_problem.setAxisymmetricCoordAxis(rz_coord_axis);
795 }
796 
797 void
799 {
800  if (_components.size() == 0)
801  return;
802 
804 }
805 
806 void
808 {
809  if (!_fe_problem.shouldSolve())
810  return;
811 
812  const TimeIntegrator * ti = nullptr;
813  const auto & time_integrators =
815  if (!time_integrators.empty())
816  ti = time_integrators.front().get();
817  // Yes, this is horrible. Don't ask why...
818  if ((dynamic_cast<const ExplicitTimeIntegrator *>(ti) != nullptr) ||
819  (dynamic_cast<const ExplicitEuler *>(ti) != nullptr) ||
820  (dynamic_cast<const ExplicitRK2 *>(ti) != nullptr) ||
821  (dynamic_cast<const ExplicitTVDRK2 *>(ti) != nullptr))
822  return;
823 
824  const CouplingMatrix * cm = _fe_problem.couplingMatrix(/*nl_sys_num=*/0);
825  if (cm == nullptr)
826  mooseError("Coupling matrix does not exists. Something really bad happened.");
827 
828  bool full = true;
829  for (unsigned int i = 0; i < cm->size(); i++)
830  for (unsigned int j = 0; j < cm->size(); j++)
831  full &= (*cm)(i, j);
832 
833  if (!full)
834  mooseError(
835  "Single matrix preconditioning with full coupling is required to run. Please, check that "
836  "your input file has the following preconditioning block:\n\n"
837  "[Preconditioning]\n"
838  " [pc]\n"
839  " type = SMP\n"
840  " full = true\n"
841  " []\n"
842  "[].\n");
843 }
844 
845 void
847 {
848  if (_components.size() == 0)
849  return;
850 
851  if (_check_jacobian)
852  return;
853 
854  // go over components and put flow channels into one "bucket"
855  std::vector<Component *> flow_channels;
856  for (auto && comp : _components)
857  {
858  auto flow_channel = dynamic_cast<FlowChannelBase *>(comp.get());
859  if (flow_channel != nullptr)
860  flow_channels.push_back(flow_channel);
861  }
862 
863  // initialize number of connected flow channel inlets and outlets to zero
864  std::map<std::string, unsigned int> flow_channel_inlets;
865  std::map<std::string, unsigned int> flow_channel_outlets;
866  for (auto && comp : flow_channels)
867  {
868  flow_channel_inlets[comp->name()] = 0;
869  flow_channel_outlets[comp->name()] = 0;
870  }
871 
872  // mark connections of any Component1DConnection components
873  for (const auto & comp : _components)
874  {
875  auto pc_comp = dynamic_cast<Component1DConnection *>(comp.get());
876  if (pc_comp != nullptr)
877  {
878  for (const auto & connection : pc_comp->getConnections())
879  {
880  if (connection._end_type == Component1DConnection::IN)
881  flow_channel_inlets[connection._component_name]++;
882  else if (connection._end_type == Component1DConnection::OUT)
883  flow_channel_outlets[connection._component_name]++;
884  }
885  }
886  }
887 
888  // finally, check that each flow channel has exactly one input and one output
889  for (auto && comp : flow_channels)
890  {
891  if (flow_channel_inlets[comp->name()] == 0)
892  logError("Component '", comp->name(), "' does not have connected inlet.");
893  else if (flow_channel_inlets[comp->name()] > 1)
894  logError("Multiple inlets specified for component '", comp->name(), "'.");
895 
896  if (flow_channel_outlets[comp->name()] == 0)
897  logError("Component '", comp->name(), "' does not have connected outlet.");
898  else if (flow_channel_outlets[comp->name()] > 1)
899  logError("Multiple outlets specified for component '", comp->name(), "'.");
900  }
901 
902  // let components check themselves
903  for (auto && comp : _components)
904  comp->executeCheck();
905 
908 }
909 
910 void
912 {
913  if (_check_jacobian)
914  return;
915 
916  // check that control data are consistent
917  for (auto && i : _control_data)
918  {
919  if (!i.second->getDeclared())
920  logError("Control data '",
921  i.first,
922  "' was requested, but was not declared by any active control object.");
923  }
924 
926 
928 
929  // initialize THM control objects
930  for (auto && i : ctrl_wh.getObjects())
931  {
932  THMControl * ctrl = dynamic_cast<THMControl *>(i.get());
933  if (ctrl != nullptr)
934  ctrl->init();
935  }
936 
937  for (auto && i : ctrl_wh.getObjects())
938  {
939  THMControl * ctrl = dynamic_cast<THMControl *>(i.get());
940  // if it is a THM control
941  if (ctrl != nullptr)
942  {
943  // get its dependencies on control data
944  auto & cd_deps = ctrl->getControlDataDependencies();
945  for (auto && cd_name : cd_deps)
946  {
947  ControlDataValue * cdv = _control_data[cd_name];
948  // find out which control object built the control data
949  std::string dep_name = cdv->getControl()->name();
950  auto & deps = ctrl->getDependencies();
951  // and if it is not in its dependency list, add it
952  auto it = std::find(deps.begin(), deps.end(), dep_name);
953  if (it == deps.end())
954  deps.push_back(dep_name);
955  }
956  }
957  }
958 
959  // Find all `TerminateControl`s and all their dependencies. Then add those
960  // objects into TIMESTEP_END control warehouse
961  MooseObjectWarehouse<Control> & ctrl_wh_tse =
963  for (auto && i : ctrl_wh.getObjects())
964  {
965  if (TerminateControl * ctrl = dynamic_cast<TerminateControl *>(i.get()))
966  {
967  std::list<const THMControl *> l;
968  l.push_back(ctrl);
969  while (l.size() > 0)
970  {
971  const THMControl * ctrl = l.front();
972  auto & cd_deps = ctrl->getControlDataDependencies();
973  for (auto && cd_name : cd_deps)
974  {
975  ControlDataValue * cdv = _control_data[cd_name];
976  l.push_back(cdv->getControl());
977  }
978  ctrl_wh_tse.addObject(ctrl_wh.getObject(ctrl->name()));
979  l.pop_front();
980  }
981  }
982  }
983 }
984 
985 void
987 {
988 }
989 
990 void
991 Simulation::addComponent(const std::string & type, const std::string & name, InputParameters params)
992 {
993  std::shared_ptr<Component> comp = _thm_factory.create<Component>(type, name, params);
994  if (_comp_by_name.find(name) == _comp_by_name.end())
995  _comp_by_name[name] = comp;
996  else
997  logError("Component with name '", name, "' already exists");
998  _components.push_back(comp);
999 }
1000 
1001 bool
1002 Simulation::hasComponent(const std::string & name) const
1003 {
1004  auto it = _comp_by_name.find(name);
1005  return (it != _comp_by_name.end());
1006 }
1007 
1008 void
1009 Simulation::addClosures(const std::string & type, const std::string & name, InputParameters params)
1010 {
1011  std::shared_ptr<ClosuresBase> obj_ptr = _thm_factory.create<ClosuresBase>(type, name, params);
1012  if (_closures_by_name.find(name) == _closures_by_name.end())
1013  _closures_by_name[name] = obj_ptr;
1014  else
1015  logError("A closures object with the name '", name, "' already exists.");
1016 }
1017 
1018 bool
1019 Simulation::hasClosures(const std::string & name) const
1020 {
1021  return _closures_by_name.find(name) != _closures_by_name.end();
1022 }
1023 
1024 std::shared_ptr<ClosuresBase>
1025 Simulation::getClosures(const std::string & name) const
1026 {
1027  auto it = _closures_by_name.find(name);
1028  if (it != _closures_by_name.end())
1029  return it->second;
1030  else
1031  mooseError("The requested closures object '", name, "' does not exist.");
1032 }
1033 
1034 void
1036 {
1037  _outputters_all.push_back(name);
1038  _outputters_file.push_back(name);
1039 }
1040 
1041 void
1043 {
1044  _outputters_all.push_back(name);
1045  _outputters_screen.push_back(name);
1046 }
1047 
1048 std::vector<OutputName>
1049 Simulation::getOutputsVector(const std::string & key) const
1050 {
1051  std::string key_lowercase = key;
1052  std::transform(key_lowercase.begin(), key_lowercase.end(), key_lowercase.begin(), ::tolower);
1053 
1054  std::vector<OutputName> outputs;
1055  if (key_lowercase == "none")
1056  outputs.push_back("none"); // provide non-existent name, so it does not get printed out
1057  else if (key_lowercase == "screen")
1058  outputs = _outputters_screen;
1059  else if (key_lowercase == "file")
1060  outputs = _outputters_file;
1061  else if (key_lowercase == "both")
1062  outputs = _outputters_all;
1063  else
1064  mooseError("The outputs vector key '" + key_lowercase + "' is invalid");
1065 
1066  return outputs;
1067 }
1068 
1069 bool
1071 {
1072  return _thm_pars.isParamValid("initial_from_file");
1073 }
1074 
1075 void
1077 {
1078  for (auto && i : _control_data)
1079  i.second->copyValuesBack();
1080 }
void addObject(std::shared_ptr< Control > object, THREAD_ID tid=0, bool recurse=true) override
LAGRANGE
bool shouldSolve() const
unsigned int FlowModelID
Abstract definition of a ControlData value.
Definition: ControlData.h:20
virtual void run()
Run the simulation.
Definition: Simulation.C:986
bool _implicit_time_integration
true if using implicit time integration scheme
Definition: Simulation.h:463
std::shared_ptr< ClosuresBase > getClosures(const std::string &name) const
Get a pointer to a closures object.
Definition: Simulation.C:1025
virtual void setupMesh()
Perform mesh setup actions such as setting up the coordinate system(s) and creating ghosted elements...
Definition: Simulation.C:798
Order
std::string genName(const std::string &prefix, unsigned int id, const std::string &suffix="") const
Build a name from a prefix, number and possible suffix.
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
RelationshipManagerType
SCALAR
char ** blocks
void addPrivateParam(const std::string &name, const T &value)
void setupInitialConditionObjects()
Definition: Simulation.C:727
void mooseError(Args &&... args)
QGAUSS
void setAdditionalValue(const std::string &names)
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
void identifyLoops()
Identifies the component loops.
Definition: Simulation.C:164
static const std::string component
Definition: NS.h:153
void emitLoggedErrors() const
Calls mooseError if there are any logged errors.
Definition: Logger.C:21
TI_EXPLICIT_EULER
FIRST
Base class for 1D component junctions and boundaries.
T & set(const std::string &name, bool quiet_mode=false)
static const size_t MAX_VARIABLE_LENGTH
std::map< std::string, ICInfo > _ics
Definition: Simulation.h:424
virtual void controlDataIntegrityCheck()
Check the integrity of the control data.
Definition: Simulation.C:911
virtual ~Simulation()
Definition: Simulation.C:64
bool _check_jacobian
True if checking jacobian.
Definition: Simulation.h:468
FEProblemBase & _fe_problem
Pointer to FEProblem representing this simulation.
Definition: Simulation.h:391
THMMesh & _thm_mesh
THM mesh.
Definition: Simulation.h:388
void addFileOutputter(const std::string &name)
Definition: Simulation.C:1035
InputParameters _params
Definition: Simulation.h:417
Order default_quadrature_order() const
OrderWrapper order
A base class for flow channels.
const ExecFlagType EXEC_TIMESTEP_END
virtual void addClosures(const std::string &type, const std::string &name, InputParameters params)
Add a closures object into this simulation.
Definition: Simulation.C:1009
void printComponentLoops() const
Prints the component loops.
Definition: Simulation.C:248
const std::vector< std::string > & getControlDataDependencies() const
Return the Controls that must run before this Control.
Definition: THMControl.h:26
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
TI_EXPLICIT_MIDPOINT
virtual void addAuxVariable(const std::string &var_type, const std::string &var_name, InputParameters &params)
SECOND
Interface class for logging errors and warnings.
void addEdge(const T &a, const T &b)
virtual const std::string & name() const
Mesh for THM.
Definition: THMMesh.h:18
virtual void couplingMatrixIntegrityCheck() const
Check integrity of coupling matrix used by the preconditioner.
Definition: Simulation.C:807
static MooseEnum getNonlinearVariableFamilies()
void addFunctionIC(const VariableName &var_name, const std::string &func_name, const std::vector< SubdomainName > &block_names)
Definition: Simulation.C:532
const libMesh::CouplingMatrix * couplingMatrix(const unsigned int nl_sys_num) const override
void addRelationshipManagers()
Add additional relationship managers to run the simulation.
Definition: Simulation.C:745
virtual void initSimulation()
Initialize this simulation.
Definition: Simulation.C:135
Base class for closures implementations.
Definition: ClosuresBase.h:28
std::size_t size() const
std::map< std::string, ControlDataValue * > _control_data
Control data created in the control logic system.
Definition: Simulation.h:460
virtual void addInitialCondition(const std::string &ic_name, const std::string &name, InputParameters &parameters)
static std::map< VariableName, int > _component_variable_order_map
Component variable order map; see setComponentVariableOrder for more info.
Definition: Simulation.h:488
void mooseInfo(Args &&... args)
void addSimVariable(bool nl, const VariableName &name, libMesh::FEType fe_type, Real scaling_factor=1.0)
Queues a variable of type MooseVariableScalar to be added to the nonlinear or aux system...
Definition: Simulation.C:271
std::string _type
Definition: Simulation.h:416
void checkVariableNameLength(const std::string &name) const
Reports an error if the variable name is too long.
Definition: Simulation.C:479
bool hasComponent(const std::string &name) const
Find out if simulation has a component with the given name.
Definition: Simulation.C:1002
bool addRelationshipManager(std::shared_ptr< RelationshipManager > relationship_manager)
static MooseEnum getNonlinearVariableOrders()
Variable information.
Definition: Simulation.h:375
virtual std::unique_ptr< Base > create()=0
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
virtual void initComponents()
Initialize this simulation&#39;s components.
Definition: Simulation.C:151
virtual void createQRules(libMesh::QuadratureType type, libMesh::Order order, libMesh::Order volume_order=libMesh::INVALID_ORDER, libMesh::Order face_order=libMesh::INVALID_ORDER, SubdomainID block=Moose::ANY_BLOCK_ID, bool allow_negative_qweights=true)
const THMControl * getControl() const
Get the pointer to the control object that declared this control data.
Definition: ControlData.h:55
std::map< VariableName, VariableInfo > _vars
variables for this simulation (name and info about the var)
Definition: Simulation.h:412
const ExecFlagType EXEC_TIMESTEP_BEGIN
ThermalHydraulicsApp & getApp()
Get the ThermalHydraulicsApp.
Definition: Simulation.h:245
void emitLoggedWarnings() const
Calls mooseWarning if there are any logged warnings.
Definition: Logger.C:35
const std::string name
Definition: Setup.h:20
std::string rawParamVal(const std::string &param) const
void logError(Args &&... args) const
Logs an error.
std::vector< OutputName > _outputters_file
Definition: Simulation.h:456
Factory & _thm_factory
The Factory associated with the MooseApp.
Definition: Simulation.h:397
void setupInitialConditionsFromFile()
Setup reading initial conditions from a specified file, see &#39;initial_from_file&#39; and &#39;initial_from_fil...
Definition: Simulation.C:686
virtual void integrityCheck() const
Check the integrity of the simulation.
Definition: Simulation.C:846
std::vector< OutputName > getOutputsVector(const std::string &key) const
Gets the vector of output names corresponding to a 1-word key string.
Definition: Simulation.C:1049
void setAxisymmetricCoordAxis(const MooseEnum &rz_coord_axis)
const T & getParam(const std::string &name) const
InputParameters _params
Input parameters.
Definition: Simulation.h:382
const std::vector< std::string > & getConnectedComponentNames() const
Returns a list of names of components that are connected to this component.
Interface class for heat structure components.
Base class for THM components.
Definition: Component.h:27
void mooseDeprecated(Args &&... args)
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
virtual void addMooseObjects()
Add component MOOSE objects.
Definition: Simulation.C:738
const std::vector< std::shared_ptr< TimeIntegrator > > & getTimeIntegrators()
std::vector< std::shared_ptr< Component > > _components
List of components in this simulation.
Definition: Simulation.h:400
Executioner * getExecutioner() const
std::map< std::string, std::string > _component_name_to_loop_name
Map of component name to component loop name.
Definition: Simulation.h:404
virtual void addVariable(const std::string &var_type, const std::string &var_name, InputParameters &params)
std::map< std::string, std::shared_ptr< Component > > _comp_by_name
Map of components by their names.
Definition: Simulation.h:402
void addConstantScalarIC(const VariableName &var_name, Real value)
Definition: Simulation.C:552
void setCoordSystem(const std::vector< SubdomainName > &blocks, const MultiMooseEnum &coord_sys)
static const libMesh::FEType & feType()
Get the FE type used for heat conduction.
const InputParameters & _thm_pars
"Global" of this simulation
Definition: Simulation.h:427
TI_EXPLICIT_TVD_RK_2
void addScreenOutputter(const std::string &name)
Definition: Simulation.C:1042
virtual void setupQuadrature()
Sets up quadrature rules.
Definition: Simulation.C:98
std::map< std::string, std::shared_ptr< ClosuresBase > > _closures_by_name
Map of closures by their names.
Definition: Simulation.h:409
bool hasClosures(const std::string &name) const
Return whether the simulation has a closures object.
Definition: Simulation.C:1019
std::string _var_type
Type (class) of the variable.
Definition: Simulation.h:380
void addSimInitialCondition(const std::string &type, const std::string &name, InputParameters params)
Definition: Simulation.C:495
const libMesh::FEType & getFlowFEType() const
Gets the FE type for the flow in this simulation.
Definition: Simulation.h:48
void addComponentScalarIC(const VariableName &var_name, const std::vector< Real > &value)
Definition: Simulation.C:565
virtual void buildMesh()
Create mesh for this simulation.
Definition: Simulation.C:87
std::vector< VariableName > sortAddedComponentVariables() const
Returns a sorted list of the variables added by components.
Definition: Simulation.C:578
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const std::string v
Definition: NS.h:84
void addNode(const T &a)
virtual void addComponent(const std::string &type, const std::string &name, InputParameters params)
Add a component into this simulation.
Definition: Simulation.C:991
Simulation(FEProblemBase &fe_problem, const InputParameters &params)
Definition: Simulation.C:45
bool compareCurrent(const MooseEnum &other, CompareMode mode=CompareMode::COMPARE_NAME) const
bool _nl
True if the variable is a nonlinear (solution) variable; otherwise, aux.
Definition: Simulation.h:378
virtual std::vector< std::shared_ptr< UserObject > > addUserObject(const std::string &user_object_name, const std::string &name, InputParameters &parameters)
static void setComponentVariableOrder(const VariableName &var, int index)
Sets a component variable order index.
Definition: Simulation.C:40
TimeIntegratorType
std::map< std::string, THM::FlowModelID > _loop_name_to_model_id
Map of loop name to model type.
Definition: Simulation.h:406
const std::vector< T > & dfs()
virtual void addVariables()
Add variables involved in this simulation.
Definition: Simulation.C:634
Moose::TimeIntegratorType getTimeScheme() const
std::vector< OutputName > _outputters_screen
Definition: Simulation.h:457
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
void setupCoordinateSystem()
Sets the coordinate system for each subdomain.
Definition: Simulation.C:770
std::map< dof_id_type, std::vector< dof_id_type > > _sparsity_elem_augmentation
Additional sparsity pattern that needs to be added into the Jacobian matrix.
Definition: Simulation.h:471
static libMesh::FEType _fe_type
ExecuteMooseObjectWarehouse< Control > & getControlWarehouse()
Logger _log
Definition: Simulation.h:465
ThermalHydraulicsApp & _thm_app
The application this is associated with.
Definition: Simulation.h:394
This control block will terminate a run if its input indicates so.
void addConstantIC(const VariableName &var_name, Real value, const std::vector< SubdomainName > &block_names)
Definition: Simulation.C:512
virtual void addObject(std::shared_ptr< Control > object, THREAD_ID tid=0, bool recurse=true) override
static const std::string k
Definition: NS.h:130
std::vector< OutputName > _outputters_all
Definition: Simulation.h:455
virtual void init()
Definition: THMControl.h:21
virtual const THM::FlowModelID & getFlowModelID() const =0
Gets the flow model ID.
const Elem & get(const ElemType type_in)
bool hasInitialConditionsFromFile() const
Are initial conditions specified from a file.
Definition: Simulation.C:1070
virtual void augmentSparsity(const dof_id_type &elem_id1, const dof_id_type &elem_id2)
Hint how to augment sparsity pattern between two elements.
Definition: Simulation.C:71
uint8_t dof_id_type
void addControl(const std::string &type, const std::string &name, InputParameters params)
Add a control.
Definition: Simulation.C:487
virtual void advanceState()
Advance all of the state holding vectors / datastructures so that we can move to the next timestep...
Definition: Simulation.C:1076
std::vector< std::string > & getDependencies()
bool isParamValid(const std::string &name) const