8#include <ryujin/base/compile_time_options.h>
18#include <deal.II/base/exceptions.h>
19#include <deal.II/base/tensor.h>
21#include <Kokkos_Pair.hpp>
50 template <
typename Description,
int dim,
typename Number>
68 std::vector<ScalarHostVector<Number>>
74 const unsigned int *indices,
75 const unsigned int n_points,
76 Number *values)
const override;
79 using View =
typename HyperbolicSystem::template View<dim, Number>;
81 template <
int n_comp,
typename MemorySpace>
88 enum class Section : std::uint8_t {
99 enum class Operation : std::uint8_t { value, schlieren, vorticity };
110 template <
typename MemorySpace>
112 const StateVector<Number> &state_vector)
const;
114 dealii::ObserverPointer<const OfflineData<dim, Number>> offline_data_;
115 dealii::ObserverPointer<const HyperbolicSystem> hyperbolic_system_;
116 dealii::ObserverPointer<const Interface::ParabolicSystem> parabolic_system_;
117 const MultiComponentVector<Number> &initial_precomputed_;
129 template <
typename Description,
int dim,
typename Number>
131 const OfflineData<dim, Number> &offline_data,
132 const HyperbolicSystem &hyperbolic_system,
133 const Interface::ParabolicSystem ¶bolic_system,
134 const MultiComponentVector<Number> &initial_precomputed)
135 : offline_data_(&offline_data)
136 , hyperbolic_system_(&hyperbolic_system)
137 , parabolic_system_(¶bolic_system)
138 , initial_precomputed_(initial_precomputed)
143 template <
typename Description,
int dim,
typename Number>
145 const std::vector<std::string> &selected)
const -> Selection
147 const auto &hyperbolic_system = *hyperbolic_system_;
149 Assert(hyperbolic_system.state_names(dim).size() ==
150 View::problem_dimension &&
151 hyperbolic_system.primitive_names(dim).size() ==
152 View::problem_dimension &&
153 hyperbolic_system.precomputed_names(dim).size() ==
154 View::n_precomputed_values &&
155 hyperbolic_system.initial_precomputed_names(dim).size() ==
156 View::n_initial_precomputed_values,
157 dealii::ExcMessage(
"The component names of the hyperbolic system "
158 "do not match the counts of its view."));
160 const std::vector<std::pair<Section, const std::vector<std::string> *>>
162 {Section::state, &hyperbolic_system.state_names(dim)},
163 {Section::primitive, &hyperbolic_system.primitive_names(dim)},
164 {Section::precomputed, &hyperbolic_system.precomputed_names(dim)},
165 {Section::initial_precomputed,
166 &hyperbolic_system.initial_precomputed_names(dim)},
167 {Section::dynamic_state, ¶bolic_system_->state_names(dim)},
174 const auto find = [&](
const std::string &name)
175 -> std::optional<std::tuple<Section, unsigned int, unsigned int>> {
176 for (
const auto &[section, names] : sections) {
177 const auto pos = std::find(names->begin(), names->end(), name);
178 if (pos != names->end())
179 return std::make_tuple(
181 static_cast<unsigned int>(pos - names->begin()),
182 static_cast<unsigned int>(names->size()));
187 const std::vector<std::pair<Operation, std::string>> prefixes{
188 {Operation::schlieren,
"schlieren_"},
189 {Operation::vorticity,
"vorticity_"},
194 for (
const auto &entry : selected) {
195 auto operation = Operation::value;
196 auto found = find(entry);
198 for (
const auto &[prefix_operation, prefix] : prefixes) {
199 if (found || entry.rfind(prefix, 0) != 0)
201 operation = prefix_operation;
202 found = find(entry.substr(prefix.size()));
207 "Invalid component name: \"" + entry +
208 "\" is not a valid conserved, primitive, precomputed, "
209 "initial, parabolic, or postprocessed "
212 const auto [section, index, n_names] = *found;
213 const unsigned int n_operands =
214 operation == Operation::vorticity ? dim : 1;
216 AssertThrow(operation != Operation::vorticity || dim > 1,
217 dealii::ExcMessage(
"Invalid component name: \"" + entry +
218 "\": the vorticity is not defined in "
219 "one spatial dimension."));
220 AssertThrow(index + n_operands <= n_names,
221 dealii::ExcMessage(
"Invalid component name: \"" + entry +
222 "\": the vorticity requires dim "
223 "consecutive components."));
225 selection.quantities.push_back(
226 {std::uint8_t(operation),
227 static_cast<unsigned int>(selection.components.size())});
228 for (
unsigned int d = 0; d < n_operands; ++d)
229 selection.components.push_back({std::uint8_t(section), index + d});
236 template <
typename Description,
int dim,
typename Number>
237 template <
typename MemorySpace>
238 auto Postprocessor<Description, dim, Number>::reader(
239 const Selection &selection,
const StateVector<Number> &state_vector)
const
241 const auto &selected = selection.components;
242 const auto selects = [&](
const Section section) {
243 return std::any_of(selected.begin(), selected.end(), [&](
const auto &it) {
244 return Section(it.first) == section;
248 const bool read_primitive = selects(Section::primitive);
249 const bool read_state = read_primitive || selects(Section::state);
250 const bool read_precomputed = selects(Section::precomputed);
251 const bool read_initial = selects(Section::initial_precomputed);
258 VectorView<View::problem_dimension, MemorySpace> U_view;
259 VectorView<View::n_precomputed_values, MemorySpace> precomputed_view;
260 VectorView<View::n_initial_precomputed_values, MemorySpace> initial_view;
263 copy_to_memory_space<MemorySpace>(state_vector, StateVectorPart::state);
264 U_view = state_vector.state
265 .template view<View::problem_dimension, MemorySpace>();
268 if (read_precomputed) {
269 copy_to_memory_space<MemorySpace>(state_vector,
270 StateVectorPart::precomputed);
272 state_vector.precomputed
273 .template view<View::n_precomputed_values, MemorySpace>();
277 copy_to_memory_space<MemorySpace>(initial_precomputed_);
280 .template view<View::n_initial_precomputed_values, MemorySpace>();
288 const auto n_components = selected.size();
289 Kokkos::View<Kokkos::pair<Section, unsigned int> *, Kokkos::HostSpace>
290 host_components(
"postprocessor_components", n_components);
291 Kokkos::View<VectorView<1, MemorySpace> *, Kokkos::HostSpace> host_scalars(
292 "postprocessor_scalars", n_components);
294 for (
unsigned int k = 0; k < n_components; ++k) {
295 const auto section = Section(selected[k].first);
296 const auto index = selected[k].second;
297 host_components[k] = {section, index};
299 if (section == Section::dynamic_state) {
300 const auto &vector = state_vector.dynamic_state[index];
301 copy_to_memory_space<MemorySpace>(vector);
302 host_scalars[k] = vector.template view<1, MemorySpace>();
306 const auto space =
typename MemorySpace::kokkos_space{};
307 const auto components =
308 Kokkos::create_mirror_view_and_copy(space, host_components);
310 Kokkos::create_mirror_view_and_copy(space, host_scalars);
312 const SelectView<dim, Number, MemorySpace, HyperbolicSystem> system_views(
313 *hyperbolic_system_);
315 return [=](
auto sentinel,
const unsigned int i,
const auto &write) {
316 using T =
decltype(sentinel);
324 decltype(U_view.template read_tensor<T>(i)) U_i;
326 U_i = U_view.template read_tensor<T>(i);
328 auto primitive_i = U_i;
330 primitive_i = system_views.template view<T>().to_primitive_state(U_i);
332 decltype(precomputed_view.template read_tensor<T>(i)) precomputed_i;
333 if (read_precomputed)
334 precomputed_i = precomputed_view.template read_tensor<T>(i);
336 decltype(initial_view.template read_tensor<T>(i)) initial_i;
338 initial_i = initial_view.template read_tensor<T>(i);
340 for (
unsigned int k = 0; k < components.extent(0); ++k) {
341 const auto [section, index] = components[k];
344 write(k, U_i[index]);
346 case Section::primitive:
347 write(k, primitive_i[index]);
349 case Section::precomputed:
350 write(k, precomputed_i[index]);
352 case Section::initial_precomputed:
353 write(k, initial_i[index]);
356 write(k, scalars[k].
template read_entry<T>(i));
363 template <
typename Description,
int dim,
typename Number>
364 std::vector<ScalarHostVector<Number>>
365 Postprocessor<Description, dim, Number>::extract(
366 const Selection &selection,
const StateVector<Number> &state_vector)
const
368 using MemorySpace = dealii::MemorySpace::Host;
370 const auto &offline_data = *offline_data_;
371 const unsigned int n_internal = offline_data.n_locally_internal();
372 const unsigned int n_owned = offline_data.n_locally_owned();
378 std::vector<ScalarHostVector<Number>> components(
379 selection.components.size());
380 std::vector<Number *> destinations;
381 for (
auto &it : components) {
382 it.reinit(offline_data.scalar_partitioner());
383 destinations.push_back(it.begin());
386 const auto read = reader<MemorySpace>(selection, state_vector);
387 auto *
const *data = destinations.data();
389 loop<MemorySpace, Number>(
390 "postprocessor_extract",
391 [=](
auto sentinel,
const unsigned int i) {
392 using T =
decltype(sentinel);
393 read(sentinel, i, [&](
const unsigned int k,
const T &value) {
394 if constexpr (std::is_same_v<T, dealii::VectorizedArray<Number>>)
395 value.store(data[k] + i);
404 for (
auto &it : components)
405 it.update_ghost_values();
411 const auto sparsity_simd_view = offline_data.sparsity_pattern_simd().view();
412 const auto lumped_mass_matrix_view =
413 offline_data.lumped_mass_matrix().template view<1>();
414 const auto cij_matrix_view = offline_data.cij_matrix().view();
416 std::vector<ScalarHostVector<Number>> extracted(selection.size());
417 for (
unsigned int k = 0; k < selection.size(); ++k) {
418 const auto operation = Operation(selection.quantities[k].first);
419 const auto first = selection.quantities[k].second;
420 auto &result = extracted[k];
422 if (operation == Operation::value) {
423 result = std::move(components[first]);
427 result.reinit(offline_data.scalar_partitioner());
428 const auto *operands = &components[first];
430 const auto body = [&](
auto sentinel,
unsigned int i) {
431 using T =
decltype(sentinel);
434 const unsigned int row_length = sparsity_simd_view.row_length(i);
438 const unsigned int stride_size = sparsity_simd_view.stride_of_row(i);
440 dealii::Tensor<1, dim, T> gradient;
441 dealii::Tensor<1, dim == 2 ? 1 : dim, T> curl;
443 const unsigned int *js = sparsity_simd_view.columns(i);
444 for (
unsigned int col_idx = 0; col_idx < row_length;
445 ++col_idx, js += stride_size) {
447 const auto c_ij = cij_matrix_view.template read_tensor<T>(i, col_idx);
449 if (operation == Operation::schlieren) {
450 gradient -= c_ij * read_entry<T>(operands[0], js);
453 dealii::Tensor<1, dim, T> u_j;
454 for (
unsigned int d = 0; d < dim; ++d)
455 u_j[d] = read_entry<T>(operands[d], js);
457 if constexpr (dim == 2) {
458 curl[0] -= cross_product_2d(c_ij) * u_j;
459 }
else if constexpr (dim == 3) {
460 curl -= cross_product_3d(c_ij, u_j);
465 const auto m_i = lumped_mass_matrix_view.template read_entry<T>(i);
468 if (operation == Operation::schlieren)
469 value_i = gradient.norm() / m_i;
471 value_i = (dim == 2 ? curl[0] / m_i : curl.norm() / m_i);
473 write_entry<T>(result, value_i, i);
476 cpu_simd_loop<Number>(
477 "postprocessor_postprocess", body, 0, n_internal, n_owned);
479 offline_data.affine_constraints().distribute(result);
480 result.update_ghost_values();
487 template <
typename Description,
int dim,
typename Number>
488 void Postprocessor<Description, dim, Number>::extract(
489 const Selection &selection,
490 const StateVector<Number> &state_vector,
491 const unsigned int *indices,
492 const unsigned int n_points,
493 Number *values)
const
496 std::all_of(selection.quantities.begin(),
497 selection.quantities.end(),
499 return Operation(it.first) == Operation::value;
501 dealii::ExcMessage(
"Postprocessed quantities cannot be extracted at "
502 "individual points."));
505 const auto read = reader<selected_memory_space_t>(selection, state_vector);
506 const auto n_components =
507 static_cast<unsigned int>(selection.components.size());
510 loop<selected_memory_space_t, Number>(
511 "postprocessor_extract_points",
512 [=](
auto ,
const unsigned int p) {
513 auto *values_p = values + p * n_components;
516 [=](
const unsigned int k,
const Number value) {
Postprocessor(const OfflineData< dim, Number > &offline_data, const HyperbolicSystem &hyperbolic_system, const Interface::ParabolicSystem ¶bolic_system, const MultiComponentVector< Number > &initial_precomputed)
std::vector< ScalarHostVector< Number > > extract(const Selection &selection, const StateVector< Number > &state_vector) const override
typename Description::HyperbolicSystem HyperbolicSystem
Selection prepare(const std::vector< std::string > &selected) const override
void extract(const Selection &selection, const StateVector< Number > &state_vector, const unsigned int *indices, const unsigned int n_points, Number *values) const override
typename Interface::Postprocessor< dim, Number >::Selection Selection