![]() |
|
|||
File indexing completed on 2025-09-14 08:50:58
0001 //------------------------------- -*- C++ -*- -------------------------------// 0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details 0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT) 0004 //---------------------------------------------------------------------------// 0005 //! \file corecel/random/distribution/PoissonDistribution.hh 0006 //---------------------------------------------------------------------------// 0007 #pragma once 0008 0009 #include <cmath> 0010 0011 #include "corecel/Assert.hh" 0012 #include "corecel/Macros.hh" 0013 #include "corecel/Types.hh" 0014 #include "corecel/math/Algorithms.hh" 0015 #include "celeritas/Constants.hh" 0016 0017 #include "NormalDistribution.hh" 0018 0019 namespace celeritas 0020 { 0021 //---------------------------------------------------------------------------// 0022 /*! 0023 * Sample from a Poisson distribution. 0024 * 0025 * The Poisson distribution describes the probability of \f$ k \f$ events 0026 * occuring in a fixed interval given a mean rate of occurance \f$ \lambda \f$ 0027 * and has the PMF: 0028 * \f[ 0029 f(k; \lambda) = \frac{\lambda^k e^{-\lambda}}{k!} \:. 0030 \f] 0031 * For small \f$ \lambda \f$, a direct method described in Knuth, Donald E., 0032 * Seminumerical Algorithms, The Art of Computer Programming, Volume 2 can be 0033 * used to generate samples from the Poisson distribution. Uniformly 0034 * distributed random numbers are generated until the relation 0035 * \f[ 0036 \prod_{k = 1}^n U_k \le e^{-\lambda} 0037 \f] 0038 * is satisfied; then, the random variable \f$ X = n - 1 \f$ will have a 0039 * Poisson distribution. On average this approach requires the generation of 0040 * \f$ \lambda + 1 \f$ uniform random samples, so a different method should be 0041 * used for large \f$ \lambda \f$. 0042 * 0043 * Geant4 uses Knuth's algorithm for \f$ \lambda \le 16 \f$ and a Gaussian 0044 * approximation for \f$ \lambda > 16 \f$ (see \c G4Poisson), which is faster 0045 * but less accurate than other methods. The same approach is used here. 0046 * 0047 * \todo Break this into two distributions: one actual poisson distribution, 0048 * one "integer normal" distribution, and a variant type that selects between 0049 * them. In most cases we care about, lambda is small. 0050 */ 0051 template<class RealType = ::celeritas::real_type> 0052 class PoissonDistribution 0053 { 0054 public: 0055 //!@{ 0056 //! \name Type aliases 0057 using real_type = RealType; 0058 using result_type = unsigned int; 0059 //!@} 0060 0061 public: 0062 // Construct with defaults 0063 explicit inline CELER_FUNCTION PoissonDistribution(real_type lambda = 1); 0064 0065 // Sample a random number according to the distribution 0066 template<class Generator> 0067 inline CELER_FUNCTION result_type operator()(Generator& rng); 0068 0069 //! Maximum value of lambda for using the direct method 0070 static CELER_CONSTEXPR_FUNCTION int lambda_threshold() { return 16; } 0071 0072 private: 0073 real_type const lambda_; 0074 NormalDistribution<real_type> sample_normal_; 0075 }; 0076 0077 //---------------------------------------------------------------------------// 0078 // INLINE DEFINITIONS 0079 //---------------------------------------------------------------------------// 0080 /*! 0081 * Construct from the mean of the Poisson distribution. 0082 */ 0083 template<class RealType> 0084 CELER_FUNCTION 0085 PoissonDistribution<RealType>::PoissonDistribution(real_type lambda) 0086 : lambda_(lambda), sample_normal_(lambda_, std::sqrt(lambda_)) 0087 { 0088 CELER_EXPECT(lambda_ > 0); 0089 } 0090 0091 //---------------------------------------------------------------------------// 0092 /*! 0093 * Sample a random number according to the distribution. 0094 */ 0095 template<class RealType> 0096 template<class Generator> 0097 CELER_FUNCTION auto 0098 PoissonDistribution<RealType>::operator()(Generator& rng) -> result_type 0099 { 0100 if (lambda_ <= PoissonDistribution::lambda_threshold()) 0101 { 0102 // Use direct method 0103 int k = 0; 0104 real_type p = std::exp(lambda_); 0105 do 0106 { 0107 ++k; 0108 p *= generate_canonical<real_type>(rng); 0109 } while (p > 1); 0110 return static_cast<result_type>(k - 1); 0111 } 0112 // Use Gaussian approximation rounded to nearest integer 0113 return result_type(sample_normal_(rng) + real_type(0.5)); 0114 } 0115 //---------------------------------------------------------------------------// 0116 } // namespace celeritas
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |