https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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"
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"
29#include "ExplicitEuler.h"
30#include "ExplicitRK2.h"
31#include "ExplicitTVDRK2.h"
32
33#include "libmesh/string_to_enum.h"
34
35using namespace libMesh;
36
37std::map<VariableName, int> Simulation::_component_variable_order_map;
38
39void
40Simulation::setComponentVariableOrder(const VariableName & var, int index)
41{
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 *>(MooseBase::app_param))),
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
70void
71Simulation::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
86void
88{
89 if (_components.size() == 0)
90 return;
91
92 // build mesh
93 for (auto && comp : _components)
94 comp->executeSetupMesh();
95}
96
97void
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
134void
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
150void
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
163void
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
247void
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
270void
271Simulation::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
313void
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))
400 "The variable '", name, "' has already been added with a different scaling factor.");
401 }
402}
403
404void
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
478void
480{
481 if (name.size() > THM::MAX_VARIABLE_LENGTH)
483 "Variable name '", name, "' is too long. The limit is ", THM::MAX_VARIABLE_LENGTH, ".");
484}
485
486void
487Simulation::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
494void
495Simulation::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
511void
512Simulation::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
531void
532Simulation::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
551void
552Simulation::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
564void
565Simulation::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
577std::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
633void
635{
636 TransientBase * trex = dynamic_cast<TransientBase *>(getApp().getExecutioner());
637 if (trex)
638 {
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
685void
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
726void
728{
729 for (auto && i : _ics)
730 {
731 const std::string & name = i.first;
732 ICInfo & ic = i.second;
734 }
735}
736
737void
739{
740 for (auto && comp : _components)
741 comp->addMooseObjects();
742}
743
744void
746{
747 {
748 const std::string class_name = "AugmentSparsityBetweenElements";
749 auto params = _thm_factory.getValidParams(class_name);
750 params.set<Moose::RelationshipManagerType>("rm_type") =
751 Moose::RelationshipManagerType::COUPLING | Moose::RelationshipManagerType::ALGEBRAIC |
752 Moose::RelationshipManagerType::GEOMETRIC;
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 |
765 Moose::RelationshipManagerType::ALGEBRAIC |
766 Moose::RelationshipManagerType::GEOMETRIC);
767}
768
769void
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");
795}
796
797void
799{
800 if (_components.size() == 0)
801 return;
802
804}
805
806void
808{
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)
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
845void
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
910void
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
985void
987{
988}
989
990void
991Simulation::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
1001bool
1002Simulation::hasComponent(const std::string & name) const
1003{
1004 auto it = _comp_by_name.find(name);
1005 return (it != _comp_by_name.end());
1006}
1007
1008void
1009Simulation::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
1018bool
1019Simulation::hasClosures(const std::string & name) const
1020{
1021 return _closures_by_name.find(name) != _closures_by_name.end();
1022}
1023
1024std::shared_ptr<ClosuresBase>
1025Simulation::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
1034void
1036{
1037 _outputters_all.push_back(name);
1038 _outputters_file.push_back(name);
1039}
1040
1041void
1043{
1044 _outputters_all.push_back(name);
1045 _outputters_screen.push_back(name);
1046}
1047
1048std::vector<OutputName>
1049Simulation::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
1069bool
1071{
1072 return _thm_pars.isParamValid("initial_from_file");
1073}
1074
1075void
1077{
1078 for (auto && i : _control_data)
1079 i.second->copyValuesBack();
1080}
const double v
void mooseInfo(Args &&... args)
void mooseError(Args &&... args)
void mooseDeprecated(Args &&... args)
const ExecFlagType EXEC_TIMESTEP_END
const ExecFlagType EXEC_TIMESTEP_BEGIN
char ** blocks
const std::string name
Definition Setup.h:21
static MooseEnum getNonlinearVariableFamilies()
static MooseEnum getNonlinearVariableOrders()
Base class for closures implementations.
Base class for 1D component junctions and boundaries.
Base class for THM components.
Definition Component.h:32
void executeCheck() const
Wrapper function for check() that marks the function as being called.
Definition Component.C:84
Abstract definition of a ControlData value.
Definition ControlData.h:21
const THMControl * getControl() const
Get the pointer to the control object that declared this control data.
Definition ControlData.h:55
std::vector< std::string > & getDependencies()
void addNode(const T &a)
const std::vector< T > & dfs()
void addEdge(const T &a, const T &b)
void addObject(std::shared_ptr< T > object, THREAD_ID tid=0, bool recurse=true) override
virtual std::vector< std::shared_ptr< UserObject > > addUserObject(const std::string &user_object_name, const std::string &name, InputParameters &parameters)
void setAxisymmetricCoordAxis(const MooseEnum &rz_coord_axis)
virtual void addVariable(const std::string &var_type, const std::string &var_name, InputParameters &params)
bool shouldSolve() const
void setCoordSystem(const std::vector< SubdomainName > &blocks, const MultiMooseEnum &coord_sys)
virtual void addInitialCondition(const std::string &ic_name, const std::string &name, InputParameters &parameters)
ExecuteMooseObjectWarehouse< Control > & getControlWarehouse()
const libMesh::CouplingMatrix * couplingMatrix(const unsigned int nl_sys_num) const override
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)
virtual void addAuxVariable(const std::string &var_type, const std::string &var_name, InputParameters &params)
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
A base class for flow channels.
static const libMesh::FEType & feType()
Get the FE type used for heat conduction.
static libMesh::FEType _fe_type
Interface class for heat structure components.
void addPrivateParam(const std::string &name, const T &value)
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
std::string rawParamVal(const std::string &param) const
T & set(const std::string &name, bool quiet_mode=false)
bool isParamValid(const std::string &name) const
void emitLoggedErrors() const
Calls mooseError if there are any logged errors.
Definition Logger.C:21
void emitLoggedWarnings() const
Calls mooseWarning if there are any logged warnings.
Definition Logger.C:35
Interface class for logging errors and warnings.
void logError(Args &&... args) const
Logs an error.
bool addRelationshipManager(std::shared_ptr< RelationshipManager > relationship_manager)
Executioner * getExecutioner() const
const std::string & name() const
const T & getParam(const std::string &name) const
bool compareCurrent(const MooseEnum &other, CompareMode mode=CompareMode::COMPARE_NAME) const
virtual void addObject(std::shared_ptr< T > object, THREAD_ID tid=0, bool recurse=true) override
void setAdditionalValue(const std::string &names)
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.
void printComponentLoops() const
Prints the component loops.
Definition Simulation.C:248
Simulation(FEProblemBase &fe_problem, const InputParameters &params)
Definition Simulation.C:45
void addComponentScalarIC(const VariableName &var_name, const std::vector< Real > &value)
Definition Simulation.C:565
void addControl(const std::string &type, const std::string &name, InputParameters params)
Add a control.
Definition Simulation.C:487
THMMesh & _thm_mesh
THM mesh.
Definition Simulation.h:388
std::map< std::string, std::shared_ptr< Component > > _comp_by_name
Map of components by their names.
Definition Simulation.h:402
bool hasInitialConditionsFromFile() const
Are initial conditions specified from a file.
std::map< VariableName, VariableInfo > _vars
variables for this simulation (name and info about the var)
Definition Simulation.h:412
std::map< std::string, ControlDataValue * > _control_data
Control data created in the control logic system.
Definition Simulation.h:460
void addConstantScalarIC(const VariableName &var_name, Real value)
Definition Simulation.C:552
FEProblemBase & _fe_problem
Pointer to FEProblem representing this simulation.
Definition Simulation.h:391
ThermalHydraulicsApp & _thm_app
The application this is associated with.
Definition Simulation.h:394
static std::map< VariableName, int > _component_variable_order_map
Component variable order map; see setComponentVariableOrder for more info.
Definition Simulation.h:488
ThermalHydraulicsApp & getApp()
Get the ThermalHydraulicsApp.
Definition Simulation.h:245
std::vector< OutputName > _outputters_file
Definition Simulation.h:456
void addConstantIC(const VariableName &var_name, Real value, const std::vector< SubdomainName > &block_names)
Definition Simulation.C:512
virtual void integrityCheck() const
Check the integrity of the simulation.
Definition Simulation.C:846
virtual void advanceState()
Advance all of the state holding vectors / datastructures so that we can move to the next timestep.
virtual void addVariables()
Add variables involved in this simulation.
Definition Simulation.C:634
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
const InputParameters & _thm_pars
"Global" of this simulation
Definition Simulation.h:427
void addFunctionIC(const VariableName &var_name, const std::string &func_name, const std::vector< SubdomainName > &block_names)
Definition Simulation.C:532
virtual void initComponents()
Initialize this simulation's components.
Definition Simulation.C:151
std::vector< OutputName > _outputters_all
Definition Simulation.h:455
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 couplingMatrixIntegrityCheck() const
Check integrity of coupling matrix used by the preconditioner.
Definition Simulation.C:807
virtual void addClosures(const std::string &type, const std::string &name, InputParameters params)
Add a closures object into this simulation.
void addRelationshipManagers()
Add additional relationship managers to run the simulation.
Definition Simulation.C:745
virtual void setupMesh()
Perform mesh setup actions such as setting up the coordinate system(s) and creating ghosted elements.
Definition Simulation.C:798
std::vector< OutputName > _outputters_screen
Definition Simulation.h:457
void checkVariableNameLength(const std::string &name) const
Reports an error if the variable name is too long.
Definition Simulation.C:479
const libMesh::FEType & getFlowFEType() const
Gets the FE type for the flow in this simulation.
Definition Simulation.h:48
bool hasComponent(const std::string &name) const
Find out if simulation has a component with the given name.
virtual ~Simulation()
Definition Simulation.C:64
virtual void controlDataIntegrityCheck()
Check the integrity of the control data.
Definition Simulation.C:911
std::map< std::string, ICInfo > _ics
Definition Simulation.h:424
std::shared_ptr< ClosuresBase > getClosures(const std::string &name) const
Get a pointer to a closures object.
void identifyLoops()
Identifies the component loops.
Definition Simulation.C:164
virtual void initSimulation()
Initialize this simulation.
Definition Simulation.C:135
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
static void setComponentVariableOrder(const VariableName &var, int index)
Sets a component variable order index.
Definition Simulation.C:40
virtual void addComponent(const std::string &type, const std::string &name, InputParameters params)
Add a component into this simulation.
Definition Simulation.C:991
bool hasClosures(const std::string &name) const
Return whether the simulation has a closures object.
std::map< std::string, std::shared_ptr< ClosuresBase > > _closures_by_name
Map of closures by their names.
Definition Simulation.h:409
virtual void addMooseObjects()
Add component MOOSE objects.
Definition Simulation.C:738
bool _implicit_time_integration
true if using implicit time integration scheme
Definition Simulation.h:463
virtual void buildMesh()
Create mesh for this simulation.
Definition Simulation.C:87
virtual void setupQuadrature()
Sets up quadrature rules.
Definition Simulation.C:98
Factory & _thm_factory
The Factory associated with the MooseApp.
Definition Simulation.h:397
std::vector< std::shared_ptr< Component > > _components
List of components in this simulation.
Definition Simulation.h:400
std::vector< VariableName > sortAddedComponentVariables() const
Returns a sorted list of the variables added by components.
Definition Simulation.C:578
void setupInitialConditionObjects()
Definition Simulation.C:727
void addFileOutputter(const std::string &name)
std::vector< OutputName > getOutputsVector(const std::string &key) const
Gets the vector of output names corresponding to a 1-word key string.
void setupCoordinateSystem()
Sets the coordinate system for each subdomain.
Definition Simulation.C:770
virtual void run()
Run the simulation.
Definition Simulation.C:986
Logger _log
Definition Simulation.h:465
void setupInitialConditionsFromFile()
Setup reading initial conditions from a specified file, see 'initial_from_file' and 'initial_from_fil...
Definition Simulation.C:686
std::map< std::string, THM::FlowModelID > _loop_name_to_model_id
Map of loop name to model type.
Definition Simulation.h:406
bool _check_jacobian
True if checking jacobian.
Definition Simulation.h:468
void addSimInitialCondition(const std::string &type, const std::string &name, InputParameters params)
Definition Simulation.C:495
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
void addScreenOutputter(const std::string &name)
const std::vector< std::shared_ptr< TimeIntegrator > > & getTimeIntegrators()
virtual void init()
Definition THMControl.h:21
const std::vector< std::string > & getControlDataDependencies() const
Return the Controls that must run before this Control.
Definition THMControl.h:26
Mesh for THM.
Definition THMMesh.h:19
This control block will terminate a run if its input indicates so.
Moose::TimeIntegratorType getTimeScheme() const
std::size_t size() const
Order default_quadrature_order() const
OrderWrapper order
virtual std::unique_ptr< Base > create()=0
TimeIntegratorType
TI_EXPLICIT_EULER
TI_EXPLICIT_TVD_RK_2
TI_EXPLICIT_MIDPOINT
RelationshipManagerType
static const size_t MAX_VARIABLE_LENGTH
unsigned int FlowModelID
std::string enum_to_string(const T e)
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
uint8_t dof_id_type
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
InputParameters _params
Definition Simulation.h:417
std::string _type
Definition Simulation.h:416
Variable information.
Definition Simulation.h:376
bool _nl
True if the variable is a nonlinear (solution) variable; otherwise, aux.
Definition Simulation.h:378
InputParameters _params
Input parameters.
Definition Simulation.h:382
std::string _var_type
Type (class) of the variable.
Definition Simulation.h:380