Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions rocketpy/simulation/monte_carlo.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,12 +461,15 @@ def __run_single_simulation(self):
Flight
The flight object of the simulation.
"""
rocket = self.rocket.create_object()
environment = self.environment.create_object()
flight_inputs = self.flight._sample_flight_inputs()
return Flight(
rocket=self.rocket.create_object(),
environment=self.environment.create_object(),
rail_length=self.flight._randomize_rail_length(),
inclination=self.flight._randomize_inclination(),
heading=self.flight._randomize_heading(),
rocket=rocket,
environment=environment,
rail_length=flight_inputs["rail_length"],
inclination=flight_inputs["inclination"],
heading=flight_inputs["heading"],
initial_solution=self.flight.initial_solution,
terminate_on_apogee=self.flight.terminate_on_apogee,
time_overshoot=self.flight.time_overshoot,
Expand Down Expand Up @@ -1377,7 +1380,7 @@ def export_ellipses_to_kml( # pylint: disable=too-many-statements
except KeyError as e:
raise KeyError("No impact data found. Skipping impact ellipses.") from e

(apogee_ellipses, impact_ellipses) = generate_monte_carlo_ellipses(
apogee_ellipses, impact_ellipses = generate_monte_carlo_ellipses(
impact_x,
impact_y,
apogee_x,
Expand Down
26 changes: 16 additions & 10 deletions rocketpy/stochastic/stochastic_flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,21 +122,28 @@ def _validate_initial_solution(self, initial_solution):
else:
raise TypeError("`initial_solution` must be a tuple of numbers")

# TODO: these methods call dict_generator a lot of times unnecessarily
def _sample_flight_inputs(self):
"""Sample rail_length, inclination, and heading in a single draw.

Returns
-------
dict
Mapping with keys ``rail_length``, ``inclination``, and ``heading``.
Also updates ``last_rnd_dict``.
"""
return next(self.dict_generator())

def _randomize_rail_length(self):
"""Randomizes the rail length of the flight."""
generated_dict = next(self.dict_generator())
return generated_dict["rail_length"]
return self._sample_flight_inputs()["rail_length"]

def _randomize_inclination(self):
"""Randomizes the inclination of the flight."""
generated_dict = next(self.dict_generator())
return generated_dict["inclination"]
return self._sample_flight_inputs()["inclination"]

def _randomize_heading(self):
"""Randomizes the heading of the flight."""
generated_dict = next(self.dict_generator())
return generated_dict["heading"]
return self._sample_flight_inputs()["heading"]

def create_object(self):
"""Creates and returns a Flight object from the randomly generated input
Expand All @@ -147,12 +154,11 @@ def create_object(self):
flight : Flight
Flight object with the randomly generated input arguments.
"""
generated_dict = next(self.dict_generator())
# TODO: maybe we should use generated_dict["rail_length"] instead
generated_dict = self._sample_flight_inputs()
return Flight(
rocket=self.obj.rocket,
environment=self.obj.env,
rail_length=self._randomize_rail_length(),
rail_length=generated_dict["rail_length"],
inclination=generated_dict["inclination"],
heading=generated_dict["heading"],
initial_solution=self.initial_solution,
Expand Down
36 changes: 36 additions & 0 deletions tests/unit/stochastic/test_stochastic_flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,39 @@ def test_stochastic_flight_optional_attributes(flight_calisto_robust):
assert obj.terminate_on_apogee is True
assert obj.time_overshoot is True
assert obj.max_time == 987.6


def test_create_object_matches_last_rnd_dict(flight_calisto_robust):
"""Regression for #1090: create_object must use one dict_generator draw.

Spreads are set on all three flight inputs so a second draw would diverge
from ``last_rnd_dict``.
"""
stochastic_flight = StochasticFlight(
flight=flight_calisto_robust,
rail_length=(5.2, 0.5),
inclination=(84.7, 1),
heading=(53, 2),
)
stochastic_flight._set_stochastic(4242)

flight = stochastic_flight.create_object()
sampled = stochastic_flight.last_rnd_dict

assert flight.rail_length == sampled["rail_length"]
assert flight.inclination == sampled["inclination"]
assert flight.heading == sampled["heading"]


def test_monte_carlo_single_simulation_matches_flight_last_rnd_dict(
monte_carlo_calisto,
):
"""Regression for #1090: MonteCarlo must fly the same sample it logs."""
monte_carlo_calisto.flight._set_stochastic(4242)

flight = monte_carlo_calisto._MonteCarlo__run_single_simulation()
sampled = monte_carlo_calisto.flight.last_rnd_dict

assert flight.rail_length == sampled["rail_length"]
assert flight.inclination == sampled["inclination"]
assert flight.heading == sampled["heading"]