LCOV - code coverage report
Current view: top level - src/Random - InverseTransformSampling.h (source / functions) Coverage Total Hit
Test: report.info Lines: 0.0 % 79 0
Test Date: 2025-05-21 16:07:51 Functions: 0.0 % 18 0
Branches: 0.0 % 72 0

             Branch data     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