8 #include <gsl/gsl_rng.h> 
    9 #include <gsl/gsl_randist.h> 
   11 #include <boost/thread/mutex.hpp> 
   12 #include <boost/thread/thread.hpp> 
   18 #include <boost/random.hpp> 
   33 #define NUKLEI_RANDOM_SYNC_NONE 
   37   static inline int nuklei_thread_num()
 
   39     return omp_get_thread_num();
 
   41   static inline int nuklei_max_threads()
 
   53   static inline int nuklei_thread_num()
 
   57   static inline int nuklei_max_threads()
 
   66   static std::vector<boost::mt19937>* bRandGens;
 
   68   static std::vector<gsl_rng*>* gRandGens;
 
   69   static std::vector<boost::shared_ptr<boost::mutex> >* mutexes;
 
   80     const char * envValPara = getenv(
"NUKLEI_PARALLELIZATION");
 
   81     if (envValPara != NULL)
 
   83       std::string para(envValPara);
 
   84       if (para == 
"single" || para == 
"openmp")
 
   88       else if (para == 
"pthread")
 
   90 #if defined(NUKLEI_RANDOM_SYNC_OMP) || defined(NUKLEI_RANDOM_SYNC_NONE) || !defined(NUKLEI_RANDOM_SYNC_MUTEX) 
   91         std::cout << 
"NUKLEI_PARALLELIZATION is set to pthread. " 
   92         "You should manually undefine all NUKLEI_RANDOM_SYNC_* in Random.cpp, " 
   93         "and define NUKLEI_RANDOM_SYNC_MUTEX instead. Note that multithreading " 
   94         "will be slower than with OpenMP. " 
   95         "See http://renaud-detry.net/nuklei/group__faq.html" << std::endl;
 
  101         std::cout << 
"Unknown value '" << para << 
"' for NUKLEI_PARALLELIZATION" 
  102         " env variable." << std::endl;
 
  107     const char * envVal = getenv(
"NUKLEI_RANDOM_SEED");
 
  110       const char * log = getenv(
"NUKLEI_LOG_LEVEL");
 
  111       if (log != NULL && numify<unsigned>(log) >= Log::INFO)
 
  112         std::cout << 
"export " << 
"NUKLEI_RANDOM_SEED" << 
"=" 
  113         << numify<int>(envVal)
 
  115       double seed_d = numify<double>(envVal);
 
  117         seed = numify<unsigned>(envVal);
 
  119         seed = time(NULL)*getpid(); 
 
  122     bRandGens = 
new std::vector<boost::mt19937>(nuklei_max_threads());
 
  123     gRandGens = 
new std::vector<gsl_rng*>(nuklei_max_threads(), NULL);
 
  124     for (
int i = 0; i < nuklei_max_threads(); i++)
 
  125       gRandGens->at(i) = gsl_rng_alloc(gsl_rng_mt19937);
 
  127     mutexes = 
new std::vector<boost::shared_ptr<boost::mutex> >();
 
  128     for (
int i = 0; i < nuklei_max_threads(); i++)
 
  129       mutexes->push_back(boost::shared_ptr<boost::mutex>(
new boost::mutex()));
 
  137     if (getenv(
"NUKLEI_RANDOM_SEED") != NULL)
 
  146     for (
int i = 0; i < bRandGens->size(); ++i)
 
  148       bRandGens->at(i).seed(s+i);
 
  150     for (
int i = 0; i < gRandGens->size(); ++i)
 
  152       gsl_rng_set(gRandGens->at(i), s+i+1); 
 
  162 #if defined(NUKLEI_RANDOM_SYNC_OMP) 
  163 #  pragma omp critical(nuklei_randomRng) 
  164 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX) 
  165     boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
 
  166 #elif defined(NUKLEI_RANDOM_SYNC_NONE) 
  168 #  error Undefined random sync method 
  170 #ifdef NUKLEI_USE_BOOST_RANDOM_GEN 
  172       boost::uniform_01<> 
dist;
 
  173       boost::variate_generator<boost::mt19937&, boost::uniform_01<> >
 
  174       die(bRandGens->at(nuklei_thread_num()), 
dist);
 
  178     r = gsl_rng_uniform(gRandGens->at(nuklei_thread_num()));
 
  188     NUKLEI_FAST_ASSERT(a < b);
 
  208 #if defined(NUKLEI_RANDOM_SYNC_OMP) 
  209 #  pragma omp critical(nuklei_randomRng) 
  210 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX) 
  211     boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
 
  212 #elif defined(NUKLEI_RANDOM_SYNC_NONE) 
  214 #  error Undefined random sync method 
  216 #ifdef NUKLEI_USE_BOOST_RANDOM_GEN 
  218       boost::uniform_int<unsigned long> 
dist(0, n-1);
 
  219       boost::variate_generator<boost::mt19937&, boost::uniform_int<unsigned long> >
 
  220       die(bRandGens->at(nuklei_thread_num()), 
dist);
 
  224     r = gsl_rng_uniform_int(gRandGens->at(nuklei_thread_num()), n);
 
  232 #if defined(NUKLEI_RANDOM_SYNC_OMP) 
  233 #  pragma omp critical(nuklei_randomRng) 
  234 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX) 
  235     boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
 
  236 #elif defined(NUKLEI_RANDOM_SYNC_NONE) 
  238 #  error Undefined random sync method 
  241       boost::triangle_distribution<> 
dist(-b/2, 0, b/2);
 
  242       boost::variate_generator<boost::mt19937&, boost::triangle_distribution<> >
 
  243       die(bRandGens->at(nuklei_thread_num()), 
dist);
 
  256 #if defined(NUKLEI_RANDOM_SYNC_OMP) 
  257 #  pragma omp critical(nuklei_randomRng) 
  258 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX) 
  259     boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
 
  260 #elif defined(NUKLEI_RANDOM_SYNC_NONE) 
  262 #  error Undefined random sync method 
  264 #ifdef NUKLEI_USE_BOOST_RANDOM_GEN 
  266       boost::normal_distribution<> 
dist(0, sigma);
 
  267       boost::variate_generator<boost::mt19937&, boost::normal_distribution<> >
 
  268       die(bRandGens->at(nuklei_thread_num()), 
dist);
 
  272     r = gsl_ran_gaussian(gRandGens->at(nuklei_thread_num()), sigma);
 
  280 #if defined(NUKLEI_RANDOM_SYNC_OMP) 
  281 #  pragma omp critical(nuklei_randomRng) 
  282 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX) 
  283     boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
 
  284 #elif defined(NUKLEI_RANDOM_SYNC_NONE) 
  286 #  error Undefined random sync method 
  288     r = gsl_ran_beta(gRandGens->at(nuklei_thread_num()), a, b);
 
  295 #if defined(NUKLEI_RANDOM_SYNC_OMP) 
  296 #  pragma omp critical(nuklei_randomRng) 
  297 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX) 
  298     boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
 
  299 #elif defined(NUKLEI_RANDOM_SYNC_NONE) 
  301 #  error Undefined random sync method 
  303 #ifdef NUKLEI_USE_BOOST_RANDOM_GEN 
  306       typedef boost::uniform_on_sphere<double, std::vector<double> > dist_t;
 
  308       boost::variate_generator<boost::mt19937&, dist_t >
 
  309       die(bRandGens->at(nuklei_thread_num()), 
dist);
 
  310       std::vector<double> r = die();
 
  315     gsl_ran_dir_2d(gRandGens->at(nuklei_thread_num()), &dir.X(), &dir.Y());
 
  323 #if defined(NUKLEI_RANDOM_SYNC_OMP) 
  324 #  pragma omp critical(nuklei_randomRng) 
  325 #elif defined(NUKLEI_RANDOM_SYNC_MUTEX) 
  326     boost::unique_lock<boost::mutex> lock(*mutexes->at(nuklei_thread_num()));
 
  327 #elif defined(NUKLEI_RANDOM_SYNC_NONE) 
  329 #  error Undefined random sync method 
  331 #ifdef NUKLEI_USE_BOOST_RANDOM_GEN 
  333     typedef boost::uniform_on_sphere<double, std::vector<double> > dist_t;
 
  335     boost::variate_generator<boost::mt19937&, dist_t >
 
  336     die(bRandGens->at(nuklei_thread_num()), 
dist);
 
  337     std::vector<double> r = die();
 
  342     gsl_ran_dir_3d(gRandGens->at(nuklei_thread_num()), &dir.X(), &dir.Y(), &dir.Z());
 
  355 #if defined(NUKLEI_RANDOM_QUATERNION_MARSAGLIA_1972) 
  356     coord_t x1, y1, s1, x2, y2, s2;
 
  371     coord_t root = std::sqrt( (1-s1)/s2 );
 
  377 #elif defined(NUKLEI_RANDOM_QUATERNION_GAUSSIAN_PROJ) 
  385 #else // Fastest method (although MARSAGLIA is comparable) 
  392     Quaternion u(std::cos(t2) * s2,
 
  401   void Random::printRandomState()
 
  403     NUKLEI_INFO(
"Random state: " <<