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 "ThermalContactAction.h"
11 :
12 : #include "AddVariableAction.h"
13 : #include "FEProblem.h"
14 : #include "GapHeatTransfer.h"
15 : #include "libmesh/string_to_enum.h"
16 : #include "GapConductance.h"
17 : #include "GapConductanceConstant.h"
18 : #include "NonlinearSystem.h"
19 :
20 : // Counter for naming materials
21 : static unsigned int materials_counter = 0;
22 :
23 : // Counter for naming dirac kernels
24 : static unsigned int dirac_counter = 0;
25 :
26 : // Counter for naming BCs
27 : static unsigned int bcs_counter = 0;
28 :
29 : // Counter for naming aux kernels
30 : static unsigned int aux_kenels_counter = 0;
31 :
32 : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_aux_kernel");
33 : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_aux_variable");
34 : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_bc");
35 : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_dirac_kernel");
36 : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_material");
37 : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_secondary_flux_vector");
38 :
39 : InputParameters
40 6508 : ThermalContactAction::validParams()
41 : {
42 6508 : InputParameters params = Action::validParams();
43 6508 : params.addClassDescription(
44 : "Action that controls the creation of all of the necessary objects for "
45 : "calculation of Thermal Contact");
46 :
47 13016 : params.addParam<std::string>(
48 : "gap_aux_type",
49 : "GapValueAux",
50 : "A string representing the Moose object that will be used for computing the gap size");
51 13016 : params.addRequiredParam<NonlinearVariableName>("variable", "The variable for thermal contact");
52 13016 : params.addParam<std::vector<BoundaryName>>(
53 : "primary", "The list of boundary IDs referring to primary sidesets");
54 13016 : params.addRequiredParam<std::vector<BoundaryName>>(
55 : "secondary", "The list of boundary IDs referring to secondary sidesets");
56 13016 : params.addRangeCheckedParam<Real>("tangential_tolerance",
57 : "tangential_tolerance>=0",
58 : "Tangential distance to extend edges of contact surfaces");
59 13016 : params.addRangeCheckedParam<Real>(
60 : "normal_smoothing_distance",
61 : "normal_smoothing_distance>=0 & normal_smoothing_distance<=1",
62 : "Distance from edge in parametric coordinates over which to smooth contact normal");
63 13016 : params.addParam<std::string>("normal_smoothing_method",
64 : "Method to use to smooth normals (edge_based|nodal_normal_based)");
65 :
66 6508 : MooseEnum orders(AddVariableAction::getNonlinearVariableOrders());
67 13016 : params.addParam<MooseEnum>("order", orders, "The finite element order");
68 :
69 13016 : params.addParam<bool>(
70 13016 : "warnings", false, "Whether to output warning messages concerning nodes not being found");
71 13016 : params.addParam<bool>(
72 13016 : "quadrature", false, "Whether or not to use quadrature point based gap heat transfer");
73 19524 : params.addRangeCheckedParam<Real>("penalty",
74 13016 : 1e3,
75 : "penalty>0",
76 : "The penalty used in the residual and Jacobian calculations "
77 : "when using the GapPerfectConductance model");
78 13016 : params.addParam<std::string>(
79 : "appended_property_name", "", "Name appended to material properties to make them unique");
80 13016 : params.addRequiredParam<std::string>(
81 : "type",
82 : "A string representing the Moose object that will be used for heat conduction over the gap");
83 :
84 13016 : params.addParam<std::vector<VariableName>>(
85 : "displacements",
86 : "The displacements appropriate for the simulation geometry and coordinate system");
87 :
88 13016 : params.addParam<std::vector<AuxVariableName>>(
89 : "save_in", {}, "The Auxiliary Variable to (optionally) save the boundary flux in");
90 19524 : params.addRangeCheckedParam<Real>("gap_conductivity",
91 13016 : 1.0,
92 : "gap_conductivity>0",
93 : "The thermal conductivity of the gap material");
94 13016 : params.addParam<FunctionName>(
95 : "gap_conductivity_function",
96 : "Thermal conductivity of the gap material as a function. Multiplied by gap_conductivity.");
97 13016 : params.addParam<std::vector<VariableName>>(
98 : "gap_conductivity_function_variable",
99 : "Variable to be used in gap_conductivity_function in place of time");
100 13016 : params.addParam<VariableName>("secondary_gap_offset",
101 : "Offset to gap distance from secondary side");
102 13016 : params.addParam<VariableName>("mapped_primary_gap_offset",
103 : "Offset to gap distance mapped from primary side");
104 13016 : params.addParam<bool>(
105 : "check_boundary_restricted",
106 13016 : true,
107 : "Whether to check for multiple element sides on the boundary for the boundary restricted, "
108 : "element aux variable set up for thermal contact enforcement. Setting this to false will "
109 : "allow contribution to a single element's elemental value(s) from multiple boundary sides "
110 : "on the same element (example: when the restricted boundary exists on two or more sides "
111 : "of an element, such as at a corner of a mesh");
112 :
113 6508 : params += GapConductance::actionParameters();
114 6508 : params += GapConductanceConstant::actionParameters();
115 :
116 13016 : params.addParamNamesToGroup("primary secondary", "Gap surface definition");
117 13016 : params.addParamNamesToGroup(
118 : "tangential_tolerance normal_smoothing_distance normal_smoothing_method",
119 : "Gap edge and edge normal smoothing");
120 13016 : params.addParamNamesToGroup("gap_aux_type secondary_gap_offset mapped_primary_gap_offset",
121 : "Gap size");
122 13016 : params.addParamNamesToGroup("order quadrature", "Integration");
123 13016 : params.addParamNamesToGroup(
124 : "gap_conductivity gap_conductivity_function gap_conductivity_function_variable",
125 : "Gap conductivity");
126 13016 : params.addParamNamesToGroup("save_in check_boundary_restricted warnings",
127 : "Diagnostics and debug");
128 :
129 6508 : return params;
130 6508 : }
131 :
132 6508 : ThermalContactAction::ThermalContactAction(const InputParameters & params)
133 : : Action(params),
134 6508 : _quadrature(getParam<bool>("quadrature")),
135 13016 : _order(getParam<MooseEnum>("order")),
136 6508 : _penetration_var_name(_quadrature ? "qpoint_penetration" : "penetration"),
137 13016 : _gap_value_name("paired_" + getParam<NonlinearVariableName>("variable")),
138 13016 : _gap_conductivity_name("paired_k_" + getParam<NonlinearVariableName>("variable")),
139 19524 : _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary"))
140 : {
141 6508 : if (!params.get<bool>("check_boundary_restricted"))
142 : {
143 50 : if (_quadrature)
144 96 : paramInfo(
145 : "check_boundary_restricted",
146 : "This parameter is set to 'false'. Although thermal contact ",
147 : "will be correctly enforced, the contact-related output may have issues ",
148 : "in cases where where more than one face of an element belongs to a contact surface ",
149 : "because the values from only one of the faces will be reported.");
150 : else
151 2 : paramError("check_boundary_restricted",
152 : "This parameter cannot be 'false' when 'quadrature=false'");
153 : }
154 13128 : if (params.isParamSetByUser("penalty") &&
155 6738 : getParam<std::string>("type") != "GapPerfectConductance")
156 2 : paramError("penalty",
157 : "This parameter should only be set by the user when 'type=GapPerfectConductance'.");
158 6504 : }
159 :
160 : void
161 6464 : ThermalContactAction::act()
162 : {
163 6464 : if (_current_task == "add_aux_kernel")
164 1077 : addAuxKernels();
165 5387 : else if (_current_task == "add_aux_variable")
166 1079 : addAuxVariables();
167 4308 : else if (_current_task == "add_bc")
168 1075 : addBCs();
169 3233 : else if (_current_task == "add_dirac_kernel")
170 1075 : addDiracKernels();
171 2158 : else if (_current_task == "add_material")
172 1079 : addMaterials();
173 1079 : else if (_current_task == "add_secondary_flux_vector")
174 1079 : addSecondaryFluxVector();
175 6460 : }
176 :
177 : void
178 1077 : ThermalContactAction::addAuxKernels()
179 : {
180 2171 : for (const auto & contact_pair : _boundary_pairs)
181 : {
182 : // Add gap aux kernel
183 : {
184 2192 : InputParameters params = _factory.getValidParams(getParam<std::string>("gap_aux_type"));
185 :
186 1096 : params.applySpecificParameters(parameters(),
187 : {"tangential_tolerance",
188 : "normal_smoothing_distance",
189 : "normal_smoothing_method",
190 : "order",
191 : "warnings",
192 : "check_boundary_restricted"});
193 1096 : params.set<AuxVariableName>("variable") = _gap_value_name;
194 4384 : params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
195 :
196 3288 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
197 1096 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
198 3288 : params.set<VariableName>("paired_variable") = getParam<NonlinearVariableName>("variable");
199 :
200 4382 : _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
201 3286 : "gap_value_" + name() + "_" + Moose::stringify(aux_kenels_counter),
202 : params);
203 :
204 1094 : if (_quadrature)
205 : {
206 1932 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
207 644 : params.set<BoundaryName>("paired_boundary") = contact_pair.second;
208 :
209 2576 : _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
210 1932 : "gap_value_primary_" + name() + "_" +
211 1288 : Moose::stringify(aux_kenels_counter),
212 : params);
213 : }
214 1094 : }
215 :
216 : // Add penetration aux kernel
217 : {
218 1094 : InputParameters params = _factory.getValidParams("PenetrationAux");
219 :
220 1094 : params.applySpecificParameters(parameters(),
221 : {"tangential_tolerance",
222 : "normal_smoothing_distance",
223 : "normal_smoothing_method",
224 : "order",
225 : "check_boundary_restricted"});
226 1094 : params.set<AuxVariableName>("variable") = _penetration_var_name;
227 2188 : if (isParamValid("secondary_gap_offset"))
228 0 : params.set<std::vector<VariableName>>("secondary_gap_offset") = {
229 0 : getParam<VariableName>("secondary_gap_offset")};
230 2188 : if (isParamValid("mapped_primary_gap_offset"))
231 0 : params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
232 0 : getParam<VariableName>("mapped_primary_gap_offset")};
233 4376 : params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
234 3282 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
235 1094 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
236 :
237 3282 : _problem->addAuxKernel("PenetrationAux",
238 3282 : "penetration_" + name() + "_" + Moose::stringify(aux_kenels_counter++),
239 : params);
240 1094 : }
241 : }
242 3265 : }
243 :
244 : void
245 1079 : ThermalContactAction::addAuxVariables()
246 : {
247 : // We need to add variables only once per variable name. However, we don't know how many unique
248 : // variable names we will have. So, we'll always add them.
249 :
250 2158 : auto order = getParam<MooseEnum>("order");
251 1079 : std::string family = "LAGRANGE";
252 :
253 1079 : if (_quadrature)
254 : {
255 1296 : order = "CONSTANT";
256 : family = "MONOMIAL";
257 : }
258 :
259 : auto var_type =
260 1079 : AddVariableAction::variableType(FEType(order, Utility::string_to_enum<FEFamily>(family)));
261 1079 : auto var_params = _factory.getValidParams(var_type);
262 1079 : var_params.set<MooseEnum>("order") = order;
263 1079 : var_params.set<MooseEnum>("family") = family;
264 :
265 1079 : _problem->addAuxVariable(var_type, _penetration_var_name, var_params);
266 1079 : _problem->addAuxVariable(var_type, _gap_value_name, var_params);
267 2158 : }
268 :
269 : void
270 1075 : ThermalContactAction::addBCs()
271 : {
272 2169 : for (const auto & contact_pair : _boundary_pairs)
273 : {
274 2188 : const std::string object_name = getParam<std::string>("type");
275 1094 : InputParameters params = _factory.getValidParams(object_name);
276 1094 : params.applyParameters(parameters());
277 :
278 1094 : if (object_name == "GapPerfectConductance")
279 : {
280 38 : params.set<Real>("penalty") = getParam<Real>("penalty");
281 57 : params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
282 57 : params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
283 57 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
284 38 : _problem->addBoundaryCondition(
285 57 : object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
286 : }
287 : else
288 : {
289 1075 : if (_quadrature)
290 : {
291 644 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
292 644 : params.set<bool>("use_displaced_mesh") = true;
293 : }
294 : else
295 : {
296 1293 : params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
297 1293 : params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
298 : }
299 :
300 3225 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
301 :
302 2150 : _problem->addBoundaryCondition(
303 3225 : object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
304 :
305 1075 : if (_quadrature)
306 : {
307 : // Swap primary and secondary for this one
308 1932 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
309 644 : params.set<BoundaryName>("paired_boundary") = contact_pair.second;
310 :
311 1288 : _problem->addBoundaryCondition(
312 1932 : object_name, "gap_bc_primary_" + name() + "_" + Moose::stringify(bcs_counter), params);
313 : }
314 : }
315 1094 : bcs_counter++;
316 1094 : }
317 1525 : }
318 :
319 : void
320 1075 : ThermalContactAction::addDiracKernels()
321 : {
322 1075 : if (_quadrature)
323 : return;
324 :
325 881 : for (const auto & contact_pair : _boundary_pairs)
326 : {
327 450 : const std::string object_name = "GapHeatPointSourceMaster";
328 450 : InputParameters params = _factory.getValidParams(object_name);
329 450 : params.applySpecificParameters(parameters(),
330 : {"tangential_tolerance",
331 : "normal_smoothing_distance",
332 : "normal_smoothing_method",
333 : "order",
334 : "variable"});
335 450 : params.set<BoundaryName>("boundary") = contact_pair.first;
336 450 : params.set<BoundaryName>("secondary") = contact_pair.second;
337 :
338 900 : _problem->addDiracKernel(
339 1350 : object_name, object_name + "_" + name() + "_" + Moose::stringify(dirac_counter++), params);
340 450 : }
341 : }
342 :
343 : void
344 1079 : ThermalContactAction::addMaterials()
345 : {
346 2158 : if (getParam<std::string>("type") != "GapHeatTransfer")
347 : return;
348 :
349 2120 : if (parameters().isParamSetByUser("gap_conductance"))
350 : {
351 114 : if (parameters().isParamSetByUser("gap_conductivity") ||
352 114 : parameters().isParamSetByUser("gap_conductivity_function"))
353 0 : mooseError(
354 : "Cannot specify both gap_conductance and gap_conductivity or gap_conductivity_function");
355 :
356 133 : for (const auto & contact_pair : _boundary_pairs)
357 : {
358 76 : const std::string object_type = "GapConductanceConstant";
359 76 : InputParameters params = _factory.getValidParams(object_type);
360 76 : params.applyParameters(parameters());
361 228 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
362 152 : _problem->addMaterial(object_type,
363 228 : name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
364 : params);
365 :
366 76 : if (_quadrature)
367 : {
368 57 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
369 38 : _problem->addMaterial(object_type,
370 57 : name() + "_" + "gap_value_primary" + "_" +
371 38 : Moose::stringify(materials_counter),
372 : params);
373 : }
374 76 : materials_counter++;
375 76 : }
376 : }
377 : else
378 : {
379 1003 : const std::string object_type = "GapConductance";
380 :
381 2004 : for (const auto & contact_pair : _boundary_pairs)
382 : {
383 1003 : InputParameters params = _factory.getValidParams(object_type);
384 1003 : params.applyParameters(parameters(), {"variable"});
385 :
386 2006 : params.set<std::vector<VariableName>>("variable") = {
387 6018 : getParam<NonlinearVariableName>("variable")};
388 3009 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
389 :
390 1003 : if (_quadrature)
391 1258 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
392 : else
393 : {
394 1122 : params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
395 1122 : params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
396 : }
397 :
398 2006 : _problem->addMaterial(object_type,
399 3007 : name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
400 : params);
401 :
402 1001 : if (_quadrature)
403 : {
404 1254 : params.set<BoundaryName>("paired_boundary") = contact_pair.second;
405 1881 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
406 :
407 1254 : _problem->addMaterial(object_type,
408 1881 : name() + "_" + "gap_value_primary" + "_" +
409 1254 : Moose::stringify(materials_counter),
410 : params);
411 : }
412 1001 : materials_counter++;
413 1001 : }
414 : }
415 1377 : }
416 :
417 : void
418 1079 : ThermalContactAction::addSecondaryFluxVector()
419 : {
420 1079 : _problem->getNonlinearSystemBase(/*nl_sys_num=*/0)
421 1079 : .addVector("secondary_flux", false, libMesh::GHOSTED);
422 1079 : _problem->getNonlinearSystemBase(/*nl_sys_num=*/0).zeroVectorForResidual("secondary_flux");
423 :
424 : // It is risky to apply this optimization to contact problems
425 : // since the problem configuration may be changed during Jacobian
426 : // evaluation. We therefore turn it off for all contact problems so that
427 : // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3 or older.
428 1079 : if (!_problem->isSNESMFReuseBaseSetbyUser())
429 : _problem->setSNESMFReuseBase(false, false);
430 1079 : }
431 :
432 : void
433 19404 : ThermalContactAction::addRelationshipManagers(Moose::RelationshipManagerType input_rm_type)
434 : {
435 19404 : if (!_quadrature)
436 : return;
437 :
438 23292 : for (const auto & contact_pair : _boundary_pairs)
439 : {
440 11646 : const auto & object_name = getParam<std::string>("type");
441 11646 : auto params = _factory.getValidParams(object_name);
442 11646 : params.applyParameters(parameters());
443 :
444 11646 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
445 11646 : params.set<bool>("use_displaced_mesh") = true;
446 34938 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
447 11646 : addRelationshipManagers(input_rm_type, params);
448 11646 : }
449 : }
|