SimiLie
Loading...
Searching...
No Matches
coboundary.hpp
1// SPDX-FileCopyrightText: 2024 Baptiste Legouix
2// SPDX-License-Identifier: MIT
3
4#pragma once
5
6#include <ddc/ddc.hpp>
7
8#include <similie/misc/are_all_same.hpp>
9#include <similie/misc/domain_contains.hpp>
10#include <similie/misc/filled_struct.hpp>
11#include <similie/misc/portable_stl.hpp>
12#include <similie/misc/specialization.hpp>
13#include <similie/misc/type_seq_conversion.hpp>
14#include <similie/tensor/antisymmetric_tensor.hpp>
15#include <similie/tensor/dummy_index.hpp>
16#include <similie/tensor/tensor_impl.hpp>
17
18#include <Kokkos_StdAlgorithms.hpp>
19
20#include "cochain.hpp"
21#include "cosimplex.hpp"
22
23
24namespace sil {
25
26namespace exterior {
27
28namespace detail {
29
30template <class T>
31struct CoboundaryType;
32
33template <
34 std::size_t K,
35 class... Tag,
36 class ElementType,
37 class LayoutStridedPolicy1,
38 class LayoutStridedPolicy2,
39 class ExecSpace>
40struct CoboundaryType<
41 Cochain<Chain<Simplex<K, Tag...>, LayoutStridedPolicy1, ExecSpace>,
42 ElementType,
43 LayoutStridedPolicy2>>
44{
45 using type = Cosimplex<Simplex<K + 1, Tag...>, ElementType>;
46};
47
48} // namespace detail
49
50template <misc::Specialization<Cochain> CochainType>
51using coboundary_t = typename detail::CoboundaryType<CochainType>::type;
52
53namespace detail {
54
55template <class TagToAddToCochain, class CochainTag>
56struct CoboundaryIndex;
57
58template <tensor::TensorNatIndex TagToAddToCochain, tensor::TensorNatIndex CochainTag>
59 requires(CochainTag::rank() == 0)
60struct CoboundaryIndex<TagToAddToCochain, CochainTag>
61{
62 using type = TagToAddToCochain;
63};
64
65template <tensor::TensorNatIndex TagToAddToCochain, tensor::TensorNatIndex CochainTag>
66 requires(CochainTag::rank() == 1)
67struct CoboundaryIndex<TagToAddToCochain, CochainTag>
68{
70};
71
72template <tensor::TensorNatIndex TagToAddToCochain, tensor::TensorNatIndex... Tag>
73struct CoboundaryIndex<TagToAddToCochain, tensor::TensorAntisymmetricIndex<Tag...>>
74{
75 using type = tensor::TensorAntisymmetricIndex<TagToAddToCochain, Tag...>;
76};
77
78} // namespace detail
79
80template <class TagToAddToCochain, class CochainTag>
81using coboundary_index_t = typename detail::CoboundaryIndex<TagToAddToCochain, CochainTag>::type;
82
83namespace detail {
84
85template <
86 tensor::TensorNatIndex TagToAddToCochain,
87 tensor::TensorIndex CochainTag,
89struct CoboundaryTensorType;
90
91template <
92 tensor::TensorNatIndex TagToAddToCochain,
93 tensor::TensorIndex CochainIndex,
94 class ElementType,
95 class... DDim,
96 class SupportType,
97 class MemorySpace>
98struct CoboundaryTensorType<
99 TagToAddToCochain,
100 CochainIndex,
101 tensor::Tensor<ElementType, ddc::DiscreteDomain<DDim...>, SupportType, MemorySpace>>
102{
103 static_assert(ddc::type_seq_contains_v<
104 ddc::detail::TypeSeq<CochainIndex>,
105 ddc::detail::TypeSeq<DDim...>>);
106 using type = tensor::Tensor<
107 ElementType,
108 ddc::replace_dim_of_t<
109 ddc::DiscreteDomain<DDim...>,
110 CochainIndex,
112 SupportType,
113 MemorySpace>;
114};
115
116} // namespace detail
117
118template <
119 tensor::TensorNatIndex TagToAddToCochain,
120 tensor::TensorIndex CochainTag,
123 typename detail::CoboundaryTensorType<TagToAddToCochain, CochainTag, TensorType>::type;
124
125namespace detail {
126
127template <misc::Specialization<Chain> ChainType>
128struct ComputeSimplex;
129
130template <std::size_t K, class... Tag, class LayoutStridedPolicy, class ExecSpace>
131struct ComputeSimplex<Chain<Simplex<K, Tag...>, LayoutStridedPolicy, ExecSpace>>
132{
133 KOKKOS_FUNCTION static Simplex<K + 1, Tag...> run(
134 Chain<Simplex<K, Tag...>, LayoutStridedPolicy, ExecSpace> const& chain)
135 {
136 ddc::DiscreteVector<Tag...> vect {
137 0 * ddc::type_seq_rank_v<Tag, ddc::detail::TypeSeq<Tag...>>...};
138 for (auto i = chain.begin(); i < chain.end(); ++i) {
139 vect = ddc::DiscreteVector<Tag...> {
140 (static_cast<bool>(vect.template get<Tag>())
141 || static_cast<bool>((*i).discrete_vector().template get<Tag>()))...};
142 }
143 return Simplex(
144 std::integral_constant<std::size_t, K + 1> {},
145 chain[0].discrete_element(), // This is an assumption on the structure of the chain, which is satisfied if it has been produced using boundary()
146 vect);
147 }
148};
149
150} // namespace detail
151
152template <misc::Specialization<Cochain> CochainType>
154 CochainType
155 cochain) // Warning: only cochain.chain() produced using boundary() are supported
156{
157 assert(cochain.size() == 2 * (cochain.dimension() + 1)
158 && "only cochain over the boundary of a single simplex is supported");
159
160 /* Commented because would require an additional buffer
161 assert(boundary(cochain.chain()) == boundary_t<typename CochainType::chain_type> {}
162 && "only cochain over the boundary of a single simplex is supported");
163 */
164
166 detail::ComputeSimplex<typename CochainType::chain_type>::run(cochain.chain()),
167 cochain.integrate());
168}
169
170namespace detail {
171
172template <tensor::TensorNatIndex Index, class Dom>
173struct NonSpectatorDimension;
174
175template <tensor::TensorNatIndex Index, class... DDim>
176struct NonSpectatorDimension<Index, ddc::DiscreteDomain<DDim...>>
177{
178 using type = ddc::cartesian_prod_t<std::conditional_t<
179 ddc::type_seq_contains_v<
180 ddc::detail::TypeSeq<typename DDim::continuous_dimension_type>,
181 typename Index::type_seq_dimensions>,
182 ddc::DiscreteDomain<DDim>,
183 ddc::DiscreteDomain<>>...>;
184};
185
186struct CoboundaryDummyIndex
187{
188};
189
190} // namespace detail
191
192template <
193 tensor::TensorNatIndex TagToAddToCochain,
194 tensor::TensorIndex CochainTag,
195 misc::Specialization<tensor::Tensor> TensorType,
196 class ExecSpace>
198 ExecSpace const& exec_space,
200 TensorType tensor)
201{
202 ddc::DiscreteDomain batch_dom
203 = ddc::remove_dims_of<coboundary_index_t<TagToAddToCochain, CochainTag>>(
204 coboundary_tensor.domain());
205
206 // buffer to store the K-chain containing the boundary of each K+1-simplex of the mesh
207 ddc::Chunk simplex_boundary_alloc(
208 ddc::cartesian_prod_t<
209 ddc::remove_dims_of_t<
210 typename coboundary_tensor_t<
211 TagToAddToCochain,
212 CochainTag,
213 TensorType>::discrete_domain_type,
215 ddc::DiscreteDomain<detail::CoboundaryDummyIndex>>(
216 batch_dom,
217 ddc::DiscreteDomain<detail::CoboundaryDummyIndex>(
218 ddc::DiscreteElement<detail::CoboundaryDummyIndex>(0),
219 ddc::DiscreteVector<detail::CoboundaryDummyIndex>(
220 2 * (CochainTag::rank() + 1)))),
221 ddc::KokkosAllocator<
223 CochainTag::rank(),
224 ddc::remove_dims_of_t<
225 typename coboundary_tensor_t<
226 TagToAddToCochain,
227 CochainTag,
228 TensorType>::discrete_domain_type,
230 typename ExecSpace::memory_space>());
231 ddc::ChunkSpan simplex_boundary(simplex_boundary_alloc);
232
233 // buffer to store the values of the K-cochain on the boundary of each K+1-cosimplex of the mesh
234 ddc::Chunk boundary_values_alloc(
235 ddc::cartesian_prod_t<
236 ddc::remove_dims_of_t<
237 typename coboundary_tensor_t<
238 TagToAddToCochain,
239 CochainTag,
240 TensorType>::discrete_domain_type,
242 ddc::DiscreteDomain<detail::CoboundaryDummyIndex>>(
243 batch_dom,
244 ddc::DiscreteDomain<detail::CoboundaryDummyIndex>(
245 ddc::DiscreteElement<detail::CoboundaryDummyIndex>(0),
246 ddc::DiscreteVector<detail::CoboundaryDummyIndex>(
247 2 * (CochainTag::rank() + 1)))),
248 ddc::KokkosAllocator<double, typename ExecSpace::memory_space>());
249 ddc::ChunkSpan boundary_values(boundary_values_alloc);
250
251 // compute the tangent K+1-basis for each node of the mesh. This is a local K+1-chain.
252 auto chain = tangent_basis<
253 CochainTag::rank() + 1,
254 typename detail::NonSpectatorDimension<
255 TagToAddToCochain,
256 typename TensorType::non_indices_domain_t>::type>(exec_space);
257
258 // compute the tangent K-basis for each node of the mesh. This is a local K-chain.
259 auto lower_chain = tangent_basis<
260 CochainTag::rank(),
261 typename detail::NonSpectatorDimension<
262 TagToAddToCochain,
263 typename TensorType::non_indices_domain_t>::type>(exec_space);
264
265 // iterate over every node, we will work inside the tangent space associated to each of them
266 ddc::parallel_for_each(
267 exec_space,
268 batch_dom,
269 KOKKOS_LAMBDA(typename decltype(batch_dom)::discrete_element_type elem) {
270 // declare a K+1-cochain storing the K+1-cosimplices of the output cochain for the current tangent space and iterate over them
271 auto cochain = Cochain(chain, coboundary_tensor[elem]);
272 for (auto i = cochain.begin(); i < cochain.end(); ++i) {
273 // extract the K+1-simplex from the current K+1-cosimplex (this is not absolutly trivial because the cochain is based on a LocalChain)
274 Simplex simplex = Simplex(
275 std::integral_constant<std::size_t, CochainTag::rank() + 1> {},
276 elem,
277 (*i).discrete_vector());
278 // compute its boundary as a K-chain in the simplex_boundary buffer
279 Chain boundary_chain
280 = boundary(simplex_boundary[elem].allocation_kokkos_view(), simplex);
281 // iterate over every K-simplex forming the boundary
282 for (auto j = boundary_chain.begin(); j < boundary_chain.end(); ++j) {
283 // extract from the input K-cochain the values associated to every K-simplex of the boundary and fill the boundary_values buffer
284 boundary_values[elem].allocation_kokkos_view()(
285 Kokkos::Experimental::distance(boundary_chain.begin(), j))
286 = tensor.mem(
288 tensor.domain(),
289 (*j).discrete_element())
290 ? (*j).discrete_element()
291 : elem, // TODO this is an assumption on boundary condition (free boundary), needs to be generalized
292 ddc::DiscreteElement<CochainTag>(
293 Kokkos::Experimental::distance(
294 lower_chain.begin(),
295 misc::detail::
296 find(lower_chain.begin(),
297 lower_chain.end(),
298 (*j).discrete_vector()))));
299 }
300 // build the cochain of the boundary
301 Cochain cochain_boundary(
302 boundary_chain,
303 boundary_values[elem].allocation_kokkos_view());
304 // integrate over the cochain forming the boundary to compute the coboundary
305 // (*i).value() = cochain_boundary.integrate(); // Cannot be used because CochainIterator::operator* does not return a reference
306 coboundary_tensor
307 .mem(elem,
308 ddc::DiscreteElement<
310 Kokkos::Experimental::distance(cochain.begin(), i)))
311 = cochain_boundary.integrate();
312 }
313 });
314
315 return coboundary_tensor;
316}
317
318template <
319 tensor::TensorNatIndex TagToAddToCochain,
320 tensor::TensorIndex CochainTag,
322 class ExecSpace>
324 ExecSpace const& exec_space,
326 TensorType tensor)
327{
328 return coboundary<
329 TagToAddToCochain,
330 CochainTag,
331 TensorType>(exec_space, coboundary_tensor, tensor);
332}
333
334} // namespace exterior
335
336} // namespace sil
Chain class.
Definition chain.hpp:26
KOKKOS_FUNCTION auto end()
Definition chain.hpp:165
KOKKOS_FUNCTION auto begin()
Definition chain.hpp:155
Cochain class.
Definition cochain.hpp:30
KOKKOS_FUNCTION element_type integrate() noexcept
Definition cochain.hpp:187
Simplex class.
Definition simplex.hpp:75
constexpr auto tangent_basis(ExecSpace const &exec_space)
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 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)
KOKKOS_FUNCTION Chain< boundary_t< SimplexType >, typename AllocationType::array_layout, typename AllocationType::memory_space > boundary(AllocationType allocation, SimplexType simplex)
Definition boundary.hpp:79
detail::SimplexForDomain< K, Dom >::type simplex_for_domain_t
Definition simplex.hpp:233
typename detail::CoboundaryIndex< TagToAddToCochain, CochainTag >::type coboundary_index_t
typename detail::CoboundaryType< CochainType >::type coboundary_t
KOKKOS_FUNCTION bool domain_contains(ddc::DiscreteDomain< DDim... > dom, ddc::DiscreteElement< ODDim... > elem)
Tensor(ddc::Chunk< ElementType, SupportType, Allocator >) -> Tensor< ElementType, SupportType, Kokkos::layout_right, typename Allocator::memory_space >
The top-level namespace of SimiLie.
Definition csr.hpp:14