https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MortarGapHeatTransferAction.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
11
12#include "AddVariableAction.h"
13#include "FEProblem.h"
14#include "libmesh/string_to_enum.h"
15#include "NonlinearSystem.h"
16
20
21#include <algorithm>
22
23registerMooseAction("HeatTransferApp", MortarGapHeatTransferAction, "append_mesh_generator");
24registerMooseAction("HeatTransferApp", MortarGapHeatTransferAction, "add_mortar_variable");
25registerMooseAction("HeatTransferApp", MortarGapHeatTransferAction, "add_constraint");
26registerMooseAction("HeatTransferApp", MortarGapHeatTransferAction, "add_user_object");
27
30{
33 "Action that controls the creation of all of the necessary objects for "
34 "calculation of heat transfer through an open/closed gap using a mortar formulation and a "
35 "modular design approach");
36
37 params.addParam<Real>("thermal_lm_scaling",
38 1.,
39 "Scaling factor to apply to the thermal Lagrange multiplier variable");
40
44
45 params.addParam<bool>(
46 "correct_edge_dropping",
47 true,
48 "Whether to enable correct edge dropping treatment for mortar constraints. When disabled "
49 "any Lagrange Multiplier degree of freedom on a secondary element without full primary "
50 "contributions will be set (strongly) to 0.");
51
52 params.makeParamNotRequired<SubdomainName>("primary_subdomain");
53 params.makeParamNotRequired<SubdomainName>("secondary_subdomain");
54 params.makeParamNotRequired<Real>("gap_conductivity");
55
57 "gap_flux_options", MortarGapHeatTransfer::gapFluxPhysics, "The gap flux models to build");
58
59 params.addParam<std::vector<UserObjectName>>(
60 "user_created_gap_flux_models",
61 {},
62 "The name of the user objects created by the user to represent gap heat transfer physics");
63
64 params.addParamNamesToGroup("primary_subdomain secondary_subdomain", "Gap surface definition");
65 params.addParamNamesToGroup("gap_flux_options user_created_gap_flux_models", "Gap flux models");
66 params.addParamNamesToGroup("thermal_lm_scaling correct_edge_dropping",
67 "Thermal Lagrange multiplier");
68
69 return params;
70}
71
73 : Action(params),
74 _user_provided_mortar_meshes(false),
75 _user_provided_gap_flux_models(
76 getParam<std::vector<UserObjectName>>("user_created_gap_flux_models").size() > 0 ? true
77 : false)
78
79{
80 if (getParam<MultiMooseEnum>("gap_flux_options").size() > 0 && _user_provided_gap_flux_models)
82 "gap_flux_options",
83 "Either create user objects for the action in the input file or provide the desire physics "
84 "to the action via the gap_flux_options parameter. Mixed use is not supported");
85
86 for (unsigned int i = 0; i < getParam<MultiMooseEnum>("gap_flux_options").size(); i++)
88 getParam<MultiMooseEnum>("gap_flux_options").get(i)));
89
90 // We do not currently support building more than one condution or more than one radiation user
91 // object from this action.
92 const unsigned int conduction_build_uos =
93 cast_int<unsigned int>(std::count(_gap_flux_models.cbegin(),
94 _gap_flux_models.cend(),
96 const unsigned int radiation_build_uos =
97 cast_int<unsigned int>(std::count(_gap_flux_models.cbegin(),
98 _gap_flux_models.cend(),
100
101 if (conduction_build_uos > 1 || radiation_build_uos > 1)
102 paramError("gap_flux_options",
103 "You cannot choose to have more than one conduction or more than one radiation user "
104 "objects when they are built by the action. If you want to superimpose multiple "
105 "physics, you can choose to create your own user objects and pass them to this "
106 "action via 'user_created_gap_flux_models'");
107
108 if (params.isParamSetByUser("primary_subdomain") &&
109 params.isParamSetByUser("secondary_subdomain"))
110 {
111 mooseInfo("Mortar gap heat transfer action is using the lower-dimensional domains provided by "
112 "the user");
114 }
115 else
116 mooseInfo("Mortar gap heat transfer action is creating new lower-dimensional domains");
117
119 mooseInfo(
120 "User decided to create user objects to model physics for the mortar gap heat transfer "
121 "action independently, i.e. not through the mortar gap heat transfer action.");
122 else
123 mooseInfo("The mortar gap heat transfer action will add gap heat transfer physics according to "
124 "the gap_flux_options input parameter");
125
126 const bool wrong_parameters_provided =
128 (params.isParamSetByUser("gap_conductivity") ||
129 params.isParamSetByUser("primary_emissivity") ||
130 params.isParamSetByUser("secondary_emissivity") ||
131 params.isParamSetByUser("gap_conductivity_function") ||
132 params.isParamSetByUser("gap_conductivity_function_variable") ||
133 params.isParamSetByUser("min_gap"));
134
135 if (wrong_parameters_provided)
137 "user_created_gap_flux_models",
138 "The mortar gap heat transfer action requires that the input file defines user objects "
139 "with physics or adds physics parameters directly into the action. You have provided both "
140 "user objects and physics parameters (e.g. emissivities, gap conductance, etc.).");
141}
142
143void
145{
146 if (_current_task == "append_mesh_generator")
148 else if (_current_task == "add_mortar_variable")
150 if (_current_task == "add_constraint")
152 else if (_current_task == "add_user_object")
155}
156
157void
159{
161 {
162 std::string action_name = MooseUtils::shortName(name());
163
164 const MeshGeneratorName primary_name = action_name + "_primary_subdomain" + "_generator";
165 const MeshGeneratorName secondary_name = action_name + "_secondary_subdomain" + "_generator";
166
167 auto primary_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
168 auto secondary_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
169
170 primary_params.set<SubdomainName>("new_block_name") = action_name + "_primary_subdomain";
171 secondary_params.set<SubdomainName>("new_block_name") = action_name + "_secondary_subdomain";
172
173 primary_params.set<std::vector<BoundaryName>>("sidesets") = {
174 getParam<BoundaryName>("primary_boundary")};
175 secondary_params.set<std::vector<BoundaryName>>("sidesets") = {
176 getParam<BoundaryName>("secondary_boundary")};
177
178 _app.appendMeshGenerator("LowerDBlockFromSidesetGenerator", primary_name, primary_params);
179 _app.appendMeshGenerator("LowerDBlockFromSidesetGenerator", secondary_name, secondary_params);
180 }
181}
182
183void
185{
187 std::string action_name = MooseUtils::shortName(name());
188
189 auto params = MortarConstraintBase::validParams();
190 params.set<bool>("use_displaced_mesh") = getParam<bool>("use_displaced_mesh");
191 params.set<BoundaryName>("primary_boundary") = getParam<BoundaryName>("primary_boundary");
192 params.set<BoundaryName>("secondary_boundary") = getParam<BoundaryName>("secondary_boundary");
193
195 {
196 params.set<SubdomainName>("primary_subdomain") = getParam<SubdomainName>("primary_subdomain");
197 params.set<SubdomainName>("secondary_subdomain") =
198 getParam<SubdomainName>("secondary_subdomain");
199 }
200 else
201 {
202 params.set<SubdomainName>("primary_subdomain") = action_name + "_primary_subdomain";
203 params.set<SubdomainName>("secondary_subdomain") = action_name + "_secondary_subdomain";
204 }
205
206 addRelationshipManagers(input_rm_type, params);
207}
208
209void
211{
213
214 InputParameters params = _factory.getValidParams("MooseVariableBase");
215
216 const std::string & temperature = getParam<std::vector<VariableName>>("temperature")[0];
217 std::string action_name = MooseUtils::shortName(name());
218
219 if (!_problem->hasVariable(temperature))
220 mooseError("Temperature variable is missing");
221
222 const auto primal_type =
223 _problem->getVariable(0, temperature, Moose::VarKindType::VAR_SOLVER).feType();
224 const int lm_order = primal_type.order.get_order();
225
226 if (primal_type.family != LAGRANGE)
227 mooseError("The mortar thermal action can only be used with LAGRANGE finite elements");
228
229 params.set<MooseEnum>("family") = Utility::enum_to_string<FEFamily>(primal_type.family);
230 params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(libMesh::OrderWrapper{lm_order});
231
233 params.set<std::vector<SubdomainName>>("block") = {
234 getParam<SubdomainName>("secondary_subdomain")};
235 else
236 params.set<std::vector<SubdomainName>>("block") = {action_name + "_secondary_subdomain"};
237
238 params.set<std::vector<Real>>("scaling") = {getParam<Real>("thermal_lm_scaling")};
239 auto fe_type = AddVariableAction::feType(params);
240 auto var_type = AddVariableAction::variableType(fe_type);
241
242 _problem->addVariable(var_type, action_name + "_thermal_lm", params);
243}
244
245void
247{
249
250 InputParameters params = _factory.getValidParams("ModularGapConductanceConstraint");
251 const std::string action_name = MooseUtils::shortName(name());
252
253 params.applyParameters(parameters());
254 params.set<bool>("use_displaced_mesh") = true;
255
256 params.set<BoundaryName>("primary_boundary") = getParam<BoundaryName>("primary_boundary");
257 params.set<BoundaryName>("secondary_boundary") = getParam<BoundaryName>("secondary_boundary");
258
260 {
261 params.set<SubdomainName>("primary_subdomain") = getParam<SubdomainName>("primary_subdomain");
262 params.set<SubdomainName>("secondary_subdomain") =
263 getParam<SubdomainName>("secondary_subdomain");
264 }
265 else
266 {
267 params.set<SubdomainName>("primary_subdomain") = action_name + "_primary_subdomain";
268 params.set<SubdomainName>("secondary_subdomain") = action_name + "_secondary_subdomain";
269 }
270
271 params.set<NonlinearVariableName>("variable") = action_name + "_thermal_lm";
272
273 params.set<VariableName>("secondary_variable") =
274 getParam<std::vector<VariableName>>("temperature")[0];
275
277 {
278 std::vector<UserObjectName> uoname_strings(0);
279
280 for (const auto & uo_name : _gap_flux_models)
281 {
283 uoname_strings.push_back("gap_flux_model_conduction_object_" +
286 uoname_strings.push_back("gap_flux_model_radiation_object_" +
288 }
289
290 params.set<std::vector<UserObjectName>>("gap_flux_models") = uoname_strings;
291 }
292 else
293 params.set<std::vector<UserObjectName>>("gap_flux_models") =
294 getParam<std::vector<UserObjectName>>("user_created_gap_flux_models");
295
296 _problem->addConstraint(
297 "ModularGapConductanceConstraint", action_name + "_ModularGapConductanceConstraint", params);
298}
299
300void
302{
303 // Evaluate whether we have sufficient information from the user to skip building the
304 // lower-dimensional domains.
306
307 // We may have available lower-dimensional domains (e.g. from a mechanical contact action), whose
308 // subdomains can be reused for adding mortar variables and constraints.
311}
312
313void
315{
316 // It is risky to apply this optimization to contact problems
317 // since the problem configuration may be changed during Jacobian
318 // evaluation. We therefore turn it off for all contact problems so that
319 // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3 or older.
320 mooseAssert(_problem, "Problem pointer is null");
321
322 if (!_problem->isSNESMFReuseBaseSetbyUser())
323 _problem->setSNESMFReuseBase(false, false);
324
325 for (const auto & uo_name : _gap_flux_models)
326 {
328 {
329 auto var_params = _factory.getValidParams("GapFluxModelConduction");
330
331 var_params.set<std::vector<VariableName>>("temperature") =
332 getParam<std::vector<VariableName>>("temperature");
333 var_params.set<Real>("gap_conductivity") = getParam<Real>("gap_conductivity");
334
335 if (isParamValid("gap_conductivity_function"))
336 var_params.set<FunctionName>("gap_conductivity_function") =
337 getParam<FunctionName>("gap_conductivity_function");
338
339 if (isParamValid("gap_conductivity_function_variable"))
340 var_params.set<std::vector<VariableName>>("gap_conductivity_function_variable") =
341 getParam<std::vector<VariableName>>("gap_conductivity_function_variable");
342
343 var_params.set<Real>("min_gap") = getParam<Real>("min_gap");
344 var_params.set<unsigned int>("min_gap_order") = getParam<unsigned int>("min_gap_order");
345
346 var_params.set<std::vector<BoundaryName>>("boundary") =
347 getParam<std::vector<BoundaryName>>("boundary");
348
349 var_params.set<bool>("use_displaced_mesh") = true;
350
351 _problem->addUserObject("GapFluxModelConduction",
352 "gap_flux_model_conduction_object_" + MooseUtils::shortName(name()),
353 var_params);
354 }
356
357 {
358 auto var_params = _factory.getValidParams("GapFluxModelRadiation");
359
360 var_params.set<Real>("stefan_boltzmann") = getParam<Real>("stefan_boltzmann");
361 var_params.set<Real>("primary_emissivity") = getParam<Real>("primary_emissivity");
362 var_params.set<Real>("secondary_emissivity") = getParam<Real>("secondary_emissivity");
363
364 var_params.set<std::vector<BoundaryName>>("boundary") =
365 getParam<std::vector<BoundaryName>>("boundary");
366
367 var_params.set<std::vector<VariableName>>("temperature") =
368 getParam<std::vector<VariableName>>("temperature");
369
370 var_params.set<bool>("use_displaced_mesh") = true;
371
372 _problem->addUserObject("GapFluxModelRadiation",
373 "gap_flux_model_radiation_object_" + MooseUtils::shortName(name()),
374 var_params);
375 }
376 }
377}
378
379void
381{
382 if (parameters().isParamSetByUser("primary_subdomain") &&
383 parameters().isParamSetByUser("secondary_subdomain"))
384 {
386 }
387 else
389}
registerMooseAction("HeatTransferApp", MortarGapHeatTransferAction, "append_mesh_generator")
static InputParameters validParams()
MooseApp & _app
std::shared_ptr< FEProblemBase > & _problem
const std::string & _current_task
static libMesh::FEType feType(const InputParameters &params)
static std::string variableType(const libMesh::FEType &fe_type, const bool is_fv=false, const bool is_array=false)
InputParameters getValidParams(const std::string &name) const
static InputParameters validParams()
static InputParameters validParams()
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
bool isParamSetByUser(const std::string &name) const
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void makeParamNotRequired(const std::string &name)
T & set(const std::string &name, bool quiet_mode=false)
void applyParameters(const InputParameters &common, const std::vector< std::string > &exclude={}, const bool allow_private=false)
bool isUltimateMaster() const
const MeshGenerator & appendMeshGenerator(const std::string &type, const std::string &name, InputParameters params)
bool isRecovering() const
bool useMasterMesh() const
const InputParameters & parameters() const
const std::string & name() const
void paramError(const std::string &param, Args... args) const
bool isParamSetByUser(const std::string &name) const
void mooseError(Args &&... args) const
const T & getParam(const std::string &name) const
void mooseInfo(Args &&... args) const
bool isParamValid(const std::string &name) const
static InputParameters validParams()
MortarGapHeatTransferAction(const InputParameters &params)
virtual void addRelationshipManagers(Moose::RelationshipManagerType input_rm_type) override
std::vector< MortarGapHeatTransfer::UserObjectToBuild > _gap_flux_models
Factory & _factory
std::string shortName(const std::string &name)
RelationshipManagerType
const MultiMooseEnum gapFluxPhysics("conduction radiation")