--- ray/src/rt/pmaprand.h 2015/05/08 13:20:23 2.3 +++ ray/src/rt/pmaprand.h 2017/08/14 21:12:10 2.8 @@ -1,44 +1,52 @@ -#ifndef PMAPRAND_H -#define PMAPRAND_H +/* RCSid $Id: pmaprand.h,v 2.8 2017/08/14 21:12:10 rschregle Exp $ */ /* - ================================================================== + ====================================================================== Random number generators for photon distribution Roland Schregle (roland.schregle@{hslu.ch, gmail.com}) (c) Fraunhofer Institute for Solar Energy Systems, (c) Lucerne University of Applied Sciences and Arts, - supported by the Swiss National Science Foundation (SNSF, #147053) - ================================================================== + supported by the Swiss National Science Foundation (SNSF, #147053) + ====================================================================== - $Id: pmaprand.h,v 2.3 2015/05/08 13:20:23 rschregle Exp $ + $Id: pmaprand.h,v 2.8 2017/08/14 21:12:10 rschregle Exp $ */ -/* According to the analytical validation, skipping numbers in the sequence - introduces bias in scenes with high reflectance. We therefore use - erand48() with separate states for photon emission, scattering, and - russian roulette. The pmapSeed() and pmapRandom() macros can be adapted - to other (better?) RNGs. */ +#ifndef PMAPRAND_H + #define PMAPRAND_H -#if defined(_WIN32) || defined(BSD) - /* Assume no erand48(), so use standard RNG without explicit multistate - control; the resulting sequences will be suboptimal */ - #include "random.h" - - #define pmapSeed(seed, state) (srandom(seed)) - #define pmapRandom(state) (frandom()) + /* According to the analytical validation, skipping sequential samples + * when sharing a single RNG among multiple sampling domains introduces + * overlapping photon rays (reported as 'duplicate keys' when building + * the underlying data structure) and therefore bias. This is aggravated + * when running parallel photon distribution subprocesses, where photon + * rays from different subprocesses may correlate. + * We therefore maintain a separate RNG state for each sampling domain + * (e.g. photon emission, scattering, and russian roulette). With + * multiprocessing, each subprocess has its own instance of the RNG + * state, which is independently seeded for decorellation -- see + * distribPhotons() and distribPhotonContrib(). + * The pmapSeed() and pmapRandom() macros below can be adapted to + * platform-specific RNGs if necessary. */ +#if defined(_WIN32) || defined(_WIN64) + /* Use standard RNG without state management; the generated sequences + * will be suboptimal */ + #include "random.h" + #define pmapSeed(seed, state) srandom(seed) + #define pmapRandom(state) frandom() #else + /* Assume NIX and manage RNG state via erand48() */ #define pmapSeed(seed, state) (state [0] += seed, state [1] += seed, \ state [2] += seed) - #define pmapRandom(state) erand48(state) + #define pmapRandom(state) erand48(state) #endif - -extern unsigned short partState [3], emitState [3], cntState [3], - mediumState [3], scatterState [3], rouletteState [3], - randSeed; - + + extern unsigned short partState [3], emitState [3], cntState [3], + mediumState [3], scatterState [3], rouletteState [3], + randSeed; #endif