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 3196 : ThermalContactAction::validParams()
41 : {
42 3196 : InputParameters params = Action::validParams();
43 3196 : params.addClassDescription(
44 : "Action that controls the creation of all of the necessary objects for "
45 : "calculation of Thermal Contact");
46 :
47 6392 : 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 6392 : params.addRequiredParam<NonlinearVariableName>("variable", "The variable for thermal contact");
52 6392 : params.addParam<std::vector<BoundaryName>>(
53 : "primary", "The list of boundary IDs referring to primary sidesets");
54 6392 : params.addRequiredParam<std::vector<BoundaryName>>(
55 : "secondary", "The list of boundary IDs referring to secondary sidesets");
56 6392 : params.addRangeCheckedParam<Real>("tangential_tolerance",
57 : "tangential_tolerance>=0",
58 : "Tangential distance to extend edges of contact surfaces");
59 6392 : 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 6392 : params.addParam<std::string>("normal_smoothing_method",
64 : "Method to use to smooth normals (edge_based|nodal_normal_based)");
65 :
66 3196 : MooseEnum orders(AddVariableAction::getNonlinearVariableOrders());
67 6392 : params.addParam<MooseEnum>("order", orders, "The finite element order");
68 :
69 6392 : params.addParam<bool>(
70 6392 : "warnings", false, "Whether to output warning messages concerning nodes not being found");
71 6392 : params.addParam<bool>(
72 6392 : "quadrature", false, "Whether or not to use quadrature point based gap heat transfer");
73 9588 : params.addRangeCheckedParam<Real>("penalty",
74 6392 : 1e3,
75 : "penalty>0",
76 : "The penalty used in the residual and Jacobian calculations "
77 : "when using the GapPerfectConductance model");
78 6392 : params.addParam<std::string>(
79 : "appended_property_name", "", "Name appended to material properties to make them unique");
80 6392 : 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 6392 : params.addParam<std::vector<VariableName>>(
85 : "displacements",
86 : "The displacements appropriate for the simulation geometry and coordinate system");
87 :
88 6392 : params.addParam<std::vector<AuxVariableName>>(
89 : "save_in", {}, "The Auxiliary Variable to (optionally) save the boundary flux in");
90 9588 : params.addRangeCheckedParam<Real>("gap_conductivity",
91 6392 : 1.0,
92 : "gap_conductivity>0",
93 : "The thermal conductivity of the gap material");
94 6392 : params.addParam<FunctionName>(
95 : "gap_conductivity_function",
96 : "Thermal conductivity of the gap material as a function. Multiplied by gap_conductivity.");
97 6392 : params.addParam<std::vector<VariableName>>(
98 : "gap_conductivity_function_variable",
99 : "Variable to be used in gap_conductivity_function in place of time");
100 6392 : params.addParam<VariableName>("secondary_gap_offset",
101 : "Offset to gap distance from secondary side");
102 6392 : params.addParam<VariableName>("mapped_primary_gap_offset",
103 : "Offset to gap distance mapped from primary side");
104 6392 : params.addParam<bool>(
105 : "check_boundary_restricted",
106 6392 : 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 3196 : params += GapConductance::actionParameters();
114 3196 : params += GapConductanceConstant::actionParameters();
115 :
116 3196 : params += GeometricSearchInterface::validParams();
117 :
118 6392 : params.addParamNamesToGroup("primary secondary", "Gap surface definition");
119 6392 : params.addParamNamesToGroup(
120 : "tangential_tolerance normal_smoothing_distance normal_smoothing_method",
121 : "Gap edge and edge normal smoothing");
122 6392 : params.addParamNamesToGroup("gap_aux_type secondary_gap_offset mapped_primary_gap_offset",
123 : "Gap size");
124 6392 : params.addParamNamesToGroup("order quadrature", "Integration");
125 6392 : params.addParamNamesToGroup(
126 : "gap_conductivity gap_conductivity_function gap_conductivity_function_variable",
127 : "Gap conductivity");
128 6392 : params.addParamNamesToGroup("save_in check_boundary_restricted warnings",
129 : "Diagnostics and debug");
130 :
131 3196 : return params;
132 3196 : }
133 :
134 3196 : ThermalContactAction::ThermalContactAction(const InputParameters & params)
135 : : Action(params),
136 3196 : _quadrature(getParam<bool>("quadrature")),
137 6392 : _order(getParam<MooseEnum>("order")),
138 3196 : _penetration_var_name(_quadrature ? "qpoint_penetration" : "penetration"),
139 6392 : _gap_value_name("paired_" + getParam<NonlinearVariableName>("variable")),
140 6392 : _gap_conductivity_name("paired_k_" + getParam<NonlinearVariableName>("variable")),
141 9588 : _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary"))
142 : {
143 3196 : if (!params.get<bool>("check_boundary_restricted"))
144 : {
145 38 : if (_quadrature)
146 72 : 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 6444 : if (params.isParamSetByUser("penalty") &&
157 3306 : getParam<std::string>("type") != "GapPerfectConductance")
158 2 : paramError("penalty",
159 : "This parameter should only be set by the user when 'type=GapPerfectConductance'.");
160 3192 : }
161 :
162 : void
163 3156 : ThermalContactAction::act()
164 : {
165 3156 : if (_current_task == "add_aux_kernel")
166 525 : addAuxKernels();
167 2631 : else if (_current_task == "add_aux_variable")
168 527 : addAuxVariables();
169 2104 : else if (_current_task == "add_bc")
170 525 : addBCs();
171 1579 : else if (_current_task == "add_dirac_kernel")
172 525 : addDiracKernels();
173 1054 : else if (_current_task == "add_material")
174 527 : addMaterials();
175 527 : else if (_current_task == "add_secondary_flux_vector")
176 527 : addSecondaryFluxVector();
177 3154 : }
178 :
179 : void
180 525 : ThermalContactAction::addAuxKernels()
181 : {
182 1059 : for (const auto & contact_pair : _boundary_pairs)
183 : {
184 : // Add gap aux kernel
185 : {
186 1068 : InputParameters params = _factory.getValidParams(getParam<std::string>("gap_aux_type"));
187 :
188 534 : 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 534 : params.set<AuxVariableName>("variable") = _gap_value_name;
197 2136 : params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
198 :
199 1602 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
200 534 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
201 1602 : params.set<VariableName>("paired_variable") = getParam<NonlinearVariableName>("variable");
202 :
203 2136 : _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
204 1602 : "gap_value_" + name() + "_" + Moose::stringify(aux_kenels_counter),
205 : params);
206 :
207 534 : if (_quadrature)
208 : {
209 948 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
210 316 : params.set<BoundaryName>("paired_boundary") = contact_pair.second;
211 :
212 1264 : _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
213 948 : "gap_value_primary_" + name() + "_" +
214 632 : Moose::stringify(aux_kenels_counter),
215 : params);
216 : }
217 534 : }
218 :
219 : // Add penetration aux kernel
220 : {
221 534 : InputParameters params = _factory.getValidParams("PenetrationAux");
222 :
223 534 : params.applySpecificParameters(parameters(),
224 : {"tangential_tolerance",
225 : "normal_smoothing_distance",
226 : "normal_smoothing_method",
227 : "order",
228 : "search_method",
229 : "check_boundary_restricted"});
230 534 : params.set<AuxVariableName>("variable") = _penetration_var_name;
231 1068 : if (isParamValid("secondary_gap_offset"))
232 0 : params.set<std::vector<VariableName>>("secondary_gap_offset") = {
233 0 : getParam<VariableName>("secondary_gap_offset")};
234 1068 : 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 2136 : params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
238 1602 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
239 534 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
240 :
241 1602 : _problem->addAuxKernel("PenetrationAux",
242 1602 : "penetration_" + name() + "_" + Moose::stringify(aux_kenels_counter++),
243 : params);
244 534 : }
245 : }
246 1593 : }
247 :
248 : void
249 527 : 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 1054 : auto order = getParam<MooseEnum>("order");
255 527 : std::string family = "LAGRANGE";
256 :
257 527 : if (_quadrature)
258 : {
259 636 : order = "CONSTANT";
260 : family = "MONOMIAL";
261 : }
262 :
263 : auto var_type =
264 527 : AddVariableAction::variableType(FEType(order, Utility::string_to_enum<FEFamily>(family)));
265 527 : auto var_params = _factory.getValidParams(var_type);
266 527 : var_params.set<MooseEnum>("order") = order;
267 527 : var_params.set<MooseEnum>("family") = family;
268 :
269 527 : _problem->addAuxVariable(var_type, _penetration_var_name, var_params);
270 527 : _problem->addAuxVariable(var_type, _gap_value_name, var_params);
271 1054 : }
272 :
273 : void
274 525 : ThermalContactAction::addBCs()
275 : {
276 1059 : for (const auto & contact_pair : _boundary_pairs)
277 : {
278 1068 : const std::string object_name = getParam<std::string>("type");
279 534 : InputParameters params = _factory.getValidParams(object_name);
280 534 : params.applyParameters(parameters());
281 :
282 534 : if (object_name == "GapPerfectConductance")
283 : {
284 18 : params.set<Real>("penalty") = getParam<Real>("penalty");
285 27 : params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
286 27 : params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
287 27 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
288 18 : _problem->addBoundaryCondition(
289 27 : object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
290 : }
291 : else
292 : {
293 525 : if (_quadrature)
294 : {
295 316 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
296 316 : params.set<bool>("use_displaced_mesh") = true;
297 : }
298 : else
299 : {
300 627 : params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
301 627 : params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
302 : }
303 :
304 1575 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
305 :
306 1050 : _problem->addBoundaryCondition(
307 1575 : object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
308 :
309 525 : if (_quadrature)
310 : {
311 : // Swap primary and secondary for this one
312 948 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
313 316 : params.set<BoundaryName>("paired_boundary") = contact_pair.second;
314 :
315 632 : _problem->addBoundaryCondition(
316 948 : object_name, "gap_bc_primary_" + name() + "_" + Moose::stringify(bcs_counter), params);
317 : }
318 : }
319 534 : bcs_counter++;
320 534 : }
321 743 : }
322 :
323 : void
324 525 : ThermalContactAction::addDiracKernels()
325 : {
326 525 : if (_quadrature)
327 : return;
328 :
329 427 : for (const auto & contact_pair : _boundary_pairs)
330 : {
331 218 : const std::string object_name = "GapHeatPointSourceMaster";
332 218 : InputParameters params = _factory.getValidParams(object_name);
333 218 : params.applySpecificParameters(parameters(),
334 : {"tangential_tolerance",
335 : "normal_smoothing_distance",
336 : "normal_smoothing_method",
337 : "order",
338 : "search_method",
339 : "variable"});
340 218 : params.set<BoundaryName>("boundary") = contact_pair.first;
341 218 : params.set<BoundaryName>("secondary") = contact_pair.second;
342 :
343 436 : _problem->addDiracKernel(
344 654 : object_name, object_name + "_" + name() + "_" + Moose::stringify(dirac_counter++), params);
345 218 : }
346 : }
347 :
348 : void
349 527 : ThermalContactAction::addMaterials()
350 : {
351 1054 : if (getParam<std::string>("type") != "GapHeatTransfer")
352 : return;
353 :
354 1036 : if (parameters().isParamSetByUser("gap_conductance"))
355 : {
356 54 : if (parameters().isParamSetByUser("gap_conductivity") ||
357 54 : parameters().isParamSetByUser("gap_conductivity_function"))
358 0 : mooseError(
359 : "Cannot specify both gap_conductance and gap_conductivity or gap_conductivity_function");
360 :
361 63 : for (const auto & contact_pair : _boundary_pairs)
362 : {
363 36 : const std::string object_type = "GapConductanceConstant";
364 36 : InputParameters params = _factory.getValidParams(object_type);
365 36 : params.applyParameters(parameters());
366 108 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
367 72 : _problem->addMaterial(object_type,
368 108 : name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
369 : params);
370 :
371 36 : if (_quadrature)
372 : {
373 27 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
374 18 : _problem->addMaterial(object_type,
375 27 : name() + "_" + "gap_value_primary" + "_" +
376 18 : Moose::stringify(materials_counter),
377 : params);
378 : }
379 36 : materials_counter++;
380 36 : }
381 : }
382 : else
383 : {
384 491 : const std::string object_type = "GapConductance";
385 :
386 980 : for (const auto & contact_pair : _boundary_pairs)
387 : {
388 491 : InputParameters params = _factory.getValidParams(object_type);
389 491 : params.applyParameters(parameters(), {"variable"});
390 :
391 982 : params.set<std::vector<VariableName>>("variable") = {
392 2946 : getParam<NonlinearVariableName>("variable")};
393 1473 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
394 :
395 491 : if (_quadrature)
396 618 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
397 : else
398 : {
399 546 : params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
400 546 : params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
401 : }
402 :
403 982 : _problem->addMaterial(object_type,
404 1471 : name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
405 : params);
406 :
407 489 : if (_quadrature)
408 : {
409 614 : params.set<BoundaryName>("paired_boundary") = contact_pair.second;
410 921 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
411 :
412 614 : _problem->addMaterial(object_type,
413 921 : name() + "_" + "gap_value_primary" + "_" +
414 614 : Moose::stringify(materials_counter),
415 : params);
416 : }
417 489 : materials_counter++;
418 489 : }
419 : }
420 673 : }
421 :
422 : void
423 527 : ThermalContactAction::addSecondaryFluxVector()
424 : {
425 527 : _problem->getNonlinearSystemBase(/*nl_sys_num=*/0)
426 527 : .addVector("secondary_flux", false, libMesh::GHOSTED);
427 527 : _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 527 : if (!_problem->isSNESMFReuseBaseSetbyUser())
434 : _problem->setSNESMFReuseBase(false, false);
435 527 : }
436 :
437 : void
438 9492 : ThermalContactAction::addRelationshipManagers(Moose::RelationshipManagerType input_rm_type)
439 : {
440 9492 : if (!_quadrature)
441 : return;
442 :
443 11460 : for (const auto & contact_pair : _boundary_pairs)
444 : {
445 5730 : const auto & object_name = getParam<std::string>("type");
446 5730 : auto params = _factory.getValidParams(object_name);
447 5730 : params.applyParameters(parameters());
448 :
449 5730 : params.set<BoundaryName>("paired_boundary") = contact_pair.first;
450 5730 : params.set<bool>("use_displaced_mesh") = true;
451 17190 : params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
452 5730 : addRelationshipManagers(input_rm_type, params);
453 5730 : }
454 : }
|