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 "FlowChannelBase.h"
11 : #include "HeatTransferBase.h"
12 : #include "ClosuresBase.h"
13 : #include "ThermalHydraulicsApp.h"
14 : #include "THMMesh.h"
15 :
16 : #include "libmesh/edge_edge2.h"
17 : #include "libmesh/edge_edge3.h"
18 :
19 : const std::map<std::string, FlowChannelBase::EConvHeatTransGeom>
20 : FlowChannelBase::_heat_transfer_geom_to_enum{
21 : {"PIPE", PIPE}, {"ROD_BUNDLE", ROD_BUNDLE}, {"HEX_ROD_BUNDLE", HEX_ROD_BUNDLE}};
22 :
23 : const std::map<std::string, FlowChannelBase::EPipeType> FlowChannelBase::_pipe_type_to_enum{
24 : {"STRAIGHT", STRAIGHT}, {"CURVED", CURVED}, {"DOWNCOMER", DOWNCOMER}};
25 :
26 : const std::map<std::string, FlowChannelBase::EPipeLocation> FlowChannelBase::_pipe_location_to_enum{
27 : {"INTERIOR", INTERIOR}, {"EDGE", EDGE}, {"CORNER", CORNER}};
28 :
29 : MooseEnum
30 8380 : FlowChannelBase::getConvHeatTransGeometry(const std::string & name)
31 : {
32 8380 : return THM::getMooseEnum<EConvHeatTransGeom>(name, _heat_transfer_geom_to_enum);
33 : }
34 :
35 : MooseEnum
36 0 : FlowChannelBase::getPipeType(const std::string & name)
37 : {
38 0 : return THM::getMooseEnum<EPipeType>(name, _pipe_type_to_enum);
39 : }
40 :
41 : MooseEnum
42 8380 : FlowChannelBase::getPipeLocation(const std::string & name)
43 : {
44 8380 : return THM::getMooseEnum<EPipeLocation>(name, _pipe_location_to_enum);
45 : }
46 :
47 : template <>
48 : FlowChannelBase::EConvHeatTransGeom
49 4189 : THM::stringToEnum(const std::string & s)
50 : {
51 4189 : return stringToEnum<FlowChannelBase::EConvHeatTransGeom>(
52 4189 : s, FlowChannelBase::_heat_transfer_geom_to_enum);
53 : }
54 :
55 : template <>
56 : FlowChannelBase::EPipeType
57 0 : THM::stringToEnum(const std::string & s)
58 : {
59 0 : return stringToEnum<FlowChannelBase::EPipeType>(s, FlowChannelBase::_pipe_type_to_enum);
60 : }
61 :
62 : template <>
63 : FlowChannelBase::EPipeLocation
64 4189 : THM::stringToEnum(const std::string & s)
65 : {
66 4189 : return stringToEnum<FlowChannelBase::EPipeLocation>(s, FlowChannelBase::_pipe_location_to_enum);
67 : }
68 :
69 : InputParameters
70 8380 : FlowChannelBase::validParams()
71 : {
72 8380 : InputParameters params = Component1D::validParams();
73 8380 : params += GravityInterface::validParams();
74 :
75 16760 : params.addRequiredParam<UserObjectName>("fp", "Fluid properties user object");
76 16760 : params.addRequiredParam<FunctionName>(
77 : "A", "Area of the flow channel, can be a constant or a function");
78 16760 : params.addParam<Real>("roughness", 0.0, "Roughness [m]");
79 16760 : params.addParam<FunctionName>("f", "Wall friction factor [-]");
80 16760 : params.addParam<MooseEnum>("heat_transfer_geom",
81 25140 : FlowChannelBase::getConvHeatTransGeometry("PIPE"),
82 : "Convective heat transfer geometry");
83 16760 : params.addParam<MooseEnum>("pipe_location",
84 25140 : FlowChannelBase::getPipeLocation("INTERIOR"),
85 : "Pipe location within the bundle");
86 16760 : params.addParam<Real>("PoD", 1, "Pitch-to-diameter ratio for parallel bundle heat transfer [-]");
87 16760 : params.addParam<bool>(
88 : "pipe_pars_transferred",
89 16760 : false,
90 : "Set to true if Dh, P_hf and A are going to be transferred in from an external source");
91 16760 : params.addParam<std::vector<std::string>>(
92 : "closures",
93 : {},
94 : "Closures object(s). This is optional since closure relations can be supplied directly by "
95 : "Materials as well.");
96 16760 : params.addParam<bool>("name_multiple_ht_by_index",
97 16760 : true,
98 : "If true, when there are multiple heat transfer components connected to "
99 : "this flow channel, use their index for naming related quantities; "
100 : "otherwise, use the name of the heat transfer component.");
101 :
102 16760 : params.setDocString(
103 : "orientation",
104 : "Direction of flow channel from start position to end position (no need to normalize). For "
105 : "curved flow channels, it is the (tangent) direction at the start position.");
106 :
107 16760 : params.addPrivateParam<std::string>("component_type", "pipe");
108 16760 : params.declareControllable("A f");
109 :
110 8380 : return params;
111 0 : }
112 :
113 4189 : FlowChannelBase::FlowChannelBase(const InputParameters & params)
114 : : Component1D(params),
115 : GravityInterface(params),
116 :
117 : _flow_model(nullptr),
118 8378 : _fp_name(getParam<UserObjectName>("fp")),
119 4189 : _gravity_angle(MooseUtils::absoluteFuzzyEqual(_gravity_magnitude, 0.0)
120 4189 : ? 0.0
121 1089 : : std::acos(_dir * _gravity_vector / (_dir.norm() * _gravity_magnitude)) *
122 : 180 / M_PI),
123 8378 : _pipe_pars_transferred(getParam<bool>("pipe_pars_transferred")),
124 8378 : _roughness(getParam<Real>("roughness")),
125 4189 : _HT_geometry(getEnumParam<EConvHeatTransGeom>("heat_transfer_geom")),
126 4189 : _pipe_location(getEnumParam<EPipeLocation>("pipe_location")),
127 8378 : _PoD(getParam<Real>("PoD")),
128 8378 : _has_PoD(isParamValid("PoD")),
129 4189 : _temperature_mode(false),
130 8378 : _n_heat_transfer_connections(0)
131 : {
132 4189 : }
133 :
134 : std::shared_ptr<const FlowModel>
135 6447 : FlowChannelBase::getFlowModel() const
136 : {
137 6447 : checkSetupStatus(INITIALIZED_PRIMARY);
138 :
139 6445 : return _flow_model;
140 : }
141 :
142 : const FunctionName &
143 4966 : FlowChannelBase::getAreaFunctionName() const
144 : {
145 4966 : checkSetupStatus(INITIALIZED_PRIMARY);
146 :
147 4966 : return _area_function;
148 : }
149 :
150 : FunctionName
151 4160 : FlowChannelBase::createAreaFunctionAndGetName()
152 : {
153 : // Area function has already been created; just need to return its name
154 8320 : return getParam<FunctionName>("A");
155 : }
156 :
157 : void
158 4160 : FlowChannelBase::init()
159 : {
160 4160 : Component1D::init();
161 :
162 4160 : _area_function = createAreaFunctionAndGetName();
163 :
164 8320 : _flow_model = buildFlowModel();
165 4160 : if (_flow_model)
166 : {
167 4160 : _flow_model->init();
168 :
169 8320 : const auto & closures_names = getParam<std::vector<std::string>>("closures");
170 8339 : for (const auto & closures_name : closures_names)
171 8358 : _closures_objects.push_back(getTHMProblem().getClosures(closures_name));
172 : }
173 4160 : }
174 :
175 : void
176 4160 : FlowChannelBase::initSecondary()
177 : {
178 : Component1D::initSecondary();
179 :
180 : // Determine heat transfer mode based on connected heat transfer components;
181 : // if at least one heat transfer component of temperature component is
182 : // connected, then it's temperature mode. Otherwise, it's heat flux mode, even
183 : // if no heat transfer components at all were provided - in that case, a zero
184 : // heat flux is added.
185 5209 : for (unsigned int i = 0; i < _heat_transfer_names.size(); i++)
186 : {
187 : const HeatTransferBase & heat_transfer =
188 : getComponentByName<HeatTransferBase>(_heat_transfer_names[i]);
189 1049 : if (heat_transfer.isTemperatureType())
190 939 : _temperature_mode = true;
191 : }
192 4160 : }
193 :
194 : void
195 4050 : FlowChannelBase::check() const
196 : {
197 4050 : Component1D::check();
198 :
199 8119 : for (const auto & closures : _closures_objects)
200 4069 : closures->checkFlowChannel(*this);
201 :
202 : // check types of heat transfer for all sources; must be all of same type
203 4050 : if (_temperature_mode)
204 1785 : for (unsigned int i = 0; i < _heat_transfer_names.size(); i++)
205 : {
206 : const HeatTransferBase & heat_transfer =
207 : getComponentByName<HeatTransferBase>(_heat_transfer_names[i]);
208 916 : if (!heat_transfer.isTemperatureType())
209 2 : logError("Heat sources for a flow channel must be all of temperature type or all of heat "
210 : "flux type");
211 : }
212 4050 : }
213 :
214 : void
215 4048 : FlowChannelBase::addVariables()
216 : {
217 : // This should be called after initSecondary() because it relies on the names
218 : // generated in initSecondary() of heat transfer components
219 4048 : getHeatTransferVariableNames();
220 :
221 4048 : _flow_model->addVariables();
222 :
223 : // total heat flux perimeter
224 4048 : if (_n_heat_transfer_connections > 1 && !_app.isRestarting())
225 : {
226 81 : const std::string class_name = "SumIC";
227 81 : InputParameters params = _factory.getValidParams(class_name);
228 162 : params.set<VariableName>("variable") = FlowModel::HEAT_FLUX_PERIMETER;
229 81 : params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
230 81 : params.set<std::vector<VariableName>>("values") = _P_hf_names;
231 162 : getTHMProblem().addSimInitialCondition(class_name, genName(name(), "P_hf_ic"), params);
232 81 : }
233 :
234 4048 : _flow_model->addInitialConditions();
235 4048 : }
236 :
237 : void
238 4048 : FlowChannelBase::addCommonObjects()
239 : {
240 4048 : ExecFlagEnum ts_execute_on(MooseUtils::getDefaultExecFlagEnum());
241 16192 : ts_execute_on = {EXEC_TIMESTEP_BEGIN, EXEC_INITIAL};
242 :
243 : {
244 4048 : std::string class_name = "DirectionMaterial";
245 4048 : InputParameters params = _factory.getValidParams(class_name);
246 4048 : params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
247 8096 : getTHMProblem().addMaterial(class_name, genName(name(), "dir_mat"), params);
248 4048 : }
249 :
250 4048 : if (!_pipe_pars_transferred)
251 : {
252 : // Area
253 : {
254 4048 : std::string class_name = "FunctionAux";
255 4048 : InputParameters params = _factory.getValidParams(class_name);
256 8096 : params.set<AuxVariableName>("variable") = FlowModel::AREA_LINEAR;
257 4048 : params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
258 4048 : params.set<FunctionName>("function") = _area_function;
259 4048 : params.set<ExecFlagEnum>("execute_on") = ts_execute_on;
260 8096 : const std::string aux_kernel_name = genName(name(), "area_linear_aux");
261 4048 : getTHMProblem().addAuxKernel(class_name, aux_kernel_name, params);
262 8096 : makeFunctionControllableIfConstant(_area_function, "Area");
263 4048 : }
264 : {
265 4048 : const std::string class_name = "ProjectionAux";
266 4048 : InputParameters params = _factory.getValidParams(class_name);
267 8096 : params.set<AuxVariableName>("variable") = FlowModel::AREA;
268 8096 : params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
269 12144 : params.set<std::vector<VariableName>>("v") = {FlowModel::AREA_LINEAR};
270 4048 : params.set<ExecFlagEnum>("execute_on") = ts_execute_on;
271 8096 : const std::string aux_kernel_name = genName(name(), "area_aux");
272 4048 : getTHMProblem().addAuxKernel(class_name, aux_kernel_name, params);
273 8096 : makeFunctionControllableIfConstant(_area_function, "Area");
274 4048 : }
275 : }
276 8096 : }
277 :
278 : void
279 4048 : FlowChannelBase::addMooseObjects()
280 : {
281 4048 : addCommonObjects();
282 :
283 4048 : ExecFlagEnum execute_on_initial_linear(MooseUtils::getDefaultExecFlagEnum());
284 16192 : execute_on_initial_linear = {EXEC_INITIAL, EXEC_LINEAR};
285 :
286 : // total heat flux perimeter aux kernel
287 4048 : if (_n_heat_transfer_connections > 1)
288 : {
289 81 : const std::string class_name = "SumAux";
290 81 : InputParameters params = _factory.getValidParams(class_name);
291 162 : params.set<AuxVariableName>("variable") = FlowModel::HEAT_FLUX_PERIMETER;
292 81 : params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
293 81 : params.set<std::vector<VariableName>>("values") = _P_hf_names;
294 81 : params.set<ExecFlagEnum>("execute_on") = execute_on_initial_linear;
295 162 : getTHMProblem().addAuxKernel(class_name, genName(name(), "P_hf_auxkernel"), params);
296 81 : }
297 :
298 : // weighted average wall heat flux aux kernel
299 4048 : if (!_temperature_mode)
300 : {
301 3190 : if (_n_heat_transfer_connections > 1)
302 : {
303 36 : const std::string class_name = "ADWeightedAverageMaterial";
304 36 : InputParameters params = _factory.getValidParams(class_name);
305 72 : params.set<MaterialPropertyName>("prop_name") = FlowModel::HEAT_FLUX_WALL;
306 36 : params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
307 36 : params.set<std::vector<MaterialPropertyName>>("values") = _q_wall_names;
308 36 : params.set<std::vector<VariableName>>("weights") = _P_hf_names;
309 72 : getTHMProblem().addMaterial(
310 36 : class_name, genName(name(), FlowModel::HEAT_FLUX_WALL, "w_avg_mat"), params);
311 36 : }
312 3154 : else if (_n_heat_transfer_connections == 0)
313 : {
314 3118 : const std::string class_name = "ADConstantMaterial";
315 3118 : InputParameters params = _factory.getValidParams(class_name);
316 3118 : params.set<std::string>("property_name") = FlowModel::HEAT_FLUX_WALL;
317 3118 : params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
318 3118 : params.set<Real>("value") = 0;
319 6236 : getTHMProblem().addMaterial(
320 3118 : class_name, genName(name(), FlowModel::HEAT_FLUX_WALL, "zero_mat"), params);
321 3118 : }
322 : }
323 :
324 4048 : _flow_model->addMooseObjects();
325 :
326 8115 : for (const auto & closures : _closures_objects)
327 4067 : closures->addMooseObjectsFlowChannel(*this);
328 8096 : }
329 :
330 : void
331 1049 : FlowChannelBase::addHeatTransferName(const std::string & name) const
332 : {
333 1049 : _heat_transfer_names.push_back(name);
334 1049 : _n_heat_transfer_connections++;
335 1049 : }
336 :
337 : void
338 4048 : FlowChannelBase::getHeatTransferVariableNames()
339 : {
340 5059 : for (unsigned int i = 0; i < _n_heat_transfer_connections; i++)
341 : {
342 : const HeatTransferBase & heat_transfer =
343 1011 : getComponentByName<HeatTransferBase>(_heat_transfer_names[i]);
344 :
345 1011 : _P_hf_names.push_back(heat_transfer.getHeatedPerimeterName());
346 1011 : _T_wall_names.push_back(heat_transfer.getWallTemperatureName());
347 1011 : _T_wall_mat_names.push_back(heat_transfer.getWallTemperatureMatName());
348 1011 : _q_wall_names.push_back(heat_transfer.getWallHeatFluxName());
349 : }
350 4048 : }
351 :
352 : std::string
353 2015 : FlowChannelBase::getHeatTransferNamesSuffix(const std::string & ht_name) const
354 : {
355 2015 : checkSetupStatus(INITIALIZED_PRIMARY);
356 :
357 : // if there is more than one connected heat transfer component, then number them
358 2015 : if (_n_heat_transfer_connections > 1)
359 : {
360 : // determine index of heat transfer name based on when it was added
361 332 : auto it = std::find(_heat_transfer_names.begin(), _heat_transfer_names.end(), ht_name);
362 332 : if (it != _heat_transfer_names.end())
363 : {
364 332 : const unsigned int index = std::distance(_heat_transfer_names.begin(), it);
365 :
366 332 : std::string suffix = ":";
367 664 : if (getParam<bool>("name_multiple_ht_by_index"))
368 520 : suffix += std::to_string(index + 1);
369 : else
370 72 : suffix += _heat_transfer_names[index];
371 :
372 332 : return suffix;
373 : }
374 : else
375 0 : mooseError(
376 0 : "Heat transfer component '", ht_name, "' was not added to flow channel '", name(), "'");
377 : }
378 : // else, don't add a suffix; there is no need
379 : else
380 1683 : return "";
381 : }
382 :
383 : std::vector<std::string>
384 0 : FlowChannelBase::getHeatTransferNames() const
385 : {
386 0 : checkSetupStatus(INITIALIZED_PRIMARY);
387 :
388 0 : return _heat_transfer_names;
389 : }
|