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
|