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 6508 : params += GeometricSearchInterface::validParams();
117 :
118 13016 : params.addParamNamesToGroup("primary secondary", "Gap surface definition");
119 13016 : params.addParamNamesToGroup(
120 : "tangential_tolerance normal_smoothing_distance normal_smoothing_method",
121 : "Gap edge and edge normal smoothing");
122 13016 : params.addParamNamesToGroup("gap_aux_type secondary_gap_offset mapped_primary_gap_offset",
123 : "Gap size");
124 13016 : params.addParamNamesToGroup("order quadrature", "Integration");
125 13016 : params.addParamNamesToGroup(
126 : "gap_conductivity gap_conductivity_function gap_conductivity_function_variable",
127 : "Gap conductivity");
128 13016 : params.addParamNamesToGroup("save_in check_boundary_restricted warnings",
129 : "Diagnostics and debug");
130 :
131 6508 : return params;
132 6508 : }
133 :
134 6508 : ThermalContactAction::ThermalContactAction(const InputParameters & params)
135 : : Action(params),
136 6508 : _quadrature(getParam<bool>("quadrature")),
137 13016 : _order(getParam<MooseEnum>("order")),
138 6508 : _penetration_var_name(_quadrature ? "qpoint_penetration" : "penetration"),
139 13016 : _gap_value_name("paired_" + getParam<NonlinearVariableName>("variable")),
140 13016 : _gap_conductivity_name("paired_k_" + getParam<NonlinearVariableName>("variable")),
141 19524 : _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary"))
142 : {
143 6508 : if (!params.get<bool>("check_boundary_restricted"))
144 : {
145 50 : if (_quadrature)
146 96 : paramInfo(
147 : "check_boundary_restricted",
148 : "This parameter is set to 'false'. Although thermal contact ",
149 : "will be correctly enforced, the contact-related output may have issues ",
150 : "in cases where where more than one face of an element belongs to a contact surface ",
151 : "because the values from only one of the faces will be reported.");
152 : else
153 2 : paramError("check_boundary_restricted",
154 : "This parameter cannot be 'false' when 'quadrature=false'");
155 : }
156 13128 : if (params.isParamSetByUser("penalty") &&
157 6738 : getParam<std::string>("type") != "GapPerfectConductance")
158 2 : paramError("penalty",
159 : "This parameter should only be set by the user when 'type=GapPerfectConductance'.");
160 6504 : }
161 :
162 : void
163 6464 : ThermalContactAction::act()
164 : {
165 6464 : if (_current_task == "add_aux_kernel")
166 1077 : addAuxKernels();
167 5387 : else if (_current_task == "add_aux_variable")
168 1079 : addAuxVariables();
169 4308 : else if (_current_task == "add_bc")
170 1075 : addBCs();
171 3233 : else if (_current_task == "add_dirac_kernel")
172 1075 : addDiracKernels();
173 2158 : else if (_current_task == "add_material")
174 1079 : addMaterials();
175 1079 : else if (_current_task == "add_secondary_flux_vector")
176 1079 : addSecondaryFluxVector();
177 6460 : }
178 :
179 : void
180 1077 : ThermalContactAction::addAuxKernels()
181 : {
182 2171 : for (const auto & contact_pair : _boundary_pairs)
183 : {
184 : // Add gap aux kernel
185 : {
186 2192 : InputParameters params = _factory.getValidParams(getParam<std::string>("gap_aux_type"));
187 :
188 1096 : params.applySpecificParameters(parameters(),
189 : {"tangential_tolerance",
190 : "normal_smoothing_distance",
191 : "normal_smoothing_method",
192 : "order",
193 : "warnings",
194 : "search_method",
195 : "check_boundary_restricted"});
196 1096 : params.set<AuxVariableName>("variable") = _gap_value_name;
197 4384 : params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
198 :
199 3288 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
200 1096 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
201 3288 : params.set<VariableName>("paired_variable") = getParam<NonlinearVariableName>("variable");
202 :
203 4382 : _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
204 3286 : "gap_value_" + name() + "_" + Moose::stringify(aux_kenels_counter),
205 : params);
206 :
207 1094 : if (_quadrature)
208 : {
209 1932 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
210 644 : params.set<BoundaryName>("paired_boundary") = contact_pair.second;
211 :
212 2576 : _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
213 1932 : "gap_value_primary_" + name() + "_" +
214 1288 : Moose::stringify(aux_kenels_counter),
215 : params);
216 : }
217 1094 : }
218 :
219 : // Add penetration aux kernel
220 : {
221 1094 : InputParameters params = _factory.getValidParams("PenetrationAux");
222 :
223 1094 : params.applySpecificParameters(parameters(),
224 : {"tangential_tolerance",
225 : "normal_smoothing_distance",
226 : "normal_smoothing_method",
227 : "order",
228 : "search_method",
229 : "check_boundary_restricted"});
230 1094 : params.set<AuxVariableName>("variable") = _penetration_var_name;
231 2188 : if (isParamValid("secondary_gap_offset"))
232 0 : params.set<std::vector<VariableName>>("secondary_gap_offset") = {
233 0 : getParam<VariableName>("secondary_gap_offset")};
234 2188 : if (isParamValid("mapped_primary_gap_offset"))
235 0 : params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
236 0 : getParam<VariableName>("mapped_primary_gap_offset")};
237 4376 : params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
238 3282 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
239 1094 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
240 :
241 3282 : _problem->addAuxKernel("PenetrationAux",
242 3282 : "penetration_" + name() + "_" + Moose::stringify(aux_kenels_counter++),
243 : params);
244 1094 : }
245 : }
246 3265 : }
247 :
248 : void
249 1079 : ThermalContactAction::addAuxVariables()
250 : {
251 : // We need to add variables only once per variable name. However, we don't know how many unique
252 : // variable names we will have. So, we'll always add them.
253 :
254 2158 : auto order = getParam<MooseEnum>("order");
255 1079 : std::string family = "LAGRANGE";
256 :
257 1079 : if (_quadrature)
258 : {
259 1296 : order = "CONSTANT";
260 : family = "MONOMIAL";
261 : }
262 :
263 : auto var_type =
264 1079 : AddVariableAction::variableType(FEType(order, Utility::string_to_enum<FEFamily>(family)));
265 1079 : auto var_params = _factory.getValidParams(var_type);
266 1079 : var_params.set<MooseEnum>("order") = order;
267 1079 : var_params.set<MooseEnum>("family") = family;
268 :
269 1079 : _problem->addAuxVariable(var_type, _penetration_var_name, var_params);
270 1079 : _problem->addAuxVariable(var_type, _gap_value_name, var_params);
271 2158 : }
272 :
273 : void
274 1075 : ThermalContactAction::addBCs()
275 : {
276 2169 : for (const auto & contact_pair : _boundary_pairs)
277 : {
278 2188 : const std::string object_name = getParam<std::string>("type");
279 1094 : InputParameters params = _factory.getValidParams(object_name);
280 1094 : params.applyParameters(parameters());
281 :
282 1094 : if (object_name == "GapPerfectConductance")
283 : {
284 38 : params.set<Real>("penalty") = getParam<Real>("penalty");
285 57 : params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
286 57 : params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
287 57 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
288 38 : _problem->addBoundaryCondition(
289 57 : object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
290 : }
291 : else
292 : {
293 1075 : if (_quadrature)
294 : {
295 644 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
296 644 : params.set<bool>("use_displaced_mesh") = true;
297 : }
298 : else
299 : {
300 1293 : params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
301 1293 : params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
302 : }
303 :
304 3225 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
305 :
306 2150 : _problem->addBoundaryCondition(
307 3225 : object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
308 :
309 1075 : if (_quadrature)
310 : {
311 : // Swap primary and secondary for this one
312 1932 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
313 644 : params.set<BoundaryName>("paired_boundary") = contact_pair.second;
314 :
315 1288 : _problem->addBoundaryCondition(
316 1932 : object_name, "gap_bc_primary_" + name() + "_" + Moose::stringify(bcs_counter), params);
317 : }
318 : }
319 1094 : bcs_counter++;
320 1094 : }
321 1525 : }
322 :
323 : void
324 1075 : ThermalContactAction::addDiracKernels()
325 : {
326 1075 : if (_quadrature)
327 : return;
328 :
329 881 : for (const auto & contact_pair : _boundary_pairs)
330 : {
331 450 : const std::string object_name = "GapHeatPointSourceMaster";
332 450 : InputParameters params = _factory.getValidParams(object_name);
333 450 : params.applySpecificParameters(parameters(),
334 : {"tangential_tolerance",
335 : "normal_smoothing_distance",
336 : "normal_smoothing_method",
337 : "order",
338 : "search_method",
339 : "variable"});
340 450 : params.set<BoundaryName>("boundary") = contact_pair.first;
341 450 : params.set<BoundaryName>("secondary") = contact_pair.second;
342 :
343 900 : _problem->addDiracKernel(
344 1350 : object_name, object_name + "_" + name() + "_" + Moose::stringify(dirac_counter++), params);
345 450 : }
346 : }
347 :
348 : void
349 1079 : ThermalContactAction::addMaterials()
350 : {
351 2158 : if (getParam<std::string>("type") != "GapHeatTransfer")
352 : return;
353 :
354 2120 : if (parameters().isParamSetByUser("gap_conductance"))
355 : {
356 114 : if (parameters().isParamSetByUser("gap_conductivity") ||
357 114 : parameters().isParamSetByUser("gap_conductivity_function"))
358 0 : mooseError(
359 : "Cannot specify both gap_conductance and gap_conductivity or gap_conductivity_function");
360 :
361 133 : for (const auto & contact_pair : _boundary_pairs)
362 : {
363 76 : const std::string object_type = "GapConductanceConstant";
364 76 : InputParameters params = _factory.getValidParams(object_type);
365 76 : params.applyParameters(parameters());
366 228 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
367 152 : _problem->addMaterial(object_type,
368 228 : name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
369 : params);
370 :
371 76 : if (_quadrature)
372 : {
373 57 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
374 38 : _problem->addMaterial(object_type,
375 57 : name() + "_" + "gap_value_primary" + "_" +
376 38 : Moose::stringify(materials_counter),
377 : params);
378 : }
379 76 : materials_counter++;
380 76 : }
381 : }
382 : else
383 : {
384 1003 : const std::string object_type = "GapConductance";
385 :
386 2004 : for (const auto & contact_pair : _boundary_pairs)
387 : {
388 1003 : InputParameters params = _factory.getValidParams(object_type);
389 1003 : params.applyParameters(parameters(), {"variable"});
390 :
391 2006 : params.set<std::vector<VariableName>>("variable") = {
392 6018 : getParam<NonlinearVariableName>("variable")};
393 3009 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
394 :
395 1003 : if (_quadrature)
396 1258 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
397 : else
398 : {
399 1122 : params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
400 1122 : params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
401 : }
402 :
403 2006 : _problem->addMaterial(object_type,
404 3007 : name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
405 : params);
406 :
407 1001 : if (_quadrature)
408 : {
409 1254 : params.set<BoundaryName>("paired_boundary") = contact_pair.second;
410 1881 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
411 :
412 1254 : _problem->addMaterial(object_type,
413 1881 : name() + "_" + "gap_value_primary" + "_" +
414 1254 : Moose::stringify(materials_counter),
415 : params);
416 : }
417 1001 : materials_counter++;
418 1001 : }
419 : }
420 1377 : }
421 :
422 : void
423 1079 : ThermalContactAction::addSecondaryFluxVector()
424 : {
425 1079 : _problem->getNonlinearSystemBase(/*nl_sys_num=*/0)
426 1079 : .addVector("secondary_flux", false, libMesh::GHOSTED);
427 1079 : _problem->getNonlinearSystemBase(/*nl_sys_num=*/0).zeroVectorForResidual("secondary_flux");
428 :
429 : // It is risky to apply this optimization to contact problems
430 : // since the problem configuration may be changed during Jacobian
431 : // evaluation. We therefore turn it off for all contact problems so that
432 : // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3 or older.
433 1079 : if (!_problem->isSNESMFReuseBaseSetbyUser())
434 : _problem->setSNESMFReuseBase(false, false);
435 1079 : }
436 :
437 : void
438 19404 : ThermalContactAction::addRelationshipManagers(Moose::RelationshipManagerType input_rm_type)
439 : {
440 19404 : if (!_quadrature)
441 : return;
442 :
443 23292 : for (const auto & contact_pair : _boundary_pairs)
444 : {
445 11646 : const auto & object_name = getParam<std::string>("type");
446 11646 : auto params = _factory.getValidParams(object_name);
447 11646 : params.applyParameters(parameters());
448 :
449 11646 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
450 11646 : params.set<bool>("use_displaced_mesh") = true;
451 34938 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
452 11646 : addRelationshipManagers(input_rm_type, params);
453 11646 : }
454 : }
|