Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <cstddef> 7 : #include <exception> 8 : #include <memory> 9 : #include <string> 10 : #include <tuple> 11 : #include <unordered_map> 12 : #include <utility> 13 : #include <variant> 14 : #include <vector> 15 : 16 : #include "DataStructures/DataBox/DataBox.hpp" 17 : #include "DataStructures/DataBox/Tag.hpp" 18 : #include "Domain/Creators/DomainCreator.hpp" 19 : #include "Domain/Creators/ExpandOverBlocks.hpp" 20 : #include "Domain/Creators/OptionTags.hpp" 21 : #include "Domain/Creators/Tags/Domain.hpp" 22 : #include "Domain/Structure/BlockGroups.hpp" 23 : #include "Domain/Structure/ElementId.hpp" 24 : #include "Domain/Tags.hpp" 25 : #include "Elliptic/Tags.hpp" 26 : #include "IO/Observer/Tags.hpp" 27 : #include "Options/String.hpp" 28 : #include "Parallel/AlgorithmExecution.hpp" 29 : #include "ParallelAlgorithms/Amr/Protocols/Projector.hpp" 30 : #include "PointwiseFunctions/Elasticity/ConstitutiveRelations/ConstitutiveRelation.hpp" 31 : #include "PointwiseFunctions/Elasticity/ConstitutiveRelations/Tags.hpp" 32 : #include "Utilities/CallWithDynamicType.hpp" 33 : #include "Utilities/ErrorHandling/Error.hpp" 34 : #include "Utilities/ProtocolHelpers.hpp" 35 : #include "Utilities/TMPL.hpp" 36 : 37 : /// \cond 38 : namespace tuples { 39 : template <typename... Tags> 40 : struct TaggedTuple; 41 : } // namespace tuples 42 : namespace Parallel { 43 : template <typename Metavariables> 44 : struct GlobalCache; 45 : } // namespace Parallel 46 : /// \endcond 47 : 48 1 : namespace Elasticity { 49 0 : namespace Tags { 50 : 51 : /// A constitutive relation in every block of the domain 52 : template <size_t Dim> 53 1 : struct ConstitutiveRelationPerBlock : db::SimpleTag, 54 : ConstitutiveRelationPerBlockBase { 55 0 : using ConstRelPtr = 56 : std::unique_ptr<ConstitutiveRelations::ConstitutiveRelation<Dim>>; 57 0 : using type = std::vector<ConstRelPtr>; 58 : 59 0 : using option_tags = tmpl::list<domain::OptionTags::DomainCreator<Dim>, 60 : OptionTags::ConstitutiveRelationPerBlock<Dim>>; 61 0 : static constexpr bool pass_metavariables = false; 62 : 63 0 : static type create_from_options( 64 : const std::unique_ptr<DomainCreator<Dim>>& domain_creator, 65 : const std::variant<ConstRelPtr, std::vector<ConstRelPtr>, 66 : std::unordered_map<std::string, ConstRelPtr>>& 67 : constitutive_relation_per_block) { 68 : const auto block_names = domain_creator->block_names(); 69 : const auto block_groups = domain_creator->block_groups(); 70 : const domain::ExpandOverBlocks<ConstRelPtr> expand_over_blocks{ 71 : block_names, block_groups}; 72 : try { 73 : return std::visit(expand_over_blocks, constitutive_relation_per_block); 74 : } catch (const std::exception& error) { 75 : ERROR_NO_TRACE("Invalid 'Material':\n" << error.what()); 76 : } 77 : } 78 : }; 79 : 80 : /// References the constitutive relation for the element's block, which is 81 : /// stored in the global cache 82 : template <size_t Dim> 83 1 : struct ConstitutiveRelationReference : ConstitutiveRelation<Dim>, 84 : db::ReferenceTag { 85 0 : using base = ConstitutiveRelation<Dim>; 86 0 : using argument_tags = 87 : tmpl::list<ConstitutiveRelationPerBlockBase, domain::Tags::Element<Dim>>; 88 0 : static const ConstitutiveRelations::ConstitutiveRelation<Dim>& get( 89 : const std::vector< 90 : std::unique_ptr<ConstitutiveRelations::ConstitutiveRelation<Dim>>>& 91 : constitutive_relation_per_block, 92 : const Element<Dim>& element) { 93 : return *constitutive_relation_per_block.at(element.id().block_id()); 94 : } 95 : }; 96 : 97 : /// Stores the names of the block groups that split the domain into layers with 98 : /// different material properties. Useful to observe quantities in each layer. 99 : template <size_t Dim> 100 1 : struct MaterialBlockGroups : db::SimpleTag { 101 0 : using type = std::unordered_set<std::string>; 102 : 103 0 : using option_tags = tmpl::list<OptionTags::ConstitutiveRelationPerBlock<Dim>>; 104 0 : static constexpr bool pass_metavariables = false; 105 0 : using ConstRelPtr = 106 : std::unique_ptr<ConstitutiveRelations::ConstitutiveRelation<Dim>>; 107 : 108 0 : static type create_from_options( 109 : const std::variant<ConstRelPtr, std::vector<ConstRelPtr>, 110 : std::unordered_map<std::string, ConstRelPtr>>& 111 : constitutive_relation_per_block) { 112 : if (std::holds_alternative<std::unordered_map<std::string, ConstRelPtr>>( 113 : constitutive_relation_per_block)) { 114 : const auto& map = std::get<std::unordered_map<std::string, ConstRelPtr>>( 115 : constitutive_relation_per_block); 116 : std::unordered_set<std::string> block_groups; 117 : for (const auto& [block_name, _] : map) { 118 : block_groups.insert(block_name); 119 : } 120 : return block_groups; 121 : } else { 122 : return {}; 123 : } 124 : } 125 : }; 126 : 127 : /// The name of the material layer (name of a block group with some material) 128 1 : struct MaterialLayerName : db::SimpleTag { 129 0 : using type = std::optional<std::string>; 130 : }; 131 : 132 : } // namespace Tags 133 : 134 : /// Actions related to solving Elasticity systems 135 1 : namespace Actions { 136 : 137 : /*! 138 : * \brief Initialize the constitutive relation describing properties of the 139 : * elastic material 140 : * 141 : * Every block in the domain can have a different constitutive relation, 142 : * allowing for composite materials. All constitutive relations are stored in 143 : * the global cache indexed by block, and elements reference their block's 144 : * constitutive relation in the DataBox. This means an element can retrieve the 145 : * local constitutive relation from the DataBox simply by requesting 146 : * `Elasticity::Tags::ConstitutiveRelation<Dim>`. 147 : */ 148 : template <size_t Dim> 149 1 : struct InitializeConstitutiveRelation 150 : : tt::ConformsTo<amr::protocols::Projector> { 151 : public: // Iterable action 152 0 : using const_global_cache_tags = 153 : tmpl::list<Tags::ConstitutiveRelationPerBlock<Dim>, 154 : Tags::MaterialBlockGroups<Dim>>; 155 0 : using simple_tags = 156 : tmpl::list<Tags::MaterialLayerName, 157 : observers::Tags::ObservationKey<Tags::MaterialLayerName>>; 158 0 : using compute_tags = tmpl::list<Tags::ConstitutiveRelationReference<Dim>>; 159 : 160 : template <typename DbTags, typename... InboxTags, typename Metavariables, 161 : typename ActionList, typename ParallelComponent> 162 0 : static Parallel::iterable_action_return_t apply( 163 : db::DataBox<DbTags>& box, 164 : const tuples::TaggedTuple<InboxTags...>& /*inboxes*/, 165 : const Parallel::GlobalCache<Metavariables>& /*cache*/, 166 : const ElementId<Dim>& /*array_index*/, const ActionList /*meta*/, 167 : const ParallelComponent* const /*meta*/) { 168 : db::mutate_apply<InitializeConstitutiveRelation>(make_not_null(&box)); 169 : return {Parallel::AlgorithmExecution::Continue, std::nullopt}; 170 : } 171 : 172 : public: // amr::protocols::Projector 173 0 : using return_tags = simple_tags; 174 0 : using argument_tags = 175 : tmpl::list<Tags::MaterialBlockGroups<Dim>, domain::Tags::Element<Dim>, 176 : domain::Tags::Domain<Dim>>; 177 : 178 : template <typename... AmrData> 179 0 : static void apply( 180 : const gsl::not_null<std::optional<std::string>*> material_layer_name, 181 : const gsl::not_null<std::optional<std::string>*> observation_key, 182 : const std::unordered_set<std::string>& material_block_groups, 183 : const Element<Dim>& element, const Domain<Dim>& domain, 184 : const AmrData&... /*unused*/) { 185 : const auto& block = domain.blocks()[element.id().block_id()]; 186 : // Check if this element is in a material layer 187 : *material_layer_name = [&material_block_groups, &domain, 188 : &block]() -> std::optional<std::string> { 189 : for (const auto& name : material_block_groups) { 190 : if (domain::block_is_in_group(block.name(), name, 191 : domain.block_groups())) { 192 : return name; 193 : } 194 : } 195 : return std::nullopt; 196 : }(); 197 : // Set the corresponding observation key, but only on the finest multigrid 198 : // level. This could be done better by supporting intersections of array 199 : // sections in observation events or something like that. 200 : *observation_key = 201 : element.id().grid_index() == 0 ? *material_layer_name : std::nullopt; 202 : } 203 : }; 204 : 205 : } // namespace Actions 206 : } // namespace Elasticity