open-space-toolkit-astrodynamics 1.3.0__py38-none-any.whl → 2.1.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.
Files changed (24) hide show
  1. {open_space_toolkit_astrodynamics-1.3.0.dist-info → open_space_toolkit_astrodynamics-2.1.0.dist-info}/METADATA +2 -2
  2. {open_space_toolkit_astrodynamics-1.3.0.dist-info → open_space_toolkit_astrodynamics-2.1.0.dist-info}/RECORD +24 -17
  3. ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-38-x86_64-linux-gnu.so +0 -0
  4. ostk/astrodynamics/{libopen-space-toolkit-astrodynamics.so.1 → libopen-space-toolkit-astrodynamics.so.2} +0 -0
  5. ostk/astrodynamics/test/event_condition/test_boolean_event_condition.py +44 -0
  6. ostk/astrodynamics/test/event_condition/test_coe_condition.py +40 -11
  7. ostk/astrodynamics/test/event_condition/test_conjunctive.py +19 -18
  8. ostk/astrodynamics/test/event_condition/test_disjunctive.py +19 -18
  9. ostk/astrodynamics/test/event_condition/test_logical_connective.py +4 -2
  10. ostk/astrodynamics/test/event_condition/test_real_event_condition.py +41 -0
  11. ostk/astrodynamics/test/flight/system/dynamics/test_dynamics.py +37 -0
  12. ostk/astrodynamics/test/test_event_condition.py +9 -28
  13. ostk/astrodynamics/test/test_numerical_solver.py +23 -15
  14. ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py +5 -0
  15. ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_cartesian_position.py +103 -0
  16. ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_cartesian_velocity.py +113 -0
  17. ostk/astrodynamics/test/trajectory/state/test_coordinates_broker.py +71 -0
  18. ostk/astrodynamics/test/trajectory/state/test_coordinates_subset.py +43 -0
  19. ostk/astrodynamics/test/trajectory/test_propagator.py +12 -8
  20. ostk/astrodynamics/test/trajectory/test_state.py +66 -15
  21. ostk/astrodynamics/viewer.py +1 -1
  22. {open_space_toolkit_astrodynamics-1.3.0.dist-info → open_space_toolkit_astrodynamics-2.1.0.dist-info}/WHEEL +0 -0
  23. {open_space_toolkit_astrodynamics-1.3.0.dist-info → open_space_toolkit_astrodynamics-2.1.0.dist-info}/top_level.txt +0 -0
  24. {open_space_toolkit_astrodynamics-1.3.0.dist-info → open_space_toolkit_astrodynamics-2.1.0.dist-info}/zip-safe +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: open-space-toolkit-astrodynamics
3
- Version: 1.3.0
3
+ Version: 2.1.0
4
4
  Summary: Orbit, attitude, access.
5
5
  Author: Open Space Collective
6
6
  Author-email: contact@open-space-collective.org
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3
11
11
  Classifier: License :: OSI Approved :: Apache Software License
12
12
  Classifier: Operating System :: POSIX :: Linux
13
13
  Description-Content-Type: text/markdown
14
- Requires-Dist: open-space-toolkit-physics (~=1.2.0)
14
+ Requires-Dist: open-space-toolkit-physics (~=2.0.0)
15
15
 
16
16
  # Open Space Toolkit ▸ Astrodynamics
17
17
 
@@ -1,19 +1,19 @@
1
1
  ostk/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
2
- ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-38-x86_64-linux-gnu.so,sha256=-NScfpfyZQ_ihsFshGqj68zv4LCfDvw8WHMMuv9-fc4,1213624
2
+ ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-38-x86_64-linux-gnu.so,sha256=BtJCIbcnMBY4AKqmSFiCt9iRkTPiVNEqCdZDCE2hWvI,1332600
3
3
  ostk/astrodynamics/__init__.py,sha256=BE7yyrOnPqFCTPT3GhYEI4IWR5nzs96VSjKphhQ09ew,97
4
4
  ostk/astrodynamics/converters.py,sha256=sBZ3_JMjowWbQ9gBPA2cSEkbBfAwXmt1IBbLks76-Vk,3502
5
5
  ostk/astrodynamics/display.py,sha256=y9FnoQbPFGM6LzkUdgXgeqtuVGhv57GuTKbeDdcFPgw,6306
6
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.1,sha256=emofzIM0g2iAiGcuguQUsor8Gizw9vU9hBum0o5MMnE,67177200
6
+ ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.2,sha256=3xgJFd7EtUQR97QzanL9AnZbbrxA6IxRInCFSKd6X-A,67701896
7
7
  ostk/astrodynamics/utilities.py,sha256=NbeKN_CtcCRHIinhoNWTEosBMR7xc924S-ZFD97mduw,4478
8
- ostk/astrodynamics/viewer.py,sha256=5YFPBiv0YSBZrI42G4UANmOeW8tnJj86_f9gfSpHGgY,8938
8
+ ostk/astrodynamics/viewer.py,sha256=_4uucNtZrIADtKtEYHbiu91RVVvKRG3vPULUAshPLJU,8912
9
9
  ostk/astrodynamics/test/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
10
10
  ostk/astrodynamics/test/conftest.py,sha256=J3SbQibnMVaPktAF6Z6cwVCa7xhW3uXpkOJRom6YtCo,2719
11
11
  ostk/astrodynamics/test/test_access.py,sha256=4I5r4Hukv0fkByHVARhaYpcDu5EOQ7dtbs-ZK7siTqg,3961
12
12
  ostk/astrodynamics/test/test_converters.py,sha256=ktkLH0xpeRdQ7kN6i5a_agmGqovUxVtCwlwcCdCUaa0,5847
13
13
  ostk/astrodynamics/test/test_display.py,sha256=8YeiYRYMpokzqprbRoDBI_xhHI5B8uxcdSzmqmF3AIc,3738
14
- ostk/astrodynamics/test/test_event_condition.py,sha256=i9B5OX3FVwzSHRDVhXEtKBmylp1aIaeM9r5KRhFenG8,2041
14
+ ostk/astrodynamics/test/test_event_condition.py,sha256=a503h3sHj-Q8c6jo1z_CcgW1kplZqtugPH-jhf3Huvk,1413
15
15
  ostk/astrodynamics/test/test_import.py,sha256=y62-SI3pmSkIgyOIrDDXeWqWI3DhnjnUl7SgWAp99kA,1212
16
- ostk/astrodynamics/test/test_numerical_solver.py,sha256=HsL6WI4uh1yYTsQJMxQMC13yYfPjusyvlL0CeHd36h0,8169
16
+ ostk/astrodynamics/test/test_numerical_solver.py,sha256=kM1zx_D1Tot1hmnVOUK1Zw5CnwUlq5BvB9ugrzOOlY4,8366
17
17
  ostk/astrodynamics/test/test_root_solver.py,sha256=hQ8O6g-WP49gZH_H3Rdufv0F0gQorpzJyIcjBGGUQ34,1831
18
18
  ostk/astrodynamics/test/test_trajectory.py,sha256=4AhlAaIrCrP17ZycJqYlYskj8SC2MH7fp3_4eqWdF9s,1366
19
19
  ostk/astrodynamics/test/test_utilities.py,sha256=edAPLXNMflCPa0gzhU4e05pa6HbAq7UV0JzMMRx3VlQ,3252
@@ -24,11 +24,13 @@ ostk/astrodynamics/test/conjunction/messages/ccsds/__init__.py,sha256=epnVn2PwdQ
24
24
  ostk/astrodynamics/test/conjunction/messages/ccsds/conftest.py,sha256=xyTd24828Ue2HgOWY8UhizIc5mzgRgoH2VSOfVfKCdw,14632
25
25
  ostk/astrodynamics/test/conjunction/messages/ccsds/test_cdm.py,sha256=SqtYXB8qhKzbQEWmCzz13xi0Uu64-VSKXuMObcFV7EI,18518
26
26
  ostk/astrodynamics/test/conjunction/messages/ccsds/data/cdm.json,sha256=-CL8Bu-ivigzkrqHs9Q5snSubHJ_D0YMroatEInkidc,12965
27
- ostk/astrodynamics/test/event_condition/test_coe_condition.py,sha256=uTL4vtAL9NebK7YwmVyrHfGNX46ZTbpAPi2_ZEz0XaE,2809
28
- ostk/astrodynamics/test/event_condition/test_conjunctive.py,sha256=X8fNUgUfXcBJB5CPip6mRDBFMNAqCHw9Mt9r3Wubjl8,1982
29
- ostk/astrodynamics/test/event_condition/test_disjunctive.py,sha256=71eNzfqtCyNeHkw6-g2i_OIWveJv40nbZU2EPfGm9Ro,1968
27
+ ostk/astrodynamics/test/event_condition/test_boolean_event_condition.py,sha256=2QOgkLM5ROhOx2uNNQQfn0XDC34sx4k0ZXn9Zm6SD_0,1184
28
+ ostk/astrodynamics/test/event_condition/test_coe_condition.py,sha256=aUQrgLUYvz5yzmlhic5-ti6Gn8kdo4G6wU1MRrF6pRk,3289
29
+ ostk/astrodynamics/test/event_condition/test_conjunctive.py,sha256=LGzxK6_qTcE8FMLap0WZ-4maJuXNU1DtXeJjodoWy9w,1916
30
+ ostk/astrodynamics/test/event_condition/test_disjunctive.py,sha256=dVmEILtS_Cj0BYNWSMA5z6T7B-mmYexQB8gXatJqrz4,1902
30
31
  ostk/astrodynamics/test/event_condition/test_duration_condition.py,sha256=wyDBde1vc06-cUjOwmJP6Po8cHbQTGHIDWB3e6eoO_o,973
31
- ostk/astrodynamics/test/event_condition/test_logical_connective.py,sha256=WQQQn1FdQEbAs7UxXawzAnX3ON8-UgKqYmKeOGkufN8,1117
32
+ ostk/astrodynamics/test/event_condition/test_logical_connective.py,sha256=DjBFecD9hNjF379if3mWUAeCnDF_vhUhJbnRZEhvb-8,1197
33
+ ostk/astrodynamics/test/event_condition/test_real_event_condition.py,sha256=HQu545o1ViLIRsNkx-3Ivmn84IUOssnLIFIcD1JxU7I,1103
32
34
  ostk/astrodynamics/test/flight/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
33
35
  ostk/astrodynamics/test/flight/test_profile.py,sha256=27g5Atvr2RGslvFujdP90cA9qldkNb7C0U1RgbOAws0,5197
34
36
  ostk/astrodynamics/test/flight/test_system.py,sha256=YPrjoV3o67_1zCXCZqohlSAR7zkU0LXP2fF20M2s0C8,1326
@@ -39,6 +41,7 @@ ostk/astrodynamics/test/flight/system/test_satellite_system.py,sha256=-5KOGVTWRI
39
41
  ostk/astrodynamics/test/flight/system/dynamics/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
40
42
  ostk/astrodynamics/test/flight/system/dynamics/test_atmospheric_drag.py,sha256=nZ2lBGq5Ni3ypuqGbTfluxTXYERpwol49d0DrgnYsIo,3115
41
43
  ostk/astrodynamics/test/flight/system/dynamics/test_central_body_gravity.py,sha256=r3JIIX7cD63BhrgvLtjFaK7ew1BqHdKP5_VxwGmuv1Q,1818
44
+ ostk/astrodynamics/test/flight/system/dynamics/test_dynamics.py,sha256=arNkAOj2y4CDmc9CXxItbFtC4QYjaByuJefdi5S6alw,914
42
45
  ostk/astrodynamics/test/flight/system/dynamics/test_position_derivative.py,sha256=ZVVewpqZwqiBLDqoNQDHDgDodtj6_M0J6ZmgHe_1gz8,1646
43
46
  ostk/astrodynamics/test/flight/system/dynamics/test_third_body_gravity.py,sha256=Z8OkM-EFafFpWziu3bfatlSlZA4Tic2fsVLU35rDp5E,1915
44
47
  ostk/astrodynamics/test/solvers/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
@@ -46,8 +49,8 @@ ostk/astrodynamics/test/solvers/test_temporal_condition_solver.py,sha256=s7r7Vel
46
49
  ostk/astrodynamics/test/trajectory/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
47
50
  ostk/astrodynamics/test/trajectory/test_model.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
48
51
  ostk/astrodynamics/test/trajectory/test_orbit.py,sha256=SlCBZ_broPaJ6L8khMuvbdPem9-zmqG6IZwxr9cECB4,3155
49
- ostk/astrodynamics/test/trajectory/test_propagator.py,sha256=cvRuIAq9OOGKj2jRaJxNMWdp0gdpJuva7dEID0BJHdo,7412
50
- ostk/astrodynamics/test/trajectory/test_state.py,sha256=HHBhJUfPhR1by7qTetRyF-51u9XzWUVKtu3XzTRHJtk,2079
52
+ ostk/astrodynamics/test/trajectory/test_propagator.py,sha256=PHeZgFO8-xaH1ItFMZdjXxyQ792z8yROYMx0HnsfSSo,7570
53
+ ostk/astrodynamics/test/trajectory/test_state.py,sha256=okpjRPixi7AUSV1YG8hNFFEo0AayfIK50X2vor9yOB0,3199
51
54
  ostk/astrodynamics/test/trajectory/orbit/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
52
55
  ostk/astrodynamics/test/trajectory/orbit/test_model.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
53
56
  ostk/astrodynamics/test/trajectory/orbit/test_pass.py,sha256=MtPRKhVz4hCzfFuE0p1x89Ps68M9s7miT7VtPIDVeOo,1898
@@ -62,11 +65,15 @@ ostk/astrodynamics/test/trajectory/orbit/models/test_propagated.py,sha256=MpGL1F
62
65
  ostk/astrodynamics/test/trajectory/orbit/models/test_sgp4.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
63
66
  ostk/astrodynamics/test/trajectory/orbit/models/test_tabulated.py,sha256=tL3gGDitdEYCCRwGtu2RP-9d4JWsujV53ck9DRkyeG4,11183
64
67
  ostk/astrodynamics/test/trajectory/orbit/models/kepler/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
65
- ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py,sha256=aAb3lr3IIFF5V4szhdHsPsLwHJAFXq3ZbCmvBuc69tA,2583
68
+ ostk/astrodynamics/test/trajectory/orbit/models/kepler/test_coe.py,sha256=uWgUO9zHrcqEKGJ-SWUiHfEbWDm8YcgptnS2I2y_V1U,2728
66
69
  ostk/astrodynamics/test/trajectory/orbit/models/sgp4/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
67
70
  ostk/astrodynamics/test/trajectory/orbit/models/sgp4/test_tle.py,sha256=lbPqHd87ExTNbBFcFSTMWRnWbpe_4BDJ2g2APlQLJkY,11486
68
- open_space_toolkit_astrodynamics-1.3.0.dist-info/METADATA,sha256=x10QyfcOARLh7Qf-1e86FIVUbTC6DAt9EohxorT9BXA,1779
69
- open_space_toolkit_astrodynamics-1.3.0.dist-info/WHEEL,sha256=pruk-ncpSL7wyHyfRUEyLDsvov8r7FCaWTBJ2klfed4,93
70
- open_space_toolkit_astrodynamics-1.3.0.dist-info/top_level.txt,sha256=zOR18699uDYnafgarhL8WU_LmTZY_5NVqutv-flp_x4,5
71
- open_space_toolkit_astrodynamics-1.3.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
72
- open_space_toolkit_astrodynamics-1.3.0.dist-info/RECORD,,
71
+ ostk/astrodynamics/test/trajectory/state/test_coordinates_broker.py,sha256=kB_gsJHxvCDY9kfuqVkwHt5ZmMuaAoRk_3YZGxoXOwg,2515
72
+ ostk/astrodynamics/test/trajectory/state/test_coordinates_subset.py,sha256=eMmifR5rJMk2yFN7pfAHq2Ub3FPvknb6gvS-nBDidro,1201
73
+ ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_cartesian_position.py,sha256=V5d7UnV6KIJjJvh5R0i3imRfyN04JCDvCUsKdvfKmhE,2708
74
+ ostk/astrodynamics/test/trajectory/state/coordinates_subset/test_cartesian_velocity.py,sha256=5a7yeOVt7gY4oQdINSElb_U2jznJmuWPrT_YJrI6KaM,3070
75
+ open_space_toolkit_astrodynamics-2.1.0.dist-info/METADATA,sha256=f4RCJAapR8IVLJRap7NK1HBhX_FX9RB8Dr0q-PsZl7E,1779
76
+ open_space_toolkit_astrodynamics-2.1.0.dist-info/WHEEL,sha256=pruk-ncpSL7wyHyfRUEyLDsvov8r7FCaWTBJ2klfed4,93
77
+ open_space_toolkit_astrodynamics-2.1.0.dist-info/top_level.txt,sha256=zOR18699uDYnafgarhL8WU_LmTZY_5NVqutv-flp_x4,5
78
+ open_space_toolkit_astrodynamics-2.1.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
79
+ open_space_toolkit_astrodynamics-2.1.0.dist-info/RECORD,,
@@ -0,0 +1,44 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.astrodynamics.event_condition import BooleanEventCondition
6
+
7
+
8
+ @pytest.fixture
9
+ def evaluator():
10
+ return lambda state_vector, time: time > 0.0
11
+
12
+
13
+ @pytest.fixture
14
+ def is_inversed() -> bool:
15
+ return False
16
+
17
+
18
+ @pytest.fixture
19
+ def event_condition(evaluator, is_inversed: bool) -> BooleanEventCondition:
20
+ return BooleanEventCondition(
21
+ "My Condition",
22
+ BooleanEventCondition.Criteria.StrictlyPositive,
23
+ evaluator,
24
+ is_inversed,
25
+ )
26
+
27
+
28
+ class TestBooleanEventCondition:
29
+ def test_is_inversed(self, event_condition: BooleanEventCondition, is_inversed: bool):
30
+ assert event_condition.is_inversed() == is_inversed
31
+
32
+ def test_evaluate(self, event_condition: BooleanEventCondition):
33
+ assert event_condition.evaluate(state_vector=[0.0], time=10.0) is not None
34
+
35
+ def test_is_satisfied(self, event_condition: BooleanEventCondition):
36
+ assert (
37
+ event_condition.is_satisfied(
38
+ previous_state_vector=[-1.0],
39
+ previous_time=-1.0,
40
+ current_state_vector=[1.0],
41
+ current_time=10.0,
42
+ )
43
+ == True
44
+ )
@@ -4,11 +4,17 @@ import pytest
4
4
 
5
5
  from ostk.physics.environment.gravitational import Earth
6
6
  from ostk.physics.units import Derived, Length, Angle
7
+ from ostk.physics.coordinate import Frame
7
8
 
8
9
  from ostk.astrodynamics.event_condition import COECondition
9
10
  from ostk.astrodynamics.trajectory.orbit.models.kepler import COE
10
11
 
11
12
 
13
+ @pytest.fixture
14
+ def frame() -> Frame:
15
+ return Frame.GCRF()
16
+
17
+
12
18
  @pytest.fixture
13
19
  def criteria() -> COECondition.Criteria:
14
20
  return COECondition.Criteria.AnyCrossing
@@ -34,10 +40,11 @@ def condition(
34
40
  criteria: COECondition.Criteria,
35
41
  element: COE.Element,
36
42
  target: float,
43
+ frame: Frame,
37
44
  gravitational_parameter: Derived,
38
45
  ) -> COECondition:
39
46
  return COECondition(
40
- "Test COECondition", criteria, element, target, gravitational_parameter
47
+ "Test COECondition", criteria, element, target, frame, gravitational_parameter
41
48
  )
42
49
 
43
50
 
@@ -54,13 +61,28 @@ def state_vector() -> list[float]:
54
61
 
55
62
 
56
63
  class TestCOECondition:
57
- def test_constructor(self, criteria, element, target, gravitational_parameter):
64
+ def test_constructor(
65
+ self,
66
+ criteria: COECondition.Criteria,
67
+ element: COE.Element,
68
+ target: float,
69
+ frame: Frame,
70
+ gravitational_parameter: Derived,
71
+ ):
58
72
  name = "Test COECondition"
59
- condition = COECondition(name, criteria, element, target, gravitational_parameter)
73
+ condition = COECondition(
74
+ name, criteria, element, target, frame, gravitational_parameter
75
+ )
60
76
 
61
77
  assert condition is not None
62
78
 
63
- def test_getters(self, condition, element, target, gravitational_parameter):
79
+ def test_getters(
80
+ self,
81
+ condition: COECondition,
82
+ element: COE.Element,
83
+ target: float,
84
+ gravitational_parameter: Derived,
85
+ ):
64
86
  assert condition.get_element() == element
65
87
  assert condition.get_target() == target
66
88
  assert condition.get_gravitational_parameter() == gravitational_parameter
@@ -79,15 +101,22 @@ class TestCOECondition:
79
101
  ),
80
102
  )
81
103
  def test_static_constructors(
82
- self, static_constructor, target, criteria, gravitational_parameter
104
+ self,
105
+ static_constructor,
106
+ target: float,
107
+ criteria: COECondition.Criteria,
108
+ frame: Frame,
109
+ gravitational_parameter: Derived,
110
+ state_vector: list[float],
83
111
  ):
84
- assert static_constructor(criteria, target, gravitational_parameter) is not None
112
+ condition = static_constructor(criteria, target, frame, gravitational_parameter)
113
+ assert condition is not None
114
+
115
+ assert condition.evaluate(state_vector, 0.0) is not None
85
116
 
86
- def test_evaluate(self, condition, state_vector, target):
117
+ def test_evaluate(
118
+ self, condition: COECondition, state_vector: list[float], target: float
119
+ ):
87
120
  assert condition.evaluate(state_vector, 0.0) == pytest.approx(
88
121
  6904757.8910061345 - target, abs=1e-9
89
122
  )
90
-
91
- def test_string_from_element(self):
92
- element_str = COECondition.string_from_element(COE.Element.SemiMajorAxis)
93
- assert element_str == "Semi-major axis"
@@ -2,42 +2,43 @@
2
2
 
3
3
  import pytest
4
4
 
5
- from ostk.astrodynamics import EventCondition
6
- from ostk.astrodynamics.event_condition import Conjunctive
5
+ from ostk.astrodynamics.event_condition import Conjunctive, RealEventCondition
7
6
 
8
7
 
9
8
  @pytest.fixture
10
- def first_condition() -> EventCondition:
11
- class FirstCondition(EventCondition):
12
- def evaluate(self, state_vector, time):
13
- return state_vector[0]
14
-
15
- return FirstCondition("First Condition", EventCondition.Criteria.PositiveCrossing)
9
+ def first_condition() -> RealEventCondition:
10
+ return RealEventCondition(
11
+ "First Condition",
12
+ RealEventCondition.Criteria.PositiveCrossing,
13
+ lambda state_vector, time: state_vector[0],
14
+ 0.0,
15
+ )
16
16
 
17
17
 
18
18
  @pytest.fixture
19
- def second_condition() -> EventCondition:
20
- class SecondCondition(EventCondition):
21
- def evaluate(self, state_vector, time):
22
- return state_vector[1] - 0.1
23
-
24
- return SecondCondition("Second condition", EventCondition.Criteria.StrictlyNegative)
19
+ def second_condition() -> RealEventCondition:
20
+ return RealEventCondition(
21
+ "Second condition",
22
+ RealEventCondition.Criteria.StrictlyNegative,
23
+ lambda state_vector, time: state_vector[1],
24
+ 0.1,
25
+ )
25
26
 
26
27
 
27
28
  @pytest.fixture
28
29
  def event_conditions(
29
- first_condition: EventCondition, second_condition: EventCondition
30
- ) -> list[EventCondition]:
30
+ first_condition: RealEventCondition, second_condition: RealEventCondition
31
+ ) -> list[RealEventCondition]:
31
32
  return [first_condition, second_condition]
32
33
 
33
34
 
34
35
  @pytest.fixture
35
- def conjunction_condition(event_conditions: list[EventCondition]) -> Conjunctive:
36
+ def conjunction_condition(event_conditions: list[RealEventCondition]) -> Conjunctive:
36
37
  return Conjunctive(event_conditions)
37
38
 
38
39
 
39
40
  class TestConjunctiveCondition:
40
- def test_constructor(self, event_conditions: list[EventCondition]):
41
+ def test_constructor(self, event_conditions: list[RealEventCondition]):
41
42
  assert Conjunctive(event_conditions) is not None
42
43
 
43
44
  def test_is_satisfied(self, conjunction_condition: Conjunctive):
@@ -2,42 +2,43 @@
2
2
 
3
3
  import pytest
4
4
 
5
- from ostk.astrodynamics import EventCondition
6
- from ostk.astrodynamics.event_condition import Disjunctive
5
+ from ostk.astrodynamics.event_condition import Disjunctive, RealEventCondition
7
6
 
8
7
 
9
8
  @pytest.fixture
10
- def first_condition() -> EventCondition:
11
- class FirstCondition(EventCondition):
12
- def evaluate(self, state_vector, time):
13
- return state_vector[0]
14
-
15
- return FirstCondition("First Condition", EventCondition.Criteria.PositiveCrossing)
9
+ def first_condition() -> RealEventCondition:
10
+ return RealEventCondition(
11
+ "First Condition",
12
+ RealEventCondition.Criteria.PositiveCrossing,
13
+ lambda state_vector, time: state_vector[0],
14
+ 0.0,
15
+ )
16
16
 
17
17
 
18
18
  @pytest.fixture
19
- def second_condition() -> EventCondition:
20
- class SecondCondition(EventCondition):
21
- def evaluate(self, state_vector, time):
22
- return state_vector[1] - 0.1
23
-
24
- return SecondCondition("Second condition", EventCondition.Criteria.StrictlyNegative)
19
+ def second_condition() -> RealEventCondition:
20
+ return RealEventCondition(
21
+ "Second condition",
22
+ RealEventCondition.Criteria.StrictlyNegative,
23
+ lambda state_vector, time: state_vector[1],
24
+ 0.1,
25
+ )
25
26
 
26
27
 
27
28
  @pytest.fixture
28
29
  def event_conditions(
29
- first_condition: EventCondition, second_condition: EventCondition
30
- ) -> list[EventCondition]:
30
+ first_condition: RealEventCondition, second_condition: RealEventCondition
31
+ ) -> list[RealEventCondition]:
31
32
  return [first_condition, second_condition]
32
33
 
33
34
 
34
35
  @pytest.fixture
35
- def disjunction_condition(event_conditions: list[EventCondition]) -> Disjunctive:
36
+ def disjunction_condition(event_conditions: list[RealEventCondition]) -> Disjunctive:
36
37
  return Disjunctive(event_conditions)
37
38
 
38
39
 
39
40
  class TestDisjunctiveCondition:
40
- def test_constructor(self, event_conditions: list[EventCondition]):
41
+ def test_constructor(self, event_conditions: list[RealEventCondition]):
41
42
  assert Disjunctive(event_conditions) is not None
42
43
 
43
44
  def test_is_satisfied(self, disjunction_condition: Disjunctive):
@@ -9,8 +9,10 @@ from ostk.astrodynamics.event_condition import LogicalConnective
9
9
  @pytest.fixture
10
10
  def event_condition() -> EventCondition:
11
11
  class MyCondition(EventCondition):
12
- def evaluate(self, state_vector, time):
13
- return time
12
+ def is_satisfied(
13
+ self, current_state_vector, current_time, previous_state_vector, previous_time
14
+ ):
15
+ return True
14
16
 
15
17
  return MyCondition("My Condition", EventCondition.Criteria.StrictlyNegative)
16
18
 
@@ -0,0 +1,41 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.astrodynamics.event_condition import RealEventCondition
6
+
7
+
8
+ @pytest.fixture
9
+ def evaluator():
10
+ return lambda state_vector, time: time
11
+
12
+
13
+ @pytest.fixture
14
+ def target() -> float:
15
+ return 10.0
16
+
17
+
18
+ @pytest.fixture
19
+ def event_condition(evaluator, target: float) -> RealEventCondition:
20
+ return RealEventCondition(
21
+ "My Condition", RealEventCondition.Criteria.PositiveCrossing, evaluator, target
22
+ )
23
+
24
+
25
+ class TestRealEventCondition:
26
+ def test_get_target(self, event_condition: RealEventCondition, target: float):
27
+ assert event_condition.get_target() == target
28
+
29
+ def test_evaluate(self, event_condition: RealEventCondition):
30
+ assert event_condition.evaluate(state_vector=[0.0], time=10.0) is not None
31
+
32
+ def test_is_satisfied(self, event_condition: RealEventCondition):
33
+ assert (
34
+ event_condition.is_satisfied(
35
+ previous_state_vector=[-1.0],
36
+ previous_time=5.0,
37
+ current_state_vector=[1.0],
38
+ current_time=15.0,
39
+ )
40
+ == True
41
+ )
@@ -0,0 +1,37 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.astrodynamics.flight.system import Dynamics
6
+ from ostk.astrodynamics.trajectory.state.coordinates_subset import CartesianPosition
7
+
8
+
9
+ @pytest.fixture
10
+ def name() -> str:
11
+ return "MyDynamics"
12
+
13
+
14
+ @pytest.fixture
15
+ def dynamics(name: str) -> Dynamics:
16
+ class MyDynamics(Dynamics):
17
+ def is_defined():
18
+ return True
19
+
20
+ def get_read_coordinates_subsets(self):
21
+ return [CartesianPosition.default()]
22
+
23
+ def get_write_coordinates_subsets(self):
24
+ return [CartesianPosition.default()]
25
+
26
+ def compute_contribution(self, instant, state_vector, frame):
27
+ return state_vector
28
+
29
+ return MyDynamics(name)
30
+
31
+
32
+ class TestDynamics:
33
+ def test_subclass(self, dynamics: Dynamics):
34
+ assert dynamics is not None
35
+
36
+ def test_get_name(self, dynamics: Dynamics, name: str):
37
+ assert dynamics.get_name() == name
@@ -18,26 +18,14 @@ def criteria() -> EventCondition.Criteria:
18
18
  @pytest.fixture
19
19
  def event_condition(name: str, criteria: EventCondition.Criteria) -> EventCondition:
20
20
  class MyEventCondition(EventCondition):
21
- def evaluate(self, state_vector, time):
22
- return state_vector[0]
21
+ def is_satisfied(
22
+ self, current_state_vector, current_time, previous_state_vector, previous_time
23
+ ):
24
+ return current_state_vector[0] > 0.0 and previous_state_vector[0] < 0.0
23
25
 
24
26
  return MyEventCondition(name, criteria)
25
27
 
26
28
 
27
- @pytest.fixture
28
- def event_condition_overloaded() -> EventCondition:
29
- class OverloadedEventCondition(EventCondition):
30
- def is_satisfied(self, current_value, previous_value):
31
- return (current_value > 0.0) and (previous_value < 0.0)
32
-
33
- def evaluate(self, aStateVector, aTime):
34
- return aStateVector[0]
35
-
36
- return OverloadedEventCondition(
37
- "OverloadedEventCondition", EventCondition.Criteria.Undefined
38
- )
39
-
40
-
41
29
  class TestEventCondition:
42
30
  def test_subclass(self, event_condition: EventCondition):
43
31
  assert event_condition is not None
@@ -52,18 +40,11 @@ class TestEventCondition:
52
40
 
53
41
  def test_is_satisfied(self, event_condition: EventCondition):
54
42
  assert (
55
- event_condition.is_satisfied(current_value=1.0, previous_value=-1.0) == True
56
- )
57
-
58
- def test_overloaded_is_satisfied(self, event_condition_overloaded: EventCondition):
59
- assert event_condition_overloaded is not None
60
- assert (
61
- event_condition_overloaded.is_satisfied(
62
- current_value=1.0, previous_value=-1.0
43
+ event_condition.is_satisfied(
44
+ previous_state_vector=[-1.0],
45
+ previous_time=0.0,
46
+ current_state_vector=[1.0],
47
+ current_time=1.0,
63
48
  )
64
49
  == True
65
50
  )
66
- assert (
67
- event_condition_overloaded.is_satisfied(current_value=1.0, previous_value=1.0)
68
- == False
69
- )
@@ -5,7 +5,8 @@ import pytest
5
5
  import numpy as np
6
6
  import math
7
7
 
8
- from ostk.astrodynamics import NumericalSolver, EventCondition
8
+ from ostk.astrodynamics import NumericalSolver
9
+ from ostk.astrodynamics.event_condition import RealEventCondition
9
10
 
10
11
 
11
12
  def oscillator(x, dxdt, _):
@@ -24,16 +25,13 @@ def initial_state_vec() -> np.ndarray:
24
25
 
25
26
 
26
27
  @pytest.fixture
27
- def custom_condition() -> EventCondition:
28
- class CustomCondition(EventCondition):
29
- def __init__(self, target: float, criteria: EventCondition.Criteria):
30
- super().__init__("Custom", criteria)
31
- self._target = target
32
-
33
- def evaluate(self, state_vector, time: float) -> bool:
34
- return time - self._target
35
-
36
- return CustomCondition(5.0, EventCondition.Criteria.StrictlyPositive)
28
+ def custom_condition() -> RealEventCondition:
29
+ return RealEventCondition(
30
+ "Custom",
31
+ RealEventCondition.Criteria.StrictlyPositive,
32
+ lambda state_vector, time: time,
33
+ 5.0,
34
+ )
37
35
 
38
36
 
39
37
  @pytest.fixture
@@ -87,6 +85,12 @@ class TestNumericalSolver:
87
85
  assert numerical_solver == numerical_solver
88
86
  assert (numerical_solver != numerical_solver) is False
89
87
 
88
+ def test_accessors(
89
+ self,
90
+ numerical_solver: NumericalSolver,
91
+ ):
92
+ assert numerical_solver.access_observed_states() is not None
93
+
90
94
  def test_get_types(
91
95
  self,
92
96
  numerical_solver_default_inputs: tuple[
@@ -108,6 +112,7 @@ class TestNumericalSolver:
108
112
  assert numerical_solver.get_relative_tolerance() == relative_tolerance
109
113
  assert numerical_solver.get_absolute_tolerance() == absolute_tolerance
110
114
  assert numerical_solver.get_root_solver() is not None
115
+ assert numerical_solver.get_observed_states() is not None
111
116
 
112
117
  def test_get_string_from_types(self):
113
118
  assert (
@@ -191,7 +196,7 @@ class TestNumericalSolver:
191
196
  self,
192
197
  numerical_solver_conditional: NumericalSolver,
193
198
  initial_state_vec: np.ndarray,
194
- custom_condition: EventCondition,
199
+ custom_condition: RealEventCondition,
195
200
  ):
196
201
  integration_duration: float = 100.0
197
202
 
@@ -207,7 +212,7 @@ class TestNumericalSolver:
207
212
 
208
213
  state_vector, time = condition_solution.solution
209
214
 
210
- assert abs(time - custom_condition._target) < 1e-6
215
+ assert abs(float(time - custom_condition.get_target())) < 1e-6
211
216
 
212
217
  assert 5e-9 >= abs(state_vector[0] - math.sin(time))
213
218
  assert 5e-9 >= abs(state_vector[1] - math.cos(time))
@@ -215,7 +220,7 @@ class TestNumericalSolver:
215
220
  def test_integrate_time_with_condition(
216
221
  self,
217
222
  numerical_solver_conditional: NumericalSolver,
218
- custom_condition: EventCondition,
223
+ custom_condition: RealEventCondition,
219
224
  ):
220
225
  start_time: float = 500.0
221
226
  end_time: float = start_time + 100.0
@@ -234,7 +239,7 @@ class TestNumericalSolver:
234
239
 
235
240
  state_vector, time = condition_solution.solution
236
241
 
237
- assert abs(time - start_time - custom_condition._target) < 1e-6
242
+ assert abs(float(time - start_time - custom_condition.get_target())) < 1e-6
238
243
 
239
244
  assert 5e-9 >= abs(state_vector[0] - math.sin(time))
240
245
  assert 5e-9 >= abs(state_vector[1] - math.cos(time))
@@ -242,6 +247,9 @@ class TestNumericalSolver:
242
247
  def test_default(self):
243
248
  assert NumericalSolver.default() is not None
244
249
 
250
+ def test_default_conditional(self):
251
+ assert NumericalSolver.default_conditional() is not None
252
+
245
253
  def test_undefined(self):
246
254
  assert NumericalSolver.undefined() is not None
247
255
  assert NumericalSolver.undefined().is_defined() is False
@@ -105,3 +105,8 @@ def test_trajectory_orbit_models_kepler_coe_static_methods():
105
105
  assert (
106
106
  COE.eccentric_anomaly_from_mean_anomaly(Angle.degrees(0.0), 0.0, 0.0) is not None
107
107
  )
108
+
109
+
110
+ def test_string_from_element():
111
+ element_str = COE.string_from_element(COE.Element.SemiMajorAxis)
112
+ assert element_str == "SemiMajorAxis"
@@ -0,0 +1,103 @@
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 CoordinatesBroker, CoordinatesSubset
9
+ from ostk.astrodynamics.trajectory.state.coordinates_subset import CartesianPosition
10
+
11
+
12
+ @pytest.fixture
13
+ def name() -> str:
14
+ return "Position"
15
+
16
+
17
+ @pytest.fixture
18
+ def cartesian_position() -> CartesianPosition:
19
+ return CartesianPosition.default()
20
+
21
+
22
+ @pytest.fixture
23
+ def coordinates_subsets(cartesian_position: CartesianPosition) -> list[CoordinatesSubset]:
24
+ return [cartesian_position]
25
+
26
+
27
+ @pytest.fixture
28
+ def instant() -> Instant:
29
+ return Instant.J2000()
30
+
31
+
32
+ @pytest.fixture
33
+ def frame() -> Frame:
34
+ return Frame.GCRF()
35
+
36
+
37
+ @pytest.fixture
38
+ def coordinates_broker(coordinates_subsets: list[CoordinatesSubset]) -> CoordinatesBroker:
39
+ return CoordinatesBroker(coordinates_subsets)
40
+
41
+
42
+ @pytest.fixture
43
+ def coordinates() -> list[float]:
44
+ return [7000000.0, 0.0, 0.0]
45
+
46
+
47
+ @pytest.fixture
48
+ def another_coordinates() -> list[float]:
49
+ return [0.0, 7000000.0, 0.0]
50
+
51
+
52
+ class TestCoordinatesSubset:
53
+ def test_constructor(self, name: str):
54
+ assert CartesianPosition(name) is not None
55
+
56
+ def test_add(
57
+ self,
58
+ cartesian_position: CartesianPosition,
59
+ instant: Instant,
60
+ frame: Frame,
61
+ coordinates: list[float],
62
+ another_coordinates: list[float],
63
+ coordinates_broker: CoordinatesBroker,
64
+ ):
65
+ assert all(
66
+ cartesian_position.add(
67
+ instant, coordinates, another_coordinates, frame, coordinates_broker
68
+ )
69
+ == [7000000.0, 7000000.0, 0.0]
70
+ )
71
+
72
+ def test_subtract(
73
+ self,
74
+ cartesian_position: CartesianPosition,
75
+ instant: Instant,
76
+ frame: Frame,
77
+ coordinates: list[float],
78
+ another_coordinates: list[float],
79
+ coordinates_broker: CoordinatesBroker,
80
+ ):
81
+ assert all(
82
+ cartesian_position.subtract(
83
+ instant, coordinates, another_coordinates, frame, coordinates_broker
84
+ )
85
+ == [7000000.0, -7000000.0, 0.0]
86
+ )
87
+
88
+ def test_in_frame(
89
+ self,
90
+ cartesian_position: CartesianPosition,
91
+ instant: Instant,
92
+ frame: Frame,
93
+ coordinates: list[float],
94
+ another_coordinates: list[float],
95
+ coordinates_broker: CoordinatesBroker,
96
+ ):
97
+ for value, expected in zip(
98
+ cartesian_position.in_frame(
99
+ instant, coordinates, frame, Frame.ITRF(), coordinates_broker
100
+ ),
101
+ [1238864.12746338, 6889500.39136482, -176.262107699686],
102
+ ):
103
+ assert value == pytest.approx(expected, rel=1e-14)
@@ -0,0 +1,113 @@
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 CoordinatesBroker, CoordinatesSubset
9
+ from ostk.astrodynamics.trajectory.state.coordinates_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 coordinates_subsets(
32
+ cartesian_position: CartesianPosition, cartesian_velocity: CartesianVelocity
33
+ ) -> list[CoordinatesSubset]:
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 coordinates_broker(coordinates_subsets: list[CoordinatesSubset]) -> CoordinatesBroker:
49
+ return CoordinatesBroker(coordinates_subsets)
50
+
51
+
52
+ @pytest.fixture
53
+ def coordinates() -> list[float]:
54
+ return [7000000.0, 0.0, 0.0, 0.0, 5335.865450622126, 5335.865450622126]
55
+
56
+
57
+ @pytest.fixture
58
+ def another_coordinates() -> list[float]:
59
+ return [0.0, 7000000.0, 0.0, 5335.865450622126, 0.0, 0.0]
60
+
61
+
62
+ class TestCoordinatesSubset:
63
+ def test_constructor(self, name: str):
64
+ assert CartesianVelocity(CartesianPosition.default(), name) is not None
65
+
66
+ def test_add(
67
+ self,
68
+ cartesian_velocity: CartesianVelocity,
69
+ instant: Instant,
70
+ frame: Frame,
71
+ coordinates: list[float],
72
+ another_coordinates: list[float],
73
+ coordinates_broker: CoordinatesBroker,
74
+ ):
75
+ assert all(
76
+ cartesian_velocity.add(
77
+ instant, coordinates, another_coordinates, frame, coordinates_broker
78
+ )
79
+ == [5335.865450622126, 5335.865450622126, 5335.865450622126]
80
+ )
81
+
82
+ def test_subtract(
83
+ self,
84
+ cartesian_velocity: CartesianVelocity,
85
+ instant: Instant,
86
+ frame: Frame,
87
+ coordinates: list[float],
88
+ another_coordinates: list[float],
89
+ coordinates_broker: CoordinatesBroker,
90
+ ):
91
+ assert all(
92
+ cartesian_velocity.subtract(
93
+ instant, coordinates, another_coordinates, frame, coordinates_broker
94
+ )
95
+ == [-5335.865450622126, 5335.865450622126, 5335.865450622126]
96
+ )
97
+
98
+ def test_in_frame(
99
+ self,
100
+ cartesian_velocity: CartesianVelocity,
101
+ instant: Instant,
102
+ frame: Frame,
103
+ coordinates: list[float],
104
+ another_coordinates: list[float],
105
+ coordinates_broker: CoordinatesBroker,
106
+ ):
107
+ for value, expected in zip(
108
+ cartesian_velocity.in_frame(
109
+ instant, coordinates, frame, Frame.ITRF(), coordinates_broker
110
+ ),
111
+ [-4749.36551256577, 854.163395375881, 5335.71857543495],
112
+ ):
113
+ assert value == pytest.approx(expected, rel=1e-14)
@@ -0,0 +1,71 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.astrodynamics.trajectory.state import CoordinatesBroker, CoordinatesSubset
6
+
7
+
8
+ @pytest.fixture
9
+ def coordinates_subsets() -> list:
10
+ return [CoordinatesSubset("Subset1", 2), CoordinatesSubset("Subset2", 3)]
11
+
12
+
13
+ @pytest.fixture
14
+ def coordinates_broker(coordinates_subsets) -> CoordinatesBroker:
15
+ return CoordinatesBroker(coordinates_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 TestCoordinatesBroker:
24
+ def test_constructor(self, coordinates_broker: CoordinatesBroker):
25
+ assert coordinates_broker is not None
26
+
27
+ def test_eq(self, coordinates_broker: CoordinatesBroker):
28
+ assert coordinates_broker == coordinates_broker
29
+
30
+ def test_ne(self, coordinates_broker: CoordinatesBroker):
31
+ assert (coordinates_broker != coordinates_broker) == False
32
+
33
+ def test_access_subsets(
34
+ self, coordinates_broker: CoordinatesBroker, coordinates_subsets: list
35
+ ):
36
+ assert coordinates_broker.access_subsets() == coordinates_subsets
37
+
38
+ def test_get_number_of_coordinates(self, coordinates_broker: CoordinatesBroker):
39
+ assert coordinates_broker.get_number_of_coordinates() == 5
40
+
41
+ def test_get_number_of_subsets(self, coordinates_broker: CoordinatesBroker):
42
+ assert coordinates_broker.get_number_of_subsets() == 2
43
+
44
+ def test_get_subsets(
45
+ self, coordinates_broker: CoordinatesBroker, coordinates_subsets: list
46
+ ):
47
+ assert coordinates_broker.get_subsets() == coordinates_subsets
48
+
49
+ def test_add_subset(self, coordinates_broker: CoordinatesBroker):
50
+ new_subset = CoordinatesSubset("NewSubset", 4)
51
+ number_of_coordinates = coordinates_broker.get_number_of_coordinates()
52
+ assert coordinates_broker.add_subset(new_subset) == number_of_coordinates
53
+ assert coordinates_broker.has_subset(new_subset)
54
+
55
+ def test_has_subset(
56
+ self, coordinates_broker: CoordinatesBroker, coordinates_subsets: list
57
+ ):
58
+ assert coordinates_broker.has_subset(coordinates_subsets[0])
59
+
60
+ def extract_coordinates(
61
+ self,
62
+ coordinates_broker: CoordinatesBroker,
63
+ coordinates: list[float],
64
+ coordinates_subsets: list[CoordinatesSubset],
65
+ ):
66
+ assert coordinates_broker.extract_coordinates(
67
+ coordinates, coordinates_subsets[0]
68
+ ) == [1.0, 2.0]
69
+ assert coordinates_broker.extract_coordinates(
70
+ coordinates, coordinates_subsets[1]
71
+ ) == [3.0, 4.0, 5.0]
@@ -0,0 +1,43 @@
1
+ # Apache License 2.0
2
+
3
+ import pytest
4
+
5
+ from ostk.astrodynamics.trajectory.state import CoordinatesSubset
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 coordinates_subset(name: str, size: int) -> CoordinatesSubset:
20
+ return CoordinatesSubset(name, size)
21
+
22
+
23
+ class TestCoordinatesSubset:
24
+ def test_constructor(self, coordinates_subset: CoordinatesSubset):
25
+ assert coordinates_subset is not None
26
+
27
+ def test_eq(self, coordinates_subset: CoordinatesSubset):
28
+ assert coordinates_subset == coordinates_subset
29
+
30
+ def test_ne(self, coordinates_subset: CoordinatesSubset):
31
+ assert (coordinates_subset != coordinates_subset) == False
32
+
33
+ def test_get_id(self, coordinates_subset: CoordinatesSubset):
34
+ assert coordinates_subset.get_id() is not None
35
+
36
+ def test_get_name(self, coordinates_subset: CoordinatesSubset, name: str):
37
+ assert coordinates_subset.get_name() == name
38
+
39
+ def test_get_size(self, coordinates_subset: CoordinatesSubset, size: int):
40
+ assert coordinates_subset.get_size() == size
41
+
42
+ def test_mass(self):
43
+ assert CoordinatesSubset.mass() is not None
@@ -13,6 +13,7 @@ from ostk.physics.units import Mass
13
13
  from ostk.physics.time import Instant
14
14
  from ostk.physics.time import DateTime
15
15
  from ostk.physics.time import Scale
16
+ from ostk.physics.time import Duration
16
17
  from ostk.physics.coordinate import Position
17
18
  from ostk.physics.coordinate import Velocity
18
19
  from ostk.physics.coordinate import Frame
@@ -25,7 +26,7 @@ from ostk.astrodynamics.flight.system.dynamics import CentralBodyGravity
25
26
  from ostk.astrodynamics.flight.system.dynamics import PositionDerivative
26
27
  from ostk.astrodynamics.trajectory import State
27
28
  from ostk.astrodynamics.trajectory import Propagator
28
- from ostk.astrodynamics import EventCondition
29
+ from ostk.astrodynamics.event_condition import DurationCondition
29
30
 
30
31
 
31
32
  @pytest.fixture
@@ -104,12 +105,10 @@ def conditional_numerical_solver() -> NumericalSolver:
104
105
 
105
106
 
106
107
  @pytest.fixture
107
- def event_condition() -> EventCondition:
108
- class MyEventCondition(EventCondition):
109
- def evaluate(self, state_vector, time):
110
- return time - 42.0
111
-
112
- return MyEventCondition("42 Seconds", EventCondition.Criteria.StrictlyPositive)
108
+ def event_condition() -> DurationCondition:
109
+ return DurationCondition(
110
+ DurationCondition.Criteria.StrictlyPositive, Duration.seconds(42.0)
111
+ )
113
112
 
114
113
 
115
114
  @pytest.fixture
@@ -123,6 +122,11 @@ class TestPropagator:
123
122
  assert isinstance(propagator, Propagator)
124
123
  assert propagator.is_defined()
125
124
 
125
+ def test_access_numerical_solver(
126
+ self, propagator: Propagator, numerical_solver: NumericalSolver
127
+ ):
128
+ assert propagator.access_numerical_solver() == numerical_solver
129
+
126
130
  def test_get_dynamics(self, propagator: Propagator, dynamics: list):
127
131
  assert propagator.get_dynamics() == dynamics
128
132
 
@@ -186,7 +190,7 @@ class TestPropagator:
186
190
  conditional_numerical_solver: NumericalSolver,
187
191
  dynamics: list[Dynamics],
188
192
  state: State,
189
- event_condition: EventCondition,
193
+ event_condition: DurationCondition,
190
194
  ):
191
195
  propagator: Propagator = Propagator(conditional_numerical_solver, dynamics)
192
196
 
@@ -12,26 +12,77 @@ from ostk.physics.coordinate import Velocity
12
12
  from ostk.physics.coordinate import Frame
13
13
 
14
14
  from ostk.astrodynamics.trajectory import State
15
+ from ostk.astrodynamics.trajectory.state import CoordinatesBroker
16
+ from ostk.astrodynamics.trajectory.state.coordinates_subset import (
17
+ CartesianPosition,
18
+ CartesianVelocity,
19
+ )
20
+
21
+
22
+ @pytest.fixture()
23
+ def instant() -> Instant:
24
+ return Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
15
25
 
16
26
 
17
27
  @pytest.fixture
18
- def state_default_inputs() -> tuple[Instant, Position, Velocity, Frame]:
19
- frame: Frame = Frame.GCRF()
20
- position: Position = Position.meters([6371000.0, 0.0, 0.0], frame)
21
- velocity: Velocity = Velocity.meters_per_second([7600.0, 0.0, 0.0], frame)
28
+ def frame() -> Frame:
29
+ return Frame.GCRF()
30
+
22
31
 
23
- instant = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC)
32
+ @pytest.fixture()
33
+ def position(frame: Frame) -> Position:
34
+ return Position.meters([6371000.0, 0.0, 0.0], frame)
24
35
 
25
- return (instant, position, velocity, frame)
36
+
37
+ @pytest.fixture()
38
+ def velocity(frame: Frame) -> Velocity:
39
+ return Velocity.meters_per_second([7600.0, 0.0, 0.0], frame)
26
40
 
27
41
 
28
42
  @pytest.fixture
29
- def state(state_default_inputs) -> State:
30
- return State(*state_default_inputs[0:-1])
43
+ def state(
44
+ instant: Instant, position: Position, velocity: Velocity, frame: Frame
45
+ ) -> State:
46
+ return State(instant, position, velocity)
47
+
48
+
49
+ @pytest.fixture
50
+ def coordinates_broker() -> CoordinatesBroker:
51
+ return CoordinatesBroker([CartesianPosition.default(), CartesianVelocity.default()])
31
52
 
32
53
 
33
54
  class TestState:
34
- def test_constructor(self, state: State):
55
+ def test_constructor(
56
+ self,
57
+ instant: Instant,
58
+ position: Position,
59
+ velocity: Velocity,
60
+ ):
61
+ state = State(instant, position, velocity)
62
+ assert state is not None
63
+ assert isinstance(state, State)
64
+ assert state.is_defined()
65
+
66
+ def test_explicit_constructor(
67
+ self,
68
+ instant: Instant,
69
+ position: Position,
70
+ velocity: Velocity,
71
+ frame: Frame,
72
+ coordinates_broker: CoordinatesBroker,
73
+ ):
74
+ state = State(instant, position, velocity)
75
+ assert state is not None
76
+ assert isinstance(state, State)
77
+ assert state.is_defined()
78
+
79
+ state = State(
80
+ instant,
81
+ np.append(position.get_coordinates(), velocity.get_coordinates()),
82
+ frame,
83
+ coordinates_broker,
84
+ )
85
+
35
86
  assert state is not None
36
87
  assert isinstance(state, State)
37
88
  assert state.is_defined()
@@ -47,13 +98,15 @@ class TestState:
47
98
  def test_getters(
48
99
  self,
49
100
  state: State,
50
- state_default_inputs: tuple[Instant, Position, Velocity, Frame],
101
+ instant: Instant,
102
+ position: Position,
103
+ velocity: Velocity,
104
+ frame: Frame,
51
105
  ):
52
- (instant, position, velocity, _) = state_default_inputs
53
-
54
106
  assert state.get_instant() == instant
55
107
  assert state.get_position() == position
56
108
  assert state.get_velocity() == velocity
109
+ assert state.get_frame() == frame
57
110
  assert (
58
111
  state.get_coordinates()
59
112
  == np.append(position.get_coordinates(), velocity.get_coordinates())
@@ -62,9 +115,7 @@ class TestState:
62
115
  def test_in_frame(
63
116
  self,
64
117
  state: State,
65
- state_default_inputs: tuple[Instant, Position, Velocity, Frame],
118
+ frame: Frame,
66
119
  ):
67
- (_, _, _, frame) = state_default_inputs
68
-
69
120
  assert state.in_frame(frame) == state
70
121
  assert state.in_frame(Frame.ITRF()) != state
@@ -303,7 +303,7 @@ def _cesium_from_ostk_sensor(sensor: Sensor) -> cesiumpy.ConicSensor:
303
303
  return cesiumpy.ConicSensor(
304
304
  name=sensor.name,
305
305
  direction=cesiumpy.Cartesian3(*sensor.direction),
306
- half_angle=cesiumpy.math.to_radians(float(sensor.half_angle.in_radians())),
306
+ half_angle=float(sensor.half_angle.in_radians()),
307
307
  length=float(sensor.length.in_meters()),
308
308
  material=sensor.color or cesiumpy.color.RED,
309
309
  )