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