From c10ac595e58ef3b3746afd9cfddd14acfd2f11ef Mon Sep 17 00:00:00 2001 From: mads-bertelsen-agentic <301266180+mads-bertelsen-agentic@users.noreply.github.com> Date: Tue, 1 Sep 2026 09:42:32 +0200 Subject: [PATCH 1/2] Fix RNG state handling for SPLIT Preserve all seven KISS RNG words when generated CPU and regular GPU SPLIT loops restore the particle state. The previous scalar backup only carried randstate[0] and reset the remaining KISS state words on every repetition. Correct the MT initialization guard in the common runtime so mt_srandom(mcseed) runs for RNG_ALG=1, matching the selector emitted by the code generator and ensuring command-line seed input is applied to MT. Validated with the Unittest_SPLIT instrument for KISS and MT at SPLITS=1, 10, and 100, including deterministic same-seed and differing-seed checks. --- common/lib/share/mccode_main.c | 2 +- mccode/src/cogen.c.in | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/common/lib/share/mccode_main.c b/common/lib/share/mccode_main.c index d40a112a1d..9a9dbd2f8f 100644 --- a/common/lib/share/mccode_main.c +++ b/common/lib/share/mccode_main.c @@ -150,7 +150,7 @@ int mccode_main(int argc, char *argv[]) #endif // MT specific init, note that per-ray init is empty -#if RNG_ALG == 2 +#if RNG_ALG == 1 mt_srandom(mcseed); #endif diff --git a/mccode/src/cogen.c.in b/mccode/src/cogen.c.in index 053fbc4faa..6d7a2bb2ed 100644 --- a/mccode/src/cogen.c.in +++ b/mccode/src/cogen.c.in @@ -1863,9 +1863,22 @@ int cogen_raytrace(struct instr_def *instr) "Split_%s_counter< SplitS_%s; " "Split_%s_counter++) {", comp->name, comp->name, comp->name, comp->name); - coutf(" randstate_t randbackup = *_particle->randstate;"); + coutf(" randstate_t randbackup[7];"); + coutf(" randbackup[0] = _particle->randstate[0];"); + coutf(" randbackup[1] = _particle->randstate[1];"); + coutf(" randbackup[2] = _particle->randstate[2];"); + coutf(" randbackup[3] = _particle->randstate[3];"); + coutf(" randbackup[4] = _particle->randstate[4];"); + coutf(" randbackup[5] = _particle->randstate[5];"); + coutf(" randbackup[6] = _particle->randstate[6];"); coutf(" *_particle=Split_%s_particle;", comp->name); // restore particle for SPLIT loop - coutf(" *_particle->randstate = randbackup;"); + coutf(" _particle->randstate[0] = randbackup[0];"); + coutf(" _particle->randstate[1] = randbackup[1];"); + coutf(" _particle->randstate[2] = randbackup[2];"); + coutf(" _particle->randstate[3] = randbackup[3];"); + coutf(" _particle->randstate[4] = randbackup[4];"); + coutf(" _particle->randstate[5] = randbackup[5];"); + coutf(" _particle->randstate[6] = randbackup[6];"); // Experimentally taking out the following line of code following discussions with Milan Klausz: // It seems that especially for the _uid=0 particle we get strange repetitions in the rng. // coutf(" srandom(_hash(_particle->_uid* %lu *(1+Split_%s_counter)));", comp->index, comp->name); From 933ec9bd4d4a3889d3fd19a1f8199dade9fc9b77 Mon Sep 17 00:00:00 2001 From: mads-bertelsen-agentic <301266180+mads-bertelsen-agentic@users.noreply.github.com> Date: Tue, 1 Sep 2026 10:15:31 +0200 Subject: [PATCH 2/2] Make SPLIT RNG backup length configurable Emit RANDSTATE_LEN alongside randstate_t for the selected MT or KISS algorithm before generating the particle and SPLIT code. Generate normal SPLIT backup and restore loops from RANDSTATE_LEN instead of assuming the seven-word KISS state. Guard the runtime header definitions so the generated preamble remains authoritative. Leave the FUNNEL implementation unchanged for a separate follow-up. --- common/lib/share/mccode-r.h.in | 8 ++++++-- mccode/src/cogen.c.in | 24 +++++++++--------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/common/lib/share/mccode-r.h.in b/common/lib/share/mccode-r.h.in index da0c0e793c..a9896d0988 100644 --- a/common/lib/share/mccode-r.h.in +++ b/common/lib/share/mccode-r.h.in @@ -619,7 +619,9 @@ void mcdis_sphere(double x, double y, double z, double r); #if RNG_ALG == _RNG_ALG_MT // MT (currently not functional for GPU) # define MC_RAND_MAX ((uint32_t)0xffffffffUL) -# define RANDSTATE_LEN 1 +# ifndef RANDSTATE_LEN +# define RANDSTATE_LEN 1 +# endif # define srandom(seed) mt_srandom_empty() # define random() mt_random() # define _random() mt_random() @@ -628,7 +630,9 @@ void mcdis_sphere(double x, double y, double z, double r); # define UINT64_MAX ((uint64_t)0xffffffffffffffffULL) # endif # define MC_RAND_MAX UINT64_MAX -# define RANDSTATE_LEN 7 +# ifndef RANDSTATE_LEN +# define RANDSTATE_LEN 7 +# endif # define srandom(seed) kiss_srandom(_particle->randstate, seed) # define random() kiss_random(_particle->randstate) # define _random() kiss_random(state) diff --git a/mccode/src/cogen.c.in b/mccode/src/cogen.c.in index 6d7a2bb2ed..ecdf96897b 100644 --- a/mccode/src/cogen.c.in +++ b/mccode/src/cogen.c.in @@ -1863,22 +1863,14 @@ int cogen_raytrace(struct instr_def *instr) "Split_%s_counter< SplitS_%s; " "Split_%s_counter++) {", comp->name, comp->name, comp->name, comp->name); - coutf(" randstate_t randbackup[7];"); - coutf(" randbackup[0] = _particle->randstate[0];"); - coutf(" randbackup[1] = _particle->randstate[1];"); - coutf(" randbackup[2] = _particle->randstate[2];"); - coutf(" randbackup[3] = _particle->randstate[3];"); - coutf(" randbackup[4] = _particle->randstate[4];"); - coutf(" randbackup[5] = _particle->randstate[5];"); - coutf(" randbackup[6] = _particle->randstate[6];"); + coutf(" randstate_t randbackup[RANDSTATE_LEN];"); + coutf(" for (int Split_%s_randstate_idx = 0; Split_%s_randstate_idx < RANDSTATE_LEN; Split_%s_randstate_idx++) {", comp->name, comp->name, comp->name); + coutf(" randbackup[Split_%s_randstate_idx] = _particle->randstate[Split_%s_randstate_idx];", comp->name, comp->name); + coutf(" }"); coutf(" *_particle=Split_%s_particle;", comp->name); // restore particle for SPLIT loop - coutf(" _particle->randstate[0] = randbackup[0];"); - coutf(" _particle->randstate[1] = randbackup[1];"); - coutf(" _particle->randstate[2] = randbackup[2];"); - coutf(" _particle->randstate[3] = randbackup[3];"); - coutf(" _particle->randstate[4] = randbackup[4];"); - coutf(" _particle->randstate[5] = randbackup[5];"); - coutf(" _particle->randstate[6] = randbackup[6];"); + coutf(" for (int Split_%s_randstate_idx = 0; Split_%s_randstate_idx < RANDSTATE_LEN; Split_%s_randstate_idx++) {", comp->name, comp->name, comp->name); + coutf(" _particle->randstate[Split_%s_randstate_idx] = randbackup[Split_%s_randstate_idx];", comp->name, comp->name); + coutf(" }"); // Experimentally taking out the following line of code following discussions with Milan Klausz: // It seems that especially for the _uid=0 particle we get strange repetitions in the rng. // coutf(" srandom(_hash(_particle->_uid* %lu *(1+Split_%s_counter)));", comp->index, comp->name); @@ -2436,8 +2428,10 @@ cogen_header(struct instr_def *instr, char *output_name) cout("#endif"); cout("#if RNG_ALG == _RNG_ALG_MT // MT "); cout("#define randstate_t uint32_t"); + cout("#define RANDSTATE_LEN 1"); cout("#elif RNG_ALG == _RNG_ALG_KISS // KISS"); cout("#define randstate_t uint64_t"); + cout("#define RANDSTATE_LEN 7"); cout("#endif"); cout("");