open-space-toolkit-astrodynamics 12.2.1__py312-none-manylinux2014_aarch64.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/METADATA +30 -0
- open_space_toolkit_astrodynamics-12.2.1.dist-info/RECORD +100 -0
- open_space_toolkit_astrodynamics-12.2.1.dist-info/WHEEL +5 -0
- open_space_toolkit_astrodynamics-12.2.1.dist-info/top_level.txt +1 -0
- open_space_toolkit_astrodynamics-12.2.1.dist-info/zip-safe +1 -0
- ostk/__init__.py +1 -0
- ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-312-aarch64-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 +220 -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 +118 -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 +180 -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 +467 -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
|
+
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"
|