Derive a unique per-job seed for minicalosim shard generation
Concurrent job launches in create_root_files.py can start within the same wall-clock second, and minicalosim's default seed falls back to time(NULL) in that case — so two "independent" shards could silently get identical RNG state and produce byte-identical physics. Requires the companion MINICALOSIM_SEED env-var support in the minicalosim repo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ from scripts import create_root_files
|
||||
parse_detector_spec = create_root_files.parse_detector_spec
|
||||
next_shard_index = create_root_files.next_shard_index
|
||||
plan_jobs = create_root_files.plan_jobs
|
||||
job_seed = create_root_files.job_seed
|
||||
run_job = create_root_files.run_job
|
||||
run_all = create_root_files.run_all
|
||||
SimJob = create_root_files.SimJob
|
||||
@@ -35,7 +36,13 @@ start = time.time()
|
||||
time.sleep({sleep})
|
||||
end = time.time()
|
||||
payload = json.dumps(
|
||||
{{"argv": sys.argv[1:], "cwd": os.getcwd(), "start": start, "end": end}}
|
||||
{{
|
||||
"argv": sys.argv[1:],
|
||||
"cwd": os.getcwd(),
|
||||
"start": start,
|
||||
"end": end,
|
||||
"seed": os.environ.get("MINICALOSIM_SEED"),
|
||||
}}
|
||||
)
|
||||
for i in range({output_count}):
|
||||
with open(f"out_{{i}}.root", "w") as f:
|
||||
@@ -130,6 +137,42 @@ def test_plan_jobs_multiple_detectors_each_start_independently(tmp_path):
|
||||
assert by_detector["sampling_fe_scint"] == [0, 1]
|
||||
|
||||
|
||||
def test_job_seed_deterministic():
|
||||
job = SimJob(detector="pbwo4", config=None, shard_index=3)
|
||||
assert job_seed("steps", "gen1", job) == job_seed("steps", "gen1", job)
|
||||
|
||||
|
||||
def test_job_seed_varies_by_shard_index():
|
||||
a = SimJob(detector="pbwo4", config=None, shard_index=0)
|
||||
b = SimJob(detector="pbwo4", config=None, shard_index=1)
|
||||
assert job_seed("steps", "gen1", a) != job_seed("steps", "gen1", b)
|
||||
|
||||
|
||||
def test_job_seed_varies_by_detector():
|
||||
a = SimJob(detector="pbwo4", config=None, shard_index=0)
|
||||
b = SimJob(detector="sampling_pb_scint", config="pb_scint", shard_index=0)
|
||||
assert job_seed("steps", "gen1", a) != job_seed("steps", "gen1", b)
|
||||
|
||||
|
||||
def test_job_seed_varies_by_gen():
|
||||
job = SimJob(detector="pbwo4", config=None, shard_index=0)
|
||||
assert job_seed("steps", "gen1", job) != job_seed("steps", "gen2", job)
|
||||
|
||||
|
||||
def test_run_job_passes_deterministic_seed_env_var(tmp_path):
|
||||
fake = _write_fake_executable(tmp_path / "fake_exe.py")
|
||||
(tmp_path / "raw" / "steps" / "gen1").mkdir(parents=True)
|
||||
tmp_root = tmp_path / ".sim-tmp"
|
||||
tmp_root.mkdir()
|
||||
|
||||
job = SimJob(detector="pbwo4", config=None, shard_index=5)
|
||||
result = run_job(job, fake, 10000, tmp_path, "steps", "gen1", tmp_root)
|
||||
|
||||
assert result.dest is not None
|
||||
payload = json.loads(result.dest.read_text())
|
||||
assert payload["seed"] == str(job_seed("steps", "gen1", job))
|
||||
|
||||
|
||||
def test_run_job_moves_output_to_correct_shard_path(tmp_path):
|
||||
fake = _write_fake_executable(tmp_path / "fake_exe.py")
|
||||
gen_dir = tmp_path / "raw" / "steps" / "gen1"
|
||||
|
||||
Reference in New Issue
Block a user