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 "CoupledHeatTransferAction.h"
11 : #include "DiscreteLineSegmentInterface.h"
12 : #include "FEProblem.h"
13 :
14 : registerMooseAction("ThermalHydraulicsApp", CoupledHeatTransferAction, "add_bc");
15 : registerMooseAction("ThermalHydraulicsApp", CoupledHeatTransferAction, "add_user_object");
16 : registerMooseAction("ThermalHydraulicsApp", CoupledHeatTransferAction, "add_transfer");
17 :
18 : InputParameters
19 164 : CoupledHeatTransferAction::validParams()
20 : {
21 164 : InputParameters params = Action::validParams();
22 :
23 164 : params.addClassDescription(
24 : "Action that creates the necessary objects, for the solid side, to couple a "
25 : "solid heat conduction region to a 1-D flow channel via convective heat transfer");
26 :
27 328 : params.addRequiredParam<std::vector<BoundaryName>>("boundary",
28 : "Boundary name(s) on the solid side");
29 328 : params.addRequiredParam<VariableName>("T", "Solid side temperature variable");
30 328 : params.addRequiredParam<VariableName>(
31 : "T_wall", "Variable on the flow channel side into which to transfer the solid temperature");
32 328 : params.addRequiredParam<std::vector<VariableName>>(
33 : "T_fluid", "Variable(s) on the solid side into which to transfer the fluid temperature(s)");
34 328 : params.addRequiredParam<std::vector<VariableName>>(
35 : "htc",
36 : "Variable(s) on the solid side into which to transfer the heat transfer coefficient(s)");
37 328 : params.addParam<std::vector<VariableName>>(
38 : "kappa", "Variables on the solid side into which to transfer the wall contact fractions");
39 328 : params.addParam<std::vector<UserObjectName>>(
40 : "T_fluid_user_objects", "Spatial user object(s) holding the fluid temperature values");
41 328 : params.addParam<std::vector<UserObjectName>>(
42 : "htc_user_objects", "Spatial user object(s) holding the heat transfer coefficient values");
43 328 : params.addDeprecatedParam<UserObjectName>(
44 : "T_fluid_user_object",
45 : "Spatial user object holding the fluid temperature values",
46 : "This parameter is deprecated in favor of 'T_fluid_user_objects' (just add an 's' to "
47 : "parameter name).");
48 328 : params.addDeprecatedParam<UserObjectName>(
49 : "htc_user_object",
50 : "Spatial user object holding the heat transfer coefficient values",
51 : "This parameter is deprecated in favor of 'htc_user_objects' (just add an 's' to parameter "
52 : "name).");
53 328 : params.addParam<std::vector<UserObjectName>>(
54 : "kappa_user_objects", "Spatial user object(s) holding the wall contact fraction values");
55 :
56 328 : MooseEnum directions("x y z");
57 328 : params.addDeprecatedParam<MooseEnum>(
58 : "direction",
59 : directions,
60 : "The direction of the layers.",
61 : "The usage of 'direction' and 'num_layers' is deprecated. Use 'position', 'orientation', "
62 : "'rotation', 'length', and 'n_elems' instead. The latter parameters correspond to the "
63 : "parameters of the same names in the coupled flow channel component.");
64 328 : params.addDeprecatedParam<unsigned int>(
65 : "num_layers",
66 : "The number of layers.",
67 : "The usage of 'direction' and 'num_layers' is deprecated. Use 'position', 'orientation', "
68 : "'rotation', 'length', and 'n_elems' instead. The latter parameters correspond to the "
69 : "parameters of the same names in the coupled flow channel component.");
70 :
71 328 : params.addParam<Point>("position", "Start position of axis in 3-D space [m]");
72 328 : params.addParam<RealVectorValue>(
73 : "orientation",
74 : "Direction of axis from start position to end position (no need to normalize)");
75 328 : params.addParam<Real>("rotation", 0.0, "Angle of rotation about the x-axis [degrees]");
76 328 : params.addParam<std::vector<Real>>("length", "Length of each axial section [m]");
77 328 : params.addParam<std::vector<unsigned int>>("n_elems", "Number of elements in each axial section");
78 :
79 328 : params.addRequiredParam<std::string>("multi_app", "The name of the multi-app.");
80 :
81 328 : params.addRangeCheckedParam<std::vector<Real>>(
82 : "fixed_bounding_box_size",
83 : "fixed_bounding_box_size >= 0",
84 : "The 'fixed_bounding_box_size' value to use for each MultiAppGeneralFieldUserObjectTransfer. "
85 : "If this parameter is not provided, a greedy search will be used instead of bounding boxes, "
86 : "which may be slower.");
87 :
88 328 : params.addParam<std::vector<Point>>(
89 : "positions", "Sub-app positions. Each set of 3 values represents a Point.");
90 328 : params.addParam<FileName>(
91 : "positions_file",
92 : "Name of file containing sub-app positions. Each set of 3 values represents a Point.");
93 164 : MultiAppTransfer::addSkipCoordCollapsingParam(params);
94 164 : return params;
95 164 : }
96 :
97 164 : CoupledHeatTransferAction::CoupledHeatTransferAction(const InputParameters & params)
98 : : Action(params),
99 :
100 164 : _boundary(getParam<std::vector<BoundaryName>>("boundary")),
101 :
102 164 : _T_solid_var_name(getParam<VariableName>("T")),
103 164 : _T_wall_var_name(getParam<VariableName>("T_wall")),
104 328 : _T_fluid_var_names(getParam<std::vector<VariableName>>("T_fluid")),
105 328 : _htc_var_names(getParam<std::vector<VariableName>>("htc")),
106 :
107 164 : _n_phases(_T_fluid_var_names.size()),
108 :
109 164 : _T_wall_user_object_name(name() + "_T_avg_uo"),
110 :
111 492 : _multi_app_name(getParam<std::string>("multi_app"))
112 : {
113 328 : if (isParamValid("T_fluid_user_objects"))
114 492 : _T_fluid_user_object_names = getParam<std::vector<UserObjectName>>("T_fluid_user_objects");
115 0 : else if (isParamValid("T_fluid_user_object"))
116 0 : _T_fluid_user_object_names = {getParam<UserObjectName>("T_fluid_user_object")};
117 : else
118 0 : mooseError("The parameter 'T_fluid_user_objects' must be specified.");
119 :
120 328 : if (isParamValid("htc_user_objects"))
121 492 : _htc_user_object_names = getParam<std::vector<UserObjectName>>("htc_user_objects");
122 0 : else if (isParamValid("htc_user_object"))
123 0 : _htc_user_object_names = {getParam<UserObjectName>("htc_user_object")};
124 : else
125 0 : mooseError("The parameter 'htc_user_objects' must be specified.");
126 :
127 164 : if (_htc_var_names.size() != _n_phases || _T_fluid_user_object_names.size() != _n_phases ||
128 : _htc_user_object_names.size() != _n_phases)
129 0 : mooseError("The parameters 'T_fluid', 'htc', 'T_fluid_user_objects', and 'htc_user_objects' "
130 : "must have the same numbers of elements.");
131 :
132 164 : if (_n_phases == 1)
133 : {
134 440 : if (isParamValid("kappa") || isParamValid("kappa_user_objects"))
135 0 : mooseError("If there is only one phase (e.g., only one element in 'T_fluid'), then the "
136 : "parameters 'kappa' and 'kappa_user_objects' must not be provided.");
137 : }
138 : else
139 : {
140 216 : if (!isParamValid("kappa") || !isParamValid("kappa_user_objects"))
141 0 : mooseError("If there is more than one phase (e.g., more than one element in 'T_fluid'), then "
142 : "the parameters 'kappa' and 'kappa_user_objects' must be provided.");
143 : else
144 : {
145 108 : _kappa_var_names = getParam<std::vector<VariableName>>("kappa");
146 162 : _kappa_user_object_names = getParam<std::vector<UserObjectName>>("kappa_user_objects");
147 54 : if (_kappa_var_names.size() != _n_phases || _kappa_user_object_names.size() != _n_phases)
148 0 : mooseError("The parameters 'kappa' and 'kappa_user_objects' must have the same number of "
149 : "elements as 'T_fluid'.");
150 : }
151 : }
152 :
153 328 : if (isParamValid("orientation"))
154 : {
155 164 : const auto & orientation = getParam<RealVectorValue>("orientation");
156 164 : if (!DiscreteLineSegmentInterface::getAlignmentAxis(orientation).isValid())
157 2 : mooseError("The direction given by the parameter 'orientation' must be aligned with the x, "
158 : "y, or z axis.");
159 : }
160 162 : }
161 :
162 : void
163 162 : CoupledHeatTransferAction::act()
164 : {
165 162 : if (_current_task == "add_bc")
166 54 : addBCs();
167 108 : else if (_current_task == "add_user_object")
168 54 : addUserObjects();
169 54 : else if (_current_task == "add_transfer")
170 54 : addTransfers();
171 162 : }
172 :
173 : void
174 54 : CoupledHeatTransferAction::addBCs()
175 : {
176 126 : for (unsigned int k = 0; k < _n_phases; k++)
177 : {
178 72 : const std::string class_name = "CoupledConvectiveHeatFluxBC";
179 72 : InputParameters params = _factory.getValidParams(class_name);
180 144 : params.set<NonlinearVariableName>("variable") = _T_solid_var_name;
181 72 : params.set<std::vector<BoundaryName>>("boundary") = {_boundary};
182 216 : params.set<std::vector<VariableName>>("T_infinity") = {_T_fluid_var_names[k]};
183 216 : params.set<std::vector<VariableName>>("htc") = {_htc_var_names[k]};
184 72 : if (_n_phases > 1)
185 108 : params.set<std::vector<VariableName>>("scale_factor") = {_kappa_var_names[k]};
186 144 : _problem->addBoundaryCondition(class_name, name() + "_bc" + std::to_string(k), params);
187 72 : }
188 54 : }
189 :
190 : void
191 54 : CoupledHeatTransferAction::addUserObjects()
192 : {
193 : // Solid temperature spatial user object
194 : {
195 54 : const std::string class_name = "NearestPointLayeredSideAverage";
196 54 : InputParameters params = _factory.getValidParams(class_name);
197 162 : params.set<std::vector<VariableName>>("variable") = {_T_solid_var_name};
198 54 : params.set<std::vector<BoundaryName>>("boundary") = {_boundary};
199 :
200 : // set sub-app positions
201 108 : if (isParamValid("positions"))
202 54 : params.set<std::vector<Point>>("points") = getParam<std::vector<Point>>("positions");
203 72 : else if (isParamValid("positions_file"))
204 0 : params.set<FileName>("points_file") = getParam<FileName>("positions_file");
205 : else
206 72 : params.set<std::vector<Point>>("points") = {Point(0, 0, 0)};
207 :
208 : // set layers
209 108 : if (isParamValid("direction") && isParamValid("num_layers"))
210 : {
211 0 : params.set<MooseEnum>("direction") = getParam<MooseEnum>("direction");
212 0 : params.set<unsigned int>("num_layers") = getParam<unsigned int>("num_layers");
213 : }
214 324 : else if (isParamValid("position") && isParamValid("orientation") && isParamValid("length") &&
215 162 : isParamValid("n_elems"))
216 : {
217 54 : const auto & position = getParam<Point>("position");
218 54 : const auto & orientation = getParam<RealVectorValue>("orientation");
219 54 : const auto & rotation = getParam<Real>("rotation");
220 54 : const auto & lengths = getParam<std::vector<Real>>("length");
221 54 : const auto & n_elems = getParam<std::vector<unsigned int>>("n_elems");
222 :
223 54 : params.set<MooseEnum>("direction") =
224 162 : DiscreteLineSegmentInterface::getAlignmentAxis(orientation);
225 108 : params.set<std::vector<Real>>("bounds") =
226 108 : DiscreteLineSegmentInterface::getElementBoundaryCoordinates(
227 : position, orientation, rotation, lengths, n_elems);
228 : }
229 : else
230 0 : mooseError(
231 : "The parameters 'position', 'orientation', 'length', and 'n_elems' must be provided.");
232 :
233 54 : _problem->addUserObject(class_name, _T_wall_user_object_name, params);
234 54 : }
235 54 : }
236 :
237 : void
238 54 : CoupledHeatTransferAction::addTransfers()
239 : {
240 : // Transfers to the flow channel application
241 :
242 108 : const bool skip_coordinate_collapsing = getParam<bool>("skip_coordinate_collapsing");
243 :
244 108 : const bool use_bounding_boxes = isParamValid("fixed_bounding_box_size");
245 : std::vector<Real> fixed_bounding_box_size;
246 54 : if (use_bounding_boxes)
247 0 : fixed_bounding_box_size = getParam<std::vector<Real>>("fixed_bounding_box_size");
248 :
249 : {
250 54 : const std::string class_name = "MultiAppGeneralFieldUserObjectTransfer";
251 54 : InputParameters params = _factory.getValidParams(class_name);
252 54 : params.set<MultiAppName>("to_multi_app") = _multi_app_name;
253 54 : params.set<UserObjectName>("source_user_object") = {_T_wall_user_object_name};
254 162 : params.set<std::vector<AuxVariableName>>("variable") = {_T_wall_var_name};
255 54 : params.set<bool>("skip_coordinate_collapsing") = skip_coordinate_collapsing;
256 54 : params.set<bool>("error_on_miss") = true;
257 54 : if (use_bounding_boxes)
258 0 : params.set<std::vector<Real>>("fixed_bounding_box_size") = fixed_bounding_box_size;
259 : else
260 : {
261 54 : params.set<bool>("use_bounding_boxes") = false;
262 54 : params.set<bool>("greedy_search") = true;
263 : }
264 54 : _problem->addTransfer(class_name, name() + "_T_solid_transfer", params);
265 54 : }
266 :
267 : // Transfers from the flow channel application. Note that
268 : // Note that MultiAppGeneralFieldNearestLocationTransfer should be more optimal
269 : // choice in parallel calculations, while MultiAppGeneralFieldUserObjectTransfer should
270 : // be more optimal in serial calculations. If these transfers prove to be a significant time
271 : // burden, we may want to provide an option to switch these transfer classes.
272 126 : for (unsigned int k = 0; k < _n_phases; k++)
273 : {
274 : {
275 72 : const std::string class_name = "MultiAppGeneralFieldUserObjectTransfer";
276 72 : InputParameters params = _factory.getValidParams(class_name);
277 72 : params.set<MultiAppName>("from_multi_app") = _multi_app_name;
278 144 : params.set<UserObjectName>("source_user_object") = _T_fluid_user_object_names[k];
279 216 : params.set<std::vector<AuxVariableName>>("variable") = {_T_fluid_var_names[k]};
280 72 : params.set<bool>("skip_coordinate_collapsing") = skip_coordinate_collapsing;
281 72 : params.set<bool>("error_on_miss") = true;
282 72 : if (use_bounding_boxes)
283 0 : params.set<std::vector<Real>>("fixed_bounding_box_size") = fixed_bounding_box_size;
284 : else
285 : {
286 72 : params.set<bool>("use_bounding_boxes") = false;
287 72 : params.set<bool>("greedy_search") = true;
288 : }
289 144 : _problem->addTransfer(class_name, name() + "_T_fluid_transfer" + std::to_string(k), params);
290 72 : }
291 : {
292 72 : const std::string class_name = "MultiAppGeneralFieldUserObjectTransfer";
293 72 : InputParameters params = _factory.getValidParams(class_name);
294 144 : params.set<MultiAppName>("from_multi_app") = _multi_app_name;
295 144 : params.set<UserObjectName>("source_user_object") = _htc_user_object_names[k];
296 216 : params.set<std::vector<AuxVariableName>>("variable") = {_htc_var_names[k]};
297 72 : params.set<bool>("skip_coordinate_collapsing") = skip_coordinate_collapsing;
298 72 : params.set<bool>("error_on_miss") = true;
299 72 : if (use_bounding_boxes)
300 0 : params.set<std::vector<Real>>("fixed_bounding_box_size") = fixed_bounding_box_size;
301 : else
302 : {
303 72 : params.set<bool>("use_bounding_boxes") = false;
304 72 : params.set<bool>("greedy_search") = true;
305 : }
306 144 : _problem->addTransfer(class_name, name() + "_htc_transfer" + std::to_string(k), params);
307 72 : }
308 72 : if (_n_phases > 1)
309 : {
310 36 : const std::string class_name = "MultiAppGeneralFieldUserObjectTransfer";
311 36 : InputParameters params = _factory.getValidParams(class_name);
312 72 : params.set<MultiAppName>("from_multi_app") = _multi_app_name;
313 72 : params.set<UserObjectName>("source_user_object") = _kappa_user_object_names[k];
314 108 : params.set<std::vector<AuxVariableName>>("variable") = {_kappa_var_names[k]};
315 36 : params.set<bool>("skip_coordinate_collapsing") = skip_coordinate_collapsing;
316 36 : params.set<bool>("error_on_miss") = true;
317 36 : if (use_bounding_boxes)
318 0 : params.set<std::vector<Real>>("fixed_bounding_box_size") = fixed_bounding_box_size;
319 : else
320 : {
321 36 : params.set<bool>("use_bounding_boxes") = false;
322 36 : params.set<bool>("greedy_search") = true;
323 : }
324 72 : _problem->addTransfer(class_name, name() + "_kappa_transfer" + std::to_string(k), params);
325 36 : }
326 : }
327 288 : }
|