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 : // MOOSE includes
11 : #include "MaterialOutputAction.h"
12 : #include "FEProblem.h"
13 : #include "FEProblemBase.h"
14 : #include "MooseApp.h"
15 : #include "AddOutputAction.h"
16 : #include "MaterialBase.h"
17 : #include "RankTwoTensor.h"
18 : #include "SymmetricRankTwoTensor.h"
19 : #include "RankFourTensor.h"
20 : #include "SymmetricRankFourTensor.h"
21 : #include "MooseEnum.h"
22 : #include "MooseVariableConstMonomial.h"
23 : #include "FunctorMaterial.h"
24 :
25 : #include "libmesh/utility.h"
26 :
27 : registerMooseAction("MooseApp", MaterialOutputAction, "add_output_aux_variables");
28 : registerMooseAction("MooseApp", MaterialOutputAction, "add_aux_kernel");
29 :
30 : InputParameters
31 67964 : MaterialOutputAction::validParams()
32 : {
33 67964 : InputParameters params = Action::validParams();
34 67964 : params.addClassDescription("Outputs material properties to various Outputs objects, based on the "
35 : "parameters set in each Material");
36 : /// A flag to tell this action whether or not to print the unsupported properties
37 : /// Note: A derived class can set this to false, override materialOutput and output
38 : /// a particular property that is not supported by this class.
39 203892 : params.addPrivateParam("print_unsupported_prop_names", true);
40 135928 : params.addParam<bool>("print_automatic_aux_variable_creation",
41 135928 : true,
42 : "Flag to print list of aux variables created for automatic output by "
43 : "MaterialOutputAction.");
44 67964 : return params;
45 0 : }
46 :
47 67760 : MaterialOutputAction::MaterialOutputAction(const InputParameters & params)
48 : : Action(params),
49 67760 : _block_material_data(nullptr),
50 67760 : _boundary_material_data(nullptr),
51 67760 : _output_warehouse(_app.getOutputWarehouse()),
52 135520 : _output_only_on_timestep_end(_app.parameters().get<bool>("use_legacy_material_output"))
53 : {
54 67760 : }
55 :
56 : void
57 123728 : MaterialOutputAction::act()
58 : {
59 : mooseAssert(_problem,
60 : "FEProblemBase pointer is nullptr, it is needed for auto material property output");
61 :
62 : // Do nothing if the application does not have output
63 371184 : if (!_app.actionWarehouse().hasActions("add_output"))
64 0 : return;
65 :
66 123728 : bool get_names_only = _current_task == "add_output_aux_variables" ? true : false;
67 :
68 : // Set the pointers to the MaterialData objects (Note, these pointers are not available at
69 : // construction)
70 123728 : _block_material_data = &_problem->getMaterialData(Moose::BLOCK_MATERIAL_DATA);
71 123728 : _boundary_material_data = &_problem->getMaterialData(Moose::BOUNDARY_MATERIAL_DATA);
72 :
73 : // A complete list of all MaterialBase objects
74 123728 : const auto & material_ptrs = _problem->getMaterialWarehouse().getObjects();
75 :
76 : // Handle setting of material property output in [Outputs] sub-blocks
77 : // Output objects can enable material property output, the following code examines the parameters
78 : // for each Output object and sets a flag if any Output object has output set and also builds a
79 : // list if the
80 : // properties are limited via the 'show_material_properties' parameters
81 123728 : bool outputs_has_properties = false;
82 123728 : std::set<std::string> output_object_properties;
83 :
84 247456 : const auto & output_actions = _app.actionWarehouse().getActionListByName("add_output");
85 730614 : for (const auto & act : output_actions)
86 : {
87 : // Extract the Output action
88 606886 : AddOutputAction * action = dynamic_cast<AddOutputAction *>(act);
89 606886 : if (!action)
90 127108 : continue;
91 :
92 : // Add the material property names from the output object parameters to the list of properties
93 : // to output
94 479778 : InputParameters & params = action->getObjectParams();
95 1994790 : if (params.isParamValid("output_material_properties") &&
96 555456 : params.get<bool>("output_material_properties"))
97 : {
98 134 : outputs_has_properties = true;
99 : std::vector<std::string> prop_names =
100 134 : params.get<std::vector<std::string>>("show_material_properties");
101 134 : output_object_properties.insert(prop_names.begin(), prop_names.end());
102 134 : }
103 : }
104 :
105 : // Loop through each material object
106 123728 : std::set<std::string> material_names;
107 123728 : std::set<std::string> unsupported_names;
108 152612 : for (const auto & mat : material_ptrs)
109 : {
110 : // Extract the names of the output objects to which the material properties will be exported
111 28888 : std::set<OutputName> outputs = mat->getOutputs();
112 :
113 : // Extract the property names that will actually be output
114 : std::vector<std::string> output_properties =
115 57776 : mat->getParam<std::vector<std::string>>("output_properties");
116 :
117 : // Append the properties listed in the Outputs block
118 28888 : if (outputs_has_properties)
119 160 : output_properties.insert(output_properties.end(),
120 : output_object_properties.begin(),
121 : output_object_properties.end());
122 :
123 : // Clear the list of variable names for the current material object, this list will be populated
124 : // with all the
125 : // variables names for the current material object and is needed for purposes of controlling the
126 : // which output objects
127 : // show the material property data
128 28888 : _material_variable_names.clear();
129 :
130 : // Create necessary outputs for the properties if:
131 : // (1) The Outputs block has material output enabled
132 : // (2) If the MaterialBase object itself has set the 'outputs' parameter
133 28888 : if (outputs_has_properties || outputs.find("none") == outputs.end())
134 : {
135 : // Get all material properties supplied by this material as a starting point
136 4528 : std::set<std::string> names = mat->getSuppliedItems();
137 4528 : if (const auto fmat_ptr = dynamic_cast<const FunctorMaterial *>(mat.get()))
138 104 : names.insert(fmat_ptr->getSuppliedFunctors().begin(),
139 104 : fmat_ptr->getSuppliedFunctors().end());
140 :
141 17998 : for (const auto & name : names)
142 : {
143 : // Output the property only if the name is contained in the 'output_properties'
144 : // list or if the list is empty (all properties)
145 18360 : if (output_properties.empty() ||
146 4890 : std::find(output_properties.begin(), output_properties.end(), name) !=
147 18360 : output_properties.end())
148 : {
149 : // Add the material property for output
150 10508 : auto curr_material_names = materialOutput(name, *mat, get_names_only);
151 10508 : if (curr_material_names.size() == 0)
152 60 : unsupported_names.insert(name);
153 10508 : material_names.insert(curr_material_names.begin(), curr_material_names.end());
154 10508 : }
155 : }
156 : // If the material object has explicitly defined outputs, store the variables associated with
157 : // the output objects
158 4528 : if (outputs.find("none") == outputs.end())
159 : {
160 : // Get all available output names from OutputWarehouse that support material output
161 4368 : const auto & all_output_names = _output_warehouse.getAllMaterialPropertyOutputNames();
162 :
163 : // For reserved name "all", set outputs to match all available output names
164 4368 : if (outputs.find("all") != outputs.end())
165 1988 : outputs = all_output_names;
166 :
167 : // Iterate through all available output names and update _material_variable_names_map
168 : // based on which of these output names are found in 'outputs' parameter
169 8660 : for (const auto & output_name : all_output_names)
170 : {
171 4292 : if (outputs.find(output_name) != outputs.end())
172 2977 : _material_variable_names_map[output_name].insert(_material_variable_names.begin(),
173 : _material_variable_names.end());
174 : else
175 1315 : _material_variable_names_map[output_name].insert({});
176 : }
177 4368 : }
178 4528 : }
179 24360 : else if (output_properties.size())
180 82 : mooseWarning("Material properties output specified is not created because 'outputs' is not "
181 : "set in the Material, and neither is Outputs/output_material_properties");
182 28884 : }
183 123754 : if (unsupported_names.size() > 0 && get_names_only &&
184 123814 : getParam<bool>("print_unsupported_prop_names"))
185 : {
186 30 : std::ostringstream oss;
187 60 : for (const auto & name : unsupported_names)
188 30 : oss << "\n " << name;
189 60 : mooseWarning("The types for total ",
190 30 : unsupported_names.size(),
191 : " material properties:",
192 60 : oss.str(),
193 : "\nare not supported for automatic output by ",
194 30 : type(),
195 : ".");
196 30 : }
197 :
198 123724 : if (_current_task == "add_output_aux_variables")
199 : {
200 186042 : auto params = _factory.getValidParams("MooseVariableConstMonomial");
201 : // currently only elemental variables are supported for material property output
202 248056 : params.set<MooseEnum>("order") = "CONSTANT";
203 186042 : params.set<MooseEnum>("family") = "MONOMIAL";
204 :
205 : // Create the AuxVariables
206 62014 : std::ostringstream oss;
207 90521 : for (const auto & var_name : material_names)
208 : {
209 28511 : oss << "\n " << var_name;
210 28511 : if (_problem->hasVariable(var_name))
211 4 : mooseError("The material property output " + var_name +
212 : " has the same name as an existing variable, either use the material"
213 : " declare_suffix parameter to disambiguate or the output_properties parameter"
214 : " to restrict the material properties to output");
215 85521 : _problem->addAuxVariable("MooseVariableConstMonomial", var_name, params);
216 : }
217 :
218 64814 : if (material_names.size() > 0 && getParam<bool>("print_automatic_aux_variable_creation"))
219 1392 : _console << COLOR_CYAN << "The following total " << material_names.size()
220 2784 : << " aux variables:" << oss.str() << "\nare added for automatic output by " << type()
221 1392 : << "." << COLOR_DEFAULT << std::endl;
222 62010 : }
223 : else
224 : {
225 : // When a MaterialBase object has 'output_properties' defined all other properties not listed
226 : // must be added to the hide list for the output objects so that properties that are not desired
227 : // do not appear.
228 64356 : for (const auto & it : _material_variable_names_map)
229 : {
230 2646 : std::set<std::string> hide;
231 2646 : std::set_difference(material_names.begin(),
232 : material_names.end(),
233 : it.second.begin(),
234 : it.second.end(),
235 : std::inserter(hide, hide.begin()));
236 :
237 2646 : _output_warehouse.addInterfaceHideVariables(it.first, hide);
238 2646 : }
239 : }
240 123720 : }
241 :
242 : std::vector<std::string>
243 10508 : MaterialOutputAction::materialOutput(const std::string & property_name,
244 : const MaterialBase & material,
245 : bool get_names_only)
246 : {
247 10508 : std::vector<std::string> names;
248 :
249 : // Material Properties
250 10508 : if (hasProperty<Real>(property_name))
251 10452 : names = outputHelper(
252 5226 : {"MaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
253 :
254 5282 : else if (hasADProperty<Real>(property_name))
255 4636 : names = outputHelper(
256 2318 : {"ADMaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
257 :
258 2964 : else if (hasProperty<RealVectorValue>(property_name))
259 686 : names = outputHelper({"MaterialRealVectorValueAux", "xyz", {"component"}},
260 : property_name,
261 1372 : property_name + "_",
262 : material,
263 686 : get_names_only);
264 :
265 2278 : else if (hasADProperty<RealVectorValue>(property_name))
266 208 : names = outputHelper({"ADMaterialRealVectorValueAux", "xyz", {"component"}},
267 : property_name,
268 416 : property_name + "_",
269 : material,
270 208 : get_names_only);
271 :
272 2070 : else if (hasProperty<RealTensorValue>(property_name))
273 452 : names = outputHelper({"MaterialRealTensorValueAux", "012", {"row", "column"}},
274 : property_name,
275 904 : property_name + "_",
276 : material,
277 452 : get_names_only);
278 :
279 1618 : else if (hasADProperty<RealTensorValue>(property_name))
280 26 : names = outputHelper({"ADMaterialRealTensorValueAux", "012", {"row", "column"}},
281 : property_name,
282 52 : property_name + "_",
283 : material,
284 26 : get_names_only);
285 :
286 1592 : else if (hasProperty<RankTwoTensor>(property_name))
287 344 : names = outputHelper({"MaterialRankTwoTensorAux", "012", {"i", "j"}},
288 : property_name,
289 688 : property_name + "_",
290 : material,
291 344 : get_names_only);
292 :
293 1248 : else if (hasADProperty<RankTwoTensor>(property_name))
294 78 : names = outputHelper({"ADMaterialRankTwoTensorAux", "012", {"i", "j"}},
295 : property_name,
296 156 : property_name + "_",
297 : material,
298 78 : get_names_only);
299 :
300 1170 : else if (hasProperty<RankFourTensor>(property_name))
301 292 : names = outputHelper({"MaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
302 : property_name,
303 584 : property_name + "_",
304 : material,
305 292 : get_names_only);
306 :
307 878 : else if (hasADProperty<RankFourTensor>(property_name))
308 26 : names = outputHelper({"ADMaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
309 : property_name,
310 52 : property_name + "_",
311 : material,
312 26 : get_names_only);
313 :
314 852 : else if (hasProperty<SymmetricRankTwoTensor>(property_name))
315 318 : names = outputHelper({"MaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
316 : property_name,
317 636 : property_name + "_",
318 : material,
319 318 : get_names_only);
320 :
321 534 : else if (hasADProperty<SymmetricRankTwoTensor>(property_name))
322 52 : names = outputHelper({"ADMaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
323 : property_name,
324 104 : property_name + "_",
325 : material,
326 52 : get_names_only);
327 :
328 482 : else if (hasProperty<SymmetricRankFourTensor>(property_name))
329 292 : names = outputHelper({"MaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
330 : property_name,
331 584 : property_name + "_",
332 : material,
333 292 : get_names_only);
334 :
335 190 : else if (hasADProperty<SymmetricRankFourTensor>(property_name))
336 26 : names = outputHelper({"ADMaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
337 : property_name,
338 52 : property_name + "_",
339 : material,
340 26 : get_names_only);
341 :
342 : // Functors
343 164 : else if (hasFunctorProperty<Real>(property_name))
344 52 : names = outputHelper({"FunctorMaterialRealAux", "", {}},
345 : property_name,
346 104 : property_name + "_out",
347 : material,
348 52 : get_names_only);
349 :
350 112 : else if (hasFunctorProperty<ADReal>(property_name))
351 0 : names = outputHelper({"ADFunctorMaterialRealAux", "", {}},
352 : property_name,
353 0 : property_name + "_out",
354 : material,
355 0 : get_names_only);
356 :
357 112 : else if (hasFunctorProperty<RealVectorValue>(property_name))
358 52 : names = outputHelper({"FunctorMaterialRealVectorValueAux", "xyz", {"component"}},
359 : property_name,
360 104 : property_name + "_out_",
361 : material,
362 52 : get_names_only);
363 :
364 60 : else if (hasFunctorProperty<ADRealVectorValue>(property_name))
365 0 : names = outputHelper({"ADFunctorMaterialRealVectorValueAux", "xyz", {"component"}},
366 : property_name,
367 0 : property_name + "_out_",
368 : material,
369 0 : get_names_only);
370 :
371 10508 : return names;
372 34196 : }
373 :
374 : std::vector<std::string>
375 10448 : MaterialOutputAction::outputHelper(const MaterialOutputAction::OutputMetaData & metadata,
376 : const std::string & property_name,
377 : const std::string & var_name_base,
378 : const MaterialBase & material,
379 : bool get_names_only)
380 : {
381 10448 : const auto & [kernel_name, index_symbols, param_names] = metadata;
382 10448 : const auto dim = param_names.size();
383 10448 : const auto size = index_symbols.size();
384 :
385 10448 : std::vector<std::string> names;
386 : // general 0 to 4 dimensional loop
387 : std::array<std::size_t, 4> i;
388 21532 : for (i[3] = 0; i[3] < (dim < 4 ? 1 : size); ++i[3])
389 24076 : for (i[2] = 0; i[2] < (dim < 3 ? 1 : size); ++i[2])
390 35098 : for (i[1] = 0; i[1] < (dim < 2 ? 1 : size); ++i[1])
391 80066 : for (i[0] = 0; i[0] < (dim < 1 ? 1 : size); ++i[0])
392 : {
393 57960 : std::string var_name = var_name_base;
394 205146 : for (const auto j : make_range(dim))
395 147186 : var_name += Moose::stringify(index_symbols[i[j]]);
396 57960 : names.push_back(var_name);
397 :
398 57960 : if (!get_names_only)
399 : {
400 28954 : auto params = getParams(kernel_name, property_name, var_name, material);
401 102505 : for (const auto j : make_range(dim))
402 73551 : params.template set<unsigned int>(param_names[j]) = i[j];
403 28954 : _problem->addAuxKernel(kernel_name, material.name() + var_name, params);
404 28954 : }
405 57960 : }
406 20896 : return names;
407 0 : }
408 :
409 : InputParameters
410 28954 : MaterialOutputAction::getParams(const std::string & type,
411 : const std::string & property_name,
412 : const std::string & variable_name,
413 : const MaterialBase & material)
414 : {
415 : // Append the list of output variables for the current material
416 28954 : _material_variable_names.insert(variable_name);
417 :
418 : // Set the action parameters
419 28954 : InputParameters params = _factory.getValidParams(type);
420 28954 : if (params.have_parameter<MaterialPropertyName>("property"))
421 86550 : params.set<MaterialPropertyName>("property") = property_name;
422 104 : else if (params.have_parameter<MooseFunctorName>("functor"))
423 312 : params.set<MooseFunctorName>("functor") = property_name;
424 : else
425 0 : mooseError("Internal error. AuxKernel has neither a `functor` nor a `property` parameter.");
426 :
427 86862 : params.set<AuxVariableName>("variable") = variable_name;
428 28954 : if (_output_only_on_timestep_end)
429 0 : params.set<ExecFlagEnum>("execute_on") = EXEC_TIMESTEP_END;
430 : else
431 115816 : params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_TIMESTEP_END};
432 :
433 28954 : if (material.boundaryRestricted())
434 543 : params.set<std::vector<BoundaryName>>("boundary") = material.boundaryNames();
435 : else
436 86319 : params.set<std::vector<SubdomainName>>("block") = material.blocks();
437 :
438 28954 : return params;
439 28954 : }
|