Skip to content

BUG: accept the seed type a Monte Carlo worker is handed - #1181

Open
thc1006 wants to merge 1 commit into
RocketPy-Team:developfrom
thc1006:bug/accept-the-seed-monte-carlo-hands-over
Open

BUG: accept the seed type a Monte Carlo worker is handed#1181
thc1006 wants to merge 1 commit into
RocketPy-Team:developfrom
thc1006:bug/accept-the-seed-monte-carlo-hands-over

Conversation

@thc1006

@thc1006 thc1006 commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Parallel Monte Carlo does not run on develop right now. It hangs, and I think it has since 12 August.

Pull request type

  • Code changes (bugfix, features)

Checklist

Current behavior

A two-worker run over a real Flight, bisected:

d21abde6^   the commit before #1117     1 passed in 2.32s
develop     4263fa95                    did not finish; killed at 90s, 180s and 900s
develop     4263fa95, serial            1 passed in 3.86s

__run_in_parallel spawns a SeedSequence per worker and passes it down, so _set_stochastic receives one of those rather than an int:

monte_carlo.py:472   seeds = np.random.SeedSequence().spawn(n_workers)
monte_carlo.py:536   self.environment._set_stochastic(seed)

_sampler_seed then hands it to SeedSequence(entropy=...), which takes an int or a sequence of ints, so the first worker dies before it draws anything:

TypeError: SeedSequence expects int or sequence of ints for entropy

Two things kept this quiet. _sampler_seed is mine, from #1102, and until recently it was only reached from the custom sampler reset loop, so a model without custom samplers never went near it. #1117 added the list-choice generator at stochastic_model.py:157, which every model goes through on every reseed. That turned a path almost nobody took into the one all of them take. Nothing wrong with the #1117 change; my function should have taken the type it can now be given.

The hang on top of the error is a separate problem in the worker's own handler, and I have that in a follow-up rather than in here.

Nothing in the test suite calls _set_stochastic with a SeedSequence, and no pull request job runs a real parallel Monte Carlo, which is why the matrix stayed green through all of it.

New behavior

_sampler_seed normalizes what it is given before building anything from it.

The value is folded through generate_state rather than read off .entropy. The children of one root share their entropy and differ only by spawn_key, so reading the entropy would have quietly put every worker on the same sampler stream, which is worse than the crash it replaces:

np.random.SeedSequence(7).spawn(2)
  same .entropy on both      True
  spawn_key                  (0,)  (1,)

An int or None seed goes through untouched, so no fixed-seed baseline moves. stochastic_calisto under seed 42 still reads mass=14.906007947 radius=0.063501935, same as develop.

The fold itself lives in rocketpy.tools. The component streams in #1170 need the same one and the per-index seeding will too, and three copies would drift on width and word order.

tests/unit/simulation/test_monte_carlo_parallel_runs.py runs a real serial and parallel Monte Carlo. Both together take under six seconds and it is not marked slow, so a pull request gets the signal that was missing here. It builds its own MonteCarlo on tmp_path rather than retargeting the fixture's: filename is a plain attribute and the three log paths are settled in __init__, so assigning it would leave the test writing into the working directory.

Breaking change

  • No

Additional information

Verification, on a clean tree:

pytest tests/unit                     2168 passed
pytest rocketpy --doctest-modules       48 passed
pytest tests/integration               154 passed
pytest tests/acceptance                 18 passed
ruff check . / ruff format --check .   clean
pylint rocketpy/ tests/ docs/          10.00/10, exit 0

The four tests/unit/test_sensitivity.py failures on my machine are a missing statsmodels and fail the same way on an untouched develop.

Each mechanism is pinned by a mutation, and each leaves a control standing:

undone goes red still passes
the seed is not normalized five the integer baseline test
the fold becomes return seed.entropy exactly one, test_two_workers_do_not_share_a_sampler_stream the other five

The second row is the reason that test exists. Reading .entropy unbreaks everything else and silently collapses the workers onto one stream, so the suite would have gone green on a fix that is worse than the bug.

Merged with #1169, #1170 and my follow-up into a throwaway tree on develop and run there as well, since green on separate bases says nothing about the combination.

@thc1006
thc1006 requested a review from a team as a code owner August 17, 2026 19:14
@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.14%. Comparing base (4263fa9) to head (7b2217a).

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1181      +/-   ##
===========================================
+ Coverage    84.57%   85.14%   +0.56%     
===========================================
  Files          131      131              
  Lines        17527    17533       +6     
===========================================
+ Hits         14824    14929     +105     
+ Misses        2703     2604      -99     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@thc1006
thc1006 force-pushed the bug/accept-the-seed-monte-carlo-hands-over branch from ffbb39d to d1e61e6 Compare August 17, 2026 20:08
A parallel run spawns a SeedSequence per worker and passes it to
environment, rocket and flight. _sampler_seed then fed it to
SeedSequence(entropy=...), which takes an int or a sequence of ints,
so the first worker raised TypeError before drawing anything.

The call was reached only from the custom sampler reset until RocketPy-Team#1117
added the list-choice generator, which every model goes through. A real
two-worker run passes at d21abde^ in 2.32s and does not finish on
develop: the worker's own error path raises UnboundLocalError on
inputs_json, so the parent never learns it died and the run hangs.

The children of one root share their entropy and differ by spawn_key,
so the value is folded through generate_state rather than read off
entropy, which would put every worker on one sampler stream. Nothing
is consumed, and an int or None seed keeps the stream it had.

The fold lives in rocketpy.tools, since the component streams and the
per-index seeding both need the same one and three copies would drift
on width and word order. _sampler_seed does its own final fold through
it as well rather than repeating the four lines.

Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>
@thc1006
thc1006 force-pushed the bug/accept-the-seed-monte-carlo-hands-over branch from d1e61e6 to 7b2217a Compare August 17, 2026 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant