Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Insert apogee state into solution list during flight simulation #638

Merged
merged 3 commits into from
Jul 15, 2024
Merged
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Attention: The newest changes should be on top -->

### Changed

- ENH: Insert apogee state into solution list during flight simulation [#638](https://github.com/RocketPy-Team/RocketPy/pull/638)
- ENH: Environment class major refactor may 2024 [#605](https://github.com/RocketPy-Team/RocketPy/pull/605)
- MNT: Refactors the code to adopt pylint [#621](https://github.com/RocketPy-Team/RocketPy/pull/621)
- MNT: Refactor AeroSurfaces [#634](https://github.com/RocketPy-Team/RocketPy/pull/634)
Expand Down
5 changes: 5 additions & 0 deletions rocketpy/simulation/flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,7 @@ def __simulate(self, verbose):
phase.solver.status = "finished"

# Check for apogee event
# TODO: negative vz doesn't really mean apogee. Improve this.
if len(self.apogee_state) == 1 and self.y_sol[5] < 0:
# Assume linear vz(t) to detect when vz = 0
t0, vz0 = self.solution[-2][0], self.solution[-2][6]
Expand All @@ -863,6 +864,10 @@ def __simulate(self, verbose):
phase.time_nodes.flush_after(node_index)
phase.time_nodes.add_node(self.t, [], [])
phase.solver.status = "finished"
elif len(self.solution) > 2:
# adding the apogee state to solution increases accuracy
# we can only do this if the apogee is not the first state
self.solution.insert(-1, [t_root, *self.apogee_state])
# Check for impact event
if self.y_sol[2] < self.env.elevation:
# Check exactly when it happened using root finding
Expand Down
6 changes: 4 additions & 2 deletions tests/integration/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ def test_set_elevation_open_elevation(
example_plain_env.set_location(lat, lon)

# either successfully gets the elevation or raises RuntimeError
with pytest.raises(RuntimeError):
try:
example_plain_env.set_elevation(elevation="Open-Elevation")
assert example_plain_env.elevation == pytest.approx(
theoretical_elevation, abs=1
)
), "The Open-Elevation API returned an unexpected value for the elevation"
except RuntimeError:
pass # Ignore the error and pass the test


@patch("matplotlib.pyplot.show")
Expand Down
34 changes: 34 additions & 0 deletions tests/integration/test_flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,3 +477,37 @@ def test_empty_motor_flight(
],
)
assert flight.all_info() is None


def test_freestream_speed_at_apogee(example_plain_env, calisto):
"""
Asserts that a rocket at apogee has a free stream speed of 0.0 m/s in all
directions given that the environment doesn't have any wind.
"""
# NOTE: this rocket doesn't move in x or z direction. There's no wind.
hard_atol = 1e-12
soft_atol = 1e-6
test_flight = Flight(
environment=example_plain_env,
rocket=calisto,
rail_length=5.2,
inclination=90,
heading=0,
terminate_on_apogee=False,
atol=13 * [hard_atol],
)

assert np.isclose(
test_flight.stream_velocity_x(test_flight.apogee_time), 0.0, atol=hard_atol
)
assert np.isclose(
test_flight.stream_velocity_y(test_flight.apogee_time), 0.0, atol=hard_atol
)
# NOTE: stream_velocity_z has a higher error due to apogee detection estimation
assert np.isclose(
test_flight.stream_velocity_z(test_flight.apogee_time), 0.0, atol=soft_atol
)
assert np.isclose(
test_flight.free_stream_speed(test_flight.apogee_time), 0.0, atol=soft_atol
)
assert np.isclose(test_flight.apogee_freestream_speed, 0.0, atol=soft_atol)
9 changes: 4 additions & 5 deletions tests/unit/test_monte_carlo.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,12 @@ def test_stochastic_solid_motor_create_object_with_impulse(stochastic_solid_moto
stochastic_solid_motor : StochasticSolidMotor
The stochastic solid motor object, this is a pytest fixture.
"""
total_impulse = []
for _ in range(20):
random_motor = stochastic_solid_motor.create_object()
total_impulse.append(random_motor.total_impulse)
total_impulse = [
stochastic_solid_motor.create_object().total_impulse for _ in range(200)
]

assert np.isclose(np.mean(total_impulse), 6500, rtol=0.3)
assert np.isclose(np.std(total_impulse), 1000, rtol=0.3)
assert np.isclose(np.std(total_impulse), 1000, rtol=0.4)


def test_stochastic_calisto_create_object_with_static_margin(stochastic_calisto):
Expand Down
Loading