open-space-toolkit-astrodynamics 5.1.5__py38-none-any.whl → 5.2.0__py38-none-any.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-5.1.5.dist-info → open_space_toolkit_astrodynamics-5.2.0.dist-info}/METADATA +1 -1
- open_space_toolkit_astrodynamics-5.2.0.dist-info/RECORD +96 -0
- ostk/__init__.py +1 -0
- ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-38-x86_64-linux-gnu.so +0 -0
- ostk/astrodynamics/converters.py +44 -6
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.5 +0 -0
- ostk/astrodynamics/pytrajectory/pystate.py +1 -3
- ostk/astrodynamics/test/access/__init__.py +1 -0
- ostk/astrodynamics/test/access/test_generator.py +248 -0
- ostk/astrodynamics/test/conjunction/messages/ccsds/__init__.py +1 -0
- ostk/astrodynamics/test/conjunction/messages/ccsds/conftest.py +325 -0
- ostk/astrodynamics/test/conjunction/messages/ccsds/data/cdm.json +303 -0
- ostk/astrodynamics/test/conjunction/messages/ccsds/test_cdm.py +416 -0
- ostk/astrodynamics/test/dynamics/__init__.py +1 -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_third_body_gravity.py +67 -0
- ostk/astrodynamics/test/dynamics/test_thruster.py +142 -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_coe_condition.py +87 -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/__init__.py +1 -0
- ostk/astrodynamics/test/flight/profile/test_state.py +144 -0
- ostk/astrodynamics/test/flight/system/__init__.py +1 -0
- ostk/astrodynamics/test/flight/system/test_propulsion_system.py +46 -0
- ostk/astrodynamics/test/flight/system/test_satellite_system.py +91 -0
- ostk/astrodynamics/test/flight/system/test_satellite_system_builder.py +71 -0
- ostk/astrodynamics/test/flight/test_profile.py +153 -0
- ostk/astrodynamics/test/flight/test_system.py +55 -0
- ostk/astrodynamics/test/guidance_law/test_constant_thrust.py +91 -0
- ostk/astrodynamics/test/guidance_law/test_qlaw.py +139 -0
- ostk/astrodynamics/test/solvers/__init__.py +1 -0
- ostk/astrodynamics/test/solvers/test_finite_difference_solver.py +181 -0
- ostk/astrodynamics/test/solvers/test_temporal_condition_solver.py +153 -0
- ostk/astrodynamics/test/test_access.py +2 -6
- ostk/astrodynamics/test/test_converters.py +213 -6
- ostk/astrodynamics/test/test_viewer.py +1 -2
- ostk/astrodynamics/test/trajectory/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/messages/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/messages/spacex/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/messages/spacex/conftest.py +18 -0
- ostk/astrodynamics/test/trajectory/orbit/messages/spacex/data/opm_1.yaml +44 -0
- ostk/astrodynamics/test/trajectory/orbit/messages/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 +167 -0
- ostk/astrodynamics/test/trajectory/orbit/models/sgp4/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/sgp4/test_tle.py +331 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_kepler.py +130 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_propagated.py +195 -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 +55 -0
- ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_angular_velocity.py +30 -0
- ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_attitude_quaternion.py +18 -0
- ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_cartesian_position.py +107 -0
- ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_cartesian_velocity.py +115 -0
- ostk/astrodynamics/test/trajectory/state/test_coordinates_broker.py +84 -0
- ostk/astrodynamics/test/trajectory/state/test_coordinates_subset.py +43 -0
- ostk/astrodynamics/test/trajectory/state/test_numerical_solver.py +314 -0
- ostk/astrodynamics/test/trajectory/test_local_orbital_frame_direction.py +81 -0
- ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py +64 -0
- ostk/astrodynamics/test/trajectory/test_model.py +1 -0
- ostk/astrodynamics/test/trajectory/test_orbit.py +92 -0
- ostk/astrodynamics/test/trajectory/test_propagator.py +402 -0
- ostk/astrodynamics/test/trajectory/test_segment.py +288 -0
- ostk/astrodynamics/test/trajectory/test_sequence.py +459 -0
- ostk/astrodynamics/test/trajectory/test_state.py +223 -0
- ostk/astrodynamics/test/trajectory/test_state_builder.py +171 -0
- ostk/astrodynamics/viewer.py +1 -3
- open_space_toolkit_astrodynamics-5.1.5.dist-info/RECORD +0 -25
- {open_space_toolkit_astrodynamics-5.1.5.dist-info → open_space_toolkit_astrodynamics-5.2.0.dist-info}/WHEEL +0 -0
- {open_space_toolkit_astrodynamics-5.1.5.dist-info → open_space_toolkit_astrodynamics-5.2.0.dist-info}/top_level.txt +0 -0
- {open_space_toolkit_astrodynamics-5.1.5.dist-info → open_space_toolkit_astrodynamics-5.2.0.dist-info}/zip-safe +0 -0
@@ -0,0 +1,130 @@
|
|
1
|
+
# Apache License 2.0
|
2
|
+
|
3
|
+
import ostk.physics as physics
|
4
|
+
|
5
|
+
import ostk.astrodynamics as astrodynamics
|
6
|
+
|
7
|
+
Length = physics.units.Length
|
8
|
+
Angle = physics.units.Angle
|
9
|
+
Scale = physics.time.Scale
|
10
|
+
Instant = physics.time.Instant
|
11
|
+
Interval = physics.time.Interval
|
12
|
+
DateTime = physics.time.DateTime
|
13
|
+
Position = physics.coordinate.Position
|
14
|
+
Velocity = physics.coordinate.Velocity
|
15
|
+
Frame = physics.coordinate.Frame
|
16
|
+
Environment = physics.Environment
|
17
|
+
|
18
|
+
Trajectory = astrodynamics.Trajectory
|
19
|
+
Model = astrodynamics.trajectory.Model
|
20
|
+
Orbit = astrodynamics.trajectory.Orbit
|
21
|
+
Pass = astrodynamics.trajectory.orbit.Pass
|
22
|
+
Kepler = astrodynamics.trajectory.orbit.models.Kepler
|
23
|
+
COE = astrodynamics.trajectory.orbit.models.kepler.COE
|
24
|
+
SGP4 = astrodynamics.trajectory.orbit.models.SGP4
|
25
|
+
TLE = astrodynamics.trajectory.orbit.models.sgp4.TLE
|
26
|
+
State = astrodynamics.trajectory.State
|
27
|
+
Access = astrodynamics.Access
|
28
|
+
|
29
|
+
earth = Environment.default().access_celestial_object_with_name("Earth")
|
30
|
+
|
31
|
+
|
32
|
+
def construct_kepler():
|
33
|
+
a = Length.kilometers(7000.0)
|
34
|
+
e = 0.1
|
35
|
+
i = Angle.degrees(35.0)
|
36
|
+
raan = Angle.degrees(40.0)
|
37
|
+
aop = Angle.degrees(50.0)
|
38
|
+
nu = Angle.degrees(60.0)
|
39
|
+
|
40
|
+
coe = COE(a, e, i, raan, aop, nu)
|
41
|
+
|
42
|
+
assert coe is not None
|
43
|
+
assert isinstance(coe, COE)
|
44
|
+
|
45
|
+
epoch = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
|
46
|
+
|
47
|
+
kepler = Kepler(coe, epoch, earth, Kepler.PerturbationType.No)
|
48
|
+
|
49
|
+
return kepler
|
50
|
+
|
51
|
+
|
52
|
+
def test_trajectory_orbit_models_kepler_constructors():
|
53
|
+
a = Length.kilometers(7000.0)
|
54
|
+
e = 0.1
|
55
|
+
i = Angle.degrees(35.0)
|
56
|
+
raan = Angle.degrees(40.0)
|
57
|
+
aop = Angle.degrees(50.0)
|
58
|
+
nu = Angle.degrees(60.0)
|
59
|
+
|
60
|
+
coe = COE(a, e, i, raan, aop, nu)
|
61
|
+
|
62
|
+
assert coe is not None
|
63
|
+
assert isinstance(coe, COE)
|
64
|
+
|
65
|
+
epoch = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
|
66
|
+
|
67
|
+
kepler = Kepler(coe, epoch, earth, Kepler.PerturbationType.No)
|
68
|
+
|
69
|
+
assert kepler is not None
|
70
|
+
assert isinstance(kepler, Kepler)
|
71
|
+
assert kepler.is_defined()
|
72
|
+
|
73
|
+
|
74
|
+
def test_trajectory_orbit_models_kepler_comparators():
|
75
|
+
kepler: Kepler = construct_kepler()
|
76
|
+
|
77
|
+
assert kepler == kepler
|
78
|
+
assert (kepler != kepler) is False
|
79
|
+
|
80
|
+
|
81
|
+
def test_trajectory_orbit_models_kepler_getters():
|
82
|
+
kepler: Kepler = construct_kepler()
|
83
|
+
|
84
|
+
# get_classical_orbital_elements
|
85
|
+
|
86
|
+
assert kepler.get_classical_orbital_elements() is not None
|
87
|
+
|
88
|
+
# get_epoch
|
89
|
+
|
90
|
+
assert kepler.get_epoch() is not None
|
91
|
+
|
92
|
+
# get_revolution_number_at_epoch()
|
93
|
+
|
94
|
+
assert kepler.get_revolution_number_at_epoch() is not None
|
95
|
+
|
96
|
+
# get_gravitational_parameter()
|
97
|
+
|
98
|
+
assert kepler.get_gravitational_parameter() is not None
|
99
|
+
|
100
|
+
# get_equatorial_radius()
|
101
|
+
|
102
|
+
assert kepler.get_equatorial_radius() is not None
|
103
|
+
|
104
|
+
# get_j2()
|
105
|
+
|
106
|
+
assert kepler.get_j2() is not None
|
107
|
+
|
108
|
+
# get_j4()
|
109
|
+
|
110
|
+
assert kepler.get_j4() is not None
|
111
|
+
|
112
|
+
# get_perturbation_type()
|
113
|
+
|
114
|
+
assert kepler.get_perturbation_type() is not None
|
115
|
+
|
116
|
+
|
117
|
+
def test_trajectory_orbit_models_kepler_calculate_state_at_epoch():
|
118
|
+
kepler: Kepler = construct_kepler()
|
119
|
+
|
120
|
+
epoch: Instant = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
|
121
|
+
|
122
|
+
assert kepler.calculate_state_at(epoch) is not None
|
123
|
+
|
124
|
+
|
125
|
+
def test_trajectory_orbit_models_kepler_calculate_rev_number_at_epoch():
|
126
|
+
kepler: Kepler = construct_kepler()
|
127
|
+
|
128
|
+
epoch: Instant = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
|
129
|
+
|
130
|
+
assert kepler.calculate_revolution_number_at(epoch) is not None
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# Apache License 2.0
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
import numpy as np
|
6
|
+
|
7
|
+
from ostk.physics.time import Instant
|
8
|
+
from ostk.physics.time import DateTime
|
9
|
+
from ostk.physics.time import Scale
|
10
|
+
from ostk.physics.coordinate import Position
|
11
|
+
from ostk.physics.coordinate import Velocity
|
12
|
+
from ostk.physics.coordinate import Frame
|
13
|
+
from ostk.physics.environment.objects.celestial_bodies import Earth
|
14
|
+
|
15
|
+
from ostk.astrodynamics.trajectory.state import NumericalSolver
|
16
|
+
from ostk.astrodynamics.trajectory import State
|
17
|
+
from ostk.astrodynamics.trajectory import Orbit
|
18
|
+
from ostk.astrodynamics.trajectory import Propagator
|
19
|
+
from ostk.astrodynamics import Dynamics
|
20
|
+
from ostk.astrodynamics.dynamics import CentralBodyGravity
|
21
|
+
from ostk.astrodynamics.dynamics import PositionDerivative
|
22
|
+
from ostk.astrodynamics.trajectory.orbit.models import Propagated
|
23
|
+
|
24
|
+
|
25
|
+
@pytest.fixture
|
26
|
+
def state() -> State:
|
27
|
+
frame: Frame = Frame.GCRF()
|
28
|
+
position: Position = Position.meters([7500000.0, 0.0, 0.0], frame)
|
29
|
+
velocity: Velocity = Velocity.meters_per_second(
|
30
|
+
[0.0, 5335.865450622126, 5335.865450622126], frame
|
31
|
+
)
|
32
|
+
|
33
|
+
instant: Instant = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
|
34
|
+
return State(instant, position, velocity)
|
35
|
+
|
36
|
+
|
37
|
+
@pytest.fixture
|
38
|
+
def central_body_dynamics() -> CentralBodyGravity:
|
39
|
+
return CentralBodyGravity(Earth.WGS84(20, 0))
|
40
|
+
|
41
|
+
|
42
|
+
@pytest.fixture
|
43
|
+
def position_derivative() -> PositionDerivative:
|
44
|
+
return PositionDerivative()
|
45
|
+
|
46
|
+
|
47
|
+
@pytest.fixture
|
48
|
+
def dynamics(
|
49
|
+
position_derivative: PositionDerivative, central_body_dynamics: CentralBodyGravity
|
50
|
+
) -> list:
|
51
|
+
return [position_derivative, central_body_dynamics]
|
52
|
+
|
53
|
+
|
54
|
+
@pytest.fixture
|
55
|
+
def numerical_solver() -> NumericalSolver:
|
56
|
+
return NumericalSolver(
|
57
|
+
NumericalSolver.LogType.NoLog,
|
58
|
+
NumericalSolver.StepperType.RungeKuttaFehlberg78,
|
59
|
+
5.0,
|
60
|
+
1.0e-15,
|
61
|
+
1.0e-15,
|
62
|
+
)
|
63
|
+
|
64
|
+
|
65
|
+
@pytest.fixture
|
66
|
+
def propagator(numerical_solver: NumericalSolver, dynamics: list[Dynamics]) -> Propagator:
|
67
|
+
return Propagator(numerical_solver, dynamics)
|
68
|
+
|
69
|
+
|
70
|
+
@pytest.fixture
|
71
|
+
def propagated(propagator: Propagator, state: State) -> Propagated:
|
72
|
+
return Propagated(propagator, state)
|
73
|
+
|
74
|
+
|
75
|
+
@pytest.fixture
|
76
|
+
def earth() -> Earth:
|
77
|
+
return Earth.spherical()
|
78
|
+
|
79
|
+
|
80
|
+
@pytest.fixture
|
81
|
+
def orbit(propagated: Propagated, earth: Earth) -> Orbit:
|
82
|
+
return Orbit(propagated, earth)
|
83
|
+
|
84
|
+
|
85
|
+
class TestPropagated:
|
86
|
+
def test_constructors(
|
87
|
+
self,
|
88
|
+
propagated: Propagated,
|
89
|
+
earth: Earth,
|
90
|
+
dynamics: list,
|
91
|
+
numerical_solver: NumericalSolver,
|
92
|
+
state: State,
|
93
|
+
):
|
94
|
+
assert propagated is not None
|
95
|
+
assert isinstance(propagated, Propagated)
|
96
|
+
assert propagated.is_defined()
|
97
|
+
|
98
|
+
orbit = Orbit(propagated, earth)
|
99
|
+
|
100
|
+
assert orbit is not None
|
101
|
+
assert isinstance(orbit, Orbit)
|
102
|
+
assert orbit.is_defined()
|
103
|
+
|
104
|
+
state_array = [state, state]
|
105
|
+
propagated_with_state_array = Propagated(
|
106
|
+
Propagator(numerical_solver, dynamics), state_array
|
107
|
+
)
|
108
|
+
|
109
|
+
assert propagated_with_state_array is not None
|
110
|
+
assert isinstance(propagated_with_state_array, Propagated)
|
111
|
+
assert propagated_with_state_array.is_defined()
|
112
|
+
|
113
|
+
def test_comparators(self, propagated: Propagated):
|
114
|
+
assert (propagated == propagated) is True
|
115
|
+
assert (propagated != propagated) is False
|
116
|
+
|
117
|
+
def test_getters(self, propagated: Propagated, state: State):
|
118
|
+
assert propagated.get_epoch() == state.get_instant()
|
119
|
+
|
120
|
+
assert propagated.get_revolution_number_at_epoch() == 1
|
121
|
+
|
122
|
+
assert propagated.access_cached_state_array() == [state]
|
123
|
+
|
124
|
+
def test_calculate_state_at(self, propagated: Propagated, orbit: Orbit):
|
125
|
+
instant: Instant = Instant.date_time(DateTime(2018, 1, 1, 0, 10, 0), Scale.UTC)
|
126
|
+
|
127
|
+
propagated_state = propagated.calculate_state_at(instant)
|
128
|
+
propagated_state_orbit = orbit.get_state_at(instant)
|
129
|
+
|
130
|
+
assert propagated_state == propagated_state_orbit
|
131
|
+
|
132
|
+
propagated_state_position_ref = np.array(
|
133
|
+
[6265892.25765909, 3024770.94961259, 3024359.72137468]
|
134
|
+
)
|
135
|
+
propagated_state_velocity_ref = np.array(
|
136
|
+
[-3974.49168221, 4468.16996776, 4466.19232746]
|
137
|
+
)
|
138
|
+
|
139
|
+
propagated_state_position = propagated_state.get_position().get_coordinates()
|
140
|
+
propagated_state_velocity = propagated_state.get_velocity().get_coordinates()
|
141
|
+
|
142
|
+
assert all(
|
143
|
+
[
|
144
|
+
round(propagated_state_position[i], 8)
|
145
|
+
== round(propagated_state_position_ref[i], 8)
|
146
|
+
for i in range(0, len(propagated_state_position_ref))
|
147
|
+
]
|
148
|
+
)
|
149
|
+
assert all(
|
150
|
+
[
|
151
|
+
round(propagated_state_velocity[i], 8)
|
152
|
+
== round(propagated_state_velocity_ref[i], 8)
|
153
|
+
for i in range(0, len(propagated_state_velocity_ref))
|
154
|
+
]
|
155
|
+
)
|
156
|
+
assert propagated_state.get_instant() == instant
|
157
|
+
|
158
|
+
def test_calculate_states_at(self, propagated: Propagated, orbit: Orbit):
|
159
|
+
instant_array = [
|
160
|
+
Instant.date_time(DateTime(2018, 1, 1, 0, 10, 0), Scale.UTC),
|
161
|
+
Instant.date_time(DateTime(2018, 1, 1, 0, 20, 0), Scale.UTC),
|
162
|
+
]
|
163
|
+
|
164
|
+
propagated_state_array = propagated.calculate_states_at(instant_array)
|
165
|
+
propagated_state_array_orbit = orbit.get_states_at(instant_array)
|
166
|
+
|
167
|
+
assert propagated_state_array_orbit == propagated_state_array
|
168
|
+
|
169
|
+
assert propagated_state_array_orbit[0].get_instant() == instant_array[0]
|
170
|
+
assert propagated_state_array_orbit[1].get_instant() == instant_array[1]
|
171
|
+
|
172
|
+
def test_calculate_rev_number_at(self, propagated: Propagated, orbit: Orbit):
|
173
|
+
instant: Instant = Instant.date_time(DateTime(2018, 1, 1, 0, 40, 0), Scale.UTC)
|
174
|
+
|
175
|
+
assert propagated.calculate_revolution_number_at(instant) == 1
|
176
|
+
assert orbit.get_revolution_number_at(instant) == 1
|
177
|
+
|
178
|
+
def test_access_cached_state_array(self, propagated: Propagated, state: State):
|
179
|
+
assert len(propagated.access_cached_state_array()) == 1
|
180
|
+
assert propagated.access_cached_state_array()[0] == state
|
181
|
+
|
182
|
+
def test_access_propagator(self, propagated: Propagated):
|
183
|
+
assert propagated.access_propagator() is not None
|
184
|
+
assert isinstance(propagated.access_propagator(), Propagator)
|
185
|
+
|
186
|
+
def test_set_cached_state_array(self, propagated: Propagated, state: State):
|
187
|
+
assert len(propagated.access_cached_state_array()) == 1
|
188
|
+
|
189
|
+
propagated.set_cached_state_array([state, state, state])
|
190
|
+
|
191
|
+
assert len(propagated.access_cached_state_array()) == 1
|
192
|
+
assert propagated.access_cached_state_array()[0] == state
|
193
|
+
|
194
|
+
with pytest.raises(Exception) as e:
|
195
|
+
propagated.set_cached_state_array([])
|
@@ -0,0 +1 @@
|
|
1
|
+
# Apache License 2.0
|
@@ -0,0 +1,380 @@
|
|
1
|
+
# Apache License 2.0
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
import numpy as np
|
6
|
+
|
7
|
+
from ostk.physics.time import Instant
|
8
|
+
from ostk.physics.time import DateTime
|
9
|
+
from ostk.physics.time import Scale
|
10
|
+
from ostk.physics.time import Duration
|
11
|
+
from ostk.physics.coordinate import Position
|
12
|
+
from ostk.physics.coordinate import Velocity
|
13
|
+
from ostk.physics.coordinate import Frame
|
14
|
+
from ostk.physics import Environment
|
15
|
+
|
16
|
+
from ostk.astrodynamics.trajectory import State
|
17
|
+
from ostk.astrodynamics.trajectory import Orbit
|
18
|
+
from ostk.astrodynamics.trajectory.orbit.models import Tabulated
|
19
|
+
|
20
|
+
|
21
|
+
@pytest.fixture
|
22
|
+
def earth():
|
23
|
+
return Environment.default().access_celestial_object_with_name("Earth")
|
24
|
+
|
25
|
+
|
26
|
+
@pytest.fixture
|
27
|
+
def reference_states() -> list[State]:
|
28
|
+
data = [
|
29
|
+
[
|
30
|
+
"2023-04-18T08:28:32.744064",
|
31
|
+
-3310024.847608758,
|
32
|
+
-6052528.239971979,
|
33
|
+
7626.534641683145,
|
34
|
+
-855.2088930507367,
|
35
|
+
495.9541573743367,
|
36
|
+
7536.520188134902,
|
37
|
+
],
|
38
|
+
[
|
39
|
+
"2023-04-18T08:28:33.744064",
|
40
|
+
-3310878.047628086,
|
41
|
+
-6052028.610429457,
|
42
|
+
15163.0493833017,
|
43
|
+
-851.1838953959017,
|
44
|
+
503.31279367207185,
|
45
|
+
7536.506322816037,
|
46
|
+
],
|
47
|
+
[
|
48
|
+
"2023-04-18T08:28:34.744064",
|
49
|
+
-3311727.222133691,
|
50
|
+
-6051521.622540367,
|
51
|
+
22699.545682944226,
|
52
|
+
-847.1578341126227,
|
53
|
+
510.67087060642456,
|
54
|
+
7536.483268627912,
|
55
|
+
],
|
56
|
+
[
|
57
|
+
"2023-04-18T08:28:35.744064",
|
58
|
+
-3312572.370064364,
|
59
|
+
-6051007.276868478,
|
60
|
+
30236.014351773065,
|
61
|
+
-843.1307141262514,
|
62
|
+
518.0283791399937,
|
63
|
+
7536.451025467619,
|
64
|
+
],
|
65
|
+
[
|
66
|
+
"2023-04-18T08:28:36.744064",
|
67
|
+
-3313413.490363804,
|
68
|
+
-6050485.573986613,
|
69
|
+
37772.44620082258,
|
70
|
+
-839.1025403636198,
|
71
|
+
525.3853102358,
|
72
|
+
7536.40959324377,
|
73
|
+
],
|
74
|
+
[
|
75
|
+
"2023-04-18T08:28:37.744064",
|
76
|
+
-3314250.5819806806,
|
77
|
+
-6049956.514476612,
|
78
|
+
45308.83204108345,
|
79
|
+
-835.0733177529921,
|
80
|
+
532.7416548573802,
|
81
|
+
7536.358971876497,
|
82
|
+
],
|
83
|
+
[
|
84
|
+
"2023-04-18T08:28:38.744064",
|
85
|
+
-3315083.6438685474,
|
86
|
+
-6049420.098929363,
|
87
|
+
52845.16268340493,
|
88
|
+
-831.0430512241197,
|
89
|
+
540.0974039686765,
|
90
|
+
7536.299161297429,
|
91
|
+
],
|
92
|
+
[
|
93
|
+
"2023-04-18T08:28:39.744064",
|
94
|
+
-3315912.6749859042,
|
95
|
+
-6048876.327944793,
|
96
|
+
60381.42893867038,
|
97
|
+
-827.0117457081434,
|
98
|
+
547.4525485342174,
|
99
|
+
7536.23016144972,
|
100
|
+
],
|
101
|
+
[
|
102
|
+
"2023-04-18T08:28:40.744064",
|
103
|
+
-3316737.6742961914,
|
104
|
+
-6048325.2021318525,
|
105
|
+
67917.62161760827,
|
106
|
+
-822.9794061376964,
|
107
|
+
554.8070795189376,
|
108
|
+
7536.1519722880375,
|
109
|
+
],
|
110
|
+
[
|
111
|
+
"2023-04-18T08:28:41.744064",
|
112
|
+
-3317558.640767768,
|
113
|
+
-6047766.722108539,
|
114
|
+
75453.73153099201,
|
115
|
+
-818.9460374467976,
|
116
|
+
562.1609878883643,
|
117
|
+
7536.064593778564,
|
118
|
+
],
|
119
|
+
[
|
120
|
+
"2023-04-18T08:28:42.744064",
|
121
|
+
-3318375.5733739412,
|
122
|
+
-6047200.888501875,
|
123
|
+
82989.7494894997,
|
124
|
+
-814.9116445709234,
|
125
|
+
569.5142646084902,
|
126
|
+
7535.968025898996,
|
127
|
+
],
|
128
|
+
[
|
129
|
+
"2023-04-18T08:28:43.744064",
|
130
|
+
-3319188.471092942,
|
131
|
+
-6046627.7019479135,
|
132
|
+
90525.66630384693,
|
133
|
+
-810.8762324469382,
|
134
|
+
576.866900645898,
|
135
|
+
7535.862268638544,
|
136
|
+
],
|
137
|
+
[
|
138
|
+
"2023-04-18T08:28:44.744064",
|
139
|
+
-3319997.332907958,
|
140
|
+
-6046047.163091751,
|
141
|
+
98061.47278470133,
|
142
|
+
-806.8398060131411,
|
143
|
+
584.2188869676824,
|
144
|
+
7535.747321997941,
|
145
|
+
],
|
146
|
+
[
|
147
|
+
"2023-04-18T08:28:45.744064",
|
148
|
+
-3320802.157807084,
|
149
|
+
-6045459.272587514,
|
150
|
+
105597.15974279115,
|
151
|
+
-802.8023702092072,
|
152
|
+
591.5702145415504,
|
153
|
+
7535.62318598943,
|
154
|
+
],
|
155
|
+
[
|
156
|
+
"2023-04-18T08:28:46.744064",
|
157
|
+
-3321602.9447833803,
|
158
|
+
-6044864.0310983565,
|
159
|
+
113132.71798877101,
|
160
|
+
-798.7639299762548,
|
161
|
+
598.9208743356983,
|
162
|
+
7535.48986063679,
|
163
|
+
],
|
164
|
+
[
|
165
|
+
"2023-04-18T08:28:47.744064",
|
166
|
+
-3322399.692834845,
|
167
|
+
-6044261.439296465,
|
168
|
+
120668.13833342775,
|
169
|
+
-794.7244902567405,
|
170
|
+
606.2708573190106,
|
171
|
+
7535.347345975296,
|
172
|
+
],
|
173
|
+
[
|
174
|
+
"2023-04-18T08:28:48.744064",
|
175
|
+
-3323192.400964402,
|
176
|
+
-6043651.497863061,
|
177
|
+
128203.41158748553,
|
178
|
+
-790.6840559945587,
|
179
|
+
613.6201544608678,
|
180
|
+
7535.195642051765,
|
181
|
+
],
|
182
|
+
[
|
183
|
+
"2023-04-18T08:28:49.744064",
|
184
|
+
-3323981.068179951,
|
185
|
+
-6043034.207488383,
|
186
|
+
135738.52856182377,
|
187
|
+
-786.6426321349277,
|
188
|
+
620.9687567313651,
|
189
|
+
7535.034748924513,
|
190
|
+
],
|
191
|
+
[
|
192
|
+
"2023-04-18T08:28:50.744064",
|
193
|
+
-3324765.6934943097,
|
194
|
+
-6042409.568871722,
|
195
|
+
143273.48006733102,
|
196
|
+
-782.6002236244674,
|
197
|
+
628.3166551011666,
|
198
|
+
7534.864666663388,
|
199
|
+
],
|
200
|
+
[
|
201
|
+
"2023-04-18T08:28:51.744064",
|
202
|
+
-3325546.2759252544,
|
203
|
+
-6041777.582721372,
|
204
|
+
150808.25691495842,
|
205
|
+
-778.5568354111685,
|
206
|
+
635.6638405415614,
|
207
|
+
7534.68539534976,
|
208
|
+
],
|
209
|
+
]
|
210
|
+
return [
|
211
|
+
State(
|
212
|
+
instant=Instant.date_time(DateTime.parse(row[0]), Scale.UTC),
|
213
|
+
position=Position.meters(
|
214
|
+
[float(row[1]), float(row[2]), float(row[3])], Frame.GCRF()
|
215
|
+
),
|
216
|
+
velocity=Velocity.meters_per_second(
|
217
|
+
[float(row[4]), float(row[5]), float(row[6])], Frame.GCRF()
|
218
|
+
),
|
219
|
+
)
|
220
|
+
for row in data
|
221
|
+
]
|
222
|
+
|
223
|
+
|
224
|
+
@pytest.fixture
|
225
|
+
def test_states(reference_states: list[State]) -> list[State]:
|
226
|
+
return reference_states[::4]
|
227
|
+
|
228
|
+
|
229
|
+
class TestTabulated:
|
230
|
+
@pytest.mark.parametrize(
|
231
|
+
"interpolation_type",
|
232
|
+
(
|
233
|
+
(Tabulated.InterpolationType.Linear),
|
234
|
+
(Tabulated.InterpolationType.CubicSpline),
|
235
|
+
(Tabulated.InterpolationType.BarycentricRational),
|
236
|
+
),
|
237
|
+
)
|
238
|
+
def test_constructor(
|
239
|
+
self, test_states: list[State], interpolation_type: Tabulated.InterpolationType
|
240
|
+
):
|
241
|
+
assert (
|
242
|
+
Tabulated(
|
243
|
+
states=test_states,
|
244
|
+
initial_revolution_number=1,
|
245
|
+
interpolation_type=interpolation_type,
|
246
|
+
)
|
247
|
+
is not None
|
248
|
+
)
|
249
|
+
|
250
|
+
def test_constructor_orbit_tabulated_sucess(
|
251
|
+
self,
|
252
|
+
test_states: list[State],
|
253
|
+
earth,
|
254
|
+
):
|
255
|
+
tabulated = Tabulated(
|
256
|
+
states=test_states,
|
257
|
+
initial_revolution_number=1,
|
258
|
+
interpolation_type=Tabulated.InterpolationType.CubicSpline,
|
259
|
+
)
|
260
|
+
|
261
|
+
orbit: Orbit = Orbit(tabulated, earth)
|
262
|
+
|
263
|
+
assert orbit is not None
|
264
|
+
assert isinstance(orbit, Orbit)
|
265
|
+
|
266
|
+
def test_get_interpolation_type(self, test_states: list[State]):
|
267
|
+
tabulated = Tabulated(
|
268
|
+
states=test_states,
|
269
|
+
initial_revolution_number=1,
|
270
|
+
interpolation_type=Tabulated.InterpolationType.CubicSpline,
|
271
|
+
)
|
272
|
+
|
273
|
+
assert (
|
274
|
+
tabulated.get_interpolation_type() == Tabulated.InterpolationType.CubicSpline
|
275
|
+
)
|
276
|
+
|
277
|
+
@pytest.mark.parametrize(
|
278
|
+
"interpolation_type,error_tolerance",
|
279
|
+
(
|
280
|
+
(Tabulated.InterpolationType.Linear, 420.0),
|
281
|
+
(Tabulated.InterpolationType.CubicSpline, 5e-3),
|
282
|
+
(Tabulated.InterpolationType.BarycentricRational, 5e-2),
|
283
|
+
),
|
284
|
+
)
|
285
|
+
def test_calculate_state_at_success(
|
286
|
+
self,
|
287
|
+
test_states: list[State],
|
288
|
+
reference_states: list[State],
|
289
|
+
interpolation_type: Tabulated.InterpolationType,
|
290
|
+
error_tolerance: float,
|
291
|
+
):
|
292
|
+
tabulated = Tabulated(
|
293
|
+
states=test_states,
|
294
|
+
initial_revolution_number=1,
|
295
|
+
interpolation_type=interpolation_type,
|
296
|
+
)
|
297
|
+
|
298
|
+
for reference_state in reference_states:
|
299
|
+
if not tabulated.get_interval().contains_instant(
|
300
|
+
reference_state.get_instant()
|
301
|
+
):
|
302
|
+
continue
|
303
|
+
|
304
|
+
calculated_state: State = tabulated.calculate_state_at(
|
305
|
+
reference_state.get_instant()
|
306
|
+
)
|
307
|
+
assert np.all(
|
308
|
+
np.abs(
|
309
|
+
calculated_state.get_coordinates() - reference_state.get_coordinates()
|
310
|
+
)
|
311
|
+
< error_tolerance
|
312
|
+
)
|
313
|
+
|
314
|
+
@pytest.mark.parametrize(
|
315
|
+
"interpolation_type,error_tolerance",
|
316
|
+
(
|
317
|
+
(Tabulated.InterpolationType.Linear, 420.0),
|
318
|
+
(Tabulated.InterpolationType.CubicSpline, 5e-3),
|
319
|
+
(Tabulated.InterpolationType.BarycentricRational, 5e-2),
|
320
|
+
),
|
321
|
+
)
|
322
|
+
def test_calculate_states_at_success(
|
323
|
+
self,
|
324
|
+
test_states: list[State],
|
325
|
+
reference_states: list[State],
|
326
|
+
interpolation_type: Tabulated.InterpolationType,
|
327
|
+
error_tolerance: float,
|
328
|
+
):
|
329
|
+
tabulated = Tabulated(
|
330
|
+
states=test_states,
|
331
|
+
initial_revolution_number=1,
|
332
|
+
interpolation_type=interpolation_type,
|
333
|
+
)
|
334
|
+
|
335
|
+
states_within_interval: list[State] = [
|
336
|
+
state
|
337
|
+
for state in reference_states
|
338
|
+
if tabulated.get_interval().contains_instant(state.get_instant())
|
339
|
+
]
|
340
|
+
|
341
|
+
calculated_states: list[State] = tabulated.calculate_states_at(
|
342
|
+
[state.get_instant() for state in states_within_interval]
|
343
|
+
)
|
344
|
+
|
345
|
+
for calculated_state, reference_state in zip(
|
346
|
+
calculated_states, states_within_interval
|
347
|
+
):
|
348
|
+
assert np.all(
|
349
|
+
np.abs(
|
350
|
+
calculated_state.get_coordinates() - reference_state.get_coordinates()
|
351
|
+
)
|
352
|
+
< error_tolerance
|
353
|
+
)
|
354
|
+
|
355
|
+
@pytest.mark.parametrize(
|
356
|
+
"interpolation_type",
|
357
|
+
(
|
358
|
+
(Tabulated.InterpolationType.Linear),
|
359
|
+
(Tabulated.InterpolationType.CubicSpline),
|
360
|
+
(Tabulated.InterpolationType.BarycentricRational),
|
361
|
+
),
|
362
|
+
)
|
363
|
+
def test_calculate_state_at_failure(
|
364
|
+
self, test_states: list[State], interpolation_type: Tabulated.InterpolationType
|
365
|
+
):
|
366
|
+
tabulated = Tabulated(
|
367
|
+
states=test_states,
|
368
|
+
initial_revolution_number=1,
|
369
|
+
interpolation_type=interpolation_type,
|
370
|
+
)
|
371
|
+
|
372
|
+
with pytest.raises(Exception):
|
373
|
+
tabulated.calculate_state_at(
|
374
|
+
test_states[0].get_instant() - Duration.seconds(1)
|
375
|
+
)
|
376
|
+
|
377
|
+
with pytest.raises(Exception):
|
378
|
+
tabulated.calculate_state_at(
|
379
|
+
test_states[-1].get_instant() + Duration.seconds(1)
|
380
|
+
)
|
@@ -0,0 +1 @@
|
|
1
|
+
# Apache License 2.0
|