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.
Files changed (151) hide show
  1. open_space_toolkit_astrodynamics-17.2.0.dist-info/METADATA +30 -0
  2. open_space_toolkit_astrodynamics-17.2.0.dist-info/RECORD +151 -0
  3. open_space_toolkit_astrodynamics-17.2.0.dist-info/WHEEL +5 -0
  4. open_space_toolkit_astrodynamics-17.2.0.dist-info/top_level.txt +1 -0
  5. open_space_toolkit_astrodynamics-17.2.0.dist-info/zip-safe +1 -0
  6. ostk/__init__.py +1 -0
  7. ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-312-x86_64-linux-gnu.so +0 -0
  8. ostk/astrodynamics/__init__.py +11 -0
  9. ostk/astrodynamics/__init__.pyi +720 -0
  10. ostk/astrodynamics/access.pyi +577 -0
  11. ostk/astrodynamics/conjunction/__init__.pyi +121 -0
  12. ostk/astrodynamics/conjunction/close_approach.pyi +89 -0
  13. ostk/astrodynamics/conjunction/message/__init__.pyi +3 -0
  14. ostk/astrodynamics/conjunction/message/ccsds.pyi +705 -0
  15. ostk/astrodynamics/converters.py +130 -0
  16. ostk/astrodynamics/converters.pyi +58 -0
  17. ostk/astrodynamics/data/__init__.pyi +3 -0
  18. ostk/astrodynamics/data/provider.pyi +22 -0
  19. ostk/astrodynamics/dataframe.py +597 -0
  20. ostk/astrodynamics/display.py +281 -0
  21. ostk/astrodynamics/dynamics.pyi +311 -0
  22. ostk/astrodynamics/eclipse.pyi +70 -0
  23. ostk/astrodynamics/estimator.pyi +268 -0
  24. ostk/astrodynamics/event_condition.pyi +910 -0
  25. ostk/astrodynamics/flight/__init__.pyi +626 -0
  26. ostk/astrodynamics/flight/profile/__init__.pyi +99 -0
  27. ostk/astrodynamics/flight/profile/model.pyi +179 -0
  28. ostk/astrodynamics/flight/system.pyi +268 -0
  29. ostk/astrodynamics/guidance_law.pyi +416 -0
  30. ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.17 +0 -0
  31. ostk/astrodynamics/pytrajectory/__init__.py +1 -0
  32. ostk/astrodynamics/pytrajectory/__init__.pyi +3 -0
  33. ostk/astrodynamics/pytrajectory/pystate.py +263 -0
  34. ostk/astrodynamics/pytrajectory/pystate.pyi +66 -0
  35. ostk/astrodynamics/solver.pyi +432 -0
  36. ostk/astrodynamics/test/__init__.py +1 -0
  37. ostk/astrodynamics/test/access/__init__.py +1 -0
  38. ostk/astrodynamics/test/access/test_generator.py +319 -0
  39. ostk/astrodynamics/test/access/test_visibility_criterion.py +201 -0
  40. ostk/astrodynamics/test/conftest.py +119 -0
  41. ostk/astrodynamics/test/conjunction/close_approach/__init__.py +0 -0
  42. ostk/astrodynamics/test/conjunction/close_approach/test_generator.py +228 -0
  43. ostk/astrodynamics/test/conjunction/message/ccsds/__init__.py +1 -0
  44. ostk/astrodynamics/test/conjunction/message/ccsds/conftest.py +325 -0
  45. ostk/astrodynamics/test/conjunction/message/ccsds/data/cdm.json +303 -0
  46. ostk/astrodynamics/test/conjunction/message/ccsds/test_cdm.py +416 -0
  47. ostk/astrodynamics/test/conjunction/test_close_approach.py +244 -0
  48. ostk/astrodynamics/test/data/provider/test_off_nadir.py +58 -0
  49. ostk/astrodynamics/test/dynamics/__init__.py +1 -0
  50. ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity.csv +565 -0
  51. ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity_Truth.csv +100 -0
  52. ostk/astrodynamics/test/dynamics/test_atmospheric_drag.py +128 -0
  53. ostk/astrodynamics/test/dynamics/test_central_body_gravity.py +58 -0
  54. ostk/astrodynamics/test/dynamics/test_dynamics.py +50 -0
  55. ostk/astrodynamics/test/dynamics/test_position_derivative.py +51 -0
  56. ostk/astrodynamics/test/dynamics/test_tabulated.py +138 -0
  57. ostk/astrodynamics/test/dynamics/test_third_body_gravity.py +67 -0
  58. ostk/astrodynamics/test/dynamics/test_thruster.py +157 -0
  59. ostk/astrodynamics/test/eclipse/__init__.py +1 -0
  60. ostk/astrodynamics/test/eclipse/test_generator.py +138 -0
  61. ostk/astrodynamics/test/estimator/test_orbit_determination_solver.py +261 -0
  62. ostk/astrodynamics/test/estimator/test_tle_solver.py +216 -0
  63. ostk/astrodynamics/test/event_condition/test_angular_condition.py +113 -0
  64. ostk/astrodynamics/test/event_condition/test_boolean_condition.py +55 -0
  65. ostk/astrodynamics/test/event_condition/test_brouwer_lyddane_mean_long_condition.py +135 -0
  66. ostk/astrodynamics/test/event_condition/test_coe_condition.py +135 -0
  67. ostk/astrodynamics/test/event_condition/test_instant_condition.py +48 -0
  68. ostk/astrodynamics/test/event_condition/test_logical_condition.py +120 -0
  69. ostk/astrodynamics/test/event_condition/test_real_condition.py +50 -0
  70. ostk/astrodynamics/test/flight/__init__.py +1 -0
  71. ostk/astrodynamics/test/flight/profile/model/test_tabulated_profile.py +115 -0
  72. ostk/astrodynamics/test/flight/system/__init__.py +1 -0
  73. ostk/astrodynamics/test/flight/system/test_propulsion_system.py +64 -0
  74. ostk/astrodynamics/test/flight/system/test_satellite_system.py +83 -0
  75. ostk/astrodynamics/test/flight/system/test_satellite_system_builder.py +71 -0
  76. ostk/astrodynamics/test/flight/test_maneuver.py +231 -0
  77. ostk/astrodynamics/test/flight/test_profile.py +293 -0
  78. ostk/astrodynamics/test/flight/test_system.py +45 -0
  79. ostk/astrodynamics/test/guidance_law/test_constant_thrust.py +177 -0
  80. ostk/astrodynamics/test/guidance_law/test_guidance_law.py +60 -0
  81. ostk/astrodynamics/test/guidance_law/test_heterogeneous_guidance_law.py +164 -0
  82. ostk/astrodynamics/test/guidance_law/test_qlaw.py +209 -0
  83. ostk/astrodynamics/test/solvers/__init__.py +1 -0
  84. ostk/astrodynamics/test/solvers/test_finite_difference_solver.py +196 -0
  85. ostk/astrodynamics/test/solvers/test_least_squares_solver.py +334 -0
  86. ostk/astrodynamics/test/solvers/test_temporal_condition_solver.py +161 -0
  87. ostk/astrodynamics/test/test_access.py +128 -0
  88. ostk/astrodynamics/test/test_converters.py +290 -0
  89. ostk/astrodynamics/test/test_dataframe.py +1355 -0
  90. ostk/astrodynamics/test/test_display.py +184 -0
  91. ostk/astrodynamics/test/test_event_condition.py +80 -0
  92. ostk/astrodynamics/test/test_import.py +26 -0
  93. ostk/astrodynamics/test/test_root_solver.py +70 -0
  94. ostk/astrodynamics/test/test_trajectory.py +126 -0
  95. ostk/astrodynamics/test/test_utilities.py +338 -0
  96. ostk/astrodynamics/test/test_viewer.py +318 -0
  97. ostk/astrodynamics/test/trajectory/__init__.py +1 -0
  98. ostk/astrodynamics/test/trajectory/model/test_nadir_trajectory.py +87 -0
  99. ostk/astrodynamics/test/trajectory/model/test_tabulated_trajectory.py +303 -0
  100. ostk/astrodynamics/test/trajectory/model/test_target_scan_trajectory.py +126 -0
  101. ostk/astrodynamics/test/trajectory/orbit/__init__.py +1 -0
  102. ostk/astrodynamics/test/trajectory/orbit/message/__init__.py +1 -0
  103. ostk/astrodynamics/test/trajectory/orbit/message/spacex/__init__.py +1 -0
  104. ostk/astrodynamics/test/trajectory/orbit/message/spacex/conftest.py +18 -0
  105. ostk/astrodynamics/test/trajectory/orbit/message/spacex/data/opm_1.yaml +44 -0
  106. ostk/astrodynamics/test/trajectory/orbit/message/spacex/test_opm.py +108 -0
  107. ostk/astrodynamics/test/trajectory/orbit/models/__init__.py +1 -0
  108. ostk/astrodynamics/test/trajectory/orbit/models/kepler/__init__.py +1 -0
  109. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean.py +65 -0
  110. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_long.py +102 -0
  111. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_short.py +102 -0
  112. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py +305 -0
  113. ostk/astrodynamics/test/trajectory/orbit/models/sgp4/__init__.py +1 -0
  114. ostk/astrodynamics/test/trajectory/orbit/models/sgp4/test_tle.py +337 -0
  115. ostk/astrodynamics/test/trajectory/orbit/models/test_kepler.py +130 -0
  116. ostk/astrodynamics/test/trajectory/orbit/models/test_modified_equinoctial.py +142 -0
  117. ostk/astrodynamics/test/trajectory/orbit/models/test_propagated.py +234 -0
  118. ostk/astrodynamics/test/trajectory/orbit/models/test_sgp4.py +1 -0
  119. ostk/astrodynamics/test/trajectory/orbit/models/test_tabulated.py +380 -0
  120. ostk/astrodynamics/test/trajectory/orbit/test_model.py +1 -0
  121. ostk/astrodynamics/test/trajectory/orbit/test_pass.py +75 -0
  122. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_angular_velocity.py +30 -0
  123. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_attitude_quaternion.py +18 -0
  124. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_acceleration.py +136 -0
  125. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_position.py +107 -0
  126. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_velocity.py +115 -0
  127. ostk/astrodynamics/test/trajectory/state/test_coordinate_broker.py +84 -0
  128. ostk/astrodynamics/test/trajectory/state/test_coordinate_subset.py +58 -0
  129. ostk/astrodynamics/test/trajectory/state/test_numerical_solver.py +316 -0
  130. ostk/astrodynamics/test/trajectory/test_local_orbital_frame_direction.py +81 -0
  131. ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py +119 -0
  132. ostk/astrodynamics/test/trajectory/test_model.py +1 -0
  133. ostk/astrodynamics/test/trajectory/test_orbit.py +212 -0
  134. ostk/astrodynamics/test/trajectory/test_propagator.py +452 -0
  135. ostk/astrodynamics/test/trajectory/test_segment.py +694 -0
  136. ostk/astrodynamics/test/trajectory/test_sequence.py +550 -0
  137. ostk/astrodynamics/test/trajectory/test_state.py +629 -0
  138. ostk/astrodynamics/test/trajectory/test_state_builder.py +172 -0
  139. ostk/astrodynamics/trajectory/__init__.pyi +1982 -0
  140. ostk/astrodynamics/trajectory/model.pyi +259 -0
  141. ostk/astrodynamics/trajectory/orbit/__init__.pyi +349 -0
  142. ostk/astrodynamics/trajectory/orbit/message/__init__.pyi +3 -0
  143. ostk/astrodynamics/trajectory/orbit/message/spacex.pyi +264 -0
  144. ostk/astrodynamics/trajectory/orbit/model/__init__.pyi +648 -0
  145. ostk/astrodynamics/trajectory/orbit/model/brouwerLyddaneMean.pyi +121 -0
  146. ostk/astrodynamics/trajectory/orbit/model/kepler.pyi +709 -0
  147. ostk/astrodynamics/trajectory/orbit/model/sgp4.pyi +330 -0
  148. ostk/astrodynamics/trajectory/state/__init__.pyi +402 -0
  149. ostk/astrodynamics/trajectory/state/coordinate_subset.pyi +208 -0
  150. ostk/astrodynamics/utilities.py +396 -0
  151. ostk/astrodynamics/viewer.py +851 -0
@@ -0,0 +1,338 @@
1
+ # Apache License 2.0
2
+
3
+ from datetime import datetime
4
+
5
+ import pytest
6
+
7
+ from ostk.mathematics.curve_fitting import Interpolator
8
+
9
+ from ostk.physics import Environment
10
+ from ostk.physics.environment.object.celestial import Earth
11
+ from ostk.physics.time import Instant
12
+ from ostk.physics.time import Interval
13
+ from ostk.physics.time import DateTime
14
+ from ostk.physics.time import Scale
15
+ from ostk.physics.coordinate import Position
16
+ from ostk.physics.coordinate import Velocity
17
+ from ostk.physics.coordinate import Frame
18
+ from ostk.physics.coordinate.spherical import LLA
19
+ from ostk.physics.coordinate.spherical import AER
20
+
21
+ from ostk.astrodynamics import utilities
22
+ from ostk.astrodynamics import Trajectory
23
+ from ostk.astrodynamics.trajectory import State
24
+ from ostk.astrodynamics.trajectory import Orbit
25
+ from ostk.astrodynamics.trajectory import LocalOrbitalFrameFactory
26
+ from ostk.astrodynamics.trajectory.orbit.model import Tabulated as TabulatedOrbit
27
+
28
+
29
+ @pytest.fixture
30
+ def instant() -> Instant:
31
+ return Instant.date_time(DateTime.parse("2024-01-29T00:00:00"), Scale.UTC)
32
+
33
+
34
+ @pytest.fixture
35
+ def frame() -> Frame:
36
+ return Frame.GCRF()
37
+
38
+
39
+ @pytest.fixture
40
+ def position_1(frame: Frame) -> Position:
41
+ return Position.meters([7000000.0, 0.0, 0.0], frame)
42
+
43
+
44
+ @pytest.fixture
45
+ def velocity_1(frame: Frame) -> Velocity:
46
+ return Velocity.meters_per_second([0.0, 7500.0, 0.0], frame)
47
+
48
+
49
+ @pytest.fixture
50
+ def position_2(frame: Frame) -> Position:
51
+ return Position.meters([7000100.0, 0.0, 0.0], frame)
52
+
53
+
54
+ @pytest.fixture
55
+ def velocity_2(frame: Frame) -> Velocity:
56
+ return Velocity.meters_per_second([0.0, 7500.0, 0.0], frame)
57
+
58
+
59
+ @pytest.fixture
60
+ def state_1(
61
+ instant: Instant,
62
+ position_1: Position,
63
+ velocity_1: Velocity,
64
+ ) -> State:
65
+ return State(instant=instant, position=position_1, velocity=velocity_1)
66
+
67
+
68
+ @pytest.fixture
69
+ def state_2(
70
+ instant: Instant,
71
+ position_2: Position,
72
+ velocity_2: Velocity,
73
+ ) -> State:
74
+ return State(instant=instant, position=position_2, velocity=velocity_2)
75
+
76
+
77
+ @pytest.fixture
78
+ def candidate_states(state_1: State) -> list[State]:
79
+ return [state_1, state_1, state_1]
80
+
81
+
82
+ @pytest.fixture
83
+ def reference_states(state_2: State) -> list[State]:
84
+ return [state_2, state_2, state_2]
85
+
86
+
87
+ @pytest.fixture
88
+ def orbit(reference_states: list[State]) -> Orbit:
89
+ return Orbit(
90
+ model=TabulatedOrbit(
91
+ states=reference_states,
92
+ initial_revolution_number=1,
93
+ interpolation_type=Interpolator.Type.Linear,
94
+ ),
95
+ celestial_object=Earth.default(),
96
+ )
97
+
98
+
99
+ class TestUtility:
100
+ def test_lla_from_state(
101
+ self,
102
+ state: State,
103
+ ):
104
+ lla: LLA = utilities.lla_from_state(state)
105
+
106
+ assert lla is not None
107
+ assert isinstance(lla, LLA)
108
+ assert lla.is_defined()
109
+
110
+ def test_lla_from_position(
111
+ self,
112
+ instant: Instant,
113
+ position: Position,
114
+ ):
115
+ lla: LLA = utilities.lla_from_position(position, instant)
116
+
117
+ assert lla is not None
118
+ assert isinstance(lla, LLA)
119
+ assert lla.is_defined()
120
+
121
+ def test_position_from_lla(
122
+ self,
123
+ lla: LLA,
124
+ ):
125
+ position: Position = utilities.position_from_lla(lla)
126
+
127
+ assert position is not None
128
+ assert isinstance(position, Position)
129
+ assert position.is_defined()
130
+
131
+ def test_compute_aer(
132
+ self,
133
+ instant: Instant,
134
+ position: Position,
135
+ environment: Environment,
136
+ ):
137
+ aer: AER = utilities.compute_aer(instant, position, position, environment)
138
+
139
+ assert aer is not None
140
+ assert isinstance(aer, AER)
141
+
142
+ def test_compute_time_lla_aer_coordinates(
143
+ self,
144
+ state: State,
145
+ position: Position,
146
+ environment: Environment,
147
+ ):
148
+ time_lla_aer: tuple[datetime, float, float, float, float, float, float] = (
149
+ utilities.compute_time_lla_aer_coordinates(state, position, environment)
150
+ )
151
+
152
+ assert time_lla_aer is not None
153
+ assert len(time_lla_aer) == 7
154
+ assert isinstance(time_lla_aer[0], datetime)
155
+ for i in range(1, 7):
156
+ assert isinstance(time_lla_aer[i], float)
157
+
158
+ def test_compute_trajectory_geometry(
159
+ self,
160
+ interval: Interval,
161
+ trajectory: Trajectory,
162
+ ):
163
+ output: list[LLA] = utilities.compute_trajectory_geometry(trajectory, interval)
164
+
165
+ assert output is not None
166
+ assert len(output) == 2
167
+ assert isinstance(output[0], LLA)
168
+
169
+ def test_compute_ground_track(
170
+ self,
171
+ interval: Interval,
172
+ trajectory: Trajectory,
173
+ ):
174
+ output: list[LLA] = utilities.compute_ground_track(trajectory, interval)
175
+
176
+ assert output is not None
177
+ assert len(output) == 2
178
+ assert isinstance(output[0], LLA)
179
+ assert output[0].get_altitude().in_meters() <= 15.0
180
+
181
+ def test_convert_state(self, state: State):
182
+ output: tuple[
183
+ str, float, float, float, float, float, float, float, float, float
184
+ ] = utilities.convert_state(state)
185
+
186
+ assert output is not None
187
+ assert len(output) == 11
188
+ assert isinstance(output[0], str)
189
+ for i in range(1, 11):
190
+ assert isinstance(output[i], float)
191
+
192
+ def test_compute_residuals_identical_states(
193
+ self,
194
+ candidate_states: list[State],
195
+ ) -> None:
196
+ residuals = utilities.compute_residuals(
197
+ candidate_states=candidate_states,
198
+ reference_states=candidate_states,
199
+ )
200
+
201
+ assert len(residuals) == len(candidate_states)
202
+ for residual in residuals:
203
+ assert isinstance(residual, utilities.Residual)
204
+ assert residual.dr == pytest.approx(0.0, abs=1e-10)
205
+ assert residual.dv == pytest.approx(0.0, abs=1e-10)
206
+ assert residual.dr_x == pytest.approx(0.0, abs=1e-10)
207
+ assert residual.dr_y == pytest.approx(0.0, abs=1e-10)
208
+ assert residual.dr_z == pytest.approx(0.0, abs=1e-10)
209
+ assert residual.dv_x == pytest.approx(0.0, abs=1e-10)
210
+ assert residual.dv_y == pytest.approx(0.0, abs=1e-10)
211
+ assert residual.dv_z == pytest.approx(0.0, abs=1e-10)
212
+
213
+ def test_compute_residuals_with_local_orbital_frame_factory(
214
+ self,
215
+ candidate_states: list[State],
216
+ reference_states: list[State],
217
+ ) -> None:
218
+ residuals = utilities.compute_residuals(
219
+ candidate_states=candidate_states,
220
+ reference_states=reference_states,
221
+ local_orbital_frame_factory_or_frame=LocalOrbitalFrameFactory.VNC(
222
+ Frame.GCRF()
223
+ ),
224
+ )
225
+
226
+ assert len(residuals) == len(candidate_states)
227
+ # Expected difference: reference_states - candidate_states = 7000000 - 7000100 = -100m in cross track-direction
228
+ for residual in residuals:
229
+ assert isinstance(residual, utilities.Residual)
230
+ assert residual.dr == pytest.approx(100.0, rel=1e-6)
231
+ assert residual.dr_x == pytest.approx(0.0, rel=1e-6)
232
+ assert residual.dr_y == pytest.approx(0.0, abs=1e-10)
233
+ assert residual.dr_z == pytest.approx(-100.0, abs=1e-10)
234
+ assert residual.dv == pytest.approx(0.0, abs=1e-10)
235
+
236
+ def test_compute_residuals_for_orbit_identical_orbit_and_states(
237
+ self,
238
+ orbit: Orbit,
239
+ reference_states: list[State],
240
+ ) -> None:
241
+ result = utilities.compute_residuals_for_orbit(
242
+ candidate_orbit=orbit,
243
+ reference_states=reference_states,
244
+ )
245
+
246
+ assert len(result) == len(reference_states)
247
+ for entry in result:
248
+ assert isinstance(entry, utilities.Residual)
249
+ assert entry.timestamp is not None
250
+ assert entry.dr_x is not None
251
+ assert entry.dr_y is not None
252
+ assert entry.dr_z is not None
253
+ assert entry.dv_x is not None
254
+ assert entry.dv_y is not None
255
+ assert entry.dv_z is not None
256
+ assert isinstance(entry.timestamp, datetime)
257
+
258
+ def test_compute_residuals_for_orbit_identical_orbit_and_states_with_local_orbital_frame_factory(
259
+ self,
260
+ orbit: Orbit,
261
+ reference_states: list[State],
262
+ ) -> None:
263
+ result = utilities.compute_residuals_for_orbit(
264
+ candidate_orbit=orbit,
265
+ reference_states=reference_states,
266
+ local_orbital_frame_factory_or_frame=LocalOrbitalFrameFactory.VNC(
267
+ Frame.GCRF()
268
+ ),
269
+ )
270
+
271
+ assert len(result) == len(reference_states)
272
+ for entry in result:
273
+ assert isinstance(entry, utilities.Residual)
274
+ assert entry.timestamp is not None
275
+ assert entry.dr_x is not None
276
+ assert entry.dr_y is not None
277
+ assert entry.dr_z is not None
278
+ assert entry.dv_x is not None
279
+ assert entry.dv_y is not None
280
+ assert entry.dv_z is not None
281
+ assert isinstance(entry.timestamp, datetime)
282
+
283
+ def test_compute_residuals_for_orbits_identical_orbits(
284
+ self,
285
+ orbit: Orbit,
286
+ reference_states: list[State],
287
+ ) -> None:
288
+ result: list[utilities.Residual] = utilities.compute_residuals_for_orbits(
289
+ candidate_orbit=orbit,
290
+ reference_orbit=orbit,
291
+ instants=[state.get_instant() for state in reference_states],
292
+ )
293
+
294
+ assert len(result) == len(reference_states)
295
+ for entry in result:
296
+ assert isinstance(entry, utilities.Residual)
297
+ assert entry.timestamp is not None
298
+ assert entry.dr is not None
299
+ assert entry.dr_x is not None
300
+ assert entry.dr_y is not None
301
+ assert entry.dr_z is not None
302
+ assert entry.dv is not None
303
+ assert entry.dv_x is not None
304
+ assert entry.dv_y is not None
305
+ assert entry.dv_z is not None
306
+ assert isinstance(entry.timestamp, datetime)
307
+ assert isinstance(entry.dr, float)
308
+ assert isinstance(entry.dv, float)
309
+
310
+ def test_compute_residuals_for_orbits_with_local_orbital_frame_factory(
311
+ self,
312
+ orbit: Orbit,
313
+ reference_states: list[State],
314
+ ) -> None:
315
+ result: list[utilities.Residual] = utilities.compute_residuals_for_orbits(
316
+ candidate_orbit=orbit,
317
+ reference_orbit=orbit,
318
+ instants=[state.get_instant() for state in reference_states],
319
+ local_orbital_frame_factory_or_frame=LocalOrbitalFrameFactory.VNC(
320
+ Frame.GCRF()
321
+ ),
322
+ )
323
+
324
+ assert len(result) == len(reference_states)
325
+ for entry in result:
326
+ assert isinstance(entry, utilities.Residual)
327
+ assert entry.timestamp is not None
328
+ assert entry.dr is not None
329
+ assert entry.dr_x is not None
330
+ assert entry.dr_y is not None
331
+ assert entry.dr_z is not None
332
+ assert entry.dv is not None
333
+ assert entry.dv_x is not None
334
+ assert entry.dv_y is not None
335
+ assert entry.dv_z is not None
336
+ assert isinstance(entry.timestamp, datetime)
337
+ assert isinstance(entry.dr, float)
338
+ assert isinstance(entry.dv, float)
@@ -0,0 +1,318 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.physics import Environment
6
+ from ostk.physics.unit import Length
7
+ from ostk.physics.unit import Angle
8
+ from ostk.physics.time import Instant
9
+ from ostk.physics.time import Interval
10
+ from ostk.physics.time import Duration
11
+ from ostk.physics.time import DateTime
12
+ from ostk.physics.time import Time
13
+ from ostk.physics.time import Scale
14
+ from ostk.physics.unit import Length
15
+ from ostk.physics.coordinate import Position
16
+ from ostk.physics.coordinate import Frame
17
+
18
+ from ostk.astrodynamics.trajectory import Orbit
19
+ from ostk.astrodynamics.flight import Profile
20
+ from ostk.astrodynamics.viewer import Viewer
21
+ from ostk.astrodynamics.viewer import ConicSensor
22
+ from ostk.astrodynamics.viewer import _compute_celestial_angular_diameter_from_states
23
+
24
+
25
+ @pytest.fixture
26
+ def environment() -> Environment:
27
+ return Environment.default()
28
+
29
+
30
+ @pytest.fixture
31
+ def orbit(environment: Environment) -> Orbit:
32
+ return Orbit.sun_synchronous(
33
+ epoch=Instant.date_time(DateTime(2020, 1, 1, 0, 0, 0), Scale.UTC),
34
+ altitude=Length.kilometers(500.0),
35
+ local_time_at_descending_node=Time(14, 0, 0),
36
+ celestial_object=environment.access_celestial_object_with_name("Earth"),
37
+ )
38
+
39
+
40
+ @pytest.fixture
41
+ def orbits(environment: Environment) -> list[Orbit]:
42
+ return [
43
+ Orbit.sun_synchronous(
44
+ epoch=Instant.date_time(DateTime(2020, 1, 1, 0, 0, 0), Scale.UTC),
45
+ altitude=Length.kilometers(500.0),
46
+ local_time_at_descending_node=Time(14, 0, 0),
47
+ celestial_object=environment.access_celestial_object_with_name("Earth"),
48
+ ),
49
+ Orbit.sun_synchronous(
50
+ epoch=Instant.date_time(DateTime(2020, 1, 1, 0, 0, 0), Scale.UTC),
51
+ altitude=Length.kilometers(500.0),
52
+ local_time_at_descending_node=Time(12, 0, 0),
53
+ celestial_object=environment.access_celestial_object_with_name("Earth"),
54
+ ),
55
+ ]
56
+
57
+
58
+ @pytest.fixture
59
+ def profile(orbit: Orbit) -> Profile:
60
+ return Profile.local_orbital_frame_pointing(
61
+ orbit=orbit,
62
+ orbital_frame_type=Orbit.FrameType.VVLH,
63
+ )
64
+
65
+
66
+ @pytest.fixture
67
+ def interval() -> Interval:
68
+ return Interval.closed(
69
+ start_instant=Instant.date_time(DateTime(2020, 1, 1, 0, 0, 0), Scale.UTC),
70
+ end_instant=Instant.date_time(DateTime(2020, 1, 1, 0, 10, 0), Scale.UTC),
71
+ )
72
+
73
+
74
+ @pytest.fixture
75
+ def viewer(interval: Interval) -> Viewer:
76
+ return Viewer(
77
+ interval=interval,
78
+ zoom_to_entity=False,
79
+ track_entity=False,
80
+ )
81
+
82
+
83
+ class TestViewer:
84
+ def test_constructor_success(self, interval: Interval):
85
+ viewer = Viewer(
86
+ interval=interval,
87
+ )
88
+
89
+ assert viewer is not None
90
+ assert viewer.interval == interval
91
+
92
+ rendered_html: str = viewer.render()
93
+
94
+ assert rendered_html.startswith('<meta charset="utf-8">')
95
+ assert "var widget = new Cesium.Viewer" in rendered_html
96
+ assert rendered_html.endswith("</script>")
97
+
98
+ def test_add_orbit_success(
99
+ self,
100
+ viewer: Viewer,
101
+ orbit: Orbit,
102
+ ):
103
+ viewer.add_orbit(
104
+ orbit=orbit,
105
+ step=Duration.seconds(5.0),
106
+ show_orbital_track=True,
107
+ )
108
+
109
+ rendered_html: str = viewer.render()
110
+
111
+ assert rendered_html.startswith('<meta charset="utf-8">')
112
+ assert "var widget = new Cesium.Viewer" in rendered_html
113
+ assert "new Cesium.SampledProperty(Cesium.Cartesian3)" in rendered_html
114
+ assert " widget.entities.add({position: widget" in rendered_html
115
+ assert "widget.entities.add({polyline:" in rendered_html
116
+ assert "billboard: {image:" in rendered_html
117
+ assert rendered_html.endswith("</script>")
118
+
119
+ def test_add_orbit_multiple_success(
120
+ self,
121
+ viewer: Viewer,
122
+ orbits: list[Orbit],
123
+ ):
124
+ for i, orbit in enumerate(orbits):
125
+ viewer.add_orbit(
126
+ orbit=orbit,
127
+ step=Duration.seconds(5.0),
128
+ show_orbital_track=True,
129
+ name=f"Satellite {i}",
130
+ )
131
+
132
+ rendered_html: str = viewer.render()
133
+
134
+ assert rendered_html.startswith('<meta charset="utf-8">')
135
+ assert "var widget = new Cesium.Viewer" in rendered_html
136
+ assert "new Cesium.SampledProperty(Cesium.Cartesian3)" in rendered_html
137
+ assert " widget.entities.add({position: widget" in rendered_html
138
+ assert "widget.entities.add({polyline:" in rendered_html
139
+ assert "billboard: {image:" in rendered_html
140
+ assert rendered_html.endswith("</script>")
141
+
142
+ def test_add_profile_success(
143
+ self,
144
+ viewer: Viewer,
145
+ profile: Profile,
146
+ ):
147
+ viewer.add_profile(
148
+ profile=profile,
149
+ step=Duration.seconds(30.0),
150
+ show_orbital_track=True,
151
+ cesium_asset_id=123,
152
+ sensors=[
153
+ ConicSensor(
154
+ name="star_tracker",
155
+ direction=(1.0, 0.0, 0.0),
156
+ half_angle=Angle.degrees(8.0),
157
+ length=Length.meters(0.1),
158
+ color="red",
159
+ ),
160
+ ],
161
+ show_xyz_axes=True,
162
+ )
163
+
164
+ rendered_html: str = viewer.render()
165
+
166
+ assert rendered_html.startswith('<meta charset="utf-8">')
167
+ assert "var widget = new Cesium.Viewer" in rendered_html
168
+ assert " widget.entities.add({position: widget" in rendered_html
169
+ assert "Cesium.IonResource.fromAssetId(123)" in rendered_html
170
+ assert "widget.entities.add({polyline:" in rendered_html
171
+ assert (
172
+ "widget.entities.add({position: widget.star_tracker_position" in rendered_html
173
+ )
174
+ assert rendered_html.endswith("</script>")
175
+
176
+ @pytest.mark.parametrize(
177
+ "celestial_body_name",
178
+ ["Earth", "Moon", "Sun"],
179
+ )
180
+ def test_add_celestial_body_direction_success(
181
+ self,
182
+ viewer: Viewer,
183
+ orbit: Orbit,
184
+ celestial_body_name: str,
185
+ environment: Environment,
186
+ ):
187
+ viewer.add_celestial_body_direction(
188
+ profile_or_trajectory=orbit,
189
+ time_step=Duration.seconds(30.0),
190
+ celestial=environment.access_celestial_object_with_name(celestial_body_name),
191
+ )
192
+
193
+ rendered_html: str = viewer.render()
194
+
195
+ assert rendered_html.startswith('<meta charset="utf-8">')
196
+ assert "var widget = new Cesium.Viewer" in rendered_html
197
+ assert " widget.entities.add({position: widget" in rendered_html
198
+ assert (
199
+ f"widget.entities.add({{position: widget.{celestial_body_name.lower()}_direction_position"
200
+ in rendered_html
201
+ )
202
+ assert rendered_html.endswith("</script>")
203
+
204
+ def test_add_ground_tracks_success(
205
+ self,
206
+ viewer: Viewer,
207
+ orbit: Orbit,
208
+ ):
209
+ viewer.add_ground_tracks(profile_or_trajectory=orbit)
210
+
211
+ rendered_html: str = viewer.render()
212
+
213
+ assert rendered_html.startswith('<meta charset="utf-8">')
214
+ assert "var widget = new Cesium.Viewer" in rendered_html
215
+ assert "widget.entities.add({polyline:" in rendered_html
216
+ assert rendered_html.endswith("</script>")
217
+
218
+ def test_add_target_success(
219
+ self,
220
+ viewer: Viewer,
221
+ ):
222
+ viewer.add_target(
223
+ position=Position.meters([1.0, 2.0, 3.0], Frame.ITRF()),
224
+ size=123,
225
+ color="red",
226
+ )
227
+
228
+ rendered_html: str = viewer.render()
229
+
230
+ assert rendered_html.startswith('<meta charset="utf-8">')
231
+ assert "var widget = new Cesium.Viewer" in rendered_html
232
+ assert (
233
+ "widget.entities.add({position: Cesium.Cartesian3.fromDegrees(63.43494882292201, 18.22447811510915, -6376045.535225509), point: {pixelSize: 123.0, color: Cesium.Color.RED}});"
234
+ in rendered_html
235
+ )
236
+ assert rendered_html.endswith("</script>")
237
+
238
+ def test_add_target_with_label_success(
239
+ self,
240
+ viewer: Viewer,
241
+ ):
242
+ viewer.add_target(
243
+ position=Position.meters([1.0, 2.0, 3.0], Frame.ITRF()),
244
+ size=123,
245
+ color="red",
246
+ label="TEST",
247
+ )
248
+
249
+ rendered_html: str = viewer.render()
250
+
251
+ assert rendered_html.startswith('<meta charset="utf-8">')
252
+ assert "var widget = new Cesium.Viewer" in rendered_html
253
+ assert (
254
+ "widget.entities.add({position: Cesium.Cartesian3.fromDegrees(63.43494882292201, 18.22447811510915, -6376045.535225509), point: {pixelSize: 123.0, color: Cesium.Color.RED}});"
255
+ in rendered_html
256
+ )
257
+ assert (
258
+ 'widget.entities.add({position: Cesium.Cartesian3.fromDegrees(63.43494882292201, 18.22447811510915, -6376045.535225509), label: {text: "TEST", fillColor: Cesium.Color.RED, scale: 123.0}});'
259
+ in rendered_html
260
+ )
261
+ assert rendered_html.endswith("</script>")
262
+
263
+ def test_add_line_success(
264
+ self,
265
+ viewer: Viewer,
266
+ ):
267
+ viewer.add_line(
268
+ positions=[
269
+ Position.meters([1.0, 2.0, 3.0], Frame.ITRF()),
270
+ Position.meters([4.0, 5.0, 6.0], Frame.ITRF()),
271
+ ],
272
+ size=10.0,
273
+ color="red",
274
+ )
275
+
276
+ rendered_html: str = viewer.render()
277
+
278
+ assert rendered_html.startswith('<meta charset="utf-8">')
279
+ assert "var widget = new Cesium.Viewer" in rendered_html
280
+ assert (
281
+ "widget.entities.add({polyline: {positions: Cesium.Cartesian3.fromDegreesArrayHeights([63.43494882292201, 18.22447811510915, 10.0, 51.34019174590991, 10.165199393640696, 10.0]), width: 10.0, material: Cesium.Color.RED}});"
282
+ in rendered_html
283
+ )
284
+ assert rendered_html.endswith("</script>")
285
+
286
+ def test_add_label_success(
287
+ self,
288
+ viewer: Viewer,
289
+ ):
290
+ viewer.add_label(
291
+ position=Position.meters([6671000.0, 0.0, 0.0], Frame.ITRF()),
292
+ text="Hello, World!",
293
+ size=1.0,
294
+ color="red",
295
+ )
296
+
297
+ rendered_html: str = viewer.render()
298
+
299
+ assert rendered_html.startswith('<meta charset="utf-8">')
300
+ assert "var widget = new Cesium.Viewer" in rendered_html
301
+ assert (
302
+ 'widget.entities.add({position: Cesium.Cartesian3.fromDegrees(0.0, 0.0, 292863.0000000001), label: {text: "Hello, World!", fillColor: Cesium.Color.RED, scale: 1.0}});'
303
+ in rendered_html
304
+ )
305
+ assert rendered_html.endswith("</script>")
306
+
307
+
308
+ def test_compute_celestial_angular_diameter_from_states_success(
309
+ orbit: Orbit,
310
+ interval: Interval,
311
+ environment: Environment,
312
+ ) -> None:
313
+ assert _compute_celestial_angular_diameter_from_states(
314
+ celestial=environment.access_celestial_object_with_name("Sun"),
315
+ states=orbit.get_states_at(
316
+ interval.generate_grid(Duration.seconds(30.0)),
317
+ ),
318
+ ).mean() == pytest.approx(0.54, rel=1e-2)
@@ -0,0 +1 @@
1
+ # Apache License 2.0