open-space-toolkit-astrodynamics 13.1.0__py313-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 (100) hide show
  1. open_space_toolkit_astrodynamics-13.1.0.dist-info/METADATA +30 -0
  2. open_space_toolkit_astrodynamics-13.1.0.dist-info/RECORD +100 -0
  3. open_space_toolkit_astrodynamics-13.1.0.dist-info/WHEEL +5 -0
  4. open_space_toolkit_astrodynamics-13.1.0.dist-info/top_level.txt +1 -0
  5. open_space_toolkit_astrodynamics-13.1.0.dist-info/zip-safe +1 -0
  6. ostk/__init__.py +1 -0
  7. ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-313-x86_64-linux-gnu.so +0 -0
  8. ostk/astrodynamics/__init__.py +11 -0
  9. ostk/astrodynamics/converters.py +130 -0
  10. ostk/astrodynamics/dataframe.py +479 -0
  11. ostk/astrodynamics/display.py +222 -0
  12. ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.13 +0 -0
  13. ostk/astrodynamics/pytrajectory/__init__.py +1 -0
  14. ostk/astrodynamics/pytrajectory/pystate.py +251 -0
  15. ostk/astrodynamics/test/__init__.py +1 -0
  16. ostk/astrodynamics/test/access/__init__.py +1 -0
  17. ostk/astrodynamics/test/access/test_generator.py +248 -0
  18. ostk/astrodynamics/test/conftest.py +119 -0
  19. ostk/astrodynamics/test/conjunction/message/ccsds/__init__.py +1 -0
  20. ostk/astrodynamics/test/conjunction/message/ccsds/conftest.py +325 -0
  21. ostk/astrodynamics/test/conjunction/message/ccsds/data/cdm.json +303 -0
  22. ostk/astrodynamics/test/conjunction/message/ccsds/test_cdm.py +416 -0
  23. ostk/astrodynamics/test/dynamics/__init__.py +1 -0
  24. ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity.csv +565 -0
  25. ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity_Truth.csv +100 -0
  26. ostk/astrodynamics/test/dynamics/test_atmospheric_drag.py +128 -0
  27. ostk/astrodynamics/test/dynamics/test_central_body_gravity.py +58 -0
  28. ostk/astrodynamics/test/dynamics/test_dynamics.py +50 -0
  29. ostk/astrodynamics/test/dynamics/test_position_derivative.py +51 -0
  30. ostk/astrodynamics/test/dynamics/test_tabulated.py +138 -0
  31. ostk/astrodynamics/test/dynamics/test_third_body_gravity.py +67 -0
  32. ostk/astrodynamics/test/dynamics/test_thruster.py +142 -0
  33. ostk/astrodynamics/test/event_condition/test_angular_condition.py +113 -0
  34. ostk/astrodynamics/test/event_condition/test_boolean_condition.py +55 -0
  35. ostk/astrodynamics/test/event_condition/test_coe_condition.py +87 -0
  36. ostk/astrodynamics/test/event_condition/test_instant_condition.py +48 -0
  37. ostk/astrodynamics/test/event_condition/test_logical_condition.py +120 -0
  38. ostk/astrodynamics/test/event_condition/test_real_condition.py +50 -0
  39. ostk/astrodynamics/test/flight/__init__.py +1 -0
  40. ostk/astrodynamics/test/flight/system/__init__.py +1 -0
  41. ostk/astrodynamics/test/flight/system/test_propulsion_system.py +73 -0
  42. ostk/astrodynamics/test/flight/system/test_satellite_system.py +91 -0
  43. ostk/astrodynamics/test/flight/system/test_satellite_system_builder.py +71 -0
  44. ostk/astrodynamics/test/flight/test_maneuver.py +212 -0
  45. ostk/astrodynamics/test/flight/test_profile.py +253 -0
  46. ostk/astrodynamics/test/flight/test_system.py +55 -0
  47. ostk/astrodynamics/test/guidance_law/test_constant_thrust.py +91 -0
  48. ostk/astrodynamics/test/guidance_law/test_qlaw.py +138 -0
  49. ostk/astrodynamics/test/solvers/__init__.py +1 -0
  50. ostk/astrodynamics/test/solvers/test_finite_difference_solver.py +181 -0
  51. ostk/astrodynamics/test/solvers/test_temporal_condition_solver.py +153 -0
  52. ostk/astrodynamics/test/test_access.py +128 -0
  53. ostk/astrodynamics/test/test_converters.py +290 -0
  54. ostk/astrodynamics/test/test_dataframe.py +875 -0
  55. ostk/astrodynamics/test/test_display.py +114 -0
  56. ostk/astrodynamics/test/test_event_condition.py +78 -0
  57. ostk/astrodynamics/test/test_import.py +26 -0
  58. ostk/astrodynamics/test/test_root_solver.py +70 -0
  59. ostk/astrodynamics/test/test_trajectory.py +118 -0
  60. ostk/astrodynamics/test/test_utilities.py +106 -0
  61. ostk/astrodynamics/test/test_viewer.py +129 -0
  62. ostk/astrodynamics/test/trajectory/__init__.py +1 -0
  63. ostk/astrodynamics/test/trajectory/orbit/__init__.py +1 -0
  64. ostk/astrodynamics/test/trajectory/orbit/message/__init__.py +1 -0
  65. ostk/astrodynamics/test/trajectory/orbit/message/spacex/__init__.py +1 -0
  66. ostk/astrodynamics/test/trajectory/orbit/message/spacex/conftest.py +18 -0
  67. ostk/astrodynamics/test/trajectory/orbit/message/spacex/data/opm_1.yaml +44 -0
  68. ostk/astrodynamics/test/trajectory/orbit/message/spacex/test_opm.py +108 -0
  69. ostk/astrodynamics/test/trajectory/orbit/models/__init__.py +1 -0
  70. ostk/astrodynamics/test/trajectory/orbit/models/kepler/__init__.py +1 -0
  71. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean.py +65 -0
  72. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_long.py +102 -0
  73. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_short.py +102 -0
  74. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py +201 -0
  75. ostk/astrodynamics/test/trajectory/orbit/models/sgp4/__init__.py +1 -0
  76. ostk/astrodynamics/test/trajectory/orbit/models/sgp4/test_tle.py +331 -0
  77. ostk/astrodynamics/test/trajectory/orbit/models/test_kepler.py +130 -0
  78. ostk/astrodynamics/test/trajectory/orbit/models/test_propagated.py +234 -0
  79. ostk/astrodynamics/test/trajectory/orbit/models/test_sgp4.py +1 -0
  80. ostk/astrodynamics/test/trajectory/orbit/models/test_tabulated.py +380 -0
  81. ostk/astrodynamics/test/trajectory/orbit/test_model.py +1 -0
  82. ostk/astrodynamics/test/trajectory/orbit/test_pass.py +75 -0
  83. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_angular_velocity.py +30 -0
  84. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_attitude_quaternion.py +18 -0
  85. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_position.py +107 -0
  86. ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_velocity.py +115 -0
  87. ostk/astrodynamics/test/trajectory/state/test_coordinate_broker.py +84 -0
  88. ostk/astrodynamics/test/trajectory/state/test_coordinate_subset.py +46 -0
  89. ostk/astrodynamics/test/trajectory/state/test_numerical_solver.py +314 -0
  90. ostk/astrodynamics/test/trajectory/test_local_orbital_frame_direction.py +81 -0
  91. ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py +108 -0
  92. ostk/astrodynamics/test/trajectory/test_model.py +1 -0
  93. ostk/astrodynamics/test/trajectory/test_orbit.py +205 -0
  94. ostk/astrodynamics/test/trajectory/test_propagator.py +458 -0
  95. ostk/astrodynamics/test/trajectory/test_segment.py +403 -0
  96. ostk/astrodynamics/test/trajectory/test_sequence.py +530 -0
  97. ostk/astrodynamics/test/trajectory/test_state.py +543 -0
  98. ostk/astrodynamics/test/trajectory/test_state_builder.py +171 -0
  99. ostk/astrodynamics/utilities.py +247 -0
  100. ostk/astrodynamics/viewer.py +392 -0
@@ -0,0 +1,91 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ import numpy as np
6
+
7
+ import ostk.mathematics as mathematics
8
+
9
+ import ostk.physics as physics
10
+
11
+ import ostk.astrodynamics as astrodynamics
12
+
13
+ Cuboid = mathematics.geometry.d3.object.Cuboid
14
+ Composite = mathematics.geometry.d3.object.Composite
15
+ Point = mathematics.geometry.d3.object.Point
16
+
17
+ Mass = physics.unit.Mass
18
+
19
+ SatelliteSystem = astrodynamics.flight.system.SatelliteSystem
20
+ PropulsionSystem = astrodynamics.flight.system.PropulsionSystem
21
+
22
+
23
+ @pytest.fixture
24
+ def satellite_system_default_inputs():
25
+ mass = Mass(90.0, Mass.Unit.Kilogram)
26
+ satellite_geometry = Composite(
27
+ Cuboid(
28
+ Point(0.0, 0.0, 0.0),
29
+ [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
30
+ [1.0, 0.0, 0.0],
31
+ )
32
+ )
33
+ inertia_tensor = np.ndarray(shape=(3, 3))
34
+ surface_area = 0.8
35
+ drag_coefficient = 2.2
36
+ propulsion_system = PropulsionSystem(
37
+ 1.0,
38
+ 150.0,
39
+ )
40
+
41
+ return (
42
+ mass,
43
+ satellite_geometry,
44
+ inertia_tensor,
45
+ surface_area,
46
+ drag_coefficient,
47
+ propulsion_system,
48
+ )
49
+
50
+
51
+ @pytest.fixture
52
+ def satellite_system(satellite_system_default_inputs) -> SatelliteSystem:
53
+ return SatelliteSystem(*satellite_system_default_inputs)
54
+
55
+
56
+ class TestSatelliteSystem:
57
+ def test_constructors(
58
+ self,
59
+ satellite_system: SatelliteSystem,
60
+ ):
61
+ assert satellite_system is not None
62
+ assert isinstance(satellite_system, SatelliteSystem)
63
+ assert satellite_system.is_defined()
64
+
65
+ def test_comparators(
66
+ self,
67
+ satellite_system: SatelliteSystem,
68
+ ):
69
+ assert (satellite_system == satellite_system) is True
70
+ assert (satellite_system != satellite_system) is False
71
+
72
+ def test_getters(
73
+ self,
74
+ satellite_system_default_inputs,
75
+ satellite_system: SatelliteSystem,
76
+ ):
77
+ (
78
+ mass,
79
+ satellite_geometry,
80
+ inertia_tensor,
81
+ surface_area,
82
+ drag_coefficient,
83
+ propulsion_system,
84
+ ) = satellite_system_default_inputs
85
+
86
+ assert satellite_system.get_mass() == mass
87
+ assert satellite_system.get_geometry() == satellite_geometry
88
+ assert np.array_equal(satellite_system.get_inertia_tensor(), inertia_tensor)
89
+ assert satellite_system.get_cross_sectional_surface_area() == surface_area
90
+ assert satellite_system.get_drag_coefficient() == drag_coefficient
91
+ assert satellite_system.get_propulsion_system() == propulsion_system
@@ -0,0 +1,71 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ import numpy as np
6
+
7
+ import ostk.mathematics as mathematics
8
+
9
+ import ostk.physics as physics
10
+
11
+ import ostk.astrodynamics as astrodynamics
12
+
13
+ Cuboid = mathematics.geometry.d3.object.Cuboid
14
+ Composite = mathematics.geometry.d3.object.Composite
15
+ Point = mathematics.geometry.d3.object.Point
16
+
17
+ Mass = physics.unit.Mass
18
+
19
+ SatelliteSystem = astrodynamics.flight.system.SatelliteSystem
20
+ SatelliteSystemBuilder = astrodynamics.flight.system.SatelliteSystemBuilder
21
+ PropulsionSystem = astrodynamics.flight.system.PropulsionSystem
22
+
23
+
24
+ class TestSatelliteSystemBuilder:
25
+ def test_constructors(self):
26
+ builder: SatelliteSystemBuilder = SatelliteSystemBuilder()
27
+ assert builder is not None
28
+ assert isinstance(builder, SatelliteSystemBuilder)
29
+
30
+ default_builder: SatelliteSystemBuilder = SatelliteSystemBuilder.default()
31
+ assert default_builder is not None
32
+ assert isinstance(default_builder, SatelliteSystemBuilder)
33
+
34
+ def test_build(self):
35
+ dry_mass = Mass(90.0, Mass.Unit.Kilogram)
36
+ geometry = Composite(
37
+ Cuboid(
38
+ Point(0.0, 0.0, 0.0),
39
+ [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
40
+ [1.0, 0.0, 0.0],
41
+ )
42
+ )
43
+ inertia_tensor = np.ndarray(shape=(3, 3))
44
+ cross_sectional_surface_area = 0.8
45
+ drag_coefficient = 2.2
46
+ propulsion_system = PropulsionSystem(
47
+ 1.0,
48
+ 150.0,
49
+ )
50
+
51
+ builder: SatelliteSystemBuilder = (
52
+ SatelliteSystemBuilder()
53
+ .with_dry_mass(dry_mass)
54
+ .with_geometry(geometry)
55
+ .with_inertia_tensor(inertia_tensor)
56
+ .with_cross_sectional_surface_area(cross_sectional_surface_area)
57
+ .with_drag_coefficient(drag_coefficient)
58
+ .with_propulsion_system(propulsion_system)
59
+ )
60
+
61
+ satellite_system: SatelliteSystem = builder.build()
62
+
63
+ assert satellite_system.get_mass() == dry_mass
64
+ assert satellite_system.get_geometry() == geometry
65
+ assert np.array_equal(satellite_system.get_inertia_tensor(), inertia_tensor)
66
+ assert (
67
+ satellite_system.get_cross_sectional_surface_area()
68
+ == cross_sectional_surface_area
69
+ )
70
+ assert satellite_system.get_drag_coefficient() == drag_coefficient
71
+ assert satellite_system.get_propulsion_system() == propulsion_system
@@ -0,0 +1,212 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ import numpy as np
6
+
7
+
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.coordinate import Frame
12
+ from ostk.physics.unit import Mass
13
+
14
+ from ostk.astrodynamics.flight import Maneuver
15
+ from ostk.astrodynamics.dynamics import Tabulated as TabulatedDynamics
16
+ from ostk.astrodynamics.trajectory.state import CoordinateSubset
17
+
18
+
19
+ from ..dynamics.test_tabulated import (
20
+ instants as tabulated_instants,
21
+ contribution_profile as tabulated_contribution_profile,
22
+ coordinate_subsets as tabulated_coordinate_subsets,
23
+ )
24
+
25
+
26
+ @pytest.fixture
27
+ def instants() -> list[Instant]:
28
+ return [
29
+ Instant.J2000(),
30
+ Instant.J2000() + Duration.seconds(1.0),
31
+ Instant.J2000() + Duration.seconds(5.0),
32
+ Instant.J2000() + Duration.seconds(7.0),
33
+ ]
34
+
35
+
36
+ @pytest.fixture
37
+ def acceleration_profile() -> list[np.ndarray]:
38
+ return [
39
+ np.array([1.0e-3, 0.0e-3, 0.0e-3]),
40
+ np.array([0.0e-3, 1.0e-3, 0.0e-3]),
41
+ np.array([0.0e-3, 0.0e-3, 1.0e-3]),
42
+ np.array([1.0e-3, 1.0e-3, 1.0e-3]),
43
+ ]
44
+
45
+
46
+ @pytest.fixture
47
+ def frame() -> Frame:
48
+ return Frame.GCRF()
49
+
50
+
51
+ @pytest.fixture
52
+ def mass_flow_rate_profile() -> list[float]:
53
+ return [-1.0e-5, -1.1e-5, -0.9e-5, -1.0e-5]
54
+
55
+
56
+ @pytest.fixture
57
+ def maneuver(
58
+ instants: list[Instant],
59
+ acceleration_profile: list[np.ndarray],
60
+ frame: Frame,
61
+ mass_flow_rate_profile: list[float],
62
+ ) -> Maneuver:
63
+ return Maneuver(instants, acceleration_profile, frame, mass_flow_rate_profile)
64
+
65
+
66
+ @pytest.fixture
67
+ def tabulated_dynamics(
68
+ tabulated_instants: list[Instant],
69
+ tabulated_contribution_profile: np.ndarray,
70
+ tabulated_coordinate_subsets: list[CoordinateSubset],
71
+ frame: Frame,
72
+ ) -> TabulatedDynamics:
73
+ return TabulatedDynamics(
74
+ tabulated_instants,
75
+ tabulated_contribution_profile,
76
+ tabulated_coordinate_subsets,
77
+ frame,
78
+ )
79
+
80
+
81
+ class TestManeuver:
82
+ def test_constructor(
83
+ self,
84
+ maneuver: Maneuver,
85
+ ):
86
+ assert maneuver is not None
87
+ assert isinstance(maneuver, Maneuver)
88
+ assert maneuver.is_defined()
89
+
90
+ def test_comparators(
91
+ self,
92
+ maneuver: Maneuver,
93
+ ):
94
+ assert (maneuver == maneuver) is True
95
+ assert (maneuver != maneuver) is False
96
+
97
+ def test_getters(
98
+ self,
99
+ maneuver: Maneuver,
100
+ instants: list[Instant],
101
+ acceleration_profile: list[np.ndarray],
102
+ mass_flow_rate_profile: list[float],
103
+ ):
104
+ assert maneuver.is_defined()
105
+
106
+ assert maneuver.get_instants() == instants
107
+
108
+ computed_acceleration_profile_default_frame = maneuver.get_acceleration_profile()
109
+ for i in range(len(instants)):
110
+ assert np.array_equal(
111
+ computed_acceleration_profile_default_frame[i], acceleration_profile[i]
112
+ )
113
+
114
+ computed_acceleration_profile_non_default_frame = (
115
+ maneuver.get_acceleration_profile(frame=Frame.ITRF())
116
+ )
117
+ for i in range(len(instants)):
118
+ assert (
119
+ np.array_equal(
120
+ computed_acceleration_profile_non_default_frame[i],
121
+ acceleration_profile[i],
122
+ )
123
+ == False
124
+ )
125
+
126
+ assert maneuver.get_mass_flow_rate_profile() == mass_flow_rate_profile
127
+
128
+ assert maneuver.get_interval() == Interval.closed(instants[0], instants[-1])
129
+
130
+ def test_calculators(
131
+ self,
132
+ maneuver: Maneuver,
133
+ ):
134
+ assert maneuver.calculate_delta_v() is not None
135
+ assert maneuver.calculate_delta_mass().in_kilograms() is not None
136
+ assert (
137
+ maneuver.calculate_average_thrust(
138
+ initial_spacecraft_mass=Mass(100.0, Mass.Unit.Kilogram)
139
+ )
140
+ is not None
141
+ )
142
+ assert (
143
+ maneuver.calculate_average_specific_impulse(
144
+ initial_spacecraft_mass=Mass(100.0, Mass.Unit.Kilogram)
145
+ )
146
+ is not None
147
+ )
148
+
149
+ def test_to_tabulated_dynamics(
150
+ self,
151
+ maneuver: Maneuver,
152
+ instants: list[Instant],
153
+ acceleration_profile: list[np.ndarray],
154
+ frame: Frame,
155
+ mass_flow_rate_profile: list[float],
156
+ ):
157
+ tabulated_dynamics: TabulatedDynamics = maneuver.to_tabulated_dynamics(
158
+ frame=frame
159
+ )
160
+
161
+ assert tabulated_dynamics.is_defined()
162
+ assert tabulated_dynamics.access_instants() == maneuver.get_instants()
163
+
164
+ contribution_profile: np.ndarray = (
165
+ tabulated_dynamics.access_contribution_profile()
166
+ )
167
+
168
+ for i in range(len(instants)):
169
+ assert contribution_profile[i][0:3] == pytest.approx(
170
+ acceleration_profile[i], rel=1e-15
171
+ )
172
+ assert contribution_profile[i][3] == pytest.approx(
173
+ mass_flow_rate_profile[i], rel=1e-15
174
+ )
175
+
176
+ assert tabulated_dynamics.access_frame() == frame
177
+
178
+ def test_from_tabulated_dynamics(
179
+ self,
180
+ tabulated_dynamics: TabulatedDynamics,
181
+ ):
182
+ maneuver = Maneuver.tabulated_dynamics(tabulated_dynamics)
183
+
184
+ assert maneuver.is_defined()
185
+ assert maneuver.get_instants() == tabulated_dynamics.access_instants()
186
+ assert (
187
+ len(maneuver.get_acceleration_profile())
188
+ == tabulated_dynamics.access_contribution_profile().shape[0]
189
+ )
190
+ assert (
191
+ len(maneuver.get_mass_flow_rate_profile())
192
+ == tabulated_dynamics.access_contribution_profile().shape[0]
193
+ )
194
+
195
+ def test_from_constant_mass_flow_rate(
196
+ self,
197
+ instants: list[Instant],
198
+ acceleration_profile: list[np.ndarray],
199
+ frame: Frame,
200
+ ):
201
+ mass_flow_rate: float = -1.0e-5
202
+ maneuver = Maneuver.constant_mass_flow_rate_profile(
203
+ instants=instants,
204
+ acceleration_profile=acceleration_profile,
205
+ frame=frame,
206
+ mass_flow_rate=mass_flow_rate,
207
+ )
208
+
209
+ assert maneuver.is_defined()
210
+ assert maneuver.get_mass_flow_rate_profile() == [
211
+ mass_flow_rate for _ in range(len(instants))
212
+ ]
@@ -0,0 +1,253 @@
1
+ # Apache License 2.0
2
+
3
+ from datetime import datetime
4
+
5
+ import pytest
6
+
7
+ from ostk.mathematics.geometry.d3.transformation.rotation import Quaternion
8
+
9
+ from ostk.physics import Environment
10
+ from ostk.physics.time import DateTime
11
+ from ostk.physics.time import Duration
12
+ from ostk.physics.time import Time
13
+ from ostk.physics.time import Scale
14
+ from ostk.physics.time import Instant
15
+ from ostk.physics.unit import Length
16
+ from ostk.physics.coordinate import Transform
17
+ from ostk.physics.coordinate import Position
18
+ from ostk.physics.coordinate import Velocity
19
+ from ostk.physics.coordinate import Frame
20
+ from ostk.physics.coordinate import Axes
21
+ from ostk.physics.coordinate.frame.provider import Dynamic as DynamicProvider
22
+
23
+ from ostk.astrodynamics import Trajectory
24
+ from ostk.astrodynamics.trajectory import Orbit
25
+ from ostk.astrodynamics.trajectory import State
26
+ from ostk.astrodynamics.flight import Profile
27
+ from ostk.astrodynamics.flight.profile.model import Transform as TransformModel
28
+ from ostk.astrodynamics.flight.profile.model import Tabulated as TabulatedModel
29
+
30
+
31
+ @pytest.fixture
32
+ def instant() -> Instant:
33
+ return Instant.date_time(DateTime(2020, 1, 1, 0, 0, 30), Scale.UTC)
34
+
35
+
36
+ @pytest.fixture
37
+ def environment() -> Environment:
38
+ return Environment.default()
39
+
40
+
41
+ @pytest.fixture
42
+ def orbit(instant: Instant, environment: Environment) -> Orbit:
43
+ return Orbit.sun_synchronous(
44
+ epoch=instant,
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
+
50
+
51
+ @pytest.fixture
52
+ def transform_model() -> TransformModel:
53
+ def dynamic_provider_generator(instant: Instant):
54
+ return Transform.identity(instant)
55
+
56
+ return TransformModel(
57
+ dynamic_provider=DynamicProvider(dynamic_provider_generator),
58
+ frame=Frame.GCRF(),
59
+ )
60
+
61
+
62
+ @pytest.fixture
63
+ def tabulated_model() -> TabulatedModel:
64
+ return TabulatedModel(
65
+ states=[
66
+ State(
67
+ instant=Instant.date_time(datetime(2020, 1, 1, 0, 0, 0), Scale.UTC),
68
+ position=Position.meters((0.0, 0.0, 0.0), Frame.GCRF()),
69
+ velocity=Velocity.meters_per_second((0.0, 0.0, 0.0), Frame.GCRF()),
70
+ attitude=Quaternion.unit(),
71
+ angular_velocity=(0.0, 0.0, 0.0),
72
+ attitude_frame=Frame.GCRF(),
73
+ ),
74
+ State(
75
+ instant=Instant.date_time(datetime(2020, 1, 1, 0, 1, 0), Scale.UTC),
76
+ position=Position.meters((0.0, 0.0, 0.0), Frame.GCRF()),
77
+ velocity=Velocity.meters_per_second((0.0, 0.0, 0.0), Frame.GCRF()),
78
+ attitude=Quaternion.unit(),
79
+ angular_velocity=(0.0, 0.0, 0.0),
80
+ attitude_frame=Frame.GCRF(),
81
+ ),
82
+ ],
83
+ )
84
+
85
+
86
+ @pytest.fixture(
87
+ params=[
88
+ "transform_model",
89
+ "tabulated_model",
90
+ ]
91
+ )
92
+ def profile(request) -> Profile:
93
+ model: TransformModel | TabulatedModel = request.getfixturevalue(request.param)
94
+ return Profile(model=model)
95
+
96
+
97
+ @pytest.fixture(
98
+ params=[
99
+ Profile.Target(Profile.TargetType.GeocentricNadir, Profile.Axis.X),
100
+ Profile.TrajectoryTarget(
101
+ Trajectory.position(Position.meters((0.0, 0.0, 0.0), Frame.ITRF())),
102
+ Profile.Axis.X,
103
+ ),
104
+ Profile.OrientationProfileTarget(
105
+ [
106
+ (Instant.J2000(), [1.0, 0.0, 0.0]),
107
+ (Instant.J2000() + Duration.minutes(1.0), [1.0, 0.0, 0.0]),
108
+ (Instant.J2000() + Duration.minutes(2.0), [1.0, 0.0, 0.0]),
109
+ (Instant.J2000() + Duration.minutes(3.0), [1.0, 0.0, 0.0]),
110
+ ],
111
+ Profile.Axis.X,
112
+ ),
113
+ Profile.CustomTarget(
114
+ lambda state: [1.0, 0.0, 0.0],
115
+ Profile.Axis.X,
116
+ ),
117
+ ]
118
+ )
119
+ def alignment_target() -> Profile.Target:
120
+ return Profile.Target(Profile.TargetType.GeocentricNadir, Profile.Axis.X)
121
+
122
+
123
+ @pytest.fixture
124
+ def clocking_target() -> Profile.Target:
125
+ return Profile.Target(Profile.TargetType.VelocityECI, Profile.Axis.Y)
126
+
127
+
128
+ class TestProfile:
129
+ def test_constructors(self, profile: Profile):
130
+ assert profile is not None
131
+ assert isinstance(profile, Profile)
132
+
133
+ def test_profile_target(self, alignment_target: Profile.Target):
134
+ assert alignment_target is not None
135
+ assert isinstance(alignment_target, Profile.Target)
136
+
137
+ def test_access_model(self, profile: Profile):
138
+ model = profile.access_model()
139
+
140
+ assert model is not None
141
+
142
+ if model.is_transform():
143
+ assert model.as_transform() is not None
144
+
145
+ if model.is_tabulated():
146
+ assert model.as_tabulated() is not None
147
+
148
+ def test_get_state_at(self, profile: Profile, instant: Instant):
149
+ state: State = profile.get_state_at(instant)
150
+
151
+ assert state is not None
152
+ assert isinstance(state, State)
153
+ state.is_defined()
154
+
155
+ def test_get_states_at(self, profile: Profile, instant: Instant):
156
+ states = profile.get_states_at([instant, instant])
157
+
158
+ assert states is not None
159
+
160
+ def test_get_axes_at(self, profile: Profile, instant: Instant):
161
+ axes = profile.get_axes_at(instant)
162
+
163
+ assert axes is not None
164
+ assert isinstance(axes, Axes)
165
+
166
+ def test_get_body_frame(self, profile: Profile):
167
+ if Frame.exists("Name"):
168
+ Frame.destruct("Name")
169
+
170
+ frame = profile.get_body_frame("Name")
171
+
172
+ assert frame is not None
173
+ assert isinstance(frame, Frame)
174
+
175
+ def test_undefined(self):
176
+ profile: Profile = Profile.undefined()
177
+
178
+ assert profile is not None
179
+ assert isinstance(profile, Profile)
180
+ assert profile.is_defined() is False
181
+
182
+ def test_inertial_pointing(self):
183
+ quaternion: Quaternion = Quaternion([0.0, 0.0, 0.0, 1.0], Quaternion.Format.XYZS)
184
+
185
+ trajectory: Trajectory = Trajectory.position(
186
+ Position.meters((0.0, 0.0, 0.0), Frame.ITRF())
187
+ )
188
+
189
+ profile: Profile = Profile.inertial_pointing(trajectory, quaternion)
190
+
191
+ assert profile is not None
192
+ assert isinstance(profile, Profile)
193
+ assert profile.is_defined()
194
+
195
+ def test_nadir_pointing(
196
+ self,
197
+ orbit: Orbit,
198
+ ):
199
+ profile: Profile = Profile.nadir_pointing(orbit, Orbit.FrameType.VVLH)
200
+
201
+ assert profile is not None
202
+ assert isinstance(profile, Profile)
203
+ assert profile.is_defined()
204
+
205
+ def test_custom_pointing(
206
+ self,
207
+ orbit: Orbit,
208
+ alignment_target: Profile.Target,
209
+ clocking_target: Profile.Target,
210
+ ):
211
+ profile = Profile.custom_pointing(
212
+ orbit, Profile.align_and_constrain(alignment_target, clocking_target)
213
+ )
214
+
215
+ assert profile is not None
216
+ assert profile.is_defined()
217
+
218
+ def test_align_and_constrain(
219
+ self,
220
+ orbit: Orbit,
221
+ instant: Instant,
222
+ alignment_target: Profile.Target,
223
+ clocking_target: Profile.Target,
224
+ ):
225
+ orientation = Profile.align_and_constrain(
226
+ alignment_target=alignment_target,
227
+ clocking_target=clocking_target,
228
+ )
229
+
230
+ assert orientation is not None
231
+ assert orientation(orbit.get_state_at(instant)) is not None
232
+
233
+ def test_custom_pointing(
234
+ self,
235
+ orbit: Orbit,
236
+ alignment_target: Profile.Target,
237
+ clocking_target: Profile.Target,
238
+ ):
239
+ profile = Profile.custom_pointing(
240
+ orbit, Profile.align_and_constrain(alignment_target, clocking_target)
241
+ )
242
+
243
+ assert profile is not None
244
+ assert profile.is_defined()
245
+
246
+ profile = Profile.custom_pointing(
247
+ orbit,
248
+ alignment_target,
249
+ clocking_target,
250
+ )
251
+
252
+ assert profile is not None
253
+ assert profile.is_defined()
@@ -0,0 +1,55 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ import numpy as np
6
+
7
+ import ostk.mathematics as mathematics
8
+
9
+ import ostk.physics as physics
10
+
11
+ import ostk.astrodynamics as astrodynamics
12
+
13
+ Cuboid = mathematics.geometry.d3.object.Cuboid
14
+ Composite = mathematics.geometry.d3.object.Composite
15
+ Point = mathematics.geometry.d3.object.Point
16
+
17
+ Mass = physics.unit.Mass
18
+
19
+ System = astrodynamics.flight.System
20
+
21
+
22
+ @pytest.fixture
23
+ def system_default_inputs():
24
+ mass = Mass(90.0, Mass.Unit.Kilogram)
25
+ geometry = Composite(
26
+ Cuboid(
27
+ Point(0.0, 0.0, 0.0),
28
+ [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
29
+ [1.0, 0.0, 0.0],
30
+ )
31
+ )
32
+
33
+ return (mass, geometry)
34
+
35
+
36
+ @pytest.fixture
37
+ def system(system_default_inputs) -> System:
38
+ return System(*system_default_inputs)
39
+
40
+
41
+ class TestSatelliteSystem:
42
+ def test_constructors(self, system: System):
43
+ assert system is not None
44
+ assert isinstance(system, System)
45
+ assert system.is_defined()
46
+
47
+ def test_comparators(self, system: System):
48
+ assert (system == system) is True
49
+ assert (system != system) is False
50
+
51
+ def test_getters(self, system_default_inputs, system: System):
52
+ (mass, geometry) = system_default_inputs
53
+
54
+ assert system.get_mass() == mass
55
+ assert system.get_geometry() == geometry