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 "ParallelAlgorithms/Amr/Tags.hpp" 31 : #include "PointwiseFunctions/Elasticity/ConstitutiveRelations/ConstitutiveRelation.hpp" 32 : #include "PointwiseFunctions/Elasticity/ConstitutiveRelations/Tags.hpp" 33 : #include "Utilities/CallWithDynamicType.hpp" 34 : #include "Utilities/ErrorHandling/Error.hpp" 35 : #include "Utilities/ProtocolHelpers.hpp" 36 : #include "Utilities/TMPL.hpp" 37 : 38 : /// \cond 39 : namespace tuples { 40 : template <typename... Tags> 41 : struct TaggedTuple; 42 : } // namespace tuples 43 : namespace Parallel { 44 : template <typename Metavariables> 45 : struct GlobalCache; 46 : } // namespace Parallel 47 : /// \endcond 48 : 49 1 : namespace Elasticity { 50 0 : namespace Tags { 51 : 52 : /// A constitutive relation in every block of the domain 53 : template <size_t Dim> 54 1 : struct ConstitutiveRelationPerBlock : db::SimpleTag { 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<ConstitutiveRelationPerBlock<Dim>, 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 : template <size_t Dim> 133 0 : struct MaterialLayerObservationKeyCompute 134 : : db::ComputeTag, 135 : observers::Tags::ObservationKey<MaterialLayerName> { 136 0 : using base = observers::Tags::ObservationKey<MaterialLayerName>; 137 0 : using return_type = typename base::type; 138 0 : using argument_tags = tmpl::list<MaterialLayerName, amr::Tags::ChildIds<Dim>>; 139 0 : static void function( 140 : const gsl::not_null<std::optional<std::string>*> observation_key, 141 : const std::optional<std::string>& material_layer_name, 142 : const std::unordered_set<ElementId<Dim>>& child_ids) { 143 : const bool is_finest_grid = child_ids.empty(); 144 : // Set the corresponding observation key, but only on the finest multigrid 145 : // level. This could be done better by supporting intersections of array 146 : // sections in observation events or something like that. 147 : if (is_finest_grid) { 148 : *observation_key = material_layer_name; 149 : } else { 150 : *observation_key = std::nullopt; 151 : } 152 : } 153 : }; 154 : 155 : } // namespace Tags 156 : 157 : /// Actions related to solving Elasticity systems 158 1 : namespace Actions { 159 : 160 : /*! 161 : * \brief Initialize the constitutive relation describing properties of the 162 : * elastic material 163 : * 164 : * Every block in the domain can have a different constitutive relation, 165 : * allowing for composite materials. All constitutive relations are stored in 166 : * the global cache indexed by block, and elements reference their block's 167 : * constitutive relation in the DataBox. This means an element can retrieve the 168 : * local constitutive relation from the DataBox simply by requesting 169 : * `Elasticity::Tags::ConstitutiveRelation<Dim>`. 170 : */ 171 : template <size_t Dim> 172 1 : struct InitializeConstitutiveRelation 173 : : tt::ConformsTo<amr::protocols::Projector> { 174 : public: // Iterable action 175 0 : using const_global_cache_tags = 176 : tmpl::list<Tags::ConstitutiveRelationPerBlock<Dim>, 177 : Tags::MaterialBlockGroups<Dim>>; 178 0 : using simple_tags = tmpl::list<Tags::MaterialLayerName>; 179 0 : using compute_tags = 180 : tmpl::list<Tags::ConstitutiveRelationReference<Dim>, 181 : Tags::MaterialLayerObservationKeyCompute<Dim>>; 182 : 183 : template <typename DbTags, typename... InboxTags, typename Metavariables, 184 : typename ActionList, typename ParallelComponent> 185 0 : static Parallel::iterable_action_return_t apply( 186 : db::DataBox<DbTags>& box, 187 : const tuples::TaggedTuple<InboxTags...>& /*inboxes*/, 188 : const Parallel::GlobalCache<Metavariables>& /*cache*/, 189 : const ElementId<Dim>& /*array_index*/, const ActionList /*meta*/, 190 : const ParallelComponent* const /*meta*/) { 191 : db::mutate_apply<InitializeConstitutiveRelation>(make_not_null(&box)); 192 : return {Parallel::AlgorithmExecution::Continue, std::nullopt}; 193 : } 194 : 195 : public: // amr::protocols::Projector 196 0 : using return_tags = simple_tags; 197 0 : using argument_tags = 198 : tmpl::list<Tags::MaterialBlockGroups<Dim>, domain::Tags::Element<Dim>, 199 : domain::Tags::Domain<Dim>>; 200 : 201 : template <typename... AmrData> 202 0 : static void apply( 203 : const gsl::not_null<std::optional<std::string>*> material_layer_name, 204 : const std::unordered_set<std::string>& material_block_groups, 205 : const Element<Dim>& element, const Domain<Dim>& domain, 206 : const AmrData&... /*unused*/) { 207 : const auto& block = domain.blocks()[element.id().block_id()]; 208 : // Check if this element is in a material layer 209 : *material_layer_name = [&material_block_groups, &domain, 210 : &block]() -> std::optional<std::string> { 211 : for (const auto& name : material_block_groups) { 212 : if (domain::block_is_in_group(block.name(), name, 213 : domain.block_groups())) { 214 : return name; 215 : } 216 : } 217 : return std::nullopt; 218 : }(); 219 : } 220 : }; 221 : 222 : } // namespace Actions 223 : } // namespace Elasticity