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 138 : HSCoupler2D3D::validParams()
20 : {
21 138 : InputParameters params = BoundaryBase::validParams();
22 :
23 276 : params.addRequiredParam<std::string>("heat_structure_2d", "The 2D heat structure to couple");
24 276 : params.addRequiredParam<std::string>("heat_structure_3d", "The 3D heat structure to couple");
25 276 : params.addRequiredParam<BoundaryName>("boundary_2d",
26 : "The boundary of the 2D heat structure to couple");
27 276 : params.addRequiredParam<BoundaryName>("boundary_3d",
28 : "The boundary of the 3D heat structure to couple");
29 :
30 276 : params.addParam<bool>("include_radiation", true, "Include radiation component of heat flux");
31 276 : params.addParam<FunctionName>(
32 : "emissivity_2d",
33 : "Emissivity of the 2D heat structure boundary as a function of temperature [K]");
34 276 : params.addParam<FunctionName>(
35 : "emissivity_3d",
36 : "Emissivity of the 3D heat structure boundary as a function of temperature [K]");
37 276 : params.addRequiredParam<FunctionName>("gap_thickness",
38 : "Gap thickness [m] as a function of temperature [K]");
39 276 : params.addRequiredParam<FunctionName>(
40 : "gap_thermal_conductivity",
41 : "Gap thermal conductivity [W/(m-K)] as a function of temperature [K]");
42 276 : params.addParam<FunctionName>(
43 276 : "gap_htc", 0, "Gap heat transfer coefficient [W/(m^2-K)] as a function of temperature [K]");
44 :
45 138 : params.addClassDescription("Couples a 2D heat structure boundary to a 3D heat structure boundary "
46 : "using gap heat transfer.");
47 :
48 138 : return params;
49 0 : }
50 :
51 69 : HSCoupler2D3D::HSCoupler2D3D(const InputParameters & parameters)
52 : : BoundaryBase(parameters),
53 :
54 69 : _hs_name_2d(getParam<std::string>("heat_structure_2d")),
55 138 : _hs_name_3d(getParam<std::string>("heat_structure_3d")),
56 138 : _boundary_2d(getParam<BoundaryName>("boundary_2d")),
57 138 : _boundary_3d(getParam<BoundaryName>("boundary_3d")),
58 :
59 138 : _mesh_alignment(constMesh())
60 : {
61 69 : addDependency(_hs_name_2d);
62 69 : addDependency(_hs_name_3d);
63 69 : }
64 :
65 : void
66 69 : HSCoupler2D3D::setupMesh()
67 : {
68 69 : BoundaryBase::setupMesh();
69 :
70 69 : if (hasComponentByName<HeatStructureCylindricalBase>(_hs_name_2d) &&
71 67 : hasComponentByName<HeatStructureFromFile3D>(_hs_name_3d))
72 : {
73 : const auto & hs_2d = getComponentByName<HeatStructureCylindricalBase>(_hs_name_2d);
74 65 : const auto & hs_3d = getComponentByName<HeatStructureFromFile3D>(_hs_name_3d);
75 :
76 65 : if (hs_2d.hasBoundary(_boundary_2d) && hs_3d.hasBoundary(_boundary_3d))
77 : {
78 : // Initialize the alignment mapping
79 61 : _mesh_alignment.initialize(hs_2d.getBoundaryInfo(_boundary_2d),
80 : hs_3d.getBoundaryInfo(_boundary_3d),
81 61 : hs_2d.getPosition(),
82 122 : hs_2d.getDirection());
83 :
84 : // Add entries to sparsity pattern for coupling
85 61 : if (_mesh_alignment.meshesAreAligned())
86 5959 : for (const auto & elem_id : _mesh_alignment.getSecondaryElemIDs())
87 : {
88 5900 : if (_mesh_alignment.hasCoupledPrimaryElemID(elem_id))
89 5900 : getTHMProblem().augmentSparsity(elem_id,
90 5900 : _mesh_alignment.getCoupledPrimaryElemID(elem_id));
91 : }
92 : }
93 : }
94 69 : }
95 :
96 : void
97 69 : HSCoupler2D3D::check() const
98 : {
99 69 : BoundaryBase::check();
100 :
101 138 : 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 192 : 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 69 : if (hasComponentByName<HeatStructureCylindricalBase>(_hs_name_2d))
115 : {
116 : const auto & hs = getComponentByName<HeatStructureCylindricalBase>(_hs_name_2d);
117 67 : 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 69 : if (hasComponentByName<HeatStructureFromFile3D>(_hs_name_3d))
128 : {
129 : const auto & hs = getComponentByName<HeatStructureFromFile3D>(_hs_name_3d);
130 67 : 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 69 : if (hasComponentByName<HeatStructureCylindricalBase>(_hs_name_2d) &&
141 67 : hasComponentByName<HeatStructureFromFile3D>(_hs_name_3d) &&
142 : !_mesh_alignment.meshesAreAligned())
143 6 : logError("The meshes of the heat structures are not aligned.");
144 :
145 69 : const unsigned int needed_ad_container_size = 4 * _mesh_alignment.getMaxCouplingSize() + 6;
146 69 : 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 69 : }
151 :
152 : void
153 55 : HSCoupler2D3D::addMooseObjects()
154 : {
155 : // add side UO on 2D boundary to cache temperature values by element ID
156 110 : const UserObjectName temperature_2d_uo_name = genName(name(), "2d_uo");
157 : {
158 55 : const std::string class_name = "StoreVariableByElemIDSideUserObject";
159 55 : InputParameters params = _factory.getValidParams(class_name);
160 165 : params.set<std::vector<BoundaryName>>("boundary") = {_boundary_2d};
161 165 : params.set<std::vector<VariableName>>("variable") = {HeatConductionModel::TEMPERATURE};
162 275 : 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 55 : params.set<int>("execution_order_group") = -1;
165 55 : getTHMProblem().addUserObject(class_name, temperature_2d_uo_name, params);
166 55 : }
167 :
168 : // get the radius of the 2D heat structure boundary
169 55 : const auto & hs_2d = getComponentByName<HeatStructureCylindricalBase>(_hs_name_2d);
170 55 : 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 110 : const UserObjectName hs_coupler_2d3d_uo_name = genName(name(), "3d_uo");
174 : {
175 55 : const std::string class_name = "HSCoupler2D3DUserObject";
176 55 : InputParameters params = _factory.getValidParams(class_name);
177 165 : params.set<std::vector<BoundaryName>>("boundary") = {_boundary_3d};
178 165 : params.set<std::vector<VariableName>>("temperature") = {HeatConductionModel::TEMPERATURE};
179 55 : params.set<Real>("radius_2d") = radius_2d;
180 110 : 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 165 : params.set<FunctionName>("gap_thickness") = getParam<FunctionName>("gap_thickness");
186 110 : params.set<FunctionName>("gap_thermal_conductivity") =
187 55 : getParam<FunctionName>("gap_thermal_conductivity");
188 165 : params.set<FunctionName>("gap_htc") = getParam<FunctionName>("gap_htc");
189 55 : params.set<UserObjectName>("temperature_2d_uo") = temperature_2d_uo_name;
190 55 : params.set<MeshAlignment2D3D *>("mesh_alignment") = &_mesh_alignment;
191 275 : params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR};
192 55 : getTHMProblem().addUserObject(class_name, hs_coupler_2d3d_uo_name, params);
193 55 : }
194 :
195 : // add BC on 2D boundary
196 : {
197 55 : const std::string class_name = "HSCoupler2D3DBC";
198 55 : InputParameters params = _factory.getValidParams(class_name);
199 110 : params.set<NonlinearVariableName>("variable") = HeatConductionModel::TEMPERATURE;
200 165 : params.set<std::vector<BoundaryName>>("boundary") = {_boundary_2d};
201 55 : params.set<UserObjectName>("hs_coupler_2d3d_uo") = hs_coupler_2d3d_uo_name;
202 55 : getTHMProblem().addBoundaryCondition(class_name, genName(name(), class_name, "2d"), params);
203 55 : }
204 :
205 : // add BC on 3D boundary
206 : {
207 55 : const std::string class_name = "HSCoupler2D3DBC";
208 55 : InputParameters params = _factory.getValidParams(class_name);
209 110 : params.set<NonlinearVariableName>("variable") = HeatConductionModel::TEMPERATURE;
210 165 : params.set<std::vector<BoundaryName>>("boundary") = {_boundary_3d};
211 55 : params.set<UserObjectName>("hs_coupler_2d3d_uo") = hs_coupler_2d3d_uo_name;
212 55 : getTHMProblem().addBoundaryCondition(class_name, genName(name(), class_name, "3d"), params);
213 55 : }
214 385 : }
|