open-space-toolkit-astrodynamics 9.4.1__py38-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-9.4.1.dist-info/METADATA +30 -0
- open_space_toolkit_astrodynamics-9.4.1.dist-info/RECORD +98 -0
- open_space_toolkit_astrodynamics-9.4.1.dist-info/WHEEL +5 -0
- open_space_toolkit_astrodynamics-9.4.1.dist-info/top_level.txt +1 -0
- open_space_toolkit_astrodynamics-9.4.1.dist-info/zip-safe +1 -0
- ostk/__init__.py +1 -0
- ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-38-x86_64-linux-gnu.so +0 -0
- ostk/astrodynamics/__init__.py +11 -0
- ostk/astrodynamics/converters.py +185 -0
- ostk/astrodynamics/display.py +220 -0
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.9 +0 -0
- ostk/astrodynamics/pytrajectory/__init__.py +1 -0
- ostk/astrodynamics/pytrajectory/pystate.py +36 -0
- ostk/astrodynamics/test/__init__.py +1 -0
- ostk/astrodynamics/test/access/__init__.py +1 -0
- ostk/astrodynamics/test/access/test_generator.py +248 -0
- ostk/astrodynamics/test/conftest.py +119 -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/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 +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/system/__init__.py +1 -0
- ostk/astrodynamics/test/flight/system/test_propulsion_system.py +73 -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_maneuver.py +212 -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 +138 -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 +128 -0
- ostk/astrodynamics/test/test_converters.py +387 -0
- ostk/astrodynamics/test/test_display.py +115 -0
- ostk/astrodynamics/test/test_event_condition.py +58 -0
- ostk/astrodynamics/test/test_import.py +26 -0
- ostk/astrodynamics/test/test_root_solver.py +70 -0
- ostk/astrodynamics/test/test_trajectory.py +40 -0
- ostk/astrodynamics/test/test_utilities.py +121 -0
- ostk/astrodynamics/test/test_viewer.py +129 -0
- ostk/astrodynamics/test/trajectory/__init__.py +1 -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 +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 +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 +72 -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_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 +46 -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 +76 -0
- ostk/astrodynamics/test/trajectory/test_model.py +1 -0
- ostk/astrodynamics/test/trajectory/test_orbit.py +174 -0
- ostk/astrodynamics/test/trajectory/test_propagator.py +458 -0
- ostk/astrodynamics/test/trajectory/test_segment.py +305 -0
- ostk/astrodynamics/test/trajectory/test_sequence.py +477 -0
- ostk/astrodynamics/test/trajectory/test_state.py +237 -0
- ostk/astrodynamics/test/trajectory/test_state_builder.py +171 -0
- ostk/astrodynamics/utilities.py +158 -0
- ostk/astrodynamics/viewer.py +392 -0
@@ -0,0 +1,387 @@
|
|
1
|
+
# Apache License 2.0
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
from datetime import datetime, timedelta, timezone
|
6
|
+
|
7
|
+
import numpy as np
|
8
|
+
|
9
|
+
from ostk.mathematics.geometry.d3.transformation.rotation import Quaternion
|
10
|
+
|
11
|
+
from ostk.physics.time import Instant
|
12
|
+
from ostk.physics.time import Interval
|
13
|
+
from ostk.physics.time import Duration
|
14
|
+
from ostk.physics.time import DateTime
|
15
|
+
from ostk.physics.time import Scale
|
16
|
+
from ostk.physics.coordinate import Position
|
17
|
+
from ostk.physics.coordinate import Velocity
|
18
|
+
from ostk.physics.coordinate import Frame
|
19
|
+
|
20
|
+
from ostk.astrodynamics.converters import coerce_to_datetime
|
21
|
+
from ostk.astrodynamics.converters import coerce_to_instant
|
22
|
+
from ostk.astrodynamics.converters import coerce_to_iso
|
23
|
+
from ostk.astrodynamics.converters import coerce_to_interval
|
24
|
+
from ostk.astrodynamics.converters import coerce_to_duration
|
25
|
+
from ostk.astrodynamics.converters import coerce_to_position
|
26
|
+
from ostk.astrodynamics.converters import coerce_to_velocity
|
27
|
+
from ostk.astrodynamics.converters import coerce_to_quaternion
|
28
|
+
|
29
|
+
|
30
|
+
def test_coerce_to_datetime_success_instant():
|
31
|
+
value = Instant.date_time(DateTime(2020, 1, 2, 3, 4, 5, 123, 456), Scale.UTC)
|
32
|
+
assert coerce_to_datetime(value) == datetime(
|
33
|
+
2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone.utc
|
34
|
+
)
|
35
|
+
|
36
|
+
value = Instant.date_time(DateTime(2020, 1, 2, 3, 4, 5, 123, 456), Scale.TAI)
|
37
|
+
assert coerce_to_datetime(value) == datetime(
|
38
|
+
2020, 1, 2, 3, 3, 28, 123456, tzinfo=timezone.utc
|
39
|
+
)
|
40
|
+
|
41
|
+
|
42
|
+
def test_coerce_to_datetime_success_datetime():
|
43
|
+
value = datetime(2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone.utc)
|
44
|
+
assert coerce_to_datetime(value) == value
|
45
|
+
|
46
|
+
value = datetime(
|
47
|
+
2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone(timedelta(seconds=3600))
|
48
|
+
)
|
49
|
+
assert coerce_to_datetime(value) == value
|
50
|
+
|
51
|
+
|
52
|
+
def test_coerce_to_datetime_success_iso():
|
53
|
+
value = "2020-01-02T03:04:05.123456+00:00"
|
54
|
+
assert coerce_to_datetime(value) == datetime(
|
55
|
+
2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone.utc
|
56
|
+
)
|
57
|
+
|
58
|
+
value = "2020-01-02T03:04:05+00:00"
|
59
|
+
assert coerce_to_datetime(value) == datetime(2020, 1, 2, 3, 4, 5, tzinfo=timezone.utc)
|
60
|
+
|
61
|
+
value = "2020-01-02T03:04:05.123456+01:00"
|
62
|
+
assert coerce_to_datetime(value) == datetime(
|
63
|
+
2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone(timedelta(seconds=3600))
|
64
|
+
)
|
65
|
+
|
66
|
+
value = "2020-01-02T03:04:05.123456Z"
|
67
|
+
assert coerce_to_datetime(value) == datetime(
|
68
|
+
2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone.utc
|
69
|
+
)
|
70
|
+
|
71
|
+
value = "2020-01-02T03:04:05Z"
|
72
|
+
assert coerce_to_datetime(value) == datetime(2020, 1, 2, 3, 4, 5, tzinfo=timezone.utc)
|
73
|
+
|
74
|
+
|
75
|
+
def test_coerce_to_datetime_failure():
|
76
|
+
with pytest.raises(TypeError):
|
77
|
+
coerce_to_datetime(False)
|
78
|
+
|
79
|
+
with pytest.raises(Exception):
|
80
|
+
coerce_to_datetime("some_ill_formed_iso")
|
81
|
+
|
82
|
+
|
83
|
+
def test_coerce_to_instant_success_datetime():
|
84
|
+
value = datetime(2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone.utc)
|
85
|
+
assert coerce_to_instant(value) == Instant.date_time(
|
86
|
+
DateTime(2020, 1, 2, 3, 4, 5, 123, 456), Scale.UTC
|
87
|
+
)
|
88
|
+
|
89
|
+
value = datetime(
|
90
|
+
2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone(timedelta(seconds=3600))
|
91
|
+
)
|
92
|
+
assert coerce_to_instant(value) == Instant.date_time(
|
93
|
+
DateTime(2020, 1, 2, 2, 4, 5, 123, 456), Scale.UTC
|
94
|
+
)
|
95
|
+
|
96
|
+
|
97
|
+
def test_coerce_to_instant_success_instant():
|
98
|
+
value = Instant.date_time(DateTime(2020, 1, 2, 3, 4, 5, 123, 456), Scale.UTC)
|
99
|
+
assert coerce_to_instant(value) == value
|
100
|
+
|
101
|
+
value = Instant.date_time(DateTime(2020, 1, 2, 3, 4, 5, 123, 456), Scale.TAI)
|
102
|
+
assert coerce_to_instant(value) == value
|
103
|
+
|
104
|
+
|
105
|
+
def test_coerce_to_instant_success_iso():
|
106
|
+
value = "2020-01-02T03:04:05.123456+00:00"
|
107
|
+
assert coerce_to_instant(value) == Instant.date_time(
|
108
|
+
DateTime(2020, 1, 2, 3, 4, 5, 123, 456), Scale.UTC
|
109
|
+
)
|
110
|
+
|
111
|
+
value = "2020-01-02T03:04:05+00:00"
|
112
|
+
assert coerce_to_instant(value) == Instant.date_time(
|
113
|
+
DateTime(2020, 1, 2, 3, 4, 5), Scale.UTC
|
114
|
+
)
|
115
|
+
|
116
|
+
value = "2020-01-02T03:04:05.123456+01:00"
|
117
|
+
assert coerce_to_instant(value) == Instant.date_time(
|
118
|
+
DateTime(2020, 1, 2, 2, 4, 5, 123, 456), Scale.UTC
|
119
|
+
)
|
120
|
+
|
121
|
+
value = "2020-01-02T03:04:05.123456Z"
|
122
|
+
assert coerce_to_instant(value) == Instant.date_time(
|
123
|
+
DateTime(2020, 1, 2, 3, 4, 5, 123, 456), Scale.UTC
|
124
|
+
)
|
125
|
+
|
126
|
+
value = "2020-01-02T03:04:05Z"
|
127
|
+
assert coerce_to_instant(value) == Instant.date_time(
|
128
|
+
DateTime(
|
129
|
+
2020,
|
130
|
+
1,
|
131
|
+
2,
|
132
|
+
3,
|
133
|
+
4,
|
134
|
+
5,
|
135
|
+
),
|
136
|
+
Scale.UTC,
|
137
|
+
)
|
138
|
+
|
139
|
+
|
140
|
+
def test_coerce_to_instant_failure():
|
141
|
+
with pytest.raises(TypeError):
|
142
|
+
coerce_to_instant(False)
|
143
|
+
|
144
|
+
with pytest.raises(Exception):
|
145
|
+
coerce_to_instant("some_ill_formed_iso")
|
146
|
+
|
147
|
+
|
148
|
+
def test_coerce_to_iso_success_datetime():
|
149
|
+
value = datetime(2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone.utc)
|
150
|
+
assert (
|
151
|
+
coerce_to_iso(value, timespec="microseconds")
|
152
|
+
== "2020-01-02T03:04:05.123456+00:00"
|
153
|
+
)
|
154
|
+
|
155
|
+
value = datetime(
|
156
|
+
2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone(timedelta(seconds=3600))
|
157
|
+
)
|
158
|
+
assert (
|
159
|
+
coerce_to_iso(value, timespec="microseconds")
|
160
|
+
== "2020-01-02T03:04:05.123456+01:00"
|
161
|
+
)
|
162
|
+
|
163
|
+
value = datetime(2020, 1, 2, 3, 4, 5, 123456, tzinfo=timezone.utc)
|
164
|
+
assert (
|
165
|
+
coerce_to_iso(value, timespec="milliseconds") == "2020-01-02T03:04:05.123+00:00"
|
166
|
+
)
|
167
|
+
|
168
|
+
value = datetime(2020, 1, 2, 3, 4, 5, 0, tzinfo=timezone.utc)
|
169
|
+
assert (
|
170
|
+
coerce_to_iso(value, timespec="microseconds")
|
171
|
+
== "2020-01-02T03:04:05.000000+00:00"
|
172
|
+
)
|
173
|
+
|
174
|
+
|
175
|
+
def test_coerce_to_iso_success_instant():
|
176
|
+
value = Instant.date_time(DateTime(2020, 1, 2, 3, 4, 5, 123, 456), Scale.UTC)
|
177
|
+
assert (
|
178
|
+
coerce_to_iso(value, timespec="microseconds")
|
179
|
+
== "2020-01-02T03:04:05.123456+00:00"
|
180
|
+
)
|
181
|
+
|
182
|
+
value = Instant.date_time(DateTime(2020, 1, 2, 3, 4, 5, 123, 456), Scale.TAI)
|
183
|
+
assert (
|
184
|
+
coerce_to_iso(value, timespec="microseconds")
|
185
|
+
== "2020-01-02T03:03:28.123456+00:00"
|
186
|
+
)
|
187
|
+
|
188
|
+
value = Instant.date_time(DateTime(2020, 1, 2, 3, 4, 5, 123, 456), Scale.UTC)
|
189
|
+
assert (
|
190
|
+
coerce_to_iso(value, timespec="milliseconds") == "2020-01-02T03:04:05.123+00:00"
|
191
|
+
)
|
192
|
+
|
193
|
+
value = Instant.date_time(DateTime(2020, 1, 2, 3, 4, 5, 123), Scale.UTC)
|
194
|
+
assert (
|
195
|
+
coerce_to_iso(value, timespec="microseconds")
|
196
|
+
== "2020-01-02T03:04:05.123000+00:00"
|
197
|
+
)
|
198
|
+
|
199
|
+
|
200
|
+
def test_coerce_to_iso_success_iso():
|
201
|
+
value = "2020-01-02T03:04:05.123456+00:00"
|
202
|
+
assert coerce_to_iso(value, timespec="microseconds") == value
|
203
|
+
|
204
|
+
value = "2020-01-02T03:04:05.123456+01:00"
|
205
|
+
assert coerce_to_iso(value, timespec="microseconds") == value
|
206
|
+
|
207
|
+
value = "2020-01-02T03:04:05.123456+00:00"
|
208
|
+
assert (
|
209
|
+
coerce_to_iso(value, timespec="milliseconds") == "2020-01-02T03:04:05.123+00:00"
|
210
|
+
)
|
211
|
+
|
212
|
+
value = "2020-01-02T03:04:05.123+00:00"
|
213
|
+
assert (
|
214
|
+
coerce_to_iso(value, timespec="microseconds")
|
215
|
+
== "2020-01-02T03:04:05.123000+00:00"
|
216
|
+
)
|
217
|
+
|
218
|
+
value = "2020-01-02T03:04:05+00:00"
|
219
|
+
assert (
|
220
|
+
coerce_to_iso(value, timespec="microseconds")
|
221
|
+
== "2020-01-02T03:04:05.000000+00:00"
|
222
|
+
)
|
223
|
+
|
224
|
+
value = "2020-01-02T03:04:05.123456Z"
|
225
|
+
assert (
|
226
|
+
coerce_to_iso(value, timespec="microseconds")
|
227
|
+
== "2020-01-02T03:04:05.123456+00:00"
|
228
|
+
)
|
229
|
+
|
230
|
+
value = "2020-01-02T03:04:05.123456Z"
|
231
|
+
assert (
|
232
|
+
coerce_to_iso(value, timespec="milliseconds") == "2020-01-02T03:04:05.123+00:00"
|
233
|
+
)
|
234
|
+
|
235
|
+
value = "2020-01-02T03:04:05.123Z"
|
236
|
+
assert (
|
237
|
+
coerce_to_iso(value, timespec="microseconds")
|
238
|
+
== "2020-01-02T03:04:05.123000+00:00"
|
239
|
+
)
|
240
|
+
|
241
|
+
value = "2020-01-02T03:04:05Z"
|
242
|
+
assert (
|
243
|
+
coerce_to_iso(value, timespec="microseconds")
|
244
|
+
== "2020-01-02T03:04:05.000000+00:00"
|
245
|
+
)
|
246
|
+
|
247
|
+
|
248
|
+
def test_coerce_to_iso_failure():
|
249
|
+
with pytest.raises(TypeError):
|
250
|
+
coerce_to_iso(False)
|
251
|
+
|
252
|
+
with pytest.raises(Exception):
|
253
|
+
coerce_to_iso("some_ill_formed_iso")
|
254
|
+
|
255
|
+
|
256
|
+
def test_coerce_to_interval_success_interval():
|
257
|
+
value = Interval.closed(
|
258
|
+
Instant.date_time(DateTime(2020, 1, 1), Scale.UTC),
|
259
|
+
Instant.date_time(DateTime(2020, 1, 2), Scale.UTC),
|
260
|
+
)
|
261
|
+
assert coerce_to_interval(value) == value
|
262
|
+
|
263
|
+
|
264
|
+
def test_coerce_to_interval_success_tuple_instant():
|
265
|
+
value = (
|
266
|
+
Instant.date_time(DateTime(2020, 1, 1), Scale.UTC),
|
267
|
+
Instant.date_time(DateTime(2020, 1, 2), Scale.UTC),
|
268
|
+
)
|
269
|
+
assert coerce_to_interval(value) == Interval.closed(
|
270
|
+
Instant.date_time(DateTime(2020, 1, 1), Scale.UTC),
|
271
|
+
Instant.date_time(DateTime(2020, 1, 2), Scale.UTC),
|
272
|
+
)
|
273
|
+
|
274
|
+
|
275
|
+
def test_coerce_to_interval_success_list_instant():
|
276
|
+
value = [
|
277
|
+
Instant.date_time(DateTime(2020, 1, 1), Scale.UTC),
|
278
|
+
Instant.date_time(DateTime(2020, 1, 2), Scale.UTC),
|
279
|
+
]
|
280
|
+
assert coerce_to_interval(value) == Interval.closed(
|
281
|
+
Instant.date_time(DateTime(2020, 1, 1), Scale.UTC),
|
282
|
+
Instant.date_time(DateTime(2020, 1, 2), Scale.UTC),
|
283
|
+
)
|
284
|
+
|
285
|
+
|
286
|
+
def test_coerce_to_interval_success_tuple_datetime():
|
287
|
+
value = (
|
288
|
+
datetime(2020, 1, 1, tzinfo=timezone.utc),
|
289
|
+
datetime(2020, 1, 2, tzinfo=timezone.utc),
|
290
|
+
)
|
291
|
+
assert coerce_to_interval(value) == Interval.closed(
|
292
|
+
Instant.date_time(DateTime(2020, 1, 1), Scale.UTC),
|
293
|
+
Instant.date_time(DateTime(2020, 1, 2), Scale.UTC),
|
294
|
+
)
|
295
|
+
|
296
|
+
|
297
|
+
def test_coerce_to_interval_success_list_datetime():
|
298
|
+
value = [
|
299
|
+
datetime(2020, 1, 1, tzinfo=timezone.utc),
|
300
|
+
datetime(2020, 1, 2, tzinfo=timezone.utc),
|
301
|
+
]
|
302
|
+
assert coerce_to_interval(value) == Interval.closed(
|
303
|
+
Instant.date_time(DateTime(2020, 1, 1), Scale.UTC),
|
304
|
+
Instant.date_time(DateTime(2020, 1, 2), Scale.UTC),
|
305
|
+
)
|
306
|
+
|
307
|
+
|
308
|
+
def test_coerce_to_duration_success_duration():
|
309
|
+
value = Duration.seconds(1.0)
|
310
|
+
assert coerce_to_duration(value) == value
|
311
|
+
|
312
|
+
|
313
|
+
def test_coerce_to_duration_success_timedelta():
|
314
|
+
value = timedelta(seconds=1.0)
|
315
|
+
assert coerce_to_duration(value) == Duration.seconds(1.0)
|
316
|
+
|
317
|
+
|
318
|
+
def test_coerce_to_position_success_position():
|
319
|
+
value = Position.meters((1.0, 2.0, 3.0), Frame.GCRF())
|
320
|
+
assert coerce_to_position(value, Frame.GCRF()) == value
|
321
|
+
|
322
|
+
|
323
|
+
def test_coerce_to_position_success_tuple_float():
|
324
|
+
value = (1.0, 2.0, 3.0)
|
325
|
+
assert coerce_to_position(value, Frame.GCRF()) == Position.meters(
|
326
|
+
(1.0, 2.0, 3.0), Frame.GCRF()
|
327
|
+
)
|
328
|
+
|
329
|
+
|
330
|
+
def test_coerce_to_position_success_list_float():
|
331
|
+
value = [1.0, 2.0, 3.0]
|
332
|
+
assert coerce_to_position(value, Frame.GCRF()) == Position.meters(
|
333
|
+
(1.0, 2.0, 3.0), Frame.GCRF()
|
334
|
+
)
|
335
|
+
|
336
|
+
|
337
|
+
def test_coerce_to_position_success_np_array():
|
338
|
+
value = np.array((1.0, 2.0, 3.0))
|
339
|
+
assert coerce_to_position(value, Frame.GCRF()) == Position.meters(
|
340
|
+
(1.0, 2.0, 3.0), Frame.GCRF()
|
341
|
+
)
|
342
|
+
|
343
|
+
|
344
|
+
def test_coerce_to_velocity_success_velocity():
|
345
|
+
value = Velocity.meters_per_second((1.0, 2.0, 3.0), Frame.GCRF())
|
346
|
+
assert coerce_to_velocity(value, Frame.GCRF()) == value
|
347
|
+
|
348
|
+
|
349
|
+
def test_coerce_to_velocity_success_tuple_float():
|
350
|
+
value = (1.0, 2.0, 3.0)
|
351
|
+
assert coerce_to_velocity(value, Frame.GCRF()) == Velocity.meters_per_second(
|
352
|
+
(1.0, 2.0, 3.0), Frame.GCRF()
|
353
|
+
)
|
354
|
+
|
355
|
+
|
356
|
+
def test_coerce_to_velocity_success_list_float():
|
357
|
+
value = [1.0, 2.0, 3.0]
|
358
|
+
assert coerce_to_velocity(value, Frame.GCRF()) == Velocity.meters_per_second(
|
359
|
+
(1.0, 2.0, 3.0), Frame.GCRF()
|
360
|
+
)
|
361
|
+
|
362
|
+
|
363
|
+
def test_coerce_to_velocity_success_np_array():
|
364
|
+
value = np.array((1.0, 2.0, 3.0))
|
365
|
+
assert coerce_to_velocity(value, Frame.GCRF()) == Velocity.meters_per_second(
|
366
|
+
(1.0, 2.0, 3.0), Frame.GCRF()
|
367
|
+
)
|
368
|
+
|
369
|
+
|
370
|
+
def test_coerce_to_quaternion_success_quaternion():
|
371
|
+
value = Quaternion.xyzs(1.0, 2.0, 3.0, 4.0)
|
372
|
+
assert coerce_to_quaternion(value) == value
|
373
|
+
|
374
|
+
|
375
|
+
def test_coerce_to_quaternion_success_list_float():
|
376
|
+
value = [1.0, 2.0, 3.0, 4.0]
|
377
|
+
assert coerce_to_quaternion(value) == Quaternion.xyzs(1.0, 2.0, 3.0, 4.0)
|
378
|
+
|
379
|
+
|
380
|
+
def test_coerce_to_quaternion_success_np_array():
|
381
|
+
value = np.array((1.0, 2.0, 3.0, 4.0))
|
382
|
+
assert coerce_to_quaternion(value) == Quaternion.xyzs(1.0, 2.0, 3.0, 4.0)
|
383
|
+
|
384
|
+
|
385
|
+
def test_coerce_to_quaternion_success_tuple_float():
|
386
|
+
value = (1.0, 2.0, 3.0, 4.0)
|
387
|
+
assert coerce_to_quaternion(value) == Quaternion.xyzs(1.0, 2.0, 3.0, 4.0)
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Apache License 2.0
|
2
|
+
|
3
|
+
from ostk.mathematics.object import RealInterval
|
4
|
+
|
5
|
+
from ostk.physics import Environment
|
6
|
+
from ostk.physics.coordinate import Position
|
7
|
+
from ostk.physics.coordinate import Frame
|
8
|
+
from ostk.physics.coordinate.spherical import LLA
|
9
|
+
from ostk.physics.environment.object import Celestial
|
10
|
+
from ostk.physics.time import DateTime
|
11
|
+
from ostk.physics.time import Duration
|
12
|
+
from ostk.physics.time import Instant
|
13
|
+
from ostk.physics.time import Interval
|
14
|
+
from ostk.physics.time import Scale
|
15
|
+
from ostk.physics.unit import Length
|
16
|
+
from ostk.physics.unit import Angle
|
17
|
+
|
18
|
+
from ostk.astrodynamics import Trajectory
|
19
|
+
from ostk.astrodynamics import display
|
20
|
+
from ostk.astrodynamics.access import Generator as AccessGenerator
|
21
|
+
from ostk.astrodynamics.trajectory import Orbit
|
22
|
+
from ostk.astrodynamics.trajectory import State
|
23
|
+
from ostk.astrodynamics.trajectory.orbit.model import SGP4
|
24
|
+
from ostk.astrodynamics.trajectory.orbit.model.sgp4 import TLE
|
25
|
+
|
26
|
+
|
27
|
+
class TestDisplay:
|
28
|
+
def test_accesses_plot(self, state: State):
|
29
|
+
start_instant: Instant = Instant.date_time(
|
30
|
+
DateTime(2023, 1, 3, 0, 0, 0),
|
31
|
+
Scale.UTC,
|
32
|
+
)
|
33
|
+
duration: Duration = Duration.days(7.0)
|
34
|
+
step: Duration = Duration.seconds(10.0)
|
35
|
+
tolerance: Duration = Duration.seconds(1.0)
|
36
|
+
|
37
|
+
ground_station_lla: LLA = LLA(
|
38
|
+
Angle.degrees(70.0),
|
39
|
+
Angle.degrees(160.0),
|
40
|
+
Length.meters(0.0),
|
41
|
+
)
|
42
|
+
|
43
|
+
tle_1 = TLE(
|
44
|
+
"1 55076U 23001BV 23146.17959645 .00004328 00000-0 23719-3 0 9993",
|
45
|
+
"2 55076 97.4793 205.9529 0016244 89.9523 270.3571 15.14609100 21723",
|
46
|
+
)
|
47
|
+
|
48
|
+
tle_2 = TLE(
|
49
|
+
"1 48915U 21059AN 23146.32782040 .00004955 00000-0 24678-3 0 9999",
|
50
|
+
"2 48915 97.5954 279.7041 0010303 354.9434 5.1694 15.18004448105867",
|
51
|
+
)
|
52
|
+
|
53
|
+
environment: Environment = Environment.default()
|
54
|
+
earth: Celestial = environment.access_celestial_object_with_name("Earth")
|
55
|
+
|
56
|
+
ground_station_trajectory: Trajectory = Trajectory.position(
|
57
|
+
Position.meters(
|
58
|
+
ground_station_lla.to_cartesian(
|
59
|
+
earth.get_equatorial_radius(),
|
60
|
+
earth.get_flattening(),
|
61
|
+
),
|
62
|
+
Frame.ITRF(),
|
63
|
+
),
|
64
|
+
)
|
65
|
+
|
66
|
+
stop_instant: Instant = start_instant + duration
|
67
|
+
search_interval: RealInterval = Interval.closed(start_instant, stop_instant)
|
68
|
+
|
69
|
+
orbit_1: Orbit = Orbit(SGP4(tle_1), earth)
|
70
|
+
orbit_2: Orbit = Orbit(SGP4(tle_2), earth)
|
71
|
+
|
72
|
+
generator = AccessGenerator(
|
73
|
+
environment=environment,
|
74
|
+
step=step,
|
75
|
+
tolerance=tolerance,
|
76
|
+
)
|
77
|
+
|
78
|
+
accesses_1 = generator.compute_accesses(
|
79
|
+
interval=search_interval,
|
80
|
+
from_trajectory=ground_station_trajectory,
|
81
|
+
to_trajectory=orbit_1,
|
82
|
+
)
|
83
|
+
|
84
|
+
assert len(accesses_1) > 0
|
85
|
+
|
86
|
+
accesses_2 = generator.compute_accesses(
|
87
|
+
interval=search_interval,
|
88
|
+
from_trajectory=ground_station_trajectory,
|
89
|
+
to_trajectory=orbit_2,
|
90
|
+
)
|
91
|
+
|
92
|
+
assert len(accesses_2) > 0
|
93
|
+
|
94
|
+
accesses_plot = display.AccessesPlot(
|
95
|
+
earth=earth,
|
96
|
+
interval=search_interval,
|
97
|
+
trajectory_step=Duration.minutes(5.0),
|
98
|
+
access_step=Duration.seconds(10.0),
|
99
|
+
ground_station_lla=ground_station_lla,
|
100
|
+
color="green",
|
101
|
+
)
|
102
|
+
|
103
|
+
accesses_plot.add_satellite(
|
104
|
+
trajectory=orbit_1,
|
105
|
+
accesses=accesses_1,
|
106
|
+
rgb=[180, 0, 0],
|
107
|
+
)
|
108
|
+
|
109
|
+
accesses_plot.add_satellite(
|
110
|
+
trajectory=orbit_2,
|
111
|
+
accesses=accesses_2,
|
112
|
+
rgb=[0, 0, 180],
|
113
|
+
)
|
114
|
+
|
115
|
+
accesses_plot.show()
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Apache License 2.0
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
from ostk.astrodynamics import EventCondition
|
6
|
+
|
7
|
+
|
8
|
+
@pytest.fixture
|
9
|
+
def name() -> str:
|
10
|
+
return "MyEvent"
|
11
|
+
|
12
|
+
|
13
|
+
@pytest.fixture
|
14
|
+
def evaluator() -> callable:
|
15
|
+
return lambda state: 0.0
|
16
|
+
|
17
|
+
|
18
|
+
@pytest.fixture
|
19
|
+
def target_value() -> float:
|
20
|
+
return 0.0
|
21
|
+
|
22
|
+
|
23
|
+
@pytest.fixture
|
24
|
+
def target(target_value: float) -> EventCondition.Target:
|
25
|
+
return EventCondition.Target(target_value, EventCondition.Target.Type.Absolute)
|
26
|
+
|
27
|
+
|
28
|
+
@pytest.fixture
|
29
|
+
def event_condition(
|
30
|
+
name: str, evaluator: callable, target: EventCondition.Target
|
31
|
+
) -> EventCondition:
|
32
|
+
class MyEventCondition(EventCondition):
|
33
|
+
def is_satisfied(
|
34
|
+
self,
|
35
|
+
current_state_vector,
|
36
|
+
current_time,
|
37
|
+
previous_state_vector,
|
38
|
+
previous_time,
|
39
|
+
):
|
40
|
+
return current_state_vector[0] > 0.0 and previous_state_vector[0] < 0.0
|
41
|
+
|
42
|
+
return MyEventCondition(name, evaluator, target)
|
43
|
+
|
44
|
+
|
45
|
+
class TestEventCondition:
|
46
|
+
def test_subclass(self, event_condition: EventCondition):
|
47
|
+
assert event_condition is not None
|
48
|
+
|
49
|
+
def test_get_name(self, event_condition: EventCondition, name: str):
|
50
|
+
assert event_condition.get_name() == name
|
51
|
+
|
52
|
+
def test_get_evaluator(self, event_condition: EventCondition):
|
53
|
+
assert event_condition.get_evaluator() is not None
|
54
|
+
|
55
|
+
def test_get_target(
|
56
|
+
self, event_condition: EventCondition, target: EventCondition.Target
|
57
|
+
):
|
58
|
+
assert event_condition.get_target() == target
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Apache License 2.0
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
|
6
|
+
class TestImport:
|
7
|
+
def test_import(self):
|
8
|
+
from ostk.astrodynamics import Trajectory
|
9
|
+
from ostk.astrodynamics.trajectory import State
|
10
|
+
from ostk.astrodynamics.trajectory import Orbit
|
11
|
+
from ostk.astrodynamics.trajectory import Model
|
12
|
+
from ostk.astrodynamics.trajectory.orbit import Pass
|
13
|
+
from ostk.astrodynamics.trajectory.orbit.model import Kepler
|
14
|
+
from ostk.astrodynamics.trajectory.orbit.model.kepler import COE
|
15
|
+
from ostk.astrodynamics.trajectory.orbit.model import SGP4
|
16
|
+
from ostk.astrodynamics.trajectory.orbit.model.sgp4 import TLE
|
17
|
+
from ostk.astrodynamics.trajectory.orbit.model import Propagated
|
18
|
+
from ostk.astrodynamics.flight import Profile
|
19
|
+
from ostk.astrodynamics.flight import System
|
20
|
+
from ostk.astrodynamics.flight import Maneuver
|
21
|
+
from ostk.astrodynamics.flight.system import SatelliteSystem
|
22
|
+
from ostk.astrodynamics.dynamics import CentralBodyGravity
|
23
|
+
from ostk.astrodynamics.dynamics import AtmosphericDrag
|
24
|
+
from ostk.astrodynamics import Access
|
25
|
+
from ostk.astrodynamics.access import Generator
|
26
|
+
from ostk.astrodynamics.trajectory.state import NumericalSolver
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Apache License 2.0
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
from ostk.astrodynamics import RootSolver
|
6
|
+
|
7
|
+
|
8
|
+
def quadratic_function(x):
|
9
|
+
return x**2 - 4
|
10
|
+
|
11
|
+
|
12
|
+
@pytest.fixture
|
13
|
+
def maximum_iteration_count() -> int:
|
14
|
+
return 100
|
15
|
+
|
16
|
+
|
17
|
+
@pytest.fixture
|
18
|
+
def tolerance() -> float:
|
19
|
+
return 1e-15
|
20
|
+
|
21
|
+
|
22
|
+
@pytest.fixture
|
23
|
+
def root_solver(maximum_iteration_count: int, tolerance: float) -> RootSolver:
|
24
|
+
return RootSolver(maximum_iteration_count, tolerance)
|
25
|
+
|
26
|
+
|
27
|
+
class TestRootSolver:
|
28
|
+
def test_constructor(self, maximum_iteration_count: int, tolerance: float):
|
29
|
+
assert (
|
30
|
+
RootSolver(
|
31
|
+
maximum_iteration_count=maximum_iteration_count, tolerance=tolerance
|
32
|
+
)
|
33
|
+
is not None
|
34
|
+
)
|
35
|
+
|
36
|
+
def test_getters(
|
37
|
+
self,
|
38
|
+
root_solver: RootSolver,
|
39
|
+
maximum_iteration_count: int,
|
40
|
+
tolerance: float,
|
41
|
+
):
|
42
|
+
assert root_solver.get_tolerance() == tolerance
|
43
|
+
assert root_solver.get_maximum_iteration_count() == maximum_iteration_count
|
44
|
+
|
45
|
+
def test_bracket_and_solve(self, root_solver):
|
46
|
+
solution = root_solver.bracket_and_solve(
|
47
|
+
function=quadratic_function,
|
48
|
+
initial_guess=1.0,
|
49
|
+
is_rising=True,
|
50
|
+
)
|
51
|
+
assert pytest.approx(solution.root, abs=1e-15) == 2.0
|
52
|
+
|
53
|
+
def test_solve(self, root_solver):
|
54
|
+
solution = root_solver.solve(
|
55
|
+
function=quadratic_function,
|
56
|
+
lower_bound=1.0,
|
57
|
+
upper_bound=3.0,
|
58
|
+
)
|
59
|
+
assert pytest.approx(solution.root, abs=1e-15) == 2.0
|
60
|
+
|
61
|
+
def test_bisection(self, root_solver):
|
62
|
+
solution = root_solver.bisection(
|
63
|
+
function=quadratic_function,
|
64
|
+
lower_bound=1.0,
|
65
|
+
upper_bound=3.0,
|
66
|
+
)
|
67
|
+
assert pytest.approx(solution.root, abs=1e-15) == 2.0
|
68
|
+
|
69
|
+
def test_default(self):
|
70
|
+
assert RootSolver.default() is not None
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Apache License 2.0
|
2
|
+
|
3
|
+
import ostk.mathematics as mathematics
|
4
|
+
|
5
|
+
import ostk.physics as physics
|
6
|
+
|
7
|
+
import ostk.astrodynamics as astrodynamics
|
8
|
+
|
9
|
+
RealInterval = mathematics.object.RealInterval
|
10
|
+
Quaternion = mathematics.geometry.d3.transformation.rotation.Quaternion
|
11
|
+
Length = physics.unit.Length
|
12
|
+
Angle = physics.unit.Angle
|
13
|
+
DateTime = physics.time.DateTime
|
14
|
+
Scale = physics.time.Scale
|
15
|
+
Duration = physics.time.Duration
|
16
|
+
Instant = physics.time.Instant
|
17
|
+
Transform = physics.coordinate.Transform
|
18
|
+
Frame = physics.coordinate.Frame
|
19
|
+
Axes = physics.coordinate.Axes
|
20
|
+
DynamicProvider = physics.coordinate.frame.provider.Dynamic
|
21
|
+
Environment = physics.Environment
|
22
|
+
Earth = physics.environment.object.celestial.Earth
|
23
|
+
Trajectory = astrodynamics.Trajectory
|
24
|
+
Profile = astrodynamics.flight.Profile
|
25
|
+
SatelliteSystem = astrodynamics.flight.system.SatelliteSystem
|
26
|
+
Orbit = astrodynamics.trajectory.Orbit
|
27
|
+
State = astrodynamics.trajectory.State
|
28
|
+
Pass = astrodynamics.trajectory.orbit.Pass
|
29
|
+
Kepler = astrodynamics.trajectory.orbit.model.Kepler
|
30
|
+
COE = astrodynamics.trajectory.orbit.model.kepler.COE
|
31
|
+
SGP4 = astrodynamics.trajectory.orbit.model.sgp4
|
32
|
+
Access = astrodynamics.Access
|
33
|
+
|
34
|
+
|
35
|
+
def test_trajectory_undefined():
|
36
|
+
trajectory: Trajectory = Trajectory.undefined()
|
37
|
+
|
38
|
+
assert trajectory is not None
|
39
|
+
assert isinstance(trajectory, Trajectory)
|
40
|
+
assert trajectory.is_defined() is False
|