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