ryujin 2.5.0 revision c64172211cf21344cb9b9b0f3a1266aa6400d392
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
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 : Interface::InitialValues<dim, Number>(subsection)
27 , mpi_ensemble_(mpi_ensemble)
28 , offline_data_(&offline_data)
29 , hyperbolic_system_(&hyperbolic_system)
30 , parabolic_system_(&parabolic_system)
31 {
32 this->parse_parameters_call_back.connect(
35 this));
36
37 initial_state_list_ =
39 *hyperbolic_system_, subsection);
40
41 configuration_ = "uniform";
42 this->add_parameter(
43 "configuration",
44 configuration_,
45 "The initial state configuration. Valid names are given by "
46 "any of the subsections defined below.",
47 this->prm,
49 initial_state_list_));
50
51 initial_direction_[0] = 1.;
52 this->add_parameter(
53 "direction",
54 initial_direction_,
55 "Initial direction of initial configuration (Galilei transform)");
56
57 initial_position_[0] = 1.;
58 this->add_parameter(
59 "position",
60 initial_position_,
61 "Initial position of initial configuration (Galilei transform)");
62
63 perturbation_ = 0.;
64 this->add_parameter(
65 "perturbation",
66 perturbation_,
67 "Add a random perturbation of the specified magnitude to the "
68 "initial state.");
69 }
70
71 namespace
72 {
76 template <int dim>
77 inline DEAL_II_ALWAYS_INLINE dealii::Point<dim>
78 affine_transform(const dealii::Tensor<1, dim> initial_direction,
79 const dealii::Point<dim> initial_position,
80 const dealii::Point<dim> x)
81 {
82 auto direction = x - initial_position;
83
84 /* Roll third component of initial_direction onto xy-plane: */
85 if constexpr (dim == 3) {
86 auto n_x = initial_direction[0];
87 auto n_z = initial_direction[2];
88 const auto norm = std::sqrt(n_x * n_x + n_z * n_z);
89 n_x /= norm;
90 n_z /= norm;
91 auto new_direction = direction;
92 if (norm > 1.0e-14) {
93 new_direction[0] = n_x * direction[0] + n_z * direction[2];
94 new_direction[2] = -n_z * direction[0] + n_x * direction[2];
95 }
96 direction = new_direction;
97 }
98
99 /* Roll second component of initial_direction onto x-axis: */
100 if constexpr (dim >= 2) {
101 auto n_x = initial_direction[0];
102 auto n_y = initial_direction[1];
103 const auto norm = std::sqrt(n_x * n_x + n_y * n_y);
104 n_x /= norm;
105 n_y /= norm;
106 auto new_direction = direction;
107 if (norm > 1.0e-14) {
108 new_direction[0] = n_x * direction[0] + n_y * direction[1];
109 new_direction[1] = -n_y * direction[0] + n_x * direction[1];
110 }
111 direction = new_direction;
112 }
113
114 if constexpr (dim == 1) {
115 auto n = initial_direction[0];
116 const auto norm = std::abs(n);
117 n /= norm;
118 auto new_direction = direction;
119 if (norm > 1.0e-14)
120 new_direction[0] = n * direction[0];
121 direction = new_direction;
122 }
124 return Point<dim>() + direction;
125 }
126
127
131 template <int dim, typename Number>
132 inline DEAL_II_ALWAYS_INLINE dealii::Tensor<1, dim, Number>
133 affine_transform_vector(const dealii::Tensor<1, dim> initial_direction,
134 dealii::Tensor<1, dim, Number> direction)
135 {
136 if constexpr (dim == 1) {
137 auto n = initial_direction[0];
138 const auto norm = std::abs(n);
139 n /= norm;
140 auto new_direction = direction;
141 if (norm > 1.0e-14)
142 new_direction[0] = n * direction[0];
143 direction = new_direction;
144 }
145
146 if constexpr (dim >= 2) {
147 auto n_x = initial_direction[0];
148 auto n_y = initial_direction[1];
149 const auto norm = std::sqrt(n_x * n_x + n_y * n_y);
150 n_x /= norm;
151 n_y /= norm;
152 auto new_direction = direction;
153 if (norm > 1.0e-14) {
154 new_direction[0] = n_x * direction[0] - n_y * direction[1];
155 new_direction[1] = n_y * direction[0] + n_x * direction[1];
156 }
157 direction = new_direction;
158 }
159
160 if constexpr (dim == 3) {
161 auto n_x = initial_direction[0];
162 auto n_z = initial_direction[2];
163 const auto norm = std::sqrt(n_x * n_x + n_z * n_z);
164 n_x /= norm;
165 n_z /= norm;
166 auto new_direction = direction;
167 if (norm > 1.0e-14) {
168 new_direction[0] = n_x * direction[0] - n_z * direction[2];
169 new_direction[2] = n_z * direction[0] + n_x * direction[2];
170 }
171 direction = new_direction;
172 }
173
174 return direction;
175 }
176 } // namespace
177
178
179 template <typename HyperbolicDescription, int dim, typename Number>
180 void
182 {
183 /* First, let's normalize the direction: */
184
185 AssertThrow(initial_direction_.norm() != 0.,
186 ExcMessage("Initial direction is set to the zero vector."));
187 initial_direction_ /= initial_direction_.norm();
188
189 /* Populate std::function object: */
190
191 {
192 auto &initial_state =
194 initial_state_list_, configuration_);
195
196 initial_state_ = [this, &initial_state](const dealii::Point<dim> &point,
197 Number t) {
198 const auto transformed_point =
199 affine_transform(initial_direction_, initial_position_, point);
200 auto state = initial_state.compute(transformed_point, t);
201 const auto view = hyperbolic_system_->template view<dim, Number>();
202 state = view.apply_galilei_transform(state, [&](const auto &momentum) {
203 return affine_transform_vector(initial_direction_, momentum);
204 });
205 return state;
206 };
207
208 initial_precomputed_ = [this,
209 &initial_state](const dealii::Point<dim> &point) {
210 const auto transformed_point =
211 affine_transform(initial_direction_, initial_position_, point);
212 return initial_state.initial_precomputations(transformed_point);
213 };
214 }
215
216 /* Add a random perturbation to the original function object: */
217
218 if (perturbation_ != 0.) {
219 initial_state_ = [old_state = this->initial_state_,
220 perturbation = this->perturbation_](
221 const dealii::Point<dim> &point, Number t) {
222 auto state = old_state(point, t);
223
224 if (t > 0.)
225 return state;
226
227 static std::default_random_engine generator =
228 std::default_random_engine(std::random_device()());
229 static std::uniform_real_distribution<Number> distribution(-1., 1.);
230 static auto draw = std::bind(distribution, generator);
231 for (unsigned int i = 0; i < problem_dimension; ++i)
232 state[i] *= (Number(1.) + perturbation * draw());
233
234 return state;
235 };
236 }
237 }
238
239
240 template <typename HyperbolicDescription, int dim, typename Number>
242 interpolate_hyperbolic_vector(Number t) const
244 {
245#ifdef DEBUG_OUTPUT
246 std::cout << "InitialValues<dim, Number>::"
247 << "interpolate_hyperbolic_vector(t = " << t << ")" << std::endl;
248#endif
249
250 const auto &scalar_partitioner = offline_data_->scalar_partitioner();
251 const auto &vector_partitioner =
252 offline_data_->hyperbolic_vector_partitioner();
253
255 U.reinit_with_vector_partitioner(vector_partitioner, problem_dimension);
256
258 temp.reinit(scalar_partitioner);
259
260 // FIXME: it is not particularly efficient to call
261 // VectorTools::interpolate for every component separately. If this
262 // gets too slow, we should consider writing out to a temporary (block)
263 // vector and then inserting into the MultiComponentVector.
264 const auto U_view = U.template view<problem_dimension>();
265 const auto callable = [&](const auto &p) { return initial_state(p, t); };
266 for (unsigned int d = 0; d < problem_dimension; ++d) {
267 VectorTools::interpolate(offline_data_->discretization().mapping(),
268 offline_data_->dof_handler(),
269 to_function<dim, Number>(callable, d),
270 temp);
271 U_view.insert_component(temp, d);
272 }
273
274 U_view.update_ghost_values();
275
276 return U;
277 }
278
279
280 template <typename HyperbolicDescription, int dim, typename Number>
283 -> MultiComponentVector<Number>
284 {
285#ifdef DEBUG_OUTPUT
286 std::cout << "InitialValues<dim, Number>::"
287 << "interpolate_initial_precomputed_vector()" << std::endl;
288#endif
289
290 const auto &scalar_partitioner = offline_data_->scalar_partitioner();
291
294 n_initial_precomputed_values);
295
296 if constexpr (n_initial_precomputed_values == 0)
297 return precomputed;
298
300 temp.reinit(scalar_partitioner);
301
302 // FIXME: it is not particularly efficient to call
303 // VectorTools::interpolate for every component separately. If this
304 // gets too slow, we should consider writing out to a temporary (block)
305 // vector and then inserting into the MultiComponentVector.
306 const auto precomputed_view =
307 precomputed.template view<n_initial_precomputed_values>();
308 const auto callable = [&](const auto &p) { return initial_precomputed(p); };
309 for (unsigned int d = 0; d < n_initial_precomputed_values; ++d) {
310 VectorTools::interpolate(offline_data_->dof_handler(),
311 to_function<dim, Number>(callable, d),
312 temp);
313 precomputed_view.insert_component(temp, d);
314 }
315
316 precomputed_view.update_ghost_values();
317 return precomputed;
318 }
319
320} // namespace ryujin
typename HyperbolicDescription::HyperbolicSystem HyperbolicSystem
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
MultiComponentVector< Number > interpolate_hyperbolic_vector(Number t=0) const override
static Base & select(const std::vector< std::unique_ptr< Base > > &objects, const std::string &name)
Definition library.h:189
static std::vector< std::unique_ptr< Base > > create(Args... args)
Definition library.h:148
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)
dealii::LinearAlgebra::distributed::Vector< Number > ScalarHostVector