open-space-toolkit-astrodynamics 12.0.1__py39-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.0.1.dist-info/METADATA +30 -0
- open_space_toolkit_astrodynamics-12.0.1.dist-info/RECORD +100 -0
- open_space_toolkit_astrodynamics-12.0.1.dist-info/WHEEL +5 -0
- open_space_toolkit_astrodynamics-12.0.1.dist-info/top_level.txt +1 -0
- open_space_toolkit_astrodynamics-12.0.1.dist-info/zip-safe +1 -0
- ostk/__init__.py +1 -0
- ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-39-x86_64-linux-gnu.so +0 -0
- ostk/astrodynamics/__init__.py +11 -0
- ostk/astrodynamics/converters.py +128 -0
- ostk/astrodynamics/dataframe.py +477 -0
- ostk/astrodynamics/display.py +220 -0
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.12 +0 -0
- ostk/astrodynamics/pytrajectory/__init__.py +1 -0
- ostk/astrodynamics/pytrajectory/pystate.py +196 -0
- ostk/astrodynamics/test/__init__.py +1 -0
- ostk/astrodynamics/test/access/__init__.py +1 -0
- ostk/astrodynamics/test/access/test_generator.py +248 -0
- ostk/astrodynamics/test/conftest.py +119 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/__init__.py +1 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/conftest.py +325 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/data/cdm.json +303 -0
- ostk/astrodynamics/test/conjunction/message/ccsds/test_cdm.py +416 -0
- ostk/astrodynamics/test/dynamics/__init__.py +1 -0
- ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity.csv +565 -0
- ostk/astrodynamics/test/dynamics/data/Tabulated_Earth_Gravity_Truth.csv +100 -0
- ostk/astrodynamics/test/dynamics/test_atmospheric_drag.py +128 -0
- ostk/astrodynamics/test/dynamics/test_central_body_gravity.py +58 -0
- ostk/astrodynamics/test/dynamics/test_dynamics.py +50 -0
- ostk/astrodynamics/test/dynamics/test_position_derivative.py +51 -0
- ostk/astrodynamics/test/dynamics/test_tabulated.py +138 -0
- ostk/astrodynamics/test/dynamics/test_third_body_gravity.py +67 -0
- ostk/astrodynamics/test/dynamics/test_thruster.py +142 -0
- ostk/astrodynamics/test/event_condition/test_angular_condition.py +113 -0
- ostk/astrodynamics/test/event_condition/test_boolean_condition.py +55 -0
- ostk/astrodynamics/test/event_condition/test_coe_condition.py +87 -0
- ostk/astrodynamics/test/event_condition/test_instant_condition.py +48 -0
- ostk/astrodynamics/test/event_condition/test_logical_condition.py +120 -0
- ostk/astrodynamics/test/event_condition/test_real_condition.py +50 -0
- ostk/astrodynamics/test/flight/__init__.py +1 -0
- ostk/astrodynamics/test/flight/system/__init__.py +1 -0
- ostk/astrodynamics/test/flight/system/test_propulsion_system.py +73 -0
- ostk/astrodynamics/test/flight/system/test_satellite_system.py +91 -0
- ostk/astrodynamics/test/flight/system/test_satellite_system_builder.py +71 -0
- ostk/astrodynamics/test/flight/test_maneuver.py +212 -0
- ostk/astrodynamics/test/flight/test_profile.py +242 -0
- ostk/astrodynamics/test/flight/test_system.py +55 -0
- ostk/astrodynamics/test/guidance_law/test_constant_thrust.py +91 -0
- ostk/astrodynamics/test/guidance_law/test_qlaw.py +138 -0
- ostk/astrodynamics/test/solvers/__init__.py +1 -0
- ostk/astrodynamics/test/solvers/test_finite_difference_solver.py +181 -0
- ostk/astrodynamics/test/solvers/test_temporal_condition_solver.py +153 -0
- ostk/astrodynamics/test/test_access.py +128 -0
- ostk/astrodynamics/test/test_converters.py +290 -0
- ostk/astrodynamics/test/test_dataframe.py +875 -0
- ostk/astrodynamics/test/test_display.py +114 -0
- ostk/astrodynamics/test/test_event_condition.py +58 -0
- ostk/astrodynamics/test/test_import.py +26 -0
- ostk/astrodynamics/test/test_root_solver.py +70 -0
- ostk/astrodynamics/test/test_trajectory.py +40 -0
- ostk/astrodynamics/test/test_utilities.py +106 -0
- ostk/astrodynamics/test/test_viewer.py +129 -0
- ostk/astrodynamics/test/trajectory/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/message/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/conftest.py +18 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/data/opm_1.yaml +44 -0
- ostk/astrodynamics/test/trajectory/orbit/message/spacex/test_opm.py +108 -0
- ostk/astrodynamics/test/trajectory/orbit/models/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean.py +65 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_long.py +102 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_brouwer_lyddane_mean_short.py +102 -0
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py +167 -0
- ostk/astrodynamics/test/trajectory/orbit/models/sgp4/__init__.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/sgp4/test_tle.py +331 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_kepler.py +130 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_propagated.py +234 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_sgp4.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/models/test_tabulated.py +380 -0
- ostk/astrodynamics/test/trajectory/orbit/test_model.py +1 -0
- ostk/astrodynamics/test/trajectory/orbit/test_pass.py +75 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_angular_velocity.py +30 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_attitude_quaternion.py +18 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_position.py +107 -0
- ostk/astrodynamics/test/trajectory/state/coordinate_subset/test_cartesian_velocity.py +115 -0
- ostk/astrodynamics/test/trajectory/state/test_coordinate_broker.py +84 -0
- ostk/astrodynamics/test/trajectory/state/test_coordinate_subset.py +46 -0
- ostk/astrodynamics/test/trajectory/state/test_numerical_solver.py +314 -0
- ostk/astrodynamics/test/trajectory/test_local_orbital_frame_direction.py +81 -0
- ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py +108 -0
- ostk/astrodynamics/test/trajectory/test_model.py +1 -0
- ostk/astrodynamics/test/trajectory/test_orbit.py +196 -0
- ostk/astrodynamics/test/trajectory/test_propagator.py +458 -0
- ostk/astrodynamics/test/trajectory/test_segment.py +305 -0
- ostk/astrodynamics/test/trajectory/test_sequence.py +477 -0
- ostk/astrodynamics/test/trajectory/test_state.py +375 -0
- ostk/astrodynamics/test/trajectory/test_state_builder.py +171 -0
- ostk/astrodynamics/utilities.py +245 -0
- 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,242 @@
|
|
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_get_state_at(self, profile: Profile, instant: Instant):
|
138
|
+
state: State = profile.get_state_at(instant)
|
139
|
+
|
140
|
+
assert state is not None
|
141
|
+
assert isinstance(state, State)
|
142
|
+
state.is_defined()
|
143
|
+
|
144
|
+
def test_get_states_at(self, profile: Profile, instant: Instant):
|
145
|
+
states = profile.get_states_at([instant, instant])
|
146
|
+
|
147
|
+
assert states is not None
|
148
|
+
|
149
|
+
def test_get_axes_at(self, profile: Profile, instant: Instant):
|
150
|
+
axes = profile.get_axes_at(instant)
|
151
|
+
|
152
|
+
assert axes is not None
|
153
|
+
assert isinstance(axes, Axes)
|
154
|
+
|
155
|
+
def test_get_body_frame(self, profile: Profile):
|
156
|
+
if Frame.exists("Name"):
|
157
|
+
Frame.destruct("Name")
|
158
|
+
|
159
|
+
frame = profile.get_body_frame("Name")
|
160
|
+
|
161
|
+
assert frame is not None
|
162
|
+
assert isinstance(frame, Frame)
|
163
|
+
|
164
|
+
def test_undefined(self):
|
165
|
+
profile: Profile = Profile.undefined()
|
166
|
+
|
167
|
+
assert profile is not None
|
168
|
+
assert isinstance(profile, Profile)
|
169
|
+
assert profile.is_defined() is False
|
170
|
+
|
171
|
+
def test_inertial_pointing(self):
|
172
|
+
quaternion: Quaternion = Quaternion([0.0, 0.0, 0.0, 1.0], Quaternion.Format.XYZS)
|
173
|
+
|
174
|
+
trajectory: Trajectory = Trajectory.position(
|
175
|
+
Position.meters((0.0, 0.0, 0.0), Frame.GCRF())
|
176
|
+
)
|
177
|
+
|
178
|
+
profile: Profile = Profile.inertial_pointing(trajectory, quaternion)
|
179
|
+
|
180
|
+
assert profile is not None
|
181
|
+
assert isinstance(profile, Profile)
|
182
|
+
assert profile.is_defined()
|
183
|
+
|
184
|
+
def test_nadir_pointing(
|
185
|
+
self,
|
186
|
+
orbit: Orbit,
|
187
|
+
):
|
188
|
+
profile: Profile = Profile.nadir_pointing(orbit, Orbit.FrameType.VVLH)
|
189
|
+
|
190
|
+
assert profile is not None
|
191
|
+
assert isinstance(profile, Profile)
|
192
|
+
assert profile.is_defined()
|
193
|
+
|
194
|
+
def test_custom_pointing(
|
195
|
+
self,
|
196
|
+
orbit: Orbit,
|
197
|
+
alignment_target: Profile.Target,
|
198
|
+
clocking_target: Profile.Target,
|
199
|
+
):
|
200
|
+
profile = Profile.custom_pointing(
|
201
|
+
orbit, Profile.align_and_constrain(alignment_target, clocking_target)
|
202
|
+
)
|
203
|
+
|
204
|
+
assert profile is not None
|
205
|
+
assert profile.is_defined()
|
206
|
+
|
207
|
+
def test_align_and_constrain(
|
208
|
+
self,
|
209
|
+
orbit: Orbit,
|
210
|
+
instant: Instant,
|
211
|
+
alignment_target: Profile.Target,
|
212
|
+
clocking_target: Profile.Target,
|
213
|
+
):
|
214
|
+
orientation = Profile.align_and_constrain(
|
215
|
+
alignment_target=alignment_target,
|
216
|
+
clocking_target=clocking_target,
|
217
|
+
)
|
218
|
+
|
219
|
+
assert orientation is not None
|
220
|
+
assert orientation(orbit.get_state_at(instant)) is not None
|
221
|
+
|
222
|
+
def test_custom_pointing(
|
223
|
+
self,
|
224
|
+
orbit: Orbit,
|
225
|
+
alignment_target: Profile.Target,
|
226
|
+
clocking_target: Profile.Target,
|
227
|
+
):
|
228
|
+
profile = Profile.custom_pointing(
|
229
|
+
orbit, Profile.align_and_constrain(alignment_target, clocking_target)
|
230
|
+
)
|
231
|
+
|
232
|
+
assert profile is not None
|
233
|
+
assert profile.is_defined()
|
234
|
+
|
235
|
+
profile = Profile.custom_pointing(
|
236
|
+
orbit,
|
237
|
+
alignment_target,
|
238
|
+
clocking_target,
|
239
|
+
)
|
240
|
+
|
241
|
+
assert profile is not None
|
242
|
+
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
|