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
+ from ostk.physics.time import Instant
6
+ from ostk.physics.time import DateTime
7
+ from ostk.physics.time import Scale
8
+ from ostk.physics.coordinate import Frame
9
+
10
+ from ostk.astrodynamics.trajectory import LocalOrbitalFrameFactory
11
+ from ostk.astrodynamics.trajectory import LocalOrbitalFrameDirection
12
+
13
+ from ostk.astrodynamics import GuidanceLaw
14
+ from ostk.astrodynamics.guidance_law import ConstantThrust
15
+
16
+
17
+ @pytest.fixture
18
+ def local_orbital_frame_direction() -> LocalOrbitalFrameDirection:
19
+ return LocalOrbitalFrameDirection(
20
+ vector=[1.0, 0.0, 0.0],
21
+ local_orbital_frame_factory=LocalOrbitalFrameFactory.VNC(Frame.GCRF()),
22
+ )
23
+
24
+
25
+ @pytest.fixture
26
+ def guidance_law(
27
+ local_orbital_frame_direction: LocalOrbitalFrameDirection,
28
+ ) -> ConstantThrust:
29
+ return ConstantThrust(thrust_direction=local_orbital_frame_direction)
30
+
31
+
32
+ @pytest.fixture
33
+ def instant() -> Instant:
34
+ return Instant.date_time(DateTime(2021, 3, 20, 12, 0, 0), Scale.UTC)
35
+
36
+
37
+ @pytest.fixture
38
+ def position_coordinates() -> list[float]:
39
+ return [7000000.0, 0.0, 0.0]
40
+
41
+
42
+ @pytest.fixture
43
+ def velocity_coordinates() -> list[float]:
44
+ return [0.0, 7546.05329, 0.0]
45
+
46
+
47
+ @pytest.fixture
48
+ def thrust_acceleration() -> float:
49
+ return 1.0 / 105.0
50
+
51
+
52
+ @pytest.fixture
53
+ def frame() -> Frame:
54
+ return Frame.GCRF()
55
+
56
+
57
+ class TestConstantThrust:
58
+ def test_constructors(self, guidance_law: ConstantThrust):
59
+ assert guidance_law is not None
60
+ assert isinstance(guidance_law, ConstantThrust)
61
+ assert isinstance(guidance_law, GuidanceLaw)
62
+
63
+ def test_getters(self, guidance_law: ConstantThrust):
64
+ assert guidance_law.get_local_thrust_direction() is not None
65
+
66
+ def test_static_constructors(self):
67
+ assert ConstantThrust.intrack() is not None
68
+
69
+ assert ConstantThrust.intrack(velocity_direction=False) is not None
70
+
71
+ assert ConstantThrust.intrack(velocity_direction=True) is not None
72
+
73
+ def test_compute_acceleration_success(
74
+ self,
75
+ guidance_law: ConstantThrust,
76
+ instant: Instant,
77
+ position_coordinates: list[float],
78
+ velocity_coordinates: list[float],
79
+ thrust_acceleration: float,
80
+ frame: Frame,
81
+ ):
82
+ contribution = guidance_law.calculate_thrust_acceleration_at(
83
+ instant=instant,
84
+ position_coordinates=position_coordinates,
85
+ velocity_coordinates=velocity_coordinates,
86
+ thrust_acceleration=thrust_acceleration,
87
+ output_frame=frame,
88
+ )
89
+
90
+ assert len(contribution) == 3
91
+ assert contribution == pytest.approx([0.0, 0.009523809523809525, 0.0], abs=5e-11)
@@ -0,0 +1,138 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ import numpy as np
6
+
7
+ from ostk.physics.time import Instant
8
+ from ostk.physics.coordinate import Frame
9
+ from ostk.physics.unit import Derived
10
+ from ostk.physics.environment.gravitational import Earth as EarthGravitationalModel
11
+ from ostk.physics.time import Instant
12
+ from ostk.physics.coordinate import Frame
13
+ from ostk.physics.unit import Length
14
+ from ostk.physics.unit import Angle
15
+
16
+
17
+ from ostk.astrodynamics.trajectory.orbit.model.kepler import COE
18
+ from ostk.astrodynamics import GuidanceLaw
19
+ from ostk.astrodynamics.guidance_law import QLaw
20
+
21
+
22
+ @pytest.fixture
23
+ def target_COE() -> COE:
24
+ return COE(
25
+ Length.meters(42000.0e3),
26
+ 0.01,
27
+ Angle.degrees(0.05),
28
+ Angle.degrees(0.0),
29
+ Angle.degrees(0.0),
30
+ Angle.degrees(0.0),
31
+ )
32
+
33
+
34
+ @pytest.fixture
35
+ def gravitational_parameter() -> Derived:
36
+ return Derived(
37
+ 3.986004418e14,
38
+ EarthGravitationalModel.EGM2008.gravitational_parameter.get_unit(),
39
+ )
40
+
41
+
42
+ @pytest.fixture
43
+ def parameters() -> QLaw.Parameters:
44
+ return QLaw.Parameters(
45
+ element_weights={
46
+ COE.Element.SemiMajorAxis: (1.0, 100.0),
47
+ COE.Element.Eccentricity: (1.0, 1e-3),
48
+ },
49
+ )
50
+
51
+
52
+ @pytest.fixture
53
+ def gradient_strategy() -> QLaw.GradientStrategy:
54
+ return QLaw.GradientStrategy.FiniteDifference
55
+
56
+
57
+ @pytest.fixture
58
+ def q_law(
59
+ target_COE: COE,
60
+ gravitational_parameter: Derived,
61
+ parameters: QLaw.Parameters,
62
+ gradient_strategy: QLaw.GradientStrategy,
63
+ ) -> QLaw:
64
+ return QLaw(
65
+ target_coe=target_COE,
66
+ gravitational_parameter=gravitational_parameter,
67
+ parameters=parameters,
68
+ gradient_strategy=gradient_strategy,
69
+ )
70
+
71
+
72
+ @pytest.fixture
73
+ def thrust_acceleration() -> float:
74
+ return 1.0 / 300.0
75
+
76
+
77
+ @pytest.fixture
78
+ def frame() -> Frame:
79
+ return Frame.GCRF()
80
+
81
+
82
+ @pytest.fixture
83
+ def position_coordinates() -> list[float]:
84
+ return [6930000.0, 0.0, 0.0]
85
+
86
+
87
+ @pytest.fixture
88
+ def velocity_coordinates() -> list[float]:
89
+ return [0.0, 7621.89248591193, 6.65135764404186]
90
+
91
+
92
+ @pytest.fixture
93
+ def instant() -> Instant:
94
+ return Instant.J2000()
95
+
96
+
97
+ class TestQLawParameters:
98
+ def test_constructors(self, parameters: QLaw.Parameters):
99
+ assert parameters is not None
100
+ assert isinstance(parameters, QLaw.Parameters)
101
+
102
+ def test_getters(self, parameters: QLaw.Parameters):
103
+ assert parameters.get_control_weights() is not None
104
+ assert parameters.m is not None
105
+ assert parameters.n is not None
106
+ assert parameters.r is not None
107
+ assert parameters.b is not None
108
+
109
+
110
+ class TestQLaw:
111
+ def test_constructors(self, q_law: QLaw):
112
+ assert q_law is not None
113
+ assert isinstance(q_law, QLaw)
114
+ assert isinstance(q_law, GuidanceLaw)
115
+
116
+ def test_getters(self, q_law: QLaw):
117
+ assert q_law.get_parameters() is not None
118
+ assert q_law.get_target_coe() is not None
119
+ assert q_law.get_gradient_strategy() is not None
120
+
121
+ def test_calculate_thrust_acceleration_at(
122
+ self,
123
+ q_law: QLaw,
124
+ position_coordinates: list[float],
125
+ velocity_coordinates: list[float],
126
+ thrust_acceleration: float,
127
+ instant: Instant,
128
+ frame: Frame,
129
+ ):
130
+ assert pytest.approx(
131
+ q_law.calculate_thrust_acceleration_at(
132
+ instant=instant,
133
+ position_coordinates=position_coordinates,
134
+ velocity_coordinates=velocity_coordinates,
135
+ thrust_acceleration=thrust_acceleration,
136
+ output_frame=frame,
137
+ )
138
+ ) == np.array([0.0, 0.0033333320640941645, 2.9088817174504986e-06])
@@ -0,0 +1 @@
1
+ # Apache License 2.0
@@ -0,0 +1,181 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+ import math
5
+
6
+ import numpy as np
7
+
8
+ from ostk.physics.coordinate import Frame
9
+ from ostk.physics.time import Instant
10
+ from ostk.physics.time import Duration
11
+
12
+ from ostk.astrodynamics.solver import FiniteDifferenceSolver
13
+ from ostk.astrodynamics.trajectory import State
14
+ from ostk.astrodynamics.trajectory.state import CoordinateSubset
15
+
16
+
17
+ @pytest.fixture
18
+ def step_percentage() -> float:
19
+ return 1e-3
20
+
21
+
22
+ @pytest.fixture
23
+ def step_duration() -> Duration:
24
+ return Duration.seconds(1e-6)
25
+
26
+
27
+ @pytest.fixture(
28
+ params=[
29
+ FiniteDifferenceSolver.Type.Forward,
30
+ FiniteDifferenceSolver.Type.Backward,
31
+ FiniteDifferenceSolver.Type.Central,
32
+ ]
33
+ )
34
+ def finite_difference_solver(request, step_percentage: float, step_duration: Duration):
35
+ return FiniteDifferenceSolver(request.param, step_percentage, step_duration)
36
+
37
+
38
+ @pytest.fixture
39
+ def coordinate_subsets() -> list[CoordinateSubset]:
40
+ return [CoordinateSubset("Position", 1), CoordinateSubset("Velocity", 1)]
41
+
42
+
43
+ @pytest.fixture
44
+ def frame() -> Frame:
45
+ return Frame.GCRF()
46
+
47
+
48
+ @pytest.fixture
49
+ def state(
50
+ initial_instant: Instant, frame: Frame, coordinate_subsets: list[CoordinateSubset]
51
+ ):
52
+ return State(initial_instant, [1, 0], frame, coordinate_subsets)
53
+
54
+
55
+ @pytest.fixture
56
+ def initial_instant() -> Instant:
57
+ return Instant.J2000()
58
+
59
+
60
+ @pytest.fixture
61
+ def instant(initial_instant: Instant) -> Instant:
62
+ return initial_instant + Duration.seconds(100.0)
63
+
64
+
65
+ @pytest.fixture
66
+ def instants(initial_instant: Instant) -> list[Instant]:
67
+ return [
68
+ initial_instant + Duration.seconds(100.0),
69
+ initial_instant + Duration.seconds(200.0),
70
+ ]
71
+
72
+
73
+ @pytest.fixture
74
+ def generate_states_coordinates() -> callable:
75
+ def state_fn(state, instants) -> np.ndarray:
76
+ x0: float = state.get_coordinates()[0]
77
+ v0: float = state.get_coordinates()[1]
78
+ omega: float = 1.0
79
+
80
+ states_coordinates: list[list[float]] = []
81
+
82
+ for instant in instants:
83
+ t: float = (instant - state.get_instant()).in_seconds()
84
+ x: float = x0 * math.cos(omega * t) + v0 / omega * math.sin(omega * t)
85
+ v: float = -x0 * omega * math.sin(omega * t) + v0 * math.cos(omega * t)
86
+
87
+ coordinates: list[float] = [x, v]
88
+
89
+ states_coordinates.append(coordinates)
90
+
91
+ return np.array(states_coordinates)
92
+
93
+ return state_fn
94
+
95
+
96
+ @pytest.fixture
97
+ def generate_state_coordinates() -> callable:
98
+ def state_fn(state, instant) -> np.ndarray:
99
+ x0: float = state.get_coordinates()[0]
100
+ v0: float = state.get_coordinates()[1]
101
+ omega: float = 1.0
102
+
103
+ t: float = (instant - state.get_instant()).in_seconds()
104
+ x: float = x0 * math.cos(omega * t) + v0 / omega * math.sin(omega * t)
105
+ v: float = -x0 * omega * math.sin(omega * t) + v0 * math.cos(omega * t)
106
+
107
+ return np.array([x, v])
108
+
109
+ return state_fn
110
+
111
+
112
+ class TestFiniteDifferenceSolver:
113
+ def test_constructor(self, finite_difference_solver: FiniteDifferenceSolver):
114
+ assert isinstance(finite_difference_solver, FiniteDifferenceSolver)
115
+
116
+ def test_getters(self, finite_difference_solver: FiniteDifferenceSolver):
117
+ assert isinstance(
118
+ finite_difference_solver.get_type(), FiniteDifferenceSolver.Type
119
+ )
120
+ assert finite_difference_solver.get_step_percentage() is not None
121
+ assert isinstance(finite_difference_solver.get_step_duration(), Duration)
122
+
123
+ def test_string_from_type(self):
124
+ assert (
125
+ FiniteDifferenceSolver.string_from_type(FiniteDifferenceSolver.Type.Forward)
126
+ == "Forward"
127
+ )
128
+
129
+ def test_compute_jacobian_array(
130
+ self,
131
+ finite_difference_solver: FiniteDifferenceSolver,
132
+ state: State,
133
+ instants: list[Instant],
134
+ generate_states_coordinates: callable,
135
+ ):
136
+ stm = finite_difference_solver.compute_jacobian(
137
+ state=state,
138
+ instants=instants,
139
+ generate_states_coordinates=generate_states_coordinates,
140
+ coordinates_dimension=2,
141
+ )
142
+ assert isinstance(stm, np.ndarray)
143
+ assert stm.shape == (
144
+ len(state.get_coordinates()) * len(instants),
145
+ len(state.get_coordinates()),
146
+ )
147
+
148
+ def test_compute_jacobian_single(
149
+ self,
150
+ finite_difference_solver: FiniteDifferenceSolver,
151
+ state: State,
152
+ generate_state_coordinates: callable,
153
+ instant: Instant,
154
+ ):
155
+ stm = finite_difference_solver.compute_jacobian(
156
+ state=state,
157
+ instant=instant,
158
+ generate_state_coordinates=generate_state_coordinates,
159
+ coordinates_dimension=2,
160
+ )
161
+ assert isinstance(stm, np.ndarray)
162
+ assert stm.shape == (
163
+ len(state.get_coordinates()),
164
+ len(state.get_coordinates()),
165
+ )
166
+
167
+ def test_compute_gradient(
168
+ self,
169
+ finite_difference_solver: FiniteDifferenceSolver,
170
+ state: State,
171
+ generate_state_coordinates: callable,
172
+ ):
173
+ gradient = finite_difference_solver.compute_gradient(
174
+ state=state,
175
+ generate_state_coordinates=generate_state_coordinates,
176
+ )
177
+ assert isinstance(gradient, np.ndarray)
178
+ assert all(gradient - np.array([0.0, -1.0]) < 1e-6)
179
+
180
+ def test_default(self):
181
+ assert isinstance(FiniteDifferenceSolver.default(), FiniteDifferenceSolver)
@@ -0,0 +1,153 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.physics.unit import Length
6
+ from ostk.physics.unit import Angle
7
+ from ostk.physics.time import Instant
8
+ from ostk.physics.time import Duration
9
+ from ostk.physics.time import Interval
10
+ from ostk.physics.time import DateTime
11
+ from ostk.physics.time import Scale
12
+ from ostk.physics import Environment
13
+
14
+ from ostk.astrodynamics.trajectory import Orbit
15
+ from ostk.astrodynamics.trajectory.orbit.model import Kepler
16
+ from ostk.astrodynamics.trajectory.orbit.model.kepler import COE
17
+ from ostk.astrodynamics.access import Generator
18
+ from ostk.astrodynamics.solver import TemporalConditionSolver
19
+
20
+
21
+ @pytest.fixture
22
+ def temporal_condition_solver() -> TemporalConditionSolver:
23
+ return TemporalConditionSolver(
24
+ time_step=Duration.seconds(30.0),
25
+ tolerance=Duration.milliseconds(1.0),
26
+ maximum_iteration_count=1234,
27
+ )
28
+
29
+
30
+ @pytest.fixture
31
+ def interval() -> Interval:
32
+ return Interval.closed(
33
+ Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC),
34
+ Instant.date_time(DateTime(2018, 1, 1, 2, 0, 0), Scale.UTC),
35
+ )
36
+
37
+
38
+ class TestTemporalConditionSolver:
39
+ def test_constructor_success(self):
40
+ temporal_condition_solver = TemporalConditionSolver(
41
+ time_step=Duration.seconds(30.0),
42
+ tolerance=Duration.milliseconds(1.0),
43
+ maximum_iteration_count=1234,
44
+ )
45
+
46
+ assert isinstance(temporal_condition_solver, TemporalConditionSolver)
47
+
48
+ def test_getters_success(
49
+ self,
50
+ temporal_condition_solver: TemporalConditionSolver,
51
+ ):
52
+ assert temporal_condition_solver.get_time_step() == Duration.seconds(30.0)
53
+ assert temporal_condition_solver.get_tolerance() == Duration.milliseconds(1.0)
54
+ assert temporal_condition_solver.get_maximum_iteration_count() == 1234
55
+
56
+ def test_solve_success_one_condition_always_true(
57
+ self,
58
+ temporal_condition_solver: TemporalConditionSolver,
59
+ interval: Interval,
60
+ ):
61
+ solution: list[Interval] = temporal_condition_solver.solve(
62
+ condition=lambda _: True,
63
+ interval=interval,
64
+ )
65
+
66
+ assert isinstance(solution, list)
67
+ assert solution == [interval]
68
+
69
+ def test_solve_success_one_condition_always_false(
70
+ self,
71
+ temporal_condition_solver: TemporalConditionSolver,
72
+ interval: Interval,
73
+ ):
74
+ solution: list[Interval] = temporal_condition_solver.solve(
75
+ condition=lambda _: False,
76
+ interval=interval,
77
+ )
78
+
79
+ assert isinstance(solution, list)
80
+ assert solution == []
81
+
82
+ def test_solve_success_multiple_conditions_always_true(
83
+ self,
84
+ temporal_condition_solver: TemporalConditionSolver,
85
+ interval: Interval,
86
+ ):
87
+ solution: list[Interval] = temporal_condition_solver.solve(
88
+ conditions=[
89
+ lambda _: True,
90
+ lambda _: True,
91
+ ],
92
+ interval=interval,
93
+ )
94
+
95
+ assert isinstance(solution, list)
96
+ assert solution == [interval]
97
+
98
+ def test_solve_success_multiple_conditions_one_always_false(
99
+ self,
100
+ temporal_condition_solver: TemporalConditionSolver,
101
+ interval: Interval,
102
+ ):
103
+ solution: list[Interval] = temporal_condition_solver.solve(
104
+ conditions=[
105
+ lambda _: True,
106
+ lambda _: False,
107
+ ],
108
+ interval=interval,
109
+ )
110
+
111
+ assert isinstance(solution, list)
112
+ assert solution == []
113
+
114
+ def test_solve_success_using_access_generator(
115
+ self,
116
+ temporal_condition_solver: TemporalConditionSolver,
117
+ interval: Interval,
118
+ ):
119
+ environment = Environment.default()
120
+
121
+ generator = Generator(
122
+ environment=environment,
123
+ )
124
+
125
+ earth = environment.access_celestial_object_with_name("Earth")
126
+
127
+ trajectory = Orbit(
128
+ model=Kepler(
129
+ coe=COE(
130
+ semi_major_axis=Length.kilometers(7000.0),
131
+ eccentricity=0.0,
132
+ inclination=Angle.degrees(45.0),
133
+ raan=Angle.degrees(0.0),
134
+ aop=Angle.degrees(0.0),
135
+ true_anomaly=Angle.degrees(0.0),
136
+ ),
137
+ epoch=Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC),
138
+ celestial_object=earth,
139
+ perturbation_type=Kepler.PerturbationType.No,
140
+ ),
141
+ celestial_object=earth,
142
+ )
143
+
144
+ solution: list[Interval] = temporal_condition_solver.solve(
145
+ condition=generator.get_condition_function(
146
+ from_trajectory=trajectory,
147
+ to_trajectory=trajectory,
148
+ ),
149
+ interval=interval,
150
+ )
151
+
152
+ assert isinstance(solution, list)
153
+ assert solution == [interval]
@@ -0,0 +1,128 @@
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
+ RealInterval = mathematics.object.RealInterval
14
+ Quaternion = mathematics.geometry.d3.transformation.rotation.Quaternion
15
+ Length = physics.unit.Length
16
+ Angle = physics.unit.Angle
17
+ DateTime = physics.time.DateTime
18
+ Scale = physics.time.Scale
19
+ Duration = physics.time.Duration
20
+ Instant = physics.time.Instant
21
+ Interval = physics.time.Interval
22
+ Transform = physics.coordinate.Transform
23
+ Frame = physics.coordinate.Frame
24
+ Axes = physics.coordinate.Axes
25
+ DynamicProvider = physics.coordinate.frame.provider.Dynamic
26
+ Environment = physics.Environment
27
+ Earth = physics.environment.object.celestial.Earth
28
+ Trajectory = astrodynamics.Trajectory
29
+ Profile = astrodynamics.flight.Profile
30
+ Orbit = astrodynamics.trajectory.Orbit
31
+ State = astrodynamics.trajectory.State
32
+ Pass = astrodynamics.trajectory.orbit.Pass
33
+ Kepler = astrodynamics.trajectory.orbit.model.Kepler
34
+ COE = astrodynamics.trajectory.orbit.model.kepler.COE
35
+ SGP4 = astrodynamics.trajectory.orbit.model.sgp4
36
+ Access = astrodynamics.Access
37
+
38
+
39
+ def test_access_constructors():
40
+ acquisition_of_signal = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
41
+ time_at_closest_approach = Instant.date_time(DateTime(2018, 1, 1, 0, 1, 0), Scale.UTC)
42
+ loss_of_signal = Instant.date_time(DateTime(2018, 1, 1, 0, 2, 0), Scale.UTC)
43
+ max_elevation = Angle.degrees(54.3)
44
+
45
+ access: Access = Access(
46
+ Access.Type.Complete,
47
+ acquisition_of_signal,
48
+ time_at_closest_approach,
49
+ loss_of_signal,
50
+ max_elevation,
51
+ )
52
+
53
+ assert access is not None
54
+ assert isinstance(access, Access)
55
+
56
+
57
+ def test_access_undefined():
58
+ access: Access = Access.undefined()
59
+
60
+ assert access is not None
61
+ assert isinstance(access, Access)
62
+ assert access.is_defined() is False
63
+
64
+
65
+ def test_access_getters():
66
+ acquisition_of_signal = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
67
+ time_at_closest_approach = Instant.date_time(DateTime(2018, 1, 1, 0, 1, 0), Scale.UTC)
68
+ loss_of_signal = Instant.date_time(DateTime(2018, 1, 1, 0, 2, 0), Scale.UTC)
69
+ max_elevation = Angle.degrees(54.3)
70
+
71
+ access: Access = Access(
72
+ Access.Type.Complete,
73
+ acquisition_of_signal,
74
+ time_at_closest_approach,
75
+ loss_of_signal,
76
+ max_elevation,
77
+ )
78
+
79
+ # get_type
80
+ access_type: Access.Type = access.get_type()
81
+
82
+ assert access_type is not None
83
+ assert isinstance(access_type, Access.Type)
84
+ assert access_type == Access.Type.Complete
85
+
86
+ # get_acquisition_of_signal
87
+ acq_signal: Instant = access.get_acquisition_of_signal()
88
+
89
+ assert acq_signal is not None
90
+ assert isinstance(acq_signal, Instant)
91
+ assert acq_signal == acquisition_of_signal
92
+
93
+ # get_time_of_closest_approach
94
+ closest_approach: Instant = access.get_time_of_closest_approach()
95
+
96
+ assert closest_approach is not None
97
+ assert isinstance(closest_approach, Instant)
98
+ assert closest_approach == time_at_closest_approach
99
+
100
+ # get_loss_of_signal
101
+ loss_signal: Instant = access.get_loss_of_signal()
102
+
103
+ assert loss_signal is not None
104
+ assert isinstance(loss_signal, Instant)
105
+ assert loss_signal == loss_of_signal
106
+
107
+ # get_interval
108
+ interval = access.get_interval()
109
+ assert interval is not None
110
+ assert isinstance(interval, Interval)
111
+
112
+ # get_duration
113
+ duration: Duration = access.get_duration()
114
+
115
+ assert duration is not None
116
+ assert isinstance(duration, Duration)
117
+
118
+ # get_max_elevation
119
+ max_el: Angle = access.get_max_elevation()
120
+
121
+ assert max_el is not None
122
+ assert isinstance(max_el, Angle)
123
+
124
+
125
+ def test_access_string_from_type():
126
+ assert Access.string_from_type(Access.Type.Undefined) == "Undefined"
127
+ assert Access.string_from_type(Access.Type.Complete) == "Complete"
128
+ assert Access.string_from_type(Access.Type.Partial) == "Partial"