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