Gyselalib++
polar_bsplines.hpp
1 #pragma once
2 #include <array>
3 #include <vector>
4 
5 #include <ddc/ddc.hpp>
6 
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>
12 
26 template <class BSplinesR, class BSplinesTheta, int C>
28 {
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.");
34 
35 private:
36  // Tags to determine what to evaluate
37  struct eval_type
38  {
39  };
40 
41  struct eval_deriv_type
42  {
43  };
44 
45 public:
48 
51 
52 
54  using DimR = typename BSplinesR::continuous_dimension_type;
55 
57  using DimTheta = typename BSplinesTheta::continuous_dimension_type;
58 
59 public:
61  static int constexpr continuity = C;
62 
63 public:
72 
77  using tensor_product_index_type = ddc::DiscreteElement<BSplinesR, BSplinesTheta>;
78 
83  using tensor_product_idx_range_type = ddc::DiscreteDomain<BSplinesR, BSplinesTheta>;
84 
89  using tensor_product_idx_step_type = ddc::DiscreteVector<BSplinesR, BSplinesTheta>;
90 
91 private:
92  using IdxR = ddc::DiscreteElement<BSplinesR>;
93  using IdxTheta = ddc::DiscreteElement<BSplinesTheta>;
94  using IdxStepR = ddc::DiscreteVector<BSplinesR>;
95  using IdxStepTheta = ddc::DiscreteVector<BSplinesTheta>;
96 
97 public:
103  static constexpr std::size_t n_singular_basis()
104  {
105  return (C + 1) * (C + 2) / 2;
106  }
107 
108 
116  template <class DDim>
117  static constexpr ddc::DiscreteDomain<DDim> singular_idx_range()
118  {
119  return ddc::DiscreteDomain<DDim>(
120  ddc::DiscreteElement<DDim> {0},
121  ddc::DiscreteVector<DDim> {n_singular_basis()});
122  }
123 
132  template <class DDim>
133  static KOKKOS_FUNCTION ddc::DiscreteElement<DDim> get_polar_index(
134  tensor_product_index_type const& idx)
135  {
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);
140  return ddc::DiscreteElement<DDim>(n_singular_basis() + local_idx);
141  }
142 
151  template <class DDim>
152  static KOKKOS_FUNCTION tensor_product_index_type
153  get_2d_index(ddc::DiscreteElement<DDim> const& idx)
154  {
155  assert(idx.uid() >= n_singular_basis());
156  int const idx_2d = idx.uid() - n_singular_basis();
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);
162  }
163 
164 public:
171  template <class DDim, class MemorySpace>
172  class Impl
173  {
174  template <class ODDim, class OMemorySpace>
175  friend class Impl;
176 
177  template <class ExecSpace, class PBSpl, class OMemorySpace>
178  friend PolarSplineSpan<PBSpl, OMemorySpace> integrals(
179  ExecSpace const& execution_space,
181 
182  private:
191  using singular_basis_linear_combination_idx_range_type
192  = ddc::DiscreteDomain<DDim, BSplinesR, BSplinesTheta>;
193 
194  ddc::Chunk<
195  double,
196  singular_basis_linear_combination_idx_range_type,
197  ddc::KokkosAllocator<double, MemorySpace>>
198  m_singular_basis_elements_alloc;
199 
200  ddc::ChunkSpan<
201  double,
202  singular_basis_linear_combination_idx_range_type,
203  std::experimental::layout_right,
204  MemorySpace>
205  m_singular_basis_elements;
206 
207  public:
209  struct Corner1Tag
210  {
211  };
213  struct Corner2Tag
214  {
215  };
217  struct Corner3Tag
218  {
219  };
220 
221  template <class DiscreteMapping>
224  typename DiscreteMapping::cartesian_tag_x,
225  typename DiscreteMapping::cartesian_tag_y,
226  Corner1Tag,
227  Corner2Tag,
228  Corner3Tag,
229  C>
230  {
231  };
232 
235 
237  using discrete_element_type = ddc::DiscreteElement<DDim>;
238 
240  using discrete_domain_type = ddc::DiscreteDomain<DDim>;
241 
243  using discrete_vector_type = ddc::DiscreteVector<DDim>;
244 
252  template <class DiscreteMapping>
253  Impl(const DiscreteMapping& curvilinear_to_cartesian)
254  {
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);
266  double tau = 0.0;
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));
271 
272  const double c_x = ddc::get<DimX>(point);
273  const double c_y = ddc::get<DimY>(point);
274 
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;
281  }
282  // Determine the corners for the barycentric coordinates
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));
288 
290  DimX,
291  DimY,
292  Corner1Tag,
293  Corner2Tag,
294  Corner3Tag>
295  barycentric_coordinate_converter(corner1, corner2, corner3);
296 
297  using BernsteinBasis = IntermediateBernsteinBasis<DiscreteMapping>;
298 
299  ddc::init_discrete_space<BernsteinBasis>(barycentric_coordinate_converter);
300 
301  // The number of radial bases used to construct the bsplines traversing the singular point.
302  constexpr IdxStepR nr_in_singular(C + 1);
303  assert(nr_in_singular.value() < int(ddc::discrete_space<BSplinesR>().size()));
304 
305  // The number of poloidal bases used to construct the bsplines traversing the singular point.
306  const IdxStepTheta np_in_singular(ddc::discrete_space<BSplinesTheta>().nbasis());
307 
308  // The number of elements of the poloidal basis which will have an associated coefficient
309  // (This will be larger than np_in_singular as it includes the periodicity)
310  const IdxStepTheta np_tot(ddc::discrete_space<BSplinesTheta>().size());
311 
312  // The index range of the 2D bsplines in the innermost circles from which the polar bsplines
313  // traversing the singular point will be constructed.
314  tensor_product_idx_range_type const dom_bsplines_inner(
316  tensor_product_idx_step_type(nr_in_singular, np_tot));
317 
318  // Initialise memory
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();
325 
326  ddc::DiscreteDomain<BernsteinBasis> bernstein_idx_range(
327  ddc::DiscreteElement<BernsteinBasis> {0},
328  ddc::DiscreteVector<BernsteinBasis> {n_singular_basis()});
329 
330  ddc::DiscreteDomain<BSplinesTheta> poloidal_spline_idx_range
331  = ddc::discrete_space<BSplinesTheta>().full_domain();
332 
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);
341  // Fill spline coefficients
342  for (auto k : bernstein_idx_range) {
343  m_singular_basis_elements(discrete_element_type {k.uid()}, ir, ip)
344  = bernstein_vals(k);
345  }
346  }
347  for (discrete_element_type k : singular_idx_range<DDim>()) {
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);
352  }
353  }
354  }
355  } else {
356  // Initialise m_singular_basis_elements to avoid any problems in the copy constructor
357  tensor_product_idx_range_type const empty_dom_bsplines(
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();
366  }
367  }
368 
374  template <class OriginMemorySpace>
375  explicit Impl(Impl<DDim, OriginMemorySpace> const& impl)
376  : m_singular_basis_elements_alloc(impl.m_singular_basis_elements.domain())
377  {
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);
380  }
381 
387  Impl(Impl const& x) = default;
388 
394  Impl(Impl&& x) = default;
395 
399  ~Impl() = default;
400 
408  Impl& operator=(Impl const& x) = default;
409 
417  Impl& operator=(Impl&& x) = default;
418 
436  DSpan1D singular_values,
437  DSpan2D values,
438  ddc::Coordinate<DimR, DimTheta> p) const;
439 
457  DSpan1D singular_derivs,
458  DSpan2D derivs,
459  ddc::Coordinate<DimR, DimTheta> p) const;
460 
478  DSpan1D singular_derivs,
479  DSpan2D derivs,
480  ddc::Coordinate<DimR, DimTheta> p) const;
481 
500  DSpan1D singular_derivs,
501  DSpan2D derivs,
502  ddc::Coordinate<DimR, DimTheta> p) const;
503 
509  template <class MemorySpace2>
510  [[deprecated("Use `integrals` instead")]] void integrals(
511  PolarSplineSpan<DDim, MemorySpace2> int_vals) const;
512 
518  std::size_t nbasis() const noexcept
519  {
520  std::size_t nr = ddc::discrete_space<BSplinesR>().nbasis() - C - 1;
521  std::size_t ntheta = ddc::discrete_space<BSplinesTheta>().nbasis();
522  return n_singular_basis() + nr * ntheta;
523  }
524 
531  {
533  }
534 
543  {
544  return full_domain().remove_first(discrete_vector_type {n_singular_basis()});
545  }
546 
547  private:
548  template <class EvalTypeR, class EvalTypeTheta>
549  ddc::DiscreteElement<BSplinesR, BSplinesTheta> eval(
550  DSpan1D singular_values,
551  DSpan2D values,
552  ddc::Coordinate<DimR, DimTheta> coord_eval,
553  EvalTypeR const,
554  EvalTypeTheta const) const;
555  };
556 };
557 
558 template <class BSplinesR, class BSplinesTheta, int C>
559 template <class DDim, class MemorySpace>
560 ddc::DiscreteElement<BSplinesR, BSplinesTheta> PolarBSplines<BSplinesR, BSplinesTheta, C>::
562  DSpan1D singular_values,
563  DSpan2D values,
564  ddc::Coordinate<DimR, DimTheta> p) const
565 {
566  return eval(singular_values, values, p, eval_type(), eval_type());
567 }
568 
569 template <class BSplinesR, class BSplinesTheta, int C>
570 template <class DDim, class MemorySpace>
571 ddc::DiscreteElement<BSplinesR, BSplinesTheta> PolarBSplines<BSplinesR, BSplinesTheta, C>::
573  DSpan1D singular_derivs,
574  DSpan2D derivs,
575  ddc::Coordinate<DimR, DimTheta> p) const
576 {
577  return eval(singular_derivs, derivs, p, eval_deriv_type(), eval_type());
578 }
579 
580 template <class BSplinesR, class BSplinesTheta, int C>
581 template <class DDim, class MemorySpace>
582 ddc::DiscreteElement<BSplinesR, BSplinesTheta> PolarBSplines<BSplinesR, BSplinesTheta, C>::
584  DSpan1D singular_derivs,
585  DSpan2D derivs,
586  ddc::Coordinate<DimR, DimTheta> p) const
587 {
588  return eval(singular_derivs, derivs, p, eval_type(), eval_deriv_type());
589 }
590 
591 template <class BSplinesR, class BSplinesTheta, int C>
592 template <class DDim, class MemorySpace>
593 ddc::DiscreteElement<BSplinesR, BSplinesTheta> PolarBSplines<BSplinesR, BSplinesTheta, C>::
595  DSpan1D singular_derivs,
596  DSpan2D derivs,
597  ddc::Coordinate<DimR, DimTheta> p) const
598 {
599  return eval(singular_derivs, derivs, p, eval_deriv_type(), eval_deriv_type());
600 }
601 
602 template <class BSplinesR, class BSplinesTheta, int C>
603 template <class DDim, class MemorySpace>
604 template <class EvalTypeR, class EvalTypeTheta>
605 ddc::DiscreteElement<BSplinesR, BSplinesTheta> PolarBSplines<BSplinesR, BSplinesTheta, C>::
607  DSpan1D singular_values,
608  DSpan2D values,
609  ddc::Coordinate<DimR, DimTheta> coord_eval,
610  EvalTypeR const,
611  EvalTypeTheta const) const
612 {
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);
616  static_assert(
617  std::is_same_v<EvalTypeR, eval_type> || std::is_same_v<EvalTypeR, eval_deriv_type>);
618  static_assert(
619  std::is_same_v<
620  EvalTypeTheta,
621  eval_type> || std::is_same_v<EvalTypeTheta, eval_deriv_type>);
622 
623  ddc::DiscreteElement<BSplinesR> jmin_r;
624  ddc::DiscreteElement<BSplinesTheta> jmin_theta;
625 
626  std::size_t constexpr nr = BSplinesR::degree() + 1;
627  std::size_t constexpr ntheta = BSplinesTheta::degree() + 1;
628 
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);
633 
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));
638  }
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));
645  }
646 
647  std::size_t nr_done = 0;
648 
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]
657  * vals_theta[j];
658  }
659  }
660  }
661  } else {
662  for (std::size_t k(0); k < n_singular_basis(); ++k) {
663  singular_values(k) = 0.0;
664  }
665  }
666 
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];
670  }
671  }
672  for (std::size_t i(nr - nr_done); i < nr; ++i) {
673  for (std::size_t j(0); j < ntheta; ++j) {
674  values(i, j) = 0.0;
675  }
676  }
677  return ddc::DiscreteElement<BSplinesR, BSplinesTheta>(jmin_r, jmin_theta);
678 }
679 
680 template <class ExecSpace, class DDim, class MemorySpace>
682  ExecSpace const& execution_space,
684 {
685  static_assert(
686  Kokkos::SpaceAccessibility<ExecSpace, MemorySpace>::accessible,
687  "MemorySpace has to be accessible for ExecutionSpace.");
688  using BSplinesR = typename DDim::BSplinesR_tag;
689  using BSplinesTheta = typename DDim::BSplinesTheta_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>;
694 
695  auto r_bspl_space = ddc::discrete_space<BSplinesR>();
696  auto theta_bspl_space = ddc::discrete_space<BSplinesTheta>();
697 
698  assert(int_vals.singular_spline_coef.domain().extents() == DDim::n_singular_basis());
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());
706 
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()}));
710  ddc::Chunk<
711  double,
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();
718 
719  ddc::integrals(execution_space, r_integrals);
720  ddc::integrals(execution_space, theta_integrals);
721 
722  ddc::DiscreteDomain<BSplinesR, BSplinesTheta> singular_2d_idx_range(
723  ddc::discrete_space<DDim>().m_singular_basis_elements.domain());
724  ddc::ChunkSpan singular_spline_integrals = int_vals.singular_spline_coef.span_view();
725 
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);
732 
733  // Sum over quadrature dimensions
734  double teamSum = 0;
735  Kokkos::parallel_reduce(
736  Kokkos::TeamThreadMDRange(
737  team,
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);
745  },
746  teamSum);
747  singular_spline_integrals(k) = teamSum;
748  });
749 
750 
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();
756 
757  ddc::parallel_for_each(
758  execution_space,
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));
763  });
764 
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);
770  }
771  return int_vals;
772 }
773 
774 template <class BSplinesR, class BSplinesTheta, int C>
775 template <class DDim, class MemorySpace>
776 template <class MemorySpace2>
779 {
780  integrals(Kokkos::DefaultHostExecutionSpace(), int_vals);
781 }
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
Definition: polar_bsplines.hpp:230
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