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,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
|