From 54b706aab00a6c08c8ca24b39f018cccd29032e0 Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Fri, 13 Oct 2023 23:35:55 -0300 Subject: [PATCH 1/5] ENH: new Flight.get_solution_at_time() method --- rocketpy/simulation/flight.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/rocketpy/simulation/flight.py b/rocketpy/simulation/flight.py index 2084e4342..6851bc62c 100644 --- a/rocketpy/simulation/flight.py +++ b/rocketpy/simulation/flight.py @@ -1934,6 +1934,32 @@ def time(self): """Returns time array from solution.""" return self.solution_array[:, 0] + def get_solution_at_time(self, t): + """Returns the solution state vector at a given time. If the time is + not found in the solution, the closest time is used and a warning is + raised. + + Parameters + ---------- + t : float + Time in seconds. + + Returns + ------- + solution : np.array + Solution state at time t. The array follows the format of the + solution array, with the first column being time like this: + [t, x, y, z, vx, vy, vz, e0, e1, e2, e3, omega1, omega2, omega3]. + + """ + time_index = find_closest(self.time, t) + if abs(self.time[time_index] - t) > 1e-5: + warnings.warn( + f"Time {t} not found in solution. Closest time is " + f"{self.time[time_index]}. Using closest time.", UserWarning + ) + return self.solution_array[time_index, :] + # Process first type of outputs - state vector # Transform solution array into Functions @funcify_method("Time (s)", "X (m)", "spline", "constant") From b9ac8e67d9a6f64c3a66b567ac00d618407ad79a Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Fri, 13 Oct 2023 23:36:24 -0300 Subject: [PATCH 2/5] TST: tests for the new feature --- tests/test_flight.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/test_flight.py b/tests/test_flight.py index 212fad932..abd2807fd 100644 --- a/tests/test_flight.py +++ b/tests/test_flight.py @@ -141,6 +141,48 @@ def test_initial_solution(mock_show, example_env, calisto_robust): assert test_flight.all_info() == None +def test_get_solution_at_time(flight_calisto): + """Test the get_solution_at_time method of the Flight class. This test + simply calls the method at the initial and final time and checks if the + returned values are correct. + + Parameters + ---------- + flight_calisto : rocketpy.Flight + Flight object to be tested. See the conftest.py file for more info + regarding this pytest fixture. + """ + assert np.allclose( + flight_calisto.get_solution_at_time(0), + np.array([0, 0, 0, 0, 0, 0, 0, 0.99904822, -0.04361939, 0, 0, 0, 0, 0]), + rtol=1e-05, + atol=1e-08, + ) + assert np.allclose( + flight_calisto.get_solution_at_time(flight_calisto.t_final), + np.array( + [ + 48.4313533, + 0.0, + 985.755944, + -0.00000229951048, + 0.0, + 11.2223284, + -341.028803, + 0.999048222, + -0.0436193874, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ] + ), + rtol=1e-05, + atol=1e-05, + ) + + @pytest.mark.parametrize("wind_u, wind_v", [(0, 10), (0, -10), (10, 0), (-10, 0)]) @pytest.mark.parametrize( "static_margin, max_time", From 5f37e723b1af278c8a7c28c9104890347f43da74 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Sat, 14 Oct 2023 02:45:40 +0000 Subject: [PATCH 3/5] Fix code style issues with Black --- rocketpy/simulation/flight.py | 5 +++-- tests/test_flight.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rocketpy/simulation/flight.py b/rocketpy/simulation/flight.py index 6851bc62c..6d6bae6b0 100644 --- a/rocketpy/simulation/flight.py +++ b/rocketpy/simulation/flight.py @@ -1948,7 +1948,7 @@ def get_solution_at_time(self, t): ------- solution : np.array Solution state at time t. The array follows the format of the - solution array, with the first column being time like this: + solution array, with the first column being time like this: [t, x, y, z, vx, vy, vz, e0, e1, e2, e3, omega1, omega2, omega3]. """ @@ -1956,7 +1956,8 @@ def get_solution_at_time(self, t): if abs(self.time[time_index] - t) > 1e-5: warnings.warn( f"Time {t} not found in solution. Closest time is " - f"{self.time[time_index]}. Using closest time.", UserWarning + f"{self.time[time_index]}. Using closest time.", + UserWarning, ) return self.solution_array[time_index, :] diff --git a/tests/test_flight.py b/tests/test_flight.py index abd2807fd..3d5533c7f 100644 --- a/tests/test_flight.py +++ b/tests/test_flight.py @@ -151,7 +151,7 @@ def test_get_solution_at_time(flight_calisto): flight_calisto : rocketpy.Flight Flight object to be tested. See the conftest.py file for more info regarding this pytest fixture. - """ + """ assert np.allclose( flight_calisto.get_solution_at_time(0), np.array([0, 0, 0, 0, 0, 0, 0, 0.99904822, -0.04361939, 0, 0, 0, 0, 0]), From f4025ec8534941c7206346df60dd2c1bc5d211ea Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Sat, 14 Oct 2023 19:42:18 -0300 Subject: [PATCH 4/5] ENH: increase tolerance due to scipy --- tests/test_flight.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_flight.py b/tests/test_flight.py index 3d5533c7f..de66d2902 100644 --- a/tests/test_flight.py +++ b/tests/test_flight.py @@ -164,7 +164,7 @@ def test_get_solution_at_time(flight_calisto): [ 48.4313533, 0.0, - 985.755944, + 985.7665845, -0.00000229951048, 0.0, 11.2223284, @@ -178,8 +178,8 @@ def test_get_solution_at_time(flight_calisto): 0.0, ] ), - rtol=1e-05, - atol=1e-05, + rtol=1e-02, + atol=5e-03, ) From 422bb51cf1ffcb1a586f79f7c063addaa103eb0b Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Sun, 15 Oct 2023 10:33:23 -0300 Subject: [PATCH 5/5] MNT: add tolerance as an attribute of get_solution --- rocketpy/simulation/flight.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rocketpy/simulation/flight.py b/rocketpy/simulation/flight.py index 6d6bae6b0..3edfbc7b9 100644 --- a/rocketpy/simulation/flight.py +++ b/rocketpy/simulation/flight.py @@ -1934,7 +1934,7 @@ def time(self): """Returns time array from solution.""" return self.solution_array[:, 0] - def get_solution_at_time(self, t): + def get_solution_at_time(self, t, atol=1e-3): """Returns the solution state vector at a given time. If the time is not found in the solution, the closest time is used and a warning is raised. @@ -1943,6 +1943,10 @@ def get_solution_at_time(self, t): ---------- t : float Time in seconds. + atol : float, optional + Absolute tolerance for time comparison. Default is 1e-3. If the + difference between the time and the closest time in the solution + is greater than this value, a warning is raised. Returns ------- @@ -1953,7 +1957,7 @@ def get_solution_at_time(self, t): """ time_index = find_closest(self.time, t) - if abs(self.time[time_index] - t) > 1e-5: + if abs(self.time[time_index] - t) > atol: warnings.warn( f"Time {t} not found in solution. Closest time is " f"{self.time[time_index]}. Using closest time.",