10#include <similie/misc/clamp_to_domain.hpp>
11#include <similie/misc/factorial.hpp>
12#include <similie/misc/small_matrix.hpp>
13#include <similie/misc/specialization.hpp>
14#include <similie/misc/type_seq_conversion.hpp>
15#include <similie/tensor/antisymmetric_tensor.hpp>
16#include <similie/tensor/character.hpp>
17#include <similie/tensor/full_tensor.hpp>
18#include <similie/tensor/prime.hpp>
19#include <similie/tensor/tensor_impl.hpp>
30template <
class ElemType>
31struct FlatNaturalElemRank;
33template <
class... Tags>
34struct FlatNaturalElemRank<ddc::DiscreteElement<Tags...>>
36 static constexpr std::size_t value = (FlatNaturalElemRank<Tags>::value + ... + 0);
40struct FlatNaturalElemRank
42 static constexpr std::size_t value = 1;
45template <
class ElemType, std::
size_t N>
46KOKKOS_FUNCTION
void copy_flat_natural_elem_ids(
47 std::array<std::size_t, N>& ids,
51 auto const entries = ddc::detail::array(elem);
52 if constexpr (std::tuple_size_v<
decltype(entries)> == 0) {
55 using EntryType = std::remove_cvref_t<
decltype(entries[0])>;
56 if constexpr (std::is_same_v<EntryType, std::size_t>) {
57 for (std::size_t i = 0; i < entries.size(); ++i) {
58 ids[offset++] = entries[i];
61 for (std::size_t i = 0; i < entries.size(); ++i) {
62 copy_flat_natural_elem_ids(ids, offset, entries[i]);
68template <
class ElemType>
69KOKKOS_FUNCTION
auto flat_natural_elem_ids(ElemType
const& elem)
71 std::array<std::size_t, FlatNaturalElemRank<ElemType>::value> ids {};
72 std::size_t offset = 0;
73 copy_flat_natural_elem_ids(ids, offset, elem);
77template <
class ElemType, std::
size_t N>
78KOKKOS_FUNCTION
void assign_flat_natural_elem_ids(
80 std::array<std::size_t, N>
const& ids,
83 auto entries = ddc::detail::array(elem);
84 if constexpr (std::tuple_size_v<
decltype(entries)> == 0) {
87 using EntryType = std::remove_cvref_t<
decltype(entries[0])>;
88 if constexpr (std::is_same_v<EntryType, std::size_t>) {
89 for (std::size_t i = 0; i < entries.size(); ++i) {
90 entries[i] = ids[offset++];
92 ddc::detail::array(elem) = entries;
94 for (std::size_t i = 0; i < entries.size(); ++i) {
95 assign_flat_natural_elem_ids(entries[i], ids, offset);
97 ddc::detail::array(elem) = entries;
102template <
class ElemType, std::
size_t N>
103KOKKOS_FUNCTION ElemType natural_elem_from_flat_ids(std::array<std::size_t, N>
const& ids)
106 FlatNaturalElemRank<ElemType>::value == N,
107 "Flat natural element ids must match the element rank.");
109 std::size_t offset = 0;
110 assign_flat_natural_elem_ids(elem, ids, offset);
114template <misc::Specialization<ddc::detail::TypeSeq> Indices>
115struct ReductionTargetIndex;
118struct ReductionTargetIndex<ddc::detail::TypeSeq<>>
120 using type = tensor::Covariant<tensor::ScalarIndex>;
123template <tensor::TensorNatIndex Index>
124struct ReductionTargetIndex<ddc::detail::TypeSeq<Index>>
129template <tensor::TensorNatIndex... Index>
130 requires(
sizeof...(Index) > 1)
131struct ReductionTargetIndex<ddc::detail::TypeSeq<Index...>>
133 using type = tensor::TensorAntisymmetricIndex<Index...>;
136template <std::
size_t N>
137KOKKOS_FUNCTION
bool has_unique_reduction_ids(std::array<std::size_t, N>
const& ids)
139 for (std::size_t i = 0; i < N; ++i) {
140 for (std::size_t j = i + 1; j < N; ++j) {
141 if (ids[i] == ids[j]) {
149template <std::
size_t N>
150KOKKOS_FUNCTION
bool have_same_reduction_ids(
151 std::array<std::size_t, N>
const& lhs,
152 std::array<std::size_t, N>
const& rhs)
154 for (std::size_t i = 0; i < N; ++i) {
155 if (lhs[i] != rhs[i]) {
162template <std::
size_t K>
163KOKKOS_FUNCTION
double reduction_determinant(std::array<double, K * K>
const& matrix)
165 if constexpr (K == 0) {
167 }
else if constexpr (K == 1) {
171 for (std::size_t col = 0; col < K; ++col) {
172 std::array<double, (K - 1) * (K - 1)> minor {};
173 for (std::size_t row = 1; row < K; ++row) {
174 std::size_t minor_col = 0;
175 for (std::size_t source_col = 0; source_col < K; ++source_col) {
176 if (source_col == col) {
179 minor[(row - 1) * (K - 1) + minor_col] = matrix[row * K + source_col];
183 double const sign = (col % 2 == 0) ? 1. : -1.;
184 det += sign * matrix[col] * reduction_determinant<K - 1>(minor);
190template <std::
size_t N, std::
size_t K>
191KOKKOS_FUNCTION std::array<std::size_t, K> combination_from_rank(std::size_t rank)
193 std::array<std::size_t, K> ids {};
194 if constexpr (K == 0) {
197 std::size_t next_candidate = 0;
198 for (std::size_t i = 0; i < K; ++i) {
199 for (std::size_t candidate = next_candidate; candidate < N; ++candidate) {
200 std::size_t
const remaining = K - i - 1;
201 std::size_t
const remaining_space = N - candidate - 1;
202 std::size_t
const count
203 = (remaining == 0) ? 1
207 next_candidate = candidate + 1;
217template <std::
size_t N, std::
size_t K>
218KOKKOS_FUNCTION std::size_t combination_rank(std::array<std::size_t, K>
const& ids)
220 if constexpr (K == 0) {
223 std::size_t rank = 0;
224 std::size_t next_candidate = 0;
225 for (std::size_t i = 0; i < K; ++i) {
226 for (std::size_t candidate = next_candidate; candidate < ids[i]; ++candidate) {
227 std::size_t
const remaining = K - i - 1;
228 std::size_t
const remaining_space = N - candidate - 1;
229 rank += (remaining == 0) ? 1
232 next_candidate = ids[i] + 1;
238template <std::
size_t N, std::
size_t M>
239KOKKOS_FUNCTION
bool hodge_has_unique_ids(std::array<std::size_t, M>
const& ids)
241 if constexpr (M > 0) {
242 for (std::size_t i = 0; i < M; ++i) {
246 for (std::size_t j = i + 1; j < M; ++j) {
247 if (ids[i] == ids[j]) {
256template <std::
size_t N, std::
size_t M1, std::
size_t M2>
257KOKKOS_FUNCTION
bool hodge_is_complete_permutation(
258 std::array<std::size_t, M1>
const& source_ids,
259 std::array<std::size_t, M2>
const& target_ids)
261 std::array<int, N> counts {};
262 for (std::size_t
id : source_ids) {
268 for (std::size_t
id : target_ids) {
274 for (
int count : counts) {
282template <std::
size_t N, std::
size_t M1, std::
size_t M2>
283KOKKOS_FUNCTION
int hodge_permutation_sign(
284 std::array<std::size_t, M1>
const& source_ids,
285 std::array<std::size_t, M2>
const& target_ids)
287 std::array<std::size_t, N> permutation {};
288 for (std::size_t i = 0; i < M1; ++i) {
289 permutation[i] = source_ids[i];
291 if constexpr (M2 > 0) {
292 for (std::size_t i = 0; i < M2; ++i) {
293 permutation[M1 + i] = target_ids[i];
298 for (std::size_t i = 0; i < N; ++i) {
299 for (std::size_t j = i + 1; j < N; ++j) {
300 odd = (permutation[i] > permutation[j]) != odd;
306template <std::
size_t N, std::
size_t M>
307KOKKOS_FUNCTION std::array<std::size_t, N - M> hodge_complement_ids(
308 std::array<std::size_t, M>
const& ids)
310 std::array<std::size_t, N - M> complement {};
311 std::size_t complement_id = 0;
312 for (std::size_t i = 0; i < N; ++i) {
314 for (std::size_t
id : ids) {
315 found = found || (
id == i);
318 complement[complement_id++] = i;
324template <
class PositionIndex,
class PositionType,
class BatchElem, std::
size_t K>
325KOKKOS_FUNCTION
double primal_reconstruction_diagonal(
326 PositionType position,
328 std::array<std::size_t, K>
const& ids)
330 if constexpr (K == 0) {
333 std::array<double, K * K> jacobian_matrix {};
334 for (std::size_t row = 0; row < K; ++row) {
335 for (std::size_t col = 0; col < K; ++col) {
336 std::array<double, PositionIndex::size()>
const edge
337 = sil::exterior::detail::edge_vector<
338 PositionIndex>(position, elem, ids[col]);
339 jacobian_matrix[row * K + col] = edge[ids[row]];
342 double const jacobian = reduction_determinant<K>(jacobian_matrix);
343 if (Kokkos::abs(jacobian) < 1e-14) {
346 return 1. / jacobian;
350template <std::
size_t N, std::
size_t K,
class MetricType,
class BatchElem>
351KOKKOS_FUNCTION
double continuous_hodge_value_from_ids(
354 std::array<std::size_t, K>
const& source_ids,
355 std::array<std::size_t, N - K>
const& target_ids)
357 if (!hodge_has_unique_ids<N>(source_ids) || !hodge_has_unique_ids<N>(target_ids)
358 || !hodge_is_complete_permutation<N>(source_ids, target_ids)) {
362 std::array<std::size_t, K>
const complement = hodge_complement_ids<N>(target_ids);
364 = ddc::type_seq_element_t<0, ddc::to_type_seq_t<typename MetricType::indices_domain_t>>;
367 std::array<double, N * N> metric_alloc {};
368 std::array<double, N * N> determinant_metric_alloc {};
369 std::array<double, N * N> inverse_metric_alloc {};
370 std::array<double, N * N> workspace_alloc {};
371 std::array<double, K * K> submatrix_alloc {};
372 for (std::size_t i = 0; i < N; ++i) {
373 for (std::size_t j = 0; j < N; ++j) {
374 metric_alloc[i * N + j] = metric.get(metric.access_element(
376 ddc::DiscreteElement<MetricIndex1, MetricIndex2>(i, j)));
379 determinant_metric_alloc = metric_alloc;
383 typename MetricType::memory_space>(determinant_metric_alloc.data(), N, N);
389 typename MetricType::memory_space>(inverse_metric_alloc.data(), N, N);
396 return Kokkos::sqrt(Kokkos::abs(determinant))
397 *
static_cast<double>(hodge_permutation_sign<N>(complement, target_ids))
399 K>(inverse_metric_view, source_ids, complement, submatrix_alloc)
410KOKKOS_FUNCTION
double legacy_discrete_hodge_value_from_ids(
412 PositionType position,
414 std::array<std::size_t, K>
const& source_ids,
415 std::array<std::size_t, N - K>
const& target_ids)
417 if (!hodge_has_unique_ids<N>(source_ids) || !hodge_has_unique_ids<N>(target_ids)
418 || !hodge_is_complete_permutation<N>(source_ids, target_ids)) {
421 double const primal_volume
422 = SimplexVolume<CellComplex::Primal, N, MetricType, PositionType, BatchElem>::
423 template run<K>(metric, position, elem, source_ids);
424 if (primal_volume == 0.) {
428 return static_cast<double>(hodge_permutation_sign<N>(source_ids, target_ids))
429 * DualSimplexVolume<Complex, N, MetricType, PositionType, BatchElem>::template run<
430 K>(metric, position, elem, source_ids)
434template <
class ReductionNaturalElemType, std::
size_t N1, std::
size_t N2>
435KOKKOS_FUNCTION ReductionNaturalElemType merge_reduction_natural_elems(
436 std::array<std::size_t, N1>
const& first_ids,
437 std::array<std::size_t, N2>
const& second_ids)
439 std::array<std::size_t, N1 + N2> reduction_ids {};
440 for (std::size_t i = 0; i < N1; ++i) {
441 reduction_ids[i] = first_ids[i];
443 for (std::size_t i = 0; i < N2; ++i) {
444 reduction_ids[N1 + i] = second_ids[i];
446 return natural_elem_from_flat_ids<ReductionNaturalElemType>(reduction_ids);
451template <misc::Specialization<ddc::detail::TypeSeq> Indices>
454template <misc::Specialization<ddc::detail::TypeSeq> Indices>
459 ddc::detail::TypeSeq<reduction_index_t<Indices>>>>;
461template <misc::Specialization<ddc::detail::TypeSeq> Indices>
463 = ddc::detail::convert_type_seq_to_discrete_domain_t<ddc::type_seq_merge_t<
464 ddc::detail::TypeSeq<reduction_index_t<Indices>>,
465 ddc::detail::TypeSeq<reduction_index_t<tensor::primes<Indices>>>>>;
483 type_seq_element_t<0, ddc::to_type_seq_t<typename PositionType::indices_domain_t>>;
488 KOKKOS_FUNCTION
static void run(
489 ReductionTensorType reduced_tensor,
490 FormTensorType form_tensor,
491 PositionType position,
494 using reduction_accessor_t
496 using reduction_natural_elem_type =
497 typename reduction_accessor_t::natural_domain_t::discrete_element_type;
498 using form_natural_elem_type =
499 typename FormTensorType::accessor_t::natural_domain_t::discrete_element_type;
500 if constexpr (target_index_type::rank() == 0) {
501 reduced_tensor.mem(ddc::DiscreteElement<target_index_type>(0))
502 = form_tensor.get(form_tensor.access_element(form_natural_elem_type()));
505 ddc::device_for_each(reduced_tensor.domain(), [&](
auto target_mem_elem) {
506 auto const target_natural_elem
507 = reduced_tensor.canonical_natural_element(target_mem_elem);
508 double reduced_value = 0.;
509 ddc::device_for_each(
510 source_accessor.natural_domain(),
511 [&](auto source_natural_elem) {
512 reduction_natural_elem_type reduction_natural_elem;
513 auto const source_ids = ddc::detail::array(source_natural_elem);
514 auto const target_ids = ddc::detail::array(target_natural_elem);
515 reduction_natural_elem = detail::merge_reduction_natural_elems<
516 reduction_natural_elem_type>(source_ids, target_ids);
518 form_natural_elem_type form_natural_elem;
519 ddc::detail::array(form_natural_elem)
520 = ddc::detail::array(source_natural_elem);
522 reduced_value += value(position, elem, reduction_natural_elem)
524 form_tensor.access_element(form_natural_elem));
526 reduced_tensor.mem(target_mem_elem) = reduced_value;
535 KOKKOS_FUNCTION
static void run(
536 ReductionTensorType reduced_tensor,
537 FormTensorType form_tensor,
539 PositionType position,
543 run(reduced_tensor, form_tensor, position, elem);
547 "Metric-aware reduction is only implemented for the circumcentric dual "
550 constexpr std::size_t N = position_index_type::size();
551 constexpr std::size_t Q = target_index_type::rank();
552 constexpr std::size_t K = N - Q;
556 "Complementary basis sizes must match.");
558 std::array<double, NBASIS * NBASIS> coeff_from_primal_alloc {};
559 std::array<double, NBASIS * NBASIS> coeff_from_primal_inverse_alloc {};
560 std::array<double, NBASIS * NBASIS> old_hodge_alloc {};
561 std::array<double, NBASIS * NBASIS> dual_reduction_alloc {};
563 for (std::size_t primal_id = 0; primal_id < NBASIS; ++primal_id) {
564 std::array<std::size_t, K>
const primal_ids
565 = detail::combination_from_rank<N, K>(primal_id);
566 double const reconstruction_diag = detail::primal_reconstruction_diagonal<
568 for (std::size_t source_id = 0; source_id < NBASIS; ++source_id) {
569 std::array<std::size_t, Q>
const source_ids
570 = detail::combination_from_rank<N, Q>(source_id);
571 coeff_from_primal_alloc[source_id * NBASIS + primal_id]
572 = detail::continuous_hodge_value_from_ids<
574 K>(metric, elem, primal_ids, source_ids)
575 * reconstruction_diag;
577 for (std::size_t target_id = 0; target_id < NBASIS; ++target_id) {
578 std::array<std::size_t, Q>
const target_ids
579 = detail::combination_from_rank<N, Q>(target_id);
580 old_hodge_alloc[target_id * NBASIS + primal_id]
581 = detail::legacy_discrete_hodge_value_from_ids<
584 K>(metric, position, elem, primal_ids, target_ids);
588 std::array<double, NBASIS * NBASIS> workspace_alloc {};
591 typename MetricType::
592 memory_space>(coeff_from_primal_alloc.data(), NBASIS, NBASIS);
595 typename MetricType::
596 memory_space>(coeff_from_primal_inverse_alloc.data(), NBASIS, NBASIS);
599 typename MetricType::memory_space>(workspace_alloc.data(), NBASIS * NBASIS);
601 invert(coeff_from_primal_inverse_view, coeff_from_primal_view, workspace);
603 ddc::device_for_each(reduced_tensor.domain(), [&](
auto target_mem_elem) {
604 auto const target_natural_elem
605 = reduced_tensor.canonical_natural_element(target_mem_elem);
606 std::size_t const target_id = [&]() {
607 if constexpr (Q == 0) {
608 return std::size_t(0);
610 std::array<std::size_t, Q> const target_ids
611 = ddc::detail::array(target_natural_elem);
612 return detail::combination_rank<N, Q>(target_ids);
616 double reduced_value = 0.;
617 ddc::device_for_each(form_tensor.domain(), [&](
auto source_mem_elem) {
618 auto const source_natural_elem
619 = form_tensor.canonical_natural_element(source_mem_elem);
620 std::size_t const source_id = [&]() {
621 if constexpr (Q == 0) {
622 return std::size_t(0);
624 std::array<std::size_t, Q> const source_ids
625 = ddc::detail::array(source_natural_elem);
626 return detail::combination_rank<N, Q>(source_ids);
629 double dual_reduction_value = 0.;
631 for (std::size_t primal_id = 0; primal_id < NBASIS; ++primal_id) {
632 dual_reduction_value += old_hodge_alloc[target_id * NBASIS + primal_id]
633 * coeff_from_primal_inverse_alloc
634 [primal_id * NBASIS + source_id];
638 using form_natural_elem_type =
typename FormTensorType::accessor_t::
639 natural_domain_t::discrete_element_type;
640 form_natural_elem_type form_natural_elem;
641 ddc::detail::array(form_natural_elem) = ddc::detail::array(source_natural_elem);
642 reduced_value += dual_reduction_value * form_tensor.mem(source_mem_elem);
644 reduced_tensor.mem(target_mem_elem) = reduced_value;
649 KOKKOS_FUNCTION
static double value(PositionType position, BatchElem elem,
auto natural_elem)
651 constexpr std::size_t K = target_index_type::rank();
652 if constexpr (K == 0) {
655 std::array
const source_ids
657 std::array
const target_ids
659 if (!detail::has_unique_reduction_ids<K>(source_ids)
660 || !detail::has_unique_reduction_ids<K>(target_ids)) {
664 std::array<double, K * K> jacobian_matrix {};
665 for (std::size_t row = 0; row < K; ++row) {
666 for (std::size_t col = 0; col < K; ++col) {
667 std::array<double, position_index_type::size()>
const edge
668 = sil::exterior::detail::edge_vector<
670 jacobian_matrix[row * K + col] = edge[source_ids[row]];
673 return detail::reduction_determinant<K>(jacobian_matrix)
674 * detail::complex_volume_factor<Complex, source_index_type::size()>(K)
675 / misc::factorial(K);
679 template <misc::Specialization<tensor::Tensor> MetricType>
680 KOKKOS_FUNCTION
static double value(
682 PositionType position,
686 if constexpr (Complex == CellComplex::Primal) {
687 return value(position, elem, natural_elem);
690 std::array<double, source_index_type::access_size()> source_alloc {};
693 ddc::DiscreteDomain<source_index_type>,
694 Kokkos::layout_right,
695 typename MetricType::memory_space>
696 source_span(source_alloc.data(), source_accessor.
domain());
698 ddc::device_for_each(source_tensor.domain(), [&](
auto source_mem_elem) {
699 source_tensor.mem(source_mem_elem) = 0.;
703 std::array<double, target_index_type::access_size()> target_alloc {};
706 ddc::DiscreteDomain<target_index_type>,
707 Kokkos::layout_right,
708 typename MetricType::memory_space>
709 target_span(target_alloc.data(), target_accessor.
domain());
711 ddc::device_for_each(target_tensor.domain(), [&](
auto target_mem_elem) {
712 target_tensor.mem(target_mem_elem) = 0.;
716 ddc::detail::array(source_natural_elem)
718 if constexpr (source_index_type::rank() > 1) {
719 if (!detail::has_unique_reduction_ids(ddc::detail::array(source_natural_elem))) {
723 source_tensor(source_tensor.accessor().access_element(source_natural_elem)) = 1.;
725 run(target_tensor, source_tensor, metric, position, elem);
727 if constexpr (target_index_type::rank() == 0) {
728 return target_tensor.get(
732 ddc::detail::array(target_natural_elem)
734 return target_tensor.get(
735 target_tensor.accessor().access_element(target_natural_elem));
749 ReductionTensorType m_reduction_tensor;
750 PositionType m_position;
753 template <
class MemElem>
754 KOKKOS_FUNCTION
void operator()(MemElem mem_elem)
const
756 m_reduction_tensor.mem(
757 typename ReductionTensorType::discrete_element_type(m_elem, mem_elem))
761 m_reduction_tensor.accessor().canonical_natural_element(mem_elem));
772 ExecSpace
const& exec_space,
773 ReductionTensorType reduction_tensor,
774 PositionType position)
776 SIMILIE_DEBUG_LOG(
"similie_compute_reduction_operator");
777 ddc::parallel_for_each(
778 "similie_compute_reduction_operator",
780 reduction_tensor.non_indices_domain(),
782 typename ReductionTensorType::non_indices_domain_t::discrete_element_type
784 ddc::device_for_each(
785 reduction_tensor.accessor().domain(),
791 typename ReductionTensorType::non_indices_domain_t::
792 discrete_element_type> {reduction_tensor, position, elem});
794 return reduction_tensor;
814 KOKKOS_FUNCTION
static void run(
815 ReconstructedTensorType reconstructed_tensor,
816 CochainTensorType cochain_tensor,
817 PositionType position,
820 using reconstruction_accessor_t
822 using reconstruction_natural_elem_type =
823 typename reconstruction_accessor_t::natural_domain_t::discrete_element_type;
824 using cochain_natural_elem_type =
825 typename CochainTensorType::accessor_t::natural_domain_t::discrete_element_type;
826 if constexpr (source_index_type::rank() == 0) {
827 reconstructed_tensor.mem(ddc::DiscreteElement<source_index_type>(0))
828 = cochain_tensor.get(
829 cochain_tensor.access_element(cochain_natural_elem_type()));
832 ddc::device_for_each(reconstructed_tensor.domain(), [&](
auto target_mem_elem) {
833 auto const target_natural_elem
834 = reconstructed_tensor.canonical_natural_element(target_mem_elem);
835 double reconstructed_value = 0.;
836 ddc::device_for_each(source_accessor.domain(), [&](auto source_mem_elem) {
837 auto const source_natural_elem
838 = source_accessor.canonical_natural_element(source_mem_elem);
839 reconstruction_natural_elem_type reconstruction_natural_elem;
840 reconstruction_natural_elem = detail::merge_reduction_natural_elems<
841 reconstruction_natural_elem_type>(
842 ddc::detail::array(source_natural_elem),
843 ddc::detail::array(target_natural_elem));
845 cochain_natural_elem_type cochain_natural_elem;
846 ddc::detail::array(cochain_natural_elem)
847 = ddc::detail::array(source_natural_elem);
849 reconstructed_value += value(position, elem, reconstruction_natural_elem)
850 * cochain_tensor.get(cochain_tensor.access_element(
851 cochain_natural_elem));
853 reconstructed_tensor.mem(target_mem_elem) = reconstructed_value;
858 KOKKOS_FUNCTION
static double value(PositionType position, BatchElem elem,
auto natural_elem)
861 Complex != CellComplex::BarycentricDual,
862 "Reconstruction is not implemented for the barycentric dual complex.");
863 constexpr std::size_t K = source_index_type::rank();
864 if constexpr (K == 0) {
867 std::array
const source_ids
869 std::array
const target_ids
871 using reduction_accessor_t
873 using reduction_natural_elem_type =
874 typename reduction_accessor_t::natural_domain_t::discrete_element_type;
875 reduction_natural_elem_type reduction_natural_elem
876 = detail::merge_reduction_natural_elems<
877 reduction_natural_elem_type>(source_ids, target_ids);
879 value(position, elem, reduction_natural_elem);
881 if (!detail::have_same_reduction_ids<K>(source_ids, target_ids)) {
882 assert(Kokkos::abs(reduction_value) < 1e-14
883 &&
"Reconstruction assumes a diagonal local reduction operator.");
887 if (Kokkos::abs(reduction_value) < 1e-14) {
890 return 1. / (misc::factorial(K) * reduction_value);
903 ReconstructionTensorType m_reconstruction_tensor;
904 PositionType m_position;
907 template <
class MemElem>
908 KOKKOS_FUNCTION
void operator()(MemElem mem_elem)
const
910 m_reconstruction_tensor.mem(
911 typename ReconstructionTensorType::discrete_element_type(m_elem, mem_elem))
915 m_reconstruction_tensor.accessor().canonical_natural_element(
927 ExecSpace
const& exec_space,
928 ReconstructionTensorType reconstruction_tensor,
929 PositionType position)
931 SIMILIE_DEBUG_LOG(
"similie_compute_reconstruction_operator");
932 ddc::parallel_for_each(
933 "similie_compute_reconstruction_operator",
935 reconstruction_tensor.non_indices_domain(),
937 typename ReconstructionTensorType::non_indices_domain_t::discrete_element_type
939 ddc::device_for_each(
940 reconstruction_tensor.accessor().domain(),
943 ReconstructionTensorType,
946 typename ReconstructionTensorType::non_indices_domain_t::
947 discrete_element_type> {
948 reconstruction_tensor,
952 return reconstruction_tensor;
static constexpr discrete_domain_type domain()
ReconstructionTensorType fill_reconstruction_operator(ExecSpace const &exec_space, ReconstructionTensorType reconstruction_tensor, PositionType position)
ddc::detail::convert_type_seq_to_discrete_domain_t< ddc::type_seq_merge_t< ddc::detail::TypeSeq< reduction_index_t< Indices > >, ddc::detail::TypeSeq< reduction_index_t< tensor::primes< Indices > > > > > reconstruction_domain_t
typename detail::ReductionTargetIndex< Indices >::type reduction_index_t
ddc::detail::convert_type_seq_to_discrete_domain_t< ddc::type_seq_merge_t< ddc::detail::TypeSeq< misc::convert_type_seq_to_t< tensor::TensorFullIndex, tensor::primes< tensor::upper_t< Indices > > > >, ddc::detail::TypeSeq< reduction_index_t< Indices > > > > reduction_domain_t
ReductionTensorType fill_reduction_operator(ExecSpace const &exec_space, ReductionTensorType reduction_tensor, PositionType position)
KOKKOS_FUNCTION bool invert(InverseView inverse, MatrixView matrix, WorkspaceView workspace)
KOKKOS_FUNCTION unmanaged_vector_view_t< Scalar, MemorySpace > vector_view(Scalar *data, std::size_t n)
KOKKOS_FUNCTION double submatrix_determinant(MatrixView matrix, RowIds const &row_ids, ColIds const &col_ids, std::array< double, N *N > &submatrix_alloc)
KOKKOS_FUNCTION unmanaged_matrix_view_t< Scalar, MemorySpace > matrix_view(Scalar *data, std::size_t rows, std::size_t cols)
KOKKOS_FUNCTION MatrixView::non_const_value_type determinant(MatrixView matrix)
constexpr std::size_t factorial(std::size_t k) noexcept
constexpr std::size_t binomial_coefficient(std::size_t n, std::size_t k) noexcept
typename detail::ConvertTypeSeqTo< T, Seq >::type convert_type_seq_to_t
Tensor(ddc::Chunk< ElementType, SupportType, Allocator >) -> Tensor< ElementType, SupportType, Kokkos::layout_right, typename Allocator::memory_space >
ddc::type_seq_element_t< 0, ddc::to_type_seq_t< typename MetricIndex::subindices_domain_t > > metric_index_1
detail::Primes< Indices, I >::type primes
ddc::type_seq_element_t< 1, ddc::to_type_seq_t< typename MetricIndex::subindices_domain_t > > metric_index_2
typename detail::NaturalDomainType< Index >::type natural_domain_t
detail::TensorAccessorForDomain< Dom >::type tensor_accessor_for_domain_t
The top-level namespace of SimiLie.
reduction_index_t< Indices > source_index_type
reduction_index_t< tensor::primes< Indices > > target_index_type
typename tensor::natural_domain_t< target_index_type >::discrete_element_type target_natural_elem_type
typename tensor::natural_domain_t< source_index_type >::discrete_element_type source_natural_elem_type
reduction_index_t< Indices > target_index_type
misc::convert_type_seq_to_t< tensor::TensorFullIndex, tensor::primes< tensor::upper_t< Indices > > > source_index_type
typename tensor::natural_domain_t< target_index_type >::discrete_element_type target_natural_elem_type
static KOKKOS_FUNCTION void run(ReductionTensorType reduced_tensor, FormTensorType form_tensor, PositionType position, BatchElem elem)
ddc:: type_seq_element_t< 0, ddc::to_type_seq_t< typename PositionType::indices_domain_t > > position_index_type
typename tensor::natural_domain_t< source_index_type >::discrete_element_type source_natural_elem_type