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,115 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.physics.time import Instant
6
+ from ostk.physics.coordinate import Frame
7
+
8
+ from ostk.astrodynamics.trajectory.state import CoordinateBroker, CoordinateSubset
9
+ from ostk.astrodynamics.trajectory.state.coordinate_subset import (
10
+ CartesianVelocity,
11
+ CartesianPosition,
12
+ )
13
+
14
+
15
+ @pytest.fixture
16
+ def name() -> str:
17
+ return "Position"
18
+
19
+
20
+ @pytest.fixture
21
+ def cartesian_position() -> CartesianPosition:
22
+ return CartesianPosition.default()
23
+
24
+
25
+ @pytest.fixture
26
+ def cartesian_velocity() -> CartesianVelocity:
27
+ return CartesianVelocity.default()
28
+
29
+
30
+ @pytest.fixture
31
+ def coordinate_subsets(
32
+ cartesian_position: CartesianPosition, cartesian_velocity: CartesianVelocity
33
+ ) -> list[CoordinateSubset]:
34
+ return [cartesian_position, cartesian_velocity]
35
+
36
+
37
+ @pytest.fixture
38
+ def instant() -> Instant:
39
+ return Instant.J2000()
40
+
41
+
42
+ @pytest.fixture
43
+ def frame() -> Frame:
44
+ return Frame.GCRF()
45
+
46
+
47
+ @pytest.fixture
48
+ def coordinate_broker(
49
+ coordinate_subsets: list[CoordinateSubset],
50
+ ) -> CoordinateBroker:
51
+ return CoordinateBroker(coordinate_subsets)
52
+
53
+
54
+ @pytest.fixture
55
+ def coordinates() -> list[float]:
56
+ return [7000000.0, 0.0, 0.0, 0.0, 5335.865450622126, 5335.865450622126]
57
+
58
+
59
+ @pytest.fixture
60
+ def another_coordinates() -> list[float]:
61
+ return [0.0, 7000000.0, 0.0, 5335.865450622126, 0.0, 0.0]
62
+
63
+
64
+ class TestCartesianVelocity:
65
+ def test_constructor(self, name: str):
66
+ assert CartesianVelocity(CartesianPosition.default(), name) is not None
67
+
68
+ def test_add(
69
+ self,
70
+ cartesian_velocity: CartesianVelocity,
71
+ instant: Instant,
72
+ frame: Frame,
73
+ coordinates: list[float],
74
+ another_coordinates: list[float],
75
+ coordinate_broker: CoordinateBroker,
76
+ ):
77
+ assert all(
78
+ cartesian_velocity.add(
79
+ instant, coordinates, another_coordinates, frame, coordinate_broker
80
+ )
81
+ == [5335.865450622126, 5335.865450622126, 5335.865450622126]
82
+ )
83
+
84
+ def test_subtract(
85
+ self,
86
+ cartesian_velocity: CartesianVelocity,
87
+ instant: Instant,
88
+ frame: Frame,
89
+ coordinates: list[float],
90
+ another_coordinates: list[float],
91
+ coordinate_broker: CoordinateBroker,
92
+ ):
93
+ assert all(
94
+ cartesian_velocity.subtract(
95
+ instant, coordinates, another_coordinates, frame, coordinate_broker
96
+ )
97
+ == [-5335.865450622126, 5335.865450622126, 5335.865450622126]
98
+ )
99
+
100
+ def test_in_frame(
101
+ self,
102
+ cartesian_velocity: CartesianVelocity,
103
+ instant: Instant,
104
+ frame: Frame,
105
+ coordinates: list[float],
106
+ another_coordinates: list[float],
107
+ coordinate_broker: CoordinateBroker,
108
+ ):
109
+ for value, expected in zip(
110
+ cartesian_velocity.in_frame(
111
+ instant, coordinates, frame, Frame.ITRF(), coordinate_broker
112
+ ),
113
+ [-4749.36551256577, 854.163395375881, 5335.71857543495],
114
+ ):
115
+ assert value == pytest.approx(expected, rel=1e-14)
@@ -0,0 +1,84 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.astrodynamics.trajectory.state import CoordinateBroker, CoordinateSubset
6
+
7
+
8
+ @pytest.fixture
9
+ def coordinate_subsets() -> list:
10
+ return [CoordinateSubset("Subset1", 2), CoordinateSubset("Subset2", 3)]
11
+
12
+
13
+ @pytest.fixture
14
+ def coordinate_broker(coordinate_subsets) -> CoordinateBroker:
15
+ return CoordinateBroker(coordinate_subsets)
16
+
17
+
18
+ @pytest.fixture
19
+ def coordinates() -> list[float]:
20
+ return [1.0, 2.0, 3.0, 4.0, 5.0]
21
+
22
+
23
+ class TestCoordinateBroker:
24
+ def test_constructor(self, coordinate_broker: CoordinateBroker):
25
+ assert coordinate_broker is not None
26
+
27
+ def test_eq(self, coordinate_broker: CoordinateBroker):
28
+ assert coordinate_broker == coordinate_broker
29
+
30
+ def test_ne(self, coordinate_broker: CoordinateBroker):
31
+ assert (coordinate_broker != coordinate_broker) == False
32
+
33
+ def test_access_subsets(
34
+ self, coordinate_broker: CoordinateBroker, coordinate_subsets: list
35
+ ):
36
+ assert coordinate_broker.access_subsets() == coordinate_subsets
37
+
38
+ def test_get_number_of_coordinates(self, coordinate_broker: CoordinateBroker):
39
+ assert coordinate_broker.get_number_of_coordinates() == 5
40
+
41
+ def test_get_number_of_subsets(self, coordinate_broker: CoordinateBroker):
42
+ assert coordinate_broker.get_number_of_subsets() == 2
43
+
44
+ def test_get_subsets(
45
+ self, coordinate_broker: CoordinateBroker, coordinate_subsets: list
46
+ ):
47
+ assert coordinate_broker.get_subsets() == coordinate_subsets
48
+
49
+ def test_add_subset(self, coordinate_broker: CoordinateBroker):
50
+ new_subset = CoordinateSubset("NewSubset", 4)
51
+ number_of_coordinates = coordinate_broker.get_number_of_coordinates()
52
+ assert coordinate_broker.add_subset(new_subset) == number_of_coordinates
53
+ assert coordinate_broker.has_subset(new_subset)
54
+
55
+ def test_has_subset(
56
+ self, coordinate_broker: CoordinateBroker, coordinate_subsets: list
57
+ ):
58
+ assert coordinate_broker.has_subset(coordinate_subsets[0])
59
+
60
+ def test_extract_coordinate(
61
+ self,
62
+ coordinate_broker: CoordinateBroker,
63
+ coordinates: list[float],
64
+ coordinate_subsets: list[CoordinateSubset],
65
+ ):
66
+ assert (
67
+ coordinate_broker.extract_coordinate(coordinates, coordinate_subsets[0])
68
+ == [1.0, 2.0]
69
+ ).all()
70
+ assert (
71
+ coordinate_broker.extract_coordinate(coordinates, coordinate_subsets[1])
72
+ == [3.0, 4.0, 5.0]
73
+ ).all()
74
+
75
+ def test_extract_coordinates(
76
+ self,
77
+ coordinate_broker: CoordinateBroker,
78
+ coordinates: list[float],
79
+ coordinate_subsets: list[CoordinateSubset],
80
+ ):
81
+ assert (
82
+ coordinate_broker.extract_coordinates(coordinates, coordinate_subsets)
83
+ == [1.0, 2.0, 3.0, 4.0, 5.0]
84
+ ).all()
@@ -0,0 +1,46 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.astrodynamics.trajectory.state import CoordinateSubset
6
+
7
+
8
+ @pytest.fixture
9
+ def name() -> str:
10
+ return "MySubset"
11
+
12
+
13
+ @pytest.fixture
14
+ def size() -> int:
15
+ return 3
16
+
17
+
18
+ @pytest.fixture
19
+ def coordinate_subset(name: str, size: int) -> CoordinateSubset:
20
+ return CoordinateSubset(name, size)
21
+
22
+
23
+ class TestCoordinateSubset:
24
+ def test_constructor(self, coordinate_subset: CoordinateSubset):
25
+ assert coordinate_subset is not None
26
+
27
+ def test_eq(self, coordinate_subset: CoordinateSubset):
28
+ assert coordinate_subset == coordinate_subset
29
+
30
+ def test_ne(self, coordinate_subset: CoordinateSubset):
31
+ assert (coordinate_subset != coordinate_subset) == False
32
+
33
+ def test_hash(self, coordinate_subset: CoordinateSubset):
34
+ assert hash(coordinate_subset) is not None
35
+
36
+ def test_get_id(self, coordinate_subset: CoordinateSubset):
37
+ assert coordinate_subset.get_id() is not None
38
+
39
+ def test_get_name(self, coordinate_subset: CoordinateSubset, name: str):
40
+ assert coordinate_subset.get_name() == name
41
+
42
+ def test_get_size(self, coordinate_subset: CoordinateSubset, size: int):
43
+ assert coordinate_subset.get_size() == size
44
+
45
+ def test_mass(self):
46
+ assert CoordinateSubset.mass() is not None
@@ -0,0 +1,314 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ import numpy as np
6
+ import math
7
+
8
+ from ostk.physics.time import Instant, Duration
9
+ from ostk.physics.coordinate import Frame
10
+
11
+ from ostk.astrodynamics.trajectory import State
12
+ from ostk.astrodynamics.trajectory.state import (
13
+ NumericalSolver,
14
+ CoordinateBroker,
15
+ CoordinateSubset,
16
+ )
17
+ from ostk.astrodynamics.event_condition import RealCondition
18
+
19
+
20
+ def oscillator(x, dxdt, _):
21
+ dxdt[0] = x[1]
22
+ dxdt[1] = -x[0]
23
+ return dxdt
24
+
25
+
26
+ def get_state_vec(time: float) -> np.ndarray:
27
+ return np.array([math.sin(time), math.cos(time)])
28
+
29
+
30
+ @pytest.fixture
31
+ def coordinate_subsets() -> list[CoordinateSubset]:
32
+ return [CoordinateSubset("Subset", 2)]
33
+
34
+
35
+ @pytest.fixture
36
+ def coordinate_broker(
37
+ coordinate_subsets: list[CoordinateSubset],
38
+ ) -> CoordinateBroker:
39
+ return CoordinateBroker(coordinate_subsets)
40
+
41
+
42
+ @pytest.fixture
43
+ def start_instant() -> Instant:
44
+ return Instant.J2000()
45
+
46
+
47
+ @pytest.fixture
48
+ def frame() -> Frame:
49
+ return Frame.GCRF()
50
+
51
+
52
+ @pytest.fixture
53
+ def initial_state(
54
+ start_instant: Instant,
55
+ frame: Frame,
56
+ coordinate_broker: CoordinateBroker,
57
+ ) -> State:
58
+ return State(start_instant, get_state_vec(0.0), frame, coordinate_broker)
59
+
60
+
61
+ @pytest.fixture
62
+ def custom_condition() -> RealCondition:
63
+ return RealCondition(
64
+ "Custom",
65
+ RealCondition.Criterion.StrictlyPositive,
66
+ lambda state: (state.get_instant() - Instant.J2000()).in_seconds(),
67
+ 5.0,
68
+ )
69
+
70
+
71
+ @pytest.fixture
72
+ def log_type() -> NumericalSolver.LogType:
73
+ return NumericalSolver.LogType.NoLog
74
+
75
+
76
+ @pytest.fixture
77
+ def variable_size_stepper_type() -> NumericalSolver.StepperType:
78
+ return NumericalSolver.StepperType.RungeKuttaCashKarp54
79
+
80
+
81
+ @pytest.fixture
82
+ def fixed_size_stepper_type() -> NumericalSolver.StepperType:
83
+ return NumericalSolver.StepperType.RungeKutta4
84
+
85
+
86
+ @pytest.fixture
87
+ def initial_time_step() -> float:
88
+ return 5.0
89
+
90
+
91
+ @pytest.fixture
92
+ def relative_tolerance() -> float:
93
+ return 1.0e-15
94
+
95
+
96
+ @pytest.fixture
97
+ def absolute_tolerance() -> float:
98
+ return 1.0e-15
99
+
100
+
101
+ @pytest.fixture
102
+ def state_logger() -> callable:
103
+ def log_state(state: State) -> None:
104
+ print(state.get_coordinates())
105
+
106
+ return log_state
107
+
108
+
109
+ @pytest.fixture
110
+ def numerical_solver(
111
+ log_type: NumericalSolver.LogType,
112
+ variable_size_stepper_type: NumericalSolver.StepperType,
113
+ initial_time_step: float,
114
+ relative_tolerance: float,
115
+ absolute_tolerance: float,
116
+ ) -> NumericalSolver:
117
+ return NumericalSolver(
118
+ log_type=log_type,
119
+ stepper_type=variable_size_stepper_type,
120
+ time_step=initial_time_step,
121
+ relative_tolerance=relative_tolerance,
122
+ absolute_tolerance=absolute_tolerance,
123
+ )
124
+
125
+
126
+ @pytest.fixture
127
+ def numerical_solver_conditional() -> NumericalSolver:
128
+ return NumericalSolver.default_conditional()
129
+
130
+
131
+ class TestNumericalSolver:
132
+ def test_constructors(self, numerical_solver: NumericalSolver):
133
+ assert numerical_solver is not None
134
+ assert isinstance(numerical_solver, NumericalSolver)
135
+ assert numerical_solver.is_defined()
136
+
137
+ def test_comparators(self, numerical_solver: NumericalSolver):
138
+ assert numerical_solver == numerical_solver
139
+ assert (numerical_solver != numerical_solver) is False
140
+
141
+ def test_get_types(
142
+ self,
143
+ log_type: NumericalSolver.LogType,
144
+ variable_size_stepper_type: NumericalSolver.StepperType,
145
+ initial_time_step: float,
146
+ relative_tolerance: float,
147
+ absolute_tolerance: float,
148
+ numerical_solver: NumericalSolver,
149
+ ):
150
+ assert numerical_solver.get_log_type() == log_type
151
+ assert numerical_solver.get_stepper_type() == variable_size_stepper_type
152
+ assert numerical_solver.get_time_step() == initial_time_step
153
+ assert numerical_solver.get_relative_tolerance() == relative_tolerance
154
+ assert numerical_solver.get_absolute_tolerance() == absolute_tolerance
155
+ assert numerical_solver.get_root_solver() is not None
156
+ assert numerical_solver.get_observed_states() is not None
157
+
158
+ def test_get_string_from_types(self):
159
+ assert (
160
+ NumericalSolver.string_from_stepper_type(
161
+ NumericalSolver.StepperType.RungeKutta4
162
+ )
163
+ == "RungeKutta4"
164
+ )
165
+ assert (
166
+ NumericalSolver.string_from_stepper_type(
167
+ NumericalSolver.StepperType.RungeKuttaCashKarp54
168
+ )
169
+ == "RungeKuttaCashKarp54"
170
+ )
171
+ assert (
172
+ NumericalSolver.string_from_stepper_type(
173
+ NumericalSolver.StepperType.RungeKuttaFehlberg78
174
+ )
175
+ == "RungeKuttaFehlberg78"
176
+ )
177
+ assert (
178
+ NumericalSolver.string_from_log_type(NumericalSolver.LogType.NoLog) == "NoLog"
179
+ )
180
+ assert (
181
+ NumericalSolver.string_from_log_type(NumericalSolver.LogType.LogConstant)
182
+ == "LogConstant"
183
+ )
184
+ assert (
185
+ NumericalSolver.string_from_log_type(NumericalSolver.LogType.LogAdaptive)
186
+ == "LogAdaptive"
187
+ )
188
+
189
+ def test_integrate_time(
190
+ self,
191
+ initial_state: State,
192
+ numerical_solver: NumericalSolver,
193
+ ):
194
+ duration_seconds: float = 10.0
195
+ end_instant: Instant = initial_state.get_instant() + Duration.seconds(
196
+ duration_seconds
197
+ )
198
+
199
+ state_vector: np.ndarray = numerical_solver.integrate_time(
200
+ initial_state, end_instant, oscillator
201
+ ).get_coordinates()
202
+
203
+ assert 5e-9 >= abs(state_vector[0] - math.sin(duration_seconds))
204
+ assert 5e-9 >= abs(state_vector[1] - math.cos(duration_seconds))
205
+
206
+ end_instants: list[Instant] = [
207
+ initial_state.get_instant() + Duration.seconds(duration)
208
+ for duration in np.arange(60.0, 100.0, 20.0)
209
+ ]
210
+ states: list[State] = numerical_solver.integrate_time(
211
+ initial_state, end_instants, oscillator
212
+ )
213
+
214
+ for state, end_instant in zip(states, end_instants):
215
+ state_vector: np.ndarray = state.get_coordinates()
216
+
217
+ assert 5e-9 >= abs(
218
+ state_vector[0]
219
+ - math.sin((end_instant - initial_state.get_instant()).in_seconds())
220
+ )
221
+ assert 5e-9 >= abs(
222
+ state_vector[1]
223
+ - math.cos((end_instant - initial_state.get_instant()).in_seconds())
224
+ )
225
+
226
+ def test_integrate_time_with_condition(
227
+ self,
228
+ initial_state: State,
229
+ numerical_solver_conditional: NumericalSolver,
230
+ custom_condition: RealCondition,
231
+ ):
232
+ end_time: float = initial_state.get_instant() + Duration.seconds(100.0)
233
+
234
+ condition_solution = numerical_solver_conditional.integrate_time(
235
+ initial_state, end_time, oscillator, custom_condition
236
+ )
237
+
238
+ assert condition_solution.condition_is_satisfied
239
+ assert (
240
+ condition_solution.iteration_count
241
+ < numerical_solver_conditional.get_root_solver().get_maximum_iteration_count()
242
+ )
243
+ assert condition_solution.root_solver_has_converged
244
+
245
+ state_vector = condition_solution.state.get_coordinates()
246
+ time = (
247
+ condition_solution.state.get_instant() - initial_state.get_instant()
248
+ ).in_seconds()
249
+
250
+ assert abs(float(time - custom_condition.get_target().value)) < 1e-6
251
+
252
+ assert 5e-9 >= abs(state_vector[0] - math.sin(time))
253
+ assert 5e-9 >= abs(state_vector[1] - math.cos(time))
254
+
255
+ def test_integrate_conditional_with_logger(
256
+ self,
257
+ initial_state: State,
258
+ state_logger: callable,
259
+ custom_condition: RealCondition,
260
+ capsys,
261
+ ):
262
+ numerical_solver: NumericalSolver = NumericalSolver.conditional(
263
+ 5.0,
264
+ 1.0e-15,
265
+ 1.0e-15,
266
+ state_logger,
267
+ )
268
+ end_time: float = initial_state.get_instant() + Duration.seconds(10.0)
269
+
270
+ numerical_solver.integrate_time(
271
+ initial_state, end_time, oscillator, custom_condition
272
+ )
273
+
274
+ captured = capsys.readouterr()
275
+
276
+ assert captured.out != ""
277
+
278
+ def test_default(self):
279
+ assert NumericalSolver.default() is not None
280
+
281
+ def test_undefined(self):
282
+ assert NumericalSolver.undefined() is not None
283
+ assert NumericalSolver.undefined().is_defined() is False
284
+
285
+ def test_fixed_step_size(
286
+ self,
287
+ fixed_size_stepper_type: NumericalSolver.StepperType,
288
+ variable_size_stepper_type: NumericalSolver.StepperType,
289
+ initial_time_step: float,
290
+ ):
291
+ assert (
292
+ NumericalSolver.fixed_step_size(fixed_size_stepper_type, initial_time_step)
293
+ is not None
294
+ )
295
+ with pytest.raises(Exception):
296
+ NumericalSolver.fixed_step_size(variable_size_stepper_type, initial_time_step)
297
+
298
+ def test_default_conditional(self, state_logger):
299
+ assert NumericalSolver.default_conditional() is not None
300
+ assert NumericalSolver.default_conditional(state_logger) is not None
301
+
302
+ def test_conditional(
303
+ self,
304
+ initial_time_step: float,
305
+ relative_tolerance: float,
306
+ absolute_tolerance: float,
307
+ state_logger,
308
+ ):
309
+ assert (
310
+ NumericalSolver.conditional(
311
+ initial_time_step, relative_tolerance, absolute_tolerance, state_logger
312
+ )
313
+ is not None
314
+ )
@@ -0,0 +1,81 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.physics.coordinate import Frame
6
+
7
+ from ostk.astrodynamics.trajectory import LocalOrbitalFrameFactory
8
+ from ostk.astrodynamics.trajectory import LocalOrbitalFrameDirection
9
+
10
+
11
+ @pytest.fixture
12
+ def local_orbital_frame_factory() -> LocalOrbitalFrameFactory:
13
+ return LocalOrbitalFrameFactory.VNC(Frame.GCRF())
14
+
15
+
16
+ @pytest.fixture
17
+ def direction_vector() -> list:
18
+ return [1.0, 0.0, 0.0]
19
+
20
+
21
+ @pytest.fixture
22
+ def local_orbital_frame_direction(
23
+ direction_vector: list,
24
+ local_orbital_frame_factory: LocalOrbitalFrameFactory,
25
+ ) -> LocalOrbitalFrameDirection:
26
+ return LocalOrbitalFrameDirection(
27
+ vector=direction_vector,
28
+ local_orbital_frame_factory=local_orbital_frame_factory,
29
+ )
30
+
31
+
32
+ class TestLocalOrbitalFrameDirection:
33
+ def test_constructor(
34
+ self,
35
+ direction_vector: list,
36
+ local_orbital_frame_factory: LocalOrbitalFrameFactory,
37
+ ):
38
+ local_orbital_frame_direction: LocalOrbitalFrameDirection = (
39
+ LocalOrbitalFrameDirection(
40
+ direction_vector,
41
+ local_orbital_frame_factory,
42
+ )
43
+ )
44
+
45
+ assert local_orbital_frame_direction is not None
46
+ assert isinstance(local_orbital_frame_direction, LocalOrbitalFrameDirection)
47
+
48
+ def test_equal_to_operator(
49
+ self, local_orbital_frame_direction: LocalOrbitalFrameDirection
50
+ ):
51
+ assert local_orbital_frame_direction == local_orbital_frame_direction
52
+ assert local_orbital_frame_direction != LocalOrbitalFrameDirection(
53
+ [0.0, 1.0, 0.0],
54
+ local_orbital_frame_direction.get_local_orbital_frame_factory(),
55
+ )
56
+
57
+ def test_is_defined(
58
+ self,
59
+ local_orbital_frame_direction: LocalOrbitalFrameDirection,
60
+ ):
61
+ assert local_orbital_frame_direction.is_defined()
62
+
63
+ def test_getters(
64
+ self,
65
+ local_orbital_frame_direction: LocalOrbitalFrameDirection,
66
+ direction_vector: list,
67
+ local_orbital_frame_factory: LocalOrbitalFrameFactory,
68
+ ):
69
+ assert list(local_orbital_frame_direction.get_value()) == direction_vector
70
+ assert (
71
+ local_orbital_frame_direction.get_local_orbital_frame_factory()
72
+ == local_orbital_frame_factory
73
+ )
74
+
75
+ def test_undefined(
76
+ self,
77
+ ):
78
+ local_orbital_frame_direction: LocalOrbitalFrameDirection = (
79
+ LocalOrbitalFrameDirection.undefined()
80
+ )
81
+ assert local_orbital_frame_direction.is_defined() is False