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 62220 : MaterialOutputAction::validParams()
32 : {
33 62220 : InputParameters params = Action::validParams();
34 62220 : 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 62220 : params.addPrivateParam("print_unsupported_prop_names", true);
40 186660 : params.addParam<bool>("print_automatic_aux_variable_creation",
41 124440 : true,
42 : "Flag to print list of aux variables created for automatic output by "
43 : "MaterialOutputAction.");
44 62220 : return params;
45 0 : }
46 :
47 62016 : MaterialOutputAction::MaterialOutputAction(const InputParameters & params)
48 : : Action(params),
49 62016 : _block_material_data(nullptr),
50 62016 : _boundary_material_data(nullptr),
51 62016 : _output_warehouse(_app.getOutputWarehouse()),
52 124032 : _output_only_on_timestep_end(_app.parameters().get<bool>("use_legacy_material_output"))
53 : {
54 62016 : }
55 :
56 : void
57 113230 : 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 113230 : if (!_app.actionWarehouse().hasActions("add_output"))
64 0 : return;
65 :
66 113230 : 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 113230 : _block_material_data = &_problem->getMaterialData(Moose::BLOCK_MATERIAL_DATA);
71 113230 : _boundary_material_data = &_problem->getMaterialData(Moose::BOUNDARY_MATERIAL_DATA);
72 :
73 : // A complete list of all MaterialBase objects
74 113230 : 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 113230 : bool outputs_has_properties = false;
82 113230 : std::set<std::string> output_object_properties;
83 :
84 113230 : const auto & output_actions = _app.actionWarehouse().getActionListByName("add_output");
85 668312 : for (const auto & act : output_actions)
86 : {
87 : // Extract the Output action
88 555082 : AddOutputAction * action = dynamic_cast<AddOutputAction *>(act);
89 555082 : if (!action)
90 116436 : continue;
91 :
92 : // Add the material property names from the output object parameters to the list of properties
93 : // to output
94 438646 : InputParameters & params = action->getObjectParams();
95 946626 : if (params.isParamValid("output_material_properties") &&
96 507980 : params.get<bool>("output_material_properties"))
97 : {
98 124 : outputs_has_properties = true;
99 : std::vector<std::string> prop_names =
100 124 : params.get<std::vector<std::string>>("show_material_properties");
101 124 : output_object_properties.insert(prop_names.begin(), prop_names.end());
102 124 : }
103 : }
104 :
105 : // Loop through each material object
106 113230 : std::set<std::string> material_names;
107 113230 : std::set<std::string> unsupported_names;
108 139112 : for (const auto & mat : material_ptrs)
109 : {
110 : // Extract the names of the output objects to which the material properties will be exported
111 25886 : 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 25886 : mat->getParam<std::vector<std::string>>("output_properties");
116 :
117 : // Append the properties listed in the Outputs block
118 25886 : if (outputs_has_properties)
119 148 : 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 25886 : _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 25886 : if (outputs_has_properties || outputs.find("none") == outputs.end())
134 : {
135 : // Get all material properties supplied by this material as a starting point
136 4186 : std::set<std::string> names = mat->getSuppliedItems();
137 4186 : if (const auto fmat_ptr = dynamic_cast<const FunctorMaterial *>(mat.get()))
138 96 : names.insert(fmat_ptr->getSuppliedFunctors().begin(),
139 96 : fmat_ptr->getSuppliedFunctors().end());
140 :
141 16646 : 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 16968 : if (output_properties.empty() ||
146 4508 : std::find(output_properties.begin(), output_properties.end(), name) !=
147 16968 : output_properties.end())
148 : {
149 : // Add the material property for output
150 9728 : auto curr_material_names = materialOutput(name, *mat, get_names_only);
151 9728 : if (curr_material_names.size() == 0)
152 60 : unsupported_names.insert(name);
153 9728 : material_names.insert(curr_material_names.begin(), curr_material_names.end());
154 9728 : }
155 : }
156 : // If the material object has explicitly defined outputs, store the variables associated with
157 : // the output objects
158 4186 : if (outputs.find("none") == outputs.end())
159 : {
160 : // Get all available output names from OutputWarehouse that support material output
161 4038 : const auto & all_output_names = _output_warehouse.getAllMaterialPropertyOutputNames();
162 :
163 : // For reserved name "all", set outputs to match all available output names
164 4038 : if (outputs.find("all") != outputs.end())
165 1828 : 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 7998 : for (const auto & output_name : all_output_names)
170 : {
171 3960 : if (outputs.find(output_name) != outputs.end())
172 2739 : _material_variable_names_map[output_name].insert(_material_variable_names.begin(),
173 : _material_variable_names.end());
174 : else
175 1221 : _material_variable_names_map[output_name].insert({});
176 : }
177 4038 : }
178 4186 : }
179 21700 : else if (output_properties.size())
180 76 : 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 25882 : }
183 113256 : if (unsupported_names.size() > 0 && get_names_only &&
184 113256 : 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 113226 : if (_current_task == "add_output_aux_variables")
199 : {
200 56761 : auto params = _factory.getValidParams("MooseVariableConstMonomial");
201 : // currently only elemental variables are supported for material property output
202 56761 : params.set<MooseEnum>("order") = "CONSTANT";
203 56761 : params.set<MooseEnum>("family") = "MONOMIAL";
204 :
205 : // Create the AuxVariables
206 56761 : std::ostringstream oss;
207 83529 : for (const auto & var_name : material_names)
208 : {
209 26772 : oss << "\n " << var_name;
210 26772 : 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 26768 : _problem->addAuxVariable("MooseVariableConstMonomial", var_name, params);
216 : }
217 :
218 56757 : if (material_names.size() > 0 && getParam<bool>("print_automatic_aux_variable_creation"))
219 1285 : _console << COLOR_CYAN << "The following total " << material_names.size()
220 2570 : << " aux variables:" << oss.str() << "\nare added for automatic output by " << type()
221 1285 : << "." << COLOR_DEFAULT << std::endl;
222 56757 : }
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 58903 : for (const auto & it : _material_variable_names_map)
229 : {
230 2438 : std::set<std::string> hide;
231 2438 : 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 2438 : _output_warehouse.addInterfaceHideVariables(it.first, hide);
238 2438 : }
239 : }
240 113222 : }
241 :
242 : std::vector<std::string>
243 9728 : MaterialOutputAction::materialOutput(const std::string & property_name,
244 : const MaterialBase & material,
245 : bool get_names_only)
246 : {
247 9728 : std::vector<std::string> names;
248 :
249 : // Material Properties
250 9728 : if (hasProperty<Real>(property_name))
251 4820 : names = outputHelper(
252 4820 : {"MaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
253 :
254 4908 : else if (hasADProperty<Real>(property_name))
255 2128 : names = outputHelper(
256 2128 : {"ADMaterialRealAux", "", {}}, property_name, property_name, material, get_names_only);
257 :
258 2780 : else if (hasProperty<RealVectorValue>(property_name))
259 1280 : names = outputHelper({"MaterialRealVectorValueAux", "xyz", {"component"}},
260 : property_name,
261 1280 : property_name + "_",
262 : material,
263 640 : get_names_only);
264 :
265 2140 : else if (hasADProperty<RealVectorValue>(property_name))
266 384 : names = outputHelper({"ADMaterialRealVectorValueAux", "xyz", {"component"}},
267 : property_name,
268 384 : property_name + "_",
269 : material,
270 192 : get_names_only);
271 :
272 1948 : else if (hasProperty<RealTensorValue>(property_name))
273 1272 : names = outputHelper({"MaterialRealTensorValueAux", "012", {"row", "column"}},
274 : property_name,
275 848 : property_name + "_",
276 : material,
277 424 : get_names_only);
278 :
279 1524 : else if (hasADProperty<RealTensorValue>(property_name))
280 72 : names = outputHelper({"ADMaterialRealTensorValueAux", "012", {"row", "column"}},
281 : property_name,
282 48 : property_name + "_",
283 : material,
284 24 : get_names_only);
285 :
286 1500 : else if (hasProperty<RankTwoTensor>(property_name))
287 972 : names = outputHelper({"MaterialRankTwoTensorAux", "012", {"i", "j"}},
288 : property_name,
289 648 : property_name + "_",
290 : material,
291 324 : get_names_only);
292 :
293 1176 : else if (hasADProperty<RankTwoTensor>(property_name))
294 216 : names = outputHelper({"ADMaterialRankTwoTensorAux", "012", {"i", "j"}},
295 : property_name,
296 144 : property_name + "_",
297 : material,
298 72 : get_names_only);
299 :
300 1104 : else if (hasProperty<RankFourTensor>(property_name))
301 1380 : names = outputHelper({"MaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
302 : property_name,
303 552 : property_name + "_",
304 : material,
305 276 : get_names_only);
306 :
307 828 : else if (hasADProperty<RankFourTensor>(property_name))
308 120 : names = outputHelper({"ADMaterialRankFourTensorAux", "012", {"i", "j", "k", "l"}},
309 : property_name,
310 48 : property_name + "_",
311 : material,
312 24 : get_names_only);
313 :
314 804 : else if (hasProperty<SymmetricRankTwoTensor>(property_name))
315 600 : names = outputHelper({"MaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
316 : property_name,
317 600 : property_name + "_",
318 : material,
319 300 : get_names_only);
320 :
321 504 : else if (hasADProperty<SymmetricRankTwoTensor>(property_name))
322 96 : names = outputHelper({"ADMaterialSymmetricRankTwoTensorAux", "012345", {"component"}},
323 : property_name,
324 96 : property_name + "_",
325 : material,
326 48 : get_names_only);
327 :
328 456 : else if (hasProperty<SymmetricRankFourTensor>(property_name))
329 828 : names = outputHelper({"MaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
330 : property_name,
331 552 : property_name + "_",
332 : material,
333 276 : get_names_only);
334 :
335 180 : else if (hasADProperty<SymmetricRankFourTensor>(property_name))
336 72 : names = outputHelper({"ADMaterialSymmetricRankFourTensorAux", "012345", {"i", "j"}},
337 : property_name,
338 48 : property_name + "_",
339 : material,
340 24 : get_names_only);
341 :
342 : // Functors
343 156 : else if (hasFunctorProperty<Real>(property_name))
344 48 : names = outputHelper({"FunctorMaterialRealAux", "", {}},
345 : property_name,
346 96 : property_name + "_out",
347 : material,
348 48 : get_names_only);
349 :
350 108 : 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 108 : else if (hasFunctorProperty<RealVectorValue>(property_name))
358 96 : names = outputHelper({"FunctorMaterialRealVectorValueAux", "xyz", {"component"}},
359 : property_name,
360 96 : property_name + "_out_",
361 : material,
362 48 : 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 9728 : return names;
372 24052 : }
373 :
374 : std::vector<std::string>
375 9668 : 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 9668 : const auto & [kernel_name, index_symbols, param_names] = metadata;
382 9668 : const auto dim = param_names.size();
383 9668 : const auto size = index_symbols.size();
384 :
385 9668 : std::vector<std::string> names;
386 : // general 0 to 4 dimensional loop
387 : std::array<std::size_t, 4> i;
388 19936 : for (i[3] = 0; i[3] < (dim < 4 ? 1 : size); ++i[3])
389 22336 : for (i[2] = 0; i[2] < (dim < 3 ? 1 : size); ++i[2])
390 32724 : for (i[1] = 0; i[1] < (dim < 2 ? 1 : size); ++i[1])
391 75076 : for (i[0] = 0; i[0] < (dim < 1 ? 1 : size); ++i[0])
392 : {
393 54420 : std::string var_name = var_name_base;
394 193140 : for (const auto j : make_range(dim))
395 138720 : var_name += Moose::stringify(index_symbols[i[j]]);
396 54420 : names.push_back(var_name);
397 :
398 54420 : if (!get_names_only)
399 : {
400 27184 : auto params = getParams(kernel_name, property_name, var_name, material);
401 96502 : for (const auto j : make_range(dim))
402 69318 : params.template set<unsigned int>(param_names[j]) = i[j];
403 27184 : _problem->addAuxKernel(kernel_name, material.name() + var_name, params);
404 27184 : }
405 54420 : }
406 19336 : return names;
407 0 : }
408 :
409 : InputParameters
410 27184 : 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 27184 : _material_variable_names.insert(variable_name);
417 :
418 : // Set the action parameters
419 27184 : InputParameters params = _factory.getValidParams(type);
420 27184 : if (params.have_parameter<MaterialPropertyName>("property"))
421 27088 : params.set<MaterialPropertyName>("property") = property_name;
422 96 : else if (params.have_parameter<MooseFunctorName>("functor"))
423 96 : params.set<MooseFunctorName>("functor") = property_name;
424 : else
425 0 : mooseError("Internal error. AuxKernel has neither a `functor` nor a `property` parameter.");
426 :
427 27184 : params.set<AuxVariableName>("variable") = variable_name;
428 27184 : if (_output_only_on_timestep_end)
429 0 : params.set<ExecFlagEnum>("execute_on") = EXEC_TIMESTEP_END;
430 : else
431 81552 : params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_TIMESTEP_END};
432 :
433 27184 : if (material.boundaryRestricted())
434 168 : params.set<std::vector<BoundaryName>>("boundary") = material.boundaryNames();
435 : else
436 27016 : params.set<std::vector<SubdomainName>>("block") = material.blocks();
437 :
438 27184 : return params;
439 27184 : }
|