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.
Files changed (85) hide show
  1. {open_space_toolkit_astrodynamics-5.1.5.dist-info → open_space_toolkit_astrodynamics-5.2.0.dist-info}/METADATA +1 -1
  2. open_space_toolkit_astrodynamics-5.2.0.dist-info/RECORD +96 -0
  3. ostk/__init__.py +1 -0
  4. ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-38-x86_64-linux-gnu.so +0 -0
  5. ostk/astrodynamics/converters.py +44 -6
  6. ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.5 +0 -0
  7. ostk/astrodynamics/pytrajectory/pystate.py +1 -3
  8. ostk/astrodynamics/test/access/__init__.py +1 -0
  9. ostk/astrodynamics/test/access/test_generator.py +248 -0
  10. ostk/astrodynamics/test/conjunction/messages/ccsds/__init__.py +1 -0
  11. ostk/astrodynamics/test/conjunction/messages/ccsds/conftest.py +325 -0
  12. ostk/astrodynamics/test/conjunction/messages/ccsds/data/cdm.json +303 -0
  13. ostk/astrodynamics/test/conjunction/messages/ccsds/test_cdm.py +416 -0
  14. ostk/astrodynamics/test/dynamics/__init__.py +1 -0
  15. ostk/astrodynamics/test/dynamics/test_atmospheric_drag.py +128 -0
  16. ostk/astrodynamics/test/dynamics/test_central_body_gravity.py +58 -0
  17. ostk/astrodynamics/test/dynamics/test_dynamics.py +50 -0
  18. ostk/astrodynamics/test/dynamics/test_position_derivative.py +51 -0
  19. ostk/astrodynamics/test/dynamics/test_third_body_gravity.py +67 -0
  20. ostk/astrodynamics/test/dynamics/test_thruster.py +142 -0
  21. ostk/astrodynamics/test/event_condition/test_angular_condition.py +113 -0
  22. ostk/astrodynamics/test/event_condition/test_boolean_condition.py +55 -0
  23. ostk/astrodynamics/test/event_condition/test_coe_condition.py +87 -0
  24. ostk/astrodynamics/test/event_condition/test_instant_condition.py +48 -0
  25. ostk/astrodynamics/test/event_condition/test_logical_condition.py +120 -0
  26. ostk/astrodynamics/test/event_condition/test_real_condition.py +50 -0
  27. ostk/astrodynamics/test/flight/__init__.py +1 -0
  28. ostk/astrodynamics/test/flight/profile/__init__.py +1 -0
  29. ostk/astrodynamics/test/flight/profile/test_state.py +144 -0
  30. ostk/astrodynamics/test/flight/system/__init__.py +1 -0
  31. ostk/astrodynamics/test/flight/system/test_propulsion_system.py +46 -0
  32. ostk/astrodynamics/test/flight/system/test_satellite_system.py +91 -0
  33. ostk/astrodynamics/test/flight/system/test_satellite_system_builder.py +71 -0
  34. ostk/astrodynamics/test/flight/test_profile.py +153 -0
  35. ostk/astrodynamics/test/flight/test_system.py +55 -0
  36. ostk/astrodynamics/test/guidance_law/test_constant_thrust.py +91 -0
  37. ostk/astrodynamics/test/guidance_law/test_qlaw.py +139 -0
  38. ostk/astrodynamics/test/solvers/__init__.py +1 -0
  39. ostk/astrodynamics/test/solvers/test_finite_difference_solver.py +181 -0
  40. ostk/astrodynamics/test/solvers/test_temporal_condition_solver.py +153 -0
  41. ostk/astrodynamics/test/test_access.py +2 -6
  42. ostk/astrodynamics/test/test_converters.py +213 -6
  43. ostk/astrodynamics/test/test_viewer.py +1 -2
  44. ostk/astrodynamics/test/trajectory/__init__.py +1 -0
  45. ostk/astrodynamics/test/trajectory/orbit/__init__.py +1 -0
  46. ostk/astrodynamics/test/trajectory/orbit/messages/__init__.py +1 -0
  47. ostk/astrodynamics/test/trajectory/orbit/messages/spacex/__init__.py +1 -0
  48. ostk/astrodynamics/test/trajectory/orbit/messages/spacex/conftest.py +18 -0
  49. ostk/astrodynamics/test/trajectory/orbit/messages/spacex/data/opm_1.yaml +44 -0
  50. ostk/astrodynamics/test/trajectory/orbit/messages/spacex/test_opm.py +108 -0
  51. ostk/astrodynamics/test/trajectory/orbit/models/__init__.py +1 -0
  52. ostk/astrodynamics/test/trajectory/orbit/models/kepler/__init__.py +1 -0
  53. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean.py +65 -0
  54. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_long.py +102 -0
  55. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_short.py +102 -0
  56. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py +167 -0
  57. ostk/astrodynamics/test/trajectory/orbit/models/sgp4/__init__.py +1 -0
  58. ostk/astrodynamics/test/trajectory/orbit/models/sgp4/test_tle.py +331 -0
  59. ostk/astrodynamics/test/trajectory/orbit/models/test_kepler.py +130 -0
  60. ostk/astrodynamics/test/trajectory/orbit/models/test_propagated.py +195 -0
  61. ostk/astrodynamics/test/trajectory/orbit/models/test_sgp4.py +1 -0
  62. ostk/astrodynamics/test/trajectory/orbit/models/test_tabulated.py +380 -0
  63. ostk/astrodynamics/test/trajectory/orbit/test_model.py +1 -0
  64. ostk/astrodynamics/test/trajectory/orbit/test_pass.py +55 -0
  65. ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_angular_velocity.py +30 -0
  66. ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_attitude_quaternion.py +18 -0
  67. ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_cartesian_position.py +107 -0
  68. ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_cartesian_velocity.py +115 -0
  69. ostk/astrodynamics/test/trajectory/state/test_coordinates_broker.py +84 -0
  70. ostk/astrodynamics/test/trajectory/state/test_coordinates_subset.py +43 -0
  71. ostk/astrodynamics/test/trajectory/state/test_numerical_solver.py +314 -0
  72. ostk/astrodynamics/test/trajectory/test_local_orbital_frame_direction.py +81 -0
  73. ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py +64 -0
  74. ostk/astrodynamics/test/trajectory/test_model.py +1 -0
  75. ostk/astrodynamics/test/trajectory/test_orbit.py +92 -0
  76. ostk/astrodynamics/test/trajectory/test_propagator.py +402 -0
  77. ostk/astrodynamics/test/trajectory/test_segment.py +288 -0
  78. ostk/astrodynamics/test/trajectory/test_sequence.py +459 -0
  79. ostk/astrodynamics/test/trajectory/test_state.py +223 -0
  80. ostk/astrodynamics/test/trajectory/test_state_builder.py +171 -0
  81. ostk/astrodynamics/viewer.py +1 -3
  82. open_space_toolkit_astrodynamics-5.1.5.dist-info/RECORD +0 -25
  83. {open_space_toolkit_astrodynamics-5.1.5.dist-info → open_space_toolkit_astrodynamics-5.2.0.dist-info}/WHEEL +0 -0
  84. {open_space_toolkit_astrodynamics-5.1.5.dist-info → open_space_toolkit_astrodynamics-5.2.0.dist-info}/top_level.txt +0 -0
  85. {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,459 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ import numpy as np
6
+
7
+ from ostk.mathematics.geometry.d3.objects import Composite
8
+ from ostk.mathematics.geometry.d3.objects import Cuboid
9
+ from ostk.mathematics.geometry.d3.objects import Point
10
+
11
+ from ostk.physics import Environment
12
+ from ostk.physics.coordinate import Frame
13
+ from ostk.physics.environment.atmospheric import Earth as EarthAtmosphericModel
14
+ from ostk.physics.environment.gravitational import Earth as EarthGravitationalModel
15
+ from ostk.physics.environment.magnetic import Earth as EarthMagneticModel
16
+ from ostk.physics.environment.objects.celestial_bodies import Earth
17
+ from ostk.physics.time import DateTime
18
+ from ostk.physics.time import Duration
19
+ from ostk.physics.time import Instant
20
+ from ostk.physics.time import Scale
21
+ from ostk.physics.units import Derived
22
+ from ostk.physics.units import Length
23
+ from ostk.physics.units import Mass
24
+
25
+ from ostk.astrodynamics.event_condition import COECondition
26
+ from ostk.astrodynamics.event_condition import InstantCondition
27
+ from ostk.astrodynamics.event_condition import RealCondition
28
+ from ostk.astrodynamics import Dynamics
29
+ from ostk.astrodynamics import EventCondition
30
+ from ostk.astrodynamics.dynamics import Thruster
31
+ from ostk.astrodynamics.guidance_law import ConstantThrust
32
+ from ostk.astrodynamics.flight.system import PropulsionSystem
33
+ from ostk.astrodynamics.flight.system import SatelliteSystem
34
+ from ostk.astrodynamics.trajectory import LocalOrbitalFrameDirection
35
+ from ostk.astrodynamics.trajectory import LocalOrbitalFrameFactory
36
+ from ostk.astrodynamics.trajectory import Segment
37
+ from ostk.astrodynamics.trajectory import Sequence
38
+ from ostk.astrodynamics.trajectory import State
39
+ from ostk.astrodynamics.trajectory.state import CoordinatesBroker
40
+ from ostk.astrodynamics.trajectory.state import CoordinatesSubset
41
+ from ostk.astrodynamics.trajectory.state import NumericalSolver
42
+ from ostk.astrodynamics.trajectory.state.coordinates_subset import CartesianPosition
43
+ from ostk.astrodynamics.trajectory.state.coordinates_subset import CartesianVelocity
44
+
45
+
46
+ @pytest.fixture
47
+ def propulsion_system() -> PropulsionSystem:
48
+ return PropulsionSystem(
49
+ 1.0,
50
+ 1500.0,
51
+ )
52
+
53
+
54
+ @pytest.fixture
55
+ def dry_mass() -> Mass:
56
+ return Mass.kilograms(100.0)
57
+
58
+
59
+ @pytest.fixture
60
+ def wet_mass() -> Mass:
61
+ return Mass.kilograms(10.0)
62
+
63
+
64
+ @pytest.fixture
65
+ def cross_sectional_surface_area() -> float:
66
+ return 1.0
67
+
68
+
69
+ @pytest.fixture
70
+ def drag_coefficient() -> float:
71
+ return 2.2
72
+
73
+
74
+ @pytest.fixture
75
+ def satellite_system(
76
+ dry_mass: Mass,
77
+ cross_sectional_surface_area: float,
78
+ drag_coefficient: float,
79
+ propulsion_system: PropulsionSystem,
80
+ ) -> SatelliteSystem:
81
+ satellite_geometry = Composite(
82
+ Cuboid(
83
+ Point(0.0, 0.0, 0.0),
84
+ [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
85
+ [1.0, 0.0, 0.0],
86
+ )
87
+ )
88
+ inertia_tensor = np.ndarray(shape=(3, 3))
89
+
90
+ return SatelliteSystem(
91
+ dry_mass,
92
+ satellite_geometry,
93
+ inertia_tensor,
94
+ cross_sectional_surface_area,
95
+ drag_coefficient,
96
+ propulsion_system,
97
+ )
98
+
99
+
100
+ @pytest.fixture
101
+ def environment() -> Environment:
102
+ return Environment(
103
+ Instant.J2000(),
104
+ [
105
+ Earth.from_models(
106
+ EarthGravitationalModel(EarthGravitationalModel.Type.Spherical),
107
+ EarthMagneticModel(EarthMagneticModel.Type.Undefined),
108
+ EarthAtmosphericModel(EarthAtmosphericModel.Type.Exponential),
109
+ )
110
+ ],
111
+ )
112
+
113
+
114
+ @pytest.fixture
115
+ def coordinates_broker() -> CoordinatesBroker:
116
+ return CoordinatesBroker(
117
+ [
118
+ CartesianPosition.default(),
119
+ CartesianVelocity.default(),
120
+ CoordinatesSubset.mass(),
121
+ CoordinatesSubset.surface_area(),
122
+ CoordinatesSubset.drag_coefficient(),
123
+ ]
124
+ )
125
+
126
+
127
+ @pytest.fixture
128
+ def cartesian_coordinates() -> list[float]:
129
+ return [
130
+ 717094.039086306,
131
+ -6872433.2241124,
132
+ 46175.9696673281,
133
+ -970.650826004612,
134
+ -45.4598114773158,
135
+ 7529.82424886455,
136
+ ]
137
+
138
+
139
+ @pytest.fixture
140
+ def state(
141
+ cartesian_coordinates: list[float],
142
+ dry_mass: Mass,
143
+ wet_mass: Mass,
144
+ cross_sectional_surface_area: float,
145
+ drag_coefficient: float,
146
+ coordinates_broker: CoordinatesBroker,
147
+ ) -> State:
148
+ frame: Frame = Frame.GCRF()
149
+ instant: Instant = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
150
+ coordinates = [
151
+ *cartesian_coordinates,
152
+ dry_mass.in_kilograms() + wet_mass.in_kilograms(),
153
+ cross_sectional_surface_area,
154
+ drag_coefficient,
155
+ ]
156
+
157
+ return State(
158
+ instant,
159
+ [
160
+ 717094.039086306,
161
+ -6872433.2241124,
162
+ 46175.9696673281,
163
+ -970.650826004612,
164
+ -45.4598114773158,
165
+ 7529.82424886455,
166
+ dry_mass.in_kilograms() + wet_mass.in_kilograms(),
167
+ cross_sectional_surface_area,
168
+ drag_coefficient,
169
+ ],
170
+ frame,
171
+ coordinates_broker,
172
+ )
173
+
174
+
175
+ @pytest.fixture
176
+ def dynamics(environment: Environment) -> list:
177
+ return Dynamics.from_environment(environment)
178
+
179
+
180
+ @pytest.fixture
181
+ def numerical_solver() -> NumericalSolver:
182
+ return NumericalSolver.default_conditional()
183
+
184
+
185
+ @pytest.fixture
186
+ def duration() -> Duration:
187
+ return Duration.minutes(5.0)
188
+
189
+
190
+ @pytest.fixture
191
+ def instant_condition(state: State, duration: Duration) -> InstantCondition:
192
+ return InstantCondition(
193
+ RealCondition.Criterion.AnyCrossing, state.get_instant() + duration
194
+ )
195
+
196
+
197
+ @pytest.fixture
198
+ def sma() -> Length:
199
+ return Length.kilometers(6907.000)
200
+
201
+
202
+ @pytest.fixture
203
+ def gravitational_parameter() -> Derived:
204
+ return EarthGravitationalModel.spherical.gravitational_parameter
205
+
206
+
207
+ @pytest.fixture
208
+ def constant_thrust() -> ConstantThrust:
209
+ return ConstantThrust(
210
+ thrust_direction=LocalOrbitalFrameDirection(
211
+ vector=[1.0, 0.0, 0.0],
212
+ local_orbital_frame_factory=LocalOrbitalFrameFactory.VNC(Frame.GCRF()),
213
+ )
214
+ )
215
+
216
+
217
+ @pytest.fixture
218
+ def thruster_dynamics(
219
+ satellite_system: SatelliteSystem, constant_thrust: ConstantThrust
220
+ ) -> ConstantThrust:
221
+ return Thruster(
222
+ satellite_system=satellite_system,
223
+ guidance_law=constant_thrust,
224
+ )
225
+
226
+
227
+ @pytest.fixture
228
+ def sma_target(sma: Length) -> EventCondition.Target:
229
+ return EventCondition.Target(sma)
230
+
231
+
232
+ @pytest.fixture
233
+ def sma_condition(
234
+ sma_target: EventCondition.Target, gravitational_parameter: Derived
235
+ ) -> COECondition:
236
+ return COECondition.semi_major_axis(
237
+ criterion=RealCondition.Criterion.AnyCrossing,
238
+ frame=Frame.GCRF(),
239
+ semi_major_axis=sma_target,
240
+ gravitational_parameter=gravitational_parameter,
241
+ )
242
+
243
+
244
+ @pytest.fixture
245
+ def coast_duration_segment(
246
+ instant_condition: InstantCondition,
247
+ dynamics: list[Dynamics],
248
+ numerical_solver: NumericalSolver,
249
+ ):
250
+ return Segment.coast(
251
+ name="duration coast",
252
+ event_condition=instant_condition,
253
+ dynamics=dynamics,
254
+ numerical_solver=numerical_solver,
255
+ )
256
+
257
+
258
+ @pytest.fixture
259
+ def coast_sma_segment(
260
+ sma_condition: COECondition,
261
+ dynamics: list[Dynamics],
262
+ numerical_solver: NumericalSolver,
263
+ ):
264
+ return Segment.coast(
265
+ name="sma coast",
266
+ event_condition=sma_condition,
267
+ dynamics=dynamics,
268
+ numerical_solver=numerical_solver,
269
+ )
270
+
271
+
272
+ @pytest.fixture
273
+ def thrust_segment(
274
+ sma_condition: RealCondition,
275
+ thruster_dynamics: Thruster,
276
+ dynamics: list[Dynamics],
277
+ numerical_solver: NumericalSolver,
278
+ ):
279
+ return Segment.maneuver(
280
+ name="duration thrust",
281
+ event_condition=sma_condition,
282
+ thruster_dynamics=thruster_dynamics,
283
+ dynamics=dynamics,
284
+ numerical_solver=numerical_solver,
285
+ )
286
+
287
+
288
+ @pytest.fixture
289
+ def segments(
290
+ coast_duration_segment: Segment,
291
+ thrust_segment: Segment,
292
+ ) -> list[Segment]:
293
+ return [coast_duration_segment, thrust_segment]
294
+
295
+
296
+ @pytest.fixture
297
+ def maximum_propagation_duration() -> Duration:
298
+ return Duration.days(2.0)
299
+
300
+
301
+ @pytest.fixture
302
+ def repetition_count() -> int:
303
+ return 1
304
+
305
+
306
+ @pytest.fixture
307
+ def sequence(
308
+ segments: list[Segment],
309
+ numerical_solver: NumericalSolver,
310
+ dynamics: list,
311
+ maximum_propagation_duration: Duration,
312
+ ):
313
+ return Sequence(
314
+ segments=segments,
315
+ dynamics=dynamics,
316
+ numerical_solver=numerical_solver,
317
+ maximum_propagation_duration=maximum_propagation_duration,
318
+ )
319
+
320
+
321
+ @pytest.fixture
322
+ def segment_solution(
323
+ dynamics: list,
324
+ state: State,
325
+ ):
326
+ return Segment.Solution(
327
+ name="A Segment Solution",
328
+ dynamics=dynamics,
329
+ states=[
330
+ state,
331
+ ],
332
+ condition_is_satisfied=True,
333
+ segment_type=Segment.Type.Maneuver,
334
+ )
335
+
336
+
337
+ class TestSequence:
338
+ def test_get_segments(
339
+ self,
340
+ sequence: Sequence,
341
+ segments: list[Segment],
342
+ ):
343
+ assert len(sequence.get_segments()) == len(segments)
344
+
345
+ def test_get_numerical_solver(
346
+ self,
347
+ sequence: Sequence,
348
+ numerical_solver: NumericalSolver,
349
+ ):
350
+ assert sequence.get_numerical_solver() == numerical_solver
351
+
352
+ def test_get_dynamics(
353
+ self,
354
+ sequence: Sequence,
355
+ dynamics: list,
356
+ ):
357
+ assert len(sequence.get_dynamics()) == len(dynamics)
358
+
359
+ def test_get_maximum_propagation_duration(
360
+ self,
361
+ sequence: Sequence,
362
+ maximum_propagation_duration: Duration,
363
+ ):
364
+ assert sequence.get_maximum_propagation_duration() == maximum_propagation_duration
365
+
366
+ def test_add_segment(
367
+ self,
368
+ sequence: Sequence,
369
+ coast_duration_segment: Segment,
370
+ ):
371
+ segments_count: int = len(sequence.get_segments())
372
+
373
+ sequence.add_segment(coast_duration_segment)
374
+
375
+ assert len(sequence.get_segments()) == segments_count + 1
376
+
377
+ segments_count = len(sequence.get_segments())
378
+
379
+ sequence.add_segments([coast_duration_segment, coast_duration_segment])
380
+
381
+ assert len(sequence.get_segments()) == segments_count + 2
382
+
383
+ def test_add_coast_segment(
384
+ self,
385
+ sequence: Sequence,
386
+ instant_condition: InstantCondition,
387
+ ):
388
+ segments_count: int = len(sequence.get_segments())
389
+
390
+ sequence.add_coast_segment(instant_condition)
391
+
392
+ assert len(sequence.get_segments()) == segments_count + 1
393
+
394
+ def test_add_maneuver_segment(
395
+ self,
396
+ sequence: Sequence,
397
+ instant_condition: InstantCondition,
398
+ thruster_dynamics: Thruster,
399
+ ):
400
+ segments_count: int = len(sequence.get_segments())
401
+
402
+ sequence.add_maneuver_segment(instant_condition, thruster_dynamics)
403
+
404
+ assert len(sequence.get_segments()) == segments_count + 1
405
+
406
+ def test_create_sequence_solution(
407
+ self,
408
+ segment_solution: Segment.Solution,
409
+ ):
410
+ solution: Sequence.Solution = Sequence.Solution(
411
+ segment_solutions=[
412
+ segment_solution,
413
+ ],
414
+ execution_is_complete=True,
415
+ )
416
+
417
+ assert solution is not None
418
+ assert len(solution.segment_solutions) == 1
419
+ assert solution.execution_is_complete
420
+
421
+ def test_solve(
422
+ self,
423
+ state: State,
424
+ repetition_count: int,
425
+ sequence: Sequence,
426
+ segments: list[Segment],
427
+ ):
428
+ solution = sequence.solve(state, repetition_count)
429
+
430
+ assert len(solution.segment_solutions) == len(segments)
431
+
432
+ assert solution.execution_is_complete
433
+
434
+ assert solution.access_start_instant() is not None
435
+ assert solution.access_end_instant() is not None
436
+
437
+ assert solution.get_states() is not None
438
+ assert solution.get_initial_mass() is not None
439
+ assert solution.get_final_mass() is not None
440
+ assert solution.get_propagation_duration() is not None
441
+
442
+ assert solution.compute_delta_mass() is not None
443
+ assert solution.compute_delta_v(1500.0) is not None
444
+
445
+ def test_solve_to_condition(
446
+ self,
447
+ state: State,
448
+ sequence: Sequence,
449
+ instant_condition: InstantCondition,
450
+ ):
451
+ assert sequence.solve_to_condition(state, instant_condition) is not None
452
+ assert (
453
+ sequence.solve_to_condition(
454
+ state=state,
455
+ event_condition=instant_condition,
456
+ maximum_propagation_duration_limit=Duration.hours(1.0),
457
+ )
458
+ is not None
459
+ )
@@ -0,0 +1,223 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ import numpy as np
6
+
7
+ from ostk.mathematics.geometry.d3.transformation.rotation import Quaternion
8
+
9
+ from ostk.physics.time import Instant
10
+ from ostk.physics.time import DateTime
11
+ from ostk.physics.time import Scale
12
+ from ostk.physics.coordinate import Position
13
+ from ostk.physics.coordinate import Velocity
14
+ from ostk.physics.coordinate import Frame
15
+
16
+ from ostk.astrodynamics.trajectory import State
17
+ from ostk.astrodynamics.trajectory.state import CoordinatesBroker
18
+ from ostk.astrodynamics.trajectory.state.coordinates_subset import (
19
+ CartesianPosition,
20
+ CartesianVelocity,
21
+ )
22
+
23
+
24
+ @pytest.fixture()
25
+ def instant() -> Instant:
26
+ return Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
27
+
28
+
29
+ @pytest.fixture
30
+ def frame() -> Frame:
31
+ return Frame.GCRF()
32
+
33
+
34
+ @pytest.fixture()
35
+ def position(frame: Frame) -> Position:
36
+ return Position.meters([6371000.0, 0.0, 0.0], frame)
37
+
38
+
39
+ @pytest.fixture()
40
+ def velocity(frame: Frame) -> Velocity:
41
+ return Velocity.meters_per_second([7600.0, 0.0, 0.0], frame)
42
+
43
+
44
+ @pytest.fixture()
45
+ def attitude() -> Quaternion:
46
+ return Quaternion([0.0, 0.0, 0.0, 1.0], Quaternion.Format.XYZS)
47
+
48
+
49
+ @pytest.fixture()
50
+ def angular_velocity() -> np.ndarray:
51
+ return np.array([-1.0, -2.0, -3.0])
52
+
53
+
54
+ @pytest.fixture
55
+ def state(
56
+ instant: Instant, position: Position, velocity: Velocity, frame: Frame
57
+ ) -> State:
58
+ return State(instant, position, velocity)
59
+
60
+
61
+ @pytest.fixture
62
+ def coordinates_broker() -> CoordinatesBroker:
63
+ return CoordinatesBroker([CartesianPosition.default(), CartesianVelocity.default()])
64
+
65
+
66
+ class TestState:
67
+ def test_constructor_position_velocity(
68
+ self,
69
+ instant: Instant,
70
+ position: Position,
71
+ velocity: Velocity,
72
+ ):
73
+ state = State(instant, position, velocity)
74
+ assert state is not None
75
+ assert isinstance(state, State)
76
+ assert state.is_defined()
77
+
78
+ def test_constructor_position_velocity_attitude_angular_velocity(
79
+ self,
80
+ instant: Instant,
81
+ frame: Frame,
82
+ position: Position,
83
+ velocity: Velocity,
84
+ attitude: Quaternion,
85
+ angular_velocity: np.ndarray,
86
+ ):
87
+ state = State(instant, position, velocity, attitude, angular_velocity, frame)
88
+ assert state is not None
89
+ assert isinstance(state, State)
90
+ assert state.is_defined()
91
+
92
+ def test_explicit_constructor(
93
+ self,
94
+ instant: Instant,
95
+ position: Position,
96
+ velocity: Velocity,
97
+ frame: Frame,
98
+ coordinates_broker: CoordinatesBroker,
99
+ ):
100
+ state = State(instant, position, velocity)
101
+ assert state is not None
102
+ assert isinstance(state, State)
103
+ assert state.is_defined()
104
+
105
+ state = State(
106
+ instant,
107
+ np.append(position.get_coordinates(), velocity.get_coordinates()),
108
+ frame,
109
+ coordinates_broker,
110
+ )
111
+
112
+ assert state is not None
113
+ assert isinstance(state, State)
114
+ assert state.is_defined()
115
+
116
+ def test_subsets_constructor(
117
+ self,
118
+ instant: Instant,
119
+ position: Position,
120
+ velocity: Velocity,
121
+ frame: Frame,
122
+ ):
123
+ state = State(
124
+ instant,
125
+ np.append(position.get_coordinates(), velocity.get_coordinates()),
126
+ frame,
127
+ [CartesianPosition.default(), CartesianVelocity.default()],
128
+ )
129
+
130
+ assert state is not None
131
+ assert isinstance(state, State)
132
+ assert state.is_defined()
133
+
134
+ def test_custom_state_class_generator(
135
+ self,
136
+ instant: Instant,
137
+ position: Position,
138
+ velocity: Velocity,
139
+ frame: Frame,
140
+ ):
141
+ state = State(
142
+ instant,
143
+ np.append(position.get_coordinates(), velocity.get_coordinates()),
144
+ frame,
145
+ [CartesianPosition.default(), CartesianVelocity.default()],
146
+ )
147
+
148
+ MySuperFunState: type = State.template(
149
+ frame,
150
+ [CartesianPosition.default(), CartesianVelocity.default()],
151
+ )
152
+
153
+ custom_state: MySuperFunState = MySuperFunState(
154
+ instant,
155
+ np.append(position.get_coordinates(), velocity.get_coordinates()),
156
+ )
157
+
158
+ assert custom_state is not None
159
+ assert isinstance(custom_state, MySuperFunState)
160
+ assert isinstance(state, State)
161
+ assert custom_state.is_defined()
162
+
163
+ assert custom_state == state
164
+ assert custom_state is not state
165
+
166
+ def test_comparators(self, state: State):
167
+ assert (state == state) is True
168
+ assert (state != state) is False
169
+
170
+ def test_operators(self, state: State):
171
+ assert isinstance(state + state, State)
172
+ assert isinstance(state - state, State)
173
+
174
+ def test_getters(
175
+ self,
176
+ state: State,
177
+ instant: Instant,
178
+ position: Position,
179
+ velocity: Velocity,
180
+ frame: Frame,
181
+ coordinates_broker: CoordinatesBroker,
182
+ ):
183
+ assert state.get_instant() == instant
184
+ assert state.get_position() == position
185
+ assert state.get_velocity() == velocity
186
+ assert state.has_subset(CartesianPosition.default())
187
+ assert state.has_subset(CartesianVelocity.default())
188
+ assert state.get_frame() == frame
189
+ assert (
190
+ state.get_coordinates()
191
+ == np.append(position.get_coordinates(), velocity.get_coordinates())
192
+ ).all()
193
+ assert state.get_coordinates_subsets() == coordinates_broker.get_subsets()
194
+
195
+ def test_in_frame(
196
+ self,
197
+ state: State,
198
+ frame: Frame,
199
+ ):
200
+ assert state.in_frame(frame) == state
201
+ assert state.in_frame(Frame.ITRF()) != state
202
+
203
+ def test_extract_coordinate(
204
+ self,
205
+ state: State,
206
+ ):
207
+ position_coordinates = state.extract_coordinate(CartesianPosition.default())
208
+ velocity_coordinates = state.extract_coordinate(CartesianVelocity.default())
209
+
210
+ assert len(position_coordinates) == 3
211
+ assert len(velocity_coordinates) == 3
212
+ assert (position_coordinates == state.get_position().get_coordinates()).all()
213
+ assert (velocity_coordinates == state.get_velocity().get_coordinates()).all()
214
+
215
+ def test_extract_coordinates(
216
+ self,
217
+ state: State,
218
+ ):
219
+ pv_coordinates = state.extract_coordinates(
220
+ [CartesianPosition.default(), CartesianVelocity.default()]
221
+ )
222
+ assert len(pv_coordinates) == 6
223
+ assert (pv_coordinates == state.get_coordinates()).all()