11#include <similie/misc/are_all_same.hpp>
12#include <similie/misc/filled_struct.hpp>
13#include <similie/misc/macros.hpp>
14#include <similie/misc/portable_stl.hpp>
15#include <similie/misc/select_from_type_seq.hpp>
16#include <similie/misc/specialization.hpp>
17#include <similie/misc/type_seq_conversion.hpp>
18#include <similie/tensor/antisymmetric_tensor.hpp>
19#include <similie/tensor/dummy_index.hpp>
20#include <similie/tensor/owning_tensor.hpp>
21#include <similie/tensor/tensor_impl.hpp>
23#include <Kokkos_StdAlgorithms.hpp>
25#include "boundary.hpp"
27#include "cosimplex.hpp"
28#include "evaluators.hpp"
44 class LayoutStridedPolicy1,
45 class LayoutStridedPolicy2,
50 LayoutStridedPolicy2>>
52 using type = Cosimplex<
Simplex<K + 1, Tag...>, ElementType>;
57template <misc::Specialization<Cochain> CochainType>
58using coboundary_t =
typename detail::CoboundaryType<CochainType>::type;
62template <
class TagToAddToCochain,
class CochainTag>
63struct CoboundaryIndex;
65template <tensor::TensorNatIndex TagToAddToCochain, tensor::TensorNatIndex CochainTag>
66 requires(CochainTag::rank() == 0)
67struct CoboundaryIndex<TagToAddToCochain, CochainTag>
69 using type = TagToAddToCochain;
72template <tensor::TensorNatIndex TagToAddToCochain, tensor::TensorNatIndex CochainTag>
73 requires(CochainTag::rank() == 1)
74struct CoboundaryIndex<TagToAddToCochain, CochainTag>
80struct CoboundaryIndex<TagToAddToCochain, tensor::TensorAntisymmetricIndex<Tag...>>
87template <
class TagToAddToCochain,
class CochainTag>
96struct CoboundaryTensorType;
105struct CoboundaryTensorType<
108 tensor::Tensor<ElementType, ddc::DiscreteDomain<DDim...>, SupportType, MemorySpace>>
110 static_assert(ddc::type_seq_contains_v<
111 ddc::detail::TypeSeq<CochainIndex>,
112 ddc::detail::TypeSeq<DDim...>>);
115 ddc::replace_dim_of_t<
116 ddc::DiscreteDomain<DDim...>,
130 typename detail::CoboundaryTensorType<TagToAddToCochain, CochainTag, TensorType>::type;
134template <misc::Specialization<Chain> ChainType>
135struct ComputeSimplex;
137template <std::size_t K,
class... Tag,
class LayoutStridedPolicy,
class ExecSpace>
138struct ComputeSimplex<
Chain<
Simplex<K, Tag...>, LayoutStridedPolicy, ExecSpace>>
140 KOKKOS_FUNCTION
static Simplex<K + 1, Tag...> run(
143 ddc::DiscreteVector<Tag...> vect {
144 0 * ddc::type_seq_rank_v<Tag, ddc::detail::TypeSeq<Tag...>>...};
145 for (
auto i = chain.begin(); i < chain.end(); ++i) {
146 vect = ddc::DiscreteVector<Tag...> {
147 (
static_cast<bool>(vect.template get<Tag>())
148 ||
static_cast<bool>((*i).discrete_vector().
template get<Tag>()))...};
152 std::integral_constant<std::size_t, K + 1> {},
161template <
class... Args>
164template <
class... Args>
167template <misc::Specialization<Cochain> CochainType>
174 assert(cochain.size() == 2 * (cochain.dimension() + 1)
175 &&
"only cochain over the boundary of a single simplex is supported");
183 detail::ComputeSimplex<typename CochainType::chain_type>::run(cochain.chain()),
184 cochain.integrate());
190template <tensor::TensorNatIndex Index,
class Dom>
191struct NonSpectatorDimension;
194struct NonSpectatorDimension<Index, ddc::DiscreteDomain<DDim...>>
196 using type = ddc::cartesian_prod_t<std::conditional_t<
197 ddc::type_seq_contains_v<
198 ddc::detail::TypeSeq<typename DDim::continuous_dimension_type>,
199 typename Index::type_seq_dimensions>,
200 ddc::DiscreteDomain<DDim>,
201 ddc::DiscreteDomain<>>...>;
204struct CoboundaryDummyIndex
208template <
class MemorySpace = Kokkos::HostSpace,
class TensorIndex,
class... DDims>
209KOKKOS_FUNCTION
auto make_stencil(ddc::DiscreteElement<DDims...> front)
213 ddc::DiscreteDomain<DDims..., TensorIndex>,
214 Kokkos::layout_right,
218 (
sizeof...(DDims) == 0 ? 1UL : (1UL <<
sizeof...(DDims)))
219 * TensorIndex::mem_size()>>
223 (
sizeof...(DDims) == 0 ? 1UL : (1UL <<
sizeof...(DDims))) * TensorIndex::mem_size()>
225 ddc::DiscreteDomain<DDims..., TensorIndex>
const
226 domain(ddc::DiscreteDomain<DDims...>(
228 typename ddc::DiscreteDomain<DDims...>::discrete_vector_type(
229 ddc::DiscreteVector<DDims>(2)...)),
230 ddc::DiscreteDomain<TensorIndex>(
231 ddc::DiscreteElement<TensorIndex>(0),
232 ddc::DiscreteVector<TensorIndex>(TensorIndex::mem_size())));
235 ddc::DiscreteDomain<DDims..., TensorIndex>,
236 Kokkos::layout_right,
238 span(storage.data(), domain);
241 ddc::DiscreteDomain<DDims..., TensorIndex>,
242 Kokkos::layout_right,
248 ddc::DiscreteDomain<DDims..., TensorIndex>,
249 Kokkos::layout_right,
253 (
sizeof...(DDims) == 0 ? 1UL : (1UL <<
sizeof...(DDims)))
254 * TensorIndex::mem_size()>>(tensor, std::move(storage));
258KOKKOS_FUNCTION Elem decrement_all(Elem elem)
261 constexpr std::size_t RANK = ddc::type_seq_size_v<ddc::to_type_seq_t<Elem>>;
262 for (std::size_t dim_id = 0; dim_id < RANK; ++dim_id) {
263 ddc::detail::array(shifted)[dim_id] -= 1;
268template <
class LowerChainType,
class VectorType>
269KOKKOS_FUNCTION
auto find_discrete_vector(
270 LowerChainType
const& lower_chain,
271 VectorType
const& vector)
273 for (
auto i = lower_chain.begin(); i < lower_chain.end(); ++i) {
274 if (i->discrete_vector() == vector) {
278 return lower_chain.end();
283template <tensor::TensorNatIndex TagToAddToCochain, tensor::TensorIndex CochainTag>
286 template <
class Evaluator,
class ChainType,
class LowerChainType,
class Elem,
class NaturalElem>
290 LowerChainType lower_chain,
292 NaturalElem natural_elem)
294 std::size_t
const stored_component_id
298 typename ChainType::simplex_type
299 simplex(std::integral_constant<std::size_t, CochainTag::rank() + 1> {},
300 typename ChainType::simplex_type::discrete_element_type(elem),
301 chain[stored_component_id].discrete_vector());
304 typename LowerChainType::simplex_type::discrete_element_type front(
305 boundary_chain.begin()->discrete_element());
306 for (
auto j = boundary_chain.begin(); j < boundary_chain.end(); ++j) {
307 for (std::size_t dim_id = 0;
308 dim_id < ddc::type_seq_size_v<ddc::to_type_seq_t<
309 typename LowerChainType::simplex_type::discrete_element_type>>;
311 ddc::detail::array(front)[dim_id] = std::
312 min(ddc::detail::array(front)[dim_id],
313 ddc::detail::array(j->discrete_element())[dim_id]);
317 auto stencil = detail::make_stencil<typename ChainType::memory_space, CochainTag>(front);
318 ddc::device_for_each(stencil.domain(), [&](
auto stencil_elem) {
320 = detail::make_stencil<typename ChainType::memory_space, CochainTag>(front);
321 basis_stencil.mem(stencil_elem) = 1.0;
323 [[maybe_unused]] sil::tensor::TensorAccessor<
324 coboundary_index_t<TagToAddToCochain, CochainTag>> accessor;
325 std::array<double, coboundary_index_t<TagToAddToCochain, CochainTag>::access_size()>
330 Kokkos::layout_right,
331 typename ChainType::memory_space>
332 output_span(output_storage.data(), accessor.domain());
335 auto basis_evaluator = [&](
auto sampled_elem,
auto cochain_elem) {
336 auto basis_sampler = [&](
auto basis_elem,
auto basis_cochain_elem) {
337 if (!basis_stencil.non_indices_domain().contains(basis_elem)) {
340 return basis_stencil(
341 basis_stencil.access_element(basis_elem, basis_cochain_elem));
343 return evaluator.value(basis_sampler, sampled_elem, cochain_elem);
346 run(output_tensor, basis_evaluator, chain, lower_chain, elem);
347 stencil.mem(stencil_elem) = output_tensor(natural_elem);
354 class CoboundaryTensorType,
357 class LowerChainType,
359 KOKKOS_FUNCTION
static void run(
360 CoboundaryTensorType coboundary_tensor,
363 LowerChainType lower_chain,
366 constexpr std::size_t BOUNDARY_SIZE = 2 * (CochainTag::rank() + 1);
367 std::array<double, BOUNDARY_SIZE> boundary_values_alloc {};
368 ddc::DiscreteDomain<detail::CoboundaryDummyIndex>
const boundary_domain(
369 ddc::DiscreteElement<detail::CoboundaryDummyIndex>(0),
370 ddc::DiscreteVector<detail::CoboundaryDummyIndex>(BOUNDARY_SIZE));
373 ddc::DiscreteDomain<detail::CoboundaryDummyIndex>,
374 Kokkos::layout_right,
375 typename CoboundaryTensorType::memory_space>
376 boundary_values(boundary_values_alloc.data(), boundary_domain);
378 typename ChainType::simplex_type::discrete_element_type
const elem_on_chain
380 typename ChainType::simplex_type::discrete_element_type>>(elem);
381 for (
auto i = chain.begin(); i < chain.end(); ++i) {
382 std::size_t
const chain_id = Kokkos::Experimental::distance(chain.begin(), i);
383 typename ChainType::simplex_type
384 simplex(std::integral_constant<std::size_t, CochainTag::rank() + 1> {},
386 i->discrete_vector());
388 for (
auto j = boundary_chain.begin(); j < boundary_chain.end(); ++j) {
389 std::size_t
const boundary_id
390 = Kokkos::Experimental::distance(boundary_chain.begin(), j);
392 ddc::type_seq_size_v<ddc::type_seq_remove_t<
393 ddc::to_type_seq_t<Elem>,
394 ddc::to_type_seq_t<
typename LowerChainType::simplex_type::
395 discrete_element_type>>>
397 boundary_values(ddc::DiscreteElement<detail::CoboundaryDummyIndex>(boundary_id))
399 Elem(j->discrete_element()),
400 ddc::DiscreteElement<CochainTag>(Kokkos::Experimental::distance(
402 detail::find_discrete_vector(
404 j->discrete_vector()))));
406 boundary_values(ddc::DiscreteElement<detail::CoboundaryDummyIndex>(boundary_id))
408 Elem(j->discrete_element(),
410 ddc::to_type_seq_t<Elem>,
412 typename LowerChainType::simplex_type::
413 discrete_element_type>>>(elem)),
414 ddc::DiscreteElement<CochainTag>(Kokkos::Experimental::distance(
416 detail::find_discrete_vector(
418 j->discrete_vector()))));
421 Cochain cochain_boundary(boundary_chain, boundary_values.allocation_kokkos_view());
422 coboundary_tensor.mem(
430template <tensor::TensorNatIndex TagToAddToCochain, tensor::TensorIndex CochainTag>
433 template <
class Evaluator,
class ChainType,
class LowerChainType,
class Elem,
class NaturalElem>
437 LowerChainType lower_chain,
439 NaturalElem natural_elem)
441 constexpr std::size_t BOUNDARY_SIZE = 2 * (CochainTag::rank() + 1);
442 std::size_t
const stored_component_id
446 typename ChainType::simplex_type
447 simplex(std::integral_constant<std::size_t, CochainTag::rank() + 1> {},
448 typename ChainType::simplex_type::discrete_element_type(elem),
449 chain[stored_component_id].discrete_vector());
450 auto boundary_chain = boundary<typename ChainType::memory_space>(simplex);
452 typename LowerChainType::simplex_type::discrete_element_type front(
453 boundary_chain.begin()->discrete_element());
454 for (
auto j = boundary_chain.begin(); j < boundary_chain.end(); ++j) {
455 auto sampled_face_elem = j->discrete_element();
456 std::size_t
const boundary_id
457 = Kokkos::Experimental::distance(boundary_chain.begin(), j);
458 if (boundary_id >= CochainTag::rank() + 1) {
459 for (std::size_t dim_id = 0;
460 dim_id < ddc::type_seq_size_v<ddc::to_type_seq_t<
461 typename LowerChainType::simplex_type::discrete_element_type>>;
463 if (ddc::detail::array(chain[stored_component_id].discrete_vector())[dim_id]
465 && ddc::detail::array(j->discrete_vector())[dim_id] == 0) {
466 ddc::detail::array(sampled_face_elem)[dim_id] -= 2;
471 for (std::size_t dim_id = 0;
472 dim_id < ddc::type_seq_size_v<ddc::to_type_seq_t<
473 typename LowerChainType::simplex_type::discrete_element_type>>;
475 ddc::detail::array(front)[dim_id] = std::
476 min(ddc::detail::array(front)[dim_id],
477 ddc::detail::array(sampled_face_elem)[dim_id]);
481 auto stencil = detail::make_stencil<typename ChainType::memory_space, CochainTag>(front);
482 ddc::device_for_each(stencil.domain(), [&](
auto stencil_elem) {
484 = detail::make_stencil<typename ChainType::memory_space, CochainTag>(front);
485 basis_stencil.mem(stencil_elem) = 1.0;
487 [[maybe_unused]] sil::tensor::TensorAccessor<
488 coboundary_index_t<TagToAddToCochain, CochainTag>> accessor;
489 std::array<double, coboundary_index_t<TagToAddToCochain, CochainTag>::access_size()>
494 Kokkos::layout_right,
495 typename ChainType::memory_space>
496 output_span(output_storage.data(), accessor.domain());
499 auto basis_evaluator = [&](
auto sampled_elem,
auto cochain_elem) {
500 auto basis_sampler = [&](
auto basis_elem,
auto basis_cochain_elem) {
501 if (!basis_stencil.non_indices_domain().contains(basis_elem)) {
504 return basis_stencil(
505 basis_stencil.access_element(basis_elem, basis_cochain_elem));
507 return evaluator.value(basis_sampler, sampled_elem, cochain_elem);
510 run(output_tensor, basis_evaluator, chain, lower_chain, elem);
511 stencil.mem(stencil_elem) = output_tensor(natural_elem);
518 class CoboundaryTensorType,
521 class LowerChainType,
523 KOKKOS_FUNCTION
static void run(
524 CoboundaryTensorType coboundary_tensor,
527 LowerChainType lower_chain,
530 constexpr std::size_t BOUNDARY_SIZE = 2 * (CochainTag::rank() + 1);
531 std::array<double, BOUNDARY_SIZE> boundary_values_alloc {};
532 ddc::DiscreteDomain<detail::CoboundaryDummyIndex>
const boundary_domain(
533 ddc::DiscreteElement<detail::CoboundaryDummyIndex>(0),
534 ddc::DiscreteVector<detail::CoboundaryDummyIndex>(BOUNDARY_SIZE));
537 ddc::DiscreteDomain<detail::CoboundaryDummyIndex>,
538 Kokkos::layout_right,
539 typename CoboundaryTensorType::memory_space>
540 boundary_values(boundary_values_alloc.data(), boundary_domain);
542 typename ChainType::simplex_type::discrete_element_type
const elem_on_chain
544 typename ChainType::simplex_type::discrete_element_type>>(elem);
545 for (
auto i = chain.begin(); i < chain.end(); ++i) {
546 std::size_t
const chain_id = Kokkos::Experimental::distance(chain.begin(), i);
547 auto simplex_vector = i->discrete_vector();
548 typename ChainType::simplex_type
549 simplex(std::integral_constant<std::size_t, CochainTag::rank() + 1> {},
552 auto boundary_chain = boundary<typename CoboundaryTensorType::memory_space>(simplex);
553 for (
auto j = boundary_chain.begin(); j < boundary_chain.end(); ++j) {
554 std::size_t
const boundary_id
555 = Kokkos::Experimental::distance(boundary_chain.begin(), j);
556 auto sampled_face_elem = j->discrete_element();
557 if (boundary_id >= CochainTag::rank() + 1) {
558 for (std::size_t dim_id = 0;
559 dim_id < ddc::type_seq_size_v<ddc::to_type_seq_t<
560 typename ChainType::simplex_type::discrete_element_type>>;
562 if (ddc::detail::array(simplex_vector)[dim_id] != 0
563 && ddc::detail::array(j->discrete_vector())[dim_id] == 0) {
564 ddc::detail::array(sampled_face_elem)[dim_id] -= 2;
570 ddc::type_seq_size_v<ddc::type_seq_remove_t<
571 ddc::to_type_seq_t<Elem>,
572 ddc::to_type_seq_t<
typename LowerChainType::simplex_type::
573 discrete_element_type>>>
575 boundary_values(ddc::DiscreteElement<detail::CoboundaryDummyIndex>(boundary_id))
577 Elem(sampled_face_elem),
578 ddc::DiscreteElement<CochainTag>(Kokkos::Experimental::distance(
580 detail::find_discrete_vector(
582 j->discrete_vector()))));
584 boundary_values(ddc::DiscreteElement<detail::CoboundaryDummyIndex>(boundary_id))
586 Elem(sampled_face_elem,
588 ddc::to_type_seq_t<Elem>,
590 typename LowerChainType::simplex_type::
591 discrete_element_type>>>(elem)),
592 ddc::DiscreteElement<CochainTag>(Kokkos::Experimental::distance(
594 detail::find_discrete_vector(
596 j->discrete_vector()))));
599 Cochain cochain_boundary(boundary_chain, boundary_values.allocation_kokkos_view());
600 coboundary_tensor.mem(
608template <misc::Specialization<Cochain> CochainType>
620 ExecSpace
const& exec_space,
624 ddc::DiscreteDomain batch_dom
625 = ddc::remove_dims_of<coboundary_index_t<TagToAddToCochain, CochainTag>>(
626 coboundary_tensor.domain());
629 CochainTag::rank() + 1,
630 typename detail::NonSpectatorDimension<
632 typename TensorType::non_indices_domain_t>::type>(exec_space);
635 typename detail::NonSpectatorDimension<
637 typename TensorType::non_indices_domain_t>::type>(exec_space);
639 SIMILIE_DEBUG_LOG(
"similie_compute_coboundary");
640 ddc::parallel_for_each(
641 "similie_compute_coboundary",
644 KOKKOS_LAMBDA(
typename decltype(batch_dom)::discrete_element_type elem) {
646 run(coboundary_tensor[elem],
647 detail::ClampedTensorEvaluator<TensorType> {tensor},
653 return coboundary_tensor;
662 ExecSpace
const& exec_space,
666 ddc::DiscreteDomain batch_dom
667 = ddc::remove_dims_of<coboundary_index_t<TagToAddToCochain, CochainTag>>(
668 coboundary_tensor.domain());
671 CochainTag::rank() + 1,
672 typename detail::NonSpectatorDimension<
674 typename TensorType::non_indices_domain_t>::type>(exec_space);
677 typename detail::NonSpectatorDimension<
679 typename TensorType::non_indices_domain_t>::type>(exec_space);
681 SIMILIE_DEBUG_LOG(
"similie_compute_transposed_coboundary");
682 ddc::parallel_for_each(
683 "similie_compute_transposed_coboundary",
686 KOKKOS_LAMBDA(
typename decltype(batch_dom)::discrete_element_type elem) {
688 run(coboundary_tensor[elem],
689 detail::ZeroOutsideTensorEvaluator<TensorType> {tensor},
695 return coboundary_tensor;
704 ExecSpace
const& exec_space,
708 return coboundary<TagToAddToCochain, CochainTag>(exec_space, coboundary_tensor, tensor);
KOKKOS_FUNCTION element_type integrate() noexcept
Cochain(ChainType, TensorType) -> Cochain< ChainType, typename TensorType::value_type, ddc::detail::mdspan_to_kokkos_layout_t< typename TensorType::layout_type > >
Simplex(ddc::DiscreteElement< Tag... >, ddc::DiscreteVector< T... >) -> Simplex< sizeof...(T), Tag... >
KOKKOS_FUNCTION constexpr auto tangent_basis(Elem elem)
KOKKOS_FUNCTION coboundary_t< CochainType > coboundary(CochainType cochain)
Chain(Head, Tail...) -> Chain< typename Head::value_type, typename Head::array_layout, typename Head::memory_space >
typename detail::CoboundaryTensorType< TagToAddToCochain, CochainTag, TensorType >::type coboundary_tensor_t
coboundary_tensor_t< TagToAddToCochain, CochainTag, TensorType > deriv(ExecSpace const &exec_space, coboundary_tensor_t< TagToAddToCochain, CochainTag, TensorType > coboundary_tensor, TensorType tensor)
coboundary_tensor_t< TagToAddToCochain, CochainTag, TensorType > transposed_coboundary(ExecSpace const &exec_space, coboundary_tensor_t< TagToAddToCochain, CochainTag, TensorType > coboundary_tensor, TensorType tensor)
KOKKOS_FUNCTION Chain< boundary_t< SimplexType >, typename AllocationType::array_layout, typename AllocationType::memory_space > boundary(AllocationType allocation, SimplexType simplex)
typename detail::CoboundaryIndex< TagToAddToCochain, CochainTag >::type coboundary_index_t
typename detail::CoboundaryType< CochainType >::type coboundary_t
KOKKOS_FUNCTION auto select_from_type_seq(T t)
Tensor(ddc::Chunk< ElementType, SupportType, Allocator >) -> Tensor< ElementType, SupportType, Kokkos::layout_right, typename Allocator::memory_space >
The top-level namespace of SimiLie.
static KOKKOS_FUNCTION coboundary_t< CochainType > run(CochainType cochain)
static KOKKOS_FUNCTION void run(CoboundaryTensorType coboundary_tensor, Evaluator evaluator, ChainType chain, LowerChainType lower_chain, Elem elem)
static KOKKOS_FUNCTION auto value(Evaluator evaluator, ChainType chain, LowerChainType lower_chain, Elem elem, NaturalElem natural_elem)
static KOKKOS_FUNCTION auto value(Evaluator evaluator, ChainType chain, LowerChainType lower_chain, Elem elem, NaturalElem natural_elem)
static KOKKOS_FUNCTION void run(CoboundaryTensorType coboundary_tensor, Evaluator evaluator, ChainType chain, LowerChainType lower_chain, Elem elem)