open-space-toolkit-astrodynamics 5.2.3__py38-none-any.whl → 6.0.0__py38-none-any.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: open-space-toolkit-astrodynamics
3
- Version: 5.2.3
3
+ Version: 6.0.0
4
4
  Summary: Orbit, attitude, access.
5
5
  Author: Open Space Collective
6
6
  Author-email: contact@open-space-collective.org
@@ -1,10 +1,10 @@
1
1
  ostk/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
2
- ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-38-x86_64-linux-gnu.so,sha256=hpZmMHdWpPa_MlebALiHk183XMVDU8DIjFajYR75s_E,2021176
2
+ ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-38-x86_64-linux-gnu.so,sha256=EGHtnJpd0wKdCpQ473s1yTdLA1dqxkrpXWAhTFFaZ60,2025272
3
3
  ostk/astrodynamics/__init__.py,sha256=3gWyqFIbhAfcdeMhmfBPQPlPQTmaOzm-6flkJe745Zk,251
4
4
  ostk/astrodynamics/converters.py,sha256=IUxJK5qNzDMsqMSiMT6hUThCjncKoIMW0ifu8kwbww0,4680
5
5
  ostk/astrodynamics/display.py,sha256=y9FnoQbPFGM6LzkUdgXgeqtuVGhv57GuTKbeDdcFPgw,6306
6
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.5,sha256=3jQE-Lhjcsh6Fj8nNdGh1XKF9ZKrza9ZmcCcKJ75jh0,96785240
7
- ostk/astrodynamics/utilities.py,sha256=NbeKN_CtcCRHIinhoNWTEosBMR7xc924S-ZFD97mduw,4478
6
+ ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.6,sha256=pcm6fERimZWFhSlMWSmNP481pzxrFX3IMuqed3QVNZI,98626392
7
+ ostk/astrodynamics/utilities.py,sha256=PDexbTDbx46aYKqK5b4pjLYSY6NGc4Wx9FwafOkJ4EU,4821
8
8
  ostk/astrodynamics/viewer.py,sha256=B5m-eNWQrd4vIBqmT7-400IfHldxU5lFDTLpfHiiHj4,8910
9
9
  ostk/astrodynamics/pytrajectory/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
10
10
  ostk/astrodynamics/pytrajectory/pystate.py,sha256=ceNZWYCqtsXWJlE6JKDxB5qn5ixTWGOwrYXge21XPmk,1037
@@ -17,7 +17,7 @@ ostk/astrodynamics/test/test_event_condition.py,sha256=mhMTH7wAoYFWRYt_8l2d1vjNP
17
17
  ostk/astrodynamics/test/test_import.py,sha256=stS8jK9HiXyzRWjtDvaTqUrzCrOVnYVX5CkmQf7MJsA,1201
18
18
  ostk/astrodynamics/test/test_root_solver.py,sha256=hQ8O6g-WP49gZH_H3Rdufv0F0gQorpzJyIcjBGGUQ34,1831
19
19
  ostk/astrodynamics/test/test_trajectory.py,sha256=pvv4GQsvtU0XfWYk-F-oQNgo8ciFQBgzeJ4FojZDW-A,1364
20
- ostk/astrodynamics/test/test_utilities.py,sha256=edAPLXNMflCPa0gzhU4e05pa6HbAq7UV0JzMMRx3VlQ,3252
20
+ ostk/astrodynamics/test/test_utilities.py,sha256=YnJ7czgRjJ5bkYr33KF5wY5A-P0lJg2q0-_mI7spvYs,3620
21
21
  ostk/astrodynamics/test/test_viewer.py,sha256=i164XnG6n-_FteiO6rjXA7GGsJhMdmT-508DpKaveVY,3957
22
22
  ostk/astrodynamics/test/access/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
23
23
  ostk/astrodynamics/test/access/test_generator.py,sha256=6cwC5GGvnWLxPXmgRQ-N7tjorGUfPxA8qFcdGaTmpp4,8038
@@ -59,15 +59,15 @@ ostk/astrodynamics/test/trajectory/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZI
59
59
  ostk/astrodynamics/test/trajectory/test_local_orbital_frame_direction.py,sha256=d72J50UGG9m0Atei0UQ8sITU1WdJmws5xgUiacLZMbw,2515
60
60
  ostk/astrodynamics/test/trajectory/test_local_orbital_frame_factory.py,sha256=FziYh9XxD2FEuj6WhnqOe5mF9twLTQtvcem8KzQZKXg,1864
61
61
  ostk/astrodynamics/test/trajectory/test_model.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
62
- ostk/astrodynamics/test/trajectory/test_orbit.py,sha256=pr_bYN3H0LjReGy1xY56u9wMUG_PWZ8v68NTMG3qpsE,3436
62
+ ostk/astrodynamics/test/trajectory/test_orbit.py,sha256=dFZRN2E538lG6ZaiRBWUDMtKzgMIKnFILV3yeofRV1I,5075
63
63
  ostk/astrodynamics/test/trajectory/test_propagator.py,sha256=kEAvrFM4MZouAAnYPi91akPSXWHbGxHTo5uaXQKexII,12631
64
- ostk/astrodynamics/test/trajectory/test_segment.py,sha256=UxSyasdBQoaT7bTBlRoBxhQ3paHw1JRDR7GJzFTmf6M,8731
65
- ostk/astrodynamics/test/trajectory/test_sequence.py,sha256=uZdHNY7wAvkSMQEzNId3DWQOilsKdCEbqBd-AbqMYVE,12412
64
+ ostk/astrodynamics/test/trajectory/test_segment.py,sha256=5XSCPUVrE6_oz8tsZeAb9mzQoLUuyUlfgJ-rWP54-ao,9170
65
+ ostk/astrodynamics/test/trajectory/test_sequence.py,sha256=N3jPB31P4i13ocYITaVMLiMfczpATmDLVbNdImM68tQ,12909
66
66
  ostk/astrodynamics/test/trajectory/test_state.py,sha256=rW0HH7oy_tZ-34VIhk2rx_v2Kyg3xegBYpKs9_NznSs,6508
67
67
  ostk/astrodynamics/test/trajectory/test_state_builder.py,sha256=3C8JeN8VGgUzEASgh5PfnJQ2JWGkKYTm7eaelE6Lw7E,4815
68
68
  ostk/astrodynamics/test/trajectory/orbit/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
69
69
  ostk/astrodynamics/test/trajectory/orbit/test_model.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
70
- ostk/astrodynamics/test/trajectory/orbit/test_pass.py,sha256=MtPRKhVz4hCzfFuE0p1x89Ps68M9s7miT7VtPIDVeOo,1898
70
+ ostk/astrodynamics/test/trajectory/orbit/test_pass.py,sha256=p6YCtb-QhCS_En3ECaSM2sJsWEnqXzmWaCmai_SuK0U,2191
71
71
  ostk/astrodynamics/test/trajectory/orbit/messages/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
72
72
  ostk/astrodynamics/test/trajectory/orbit/messages/spacex/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
73
73
  ostk/astrodynamics/test/trajectory/orbit/messages/spacex/conftest.py,sha256=O75ywkPJjoFp0uKptCu4C2tGMRaGN-8NVFVhps85eWE,379
@@ -92,8 +92,8 @@ ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_angular_velocit
92
92
  ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_attitude_quaternion.py,sha256=B1Tni_YpKB9Fzb0fpXSokw9DjgiZem9uBATMQbcq8P4,394
93
93
  ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_cartesian_position.py,sha256=L3MpDG9MDHbK2HPZejqiY0QJdiEB-FZe0rVGDl379YA,2722
94
94
  ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_cartesian_velocity.py,sha256=k0aNqdMwwt-XSFQ1Si8kDTY79SB7fC0WWm2UNjpaOI0,3077
95
- open_space_toolkit_astrodynamics-5.2.3.dist-info/METADATA,sha256=uIQTdwc1p0cXtrJo1wlK_XECijh-aCkcPNR-_qIj0as,1777
96
- open_space_toolkit_astrodynamics-5.2.3.dist-info/WHEEL,sha256=LNQH4F1F9_Ua4GgazGQDFGQhQ8B1tSrkPIuEzIRv9nc,93
97
- open_space_toolkit_astrodynamics-5.2.3.dist-info/top_level.txt,sha256=zOR18699uDYnafgarhL8WU_LmTZY_5NVqutv-flp_x4,5
98
- open_space_toolkit_astrodynamics-5.2.3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
99
- open_space_toolkit_astrodynamics-5.2.3.dist-info/RECORD,,
95
+ open_space_toolkit_astrodynamics-6.0.0.dist-info/METADATA,sha256=S1Y1p4wX6YCRlOm_yajNftMXaoccfzjKuMcGCxvGSTw,1777
96
+ open_space_toolkit_astrodynamics-6.0.0.dist-info/WHEEL,sha256=LNQH4F1F9_Ua4GgazGQDFGQhQ8B1tSrkPIuEzIRv9nc,93
97
+ open_space_toolkit_astrodynamics-6.0.0.dist-info/top_level.txt,sha256=zOR18699uDYnafgarhL8WU_LmTZY_5NVqutv-flp_x4,5
98
+ open_space_toolkit_astrodynamics-6.0.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
99
+ open_space_toolkit_astrodynamics-6.0.0.dist-info/RECORD,,
@@ -23,12 +23,15 @@ State = astrodynamics.flight.profile.State
23
23
 
24
24
 
25
25
  class TestUtilities:
26
- def test_lla_from_state(self, state: State):
27
- lla: list = utilities.lla_from_state(state)
26
+ def test_lla_from_state(
27
+ self,
28
+ state: State,
29
+ ):
30
+ lla: tuple[float, float, float] = utilities.lla_from_state(state)
28
31
 
29
32
  assert lla is not None
30
33
  assert len(lla) == 3
31
- assert isinstance(lla, list)
34
+ assert isinstance(lla, tuple)
32
35
  assert isinstance(lla[0], float)
33
36
  assert lla[0] >= -90.0 and lla[0] <= 90.0
34
37
  assert isinstance(lla[1], float)
@@ -47,13 +50,16 @@ class TestUtilities:
47
50
  assert isinstance(lla, LLA)
48
51
  assert lla.is_defined()
49
52
 
50
- lla_from_state: list = utilities.lla_from_state(state)
53
+ lla_from_state: tuple[float, float, float] = utilities.lla_from_state(state)
51
54
 
52
55
  assert lla.get_latitude().in_degrees() == lla_from_state[0]
53
56
  assert lla.get_longitude().in_degrees() == lla_from_state[1]
54
57
  assert lla.get_altitude().in_meters() == lla_from_state[2]
55
58
 
56
- def test_position_from_lla(self, lla: LLA):
59
+ def test_position_from_lla(
60
+ self,
61
+ lla: LLA,
62
+ ):
57
63
  position: Position = utilities.position_from_lla(lla)
58
64
 
59
65
  assert position is not None
@@ -61,20 +67,28 @@ class TestUtilities:
61
67
  assert position.is_defined()
62
68
 
63
69
  def test_compute_aer(
64
- self, instant: Instant, position: Position, environment: Environment
70
+ self,
71
+ instant: Instant,
72
+ position: Position,
73
+ environment: Environment,
65
74
  ):
66
- aer: list = utilities.compute_aer(instant, position, position, environment)
75
+ aer: tuple[float, float, float] = utilities.compute_aer(
76
+ instant, position, position, environment
77
+ )
67
78
 
68
79
  assert aer is not None
69
80
  assert len(aer) == 3
70
81
  assert aer[2] == 0.0
71
82
 
72
83
  def test_compute_time_lla_aer_state(
73
- self, state: State, position: Position, environment: Environment
84
+ self,
85
+ state: State,
86
+ position: Position,
87
+ environment: Environment,
74
88
  ):
75
- time_lla_aer: list = utilities.compute_time_lla_aer_state(
76
- state, position, environment
77
- )
89
+ time_lla_aer: float[
90
+ Instant, float, float, float, float, float, float
91
+ ] = utilities.compute_time_lla_aer_state(state, position, environment)
78
92
 
79
93
  assert time_lla_aer is not None
80
94
  assert len(time_lla_aer) == 7
@@ -84,15 +98,21 @@ class TestUtilities:
84
98
  assert isinstance(time_lla_aer[i], float)
85
99
 
86
100
  def test_compute_trajectory_geometry(
87
- self, interval: Interval, trajectory: Trajectory
101
+ self,
102
+ interval: Interval,
103
+ trajectory: Trajectory,
88
104
  ):
89
- output: list = utilities.compute_trajectory_geometry(trajectory, interval)
105
+ output: list[tuple[float, float, float]] = utilities.compute_trajectory_geometry(
106
+ trajectory, interval
107
+ )
90
108
 
91
109
  assert output is not None
92
110
  assert len(output) == 2
93
111
 
94
- def test_convert_state(self, instant: Instant, state: State):
95
- output: list = utilities.convert_state(instant, state)
112
+ def test_convert_state(self, state: State):
113
+ output: tuple[
114
+ str, float, float, float, float, float, float, float, float, float
115
+ ] = utilities.convert_state(state)
96
116
 
97
117
  assert output is not None
98
118
  assert len(output) == 11
@@ -2,54 +2,65 @@
2
2
 
3
3
  import pytest
4
4
 
5
- import ostk.physics as physics
6
-
7
- import ostk.astrodynamics as astrodynamics
8
-
9
- Length = physics.units.Length
10
- Angle = physics.units.Angle
11
- Scale = physics.time.Scale
12
- Instant = physics.time.Instant
13
- Interval = physics.time.Interval
14
- DateTime = physics.time.DateTime
15
- Position = physics.coordinate.Position
16
- Velocity = physics.coordinate.Velocity
17
- Frame = physics.coordinate.Frame
18
- Environment = physics.Environment
19
-
20
- Trajectory = astrodynamics.Trajectory
21
- Model = astrodynamics.trajectory.Model
22
- Orbit = astrodynamics.trajectory.Orbit
23
- Pass = astrodynamics.trajectory.orbit.Pass
24
- Kepler = astrodynamics.trajectory.orbit.models.Kepler
25
- COE = astrodynamics.trajectory.orbit.models.kepler.COE
26
- SGP4 = astrodynamics.trajectory.orbit.models.SGP4
27
- TLE = astrodynamics.trajectory.orbit.models.sgp4.TLE
28
- State = astrodynamics.trajectory.State
29
- Access = astrodynamics.Access
5
+ from ostk.physics.time import Scale
6
+ from ostk.physics.time import Instant
7
+ from ostk.physics.time import Interval
8
+ from ostk.physics.time import DateTime
9
+ from ostk.physics import Environment
10
+
11
+ from ostk.astrodynamics.trajectory.orbit import Pass
30
12
 
31
13
  earth = Environment.default().access_celestial_object_with_name("Earth")
32
14
 
33
15
 
34
- def test_trajectory_orbit_pass():
35
- pass_type = Pass.Type.Partial
36
- pass_revolution_number = 123
37
- pass_start_instant = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
38
- pass_end_instant = Instant.date_time(DateTime(2018, 1, 1, 1, 0, 0), Scale.UTC)
39
- pass_interval = Interval.closed(pass_start_instant, pass_end_instant)
16
+ @pytest.fixture
17
+ def pass_() -> Pass:
18
+ return Pass(
19
+ 123,
20
+ Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC),
21
+ Instant.date_time(DateTime(2018, 1, 1, 0, 15, 0), Scale.UTC),
22
+ Instant.date_time(DateTime(2018, 1, 1, 0, 30, 0), Scale.UTC),
23
+ Instant.date_time(DateTime(2018, 1, 1, 0, 45, 0), Scale.UTC),
24
+ Instant.date_time(DateTime(2018, 1, 1, 1, 0, 0), Scale.UTC),
25
+ )
26
+
27
+
28
+ class TestPass:
29
+ def test_is_defined(self, pass_: Pass):
30
+ assert pass_.is_defined()
31
+
32
+ def test_is_complete(self, pass_: Pass):
33
+ assert pass_.is_complete() is not None
34
+
35
+ def test_get_type(self, pass_: Pass):
36
+ assert pass_.get_type() is not None
37
+
38
+ def test_get_revolution_number(self, pass_: Pass):
39
+ assert pass_.get_revolution_number() is not None
40
+
41
+ def test_get_duration(self, pass_: Pass):
42
+ assert pass_.get_duration() is not None
43
+
44
+ def test_get_instant_at_ascending_node(self, pass_: Pass):
45
+ assert pass_.get_instant_at_ascending_node() is not None
46
+
47
+ def test_get_instant_at_north_point(self, pass_: Pass):
48
+ assert pass_.get_instant_at_north_point() is not None
49
+
50
+ def test_get_instant_at_descending_node(self, pass_: Pass):
51
+ assert pass_.get_instant_at_descending_node() is not None
52
+
53
+ def test_get_instant_at_south_point(self, pass_: Pass):
54
+ assert pass_.get_instant_at_south_point() is not None
40
55
 
41
- pass_ = Pass(pass_type, pass_revolution_number, pass_interval)
56
+ def test_get_instant_at_pass_break(self, pass_: Pass):
57
+ assert pass_.get_instant_at_pass_break() is not None
42
58
 
43
- assert pass_ is not None
44
- assert isinstance(pass_, Pass)
59
+ def test_undefined(self):
60
+ assert Pass.undefined().is_defined() is False
45
61
 
46
- assert pass_.is_defined()
47
- assert pass_.is_complete() is not None
48
- assert pass_.get_type() is not None
49
- assert pass_.get_revolution_number() is not None
50
- # Interval conversion to Python type of issue
51
- # assert pass_.get_interval() is not None
62
+ def test_string_from_type(self):
63
+ assert Pass.string_from_type(Pass.Type.Complete) is not None
52
64
 
53
- assert Pass.string_from_type(Pass.Type.Complete) is not None
54
- assert Pass.string_from_phase(Pass.Phase.Ascending) is not None
55
- assert Pass.string_from_quarter(Pass.Quarter.First) is not None
65
+ def test_string_from_phase(self):
66
+ assert Pass.string_from_phase(Pass.Phase.Ascending) is not None
@@ -2,22 +2,43 @@
2
2
 
3
3
  import pytest
4
4
 
5
- from ostk.physics import Environment
5
+ from ostk.physics.environment.objects.celestial_bodies import Earth
6
6
  from ostk.physics.units import Length, Angle
7
- from ostk.physics.time import Scale, Instant, DateTime, Time
7
+ from ostk.physics.time import Scale, Instant, DateTime, Time, Duration, Interval
8
8
 
9
9
  from ostk.astrodynamics.trajectory import Orbit, State
10
+ from ostk.astrodynamics.trajectory.orbit import Pass
11
+ from ostk.astrodynamics.trajectory.orbit import Pass
10
12
  from ostk.astrodynamics.trajectory.orbit.models import SGP4
11
13
  from ostk.astrodynamics.trajectory.orbit.models.sgp4 import TLE
12
14
 
13
15
 
14
16
  @pytest.fixture
15
- def earth():
16
- return Environment.default().access_celestial_object_with_name("Earth")
17
+ def earth() -> Earth:
18
+ return Earth.default()
19
+
20
+
21
+ @pytest.fixture
22
+ def epoch() -> Instant:
23
+ return Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
24
+
25
+
26
+ @pytest.fixture
27
+ def orbit(earth: Earth, epoch: Instant):
28
+ return Orbit.sun_synchronous(epoch, Length.kilometers(500.0), Time.midnight(), earth)
29
+
30
+
31
+ @pytest.fixture
32
+ def states(orbit: Orbit, epoch: Instant) -> list[State]:
33
+ instants: list[Instant] = Interval.closed(
34
+ epoch, epoch + Duration.days(1.0)
35
+ ).generate_grid(Duration.seconds(20.0))
36
+
37
+ return orbit.get_states_at(instants)
17
38
 
18
39
 
19
40
  class TestOrbit:
20
- def test_trajectory_orbit_constructors(self, earth):
41
+ def test_constructors(self, earth):
21
42
  # Construct Two-Line Element set
22
43
  tle = TLE(
23
44
  "1 25544U 98067A 18231.17878740 .00000187 00000-0 10196-4 0 9994",
@@ -37,14 +58,45 @@ class TestOrbit:
37
58
  assert state is not None
38
59
  assert isinstance(state, State)
39
60
 
40
- def test_trajectory_orbit_circular(self, earth):
61
+ def test_get_revolution_number_at(self, orbit: Orbit):
62
+ assert (
63
+ orbit.get_revolution_number_at(
64
+ Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
65
+ )
66
+ == 1
67
+ )
68
+
69
+ def test_get_pass_at(self, orbit: Orbit):
70
+ pass_ = orbit.get_pass_at(
71
+ Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
72
+ )
73
+
74
+ assert pass_ is not None
75
+ assert isinstance(pass_, Pass)
76
+ assert pass_.is_defined()
77
+
78
+ def test_get_pass_with_revolution_number(self, orbit: Orbit):
79
+ pass_ = orbit.get_pass_with_revolution_number(1)
80
+
81
+ assert pass_ is not None
82
+ assert isinstance(pass_, Pass)
83
+ assert pass_.is_defined()
84
+
85
+ def test_undefined(self):
86
+ assert Orbit.undefined().is_defined() is False
87
+
88
+ def test_circular(self, earth):
41
89
  epoch = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
42
90
  altitude = Length.kilometers(500.0)
43
91
  inclination = Angle.degrees(45.0)
44
92
 
45
93
  orbit: Orbit = Orbit.circular(epoch, altitude, inclination, earth)
46
94
 
47
- def test_trajectory_orbit_equatorial(self, earth):
95
+ assert orbit is not None
96
+ assert isinstance(orbit, Orbit)
97
+ assert orbit.is_defined()
98
+
99
+ def test_equatorial(self, earth):
48
100
  epoch = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
49
101
  apoapsis_altitude = Length.kilometers(500.1)
50
102
  periapsis_altitude = Length.kilometers(499.9)
@@ -57,7 +109,7 @@ class TestOrbit:
57
109
  assert isinstance(orbit, Orbit)
58
110
  assert orbit.is_defined()
59
111
 
60
- def test_trajectory_orbit_circular_equatorial(self, earth):
112
+ def test_circular_equatorial(self, earth):
61
113
  epoch = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
62
114
  altitude = Length.kilometers(500.0)
63
115
 
@@ -67,7 +119,7 @@ class TestOrbit:
67
119
  assert isinstance(orbit, Orbit)
68
120
  assert orbit.is_defined()
69
121
 
70
- def test_trajectory_orbit_geo_synchronous(self, earth):
122
+ def test_geo_synchronous(self, earth):
71
123
  epoch = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
72
124
  inclination = Angle.degrees(45.0)
73
125
  longitude = Angle.degrees(45.0)
@@ -78,7 +130,7 @@ class TestOrbit:
78
130
  assert isinstance(orbit, Orbit)
79
131
  assert orbit.is_defined()
80
132
 
81
- def test_trajectory_orbit_sun_synchronous(self, earth):
133
+ def test_sun_synchronous(self, earth):
82
134
  epoch = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
83
135
  altitude = Length.kilometers(500.0)
84
136
  local_time_at_descending_node = Time.midnight()
@@ -98,3 +150,7 @@ class TestOrbit:
98
150
  celestial_object=earth,
99
151
  argument_of_latitude=Angle.degrees(50.0),
100
152
  ).is_defined()
153
+
154
+ def test_compute_passes(self, orbit: Orbit, states: list[State]):
155
+ passes: list[tuple[int, Pass]] = orbit.compute_passes(states, 1)
156
+ assert passes is not None
@@ -121,6 +121,11 @@ def maneuver_segment(
121
121
  )
122
122
 
123
123
 
124
+ @pytest.fixture
125
+ def instants(state: State) -> list[Instant]:
126
+ return [state.get_instant(), state.get_instant() + Duration.minutes(1.0)]
127
+
128
+
124
129
  @pytest.fixture
125
130
  def thruster_dynamics() -> Thruster:
126
131
  return Thruster(
@@ -212,6 +217,8 @@ class TestSegment:
212
217
  state: State,
213
218
  end_instant: Instant,
214
219
  maneuver_segment: Segment,
220
+ instants: list[Instant],
221
+ numerical_solver: NumericalSolver,
215
222
  ):
216
223
  solution = maneuver_segment.solve(state)
217
224
 
@@ -241,6 +248,14 @@ class TestSegment:
241
248
 
242
249
  state_frame: Frame = state.get_frame()
243
250
 
251
+ propagated_states = solution.calculate_states_at(
252
+ instants,
253
+ numerical_solver,
254
+ )
255
+
256
+ assert propagated_states is not None
257
+ assert len(propagated_states) == len(instants)
258
+
244
259
  first_dynamics_contribution = solution.get_dynamics_contribution(
245
260
  solution.dynamics[0], state_frame
246
261
  )
@@ -334,6 +334,11 @@ def segment_solution(
334
334
  )
335
335
 
336
336
 
337
+ @pytest.fixture
338
+ def instants(state: State) -> list[Instant]:
339
+ return [state.get_instant(), state.get_instant() + Duration.minutes(1.0)]
340
+
341
+
337
342
  class TestSequence:
338
343
  def test_get_segments(
339
344
  self,
@@ -424,8 +429,13 @@ class TestSequence:
424
429
  repetition_count: int,
425
430
  sequence: Sequence,
426
431
  segments: list[Segment],
432
+ instants: list[Instant],
433
+ numerical_solver: NumericalSolver,
427
434
  ):
428
- solution = sequence.solve(state, repetition_count)
435
+ solution = sequence.solve(
436
+ state=state,
437
+ repetition_count=repetition_count,
438
+ )
429
439
 
430
440
  assert len(solution.segment_solutions) == len(segments)
431
441
 
@@ -442,6 +452,14 @@ class TestSequence:
442
452
  assert solution.compute_delta_mass() is not None
443
453
  assert solution.compute_delta_v(1500.0) is not None
444
454
 
455
+ propagated_states = solution.calculate_states_at(
456
+ instants,
457
+ numerical_solver,
458
+ )
459
+
460
+ assert propagated_states is not None
461
+ assert len(propagated_states) == len(instants)
462
+
445
463
  def test_solve_to_condition(
446
464
  self,
447
465
  state: State,
@@ -15,18 +15,18 @@ from ostk.physics.environment.objects.celestial_bodies import Earth
15
15
  from ostk.physics.environment.gravitational import Earth as EarthGravitationalModel
16
16
 
17
17
 
18
- def lla_from_state(state: trajectory.State) -> list:
18
+ def lla_from_state(state: trajectory.State) -> tuple[float, float, float]:
19
19
  """
20
20
  Return latitude (degrees), longitude (degrees), altitude (meters) float list from a state.
21
21
  """
22
22
 
23
- lla = lla_from_position(state.get_position(), state.get_instant())
23
+ lla: LLA = lla_from_position(state.get_position(), state.get_instant())
24
24
 
25
- return [
25
+ return (
26
26
  float(lla.get_latitude().in_degrees()),
27
27
  float(lla.get_longitude().in_degrees()),
28
28
  float(lla.get_altitude().in_meters()),
29
- ]
29
+ )
30
30
 
31
31
 
32
32
  def lla_from_position(
@@ -42,7 +42,7 @@ def lla_from_position(
42
42
  raise ValueError(
43
43
  "Instant must be provided if position is not expressed in ECEF."
44
44
  )
45
- position = position.in_frame(Frame.ITRF(), instant)
45
+ position: Position = position.in_frame(Frame.ITRF(), instant)
46
46
 
47
47
  return LLA.cartesian(
48
48
  position.get_coordinates(),
@@ -70,51 +70,54 @@ def compute_aer(
70
70
  from_position: Position,
71
71
  to_position: Position,
72
72
  environment: Environment,
73
- ) -> list:
73
+ ) -> tuple[float, float, float]:
74
74
  """
75
75
  Return [azimuth (degrees), elevation (degrees), range (meters)] from Instant and Positions (observer, target).
76
76
  """
77
77
 
78
- from_lla = lla_from_position(from_position, instant)
78
+ from_lla: LLA = lla_from_position(from_position, instant)
79
79
 
80
- earth = environment.access_celestial_object_with_name("Earth")
81
- ned_frame = earth.get_frame_at(from_lla, Earth.FrameType.NED)
80
+ earth: Earth = environment.access_celestial_object_with_name("Earth")
81
+ ned_frame: Frame = earth.get_frame_at(from_lla, Earth.FrameType.NED)
82
82
 
83
- from_position_NED = from_position.in_frame(ned_frame, instant)
84
- to_position_NED = to_position.in_frame(ned_frame, instant)
83
+ from_position_NED: Position = from_position.in_frame(ned_frame, instant)
84
+ to_position_NED: Position = to_position.in_frame(ned_frame, instant)
85
85
 
86
- aer = AER.from_position_to_position(from_position_NED, to_position_NED, True)
86
+ aer: AER = AER.from_position_to_position(from_position_NED, to_position_NED, True)
87
87
 
88
- return [
88
+ return (
89
89
  float(aer.get_azimuth().in_degrees()),
90
90
  float(aer.get_elevation().in_degrees()),
91
91
  float(aer.get_range().in_meters()),
92
- ]
92
+ )
93
93
 
94
94
 
95
95
  def compute_time_lla_aer_state(
96
96
  state: trajectory.State,
97
97
  from_position: Position,
98
98
  environment: Environment,
99
- ) -> list:
99
+ ) -> tuple[Instant, float, float, float, float, float, float]:
100
100
  """
101
101
  Return [instant, latitude, longitude, altitude, azimuth, elevation, range] from State and observer Position.
102
102
  """
103
103
 
104
- instant = state.get_instant()
104
+ instant: Instant = state.get_instant()
105
105
 
106
- lla = lla_from_state(state)
107
- aer = compute_aer(
106
+ lla: tuple[float, float, float] = lla_from_state(state)
107
+ aer: AER = compute_aer(
108
108
  instant,
109
109
  from_position,
110
110
  state.get_position().in_frame(Frame.ITRF(), state.get_instant()),
111
111
  environment,
112
112
  )
113
113
 
114
- return [instant, lla[0], lla[1], lla[2], aer[0], aer[1], aer[2]]
114
+ return (instant, lla[0], lla[1], lla[2], aer[0], aer[1], aer[2])
115
115
 
116
116
 
117
- def compute_trajectory_geometry(trajectory: Trajectory, interval: Interval) -> list:
117
+ def compute_trajectory_geometry(
118
+ trajectory: Trajectory,
119
+ interval: Interval,
120
+ ) -> list[tuple[float, float, float]]:
118
121
  """
119
122
  Return [latitude (degrees), longitude (degrees), altitude (meters)] values along a Trajectory during Interval.
120
123
  """
@@ -127,12 +130,14 @@ def compute_trajectory_geometry(trajectory: Trajectory, interval: Interval) -> l
127
130
  ]
128
131
 
129
132
 
130
- def convert_state(instant: Instant, state: trajectory.State) -> list:
133
+ def convert_state(
134
+ state: trajectory.State,
135
+ ) -> tuple[str, float, float, float, float, float, float, float, float, float]:
131
136
  """
132
137
  Convert an input (Instant, State) into dataframe-ready values.
133
138
  """
134
139
 
135
- lla = LLA.cartesian(
140
+ lla: LLA = LLA.cartesian(
136
141
  state.get_position()
137
142
  .in_frame(Frame.ITRF(), state.get_instant())
138
143
  .get_coordinates(),
@@ -140,7 +145,9 @@ def convert_state(instant: Instant, state: trajectory.State) -> list:
140
145
  EarthGravitationalModel.EGM2008.flattening,
141
146
  )
142
147
 
143
- return [
148
+ instant: Instant = state.get_instant()
149
+
150
+ return (
144
151
  repr(instant),
145
152
  float(instant.get_modified_julian_date(Scale.UTC)),
146
153
  *state.get_position().get_coordinates().transpose().tolist(),
@@ -148,4 +155,4 @@ def convert_state(instant: Instant, state: trajectory.State) -> list:
148
155
  float(lla.get_latitude().in_degrees()),
149
156
  float(lla.get_longitude().in_degrees()),
150
157
  float(lla.get_altitude().in_meters()),
151
- ]
158
+ )