7 #include <sll/bernstein.hpp>
8 #include <sll/mapping/barycentric_coordinates.hpp>
9 #include <sll/mapping/discrete_to_cartesian.hpp>
10 #include <sll/polar_spline.hpp>
11 #include <sll/view.hpp>
26 template <
class BSplinesR,
class BSplinesTheta,
int C>
29 static_assert(C >= -1,
"Parameter `C` cannot be less than -1");
30 static_assert(C < 2,
"Values larger than 1 are not implemented for parameter `C`");
31 static_assert(!BSplinesR::is_periodic(),
"Radial bsplines must not be periodic.");
32 static_assert(!BSplinesR::is_uniform(),
"Radial bsplines must have knots at the boundary.");
33 static_assert(BSplinesTheta::is_periodic(),
"Poloidal bsplines should be periodic.");
41 struct eval_deriv_type
54 using DimR =
typename BSplinesR::continuous_dimension_type;
57 using DimTheta =
typename BSplinesTheta::continuous_dimension_type;
92 using IdxR = ddc::DiscreteElement<BSplinesR>;
93 using IdxTheta = ddc::DiscreteElement<BSplinesTheta>;
94 using IdxStepR = ddc::DiscreteVector<BSplinesR>;
95 using IdxStepTheta = ddc::DiscreteVector<BSplinesTheta>;
105 return (C + 1) * (C + 2) / 2;
116 template <
class DDim>
119 return ddc::DiscreteDomain<DDim>(
120 ddc::DiscreteElement<DDim> {0},
132 template <
class DDim>
136 int const r_idx = ddc::select<BSplinesR>(idx).uid();
137 int const theta_idx = ddc::select<BSplinesTheta>(idx).uid();
138 assert(r_idx >= C + 1);
139 int local_idx((r_idx - C - 1) * ddc::discrete_space<BSplinesTheta>().nbasis() + theta_idx);
151 template <
class DDim>
157 int const r_idx = idx_2d / ddc::discrete_space<BSplinesTheta>().nbasis();
158 int const theta_idx = idx_2d - r_idx * ddc::discrete_space<BSplinesTheta>().nbasis();
159 ddc::DiscreteElement<BSplinesR> r_idx_elem(r_idx + C + 1);
160 ddc::DiscreteElement<BSplinesTheta> theta_idx_elem(theta_idx);
161 return ddc::DiscreteElement<BSplinesR, BSplinesTheta>(r_idx_elem, theta_idx_elem);
171 template <
class DDim,
class MemorySpace>
174 template <
class ODDim,
class OMemorySpace>
177 template <
class ExecSpace,
class PBSpl,
class OMemorySpace>
179 ExecSpace
const& execution_space,
191 using singular_basis_linear_combination_idx_range_type
192 = ddc::DiscreteDomain<DDim, BSplinesR, BSplinesTheta>;
196 singular_basis_linear_combination_idx_range_type,
197 ddc::KokkosAllocator<double, MemorySpace>>
198 m_singular_basis_elements_alloc;
202 singular_basis_linear_combination_idx_range_type,
203 std::experimental::layout_right,
205 m_singular_basis_elements;
221 template <
class DiscreteMapping>
224 typename DiscreteMapping::cartesian_tag_x,
225 typename DiscreteMapping::cartesian_tag_y,
252 template <
class DiscreteMapping>
253 Impl(
const DiscreteMapping& curvilinear_to_cartesian)
255 static_assert(std::is_same_v<MemorySpace, Kokkos::HostSpace>);
256 using DimX =
typename DiscreteMapping::cartesian_tag_x;
257 using DimY =
typename DiscreteMapping::cartesian_tag_y;
258 using mapping_tensor_product_index_type = ddc::DiscreteElement<
259 typename DiscreteMapping::BSplineR,
260 typename DiscreteMapping::BSplineTheta>;
261 if constexpr (C > -1) {
262 const ddc::Coordinate<DimX, DimY> pole
263 = curvilinear_to_cartesian(ddc::Coordinate<DimR, DimTheta>(0.0, 0.0));
264 const double x0 = ddc::get<DimX>(pole);
265 const double y0 = ddc::get<DimY>(pole);
267 for (std::size_t i(0); i < ddc::discrete_space<BSplinesTheta>().size(); ++i) {
268 const ddc::Coordinate<DimX, DimY> point
269 = curvilinear_to_cartesian.control_point(
270 mapping_tensor_product_index_type(1, i));
272 const double c_x = ddc::get<DimX>(point);
273 const double c_y = ddc::get<DimY>(point);
275 double tau1 = -2.0 * (c_x - x0);
276 double tau2 = c_x - x0 - sqrt(3.0) * (c_y - y0);
277 double tau3 = c_x - x0 + sqrt(3.0) * (c_y - y0);
278 tau = tau > tau1 ? tau : tau1;
279 tau = tau > tau2 ? tau : tau2;
280 tau = tau > tau3 ? tau : tau3;
283 const ddc::Coordinate<DimX, DimY> corner1(x0 + tau, y0);
284 const ddc::Coordinate<DimX, DimY>
285 corner2(x0 - 0.5 * tau, y0 + 0.5 * tau * sqrt(3.0));
286 const ddc::Coordinate<DimX, DimY>
287 corner3(x0 - 0.5 * tau, y0 - 0.5 * tau * sqrt(3.0));
295 barycentric_coordinate_converter(corner1, corner2, corner3);
299 ddc::init_discrete_space<BernsteinBasis>(barycentric_coordinate_converter);
302 constexpr IdxStepR nr_in_singular(C + 1);
303 assert(nr_in_singular.value() <
int(ddc::discrete_space<BSplinesR>().size()));
306 const IdxStepTheta np_in_singular(ddc::discrete_space<BSplinesTheta>().
nbasis());
310 const IdxStepTheta np_tot(ddc::discrete_space<BSplinesTheta>().size());
319 m_singular_basis_elements_alloc
320 = ddc::Chunk<double, singular_basis_linear_combination_idx_range_type>(
321 singular_basis_linear_combination_idx_range_type(
322 singular_idx_range<DDim>(),
323 dom_bsplines_inner));
324 m_singular_basis_elements = m_singular_basis_elements_alloc.span_view();
326 ddc::DiscreteDomain<BernsteinBasis> bernstein_idx_range(
327 ddc::DiscreteElement<BernsteinBasis> {0},
330 ddc::DiscreteDomain<BSplinesTheta> poloidal_spline_idx_range
331 = ddc::discrete_space<BSplinesTheta>().full_domain();
333 for (IdxR
const ir : ddc::DiscreteDomain<BSplinesR>(IdxR(0), IdxStepR(C + 1))) {
334 for (IdxTheta
const ip : poloidal_spline_idx_range.take_first(np_in_singular)) {
335 const ddc::Coordinate<DimX, DimY> point
336 = curvilinear_to_cartesian.control_point(
337 mapping_tensor_product_index_type(ir, ip));
338 ddc::Chunk<double, ddc::DiscreteDomain<BernsteinBasis>> bernstein_vals(
339 bernstein_idx_range);
340 ddc::discrete_space<BernsteinBasis>().eval_basis(bernstein_vals, point);
342 for (
auto k : bernstein_idx_range) {
348 for (IdxTheta
const ip : poloidal_spline_idx_range.take_first(
349 IdxStepTheta {BSplinesTheta::degree()})) {
350 m_singular_basis_elements(k, ir, ip + np_in_singular)
351 = m_singular_basis_elements(k, ir, ip);
360 m_singular_basis_elements_alloc
361 = ddc::Chunk<double, singular_basis_linear_combination_idx_range_type>(
362 singular_basis_linear_combination_idx_range_type(
363 singular_idx_range<DDim>(),
364 empty_dom_bsplines));
365 m_singular_basis_elements = m_singular_basis_elements_alloc.span_view();
374 template <
class OriginMemorySpace>
376 : m_singular_basis_elements_alloc(impl.m_singular_basis_elements.domain())
378 m_singular_basis_elements = m_singular_basis_elements_alloc.span_view();
379 ddc::parallel_deepcopy(m_singular_basis_elements, impl.m_singular_basis_elements);
436 DSpan1D singular_values,
438 ddc::Coordinate<DimR, DimTheta> p)
const;
457 DSpan1D singular_derivs,
459 ddc::Coordinate<DimR, DimTheta> p)
const;
478 DSpan1D singular_derivs,
480 ddc::Coordinate<DimR, DimTheta> p)
const;
500 DSpan1D singular_derivs,
502 ddc::Coordinate<DimR, DimTheta> p)
const;
509 template <
class MemorySpace2>
510 [[deprecated(
"Use `integrals` instead")]]
void integrals(
520 std::size_t nr = ddc::discrete_space<BSplinesR>().nbasis() - C - 1;
521 std::size_t ntheta = ddc::discrete_space<BSplinesTheta>().nbasis();
548 template <
class EvalTypeR,
class EvalTypeTheta>
549 ddc::DiscreteElement<BSplinesR, BSplinesTheta> eval(
550 DSpan1D singular_values,
552 ddc::Coordinate<DimR, DimTheta> coord_eval,
554 EvalTypeTheta
const)
const;
558 template <
class BSplinesR,
class BSplinesTheta,
int C>
559 template <
class DDim,
class MemorySpace>
562 DSpan1D singular_values,
564 ddc::Coordinate<DimR, DimTheta> p)
const
566 return eval(singular_values, values, p, eval_type(), eval_type());
569 template <
class BSplinesR,
class BSplinesTheta,
int C>
570 template <
class DDim,
class MemorySpace>
573 DSpan1D singular_derivs,
575 ddc::Coordinate<DimR, DimTheta> p)
const
577 return eval(singular_derivs, derivs, p, eval_deriv_type(), eval_type());
580 template <
class BSplinesR,
class BSplinesTheta,
int C>
581 template <
class DDim,
class MemorySpace>
584 DSpan1D singular_derivs,
586 ddc::Coordinate<DimR, DimTheta> p)
const
588 return eval(singular_derivs, derivs, p, eval_type(), eval_deriv_type());
591 template <
class BSplinesR,
class BSplinesTheta,
int C>
592 template <
class DDim,
class MemorySpace>
595 DSpan1D singular_derivs,
597 ddc::Coordinate<DimR, DimTheta> p)
const
599 return eval(singular_derivs, derivs, p, eval_deriv_type(), eval_deriv_type());
602 template <
class BSplinesR,
class BSplinesTheta,
int C>
603 template <
class DDim,
class MemorySpace>
604 template <
class EvalTypeR,
class EvalTypeTheta>
607 DSpan1D singular_values,
609 ddc::Coordinate<DimR, DimTheta> coord_eval,
611 EvalTypeTheta
const)
const
613 assert(singular_values.extent(0) == n_singular_basis());
614 assert(values.extent(0) == BSplinesR::degree() + 1);
615 assert(values.extent(1) == BSplinesTheta::degree() + 1);
617 std::is_same_v<EvalTypeR, eval_type> || std::is_same_v<EvalTypeR, eval_deriv_type>);
621 eval_type> || std::is_same_v<EvalTypeTheta, eval_deriv_type>);
623 ddc::DiscreteElement<BSplinesR> jmin_r;
624 ddc::DiscreteElement<BSplinesTheta> jmin_theta;
626 std::size_t constexpr nr = BSplinesR::degree() + 1;
627 std::size_t constexpr ntheta = BSplinesTheta::degree() + 1;
629 std::array<double, nr> vals_r_ptr;
630 std::array<double, ntheta> vals_theta_ptr;
631 DSpan1D
const vals_r(vals_r_ptr.data(), nr);
632 DSpan1D
const vals_theta(vals_theta_ptr.data(), ntheta);
634 if constexpr (std::is_same_v<EvalTypeR, eval_type>) {
635 jmin_r = ddc::discrete_space<BSplinesR>().eval_basis(vals_r, ddc::select<DimR>(coord_eval));
636 }
else if constexpr (std::is_same_v<EvalTypeR, eval_deriv_type>) {
637 jmin_r = ddc::discrete_space<BSplinesR>().eval_deriv(vals_r, ddc::select<DimR>(coord_eval));
639 if constexpr (std::is_same_v<EvalTypeTheta, eval_type>) {
640 jmin_theta = ddc::discrete_space<BSplinesTheta>()
641 .eval_basis(vals_theta, ddc::select<DimTheta>(coord_eval));
642 }
else if constexpr (std::is_same_v<EvalTypeTheta, eval_deriv_type>) {
643 jmin_theta = ddc::discrete_space<BSplinesTheta>()
644 .eval_deriv(vals_theta, ddc::select<DimTheta>(coord_eval));
647 std::size_t nr_done = 0;
649 if (jmin_r.uid() < C + 1) {
650 nr_done = C + 1 - jmin_r.uid();
651 for (discrete_element_type k : singular_idx_range<DDim>()) {
652 singular_values(k.uid()) = 0.0;
653 for (std::size_t i(0); i < nr_done; ++i) {
654 for (std::size_t j(0); j < ntheta; ++j) {
655 singular_values(k.uid())
656 += m_singular_basis_elements(k, jmin_r + i, jmin_theta + j) * vals_r[i]
662 for (std::size_t k(0); k < n_singular_basis(); ++k) {
663 singular_values(k) = 0.0;
667 for (std::size_t i(0); i < nr - nr_done; ++i) {
668 for (std::size_t j(0); j < ntheta; ++j) {
669 values(i, j) = vals_r[i + nr_done] * vals_theta[j];
672 for (std::size_t i(nr - nr_done); i < nr; ++i) {
673 for (std::size_t j(0); j < ntheta; ++j) {
677 return ddc::DiscreteElement<BSplinesR, BSplinesTheta>(jmin_r, jmin_theta);
680 template <
class ExecSpace,
class DDim,
class MemorySpace>
682 ExecSpace
const& execution_space,
686 Kokkos::SpaceAccessibility<ExecSpace, MemorySpace>::accessible,
687 "MemorySpace has to be accessible for ExecutionSpace.");
688 using BSplinesR =
typename DDim::BSplinesR_tag;
690 using tensor_product_idx_range_type = ddc::DiscreteDomain<BSplinesR, BSplinesTheta>;
691 using tensor_product_idx_type = ddc::DiscreteElement<BSplinesR, BSplinesTheta>;
692 using IdxR = ddc::DiscreteElement<BSplinesR>;
693 using IdxTheta = ddc::DiscreteElement<BSplinesTheta>;
695 auto r_bspl_space = ddc::discrete_space<BSplinesR>();
696 auto theta_bspl_space = ddc::discrete_space<BSplinesTheta>();
699 assert(int_vals.
spline_coef.domain().front().template uid<BSplinesR>() == DDim::continuity + 1);
700 assert(int_vals.
spline_coef.domain().back().template uid<BSplinesR>()
701 == r_bspl_space.nbasis() - 1);
702 assert(int_vals.
spline_coef.domain().template extent<BSplinesTheta>()
703 == theta_bspl_space.nbasis()
704 || int_vals.
spline_coef.domain().template extent<BSplinesTheta>()
705 == theta_bspl_space.size());
707 ddc::Chunk<double, ddc::DiscreteDomain<BSplinesR>, ddc::KokkosAllocator<double, MemorySpace>>
708 r_integrals_alloc(r_bspl_space.full_domain().take_first(
709 ddc::DiscreteVector<BSplinesR> {r_bspl_space.nbasis()}));
712 ddc::DiscreteDomain<BSplinesTheta>,
713 ddc::KokkosAllocator<double, MemorySpace>>
714 theta_integrals_alloc(theta_bspl_space.full_domain().take_first(
715 ddc::DiscreteVector<BSplinesTheta> {theta_bspl_space.size()}));
716 ddc::ChunkSpan r_integrals = r_integrals_alloc.span_view();
717 ddc::ChunkSpan theta_integrals = theta_integrals_alloc.span_view();
719 ddc::integrals(execution_space, r_integrals);
720 ddc::integrals(execution_space, theta_integrals);
722 ddc::DiscreteDomain<BSplinesR, BSplinesTheta> singular_2d_idx_range(
723 ddc::discrete_space<DDim>().m_singular_basis_elements.domain());
726 ddc::DiscreteDomain<DDim> singular_idx_range = DDim::template singular_idx_range<DDim>();
727 Kokkos::parallel_for(
728 Kokkos::TeamPolicy<>(execution_space, singular_idx_range.size(), Kokkos::AUTO),
729 KOKKOS_LAMBDA(
const Kokkos::TeamPolicy<>::member_type& team) {
730 const int idx = team.league_rank();
731 ddc::DiscreteElement<DDim> k(idx);
735 Kokkos::parallel_reduce(
736 Kokkos::TeamThreadMDRange(
738 singular_2d_idx_range.template extent<BSplinesR>().value(),
739 singular_2d_idx_range.template extent<BSplinesTheta>().value()),
740 [&](
int r_thread_index,
int theta_thread_index,
double& sum) {
741 IdxR i(r_thread_index);
742 IdxTheta j(theta_thread_index);
743 sum += ddc::discrete_space<DDim>().m_singular_basis_elements(k, i, j)
744 * r_integrals(i) * theta_integrals(j);
747 singular_spline_integrals(k) = teamSum;
751 ddc::DiscreteDomain<BSplinesR> r_tensor_product_dom(
752 ddc::select<BSplinesR>(int_vals.
spline_coef.domain()));
753 tensor_product_idx_range_type
754 tensor_bspline_idx_range(r_tensor_product_dom, theta_integrals.domain());
755 ddc::ChunkSpan spline_integrals = int_vals.
spline_coef.span_view();
757 ddc::parallel_for_each(
759 tensor_bspline_idx_range,
760 KOKKOS_LAMBDA(tensor_product_idx_type idx) {
761 int_vals.
spline_coef(idx) = r_integrals(ddc::select<BSplinesR>(idx))
762 * theta_integrals(ddc::select<BSplinesTheta>(idx));
765 if (int_vals.
spline_coef.domain().template extent<BSplinesTheta>() == theta_bspl_space.size()) {
766 ddc::DiscreteDomain<BSplinesTheta> periodic_points(theta_integrals.domain().take_last(
767 ddc::DiscreteVector<BSplinesTheta> {BSplinesTheta::degree()}));
768 tensor_product_idx_range_type repeat_idx_range(r_tensor_product_dom, periodic_points);
769 ddc::parallel_fill(execution_space, int_vals.
spline_coef, 0.0);
774 template <
class BSplinesR,
class BSplinesTheta,
int C>
775 template <
class DDim,
class MemorySpace>
776 template <
class MemorySpace2>
780 integrals(Kokkos::DefaultHostExecutionSpace(), int_vals);
Definition: bernstein.hpp:16
A class to convert cartesian coordinates to barycentric coordinates on a triangle.
Definition: barycentric_coordinates.hpp:28
The Impl class holds the implementation of the PolarBSplines.
Definition: polar_bsplines.hpp:173
Impl & operator=(Impl const &x)=default
A copy operator for the PolarBSplines.
std::size_t nbasis() const noexcept
Get the total number of basis functions.
Definition: polar_bsplines.hpp:518
discrete_domain_type full_domain() const noexcept
Returns the index range containing the indices of all the polar b-splines.
Definition: polar_bsplines.hpp:530
Impl(Impl &&x)=default
A copy constructor for the PolarBSplines taking a temporary r-value.
tensor_product_index_type eval_deriv_r_and_theta(DSpan1D singular_derivs, DSpan2D derivs, ddc::Coordinate< DimR, DimTheta > p) const
Evaluate the second order derivative of the polar basis splines in the radial and poloidal directions...
Definition: polar_bsplines.hpp:594
Impl(const DiscreteMapping &curvilinear_to_cartesian)
A constructor for the PolarBSplines.
Definition: polar_bsplines.hpp:253
Impl & operator=(Impl &&x)=default
A copy operator for the PolarBSplines taking a temporary r-value.
ddc::DiscreteDomain< DDim > discrete_domain_type
The type of a index range of PolarBSplines.
Definition: polar_bsplines.hpp:240
~Impl()=default
The destructor for the PolarBSplines.
Impl(Impl< DDim, OriginMemorySpace > const &impl)
A copy constructor for the PolarBSplines.
Definition: polar_bsplines.hpp:375
ddc::DiscreteVector< DDim > discrete_vector_type
The type of a vector associated with a PolarBSpline.
Definition: polar_bsplines.hpp:243
tensor_product_index_type eval_basis(DSpan1D singular_values, DSpan2D values, ddc::Coordinate< DimR, DimTheta > p) const
Evaluate the polar basis splines at the coordinate p.
Definition: polar_bsplines.hpp:561
ddc::DiscreteElement< DDim > discrete_element_type
The type of an index associated with a PolarBSpline.
Definition: polar_bsplines.hpp:237
tensor_product_index_type eval_deriv_theta(DSpan1D singular_derivs, DSpan2D derivs, ddc::Coordinate< DimR, DimTheta > p) const
Evaluate the poloidal derivative of the polar basis splines at the coordinate p.
Definition: polar_bsplines.hpp:583
tensor_product_index_type eval_deriv_r(DSpan1D singular_derivs, DSpan2D derivs, ddc::Coordinate< DimR, DimTheta > p) const
Evaluate the radial derivative of the polar basis splines at the coordinate p.
Definition: polar_bsplines.hpp:572
discrete_domain_type tensor_bspline_idx_range() const noexcept
Returns the ddc::DiscreteDomain containing the indices of the b-splines which don't traverse the sing...
Definition: polar_bsplines.hpp:542
Impl(Impl const &x)=default
A copy constructor for the PolarBSplines.
The tag for the first corner of the Barycentric coordinates.
Definition: polar_bsplines.hpp:210
The tag for the second corner of the Barycentric coordinates.
Definition: polar_bsplines.hpp:214
The tag for the third corner of the Barycentric coordinates.
Definition: polar_bsplines.hpp:218
A class containing all information describing polar bsplines.
Definition: polar_bsplines.hpp:28
static KOKKOS_FUNCTION ddc::DiscreteElement< DDim > get_polar_index(tensor_product_index_type const &idx)
Get the index of the polar bspline which, when evaluated at the same point, returns the same values a...
Definition: polar_bsplines.hpp:133
static KOKKOS_FUNCTION tensor_product_index_type get_2d_index(ddc::DiscreteElement< DDim > const &idx)
Get the 2D index of the tensor product bspline which, when evaluated at the same point,...
Definition: polar_bsplines.hpp:153
ddc::DiscreteVector< BSplinesR, BSplinesTheta > tensor_product_idx_step_type
The type of a 2D vector for the subset of the polar bsplines which can be expressed as a tensor produ...
Definition: polar_bsplines.hpp:89
static constexpr std::size_t n_singular_basis()
Get the number of singular bsplines i.e.
Definition: polar_bsplines.hpp:103
typename BSplinesTheta::continuous_dimension_type DimTheta
The tag for the poloidal direction of the bsplines.
Definition: polar_bsplines.hpp:57
ddc::DiscreteDomain< BSplinesR, BSplinesTheta > tensor_product_idx_range_type
The type of the 2D idx_range for the subset of the polar bsplines which can be expressed as a tensor ...
Definition: polar_bsplines.hpp:83
ddc::DiscreteElement< BSplinesR, BSplinesTheta > tensor_product_index_type
The type of a 2D index for the subset of the polar bsplines which can be expressed as a tensor produc...
Definition: polar_bsplines.hpp:77
typename BSplinesR::continuous_dimension_type DimR
The tag for the radial direction of the bsplines.
Definition: polar_bsplines.hpp:54
static constexpr int continuity
The continuity enforced by the bsplines at the singular point.
Definition: polar_bsplines.hpp:61
static constexpr ddc::DiscreteDomain< DDim > singular_idx_range()
Get the ddc::DiscreteDomain containing the indices of the b-splines which traverse the singular point...
Definition: polar_bsplines.hpp:117
Definition: geometry.hpp:93
Definition: geometry.hpp:100
A structure containing the two ChunkSpans necessary to define a reference to a spline on a set of pol...
Definition: polar_spline.hpp:116
ddc::ChunkSpan< double, ddc::DiscreteDomain< PolarBSplinesType >, std::experimental::layout_right, MemSpace > singular_spline_coef
A ChunkSpan containing the coefficients in front of the b-spline elements near the singular point whi...
Definition: polar_spline.hpp:144
ddc::ChunkSpan< double, ddc::DiscreteDomain< BSplinesR, BSplinesTheta >, std::experimental::layout_right, MemSpace > spline_coef
A ChunkSpan containing the coefficients in front of the b-spline elements which can be expressed as a...
Definition: polar_spline.hpp:133