SimiLie
Loading...
Searching...
No Matches
hodge_star.hpp
1// SPDX-FileCopyrightText: 2024 Baptiste Legouix
2// SPDX-License-Identifier: MIT
3
4#pragma once
5
6#include <array>
7
8#include <ddc/ddc.hpp>
9
10#include <similie/misc/factorial.hpp>
11#include <similie/misc/macros.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/metric.hpp>
19
20#include "reduction_and_reconstruction.hpp"
21#include "volume.hpp"
22
23namespace sil {
24
25namespace exterior {
26
27template <
28 misc::Specialization<ddc::detail::TypeSeq> Indices1,
29 misc::Specialization<ddc::detail::TypeSeq> Indices2>
31 = ddc::detail::convert_type_seq_to_discrete_domain_t<ddc::type_seq_merge_t<
32 ddc::detail::TypeSeq<
34 std::conditional_t<
35 (ddc::type_seq_size_v<Indices2> == 0),
36 ddc::detail::TypeSeq<>,
37 ddc::detail::TypeSeq<misc::convert_type_seq_to_t<
39 Indices2>>>>>;
40
41template <
44 class MetricType,
45 class BatchElem>
47
48template <
49 CellComplex Complex,
52 class MetricType,
53 class PositionType,
54 class BatchElem>
56
57namespace detail {
58
59template <std::size_t N, std::size_t M>
60KOKKOS_FUNCTION bool has_unique_ids(std::array<std::size_t, M> const& ids)
61{
62 if constexpr (M > 0) {
63 for (std::size_t i = 0; i < M; ++i) {
64 if (ids[i] >= N) {
65 return false;
66 }
67 for (std::size_t j = i + 1; j < M; ++j) {
68 if (ids[i] == ids[j]) {
69 return false;
70 }
71 }
72 }
73 }
74 return true;
75}
76
77template <std::size_t N, std::size_t M1, std::size_t M2>
78KOKKOS_FUNCTION bool is_complete_permutation(
79 std::array<std::size_t, M1> const& source_ids,
80 std::array<std::size_t, M2> const& target_ids)
81{
82 std::array<int, N> counts {};
83 for (std::size_t id : source_ids) {
84 if (id >= N) {
85 return false;
86 }
87 counts[id]++;
88 }
89 for (std::size_t id : target_ids) {
90 if (id >= N) {
91 return false;
92 }
93 counts[id]++;
94 }
95 for (int count : counts) {
96 if (count != 1) {
97 return false;
98 }
99 }
100 return true;
101}
102
103template <std::size_t N, std::size_t M1, std::size_t M2>
104KOKKOS_FUNCTION int permutation_sign(
105 std::array<std::size_t, M1> const& source_ids,
106 std::array<std::size_t, M2> const& target_ids)
107{
108 std::array<std::size_t, N> permutation {};
109 for (std::size_t i = 0; i < M1; ++i) {
110 permutation[i] = source_ids[i];
111 }
112 if constexpr (M2 > 0) {
113 for (std::size_t i = 0; i < M2; ++i) {
114 permutation[M1 + i] = target_ids[i];
115 }
116 }
117
118 bool odd = false;
119 for (std::size_t i = 0; i < N; ++i) {
120 for (std::size_t j = i + 1; j < N; ++j) {
121 odd = (permutation[i] > permutation[j]) != odd;
122 }
123 }
124 return odd ? -1 : 1;
125}
126
127template <std::size_t N, std::size_t M>
128KOKKOS_FUNCTION std::array<std::size_t, N - M> complement_ids(std::array<std::size_t, M> const& ids)
129{
130 std::array<std::size_t, N - M> complement {};
131 std::size_t complement_id = 0;
132 for (std::size_t i = 0; i < N; ++i) {
133 bool found = false;
134 for (std::size_t id : ids) {
135 found = found || (id == i);
136 }
137 if (!found) {
138 complement[complement_id++] = i;
139 }
140 }
141 return complement;
142}
143
144template <misc::Specialization<ddc::detail::TypeSeq> Indices>
145struct HodgeStarTargetSize
146{
147 static constexpr std::size_t value
148 = misc::convert_type_seq_to_t<tensor::TensorAntisymmetricIndex, Indices>::access_size();
149};
150
151template <>
152struct HodgeStarTargetSize<ddc::detail::TypeSeq<>>
153{
154 static constexpr std::size_t value = 1;
155};
156
157template <
158 CellComplex Complex,
159 misc::Specialization<ddc::detail::TypeSeq> Indices1,
160 misc::Specialization<ddc::detail::TypeSeq> Indices2,
161 misc::Specialization<tensor::Tensor> HodgeStarType,
162 misc::Specialization<tensor::Tensor> MetricType,
163 misc::Specialization<tensor::Tensor> PositionType,
164 class BatchElem>
165struct FillDiscreteHodgeStarMem
166{
167 HodgeStarType m_hodge_star;
168 MetricType m_metric;
169 PositionType m_position;
170 BatchElem m_elem;
171
172 template <class MemElem>
173 KOKKOS_FUNCTION void operator()(MemElem mem_elem) const
174 {
175 m_hodge_star.mem(typename HodgeStarType::discrete_element_type(m_elem, mem_elem))
176 = DiscreteHodgeStar<
177 Complex,
178 Indices1,
179 Indices2,
180 MetricType,
181 PositionType,
182 BatchElem>::
183 value(m_metric,
184 m_position,
185 m_elem,
186 m_hodge_star.accessor().canonical_natural_element(mem_elem));
187 }
188};
189
190template <
191 misc::Specialization<ddc::detail::TypeSeq> Indices1,
192 misc::Specialization<ddc::detail::TypeSeq> Indices2,
193 misc::Specialization<tensor::Tensor> HodgeStarType,
194 misc::Specialization<tensor::Tensor> MetricType,
195 class BatchElem>
196struct FillContinuousHodgeStarMem
197{
198 HodgeStarType m_hodge_star;
199 MetricType m_metric;
200 BatchElem m_elem;
201
202 template <class MemElem>
203 KOKKOS_FUNCTION void operator()(MemElem mem_elem) const
204 {
205 m_hodge_star.mem(typename HodgeStarType::discrete_element_type(m_elem, mem_elem))
207 value(m_metric,
208 m_elem,
209 m_hodge_star.accessor().canonical_natural_element(mem_elem));
210 }
211};
212
213} // namespace detail
214
215template <
216 CellComplex Complex,
217 misc::Specialization<ddc::detail::TypeSeq> Indices1,
218 misc::Specialization<ddc::detail::TypeSeq> Indices2,
219 class MetricType,
220 class PositionType,
221 class BatchElem>
223{
224 template <
227 KOKKOS_FUNCTION static void run(
228 HodgeTensorType hodge_tensor,
229 FormTensorType form_tensor,
230 MetricType metric,
231 PositionType position,
232 BatchElem elem)
233 {
234 using InputIndex = ddc::type_seq_element_t<
235 0,
236 ddc::to_type_seq_t<typename FormTensorType::indices_domain_t>>;
237 using OutputIndex = ddc::type_seq_element_t<
238 0,
239 ddc::to_type_seq_t<typename HodgeTensorType::indices_domain_t>>;
240 using InputIndexSeq
241 = ddc::to_type_seq_t<typename FormTensorType::accessor_t::natural_domain_t>;
242 using OutputIndexSeq
243 = ddc::to_type_seq_t<typename HodgeTensorType::accessor_t::natural_domain_t>;
244
245 [[maybe_unused]] tensor::TensorAccessor<InputIndex> reconstructed_accessor;
246 std::array<double, InputIndex::access_size()> reconstructed_alloc {};
247 ddc::ChunkSpan<
248 double,
249 ddc::DiscreteDomain<InputIndex>,
250 Kokkos::layout_right,
251 typename FormTensorType::memory_space>
252 reconstructed_span(reconstructed_alloc.data(), reconstructed_accessor.domain());
253 sil::tensor::Tensor reconstructed_form(reconstructed_span);
254
255 [[maybe_unused]] tensor::TensorAccessor<OutputIndex> continuous_output_accessor;
256 std::array<double, OutputIndex::access_size()> continuous_output_alloc {};
257 ddc::ChunkSpan<
258 double,
259 ddc::DiscreteDomain<OutputIndex>,
260 Kokkos::layout_right,
261 typename HodgeTensorType::memory_space>
262 continuous_output_span(
263 continuous_output_alloc.data(),
264 continuous_output_accessor.domain());
265 sil::tensor::Tensor continuous_output(continuous_output_span);
266
268 run(reconstructed_form, form_tensor, position, elem);
270 run(continuous_output, reconstructed_form, metric, elem);
272 run(hodge_tensor, continuous_output, metric, position, elem);
273 }
275 KOKKOS_FUNCTION static double value(
276 MetricType metric,
277 PositionType position,
278 BatchElem elem,
279 auto natural_elem)
280 {
282 using TargetIndex = reduction_index_t<Indices2>;
283 using SourceNaturalElem =
285 using TargetNaturalElem =
289
290 [[maybe_unused]] tensor::TensorAccessor<SourceIndex> source_accessor;
291 std::array<double, SourceIndex::access_size()> source_alloc {};
292 ddc::ChunkSpan<
293 double,
294 ddc::DiscreteDomain<SourceIndex>,
295 Kokkos::layout_right,
296 typename MetricType::memory_space>
297 source_span(source_alloc.data(), source_accessor.domain());
298 sil::tensor::Tensor source_tensor(source_span);
299 ddc::device_for_each(source_tensor.domain(), [&](auto source_mem_elem) {
300 source_tensor.mem(source_mem_elem) = 0.;
301 });
302
303 [[maybe_unused]] tensor::TensorAccessor<TargetIndex> target_accessor;
304 std::array<double, TargetIndex::access_size()> target_alloc {};
305 ddc::ChunkSpan<
306 double,
307 ddc::DiscreteDomain<TargetIndex>,
308 Kokkos::layout_right,
309 typename MetricType::memory_space>
310 target_span(target_alloc.data(), target_accessor.domain());
311 sil::tensor::Tensor target_tensor(target_span);
312 ddc::device_for_each(target_tensor.domain(), [&](auto target_mem_elem) {
313 target_tensor.mem(target_mem_elem) = 0.;
314 });
315
316 std::array source_ids = ddc::detail::array(SourceFullElem(natural_elem));
317 if constexpr (ddc::type_seq_size_v<Indices1> > 1) {
318 if (!detail::has_unique_ids<SourceIndex::size()>(source_ids)) {
319 return 0.;
320 }
321 }
322 bool odd = false;
323 for (std::size_t i = 0; i < source_ids.size(); ++i) {
324 for (std::size_t j = i + 1; j < source_ids.size(); ++j) {
325 odd = (source_ids[i] > source_ids[j]) != odd;
326 }
327 }
328 std::array canonical_source_ids(source_ids);
329 if constexpr (source_ids.size() > 1) {
330 for (std::size_t i = 0; i < canonical_source_ids.size(); ++i) {
331 for (std::size_t j = i + 1; j < canonical_source_ids.size(); ++j) {
332 if (canonical_source_ids[j] < canonical_source_ids[i]) {
333 Kokkos::kokkos_swap(canonical_source_ids[i], canonical_source_ids[j]);
334 }
335 }
336 }
337 }
338
339 SourceNaturalElem source_natural_elem;
340 ddc::detail::array(source_natural_elem) = canonical_source_ids;
341 source_tensor(source_tensor.accessor().access_element(source_natural_elem)) = 1.;
342
343 run(target_tensor, source_tensor, metric, position, elem);
344
345 double const source_factor
346 = (odd ? -1. : 1.) / misc::factorial(ddc::type_seq_size_v<Indices1>);
347 if constexpr (ddc::type_seq_size_v<Indices2> == 0) {
348 return source_factor
349 * target_tensor(target_tensor.accessor().access_element(TargetNaturalElem()));
350 } else {
351 TargetNaturalElem target_natural_elem;
352 ddc::detail::array(target_natural_elem)
353 = ddc::detail::array(TargetFullElem(natural_elem));
354 return source_factor
355 * target_tensor.get(
356 target_tensor.accessor().access_element(target_natural_elem));
357 }
358 }
359};
360
361template <
364 class MetricType,
365 class BatchElem>
367{
368 template <
371 KOKKOS_FUNCTION static void run(
372 HodgeTensorType hodge_tensor,
373 FormTensorType form_tensor,
374 MetricType metric,
375 BatchElem elem)
376 {
378 hodge_star_domain_t<Indices1, Indices2>> hodge_star_accessor;
379 static constexpr std::size_t HODGE_STAR_SIZE
381 * detail::HodgeStarTargetSize<Indices2>::value;
382 std::array<double, HODGE_STAR_SIZE> hodge_star_alloc {};
383 ddc::ChunkSpan<
384 double,
386 Kokkos::layout_right,
387 typename HodgeTensorType::memory_space>
388 hodge_star_span(hodge_star_alloc.data(), hodge_star_accessor.domain());
389 sil::tensor::Tensor hodge_star(hodge_star_span);
390 ddc::device_for_each(hodge_star.domain(), [&](auto it) {
391 hodge_star.mem(it) = value(metric, elem, hodge_star.canonical_natural_element(it));
392 });
393 sil::tensor::tensor_prod(hodge_tensor, hodge_star, form_tensor);
394 }
396 KOKKOS_FUNCTION static double value(MetricType metric, BatchElem elem, auto natural_elem)
397 {
398 constexpr std::size_t N = ddc::type_seq_size_v<Indices1> + ddc::type_seq_size_v<Indices2>;
399 constexpr std::size_t K = ddc::type_seq_size_v<Indices1>;
402 std::array const source_ids = ddc::detail::array(SourceElem(natural_elem));
403 std::array const target_ids = ddc::detail::array(TargetElem(natural_elem));
404
405 if (!detail::has_unique_ids<N>(source_ids) || !detail::has_unique_ids<N>(target_ids)
406 || !detail::is_complete_permutation<N>(source_ids, target_ids)) {
407 return 0.;
408 }
409
410 std::array<std::size_t, K> const complement = detail::complement_ids<N>(target_ids);
411 using MetricIndex = ddc::
412 type_seq_element_t<0, ddc::to_type_seq_t<typename MetricType::indices_domain_t>>;
413 using MetricIndex1 = tensor::metric_index_1<MetricIndex>;
414 using MetricIndex2 = tensor::metric_index_2<MetricIndex>;
415 std::array<double, N * N> metric_alloc {};
416 std::array<double, N * N> determinant_metric_alloc {};
417 std::array<double, N * N> inverse_metric_alloc {};
418 std::array<double, N * N> workspace_alloc {};
419 std::array<double, K * K> submatrix_alloc {};
420 for (std::size_t i = 0; i < N; ++i) {
421 for (std::size_t j = 0; j < N; ++j) {
422 metric_alloc[i * N + j] = metric.get(metric.access_element(
423 elem,
424 ddc::DiscreteElement<MetricIndex1, MetricIndex2>(i, j)));
425 }
426 }
427 determinant_metric_alloc = metric_alloc;
428
429 auto determinant_metric_view = misc::math::matrix_view<
430 double,
431 typename MetricType::memory_space>(determinant_metric_alloc.data(), N, N);
432 auto metric_view = misc::math::
434 double const determinant = misc::math::determinant(determinant_metric_view);
435 auto inverse_metric_view = misc::math::matrix_view<
436 double,
437 typename MetricType::memory_space>(inverse_metric_alloc.data(), N, N);
438 auto workspace = misc::math::vector_view<
439 double,
440 typename MetricType::memory_space>(workspace_alloc.data(), N * N);
441 if (!misc::math::invert(inverse_metric_view, metric_view, workspace)) {
442 return 0.;
443 }
444
445 return Kokkos::sqrt(Kokkos::abs(determinant))
446 * static_cast<double>(detail::permutation_sign<N>(complement, target_ids))
448 K>(inverse_metric_view, source_ids, complement, submatrix_alloc)
449 / misc::factorial(K);
450 }
451};
452
453template <
460 class ExecSpace>
461HodgeStarType fill_discrete_hodge_star(
462 ExecSpace const& exec_space,
463 HodgeStarType hodge_star,
464 MetricType metric,
465 PositionType position)
466{
467 static_assert(
468 ddc::type_seq_size_v<ddc::to_type_seq_t<typename PositionType::indices_domain_t>> == 1);
469
470 SIMILIE_DEBUG_LOG("similie_compute_hodge_star");
471 ddc::parallel_for_each(
472 "similie_compute_hodge_star",
473 exec_space,
474 hodge_star.non_indices_domain(),
475 KOKKOS_LAMBDA(
476 typename HodgeStarType::non_indices_domain_t::discrete_element_type elem) {
477 ddc::device_for_each(
478 hodge_star.accessor().domain(),
479 detail::FillDiscreteHodgeStarMem<
480 Complex,
481 Indices1,
482 Indices2,
483 HodgeStarType,
484 MetricType,
485 PositionType,
486 typename HodgeStarType::non_indices_domain_t::
487 discrete_element_type> {
488 hodge_star,
489 metric,
490 position,
491 elem});
492 });
493 return hodge_star;
494}
495
496template <
501 class ExecSpace>
502HodgeStarType fill_continuous_hodge_star(
503 ExecSpace const& exec_space,
504 HodgeStarType hodge_star,
505 MetricType metric)
506{
507 SIMILIE_DEBUG_LOG("similie_compute_continuous_hodge_star");
508 ddc::parallel_for_each(
509 "similie_compute_continuous_hodge_star",
510 exec_space,
511 hodge_star.non_indices_domain(),
512 KOKKOS_LAMBDA(
513 typename HodgeStarType::non_indices_domain_t::discrete_element_type elem) {
514 ddc::device_for_each(
515 hodge_star.accessor().domain(),
516 detail::FillContinuousHodgeStarMem<
517 Indices1,
518 Indices2,
519 HodgeStarType,
520 MetricType,
521 typename HodgeStarType::non_indices_domain_t::
522 discrete_element_type> {hodge_star, metric, elem});
523 });
524 return hodge_star;
525}
526
527} // namespace exterior
528
529} // namespace sil
static constexpr discrete_domain_type domain()
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, Indices1 > >, std::conditional_t<(ddc::type_seq_size_v< Indices2 >==0), ddc::detail::TypeSeq<>, ddc::detail::TypeSeq< misc::convert_type_seq_to_t< tensor::TensorAntisymmetricIndex, Indices2 > > > > > hodge_star_domain_t
HodgeStarType fill_continuous_hodge_star(ExecSpace const &exec_space, HodgeStarType hodge_star, MetricType metric)
typename detail::ReductionTargetIndex< Indices >::type reduction_index_t
HodgeStarType fill_discrete_hodge_star(ExecSpace const &exec_space, HodgeStarType hodge_star, MetricType metric, 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
Definition factorial.hpp:13
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
Definition metric.hpp:33
ddc::type_seq_element_t< 1, ddc::to_type_seq_t< typename MetricIndex::subindices_domain_t > > metric_index_2
Definition metric.hpp:41
Tensor< ElementType, ddc::DiscreteDomain< ProdDDim... >, LayoutStridedPolicy, MemorySpace > tensor_prod(Tensor< ElementType, ddc::DiscreteDomain< ProdDDim... >, LayoutStridedPolicy, MemorySpace > prod_tensor, Tensor< ElementType, ddc::DiscreteDomain< DDim1... >, LayoutStridedPolicy, MemorySpace > tensor1, Tensor< ElementType, ddc::DiscreteDomain< DDim2... >, LayoutStridedPolicy, MemorySpace > tensor2)
detail::Lower< T >::type lower_t
Definition character.hpp:80
typename detail::NaturalDomainType< Index >::type natural_domain_t
detail::TensorAccessorForDomain< Dom >::type tensor_accessor_for_domain_t
The top-level namespace of SimiLie.
Definition csr.hpp:15
static KOKKOS_FUNCTION double value(MetricType metric, BatchElem elem, auto natural_elem)
static KOKKOS_FUNCTION void run(HodgeTensorType hodge_tensor, FormTensorType form_tensor, MetricType metric, BatchElem elem)
static KOKKOS_FUNCTION double value(MetricType metric, PositionType position, BatchElem elem, auto natural_elem)
static KOKKOS_FUNCTION void run(HodgeTensorType hodge_tensor, FormTensorType form_tensor, MetricType metric, PositionType position, BatchElem elem)
static KOKKOS_FUNCTION void run(ReconstructedTensorType reconstructed_tensor, CochainTensorType cochain_tensor, PositionType position, BatchElem elem)
static KOKKOS_FUNCTION void run(ReductionTensorType reduced_tensor, FormTensorType form_tensor, PositionType position, BatchElem elem)