LCOV - code coverage report
Current view: top level - src/Random - InverseTransformSampling.h (source / functions) Coverage Total Hit
Test: final_report.info Lines: 0.0 % 79 0
Test Date: 2025-07-10 08:04:31 Functions: 0.0 % 18 0

            Line data    Source code
       1              : // Class InverseTransformSampling
       2              : //   This class can be used for generating samples of a given distribution function class using
       3              : //   inverse of its cumulative distribution on host or device.
       4              : //
       5              : 
       6              : #ifndef IPPL_INVERSE_TRANSFORM_SAMPLING_H
       7              : #define IPPL_INVERSE_TRANSFORM_SAMPLING_H
       8              : 
       9              : #include "Random/Utility.h"
      10              : 
      11              : namespace ippl {
      12              :     namespace random {
      13              :         /*!
      14              :          * @file InverseTransformSampling.h
      15              :          * @class InverseTransformSampling
      16              :          * @brief A class for inverse transform sampling.
      17              :          *
      18              :          * This class performs inverse transform sampling for a given distribution.
      19              :          *
      20              :          * @tparam T Data type.
      21              :          * @tparam Dim Dimensionality of the sample space.
      22              :          * @tparam DeviceType The device type for Kokkos.
      23              :          * @tparam Distribution Type of the distribution to sample from.
      24              :          */
      25              :         template <typename T, unsigned Dim, class DeviceType, class Distribution>
      26              :         class InverseTransformSampling {
      27              :         public:
      28              :             using view_type = typename ippl::detail::ViewType<Vector<T, Dim>, 1>::view_type;
      29              :             using size_type = ippl::detail::size_type;
      30              : 
      31              :             Distribution dist_m;
      32              :             size_type ntotal_m;
      33              :             Vector<T, Dim> umin_m, umax_m;
      34              : 
      35              :             /*!
      36              :              * @brief Constructor for InverseTransformSampling class with domain decomposition.
      37              :              *
      38              :              * @param dist_r The distribution to sample from.
      39              :              * @param rmax_r Maximum global range.
      40              :              * @param rmin_r Minimum global range.
      41              :              * @param rlayout_r The region layout.
      42              :              * @param ntotal_r Total number of samples to generate.
      43              :              */
      44              :             template <class RegionLayout>
      45            0 :             InverseTransformSampling(Distribution& dist_r, Vector<T, Dim>& rmax_r,
      46              :                                      Vector<T, Dim>& rmin_r, RegionLayout& rlayout_r,
      47              :                                      size_type& ntotal_r)
      48            0 :                 : dist_m(dist_r)
      49            0 :                 , ntotal_m(ntotal_r) {
      50            0 :                 const typename RegionLayout::host_mirror_type regions =
      51              :                     rlayout_r.gethLocalRegions();
      52            0 :                 int rank = ippl::Comm->rank();
      53              : 
      54            0 :                 Vector<T, Dim> locrmax, locrmin;
      55            0 :                 for (unsigned d = 0; d < Dim; ++d) {
      56            0 :                     locrmax[d] = regions(rank)[d].max();
      57            0 :                     locrmin[d] = regions(rank)[d].min();
      58              :                 }
      59              : 
      60            0 :                 updateBounds(rmax_r, rmin_r, locrmax, locrmin);
      61            0 :             }
      62              : 
      63              :             /*!
      64              :              * @brief Constructor for InverseTransformSampling class without applying domain
      65              :              * decomposition..
      66              :              *
      67              :              * @param dist_r The distribution to sample from.
      68              :              * @param rmax_r Maximum global range.
      69              :              * @param rmin_r Minimum global range.
      70              :              * @param locrmax_r Maximum local (per rank) range.
      71              :              * @param locrmin_r Minimum local (per rank) range.
      72              :              * @param ntotal_ Total number of samples to generate.
      73              :              */
      74            0 :             InverseTransformSampling(Distribution& dist_r, Vector<T, Dim>& rmax_r,
      75              :                                      Vector<T, Dim>& rmin_r, Vector<T, Dim>& locrmax_r,
      76              :                                      Vector<T, Dim>& locrmin_r, size_type& ntotal_r)
      77            0 :                 : dist_m(dist_r)
      78            0 :                 , ntotal_m(ntotal_r) {
      79            0 :                 updateBounds(rmax_r, rmin_r, locrmax_r, locrmin_r);
      80            0 :             }
      81              : 
      82              :             /*!
      83              :              * @brief Constructor for InverseTransformSampling class.
      84              :              *        In this method, we do not consider any domain decomposition.
      85              :              *
      86              :              * @param dist_r The distribution to sample from.
      87              :              * @param rmax_r Maximum global range for sampling.
      88              :              * @param rmin_r Minimum global range for sampling.
      89              :              * @param ntotal_r Total number of samples to generate.
      90              :              */
      91              :             InverseTransformSampling(Distribution& dist_r, Vector<T, Dim>& rmax_r,
      92              :                                      Vector<T, Dim>& rmin_r, size_type& ntotal_r)
      93              :                 : dist_m(dist_r)
      94              :                 , ntotal_m(ntotal_r) {
      95              :                 updateBounds(rmax_r, rmin_r);
      96              : 
      97              :                 nlocal_m = ntotal_m;
      98              :             }
      99              : 
     100              :             /*!
     101              :              * @brief Updates the sampling bounds and reinitializes internal variables.
     102              :              *
     103              :              * This method allows the user to update the minimum and maximum bounds
     104              :              * for the sampling process It recalculates
     105              :              * the cumulative distribution function (CDF) values for the new bounds and
     106              :              * updates the internal variables to reflect these changes.
     107              :              *
     108              :              * @param rmax The new maximum range for sampling. This vector defines
     109              :              *                 the upper bounds for each dimension.
     110              :              * @param rmin The new minimum range for sampling. This vector defines
     111              :              *                 the lower bounds for each dimension.
     112              :              * @param locrmax  The new local maximum range for sampling. This vector defines
     113              :              *                 the upper bounds for each dimension for a given rank.
     114              :              * @param locrmin  The new minimum range for sampling. This vector defines
     115              :              *                 the lower bounds for each dimension for a given rank.
     116              :              */
     117            0 :             void updateBounds(Vector<T, Dim>& rmax, Vector<T, Dim>& rmin, Vector<T, Dim>& locrmax,
     118              :                               Vector<T, Dim>& locrmin) {
     119            0 :                 int rank = ippl::Comm->rank();
     120            0 :                 Vector<T, Dim> nr_m, dr_m;
     121            0 :                 for (unsigned d = 0; d < Dim; ++d) {
     122            0 :                     nr_m[d]   = dist_m.getCdf(locrmax[d], d) - dist_m.getCdf(locrmin[d], d);
     123            0 :                     dr_m[d]   = dist_m.getCdf(rmax[d], d) - dist_m.getCdf(rmin[d], d);
     124            0 :                     umin_m[d] = dist_m.getCdf(locrmin[d], d);
     125            0 :                     umax_m[d] = dist_m.getCdf(locrmax[d], d);
     126              :                 }
     127            0 :                 T pnr = std::accumulate(nr_m.begin(), nr_m.end(), 1.0, std::multiplies<T>());
     128            0 :                 T pdr = std::accumulate(dr_m.begin(), dr_m.end(), 1.0, std::multiplies<T>());
     129              : 
     130            0 :                 T factor = pnr / pdr;
     131            0 :                 nlocal_m = (size_type)(factor * ntotal_m);
     132              : 
     133            0 :                 size_type nglobal = 0;
     134            0 :                 ippl::Comm->allreduce(&nlocal_m, &nglobal, 1, std::plus<size_type>());
     135              : 
     136            0 :                 int rest = (int)(ntotal_m - nglobal);
     137            0 :                 if (rank < rest) {
     138            0 :                     ++nlocal_m;
     139              :                 }
     140            0 :             }
     141              : 
     142              :             /*!
     143              :              * @brief Updates the sampling bounds using the CDF without any domain decomposition.
     144              :              *
     145              :              * This method allows the user to update the minimum and maximum bounds
     146              :              * for the inverse transform sampling method. It recalculates
     147              :              * the cumulative distribution function (CDF) values for the new bounds and
     148              :              * updates the internal variables to reflect these changes.
     149              :              *
     150              :              * @param new_rmax The new maximum range for sampling. This vector defines
     151              :              *                 the upper bounds for each dimension.
     152              :              * @param new_rmin The new minimum range for sampling. This vector defines
     153              :              *                 the lower bounds for each dimension.
     154              :              */
     155            0 :             void updateBounds(Vector<T, Dim>& rmax, Vector<T, Dim>& rmin) {
     156            0 :                 Vector<T, Dim> nr_m, dr_m;
     157            0 :                 for (unsigned d = 0; d < Dim; ++d) {
     158            0 :                     umin_m[d] = dist_m.getCdf(rmin[d], d);
     159            0 :                     umax_m[d] = dist_m.getCdf(rmax[d], d);
     160              :                 }
     161            0 :             }
     162              : 
     163              :             /*!
     164              :              * @brief Deconstructor for InverseTransformSampling class.
     165              :              */
     166            0 :             ~InverseTransformSampling() {}
     167              : 
     168              :             /*!
     169              :              * @brief Functor that is used for generating samples.
     170              :              */
     171              :             template <class GeneratorPool>
     172              :             struct fill_random {
     173              :                 using value_type = T;
     174              :                 Distribution targetdist_m;
     175              :                 view_type sample_m;
     176              :                 GeneratorPool pool_m;
     177              :                 Vector<T, Dim> minbound_m;
     178              :                 Vector<T, Dim> maxbound_m;
     179              :                 unsigned int dim_m;
     180              : 
     181              :                 /*!
     182              :                  * @brief Constructor for the fill_random functor.
     183              :                  *
     184              :                  * @param dist_ The distribution to sample from.
     185              :                  * @param x_ The view to generate samples in.
     186              :                  * @param rand_pool_ The random number generator pool.
     187              :                  * @param umin_ Minimum cumulative distribution values.
     188              :                  * @param umax_ Maximum cumulative distribution values.
     189              :                  */
     190              :                 KOKKOS_FUNCTION
     191            0 :                 fill_random(Distribution& dist_r, view_type& x_r, GeneratorPool& rand_pool_r,
     192              :                             Vector<T, Dim>& umin_r, Vector<T, Dim>& umax_r, unsigned int& d_r)
     193            0 :                     : targetdist_m(dist_r)
     194            0 :                     , sample_m(x_r)
     195            0 :                     , pool_m(rand_pool_r)
     196            0 :                     , minbound_m(umin_r)
     197            0 :                     , maxbound_m(umax_r)
     198            0 :                     , dim_m(d_r) {}
     199              : 
     200              :                 /*!
     201              :                  * @brief Operator to fill random values.
     202              :                  *
     203              :                  * @param i Index for the random values.
     204              :                  */
     205            0 :                 KOKKOS_INLINE_FUNCTION void operator()(const size_t i) const {
     206            0 :                     typename GeneratorPool::generator_type rand_gen = pool_m.get_state();
     207              : 
     208            0 :                     value_type u = 0.0;
     209              : 
     210            0 :                     u = rand_gen.drand(minbound_m[dim_m], maxbound_m[dim_m]);
     211              : 
     212              :                     // first guess for Newton-Raphson
     213            0 :                     sample_m(i)[dim_m] = targetdist_m.getEstimate(u, dim_m);
     214              : 
     215              :                     // solve
     216            0 :                     ippl::random::detail::NewtonRaphson<value_type, Distribution> solver(
     217            0 :                         targetdist_m);
     218              : 
     219            0 :                     solver.solve(dim_m, sample_m(i)[dim_m], u);
     220              : 
     221            0 :                     pool_m.free_state(rand_gen);
     222            0 :                 }
     223              :             };
     224              : 
     225              :             /*!
     226              :              * @brief Get the local number of samples.
     227              :              *
     228              :              * @returns The local number of samples.
     229              :              */
     230            0 :             KOKKOS_INLINE_FUNCTION size_type getLocalSamplesNum() const { return nlocal_m; }
     231              : 
     232              :             /*!
     233              :              * @brief Set the local number of particles.
     234              :              *
     235              :              * @param nlocal The new number of local particles.
     236              :              */
     237            0 :             KOKKOS_INLINE_FUNCTION void setLocalSamplesNum(size_type nlocal) { nlocal_m = nlocal; }
     238              : 
     239              :             /*!
     240              :              * @brief Generate random samples using inverse transform sampling.
     241              :              *
     242              :              * @param view The view to fill with random samples.
     243              :              * @param rand_pool64 The random number generator pool.
     244              :              */
     245            0 :             void generate(view_type view, Kokkos::Random_XorShift64_Pool<> rand_pool64) {
     246            0 :                 Vector<T, Dim> minbound_m = umin_m;
     247            0 :                 Vector<T, Dim> maxbound_m = umax_m;
     248            0 :                 Distribution targetdist_m = dist_m;
     249            0 :                 size_type numlocal_m      = nlocal_m;
     250            0 :                 for (unsigned d = 0; d < Dim; ++d) {
     251            0 :                     Kokkos::parallel_for(numlocal_m, fill_random<Kokkos::Random_XorShift64_Pool<>>(
     252              :                                                          targetdist_m, view, rand_pool64,
     253              :                                                          minbound_m, maxbound_m, d));
     254            0 :                     Kokkos::fence();
     255              :                 }
     256            0 :             }
     257              : 
     258              :             /*!
     259              :              * @brief Generate random samples using inverse transform sampling for a specific range
     260              :              * of particles
     261              :              *
     262              :              * @param view The view to fill with random samples.
     263              :              * @param startIndex The starting index of view.
     264              :              * @param endIndex The ending index of view.
     265              :              * @param rand_pool64 The random number generator pool.
     266              :              */
     267            0 :             void generate(view_type view, size_type startIndex, size_type endIndex,
     268              :                           Kokkos::Random_XorShift64_Pool<> rand_pool64) {
     269            0 :                 Vector<T, Dim> minbound_m = umin_m;
     270            0 :                 Vector<T, Dim> maxbound_m = umax_m;
     271            0 :                 Distribution targetdist_m = dist_m;
     272            0 :                 for (unsigned d = 0; d < Dim; ++d) {
     273            0 :                     Kokkos::parallel_for(
     274            0 :                         Kokkos::RangePolicy<>(startIndex, endIndex),
     275            0 :                         fill_random<Kokkos::Random_XorShift64_Pool<>>(
     276              :                             targetdist_m, view, rand_pool64, minbound_m, maxbound_m, d));
     277            0 :                     Kokkos::fence();
     278              :                 }
     279            0 :             }
     280              : 
     281              :         private:
     282              :             size_type nlocal_m;
     283              :         };
     284              : 
     285              :     }  // namespace random
     286              : }  // namespace ippl
     287              : 
     288              : #endif
        

Generated by: LCOV version 2.0-1