From 99c5320f8b81d88c28a54bddd267e705ad27b965 Mon Sep 17 00:00:00 2001 From: Guillaume Giudicelli Date: Mon, 1 Jan 2024 22:18:51 +0100 Subject: [PATCH] Add functor material property shortcut output, closes #19382 Fix up logic, add more comments to avoid confusion next time around --- .../include/actions/MaterialOutputAction.h | 44 ++++++++ .../functormaterials/FunctorMaterial.h | 8 ++ framework/src/actions/MaterialOutputAction.C | 101 +++++++++++++++--- 3 files changed, 140 insertions(+), 13 deletions(-) diff --git a/framework/include/actions/MaterialOutputAction.h b/framework/include/actions/MaterialOutputAction.h index 0469f7535014..566018d03e96 100644 --- a/framework/include/actions/MaterialOutputAction.h +++ b/framework/include/actions/MaterialOutputAction.h @@ -12,6 +12,7 @@ // MOOSE includes #include "Action.h" #include "MaterialData.h" +#include "FEProblemBase.h" class MooseObjectAction; class MaterialBase; @@ -48,6 +49,14 @@ class MaterialOutputAction : public Action template bool hasADProperty(const std::string & property_name); + /** + * Helper method for testing if the functor material property exists + * @tparam T The functor property type (e.g., REAL) + * @param property_name The name of the property to test + */ + template + bool hasFunctorProperty(const std::string & property_name); + /** * A function to be overriden by derived actions to handle a set of material property types */ @@ -88,6 +97,25 @@ class MaterialOutputAction : public Action const MaterialBase & material, bool get_names_only); + /** + * Template method for creating the necessary objects for the various functor material property + * types + * @tparam T The type of material property that automatic output is being performed + * @param property_name The name of the functor material property to output + * @param material A pointer to the MaterialBase object containing the property of interest + * @param get_names_only A bool used to indicate that only the variable names should be returned + * + * @return A vector of names that can be used as AuxVariable names + * + * By default this function produces an mooseError, you must create a specialization for any type + * that you wish to have the automatic output capability. Also, you need to add a test for this + * type within the act() method. + */ + template + std::vector functorMaterialOutputHelper(const std::string & property_name, + const MaterialBase & material, + bool get_names_only); + /// Pointer the MaterialData object storing the block restricted materials const MaterialData * _block_material_data; @@ -119,6 +147,15 @@ MaterialOutputAction::materialOutputHelper(const std::string & /*property_name*/ mooseError("Unknown type, you must create a specialization of materialOutputHelper"); } +template +std::vector +MaterialOutputAction::functorMaterialOutputHelper(const std::string & /*property_name*/, + const MaterialBase & /*material*/, + bool /*get_names_only*/) +{ + mooseError("Unknown type, you must create a specialization of functorMaterialOutputHelper"); +} + template bool MaterialOutputAction::hasProperty(const std::string & property_name) @@ -140,3 +177,10 @@ MaterialOutputAction::hasADProperty(const std::string & property_name) else return false; } + +template +bool +MaterialOutputAction::hasFunctorProperty(const std::string & property_name) +{ + return _problem->hasFunctorWithType(property_name, 0); +} diff --git a/framework/include/functormaterials/FunctorMaterial.h b/framework/include/functormaterials/FunctorMaterial.h index ed4232464b8c..34716e045375 100644 --- a/framework/include/functormaterials/FunctorMaterial.h +++ b/framework/include/functormaterials/FunctorMaterial.h @@ -22,6 +22,8 @@ class FunctorMaterial : public Material FunctorMaterial(const InputParameters & parameters); void computeProperties() override final {} + const std::set & getSuppliedFunctors() const { return _supplied_functor_props; } + protected: void computeQpProperties() override final {} @@ -43,6 +45,10 @@ class FunctorMaterial : public Material PolymorphicLambda my_lammy, const std::set & sub_ids, const std::set & clearance_schedule = {EXEC_ALWAYS}); + +private: + /// List of the properties supplied + std::set _supplied_functor_props; }; template @@ -51,6 +57,7 @@ FunctorMaterial::addFunctorProperty(const std::string & name, PolymorphicLambda my_lammy, const std::set & clearance_schedule) { + _supplied_functor_props.insert(name); return addFunctorPropertyByBlocks(name, my_lammy, blockIDs(), clearance_schedule); } @@ -71,6 +78,7 @@ FunctorMaterial::addFunctorPropertyByBlocks(const std::string & name, prop_name = _pars.get(name); } + _supplied_functor_props.insert(name); return _subproblem.addPiecewiseByBlockLambdaFunctor( prop_name, my_lammy, clearance_schedule, _mesh, sub_ids, _tid); } diff --git a/framework/src/actions/MaterialOutputAction.C b/framework/src/actions/MaterialOutputAction.C index bf892c89f13c..4d9cc863088c 100644 --- a/framework/src/actions/MaterialOutputAction.C +++ b/framework/src/actions/MaterialOutputAction.C @@ -10,6 +10,7 @@ // MOOSE includes #include "MaterialOutputAction.h" #include "FEProblem.h" +#include "FEProblemBase.h" #include "MooseApp.h" #include "AddOutputAction.h" #include "MaterialBase.h" @@ -17,6 +18,7 @@ #include "RankFourTensor.h" #include "MooseEnum.h" #include "MooseVariableConstMonomial.h" +#include "FunctorMaterial.h" #include "libmesh/utility.h" @@ -53,6 +55,14 @@ template <> std::vector MaterialOutputAction::materialOutputHelper( const std::string & material_name, const MaterialBase & material, bool get_names_only); +template <> +std::vector MaterialOutputAction::functorMaterialOutputHelper( + const std::string & material_name, const MaterialBase & material, bool get_names_only); + +template <> +std::vector MaterialOutputAction::functorMaterialOutputHelper( + const std::string & material_name, const MaterialBase & material, bool get_names_only); + registerMooseAction("MooseApp", MaterialOutputAction, "add_output_aux_variables"); registerMooseAction("MooseApp", MaterialOutputAction, "add_aux_kernel"); @@ -152,30 +162,36 @@ MaterialOutputAction::act() // (2) If the MaterialBase object itself has set the 'outputs' parameter if (outputs_has_properties || outputs.find("none") == outputs.end()) { - // Add the material property for output if the name is contained in the 'output_properties' - // list - // or if the list is empty (all properties) - const std::set names = mat->getSuppliedItems(); + // Get all material properties supplied by this material as a starting point + std::set names = mat->getSuppliedItems(); + if (dynamic_cast(mat.get())) + { + const auto fmat_ptr = dynamic_cast(mat.get()); + names.insert(fmat_ptr->getSuppliedFunctors().begin(), + fmat_ptr->getSuppliedFunctors().end()); + } + for (const auto & name : names) { - // Add the material property for output + // Output the property only if the name is contained in the 'output_properties' + // list or if the list is empty (all properties) if (output_properties.empty() || std::find(output_properties.begin(), output_properties.end(), name) != output_properties.end()) { + // Add the material property for output auto curr_material_names = materialOutput(name, *mat, get_names_only); if (curr_material_names.size() == 0) unsupported_names.insert(name); material_names.insert(curr_material_names.begin(), curr_material_names.end()); } - - // If the material object has limited outputs, store the variables associated with the - // output objects - if (!outputs.empty()) - for (const auto & output_name : outputs) - _material_variable_names_map[output_name].insert(_material_variable_names.begin(), - _material_variable_names.end()); } + // If the material object has limited outputs, store the variables associated with the + // output objects + if (!outputs.empty()) + for (const auto & output_name : outputs) + _material_variable_names_map[output_name].insert(_material_variable_names.begin(), + _material_variable_names.end()); } } if (unsupported_names.size() > 0 && get_names_only) @@ -265,6 +281,18 @@ MaterialOutputAction::materialOutput(const std::string & property_name, else if (hasProperty(property_name)) names = materialOutputHelper(property_name, material, get_names_only); + else if (hasFunctorProperty(property_name)) + names = functorMaterialOutputHelper(property_name, material, get_names_only); + + else if (hasFunctorProperty(property_name)) + names = functorMaterialOutputHelper(property_name, material, get_names_only); + + else if (hasFunctorProperty(property_name)) + names = functorMaterialOutputHelper(property_name, material, get_names_only); + + else if (hasFunctorProperty(property_name)) + names = functorMaterialOutputHelper(property_name, material, get_names_only); + return names; } @@ -280,7 +308,12 @@ MaterialOutputAction::getParams(const std::string & type, // Set the action parameters InputParameters params = _factory.getValidParams(type); - params.set("property") = property_name; + // Adapt for regular or functor materials + if (type.find("Material") != std::string::npos) + params.set("property") = property_name; + else + params.set("functor") = property_name; + params.set("variable") = variable_name; if (_output_only_on_timestep_end) params.set("execute_on") = EXEC_TIMESTEP_END; @@ -491,3 +524,45 @@ MaterialOutputAction::materialOutputHelper(const std::string & p return names; } + +template <> +std::vector +MaterialOutputAction::functorMaterialOutputHelper(const std::string & property_name, + const MaterialBase & material, + bool get_names_only) +{ + std::vector names = {property_name + "_out"}; + if (!get_names_only) + { + // add a '_out' suffix to avoid name conflicts between the functor property and aux-variable + auto params = getParams("FunctorAux", property_name, property_name + "_out", material); + _problem->addAuxKernel("FunctorAux", material.name() + property_name, params); + } + + return names; +} + +template <> +std::vector +MaterialOutputAction::functorMaterialOutputHelper( + const std::string & property_name, const MaterialBase & material, bool get_names_only) +{ + std::array suffix = {{'x', 'y', 'z'}}; + std::vector names(3); + for (const auto i : make_range(Moose::dim)) + { + std::ostringstream oss; + // add a '_out' suffix to avoid name conflicts between the functor property and aux-variable + oss << property_name << "_out_" << suffix[i]; + names[i] = oss.str(); + + if (!get_names_only) + { + auto params = getParams("FunctorVectorElementalAux", property_name, oss.str(), material); + params.set("component") = i; + _problem->addAuxKernel("FunctorVectorElementalAux", material.name() + oss.str(), params); + } + } + + return names; +}