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 Interface::OfflineData<dim, Number>>
116 dealii::ObserverPointer<const HyperbolicSystem> hyperbolic_system_;
117 dealii::ObserverPointer<const Interface::ParabolicSystem> parabolic_system_;
118 const MultiComponentVector<Number> &initial_precomputed_;
130 template <
typename Description,
int dim,
typename Number>
132 const Interface::OfflineData<dim, Number> &offline_data,
133 const HyperbolicSystem &hyperbolic_system,
134 const Interface::ParabolicSystem ¶bolic_system,
135 const MultiComponentVector<Number> &initial_precomputed)
136 : offline_data_(&offline_data)
137 , hyperbolic_system_(&hyperbolic_system)
138 , parabolic_system_(¶bolic_system)
139 , initial_precomputed_(initial_precomputed)
144 template <
typename Description,
int dim,
typename Number>
146 const std::vector<std::string> &selected)
const -> Selection
148 const auto &hyperbolic_system = *hyperbolic_system_;
150 Assert(hyperbolic_system.state_names(dim).size() ==
151 View::problem_dimension &&
152 hyperbolic_system.primitive_names(dim).size() ==
153 View::problem_dimension &&
154 hyperbolic_system.precomputed_names(dim).size() ==
155 View::n_precomputed_values &&
156 hyperbolic_system.initial_precomputed_names(dim).size() ==
157 View::n_initial_precomputed_values,
158 dealii::ExcMessage(
"The component names of the hyperbolic system "
159 "do not match the counts of its view."));
161 const std::vector<std::pair<Section, const std::vector<std::string> *>>
163 {Section::state, &hyperbolic_system.state_names(dim)},
164 {Section::primitive, &hyperbolic_system.primitive_names(dim)},
165 {Section::precomputed, &hyperbolic_system.precomputed_names(dim)},
166 {Section::initial_precomputed,
167 &hyperbolic_system.initial_precomputed_names(dim)},
168 {Section::dynamic_state, ¶bolic_system_->state_names(dim)},
175 const auto find = [&](
const std::string &name)
176 -> std::optional<std::tuple<Section, unsigned int, unsigned int>> {
177 for (
const auto &[section, names] : sections) {
178 const auto pos = std::find(names->begin(), names->end(), name);
179 if (pos != names->end())
180 return std::make_tuple(
182 static_cast<unsigned int>(pos - names->begin()),
183 static_cast<unsigned int>(names->size()));
188 const std::vector<std::pair<Operation, std::string>> prefixes{
189 {Operation::schlieren,
"schlieren_"},
190 {Operation::vorticity,
"vorticity_"},
195 for (
const auto &entry : selected) {
196 auto operation = Operation::value;
197 auto found = find(entry);
199 for (
const auto &[prefix_operation, prefix] : prefixes) {
200 if (found || entry.rfind(prefix, 0) != 0)
202 operation = prefix_operation;
203 found = find(entry.substr(prefix.size()));
208 "Invalid component name: \"" + entry +
209 "\" is not a valid conserved, primitive, precomputed, "
210 "initial, parabolic, or postprocessed "
213 const auto [section, index, n_names] = *found;
214 const unsigned int n_operands =
215 operation == Operation::vorticity ? dim : 1;
217 AssertThrow(operation != Operation::vorticity || dim > 1,
218 dealii::ExcMessage(
"Invalid component name: \"" + entry +
219 "\": the vorticity is not defined in "
220 "one spatial dimension."));
221 AssertThrow(index + n_operands <= n_names,
222 dealii::ExcMessage(
"Invalid component name: \"" + entry +
223 "\": the vorticity requires dim "
224 "consecutive components."));
226 selection.quantities.push_back(
227 {std::uint8_t(operation),
228 static_cast<unsigned int>(selection.components.size())});
229 for (
unsigned int d = 0; d < n_operands; ++d)
230 selection.components.push_back({std::uint8_t(section), index + d});
237 template <
typename Description,
int dim,
typename Number>
238 template <
typename MemorySpace>
239 auto Postprocessor<Description, dim, Number>::reader(
240 const Selection &selection,
const StateVector<Number> &state_vector)
const
242 const auto &selected = selection.components;
243 const auto selects = [&](
const Section section) {
244 return std::any_of(selected.begin(), selected.end(), [&](
const auto &it) {
245 return Section(it.first) == section;
249 const bool read_primitive = selects(Section::primitive);
250 const bool read_state = read_primitive || selects(Section::state);
251 const bool read_precomputed = selects(Section::precomputed);
252 const bool read_initial = selects(Section::initial_precomputed);
259 VectorView<View::problem_dimension, MemorySpace> U_view;
260 VectorView<View::n_precomputed_values, MemorySpace> precomputed_view;
261 VectorView<View::n_initial_precomputed_values, MemorySpace> initial_view;
264 copy_to_memory_space<MemorySpace>(state_vector, StateVectorPart::state);
265 U_view = state_vector.state
266 .template view<View::problem_dimension, MemorySpace>();
269 if (read_precomputed) {
270 copy_to_memory_space<MemorySpace>(state_vector,
271 StateVectorPart::precomputed);
273 state_vector.precomputed
274 .template view<View::n_precomputed_values, MemorySpace>();
278 copy_to_memory_space<MemorySpace>(initial_precomputed_);
281 .template view<View::n_initial_precomputed_values, MemorySpace>();
289 const auto n_components = selected.size();
290 Kokkos::View<Kokkos::pair<Section, unsigned int> *, Kokkos::HostSpace>
291 host_components(
"postprocessor_components", n_components);
292 Kokkos::View<VectorView<1, MemorySpace> *, Kokkos::HostSpace> host_scalars(
293 "postprocessor_scalars", n_components);
295 for (
unsigned int k = 0; k < n_components; ++k) {
296 const auto section = Section(selected[k].first);
297 const auto index = selected[k].second;
298 host_components[k] = {section, index};
300 if (section == Section::dynamic_state) {
301 const auto &vector = state_vector.dynamic_state[index];
302 copy_to_memory_space<MemorySpace>(vector);
303 host_scalars[k] = vector.template view<1, MemorySpace>();
307 const auto space =
typename MemorySpace::kokkos_space{};
308 const auto components =
309 Kokkos::create_mirror_view_and_copy(space, host_components);
311 Kokkos::create_mirror_view_and_copy(space, host_scalars);
313 const SelectView<dim, Number, MemorySpace, HyperbolicSystem> system_views(
314 *hyperbolic_system_);
316 return [=](
auto sentinel,
const unsigned int i,
const auto &write) {
317 using T =
decltype(sentinel);
325 decltype(U_view.template read_tensor<T>(i)) U_i;
327 U_i = U_view.template read_tensor<T>(i);
329 auto primitive_i = U_i;
331 primitive_i = system_views.template view<T>().to_primitive_state(U_i);
333 decltype(precomputed_view.template read_tensor<T>(i)) precomputed_i;
334 if (read_precomputed)
335 precomputed_i = precomputed_view.template read_tensor<T>(i);
337 decltype(initial_view.template read_tensor<T>(i)) initial_i;
339 initial_i = initial_view.template read_tensor<T>(i);
341 for (
unsigned int k = 0; k < components.extent(0); ++k) {
342 const auto [section, index] = components[k];
345 write(k, U_i[index]);
347 case Section::primitive:
348 write(k, primitive_i[index]);
350 case Section::precomputed:
351 write(k, precomputed_i[index]);
353 case Section::initial_precomputed:
354 write(k, initial_i[index]);
357 write(k, scalars[k].
template read_entry<T>(i));
364 template <
typename Description,
int dim,
typename Number>
365 std::vector<ScalarHostVector<Number>>
366 Postprocessor<Description, dim, Number>::extract(
367 const Selection &selection,
const StateVector<Number> &state_vector)
const
369 using MemorySpace = dealii::MemorySpace::Host;
371 const auto &offline_data = *offline_data_;
372 const unsigned int n_internal = offline_data.n_locally_internal();
373 const unsigned int n_owned = offline_data.n_locally_owned();
379 std::vector<ScalarHostVector<Number>> components(
380 selection.components.size());
381 std::vector<Number *> destinations;
382 for (
auto &it : components) {
383 it.reinit(offline_data.scalar_partitioner());
384 destinations.push_back(it.begin());
387 const auto read = reader<MemorySpace>(selection, state_vector);
388 auto *
const *data = destinations.data();
390 loop<MemorySpace, Number>(
391 "postprocessor_extract",
392 [=](
auto sentinel,
const unsigned int i) {
393 using T =
decltype(sentinel);
394 read(sentinel, i, [&](
const unsigned int k,
const T &value) {
395 if constexpr (std::is_same_v<T, dealii::VectorizedArray<Number>>)
396 value.store(data[k] + i);
405 for (
auto &it : components)
406 it.update_ghost_values();
412 const auto sparsity_simd_view = offline_data.sparsity_pattern_simd().view();
413 const auto lumped_mass_matrix_view =
414 offline_data.lumped_mass_matrix().template view<1>();
415 const auto cij_matrix_view = offline_data.cij_matrix().view();
417 std::vector<ScalarHostVector<Number>> extracted(selection.size());
418 for (
unsigned int k = 0; k < selection.size(); ++k) {
419 const auto operation = Operation(selection.quantities[k].first);
420 const auto first = selection.quantities[k].second;
421 auto &result = extracted[k];
423 if (operation == Operation::value) {
424 result = std::move(components[first]);
428 result.reinit(offline_data.scalar_partitioner());
429 const auto *operands = &components[first];
431 const auto body = [&](
auto sentinel,
unsigned int i) {
432 using T =
decltype(sentinel);
435 const unsigned int row_length = sparsity_simd_view.row_length(i);
439 const unsigned int stride_size = sparsity_simd_view.stride_of_row(i);
441 dealii::Tensor<1, dim, T> gradient;
442 dealii::Tensor<1, dim == 2 ? 1 : dim, T> curl;
444 const unsigned int *js = sparsity_simd_view.columns(i);
445 for (
unsigned int col_idx = 0; col_idx < row_length;
446 ++col_idx, js += stride_size) {
448 const auto c_ij = cij_matrix_view.template read_tensor<T>(i, col_idx);
450 if (operation == Operation::schlieren) {
451 gradient -= c_ij * read_entry<T>(operands[0], js);
454 dealii::Tensor<1, dim, T> u_j;
455 for (
unsigned int d = 0; d < dim; ++d)
456 u_j[d] = read_entry<T>(operands[d], js);
458 if constexpr (dim == 2) {
459 curl[0] -= cross_product_2d(c_ij) * u_j;
460 }
else if constexpr (dim == 3) {
461 curl -= cross_product_3d(c_ij, u_j);
466 const auto m_i = lumped_mass_matrix_view.template read_entry<T>(i);
469 if (operation == Operation::schlieren)
470 value_i = gradient.norm() / m_i;
472 value_i = (dim == 2 ? curl[0] / m_i : curl.norm() / m_i);
474 write_entry<T>(result, value_i, i);
477 cpu_simd_loop<Number>(
478 "postprocessor_postprocess", body, 0, n_internal, n_owned);
480 offline_data.affine_constraints().distribute(result);
481 result.update_ghost_values();
488 template <
typename Description,
int dim,
typename Number>
489 void Postprocessor<Description, dim, Number>::extract(
490 const Selection &selection,
491 const StateVector<Number> &state_vector,
492 const unsigned int *indices,
493 const unsigned int n_points,
494 Number *values)
const
497 std::all_of(selection.quantities.begin(),
498 selection.quantities.end(),
500 return Operation(it.first) == Operation::value;
502 dealii::ExcMessage(
"Postprocessed quantities cannot be extracted at "
503 "individual points."));
506 const auto read = reader<selected_memory_space_t>(selection, state_vector);
507 const auto n_components =
508 static_cast<unsigned int>(selection.components.size());
511 loop<selected_memory_space_t, Number>(
512 "postprocessor_extract_points",
513 [=](
auto ,
const unsigned int p) {
514 auto *values_p = values + p * n_components;
517 [=](
const unsigned int k,
const Number value) {
Postprocessor(const Interface::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