SimiLie
Loading...
Searching...
No Matches
magnetostatics_quantities.hpp
1// SPDX-FileCopyrightText: 2026 Baptiste Legouix
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4#pragma once
5
6#include <type_traits>
7
8#include <similie/exterior/coboundary.hpp>
9#include <similie/tensor/tensor.hpp>
10
11#include <Kokkos_Core.hpp>
12
14
16{
17 static constexpr bool PERIODIC = false;
18};
19
20template <class... SpatialIndex>
22
23template <class... SpatialIndex>
24concept TwoDimensional = sizeof...(SpatialIndex) == 2;
25
26template <class... SpatialIndex>
27concept ThreeDimensional = sizeof...(SpatialIndex) == 3;
28
29namespace detail {
30
31template <class... SpatialIndex>
32struct CoboundarySpatialIndex : sil::tensor::TensorNaturalIndex<SpatialIndex...>
33{
34};
35
36template <class... SpatialIndex>
37struct VectorPotentialSpatialIndex : sil::tensor::TensorNaturalIndex<SpatialIndex...>
38{
39};
40
41template <class Elem>
42struct ElementSpatialDomain;
43
44template <class... Tags>
45struct ElementSpatialDomain<ddc::DiscreteElement<Tags...>>
46{
47 using type = ddc::DiscreteDomain<Tags...>;
48};
49
50template <class CochainIndex, class VectorStencil, class Elem>
51[[nodiscard]] KOKKOS_FUNCTION auto project_to_scalar_potential_stencil(
52 VectorStencil vector_stencil,
53 Elem elem,
54 ddc::DiscreteElement<CochainIndex> selected_potential_component)
55{
56 using spatial_domain_type = typename ElementSpatialDomain<Elem>::type;
57 using ScalarPotentialIndex = sil::tensor::Covariant<sil::tensor::ScalarIndex>;
58
59 auto projected = sil::exterior::detail::make_stencil<Kokkos::HostSpace, ScalarPotentialIndex>(
60 vector_stencil.non_indices_domain().front());
61 ddc::device_for_each(projected.domain(), [&](auto projected_elem) {
62 auto const spatial_elem =
63 typename spatial_domain_type::discrete_element_type(projected_elem);
64 projected.mem(projected_elem)
65 = vector_stencil.get(spatial_elem, selected_potential_component);
66 });
67 static_cast<void>(elem);
68 return projected;
69}
70
71} // namespace detail
72
73template <class... SpatialIndex>
75
76template <class... SpatialIndex>
77 requires TwoDimensional<SpatialIndex...>
79{
80 using SpatialIndexSeq = ddc::detail::TypeSeq<SpatialIndex...>;
81 using PotentialScalarIndex = sil::tensor::ScalarIndex;
82 using MagneticInductionIndex = sil::exterior::coboundary_index_t<
84 PotentialScalarIndex>;
85 using OrthogonalPotentialComponent = sil::tensor::TensorNaturalIndex<OrthogonalPlaneIndex>;
86
87 template <class Index>
88 [[nodiscard]] KOKKOS_FUNCTION static constexpr auto magnetic_induction_component()
89 {
91 static_cast<void>(sizeof(OrthogonalPotentialComponent));
92 if constexpr (std::is_same_v<Index, ddc::type_seq_element_t<0, SpatialIndexSeq>>) {
93 return accessor.template access_element<ddc::type_seq_element_t<1, SpatialIndexSeq>>();
94 } else {
95 return accessor.template access_element<ddc::type_seq_element_t<0, SpatialIndexSeq>>();
96 }
97 }
98
99public:
100 template <class Index, class Elem>
101 [[nodiscard]] KOKKOS_FUNCTION static auto forward_value(Elem elem)
102 {
103 static_assert(
104 std::is_same_v<Index, ddc::type_seq_element_t<0, SpatialIndexSeq>>
105 || std::is_same_v<Index, ddc::type_seq_element_t<1, SpatialIndexSeq>>,
106 "2D magnetic induction component tag must be one of the spatial tags");
107 using spatial_domain_type = typename detail::ElementSpatialDomain<Elem>::type;
109 auto const lower_chain = sil::exterior::tangent_basis<0, spatial_domain_type>(elem);
110
111 auto stencil = sil::exterior::Coboundary<
114 value(sil::exterior::detail::IdentityStencilEvaluator {},
115 chain,
116 lower_chain,
117 elem,
118 magnetic_induction_component<Index>());
119 if constexpr (std::is_same_v<Index, ddc::type_seq_element_t<1, SpatialIndexSeq>>) {
120 stencil *= -1.0;
121 }
122 return stencil;
123 }
124
125 template <class TensorType, class Evaluator, class ChainType, class LowerChainType, class Elem>
126 KOKKOS_FUNCTION static void forward(
127 TensorType magnetic_induction,
128 Evaluator evaluator,
129 ChainType chain,
130 LowerChainType lower_chain,
131 Elem elem)
132 {
135 PotentialScalarIndex>::run(magnetic_induction, evaluator, chain, lower_chain, elem);
136 }
137};
138
139template <class... SpatialIndex>
140 requires ThreeDimensional<SpatialIndex...>
142{
143 using SpatialIndexSeq = ddc::detail::TypeSeq<SpatialIndex...>;
147 using MagneticInductionIndex
149
150 template <class Index>
151 [[nodiscard]] KOKKOS_FUNCTION static constexpr auto magnetic_induction_component()
152 {
154 if constexpr (std::is_same_v<Index, ddc::type_seq_element_t<0, SpatialIndexSeq>>) {
155 return accessor.template access_element<
156 ddc::type_seq_element_t<1, SpatialIndexSeq>,
157 ddc::type_seq_element_t<2, SpatialIndexSeq>>();
158 } else if constexpr (std::is_same_v<Index, ddc::type_seq_element_t<1, SpatialIndexSeq>>) {
159 return accessor.template access_element<
160 ddc::type_seq_element_t<0, SpatialIndexSeq>,
161 ddc::type_seq_element_t<2, SpatialIndexSeq>>();
162 } else {
163 return accessor.template access_element<
164 ddc::type_seq_element_t<0, SpatialIndexSeq>,
165 ddc::type_seq_element_t<1, SpatialIndexSeq>>();
166 }
167 }
168
169public:
171 using magnetic_induction_index = MagneticInductionIndex;
172
173 template <class Index, class Elem>
174 [[nodiscard]] KOKKOS_FUNCTION static auto forward_value(Elem elem)
175 {
176 static_assert(
177 std::is_same_v<Index, ddc::type_seq_element_t<0, SpatialIndexSeq>>
178 || std::is_same_v<Index, ddc::type_seq_element_t<1, SpatialIndexSeq>>
179 || std::is_same_v<Index, ddc::type_seq_element_t<2, SpatialIndexSeq>>,
180 "3D magnetic induction component tag must be one of the spatial tags");
181 using spatial_domain_type = typename detail::ElementSpatialDomain<Elem>::type;
183 auto const lower_chain = sil::exterior::tangent_basis<1, spatial_domain_type>(elem);
184
185 auto const output_component = magnetic_induction_component<Index>();
187 value(sil::exterior::detail::IdentityStencilEvaluator {},
188 chain,
189 lower_chain,
190 elem,
191 output_component);
192 if constexpr (std::is_same_v<Index, ddc::type_seq_element_t<1, SpatialIndexSeq>>) {
193 stencil *= -1.0;
194 }
195 return stencil;
196 }
197
198 template <class TensorType, class Evaluator, class ChainType, class LowerChainType, class Elem>
199 KOKKOS_FUNCTION static void forward(
200 TensorType magnetic_induction,
201 Evaluator evaluator,
202 ChainType chain,
203 LowerChainType lower_chain,
204 Elem elem)
205 {
207 run(magnetic_induction, evaluator, chain, lower_chain, elem);
208 }
209
210 template <class Index, class Elem>
211 [[nodiscard]] KOKKOS_FUNCTION static auto scalar_forward_value(Elem elem)
212 {
213 auto stencil = forward_value<Index>(elem);
214 [[maybe_unused]] sil::tensor::TensorAccessor<VectorPotentialIndex> potential_accessor;
215 auto projected = detail::project_to_scalar_potential_stencil(
216 stencil,
217 elem,
218 potential_accessor
219 .template access_element<ddc::type_seq_element_t<2, SpatialIndexSeq>>());
220 if constexpr (std::is_same_v<Index, ddc::type_seq_element_t<2, SpatialIndexSeq>>) {
221 projected *= 0.0;
222 }
223 return projected;
224 }
225};
226
227} // namespace similie::physics::magnetostatics
static KOKKOS_FUNCTION void forward(TensorType magnetic_induction, Evaluator evaluator, ChainType chain, LowerChainType lower_chain, Elem elem)
KOKKOS_FUNCTION constexpr auto tangent_basis(Elem elem)
typename detail::CoboundaryIndex< TagToAddToCochain, CochainTag >::type coboundary_index_t