open-space-toolkit-astrodynamics 17.2.0__py312-none-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- open_space_toolkit_astrodynamics-17.2.0.dist-info/METADATA +30 -0
- open_space_toolkit_astrodynamics-17.2.0.dist-info/RECORD +151 -0
- open_space_toolkit_astrodynamics-17.2.0.dist-info/WHEEL +5 -0
- open_space_toolkit_astrodynamics-17.2.0.dist-info/top_level.txt +1 -0
- open_space_toolkit_astrodynamics-17.2.0.dist-info/zip-safe +1 -0
- ostk/__init__.py +1 -0
- ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-312-x86_64-linux-gnu.so +0 -0
- ostk/astrodynamics/__init__.py +11 -0
- ostk/astrodynamics/__init__.pyi +720 -0
- ostk/astrodynamics/access.pyi +577 -0
- ostk/astrodynamics/conjunction/__init__.pyi +121 -0
- ostk/astrodynamics/conjunction/close_approach.pyi +89 -0
- ostk/astrodynamics/conjunction/message/__init__.pyi +3 -0
- ostk/astrodynamics/conjunction/message/ccsds.pyi +705 -0
- ostk/astrodynamics/converters.py +130 -0
- ostk/astrodynamics/converters.pyi +58 -0
- ostk/astrodynamics/data/__init__.pyi +3 -0
- ostk/astrodynamics/data/provider.pyi +22 -0
- ostk/astrodynamics/dataframe.py +597 -0
- ostk/astrodynamics/display.py +281 -0
- ostk/astrodynamics/dynamics.pyi +311 -0
- ostk/astrodynamics/eclipse.pyi +70 -0
- ostk/astrodynamics/estimator.pyi +268 -0
- ostk/astrodynamics/event_condition.pyi +910 -0
- ostk/astrodynamics/flight/__init__.pyi +626 -0
- ostk/astrodynamics/flight/profile/__init__.pyi +99 -0
- ostk/astrodynamics/flight/profile/model.pyi +179 -0
- ostk/astrodynamics/flight/system.pyi +268 -0
- ostk/astrodynamics/guidance_law.pyi +416 -0
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.17 +0 -0
- ostk/astrodynamics/pytrajectory/__init__.py +1 -0
- ostk/astrodynamics/pytrajectory/__init__.pyi +3 -0
- ostk/astrodynamics/pytrajectory/pystate.py +263 -0
- ostk/astrodynamics/pytrajectory/pystate.pyi +66 -0
- ostk/astrodynamics/solver.pyi +432 -0
- ostk/astrodynamics/test/__init__.py +1 -0
- ostk/astrodynamics/test/access/__init__.py +1 -0
- ostk/astrodynamics/test/access/test_generator.py +319 -0
- ostk/astrodynamics/test/access/test_visibility_criterion.py +201 -0
- ostk/astrodynamics/test/conftest.py +119 -0
- ostk/astrodynamics/test/conjunction/close_approach/__init__.py +0 -0
- ostk/astrodynamics/test/conjunction/close_approach/test_generator.py +228 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/__init__.py +1 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/conftest.py +325 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/data/cdm.json +303 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/test_cdm.py +416 -0
- ostk/astrodynamics/test/conjunction/test_close_approach.py +244 -0
- ostk/astrodynamics/test/data/provider/test_off_nadir.py +58 -0
- ostk/astrodynamics/test/dynamics/__init__.py +1 -0
- ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity.csv +565 -0
- ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity_Truth.csv +100 -0
- ostk/astrodynamics/test/dynamics/test_atmospheric_drag.py +128 -0
- ostk/astrodynamics/test/dynamics/test_central_body_gravity.py +58 -0
- ostk/astrodynamics/test/dynamics/test_dynamics.py +50 -0
- ostk/astrodynamics/test/dynamics/test_position_derivative.py +51 -0
- ostk/astrodynamics/test/dynamics/test_tabulated.py +138 -0
- ostk/astrodynamics/test/dynamics/test_third_body_gravity.py +67 -0
- ostk/astrodynamics/test/dynamics/test_thruster.py +157 -0
- ostk/astrodynamics/test/eclipse/__init__.py +1 -0
- ostk/astrodynamics/test/eclipse/test_generator.py +138 -0
- ostk/astrodynamics/test/estimator/test_orbit_determination_solver.py +261 -0
- ostk/astrodynamics/test/estimator/test_tle_solver.py +216 -0
- ostk/astrodynamics/test/event_condition/test_angular_condition.py +113 -0
- ostk/astrodynamics/test/event_condition/test_boolean_condition.py +55 -0
- ostk/astrodynamics/test/event_condition/test_brouwer_lyddane_mean_long_condition.py +135 -0
- ostk/astrodynamics/test/event_condition/test_coe_condition.py +135 -0
- ostk/astrodynamics/test/event_condition/test_instant_condition.py +48 -0
- ostk/astrodynamics/test/event_condition/test_logical_condition.py +120 -0
- ostk/astrodynamics/test/event_condition/test_real_condition.py +50 -0
- ostk/astrodynamics/test/flight/__init__.py +1 -0
- ostk/astrodynamics/test/flight/profile/model/test_tabulated_profile.py +115 -0
- ostk/astrodynamics/test/flight/system/__init__.py +1 -0
- ostk/astrodynamics/test/flight/system/test_propulsion_system.py +64 -0
- ostk/astrodynamics/test/flight/system/test_satellite_system.py +83 -0
- ostk/astrodynamics/test/flight/system/test_satellite_system_builder.py +71 -0
- ostk/astrodynamics/test/flight/test_maneuver.py +231 -0
- ostk/astrodynamics/test/flight/test_profile.py +293 -0
- ostk/astrodynamics/test/flight/test_system.py +45 -0
- ostk/astrodynamics/test/guidance_law/test_constant_thrust.py +177 -0
- ostk/astrodynamics/test/guidance_law/test_guidance_law.py +60 -0
- ostk/astrodynamics/test/guidance_law/test_heterogeneous_guidance_law.py +164 -0
- ostk/astrodynamics/test/guidance_law/test_qlaw.py +209 -0
- ostk/astrodynamics/test/solvers/__init__.py +1 -0
- ostk/astrodynamics/test/solvers/test_finite_difference_solver.py +196 -0
- ostk/astrodynamics/test/solvers/test_least_squares_solver.py +334 -0
- ostk/astrodynamics/test/solvers/test_temporal_condition_solver.py +161 -0
- ostk/astrodynamics/test/test_access.py +128 -0
- ostk/astrodynamics/test/test_converters.py +290 -0
- ostk/astrodynamics/test/test_dataframe.py +1355 -0
- ostk/astrodynamics/test/test_display.py +184 -0
- ostk/astrodynamics/test/test_event_condition.py +80 -0
- ostk/astrodynamics/test/test_import.py +26 -0
- ostk/astrodynamics/test/test_root_solver.py +70 -0
- ostk/astrodynamics/test/test_trajectory.py +126 -0
- ostk/astrodynamics/test/test_utilities.py +338 -0
- ostk/astrodynamics/test/test_viewer.py +318 -0
- ostk/astrodynamics/test/trajectory/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/model/test_nadir_trajectory.py +87 -0
- ostk/astrodynamics/test/trajectory/model/test_tabulated_trajectory.py +303 -0
- ostk/astrodynamics/test/trajectory/model/test_target_scan_trajectory.py +126 -0
- ostk/astrodynamics/test/trajectory/orbit/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/message/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/conftest.py +18 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/data/opm_1.yaml +44 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/test_opm.py +108 -0
- ostk/astrodynamics/test/trajectory/orbit/models/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean.py +65 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_long.py +102 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_short.py +102 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py +305 -0
- ostk/astrodynamics/test/trajectory/orbit/models/sgp4/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/sgp4/test_tle.py +337 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_kepler.py +130 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_modified_equinoctial.py +142 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_propagated.py +234 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_sgp4.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_tabulated.py +380 -0
- ostk/astrodynamics/test/trajectory/orbit/test_model.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/test_pass.py +75 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_angular_velocity.py +30 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_attitude_quaternion.py +18 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_acceleration.py +136 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_position.py +107 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_velocity.py +115 -0
- ostk/astrodynamics/test/trajectory/state/test_coordinate_broker.py +84 -0
- ostk/astrodynamics/test/trajectory/state/test_coordinate_subset.py +58 -0
- ostk/astrodynamics/test/trajectory/state/test_numerical_solver.py +316 -0
- ostk/astrodynamics/test/trajectory/test_local_orbital_frame_direction.py +81 -0
- ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py +119 -0
- ostk/astrodynamics/test/trajectory/test_model.py +1 -0
- ostk/astrodynamics/test/trajectory/test_orbit.py +212 -0
- ostk/astrodynamics/test/trajectory/test_propagator.py +452 -0
- ostk/astrodynamics/test/trajectory/test_segment.py +694 -0
- ostk/astrodynamics/test/trajectory/test_sequence.py +550 -0
- ostk/astrodynamics/test/trajectory/test_state.py +629 -0
- ostk/astrodynamics/test/trajectory/test_state_builder.py +172 -0
- ostk/astrodynamics/trajectory/__init__.pyi +1982 -0
- ostk/astrodynamics/trajectory/model.pyi +259 -0
- ostk/astrodynamics/trajectory/orbit/__init__.pyi +349 -0
- ostk/astrodynamics/trajectory/orbit/message/__init__.pyi +3 -0
- ostk/astrodynamics/trajectory/orbit/message/spacex.pyi +264 -0
- ostk/astrodynamics/trajectory/orbit/model/__init__.pyi +648 -0
- ostk/astrodynamics/trajectory/orbit/model/brouwerLyddaneMean.pyi +121 -0
- ostk/astrodynamics/trajectory/orbit/model/kepler.pyi +709 -0
- ostk/astrodynamics/trajectory/orbit/model/sgp4.pyi +330 -0
- ostk/astrodynamics/trajectory/state/__init__.pyi +402 -0
- ostk/astrodynamics/trajectory/state/coordinate_subset.pyi +208 -0
- ostk/astrodynamics/utilities.py +396 -0
- ostk/astrodynamics/viewer.py +851 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from ostk.core.type import Real
|
|
8
|
+
from ostk.core.type import Integer
|
|
9
|
+
|
|
10
|
+
from ostk.physics.coordinate import Frame
|
|
11
|
+
|
|
12
|
+
from ostk.astrodynamics.solver import LeastSquaresSolver
|
|
13
|
+
from ostk.astrodynamics.trajectory import State
|
|
14
|
+
from ostk.astrodynamics.trajectory import StateBuilder
|
|
15
|
+
from ostk.astrodynamics.trajectory import Orbit
|
|
16
|
+
from ostk.astrodynamics.trajectory.orbit.model.sgp4 import TLE
|
|
17
|
+
from ostk.astrodynamics.estimator import TLESolver
|
|
18
|
+
from ostk.astrodynamics.dataframe import generate_states_from_dataframe
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.fixture
|
|
22
|
+
def least_squares_solver() -> LeastSquaresSolver:
|
|
23
|
+
return LeastSquaresSolver.default()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.fixture
|
|
27
|
+
def tle_solver(least_squares_solver: LeastSquaresSolver) -> TLESolver:
|
|
28
|
+
return TLESolver(
|
|
29
|
+
solver=least_squares_solver,
|
|
30
|
+
satellite_number=25544, # ISS NORAD ID
|
|
31
|
+
international_designator="98067A", # ISS Int'l Designator
|
|
32
|
+
revolution_number=12345,
|
|
33
|
+
estimate_b_star=True,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.fixture
|
|
38
|
+
def initial_tle() -> TLE:
|
|
39
|
+
return TLE(
|
|
40
|
+
"1 25544U 98067A 22253.00000622 .00000000 00000-0 71655-1 0 02",
|
|
41
|
+
"2 25544 97.5641 21.8296 0012030 155.5301 309.4836 15.14446734123455",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.fixture
|
|
46
|
+
def initial_state(observations: list[State]) -> State:
|
|
47
|
+
return observations[0]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@pytest.fixture
|
|
51
|
+
def initial_state_with_b_star(observations: list[State]) -> tuple[State, float]:
|
|
52
|
+
return observations[0], 1e-4
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.fixture
|
|
56
|
+
def observations() -> list[State]:
|
|
57
|
+
return generate_states_from_dataframe(
|
|
58
|
+
pd.read_csv(
|
|
59
|
+
"/app/test/OpenSpaceToolkit/Astrodynamics/Estimator/OrbitDeterminationSolverData/gnss_data.csv"
|
|
60
|
+
),
|
|
61
|
+
reference_frame=Frame.ITRF(),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TestTLESolver:
|
|
66
|
+
def test_constructor(
|
|
67
|
+
self,
|
|
68
|
+
tle_solver: TLESolver,
|
|
69
|
+
):
|
|
70
|
+
assert isinstance(tle_solver, TLESolver)
|
|
71
|
+
assert tle_solver.access_satellite_number() == 25544
|
|
72
|
+
assert tle_solver.access_international_designator() == "98067A"
|
|
73
|
+
assert tle_solver.access_revolution_number() == 12345
|
|
74
|
+
assert tle_solver.access_estimate_b_star() is True
|
|
75
|
+
|
|
76
|
+
def test_constructor_defaults(self):
|
|
77
|
+
solver = TLESolver()
|
|
78
|
+
assert solver.access_satellite_number() == 0
|
|
79
|
+
assert solver.access_international_designator() == "00001A"
|
|
80
|
+
assert solver.access_revolution_number() == 0
|
|
81
|
+
assert solver.access_estimate_b_star() is True
|
|
82
|
+
|
|
83
|
+
def test_access_methods(self, tle_solver: TLESolver):
|
|
84
|
+
assert isinstance(tle_solver.access_solver(), LeastSquaresSolver)
|
|
85
|
+
assert isinstance(tle_solver.access_default_b_star(), Real)
|
|
86
|
+
assert isinstance(
|
|
87
|
+
tle_solver.access_first_derivative_mean_motion_divided_by_2(), Real
|
|
88
|
+
)
|
|
89
|
+
assert isinstance(
|
|
90
|
+
tle_solver.access_second_derivative_mean_motion_divided_by_6(), Real
|
|
91
|
+
)
|
|
92
|
+
assert isinstance(tle_solver.access_ephemeris_type(), Integer)
|
|
93
|
+
assert isinstance(tle_solver.access_element_set_number(), Integer)
|
|
94
|
+
assert isinstance(tle_solver.access_tle_state_builder(), StateBuilder)
|
|
95
|
+
|
|
96
|
+
def test_estimate_from_tle(
|
|
97
|
+
self,
|
|
98
|
+
tle_solver: TLESolver,
|
|
99
|
+
initial_tle: TLE,
|
|
100
|
+
observations: list[State],
|
|
101
|
+
):
|
|
102
|
+
analysis: TLESolver.Analysis = tle_solver.estimate(
|
|
103
|
+
initial_guess=initial_tle,
|
|
104
|
+
observations=observations,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
assert isinstance(analysis, TLESolver.Analysis)
|
|
108
|
+
assert isinstance(analysis.estimated_tle, TLE)
|
|
109
|
+
assert isinstance(analysis.solver_analysis, LeastSquaresSolver.Analysis)
|
|
110
|
+
|
|
111
|
+
assert analysis.solver_analysis.termination_criteria == "RMS Update Threshold"
|
|
112
|
+
|
|
113
|
+
def test_estimate_from_state_b_star(
|
|
114
|
+
self,
|
|
115
|
+
tle_solver: TLESolver,
|
|
116
|
+
initial_state: State,
|
|
117
|
+
observations: list[State],
|
|
118
|
+
):
|
|
119
|
+
analysis: TLESolver.Analysis = tle_solver.estimate(
|
|
120
|
+
initial_guess=(initial_state, 1e-4),
|
|
121
|
+
observations=observations,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
assert isinstance(analysis, TLESolver.Analysis)
|
|
125
|
+
assert isinstance(analysis.estimated_tle, TLE)
|
|
126
|
+
assert isinstance(analysis.solver_analysis, LeastSquaresSolver.Analysis)
|
|
127
|
+
|
|
128
|
+
assert analysis.solver_analysis.termination_criteria == "RMS Update Threshold"
|
|
129
|
+
|
|
130
|
+
def test_estimate_from_state(
|
|
131
|
+
self,
|
|
132
|
+
initial_state: State,
|
|
133
|
+
observations: list[State],
|
|
134
|
+
):
|
|
135
|
+
tle_solver_no_b_star = TLESolver(
|
|
136
|
+
satellite_number=25544,
|
|
137
|
+
international_designator="98067A",
|
|
138
|
+
revolution_number=12345,
|
|
139
|
+
estimate_b_star=False,
|
|
140
|
+
)
|
|
141
|
+
analysis: TLESolver.Analysis = tle_solver_no_b_star.estimate(
|
|
142
|
+
initial_guess=initial_state,
|
|
143
|
+
observations=observations,
|
|
144
|
+
)
|
|
145
|
+
assert isinstance(analysis, TLESolver.Analysis)
|
|
146
|
+
assert isinstance(analysis.estimated_tle, TLE)
|
|
147
|
+
assert isinstance(analysis.solver_analysis, LeastSquaresSolver.Analysis)
|
|
148
|
+
|
|
149
|
+
assert analysis.solver_analysis.termination_criteria == "RMS Update Threshold"
|
|
150
|
+
|
|
151
|
+
def test_estimate_invalid_initial_guess(
|
|
152
|
+
self,
|
|
153
|
+
tle_solver: TLESolver,
|
|
154
|
+
observations: list[State],
|
|
155
|
+
):
|
|
156
|
+
with pytest.raises(RuntimeError) as e:
|
|
157
|
+
tle_solver.estimate(initial_guess="invalid", observations=observations)
|
|
158
|
+
assert "Initial guess must be a TLE, tuple[State, float], or State." in str(
|
|
159
|
+
e.value
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
def test_estimate_invalid_state_only(
|
|
163
|
+
self,
|
|
164
|
+
tle_solver: TLESolver,
|
|
165
|
+
initial_state: State,
|
|
166
|
+
observations: list[State],
|
|
167
|
+
):
|
|
168
|
+
with pytest.raises(RuntimeError) as e:
|
|
169
|
+
tle_solver.estimate(initial_guess=initial_state, observations=observations)
|
|
170
|
+
assert (
|
|
171
|
+
"Initial guess must be a TLE or (State, B*) when also estimating B*."
|
|
172
|
+
in str(e.value)
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
def test_estimate_no_observations(
|
|
176
|
+
self,
|
|
177
|
+
tle_solver: TLESolver,
|
|
178
|
+
initial_state: State,
|
|
179
|
+
):
|
|
180
|
+
with pytest.raises(Exception):
|
|
181
|
+
tle_solver.estimate(initial_guess=initial_state, observations=[])
|
|
182
|
+
|
|
183
|
+
def test_estimate_orbit(
|
|
184
|
+
self,
|
|
185
|
+
initial_state: State,
|
|
186
|
+
observations: list[State],
|
|
187
|
+
):
|
|
188
|
+
tle_solver_no_b_star = TLESolver(
|
|
189
|
+
satellite_number=25544,
|
|
190
|
+
international_designator="98067A",
|
|
191
|
+
revolution_number=12345,
|
|
192
|
+
estimate_b_star=False,
|
|
193
|
+
)
|
|
194
|
+
orbit: Orbit = tle_solver_no_b_star.estimate_orbit(
|
|
195
|
+
initial_guess=initial_state,
|
|
196
|
+
observations=observations,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
assert isinstance(orbit, Orbit)
|
|
200
|
+
|
|
201
|
+
def test_fit_with_different_frames(
|
|
202
|
+
self,
|
|
203
|
+
tle_solver: TLESolver,
|
|
204
|
+
initial_state_with_b_star: tuple[State, float],
|
|
205
|
+
observations: list[State],
|
|
206
|
+
):
|
|
207
|
+
# Convert observations to ITRF frame
|
|
208
|
+
itrf_observations = [obs.in_frame(Frame.ITRF()) for obs in observations]
|
|
209
|
+
|
|
210
|
+
analysis: TLESolver.Analysis = tle_solver.estimate(
|
|
211
|
+
initial_guess=initial_state_with_b_star, observations=itrf_observations
|
|
212
|
+
)
|
|
213
|
+
assert isinstance(analysis, TLESolver.Analysis)
|
|
214
|
+
assert isinstance(analysis.estimated_tle, TLE)
|
|
215
|
+
|
|
216
|
+
assert analysis.solver_analysis.termination_criteria == "RMS Update Threshold"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from ostk.physics.time import Instant, DateTime, Scale
|
|
6
|
+
from ostk.physics.coordinate import Frame, Position, Velocity
|
|
7
|
+
from ostk.physics.unit import Angle
|
|
8
|
+
|
|
9
|
+
from ostk.astrodynamics.trajectory import State
|
|
10
|
+
|
|
11
|
+
from ostk.astrodynamics.event_condition import AngularCondition
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture
|
|
15
|
+
def state() -> State:
|
|
16
|
+
frame: Frame = Frame.GCRF()
|
|
17
|
+
position: Position = Position.meters([7500000.0, 0.0, 0.0], frame)
|
|
18
|
+
velocity: Velocity = Velocity.meters_per_second(
|
|
19
|
+
[0.0, 5335.865450622126, 5335.865450622126], frame
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
instant: Instant = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
|
|
23
|
+
return State(instant, position, velocity)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.fixture
|
|
27
|
+
def criterion() -> AngularCondition.Criterion:
|
|
28
|
+
return AngularCondition.Criterion.PositiveCrossing
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.fixture
|
|
32
|
+
def evaluator():
|
|
33
|
+
return lambda state: state.get_coordinates()[0]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pytest.fixture
|
|
37
|
+
def target_angle() -> Angle:
|
|
38
|
+
return Angle.degrees(0.0)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def target_range() -> tuple[Angle, Angle]:
|
|
43
|
+
return (Angle.degrees(0.0), Angle.degrees(10.0))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@pytest.fixture
|
|
47
|
+
def event_condition(
|
|
48
|
+
criterion: AngularCondition.Criterion, evaluator, target_angle: Angle
|
|
49
|
+
) -> AngularCondition:
|
|
50
|
+
return AngularCondition(
|
|
51
|
+
"My Condition",
|
|
52
|
+
criterion,
|
|
53
|
+
evaluator,
|
|
54
|
+
target_angle,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@pytest.fixture
|
|
59
|
+
def within_range_condition(
|
|
60
|
+
evaluator, target_range: tuple[Angle, Angle]
|
|
61
|
+
) -> AngularCondition:
|
|
62
|
+
return AngularCondition.within_range("My Condition", evaluator, target_range)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TestAngularCondition:
|
|
66
|
+
def test_constructor(
|
|
67
|
+
self,
|
|
68
|
+
criterion: AngularCondition.Criterion,
|
|
69
|
+
evaluator,
|
|
70
|
+
target_angle: Angle,
|
|
71
|
+
):
|
|
72
|
+
assert (
|
|
73
|
+
AngularCondition("My Condition", criterion, evaluator, target_angle)
|
|
74
|
+
is not None
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
def test_get_criterion(
|
|
78
|
+
self,
|
|
79
|
+
event_condition: AngularCondition,
|
|
80
|
+
criterion: AngularCondition.Criterion,
|
|
81
|
+
):
|
|
82
|
+
assert event_condition.get_criterion() == criterion
|
|
83
|
+
|
|
84
|
+
def test_get_target_angle(
|
|
85
|
+
self,
|
|
86
|
+
event_condition: AngularCondition,
|
|
87
|
+
within_range_condition: AngularCondition,
|
|
88
|
+
target_angle: Angle,
|
|
89
|
+
):
|
|
90
|
+
assert event_condition.get_target_angle() == target_angle
|
|
91
|
+
|
|
92
|
+
with pytest.raises(RuntimeError):
|
|
93
|
+
within_range_condition.get_target_angle()
|
|
94
|
+
|
|
95
|
+
def test_get_target_range(
|
|
96
|
+
self,
|
|
97
|
+
event_condition: AngularCondition,
|
|
98
|
+
within_range_condition: AngularCondition,
|
|
99
|
+
target_range: tuple[Angle, Angle],
|
|
100
|
+
):
|
|
101
|
+
with pytest.raises(RuntimeError):
|
|
102
|
+
event_condition.get_target_range()
|
|
103
|
+
|
|
104
|
+
assert within_range_condition.get_target_range() == target_range
|
|
105
|
+
|
|
106
|
+
def test_is_satisfied(self, state: State, event_condition: AngularCondition):
|
|
107
|
+
assert (
|
|
108
|
+
event_condition.is_satisfied(previous_state=state, current_state=state)
|
|
109
|
+
is not None
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def test_string_from_criterion(self, criterion: AngularCondition.Criterion):
|
|
113
|
+
assert AngularCondition.string_from_criterion(criterion) is not None
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from ostk.physics.time import Instant, DateTime, Scale
|
|
6
|
+
from ostk.physics.coordinate import Frame, Position, Velocity
|
|
7
|
+
|
|
8
|
+
from ostk.astrodynamics.trajectory import State
|
|
9
|
+
from ostk.astrodynamics.event_condition import BooleanCondition
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture
|
|
13
|
+
def state() -> State:
|
|
14
|
+
frame: Frame = Frame.GCRF()
|
|
15
|
+
position: Position = Position.meters([7500000.0, 0.0, 0.0], frame)
|
|
16
|
+
velocity: Velocity = Velocity.meters_per_second(
|
|
17
|
+
[0.0, 5335.865450622126, 5335.865450622126], frame
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
instant: Instant = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
|
|
21
|
+
return State(instant, position, velocity)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.fixture
|
|
25
|
+
def evaluator():
|
|
26
|
+
return lambda state: state.get_coordinates()[0]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.fixture
|
|
30
|
+
def is_inversed() -> bool:
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.fixture
|
|
35
|
+
def event_condition(evaluator, is_inversed: bool) -> BooleanCondition:
|
|
36
|
+
return BooleanCondition(
|
|
37
|
+
"My Condition",
|
|
38
|
+
BooleanCondition.Criterion.StrictlyPositive,
|
|
39
|
+
evaluator,
|
|
40
|
+
is_inversed,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TestBooleanCondition:
|
|
45
|
+
def test_is_inversed(self, event_condition: BooleanCondition, is_inversed: bool):
|
|
46
|
+
assert event_condition.is_inversed() == is_inversed
|
|
47
|
+
|
|
48
|
+
def test_evaluate(self, state: State, event_condition: BooleanCondition):
|
|
49
|
+
assert event_condition.evaluate(state) is not None
|
|
50
|
+
|
|
51
|
+
def test_is_satisfied(self, state: State, event_condition: BooleanCondition):
|
|
52
|
+
assert (
|
|
53
|
+
event_condition.is_satisfied(previous_state=state, current_state=state)
|
|
54
|
+
is not None
|
|
55
|
+
)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from ostk.physics.environment.gravitational import Earth
|
|
6
|
+
from ostk.physics.unit import Derived, Length, Angle
|
|
7
|
+
from ostk.physics.coordinate import Frame
|
|
8
|
+
|
|
9
|
+
from ostk.astrodynamics import EventCondition
|
|
10
|
+
from ostk.astrodynamics.event_condition import (
|
|
11
|
+
BrouwerLyddaneMeanLongCondition,
|
|
12
|
+
AngularCondition,
|
|
13
|
+
RealCondition,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture
|
|
18
|
+
def criterion() -> AngularCondition.Criterion:
|
|
19
|
+
return AngularCondition.Criterion.AnyCrossing
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def gravitational_parameter() -> Derived:
|
|
24
|
+
return Earth.spherical.gravitational_parameter
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def frame() -> Frame:
|
|
29
|
+
return Frame.GCRF()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TestBrouwerLyddaneMeanLongCondition:
|
|
33
|
+
@pytest.mark.parametrize(
|
|
34
|
+
"static_constructor,target,criterion",
|
|
35
|
+
(
|
|
36
|
+
(
|
|
37
|
+
BrouwerLyddaneMeanLongCondition.semi_major_axis,
|
|
38
|
+
EventCondition.Target(Length.meters(7e6)),
|
|
39
|
+
RealCondition.Criterion.PositiveCrossing,
|
|
40
|
+
),
|
|
41
|
+
(
|
|
42
|
+
BrouwerLyddaneMeanLongCondition.eccentricity,
|
|
43
|
+
EventCondition.Target(0.1),
|
|
44
|
+
RealCondition.Criterion.PositiveCrossing,
|
|
45
|
+
),
|
|
46
|
+
(
|
|
47
|
+
BrouwerLyddaneMeanLongCondition.inclination,
|
|
48
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
49
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
50
|
+
),
|
|
51
|
+
(
|
|
52
|
+
BrouwerLyddaneMeanLongCondition.aop,
|
|
53
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
54
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
55
|
+
),
|
|
56
|
+
(
|
|
57
|
+
BrouwerLyddaneMeanLongCondition.raan,
|
|
58
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
59
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
60
|
+
),
|
|
61
|
+
(
|
|
62
|
+
BrouwerLyddaneMeanLongCondition.true_anomaly,
|
|
63
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
64
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
65
|
+
),
|
|
66
|
+
(
|
|
67
|
+
BrouwerLyddaneMeanLongCondition.mean_anomaly,
|
|
68
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
69
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
70
|
+
),
|
|
71
|
+
(
|
|
72
|
+
BrouwerLyddaneMeanLongCondition.eccentric_anomaly,
|
|
73
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
74
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
75
|
+
),
|
|
76
|
+
(
|
|
77
|
+
BrouwerLyddaneMeanLongCondition.argument_of_latitude,
|
|
78
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
79
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
80
|
+
),
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
def test_static_constructors(
|
|
84
|
+
self,
|
|
85
|
+
static_constructor,
|
|
86
|
+
target,
|
|
87
|
+
criterion,
|
|
88
|
+
frame: Frame,
|
|
89
|
+
gravitational_parameter: Derived,
|
|
90
|
+
):
|
|
91
|
+
condition = static_constructor(criterion, frame, target, gravitational_parameter)
|
|
92
|
+
assert condition is not None
|
|
93
|
+
|
|
94
|
+
@pytest.mark.parametrize(
|
|
95
|
+
"static_constructor,target_range",
|
|
96
|
+
(
|
|
97
|
+
(
|
|
98
|
+
BrouwerLyddaneMeanLongCondition.inclination,
|
|
99
|
+
(Angle.degrees(10.0), Angle.degrees(20.0)),
|
|
100
|
+
),
|
|
101
|
+
(
|
|
102
|
+
BrouwerLyddaneMeanLongCondition.aop,
|
|
103
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
104
|
+
),
|
|
105
|
+
(
|
|
106
|
+
BrouwerLyddaneMeanLongCondition.raan,
|
|
107
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
108
|
+
),
|
|
109
|
+
(
|
|
110
|
+
BrouwerLyddaneMeanLongCondition.true_anomaly,
|
|
111
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
112
|
+
),
|
|
113
|
+
(
|
|
114
|
+
BrouwerLyddaneMeanLongCondition.mean_anomaly,
|
|
115
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
116
|
+
),
|
|
117
|
+
(
|
|
118
|
+
BrouwerLyddaneMeanLongCondition.eccentric_anomaly,
|
|
119
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
120
|
+
),
|
|
121
|
+
(
|
|
122
|
+
BrouwerLyddaneMeanLongCondition.argument_of_latitude,
|
|
123
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
124
|
+
),
|
|
125
|
+
),
|
|
126
|
+
)
|
|
127
|
+
def test_static_constructors_within_range(
|
|
128
|
+
self,
|
|
129
|
+
static_constructor,
|
|
130
|
+
target_range,
|
|
131
|
+
frame: Frame,
|
|
132
|
+
gravitational_parameter: Derived,
|
|
133
|
+
):
|
|
134
|
+
condition = static_constructor(frame, target_range, gravitational_parameter)
|
|
135
|
+
assert condition is not None
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from ostk.physics.environment.gravitational import Earth
|
|
6
|
+
from ostk.physics.unit import Derived, Length, Angle
|
|
7
|
+
from ostk.physics.coordinate import Frame
|
|
8
|
+
|
|
9
|
+
from ostk.astrodynamics import EventCondition
|
|
10
|
+
from ostk.astrodynamics.event_condition import (
|
|
11
|
+
COECondition,
|
|
12
|
+
AngularCondition,
|
|
13
|
+
RealCondition,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture
|
|
18
|
+
def criterion() -> AngularCondition.Criterion:
|
|
19
|
+
return AngularCondition.Criterion.AnyCrossing
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def gravitational_parameter() -> Derived:
|
|
24
|
+
return Earth.spherical.gravitational_parameter
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def frame() -> Frame:
|
|
29
|
+
return Frame.GCRF()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TestCOECondition:
|
|
33
|
+
@pytest.mark.parametrize(
|
|
34
|
+
"static_constructor,target,criterion",
|
|
35
|
+
(
|
|
36
|
+
(
|
|
37
|
+
COECondition.semi_major_axis,
|
|
38
|
+
EventCondition.Target(Length.meters(7e6)),
|
|
39
|
+
RealCondition.Criterion.PositiveCrossing,
|
|
40
|
+
),
|
|
41
|
+
(
|
|
42
|
+
COECondition.eccentricity,
|
|
43
|
+
EventCondition.Target(0.1),
|
|
44
|
+
RealCondition.Criterion.PositiveCrossing,
|
|
45
|
+
),
|
|
46
|
+
(
|
|
47
|
+
COECondition.inclination,
|
|
48
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
49
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
50
|
+
),
|
|
51
|
+
(
|
|
52
|
+
COECondition.aop,
|
|
53
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
54
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
55
|
+
),
|
|
56
|
+
(
|
|
57
|
+
COECondition.raan,
|
|
58
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
59
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
60
|
+
),
|
|
61
|
+
(
|
|
62
|
+
COECondition.true_anomaly,
|
|
63
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
64
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
65
|
+
),
|
|
66
|
+
(
|
|
67
|
+
COECondition.mean_anomaly,
|
|
68
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
69
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
70
|
+
),
|
|
71
|
+
(
|
|
72
|
+
COECondition.eccentric_anomaly,
|
|
73
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
74
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
75
|
+
),
|
|
76
|
+
(
|
|
77
|
+
COECondition.argument_of_latitude,
|
|
78
|
+
EventCondition.Target(Angle.degrees(0.0)),
|
|
79
|
+
AngularCondition.Criterion.PositiveCrossing,
|
|
80
|
+
),
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
def test_static_constructors(
|
|
84
|
+
self,
|
|
85
|
+
static_constructor,
|
|
86
|
+
target,
|
|
87
|
+
criterion,
|
|
88
|
+
frame: Frame,
|
|
89
|
+
gravitational_parameter: Derived,
|
|
90
|
+
):
|
|
91
|
+
condition = static_constructor(criterion, frame, target, gravitational_parameter)
|
|
92
|
+
assert condition is not None
|
|
93
|
+
|
|
94
|
+
@pytest.mark.parametrize(
|
|
95
|
+
"static_constructor,target_range",
|
|
96
|
+
(
|
|
97
|
+
(
|
|
98
|
+
COECondition.inclination,
|
|
99
|
+
(Angle.degrees(10.0), Angle.degrees(20.0)),
|
|
100
|
+
),
|
|
101
|
+
(
|
|
102
|
+
COECondition.aop,
|
|
103
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
104
|
+
),
|
|
105
|
+
(
|
|
106
|
+
COECondition.raan,
|
|
107
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
108
|
+
),
|
|
109
|
+
(
|
|
110
|
+
COECondition.true_anomaly,
|
|
111
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
112
|
+
),
|
|
113
|
+
(
|
|
114
|
+
COECondition.mean_anomaly,
|
|
115
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
116
|
+
),
|
|
117
|
+
(
|
|
118
|
+
COECondition.eccentric_anomaly,
|
|
119
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
120
|
+
),
|
|
121
|
+
(
|
|
122
|
+
COECondition.argument_of_latitude,
|
|
123
|
+
(Angle.degrees(0.0), Angle.degrees(90.0)),
|
|
124
|
+
),
|
|
125
|
+
),
|
|
126
|
+
)
|
|
127
|
+
def test_static_constructors_within_range(
|
|
128
|
+
self,
|
|
129
|
+
static_constructor,
|
|
130
|
+
target_range,
|
|
131
|
+
frame: Frame,
|
|
132
|
+
gravitational_parameter: Derived,
|
|
133
|
+
):
|
|
134
|
+
condition = static_constructor(frame, target_range, gravitational_parameter)
|
|
135
|
+
assert condition is not None
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Apache License 2.0
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from ostk.physics.coordinate import Frame, Position, Velocity
|
|
6
|
+
from ostk.physics.time import DateTime, Instant, Scale
|
|
7
|
+
|
|
8
|
+
from ostk.astrodynamics.event_condition import InstantCondition
|
|
9
|
+
from ostk.astrodynamics.trajectory import State
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture
|
|
13
|
+
def instant() -> Instant:
|
|
14
|
+
return Instant.date_time(DateTime(2023, 1, 1, 0, 0, 0), Scale.UTC)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture
|
|
18
|
+
def criterion() -> InstantCondition.Criterion:
|
|
19
|
+
return InstantCondition.Criterion.StrictlyPositive
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def instant_condition(
|
|
24
|
+
criterion: InstantCondition.Criterion, instant: Instant
|
|
25
|
+
) -> InstantCondition:
|
|
26
|
+
return InstantCondition(criterion, instant)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.fixture
|
|
30
|
+
def state() -> State:
|
|
31
|
+
frame: Frame = Frame.GCRF()
|
|
32
|
+
position: Position = Position.meters(
|
|
33
|
+
[717094.039086306, -6872433.2241124, 46175.9696673281], frame
|
|
34
|
+
)
|
|
35
|
+
velocity: Velocity = Velocity.meters_per_second(
|
|
36
|
+
[-970.650826004612, -45.4598114773158, 7529.82424886455], frame
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
instant: Instant = Instant.date_time(DateTime(2023, 1, 1, 0, 1, 0), Scale.UTC)
|
|
40
|
+
return State(instant, position, velocity)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TestInstantCondition:
|
|
44
|
+
def test_get_instant(self, instant_condition: InstantCondition, instant: Instant):
|
|
45
|
+
assert instant_condition.get_instant() == instant
|
|
46
|
+
|
|
47
|
+
def test_evaluate(self, instant_condition: InstantCondition, state: State):
|
|
48
|
+
assert instant_condition.evaluate(state) == 60.0
|