Line data Source code
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 "HSCoupler2D3D.h"
11 : #include "HeatStructureCylindricalBase.h"
12 : #include "HeatStructureFromFile3D.h"
13 : #include "MeshAlignment2D3D.h"
14 : #include "THMMesh.h"
15 :
16 : registerMooseObject("ThermalHydraulicsApp", HSCoupler2D3D);
17 :
18 : InputParameters
19 140 : HSCoupler2D3D::validParams()
20 : {
21 140 : InputParameters params = BoundaryBase::validParams();
22 :
23 280 : params.addRequiredParam<std::string>("heat_structure_2d", "The 2D heat structure to couple");
24 280 : params.addRequiredParam<std::string>("heat_structure_3d", "The 3D heat structure to couple");
25 280 : params.addRequiredParam<BoundaryName>("boundary_2d",
26 : "The boundary of the 2D heat structure to couple");
27 280 : params.addRequiredParam<BoundaryName>("boundary_3d",
28 : "The boundary of the 3D heat structure to couple");
29 :
30 280 : params.addParam<bool>("include_radiation", true, "Include radiation component of heat flux");
31 280 : params.addParam<FunctionName>(
32 : "emissivity_2d",
33 : "Emissivity of the 2D heat structure boundary as a function of temperature [K]");
34 280 : params.addParam<FunctionName>(
35 : "emissivity_3d",
36 : "Emissivity of the 3D heat structure boundary as a function of temperature [K]");
37 280 : params.addRequiredParam<FunctionName>("gap_thickness",
38 : "Gap thickness [m] as a function of temperature [K]");
39 280 : params.addRequiredParam<FunctionName>(
40 : "gap_thermal_conductivity",
41 : "Gap thermal conductivity [W/(m-K)] as a function of temperature [K]");
42 280 : params.addParam<FunctionName>(
43 280 : "gap_htc", 0, "Gap heat transfer coefficient [W/(m^2-K)] as a function of temperature [K]");
44 :
45 140 : params.addClassDescription("Couples a 2D heat structure boundary to a 3D heat structure boundary "
46 : "using gap heat transfer.");
47 :
48 140 : return params;
49 0 : }
50 :
51 70 : HSCoupler2D3D::HSCoupler2D3D(const InputParameters & parameters)
52 : : BoundaryBase(parameters),
53 :
54 70 : _hs_name_2d(getParam<std::string>("heat_structure_2d")),
55 140 : _hs_name_3d(getParam<std::string>("heat_structure_3d")),
56 140 : _boundary_2d(getParam<BoundaryName>("boundary_2d")),
57 140 : _boundary_3d(getParam<BoundaryName>("boundary_3d")),
58 :
59 140 : _mesh_alignment(constMesh())
60 : {
61 70 : addDependency(_hs_name_2d);
62 70 : addDependency(_hs_name_3d);
63 70 : }
64 :
65 : void
66 70 : HSCoupler2D3D::setupMesh()
67 : {
68 : BoundaryBase::setupMesh();
69 :
70 70 : if (hasComponentByName<HeatStructureCylindricalBase>(_hs_name_2d) &&
71 68 : hasComponentByName<HeatStructureFromFile3D>(_hs_name_3d))
72 : {
73 : const auto & hs_2d = getComponentByName<HeatStructureCylindricalBase>(_hs_name_2d);
74 66 : const auto & hs_3d = getComponentByName<HeatStructureFromFile3D>(_hs_name_3d);
75 :
76 66 : if (hs_2d.hasBoundary(_boundary_2d) && hs_3d.hasBoundary(_boundary_3d))
77 : {
78 : // Initialize the alignment mapping
79 62 : _mesh_alignment.initialize(hs_2d.getBoundaryInfo(_boundary_2d),
80 : hs_3d.getBoundaryInfo(_boundary_3d),
81 62 : hs_2d.getPosition(),
82 124 : hs_2d.getDirection());
83 :
84 : // Add entries to sparsity pattern for coupling
85 62 : if (_mesh_alignment.meshesAreAligned())
86 6060 : for (const auto & elem_id : _mesh_alignment.getSecondaryElemIDs())
87 : {
88 6000 : if (_mesh_alignment.hasCoupledPrimaryElemID(elem_id))
89 6000 : getTHMProblem().augmentSparsity(elem_id,
90 6000 : _mesh_alignment.getCoupledPrimaryElemID(elem_id));
91 : }
92 : }
93 : }
94 70 : }
95 :
96 : void
97 70 : HSCoupler2D3D::check() const
98 : {
99 : BoundaryBase::check();
100 :
101 140 : if (getParam<bool>("include_radiation"))
102 : {
103 76 : if (!(isParamValid("emissivity_2d") && isParamValid("emissivity_3d")))
104 2 : logError("If 'include_radiation' is 'true', then 'emissivity_2d' and 'emissivity_3d' are "
105 : "required.");
106 : }
107 : else
108 : {
109 196 : if (isParamValid("emissivity_2d") || isParamValid("emissivity_3d"))
110 2 : logError("If 'include_radiation' is 'false', then neither 'emissivity_2d' nor "
111 : "'emissivity_3d' can be specified.");
112 : }
113 :
114 70 : if (hasComponentByName<HeatStructureCylindricalBase>(_hs_name_2d))
115 : {
116 : const auto & hs = getComponentByName<HeatStructureCylindricalBase>(_hs_name_2d);
117 68 : if (!hs.hasBoundary(_boundary_2d))
118 2 : logError("The heat structure '",
119 2 : _hs_name_2d,
120 : "' does not have the boundary '",
121 : _boundary_2d,
122 : "'.");
123 : }
124 : else
125 2 : logError("There is no 2D cylindrical heat structure with the name '", _hs_name_2d, "'.");
126 :
127 70 : if (hasComponentByName<HeatStructureFromFile3D>(_hs_name_3d))
128 : {
129 : const auto & hs = getComponentByName<HeatStructureFromFile3D>(_hs_name_3d);
130 68 : if (!hs.hasBoundary(_boundary_3d))
131 2 : logError("The heat structure '",
132 2 : _hs_name_3d,
133 : "' does not have the boundary '",
134 : _boundary_3d,
135 : "'.");
136 : }
137 : else
138 2 : logError("There is no 3D heat structure with the name '", _hs_name_3d, "'.");
139 :
140 70 : if (hasComponentByName<HeatStructureCylindricalBase>(_hs_name_2d) &&
141 68 : hasComponentByName<HeatStructureFromFile3D>(_hs_name_3d) &&
142 : !_mesh_alignment.meshesAreAligned())
143 6 : logError("The meshes of the heat structures are not aligned.");
144 :
145 70 : const unsigned int needed_ad_container_size = 4 * _mesh_alignment.getMaxCouplingSize() + 6;
146 70 : if (MOOSE_AD_MAX_DOFS_PER_ELEM < needed_ad_container_size)
147 2 : logError("MOOSE must be configured with a larger AD container size (>= ",
148 : needed_ad_container_size,
149 : "). See HSCoupler2D3D's documentation for more information.");
150 70 : }
151 :
152 : void
153 56 : HSCoupler2D3D::addMooseObjects()
154 : {
155 : // add side UO on 2D boundary to cache temperature values by element ID
156 112 : const UserObjectName temperature_2d_uo_name = genName(name(), "2d_uo");
157 : {
158 56 : const std::string class_name = "StoreVariableByElemIDSideUserObject";
159 56 : InputParameters params = _factory.getValidParams(class_name);
160 168 : params.set<std::vector<BoundaryName>>("boundary") = {_boundary_2d};
161 168 : params.set<std::vector<VariableName>>("variable") = {HeatConductionModel::TEMPERATURE};
162 280 : params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR};
163 : // This UO needs to execute before the UO on the 3D boundary
164 56 : params.set<int>("execution_order_group") = -1;
165 56 : getTHMProblem().addUserObject(class_name, temperature_2d_uo_name, params);
166 56 : }
167 :
168 : // get the radius of the 2D heat structure boundary
169 56 : const auto & hs_2d = getComponentByName<HeatStructureCylindricalBase>(_hs_name_2d);
170 56 : const auto radius_2d = hs_2d.getInnerRadius() + hs_2d.getTotalWidth();
171 :
172 : // add side UO on 3D boundary to compute heat fluxes across each 3D boundary
173 112 : const UserObjectName hs_coupler_2d3d_uo_name = genName(name(), "3d_uo");
174 : {
175 56 : const std::string class_name = "HSCoupler2D3DUserObject";
176 56 : InputParameters params = _factory.getValidParams(class_name);
177 168 : params.set<std::vector<BoundaryName>>("boundary") = {_boundary_3d};
178 168 : params.set<std::vector<VariableName>>("temperature") = {HeatConductionModel::TEMPERATURE};
179 56 : params.set<Real>("radius_2d") = radius_2d;
180 112 : if (getParam<bool>("include_radiation"))
181 : {
182 54 : params.set<FunctionName>("emissivity_2d") = getParam<FunctionName>("emissivity_2d");
183 54 : params.set<FunctionName>("emissivity_3d") = getParam<FunctionName>("emissivity_3d");
184 : }
185 168 : params.set<FunctionName>("gap_thickness") = getParam<FunctionName>("gap_thickness");
186 112 : params.set<FunctionName>("gap_thermal_conductivity") =
187 56 : getParam<FunctionName>("gap_thermal_conductivity");
188 168 : params.set<FunctionName>("gap_htc") = getParam<FunctionName>("gap_htc");
189 56 : params.set<UserObjectName>("temperature_2d_uo") = temperature_2d_uo_name;
190 56 : params.set<MeshAlignment2D3D *>("mesh_alignment") = &_mesh_alignment;
191 280 : params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR};
192 56 : getTHMProblem().addUserObject(class_name, hs_coupler_2d3d_uo_name, params);
193 56 : }
194 :
195 : // add BC on 2D boundary
196 : {
197 56 : const std::string class_name = "HSCoupler2D3DBC";
198 56 : InputParameters params = _factory.getValidParams(class_name);
199 112 : params.set<NonlinearVariableName>("variable") = HeatConductionModel::TEMPERATURE;
200 168 : params.set<std::vector<BoundaryName>>("boundary") = {_boundary_2d};
201 56 : params.set<UserObjectName>("hs_coupler_2d3d_uo") = hs_coupler_2d3d_uo_name;
202 56 : getTHMProblem().addBoundaryCondition(class_name, genName(name(), class_name, "2d"), params);
203 56 : }
204 :
205 : // add BC on 3D boundary
206 : {
207 56 : const std::string class_name = "HSCoupler2D3DBC";
208 56 : InputParameters params = _factory.getValidParams(class_name);
209 112 : params.set<NonlinearVariableName>("variable") = HeatConductionModel::TEMPERATURE;
210 168 : params.set<std::vector<BoundaryName>>("boundary") = {_boundary_3d};
211 56 : params.set<UserObjectName>("hs_coupler_2d3d_uo") = hs_coupler_2d3d_uo_name;
212 56 : getTHMProblem().addBoundaryCondition(class_name, genName(name(), class_name, "3d"), params);
213 56 : }
214 392 : }
|