open-space-toolkit-astrodynamics 12.2.1__py312-none-manylinux2014_x86_64.whl → 12.3.1__py312-none-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {open_space_toolkit_astrodynamics-12.2.1.dist-info → open_space_toolkit_astrodynamics-12.3.1.dist-info}/METADATA +2 -2
- {open_space_toolkit_astrodynamics-12.2.1.dist-info → open_space_toolkit_astrodynamics-12.3.1.dist-info}/RECORD +17 -17
- ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-312-x86_64-linux-gnu.so +0 -0
- ostk/astrodynamics/converters.py +2 -0
- ostk/astrodynamics/dataframe.py +3 -1
- ostk/astrodynamics/display.py +2 -0
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.12 +0 -0
- ostk/astrodynamics/pytrajectory/pystate.py +41 -10
- ostk/astrodynamics/test/flight/test_profile.py +11 -0
- ostk/astrodynamics/test/test_event_condition.py +27 -7
- ostk/astrodynamics/test/trajectory/test_segment.py +99 -1
- ostk/astrodynamics/test/trajectory/test_sequence.py +53 -0
- ostk/astrodynamics/test/trajectory/test_state.py +76 -0
- ostk/astrodynamics/utilities.py +2 -0
- {open_space_toolkit_astrodynamics-12.2.1.dist-info → open_space_toolkit_astrodynamics-12.3.1.dist-info}/WHEEL +0 -0
- {open_space_toolkit_astrodynamics-12.2.1.dist-info → open_space_toolkit_astrodynamics-12.3.1.dist-info}/top_level.txt +0 -0
- {open_space_toolkit_astrodynamics-12.2.1.dist-info → open_space_toolkit_astrodynamics-12.3.1.dist-info}/zip-safe +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: open-space-toolkit-astrodynamics
|
3
|
-
Version: 12.
|
3
|
+
Version: 12.3.1
|
4
4
|
Summary: Orbit, attitude, access.
|
5
5
|
Author: Open Space Collective
|
6
6
|
Author-email: contact@open-space-collective.org
|
@@ -13,7 +13,7 @@ Classifier: Operating System :: POSIX :: Linux
|
|
13
13
|
Description-Content-Type: text/markdown
|
14
14
|
Requires-Dist: open-space-toolkit-core ~=4.1
|
15
15
|
Requires-Dist: open-space-toolkit-io ~=4.0
|
16
|
-
Requires-Dist: open-space-toolkit-mathematics ~=4.
|
16
|
+
Requires-Dist: open-space-toolkit-mathematics ~=4.3
|
17
17
|
Requires-Dist: open-space-toolkit-physics ~=10.1
|
18
18
|
|
19
19
|
# Open Space Toolkit ▸ Astrodynamics
|
@@ -1,21 +1,21 @@
|
|
1
1
|
ostk/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
|
2
|
-
ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-312-x86_64-linux-gnu.so,sha256=
|
2
|
+
ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-312-x86_64-linux-gnu.so,sha256=HGNVJBFpq-zdbqD9VGcAR_rzqfBWCoHtZfS7pBL0oW0,2471960
|
3
3
|
ostk/astrodynamics/__init__.py,sha256=3gWyqFIbhAfcdeMhmfBPQPlPQTmaOzm-6flkJe745Zk,251
|
4
|
-
ostk/astrodynamics/converters.py,sha256=
|
5
|
-
ostk/astrodynamics/dataframe.py,sha256=
|
6
|
-
ostk/astrodynamics/display.py,sha256=
|
7
|
-
ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.12,sha256=
|
8
|
-
ostk/astrodynamics/utilities.py,sha256=
|
4
|
+
ostk/astrodynamics/converters.py,sha256=luPh30qMp9bzEkN7hUccmxlLf7zRp_AzqmBe8IUjPhU,3314
|
5
|
+
ostk/astrodynamics/dataframe.py,sha256=9fXRk7sJl_OrBTCjZC_TFx6JMPE7IDGqv2JgEmGCdgM,18775
|
6
|
+
ostk/astrodynamics/display.py,sha256=LZESZgx2wlrFO4cwAGMb3VPJfdtcjNgCgKFrqot0NYU,6339
|
7
|
+
ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.12,sha256=d7BxOKEmIzb92U4QFrZxKhAAYhjPkJRCmpp51B_Rnus,87167760
|
8
|
+
ostk/astrodynamics/utilities.py,sha256=mlKL3WrOASrY_pLt7bzUz0XZT7jagzLOZjMOIqjbQ1Y,6999
|
9
9
|
ostk/astrodynamics/viewer.py,sha256=8UxqsvU5wui7gPUwxXaKcIB-509NJiih9Df3mQgXyXY,11776
|
10
10
|
ostk/astrodynamics/pytrajectory/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
|
11
|
-
ostk/astrodynamics/pytrajectory/pystate.py,sha256=
|
11
|
+
ostk/astrodynamics/pytrajectory/pystate.py,sha256=zyQon4c-bemdl_PBFWrXV_VVchpvbkEBRod8ospAuFA,7867
|
12
12
|
ostk/astrodynamics/test/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
|
13
13
|
ostk/astrodynamics/test/conftest.py,sha256=stmQOt7UXjBlXKJzNN6RkS2miv1xXSOX-YNpFhaHTqI,2771
|
14
14
|
ostk/astrodynamics/test/test_access.py,sha256=MCBsUPtuVm7NgHZR0z0DpWnPZ_qBu4aRhLI2PnRNUYs,3940
|
15
15
|
ostk/astrodynamics/test/test_converters.py,sha256=mFpDD0YM8o356lj91GGIwYdMk2ut6xZFV3uYcgZepMY,8744
|
16
16
|
ostk/astrodynamics/test/test_dataframe.py,sha256=IJMOODzTVYtiPxekmltH6lOMArPXbHwSEAl-jg0Ab2g,28414
|
17
17
|
ostk/astrodynamics/test/test_display.py,sha256=Ykvw2rUWWw8jsX0Suy11X27bHjwm_ira__xj0ZyHHxw,3672
|
18
|
-
ostk/astrodynamics/test/test_event_condition.py,sha256=
|
18
|
+
ostk/astrodynamics/test/test_event_condition.py,sha256=RSO2L5x3D8grWW4t7WK-aTMl7vFOMpj6F3ByN3EaovY,2175
|
19
19
|
ostk/astrodynamics/test/test_import.py,sha256=py_hALBR0IYuUzv9dfgQZzrrLHJIpnyKvt3Oi1XBqCg,1251
|
20
20
|
ostk/astrodynamics/test/test_root_solver.py,sha256=hQ8O6g-WP49gZH_H3Rdufv0F0gQorpzJyIcjBGGUQ34,1831
|
21
21
|
ostk/astrodynamics/test/test_trajectory.py,sha256=0sgGPkMFy-u-33z6SF-sTvaBb_NU7OvaeMTVF6wevfY,3148
|
@@ -45,7 +45,7 @@ ostk/astrodynamics/test/event_condition/test_logical_condition.py,sha256=09h5TYW
|
|
45
45
|
ostk/astrodynamics/test/event_condition/test_real_condition.py,sha256=tle6HVzMFMIIkfRY7CuaA0mPtw3riJBG_JQkc1L0dpk,1374
|
46
46
|
ostk/astrodynamics/test/flight/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
|
47
47
|
ostk/astrodynamics/test/flight/test_maneuver.py,sha256=6LhnNhaiwId-IveUraHnhx8dYxeOgzntP_WPtv9GFjQ,6197
|
48
|
-
ostk/astrodynamics/test/flight/test_profile.py,sha256
|
48
|
+
ostk/astrodynamics/test/flight/test_profile.py,sha256=mV5ru4odPTxg3nkiMjRbDzzXK3hkAyOsv_wLYiD60ho,7815
|
49
49
|
ostk/astrodynamics/test/flight/test_system.py,sha256=MVaE7lJYisH4vmJPD-G-Hw4wNj-Xe8yMksgu8IXCLvg,1322
|
50
50
|
ostk/astrodynamics/test/flight/system/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
|
51
51
|
ostk/astrodynamics/test/flight/system/test_propulsion_system.py,sha256=jLUC74YjIQz7APr-kQcdYRYiKm8lfequjosptG29kmI,1964
|
@@ -62,9 +62,9 @@ ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py,sha256=hX
|
|
62
62
|
ostk/astrodynamics/test/trajectory/test_model.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
|
63
63
|
ostk/astrodynamics/test/trajectory/test_orbit.py,sha256=iKVgScEo1osMIXjON4ToURCgp2LDZV18fKQuy49RktI,6484
|
64
64
|
ostk/astrodynamics/test/trajectory/test_propagator.py,sha256=dG31S5FY0NjJ5bnisqJ_HdL7amj_AZAWWLiOmdHfJAc,14233
|
65
|
-
ostk/astrodynamics/test/trajectory/test_segment.py,sha256=
|
66
|
-
ostk/astrodynamics/test/trajectory/test_sequence.py,sha256=
|
67
|
-
ostk/astrodynamics/test/trajectory/test_state.py,sha256=
|
65
|
+
ostk/astrodynamics/test/trajectory/test_segment.py,sha256=4XacBFrX8ZkS-OLDWyIs7kqDa2vG9UQ5guMXVl5ecJk,12275
|
66
|
+
ostk/astrodynamics/test/trajectory/test_sequence.py,sha256=iCNDDqEGoo4WZIOOov0qKGzrxjg7yWVIk8ajfKMhgI4,14503
|
67
|
+
ostk/astrodynamics/test/trajectory/test_state.py,sha256=8B7KVlxZZPzwwsfCrTudeSkTTC2wAjXcglB0PZdjD1Y,15688
|
68
68
|
ostk/astrodynamics/test/trajectory/test_state_builder.py,sha256=PSlXtmGURCrlf0w50tn3dEBRo6p0x4NmIF9gJsNOR3k,4782
|
69
69
|
ostk/astrodynamics/test/trajectory/orbit/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
|
70
70
|
ostk/astrodynamics/test/trajectory/orbit/test_model.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
|
@@ -93,8 +93,8 @@ ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_angular_velocity
|
|
93
93
|
ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_attitude_quaternion.py,sha256=UEu9ApzQLmT87eeISw6_gcHTlX-4b2scIvHz-uE1p_c,393
|
94
94
|
ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_position.py,sha256=XvHdk1KjacTwtkgx2jUAc9I9N3nvjPDv03FAanpv8jQ,2702
|
95
95
|
ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_velocity.py,sha256=-kd5TZO5TICihbkqDTew2i_tDpggdpe3Yf23046FATM,3057
|
96
|
-
open_space_toolkit_astrodynamics-12.
|
97
|
-
open_space_toolkit_astrodynamics-12.
|
98
|
-
open_space_toolkit_astrodynamics-12.
|
99
|
-
open_space_toolkit_astrodynamics-12.
|
100
|
-
open_space_toolkit_astrodynamics-12.
|
96
|
+
open_space_toolkit_astrodynamics-12.3.1.dist-info/METADATA,sha256=mde0fmiPmEGDLf9bAhf49xo7FbtLJmvTh5ZQKYIgkjc,1917
|
97
|
+
open_space_toolkit_astrodynamics-12.3.1.dist-info/WHEEL,sha256=zu14iyvFQQM13lKzfs39VKk9HB677YiFl5ToD7bb_JU,110
|
98
|
+
open_space_toolkit_astrodynamics-12.3.1.dist-info/top_level.txt,sha256=zOR18699uDYnafgarhL8WU_LmTZY_5NVqutv-flp_x4,5
|
99
|
+
open_space_toolkit_astrodynamics-12.3.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
100
|
+
open_space_toolkit_astrodynamics-12.3.1.dist-info/RECORD,,
|
Binary file
|
ostk/astrodynamics/converters.py
CHANGED
ostk/astrodynamics/dataframe.py
CHANGED
ostk/astrodynamics/display.py
CHANGED
Binary file
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# Apache License 2.0
|
2
2
|
|
3
|
-
|
4
3
|
# Python-only State functionality
|
4
|
+
import re
|
5
|
+
|
5
6
|
import numpy as np
|
6
7
|
|
7
8
|
from ostk.physics.coordinate import Frame
|
@@ -17,6 +18,8 @@ from ostk.astrodynamics.trajectory.state.coordinate_subset import (
|
|
17
18
|
AngularVelocity,
|
18
19
|
)
|
19
20
|
|
21
|
+
CANONICAL_FORMAT: str = r"(r|v)_(.*?)_(x|y|z)"
|
22
|
+
|
20
23
|
|
21
24
|
@staticmethod
|
22
25
|
def custom_class_generator(frame: Frame, coordinate_subsets: list) -> type:
|
@@ -45,14 +48,17 @@ def custom_class_generator(frame: Frame, coordinate_subsets: list) -> type:
|
|
45
48
|
def from_dict(data: dict) -> State:
|
46
49
|
"""
|
47
50
|
Create a State from a dictionary.
|
51
|
+
|
52
|
+
Note: Implicit assumption that ECEF = ITRF, and ECI = GCRF.
|
53
|
+
|
48
54
|
The dictionary must contain the following:
|
49
55
|
- 'timestamp': The timestamp of the state.
|
50
|
-
- 'rx'/'
|
51
|
-
- 'ry'/'
|
52
|
-
- 'rz'/'
|
53
|
-
- 'vx'/'vx_eci'/'vx_ecef': The x-coordinate of the velocity.
|
54
|
-
- 'vy'/'vy_eci'/'vy_ecef': The y-coordinate of the velocity.
|
55
|
-
- 'vz'/'vz_eci'/'vz_ecef': The z-coordinate of the velocity.
|
56
|
+
- 'r_ITRF_x'/'rx'/'rx_eci'/'rx_ecef': The x-coordinate of the position.
|
57
|
+
- 'r_ITRF_y'/'ry'/'ry_eci'/'ry_ecef': The y-coordinate of the position.
|
58
|
+
- 'r_ITRF_z'/'rz'/'rz_eci'/'rz_ecef': The z-coordinate of the position.
|
59
|
+
- 'v_ITRF_x'/'vx'/'vx_eci'/'vx_ecef': The x-coordinate of the velocity.
|
60
|
+
- 'v_ITRF_y'/'vy'/'vy_eci'/'vy_ecef': The y-coordinate of the velocity.
|
61
|
+
- 'v_ITRF_z'/'vz'/'vz_eci'/'vz_ecef': The z-coordinate of the velocity.
|
56
62
|
- 'frame': The frame of the state. Required if 'rx', 'ry', 'rz', 'vx', 'vy', 'vz' are provided.
|
57
63
|
- 'q_B_ECI_x': The x-coordinate of the quaternion. Optional.
|
58
64
|
- 'q_B_ECI_y': The y-coordinate of the quaternion. Optional.
|
@@ -65,7 +71,6 @@ def from_dict(data: dict) -> State:
|
|
65
71
|
- 'cross_sectional_area'/'surface_area': The cross-sectional area. Optional.
|
66
72
|
- 'mass': The mass. Optional.
|
67
73
|
|
68
|
-
|
69
74
|
Args:
|
70
75
|
data (dict): The dictionary.
|
71
76
|
|
@@ -100,6 +105,17 @@ def from_dict(data: dict) -> State:
|
|
100
105
|
"vz",
|
101
106
|
]
|
102
107
|
|
108
|
+
# Replace non-standard position keys with canonical representation
|
109
|
+
if all(key in data.keys() for key in ("x_eci", "y_eci", "z_eci")):
|
110
|
+
data["rx_eci"] = data["x_eci"]
|
111
|
+
data["ry_eci"] = data["y_eci"]
|
112
|
+
data["rz_eci"] = data["z_eci"]
|
113
|
+
|
114
|
+
if all(key in data.keys() for key in ("x_ecef", "y_ecef", "z_ecef")):
|
115
|
+
data["rx_ecef"] = data["x_ecef"]
|
116
|
+
data["ry_ecef"] = data["y_ecef"]
|
117
|
+
data["rz_ecef"] = data["z_ecef"]
|
118
|
+
|
103
119
|
frame: Frame
|
104
120
|
coordinates: np.ndarray
|
105
121
|
|
@@ -108,8 +124,21 @@ def from_dict(data: dict) -> State:
|
|
108
124
|
CartesianVelocity.default(),
|
109
125
|
]
|
110
126
|
|
111
|
-
|
112
|
-
|
127
|
+
match_groups: list[re.Match] = [
|
128
|
+
re.match(CANONICAL_FORMAT, column) for column in data.keys()
|
129
|
+
]
|
130
|
+
|
131
|
+
if len(matches := [match for match in match_groups if match is not None]) == 6:
|
132
|
+
frame_name: str = matches[0].group(2)
|
133
|
+
try:
|
134
|
+
frame: Frame = Frame.with_name(frame_name) or getattr(Frame, frame_name)()
|
135
|
+
except Exception:
|
136
|
+
raise ValueError(f"No frame exists with name [{frame_name}].")
|
137
|
+
|
138
|
+
coordinates = np.array([data[match.group(0)] for match in matches])
|
139
|
+
|
140
|
+
elif all(column in data for column in eci_columns):
|
141
|
+
frame: Frame = Frame.GCRF()
|
113
142
|
coordinates = np.array(
|
114
143
|
[
|
115
144
|
data["rx_eci"],
|
@@ -120,6 +149,7 @@ def from_dict(data: dict) -> State:
|
|
120
149
|
data["vz_eci"],
|
121
150
|
]
|
122
151
|
)
|
152
|
+
|
123
153
|
elif all(column in data for column in ecef_columns):
|
124
154
|
frame = Frame.ITRF()
|
125
155
|
coordinates = np.array(
|
@@ -132,6 +162,7 @@ def from_dict(data: dict) -> State:
|
|
132
162
|
data["vz_ecef"],
|
133
163
|
]
|
134
164
|
)
|
165
|
+
|
135
166
|
elif all(column in data for column in generic_columns):
|
136
167
|
if "frame" not in data:
|
137
168
|
raise ValueError("Frame must be provided for generic columns.")
|
@@ -134,6 +134,17 @@ class TestProfile:
|
|
134
134
|
assert alignment_target is not None
|
135
135
|
assert isinstance(alignment_target, Profile.Target)
|
136
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
|
+
|
137
148
|
def test_get_state_at(self, profile: Profile, instant: Instant):
|
138
149
|
state: State = profile.get_state_at(instant)
|
139
150
|
|
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
import pytest
|
4
4
|
|
5
|
+
from ostk.physics.time import Instant
|
6
|
+
from ostk.physics.coordinate import Position, Velocity, Frame
|
7
|
+
|
8
|
+
from ostk.astrodynamics.trajectory import State
|
5
9
|
from ostk.astrodynamics import EventCondition
|
6
10
|
|
7
11
|
|
@@ -12,7 +16,7 @@ def name() -> str:
|
|
12
16
|
|
13
17
|
@pytest.fixture
|
14
18
|
def evaluator() -> callable:
|
15
|
-
return lambda state:
|
19
|
+
return lambda state: 5.0
|
16
20
|
|
17
21
|
|
18
22
|
@pytest.fixture
|
@@ -22,7 +26,7 @@ def target_value() -> float:
|
|
22
26
|
|
23
27
|
@pytest.fixture
|
24
28
|
def target(target_value: float) -> EventCondition.Target:
|
25
|
-
return EventCondition.Target(target_value, EventCondition.Target.Type.
|
29
|
+
return EventCondition.Target(target_value, EventCondition.Target.Type.Relative)
|
26
30
|
|
27
31
|
|
28
32
|
@pytest.fixture
|
@@ -32,12 +36,13 @@ def event_condition(
|
|
32
36
|
class MyEventCondition(EventCondition):
|
33
37
|
def is_satisfied(
|
34
38
|
self,
|
35
|
-
|
36
|
-
|
37
|
-
previous_state_vector,
|
38
|
-
previous_time,
|
39
|
+
current_state,
|
40
|
+
previous_state,
|
39
41
|
):
|
40
|
-
return
|
42
|
+
return (
|
43
|
+
current_state.get_position().get_coordinates()[2] > 0.0
|
44
|
+
and previous_state.get_position().get_coordinates()[2] < 0.0
|
45
|
+
)
|
41
46
|
|
42
47
|
return MyEventCondition(name, evaluator, target)
|
43
48
|
|
@@ -56,3 +61,18 @@ class TestEventCondition:
|
|
56
61
|
self, event_condition: EventCondition, target: EventCondition.Target
|
57
62
|
):
|
58
63
|
assert event_condition.get_target() == target
|
64
|
+
|
65
|
+
def test_update_target(
|
66
|
+
self,
|
67
|
+
event_condition: EventCondition,
|
68
|
+
):
|
69
|
+
current_target_value_offset: float = event_condition.get_target().value_offset
|
70
|
+
event_condition.update_target(
|
71
|
+
State(
|
72
|
+
Instant.J2000(),
|
73
|
+
Position.meters([0.0, 0.0, 0.0], Frame.GCRF()),
|
74
|
+
Velocity.meters_per_second([0.0, 0.0, 0.0], Frame.GCRF()),
|
75
|
+
)
|
76
|
+
)
|
77
|
+
|
78
|
+
assert event_condition.get_target().value_offset != current_target_value_offset
|
@@ -11,8 +11,8 @@ from ostk.physics.time import Duration
|
|
11
11
|
from ostk.physics.coordinate import Frame
|
12
12
|
from ostk.physics.environment.object.celestial import Earth
|
13
13
|
|
14
|
-
from ostk.astrodynamics.flight import Maneuver
|
15
14
|
from ostk.astrodynamics.flight.system import SatelliteSystem
|
15
|
+
from ostk.astrodynamics import Dynamics
|
16
16
|
from ostk.astrodynamics.dynamics import CentralBodyGravity
|
17
17
|
from ostk.astrodynamics.dynamics import PositionDerivative
|
18
18
|
from ostk.astrodynamics.dynamics import Thruster
|
@@ -135,6 +135,104 @@ def thruster_dynamics() -> Thruster:
|
|
135
135
|
)
|
136
136
|
|
137
137
|
|
138
|
+
@pytest.fixture
|
139
|
+
def segment_solution(dynamics: list[Dynamics], state: State) -> Segment.Solution:
|
140
|
+
return Segment.Solution(
|
141
|
+
name="A Segment",
|
142
|
+
dynamics=dynamics,
|
143
|
+
states=[
|
144
|
+
state,
|
145
|
+
],
|
146
|
+
condition_is_satisfied=True,
|
147
|
+
segment_type=Segment.Type.Coast,
|
148
|
+
)
|
149
|
+
|
150
|
+
|
151
|
+
class TestSegmentSolution:
|
152
|
+
def test_constructors(
|
153
|
+
self,
|
154
|
+
segment_solution: Segment.Solution,
|
155
|
+
):
|
156
|
+
assert segment_solution is not None
|
157
|
+
assert segment_solution.name is not None
|
158
|
+
assert segment_solution.dynamics is not None
|
159
|
+
assert segment_solution.states is not None
|
160
|
+
assert segment_solution.condition_is_satisfied is not None
|
161
|
+
assert segment_solution.segment_type is not None
|
162
|
+
|
163
|
+
def test_getters_and_accessors(
|
164
|
+
self,
|
165
|
+
segment_solution: Segment.Solution,
|
166
|
+
):
|
167
|
+
assert segment_solution.access_start_instant() is not None
|
168
|
+
assert segment_solution.access_end_instant() is not None
|
169
|
+
assert segment_solution.get_interval() is not None
|
170
|
+
assert segment_solution.get_initial_mass() is not None
|
171
|
+
assert segment_solution.get_final_mass() is not None
|
172
|
+
assert segment_solution.get_propagation_duration() is not None
|
173
|
+
|
174
|
+
def test_compute_delta_v(
|
175
|
+
self,
|
176
|
+
segment_solution: Segment.Solution,
|
177
|
+
):
|
178
|
+
assert segment_solution.compute_delta_v(1500.0) is not None
|
179
|
+
|
180
|
+
def test_compute_delta_mass(
|
181
|
+
self,
|
182
|
+
segment_solution: Segment.Solution,
|
183
|
+
):
|
184
|
+
assert segment_solution.compute_delta_mass() is not None
|
185
|
+
|
186
|
+
@pytest.mark.skip(reason="Not implemented yet")
|
187
|
+
def test_extract_maneuvers(
|
188
|
+
self,
|
189
|
+
segment_solution: Segment.Solution,
|
190
|
+
):
|
191
|
+
assert segment_solution.extract_maneuvers(Frame.GCRF()) is not None
|
192
|
+
|
193
|
+
def test_calculate_states_at(
|
194
|
+
self,
|
195
|
+
segment_solution: Segment.Solution,
|
196
|
+
):
|
197
|
+
assert (
|
198
|
+
segment_solution.calculate_states_at(
|
199
|
+
[
|
200
|
+
segment_solution.states[0].get_instant(),
|
201
|
+
],
|
202
|
+
NumericalSolver.default_conditional(),
|
203
|
+
)
|
204
|
+
is not None
|
205
|
+
)
|
206
|
+
|
207
|
+
def get_dynamics_contribution(
|
208
|
+
self,
|
209
|
+
segment_solution: Segment.Solution,
|
210
|
+
):
|
211
|
+
assert (
|
212
|
+
segment_solution.get_dynamics_contribution(
|
213
|
+
segment_solution.dynamics[0], Frame.GCRF()
|
214
|
+
)
|
215
|
+
is not None
|
216
|
+
)
|
217
|
+
|
218
|
+
def get_dynamics_acceleration_contribution(
|
219
|
+
self,
|
220
|
+
segment_solution: Segment.Solution,
|
221
|
+
):
|
222
|
+
assert (
|
223
|
+
segment_solution.get_dynamics_acceleration_contribution(
|
224
|
+
segment_solution.dynamics[0], Frame.GCRF()
|
225
|
+
)
|
226
|
+
is not None
|
227
|
+
)
|
228
|
+
|
229
|
+
def get_all_dynamics_contributions(
|
230
|
+
self,
|
231
|
+
segment_solution: Segment.Solution,
|
232
|
+
):
|
233
|
+
assert segment_solution.get_all_dynamics_contributions(Frame.GCRF()) is not None
|
234
|
+
|
235
|
+
|
138
236
|
class TestSegment:
|
139
237
|
def test_get_name(self, coast_duration_segment: Segment, name: str):
|
140
238
|
assert coast_duration_segment.get_name() == name
|
@@ -339,6 +339,59 @@ def instants(state: State) -> list[Instant]:
|
|
339
339
|
return [state.get_instant(), state.get_instant() + Duration.minutes(1.0)]
|
340
340
|
|
341
341
|
|
342
|
+
@pytest.fixture
|
343
|
+
def sequence_solution(
|
344
|
+
segment_solution: Segment.Solution,
|
345
|
+
):
|
346
|
+
return Sequence.Solution(
|
347
|
+
segment_solutions=[
|
348
|
+
segment_solution,
|
349
|
+
],
|
350
|
+
execution_is_complete=True,
|
351
|
+
)
|
352
|
+
|
353
|
+
|
354
|
+
class TestSequenceSolution:
|
355
|
+
def test_properties(
|
356
|
+
self,
|
357
|
+
sequence_solution: Sequence.Solution,
|
358
|
+
):
|
359
|
+
assert sequence_solution is not None
|
360
|
+
assert len(sequence_solution.segment_solutions) == 1
|
361
|
+
assert sequence_solution.execution_is_complete
|
362
|
+
|
363
|
+
def test_getters_and_accessors(
|
364
|
+
self,
|
365
|
+
sequence_solution: Sequence.Solution,
|
366
|
+
):
|
367
|
+
assert sequence_solution.access_start_instant() is not None
|
368
|
+
assert sequence_solution.access_end_instant() is not None
|
369
|
+
|
370
|
+
assert sequence_solution.get_states() is not None
|
371
|
+
assert sequence_solution.get_initial_mass() is not None
|
372
|
+
assert sequence_solution.get_final_mass() is not None
|
373
|
+
assert sequence_solution.get_propagation_duration() is not None
|
374
|
+
|
375
|
+
assert sequence_solution.compute_delta_mass() is not None
|
376
|
+
assert sequence_solution.compute_delta_v(1500.0) is not None
|
377
|
+
|
378
|
+
def test_calculate_states_at(
|
379
|
+
self,
|
380
|
+
sequence_solution: Sequence.Solution,
|
381
|
+
numerical_solver: NumericalSolver,
|
382
|
+
):
|
383
|
+
instants: list[Instant] = sequence_solution.get_interval().generate_grid(
|
384
|
+
Duration.seconds(10.0)
|
385
|
+
)
|
386
|
+
states: list[State] = sequence_solution.calculate_states_at(
|
387
|
+
instants,
|
388
|
+
numerical_solver,
|
389
|
+
)
|
390
|
+
|
391
|
+
assert states is not None
|
392
|
+
assert len(states) == len(instants)
|
393
|
+
|
394
|
+
|
342
395
|
class TestSequence:
|
343
396
|
def test_get_segments(
|
344
397
|
self,
|
@@ -407,6 +407,82 @@ class TestState:
|
|
407
407
|
assert isinstance(state, State)
|
408
408
|
assert state.get_size() == 7
|
409
409
|
|
410
|
+
@pytest.mark.parametrize(
|
411
|
+
("data", "expected_length", "expected_frame"),
|
412
|
+
[
|
413
|
+
(
|
414
|
+
{
|
415
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
416
|
+
"r_GCRF_x": 1.0,
|
417
|
+
"r_GCRF_y": 2.0,
|
418
|
+
"r_GCRF_z": 3.0,
|
419
|
+
"v_GCRF_x": 4.0,
|
420
|
+
"v_GCRF_y": 5.0,
|
421
|
+
"v_GCRF_z": 6.0,
|
422
|
+
},
|
423
|
+
6,
|
424
|
+
Frame.GCRF(),
|
425
|
+
),
|
426
|
+
(
|
427
|
+
{
|
428
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
429
|
+
"r_ITRF_x": 1.0,
|
430
|
+
"r_ITRF_y": 2.0,
|
431
|
+
"r_ITRF_z": 3.0,
|
432
|
+
"v_ITRF_x": 4.0,
|
433
|
+
"v_ITRF_y": 5.0,
|
434
|
+
"v_ITRF_z": 6.0,
|
435
|
+
},
|
436
|
+
6,
|
437
|
+
Frame.ITRF(),
|
438
|
+
),
|
439
|
+
],
|
440
|
+
)
|
441
|
+
def test_from_dict_cannonical_success(
|
442
|
+
self, data: dict, expected_length: int, expected_frame: Frame
|
443
|
+
):
|
444
|
+
state: State = State.from_dict(data)
|
445
|
+
|
446
|
+
assert state is not None
|
447
|
+
assert isinstance(state, State)
|
448
|
+
|
449
|
+
assert state.get_size() == expected_length
|
450
|
+
assert state.get_frame() == expected_frame
|
451
|
+
|
452
|
+
@pytest.mark.parametrize(
|
453
|
+
("data", "expected_failure_message"),
|
454
|
+
[
|
455
|
+
(
|
456
|
+
{
|
457
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
458
|
+
"r_GCRF_x": 1.0,
|
459
|
+
"r_GCRF_y": 2.0,
|
460
|
+
"r_GCRF_z": 3.0,
|
461
|
+
"v_GCRF_x": 4.0,
|
462
|
+
"v_GCRF_y": 5.0,
|
463
|
+
},
|
464
|
+
"Invalid state data.",
|
465
|
+
),
|
466
|
+
(
|
467
|
+
{
|
468
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
469
|
+
"r_TEST_x": 1.0,
|
470
|
+
"r_TEST_y": 2.0,
|
471
|
+
"r_TEST_z": 3.0,
|
472
|
+
"v_TEST_x": 4.0,
|
473
|
+
"v_TEST_y": 5.0,
|
474
|
+
"v_TEST_z": 6.0,
|
475
|
+
},
|
476
|
+
"No frame exists with name \\[TEST\\].",
|
477
|
+
),
|
478
|
+
],
|
479
|
+
)
|
480
|
+
def test_from_dict_cannonical_failure(
|
481
|
+
self, data: dict, expected_failure_message: str
|
482
|
+
):
|
483
|
+
with pytest.raises(ValueError, match=expected_failure_message):
|
484
|
+
State.from_dict(data)
|
485
|
+
|
410
486
|
def test_comparators(self, state: State):
|
411
487
|
assert (state == state) is True
|
412
488
|
assert (state != state) is False
|
ostk/astrodynamics/utilities.py
CHANGED
File without changes
|
File without changes
|
File without changes
|