Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/18 fix retasking format #92

Merged
merged 2 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions bsk_rl/envs/general_satellite_tasking/gym_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from gymnasium import Env, spaces

from bsk_rl.envs.general_satellite_tasking.scenario.communication import NoCommunication
from bsk_rl.envs.general_satellite_tasking.scenario.satellites import REQUIRES_RETASKING
from bsk_rl.envs.general_satellite_tasking.simulation.simulator import Simulator
from bsk_rl.envs.general_satellite_tasking.types import (
CommunicationMethod,
Expand Down Expand Up @@ -187,6 +186,11 @@ def _get_info(self) -> dict[str, Any]:
satellite.id: deepcopy(satellite.info) for satellite in self.satellites
}
info["d_ts"] = self.latest_step_duration
info["requires_retasking"] = [
satellite.id
for satellite in self.satellites
if satellite.requires_retasking
]
return info

@property
Expand Down Expand Up @@ -221,25 +225,24 @@ def step(
"""Propagate the simulation, update information, and get rewards

Args:
Joint action for satellites. Can be none to maintain current task.
Joint action for satellites

Returns:
observation, reward, terminated, truncated, info
"""
if len(actions) != len(self.satellites):
raise ValueError("There must be the same number of actions and satellites")
for satellite, action in zip(self.satellites, actions):
old_info = satellite.info
satellite.info = [] # reset satellite info log
if action is not None:
satellite.requires_retasking = False
satellite.set_action(action)
else:
if REQUIRES_RETASKING in old_info:
if satellite.requires_retasking:
print(
f"Satellite {satellite.id} requires retasking "
"but received no task."
)
satellite.info.append(REQUIRES_RETASKING)

previous_time = self.simulator.sim_time # should these be recorded in simulator
self.simulator.run()
Expand Down
10 changes: 5 additions & 5 deletions bsk_rl/envs/general_satellite_tasking/scenario/satellites.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
SatObs = Any
SatAct = Any

REQUIRES_RETASKING = "REQUIRES_RETASKING"


class Satellite(ABC):
dyn_type: type["DynamicsModel"] # Type of dynamics model used by this satellite
Expand Down Expand Up @@ -89,6 +87,7 @@ def __init__(
self.fsw: "FSWModel"
self.dynamics: "DynamicsModel"
self.data_store: DataStore
self.requires_retasking: bool
self.variable_interval = variable_interval
self._timed_terminal_event_name = None

Expand All @@ -106,6 +105,7 @@ def _generate_sat_args(self) -> None:
def reset_pre_sim(self) -> None:
"""Called in environment reset, before simulator initialization"""
self.info = []
self.requires_retasking = True
self._generate_sat_args()
assert self.data_store.is_fresh
self.data_store.is_fresh = False
Expand Down Expand Up @@ -155,7 +155,7 @@ def set_fsw(self, fsw_rate: float) -> "FSWModel":

def reset_post_sim(self) -> None:
"""Called in environment reset, after simulator initialization"""
self.info.append(REQUIRES_RETASKING)
pass

@property
def observation_space(self) -> spaces.Box:
Expand Down Expand Up @@ -237,7 +237,7 @@ def _update_timed_terminal_event(
[f"self.TotalSim.CurrentNanos * {macros.NANO2SEC} >= {t_close}"],
[
self._info_command(f"timed termination at {t_close:.1f} " + info),
self._satellite_command + f".info.append('{REQUIRES_RETASKING}')",
self._satellite_command + ".requires_retasking = True",
]
+ extra_actions,
terminal=self.variable_interval,
Expand Down Expand Up @@ -750,7 +750,7 @@ def _update_image_event(self, target: Target) -> None:
[
self._info_command(f"imaged {target}"),
self._satellite_command + ".imaged += 1",
self._satellite_command + f".info.append('{REQUIRES_RETASKING}')",
self._satellite_command + ".requires_retasking = True",
],
terminal=self.variable_interval,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,12 @@ def test_init(self, sat_init):

def test_explicit_normalization(self, sat_init):
sat = so.TimeState(normalization_time=10.0)
sat.info = MagicMock()
sat.simulator = MagicMock(sim_time=1.0)
sat.reset_post_sim()
assert sat.normalized_time() == 0.1

def test_implicit_normalization(self, sat_init):
sat = so.TimeState(normalization_time=None)
sat.info = MagicMock()
sat.simulator = MagicMock(sim_time=1.0, time_limit=10.0)
sat.reset_post_sim()
assert sat.normalized_time() == 0.1
Expand Down
40 changes: 19 additions & 21 deletions tests/unittest/envs/general_satellite_tasking/test_gym_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
GeneralSatelliteTasking,
SingleSatelliteTasking,
)
from bsk_rl.envs.general_satellite_tasking.scenario.satellites import (
REQUIRES_RETASKING,
Satellite,
)
from bsk_rl.envs.general_satellite_tasking.scenario.satellites import Satellite


class TestGeneralSatelliteTasking:
Expand Down Expand Up @@ -67,6 +64,7 @@ def test_get_info(self):
env.latest_step_duration = 10.0
expected = {sat.id: {"sat_index": i} for i, sat in enumerate(mock_sats)}
expected["d_ts"] = 10.0
expected["requires_retasking"] = [sat.id for sat in mock_sats]
assert env._get_info() == expected

def test_action_space(self):
Expand Down Expand Up @@ -147,23 +145,6 @@ def test_step_bad_action(self):
with pytest.raises(ValueError):
env.step((0,))

@patch.multiple(Satellite, __abstractmethods__=set())
def test_step_retask_needed(self, capfd):
mock_sat = MagicMock()
env = SingleSatelliteTasking(
satellites=[mock_sat],
env_type=MagicMock(),
env_features=MagicMock(),
data_manager=MagicMock(reward=MagicMock(return_value=25.0)),
)
env.simulator = MagicMock(sim_time=101.0)
env.step(None)
assert REQUIRES_RETASKING not in mock_sat.info
mock_sat.info = [REQUIRES_RETASKING]
env.step(None)
assert REQUIRES_RETASKING in mock_sat.info
assert "requires retasking but received no task" in capfd.readouterr().out

@pytest.mark.parametrize("sat_death", [True, False])
@pytest.mark.parametrize("timeout", [True, False])
@pytest.mark.parametrize("terminate_on_time_limit", [True, False])
Expand All @@ -190,6 +171,23 @@ def test_step_stopped(self, sat_death, timeout, terminate_on_time_limit):
assert terminated == (sat_death or (timeout and terminate_on_time_limit))
assert truncated == timeout

@patch.multiple(Satellite, __abstractmethods__=set())
def test_step_retask_needed(self, capfd):
mock_sat = MagicMock()
env = SingleSatelliteTasking(
satellites=[mock_sat],
env_type=MagicMock(),
env_features=MagicMock(),
data_manager=MagicMock(reward=MagicMock(return_value=25.0)),
)
env.simulator = MagicMock(sim_time=101.0)
env.step(None)
assert mock_sat.requires_retasking
mock_sat.requires_retasking = True
env.step(None)
assert mock_sat.requires_retasking
assert "requires retasking but received no task" in capfd.readouterr().out

def test_render(self):
pass

Expand Down