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 67073 : MaterialOutputAction::validParams()
32 : {
33 67073 : InputParameters params = Action::validParams();
34 67073 : 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 67073 : params.addPrivateParam("print_unsupported_prop_names", true);
40 201219 : params.addParam<bool>("print_automatic_aux_variable_creation",
41 134146 : true,
42 : "Flag to print list of aux variables created for automatic output by "
43 : "MaterialOutputAction.");
44 67073 : return params;
45 0 : }
46 :
47 66869 : MaterialOutputAction::MaterialOutputAction(const InputParameters & params)
48 : : Action(params),
49 66869 : _block_material_data(nullptr),
50 66869 : _boundary_material_data(nullptr),
51 66869 : _output_warehouse(_app.getOutputWarehouse()),
52 133738 : _output_only_on_timestep_end(_app.parameters().get<bool>("use_legacy_material_output"))
53 : {
54 66869 : }
55 :
56 : void
57 122266 : 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 122266 : if (!_app.actionWarehouse().hasActions("add_output"))
64 0 : return;
65 :
66 122266 : 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 122266 : _block_material_data = &_problem->getMaterialData(Moose::BLOCK_MATERIAL_DATA);
71 122266 : _boundary_material_data = &_problem->getMaterialData(Moose::BOUNDARY_MATERIAL_DATA);
72 :
73 : // A complete list of all MaterialBase objects
74 122266 : 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 122266 : bool outputs_has_properties = false;
82 122266 : std::set<std::string> output_object_properties;
83 :
84 122266 : const auto & output_actions = _app.actionWarehouse().getActionListByName("add_output");
85 721888 : for (const auto & act : output_actions)
86 : {
87 : // Extract the Output action
88 599622 : AddOutputAction * action = dynamic_cast<AddOutputAction *>(act);
89 599622 : if (!action)
90 125646 : continue;
91 :
92 : // Add the material property names from the output object parameters to the list of properties
93 : // to output
94 473976 : InputParameters & params = action->getObjectParams();
95 1022892 : if (params.isParamValid("output_material_properties") &&
96 548916 : 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 122266 : std::set<std::string> material_names;
107 122266 : std::set<std::string> unsupported_names;
108 150152 : for (const auto & mat : material_ptrs)
109 : {
110 : // Extract the names of the output objects to which the material properties will be exported
111 27890 : 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 27890 : mat->getParam<std::vector<std::string>>("output_properties");
116 :
117 : // Append the properties listed in the Outputs block
118 27890 : 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 27890 : _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 27890 : if (outputs_has_properties || outputs.find("none") == outputs.end())
134 : {
135 : // Get all material properties supplied by this material as a starting point
136 4520 : std::set<std::string> names = mat->getSuppliedItems();
137 4520 : 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 17982 : 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 18352 : if (output_properties.empty() ||
146 4890 : std::find(output_properties.begin(), output_properties.end(), name) !=
147 18352 : output_properties.end())
148 : {
149 : // Add the material property for output
150 10500 : auto curr_material_names = materialOutput(name, *mat, get_names_only);
151 10500 : if (curr_material_names.size() == 0)
152 60 : unsupported_names.insert(name);
153 10500 : material_names.insert(curr_material_names.begin(), curr_material_names.end());
154 10500 : }
155 : }
156 : // If the material object has explicitly defined outputs, store the variables associated with
157 : // the output objects
158 4520 : if (outputs.find("none") == outputs.end())
159 : {
160 : // Get all available output names from OutputWarehouse that support material output
161 4360 : const auto & all_output_names = _output_warehouse.getAllMaterialPropertyOutputNames();
162 :
163 : // For reserved name "all", set outputs to match all available output names
164 4360 : 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 8644 : for (const auto & output_name : all_output_names)
170 : {
171 4284 : if (outputs.find(output_name) != outputs.end())
172 2973 : _material_variable_names_map[output_name].insert(_material_variable_names.begin(),
173 : _material_variable_names.end());
174 : else
175 1311 : _material_variable_names_map[output_name].insert({});
176 : }
177 4360 : }
178 4520 : }
179 23370 : 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 27886 : }
183 122292 : if (unsupported_names.size() > 0 && get_names_only &&
184 122292 : 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 122262 : if (_current_task == "add_output_aux_variables")
199 : {
200 61281 : auto params = _factory.getValidParams("MooseVariableConstMonomial");
201 : // currently only elemental variables are supported for material property output
202 61281 : params.set<MooseEnum>("order") = "CONSTANT";
203 61281 : params.set<MooseEnum>("family") = "MONOMIAL";
204 :
205 : // Create the AuxVariables
206 61281 : std::ostringstream oss;
207 89784 : for (const auto & var_name : material_names)
208 : {
209 28507 : oss << "\n " << var_name;
210 28507 : 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 28503 : _problem->addAuxVariable("MooseVariableConstMonomial", var_name, params);
216 : }
217 :
218 61277 : if (material_names.size() > 0 && getParam<bool>("print_automatic_aux_variable_creation"))
219 1388 : _console << COLOR_CYAN << "The following total " << material_names.size()
220 2776 : << " aux variables:" << oss.str() << "\nare added for automatic output by " << type()
221 1388 : << "." << COLOR_DEFAULT << std::endl;
222 61277 : }
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 63619 : for (const auto & it : _material_variable_names_map)
229 : {
230 2638 : std::set<std::string> hide;
231 2638 : 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 2638 : _output_warehouse.addInterfaceHideVariables(it.first, hide);
238 2638 : }
239 : }
240 122258 : }
241 :
242 : std::vector<std::string>
243 10500 : MaterialOutputAction::materialOutput(const std::string & property_name,
244 : const MaterialBase & material,
245 : bool get_names_only)
246 : {
247 10500 : std::vector<std::string> names;
248 :
249 : // Material Properties
250 10500 : if (hasProperty<Real>(property_name))
251 5218 : names = outputHelper(
252 5218 : {"MaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
253 :
254 5282 : else if (hasADProperty<Real>(property_name))
255 2318 : names = outputHelper(
256 2318 : {"ADMaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
257 :
258 2964 : else if (hasProperty<RealVectorValue>(property_name))
259 1372 : 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 416 : 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 1356 : 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 78 : 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 1032 : 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 234 : 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 1460 : 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 130 : 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 636 : 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 104 : 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 876 : 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 78 : 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 104 : 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 10500 : return names;
372 25904 : }
373 :
374 : std::vector<std::string>
375 10440 : 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 10440 : const auto & [kernel_name, index_symbols, param_names] = metadata;
382 10440 : const auto dim = param_names.size();
383 10440 : const auto size = index_symbols.size();
384 :
385 10440 : std::vector<std::string> names;
386 : // general 0 to 4 dimensional loop
387 : std::array<std::size_t, 4> i;
388 21516 : for (i[3] = 0; i[3] < (dim < 4 ? 1 : size); ++i[3])
389 24060 : for (i[2] = 0; i[2] < (dim < 3 ? 1 : size); ++i[2])
390 35082 : for (i[1] = 0; i[1] < (dim < 2 ? 1 : size); ++i[1])
391 80050 : for (i[0] = 0; i[0] < (dim < 1 ? 1 : size); ++i[0])
392 : {
393 57952 : std::string var_name = var_name_base;
394 205138 : for (const auto j : make_range(dim))
395 147186 : var_name += Moose::stringify(index_symbols[i[j]]);
396 57952 : names.push_back(var_name);
397 :
398 57952 : if (!get_names_only)
399 : {
400 28950 : auto params = getParams(kernel_name, property_name, var_name, material);
401 102501 : for (const auto j : make_range(dim))
402 73551 : params.template set<unsigned int>(param_names[j]) = i[j];
403 28950 : _problem->addAuxKernel(kernel_name, material.name() + var_name, params);
404 28950 : }
405 57952 : }
406 20880 : return names;
407 0 : }
408 :
409 : InputParameters
410 28950 : 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 28950 : _material_variable_names.insert(variable_name);
417 :
418 : // Set the action parameters
419 28950 : InputParameters params = _factory.getValidParams(type);
420 28950 : if (params.have_parameter<MaterialPropertyName>("property"))
421 28846 : params.set<MaterialPropertyName>("property") = property_name;
422 104 : else if (params.have_parameter<MooseFunctorName>("functor"))
423 104 : params.set<MooseFunctorName>("functor") = property_name;
424 : else
425 0 : mooseError("Internal error. AuxKernel has neither a `functor` nor a `property` parameter.");
426 :
427 28950 : params.set<AuxVariableName>("variable") = variable_name;
428 28950 : if (_output_only_on_timestep_end)
429 0 : params.set<ExecFlagEnum>("execute_on") = EXEC_TIMESTEP_END;
430 : else
431 86850 : params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_TIMESTEP_END};
432 :
433 28950 : if (material.boundaryRestricted())
434 181 : params.set<std::vector<BoundaryName>>("boundary") = material.boundaryNames();
435 : else
436 28769 : params.set<std::vector<SubdomainName>>("block") = material.blocks();
437 :
438 28950 : return params;
439 28950 : }
|