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
1 change: 1 addition & 0 deletions rocketpy/stochastic/stochastic_flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def __init__(
heading=heading,
)

self._validate_initial_solution(initial_solution)
self.initial_solution = initial_solution
self.terminate_on_apogee = terminate_on_apogee
if max_time is None:
Expand Down
10 changes: 8 additions & 2 deletions rocketpy/stochastic/stochastic_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,13 +621,19 @@ def dict_generator(self):

Notes
-----
1. The dictionary is generated by iterating over the class attributes and:
1. The dictionary is generated by iterating over the *declared*
stochastic inputs (constructor kwargs), not every attribute on
``self``. This avoids treating opaque tuples such as
``initial_solution`` as ``(nominal, spread, sampler)`` triples.
a. If the attribute is a tuple, the value is generated using the\
distribution function specified in the tuple.
b. If the attribute is a list, the value is randomly chosen from the list.
"""
generated_dict = {}
for arg, value in self.__dict__.items():
for arg in self.__stochastic_dict:
if not hasattr(self, arg):
continue
value = getattr(self, arg)
if isinstance(value, tuple):
dist_sampler = value[-1]
generated_dict[arg] = dist_sampler(value[0], value[1])
Expand Down
26 changes: 26 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,29 @@ 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_dict_generator_skips_initial_solution_tuple(flight_calisto_robust):
"""Regression for #1109: tuple initial_solution must not be sampled."""
initial_solution = tuple(float(i) for i in range(14))
stochastic_flight = StochasticFlight(
flight=flight_calisto_robust,
initial_solution=initial_solution,
rail_length=(5.2, 0.1),
)
generated = next(stochastic_flight.dict_generator())
assert "initial_solution" not in generated
assert stochastic_flight.initial_solution == initial_solution


def test_dict_generator_skips_initial_solution_list(flight_calisto_robust):
"""List-form initial_solution must not be randomly subset-sampled."""
initial_solution = [float(i) for i in range(14)]
stochastic_flight = StochasticFlight(
flight=flight_calisto_robust,
initial_solution=initial_solution,
inclination=[85, 86, 87],
)
generated = next(stochastic_flight.dict_generator())
assert "initial_solution" not in generated
assert stochastic_flight.initial_solution == initial_solution