BUG: fly the parachute the simulation sampled - #1098
Conversation
|
CI here is red on #1078 and not on anything in this branch. Three runs so far, all of them dying the same way: In the run that got furthest, the unit suite was 1855 passed and the doctests 46 passed before the integration job crashed. Locally the whole thing is green: I have added the numbers to #1078. The short version is that it is a 3.14 fault rather than a platform one: nine failures on macOS 3.14 and five on ubuntu 3.14 across the last forty runs, the same stack on both, and nothing on 3.10 or on Windows. Not asking anyone to chase that here. Flagging it so the red is not read as this branch. |
|
Two corrections to the description above, both mine and both now edited in. I wrote that this touches no file #1054 changes. That is wrong: both change I also wrote that nothing here touches the flight path, in the same breath as a breaking-change section explaining that |
StochasticParachute.create_object() builds a Parachute from a complete draw. StochasticRocket.create_object() threw it away and built a second one from six of its ten fields, so radius, height, porosity and the drag coefficient never left last_rnd_dict. Parachute re-derived radius from cd_s and the default drag coefficient, and height fell back to that radius. Randomizing the geometry was not required to hit it. A parachute configured with an explicit radius of 2.0 flew 1.519 in every simulation, because the value was dropped on the way to add_parachute rather than sampled away. Attaching the object _create_parachute already built fixes both, and stops Parachute.__init__ running twice per parachute per simulation. The second run drew the initial pressure noise from the global NumPy RNG again (RocketPy-Team#1091). Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>
f960ed8 to
0a1a5a4
Compare
|
Thanks @Gui-FernandesBR. One check before this goes in, because the description has a question in it that an approval does not obviously answer, and I would rather ask twice than have it merge unnoticed. The section is "One case I would like your call on". A parachute built without an explicit radius has one derived from Both behaviours are defensible and I did not want to pick. If you are happy with the frozen-derived version, nothing needs to change and I will note it in the issue. If you would rather the derived case kept tracking Rebased onto current |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #1098 +/- ##
===========================================
+ Coverage 82.18% 82.55% +0.37%
===========================================
Files 122 128 +6
Lines 16355 16555 +200
===========================================
+ Hits 13441 13667 +226
+ Misses 2914 2888 -26 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Take the frozen-derived version — nothing needs to change here. The reason is that the geometry only feeds Your own argument settles it anyway: the object recorded 1.5079 and flew 1.5531. A run whose Please note it in the issue as you offered. Thanks for asking twice, and for the two corrections to the description — the |
Closes #1094.
Pull request type
Checklist
ruff check/ruff format --check/pylint rocketpy/ tests/ docs/) has passed locallypylintexits 0, andpytest tests/unit tests/integrationis 2033 passed, 44 skipped. I did not run-m slow --runslow. No code underrocketpy/simulation/changes, but the values this patch corrects are read by the flight path, so that is a statement about the diff and not about the blast radius. The breaking-change section below has the numbers.Current behavior
StochasticParachute.create_object()builds aParachutefrom a complete draw:StochasticRocket.create_object()then discards that object and builds a second one from six of its ten fields:radius,height,porosityanddrag_coefficientare not passed.Parachute.__init__accepts all four andRocket.add_parachuteforwards all four, so the omission is silent: the second parachute re-derivesradiusfromcd_sand the default drag coefficient, andheightfalls back to that radius.Randomizing the geometry is not required to hit this, which is the part I had wrong when I filed the issue. A parachute configured with an explicit radius and no randomization at all:
radiusandheightcome back equal because both were re-derived. So the affected set is every study whose parachute carries geometry, not only those that sample it, andlast_rnd_dictrecords values the flight never used.New behavior
The object
_create_parachutealready built is the one that gets attached:Rocket.add_parachutedoes three things: construct, append, return. Nothing else is skipped by attaching directly. Same table after the change:This also stops
Parachute.__init__running twice per parachute per simulation. The second run drew the initial pressure noise from the global NumPy RNG again, which is #1091: fixing the seed tree without fixing this would leave the second initialization undoing the first.Tests
Four in
tests/unit/stochastic/test_stochastic_rocket.py, and each of the two failure modes is pinned by a mutation:add_parachute, as todayThe overlap is deliberate.
test_the_parachute_is_attached_exactly_onceis the control: it survives the first mutation, because the old code did attach parachutes, and it catches the second, which would otherwise let a passing suite fly every Monte Carlo rocket with no parachutes at all.Breaking change
radiusandheightfeed the added mass term inflight.py, so this is descent dynamics and not just bookkeeping:For a parachute configured with
radius=2.0, height=1.5against the 1.5193 it was flying, added mass moves by about 71%. Landing points move with it. That is the bug being fixed, so the old numbers were not the right ones, but anyone with a baselined study will see them change.One fewer draw from the global NumPy RNG per parachute per simulation, so anything downstream of that stream shifts too. #1091 is the reason that stream should not be there at all.
One case I would like your call on
There is a third group, and I got it wrong in the issue before measuring it.
If a parachute is built with no explicit geometry,
Parachute.__init__derivesradiusfromcd_s, andStochasticParachutecaptures that derived value. The old code then re-derived it downstream from the sampledcd_s, so a study randomizingcd_shad its canopy grow and shrink with it. Attaching the sampled object stops that:radiusnow stays at the value derived from the nominalcd_s.Both are defensible. The old one is arguably more physical, since a larger drag area ought to mean a larger canopy. The new one is at least self-consistent, since the object now flies what it recorded, whereas before it recorded 1.5079 and flew 1.5531.
I did not try to keep the old coupling, because deriving geometry from a sampled
cd_sis a modelling decision rather than a bug fix, and it belongs inStochasticParachuterather than here. If you would rather it were preserved, say so and I will follow up with it, either in this PR or a separate one.Additional information
Found while reviewing #1054. The two overlap in
rocketpy/stochastic/stochastic_rocket.py: #1054 changes the base model's list sampling and adds acomponent_collectionsskip, this one changes the parachute loop below it. They merge cleanly, and I ran the combined tree to check rather than assuming:tests/unit/stochasticandtests/unit/simulationare 275 passed, 4 skipped on the merge of the two heads. Whichever lands second still wants a rebase.Related: #1091 (parachute pressure noise outside the seed tree), and #1093, #1095, #1096 from the same review.