ryujin 2.1.1 revision b04fb4aba7bd97ddfa5994a6b4b6e8586eb15db2
Loading...
Searching...
No Matches
initial_values.template.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2020 - 2026 by the ryujin authors
4//
5
6#pragma once
7
8#include "initial_values.h"
9
10#include <deal.II/numerics/vector_tools.h>
11#include <deal.II/numerics/vector_tools.templates.h>
12
13#include <random>
14
15namespace ryujin
16{
17 using namespace dealii;
18
19 template <typename HyperbolicDescription, int dim, typename Number>
21 const MPIEnsemble &mpi_ensemble,
22 const OfflineData<dim, Number> &offline_data,
23 const HyperbolicSystem &hyperbolic_system,
24 const Interface::ParabolicSystem &parabolic_system,
25 const std::string &subsection)
26 : ParameterAcceptor(subsection)
27 , mpi_ensemble_(mpi_ensemble)
28 , offline_data_(&offline_data)
29 , hyperbolic_system_(&hyperbolic_system)
30 , parabolic_system_(&parabolic_system)
31 {
32 ParameterAcceptor::parse_parameters_call_back.connect(
35 this));
36
37 configuration_ = "uniform";
38 add_parameter("configuration",
39 configuration_,
40 "The initial state configuration. Valid names are given by "
41 "any of the subsections defined below.");
42
43 initial_direction_[0] = 1.;
44 add_parameter(
45 "direction",
46 initial_direction_,
47 "Initial direction of initial configuration (Galilei transform)");
48
49 initial_position_[0] = 1.;
50 add_parameter(
51 "position",
52 initial_position_,
53 "Initial position of initial configuration (Galilei transform)");
54
55 perturbation_ = 0.;
56 add_parameter("perturbation",
57 perturbation_,
58 "Add a random perturbation of the specified magnitude to the "
59 "initial state.");
60
61 /*
62 * And finally populate the initial state list with all initial state
63 * configurations defined in the InitialStateLibrary namespace:
64 */
66 populate_initial_state_list(initial_state_list_,
67 *hyperbolic_system_,
68 *parabolic_system_,
69 subsection);
70 }
72 namespace
73 {
77 template <int dim>
78 inline DEAL_II_ALWAYS_INLINE dealii::Point<dim>
79 affine_transform(const dealii::Tensor<1, dim> initial_direction,
80 const dealii::Point<dim> initial_position,
81 const dealii::Point<dim> x)
82 {
83 auto direction = x - initial_position;
84
85 /* Roll third component of initial_direction onto xy-plane: */
86 if constexpr (dim == 3) {
87 auto n_x = initial_direction[0];
88 auto n_z = initial_direction[2];
89 const auto norm = std::sqrt(n_x * n_x + n_z * n_z);
90 n_x /= norm;
91 n_z /= norm;
92 auto new_direction = direction;
93 if (norm > 1.0e-14) {
94 new_direction[0] = n_x * direction[0] + n_z * direction[2];
95 new_direction[2] = -n_z * direction[0] + n_x * direction[2];
96 }
97 direction = new_direction;
98 }
99
100 /* Roll second component of initial_direction onto x-axis: */
101 if constexpr (dim >= 2) {
102 auto n_x = initial_direction[0];
103 auto n_y = initial_direction[1];
104 const auto norm = std::sqrt(n_x * n_x + n_y * n_y);
105 n_x /= norm;
106 n_y /= norm;
107 auto new_direction = direction;
108 if (norm > 1.0e-14) {
109 new_direction[0] = n_x * direction[0] + n_y * direction[1];
110 new_direction[1] = -n_y * direction[0] + n_x * direction[1];
111 }
112 direction = new_direction;
113 }
114
115 if constexpr (dim == 1) {
116 auto n = initial_direction[0];
117 const auto norm = std::abs(n);
118 n /= norm;
119 auto new_direction = direction;
120 if (norm > 1.0e-14)
121 new_direction[0] = n * direction[0];
122 direction = new_direction;
123 }
124
125 return Point<dim>() + direction;
126 }
127
132 template <int dim, typename Number>
133 inline DEAL_II_ALWAYS_INLINE dealii::Tensor<1, dim, Number>
134 affine_transform_vector(const dealii::Tensor<1, dim> initial_direction,
135 dealii::Tensor<1, dim, Number> direction)
136 {
137 if constexpr (dim == 1) {
138 auto n = initial_direction[0];
139 const auto norm = std::abs(n);
140 n /= norm;
141 auto new_direction = direction;
142 if (norm > 1.0e-14)
143 new_direction[0] = n * direction[0];
144 direction = new_direction;
145 }
146
147 if constexpr (dim >= 2) {
148 auto n_x = initial_direction[0];
149 auto n_y = initial_direction[1];
150 const auto norm = std::sqrt(n_x * n_x + n_y * n_y);
151 n_x /= norm;
152 n_y /= norm;
153 auto new_direction = direction;
154 if (norm > 1.0e-14) {
155 new_direction[0] = n_x * direction[0] - n_y * direction[1];
156 new_direction[1] = n_y * direction[0] + n_x * direction[1];
157 }
158 direction = new_direction;
159 }
160
161 if constexpr (dim == 3) {
162 auto n_x = initial_direction[0];
163 auto n_z = initial_direction[2];
164 const auto norm = std::sqrt(n_x * n_x + n_z * n_z);
165 n_x /= norm;
166 n_z /= norm;
167 auto new_direction = direction;
168 if (norm > 1.0e-14) {
169 new_direction[0] = n_x * direction[0] - n_z * direction[2];
170 new_direction[2] = n_z * direction[0] + n_x * direction[2];
171 }
172 direction = new_direction;
173 }
174
175 return direction;
176 }
177 } /* namespace */
178
179
180 template <typename HyperbolicDescription, int dim, typename Number>
181 void
183 {
184 /* First, let's normalize the direction: */
185
186 AssertThrow(initial_direction_.norm() != 0.,
187 ExcMessage("Initial direction is set to the zero vector."));
188 initial_direction_ /= initial_direction_.norm();
189
190 /* Populate std::function object: */
191
192 {
193 bool initialized = false;
194 for (auto &it : initial_state_list_)
195 if (it->name() == configuration_) {
196 initial_state_ = [this, &it](const dealii::Point<dim> &point,
197 Number t) {
198 const auto transformed_point =
199 affine_transform(initial_direction_, initial_position_, point);
200 auto state = it->compute(transformed_point, t);
201 const auto view = hyperbolic_system_->template view<dim, Number>();
202 state =
203 view.apply_galilei_transform(state, [&](const auto &momentum) {
204 return affine_transform_vector(initial_direction_, momentum);
205 });
206 return state;
207 };
208
209 initial_precomputed_ = [this, &it](const dealii::Point<dim> &point) {
210 const auto transformed_point =
211 affine_transform(initial_direction_, initial_position_, point);
212 return it->initial_precomputations(transformed_point);
213 };
214
215 initialized = true;
216 break;
217 }
218
219 AssertThrow(
220 initialized,
221 ExcMessage(
222 "Could not find an initial state description with name \"" +
223 configuration_ + "\""));
224 }
225
226 /* Add a random perturbation to the original function object: */
227
228 if (perturbation_ != 0.) {
229 initial_state_ = [old_state = this->initial_state_,
230 perturbation = this->perturbation_](
231 const dealii::Point<dim> &point, Number t) {
232 auto state = old_state(point, t);
233
234 if (t > 0.)
235 return state;
236
237 static std::default_random_engine generator =
238 std::default_random_engine(std::random_device()());
239 static std::uniform_real_distribution<Number> distribution(-1., 1.);
240 static auto draw = std::bind(distribution, generator);
241 for (unsigned int i = 0; i < problem_dimension; ++i)
242 state[i] *= (Number(1.) + perturbation * draw());
243
244 return state;
245 };
246 }
247 }
248
249
250 template <typename HyperbolicDescription, int dim, typename Number>
252 interpolate_hyperbolic_vector(Number t) const
254 {
255#ifdef DEBUG_OUTPUT
256 std::cout << "InitialValues<dim, Number>::"
257 << "interpolate_hyperbolic_vector(t = " << t << ")" << std::endl;
258#endif
259
260 const auto &scalar_partitioner = offline_data_->scalar_partitioner();
261 const auto &vector_partitioner =
262 offline_data_->hyperbolic_vector_partitioner();
263
265 U.reinit_with_vector_partitioner(vector_partitioner, problem_dimension);
266
268 temp.reinit(scalar_partitioner);
269
270 // FIXME: it is not particularly efficient to call
271 // VectorTools::interpolate for every component separately. If this
272 // gets too slow, we should consider writing out to a temporary (block)
273 // vector and then inserting into the MultiComponentVector.
274 const auto U_view = U.template view<problem_dimension>();
275 const auto callable = [&](const auto &p) { return initial_state(p, t); };
276 for (unsigned int d = 0; d < problem_dimension; ++d) {
277 VectorTools::interpolate(offline_data_->discretization().mapping(),
278 offline_data_->dof_handler(),
279 to_function<dim, Number>(callable, d),
280 temp);
281 U_view.insert_component(temp, d);
282 }
283
284 U_view.update_ghost_values();
285
286 return U;
287 }
288
289
290 template <typename HyperbolicDescription, int dim, typename Number>
293 -> MultiComponentVector<Number>
294 {
295#ifdef DEBUG_OUTPUT
296 std::cout << "InitialValues<dim, Number>::"
297 << "interpolate_initial_precomputed_vector()" << std::endl;
298#endif
299
300 const auto &scalar_partitioner = offline_data_->scalar_partitioner();
301
304 n_initial_precomputed_values);
305
306 if constexpr (n_initial_precomputed_values == 0)
307 return precomputed;
308
310 temp.reinit(scalar_partitioner);
311
312 // FIXME: it is not particularly efficient to call
313 // VectorTools::interpolate for every component separately. If this
314 // gets too slow, we should consider writing out to a temporary (block)
315 // vector and then inserting into the MultiComponentVector.
316 const auto precomputed_view =
317 precomputed.template view<n_initial_precomputed_values>();
318 const auto callable = [&](const auto &p) { return initial_precomputed(p); };
319 for (unsigned int d = 0; d < n_initial_precomputed_values; ++d) {
320 VectorTools::interpolate(offline_data_->dof_handler(),
321 to_function<dim, Number>(callable, d),
322 temp);
323 precomputed_view.insert_component(temp, d);
324 }
325
326 precomputed_view.update_ghost_values();
327 return precomputed;
328 }
329
330} /* namespace ryujin */
typename HyperbolicDescription::HyperbolicSystem HyperbolicSystem
MultiComponentVector< Number > interpolate_hyperbolic_vector(Number t=0) const
InitialValues(const MPIEnsemble &mpi_ensemble, const OfflineData< dim, Number > &offline_data, const HyperbolicSystem &hyperbolic_system, const Interface::ParabolicSystem &parabolic_system, const std::string &subsection="/InitialValues")
MultiComponentVector< Number > interpolate_initial_precomputed_vector() const
void reinit_with_vector_partitioner(const std::shared_ptr< const dealii::Utilities::MPI::Partitioner > &vector_partitioner, const unsigned int n_comp, const TransferPolicy transfer_policy=TransferPolicy::explicit_transfers)
void reinit_with_scalar_partitioner(const std::shared_ptr< const dealii::Utilities::MPI::Partitioner > &scalar_partitioner, const unsigned int n_comp, const TransferPolicy transfer_policy=TransferPolicy::explicit_transfers)
static void populate_initial_state_list(initial_state_list_type &initial_state_list, const HyperbolicSystem &h, const Interface::ParabolicSystem &p, const std::string &s)
dealii::LinearAlgebra::distributed::Vector< Number > ScalarHostVector