diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..0b9075ae --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 561015c04587085d1ef695fb505b3604 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/API Reference/agents/genetic_algorithm.html b/API Reference/agents/genetic_algorithm.html new file mode 100644 index 00000000..54a31947 --- /dev/null +++ b/API Reference/agents/genetic_algorithm.html @@ -0,0 +1,164 @@ + + + + + + + genetic_algorithm — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

genetic_algorithm

+

bsk_rl.agents.genetic_algorithm

+
+
+
+
+class env2opt_problem(env_name, initial_conditions=None)[source]
+

Bases: object

+

This class provides a generic interface for recasting a gymnasium environment as a +total reward maximization problem.

+
+
+__init__(env_name, initial_conditions=None)[source]
+
+ +
+
+evaluate(action_set)[source]
+

Evaluates a full run of the environment given a list of actions.

+
+ +
+ +
+
+mutUniformIntList(individual, num_samples=2, low=0, up=5, indpb=0.3)[source]
+

This function is designed to mutate a list of integers, rather than a single +integer. +:param individual: The individual to be mutated +:param num_samples: The number of samples to be mutated +:param low: The lower bound for the mutation +:param up: The upper bound for the mutation +:param indpb: The probability of mutation +:returns: A list of a single individual.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/agents/index.html b/API Reference/agents/index.html new file mode 100644 index 00000000..78d6f7e8 --- /dev/null +++ b/API Reference/agents/index.html @@ -0,0 +1,137 @@ + + + + + + + agents — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

agents

+

bsk_rl.agents

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/agents/mcts.html b/API Reference/agents/mcts.html new file mode 100644 index 00000000..bc44a2bd --- /dev/null +++ b/API Reference/agents/mcts.html @@ -0,0 +1,202 @@ + + + + + + + mcts — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mcts

+

bsk_rl.agents.mcts

+
+
+
+
+class MCTS(c=1.0, num_sims=10, max_length=270.0, max_steps=45, rollout_policy=None, backup_type='max')[source]
+

Bases: object

+

This provides and MCTS class for deterministic environments.

+

To use as UCT, set the rollout type to either ‘heuristic’ or ‘random’ +If a heuristic rollout type is used, create the policy using the following two +lines of code:

+
stateMachineMCTS = state_machine.StateMachine()
+stateMachineMCTS.loadTransferConditions("agile_eos_ops.adv")
+rollout_policy = AgileEOSRolloutPolicy(env=env, state_machine=stateMachineMCTS)
+
+
+

Then, load the policy as the rollout_policy during initialization:

+
MCTS_Agent = MCTS(c=c, num_sims=num_sims, rollout_policy=rollout_policy)
+
+
+

The env and initial conditions must be loaded in after initialization. The +algorithm will automatically restart the sim and step it forward to the last +state. This is due to limitations in copying Basilisk:

+
MCTS_Agent.setEnv(
+    env_name, env.initial_conditions, max_steps=num_steps, max_length=t_final
+)
+
+
+
+
Parameters:
+
    +
  • c – scaling of the exploration bonus

  • +
  • num_sims – number of simulations per call of selectAction()

  • +
+
+
+
+
+__init__(c=1.0, num_sims=10, max_length=270.0, max_steps=45, rollout_policy=None, backup_type='max')[source]
+
+ +
+
+backup_tree()[source]
+

Backs up the value along the main tree once the sim has terminated

+
+ +
+
+rollout(s, d)[source]
+

Executes a rollout to the desired depth or end of the environment

+
+ +
+
+selectAction(s, d, actHist)[source]
+

Selects the next action for the true environment to step through

+
+ +
+
+setEnv(envType, initial_conditions, max_steps=30, max_length=90)[source]
+

Sets the environment and initial conditions MCTS will step through

+
+ +
+
+simulate(s, d)[source]
+

Simulates a trajectory through the environment and updates Q_search

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/agents/state_machine.html b/API Reference/agents/state_machine.html new file mode 100644 index 00000000..d3d38021 --- /dev/null +++ b/API Reference/agents/state_machine.html @@ -0,0 +1,132 @@ + + + + + + + state_machine — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

state_machine

+

bsk_rl.agents.state_machine

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/agile_eos/bsk_sim.html b/API Reference/envs/agile_eos/bsk_sim.html new file mode 100644 index 00000000..a6f1dfa7 --- /dev/null +++ b/API Reference/envs/agile_eos/bsk_sim.html @@ -0,0 +1,141 @@ + + + + + + + bsk_sim — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

bsk_sim

+

bsk_rl.envs.agile_eos.bsk_sim

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/agile_eos/gym_env.html b/API Reference/envs/agile_eos/gym_env.html new file mode 100644 index 00000000..561b465e --- /dev/null +++ b/API Reference/envs/agile_eos/gym_env.html @@ -0,0 +1,236 @@ + + + + + + + gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

gym_env

+

bsk_rl.envs.agile_eos.gym_env

+
+
+
+
+class AgileEOS(failure_penalty=1, image_component=0.1, downlink_component=0.9)[source]
+

Bases: Env

+

This Gymnasium environment is designed to simulate an agile EOS scheduling problem +in which a satellite in low-Earth orbit attempts to maximize the number of targets +imaged and downlinked while avoiding resource constraint violations. Resource +constraint include:

+
    +
  1. Power: The spacecraft must keep its battery charge above zero

  2. +
  3. +
    Reaction Wheel Saturation: The spacecraft must keep its reaction wheels within

    their speed limits

    +
    +
    +
  4. +
  5. +
    Data Buffer: The spacecraft must keep its data buffer from overflowing (i.e.

    exceeding or meeting the maximum buffer size)

    +
    +
    +
  6. +
+

The spacecraft must decide between pointing at any one of J number of ground targets +for imaging, pointing at the sun to charge, desaturating reaction wheels, or +downlinking data. This is referred to as the AgileEOS environment.

+

Action Space (Discrete): +0 - Charging mode +1 - Downlink mode +2 - Desat mode +3:J+3 - Image target j

+

Observation Space: +ECEF position and velocity - indices 0-5 +Attitude error and attitude rate - indices 6-7 +Reaction wheel speeds - indices 8-11 +Battery charge - indices 12 +Eclipse indicator - indices 13 +Stored data onboard spacecraft - indices 14 +Data transmitted over interval - indices 15 +Amount of time ground stations were accessible (s) - 16-22 +Target Tuples (4 values each) - priority and Hill frame pos

+

Reward Function: +r = +A/priority for for each tgt downlinked for first time +r = +B/priority for for each tgt imaged for first time +r = -C if failure

+
+
+__init__(failure_penalty=1, image_component=0.1, downlink_component=0.9)[source]
+
+ +
+
+reset(seed=None, options=None)[source]
+

Reset the state of the environment and returns an initial observation. +:returns: observation (object) +:rtype: the initial observation of the space.

+
+ +
+
+step(action)[source]
+

The agent takes a step in the environment. +:param action: +:type action: int

+
+
Returns:
+

ob, reward, episode_over, info

+
+
ob (object) :

an environment-specific object representing your observation of +the environment.

+
+
reward (float) :

amount of reward achieved by the previous action. The scale +varies between environments, but the goal is always to increase +your total reward.

+
+
episode_over (bool) :

whether it’s time to reset the environment again. Most (but not +all) tasks are divided up into well-defined episodes, and done +being True indicates the episode has terminated. (For example, +perhaps the pole tipped too far, or you lost your last life.)

+
+
info (dict) :

diagnostic information useful for debugging. It can sometimes +be useful for learning (for example, it might contain the raw +probabilities behind the environment’s last state change). +However, official evaluations of your agent are not allowed to +use this for learning.

+
+
+

+
+
Return type:
+

tuple

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/agile_eos/index.html b/API Reference/envs/agile_eos/index.html new file mode 100644 index 00000000..5493e321 --- /dev/null +++ b/API Reference/envs/agile_eos/index.html @@ -0,0 +1,145 @@ + + + + + + + agile_eos — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

agile_eos

+

bsk_rl.envs.agile_eos

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/gym_env.html b/API Reference/envs/general_satellite_tasking/gym_env.html new file mode 100644 index 00000000..cb94a50b --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/gym_env.html @@ -0,0 +1,383 @@ + + + + + + + gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

gym_env

+

bsk_rl.envs.general_satellite_tasking.gym_env

+
+
+

General Satellite Tasking is a framework for satellite tasking RL environments.

+
+
+class GeneralSatelliteTasking(satellites: Satellite | list[Satellite], env_type: type[EnvironmentModel], env_features: EnvironmentFeatures, data_manager: DataManager, env_args: dict[str, Any] | None = None, communicator: CommunicationMethod | None = None, sim_rate: float = 1.0, max_step_duration: float = 600.0, failure_penalty: float = -100, time_limit: float = inf, terminate_on_time_limit: bool = False, log_level: int | str = 30, log_dir: str | None = None, render_mode=None)[source]
+

Bases: Env, Generic[SatObs, SatAct]

+

A Gymnasium environment adaptable to a wide range satellite tasking problems.

+

These problems involve satellite(s) being tasked to complete tasks and maintain +aliveness. These tasks often include rewards for data collection. The environment +can be configured for any collection of satellites, including heterogenous +constellations. Other configurable aspects are environment features (e.g. +imaging targets), data collection and recording, and intersatellite +communication of data.

+

The state space is a tuple containing the state of each satellite. Actions are +assigned as a tuple of actions, one per satellite.

+

The preferred method of instantiating this environment is to make the +“GeneralSatelliteTasking-v1” environment and pass a kwargs dict with the +environment configuration. In some cases (e.g. the multiprocessed Gymnasium +vector environment), it is necessary for compatibility to instead register a new +environment using the GeneralSatelliteTasking class and a kwargs dict. See +examples/general_satellite_tasking for examples of environment configuration.

+

New environments should be built using this framework.

+
+
+__init__(satellites: Satellite | list[Satellite], env_type: type[EnvironmentModel], env_features: EnvironmentFeatures, data_manager: DataManager, env_args: dict[str, Any] | None = None, communicator: CommunicationMethod | None = None, sim_rate: float = 1.0, max_step_duration: float = 600.0, failure_penalty: float = -100, time_limit: float = inf, terminate_on_time_limit: bool = False, log_level: int | str = 30, log_dir: str | None = None, render_mode=None) None[source]
+

Construct the GeneralSatelliteTasking environment.

+
+
Parameters:
+
    +
  • satellites – Satellites(s) to be simulated.

  • +
  • env_type – Type of environment model to be constructed.

  • +
  • env_args – Arguments for environment model construction. {key: value or key: +function}, where function is called at reset to set the value (used for +randomization).

  • +
  • env_features – Information about the environment.

  • +
  • data_manager – Object to record and reward data collection.

  • +
  • communicator – Object to manage communication between satellites

  • +
  • sim_rate – Rate for model simulation [s].

  • +
  • max_step_duration – Maximum time to propagate sim at a step [s].

  • +
  • failure_penalty – Reward for satellite failure. Should be nonpositive.

  • +
  • time_limit – Time at which to truncate the simulation [s].

  • +
  • terminate_on_time_limit – Send terminations signal time_limit instead of just +truncation.

  • +
  • log_level – Logging level for the environment. Default is WARNING.

  • +
  • log_dir – Directory to write logs to in addition to the console.

  • +
  • render_mode – Unused.

  • +
+
+
+
+ +
+
+property action_space: Space[Iterable[SatAct]]
+

Compose satellite action spaces.

+
+
Returns:
+

Joint action space

+
+
+
+ +
+
+close() None[source]
+

Try to cleanly delete everything.

+
+ +
+
+delete_simulator()[source]
+

Delete Basilisk objects.

+

Only self.simulator contains strong references to BSK models, so deleting it +will delete all Basilisk objects. Enable debug-level logging to verify that the +simulator, FSW, dynamics, and environment models are all deleted on reset.

+
+ +
+
+property observation_space: Space[tuple[SatObs, ...]]
+

Compose satellite observation spaces.

+

Note: calls reset(), which can be expensive, to determine observation size.

+
+
Returns:
+

Joint observation space

+
+
+
+ +
+
+render() None[source]
+

No rendering implemented.

+
+ +
+
+reset(seed: int | None = None, options=None) tuple[tuple[SatObs, ...], dict[str, Any]][source]
+

Reconstruct the simulator and wipe data records.

+
+
Parameters:
+
    +
  • seed – Gymnasium environment seed.

  • +
  • options – Unused.

  • +
+
+
Returns:
+

observation, info

+
+
+
+ +
+
+step(actions: Iterable[SatAct]) tuple[tuple[SatObs, ...], float, bool, bool, dict[str, Any]][source]
+

Propagate the simulation, update information, and get rewards.

+
+
Parameters:
+

actions – Joint action for satellites

+
+
Returns:
+

observation, reward, terminated, truncated, info

+
+
+
+ +
+ +
+
+class MultiagentSatelliteTasking(satellites: Satellite | list[Satellite], env_type: type[EnvironmentModel], env_features: EnvironmentFeatures, data_manager: DataManager, env_args: dict[str, Any] | None = None, communicator: CommunicationMethod | None = None, sim_rate: float = 1.0, max_step_duration: float = 600.0, failure_penalty: float = -100, time_limit: float = inf, terminate_on_time_limit: bool = False, log_level: int | str = 30, log_dir: str | None = None, render_mode=None)[source]
+

Bases: GeneralSatelliteTasking, ParallelEnv, Generic[SatObs, SatAct, AgentID]

+

Implements the environment with the PettingZoo parallel API.

+
+
+action_space(agent: AgentID) Space[SatAct][source]
+

Return the action space for a certain agent.

+
+ +
+
+property action_spaces: dict[AgentID, Space[SatAct]]
+

Return the action space for each agent.

+
+ +
+
+property agents: list[AgentID]
+

Agents currently in the environment.

+
+ +
+
+property max_num_agents: int
+

Maximum number of agents possible in the environment.

+
+ +
+
+property num_agents: int
+

Number of agents currently in the environment.

+
+ +
+
+observation_space(agent: AgentID) Space[SatObs][source]
+

Return the observation space for a certain agent.

+
+ +
+
+property observation_spaces: dict[AgentID, Box]
+

Return the observation space for each agent.

+
+ +
+
+property possible_agents: list[AgentID]
+

Return the list of all possible agents.

+
+ +
+
+property previously_dead: list[AgentID]
+

Return the list of agents that died at least one step ago.

+
+ +
+
+reset(seed: int | None = None, options=None) tuple[tuple[SatObs, ...], dict[str, Any]][source]
+

Reset the environment and return PettingZoo Parallel API format.

+
+ +
+
+step(actions: dict[AgentID, SatAct]) tuple[dict[AgentID, SatObs], dict[AgentID, float], dict[AgentID, bool], dict[AgentID, bool], dict[AgentID, dict]][source]
+

Step the environment and return PettingZoo Parallel API format.

+
+ +
+ +
+
+class SingleSatelliteTasking(*args, **kwargs)[source]
+

Bases: GeneralSatelliteTasking, Generic[SatObs, SatAct]

+

A special case of the GeneralSatelliteTasking for one satellite.

+

For compatibility with standard training APIs, actions and observations are directly +exposed for the single satellite and are not wrapped in a tuple.

+
+
+__init__(*args, **kwargs) None[source]
+

Construct the SingleSatelliteTasking environment.

+
+ +
+
+property action_space: Space[SatAct]
+

Return the single satellite action space.

+
+ +
+
+property observation_space: Box
+

Return the single satellite observation space.

+
+ +
+
+property satellite: Satellite
+

Satellite being tasked.

+
+ +
+
+step(action) tuple[Any, float, bool, bool, dict[str, Any]][source]
+

Task the satellite with a single action.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/index.html b/API Reference/envs/general_satellite_tasking/index.html new file mode 100644 index 00000000..547779f1 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/index.html @@ -0,0 +1,154 @@ + + + + + + + general_satellite_tasking — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

general_satellite_tasking

+

bsk_rl.envs.general_satellite_tasking

+
+

Files:

+ +
+
+

Directories:

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/scenario/communication.html b/API Reference/envs/general_satellite_tasking/scenario/communication.html new file mode 100644 index 00000000..06f6b331 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/scenario/communication.html @@ -0,0 +1,242 @@ + + + + + + + communication — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

communication

+

bsk_rl.envs.general_satellite_tasking.scenario.communication

+
+
+

Communication of data between satellites.

+
+
+class CommunicationMethod(satellites: list[Satellite] | None = None)[source]
+

Bases: ABC

+

Base class for defining data sharing between satellites.

+
+
+__init__(satellites: list[Satellite] | None = None) None[source]
+

Construct base communication class.

+

Subclasses implement a way of determining which pairs of satellites share data.

+
+ +
+
+communicate() None[source]
+

Share data between paired satellites.

+
+ +
+
+reset() None[source]
+

Reset communication after simulator initialization.

+
+ +
+ +
+
+class FreeCommunication(satellites: list[Satellite] | None = None)[source]
+

Bases: CommunicationMethod

+

Implements communication between satellites at every step.

+
+ +
+
+class LOSCommunication(satellites: list[Satellite])[source]
+

Bases: CommunicationMethod

+

Implements communication between satellites with a direct line-of-sight.

+

# TODO only communicate data from before latest LOS time

+
+
+__init__(satellites: list[Satellite]) None[source]
+

Construct line-of-sigh communication management.

+
+
Parameters:
+

satellites – List of satellites to communicate between.

+
+
+
+ +
+
+communicate() None[source]
+

Clear line-of-sight communication logs once communicated.

+
+ +
+
+reset() None[source]
+

Add loggers to satellites to track line-of-sight communication.

+
+ +
+ +
+
+class LOSMultiCommunication(satellites: list[Satellite])[source]
+

Bases: MultiDegreeCommunication, LOSCommunication

+

Multidegree line of sight communication.

+

Composes MultiDegreeCommunication with LOSCommunication.

+
+ +
+
+class MultiDegreeCommunication(satellites: list[Satellite] | None = None)[source]
+

Bases: CommunicationMethod

+

Compose with another type to use multi-degree communications.

+

For example, if a <-> b and b <-> c, multidegree communication will also communicate +between a <-> c.

+
+ +
+
+class NoCommunication(satellites: list[Satellite] | None = None)[source]
+

Bases: CommunicationMethod

+

Implements no communication between satellite.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/scenario/data.html b/API Reference/envs/general_satellite_tasking/scenario/data.html new file mode 100644 index 00000000..b26aa91f --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/scenario/data.html @@ -0,0 +1,407 @@ + + + + + + + data — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

data

+

bsk_rl.envs.general_satellite_tasking.scenario.data

+
+
+

Data logging, management, and reward calculation.

+
+
+class DataManager(env_features: EnvironmentFeatures | None = None)[source]
+

Bases: ABC

+

Base class for simulation-wide data management.

+
+
+__init__(env_features: EnvironmentFeatures | None = None) None[source]
+

Construct base class to handle data recording and rewarding.

+

TODO: allow for creation/composition of multiple managers.

+
+
Parameters:
+

env_features – Information about the environment that can be collected as +data

+
+
+
+ +
+
+create_data_store(satellite: Satellite) None[source]
+

Create a data store for a satellite.

+
+ +
+
+reset() None[source]
+

Refresh data and cumulative reward for a new episode.

+
+ +
+
+reward(new_data_dict: dict[str, DataType]) dict[str, float][source]
+

Call _calc_reward and log cumulative reward.

+
+ +
+ +
+
+class DataStore(data_manager: DataManager, satellite: Satellite)[source]
+

Bases: ABC

+

Base class for satellite data logging.

+

One DataStore is created per satellite.

+
+
+__init__(data_manager: DataManager, satellite: Satellite) None[source]
+

Construct a DataStore base class.

+
+
Parameters:
+
    +
  • data_manager – Simulation data manager to report back to

  • +
  • satellite – Satellite’s data being stored

  • +
+
+
+
+ +
+
+communication_update() None[source]
+

Update the data store from staged data.

+
+
Parameters:
+

external_data (DataType) – Data collected by another satellite

+
+
+
+ +
+
+internal_update() DataType[source]
+

Update the data store based on collected information.

+
+
Returns:
+

New data from the previous step

+
+
+
+ +
+
+stage_communicated_data(external_data: DataType) None[source]
+

Prepare data to be added from another source, but don’t add it yet.

+
+
Parameters:
+

external_data – Data from another satellite to be added

+
+
+
+ +
+ +
+
+class DataType[source]
+

Bases: ABC

+

Base class for units of satellite data.

+
+ +
+
+class NadirScanningManager(env_features: EnvironmentFeatures | None = None, reward_fn: Callable | None = None)[source]
+

Bases: DataManager

+

DataManager for rewarding time spent scanning nadir.

+
+
+DataStore
+

alias of ScanningNadirTimeStore

+
+ +
+
+__init__(env_features: EnvironmentFeatures | None = None, reward_fn: Callable | None = None) None[source]
+

Construct a data manager for nadir scanning.

+
+
Parameters:
+
    +
  • env_features – Information about the environment that can be collected as +data

  • +
  • reward_fn – Reward as function of time spend pointing nadir.

  • +
+
+
+
+ +
+ +
+
+class NadirScanningTimeData(scanning_time: float = 0.0)[source]
+

Bases: DataType

+

DataType for time spent scanning nadir.

+
+
+__init__(scanning_time: float = 0.0) None[source]
+

DataType to log data generated scanning nadir.

+
+
Parameters:
+

scanning_time – Time spent scanning nadir

+
+
+
+ +
+ +
+
+class NoData[source]
+

Bases: DataType

+

DataType for no data.

+
+ +
+
+class NoDataManager(env_features: EnvironmentFeatures | None = None)[source]
+

Bases: DataManager

+

DataManager for no data.

+
+
+DataStore
+

alias of NoDataStore

+
+ +
+ +
+
+class NoDataStore(data_manager: DataManager, satellite: Satellite)[source]
+

Bases: DataStore

+

DataStore for no data.

+
+
+DataType
+

alias of NoData

+
+ +
+ +
+
+class ScanningNadirTimeStore(data_manager: DataManager, satellite: Satellite)[source]
+

Bases: DataStore

+

DataStore for time spent scanning nadir.

+
+
+DataType
+

alias of NadirScanningTimeData

+
+ +
+ +
+
+class UniqueImageData(imaged: list[Target] | None = None, duplicates: int = 0)[source]
+

Bases: DataType

+

DataType for unique images of targets.

+
+
+__init__(imaged: list[Target] | None = None, duplicates: int = 0) None[source]
+

Construct unit of data to record unique images.

+
+
Parameters:
+
    +
  • imaged – List of targets that are known to be imaged.

  • +
  • duplicates – Count of target imaging duplication.

  • +
+
+
+
+ +
+ +
+
+class UniqueImageStore(data_manager: DataManager, satellite: Satellite)[source]
+

Bases: DataStore

+

DataStore for unique images of targets.

+
+
+DataType
+

alias of UniqueImageData

+
+ +
+ +
+
+class UniqueImagingManager(env_features: EnvironmentFeatures | None = None, reward_fn: ~typing.Callable = <function UniqueImagingManager.<lambda>>)[source]
+

Bases: DataManager

+

DataManager for rewarding unique images.

+
+
+DataStore
+

alias of UniqueImageStore

+
+ +
+
+__init__(env_features: EnvironmentFeatures | None = None, reward_fn: ~typing.Callable = <function UniqueImagingManager.<lambda>>) None[source]
+

DataManager for rewarding unique images.

+
+
Parameters:
+
    +
  • env_features – DataManager.env_features

  • +
  • reward_fn – Reward as function of priority.

  • +
+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/scenario/environment_features.html b/API Reference/envs/general_satellite_tasking/scenario/environment_features.html new file mode 100644 index 00000000..3d416814 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/scenario/environment_features.html @@ -0,0 +1,297 @@ + + + + + + + environment_features — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

environment_features

+

bsk_rl.envs.general_satellite_tasking.scenario.environment_features

+
+
+

Environment features define data available for satellites to collect.

+
+
+class CityTargets(n_targets: int | tuple[int, int], n_select_from: int = 9223372036854775807, location_offset: float = 0, priority_distribution: ~typing.Callable | None = None, radius: float = <MagicMock name='mock.orbitalMotion.REQ_EARTH.__mul__()' id='140255136257776'>)[source]
+

Bases: StaticTargets

+

Environment with targets distributed around population centers.

+
+
+__init__(n_targets: int | tuple[int, int], n_select_from: int = 9223372036854775807, location_offset: float = 0, priority_distribution: ~typing.Callable | None = None, radius: float = <MagicMock name='mock.orbitalMotion.REQ_EARTH.__mul__()' id='140255136257776'>) None[source]
+

Construct environment with of static targets around population centers.

+
+
Parameters:
+
    +
  • n_targets – Number of targets to generate

  • +
  • n_select_from – Generate targets from the top n most populous.

  • +
  • location_offset – Offset targets randomly from the city center [m].

  • +
  • priority_distribution – Function for generating target priority.

  • +
  • radius – Radius to place targets from body center.

  • +
+
+
+
+ +
+
+regenerate_targets() None[source]
+

Regenerate targets based on cities.

+
+ +
+ +
+
+class EnvironmentFeatures[source]
+

Bases: ABC

+

Base environment feature class.

+
+
+reset() None[source]
+

Reset environment features.

+
+ +
+ +
+
+class StaticTargets(n_targets: int | tuple[int, int], priority_distribution: ~typing.Callable | None = None, radius: float = <MagicMock name='mock.orbitalMotion.REQ_EARTH.__mul__()' id='140255136257776'>)[source]
+

Bases: EnvironmentFeatures

+

Environment with targets distributed uniformly.

+
+
+__init__(n_targets: int | tuple[int, int], priority_distribution: ~typing.Callable | None = None, radius: float = <MagicMock name='mock.orbitalMotion.REQ_EARTH.__mul__()' id='140255136257776'>) None[source]
+

Construct an environment with evenly-distributed static targets.

+
+
Parameters:
+
    +
  • n_targets – Number (or range) of targets to generate

  • +
  • priority_distribution – Function for generating target priority.

  • +
  • radius – Radius to place targets from body center.

  • +
+
+
+
+ +
+
+regenerate_targets() None[source]
+

Regenerate targets uniformly.

+
+ +
+
+reset() None[source]
+

Regenerate target set for new episode.

+
+ +
+ +
+
+class Target(name: str, location: Iterable[float], priority: float)[source]
+

Bases: object

+

Ground target with associated value.

+
+
+__init__(name: str, location: Iterable[float], priority: float) None[source]
+

Construct a Target.

+
+
Parameters:
+
    +
  • name – Identifier; does not need to be unique

  • +
  • location – PCPF location [m]

  • +
  • priority – Value metric.

  • +
+
+
+
+ +
+
+property id: str
+

Get unique human-readable identifier.

+
+
Returns:
+

Unique human-readable identifier.

+
+
+
+ +
+ +
+
+class UniformNadirFeature(value_per_second: float = 1.0)[source]
+

Bases: EnvironmentFeatures

+

Defines a nadir target center at the center of the planet.

+
+
+__init__(value_per_second: float = 1.0) None[source]
+

Construct uniform data over the surface of the planet.

+
+
Parameters:
+

value_per_second – Amount of reward per second imaging nadir.

+
+
+
+ +
+ +
+
+lla2ecef(lat: float, long: float, radius: float)[source]
+

Project LLA to Earth Centered, Earth Fixed location.

+
+
Parameters:
+
    +
  • lat – [deg]

  • +
  • long – [deg]

  • +
  • radius – [any]

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/scenario/index.html b/API Reference/envs/general_satellite_tasking/scenario/index.html new file mode 100644 index 00000000..22c39539 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/scenario/index.html @@ -0,0 +1,161 @@ + + + + + + + scenario — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

scenario

+

bsk_rl.envs.general_satellite_tasking.scenario

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/scenario/sat_actions.html b/API Reference/envs/general_satellite_tasking/scenario/sat_actions.html new file mode 100644 index 00000000..e7ced65f --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/scenario/sat_actions.html @@ -0,0 +1,315 @@ + + + + + + + sat_actions — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

sat_actions

+

bsk_rl.envs.general_satellite_tasking.scenario.sat_actions

+
+
+

Satellite action types can be used to add actions to the agents.

+
+
+ChargingAction
+

alias of FSWAction

+
+ +
+
+DesatAction
+

alias of FSWAction

+
+ +
+
+class DiscreteSatAction(*args, **kwargs)[source]
+

Bases: SatAction

+

Base satellite subclass for composing discrete actions.

+
+
+__init__(*args, **kwargs) None[source]
+

Construct satellite with discrete actions.

+

Actions are added to the satellite for each DiscreteSatAction subclass, and can +be accessed by index in order added.

+
+ +
+
+property action_space: Discrete
+

Infer action space.

+
+ +
+
+add_action(act_fn, act_name: str | None = None, n_actions: int | None = None)[source]
+

Add an action to the action map.

+
+
Parameters:
+
    +
  • act_fn – Function to call when selecting action. Takes as a keyword +prev_action_key, used to avoid retasking of BSK models. Can accept an +integer argument.

  • +
  • act_name – String to refer to action.

  • +
  • n_actions – If not none, add action n_actions times, calling it with an +increasing integer argument for each subsequent action.

  • +
+
+
+
+ +
+
+generate_indexed_action(act_fn, index: int)[source]
+

Create an indexed action function.

+

Makes an indexed action function from an action function that takes an index +as an argument.

+
+
Parameters:
+
    +
  • act_fn – Action function to index.

  • +
  • index – Index to pass to act_fn.

  • +
+
+
+
+ +
+
+set_action(action: int)[source]
+

Call action function my index.

+
+ +
+ +
+
+DownlinkAction
+

alias of FSWAction

+
+ +
+
+DriftAction
+

alias of FSWAction

+
+ +
+
+class ImagingActions(*args, n_ahead_act=10, **kwargs)[source]
+

Bases: DiscreteSatAction, ImagingSatellite

+

Satellite subclass to add upcoming target imaging to action space.

+
+
+__init__(*args, n_ahead_act=10, **kwargs) None[source]
+

Discrete action to image upcoming targets.

+
+
Parameters:
+
    +
  • n_ahead_act – Number of actions to include in action space.

  • +
  • args – Passed through to satellite

  • +
  • kwargs – Passed through to satellite

  • +
+
+
+
+ +
+
+image(target: int | Target | str, prev_action_key=None) str[source]
+

Activate imaging action.

+
+
Parameters:
+
    +
  • target – Target, in terms of upcoming index, Target, or ID,

  • +
  • prev_action_key – Previous action key

  • +
+
+
Returns:
+

Target ID

+
+
+
+ +
+
+set_action(action: int | Target | str)[source]
+

Allow the satellite to be tasked by Target or target id.

+

Allows for additional tasking modes in addition to action index-based tasking.

+
+ +
+ +
+
+NadirImagingAction
+

alias of FSWAction

+
+ +
+
+class SatAction(name: str, sat_args: dict[str, Any] | None, variable_interval: bool = True, **kwargs)[source]
+

Bases: Satellite

+

Base satellite subclass for composing actions.

+
+ +
+
+fsw_action_gen(fsw_action: str, action_duration: float = 1000000000.0) type[source]
+

Generate an action class for a FSW @action.

+
+
Parameters:
+
    +
  • fsw_action – Function name of FSW action.

  • +
  • action_duration – Time to task action for.

  • +
+
+
Returns:
+

Satellite action class with fsw_action action.

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/scenario/sat_observations.html b/API Reference/envs/general_satellite_tasking/scenario/sat_observations.html new file mode 100644 index 00000000..82916a2c --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/scenario/sat_observations.html @@ -0,0 +1,407 @@ + + + + + + + sat_observations — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

sat_observations

+

bsk_rl.envs.general_satellite_tasking.scenario.sat_observations

+
+
+

Satellite observation types can be used to add information to the observation.

+
+
+class EclipseState(*args, orbit_period=5700, **kwargs)[source]
+

Bases: SatObservation

+

Satellite subclass to add upcoming eclipse information to the observation.

+
+
+__init__(*args, orbit_period=5700, **kwargs)[source]
+

Add a tuple of the orbit-normalized next orbit start and end.

+
+
Parameters:
+
    +
  • orbit_period – Normalization factor for eclipse time.

  • +
  • args – Passed through to satellite

  • +
  • kwargs – Passed through to satellite

  • +
+
+
+
+ +
+
+eclipse_state()[source]
+

Return tuple of normalized next eclipse start and end.

+
+ +
+ +
+
+class GroundStationState(*args, n_ahead_observe_downlinks: int = 1, downlink_window_properties: list[dict[str, Any]] | None = None, **kwargs)[source]
+

Bases: SatObservation, AccessSatellite

+

Satellite subclass to add ground station information to the observation.

+
+
+__init__(*args, n_ahead_observe_downlinks: int = 1, downlink_window_properties: list[dict[str, Any]] | None = None, **kwargs)[source]
+

Add information about downlink opportunities to the observation state.

+
+
Parameters:
+
    +
  • n_ahead_observe_downlinks – Number of upcoming downlink opportunities to +consider.

  • +
  • downlink_window_properties – List of properties to include in the observation +in the format [dict(prop=”prop_name”, norm=norm)]. If norm is not +specified, it is set to 1.0 (no normalization). Properties to choose +from: +* location +* window_open +* window_mid +* window_close

  • +
  • args – Passed through to satellite

  • +
  • kwargs – Passed through to satellite

  • +
+
+
+
+ +
+
+ground_station_obs_generator(downlink_window_properties: list[dict[str, Any]], n_ahead_observe_downlinks: int) None[source]
+

Generate the ground_station_obs function.

+

Generates an obs function from the downlink_window_properties spec and adds it +to the observation.

+
+ +
+
+reset_post_sim() None[source]
+

Add downlink ground stations to be considered by the access checker.

+
+ +
+ +
+
+class NormdPropertyState(*args, obs_properties: list[dict[str, Any]] = [], **kwargs)[source]
+

Bases: SatObservation

+

Satellite subclass to add satellites properties to the observation.

+
+
+__init__(*args, obs_properties: list[dict[str, Any]] = [], **kwargs) None[source]
+

Add a list of properties to the satellite observation.

+
+
Parameters:
+
    +
  • obs_properties

    List of properties that can be found in fsw or dynamics that +are to be appended to the the observation. Properties are optionally +normalized by some factor. Specified in the form

    +
    +
    code-block:
    +

    python

    +

    [dict(prop=”prop_name”, module=”fsw”/”dynamics”/None, norm=1.0)]

    +
    +
    +

    If module is not specified or None, the source of the property is +inferred. If norm is not specified, it is set to 1.0 (no normalization).

    +

  • +
  • args – Passed through to satellite

  • +
  • kwargs – Passed through to satellite

  • +
+
+
+
+ +
+
+add_prop_function(prop: str, module: str | None = None, norm: float = 1.0)[source]
+

Add a property to the observation.

+
+
Parameters:
+
    +
  • prop – Property to query

  • +
  • module – Module (dynamics or fsw) that holds the property. Can be inferred.

  • +
  • norm – Value to normalize property by. Defaults to 1.0.

  • +
+
+
+
+ +
+ +
+
+class SatObservation(*args, obs_type: type = <class 'numpy.ndarray'>, **kwargs)[source]
+

Bases: Satellite

+

Base satellite subclass for composing observations.

+
+
+__init__(*args, obs_type: type = <class 'numpy.ndarray'>, **kwargs) None[source]
+

Satellite subclass for composing observations.

+
+
Parameters:
+
    +
  • obs_type – Datatype of satellite’s returned observation

  • +
  • args – Passed through to satellite

  • +
  • kwargs – Passed through to satellite

  • +
+
+
+
+ +
+
+add_to_observation(obs_element: Callable) None[source]
+

Add a function to be called when constructing observations.

+
+
Parameters:
+

obs_element – Callable to be observed

+
+
+
+ +
+
+get_obs() dict | ndarray | list[source]
+

Update the observation.

+
+ +
+
+property obs_dict
+

Human-readable observation format.

+

Cached so only computed once per timestep.

+
+ +
+
+property obs_list
+

List observation format.

+
+ +
+
+property obs_ndarray
+

Numpy vector observation format.

+
+ +
+ +
+
+class TargetState(*args, n_ahead_observe: int = 1, target_properties: list[dict[str, Any]] | None = None, **kwargs)[source]
+

Bases: SatObservation, ImagingSatellite

+

Satellite subclass to add upcoming target information to the observation.

+
+
+__init__(*args, n_ahead_observe: int = 1, target_properties: list[dict[str, Any]] | None = None, **kwargs)[source]
+

Add information about upcoming targets to the observation state.

+
+
Parameters:
+
    +
  • n_ahead_observe – Number of upcoming targets to consider.

  • +
  • target_properties – List of properties to include in the observation in the +format [dict(prop=”prop_name”, norm=norm)]. If norm is not specified, it +is set to 1.0 (no normalization). Properties to choose from: +* priority +* location +* window_open +* window_mid +* window_close

  • +
  • args – Passed through to satellite

  • +
  • kwargs – Passed through to satellite

  • +
+
+
+
+ +
+
+target_obs_generator(target_properties)[source]
+

Generate the target_obs function.

+

Generates the observation function from the target_properties spec and add it +to the observation.

+
+ +
+ +
+
+class TimeState(*args, normalization_time: float | None = None, **kwargs)[source]
+

Bases: SatObservation

+

Satellite subclass to add simulation time to the observation.

+
+
+__init__(*args, normalization_time: float | None = None, **kwargs)[source]
+

Add the sim time to the observation state.

+

Automatically normalizes to the sim duration.

+
+
Parameters:
+
    +
  • normalization_time – Time to normalize by. If None, is set to simulation +duration

  • +
  • args – Passed through to satellite

  • +
  • kwargs – Passed through to satellite

  • +
+
+
+
+ +
+
+normalized_time()[source]
+

Return time normalized by normalization_time.

+
+ +
+
+reset_post_sim()[source]
+

Autodetect normalization time.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/scenario/satellites.html b/API Reference/envs/general_satellite_tasking/scenario/satellites.html new file mode 100644 index 00000000..73218140 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/scenario/satellites.html @@ -0,0 +1,671 @@ + + + + + + + satellites — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

satellites

+

bsk_rl.envs.general_satellite_tasking.scenario.satellites

+
+
+

Satellites are the agents in the environment.

+
+
+class AccessSatellite(*args, generation_duration: float = 5700, initial_generation_duration: float | None = None, access_dist_threshold: float = 4000000.0, **kwargs)[source]
+

Bases: Satellite

+

Satellite that can detect access opportunities for ground locations.

+
+
+__init__(*args, generation_duration: float = 5700, initial_generation_duration: float | None = None, access_dist_threshold: float = 4000000.0, **kwargs) None[source]
+

Construct an AccessSatellite.

+
+
Parameters:
+
    +
  • generation_duration – Duration to calculate additional imaging windows for +when windows are exhausted. If None, generate for the simulation +time_limit unless the simulation is infinite. [s]

  • +
  • initial_generation_duration – Duration to initially calculate imaging windows +[s]

  • +
  • access_dist_threshold – Distance bound [m] for evaluating imaging windows +more exactly. 4e6 will capture >10 elevation windows for a 500 km orbit.

  • +
  • args – Passed through to Satellite constructor

  • +
  • kwargs – Passed through to Satellite constructor

  • +
+
+
+
+ +
+
+add_location_for_access_checking(object: Any, location: ndarray, min_elev: float, type: str) None[source]
+

Add a location to be included in window calculations.

+

Note that this location will only be included in future calls to +calculate_additional_windows.

+
+
Parameters:
+
    +
  • object – Object to add window for

  • +
  • location – Objects PCPF location [m]

  • +
  • min_elev – Minimum elevation angle for access [rad]

  • +
  • type – Category of windows to add location to

  • +
+
+
+
+ +
+
+calculate_additional_windows(duration: float) None[source]
+

Use a multiroot finding method to evaluate imaging windows for each location.

+
+
Parameters:
+

duration – Time to calculate windows from end of previous window.

+
+
+
+ +
+
+find_next_opportunities(n: int, pad: bool = True, max_lookahead: int = 100, types: str | list[str] | None = None, filter: list = []) list[dict][source]
+

Find the n nearest opportunities, sorted by window close time.

+
+
Parameters:
+
    +
  • n – Number of opportunities to attempt to include.

  • +
  • pad – If true, duplicates the last target if the number of opportunities +found is less than n.

  • +
  • max_lookahead – Maximum times to call calculate_additional_windows.

  • +
  • types – Types of opportunities to include. If None, include all types.

  • +
  • filter – Objects to exclude from the dictionary.

  • +
+
+
Returns:
+

n nearest opportunities, ordered

+
+
Return type:
+

list

+
+
+
+ +
+
+next_opportunities_dict(types: str | list[str] | None = None, filter: list = []) dict[Any, tuple[float, float]][source]
+

Make dictionary of opportunities that maps objects to the next open windows.

+
+
Parameters:
+
    +
  • types – Types of opportunities to include. If None, include all types.

  • +
  • filter – Objects to exclude from the dictionary.

  • +
+
+
Returns:
+

objects -> next window

+
+
Return type:
+

windows

+
+
+
+ +
+
+opportunities_dict(types: str | list[str] | None = None, filter: list = []) dict[Any, list[tuple[float, float]]][source]
+

Make dictionary of opportunities that maps objects to lists of windows.

+
+
Parameters:
+
    +
  • types – Types of opportunities to include. If None, include all types.

  • +
  • filter – Objects to exclude from the dictionary.

  • +
+
+
Returns:
+

objects -> windows list

+
+
Return type:
+

windows

+
+
+
+ +
+
+reset_post_sim() None[source]
+

Handle initial window calculations for new simulation.

+
+ +
+
+reset_pre_sim() None[source]
+

Reset satellite window calculations and lists.

+
+ +
+
+property upcoming_opportunities: list[dict]
+

Ordered list of opportunities that have not yet closed.

+
+
Returns:
+

list of upcoming opportunities

+
+
Return type:
+

list

+
+
+
+ +
+
+upcoming_opportunities_dict(types: str | list[str] | None = None, filter: list = []) dict[Any, list[tuple[float, float]]][source]
+

Get dictionary of opportunities.

+

Maps objects to lists of windows that have not yet closed.

+
+
Parameters:
+
    +
  • types – Types of opportunities to include. If None, include all types.

  • +
  • filter – Objects to exclude from the dictionary.

  • +
+
+
Returns:
+

objects -> windows list (upcoming only)

+
+
Return type:
+

windows

+
+
+
+ +
+ +
+
+class DoNothingSatellite(*args, action_duration: float = 1000000000.0, **kwargs)[source]
+

Bases: FSWAction, TimeState

+

Convenience type for a satellite that does nothing.

+
+
+dyn_type
+

alias of BasicDynamicsModel

+
+ +
+
+fsw_type
+

alias of BasicFSWModel

+
+ +
+ +
+
+class FBImagerSatellite(*args, **kwargs)[source]
+

Bases: ImagingSatellite

+

Convenience type for an imaging satellite with feedback control.

+
+
+dyn_type
+

alias of FullFeaturedDynModel

+
+ +
+
+fsw_type
+

alias of ImagingFSWModel

+
+ +
+ +
+
+class FullFeaturedSatellite(*args, n_ahead_act=10, **kwargs)[source]
+

Bases: ImagingActions, FSWAction, FSWAction, TimeState, Configurable, Configurable, SteeringImagerSatellite

+

Convenience type for a satellite with common features enabled.

+
+ +
+
+class ImageAheadSatellite(*args, n_ahead_act=10, **kwargs)[source]
+

Bases: ImagingActions, TimeState, Configurable, Configurable, SteeringImagerSatellite

+

Convenience type for a satellite with common features enabled.

+
+ +
+
+class ImagingSatellite(*args, **kwargs)[source]
+

Bases: AccessSatellite

+

Satellite with agile imaging capabilities.

+
+
+__init__(*args, **kwargs) None[source]
+

Construct an ImagingSatellite.

+

Can stop the simulation when a target is imaged or missed.

+
+ +
+
+dyn_type
+

alias of ImagingDynModel

+
+ +
+
+enable_target_window(target: Target)[source]
+

Enable the next window close event for target.

+
+ +
+
+fsw_type
+

alias of ImagingFSWModel

+
+ +
+
+property next_windows: dict[Target, tuple[float, float]]
+

Soonest window for each target.

+
+
Returns:
+

first non-closed window for each target

+
+
Return type:
+

dict

+
+
+
+ +
+
+parse_target_selection(target_query: int | Target | str)[source]
+

Identify a target from a query.

+

Parses an upcoming target index, Target object, or target id.

+
+
Parameters:
+

target_query – Taret upcoming index, object, or id.

+
+
+
+ +
+
+reset_post_sim() None[source]
+

Handle initial_generation_duration setting and calculate windows.

+
+ +
+
+reset_pre_sim() None[source]
+

Set the buffer parameters based on computed windows.

+
+ +
+
+task_target_for_imaging(target: Target)[source]
+

Task the satellite to image a target.

+
+
Parameters:
+

target – Selected target

+
+
+
+ +
+
+upcoming_targets(n: int, pad: bool = True, max_lookahead: int = 100) list[Target][source]
+

Find the n nearest targets.

+

Targets are sorted by window close time; currently open windows are included.

+
+
Parameters:
+
    +
  • n – number of windows to look ahead

  • +
  • pad – if true, duplicates the last target if the number of targets found is +less than n

  • +
  • max_lookahead – maximum times to call calculate_additional_windows

  • +
+
+
Returns:
+

n nearest targets, ordered

+
+
Return type:
+

list

+
+
+
+ +
+
+property upcoming_windows: dict[Target, list[tuple[float, float]]]
+

Access upcoming windows in a dict of targets -> list of windows.

+
+ +
+
+property windows: dict[Target, list[tuple[float, float]]]
+

Access windows via dict of targets -> list of windows.

+
+ +
+ +
+
+class Satellite(name: str, sat_args: dict[str, Any] | None, variable_interval: bool = True, **kwargs)[source]
+

Bases: ABC

+

Abstract base class for satellites.

+
+
+__init__(name: str, sat_args: dict[str, Any] | None, variable_interval: bool = True, **kwargs) None[source]
+

Construct base satellite.

+
+
Parameters:
+
    +
  • name – identifier for satellite; does not need to be unique

  • +
  • sat_args – arguments for FSW and dynamic model construction. {key: value or +key: function}, where function is called at reset to set the value (used +for randomization).

  • +
  • variable_interval – Stop simulation at terminal events

  • +
  • kwargs – Ignored

  • +
+
+
+
+ +
+
+abstract property action_space: Space
+

Action space for single satellite.

+
+
Returns:
+

gymanisium action space

+
+
+
+ +
+
+classmethod default_sat_args(**kwargs) dict[str, Any][source]
+

Compile default arguments for FSW and dynamics models.

+
+
Returns:
+

default arguments for satellite models

+
+
+
+ +
+
+abstract get_obs() Any[source]
+

Construct the satellite’s observation.

+
+
Returns:
+

satellite observation

+
+
+
+ +
+
+property id: str
+

Unique human-readable identifier.

+
+ +
+
+is_alive(log_failure=False) bool[source]
+

Check if the satellite is violating any aliveness requirements.

+

Checkes aliveness checkers in dynamics and FSW models.

+
+
Returns:
+

is_alive

+
+
+
+ +
+
+log_info(info: Any) None[source]
+

Record information at the current time.

+
+
Parameters:
+

info – Information to log

+
+
+
+ +
+
+property observation_space: Box
+

Observation space for single satellite, determined from observation.

+
+
Returns:
+

gymanisium observation space

+
+
+
+ +
+
+reset_post_sim() None[source]
+

Reset in environment reset, after simulator initialization.

+
+ +
+
+reset_pre_sim() None[source]
+

Reset during environment reset, before simulator initialization.

+
+ +
+
+abstract set_action(action: int) None[source]
+

Enable certain processes in the simulator to command the satellite task.

+

Should call an @action from FSW, among other things.

+
+
Parameters:
+

action – action index

+
+
+
+ +
+
+set_dynamics(dyn_rate: float) DynamicsModel[source]
+

Create dynamics model; called during simulator initialization.

+
+
Parameters:
+

dyn_rate – rate for dynamics simulation [s]

+
+
Returns:
+

Satellite’s dynamics model

+
+
+
+ +
+
+set_fsw(fsw_rate: float) FSWModel[source]
+

Create flight software model; called during simulator initialization.

+
+
Parameters:
+

fsw_rate – rate for FSW simulation [s]

+
+
Returns:
+

Satellite’s FSW model

+
+
+
+ +
+
+set_simulator(simulator: Simulator)[source]
+

Set the simulator for models.

+

Called during simulator initialization.

+
+
Parameters:
+

simulator – Basilisk simulator

+
+
+
+ +
+ +
+
+class SteeringImagerSatellite(*args, **kwargs)[source]
+

Bases: ImagingSatellite

+

Convenience type for an imaging satellite with MRP steering.

+
+
+dyn_type
+

alias of FullFeaturedDynModel

+
+ +
+
+fsw_type
+

alias of SteeringImagerFSWModel

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/simulation/dynamics.html b/API Reference/envs/general_satellite_tasking/simulation/dynamics.html new file mode 100644 index 00000000..0a21d6e5 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/simulation/dynamics.html @@ -0,0 +1,346 @@ + + + + + + + dynamics — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

dynamics

+

bsk_rl.envs.general_satellite_tasking.simulation.dynamics

+
+
+

Basilisk dynamics models.

+
+
+class BasicDynamicsModel(satellite: Satellite, dyn_rate: float, priority: int = 200, **kwargs)[source]
+

Bases: DynamicsModel

+

Basic Dynamics model with minimum necessary Basilisk components.

+
+
+property BN
+

Body relative to inertial frame rotation matrix.

+
+ +
+
+property BP
+

Body relative to planet freame rotation matrix.

+
+ +
+
+property battery_charge
+

Battery charge [W*s].

+
+ +
+
+property battery_charge_fraction
+

Battery charge as a fraction of capacity.

+
+ +
+
+property omega_BN_B
+

Body rate relative to inertial frame in body frame [rad/s].

+
+ +
+
+property omega_BP_P
+

Body angular velocity relative to planet frame in plant frame [rad/s].

+
+ +
+
+property r_BN_N
+

Body position relative to inertial origin in inertial frame [m].

+
+ +
+
+property r_BN_P
+

Body position relative to inertial origin in planet frame [m].

+
+ +
+
+property sigma_BN
+

Body attitude MRP relative to inertial frame.

+
+ +
+
+property v_BN_N
+

Body velocity relative to inertial origin in inertial frame [m/s].

+
+ +
+
+property v_BN_P
+

P-frame derivative of r_BN.

+
+ +
+
+property wheel_speeds
+

Wheel speeds [rad/s].

+
+ +
+
+property wheel_speeds_fraction
+

Wheel speeds normalized by maximum.

+
+ +
+ +
+
+class ContinuousImagingDynModel(satellite: Satellite, dyn_rate: float, priority: int = 200, **kwargs)[source]
+

Bases: ImagingDynModel

+

Equips the satellite for continuous nadir imaging.

+

Equips satellite with an instrument, storage unit, and transmitter +for continuous nadir imaging.

+
+ +
+
+class DynamicsModel(satellite: Satellite, dyn_rate: float, priority: int = 200, **kwargs)[source]
+

Bases: ABC

+

Abstract Basilisk dynamics model.

+

One DynamicsModel is instantiated for each satellite in the environment each time a +new simulator is created.

+
+
+__init__(satellite: Satellite, dyn_rate: float, priority: int = 200, **kwargs) None[source]
+

Construct a base dynamics model.

+
+
Parameters:
+
    +
  • satellite – Satellite modelled by this model

  • +
  • dyn_rate – Rate of dynamics simulation [s]

  • +
  • priority – Model priority.

  • +
  • kwargs – Ignored

  • +
+
+
+
+ +
+
+property environment: EnvironmentModel
+

Reference to the episode environment model.

+
+ +
+
+is_alive(log_failure=False) bool[source]
+

Check if the dynamics model has failed any aliveness requirements.

+
+
Returns:
+

If the satellite dynamics are still alive

+
+
+
+ +
+
+reset_for_action() None[source]
+

Reset whenever a FSW @action is called.

+
+ +
+
+property simulator: Simulator
+

Reference to the episode simulator.

+
+ +
+ +
+
+class FullFeaturedDynModel(satellite: Satellite, dyn_rate: float, priority: int = 200, **kwargs)[source]
+

Bases: GroundStationDynModel, LOSCommDynModel

+

Convenience class for a satellite with ground station and line-of-sight comms.

+
+ +
+
+class GroundStationDynModel(satellite: Satellite, dyn_rate: float, priority: int = 200, **kwargs)[source]
+

Bases: ImagingDynModel

+

Model that connects satellite to environment ground stations.

+
+ +
+
+class ImagingDynModel(satellite: Satellite, dyn_rate: float, priority: int = 200, **kwargs)[source]
+

Bases: BasicDynamicsModel

+

Equips the satellite with an instrument, storage unit, and transmitter.

+
+
+reset_for_action() None[source]
+

Shut off power sinks.

+
+ +
+
+property storage_level
+

Storage level [bits].

+
+ +
+
+property storage_level_fraction
+

Storage level as a fraction of capacity.

+
+ +
+ +
+
+class LOSCommDynModel(satellite: Satellite, dyn_rate: float, priority: int = 200, **kwargs)[source]
+

Bases: BasicDynamicsModel

+

For evaluating line-of-sight connections between satellites for communication.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/simulation/environment.html b/API Reference/envs/general_satellite_tasking/simulation/environment.html new file mode 100644 index 00000000..fba37496 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/simulation/environment.html @@ -0,0 +1,209 @@ + + + + + + + environment — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

environment

+

bsk_rl.envs.general_satellite_tasking.simulation.environment

+
+
+

Basilisk environment models.

+
+
+class BasicEnvironmentModel(simulator: Simulator, env_rate: float, priority: int = 300, **kwargs)[source]
+

Bases: EnvironmentModel

+

Basic Environment with minimum necessary Basilisk environment components.

+
+
+property PN
+

Planet relative to inertial frame rotation matrix.

+
+ +
+
+property omega_PN_N
+

Planet angular velocity in inertial frame [rad/s].

+
+ +
+ +
+
+class EnvironmentModel(simulator: Simulator, env_rate: float, priority: int = 300, **kwargs)[source]
+

Bases: ABC

+

Abstract Basilisk environment model.

+

One EnvironmentModel is instantiated for the environment each time a new simulator +is created.

+
+
+__init__(simulator: Simulator, env_rate: float, priority: int = 300, **kwargs) None[source]
+

Construct base environment model.

+
+
Parameters:
+
    +
  • simulator – Simulator using this model

  • +
  • env_rate – Rate of environment simulation [s]

  • +
  • priority – Model priority.

  • +
  • kwargs – Ignored

  • +
+
+
+
+ +
+
+classmethod default_env_args(**kwargs) dict[str, Any][source]
+

Compile default argments for the environment model.

+
+ +
+ +
+
+class GroundStationEnvModel(simulator: Simulator, env_rate: float, priority: int = 300, **kwargs)[source]
+

Bases: BasicEnvironmentModel

+

Model that includes downlink ground stations.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/simulation/fsw.html b/API Reference/envs/general_satellite_tasking/simulation/fsw.html new file mode 100644 index 00000000..45426d13 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/simulation/fsw.html @@ -0,0 +1,471 @@ + + + + + + + fsw — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fsw

+

bsk_rl.envs.general_satellite_tasking.simulation.fsw

+
+
+

Basilisk flight software models.

+
+
+class BasicFSWModel(satellite: Satellite, fsw_rate: float, priority: int = 100, **kwargs)[source]
+

Bases: FSWModel

+

Basic FSW model with minimum necessary Basilisk components.

+
+
+class MRPControlTask(fsw, priority=80)[source]
+

Bases: Task

+

Task to control the satellite with reaction wheels.

+
+
+__init__(fsw, priority=80) None[source]
+

Template class for defining FSW processes.

+
+
Parameters:
+
    +
  • fsw – FSW model task contributes to

  • +
  • priority – Task priority

  • +
+
+
+
+ +
+
+reset_for_action() None[source]
+

MRP control enabled by default for all tasks.

+
+ +
+ +
+
+class NadirPointTask(fsw, priority=98)[source]
+

Bases: Task

+

Task to generate nadir-pointing reference.

+
+
+__init__(fsw, priority=98) None[source]
+

Template class for defining FSW processes.

+
+
Parameters:
+
    +
  • fsw – FSW model task contributes to

  • +
  • priority – Task priority

  • +
+
+
+
+ +
+ +
+
+class RWDesatTask(fsw, priority=97)[source]
+

Bases: Task

+

Task to desaturate reaction wheels.

+
+
+__init__(fsw, priority=97) None[source]
+

Template class for defining FSW processes.

+
+
Parameters:
+
    +
  • fsw – FSW model task contributes to

  • +
  • priority – Task priority

  • +
+
+
+
+ +
+
+reset_for_action() None[source]
+

Disable power draw for thrusters.

+
+ +
+ +
+
+class SunPointTask(fsw, priority=99)[source]
+

Bases: Task

+

Task to generate sun-pointing reference.

+
+
+__init__(fsw, priority=99) None[source]
+

Template class for defining FSW processes.

+
+
Parameters:
+
    +
  • fsw – FSW model task contributes to

  • +
  • priority – Task priority

  • +
+
+
+
+ +
+ +
+
+class TrackingErrorTask(fsw, priority=90)[source]
+

Bases: Task

+

Task to convert an attitude reference to guidance.

+
+
+__init__(fsw, priority=90) None[source]
+

Template class for defining FSW processes.

+
+
Parameters:
+
    +
  • fsw – FSW model task contributes to

  • +
  • priority – Task priority

  • +
+
+
+
+ +
+ +
+ +
+
+class ContinuousImagingFSWModel(satellite: Satellite, fsw_rate: float, priority: int = 100, **kwargs)[source]
+

Bases: ImagingFSWModel

+

FSW model for continuous nadir scanning.

+
+
+class LocPointTask(fsw, priority=96)[source]
+

Bases: LocPointTask

+

Task to point at targets and trigger the instrument.

+
+
+reset_for_action() None[source]
+

Reset scanning controller.

+
+ +
+ +
+ +
+
+class FSWModel(satellite: Satellite, fsw_rate: float, priority: int = 100, **kwargs)[source]
+

Bases: ABC

+

Abstract Basilisk flight software model.

+

One FSWModel is instantiated for each satellite in the environment each time a +new simulator is created.

+
+
+__init__(satellite: Satellite, fsw_rate: float, priority: int = 100, **kwargs) None[source]
+

Construct a base flight software model.

+
+
Parameters:
+
    +
  • satellite – Satellite modelled by this model

  • +
  • fsw_rate – Rate of FSW simulation [s]

  • +
  • priority – Model priority.

  • +
  • kwargs – Passed to task creation functions

  • +
+
+
+
+ +
+
+property dynamics: DynamicsModel
+

Reference to the satellite dynamics model for the episode.

+
+ +
+
+property environment: EnvironmentModel
+

Reference to the episode environment model.

+
+ +
+
+is_alive(log_failure=False) bool[source]
+

Check if the fsw model has failed any aliveness requirements.

+
+
Returns:
+

If the satellite fsw is still alive

+
+
+
+ +
+
+property simulator: Simulator
+

Reference to the episode simulator.

+
+ +
+ +
+
+class ImagingFSWModel(satellite: Satellite, fsw_rate: float, priority: int = 100, **kwargs)[source]
+

Bases: BasicFSWModel

+

Extend FSW with instrument pointing and triggering control.

+
+
+class LocPointTask(fsw, priority=96)[source]
+

Bases: Task

+

Task to point at targets and trigger the instrument.

+
+
+__init__(fsw, priority=96) None[source]
+

Template class for defining FSW processes.

+
+
Parameters:
+
    +
  • fsw – FSW model task contributes to

  • +
  • priority – Task priority

  • +
+
+
+
+ +
+
+reset_for_action() None[source]
+

Reset pointing controller.

+
+ +
+ +
+
+property c_hat_P
+

Instrument pointing direction in the planet frame.

+
+ +
+ +
+
+class SteeringFSWModel(satellite: Satellite, fsw_rate: float, priority: int = 100, **kwargs)[source]
+

Bases: BasicFSWModel

+

FSW extending MRP control to use MRP steering instead of MRP feedback.

+
+
+class MRPControlTask(fsw, priority=80)[source]
+

Bases: Task

+

Task that uses MRP steering to control reaction wheels.

+
+
+__init__(fsw, priority=80) None[source]
+

Template class for defining FSW processes.

+
+
Parameters:
+
    +
  • fsw – FSW model task contributes to

  • +
  • priority – Task priority

  • +
+
+
+
+ +
+
+reset_for_action() None[source]
+

Keep MRP control enabled on action calls.

+
+ +
+ +
+ +
+
+class SteeringImagerFSWModel(satellite: Satellite, fsw_rate: float, priority: int = 100, **kwargs)[source]
+

Bases: SteeringFSWModel, ImagingFSWModel

+

Convenience type for ImagingFSWModel with MRP steering.

+
+ +
+
+class Task(fsw: FSWModel, priority: int)[source]
+

Bases: ABC

+

Abstract class for defining FSW tasks.

+
+
+__init__(fsw: FSWModel, priority: int) None[source]
+

Template class for defining FSW processes.

+
+
Parameters:
+
    +
  • fsw – FSW model task contributes to

  • +
  • priority – Task priority

  • +
+
+
+
+ +
+
+create_task() None[source]
+

Add task to FSW with a unique name.

+
+ +
+
+reset_for_action() None[source]
+

Housekeeping for task when a new action is called.

+

Disables task by default, can be overridden by subclasses.

+
+ +
+ +
+
+action(func: Callable[[...], None]) Callable[[Callable[[...], None]], Callable[[...], None]][source]
+

Decorate to run housekeeping for action functions called by the satellite.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/simulation/index.html b/API Reference/envs/general_satellite_tasking/simulation/index.html new file mode 100644 index 00000000..d031b6a1 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/simulation/index.html @@ -0,0 +1,157 @@ + + + + + + + simulation — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

simulation

+

bsk_rl.envs.general_satellite_tasking.simulation

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/simulation/simulator.html b/API Reference/envs/general_satellite_tasking/simulation/simulator.html new file mode 100644 index 00000000..77cffd41 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/simulation/simulator.html @@ -0,0 +1,152 @@ + + + + + + + simulator — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

simulator

+

bsk_rl.envs.general_satellite_tasking.simulation.simulator

+
+
+

Extended Basilisk SimBaseClass for GeneralSatelliteTasking environments.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/types.html b/API Reference/envs/general_satellite_tasking/types.html new file mode 100644 index 00000000..8eaca548 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/types.html @@ -0,0 +1,144 @@ + + + + + + + types — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

types

+

bsk_rl.envs.general_satellite_tasking.types

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/utils/functional.html b/API Reference/envs/general_satellite_tasking/utils/functional.html new file mode 100644 index 00000000..1a8123e4 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/utils/functional.html @@ -0,0 +1,260 @@ + + + + + + + functional — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

functional

+

bsk_rl.envs.general_satellite_tasking.utils.functional

+
+
+

General utility functions.

+
+
+aliveness_checker(func: Callable[[...], bool]) Callable[[...], bool][source]
+

Decorate function to evaluate when checking for satellite aliveness.

+
+ +
+
+bind(instance, func, as_name=None)[source]
+

Bind the function func to instance.

+

Uses either provided name as_name or the existing name of func. The provided +func should accept the instance as the first argument, i.e. “self”.

+
+ +
+
+check_aliveness_checkers(model: Any, log_failure=False) bool[source]
+

Evaluate all functions with @aliveness_checker in a model.

+
+
Parameters:
+
    +
  • model – Model to search for checkers in

  • +
  • log_failure – Whether to log on checker failure

  • +
+
+
Returns:
+

Model aliveness status

+
+
Return type:
+

bool

+
+
+
+ +
+
+collect_default_args(object: object) dict[str, Any][source]
+

Collect all function @default_args in an object.

+
+
Parameters:
+

object – object with @default_args decorated functions

+
+
Returns:
+

dict of keyword-value pairs of default arguments

+
+
Return type:
+

dict

+
+
+
+ +
+
+configurable(cls)[source]
+

Class decorator to create class with different init defaults.

+
+ +
+
+default_args(**defaults) Callable[source]
+

Decorate function to enumerate default arguments for collection.

+
+ +
+
+is_property(obj: Any, attr_name: str) bool[source]
+

Check if obj has an @property attr_name without calling it.

+
+ +
+
+safe_dict_merge(updates: dict, base: dict) dict[source]
+

Merge a dict with another dict, warning for conflicts.

+
+
Parameters:
+
    +
  • updates – dictionary to be added to base

  • +
  • base – base dictionary to be modified

  • +
+
+
Returns:
+

updated base

+
+
Return type:
+

dict

+
+
+
+ +
+
+valid_func_name(name: str) str[source]
+

Convert a string into a valid function name.

+
+
Parameters:
+

name – desired function name

+
+
Returns:
+

sanitized function name

+
+
+
+ +
+
+vectorize_nested_dict(dictionary: dict) ndarray[source]
+

Flattens a dictionary of dicts, arrays, and scalars into a single vector.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/utils/index.html b/API Reference/envs/general_satellite_tasking/utils/index.html new file mode 100644 index 00000000..4e472b87 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/utils/index.html @@ -0,0 +1,155 @@ + + + + + + + utils — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

utils

+

bsk_rl.envs.general_satellite_tasking.utils

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/utils/logging_config.html b/API Reference/envs/general_satellite_tasking/utils/logging_config.html new file mode 100644 index 00000000..5b7b9248 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/utils/logging_config.html @@ -0,0 +1,209 @@ + + + + + + + logging_config — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

logging_config

+

bsk_rl.envs.general_satellite_tasking.utils.logging_config

+
+
+
+
+class ContextFilter(name: str = '', env=None, proc_id=None)[source]
+

Bases: Filter

+
+
+__init__(name: str = '', env=None, proc_id=None) None[source]
+

Initialize a filter.

+

Initialize with the name of the logger which, together with its +children, will have its events allowed through the filter. If no +name is specified, allow every event.

+
+ +
+
+filter(record)[source]
+

Determine if the specified record is to be logged.

+

Returns True if the record should be logged, or False otherwise. +If deemed appropriate, the record may be modified in-place.

+
+ +
+ +
+
+class SimFormatter(*args, color_output=True, **kwargs)[source]
+

Bases: Formatter

+
+
+__init__(*args, color_output=True, **kwargs)[source]
+

Initialize the formatter with specified format strings.

+

Initialize the formatter either with the specified format string, or a +default as described above. Allow for specialized date formatting with +the optional datefmt argument. If datefmt is omitted, you get an +ISO8601-like (or RFC 3339-like) format.

+

Use a style parameter of ‘%’, ‘{’ or ‘$’ to specify that you want to +use one of %-formatting, str.format() ({}) formatting or +string.Template formatting in your format string.

+
+

Changed in version 3.2: Added the style parameter.

+
+
+ +
+
+format(record)[source]
+

Format the specified record as text.

+

The record’s attribute dictionary is used as the operand to a +string formatting operation which yields the returned string. +Before formatting the dictionary, a couple of preparatory steps +are carried out. The message attribute of the record is computed +using LogRecord.getMessage(). If the formatting string uses the +time (as determined by a call to usesTime(), formatTime() is +called to format the event time. If there is exception information, +it is formatted using formatException() and appended to the message.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/general_satellite_tasking/utils/orbital.html b/API Reference/envs/general_satellite_tasking/utils/orbital.html new file mode 100644 index 00000000..062877d8 --- /dev/null +++ b/API Reference/envs/general_satellite_tasking/utils/orbital.html @@ -0,0 +1,212 @@ + + + + + + + orbital — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

orbital

+

bsk_rl.envs.general_satellite_tasking.utils.orbital

+
+
+

Utilities for computing orbital events.

+
+
+elevation(r_sat: ndarray, r_target: ndarray) ndarray[source]
+

Find the elevation angle from a target to a satellite.

+
+
Parameters:
+
    +
  • r_sat – Satellite position(s)

  • +
  • r_target – Target position

  • +
+
+
Returns:
+

Elevation angle(s)

+
+
+
+ +
+
+random_epoch(start: int = 2000, end: int = 2022)[source]
+

Generate a random epoch in a year range.

+

Date will always be in the first 28 days of the month.

+
+
Parameters:
+
    +
  • start – Initial year.

  • +
  • end – Final year.

  • +
+
+
Returns:
+

Epoch in YYYY MMM DD HH:MM:SS.SSS (UTC) format

+
+
+
+ +
+
+random_orbit(i: float | None = 45.0, alt: float = 500, r_body: float = 6371, e: float = 0, Omega: float | None = None, omega: float | None = 0, f: float | None = None) <MagicMock name='mock.ClassicElements' id='140255387338736'>[source]
+

Create a set of orbit elements.

+

Parameters are fixed if specified and randomized if None.

+
+
Parameters:
+
    +
  • i – inclination [deg], randomized in [-pi, pi]

  • +
  • alt – altitude above r_body [km]

  • +
  • r_body – body radius [km]

  • +
  • e – eccentricity

  • +
  • Omega – LAN [deg], randomized in [0, 2pi]

  • +
  • omega – Argument of periapsis [deg], randomized in [0, 2pi]

  • +
  • f – true anomaly [deg], randomized in [0, 2pi]

  • +
+
+
Returns:
+

orbital elements

+
+
Return type:
+

ClassicElements

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/index.html b/API Reference/envs/index.html new file mode 100644 index 00000000..b9d50ce9 --- /dev/null +++ b/API Reference/envs/index.html @@ -0,0 +1,145 @@ + + + + + + + envs — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisat_agile_eos/bsk_models/dynamics.html b/API Reference/envs/multisat_agile_eos/bsk_models/dynamics.html new file mode 100644 index 00000000..5dc0a0cf --- /dev/null +++ b/API Reference/envs/multisat_agile_eos/bsk_models/dynamics.html @@ -0,0 +1,270 @@ + + + + + + + dynamics — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

dynamics

+

bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics

+
+
+
+
+class DynamicModel(SimBase, dynRate, spacecraftIndex, singleSat=False)[source]
+

Bases: object

+

Defines the Dynamics class.

+
+
+InitAllDynObjects(SimBase)[source]
+

Initializes all dynamic objects.

+
+ +
+
+SetBattery(SimBase)[source]
+

Sets up the battery with all the power components

+
+ +
+
+SetDensityModel(SimBase)[source]
+

Attaches the density model effector to the spacecraft

+
+ +
+
+SetDisturbanceTorque(SimBase)[source]
+

Attach the disturbance torque to the spacecraft object

+
+ +
+
+SetDragEffector(SimBase)[source]
+

Set the drag effector

+
+ +
+
+SetEclipseObject(SimBase)[source]
+

Adds the spacecraft to the eclipse module.

+
+ +
+
+SetGravityBodies(SimBase)[source]
+

Specify what gravitational bodies to include in the simulation

+
+ +
+
+SetGroundLocations(SimBase)[source]
+

Adds the spacecraft to the ground location modules.

+
+ +
+
+SetInstrument(SimBase)[source]
+

Create the instrument

+
+ +
+
+SetInstrumentPowerSink(SimBase)[source]
+

Defines the instrument power sink parameters

+
+ +
+
+SetReactionWheelDynEffector(SimBase)[source]
+

Defines the RW state effector.

+
+ +
+
+SetReactionWheelPower(SimBase)[source]
+

Defines the reaction wheel power draw

+
+ +
+
+SetSimpleNavObject()[source]
+

Defines the navigation module.

+
+ +
+
+SetSolarPanel(SimBase)[source]
+

Sets the solar panel

+
+ +
+
+SetSpacecraftHub(SimBase)[source]
+

Defines the spacecraft object properties.

+
+ +
+
+SetThrusterDynEffector()[source]
+

Defines the thruster state effector.

+
+ +
+
+SetTransmitter(SimBase)[source]
+

Create the transmitter

+
+ +
+
+SetTransmitterPowerSink(SimBase)[source]
+

Defines the trasmitter power sink parameters

+
+ +
+
+__init__(SimBase, dynRate, spacecraftIndex, singleSat=False)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisat_agile_eos/bsk_models/environment.html b/API Reference/envs/multisat_agile_eos/bsk_models/environment.html new file mode 100644 index 00000000..b0e6a9b4 --- /dev/null +++ b/API Reference/envs/multisat_agile_eos/bsk_models/environment.html @@ -0,0 +1,186 @@ + + + + + + + environment — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

environment

+

bsk_rl.envs.multisat_agile_eos.bsk_models.environment

+
+
+
+
+class EnvironmentModel(SimBase, envRate)[source]
+

Bases: object

+

Defines the Earth Environment.

+
+
+SetEclipseObject()[source]
+

Specify what celestial object is causing an eclipse message.

+
+ +
+
+SetEpochObject()[source]
+

Add the ephemeris object to use with the SPICE library.

+
+ +
+
+SetGravityBodies(SimBase)[source]
+

Specify what gravitational bodies to include in the simulation.

+
+ +
+
+SetGroundLocations(SimBase)[source]
+

Specify which ground locations are of interest.

+
+ +
+
+__init__(SimBase, envRate)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisat_agile_eos/bsk_models/fsw.html b/API Reference/envs/multisat_agile_eos/bsk_models/fsw.html new file mode 100644 index 00000000..487f7371 --- /dev/null +++ b/API Reference/envs/multisat_agile_eos/bsk_models/fsw.html @@ -0,0 +1,253 @@ + + + + + + + fsw — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fsw

+

bsk_rl.envs.multisat_agile_eos.bsk_models.fsw

+
+
+
+
+class FSWModel(SimBase, fswRate, spacecraftIndex)[source]
+

Bases: object

+

Defines the FSW class

+
+
+InitAllFSWObjects(SimBase)[source]
+

Initializes all FSW objects.

+
+ +
+
+SetAttitudeTrackingError(SimBase)[source]
+

Defines the module that converts a reference message into a guidance message.

+
+ +
+
+SetInstrumentController(SimBase)[source]
+

Defines the instrument controller.

+
+ +
+
+SetLocationPointGuidance(SimBase)[source]
+

Defines the Earth location pointing guidance module.

+
+ +
+
+SetMRPFeedbackRWA(SimBase)[source]
+

Defines the control properties.

+
+ +
+
+SetMomentumDumping(SimBase)[source]
+

Defines the momentum dumping configuration.

+
+ +
+
+SetNadirPointGuidance(SimBase)[source]
+

Defines the nadir pointing guidance module.

+
+ +
+
+SetRWConfigMsg(SimBase)[source]
+

Imports the RWs configuration information.

+
+ +
+
+SetRWMotorTorque(SimBase)[source]
+

Defines the motor torque from the control law.

+
+ +
+
+SetSunPointGuidance(SimBase)[source]
+

Defines the Sun pointing guidance module.

+
+ +
+
+SetThrusterMapping(SimBase)[source]
+

Defines the thrusters mapping.

+
+ +
+
+SetThrustersConfigMsg(SimBase)[source]
+

Imports the thrusters configuration information.

+
+ +
+
+SetVehicleConfigMsg(SimBase)[source]
+

Set the vehicle configuration message.

+
+ +
+
+__init__(SimBase, fswRate, spacecraftIndex)[source]
+
+ +
+
+setupGatewayMsgs(SimBase)[source]
+

create C-wrapped gateway messages such that different modules can write to +this message and provide a common input msg for down-stream modules

+
+ +
+
+zeroGateWayMsgs()[source]
+

Zero all the FSW gateway message payloads

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisat_agile_eos/bsk_models/fsw_steering.html b/API Reference/envs/multisat_agile_eos/bsk_models/fsw_steering.html new file mode 100644 index 00000000..dd958ec6 --- /dev/null +++ b/API Reference/envs/multisat_agile_eos/bsk_models/fsw_steering.html @@ -0,0 +1,253 @@ + + + + + + + fsw_steering — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fsw_steering

+

bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering

+
+
+
+
+class FSWModel(SimBase, fswRate, spacecraftIndex)[source]
+

Bases: object

+

Defines the FSW class

+
+
+InitAllFSWObjects(SimBase)[source]
+

Initializes all FSW objects.

+
+ +
+
+SetAttitudeTrackingError(SimBase)[source]
+

Defines the module that converts a reference message into a guidance message.

+
+ +
+
+SetInstrumentController(SimBase)[source]
+

Defines the instrument controller.

+
+ +
+
+SetLocationPointGuidance(SimBase)[source]
+

Defines the Earth location pointing guidance module.

+
+ +
+
+SetMRPSteeringRWA(SimBase)[source]
+

Defines the control properties.

+
+ +
+
+SetMomentumDumping(SimBase)[source]
+

Defines the momentum dumping configuration.

+
+ +
+
+SetNadirPointGuidance(SimBase)[source]
+

Defines the nadir pointing guidance module.

+
+ +
+
+SetRWConfigMsg(SimBase)[source]
+

Imports the RWs configuration information.

+
+ +
+
+SetRWMotorTorque(SimBase)[source]
+

Defines the motor torque from the control law.

+
+ +
+
+SetSunPointGuidance(SimBase)[source]
+

Defines the Sun pointing guidance module.

+
+ +
+
+SetThrusterMapping(SimBase)[source]
+

Defines the thrusters mapping.

+
+ +
+
+SetThrustersConfigMsg(SimBase)[source]
+

Imports the thrusters configuration information.

+
+ +
+
+SetVehicleConfigMsg(SimBase)[source]
+

Set the vehicle configuration message.

+
+ +
+
+__init__(SimBase, fswRate, spacecraftIndex)[source]
+
+ +
+
+setupGatewayMsgs(SimBase)[source]
+

create C-wrapped gateway messages such that different modules can write to +this message and provide a common input msg for down-stream modules

+
+ +
+
+zeroGateWayMsgs()[source]
+

Zero all the FSW gateway message payloads

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisat_agile_eos/bsk_models/index.html b/API Reference/envs/multisat_agile_eos/bsk_models/index.html new file mode 100644 index 00000000..e22cea34 --- /dev/null +++ b/API Reference/envs/multisat_agile_eos/bsk_models/index.html @@ -0,0 +1,156 @@ + + + + + + + bsk_models — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

bsk_models

+

bsk_rl.envs.multisat_agile_eos.bsk_models

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisat_agile_eos/bsk_sim.html b/API Reference/envs/multisat_agile_eos/bsk_sim.html new file mode 100644 index 00000000..254b5bec --- /dev/null +++ b/API Reference/envs/multisat_agile_eos/bsk_sim.html @@ -0,0 +1,143 @@ + + + + + + + bsk_sim — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

bsk_sim

+

bsk_rl.envs.multisat_agile_eos.bsk_sim

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisat_agile_eos/env_settings.html b/API Reference/envs/multisat_agile_eos/env_settings.html new file mode 100644 index 00000000..6f4734ec --- /dev/null +++ b/API Reference/envs/multisat_agile_eos/env_settings.html @@ -0,0 +1,143 @@ + + + + + + + env_settings — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

env_settings

+

bsk_rl.envs.multisat_agile_eos.env_settings

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisat_agile_eos/gym_env.html b/API Reference/envs/multisat_agile_eos/gym_env.html new file mode 100644 index 00000000..084fa799 --- /dev/null +++ b/API Reference/envs/multisat_agile_eos/gym_env.html @@ -0,0 +1,261 @@ + + + + + + + gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

gym_env

+

bsk_rl.envs.multisat_agile_eos.gym_env

+
+
+
+
+class MultiSatAgileEOS[source]
+

Bases: Env

+

This Gymnasium environment is designed to simulate the multi-satellite agile EOS +scheduling problem in which K satellites in a low-Earth orbit Walker-delta formation +attempt to maximize the number of targets imaged and downlinked while avoiding +resource constraint violations. Satellites update their local target lists through +communication with one another. Resource constraint violations include:

+
    +
  1. Power: The spacecraft must keep its battery charge above zero

  2. +
  3. +
    Reaction Wheel Saturation: The spacecraft must keep its reaction wheels within

    their speed limits

    +
    +
    +
  4. +
  5. +
    Data Buffer: The spacecraft must keep its data buffer from overflowing (i.e.

    exceeding or meeting the maximum buffer size)

    +
    +
    +
  6. +
+

Each spacecraft must decide between pointing at any one of J number of ground +targets for imaging, pointing at the sun to charge, desaturating reaction wheels, +or downlinking data. This is referred to as the MultiSatAgileEOS environment.

+
+
Action Space (MultiDiscrete):
+
For each spacecraft:

0 - Charging mode +1 - Downlink mode +2 - Desat mode +3:J+3 - Image target j

+
+
+
+
Observation Space:

For each spacecraft: +ECEF position and velocity - indices 0-5 +Attitude error and attitude rate - indices 6-7 +Reaction wheel speeds - indices 8-11 +Battery charge - indices 12 +Eclipse indicator - indices 13 +Stored data onboard spacecraft - indices 14 +Data transmitted over interval - indices 15 +Amount of time ground stations were accessible (s) - 16-22 +Target Tuples (4 values each) - priority and Hill frame pos

+
+
Reward Function:

r = +A/priority for for each tgt downlinked for first time +r = +B/priority for for each tgt imaged for first time +r = -C if failure

+

No reward is given for imaging or downlinking the same target twice

+
+
+
+
+__init__()[source]
+
+ +
+
+reset(seed=None, options=None)[source]
+

Reset the state of the environment and returns an initial observation. +:return ob: n_spacecraft x dim_obs nparray of observations

+
+ +
+
+set_env_params(**kwargs)[source]
+

Set arbitrary environment variables. Can be used to override simulator defaults.

+
+ +
+
+set_params(n_spacecraft, n_planes, rel_phasing, inc, global_tgts, priorities, comm_method, **kwargs)[source]
+

Updates the constellation and target parameters in the environment. Environment +must be reset afterwards. Reset is not called within this function so user can +choose between reset and reset_init.

+
+ +
+
+sim_attrs()[source]
+

Creates keyword arguments for instantiating the simulator. If an attribute is +present that matches a simulatormkeyword, pass it in.

+
+ +
+
+step(action, return_obs=True)[source]
+
+
Parameters:
+
    +
  • action – 1 x n_spacecraft list of actions

  • +
  • return_obs – whether or not to return observations

  • +
+
+
Return ob:
+

n_spacecraft x dim_obs nparray of observations

+
+
Return reward:
+

1 x (n_spacecraft + 1) nparray of rewards, last index is global +reward, other are local rewards

+
+
Return episode over:
+

True/False if episode is over

+
+
Return info:
+

dictionary of info for debugging purposes

+
+
+
+ +
+
+update_spaces()[source]
+

Updates the size of action and observation spaces and preallocations.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisat_agile_eos/index.html b/API Reference/envs/multisat_agile_eos/index.html new file mode 100644 index 00000000..f81b345e --- /dev/null +++ b/API Reference/envs/multisat_agile_eos/index.html @@ -0,0 +1,152 @@ + + + + + + + multisat_agile_eos — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

multisat_agile_eos

+

bsk_rl.envs.multisat_agile_eos

+
+

Files:

+ +
+
+

Directories:

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisensor_eos/bsk_sim.html b/API Reference/envs/multisensor_eos/bsk_sim.html new file mode 100644 index 00000000..2f80a33b --- /dev/null +++ b/API Reference/envs/multisensor_eos/bsk_sim.html @@ -0,0 +1,148 @@ + + + + + + + bsk_sim — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

bsk_sim

+

bsk_rl.envs.multisensor_eos.bsk_sim

+
+
+
+
+exception invalid_action[source]
+

Bases: Exception

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisensor_eos/env_settings.html b/API Reference/envs/multisensor_eos/env_settings.html new file mode 100644 index 00000000..ef9235af --- /dev/null +++ b/API Reference/envs/multisensor_eos/env_settings.html @@ -0,0 +1,154 @@ + + + + + + + env_settings — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

env_settings

+

bsk_rl.envs.multisensor_eos.env_settings

+
+
+
+
+class Settings[source]
+

Bases: object

+

To be used as settings for the MultiSensorEOS gymnasium environment and bsk sim.

+
+
+__init__()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisensor_eos/gym_env.html b/API Reference/envs/multisensor_eos/gym_env.html new file mode 100644 index 00000000..aea35ef4 --- /dev/null +++ b/API Reference/envs/multisensor_eos/gym_env.html @@ -0,0 +1,222 @@ + + + + + + + gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

gym_env

+

bsk_rl.envs.multisensor_eos.gym_env

+
+
+
+
+class MultiSensorEOS[source]
+

Bases: Env

+

Earth observation environment - simulates a spacecraft with variable imager modes +attempting to image a ground location. +Agent must choose between charging, desaturating, and image type(s); also needs to +choose an appropriate imaging type. +Taking the image type corresponding to the ground location’s required sensor type +results in full reward, other image types results in no reward.

+

Action Space (discrete):

+
    +
  • 0 - Points solar panels at the sun.

  • +
  • 1 - Desaturates the reaction wheels.

  • +
  • >1 - Orients the s/c towards the earth; takes image of type _.

  • +
+

Observation Space:

+
    +
  • r_sc_I - float[3,] - spacecraft position.

  • +
  • v_sc - float[3,] - spacecraft velocity in PCPF.

  • +
  • sigma_RB - float [0,1] - norm of the spacecraft error MRP with respect to the +last reference frame specified.

  • +
  • omega_BN - float - norm of the total spacecraft bus rotational velocity with +respect to the inertial frame.

  • +
  • omega_RW - float - norm of the reaction wheel rotational velocities.

  • +
  • storedCharge - float [0,batCapacity] - indicates the s/c battery charge level in +W-s.

  • +
  • sun_indicator - float [0, 1] - indicates the flux mitigator due to eclipse.

  • +
  • access indicator - access to the next target

  • +
  • img_mode norm - float [0,1] - indicates the required imaging mode.

  • +
+

Reward Function: +r = 1/(1+ | sigma_RB|) if correct sensor

+

Intended to provide a rich reward in action 1 when the spacecraft is pointed +towards the earth, decaying as sigma^2 as the pointing error increases.

+
+
+__init__()[source]
+
+ +
+
+reset(seed=None, options=None)[source]
+

Reset the state of the environment and returns an initial observation. +:returns: observation (object) +:rtype: the initial observation of the space.

+
+ +
+
+step(action)[source]
+

The agent takes a step in the environment. Note that the simulator must be +initialized

+
+
Parameters:
+

action – int

+
+
+

Returns:

+
    +
  • ob (object): an environment-specific object representing your observation of +the environment.

  • +
  • reward (float): amount of reward achieved by the previous action. The scale +varies between environments, but the goal is always to increase +your total reward.

  • +
  • episode_over (bool): whether it’s time to reset the environment again. Most (but not +all) tasks are divided up into well-defined episodes, and done +being True indicates the episode has terminated. (For example, +perhaps the pole tipped too far, or you lost your last life.)

  • +
  • truncated (truncated): set to false. Gymnasium requirement.

  • +
  • info (dict): diagnostic information useful for debugging. It can sometimes +be useful for learning (for example, it might contain the raw +probabilities behind the environment’s last state change). +However, official evaluations of your agent are not allowed to +use this for learning.

  • +
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/multisensor_eos/index.html b/API Reference/envs/multisensor_eos/index.html new file mode 100644 index 00000000..3c1389dc --- /dev/null +++ b/API Reference/envs/multisensor_eos/index.html @@ -0,0 +1,147 @@ + + + + + + + multisensor_eos — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

multisensor_eos

+

bsk_rl.envs.multisensor_eos

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/simple_eos/bsk_sim.html b/API Reference/envs/simple_eos/bsk_sim.html new file mode 100644 index 00000000..865a6da7 --- /dev/null +++ b/API Reference/envs/simple_eos/bsk_sim.html @@ -0,0 +1,141 @@ + + + + + + + bsk_sim — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

bsk_sim

+

bsk_rl.envs.simple_eos.bsk_sim

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/simple_eos/gym_env.html b/API Reference/envs/simple_eos/gym_env.html new file mode 100644 index 00000000..ec78e61f --- /dev/null +++ b/API Reference/envs/simple_eos/gym_env.html @@ -0,0 +1,220 @@ + + + + + + + gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

gym_env

+

bsk_rl.envs.simple_eos.gym_env

+
+
+
+
+class SimpleEOS[source]
+

Bases: Env

+

The spacecraft must decide between pointing at the ground to collect science data, +pointing at the sun to charge, desaturating reaction wheels, and downlinking data. +This is referred to as the “simple” simulator as science data is simply collected +by nadir pointing. Specific imaging targets are not considered.

+

Action Space (discrete, 0 or 1): +* 0 - Imaging mode +* 1 - Charging mode +* 2 - Desat mode +* 3 - Downlink mode

+

Observation Space: +* Inertial position and velocity - indices 0-5 +* Attitude error and attitude rate - indices 6-7 +* Reaction wheel speeds - indices 8-11 +* Battery charge - indices 12 +* Eclipse indicator - indices 13 +* Stored data onboard spacecraft - indices 14 +* Data transmitted over interval - indices 15 +* Amount of time ground stations were accessible (s) - 16-22 +* Percent through planning interval - 23

+

Reward Function: +r = +1 for each MB downlinked and no failure +r = +1 for each MB downlinked and no failure and +1 if t > t_max +r = - 1000 if failure (battery drained, buffer overflow, reaction wheel speeds over max)

+
+
+__init__()[source]
+
+ +
+
+reset(seed=None, options=None)[source]
+

Reset the state of the environment and returns an initial observation. +:returns: observation (object) +:rtype: the initial observation of the space.

+
+ +
+
+step(action)[source]
+

The agent takes a step in the environment. +:param action: +:type action: int

+
+
Returns:
+

ob, reward, episode_over, info

+
+
ob (object) :

an environment-specific object representing your observation of +the environment.

+
+
reward (float) :

amount of reward achieved by the previous action. The scale +varies between environments, but the goal is always to increase +your total reward.

+
+
episode_over (bool) :

whether it’s time to reset the environment again. Most (but not +all) tasks are divided up into well-defined episodes, and done +being True indicates the episode has terminated. (For example, +perhaps the pole tipped too far, or you lost your last life.)

+
+
info (dict) :

diagnostic information useful for debugging. It can sometimes +be useful for learning (for example, it might contain the raw +probabilities behind the environment’s last state change). +However, official evaluations of your agent are not allowed to +use this for learning.

+
+
+

+
+
Return type:
+

tuple

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/simple_eos/index.html b/API Reference/envs/simple_eos/index.html new file mode 100644 index 00000000..6dc2feb2 --- /dev/null +++ b/API Reference/envs/simple_eos/index.html @@ -0,0 +1,145 @@ + + + + + + + simple_eos — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

simple_eos

+

bsk_rl.envs.simple_eos

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/small_body_science/bsk_sim.html b/API Reference/envs/small_body_science/bsk_sim.html new file mode 100644 index 00000000..c04617e5 --- /dev/null +++ b/API Reference/envs/small_body_science/bsk_sim.html @@ -0,0 +1,141 @@ + + + + + + + bsk_sim — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

bsk_sim

+

bsk_rl.envs.small_body_science.bsk_sim

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/small_body_science/gym_env.html b/API Reference/envs/small_body_science/gym_env.html new file mode 100644 index 00000000..b7bc1d5f --- /dev/null +++ b/API Reference/envs/small_body_science/gym_env.html @@ -0,0 +1,226 @@ + + + + + + + gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

gym_env

+

bsk_rl.envs.small_body_science.gym_env

+
+
+
+
+class SmallBodyScience(failure_penalty=1, target_component=0.25, target_downlink_component=0.25, map_component=0.25, map_downlink_component=0.25)[source]
+

Bases: Env

+

Small body gym environment where an agent can transition between different +waypoints defined in the sun anti-momentum frame to image candidate landing sites +or collect spectroscopy map data while avoiding resource constraint violations. +Resource constraint violations include: +* Fuel +* Power +* Data storage +* Collision with the body (not necessarilly a resource, but considered a +failure condition)

+

Action Space (Discrete): +* 0 - Charging Mode +* 1 - 8 - Transition to waypoint 1-8 +* 9 - Map +* 10 - Downlink +* 11 - Image

+

Observation Space (Box): +* 0-2: Hill-frame position +* 3-5: Hill-frame velocity +* 6: Eclipse +* 7: Data buffer storage +* 8: Battery level +* 9: dV consumed +* 10: Downlink availability +* 11-13: Current waypoint +* 14-16: Last waypoint +* 17: Imaged targets +* 18: Downlinked targets +* 19-21: Next closest unimaged target position in Hill frame +* 22-30: Map regions collected

+

Reward Function: +* r = +A each tgt downlinked for first time +* r = +B for each tgt imaged for first time +* r = +C for each map region downlinked for first time +* r = +D for each map region collected for first time +* r = -E for failure

+
+
+__init__(failure_penalty=1, target_component=0.25, target_downlink_component=0.25, map_component=0.25, map_downlink_component=0.25)[source]
+
+ +
+
+reset(seed=None, options=None)[source]
+

Reset the state of the environment and returns an initial observation. +:returns: observation (object) +:rtype: the initial observation of the space.

+
+ +
+
+step(action)[source]
+

The agent takes a step in the environment. +:param action: +:type action: int

+
+
Returns:
+

ob, reward, episode_over, truncated, info

+
+
ob (object) :

an environment-specific object representing your observation of +the environment.

+
+
reward (float) :

amount of reward achieved by the previous action. The scale +varies between environments, but the goal is always to increase +your total reward.

+
+
episode_over (bool) :

whether it’s time to reset the environment again. Most (but not +all) tasks are divided up into well-defined episodes, and done +being True indicates the episode has terminated. (For example, +perhaps the pole tipped too far, or you lost your last life.)

+
+
+

+
+
Return type:
+

tuple

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/small_body_science/index.html b/API Reference/envs/small_body_science/index.html new file mode 100644 index 00000000..a7f546d1 --- /dev/null +++ b/API Reference/envs/small_body_science/index.html @@ -0,0 +1,145 @@ + + + + + + + small_body_science — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

small_body_science

+

bsk_rl.envs.small_body_science

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/small_body_science_pomdp/bsk_sim.html b/API Reference/envs/small_body_science_pomdp/bsk_sim.html new file mode 100644 index 00000000..a25a378a --- /dev/null +++ b/API Reference/envs/small_body_science_pomdp/bsk_sim.html @@ -0,0 +1,141 @@ + + + + + + + bsk_sim — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

bsk_sim

+

bsk_rl.envs.small_body_science_pomdp.bsk_sim

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/small_body_science_pomdp/gym_env.html b/API Reference/envs/small_body_science_pomdp/gym_env.html new file mode 100644 index 00000000..f80d1712 --- /dev/null +++ b/API Reference/envs/small_body_science_pomdp/gym_env.html @@ -0,0 +1,237 @@ + + + + + + + gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

gym_env

+

bsk_rl.envs.small_body_science_pomdp.gym_env

+
+
+
+
+class SmallBodySciencePOMDP[source]
+

Bases: SmallBodyScience

+

Small body gym environment where an agent can transition between different +waypoints defined in the sun anti-momentum frame to image candidate landing sites +or collect spectroscopy map data while avoiding resource constraint violations. As +opposed to the SmallBodyScience environment, this environment is utilizes an EKF +filter for the observation space to simulate a POMDP, which provides a belief state +for the POMDP.

+

Resource constraint violations include: +* Fuel +* Power +* Data storage +* Collision with the body (not necessarily a resource, but considered a +failure condition)

+

Action Space (Discrete): +* 0 - Charging Mode +* 1 - 8 - Transition to waypoint 1-8 +* 9 - Map +* 10 - Downlink +* 11 - Image +* 12 - Navigation Mode

+

Observation Space (Box): +* 0-2: Hill-frame position +* 3-5: Hill-frame velocity +* 6: Eclipse +* 7: Data buffer storage +* 8: Battery level +* 9: dV consumed +* 10: Downlink availability +* 11-13: Current waypoint +* 14-16: Last waypoint +* 17-20: Location of the next target for imaging +* 20-26: Filter covariance diagonals

+

Reward Function: +* r = +A each tgt downlinked for first time +* r = +B for each tgt imaged for first time +* r = +C for each map region downlinked for first time +* r = +D for each map region collected for first time +* r = -E for failure

+
+
+__init__()[source]
+
+ +
+
+modify_ob(ob)[source]
+

Modifies the observation of the MDP such that it conforms to the POMDP +specification. +:param ob: +:return:

+
+ +
+
+reset(seed=None, options=None)[source]
+

Reset the state of the environment and returns an initial observation. +:returns: observation (object) +:rtype: the initial observation of the space.

+
+ +
+
+step(action, return_obs=True)[source]
+

The agent takes a step in the environment. +:param action: +:type action: int

+
+
Returns:
+

ob, reward, episode_over, truncated, info

+
+
ob (object) :

an environment-specific object representing your observation of +the environment.

+
+
reward (float) :

amount of reward achieved by the previous action. The scale +varies between environments, but the goal is always to increase +your total reward.

+
+
episode_over (bool) :

whether it’s time to reset the environment again. Most (but not +all) tasks are divided up into well-defined episodes, and done +being True indicates the episode has terminated. (For example, +perhaps the pole tipped too far, or you lost your last life.)

+
+
+

+
+
Return type:
+

tuple

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/envs/small_body_science_pomdp/index.html b/API Reference/envs/small_body_science_pomdp/index.html new file mode 100644 index 00000000..2bc41c26 --- /dev/null +++ b/API Reference/envs/small_body_science_pomdp/index.html @@ -0,0 +1,145 @@ + + + + + + + small_body_science_pomdp — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

small_body_science_pomdp

+

bsk_rl.envs.small_body_science_pomdp

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/index.html b/API Reference/index.html new file mode 100644 index 00000000..163a2c8d --- /dev/null +++ b/API Reference/index.html @@ -0,0 +1,132 @@ + + + + + + + API Reference — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

API Reference

+

bsk_rl

+
+
+
+

Directories:

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/training/index.html b/API Reference/training/index.html new file mode 100644 index 00000000..dcb782a2 --- /dev/null +++ b/API Reference/training/index.html @@ -0,0 +1,135 @@ + + + + + + + training — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

training

+

bsk_rl.training

+
+
+
+

Directories:

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/training/mcts/index.html b/API Reference/training/mcts/index.html new file mode 100644 index 00000000..8e0f3604 --- /dev/null +++ b/API Reference/training/mcts/index.html @@ -0,0 +1,138 @@ + + + + + + + mcts — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mcts

+

bsk_rl.training.mcts

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/training/mcts/mcts_train.html b/API Reference/training/mcts/mcts_train.html new file mode 100644 index 00000000..6e8bed92 --- /dev/null +++ b/API Reference/training/mcts/mcts_train.html @@ -0,0 +1,219 @@ + + + + + + + mcts_train — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mcts_train

+

bsk_rl.training.mcts.mcts_train

+
+
+
+
+create_model(hidden_layer_num, net_size, activation, num_states, dropout, alpha, num_actions)[source]
+

Creates a feedforward neural network subject to various hyperparameters. +:param hidden_layer_num: Number of hidden layers +:param net_size: Widths of hidden layers +:param activation: activation function, either Leaky ReLU or tanh +:param num_states: Number of states +:param dropout: Dropout rate +:param alpha: alpha-parameter for Leaky ReLU activation function +:param num_actions: number of actions +:return: model

+
+ +
+
+data_number(x)[source]
+

Splits the data indicator string to return the data number +:param x: data indicator string +:return: data number

+
+ +
+
+load_and_modify_data(data_directory, modified_states=[])[source]
+

Loads AND modifies the training data +:param data_directory: data directory to load data from +:param modified_states: modified states. First entry is a list of indices to keep. Next entries are dictionary keys +for info. +:return: train-test split of data

+
+ +
+
+load_data(data_directory)[source]
+

Loads the data to train with. +:param data_directory: Data directory to load data from. +:return: train-test split of training data.

+
+ +
+
+mcts_batch(data_directory, data_indicator, c=50, num_sims=50, initial_conditions=None, result_list=None, render=False, env_name='SimpleEOS-v0', num_steps=45, t_final=270.0)[source]
+

The function performs a single run of MCTS over a planning horizon, generating performance and training data +:param data_directory: Data directory to store training data +:param data_indicator: Data indicator to append to filename +:param c: MCTS exploration constant +:param num_sims: number of simulations-per-step +:param initial_conditions: Dictionary of initial conditions +:param result_list: Results list +:param render: T/F to render BSK sim using Vizard +:param env_name: environment name +:return: N/A

+
+ +
+
+run_episode(env, num_steps, t_final, c, num_sims, initial_conditions, env_name)[source]
+

Runs an episode of MCTS. +:param env: Gym environment +:param num_steps: number of steps to take +:param t_final: Final time +:param c: Exploration constant +:param num_sims: Number of simulations-per-step +:param initial_conditions: Dictionary of initial conditions +:param env_name: environment name +:return Q: state-action value estimates +:return N: Number of times the state-action pairs were visited +:return reward: Reward sum +:return actHist: history of actions +:return exec_time: execution time +:return final_info: final infor from env

+
+ +
+
+run_experiment(data_directory, parameters, modified_states=[], batch_sizes=None)[source]
+

Runs a hyperparameter search over neural network hyperparameters +:param data_directory: Data directory to load data from and save networks, training plots. +:param parameters: dictionary of network hyperparameters. +:param modified_states (optional): Modified states +:return:

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/training/sb3/experiments.html b/API Reference/training/sb3/experiments.html new file mode 100644 index 00000000..4b9aaeee --- /dev/null +++ b/API Reference/training/sb3/experiments.html @@ -0,0 +1,183 @@ + + + + + + + experiments — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

experiments

+

bsk_rl.training.sb3.experiments

+
+
+
+
+a2c_experiment(agent_dir, policy_kwargs, learning_rate=0.0007, ent_coef=0.01, idx=0, n_its=10, base_steps=1020, env_name='MultiSensorEOS-v0', max_steps=90, n_steps=45, num_cores=4)[source]
+

Run an A2C experiment with the given hyperparameters +:param policy_kwargs: (dict) Policy kwargs +:param learning_rate: (float) Learning rate +:param ent_coef: (float) Entropy coefficient +:param idx: (int) Index of the experiment +:param agent_dir: (str) Directory where to save the agent +:param n_its: (int) Number of iterations +:param env_name: (str) Name of the environment +:param max_steps: (int) Maximum number of steps in the environment +:param n_steps: (int) Number of steps before update +:param num_cores: (int) Number of cores

+
+ +
+
+ppo_experiment(policy_kwargs, learning_rate, clip_range, ent_coef, batch_size, epoch, max_grad_norm, idx, agent_dir, n_its=10, base_steps=1020, shielded=False, env_name='MultiSensorEOS-v0', n_steps=90, num_cores=4)[source]
+

Run a PPO experiment with the given hyperparameters +:param policy_kwargs: (dict) Policy kwargs +:param learning_rate: (float) Learning rate +:param clip_range: (float) Clip range +:param ent_coef: (float) Entropy coefficient +:param batch_size: (int) Batch size +:param epoch: (int) Number of epochs +:param idx: (int) Index of the experiment +:param agent_dir: (str) Directory where to save the agent +:param n_its: (int) Number of iterations +:param shielded: (bool) Whether to use the shielded policy +:param env_name: (str) Name of the environment +:param n_steps: (int) Number of steps

+
+ +
+
+run_ppo_experiments(agent_dir, kwargs_list, n_its=10, base_steps=1020, index=None, env_name='MultiSensorEOS-v0', n_steps=45, num_cores=4, shielded=False)[source]
+

Run PPO experiments with the given hyperparameters +:param agent_dir: (str) Directory where to save the agent +:param n_its: (int) Number of iterations +:param kwargs_list: (list) List of dictionaries containing hyperparameters +:param index: (int) Index of the hyperparameter dictionary to use +:param env_name: (str) Name of the environment +:param n_steps: (int) Number of steps +:param num_cores: (int) Number of cores +:param shielded: (bool) Whether to use shielded policy]

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/training/sb3/index.html b/API Reference/training/sb3/index.html new file mode 100644 index 00000000..105b2f3b --- /dev/null +++ b/API Reference/training/sb3/index.html @@ -0,0 +1,138 @@ + + + + + + + sb3 — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

sb3

+

bsk_rl.training.sb3

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/effector_primitives/actuator_primitives.html b/API Reference/utilities/effector_primitives/actuator_primitives.html new file mode 100644 index 00000000..b6b9222a --- /dev/null +++ b/API Reference/utilities/effector_primitives/actuator_primitives.html @@ -0,0 +1,159 @@ + + + + + + + actuator_primitives — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

actuator_primitives

+

bsk_rl.utilities.effector_primitives.actuator_primitives

+
+
+
+
+balancedHR16Triad(useRandom=False, randomBounds=(-400, 400), wheelSpeeds=[500, 500, 500])[source]
+

Creates a set of three HR16 reaction wheels. +Returns a set of thrusters and thrusterFac instance to add thrusters to a +spacecraft. +:return thrusterSet: thruster dynamic effector instance +:return thrusterFac: factory containing defined thrusters

+
+ +
+
+idealMonarc1Octet()[source]
+

Creates a set of eight ADCS thrusters using MOOG Monarc-1 attributes. +Returns a set of thrusters and thrusterFac instance to add thrusters to a +spacecraft. +:return thrusterSet: thruster dynamic effector instance +:return thrusterFac: factory containing defined thrusters

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/effector_primitives/index.html b/API Reference/utilities/effector_primitives/index.html new file mode 100644 index 00000000..49ba7564 --- /dev/null +++ b/API Reference/utilities/effector_primitives/index.html @@ -0,0 +1,142 @@ + + + + + + + effector_primitives — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

effector_primitives

+

bsk_rl.utilities.effector_primitives

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/genetic_algorithm/experiments.html b/API Reference/utilities/genetic_algorithm/experiments.html new file mode 100644 index 00000000..a9981134 --- /dev/null +++ b/API Reference/utilities/genetic_algorithm/experiments.html @@ -0,0 +1,146 @@ + + + + + + + experiments — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

experiments

+

bsk_rl.utilities.genetic_algorithm.experiments

+
+
+
+
+run_ga_hp_experiment(ga_dir, ga_kwargs, index=None, num_cores=4, env_name='AgileEOS-v0')[source]
+

Runs a genetic algorithm experiment hyperparameter search experiment over the +number of generations and population size.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/genetic_algorithm/index.html b/API Reference/utilities/genetic_algorithm/index.html new file mode 100644 index 00000000..f1318de1 --- /dev/null +++ b/API Reference/utilities/genetic_algorithm/index.html @@ -0,0 +1,142 @@ + + + + + + + genetic_algorithm — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

genetic_algorithm

+

bsk_rl.utilities.genetic_algorithm

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/index.html b/API Reference/utilities/index.html new file mode 100644 index 00000000..07cb8fe4 --- /dev/null +++ b/API Reference/utilities/index.html @@ -0,0 +1,143 @@ + + + + + + + utilities — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

utilities

+

bsk_rl.utilities

+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/initial_conditions/index.html b/API Reference/utilities/initial_conditions/index.html new file mode 100644 index 00000000..190a621f --- /dev/null +++ b/API Reference/utilities/initial_conditions/index.html @@ -0,0 +1,148 @@ + + + + + + + initial_conditions — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

initial_conditions

+

bsk_rl.utilities.initial_conditions

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/initial_conditions/leo_initial_conditions.html b/API Reference/utilities/initial_conditions/leo_initial_conditions.html new file mode 100644 index 00000000..f0f16e2a --- /dev/null +++ b/API Reference/utilities/initial_conditions/leo_initial_conditions.html @@ -0,0 +1,142 @@ + + + + + + + leo_initial_conditions — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

leo_initial_conditions

+

bsk_rl.utilities.initial_conditions.leo_initial_conditions

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/initial_conditions/leo_orbit.html b/API Reference/utilities/initial_conditions/leo_orbit.html new file mode 100644 index 00000000..d62c14a2 --- /dev/null +++ b/API Reference/utilities/initial_conditions/leo_orbit.html @@ -0,0 +1,255 @@ + + + + + + + leo_orbit — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

leo_orbit

+

bsk_rl.utilities.initial_conditions.leo_orbit

+
+
+
+
+create_ground_tgts(n_targets, rN, vN, sim_length, utc_init)[source]
+

Returns a set of targets based on the orbital parameters by running a simplified +BSK scenario +:param n_targets: number of targets to generate +:param rN: Initial inertial position +:param vN: Initial inertial velocity +:param sim_length: simulation length +:param uct_init: time initialization string +:return targets:

+
+ +
+
+distribute_tgts(rN, vN, sim_length, utc_init, global_tgts, dt=60.0)[source]
+
+
Parameters:
+
    +
  • rN

  • +
  • vN

  • +
  • sim_length – [m]

  • +
  • utc_init

  • +
  • global_tgts – np.array of global tgts in ECEF coordinates

  • +
  • dt – [s]

  • +
+
+
Return local_tgts:
+

list of indexes into global tgts

+
+
Return local_tgt_times:
+

local time each global tgt in local_tgts is encountered

+
+
+
+ +
+
+elrange_req(sc_pos, tgt_pos)[source]
+

Determines if the spacecraft is within the elevation and range requirements of +a target

+
+
Parameters:
+
    +
  • sc_pos – spacecraft position expressed in the ECEF frame

  • +
  • tgt_pos – tgt_pos expressed in the ECEF frame

  • +
+
+
Returns:
+

T/F - within el, range requirements or not

+
+
+
+ +
+
+inclined_400km()[source]
+

Returns an elliptical, prograde LEO orbit with an SMA of 400km. +:return:

+
+ +
+
+inclined_circular_300km()[source]
+

Returns an inclined, circular LEO orbit. +:return:

+
+ +
+
+random_inclined_circular_300km()[source]
+

Returns an inclined, circular LEO orbit. +:return:

+
+ +
+
+sampled_400km()[source]
+

Returns an elliptical, prograde LEO orbit with an SMA of 400km. +:return:

+
+ +
+
+sampled_500km_boulder_gs()[source]
+

Returns an elliptical, prograde LEO orbit with an SMA of 500km. +Inclination is bounded so the spacecraft can communicate with Boulder. +:return:

+
+ +
+
+sampled_boulder_gs(nominal_radius)[source]
+

Returns an elliptical, prograde LEO orbit with an SMA of 500km. +Inclination is bounded so the spacecraft can communicate with Boulder. +:return:

+
+ +
+
+walker_delta(n_spacecraft, n_planes, rel_phasing, altitude, inc, clustersize=1, clusterspacing=0)[source]
+

Computes the initial orbit conditions of a constellation of spacecraft in the +walker delta pattern +:param n_spacecraft: number of spacecraft in the constellation +:param n_planes: number of orbital planes +:param rel_phasing: relative phasing between the planes [0, 1) +:param altitude: Altitude of the s/c (m) +:param inc: Inclination of the orbit (deg) +:param clustersize: Size of satellite groups +:param clusterspacing: True anomaly spacing within cluster (deg) +:return oe_all: n_spacecraft x 1 list of BSK oe elements

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/initial_conditions/sc_attitudes.html b/API Reference/utilities/initial_conditions/sc_attitudes.html new file mode 100644 index 00000000..cc7e8a36 --- /dev/null +++ b/API Reference/utilities/initial_conditions/sc_attitudes.html @@ -0,0 +1,157 @@ + + + + + + + sc_attitudes — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

sc_attitudes

+

bsk_rl.utilities.initial_conditions.sc_attitudes

+
+
+
+
+random_tumble(maxSpinRate=0.001)[source]
+

Simulates a spacecraft in a random tumble with uniformly sampled initial conditions. +:return: sigma_bn +:return: omega_bn

+
+ +
+
+static_inertial()[source]
+

Simulates a spacecraft in a sidereal stare fixed to the inertial origin. +:return:

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/initial_conditions/small_body.html b/API Reference/utilities/initial_conditions/small_body.html new file mode 100644 index 00000000..06831de4 --- /dev/null +++ b/API Reference/utilities/initial_conditions/small_body.html @@ -0,0 +1,163 @@ + + + + + + + small_body — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

small_body

+

bsk_rl.utilities.initial_conditions.small_body

+
+
+
+
+generate_imaging_points(num_points, radius)[source]
+

Generates a number of random imaging points on the surface of the body

+
+ +
+
+generate_mapping_points(num_points, radius)[source]
+

Generates a number of mapping points on the surface of the body using a +Fibonnaci sphere Algorithm from: +https://stackoverflow.com/questions/9600801/evenly-distributing-n-points-on-a-sphere

+
+ +
+
+generate_waypoints(num_spheres, num_lat, num_lon, radius)[source]
+

Generates a number of spheres of waypoints, each sphere is at [1…n]*radius, +where n is the num_spheres

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/mcts/index.html b/API Reference/utilities/mcts/index.html new file mode 100644 index 00000000..4fb73f3e --- /dev/null +++ b/API Reference/utilities/mcts/index.html @@ -0,0 +1,142 @@ + + + + + + + mcts — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mcts

+

bsk_rl.utilities.mcts

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/mcts/rollout_policies.html b/API Reference/utilities/mcts/rollout_policies.html new file mode 100644 index 00000000..c636e526 --- /dev/null +++ b/API Reference/utilities/mcts/rollout_policies.html @@ -0,0 +1,139 @@ + + + + + + + rollout_policies — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

rollout_policies

+

bsk_rl.utilities.mcts.rollout_policies

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/sb3/custom_sb3_policies.html b/API Reference/utilities/sb3/custom_sb3_policies.html new file mode 100644 index 00000000..de3fee25 --- /dev/null +++ b/API Reference/utilities/sb3/custom_sb3_policies.html @@ -0,0 +1,191 @@ + + + + + + + custom_sb3_policies — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

custom_sb3_policies

+

bsk_rl.utilities.sb3.custom_sb3_policies

+
+
+
+
+class CustomActorCriticPolicy(observation_space: ~gymnasium.spaces.space.Space, action_space: ~gymnasium.spaces.space.Space, lr_schedule: ~typing.Callable[[float], float], net_arch: ~typing.Dict | None = None, activation_fn: ~typing.Type[~torch.nn.modules.module.Module] = <class 'torch.nn.modules.activation.Tanh'>, *args, **kwargs)[source]
+

Bases: ActorCriticPolicy

+
+
+__init__(observation_space: ~gymnasium.spaces.space.Space, action_space: ~gymnasium.spaces.space.Space, lr_schedule: ~typing.Callable[[float], float], net_arch: ~typing.Dict | None = None, activation_fn: ~typing.Type[~torch.nn.modules.module.Module] = <class 'torch.nn.modules.activation.Tanh'>, *args, **kwargs)[source]
+

Initializes internal Module state, shared by both nn.Module and ScriptModule.

+
+ +
+ +
+
+class CustomNetwork(num_states=12, num_actions=4, width=100, depth=1, dropout=None, activation_function=<class 'torch.nn.modules.activation.LeakyReLU'>, alpha=None)[source]
+

Bases: Module

+

Custom network for policy and value function. +It receives as input the features extracted by the feature extractor.

+
+
Parameters:
+
    +
  • feature_dim – dimension of the features extracted with the features_extractor +(e.g. features from a CNN)

  • +
  • last_layer_dim_pi – (int) number of units for the last layer of the policy +network

  • +
  • last_layer_dim_vf – (int) number of units for the last layer of the value +network

  • +
+
+
+
+
+__init__(num_states=12, num_actions=4, width=100, depth=1, dropout=None, activation_function=<class 'torch.nn.modules.activation.LeakyReLU'>, alpha=None)[source]
+

Initializes internal Module state, shared by both nn.Module and ScriptModule.

+
+ +
+
+forward(features: Tensor) Tuple[Tensor, Tensor][source]
+
+
Returns:
+

(th.Tensor, th.Tensor) latent_policy, latent_value of the specified +network. +If all layers are shared, then latent_policy == latent_value

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/sb3/index.html b/API Reference/utilities/sb3/index.html new file mode 100644 index 00000000..723ef299 --- /dev/null +++ b/API Reference/utilities/sb3/index.html @@ -0,0 +1,146 @@ + + + + + + + sb3 — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

sb3

+

bsk_rl.utilities.sb3

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/sb3/shielded_policies.html b/API Reference/utilities/sb3/shielded_policies.html new file mode 100644 index 00000000..aac65347 --- /dev/null +++ b/API Reference/utilities/sb3/shielded_policies.html @@ -0,0 +1,195 @@ + + + + + + + shielded_policies — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

shielded_policies

+

bsk_rl.utilities.sb3.shielded_policies

+
+
+
+
+class CustomActorCriticShieldedAgileEOSPolicy(observation_space: ~gymnasium.spaces.space.Space, action_space: ~gymnasium.spaces.space.Space, lr_schedule: ~typing.Callable[[float], float], net_arch: ~typing.Dict | None = None, activation_fn: ~typing.Type[~torch.nn.modules.module.Module] = <class 'torch.nn.modules.activation.Tanh'>, *args, **kwargs)[source]
+

Bases: CustomActorCriticShieldedPolicy

+
+
+__init__(observation_space: ~gymnasium.spaces.space.Space, action_space: ~gymnasium.spaces.space.Space, lr_schedule: ~typing.Callable[[float], float], net_arch: ~typing.Dict | None = None, activation_fn: ~typing.Type[~torch.nn.modules.module.Module] = <class 'torch.nn.modules.activation.Tanh'>, *args, **kwargs)[source]
+

Initializes internal Module state, shared by both nn.Module and ScriptModule.

+
+ +
+ +
+
+class CustomActorCriticShieldedMultiSensorEOSPolicy(observation_space: ~gymnasium.spaces.space.Space, action_space: ~gymnasium.spaces.space.Space, lr_schedule: ~typing.Callable[[float], float], net_arch: ~typing.Dict | None = None, activation_fn: ~typing.Type[~torch.nn.modules.module.Module] = <class 'torch.nn.modules.activation.Tanh'>, *args, **kwargs)[source]
+

Bases: CustomActorCriticShieldedPolicy

+
+
+__init__(observation_space: ~gymnasium.spaces.space.Space, action_space: ~gymnasium.spaces.space.Space, lr_schedule: ~typing.Callable[[float], float], net_arch: ~typing.Dict | None = None, activation_fn: ~typing.Type[~torch.nn.modules.module.Module] = <class 'torch.nn.modules.activation.Tanh'>, *args, **kwargs)[source]
+

Initializes internal Module state, shared by both nn.Module and ScriptModule.

+
+ +
+ +
+
+class CustomActorCriticShieldedPolicy(observation_space: ~gymnasium.spaces.space.Space, action_space: ~gymnasium.spaces.space.Space, lr_schedule: ~typing.Callable[[float], float], net_arch: ~typing.Dict | None = None, activation_fn: ~typing.Type[~torch.nn.modules.module.Module] = <class 'torch.nn.modules.activation.Tanh'>, *args, **kwargs)[source]
+

Bases: ActorCriticPolicy

+

Custom actor critic policy with a shield. Made for AgileEOS environment.

+
+
+__init__(observation_space: ~gymnasium.spaces.space.Space, action_space: ~gymnasium.spaces.space.Space, lr_schedule: ~typing.Callable[[float], float], net_arch: ~typing.Dict | None = None, activation_fn: ~typing.Type[~torch.nn.modules.module.Module] = <class 'torch.nn.modules.activation.Tanh'>, *args, **kwargs)[source]
+

Initializes internal Module state, shared by both nn.Module and ScriptModule.

+
+ +
+
+forward(obs: Tensor, deterministic: bool = False) Tuple[Tensor, Tensor, Tensor][source]
+

Forward pass in all the networks (actor and critic)

+
+
Parameters:
+
    +
  • obs – Observation

  • +
  • deterministic – Whether to sample or use deterministic actions

  • +
+
+
Returns:
+

action, value and log probability of the action

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/sb3/shields.html b/API Reference/utilities/sb3/shields.html new file mode 100644 index 00000000..0c58aa9d --- /dev/null +++ b/API Reference/utilities/sb3/shields.html @@ -0,0 +1,169 @@ + + + + + + + shields — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

shields

+

bsk_rl.utilities.sb3.shields

+
+
+
+
+class AgileEOSShield[source]
+

Bases: object

+

Custom shield layer +:param: size_in -> input size, should be equal to the number of actions +:param: size_out -> output size, should be equal to the number of actions

+
+
+__init__()[source]
+
+ +
+ +
+
+class MultiSensorEOSShield[source]
+

Bases: object

+

Custom shield layer +:param: size_in -> input size, should be equal to the number of actions +:param: size_out -> output size, should be equal to the number of actions

+
+
+__init__()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/API Reference/utilities/state_machine/index.html b/API Reference/utilities/state_machine/index.html new file mode 100644 index 00000000..ebf94afa --- /dev/null +++ b/API Reference/utilities/state_machine/index.html @@ -0,0 +1,137 @@ + + + + + + + state_machine — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

state_machine

+

bsk_rl.utilities.state_machine

+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/general_satellite_tasking/index.html b/Examples/general_satellite_tasking/index.html new file mode 100644 index 00000000..81112baa --- /dev/null +++ b/Examples/general_satellite_tasking/index.html @@ -0,0 +1,139 @@ + + + + + + + general_satellite_tasking — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

general_satellite_tasking

+

examples.general_satellite_tasking

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/general_satellite_tasking/multisat_aeos.html b/Examples/general_satellite_tasking/multisat_aeos.html new file mode 100644 index 00000000..79fe21d6 --- /dev/null +++ b/Examples/general_satellite_tasking/multisat_aeos.html @@ -0,0 +1,144 @@ + + + + + + + multisat_aeos — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

multisat_aeos

+

examples.general_satellite_tasking.multisat_aeos

+
+
+
+

Multisat AEOS

+

some text here

+
+
+
+run()[source]
+

Demonstrate the configuration of an environment with multiple imaging satellites.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/general_satellite_tasking/satellite_customization.html b/Examples/general_satellite_tasking/satellite_customization.html new file mode 100644 index 00000000..f4187b34 --- /dev/null +++ b/Examples/general_satellite_tasking/satellite_customization.html @@ -0,0 +1,134 @@ + + + + + + + satellite_customization — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

satellite_customization

+

examples.general_satellite_tasking.satellite_customization

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/general_satellite_tasking/single_sat.html b/Examples/general_satellite_tasking/single_sat.html new file mode 100644 index 00000000..59fff665 --- /dev/null +++ b/Examples/general_satellite_tasking/single_sat.html @@ -0,0 +1,134 @@ + + + + + + + single_sat — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

single_sat

+

examples.general_satellite_tasking.single_sat

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/genetic_algorithm/ga_hp_solver.html b/Examples/genetic_algorithm/ga_hp_solver.html new file mode 100644 index 00000000..4f343051 --- /dev/null +++ b/Examples/genetic_algorithm/ga_hp_solver.html @@ -0,0 +1,132 @@ + + + + + + + ga_hp_solver — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

ga_hp_solver

+

examples.genetic_algorithm.ga_hp_solver

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/genetic_algorithm/index.html b/Examples/genetic_algorithm/index.html new file mode 100644 index 00000000..04df65a8 --- /dev/null +++ b/Examples/genetic_algorithm/index.html @@ -0,0 +1,135 @@ + + + + + + + genetic_algorithm — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

genetic_algorithm

+

examples.genetic_algorithm

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/index.html b/Examples/index.html new file mode 100644 index 00000000..ddebc244 --- /dev/null +++ b/Examples/index.html @@ -0,0 +1,136 @@ + + + + + + + Examples — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Examples

+

examples

+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/mcts/index.html b/Examples/mcts/index.html new file mode 100644 index 00000000..b63b41f7 --- /dev/null +++ b/Examples/mcts/index.html @@ -0,0 +1,139 @@ + + + + + + + mcts — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mcts

+

examples.mcts

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/mcts/mcts_data_generator.html b/Examples/mcts/mcts_data_generator.html new file mode 100644 index 00000000..f8c03aac --- /dev/null +++ b/Examples/mcts/mcts_data_generator.html @@ -0,0 +1,134 @@ + + + + + + + mcts_data_generator — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mcts_data_generator

+

examples.mcts.mcts_data_generator

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/mcts/network_hyperparam_search.html b/Examples/mcts/network_hyperparam_search.html new file mode 100644 index 00000000..1735f476 --- /dev/null +++ b/Examples/mcts/network_hyperparam_search.html @@ -0,0 +1,134 @@ + + + + + + + network_hyperparam_search — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + + + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/mcts/network_validation_multiprocessing.html b/Examples/mcts/network_validation_multiprocessing.html new file mode 100644 index 00000000..4c985d14 --- /dev/null +++ b/Examples/mcts/network_validation_multiprocessing.html @@ -0,0 +1,161 @@ + + + + + + + network_validation_multiprocessing — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

network_validation_multiprocessing

+

examples.mcts.network_validation_multiprocessing

+
+
+
+
+modify_observation(obs, info, modified_states)[source]
+

This function modifies the observation from the environment if this is required. +:param obs: environment observation +:param info: info that may be add to the observation +:param modified states: a list of state indices to keep and dictionary keys +:return obs: modified observation

+
+ +
+
+run_simulator(network, reward_specific, success_specific, downlink_util_specific, exec_time_specific, imaged_specific, downlinked_specific, modified_states, ic)[source]
+

This function is utilized to a.) load the network, b.) run the network in the +environment, and c.) update performance metrics +:param network: File name of neural network +:param reward_specific: List of reward metrics +:param success_specific: List of success metrics +:param downlink_util_specific: List of downlink utilization metrics +:param exec_time_specific: List of execution time metrics +:param imaged_specific: List of image metric +:param downlinked_specific: List of downlinked metric +:param modified_states: List containing indices of states to keep and entries of +the info dictionary +:param ic: initial conditions

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/plotting_tools/index.html b/Examples/plotting_tools/index.html new file mode 100644 index 00000000..90e41bd9 --- /dev/null +++ b/Examples/plotting_tools/index.html @@ -0,0 +1,147 @@ + + + + + + + plotting_tools — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+ +
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/plotting_tools/plot_a2c_hyperparams.html b/Examples/plotting_tools/plot_a2c_hyperparams.html new file mode 100644 index 00000000..38a2b70b --- /dev/null +++ b/Examples/plotting_tools/plot_a2c_hyperparams.html @@ -0,0 +1,138 @@ + + + + + + + plot_a2c_hyperparams — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

plot_a2c_hyperparams

+

examples.plotting_tools.plot_a2c_hyperparams

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/plotting_tools/plot_dqn_hyperparams.html b/Examples/plotting_tools/plot_dqn_hyperparams.html new file mode 100644 index 00000000..0aa6bb69 --- /dev/null +++ b/Examples/plotting_tools/plot_dqn_hyperparams.html @@ -0,0 +1,138 @@ + + + + + + + plot_dqn_hyperparams — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

plot_dqn_hyperparams

+

examples.plotting_tools.plot_dqn_hyperparams

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/plotting_tools/plot_ga_hyperparams.html b/Examples/plotting_tools/plot_ga_hyperparams.html new file mode 100644 index 00000000..2a0e07e1 --- /dev/null +++ b/Examples/plotting_tools/plot_ga_hyperparams.html @@ -0,0 +1,138 @@ + + + + + + + plot_ga_hyperparams — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

plot_ga_hyperparams

+

examples.plotting_tools.plot_ga_hyperparams

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/plotting_tools/plot_mcts_hyperparams.html b/Examples/plotting_tools/plot_mcts_hyperparams.html new file mode 100644 index 00000000..5c3dd311 --- /dev/null +++ b/Examples/plotting_tools/plot_mcts_hyperparams.html @@ -0,0 +1,138 @@ + + + + + + + plot_mcts_hyperparams — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

plot_mcts_hyperparams

+

examples.plotting_tools.plot_mcts_hyperparams

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/plotting_tools/plot_ppo_hyperparams.html b/Examples/plotting_tools/plot_ppo_hyperparams.html new file mode 100644 index 00000000..b1f1e15b --- /dev/null +++ b/Examples/plotting_tools/plot_ppo_hyperparams.html @@ -0,0 +1,138 @@ + + + + + + + plot_ppo_hyperparams — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

plot_ppo_hyperparams

+

examples.plotting_tools.plot_ppo_hyperparams

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/plotting_tools/process_ga_curves.html b/Examples/plotting_tools/process_ga_curves.html new file mode 100644 index 00000000..27db8335 --- /dev/null +++ b/Examples/plotting_tools/process_ga_curves.html @@ -0,0 +1,146 @@ + + + + + + + process_ga_curves — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

process_ga_curves

+

examples.plotting_tools.process_ga_curves

+
+
+
+
+process_ga_curve(run_dir, env_name)[source]
+

Generates plots of GA convergence, performance, and final population vector behavior +:param checkpoint_names: list of checkpoint names, assumed to be pickle files. +:return:

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/plotting_tools/process_sb3_curves.html b/Examples/plotting_tools/process_sb3_curves.html new file mode 100644 index 00000000..19835551 --- /dev/null +++ b/Examples/plotting_tools/process_sb3_curves.html @@ -0,0 +1,138 @@ + + + + + + + process_sb3_curves — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

process_sb3_curves

+

examples.plotting_tools.process_sb3_curves

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/sb3/a2c_hyperparam_search.html b/Examples/sb3/a2c_hyperparam_search.html new file mode 100644 index 00000000..86efd677 --- /dev/null +++ b/Examples/sb3/a2c_hyperparam_search.html @@ -0,0 +1,135 @@ + + + + + + + a2c_hyperparam_search — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + + + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/sb3/dqn_hyperparam_search.html b/Examples/sb3/dqn_hyperparam_search.html new file mode 100644 index 00000000..2a6df18d --- /dev/null +++ b/Examples/sb3/dqn_hyperparam_search.html @@ -0,0 +1,135 @@ + + + + + + + dqn_hyperparam_search — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + + + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/sb3/index.html b/Examples/sb3/index.html new file mode 100644 index 00000000..71502e9c --- /dev/null +++ b/Examples/sb3/index.html @@ -0,0 +1,141 @@ + + + + + + + sb3 — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

sb3

+

examples.sb3

+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/sb3/ppo_hyperparam_search.html b/Examples/sb3/ppo_hyperparam_search.html new file mode 100644 index 00000000..a1a5731e --- /dev/null +++ b/Examples/sb3/ppo_hyperparam_search.html @@ -0,0 +1,135 @@ + + + + + + + ppo_hyperparam_search — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + + + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/sb3/sppo_hyperparam_search.html b/Examples/sb3/sppo_hyperparam_search.html new file mode 100644 index 00000000..ad605af1 --- /dev/null +++ b/Examples/sb3/sppo_hyperparam_search.html @@ -0,0 +1,135 @@ + + + + + + + sppo_hyperparam_search — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ + + + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/state_machine/index.html b/Examples/state_machine/index.html new file mode 100644 index 00000000..0701ced7 --- /dev/null +++ b/Examples/state_machine/index.html @@ -0,0 +1,135 @@ + + + + + + + state_machine — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

state_machine

+

examples.state_machine

+
+

Files:

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Examples/state_machine/state_machine_example.html b/Examples/state_machine/state_machine_example.html new file mode 100644 index 00000000..694c6105 --- /dev/null +++ b/Examples/state_machine/state_machine_example.html @@ -0,0 +1,130 @@ + + + + + + + state_machine_example — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

state_machine_example

+

examples.state_machine.state_machine_example

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/agents/genetic_algorithm.html b/_modules/bsk_rl/agents/genetic_algorithm.html new file mode 100644 index 00000000..510518b2 --- /dev/null +++ b/_modules/bsk_rl/agents/genetic_algorithm.html @@ -0,0 +1,428 @@ + + + + + + bsk_rl.agents.genetic_algorithm — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.agents.genetic_algorithm

+import multiprocessing
+import os
+import pickle
+import random
+from datetime import datetime
+from os import sep as SEP
+
+import gymnasium as gym
+import numpy as np
+from deap import algorithms, base, creator, tools
+from matplotlib import pyplot as plt
+
+"""
+This file is designed to provide generitc interfaces to a DEAP-based genetic algorithm
+for solving arbitrary gymnasium environments. It does a few things:
+1. Includes the ability to cast arbitrary gymnasium environments with a max_length
+    parameter as many-input, single-output optimzation problems
+2. Allows a genetic algorithm to be called to optimize said environments in a parellel
+    way
+"""
+
+creator.create("FitnessMax", base.Fitness, weights=(1.0,))
+creator.create("Individual", list, fitness=creator.FitnessMax)
+
+
+
+[docs] +def mutUniformIntList(individual, num_samples=2, low=0, up=5, indpb=0.3): + """ + This function is designed to mutate a list of integers, rather than a single + integer. + :param individual: The individual to be mutated + :param num_samples: The number of samples to be mutated + :param low: The lower bound for the mutation + :param up: The upper bound for the mutation + :param indpb: The probability of mutation + :returns: A list of a single individual. + """ + + size = len(individual) + for i in range(size): + for j in range(num_samples): + if random.random() < indpb: + individual[i][j] = random.randint(low, up) + + return (individual,)
+ + + +
+[docs] +class env2opt_problem(object): + """ + This class provides a generic interface for recasting a gymnasium environment as a + total reward maximization problem. + """ + +
+[docs] + def __init__(self, env_name, initial_conditions=None): + self.env_name = env_name + tmp_env = gym.make(env_name) + if initial_conditions is None: + tmp_env.reset() + self.initial_conditions = tmp_env.simulator.initial_conditions + else: + self.initial_conditions = initial_conditions + + try: + self.n_actions = tmp_env.max_steps + except AttributeError: + print("Error - environment must have max_steps attribute.") + return + + self.action_space = tmp_env.action_space
+ + +
+[docs] + def evaluate(self, action_set): + """ + Evaluates a full run of the environment given a list of actions. + """ + total_reward = 0 + + self.env = gym.make(self.env_name) + self.env.reset(options={"initial_conditions": self.initial_conditions}) + + for ind in range(0, self.n_actions): + _, r, ep_over, _, info = self.env.step(action_set[ind]) + total_reward = total_reward + r + if ep_over: + break + + # Initialize a metrics dictionary + metrics = {} + # Add the total reward to the metrics dictionary + metrics["total_reward"] = total_reward + # Add the number of steps taken to the metrics dictionary + metrics["steps"] = ind + 1 + if self.env_name == "AgileEOS-v0" or self.env_name == "MultiSatAgileEOS-v0": + metrics["imaged_targets"] = np.sum(self.env.simulator.imaged_targets) + metrics["downlinked_targets"] = np.sum( + self.env.simulator.downlinked_targets + ) + elif self.env_name == "MultiSensorEOS-v0": + metrics["imaged_targets"] = np.sum(self.env.simulator.imaged_targets) + elif self.env_name == "SmallBodyScience-v0": + metrics["imaged_targets"] = np.sum(self.env.simulator.imaged_targets) + metrics["downlinked_targets"] = np.sum( + self.env.simulator.downlinked_targets + ) + metrics["imaged_maps"] = self.env.simulator.imaged_maps + metrics["downlinked_maps"] = self.env.simulator.downlinked_maps + elif self.env_name == "SimpleEOS-v0": + metrics["downlinked"] = self.env.simulator.downlinked + metrics["total_access"] = self.env.simulator.total_access + metrics["utilized_access"] = self.env.simulator.utilized_access + + if self.env_name == "MultiSatAgileEOS-v0": + return (total_reward[0, -1], metrics) + else: + return (total_reward, metrics)
+
+ + + +class ga_env_solver(object): + def __init__( + self, + env_name, + n_gens, + gen_size, + cx_prob=0.25, + mut_prob=0.25, + num_cores=4, + ga_dir="ga_results" + SEP, + ): + self.env_name = env_name + self.n_gens = n_gens + self.gen_size = gen_size + self.ga_dir = ga_dir + self.num_cores = num_cores + + problem = env2opt_problem(env_name) + + # Define some problem-specific parameters + IND_SIZE = ( + problem.n_actions + ) # Each individual is a list of actions to take at each env.step() + + creator.create("FitnessMax", base.Fitness, weights=(1.0,)) + creator.create("Individual", list, fitness=creator.FitnessMax) + + self.toolbox = base.Toolbox() + + # Check to see whether the env takes integer, list of integer, or float inputs + if type(problem.action_space) == gym.spaces.discrete.Discrete: + act_min = 0 + act_max = problem.action_space.n - 1 + self.toolbox.register("attr_action", random.randint, act_min, act_max) + self.toolbox.register( + "mutate", tools.mutUniformInt, low=act_min, up=act_max, indpb=0.3 + ) + elif type(problem.action_space) == gym.spaces.multi_discrete.MultiDiscrete: + num_agents = len(problem.action_space.nvec) + act_min = 0 + act_max = problem.action_space.nvec[0] - 1 + self.toolbox.register( + "attr_action", random.sample, range(act_min, act_max + 1), num_agents + ) + self.toolbox.register( + "mutate", + mutUniformIntList, + num_samples=num_agents, + low=act_min, + up=act_max, + indpb=0.3, + ) + + self.MU = gen_size # Number of individuals per generation + self.NGEN = n_gens # Number of generations + self.CXPB = cx_prob # Crossover probability. + self.MUTPB = mut_prob # Mutation probability. + + # generation functions + self.toolbox.register( + "individual", + tools.initRepeat, + creator.Individual, + (self.toolbox.attr_action), + n=IND_SIZE, + ) + self.toolbox.register( + "population", tools.initRepeat, list, self.toolbox.individual + ) + + # evolutionary ops + self.toolbox.register("mate", tools.cxOnePoint) + self.toolbox.register("select", tools.selTournament, tournsize=3) + + # Evaluation ops + self.toolbox.register("evaluate", problem.evaluate) + + def optimize(self, seed=datetime.now(), checkpoint_freq=1, checkpoint=None): + if not os.path.exists(self.ga_dir): + os.makedirs(self.ga_dir) + + pool = multiprocessing.Pool(min(self.num_cores, self.MU)) + self.toolbox.register("map", pool.map) + stats = tools.Statistics(lambda ind: ind.fitness.values) + stats.register("avg", np.mean, axis=0) + stats.register("std", np.std, axis=0) + stats.register("min", np.min, axis=0) + stats.register("max", np.max, axis=0) + + print("Multiprocessing start method: ", multiprocessing.get_start_method()) + + if checkpoint is not None: + with open(checkpoint, "rb") as checkpoint_file: + check_dict = pickle.load(checkpoint_file) + pop = check_dict["population"] + start_gen = check_dict["generation"] + logbook = check_dict["logbook"] + else: + logbook = tools.Logbook() + logbook.header = "gen", "evals", "std", "min", "avg", "max" + pop = self.toolbox.population(n=self.MU) + + invalid_ind = [ind for ind in pop if not ind.fitness.valid] + fitnesses = self.toolbox.map(self.toolbox.evaluate, invalid_ind) + fitness_list = [list(fitness) for fitness in fitnesses] + + for ind, fit in zip(invalid_ind, fitnesses): + ind.fitness.values = (fit[0],) + + record = stats.compile(pop) + logbook.record(gen=0, evals=len(invalid_ind), **record) + print(logbook.stream) + start_gen = 1 + + for gen in range(start_gen, start_gen + self.NGEN): + offspring = algorithms.varAnd(pop, self.toolbox, self.CXPB, self.MUTPB) + + invalid_ind = [ind for ind in offspring if not ind.fitness.valid] + fitnesses = self.toolbox.map(self.toolbox.evaluate, invalid_ind) + for ind, fit in zip(invalid_ind, fitnesses): + ind.fitness.values = (fit[0],) + + fitness_list.extend([list(fitness) for fitness in fitnesses]) + + pop = self.toolbox.select(pop + offspring, self.MU) + + record = stats.compile(pop) + logbook.record(gen=gen, evals=len(invalid_ind), **record) + print(logbook.stream) + + if gen % checkpoint_freq == 0: + chkpnt = dict( + population=pop, + generation=gen, + logbook=logbook, + rndstate=random.getstate(), + ) + pickle.dump( + chkpnt, open(self.ga_dir + self.env_name + f"_{gen}.pkl", "wb") + ) + + fitness_list = np.array(fitness_list) + index = np.where(fitness_list[:, 0] == np.max(fitness_list[:, 0]))[0] + max_reward = fitness_list[index[0], 0] + metrics = fitness_list[index[0], 1] + + results = (max_reward, metrics) + + return results + + def plot_results(self): + """ + Generates plots of GA convergence, performance, and final population vector + behavior + :param checkpoint_names: list of checkpoint names, assumed to be pickle files. + :return: + """ + # Pull data out of the pickles + gen_list = [] + min_reward = [] + max_reward = [] + mean_reward = [] + + checkpoint_names = [ + self.ga_dir + self.env_name + f"_{gen}.pkl" for gen in range(1, self.n_gens) + ] + + for name in checkpoint_names: + with open(name, "rb") as file: + result = pickle.load(file) + gen_list.append(result["generation"]) + tmp_log = result["logbook"] + mean_reward.append(tmp_log[-1]["avg"]) + min_reward.append(tmp_log[-1]["min"]) + max_reward.append(tmp_log[-1]["max"]) + + fig, ax = plt.subplots(figsize=(7, 5)) + plt.plot(gen_list, mean_reward, label="Mean Reward") + plt.plot(gen_list, max_reward, "--", label="Max Reward") + plt.plot(gen_list, min_reward, "--", label="Min Reward") + plt.grid() + plt.ylabel("Total Reward", fontsize=16) + plt.xlabel("Training Generation", fontsize=16) + plt.xticks(fontsize=12) + plt.yticks(fontsize=12) + plt.legend(fontsize=12) + plt.savefig( + self.ga_dir + self.env_name + "_training.png", + dpi=300, + pad_inches=0.1, + bbox_inches="tight", + transparent=True, + ) + + plt.show() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/agents/mcts.html b/_modules/bsk_rl/agents/mcts.html new file mode 100644 index 00000000..85c728ac --- /dev/null +++ b/_modules/bsk_rl/agents/mcts.html @@ -0,0 +1,398 @@ + + + + + + bsk_rl.agents.mcts — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for bsk_rl.agents.mcts

+import math
+
+import gymnasium as gym
+import numpy as np
+
+from bsk_rl.utilities.mcts.rollout_policies import SmallBodyRolloutPolicy
+
+
+
+[docs] +class MCTS: + """ + This provides and MCTS class for deterministic environments. + + To use as UCT, set the rollout type to either 'heuristic' or 'random' + If a heuristic rollout type is used, create the policy using the following two + lines of code: + + .. code-block:: python + + stateMachineMCTS = state_machine.StateMachine() + stateMachineMCTS.loadTransferConditions("agile_eos_ops.adv") + rollout_policy = AgileEOSRolloutPolicy(env=env, state_machine=stateMachineMCTS) + + Then, load the policy as the rollout_policy during initialization: + + .. code-block:: python + + MCTS_Agent = MCTS(c=c, num_sims=num_sims, rollout_policy=rollout_policy) + + The env and initial conditions must be loaded in after initialization. The + algorithm will automatically restart the sim and step it forward to the last + state. This is due to limitations in copying Basilisk: + + .. code-block:: python + + MCTS_Agent.setEnv( + env_name, env.initial_conditions, max_steps=num_steps, max_length=t_final + ) + + Args: + c: scaling of the exploration bonus + num_sims: number of simulations per call of selectAction() + """ + +
+[docs] + def __init__( + self, + c=1.0, + num_sims=10, + max_length=270.0, + max_steps=45, + rollout_policy=None, + backup_type="max", + ): + # Set the env to none + self.env = None + # Set the initial conditions to none + self.initial_conditions = None + # Initialize Q and N as empty dicts + self.Q = {} + self.N = {} + # Initialize Q, N, and the trajectory along the main tree + self.Q_main = {} + self.N_main = {} + self.info = {} + self.trajectory = [] # Make into a list so order is preserved + # Initialize T as empty (visited states) + self.T = [] + # Initialize C + self.c = c + # Rollout policy initialization + self.rollout_policy = rollout_policy + # Number of simulations + self.num_sims = num_sims + # set env type + self.envType = None + # set max length and max steps + self.max_length = max_length + self.max_steps = max_steps + self.action_history = None + # Set the backup type + self.backup_type = backup_type
+ + + # Define the environment +
+[docs] + def setEnv(self, envType, initial_conditions, max_steps=30, max_length=90): + """Sets the environment and initial conditions MCTS will step through""" + # Create the environment + self.envType = envType + self.env = gym.make(envType) + self.env.max_steps = max_steps + self.env.max_length = max_length + print(max_steps) + print(max_length) + # Set the initial conditions for MCTS + self.initial_conditions = initial_conditions + # initialize the environment with the initial conditions + self.env.reset(options={"initial_conditions": self.initial_conditions})
+ + + # @profiler.profile +
+[docs] + def selectAction(self, s, d, actHist): + """Selects the next action for the true environment to step through""" + # We make a tuple out of s so it an be used as a dictionary key + s_tuple = tuple(s.reshape(1, -1)[0]) + + # Run simulate for the specified number, defaults to 10 + for i in range(self.num_sims): + # Before calling simulate each time, reset env and take it to current place + # initialize the environment with the initial conditions + ob, info = self.env.reset( + options={"initial_conditions": self.initial_conditions} + ) + + # Step through env to take it to current place + self.env.return_obs = False + for index, act in enumerate(actHist): + if index != (len(actHist) - 1): + _, _, _, _, _ = self.env.step(act) + else: + s_temp, _, _, _, _ = self.env.step(act) + self.env.return_obs = True + + if actHist != []: + try: + if tuple(s_temp.reshape(1, -1)[0]) != s_tuple: + raise Exception("Environment is not deterministic") + except Exception: + self.rewind_sim(actHist) + print("Rewound state: ", tuple(s_temp.reshape(1, -1)[0])) + print("Passed state: ", s_tuple) + + # Reset the rollout policy + if self.rollout_policy is type(SmallBodyRolloutPolicy): + self.rollout_policy.state_machine.setupSmallBodyScience() + + self.action_history = np.copy(actHist).tolist() + self.simulate(s, d) + + # Copy Q[s] to Q_main + self.Q_main[s_tuple] = self.Q[s_tuple].copy() + self.N_main[s_tuple] = self.N[s_tuple].copy() + + # Return the action associated with the max Q at the current state + try: + print("Q(s): ", self.Q[s_tuple]) + print("N(s): ", self.N[s_tuple]) + except KeyError: + print("Raw s: ", s) + print("Tuple s: ", s_tuple) + + print("s: ", s_tuple) + return max(self.Q[s_tuple], key=self.Q[s_tuple].get)
+ + +
+[docs] + def simulate(self, s, d): + """Simulates a trajectory through the environment and updates Q_search""" + # We make a tuple out of s so it an be used as a dictionary key + try: + s_tuple = tuple(s.reshape(1, -1)[0]) + if np.isnan(np.sum(s_tuple)): + raise Exception("State is NaN") + except Exception: + s = self.rewind_sim(self.action_history) + self.simulate(s, d) + + # If depth is zero, return 0 + if d == 0: + return 0.0 + + # If s is not in T + if s_tuple not in self.T: + # Initialize empty dicts inside of Q and N + self.Q[s_tuple] = {} + self.N[s_tuple] = {} + # Loop through actions + for a in range(self.env.action_space.n): + # Initialize Q and N for action and state to zero + self.Q[s_tuple][a] = -self.env.failure_penalty + self.N[s_tuple][a] = 0.0 + # Add s to visited set + self.T.append(s_tuple) + # Roll it out + return self.rollout(s, d) + + function_max = {} + for action in self.Q[s_tuple]: + function_max[action] = self.Q[s_tuple][action] + self.c * math.sqrt( + sum(self.N[s_tuple].values()) + ) / (1 + self.N[s_tuple][action]) + + # Get action + a = max(function_max, key=function_max.get) + + # Take our new action! + sp, reward, episode_over, _, _ = self.env.step(a) + self.action_history.append(a) + + # If the episode is over, don't call simulate recursively. Sim is over. + if episode_over: + q = reward + # Otherwise, call simulate recursively using new action history and add to q + else: + q = reward + self.simulate(sp, d - 1) + + # Update N + self.N[s_tuple][a] = self.N[s_tuple][a] + 1 + + # Update Q + if self.backup_type == "incremental_avg": + self.Q[s_tuple][a] = ( + self.Q[s_tuple][a] + (q - self.Q[s_tuple][a]) / self.N[s_tuple][a] + ) + elif self.backup_type == "max": + # Max-q + if self.Q[s_tuple][a] < q: + self.Q[s_tuple][a] = q + else: + raise Exception("Invalid backup type") + + return q
+ + +
+[docs] + def rollout(self, s, d): + """Executes a rollout to the desired depth or end of the environment""" + # If we have reached max depth, just return 0 + if d == 0: + return 0.0 + # If we have not reached max depth, select action using rollout policy + else: + # Select action using rollout policy + act = self.rollout_policy.act(s) + + # Take a step in the environment + sp, reward, episode_over, _, _ = self.env.step(act) + + # If the episode is over, return the penalty reward only + if episode_over: + return reward + + # Recursively call rollout + return reward + self.rollout(sp, d - 1)
+ + +
+[docs] + def backup_tree(self): + """Backs up the value along the main tree once the sim has terminated""" + # 'Anti-Sum' is added to at each node to subtract from r_sum at last node + r_anti_sum = 0 + # Grab the total reward from the last node + r_sum = self.trajectory[-1][3] + for idx, node in enumerate(self.trajectory): + # If we're at the first node + if idx == 0: + # Update the state-action value at that node with r_sum + self.Q_main[node[0]][node[1]] = r_sum + # Add the reward at the node to r_anti_sum + r_anti_sum += node[2] + else: + self.Q_main[node[0]][node[1]] = r_sum - r_anti_sum + r_anti_sum += node[2] + # Add the info + self.info[node[0]] = node[4]
+ + + def rewind_sim(self, action_history): + self.env.reset(options={"initial_conditions": self.initial_conditions}) + for action in action_history: + s, _, _, _, _ = self.env.step(action) + + # Check to make sure it isn't nan again + try: + s_tuple = tuple(s.reshape(1, -1)[0]) + if np.isnan(np.sum(s_tuple)): + raise Exception("State is NaN inside of rewind_sim") + except Exception: + print("State is NaN inside of rewind_sim") + return self.rewind_sim(self.action_history) + + return s
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/agile_eos/gym_env.html b/_modules/bsk_rl/envs/agile_eos/gym_env.html new file mode 100644 index 00000000..12e0196f --- /dev/null +++ b/_modules/bsk_rl/envs/agile_eos/gym_env.html @@ -0,0 +1,480 @@ + + + + + + bsk_rl.envs.agile_eos.gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.agile_eos.gym_env

+import gymnasium as gym
+import numpy as np
+from Basilisk.utilities import macros as mc
+from gymnasium import spaces
+
+from bsk_rl.envs.agile_eos.bsk_sim import AgileEOSSimulator
+
+
+
+[docs] +class AgileEOS(gym.Env): + """ + This Gymnasium environment is designed to simulate an agile EOS scheduling problem + in which a satellite in low-Earth orbit attempts to maximize the number of targets + imaged and downlinked while avoiding resource constraint violations. Resource + constraint include: + + 1. Power: The spacecraft must keep its battery charge above zero + 2. Reaction Wheel Saturation: The spacecraft must keep its reaction wheels within + their speed limits + 3. Data Buffer: The spacecraft must keep its data buffer from overflowing (i.e. + exceeding or meeting the maximum buffer size) + + The spacecraft must decide between pointing at any one of J number of ground targets + for imaging, pointing at the sun to charge, desaturating reaction wheels, or + downlinking data. This is referred to as the AgileEOS environment. + + Action Space (Discrete): + 0 - Charging mode + 1 - Downlink mode + 2 - Desat mode + 3:J+3 - Image target j + + Observation Space: + ECEF position and velocity - indices 0-5 + Attitude error and attitude rate - indices 6-7 + Reaction wheel speeds - indices 8-11 + Battery charge - indices 12 + Eclipse indicator - indices 13 + Stored data onboard spacecraft - indices 14 + Data transmitted over interval - indices 15 + Amount of time ground stations were accessible (s) - 16-22 + Target Tuples (4 values each) - priority and Hill frame pos + + Reward Function: + r = +A/priority for for each tgt downlinked for first time + r = +B/priority for for each tgt imaged for first time + r = -C if failure + """ + +
+[docs] + def __init__(self, failure_penalty=1, image_component=0.1, downlink_component=0.9): + self.__version__ = "0.0.1" + print("AgileEOS Environment - Version {}".format(self.__version__)) + + # General variables defining the environment + self.max_length = float(270.0) # Specify the maximum number of minutes + self.max_steps = 45 + self.render = False + + # Tell the environment that it doesn't have a sim attribute... + self.simulator_init = 0 + self.simulator = None + self.reward_total = 0 + + # Set initial conditions to none (gets assigned in reset) + self.initial_conditions = None + + # Set the dynRate for the env, which is passed into the simulator + self.dynRate = 1.0 + self.fswRate = 1.0 + + # Set up options, constants for this environment + self.step_duration = 6 * 60.0 # seconds, tune as desired + self.reward_mult = 1.0 + + # Set the reward components + self.failure_penalty = failure_penalty + self.image_component = image_component + self.downlink_component = downlink_component + + # Set up targets and action, observation spaces + self.n_targets = ( + 3 # Assumes 100 targets, three other actions (charge, desat, downlink) + ) + self.target_tuple_size = 4 + self.action_space = spaces.Discrete(3 + self.n_targets) + low = -1e16 + high = 1e16 + self.observation_space = spaces.Box( + low, + high, + shape=(22 + self.n_targets * self.target_tuple_size,), + dtype=np.float64, + ) + self.obs = np.zeros(22 + self.n_targets * self.target_tuple_size) + self.obs_full = np.zeros(22 + self.n_targets * self.target_tuple_size) + + # Store what the agent tried + self.curr_episode = -1 + self.action_episode_memory = [] + self.curr_step = 0 + self.episode_over = False + self.failure = False + + self.dvc_cmd = 0 + self.act_hold = None + + self.return_obs = True
+ + +
+[docs] + def step(self, action): + """ + The agent takes a step in the environment. + Parameters + ---------- + action : int + Returns + ------- + ob, reward, episode_over, info : tuple + ob (object) : + an environment-specific object representing your observation of + the environment. + reward (float) : + amount of reward achieved by the previous action. The scale + varies between environments, but the goal is always to increase + your total reward. + episode_over (bool) : + whether it's time to reset the environment again. Most (but not + all) tasks are divided up into well-defined episodes, and done + being True indicates the episode has terminated. (For example, + perhaps the pole tipped too far, or you lost your last life.) + info (dict) : + diagnostic information useful for debugging. It can sometimes + be useful for learning (for example, it might contain the raw + probabilities behind the environment's last state change). + However, official evaluations of your agent are not allowed to + use this for learning. + """ + + # If the simTime in minutes is greater than the planning interval in minutes, + # end the sim + if (self.simulator.simTime / 60.0) >= self.max_length: + print("End of simulation reached", self.simulator.simTime / 60) + self.episode_over = True + + downlinked, imaged, info = self._take_action(action) + + # If we want to return observations, do the following + if self.return_obs: + reward = 0 + ob = self._get_state() + self.prev_dvc_cmd = self.dvc_cmd + self.dvc_cmd = ( + self.simulator.simpleInsControlConfig.deviceCmdOutMsg.read().deviceCmd + ) + + # If the wheel speeds get too large, end the episode. + if any( + speeds > self.simulator.initial_conditions["maxSpeed"] * mc.RPM + for speeds in self.obs_full[8:11] + ): + self.episode_over = True + self.failure = True + print( + "Died from wheel explosion. RPMs were: " + + str(self.obs_full[8:11] / mc.RPM) + + ", limit is " + + str(self.simulator.initial_conditions["maxSpeed"]) + + ", body rate was " + + str(self.obs_full[7]) + + ", action taken was " + + str(action) + + ", env step " + + str(self.curr_step) + ) + # If we run out of power, end the episode. + elif self.obs_full[11] == 0: + self.failure = True + self.episode_over = True + print( + "Ran out of power. Battery level at: " + + str(self.obs_full[11]) + + ", env step " + + str(self.curr_step) + + ", action taken was " + + str(action) + ) + # If we overflow the buffer, end the episode. + elif self.obs_full[13] >= self.simulator.storageUnit.storageCapacity: + self.failure = True + self.episode_over = True + print( + "Data buffer overflow. Data storage level at:" + + str(self.obs_full[13]) + + ", env step, " + + str(self.curr_step) + + ", action taken was " + + str(action) + ) + elif self.sim_over: + self.episode_over = True + print("Orbit decayed - no penalty, but this one is over.") + else: + self.failure = False + + reward = self._get_reward(downlinked, imaged) + self.reward_total += reward + + # Otherwise, return nothing + else: + ob = [] + reward = 0 + + num_imaged, num_downlinked = self._get_imaged_downlinked() + + # Update the info with the metrics + info["metrics"] = { + "downlinked": self.simulator.total_downlinked, + "sim_length": self.simulator.simTime / 60, + "total_access": self.simulator.total_access, + "utilized_access": self.simulator.utilized_access, + "num_imaged": num_imaged, + "num_downlinked": num_downlinked, + } + + self.act_hold = action + + self.curr_step += 1 + return ob.flatten(), reward, self.episode_over, False, info
+ + + def _take_action(self, action): + """ + Interfaces with the simulator to + :param action: + :return: + """ + + self.action_episode_memory[self.curr_episode].append(action) + ( + self.obs, + self.sim_over, + self.obs_full, + downlinked, + imaged, + info, + ) = self.simulator.run_sim(action, self.return_obs) + + return downlinked, imaged, info + + def _get_reward(self, downlinked, imaged): + """ + Reward is based on the total number of imaged and downlinked targets, failure i + f it occurs + """ + reward = 0 + if self.failure: + reward = -self.failure_penalty + else: + for idx in downlinked: + reward += ( + self.downlink_component + / float( + self.simulator.initial_conditions.get("targetPriorities")[idx] + ) + / self.max_steps + ) + for idx in imaged: + reward += ( + self.image_component + / float( + self.simulator.initial_conditions.get("targetPriorities")[idx] + ) + / self.max_steps + ) + + return reward + +
+[docs] + def reset(self, seed=None, options=None): + """ + Reset the state of the environment and returns an initial observation. + Returns + ------- + observation (object): the initial observation of the space. + """ + super().reset(seed=seed) + self.action_episode_memory.append([]) + self.episode_over = False + self.failure = False + self.curr_step = 0 + self.reward_total = 0 + + if self.simulator is not None: + del self.simulator + + if options is not None: + if "initial_conditions" in options: + self.initial_conditions = options["initial_conditions"] + + # Create the simulator + self.simulator = AgileEOSSimulator( + self.dynRate, + self.fswRate, + self.step_duration, + initial_conditions=self.initial_conditions, + render=self.render, + n_targets=self.n_targets, + max_length=self.max_length, + target_tuple_size=self.target_tuple_size, + ) + + # Extract initial conditions from instantiation of simulator + self.initial_conditions = self.simulator.initial_conditions + self.simulator.max_steps = self.max_steps + self.simulator_init = 1 + + return self.simulator.obs.flatten(), self.simulator.info
+ + + def _render(self, mode="human", close=False): + return + + def _get_state(self): + """Return the non-normalized observation to the environment""" + + return self.simulator.obs + + def _get_imaged_downlinked(self): + num_imaged = 0 + num_downlinked = 0 + for idx in range(len(self.simulator.imaged_targets)): + if self.simulator.imaged_targets[idx] >= 1.0: + num_imaged += 1 + + if self.simulator.downlinked_targets[idx] >= 1.0: + num_downlinked += 1 + + return num_imaged, num_downlinked + + def update_tgt_count(self, n_targets): + self.n_targets = n_targets + self.action_space = spaces.Discrete(3 + self.n_targets) + low = -1e16 + high = 1e16 + self.observation_space = spaces.Box( + low, high, shape=(22 + self.n_targets * self.target_tuple_size,) + ) + self.obs = np.zeros(22 + self.n_targets * self.target_tuple_size) + self.obs_full = np.zeros(22 + self.n_targets * self.target_tuple_size)
+ + + +if __name__ == "__main__": + env = gym.make("AgileEOS-v0") + + env.reset() + + reward_sum = 0 + for idx in range(0, env.max_steps): + action = env.action_space.sample() + ob, reward, episode_over, truncated, info = env.step(action) + reward_sum += reward + + if episode_over: + print("Episode over at step " + str(idx)) + break + + print("Reward total: " + str(reward_sum)) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/gym_env.html b/_modules/bsk_rl/envs/general_satellite_tasking/gym_env.html new file mode 100644 index 00000000..49c5be2b --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/gym_env.html @@ -0,0 +1,710 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.gym_env

+"""General Satellite Tasking is a framework for satellite tasking RL environments."""
+
+import functools
+import logging
+import os
+from copy import deepcopy
+from time import time_ns
+from typing import Any, Generic, Iterable, Optional, TypeVar, Union
+
+import numpy as np
+from gymnasium import Env, spaces
+from pettingzoo.utils.env import AgentID, ParallelEnv
+
+from bsk_rl.envs.general_satellite_tasking.scenario.communication import NoCommunication
+from bsk_rl.envs.general_satellite_tasking.simulation.simulator import Simulator
+from bsk_rl.envs.general_satellite_tasking.types import (
+    CommunicationMethod,
+    DataManager,
+    EnvironmentFeatures,
+    EnvironmentModel,
+    Satellite,
+)
+from bsk_rl.envs.general_satellite_tasking.utils import logging_config
+
+logger = logging.getLogger(__name__)
+
+
+SatObs = TypeVar("SatObs")
+SatAct = TypeVar("SatAct")
+MultiSatObs = tuple[SatObs, ...]
+MultiSatAct = Iterable[SatAct]
+
+
+
+[docs] +class GeneralSatelliteTasking(Env, Generic[SatObs, SatAct]): + """A Gymnasium environment adaptable to a wide range satellite tasking problems. + + These problems involve satellite(s) being tasked to complete tasks and maintain + aliveness. These tasks often include rewards for data collection. The environment + can be configured for any collection of satellites, including heterogenous + constellations. Other configurable aspects are environment features (e.g. + imaging targets), data collection and recording, and intersatellite + communication of data. + + The state space is a tuple containing the state of each satellite. Actions are + assigned as a tuple of actions, one per satellite. + + The preferred method of instantiating this environment is to make the + "GeneralSatelliteTasking-v1" environment and pass a kwargs dict with the + environment configuration. In some cases (e.g. the multiprocessed Gymnasium + vector environment), it is necessary for compatibility to instead register a new + environment using the GeneralSatelliteTasking class and a kwargs dict. See + examples/general_satellite_tasking for examples of environment configuration. + + New environments should be built using this framework. + """ + +
+[docs] + def __init__( + self, + satellites: Union[Satellite, list[Satellite]], + env_type: type[EnvironmentModel], + env_features: EnvironmentFeatures, + data_manager: DataManager, + env_args: Optional[dict[str, Any]] = None, + communicator: Optional[CommunicationMethod] = None, + sim_rate: float = 1.0, + max_step_duration: float = 600.0, + failure_penalty: float = -100, + time_limit: float = float("inf"), + terminate_on_time_limit: bool = False, + log_level: Union[int, str] = logging.WARNING, + log_dir: Optional[str] = None, + render_mode=None, + ) -> None: + """Construct the GeneralSatelliteTasking environment. + + Args: + satellites: Satellites(s) to be simulated. + env_type: Type of environment model to be constructed. + env_args: Arguments for environment model construction. {key: value or key: + function}, where function is called at reset to set the value (used for + randomization). + env_features: Information about the environment. + data_manager: Object to record and reward data collection. + communicator: Object to manage communication between satellites + sim_rate: Rate for model simulation [s]. + max_step_duration: Maximum time to propagate sim at a step [s]. + failure_penalty: Reward for satellite failure. Should be nonpositive. + time_limit: Time at which to truncate the simulation [s]. + terminate_on_time_limit: Send terminations signal time_limit instead of just + truncation. + log_level: Logging level for the environment. Default is WARNING. + log_dir: Directory to write logs to in addition to the console. + render_mode: Unused. + """ + self.seed = None + self._configure_logging(log_level, log_dir) + if isinstance(satellites, Satellite): + satellites = [satellites] + self.satellites = satellites + self.simulator: Simulator + self.env_type = env_type + if env_args is None: + env_args = self.env_type.default_env_args() + self.env_args_generator = self.env_type.default_env_args(**env_args) + self.env_features = env_features + self.data_manager = data_manager + if self.data_manager.env_features is None: + self.data_manager.env_features = self.env_features + + if communicator is None: + communicator = NoCommunication() + self.communicator = communicator + if self.communicator.satellites is None: + self.communicator.satellites = self.satellites + + self.sim_rate = sim_rate + self.max_step_duration = max_step_duration + self.failure_penalty = failure_penalty + self.time_limit = time_limit + self.terminate_on_time_limit = terminate_on_time_limit + self.latest_step_duration = 0 + self.render_mode = render_mode
+ + + def _configure_logging(self, log_level, log_dir=None): + if isinstance(log_level, str): + log_level = log_level.upper() + logger = logging.getLogger("bsk_rl.envs.general_satellite_tasking") + logger.setLevel(log_level) + + # Ensure each process has its own logger to avoid conflicts when printing + # sim timestamps. Running multiple environments in the same process in + # parallel will cause logging times to be incorrectly reported. + warn_new_env = False + for handler in logger.handlers: + if handler.filters[0].proc_id == os.getpid(): + logger.handlers.remove(handler) + warn_new_env = True + + ch = logging.StreamHandler() + ch.setFormatter(logging_config.SimFormatter(color_output=True)) + ch.addFilter(logging_config.ContextFilter(env=self, proc_id=os.getpid())) + logger.addHandler(ch) + if warn_new_env: + logger.warning( + f"Creating logger for new env on PID={os.getpid()}. " + "Old environments in process may now log times incorrectly." + ) + + if log_dir is not None: + fh = logging.FileHandler(log_dir) + fh.setFormatter(logging_config.SimFormatter(color_output=False)) + fh.addFilter(logging_config.ContextFilter(env=self, proc_id=os.getpid())) + logger.addHandler(fh) + + def _generate_env_args(self) -> None: + """Instantiate env_args from any randomizers in provided env_args.""" + self.env_args = { + k: v if not callable(v) else v() for k, v in self.env_args_generator.items() + } + +
+[docs] + def reset( + self, + seed: Optional[int] = None, + options=None, + ) -> tuple[MultiSatObs, dict[str, Any]]: + """Reconstruct the simulator and wipe data records. + + Args: + seed: Gymnasium environment seed. + options: Unused. + + Returns: + observation, info + """ + # Explicitly delete the Basilisk simulation before creating a new one. + self.delete_simulator() + + if seed is None: + seed = time_ns() % 2**32 + logger.info(f"Resetting environment with seed={seed}") + self.seed = seed + super().reset(seed=self.seed) + np.random.seed(self.seed) + self._generate_env_args() + + self.env_features.reset() + self.data_manager.reset() + + for satellite in self.satellites: + self.data_manager.create_data_store(satellite) + satellite.sat_args_generator["utc_init"] = self.env_args["utc_init"] + satellite.reset_pre_sim() + + self.simulator = Simulator( + self.satellites, + self.env_type, + self.env_args, + sim_rate=self.sim_rate, + max_step_duration=self.max_step_duration, + time_limit=self.time_limit, + ) + + self.communicator.reset() + + for satellite in self.satellites: + satellite.reset_post_sim() + satellite.data_store.internal_update() + + observation = self._get_obs() + info = self._get_info() + logger.info("Environment reset") + return observation, info
+ + +
+[docs] + def delete_simulator(self): + """Delete Basilisk objects. + + Only self.simulator contains strong references to BSK models, so deleting it + will delete all Basilisk objects. Enable debug-level logging to verify that the + simulator, FSW, dynamics, and environment models are all deleted on reset. + """ + try: + del self.simulator + except AttributeError: + pass
+ + + def _get_obs(self) -> MultiSatObs: + """Compose satellite observations into a single observation. + + Returns: + tuple: Joint observation + """ + return tuple(satellite.get_obs() for satellite in self.satellites) + + def _get_info(self) -> dict[str, Any]: + """Compose satellite info into a single info dict. + + Returns: + tuple: Joint info + """ + info: 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 and satellite.is_alive() + ] + if len(info["requires_retasking"]) > 0: + logger.info(f"Satellites requiring retasking: {info['requires_retasking']}") + return info + + def _get_reward(self): + """Return a scalar reward for the step.""" + reward = sum(self.reward_dict.values()) + for satellite in self.satellites: + if not satellite.is_alive(log_failure=True): + reward += self.failure_penalty + return reward + + def _get_terminated(self) -> bool: + """Return the terminated flag for the step.""" + if self.terminate_on_time_limit and self._get_truncated(): + return True + else: + return not all(satellite.is_alive() for satellite in self.satellites) + + def _get_truncated(self) -> bool: + """Return the truncated flag for the step.""" + return self.simulator.sim_time >= self.time_limit + + @property + def action_space(self) -> spaces.Space[MultiSatAct]: + """Compose satellite action spaces. + + Returns: + Joint action space + """ + return spaces.Tuple((satellite.action_space for satellite in self.satellites)) + + @property + def observation_space(self) -> spaces.Space[MultiSatObs]: + """Compose satellite observation spaces. + + Note: calls reset(), which can be expensive, to determine observation size. + + Returns: + Joint observation space + """ + try: + self.simulator + except AttributeError: + logger.info("Calling env.reset() to get observation space") + self.reset(seed=self.seed) + return spaces.Tuple( + [satellite.observation_space for satellite in self.satellites] + ) + + def _step(self, actions: MultiSatAct) -> None: + logger.debug(f"Stepping environment with actions: {actions}") + 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): + satellite.info = [] # reset satellite info log + if action is not None: + satellite.requires_retasking = False + satellite.set_action(action) + else: + if satellite.requires_retasking: + logger.warning( + f"Satellite {satellite.id} requires retasking " + "but received no task." + ) + + previous_time = self.simulator.sim_time # should these be recorded in simulator + self.simulator.run() + self.latest_step_duration = self.simulator.sim_time - previous_time + + new_data = { + satellite.id: satellite.data_store.internal_update() + for satellite in self.satellites + } + self.reward_dict = self.data_manager.reward(new_data) + + self.communicator.communicate() + +
+[docs] + def step( + self, actions: MultiSatAct + ) -> tuple[MultiSatObs, float, bool, bool, dict[str, Any]]: + """Propagate the simulation, update information, and get rewards. + + Args: + actions: Joint action for satellites + + Returns: + observation, reward, terminated, truncated, info + """ + logger.info("=== STARTING STEP ===") + self._step(actions) + + observation = self._get_obs() + reward = self._get_reward() + terminated = self._get_terminated() + truncated = self._get_truncated() + info = self._get_info() + logger.info(f"Step reward: {reward}") + logger.info(f"Episode terminated: {terminated}") + logger.info(f"Episode truncated: {truncated}") + logger.debug(f"Step info: {info}") + logger.debug(f"Step observation: {observation}") + return observation, reward, terminated, truncated, info
+ + +
+[docs] + def render(self) -> None: # pragma: no cover + """No rendering implemented.""" + return None
+ + +
+[docs] + def close(self) -> None: + """Try to cleanly delete everything.""" + if self.simulator is not None: + del self.simulator
+
+ + + +
+[docs] +class SingleSatelliteTasking(GeneralSatelliteTasking, Generic[SatObs, SatAct]): + """A special case of the GeneralSatelliteTasking for one satellite. + + For compatibility with standard training APIs, actions and observations are directly + exposed for the single satellite and are not wrapped in a tuple. + """ + +
+[docs] + def __init__(self, *args, **kwargs) -> None: + """Construct the SingleSatelliteTasking environment.""" + super().__init__(*args, **kwargs) + if not len(self.satellites) == 1: + raise ValueError( + "SingleSatelliteTasking must be initialized with a single satellite." + )
+ + + @property + def action_space(self) -> spaces.Space[SatAct]: + """Return the single satellite action space.""" + return self.satellite.action_space + + @property + def observation_space(self) -> spaces.Box: + """Return the single satellite observation space.""" + super().observation_space + return self.satellite.observation_space + + @property + def satellite(self) -> Satellite: + """Satellite being tasked.""" + return self.satellites[0] + +
+[docs] + def step(self, action) -> tuple[Any, float, bool, bool, dict[str, Any]]: + """Task the satellite with a single action.""" + return super().step([action])
+ + + def _get_obs(self) -> Any: + return self.satellite.get_obs()
+ + + +
+[docs] +class MultiagentSatelliteTasking( + GeneralSatelliteTasking, ParallelEnv, Generic[SatObs, SatAct, AgentID] +): + """Implements the environment with the PettingZoo parallel API.""" + +
+[docs] + def reset( + self, seed: int | None = None, options=None + ) -> tuple[MultiSatObs, dict[str, Any]]: + """Reset the environment and return PettingZoo Parallel API format.""" + self.newly_dead = [] + return super().reset(seed, options)
+ + + @property + def agents(self) -> list[AgentID]: + """Agents currently in the environment.""" + truncated = super()._get_truncated() + return [ + satellite.id + for satellite in self.satellites + if (satellite.is_alive() and not truncated) + ] + + @property + def num_agents(self) -> int: + """Number of agents currently in the environment.""" + return len(self.agents) + + @property + def possible_agents(self) -> list[AgentID]: + """Return the list of all possible agents.""" + return [satellite.id for satellite in self.satellites] + + @property + def max_num_agents(self) -> int: + """Maximum number of agents possible in the environment.""" + return len(self.possible_agents) + + @property + def previously_dead(self) -> list[AgentID]: + """Return the list of agents that died at least one step ago.""" + return list(set(self.possible_agents) - set(self.agents) - set(self.newly_dead)) + + @property + def observation_spaces(self) -> dict[AgentID, spaces.Box]: + """Return the observation space for each agent.""" + return { + agent: obs_space + for agent, obs_space in zip(self.possible_agents, super().observation_space) + } + +
+[docs] + @functools.lru_cache(maxsize=None) + def observation_space(self, agent: AgentID) -> spaces.Space[SatObs]: + """Return the observation space for a certain agent.""" + return self.observation_spaces[agent]
+ + + @property + def action_spaces(self) -> dict[AgentID, spaces.Space[SatAct]]: + """Return the action space for each agent.""" + return { + agent: act_space + for agent, act_space in zip(self.possible_agents, super().action_space) + } + +
+[docs] + @functools.lru_cache(maxsize=None) + def action_space(self, agent: AgentID) -> spaces.Space[SatAct]: + """Return the action space for a certain agent.""" + return self.action_spaces[agent]
+ + + def _get_obs(self) -> dict[AgentID, SatObs]: + """Format the observation per the PettingZoo Parallel API.""" + return { + agent: satellite.get_obs() + for agent, satellite in zip(self.possible_agents, self.satellites) + if agent not in self.previously_dead + } + + def _get_reward(self) -> dict[AgentID, float]: + """Format the reward per the PettingZoo Parallel API.""" + reward = deepcopy(self.reward_dict) + for agent, satellite in zip(self.possible_agents, self.satellites): + if not satellite.is_alive(): + reward[agent] += self.failure_penalty + + reward_keys = list(reward.keys()) + for agent in reward_keys: + if agent in self.previously_dead: + del reward[agent] + + return reward + + def _get_terminated(self) -> dict[AgentID, bool]: + """Format terminations per the PettingZoo Parallel API.""" + if self.terminate_on_time_limit and super()._get_truncated(): + return { + agent: True + for agent in self.possible_agents + if agent not in self.previously_dead + } + else: + return { + agent: not satellite.is_alive() + for agent, satellite in zip(self.possible_agents, self.satellites) + if agent not in self.previously_dead + } + + def _get_truncated(self) -> dict[AgentID, bool]: + """Format truncations per the PettingZoo Parallel API.""" + truncated = super()._get_truncated() + return { + agent: truncated + for agent in self.possible_agents + if agent not in self.previously_dead + } + + def _get_info(self) -> dict[AgentID, dict]: + """Format info per the PettingZoo Parallel API.""" + info = super()._get_info() + for agent in self.possible_agents: + if agent in self.previously_dead: + del info[agent] + return info + +
+[docs] + def step( + self, + actions: dict[AgentID, SatAct], + ) -> tuple[ + dict[AgentID, SatObs], + dict[AgentID, float], + dict[AgentID, bool], + dict[AgentID, bool], + dict[AgentID, dict], + ]: + """Step the environment and return PettingZoo Parallel API format.""" + logger.info("=== STARTING STEP ===") + + previous_alive = self.agents + + action_vector = [] + for agent in self.possible_agents: + if agent in actions.keys(): + action_vector.append(actions[agent]) + else: + action_vector.append(None) + self._step(action_vector) + + self.newly_dead = list(set(previous_alive) - set(self.agents)) + + observation = self._get_obs() + reward = self._get_reward() + terminated = self._get_terminated() + truncated = self._get_truncated() + info = self._get_info() + logger.info(f"Step reward: {reward}") + logger.info(f"Episode terminated: {terminated}") + logger.info(f"Episode truncated: {truncated}") + logger.debug(f"Step info: {info}") + logger.debug(f"Step observation: {observation}") + return observation, reward, terminated, truncated, info
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/scenario/communication.html b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/communication.html new file mode 100644 index 00000000..df1301c0 --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/communication.html @@ -0,0 +1,286 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.scenario.communication — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.scenario.communication

+"""Communication of data between satellites."""
+
+import logging
+from abc import ABC, abstractmethod
+from itertools import combinations
+from typing import TYPE_CHECKING, Optional
+
+if TYPE_CHECKING:  # pragma: no cover
+    from bsk_rl.envs.general_satellite_tasking.types import Satellite
+
+import numpy as np
+from scipy.sparse.csgraph import connected_components
+
+from bsk_rl.envs.general_satellite_tasking.simulation.dynamics import LOSCommDynModel
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +class CommunicationMethod(ABC): + """Base class for defining data sharing between satellites.""" + +
+[docs] + def __init__(self, satellites: Optional[list["Satellite"]] = None) -> None: + """Construct base communication class. + + Subclasses implement a way of determining which pairs of satellites share data. + """ + self.satellites = satellites
+ + +
+[docs] + def reset(self) -> None: + """Reset communication after simulator initialization.""" + pass
+ + + @abstractmethod # pragma: no cover + def _communication_pairs(self) -> list[tuple["Satellite", "Satellite"]]: + """List pair of satellite that should share data.""" + pass + +
+[docs] + def communicate(self) -> None: + """Share data between paired satellites.""" + for sat_1, sat_2 in self._communication_pairs(): + sat_1.data_store.stage_communicated_data(sat_2.data_store.data) + sat_2.data_store.stage_communicated_data(sat_1.data_store.data) + for satellite in self.satellites: + satellite.data_store.communication_update()
+
+ + + +
+[docs] +class NoCommunication(CommunicationMethod): + """Implements no communication between satellite.""" + + def _communication_pairs(self) -> list[tuple["Satellite", "Satellite"]]: + return []
+ + + +
+[docs] +class FreeCommunication(CommunicationMethod): + """Implements communication between satellites at every step.""" + + def _communication_pairs(self) -> list[tuple["Satellite", "Satellite"]]: + return list(combinations(self.satellites, 2))
+ + + +
+[docs] +class LOSCommunication(CommunicationMethod): + """Implements communication between satellites with a direct line-of-sight. + + # TODO only communicate data from before latest LOS time + """ + +
+[docs] + def __init__(self, satellites: list["Satellite"]) -> None: + """Construct line-of-sigh communication management. + + Args: + satellites: List of satellites to communicate between. + """ + super().__init__(satellites) + for satellite in self.satellites: + if not issubclass(satellite.dyn_type, LOSCommDynModel): + raise TypeError( + f"Satellite dynamics type {satellite.dyn_type} must be a subclass " + + "of LOSCommDynModel to use LOSCommunication" + )
+ + +
+[docs] + def reset(self) -> None: + """Add loggers to satellites to track line-of-sight communication.""" + super().reset() + + self.los_logs = {} + for sat_1 in self.satellites: + assert isinstance(sat_1.dynamics, LOSCommDynModel) + for sat_2 in self.satellites: + if sat_1 is not sat_2: + if sat_1 not in self.los_logs: + self.los_logs[sat_1] = {} + + msg_index = sat_1.dynamics.los_comms_ids.index(sat_2.id) + logger = self.los_logs[sat_1][ + sat_2 + ] = sat_1.dynamics.losComms.accessOutMsgs[msg_index].recorder() + + sat_1.simulator.AddModelToTask( + sat_1.dynamics.task_name, logger, ModelPriority=586 + )
+ + + def _communication_pairs(self) -> list[tuple["Satellite", "Satellite"]]: + pairs = [] + for sat_1, logs in self.los_logs.items(): + for sat_2, logger in logs.items(): + if any(logger.hasAccess): + pairs.append((sat_1, sat_2)) + return pairs + +
+[docs] + def communicate(self) -> None: + """Clear line-of-sight communication logs once communicated.""" + super().communicate() + for sat_1, logs in self.los_logs.items(): + for sat_2, logger in logs.items(): + logger.clear()
+
+ + + +
+[docs] +class MultiDegreeCommunication(CommunicationMethod): + """Compose with another type to use multi-degree communications. + + For example, if a <-> b and b <-> c, multidegree communication will also communicate + between a <-> c. + """ + + def _communication_pairs(self) -> list[tuple["Satellite", "Satellite"]]: + graph = np.zeros((len(self.satellites), len(self.satellites)), dtype=bool) + for sat_1, sat_2 in super()._communication_pairs(): + graph[self.satellites.index(sat_1), self.satellites.index(sat_2)] = True + + pairs = [] + n_components, labels = connected_components(graph, directed=False) + for comp in range(n_components): + for i_sat_1, i_sat_2 in combinations(np.where(labels == comp)[0], 2): + pairs.append((self.satellites[i_sat_1], self.satellites[i_sat_2])) + return pairs
+ + + +
+[docs] +class LOSMultiCommunication(MultiDegreeCommunication, LOSCommunication): + """Multidegree line of sight communication. + + Composes MultiDegreeCommunication with LOSCommunication. + """ + + pass
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/scenario/data.html b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/data.html new file mode 100644 index 00000000..2c4715b7 --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/data.html @@ -0,0 +1,705 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.scenario.data — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.scenario.data

+"""Data logging, management, and reward calculation."""
+
+import logging
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING, Any, Callable, Optional
+
+if TYPE_CHECKING:  # pragma: no cover
+    from bsk_rl.envs.general_satellite_tasking.scenario.environment_features import (
+        Target,
+    )
+    from bsk_rl.envs.general_satellite_tasking.types import (
+        EnvironmentFeatures,
+        Satellite,
+    )
+
+import numpy as np
+
+logger = logging.getLogger(__name__)
+
+LogStateType = Any
+
+
+
+[docs] +class DataType(ABC): + """Base class for units of satellite data.""" + + @abstractmethod # pragma: no cover + def __add__(self, other: "DataType") -> "DataType": + """Define the combination of two units of data.""" + pass
+ + + +
+[docs] +class DataStore(ABC): + """Base class for satellite data logging. + + One DataStore is created per satellite. + """ + + DataType: type[DataType] # Define the unit of data used by the DataStore + +
+[docs] + def __init__(self, data_manager: "DataManager", satellite: "Satellite") -> None: + """Construct a DataStore base class. + + Args: + data_manager: Simulation data manager to report back to + satellite: Satellite's data being stored + """ + self.satellite = satellite + self.is_fresh = True + self.staged_data = [] + + self._initialize_knowledge(data_manager.env_features) + self.data = self.DataType() + self.new_data = self.DataType()
+ + + def _initialize_knowledge(self, env_features: "EnvironmentFeatures") -> None: + """Establish knowledge about the world known to the satellite. + + Defaults to knowing everything about the environment. + """ + self.env_knowledge = env_features + + def _clear_logs(self) -> None: + """If necessary, clear any loggers.""" + pass + + def _get_log_state(self) -> LogStateType: + """Pull information for current data contribution e.g. sensor readings.""" + pass + + @abstractmethod # pragma: no cover + def _compare_log_states( + self, old_state: LogStateType, new_state: LogStateType + ) -> "DataType": + """Generate a unit of data based on previous step and current step logs. + + Args: + old_state: A previous result of _get_log_state() + new_state: A newer result of _get_log_state() + + Returns: + DataType: Data generated + """ + pass + +
+[docs] + def internal_update(self) -> "DataType": + """Update the data store based on collected information. + + Returns: + New data from the previous step + """ + if not hasattr(self, "log_state"): + self.log_state = self._get_log_state() + self._clear_logs() + return self.DataType() + old_log_state = self.log_state + self.log_state = self._get_log_state() + self._clear_logs() + new_data = self._compare_log_states(old_log_state, self.log_state) + self.data += new_data + self.new_data = new_data + return new_data
+ + +
+[docs] + def stage_communicated_data(self, external_data: "DataType") -> None: + """Prepare data to be added from another source, but don't add it yet. + + Args: + external_data: Data from another satellite to be added + """ + self.staged_data.append(external_data)
+ + +
+[docs] + def communication_update(self) -> None: + """Update the data store from staged data. + + Args: + external_data (DataType): Data collected by another satellite + """ + for staged in self.staged_data: + self.data += staged + self.staged_data = []
+
+ + + +
+[docs] +class DataManager(ABC): + """Base class for simulation-wide data management.""" + + DataStore: type[DataStore] # type of DataStore managed by the DataManager + +
+[docs] + def __init__(self, env_features: Optional["EnvironmentFeatures"] = None) -> None: + """Construct base class to handle data recording and rewarding. + + TODO: allow for creation/composition of multiple managers. + + Args: + env_features: Information about the environment that can be collected as + data + """ + self.env_features = env_features + self.DataType = self.DataStore.DataType
+ + +
+[docs] + def reset(self) -> None: + """Refresh data and cumulative reward for a new episode.""" + self.data = self.DataType() + self.cum_reward = {}
+ + +
+[docs] + def create_data_store(self, satellite: "Satellite") -> None: + """Create a data store for a satellite.""" + satellite.data_store = self.DataStore(self, satellite) + self.cum_reward[satellite.id] = 0.0
+ + + @abstractmethod # pragma: no cover + def _calc_reward(self, new_data_dict: dict[str, DataType]) -> dict[str, float]: + """Calculate step reward based on all satellite data from a step. + + Args: + new_data_dict: Satellite-DataType pairs of new data from a step + + Returns: + Step reward for each satellite + """ + pass + +
+[docs] + def reward(self, new_data_dict: dict[str, DataType]) -> dict[str, float]: + """Call _calc_reward and log cumulative reward.""" + reward = self._calc_reward(new_data_dict) + for satellite_id, sat_reward in reward.items(): + self.cum_reward[satellite_id] += sat_reward + logger.info(f"Data reward: {reward}") + return reward
+
+ + + +########### +# No Data # +########### +
+[docs] +class NoData(DataType): + """DataType for no data.""" + + def __add__(self, other): + """Add nothing to nothing.""" + return self.__class__()
+ + + +
+[docs] +class NoDataStore(DataStore): + """DataStore for no data.""" + + DataType = NoData + + def _compare_log_states(self, old_state, new_state): + return self.DataType()
+ + + +
+[docs] +class NoDataManager(DataManager): + """DataManager for no data.""" + + DataStore = NoDataStore + + def _calc_reward(self, new_data_dict): + """Reward nothing.""" + return {sat: 0.0 for sat in new_data_dict.keys()}
+ + + +####################################### +# Unique Targets with Constant Values # +####################################### + + +
+[docs] +class UniqueImageData(DataType): + """DataType for unique images of targets.""" + +
+[docs] + def __init__( + self, imaged: Optional[list["Target"]] = None, duplicates: int = 0 + ) -> None: + """Construct unit of data to record unique images. + + Args: + imaged: List of targets that are known to be imaged. + duplicates: Count of target imaging duplication. + """ + if imaged is None: + imaged = [] + + self.imaged = list(set(imaged)) + self.duplicates = duplicates + len(imaged) - len(self.imaged)
+ + + def __add__(self, other: "UniqueImageData") -> "UniqueImageData": + """Combine two units of data. + + Args: + other: Another unit of data to combine with this one. + + Returns: + Combined unit of data. + """ + imaged = list(set(self.imaged + other.imaged)) + duplicates = ( + self.duplicates + + other.duplicates + + len(self.imaged) + + len(other.imaged) + - len(imaged) + ) + return self.__class__(imaged=imaged, duplicates=duplicates)
+ + + +
+[docs] +class UniqueImageStore(DataStore): + """DataStore for unique images of targets.""" + + DataType = UniqueImageData + + def _get_log_state(self) -> np.ndarray: + """Log the instantaneous storage unit state at the end of each step. + + Returns: + array: storedData from satellite storage unit + """ + return np.array( + self.satellite.dynamics.storageUnit.storageUnitDataOutMsg.read().storedData + ) + + def _compare_log_states( + self, old_state: np.ndarray, new_state: np.ndarray + ) -> UniqueImageData: + """Check for an increase in logged data to identify new images. + + Args: + old_state: older storedData from satellite storage unit + new_state: newer storedData from satellite storage unit + + Returns: + list: Targets imaged at new_state that were unimaged at old_state + """ + update_idx = np.where(new_state - old_state > 0)[0] + imaged = [] + for idx in update_idx: + message = self.satellite.dynamics.storageUnit.storageUnitDataOutMsg + target_id = message.read().storedDataName[int(idx)] + imaged.append( + [ + target + for target in self.env_knowledge.targets + if target.id == target_id + ][0] + ) + return UniqueImageData(imaged=imaged)
+ + + +
+[docs] +class UniqueImagingManager(DataManager): + """DataManager for rewarding unique images.""" + + DataStore = UniqueImageStore + +
+[docs] + def __init__( + self, + env_features: Optional["EnvironmentFeatures"] = None, + reward_fn: Callable = lambda p: p, + ) -> None: + """DataManager for rewarding unique images. + + Args: + env_features: DataManager.env_features + reward_fn: Reward as function of priority. + """ + super().__init__(env_features) + self.reward_fn = reward_fn
+ + + def _calc_reward( + self, new_data_dict: dict[str, UniqueImageData] + ) -> dict[str, float]: + """Reward new each unique image once using self.reward_fn(). + + Args: + new_data_dict: Record of new images for each satellite + + Returns: + reward: Cumulative reward across satellites for one step + """ + reward = {} + imaged_targets = sum( + [new_data.imaged for new_data in new_data_dict.values()], [] + ) + for sat_id, new_data in new_data_dict.items(): + reward[sat_id] = 0.0 + for target in new_data.imaged: + if target not in self.data.imaged: + reward[sat_id] += self.reward_fn( + target.priority + ) / imaged_targets.count(target) + + for new_data in new_data_dict.values(): + self.data += new_data + return reward
+ + + +"""Targets with Time-Dependent Rewards""" + + +# class TimeDepImageData(DataType): +# def __init__(self, rewards=None) -> None: +# """DataType to log scalar imaging + +# Args: +# imaged (dict, optional): Reward obtained from each target. +# """ +# if rewards is None: +# rewards = {} +# self.rewards = rewards + +# def __add__(self, other) -> "TimeDepImageData": +# rewards = copy(self.rewards) +# for target, reward in other.rewards.items(): +# if target in rewards: +# rewards[target] = max(rewards[target], reward) +# else: +# rewards[target] = reward +# return self.__class__(rewards=rewards) + + +# class TimeDepImageStore(DataStore): +# DataType = TimeDepImageData + +# def _get_log_state(self) -> Iterable[float]: +# """Log the instaneous storage unit state at the end of each step + +# Returns: +# array: storedData from satellite storage unit +# """ +# return np.array( +# self.satellite.dynamics.storageUnit.storageUnitDataOutMsg.read().storedData +# ) + +# def _compare_log_states(self, old_state, new_state) -> TimeDepImageData: +# """Checks two storage unit logs for an increase in logged data to identify new +# images + +# Args: +# old_state (array): older storedData from satellite storage unit +# new_state (array): newer storedData from satellite storage unit + +# Returns: +# list: Targets imaged at new_state that were unimaged at old_state +# """ +# update_idx = np.where(new_state - old_state > 0)[0] +# imaged = [] +# for idx in update_idx: +# message = self.satellite.dynamics.storageUnit.storageUnitDataOutMsg +# target_id = message.read().storedDataName[int(idx)] +# imaged.append( +# [ +# target +# for target in self.env_knowledge.targets +# if target.id == target_id +# ][0] +# ) +# return self.DataType(imaged=imaged) + + +# class TimeDepImagingManager(DataManager): +# DataStore = TimeDepImageStore + +# # def __init__(self, env_features): +# # """DataManager for rewarding time-dependent images. Will only give marginal +# # reward for reimaging at higher value + +# # Args: +# # env_features (EnvironmentFeatures): DataManager.env_features +# # reward_fn (function, optional): Reward as function of priority. +# # """ +# # super().__init__(env_features) + +# def _calc_reward(self, new_data_dict): +# """Reward each image for additional reward from higher quality images + +# Args: +# new_data_dict (dict): Record of new images for each satellite + +# Returns: +# float: Cumulative new reward +# """ +# reward = 0.0 +# for new_data in new_data_dict.values(): +# for target, reward in new_data.rewards.items(): +# if target not in self.data.rewards: +# reward += reward +# elif reward > self.data.rewards[target]: +# reward += reward - self.data.rewards[target] +# self.data += new_data +# return reward + +################## +# Nadir Pointing # +################## + + +
+[docs] +class NadirScanningTimeData(DataType): + """DataType for time spent scanning nadir.""" + +
+[docs] + def __init__(self, scanning_time: float = 0.0) -> None: + """DataType to log data generated scanning nadir. + + Args: + scanning_time: Time spent scanning nadir + """ + self.scanning_time = scanning_time
+ + + def __add__(self, other: "NadirScanningTimeData") -> "NadirScanningTimeData": + """Define the combination of two units of data.""" + scanning_time = self.scanning_time + other.scanning_time + + return self.__class__(scanning_time)
+ + + +
+[docs] +class ScanningNadirTimeStore(DataStore): + """DataStore for time spent scanning nadir.""" + + DataType = NadirScanningTimeData + + def _get_log_state(self) -> LogStateType: + """Return the amount of data stored in the storage unit.""" + storage_unit = self.satellite.dynamics.storageUnit.storageUnitDataOutMsg.read() + stored_amount = storage_unit.storageLevel + + # return amount of data stored + return stored_amount + + def _compare_log_states( + self, old_state: float, new_state: float + ) -> "NadirScanningTimeData": + """Generate a unit of data based on change in stored data amount. + + Args: + old_state: Previous amount of data in the storage unit + new_state: Current amount of data in the storage unit + + Returns: + DataType: Data generated + """ + instrument_baudrate = self.satellite.dynamics.instrument.nodeBaudRate + + if new_state > old_state: + data_generated = (new_state - old_state) / instrument_baudrate + else: + data_generated = 0.0 + + return NadirScanningTimeData(data_generated)
+ + + +
+[docs] +class NadirScanningManager(DataManager): + """DataManager for rewarding time spent scanning nadir.""" + + DataStore = ScanningNadirTimeStore # type of DataStore managed by the DataManager + +
+[docs] + def __init__( + self, + env_features: Optional["EnvironmentFeatures"] = None, + reward_fn: Optional[Callable] = None, + ) -> None: + """Construct a data manager for nadir scanning. + + Args: + env_features: Information about the environment that can be collected as + data + reward_fn: Reward as function of time spend pointing nadir. + """ + super().__init__(env_features) + if reward_fn is None: + + def reward_fn(p): + # Reward as a function of time send pointing nadir (p) and value + # per second + return p * self.env_features.value_per_second + + self.reward_fn = reward_fn
+ + + def _calc_reward( + self, new_data_dict: dict[str, "NadirScanningTimeData"] + ) -> dict[str, float]: + """Calculate step reward based on all satellite data from a step. + + Args: + new_data_dict (dict): Satellite-DataType of new data from a step + + Returns: + Step reward + """ + reward = {} + for sat, scanning_time in new_data_dict.items(): + reward[sat] = self.reward_fn(scanning_time.scanning_time) + + return reward
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/scenario/environment_features.html b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/environment_features.html new file mode 100644 index 00000000..f808bb04 --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/environment_features.html @@ -0,0 +1,342 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.scenario.environment_features — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.scenario.environment_features

+"""Environment features define data available for satellites to collect."""
+
+import logging
+import os
+import sys
+from abc import ABC
+from typing import Callable, Iterable, Optional, Union
+
+import numpy as np
+import pandas as pd
+from Basilisk.utilities import orbitalMotion
+
+logger = logging.getLogger(__name__)
+
+
+
+[docs] +class EnvironmentFeatures(ABC): + """Base environment feature class.""" + +
+[docs] + def reset(self) -> None: # pragma: no cover + """Reset environment features.""" + pass
+
+ + + +
+[docs] +class Target: + """Ground target with associated value.""" + +
+[docs] + def __init__(self, name: str, location: Iterable[float], priority: float) -> None: + """Construct a Target. + + Args: + name: Identifier; does not need to be unique + location: PCPF location [m] + priority: Value metric. + """ + self.name = name + self.location = np.array(location) + self.priority = priority
+ + + @property + def id(self) -> str: + """Get unique human-readable identifier. + + Returns: + Unique human-readable identifier. + """ + try: + return self._id + except AttributeError: + self._id = f"{self.name}_{id(self)}" + return self._id + + def __hash__(self) -> int: + """Hash target by unique id.""" + return hash((self.id)) + + def __repr__(self) -> str: + """Get string representation of target. + + Use target.id for a unique string identifier. + + Returns: + Target string + """ + return f"Target({self.name})"
+ + + +
+[docs] +class StaticTargets(EnvironmentFeatures): + """Environment with targets distributed uniformly.""" + +
+[docs] + def __init__( + self, + n_targets: Union[int, tuple[int, int]], + priority_distribution: Optional[Callable] = None, + radius: float = orbitalMotion.REQ_EARTH * 1e3, + ) -> None: + """Construct an environment with evenly-distributed static targets. + + Args: + n_targets: Number (or range) of targets to generate + priority_distribution: Function for generating target priority. + radius: Radius to place targets from body center. + """ + self._n_targets = n_targets + if priority_distribution is None: + priority_distribution = lambda: np.random.rand() # noqa: E731 + self.priority_distribution = priority_distribution + self.radius = radius + self.targets = []
+ + +
+[docs] + def reset(self) -> None: + """Regenerate target set for new episode.""" + if isinstance(self._n_targets, int): + self.n_targets = self._n_targets + else: + self.n_targets = np.random.randint(self._n_targets[0], self._n_targets[1]) + logger.info(f"Generating {self.n_targets} targets") + self.regenerate_targets()
+ + +
+[docs] + def regenerate_targets(self) -> None: + """Regenerate targets uniformly.""" + self.targets = [] + for i in range(self.n_targets): + x = np.random.normal(size=3) + x *= self.radius / np.linalg.norm(x) + self.targets.append( + Target( + name=f"tgt-{i}", location=x, priority=self.priority_distribution() + ) + )
+
+ + + +
+[docs] +def lla2ecef(lat: float, long: float, radius: float): + """Project LLA to Earth Centered, Earth Fixed location. + + Args: + lat: [deg] + long: [deg] + radius: [any] + """ + lat = np.radians(lat) + long = np.radians(long) + return radius * np.array( + [np.cos(lat) * np.cos(long), np.cos(lat) * np.sin(long), np.sin(lat)] + )
+ + + +
+[docs] +class CityTargets(StaticTargets): + """Environment with targets distributed around population centers.""" + +
+[docs] + def __init__( + self, + n_targets: Union[int, tuple[int, int]], + n_select_from: int = sys.maxsize, + location_offset: float = 0, + priority_distribution: Optional[Callable] = None, + radius: float = orbitalMotion.REQ_EARTH * 1e3, + ) -> None: + """Construct environment with of static targets around population centers. + + Args: + n_targets: Number of targets to generate + n_select_from: Generate targets from the top n most populous. + location_offset: Offset targets randomly from the city center [m]. + priority_distribution: Function for generating target priority. + radius: Radius to place targets from body center. + """ + super().__init__(n_targets, priority_distribution, radius) + if n_select_from == "all": + n_select_from = sys.maxsize + self.n_select_from = n_select_from + self.location_offset = location_offset
+ + +
+[docs] + def regenerate_targets(self) -> None: + """Regenerate targets based on cities.""" + self.targets = [] + cities = pd.read_csv( + os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "simplemaps_worldcities", + "worldcities.csv", + ) + ) + if self.n_select_from > len(cities): + self.n_select_from = len(cities) + + for i in np.random.choice(self.n_select_from, self.n_targets, replace=False): + city = cities.iloc[i] + location = lla2ecef(city["lat"], city["lng"], self.radius) + offset = np.random.normal(size=3) + offset /= np.linalg.norm(offset) + offset *= self.location_offset + location += offset + location /= np.linalg.norm(location) + location *= self.radius + self.targets.append( + Target( + name=city["city"].replace("'", ""), + location=location, + priority=self.priority_distribution(), + ) + )
+
+ + + +
+[docs] +class UniformNadirFeature(EnvironmentFeatures): + """Defines a nadir target center at the center of the planet.""" + +
+[docs] + def __init__(self, value_per_second: float = 1.0) -> None: + """Construct uniform data over the surface of the planet. + + Args: + value_per_second: Amount of reward per second imaging nadir. + """ + self.name = "NadirFeature" + self.value_per_second = value_per_second
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/scenario/sat_actions.html b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/sat_actions.html new file mode 100644 index 00000000..17e99d9d --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/sat_actions.html @@ -0,0 +1,351 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.scenario.sat_actions — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.scenario.sat_actions

+"""Satellite action types can be used to add actions to the agents."""
+
+from copy import deepcopy
+from typing import Any, Optional, Union
+
+import numpy as np
+from gymnasium import spaces
+
+from bsk_rl.envs.general_satellite_tasking.scenario.environment_features import Target
+from bsk_rl.envs.general_satellite_tasking.scenario.satellites import (
+    ImagingSatellite,
+    Satellite,
+)
+from bsk_rl.envs.general_satellite_tasking.utils.functional import bind, configurable
+
+
+
+[docs] +class SatAction(Satellite): + """Base satellite subclass for composing actions.""" + + pass
+ + + +
+[docs] +class DiscreteSatAction(SatAction): + """Base satellite subclass for composing discrete actions.""" + +
+[docs] + def __init__(self, *args, **kwargs) -> None: + """Construct satellite with discrete actions. + + Actions are added to the satellite for each DiscreteSatAction subclass, and can + be accessed by index in order added. + """ + super().__init__(*args, **kwargs) + self.action_list = [] + self.action_map = {} + self.prev_action_key = None # Used to avoid retasking of BSK tasks
+ + +
+[docs] + def add_action( + self, act_fn, act_name: Optional[str] = None, n_actions: Optional[int] = None + ): + """Add an action to the action map. + + Args: + act_fn: Function to call when selecting action. Takes as a keyword + prev_action_key, used to avoid retasking of BSK models. Can accept an + integer argument. + act_name: String to refer to action. + n_actions: If not none, add action n_actions times, calling it with an + increasing integer argument for each subsequent action. + """ + if act_name is None: + act_name = act_fn.__name__ + + if n_actions is None: + self.action_map[f"{len(self.action_list)}"] = act_name + self.action_list.append(act_fn) + else: + self.action_map[ + f"{len(self.action_list)}-{len(self.action_list)+n_actions-1}" + ] = act_name + for i in range(n_actions): + act_i = self.generate_indexed_action(act_fn, i) + act_i.__name__ = f"act_{act_fn.__name__}_{i}" + self.action_list.append(bind(self, deepcopy(act_i)))
+ + +
+[docs] + def generate_indexed_action(self, act_fn, index: int): + """Create an indexed action function. + + Makes an indexed action function from an action function that takes an index + as an argument. + + Args: + act_fn: Action function to index. + index: Index to pass to act_fn. + """ + + def act_i(self, prev_action_key=None) -> Any: + return getattr(self, act_fn.__name__)( + index, prev_action_key=prev_action_key + ) + + return act_i
+ + +
+[docs] + def set_action(self, action: int): + """Call action function my index.""" + self._disable_timed_terminal_event() + self.prev_action_key = self.action_list[action]( + prev_action_key=self.prev_action_key + ) # Update prev action data to avoid retasking
+ + + @property + def action_space(self) -> spaces.Discrete: + """Infer action space.""" + return spaces.Discrete(len(self.action_list))
+ + + +
+[docs] +def fsw_action_gen(fsw_action: str, action_duration: float = 1e9) -> type: + """Generate an action class for a FSW @action. + + Args: + fsw_action: Function name of FSW action. + action_duration: Time to task action for. + + Returns: + Satellite action class with fsw_action action. + """ + + @configurable + class FSWAction(DiscreteSatAction): + def __init__( + self, *args, action_duration: float = action_duration, **kwargs + ) -> None: + """Discrete action to perform a fsw action. + + Typically this is includes a function decorated by @action. + + Args: + action_duration: Time to act when action selected. [s] + args: Passed through to satellite + kwargs: Passed through to satellite + + """ + super().__init__(*args, **kwargs) + setattr(self, fsw_action + "_duration", action_duration) + + def act(self, prev_action_key=None) -> str: + """Activate action. + + Returns: + action key + """ + duration = getattr(self, fsw_action + "_duration") + self.log_info(f"{fsw_action} tasked for {duration} seconds") + self._disable_timed_terminal_event() + self._update_timed_terminal_event( + self.simulator.sim_time + duration, info=f"for {fsw_action}" + ) + if prev_action_key != fsw_action: + getattr(self.fsw, fsw_action)() + return fsw_action + + act.__name__ = f"act_{fsw_action}" + + self.add_action( + bind(self, act), + act_name=fsw_action, + ) + + return FSWAction
+ + + +# Charges the satellite +ChargingAction = fsw_action_gen("action_charge") + +# Disables all actuators and control +DriftAction = fsw_action_gen("action_drift") + +# Points in a specified direction while firing desat thrusters and desaturating wheels +DesatAction = fsw_action_gen("action_desat") + +# Points nadir while downlinking data +DownlinkAction = fsw_action_gen("action_downlink") + + +
+[docs] +@configurable +class ImagingActions(DiscreteSatAction, ImagingSatellite): + """Satellite subclass to add upcoming target imaging to action space.""" + +
+[docs] + def __init__(self, *args, n_ahead_act=10, **kwargs) -> None: + """Discrete action to image upcoming targets. + + Args: + n_ahead_act: Number of actions to include in action space. + args: Passed through to satellite + kwargs: Passed through to satellite + """ + super().__init__(*args, **kwargs) + self.add_action(self.image, n_actions=n_ahead_act, act_name="image")
+ + +
+[docs] + def image(self, target: Union[int, Target, str], prev_action_key=None) -> str: + """Activate imaging action. + + Args: + target: Target, in terms of upcoming index, Target, or ID, + prev_action_key: Previous action key + + Returns: + Target ID + """ + if np.issubdtype(type(target), np.integer): + self.log_info(f"target index {target} tasked") + + target = self.parse_target_selection(target) + if target.id != prev_action_key: + self.task_target_for_imaging(target) + else: + self.enable_target_window(target) + + return target.id
+ + +
+[docs] + def set_action(self, action: Union[int, Target, str]): + """Allow the satellite to be tasked by Target or target id. + + Allows for additional tasking modes in addition to action index-based tasking. + """ + self._disable_image_event() + if isinstance(action, (Target, str)): + self.prev_action_key = self.image(action, self.prev_action_key) + else: + super().set_action(action)
+
+ + + +NadirImagingAction = fsw_action_gen("action_nadir_scan") +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/scenario/sat_observations.html b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/sat_observations.html new file mode 100644 index 00000000..7be93137 --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/sat_observations.html @@ -0,0 +1,539 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.scenario.sat_observations — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.scenario.sat_observations

+"""Satellite observation types can be used to add information to the observation."""
+
+from copy import deepcopy
+from typing import Any, Callable, Optional, Union
+
+import numpy as np
+from Basilisk.utilities import orbitalMotion
+
+from bsk_rl.envs.general_satellite_tasking.scenario.satellites import (
+    AccessSatellite,
+    ImagingSatellite,
+    Satellite,
+)
+from bsk_rl.envs.general_satellite_tasking.utils.functional import (
+    bind,
+    configurable,
+    vectorize_nested_dict,
+)
+
+
+
+[docs] +@configurable +class SatObservation(Satellite): + """Base satellite subclass for composing observations.""" + +
+[docs] + def __init__(self, *args, obs_type: type = np.ndarray, **kwargs) -> None: + """Satellite subclass for composing observations. + + Args: + obs_type: Datatype of satellite's returned observation + args: Passed through to satellite + kwargs: Passed through to satellite + """ + super().__init__(*args, **kwargs) + self.obs_type = obs_type + self.obs_fn_list = [] + self.obs_dict_cache = None + self.obs_cache_time = 0.0
+ + + @property + def obs_dict(self): + """Human-readable observation format. + + Cached so only computed once per timestep. + """ + if ( + self.obs_dict_cache is None + or self.simulator.sim_time != self.obs_cache_time + ): + self.obs_dict_cache = {obs.__name__: obs() for obs in self.obs_fn_list} + self.obs_cache_time = self.simulator.sim_time + return deepcopy(self.obs_dict_cache) + + @property + def obs_ndarray(self): + """Numpy vector observation format.""" + return vectorize_nested_dict(self.obs_dict) + + @property + def obs_list(self): + """List observation format.""" + return list(self.obs_ndarray) + +
+[docs] + def get_obs(self) -> Union[dict, np.ndarray, list]: + """Update the observation.""" + if self.obs_type is dict: + return self.obs_dict + elif self.obs_type is np.ndarray: + return self.obs_ndarray + elif self.obs_type is list: + return self.obs_list + else: + raise ValueError(f"Invalid observation type: {self.obs_type}")
+ + +
+[docs] + def add_to_observation(self, obs_element: Callable) -> None: + """Add a function to be called when constructing observations. + + Args: + obs_element: Callable to be observed + """ + self.obs_fn_list.append(obs_element)
+
+ + + +
+[docs] +@configurable +class NormdPropertyState(SatObservation): + """Satellite subclass to add satellites properties to the observation.""" + +
+[docs] + def __init__( + self, *args, obs_properties: list[dict[str, Any]] = [], **kwargs + ) -> None: + """Add a list of properties to the satellite observation. + + Args: + obs_properties: List of properties that can be found in fsw or dynamics that + are to be appended to the the observation. Properties are optionally + normalized by some factor. Specified in the form + + :code-block: python + + [dict(prop="prop_name", module="fsw"/"dynamics"/None, norm=1.0)] + + If module is not specified or None, the source of the property is + inferred. If norm is not specified, it is set to 1.0 (no normalization). + args: Passed through to satellite + kwargs: Passed through to satellite + """ + super().__init__(*args, **kwargs) + + for obs_prop in obs_properties: + self.add_prop_function(**obs_prop)
+ + +
+[docs] + def add_prop_function( + self, prop: str, module: Optional[str] = None, norm: float = 1.0 + ): + """Add a property to the observation. + + Args: + prop: Property to query + module: Module (dynamics or fsw) that holds the property. Can be inferred. + norm: Value to normalize property by. Defaults to 1.0. + """ + if module is not None: + + def prop_fn(self): + return np.array(getattr(getattr(self, module), prop)) / norm + + else: + + def prop_fn(self): + for module in ["dynamics", "fsw"]: + if hasattr(getattr(self, module), prop): + return np.array(getattr(getattr(self, module), prop)) / norm + else: + raise AttributeError(f"Property {prop} not found") + + prop_fn.__name__ = prop + if norm != 1: + prop_fn.__name__ += "_normd" + + self.add_to_observation(bind(self, prop_fn, prop_fn.__name__ + "_bound"))
+
+ + + +
+[docs] +@configurable +class TimeState(SatObservation): + """Satellite subclass to add simulation time to the observation.""" + +
+[docs] + def __init__(self, *args, normalization_time: Optional[float] = None, **kwargs): + """Add the sim time to the observation state. + + Automatically normalizes to the sim duration. + + Args: + normalization_time: Time to normalize by. If None, is set to simulation + duration + args: Passed through to satellite + kwargs: Passed through to satellite + """ + super().__init__(*args, **kwargs) + self.normalization_time = normalization_time + self.add_to_observation(self.normalized_time)
+ + +
+[docs] + def reset_post_sim(self): + """Autodetect normalization time.""" + super().reset_post_sim() + if self.normalization_time is None: + self.normalization_time = self.simulator.time_limit
+ + +
+[docs] + def normalized_time(self): + """Return time normalized by normalization_time.""" + assert self.normalization_time is not None + return self.simulator.sim_time / self.normalization_time
+
+ + + +
+[docs] +@configurable +class TargetState(SatObservation, ImagingSatellite): + """Satellite subclass to add upcoming target information to the observation.""" + +
+[docs] + def __init__( + self, + *args, + n_ahead_observe: int = 1, + target_properties: Optional[list[dict[str, Any]]] = None, + **kwargs, + ): + """Add information about upcoming targets to the observation state. + + Args: + n_ahead_observe: Number of upcoming targets to consider. + target_properties: List of properties to include in the observation in the + format [dict(prop="prop_name", norm=norm)]. If norm is not specified, it + is set to 1.0 (no normalization). Properties to choose from: + * priority + * location + * window_open + * window_mid + * window_close + args: Passed through to satellite + kwargs: Passed through to satellite + """ + super().__init__(*args, n_ahead_observe=n_ahead_observe, **kwargs) + if target_properties is None: + target_properties = [ + dict(prop="priority"), + dict(prop="location", norm=orbitalMotion.REQ_EARTH * 1e3), + ] + if "location_norm" in kwargs: + self.logger.warning( + "location_norm is ignored and should be specified in target_properties" + ) # pragma: no cover + self.n_ahead_observe = int(n_ahead_observe) + self.target_obs_generator(target_properties)
+ + +
+[docs] + def target_obs_generator(self, target_properties): + """Generate the target_obs function. + + Generates the observation function from the target_properties spec and add it + to the observation. + """ + + def target_obs(self): + obs = {} + for i, opportunity in enumerate( + self.find_next_opportunities( + n=self.n_ahead_observe, + filter=self._get_imaged_filter(), + types="target", + ) + ): + props = {} + for prop_spec in target_properties: + name = prop_spec["prop"] + norm = prop_spec.get("norm", 1.0) + if name == "priority": + value = opportunity["target"].priority + elif name == "location": + value = opportunity["target"].location + elif name == "window_open": + value = opportunity["window"][0] - self.simulator.sim_time + elif name == "window_mid": + value = sum(opportunity["window"]) / 2 - self.simulator.sim_time + elif name == "window_close": + value = opportunity["window"][1] - self.simulator.sim_time + else: + raise ValueError( + f"Invalid target property: {prop_spec['prop']}" + ) + if norm != 1.0: + name += "_normd" + props[name] = value / norm + obs[f"target_{i}"] = props + return obs + + self.add_to_observation(bind(self, target_obs, "target_obs"))
+
+ + + +
+[docs] +@configurable +class EclipseState(SatObservation): + """Satellite subclass to add upcoming eclipse information to the observation.""" + +
+[docs] + def __init__(self, *args, orbit_period=5700, **kwargs): + """Add a tuple of the orbit-normalized next orbit start and end. + + Args: + orbit_period: Normalization factor for eclipse time. + args: Passed through to satellite + kwargs: Passed through to satellite + """ + super().__init__(*args, **kwargs) + self.orbit_period_eclipse_norm = orbit_period + self.add_to_observation(self.eclipse_state)
+ + +
+[docs] + def eclipse_state(self): + """Return tuple of normalized next eclipse start and end.""" + eclipse_start, eclipse_end = self.trajectory.next_eclipse( + self.simulator.sim_time + ) + return [ + (eclipse_start - self.simulator.sim_time) / self.orbit_period_eclipse_norm, + (eclipse_end - self.simulator.sim_time) / self.orbit_period_eclipse_norm, + ]
+
+ + + +
+[docs] +@configurable +class GroundStationState(SatObservation, AccessSatellite): + """Satellite subclass to add ground station information to the observation.""" + +
+[docs] + def __init__( + self, + *args, + n_ahead_observe_downlinks: int = 1, + downlink_window_properties: Optional[list[dict[str, Any]]] = None, + **kwargs, + ): + """Add information about downlink opportunities to the observation state. + + Args: + n_ahead_observe_downlinks: Number of upcoming downlink opportunities to + consider. + downlink_window_properties: List of properties to include in the observation + in the format [dict(prop="prop_name", norm=norm)]. If norm is not + specified, it is set to 1.0 (no normalization). Properties to choose + from: + * location + * window_open + * window_mid + * window_close + args: Passed through to satellite + kwargs: Passed through to satellite + """ + super().__init__(*args, **kwargs) + if downlink_window_properties is None: + downlink_window_properties = [ + dict(prop="window_open", norm=5700), + dict(prop="window_close", norm=5700), + ] + self.ground_station_obs_generator( + downlink_window_properties, n_ahead_observe_downlinks + )
+ + +
+[docs] + def reset_post_sim(self) -> None: + """Add downlink ground stations to be considered by the access checker.""" + for ground_station in self.simulator.environment.groundStations: + self.add_location_for_access_checking( + object=ground_station.ModelTag, + location=np.array(ground_station.r_LP_P_Init).flatten(), + min_elev=ground_station.minimumElevation, + type="ground_station", + ) + super().reset_post_sim()
+ + +
+[docs] + def ground_station_obs_generator( + self, + downlink_window_properties: list[dict[str, Any]], + n_ahead_observe_downlinks: int, + ) -> None: + """Generate the ground_station_obs function. + + Generates an obs function from the downlink_window_properties spec and adds it + to the observation. + """ + + def ground_station_obs(self): + obs = {} + for i, opportunity in enumerate( + self.find_next_opportunities( + n=n_ahead_observe_downlinks, types="ground_station" + ) + ): + props = {} + for prop_spec in downlink_window_properties: + name = prop_spec["prop"] + norm = prop_spec.get("norm", 1.0) + if name == "location": + value = opportunity["location"] + elif name == "window_open": + value = opportunity["window"][0] - self.simulator.sim_time + elif name == "window_mid": + value = sum(opportunity["window"]) / 2 - self.simulator.sim_time + elif name == "window_close": + value = opportunity["window"][1] - self.simulator.sim_time + else: + raise ValueError( + f"Invalid ground station property: {prop_spec['prop']}" + ) + if norm != 1.0: + name += "_normd" + props[name] = value / norm + obs[f"ground_station_{i}"] = props + return obs + + self.add_to_observation(bind(self, ground_station_obs, "ground_station_obs"))
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/scenario/satellites.html b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/satellites.html new file mode 100644 index 00000000..fd91b43d --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/scenario/satellites.html @@ -0,0 +1,1144 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.scenario.satellites — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.scenario.satellites

+"""Satellites are the agents in the environment."""
+
+import bisect
+import inspect
+import logging
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING, Any, Iterable, Optional, Union
+from weakref import proxy
+
+if TYPE_CHECKING:  # pragma: no cover
+    from bsk_rl.envs.general_satellite_tasking.types import (
+        DynamicsModel,
+        FSWModel,
+        Simulator,
+    )
+
+import chebpy
+import numpy as np
+from Basilisk.utilities import macros
+from gymnasium import spaces
+
+from bsk_rl.envs.general_satellite_tasking.scenario.data import (
+    DataStore,
+    UniqueImageStore,
+)
+from bsk_rl.envs.general_satellite_tasking.scenario.environment_features import Target
+from bsk_rl.envs.general_satellite_tasking.simulation import dynamics, fsw
+from bsk_rl.envs.general_satellite_tasking.utils.functional import (
+    collect_default_args,
+    safe_dict_merge,
+    valid_func_name,
+)
+from bsk_rl.envs.general_satellite_tasking.utils.orbital import (
+    TrajectorySimulator,
+    elevation,
+)
+
+SatObs = Any
+SatAct = Any
+
+
+
+[docs] +class Satellite(ABC): + """Abstract base class for satellites.""" + + dyn_type: type["DynamicsModel"] # Type of dynamics model used by this satellite + fsw_type: type["FSWModel"] # Type of FSW model used by this satellite + +
+[docs] + @classmethod + def default_sat_args(cls, **kwargs) -> dict[str, Any]: + """Compile default arguments for FSW and dynamics models. + + Returns: + default arguments for satellite models + """ + defaults = collect_default_args(cls.dyn_type) + defaults = safe_dict_merge(defaults, collect_default_args(cls.fsw_type)) + for name in dir(cls.fsw_type): + if inspect.isclass(getattr(cls.fsw_type, name)) and issubclass( + getattr(cls.fsw_type, name), fsw.Task + ): + defaults = safe_dict_merge( + defaults, collect_default_args(getattr(cls.fsw_type, name)) + ) + + for k, v in kwargs.items(): + if k not in defaults: + raise KeyError(f"{k} not a valid key for sat_args") + defaults[k] = v + return defaults
+ + +
+[docs] + def __init__( + self, + name: str, + sat_args: Optional[dict[str, Any]], + variable_interval: bool = True, + **kwargs, + ) -> None: + """Construct base satellite. + + Args: + name: identifier for satellite; does not need to be unique + sat_args: arguments for FSW and dynamic model construction. {key: value or + key: function}, where function is called at reset to set the value (used + for randomization). + variable_interval: Stop simulation at terminal events + kwargs: Ignored + """ + self.name = name + self.logger = logging.getLogger(__name__).getChild(self.name) + if sat_args is None: + sat_args = self.default_sat_args() + self.sat_args_generator = self.default_sat_args(**sat_args) + self.simulator: Simulator + 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
+ + + @property + def id(self) -> str: + """Unique human-readable identifier.""" + return f"{self.name}_{id(self)}" + + def _generate_sat_args(self) -> None: + """Instantiate sat_args from any randomizers in provided sat_args.""" + self.sat_args = { + k: v if not callable(v) else v() for k, v in self.sat_args_generator.items() + } + self.logger.debug(f"Satellite initialized with {self.sat_args}") + +
+[docs] + def reset_pre_sim(self) -> None: + """Reset during 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 + + self.trajectory = TrajectorySimulator( + utc_init=self.sat_args["utc_init"], + rN=self.sat_args["rN"], + vN=self.sat_args["vN"], + oe=self.sat_args["oe"], + mu=self.sat_args["mu"], + ) + self._timed_terminal_event_name = None
+ + +
+[docs] + def set_simulator(self, simulator: "Simulator"): + """Set the simulator for models. + + Called during simulator initialization. + + Args: + simulator: Basilisk simulator + """ + self.simulator = proxy(simulator)
+ + +
+[docs] + def set_dynamics(self, dyn_rate: float) -> "DynamicsModel": + """Create dynamics model; called during simulator initialization. + + Args: + dyn_rate: rate for dynamics simulation [s] + + Returns: + Satellite's dynamics model + """ + dynamics = self.dyn_type(self, dyn_rate, **self.sat_args) + self.dynamics = proxy(dynamics) + return dynamics
+ + +
+[docs] + def set_fsw(self, fsw_rate: float) -> "FSWModel": + """Create flight software model; called during simulator initialization. + + Args: + fsw_rate: rate for FSW simulation [s] + + Returns: + Satellite's FSW model + """ + fsw = self.fsw_type(self, fsw_rate, **self.sat_args) + self.fsw = proxy(fsw) + return fsw
+ + +
+[docs] + def reset_post_sim(self) -> None: + """Reset in environment reset, after simulator initialization.""" + pass
+ + + @property + def observation_space(self) -> spaces.Box: + """Observation space for single satellite, determined from observation. + + Returns: + gymanisium observation space + """ + return spaces.Box( + low=-1e16, high=1e16, shape=self.get_obs().shape, dtype=np.float64 + ) + + @property + @abstractmethod # pragma: no cover + def action_space(self) -> spaces.Space: + """Action space for single satellite. + + Returns: + gymanisium action space + """ + pass + +
+[docs] + def is_alive(self, log_failure=False) -> bool: + """Check if the satellite is violating any aliveness requirements. + + Checkes aliveness checkers in dynamics and FSW models. + + Returns: + is_alive + """ + return self.dynamics.is_alive(log_failure=log_failure) and self.fsw.is_alive( + log_failure=log_failure + )
+ + + @property + def _satellite_command(self) -> str: + """Generate string that refers to self in simBase.""" + return ( + "[satellite for satellite in self.satellites " + + f"if satellite.id=='{self.id}'][0]" + ) + + def _info_command(self, info: str) -> str: + """Generate command to log to info from an event. + + Args: + info: information to log; cannot include `'` or `"` + + Returns: + actionList action for simBase.createNewEvent + """ + return self._satellite_command + f".log_info('{info}')" + +
+[docs] + def log_info(self, info: Any) -> None: + """Record information at the current time. + + Args: + info: Information to log + """ + self.info.append((self.simulator.sim_time, info)) + self.logger.info(f"{info}")
+ + + def _update_timed_terminal_event( + self, t_close: float, info: str = "", extra_actions: list[str] = [] + ) -> None: + """Create a simulator event that stops the simulation a certain time. + + Args: + t_close: Termination time [s] + info: Additional identifying info to log at terminal time + extra_actions: Additional actions to perform at terminal time + """ + self._disable_timed_terminal_event() + self.log_info(f"setting timed terminal event at {t_close:.1f}") + + # Create new timed terminal event + self._timed_terminal_event_name = valid_func_name( + f"timed_terminal_{t_close}_{self.id}" + ) + self.simulator.createNewEvent( + self._timed_terminal_event_name, + macros.sec2nano(self.simulator.sim_rate), + True, + [f"self.TotalSim.CurrentNanos * {macros.NANO2SEC} >= {t_close}"], + [ + self._info_command(f"timed termination at {t_close:.1f} " + info), + self._satellite_command + ".requires_retasking = True", + ] + + extra_actions, + terminal=self.variable_interval, + ) + self.simulator.eventMap[self._timed_terminal_event_name].eventActive = True + + def _disable_timed_terminal_event(self) -> None: + """Turn off simulator termination due to window close checker.""" + if ( + self._timed_terminal_event_name is not None + and self._timed_terminal_event_name in self.simulator.eventMap + ): + self.simulator.delete_event(self._timed_terminal_event_name) + +
+[docs] + @abstractmethod # pragma: no cover + def get_obs(self) -> SatObs: + """Construct the satellite's observation. + + Returns: + satellite observation + """ + pass
+ + +
+[docs] + @abstractmethod # pragma: no cover + def set_action(self, action: int) -> None: + """Enable certain processes in the simulator to command the satellite task. + + Should call an @action from FSW, among other things. + + Args: + action: action index + """ + pass
+
+ + + +
+[docs] +class AccessSatellite(Satellite): + """Satellite that can detect access opportunities for ground locations.""" + +
+[docs] + def __init__( + self, + *args, + generation_duration: float = 60 * 95, + initial_generation_duration: Optional[float] = None, + access_dist_threshold: float = 4e6, + **kwargs, + ) -> None: + """Construct an AccessSatellite. + + Args: + generation_duration: Duration to calculate additional imaging windows for + when windows are exhausted. If `None`, generate for the simulation + `time_limit` unless the simulation is infinite. [s] + initial_generation_duration: Duration to initially calculate imaging windows + [s] + access_dist_threshold: Distance bound [m] for evaluating imaging windows + more exactly. 4e6 will capture >10 elevation windows for a 500 km orbit. + args: Passed through to Satellite constructor + kwargs: Passed through to Satellite constructor + """ + super().__init__(*args, **kwargs) + self.generation_duration = generation_duration + self.initial_generation_duration = initial_generation_duration + self.access_dist_threshold = access_dist_threshold
+ + +
+[docs] + def reset_pre_sim(self) -> None: + """Reset satellite window calculations and lists.""" + super().reset_pre_sim() + self.opportunities: list[dict] = [] + self.window_calculation_time = 0 + self.locations_for_access_checking: list[dict[str, Any]] = []
+ + +
+[docs] + def add_location_for_access_checking( + self, + object: Any, + location: np.ndarray, + min_elev: float, + type: str, + ) -> None: + """Add a location to be included in window calculations. + + Note that this location will only be included in future calls to + calculate_additional_windows. + + Args: + object: Object to add window for + location: Objects PCPF location [m] + min_elev: Minimum elevation angle for access [rad] + type: Category of windows to add location to + """ + location_dict = dict(location=location, min_elev=min_elev, type=type) + location_dict[type] = object + self.locations_for_access_checking.append(location_dict)
+ + +
+[docs] + def reset_post_sim(self) -> None: + """Handle initial window calculations for new simulation.""" + super().reset_post_sim() + if self.initial_generation_duration is None: + if self.simulator.time_limit == float("inf"): + self.initial_generation_duration = 0 + else: + self.initial_generation_duration = self.simulator.time_limit + self.calculate_additional_windows(self.initial_generation_duration)
+ + +
+[docs] + def calculate_additional_windows(self, duration: float) -> None: + """Use a multiroot finding method to evaluate imaging windows for each location. + + Args: + duration: Time to calculate windows from end of previous window. + """ + if duration <= 0: + return + + self.logger.info( + "Finding opportunity windows from " + f"{self.window_calculation_time:.2f} to " + f"{self.window_calculation_time + duration:.2f} seconds" + ) + calculation_start = self.window_calculation_time + calculation_end = self.window_calculation_time + max( + duration, self.trajectory.dt * 2, self.generation_duration + ) + calculation_end = self.generation_duration * np.ceil( + calculation_end / self.generation_duration + ) + + # Get discrete times and positions for next trajectory segment + self.trajectory.extend_to(calculation_end) + r_BP_P_interp = self.trajectory.r_BP_P + window_calc_span = np.logical_and( + r_BP_P_interp.x >= calculation_start - 1e-9, + r_BP_P_interp.x <= calculation_end + 1e-9, + ) # Account for floating point error in window_calculation_time + times = r_BP_P_interp.x[window_calc_span] + positions = r_BP_P_interp.y[window_calc_span] + + for location in self.locations_for_access_checking: + candidate_windows = self._find_candidate_windows( + location["location"], times, positions, self.access_dist_threshold + ) + + for candidate_window in candidate_windows: + roots = self._find_elevation_roots( + r_BP_P_interp, + location["location"], + location["min_elev"], + candidate_window, + ) + new_windows = self._refine_window( + roots, candidate_window, (times[0], times[-1]) + ) + for new_window in new_windows: + self._add_window( + location[location["type"]], + new_window, + type=location["type"], + merge_time=times[0], + ) + + self.window_calculation_time = calculation_end
+ + + @staticmethod + def _find_elevation_roots( + position_interp, + location: np.ndarray, + min_elev: float, + window: tuple[float, float], + ): + """Find times where the elevation is equal to the minimum elevation. + + Finds exact times where the satellite's elevation relative to a target is + equal to the minimum elevation. + """ + + def root_fn(t): + return elevation(position_interp(t), location) - min_elev + + settings = chebpy.UserPreferences() + with settings: + settings.eps = 1e-6 + settings.sortroots = True + roots = chebpy.chebfun(root_fn, window).roots() + + return roots + + @staticmethod + def _find_candidate_windows( + location: np.ndarray, times: np.ndarray, positions: np.ndarray, threshold: float + ) -> list[tuple[float, float]]: + """Find `times` where a window is plausible. + + i.e. where a `positions` point is within `threshold` of `location`. Too big of + a dt in times may miss windows or produce bad results. + """ + close_times = np.linalg.norm(positions - location, axis=1) < threshold + close_indices = np.where(close_times)[0] + groups = np.split(close_indices, np.where(np.diff(close_indices) != 1)[0] + 1) + groups = [group for group in groups if len(group) > 0] + candidate_windows = [] + for group in groups: + t_start = times[max(0, group[0] - 1)] + t_end = times[min(len(times) - 1, group[-1] + 1)] + candidate_windows.append((t_start, t_end)) + return candidate_windows + + @staticmethod + def _refine_window( + endpoints: Iterable, + candidate_window: tuple[float, float], + computation_window: tuple[float, float], + ) -> list[tuple[float, float]]: + """Detect if an exact window has been truncated by a coarse window.""" + endpoints = list(endpoints) + + # Filter endpoints that are too close + for i, endpoint in enumerate(endpoints[0:-1]): + if abs(endpoint - endpoints[i + 1]) < 1e-6: + endpoints[i] = None + endpoints = [endpoint for endpoint in endpoints if endpoint is not None] + + # Find pairs + if len(endpoints) % 2 == 1: + if candidate_window[0] == computation_window[0]: + endpoints.insert(0, computation_window[0]) + elif candidate_window[-1] == computation_window[-1]: + endpoints.append(computation_window[-1]) + else: + return [] # Temporary fix for rare issue. + + new_windows = [] + for t1, t2 in zip(endpoints[0::2], endpoints[1::2]): + new_windows.append((t1, t2)) + + return new_windows + + def _add_window( + self, + object: Any, + new_window: tuple[float, float], + type: str, + merge_time: Optional[float] = None, + ): + """Add an opportunity window. + + Args: + object: Object to add window for + new_window: New window for target + type: Type of window being added + merge_time: Time at which merges with existing windows will occur. If None, + check all windows for merges. + """ + if new_window[0] == merge_time or merge_time is None: + for opportunity in self.opportunities: + if ( + opportunity["type"] == type + and opportunity[type] == object + and opportunity["window"][1] == new_window[0] + ): + opportunity["window"] = (opportunity["window"][0], new_window[1]) + return + bisect.insort( + self.opportunities, + {type: object, "window": new_window, "type": type}, + key=lambda x: x["window"][1], + ) + + @property + def upcoming_opportunities(self) -> list[dict]: + """Ordered list of opportunities that have not yet closed. + + Returns: + list: list of upcoming opportunities + """ + start = bisect.bisect_left( + self.opportunities, + self.simulator.sim_time + 1e-12, + key=lambda x: x["window"][1], + ) + upcoming = self.opportunities[start:] + return upcoming + +
+[docs] + def opportunities_dict( + self, + types: Optional[Union[str, list[str]]] = None, + filter: list = [], + ) -> dict[Any, list[tuple[float, float]]]: + """Make dictionary of opportunities that maps objects to lists of windows. + + Args: + types: Types of opportunities to include. If None, include all types. + filter: Objects to exclude from the dictionary. + + Returns: + windows: objects -> windows list + """ + if isinstance(types, str): + types = [types] + + windows = {} + for opportunity in self.opportunities: + type = opportunity["type"] + if (types is None or type in types) and opportunity[type] not in filter: + if opportunity[type] not in windows: + windows[opportunity[type]] = [] + windows[opportunity[type]].append(opportunity["window"]) + return windows
+ + +
+[docs] + def upcoming_opportunities_dict( + self, + types: Optional[Union[str, list[str]]] = None, + filter: list = [], + ) -> dict[Any, list[tuple[float, float]]]: + """Get dictionary of opportunities. + + Maps objects to lists of windows that have not yet closed. + + Args: + types: Types of opportunities to include. If None, include all types. + filter: Objects to exclude from the dictionary. + + Returns: + windows: objects -> windows list (upcoming only) + """ + if isinstance(types, str): + types = [types] + + windows = {} + for opportunity in self.upcoming_opportunities: + type = opportunity["type"] + if (types is None or type in types) and opportunity[type] not in filter: + if opportunity[type] not in windows: + windows[opportunity[type]] = [] + windows[opportunity[type]].append(opportunity["window"]) + return windows
+ + +
+[docs] + def next_opportunities_dict( + self, + types: Optional[Union[str, list[str]]] = None, + filter: list = [], + ) -> dict[Any, tuple[float, float]]: + """Make dictionary of opportunities that maps objects to the next open windows. + + Args: + types: Types of opportunities to include. If None, include all types. + filter: Objects to exclude from the dictionary. + + Returns: + windows: objects -> next window + """ + if isinstance(types, str): + types = [types] + + next_windows = {} + for opportunity in self.upcoming_opportunities: + type = opportunity["type"] + if (types is None or type in types) and opportunity[type] not in filter: + if opportunity[type] not in next_windows: + next_windows[opportunity[type]] = opportunity["window"] + return next_windows
+ + +
+[docs] + def find_next_opportunities( + self, + n: int, + pad: bool = True, + max_lookahead: int = 100, + types: Optional[Union[str, list[str]]] = None, + filter: list = [], + ) -> list[dict]: + """Find the n nearest opportunities, sorted by window close time. + + Args: + n: Number of opportunities to attempt to include. + pad: If true, duplicates the last target if the number of opportunities + found is less than n. + max_lookahead: Maximum times to call calculate_additional_windows. + types: Types of opportunities to include. If None, include all types. + filter: Objects to exclude from the dictionary. + + Returns: + list: n nearest opportunities, ordered + """ + if isinstance(types, str): + types = [types] + + if n == 0: + return [] + + for _ in range(max_lookahead): + upcoming_opportunities = self.upcoming_opportunities + next_opportunities = [] + for opportunity in upcoming_opportunities: + type = opportunity["type"] + if (types is None or type in types) and opportunity[type] not in filter: + next_opportunities.append(opportunity) + + if len(next_opportunities) >= n: + return next_opportunities + self.calculate_additional_windows(self.generation_duration) + if pad: + next_opportunities += [next_opportunities[-1]] * ( + n - len(next_opportunities) + ) + return next_opportunities
+
+ + + +
+[docs] +class ImagingSatellite(AccessSatellite): + """Satellite with agile imaging capabilities.""" + + dyn_type = dynamics.ImagingDynModel + fsw_type = fsw.ImagingFSWModel + +
+[docs] + def __init__( + self, + *args, + **kwargs, + ) -> None: + """Construct an ImagingSatellite. + + Can stop the simulation when a target is imaged or missed. + """ + super().__init__(*args, **kwargs) + self.fsw: ImagingSatellite.fsw_type + self.dynamics: ImagingSatellite.dyn_type + self.data_store: UniqueImageStore
+ + +
+[docs] + def reset_pre_sim(self) -> None: + """Set the buffer parameters based on computed windows.""" + super().reset_pre_sim() + self.sat_args["transmitterNumBuffers"] = len( + self.data_store.env_knowledge.targets + ) + self.sat_args["bufferNames"] = [ + target.id for target in self.data_store.env_knowledge.targets + ] + self._image_event_name = None + self.imaged = 0 + self.missed = 0
+ + +
+[docs] + def reset_post_sim(self) -> None: + """Handle initial_generation_duration setting and calculate windows.""" + for target in self.data_store.env_knowledge.targets: + self.add_location_for_access_checking( + object=target, + location=target.location, + min_elev=self.sat_args["imageTargetMinimumElevation"], + type="target", + ) + super().reset_post_sim()
+ + + def _get_imaged_filter(self): + try: + return self.data_store.data.imaged + except AttributeError: + return [] + + @property + def windows(self) -> dict[Target, list[tuple[float, float]]]: + """Access windows via dict of targets -> list of windows.""" + return self.opportunities_dict(types="target", filter=self._get_imaged_filter()) + + @property + def upcoming_windows(self) -> dict[Target, list[tuple[float, float]]]: + """Access upcoming windows in a dict of targets -> list of windows.""" + return self.upcoming_opportunities_dict( + types="target", filter=self._get_imaged_filter() + ) + + @property + def next_windows(self) -> dict[Target, tuple[float, float]]: + """Soonest window for each target. + + Returns: + dict: first non-closed window for each target + """ + return self.next_opportunities_dict( + types="target", filter=self._get_imaged_filter() + ) + +
+[docs] + def upcoming_targets( + self, n: int, pad: bool = True, max_lookahead: int = 100 + ) -> list[Target]: + """Find the n nearest targets. + + Targets are sorted by window close time; currently open windows are included. + + Args: + n: number of windows to look ahead + pad: if true, duplicates the last target if the number of targets found is + less than n + max_lookahead: maximum times to call calculate_additional_windows + + Returns: + list: n nearest targets, ordered + """ + return [ + opportunity["target"] + for opportunity in self.find_next_opportunities( + n=n, + pad=pad, + max_lookahead=max_lookahead, + filter=self._get_imaged_filter(), + types="target", + ) + ]
+ + + def _update_image_event(self, target: Target) -> None: + """Create a simulator event that terminates on imaging. + + Causes the simulation to stop when a target is imaged. + + Args: + target: Target expected to be imaged + """ + self._disable_image_event() + + self._image_event_name = valid_func_name(f"image_{self.id}_{target.id}") + if self._image_event_name not in self.simulator.eventMap.keys(): + data_names = np.array( + list( + self.dynamics.storageUnit.storageUnitDataOutMsg.read().storedDataName + ) + ) + data_index = int(np.where(data_names == target.id)[0][0]) + current_data_level = ( + self.dynamics.storageUnit.storageUnitDataOutMsg.read().storedData[ + data_index + ] + ) + self.simulator.createNewEvent( + self._image_event_name, + macros.sec2nano(self.fsw.fsw_rate), + True, + [ + f"self.dynamics_list['{self.id}'].storageUnit.storageUnitDataOutMsg.read()" + + f".storedData[{data_index}] > {current_data_level}" + ], + [ + self._info_command(f"imaged {target}"), + self._satellite_command + ".imaged += 1", + self._satellite_command + ".requires_retasking = True", + ], + terminal=self.variable_interval, + ) + else: + self.simulator.eventMap[self._image_event_name].eventActive = True + + def _disable_image_event(self) -> None: + """Turn off simulator termination due to this satellite's imaging checker.""" + if ( + self._image_event_name is not None + and self._image_event_name in self.simulator.eventMap + ): + self.simulator.delete_event(self._image_event_name) + +
+[docs] + def parse_target_selection(self, target_query: Union[int, Target, str]): + """Identify a target from a query. + + Parses an upcoming target index, Target object, or target id. + + Args: + target_query: Taret upcoming index, object, or id. + """ + if np.issubdtype(type(target_query), np.integer): + target = self.upcoming_targets(target_query + 1)[-1] + elif isinstance(target_query, Target): + target = target_query + elif isinstance(target_query, str): + target = [ + target + for target in self.data_store.env_knowledge.targets + if target.id == target_query + ][0] + else: + raise TypeError(f"Invalid target_query! Cannot be a {type(target_query)}!") + + return target
+ + +
+[docs] + def enable_target_window(self, target: Target): + """Enable the next window close event for target.""" + self._update_image_event(target) + next_window = self.next_windows[target] + self.log_info( + f"{target} window enabled: {next_window[0]:.1f} to {next_window[1]:.1f}" + ) + self._update_timed_terminal_event( + next_window[1], + info=f"for {target} window", + extra_actions=[self._satellite_command + ".missed += 1"], + )
+ + +
+[docs] + def task_target_for_imaging(self, target: Target): + """Task the satellite to image a target. + + Args: + target: Selected target + """ + msg = f"{target} tasked for imaging" + self.log_info(msg) + self.fsw.action_image(target.location, target.id) + self.enable_target_window(target)
+
+ + + +######################### +### Convenience Types ### +######################### +
+[docs] +class SteeringImagerSatellite(ImagingSatellite): + """Convenience type for an imaging satellite with MRP steering.""" + + dyn_type = dynamics.FullFeaturedDynModel + fsw_type = fsw.SteeringImagerFSWModel
+ + + +
+[docs] +class FBImagerSatellite(ImagingSatellite): + """Convenience type for an imaging satellite with feedback control.""" + + dyn_type = dynamics.FullFeaturedDynModel + fsw_type = fsw.ImagingFSWModel
+ + + +########################## +### Ready-to-use Types ### +########################## +from Basilisk.utilities import orbitalMotion # noqa: E402 + +from bsk_rl.envs.general_satellite_tasking.scenario import ( # noqa: E402 + sat_actions as sa, +) +from bsk_rl.envs.general_satellite_tasking.scenario import ( # noqa: E402 + sat_observations as so, +) + + +
+[docs] +class DoNothingSatellite(sa.DriftAction, so.TimeState): + """Convenience type for a satellite that does nothing.""" + + dyn_type = dynamics.BasicDynamicsModel + fsw_type = fsw.BasicFSWModel
+ + + +
+[docs] +class ImageAheadSatellite( + sa.ImagingActions, + so.TimeState, + so.TargetState.configure(n_ahead_observe=3), + so.NormdPropertyState.configure( + obs_properties=[ + dict(prop="omega_BP_P", norm=0.03), + dict(prop="c_hat_P"), + dict(prop="r_BN_P", norm=orbitalMotion.REQ_EARTH * 1e3), + dict(prop="v_BN_P", norm=7616.5), + dict(prop="battery_charge_fraction"), + ] + ), + SteeringImagerSatellite, +): + """Convenience type for a satellite with common features enabled.""" + + pass
+ + + +
+[docs] +class FullFeaturedSatellite( + sa.ImagingActions, + sa.DesatAction, + sa.ChargingAction, + so.TimeState, + so.TargetState.configure(n_ahead_observe=3), + so.NormdPropertyState.configure( + obs_properties=[ + dict(prop="omega_BP_P", norm=0.03), + dict(prop="c_hat_P"), + dict(prop="r_BN_P", norm=orbitalMotion.REQ_EARTH * 1e3), + dict(prop="v_BN_P", norm=7616.5), + dict(prop="battery_charge_fraction"), + ] + ), + SteeringImagerSatellite, +): + """Convenience type for a satellite with common features enabled.""" + + pass
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/simulation/dynamics.html b/_modules/bsk_rl/envs/general_satellite_tasking/simulation/dynamics.html new file mode 100644 index 00000000..78f914d5 --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/simulation/dynamics.html @@ -0,0 +1,1130 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.simulation.dynamics — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.simulation.dynamics

+"""Basilisk dynamics models."""
+
+
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING, Iterable, Optional
+
+if TYPE_CHECKING:  # pragma: no cover
+    from bsk_rl.envs.general_satellite_tasking.types import (
+        EnvironmentModel,
+        Satellite,
+        Simulator,
+    )
+
+import numpy as np
+from Basilisk.simulation import (
+    ReactionWheelPower,
+    extForceTorque,
+    facetDragDynamicEffector,
+    groundLocation,
+    partitionedStorageUnit,
+    simpleBattery,
+    simpleInstrument,
+    simpleNav,
+    simplePowerSink,
+    simpleSolarPanel,
+    simpleStorageUnit,
+    spacecraft,
+    spacecraftLocation,
+    spaceToGroundTransmitter,
+)
+from Basilisk.utilities import (
+    RigidBodyKinematics,
+    macros,
+    orbitalMotion,
+    unitTestSupport,
+)
+
+from bsk_rl.envs.general_satellite_tasking.simulation import environment
+from bsk_rl.envs.general_satellite_tasking.utils.functional import (
+    aliveness_checker,
+    check_aliveness_checkers,
+    default_args,
+)
+from bsk_rl.utilities.effector_primitives import actuator_primitives as aP
+from bsk_rl.utilities.initial_conditions import leo_orbit, sc_attitudes
+
+
+
+[docs] +class DynamicsModel(ABC): + """Abstract Basilisk dynamics model. + + One DynamicsModel is instantiated for each satellite in the environment each time a + new simulator is created. + """ + + @classmethod + @property + def _requires_env(cls) -> list[type["EnvironmentModel"]]: + """Define minimum EnvironmentModels for compatibility.""" + return [] + +
+[docs] + def __init__( + self, + satellite: "Satellite", + dyn_rate: float, + priority: int = 200, + **kwargs, + ) -> None: + """Construct a base dynamics model. + + Args: + satellite: Satellite modelled by this model + dyn_rate: Rate of dynamics simulation [s] + priority: Model priority. + kwargs: Ignored + """ + self.satellite = satellite + self.logger = self.satellite.logger.getChild(self.__class__.__name__) + + for required in self._requires_env: + if not issubclass(type(self.simulator.environment), required): + raise TypeError( + f"{self.simulator.environment} must be a subclass of {required} to " + + f"use dynamics model of type {self.__class__}" + ) + + dyn_proc_name = "DynamicsProcess" + self.satellite.id + self.dyn_proc = self.simulator.CreateNewProcess(dyn_proc_name, priority) + self.dyn_rate = dyn_rate + self.task_name = "DynamicsTask" + self.satellite.id + self.dyn_proc.addTask( + self.simulator.CreateNewTask(self.task_name, macros.sec2nano(self.dyn_rate)) + ) + + # Initialize all modules and write init one-time messages + self.scObject: spacecraft.Spacecraft + self._init_dynamics_objects(**kwargs)
+ + + @property + def simulator(self) -> "Simulator": + """Reference to the episode simulator.""" + return self.satellite.simulator + + @property + def environment(self) -> "EnvironmentModel": + """Reference to the episode environment model.""" + return self.simulator.environment + + @abstractmethod # pragma: no cover + def _init_dynamics_objects(self, **kwargs) -> None: + """Caller for all dynamics object initialization.""" + pass + +
+[docs] + def is_alive(self, log_failure=False) -> bool: + """Check if the dynamics model has failed any aliveness requirements. + + Returns: + If the satellite dynamics are still alive + """ + return check_aliveness_checkers(self, log_failure=log_failure)
+ + +
+[docs] + def reset_for_action(self) -> None: + """Reset whenever a FSW @action is called.""" + pass
+ + + def __del__(self): + """Log when dynamics are deleted.""" + self.logger.debug("Basilisk dynamics deleted")
+ + + +
+[docs] +class BasicDynamicsModel(DynamicsModel): + """Basic Dynamics model with minimum necessary Basilisk components.""" + + @classmethod + @property + def _requires_env(cls) -> list[type["EnvironmentModel"]]: + return [environment.BasicEnvironmentModel] + + @property + def sigma_BN(self): + """Body attitude MRP relative to inertial frame.""" + return self.scObject.scStateOutMsg.read().sigma_BN + + @property + def BN(self): + """Body relative to inertial frame rotation matrix.""" + return RigidBodyKinematics.MRP2C(self.sigma_BN) + + @property + def omega_BN_B(self): + """Body rate relative to inertial frame in body frame [rad/s].""" + return self.scObject.scStateOutMsg.read().omega_BN_B + + @property + def BP(self): + """Body relative to planet freame rotation matrix.""" + return np.matmul(self.BN, self.environment.PN.T) + + @property + def r_BN_N(self): + """Body position relative to inertial origin in inertial frame [m].""" + return self.scObject.scStateOutMsg.read().r_BN_N + + @property + def r_BN_P(self): + """Body position relative to inertial origin in planet frame [m].""" + return np.matmul(self.environment.PN, self.r_BN_N) + + @property + def v_BN_N(self): + """Body velocity relative to inertial origin in inertial frame [m/s].""" + return self.scObject.scStateOutMsg.read().v_BN_N + + @property + def v_BN_P(self): + """P-frame derivative of r_BN.""" + omega_NP_P = np.matmul(self.environment.PN, -self.environment.omega_PN_N) + return np.matmul(self.environment.PN, self.v_BN_N) + np.cross( + omega_NP_P, self.r_BN_P + ) + + @property + def omega_BP_P(self): + """Body angular velocity relative to planet frame in plant frame [rad/s].""" + omega_BN_N = np.matmul(self.BN.T, self.omega_BN_B) + omega_BP_N = omega_BN_N - self.environment.omega_PN_N + return np.matmul(self.environment.PN, omega_BP_N) + + @property + def battery_charge(self): + """Battery charge [W*s].""" + return self.powerMonitor.batPowerOutMsg.read().storageLevel + + @property + def battery_charge_fraction(self): + """Battery charge as a fraction of capacity.""" + return self.battery_charge / self.powerMonitor.storageCapacity + + @property + def wheel_speeds(self): + """Wheel speeds [rad/s].""" + return np.array(self.rwStateEffector.rwSpeedOutMsg.read().wheelSpeeds) + + @property + def wheel_speeds_fraction(self): + """Wheel speeds normalized by maximum.""" + return self.wheel_speeds / (self.maxWheelSpeed * macros.rpm2radsec) + + def _init_dynamics_objects(self, **kwargs) -> None: + self._set_spacecraft_hub(**kwargs) + self._set_drag_effector(**kwargs) + self._set_reaction_wheel_dyn_effector(**kwargs) + self._set_thruster_dyn_effector() + self._set_simple_nav_object() + self._set_eclipse_object() + self._set_solar_panel(**kwargs) + self._set_battery(**kwargs) + self._set_reaction_wheel_power(**kwargs) + self._set_thruster_power(**kwargs) + + @default_args( + mass=330, + width=1.38, + depth=1.04, + height=1.58, + sigma_init=lambda: sc_attitudes.random_tumble(maxSpinRate=0.0001)[0], + omega_init=lambda: sc_attitudes.random_tumble(maxSpinRate=0.0001)[1], + rN=None, + vN=None, + oe=None, + mu=leo_orbit.mu, + ) + def _set_spacecraft_hub( + self, + mass: float, + width: float, + depth: float, + height: float, + sigma_init: Iterable[float], + omega_init: Iterable[float], + rN: Iterable[float], + vN: Iterable[float], + oe: Iterable[float], + mu: float, + priority: int = 2000, + **kwargs, + ) -> None: + """Set the spacecraft object properties. + + Args: + mass: Hub mass [kg] + width: Hub width [m] + depth: Hub depth [m] + height: Hub height [m] + sigma_init: Initial MRP + omega_init: Initial body rate [rad/s] + rN: Initial inertial position [m] + vN: Initial inertial velocity [m/s] + oe: (a, e, i, AN, AP, f); alternative to rN, vN [km, rad] + mu: Gravitational parameter (used only with oe) + priority: Model priority. + kwargs: Ignored + """ + if rN is not None and vN is not None and oe is None: + pass + elif oe is not None and rN is None and vN is None: + rN, vN = orbitalMotion.elem2rv(mu, oe) + else: + raise (KeyError("Orbit is overspecified. Provide either (rN, vN) or oe")) + + self.scObject = spacecraft.Spacecraft() + self.scObject.ModelTag = "sat-" + self.satellite.id + + Ixx = 1.0 / 12.0 * mass * (width**2.0 + depth**2.0) + Iyy = 1.0 / 12.0 * mass * (depth**2.0 + height**2.0) + Izz = 1.0 / 12.0 * mass * (width**2.0 + height**2.0) + self.I_mat = [Ixx, 0.0, 0.0, 0.0, Iyy, 0.0, 0.0, 0.0, Izz] + + self.scObject.hub.mHub = mass # kg + self.scObject.hub.IHubPntBc_B = unitTestSupport.np2EigenMatrix3d(self.I_mat) + + # Set the initial attitude and position + self.scObject.hub.sigma_BNInit = sigma_init + self.scObject.hub.omega_BN_BInit = omega_init + self.scObject.hub.r_CN_NInit = unitTestSupport.np2EigenVectorXd(rN) + self.scObject.hub.v_CN_NInit = unitTestSupport.np2EigenVectorXd(vN) + + self.simulator.AddModelToTask( + self.task_name, self.scObject, ModelPriority=priority + ) + + self._set_gravity_bodies() + self._set_disturbance_torque(**kwargs) + self._set_density_model() + + def _set_gravity_bodies(self) -> None: + """Specify what gravitational bodies to include in the simulation.""" + self.scObject.gravField.gravBodies = spacecraft.GravBodyVector( + list(self.environment.gravFactory.gravBodies.values()) + ) + + @default_args(disturbance_vector=None) + def _set_disturbance_torque( + self, disturbance_vector: Optional[Iterable[float]] = None, **kwargs + ) -> None: + """Attach the disturbance torque to the satellite. + + Args: + disturbance_vector: Constant disturbance torque [N*m]. + kwargs: Ignored + """ + if disturbance_vector is None: + disturbance_vector = np.array([0, 0, 0]) + self.extForceTorqueObject = extForceTorque.ExtForceTorque() + self.extForceTorqueObject.ModelTag = "DisturbanceTorque" + self.extForceTorqueObject.extTorquePntB_B = disturbance_vector + self.scObject.addDynamicEffector(self.extForceTorqueObject) + + def _set_density_model(self) -> None: + """Attaches the density model effector to the satellite.""" + self.environment.densityModel.addSpacecraftToModel(self.scObject.scStateOutMsg) + + def _set_drag_effector( + self, + width: float, + depth: float, + height: float, + panelArea: float, + priority: int = 999, + **kwargs, + ) -> None: + """Attach the drag effector to the satellite. + + Args: + width: Hub width [m] + depth: Hub depth [m] + height: Hub height [m] + panelArea: Solar panel surface area [m**2] + priority: Model priority. + kwargs: Ignored + """ + self.dragEffector = facetDragDynamicEffector.FacetDragDynamicEffector() + self.dragEffector.ModelTag = "FacetDrag" + # Set up the geometry of a small satellite, starting w/ bus + self.dragEffector.addFacet(width * depth, 2.2, [1, 0, 0], [height / 2, 0.0, 0]) + self.dragEffector.addFacet(width * depth, 2.2, [-1, 0, 0], [height / 2, 0.0, 0]) + self.dragEffector.addFacet(height * width, 2.2, [0, 1, 0], [0, depth / 2, 0]) + self.dragEffector.addFacet(height * width, 2.2, [0, -1, 0], [0, -depth / 2, 0]) + self.dragEffector.addFacet(height * depth, 2.2, [0, 0, 1], [0, 0, width / 2]) + self.dragEffector.addFacet(height * depth, 2.2, [0, 0, -1], [0, 0, -width / 2]) + # Add solar panels + self.dragEffector.addFacet( + panelArea / 2, + 2.2, + [0, 1, 0], + [0, height, 0], + ) + self.dragEffector.addFacet( + panelArea / 2, + 2.2, + [0, -1, 0], + [0, height, 0], + ) + self.dragEffector.atmoDensInMsg.subscribeTo( + self.environment.densityModel.envOutMsgs[-1] + ) + self.scObject.addDynamicEffector(self.dragEffector) + + self.simulator.AddModelToTask( + self.task_name, self.dragEffector, ModelPriority=priority + ) + + def _set_simple_nav_object(self, priority: int = 1400, **kwargs) -> None: + """Make the navigation module. + + Args: + priority: Model priority. + kwargs: Ignored + """ + self.simpleNavObject = simpleNav.SimpleNav() + self.simpleNavObject.ModelTag = "SimpleNav" + self.simpleNavObject.scStateInMsg.subscribeTo(self.scObject.scStateOutMsg) + self.simulator.AddModelToTask( + self.task_name, self.simpleNavObject, ModelPriority=priority + ) + + @aliveness_checker + def altitude_valid(self) -> bool: + """Check that satellite has not deorbited. + + Checks if altitude is greater than 200km above Earth's surface. + """ + return np.linalg.norm(self.r_BN_N) > (orbitalMotion.REQ_EARTH + 200) * 1e3 + + @default_args( + wheelSpeeds=lambda: np.random.uniform(-1500, 1500, 3), + maxWheelSpeed=np.inf, + u_max=0.200, + ) + def _set_reaction_wheel_dyn_effector( + self, + wheelSpeeds: Iterable[float], + maxWheelSpeed: float, + u_max: float, + priority: int = 997, + **kwargs, + ) -> None: + """Set the RW state effector parameters. + + Args: + wheelSpeeds: Initial speeds of each wheel [RPM] + maxWheelSpeed: Failure speed for wheels [RPM] + u_max: Torque producible by wheel [N*m] + priority: Model priority. + kwargs: Ignored + """ + self.maxWheelSpeed = maxWheelSpeed + self.rwStateEffector, self.rwFactory, _ = aP.balancedHR16Triad( + useRandom=False, + wheelSpeeds=wheelSpeeds, + ) + for RW in self.rwFactory.rwList.values(): + RW.u_max = u_max + self.rwFactory.addToSpacecraft( + "ReactionWheels", self.rwStateEffector, self.scObject + ) + self.simulator.AddModelToTask( + self.task_name, self.rwStateEffector, ModelPriority=priority + ) + + @aliveness_checker + def rw_speeds_valid(self) -> bool: + """Check if any wheel speed exceeds the maximum.""" + valid = all( + abs(speed) < self.maxWheelSpeed * macros.rpm2radsec + for speed in self.wheel_speeds + ) + return valid + + def _set_thruster_dyn_effector(self, priority: int = 996) -> None: + """Make the thruster state effector. + + Args: + priority: Model priority. + """ + self.thrusterSet, self.thrFactory = aP.idealMonarc1Octet() + thrModelTag = "ACSThrusterDynamics" + self.thrFactory.addToSpacecraft(thrModelTag, self.thrusterSet, self.scObject) + self.simulator.AddModelToTask( + self.task_name, self.thrusterSet, ModelPriority=priority + ) + + @default_args(thrusterPowerDraw=0.0) + def _set_thruster_power( + self, thrusterPowerDraw, priority: int = 899, **kwargs + ) -> None: + """Set the thruster power draw. + + Args: + thrusterPowerDraw: Constant power draw desat mode is active. [W] + priority: Model priority. + kwargs: Ignored + """ + self.thrusterPowerSink = simplePowerSink.SimplePowerSink() + self.thrusterPowerSink.ModelTag = "thrustPowerSink" + self.satellite.id + self.thrusterPowerSink.nodePowerOut = thrusterPowerDraw # Watts + self.simulator.AddModelToTask( + self.task_name, self.thrusterPowerSink, ModelPriority=priority + ) + self.powerMonitor.addPowerNodeToModel(self.thrusterPowerSink.nodePowerOutMsg) + + def _set_eclipse_object(self) -> None: + """Add the spacecraft to the eclipse module.""" + self.environment.eclipseObject.addSpacecraftToModel(self.scObject.scStateOutMsg) + self.eclipse_index = len(self.environment.eclipseObject.eclipseOutMsgs) - 1 + + @default_args( + panelArea=2 * 1.0 * 0.5, + panelEfficiency=0.20, + nHat_B=np.array([0, 1, 0]), + ) + def _set_solar_panel( + self, + panelArea: float, + panelEfficiency: float, + nHat_B: Iterable[float], + priority: int = 898, + **kwargs, + ) -> None: + """Set the solar panel parameters for power generation. + + Args: + panelArea: Solar panel surface area [m**2] + panelEfficiency: Efficiency coefficient of solar to electrical power + conversion + nHat_B: Body-fixed array normal vector + priority: Model priority. + kwargs: Ignored + """ + self.solarPanel = simpleSolarPanel.SimpleSolarPanel() + self.solarPanel.ModelTag = "solarPanel" + self.satellite.id + self.solarPanel.stateInMsg.subscribeTo(self.scObject.scStateOutMsg) + self.solarPanel.sunEclipseInMsg.subscribeTo( + self.environment.eclipseObject.eclipseOutMsgs[self.eclipse_index] + ) + self.solarPanel.sunInMsg.subscribeTo( + self.environment.gravFactory.spiceObject.planetStateOutMsgs[ + self.environment.sun_index + ] + ) + self.solarPanel.setPanelParameters( + unitTestSupport.np2EigenVectorXd(nHat_B), + panelArea, + panelEfficiency, + ) + self.simulator.AddModelToTask( + self.task_name, self.solarPanel, ModelPriority=priority + ) + + @default_args( + batteryStorageCapacity=80.0 * 3600.0, + storedCharge_Init=lambda: np.random.uniform(30.0 * 3600.0, 70.0 * 3600.0), + ) + def _set_battery( + self, + batteryStorageCapacity: float, + storedCharge_Init: float, + priority: int = 799, + **kwargs, + ) -> None: + """Set the battery model parameters. + + Args: + batteryStorageCapacity: Maximum battery charge [W*s] + storedCharge_Init: Initial battery charge [W*s] + priority: Model priority. + kwargs: Ignored + """ + self.powerMonitor = simpleBattery.SimpleBattery() + self.powerMonitor.ModelTag = "powerMonitor" + self.powerMonitor.storageCapacity = batteryStorageCapacity + self.powerMonitor.storedCharge_Init = storedCharge_Init + self.powerMonitor.addPowerNodeToModel(self.solarPanel.nodePowerOutMsg) + self.simulator.AddModelToTask( + self.task_name, self.powerMonitor, ModelPriority=priority + ) + + @aliveness_checker + def battery_valid(self) -> bool: + """Check if the battery has charge remaining.""" + return self.battery_charge > 0 + + @default_args( + rwBasePower=0.4, rwMechToElecEfficiency=0.0, rwElecToMechEfficiency=0.5 + ) + def _set_reaction_wheel_power( + self, + rwBasePower: float, + rwMechToElecEfficiency: float, + rwElecToMechEfficiency: float, + priority: int = 987, + **kwargs, + ) -> None: + """Set the reaction wheel power draw. + + Args: + rwBasePower: Constant power draw when operational [W] + rwMechToElecEfficiency: Efficiency factor to convert mechanical power to + electrical power + rwElecToMechEfficiency: Efficiency factor to convert electrical power to + mechanical power + priority: Model priority. + kwargs: Ignored + """ + self.rwPowerList = [] + for i_device in range(self.rwFactory.getNumOfDevices()): + powerRW = ReactionWheelPower.ReactionWheelPower() + powerRW.ModelTag = "rwPower" + str(i_device) + powerRW.basePowerNeed = rwBasePower # baseline power draw, Watts + powerRW.rwStateInMsg.subscribeTo(self.rwStateEffector.rwOutMsgs[i_device]) + powerRW.mechToElecEfficiency = rwMechToElecEfficiency + powerRW.elecToMechEfficiency = rwElecToMechEfficiency + self.rwPowerList.append(powerRW) + self.simulator.AddModelToTask( + self.task_name, powerRW, ModelPriority=(priority - i_device) + ) + self.powerMonitor.addPowerNodeToModel(powerRW.nodePowerOutMsg)
+ + + +
+[docs] +class LOSCommDynModel(BasicDynamicsModel): + """For evaluating line-of-sight connections between satellites for communication.""" + + def _init_dynamics_objects(self, **kwargs) -> None: + super()._init_dynamics_objects(**kwargs) + self._set_los_comms(**kwargs) + + def _set_los_comms(self, priority: int = 500, **kwargs) -> None: + """Set up line-of-sight visibility checking between satellites. + + Args: + priority: Model priority. + kwargs: Ignored + """ + self.losComms = spacecraftLocation.SpacecraftLocation() + self.losComms.ModelTag = "losComms" + self.losComms.primaryScStateInMsg.subscribeTo(self.scObject.scStateOutMsg) + self.losComms.planetInMsg.subscribeTo( + self.environment.gravFactory.spiceObject.planetStateOutMsgs[ + self.environment.body_index + ] + ) + self.losComms.rEquator = self.simulator.environment.planet.radEquator + self.losComms.rPolar = self.simulator.environment.planet.radEquator * 0.98 + self.losComms.maximumRange = -1.0 # m, unlimited + + self.los_comms_ids = [] + + for sat_dyn in self.simulator.dynamics_list.values(): + if sat_dyn != self and sat_dyn.satellite.id not in self.los_comms_ids: + self.losComms.addSpacecraftToModel(sat_dyn.scObject.scStateOutMsg) + self.los_comms_ids.append(sat_dyn.satellite.id) + sat_dyn.losComms.addSpacecraftToModel(self.scObject.scStateOutMsg) + sat_dyn.los_comms_ids.append(self.satellite.id) + if len(sat_dyn.los_comms_ids) == 1: + sat_dyn.simulator.AddModelToTask( + sat_dyn.task_name, sat_dyn.losComms, ModelPriority=priority + ) + + if len(self.los_comms_ids) > 0: + self.simulator.AddModelToTask( + self.task_name, self.losComms, ModelPriority=priority + )
+ + + +
+[docs] +class ImagingDynModel(BasicDynamicsModel): + """Equips the satellite with an instrument, storage unit, and transmitter.""" + + @property + def storage_level(self): + """Storage level [bits].""" + return self.storageUnit.storageUnitDataOutMsg.read().storageLevel + + @property + def storage_level_fraction(self): + """Storage level as a fraction of capacity.""" + return self.storage_level / self.storageUnit.storageCapacity + + def _init_dynamics_objects(self, **kwargs) -> None: + super()._init_dynamics_objects(**kwargs) + self._set_instrument_power_sink(**kwargs) + self._set_transmitter_power_sink(**kwargs) + self._set_instrument(**kwargs) + self._set_transmitter(**kwargs) + self._set_storage_unit(**kwargs) + self._set_imaging_target(**kwargs) + + @default_args(instrumentBaudRate=8e6) + def _set_instrument( + self, instrumentBaudRate: float, priority: int = 895, **kwargs + ) -> None: + """Create the instrument model. + + Args: + instrumentBaudRate: Data generated in a single step by an image [bits] + priority: Model priority. + kwargs: Ignored + """ + self.instrument = simpleInstrument.SimpleInstrument() + self.instrument.ModelTag = "instrument" + self.satellite.id + self.instrument.nodeBaudRate = ( + instrumentBaudRate / self.dyn_rate + ) # make imaging instantaneous + self.instrument.nodeDataName = "Instrument" + self.satellite.id + self.simulator.AddModelToTask( + self.task_name, self.instrument, ModelPriority=priority + ) + + @default_args(transmitterBaudRate=-8e6, transmitterNumBuffers=100) + def _set_transmitter( + self, + transmitterBaudRate: float, + instrumentBaudRate: float, + transmitterNumBuffers: int, + priority: int = 798, + **kwargs, + ) -> None: + """Create the transmitter model. + + Args: + transmitterBaudRate: Rate of data downlink. Should be negative. [baud] + instrumentBaudRate: Image size, used to set packet size [bits] + transmitterNumBuffers: Number of transmitter buffers + priority: Model priority. + kwargs: Ignored + """ + if transmitterBaudRate > 0: + self.logger.warning( + "Positive transmitterBaudRate will lead to increased data in buffer " + + "on downlink" + ) + self.transmitter = spaceToGroundTransmitter.SpaceToGroundTransmitter() + self.transmitter.ModelTag = "transmitter" + self.satellite.id + self.transmitter.nodeBaudRate = transmitterBaudRate # baud + # set packet size equal to the size of a single image + self.transmitter.packetSize = -instrumentBaudRate # bits + self.transmitter.numBuffers = transmitterNumBuffers + self.simulator.AddModelToTask( + self.task_name, self.transmitter, ModelPriority=priority + ) + + @default_args(instrumentPowerDraw=-30.0) + def _set_instrument_power_sink( + self, instrumentPowerDraw: float, priority: int = 897, **kwargs + ) -> None: + """Set the instrument power sink parameters. + + Args: + instrumentPowerDraw: Power draw when instrument is enabled [W] + priority: Model priority. + kwargs: Ignored + """ + self.instrumentPowerSink = simplePowerSink.SimplePowerSink() + self.instrumentPowerSink.ModelTag = "insPowerSink" + self.satellite.id + self.instrumentPowerSink.nodePowerOut = instrumentPowerDraw # Watts + self.simulator.AddModelToTask( + self.task_name, self.instrumentPowerSink, ModelPriority=priority + ) + self.powerMonitor.addPowerNodeToModel(self.instrumentPowerSink.nodePowerOutMsg) + + @default_args(transmitterPowerDraw=-15.0) + def _set_transmitter_power_sink( + self, transmitterPowerDraw: float, priority: int = 896, **kwargs + ) -> None: + """Set the transmitter power sink parameters. + + Args: + transmitterPowerDraw: Power draw when transmitter is enabled [W] + priority: Model priority. + kwargs: Ignored + """ + self.transmitterPowerSink = simplePowerSink.SimplePowerSink() + self.transmitterPowerSink.ModelTag = "transPowerSink" + self.satellite.id + self.transmitterPowerSink.nodePowerOut = transmitterPowerDraw # Watts + self.simulator.AddModelToTask( + self.task_name, self.transmitterPowerSink, ModelPriority=priority + ) + self.powerMonitor.addPowerNodeToModel(self.transmitterPowerSink.nodePowerOutMsg) + + @default_args( + dataStorageCapacity=20 * 8e6, bufferNames=None, storageUnitValidCheck=True + ) + def _set_storage_unit( + self, + dataStorageCapacity: int, + transmitterNumBuffers: Optional[int] = None, + bufferNames: Optional[Iterable[str]] = None, + priority: int = 699, + storageUnitValidCheck: bool = True, + **kwargs, + ) -> None: + """Configure the storage unit and its buffers. + + Args: + dataStorageCapacity: Maximum data to be stored [bits] + transmitterNumBuffers: Number of unit buffers. Not necessary if bufferNames + given. + bufferNames: List of buffer names to use. Named by number if None. + priority: Model priority. + storageUnitValidCheck: If True, check that the storage level is below the + storage capacity. + kwargs: Ignored + """ + self.storageUnit = partitionedStorageUnit.PartitionedStorageUnit() + self.storageUnit.ModelTag = "storageUnit" + self.satellite.id + self.storageUnit.storageCapacity = dataStorageCapacity # bits + self.storageUnit.addDataNodeToModel(self.instrument.nodeDataOutMsg) + self.storageUnit.addDataNodeToModel(self.transmitter.nodeDataOutMsg) + self.storageUnitValidCheck = storageUnitValidCheck + # Add all of the targets to the data buffer + if bufferNames is None: + for buffer_idx in range(transmitterNumBuffers): + self.storageUnit.addPartition(str(buffer_idx)) + else: + if transmitterNumBuffers is not None and transmitterNumBuffers != len( + bufferNames + ): + raise ValueError( + "transmitterNumBuffers cannot be different than len(bufferNames)." + ) + for buffer_name in bufferNames: + self.storageUnit.addPartition(buffer_name) + + # Add the storage unit to the transmitter + self.transmitter.addStorageUnitToTransmitter( + self.storageUnit.storageUnitDataOutMsg + ) + + self.simulator.AddModelToTask( + self.task_name, self.storageUnit, ModelPriority=priority + ) + + @aliveness_checker + def data_storage_valid(self) -> bool: + """Check that the buffer has not run out of space.""" + storage_check = self.storageUnitValidCheck + if storage_check: + return self.storage_level < self.storageUnit.storageCapacity or np.isclose( + self.storage_level, self.storageUnit.storageCapacity + ) + else: + return True + + @default_args( + groundLocationPlanetRadius=orbitalMotion.REQ_EARTH * 1e3, + imageTargetMinimumElevation=np.radians(45.0), + imageTargetMaximumRange=-1, + ) + def _set_imaging_target( + self, + groundLocationPlanetRadius: float, + imageTargetMinimumElevation: float, + imageTargetMaximumRange: float, + priority: int = 2000, + **kwargs, + ) -> None: + """Add a generic imaging target to dynamics. + + The target must be updated with a particular location when used. + + Args: + groundLocationPlanetRadius: Radius of ground locations from center of planet + [m] + imageTargetMinimumElevation: Minimum elevation angle from target to + satellite when imaging [rad] + imageTargetMaximumRange: Maximum range from target to satellite when + imaging. -1 to disable. [m] + priority: Model priority. + kwargs: Ignored + """ + self.imagingTarget = groundLocation.GroundLocation() + self.imagingTarget.ModelTag = "ImagingTarget" + self.imagingTarget.planetRadius = groundLocationPlanetRadius + self.imagingTarget.specifyLocation(0.0, 0.0, 1000.0) + self.imagingTarget.planetInMsg.subscribeTo( + self.environment.gravFactory.spiceObject.planetStateOutMsgs[ + self.environment.body_index + ] + ) + self.imagingTarget.minimumElevation = imageTargetMinimumElevation + self.imagingTarget.maximumRange = imageTargetMaximumRange + + self.simulator.AddModelToTask( + self.environment.env_task_name, + self.imagingTarget, + ModelPriority=priority, + ) + self.imagingTarget.addSpacecraftToModel(self.scObject.scStateOutMsg) + +
+[docs] + def reset_for_action(self) -> None: + """Shut off power sinks.""" + super().reset_for_action() + self.transmitter.dataStatus = 0 + self.transmitterPowerSink.powerStatus = 0 + self.instrumentPowerSink.powerStatus = 0
+
+ + + +
+[docs] +class ContinuousImagingDynModel(ImagingDynModel): + """Equips the satellite for continuous nadir imaging. + + Equips satellite with an instrument, storage unit, and transmitter + for continuous nadir imaging. + """ + + @default_args(instrumentBaudRate=8e6) + def _set_instrument( + self, instrumentBaudRate: float, priority: int = 895, **kwargs + ) -> None: + """Create the continuous instrument model. + + Args: + instrumentBaudRate: Data generated in step by continuous imaging [bits] + priority: Model priority. + kwargs: Ignored + """ + self.instrument = simpleInstrument.SimpleInstrument() + self.instrument.ModelTag = "instrument" + self.satellite.id + self.instrument.nodeBaudRate = instrumentBaudRate # make imaging instantaneous + self.instrument.nodeDataName = "Instrument" + self.satellite.id + self.simulator.AddModelToTask( + self.task_name, self.instrument, ModelPriority=priority + ) + + @default_args( + dataStorageCapacity=20 * 8e6, storageUnitValidCheck=True, storageInit=0 + ) + def _set_storage_unit( + self, + dataStorageCapacity: int, + priority: int = 699, + storageUnitValidCheck: bool = True, + storageInit: int = 0, + **kwargs, + ) -> None: + """Configure the storage unit and its buffers. + + Args: + dataStorageCapacity: Maximum data to be stored [bits] + priority: Model priority. + storageUnitValidCheck: If True, check that the storage level is below the + storage capacity. + storageInit: Initial storage level [bits] + kwargs: Ignored + """ + self.storageUnit = simpleStorageUnit.SimpleStorageUnit() + self.storageUnit.ModelTag = "storageUnit" + self.satellite.id + self.storageUnit.storageCapacity = dataStorageCapacity # bits + self.storageUnit.addDataNodeToModel(self.instrument.nodeDataOutMsg) + self.storageUnit.addDataNodeToModel(self.transmitter.nodeDataOutMsg) + self.storageUnitValidCheck = storageUnitValidCheck + self.storageUnit.setDataBuffer(storageInit) + + # Add the storage unit to the transmitter + self.transmitter.addStorageUnitToTransmitter( + self.storageUnit.storageUnitDataOutMsg + ) + + self.simulator.AddModelToTask( + self.task_name, self.storageUnit, ModelPriority=priority + ) + + @default_args( + imageTargetMaximumRange=-1, + ) + def _set_imaging_target( + self, + imageTargetMaximumRange: float = -1, + priority: int = 2000, + **kwargs, + ) -> None: + """Add a generic imaging target to dynamics. + + The target must be updated with a particular location when used. + + Args: + imageTargetMaximumRange: Maximum range from target to satellite when + imaging. -1 to disable. [m] + priority: Model priority. + kwargs: Ignored + """ + self.imagingTarget = groundLocation.GroundLocation() + self.imagingTarget.ModelTag = "scanningTarget" + self.imagingTarget.planetRadius = 1e-6 + self.imagingTarget.specifyLocation(0, 0, 0) + self.imagingTarget.planetInMsg.subscribeTo( + self.environment.gravFactory.spiceObject.planetStateOutMsgs[ + self.environment.body_index + ] + ) + self.imagingTarget.minimumElevation = np.radians(-90) + self.imagingTarget.maximumRange = imageTargetMaximumRange + + self.simulator.AddModelToTask( + self.environment.env_task_name, + self.imagingTarget, + ModelPriority=priority, + ) + self.imagingTarget.addSpacecraftToModel(self.scObject.scStateOutMsg)
+ + + +
+[docs] +class GroundStationDynModel(ImagingDynModel): + """Model that connects satellite to environment ground stations.""" + + @classmethod + @property + def _requires_env(cls) -> list[type["EnvironmentModel"]]: + return super()._requires_env + [environment.GroundStationEnvModel] + + def _init_dynamics_objects(self, **kwargs) -> None: + super()._init_dynamics_objects(**kwargs) + self._set_ground_station_locations() + + def _set_ground_station_locations(self) -> None: + """Connect the transmitter to ground stations.""" + for groundStation in self.environment.groundStations: + groundStation.addSpacecraftToModel(self.scObject.scStateOutMsg) + self.transmitter.addAccessMsgToTransmitter(groundStation.accessOutMsgs[-1])
+ + + +
+[docs] +class FullFeaturedDynModel(GroundStationDynModel, LOSCommDynModel): + """Convenience class for a satellite with ground station and line-of-sight comms.""" + + pass
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/simulation/environment.html b/_modules/bsk_rl/envs/general_satellite_tasking/simulation/environment.html new file mode 100644 index 00000000..b597c304 --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/simulation/environment.html @@ -0,0 +1,437 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.simulation.environment — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.simulation.environment

+"""Basilisk environment models."""
+
+import logging
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING, Any, Optional, Union
+from weakref import proxy
+
+if TYPE_CHECKING:  # pragma: no cover
+    from bsk_rl.envs.general_satellite_tasking.types import Simulator
+
+import numpy as np
+from Basilisk import __path__
+from Basilisk.simulation import (
+    eclipse,
+    ephemerisConverter,
+    exponentialAtmosphere,
+    groundLocation,
+)
+from Basilisk.utilities import macros as mc
+from Basilisk.utilities import orbitalMotion, simIncludeGravBody
+
+from bsk_rl.envs.general_satellite_tasking.utils.functional import (
+    collect_default_args,
+    default_args,
+)
+from bsk_rl.envs.general_satellite_tasking.utils.orbital import random_epoch
+
+logger = logging.getLogger(__name__)
+
+bsk_path = __path__[0]
+
+
+
+[docs] +class EnvironmentModel(ABC): + """Abstract Basilisk environment model. + + One EnvironmentModel is instantiated for the environment each time a new simulator + is created. + """ + +
+[docs] + @classmethod + def default_env_args(cls, **kwargs) -> dict[str, Any]: + """Compile default argments for the environment model.""" + defaults = collect_default_args(cls) + for k, v in kwargs.items(): + if k not in defaults: + raise KeyError(f"{k} not a valid key for env_args") + defaults[k] = v + return defaults
+ + +
+[docs] + def __init__( + self, + simulator: "Simulator", + env_rate: float, + priority: int = 300, + **kwargs, + ) -> None: + """Construct base environment model. + + Args: + simulator: Simulator using this model + env_rate: Rate of environment simulation [s] + priority: Model priority. + kwargs: Ignored + """ + self.simulator: Simulator = proxy(simulator) + + env_proc_name = "EnvironmentProcess" + env_proc = self.simulator.CreateNewProcess(env_proc_name, priority) + + # Define process name, task name and task time-step + self.env_task_name = "EnvironmentTask" + env_proc.addTask( + self.simulator.CreateNewTask(self.env_task_name, mc.sec2nano(env_rate)) + ) + + self._init_environment_objects(**kwargs)
+ + + def __del__(self): + """Log when environment is deleted.""" + logger.debug("Basilisk environment deleted") + + @abstractmethod # pragma: no cover + def _init_environment_objects(self, **kwargs) -> None: + """Caller for all environment objects.""" + pass
+ + + +
+[docs] +class BasicEnvironmentModel(EnvironmentModel): + """Basic Environment with minimum necessary Basilisk environment components.""" + + @property + def PN(self): + """Planet relative to inertial frame rotation matrix.""" + return np.array( + self.gravFactory.spiceObject.planetStateOutMsgs[self.body_index] + .read() + .J20002Pfix + ).reshape((3, 3)) + + @property + def omega_PN_N(self): + """Planet angular velocity in inertial frame [rad/s].""" + PNdot = np.array( + self.gravFactory.spiceObject.planetStateOutMsgs[self.body_index] + .read() + .J20002Pfix_dot + ).reshape((3, 3)) + skew_PN_N = -np.matmul(np.transpose(self.PN), PNdot) + return np.array([skew_PN_N[2, 1], skew_PN_N[0, 2], skew_PN_N[1, 0]]) + + def _init_environment_objects(self, **kwargs) -> None: + self._set_gravity_bodies(**kwargs) + self._set_epoch_object(**kwargs) + self._set_atmosphere_density_model(**kwargs) + self._set_eclipse_object(**kwargs) + + @default_args(utc_init=random_epoch) + def _set_gravity_bodies( + self, utc_init: str, priority: int = 1100, **kwargs + ) -> None: + """Specify gravitational models to use in the simulation. + + Args: + utc_init: UTC datetime string + priority: Model priority. + kwargs: Ignored + """ + self.gravFactory = simIncludeGravBody.gravBodyFactory() + self.gravFactory.createSun() + self.planet = self.gravFactory.createEarth() + self.sun_index = 0 + self.body_index = 1 + + self.planet.isCentralBody = ( + True # ensure this is the central gravitational body + ) + self.planet.useSphericalHarmonicsGravityModel( + bsk_path + "/supportData/LocalGravData/GGM03S.txt", 10 + ) + + # setup Spice interface for some solar system bodies + timeInitString = utc_init + self.gravFactory.createSpiceInterface( + bsk_path + "/supportData/EphemerisData/", timeInitString + ) + self.gravFactory.spiceObject.zeroBase = "earth" + + self.simulator.AddModelToTask( + self.env_task_name, self.gravFactory.spiceObject, ModelPriority=priority + ) + + def _set_epoch_object(self, priority: int = 988, **kwargs) -> None: + """Add the ephemeris object to use with the SPICE library. + + Args: + priority: Model priority. + kwargs: Ignored + """ + self.ephemConverter = ephemerisConverter.EphemerisConverter() + self.ephemConverter.ModelTag = "ephemConverter" + self.ephemConverter.addSpiceInputMsg( + self.gravFactory.spiceObject.planetStateOutMsgs[self.sun_index] + ) + self.ephemConverter.addSpiceInputMsg( + self.gravFactory.spiceObject.planetStateOutMsgs[self.body_index] + ) + self.simulator.AddModelToTask( + self.env_task_name, self.ephemConverter, ModelPriority=priority + ) + + @default_args( + planetRadius=orbitalMotion.REQ_EARTH * 1e3, + baseDensity=1.22, + scaleHeight=8e3, + ) + def _set_atmosphere_density_model( + self, + planetRadius: float, + baseDensity: float, + scaleHeight: float, + priority: int = 1000, + **kwargs, + ) -> None: + """Add the exponential gravity model. + + Args: + planetRadius: Planet ground radius [m] + baseDensity: Exponential model parameter [kg/m^3] + scaleHeight: Exponential model parameter [m] + priority (int, optional): Model priority. + kwargs: Ignored + """ + self.densityModel = exponentialAtmosphere.ExponentialAtmosphere() + self.densityModel.ModelTag = "expDensity" + self.densityModel.planetRadius = planetRadius + self.densityModel.baseDensity = baseDensity + self.densityModel.scaleHeight = scaleHeight + self.densityModel.planetPosInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.body_index] + ) + self.simulator.AddModelToTask( + self.env_task_name, self.densityModel, ModelPriority=priority + ) + + def _set_eclipse_object(self, priority: int = 988, **kwargs) -> None: + """Specify what celestial object is causing an eclipse message. + + Args: + priority: Model priority. + kwargs: Ignored + """ + self.eclipseObject = eclipse.Eclipse() + self.eclipseObject.addPlanetToModel( + self.gravFactory.spiceObject.planetStateOutMsgs[self.body_index] + ) + self.eclipseObject.sunInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.sun_index] + ) + self.simulator.AddModelToTask( + self.env_task_name, self.eclipseObject, ModelPriority=priority + ) + + def __del__(self) -> None: + """Log when environment is deleted and unload SPICE.""" + super().__del__() + try: + self.gravFactory.unloadSpiceKernels() + except AttributeError: + pass
+ + + +
+[docs] +class GroundStationEnvModel(BasicEnvironmentModel): + """Model that includes downlink ground stations.""" + + def _init_environment_objects(self, **kwargs) -> None: + super()._init_environment_objects(**kwargs) + self._set_ground_locations(**kwargs) + + @default_args( + groundStationsData=[ + dict(name="Boulder", lat=40.009971, long=-105.243895, elev=1624), + dict(name="Merritt", lat=28.3181, long=-80.6660, elev=0.9144), + dict(name="Singapore", lat=1.3521, long=103.8198, elev=15), + dict(name="Weilheim", lat=47.8407, long=11.1421, elev=563), + dict(name="Santiago", lat=-33.4489, long=-70.6693, elev=570), + dict(name="Dongara", lat=-29.2452, long=114.9326, elev=34), + dict(name="Hawaii", lat=19.8968, long=-155.5828, elev=9), + ], + groundLocationPlanetRadius=orbitalMotion.REQ_EARTH * 1e3, + gsMinimumElevation=10.0 * mc.D2R, + gsMaximumRange=-1, + ) + def _set_ground_locations( + self, + groundStationsData: list[dict[str, Union[str, float]]], + groundLocationPlanetRadius: float, + gsMinimumElevation: float, + gsMaximumRange: float, + priority: int = 1399, + **kwargs, + ) -> None: + """Specify the ground locations of interest. + + Args: + groundStationsData: Dicts with name (optional), lat (required), long + (required), and elevation (optional). + groundLocationPlanetRadius: Radius of ground locations from center of planet + [m] + gsMinimumElevation: Minimum elevation angle from station to satellite when + downlinking [rad] + gsMaximumRange: Maximum range from station to satellite when downlinking. -1 + to disable. [m] + priority: Model priority. + kwargs: Ignored + """ + self.groundStations = [] + self.groundLocationPlanetRadius = groundLocationPlanetRadius + self.gsMinimumElevation = gsMinimumElevation + self.gsMaximumRange = gsMaximumRange + for i, groundStationData in enumerate(groundStationsData): + self._create_ground_station(**groundStationData, priority=priority - i) + + def _create_ground_station( + self, + lat: float, + long: float, + elev: float = 0, + name: Optional[str] = None, + priority: int = 1399, + ) -> None: + """Add a ground station with given parameters. + + Args: + lat: Latitude [deg] + long: Longitude [deg] + elev: Elevation [m]. + name: Ground station identifier. + priority: Model priority. + """ + if name is None: + name = str(len(self.groundStations)) + + groundStation = groundLocation.GroundLocation() + groundStation.ModelTag = "GroundStation" + name + groundStation.planetRadius = self.groundLocationPlanetRadius + groundStation.specifyLocation(lat * mc.D2R, long * mc.D2R, elev) + groundStation.planetInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.body_index] + ) + groundStation.minimumElevation = self.gsMinimumElevation + groundStation.maximumRange = self.gsMaximumRange + self.groundStations.append(groundStation) + + self.simulator.AddModelToTask( + self.env_task_name, groundStation, ModelPriority=priority + )
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/simulation/fsw.html b/_modules/bsk_rl/envs/general_satellite_tasking/simulation/fsw.html new file mode 100644 index 00000000..5eb7f3cc --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/simulation/fsw.html @@ -0,0 +1,1071 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.simulation.fsw — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.simulation.fsw

+"""Basilisk flight software models."""
+
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING, Callable, Iterable, Optional
+from weakref import proxy
+
+if TYPE_CHECKING:  # pragma: no cover
+    from bsk_rl.envs.general_satellite_tasking.types import (
+        DynamicsModel,
+        EnvironmentModel,
+        Satellite,
+        Simulator,
+    )
+
+import Basilisk.architecture.cMsgCInterfacePy as cMsgPy
+import numpy as np
+from Basilisk.architecture import messaging
+from Basilisk.fswAlgorithms import (
+    attTrackingError,
+    hillPoint,
+    locationPointing,
+    mrpFeedback,
+    mrpSteering,
+    rateServoFullNonlinear,
+    rwMotorTorque,
+    scanningInstrumentController,
+    simpleInstrumentController,
+    thrForceMapping,
+    thrMomentumDumping,
+    thrMomentumManagement,
+)
+from Basilisk.utilities import macros as mc
+
+from bsk_rl.envs.general_satellite_tasking.simulation import dynamics
+from bsk_rl.envs.general_satellite_tasking.utils.functional import (
+    check_aliveness_checkers,
+    default_args,
+)
+
+
+
+[docs] +def action( + func: Callable[..., None] +) -> Callable[Callable[..., None], Callable[..., None]]: + """Decorate to run housekeeping for action functions called by the satellite.""" + + def inner(self, *args, **kwargs) -> Callable[..., None]: + self.fsw_proc.disableAllTasks() + self._zero_gateway_msgs() + self.dynamics.reset_for_action() + for task in self.tasks: + task.reset_for_action() + return func(self, *args, **kwargs) + + return inner
+ + + +
+[docs] +class FSWModel(ABC): + """Abstract Basilisk flight software model. + + One FSWModel is instantiated for each satellite in the environment each time a + new simulator is created. + """ + + @classmethod + @property + def _requires_dyn(cls) -> list[type["DynamicsModel"]]: + """Define minimum DynamicsModels for compatibility.""" + return [] + +
+[docs] + def __init__( + self, satellite: "Satellite", fsw_rate: float, priority: int = 100, **kwargs + ) -> None: + """Construct a base flight software model. + + Args: + satellite: Satellite modelled by this model + fsw_rate: Rate of FSW simulation [s] + priority: Model priority. + kwargs: Passed to task creation functions + """ + self.satellite = satellite + self.logger = self.satellite.logger.getChild(self.__class__.__name__) + + for required in self._requires_dyn: + if not issubclass(satellite.dyn_type, required): + raise TypeError( + f"{satellite.dyn_type} must be a subclass of {required} to " + + f"use FSW model of type {self.__class__}" + ) + + fsw_proc_name = "FSWProcess" + self.satellite.id + self.fsw_proc = self.simulator.CreateNewProcess(fsw_proc_name, priority) + self.fsw_rate = fsw_rate + + self.tasks = self._make_task_list() + + for task in self.tasks: + task.create_task() + + for task in self.tasks: + task._create_module_data() + + self._set_messages() + + for task in self.tasks: + task._init_objects(**kwargs) + + self.fsw_proc.disableAllTasks()
+ + + @property + def simulator(self) -> "Simulator": + """Reference to the episode simulator.""" + return self.satellite.simulator + + @property + def environment(self) -> "EnvironmentModel": + """Reference to the episode environment model.""" + return self.simulator.environment + + @property + def dynamics(self) -> "DynamicsModel": + """Reference to the satellite dynamics model for the episode.""" + return self.satellite.dynamics + + def _make_task_list(self) -> list["Task"]: + return [] + + @abstractmethod # pragma: no cover + def _set_messages(self) -> None: + """Message setup after task creation.""" + pass + +
+[docs] + def is_alive(self, log_failure=False) -> bool: + """Check if the fsw model has failed any aliveness requirements. + + Returns: + If the satellite fsw is still alive + """ + return check_aliveness_checkers(self, log_failure=log_failure)
+ + + def __del__(self): + """Log when FSW model is deleted.""" + self.logger.debug("Basilisk FSW deleted")
+ + + +
+[docs] +class Task(ABC): + """Abstract class for defining FSW tasks.""" + + @property + @abstractmethod # pragma: no cover + def name(self) -> str: # noqa: D102 + pass + +
+[docs] + def __init__(self, fsw: FSWModel, priority: int) -> None: + """Template class for defining FSW processes. + + Args: + fsw: FSW model task contributes to + priority: Task priority + """ + self.fsw: FSWModel = proxy(fsw) + self.priority = priority
+ + +
+[docs] + def create_task(self) -> None: + """Add task to FSW with a unique name.""" + self.fsw.fsw_proc.addTask( + self.fsw.simulator.CreateNewTask( + self.name + self.fsw.satellite.id, mc.sec2nano(self.fsw.fsw_rate) + ), + taskPriority=self.priority, + )
+ + + @abstractmethod # pragma: no cover + def _create_module_data(self) -> None: + """Create module data wrappers.""" + pass + + @abstractmethod # pragma: no cover + def _init_objects(self, **kwargs) -> None: + """Initialize model parameters with satellite arguments.""" + pass + + def _add_model_to_task(self, module, priority) -> None: + """Add a model to this task. + + Args: + module: Basilisk module + priority: Model priority + """ + self.fsw.simulator.AddModelToTask( + self.name + self.fsw.satellite.id, + module, + ModelPriority=priority, + ) + +
+[docs] + def reset_for_action(self) -> None: + """Housekeeping for task when a new action is called. + + Disables task by default, can be overridden by subclasses. + """ + self.fsw.simulator.disableTask(self.name + self.fsw.satellite.id)
+
+ + + +
+[docs] +class BasicFSWModel(FSWModel): + """Basic FSW model with minimum necessary Basilisk components.""" + + @classmethod + @property + def _requires_dyn(cls) -> list[type["DynamicsModel"]]: + return [dynamics.BasicDynamicsModel] + + def _make_task_list(self) -> list[Task]: + return [ + self.SunPointTask(self), + self.NadirPointTask(self), + self.RWDesatTask(self), + self.TrackingErrorTask(self), + self.MRPControlTask(self), + ] + + def _set_messages(self) -> None: + self._set_config_msgs() + self._set_gateway_msgs() + + def _set_config_msgs(self) -> None: + self._set_vehicle_config_msg() + self._set_thrusters_config_msg() + self._set_rw_config_msg() + + def _set_vehicle_config_msg(self) -> None: + """Set the vehicle configuration message.""" + # Use the same inertia in the FSW algorithm as in the simulation + vehicleConfigOut = messaging.VehicleConfigMsgPayload() + vehicleConfigOut.ISCPntB_B = self.dynamics.I_mat + self.vcConfigMsg = messaging.VehicleConfigMsg().write(vehicleConfigOut) + + def _set_thrusters_config_msg(self) -> None: + """Import the thrusters configuration information.""" + self.thrusterConfigMsg = self.dynamics.thrFactory.getConfigMessage() + + def _set_rw_config_msg(self) -> None: + """Configure RW pyramid exactly as it is in dynamics.""" + self.fswRwConfigMsg = self.dynamics.rwFactory.getConfigMessage() + + def _set_gateway_msgs(self) -> None: + """Create C-wrapped gateway messages.""" + self.attRefMsg = cMsgPy.AttRefMsg_C() + self.attGuidMsg = cMsgPy.AttGuidMsg_C() + + self._zero_gateway_msgs() + + # connect gateway FSW effector command msgs with the dynamics + self.dynamics.rwStateEffector.rwMotorCmdInMsg.subscribeTo( + self.rwMotorTorque.rwMotorTorqueOutMsg + ) + self.dynamics.thrusterSet.cmdsInMsg.subscribeTo( + self.thrDump.thrusterOnTimeOutMsg + ) + + def _zero_gateway_msgs(self) -> None: + """Zero all the FSW gateway message payloads.""" + self.attRefMsg.write(messaging.AttRefMsgPayload()) + self.attGuidMsg.write(messaging.AttGuidMsgPayload()) + + @action + def action_drift(self) -> None: + """Disable all tasks.""" + self.simulator.disableTask( + BasicFSWModel.MRPControlTask.name + self.satellite.id + ) + +
+[docs] + class SunPointTask(Task): + """Task to generate sun-pointing reference.""" + + name = "sunPointTask" + +
+[docs] + def __init__(self, fsw, priority=99) -> None: # noqa: D107 + super().__init__(fsw, priority)
+ + + def _create_module_data(self) -> None: + self.sunPoint = self.fsw.sunPoint = locationPointing.locationPointing() + self.sunPoint.ModelTag = "sunPoint" + + def _init_objects(self, nHat_B: Iterable[float], **kwargs) -> None: + """Configure the sun-pointing task. + + Args: + nHat_B: Solar array normal vector + kwargs: Ignored + """ + self.sunPoint.pHat_B = nHat_B + self.sunPoint.scAttInMsg.subscribeTo( + self.fsw.dynamics.simpleNavObject.attOutMsg + ) + self.sunPoint.scTransInMsg.subscribeTo( + self.fsw.dynamics.simpleNavObject.transOutMsg + ) + self.sunPoint.celBodyInMsg.subscribeTo( + self.fsw.environment.ephemConverter.ephemOutMsgs[ + self.fsw.environment.sun_index + ] + ) + self.sunPoint.useBoresightRateDamping = 1 + cMsgPy.AttGuidMsg_C_addAuthor( + self.sunPoint.attGuidOutMsg, self.fsw.attGuidMsg + ) + + self._add_model_to_task(self.sunPoint, priority=1200)
+ + + @action + def action_charge(self) -> None: + """Charge battery using solar panels.""" + self.sunPoint.Reset(self.simulator.sim_time_ns) + self.simulator.enableTask(self.SunPointTask.name + self.satellite.id) + +
+[docs] + class NadirPointTask(Task): + """Task to generate nadir-pointing reference.""" + + name = "nadirPointTask" + +
+[docs] + def __init__(self, fsw, priority=98) -> None: # noqa: D107 + super().__init__(fsw, priority)
+ + + def _create_module_data(self) -> None: + self.hillPoint = self.fsw.hillPoint = hillPoint.hillPoint() + self.hillPoint.ModelTag = "hillPoint" + + def _init_objects(self, **kwargs) -> None: + """Configure the nadir-pointing task.""" + self.hillPoint.transNavInMsg.subscribeTo( + self.fsw.dynamics.simpleNavObject.transOutMsg + ) + self.hillPoint.celBodyInMsg.subscribeTo( + self.fsw.environment.ephemConverter.ephemOutMsgs[ + self.fsw.environment.body_index + ] + ) + cMsgPy.AttRefMsg_C_addAuthor( + self.hillPoint.attRefOutMsg, self.fsw.attRefMsg + ) + + self._add_model_to_task(self.hillPoint, priority=1199)
+ + +
+[docs] + class RWDesatTask(Task): + """Task to desaturate reaction wheels.""" + + name = "rwDesatTask" + +
+[docs] + def __init__(self, fsw, priority=97) -> None: # noqa: D107 + super().__init__(fsw, priority)
+ + + def _create_module_data(self) -> None: + """Set up momentum dumping and thruster control.""" + # Momentum dumping configuration + self.thrDesatControl = ( + self.fsw.thrDesatControl + ) = thrMomentumManagement.thrMomentumManagement() + self.thrDesatControl.ModelTag = "thrMomentumManagement" + + self.thrDump = self.fsw.thrDump = thrMomentumDumping.thrMomentumDumping() + self.thrDump.ModelTag = "thrDump" + + # Thruster force mapping configuration + self.thrForceMapping = ( + self.fsw.thrForceMapping + ) = thrForceMapping.thrForceMapping() + self.thrForceMapping.ModelTag = "thrForceMapping" + + def _init_objects(self, **kwargs) -> None: + self._set_thruster_mapping(**kwargs) + self._set_momentum_dumping(**kwargs) + + @default_args(controlAxes_B=[1, 0, 0, 0, 1, 0, 0, 0, 1], thrForceSign=+1) + def _set_thruster_mapping( + self, controlAxes_B: Iterable[float], thrForceSign: int, **kwargs + ) -> None: + """Configure the thruster mapping. + + Args: + controlAxes_B: Control unit axes + thrForceSign: Flag indicating if pos (+1) or negative (-1) thruster + solutions are found + kwargs: Ignored + """ + self.thrForceMapping.cmdTorqueInMsg.subscribeTo( + self.thrDesatControl.deltaHOutMsg + ) + self.thrForceMapping.thrConfigInMsg.subscribeTo(self.fsw.thrusterConfigMsg) + self.thrForceMapping.vehConfigInMsg.subscribeTo(self.fsw.vcConfigMsg) + self.thrForceMapping.controlAxes_B = controlAxes_B + self.thrForceMapping.thrForceSign = thrForceSign + self.thrForceMapping.angErrThresh = 3.15 + + self._add_model_to_task(self.thrForceMapping, priority=1192) + + @default_args( + hs_min=0.0, + maxCounterValue=4, + thrMinFireTime=0.02, + desatAttitude="sun", + ) + def _set_momentum_dumping( + self, + hs_min: float, + maxCounterValue: int, + thrMinFireTime: float, + desatAttitude: Optional[str], + **kwargs, + ) -> None: + """Configure the momentum dumping algorithm. + + Args: + hs_min: minimum RW cluster momentum for dumping [N*m*s] + maxCounterValue: Control periods between firing thrusters + thrMinFireTime: Minimum thruster firing time [s] + desatAttitude: Direction to point while desaturating: "sun" points + panels at sun, "nadir" points instrument nadir, None disables + attitude control + kwargs: Ignored + """ + self.fsw.desatAttitude = desatAttitude + self.thrDesatControl.hs_min = hs_min # Nms + self.thrDesatControl.rwSpeedsInMsg.subscribeTo( + self.fsw.dynamics.rwStateEffector.rwSpeedOutMsg + ) + self.thrDesatControl.rwConfigDataInMsg.subscribeTo(self.fsw.fswRwConfigMsg) + + self.thrDump.deltaHInMsg.subscribeTo(self.thrDesatControl.deltaHOutMsg) + self.thrDump.thrusterImpulseInMsg.subscribeTo( + self.thrForceMapping.thrForceCmdOutMsg + ) + self.thrDump.thrusterConfInMsg.subscribeTo(self.fsw.thrusterConfigMsg) + self.thrDump.maxCounterValue = maxCounterValue + self.thrDump.thrMinFireTime = thrMinFireTime + + self._add_model_to_task(self.thrDesatControl, priority=1193) + self._add_model_to_task(self.thrDump, priority=1191) + +
+[docs] + def reset_for_action(self) -> None: + """Disable power draw for thrusters.""" + super().reset_for_action() + self.fsw.dynamics.thrusterPowerSink.powerStatus = 0
+
+ + + @action + def action_desat(self) -> None: + """Charge while desaturating reaction wheels.""" + self.trackingError.Reset(self.simulator.sim_time_ns) + self.thrDesatControl.Reset(self.simulator.sim_time_ns) + self.thrDump.Reset(self.simulator.sim_time_ns) + self.dynamics.thrusterPowerSink.powerStatus = 1 + self.simulator.enableTask(self.RWDesatTask.name + self.satellite.id) + if self.desatAttitude == "sun": + self.sunPoint.Reset(self.simulator.sim_time_ns) + self.simulator.enableTask(self.SunPointTask.name + self.satellite.id) + elif self.desatAttitude == "nadir": + self.hillPoint.Reset(self.simulator.sim_time_ns) + self.simulator.enableTask( + BasicFSWModel.NadirPointTask.name + self.satellite.id + ) + elif self.desatAttitude is None: + pass + else: + raise ValueError(f"{self.desatAttitude} not a valid desatAttitude") + self.simulator.enableTask(self.TrackingErrorTask.name + self.satellite.id) + +
+[docs] + class TrackingErrorTask(Task): + """Task to convert an attitude reference to guidance.""" + + name = "trackingErrTask" + +
+[docs] + def __init__(self, fsw, priority=90) -> None: # noqa: D107 + super().__init__(fsw, priority)
+ + + def _create_module_data(self) -> None: + self.trackingError = ( + self.fsw.trackingError + ) = attTrackingError.attTrackingError() + self.trackingError.ModelTag = "trackingError" + + def _init_objects(self, **kwargs) -> None: + self.trackingError.attNavInMsg.subscribeTo( + self.fsw.dynamics.simpleNavObject.attOutMsg + ) + self.trackingError.attRefInMsg.subscribeTo(self.fsw.attRefMsg) + cMsgPy.AttGuidMsg_C_addAuthor( + self.trackingError.attGuidOutMsg, self.fsw.attGuidMsg + ) + + self._add_model_to_task(self.trackingError, priority=1197)
+ + +
+[docs] + class MRPControlTask(Task): + """Task to control the satellite with reaction wheels.""" + + name = "mrpControlTask" + +
+[docs] + def __init__(self, fsw, priority=80) -> None: # noqa: D107 + super().__init__(fsw, priority)
+ + + def _create_module_data(self) -> None: + # Attitude controller configuration + self.mrpFeedbackControl = ( + self.fsw.mrpFeedbackControl + ) = mrpFeedback.mrpFeedback() + self.mrpFeedbackControl.ModelTag = "mrpFeedbackControl" + + # add module that maps the Lr control torque into the RW motor torques + self.rwMotorTorque = self.fsw.rwMotorTorque = rwMotorTorque.rwMotorTorque() + self.rwMotorTorque.ModelTag = "rwMotorTorque" + + def _init_objects(self, **kwargs) -> None: + self._set_mrp_feedback_rwa(**kwargs) + self._set_rw_motor_torque(**kwargs) + + @default_args(K=7.0, Ki=-1, P=35.0) + def _set_mrp_feedback_rwa( + self, K: float, Ki: float, P: float, **kwargs + ) -> None: + """Set the MRP feedback control properties. + + Args: + K: Proportional gain + Ki: Integral gain + P: Derivative gain + kwargs: Ignored + """ + self.mrpFeedbackControl.guidInMsg.subscribeTo(self.fsw.attGuidMsg) + self.mrpFeedbackControl.vehConfigInMsg.subscribeTo(self.fsw.vcConfigMsg) + self.mrpFeedbackControl.K = K + self.mrpFeedbackControl.Ki = Ki + self.mrpFeedbackControl.P = P + self.mrpFeedbackControl.integralLimit = ( + 2.0 / self.mrpFeedbackControl.Ki * 0.1 + ) + + self._add_model_to_task(self.mrpFeedbackControl, priority=1196) + + def _set_rw_motor_torque( + self, controlAxes_B: Iterable[float], **kwargs + ) -> None: + """Set parameters for finding motor torque from the control law. + + Args: + controlAxes_B: Control unit axes + kwargs: Ignored + """ + self.rwMotorTorque.rwParamsInMsg.subscribeTo(self.fsw.fswRwConfigMsg) + self.rwMotorTorque.vehControlInMsg.subscribeTo( + self.mrpFeedbackControl.cmdTorqueOutMsg + ) + self.rwMotorTorque.controlAxes_B = controlAxes_B + + self._add_model_to_task(self.rwMotorTorque, priority=1195) + +
+[docs] + def reset_for_action(self) -> None: + """MRP control enabled by default for all tasks.""" + self.fsw.simulator.enableTask(self.name + self.fsw.satellite.id)
+
+
+ + + +
+[docs] +class ImagingFSWModel(BasicFSWModel): + """Extend FSW with instrument pointing and triggering control.""" + + @classmethod + @property + def _requires_dyn(cls) -> list[type["DynamicsModel"]]: + return super()._requires_dyn + [dynamics.ImagingDynModel] + + @property + def c_hat_P(self): + """Instrument pointing direction in the planet frame.""" + c_hat_B = self.locPoint.pHat_B + return np.matmul(self.dynamics.BP.T, c_hat_B) + + def _make_task_list(self) -> list[Task]: + return super()._make_task_list() + [self.LocPointTask(self)] + + def _set_gateway_msgs(self) -> None: + super()._set_gateway_msgs() + self.dynamics.instrument.nodeStatusInMsg.subscribeTo( + self.insControl.deviceCmdOutMsg + ) + +
+[docs] + class LocPointTask(Task): + """Task to point at targets and trigger the instrument.""" + + name = "locPointTask" + +
+[docs] + def __init__(self, fsw, priority=96) -> None: # noqa: D107 + super().__init__(fsw, priority)
+ + + def _create_module_data(self) -> None: + # Location pointing configuration + self.locPoint = self.fsw.locPoint = locationPointing.locationPointing() + self.locPoint.ModelTag = "locPoint" + + # SimpleInstrumentController configuration + self.insControl = ( + self.fsw.insControl + ) = simpleInstrumentController.simpleInstrumentController() + self.insControl.ModelTag = "instrumentController" + + def _init_objects(self, **kwargs) -> None: + self._set_location_pointing(**kwargs) + self._set_instrument_controller(**kwargs) + + @default_args(inst_pHat_B=[0, 0, 1]) + def _set_location_pointing( + self, inst_pHat_B: Iterable[float], **kwargs + ) -> None: + """Set the Earth location pointing guidance module. + + Args: + inst_pHat_B: Instrument pointing direction + kwargs: Ignored + """ + self.locPoint.pHat_B = inst_pHat_B + self.locPoint.scAttInMsg.subscribeTo( + self.fsw.dynamics.simpleNavObject.attOutMsg + ) + self.locPoint.scTransInMsg.subscribeTo( + self.fsw.dynamics.simpleNavObject.transOutMsg + ) + self.locPoint.locationInMsg.subscribeTo( + self.fsw.dynamics.imagingTarget.currentGroundStateOutMsg + ) + self.locPoint.useBoresightRateDamping = 1 + cMsgPy.AttGuidMsg_C_addAuthor( + self.locPoint.attGuidOutMsg, self.fsw.attGuidMsg + ) + + self._add_model_to_task(self.locPoint, priority=1198) + + @default_args(imageAttErrorRequirement=0.01, imageRateErrorRequirement=None) + def _set_instrument_controller( + self, + imageAttErrorRequirement: float, + imageRateErrorRequirement: float, + **kwargs, + ) -> None: + """Set the instrument controller parameters. + + Args: + imageAttErrorRequirement: Pointing attitude error tolerance for imaging + [MRP norm] + imageRateErrorRequirement: Rate tolerance for imaging. Disable with + None. [rad/s] + kwargs: Ignored + """ + self.insControl.attErrTolerance = imageAttErrorRequirement + if imageRateErrorRequirement is not None: + self.insControl.useRateTolerance = 1 + self.insControl.rateErrTolerance = imageRateErrorRequirement + self.insControl.attGuidInMsg.subscribeTo(self.fsw.attGuidMsg) + self.insControl.locationAccessInMsg.subscribeTo( + self.fsw.dynamics.imagingTarget.accessOutMsgs[-1] + ) + + self._add_model_to_task(self.insControl, priority=987) + +
+[docs] + def reset_for_action(self) -> None: + """Reset pointing controller.""" + self.fsw.dynamics.imagingTarget.Reset(self.fsw.simulator.sim_time_ns) + self.locPoint.Reset(self.fsw.simulator.sim_time_ns) + self.insControl.controllerStatus = 0 + return super().reset_for_action()
+
+ + + @action + def action_image(self, location: Iterable[float], data_name: str) -> None: + """Attempt to image a target at a location. + + Args: + location: PCPF target location [m] + data_name: Data buffer to store image data to + """ + self.insControl.controllerStatus = 1 + self.dynamics.instrumentPowerSink.powerStatus = 1 + self.dynamics.imagingTarget.r_LP_P_Init = location + self.dynamics.instrument.nodeDataName = data_name + self.insControl.imaged = 0 + self.simulator.enableTask(self.LocPointTask.name + self.satellite.id) + + @action + def action_downlink(self) -> None: + """Attempt to downlink data.""" + self.hillPoint.Reset(self.simulator.sim_time_ns) + self.trackingError.Reset(self.simulator.sim_time_ns) + self.dynamics.transmitter.dataStatus = 1 + self.dynamics.transmitterPowerSink.powerStatus = 1 + self.simulator.enableTask(BasicFSWModel.NadirPointTask.name + self.satellite.id) + self.simulator.enableTask( + BasicFSWModel.TrackingErrorTask.name + self.satellite.id + )
+ + + +
+[docs] +class ContinuousImagingFSWModel(ImagingFSWModel): + """FSW model for continuous nadir scanning.""" + +
+[docs] + class LocPointTask(ImagingFSWModel.LocPointTask): + """Task to point at targets and trigger the instrument.""" + + def _create_module_data(self) -> None: + # Location pointing configuration + self.locPoint = self.fsw.locPoint = locationPointing.locationPointing() + self.locPoint.ModelTag = "locPoint" + + # scanningInstrumentController configuration + self.insControl = ( + self.fsw.insControl + ) = scanningInstrumentController.scanningInstrumentController() + self.insControl.ModelTag = "instrumentController" + + @default_args(imageAttErrorRequirement=0.01, imageRateErrorRequirement=None) + def _set_instrument_controller( + self, + imageAttErrorRequirement: float, + imageRateErrorRequirement: float, + **kwargs, + ) -> None: + """Set the instrument controller parameters. + + Args: + imageAttErrorRequirement: Pointing attitude error tolerance for imaging + [MRP norm] + imageRateErrorRequirement: Rate tolerance for imaging. Disable with + None. [rad/s] + kwargs: Ignored + """ + self.insControl.attErrTolerance = imageAttErrorRequirement + if imageRateErrorRequirement is not None: + self.insControl.useRateTolerance = 1 + self.insControl.rateErrTolerance = imageRateErrorRequirement + self.insControl.attGuidInMsg.subscribeTo(self.fsw.attGuidMsg) + self.insControl.accessInMsg.subscribeTo( + self.fsw.dynamics.imagingTarget.accessOutMsgs[-1] + ) + + self._add_model_to_task(self.insControl, priority=987) + +
+[docs] + def reset_for_action(self) -> None: + """Reset scanning controller.""" + self.instMsg = cMsgPy.DeviceCmdMsg_C() + self.instMsg.write(messaging.DeviceCmdMsgPayload()) + self.fsw.dynamics.instrument.nodeStatusInMsg.subscribeTo(self.instMsg) + return super().reset_for_action()
+
+ + + @action + def action_nadir_scan(self) -> None: + """Scan nadir. + + Args: + location: PCPF target location [m] + data_name: Data buffer to store image data to + """ + self.dynamics.instrument.nodeStatusInMsg.subscribeTo( + self.insControl.deviceCmdOutMsg + ) + self.insControl.controllerStatus = 1 + self.dynamics.instrumentPowerSink.powerStatus = 1 + self.dynamics.imagingTarget.r_LP_P_Init = np.array([0, 0, 0.1]) + self.dynamics.instrument.nodeDataName = "nadir" + self.simulator.enableTask(self.LocPointTask.name + self.satellite.id) + + @action + def action_image(self, *args, **kwargs) -> None: + """Disable imaging from parent class.""" + raise NotImplementedError("Use action_nadir_scan instead")
+ + + +
+[docs] +class SteeringFSWModel(BasicFSWModel): + """FSW extending MRP control to use MRP steering instead of MRP feedback.""" + +
+[docs] + class MRPControlTask(Task): + """Task that uses MRP steering to control reaction wheels.""" + + name = "mrpControlTask" + +
+[docs] + def __init__(self, fsw, priority=80) -> None: # noqa: D107 + super().__init__(fsw, priority)
+ + + def _create_module_data(self) -> None: + # Attitude controller configuration + self.mrpSteeringControl = ( + self.fsw.mrpSteeringControl + ) = mrpSteering.mrpSteering() + self.mrpSteeringControl.ModelTag = "mrpSteeringControl" + + # Rate servo + self.servo = ( + self.fsw.servo + ) = rateServoFullNonlinear.rateServoFullNonlinear() + self.servo.ModelTag = "rateServo" + + # add module that maps the Lr control torque into the RW motor torques + self.rwMotorTorque = self.fsw.rwMotorTorque = rwMotorTorque.rwMotorTorque() + self.rwMotorTorque.ModelTag = "rwMotorTorque" + + def _init_objects(self, **kwargs) -> None: + self._set_mrp_steering_rwa(**kwargs) + self._set_rw_motor_torque(**kwargs) + + @default_args(K1=0.25, K3=3.0, omega_max=3 * mc.D2R, servo_Ki=5.0, servo_P=150) + def _set_mrp_steering_rwa( + self, + K1: float, + K3: float, + omega_max: float, + servo_Ki: float, + servo_P: float, + **kwargs, + ) -> None: + """Define the control properties. + + Args: + K1: MRP steering gain + K3: MRP steering gain + omega_max: Maximum targetable spacecraft body rate [rad/s] + servo_Ki: Servo gain + servo_P: Servo gain + kwargs: Ignored + """ + self.mrpSteeringControl.guidInMsg.subscribeTo(self.fsw.attGuidMsg) + self.mrpSteeringControl.K1 = K1 + self.mrpSteeringControl.K3 = K3 + self.mrpSteeringControl.omega_max = omega_max + self.mrpSteeringControl.ignoreOuterLoopFeedforward = False + + self.servo.Ki = servo_Ki + self.servo.P = servo_P + self.servo.integralLimit = 2.0 / self.servo.Ki * 0.1 + self.servo.knownTorquePntB_B = [0.0, 0.0, 0.0] + self.servo.guidInMsg.subscribeTo(self.fsw.attGuidMsg) + self.servo.vehConfigInMsg.subscribeTo(self.fsw.vcConfigMsg) + self.servo.rwParamsInMsg.subscribeTo(self.fsw.fswRwConfigMsg) + self.servo.rwSpeedsInMsg.subscribeTo( + self.fsw.dynamics.rwStateEffector.rwSpeedOutMsg + ) + self.servo.rateSteeringInMsg.subscribeTo( + self.mrpSteeringControl.rateCmdOutMsg + ) + + self._add_model_to_task(self.mrpSteeringControl, priority=1196) + self._add_model_to_task(self.servo, priority=1195) + + def _set_rw_motor_torque( + self, controlAxes_B: Iterable[float], **kwargs + ) -> None: + """Define the motor torque from the control law. + + Args: + controlAxes_B: Control unit axes + kwargs: Ignored + """ + self.rwMotorTorque.rwParamsInMsg.subscribeTo(self.fsw.fswRwConfigMsg) + self.rwMotorTorque.vehControlInMsg.subscribeTo(self.servo.cmdTorqueOutMsg) + self.rwMotorTorque.controlAxes_B = controlAxes_B + + self._add_model_to_task(self.rwMotorTorque, priority=1194) + +
+[docs] + def reset_for_action(self) -> None: + """Keep MRP control enabled on action calls.""" + self.fsw.simulator.enableTask(self.name + self.fsw.satellite.id)
+
+
+ + + +
+[docs] +class SteeringImagerFSWModel(SteeringFSWModel, ImagingFSWModel): + """Convenience type for ImagingFSWModel with MRP steering.""" + + pass
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/utils/functional.html b/_modules/bsk_rl/envs/general_satellite_tasking/utils/functional.html new file mode 100644 index 00000000..6dc7605c --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/utils/functional.html @@ -0,0 +1,310 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.utils.functional — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.utils.functional

+"""General utility functions."""
+
+import inspect
+import re
+import warnings
+from copy import deepcopy
+from typing import Any, Callable
+
+import numpy as np
+
+
+
+[docs] +def valid_func_name(name: str) -> str: + """Convert a string into a valid function name. + + Args: + name: desired function name + + Returns: + sanitized function name + """ + # Remove all characters except for letters, digits, and underscores + name = re.sub(r"\W+", "_", name) + # If the name starts with a digit, add an underscore to the beginning + if name[0].isdigit(): + name = "_" + name + return name
+ + + +
+[docs] +def safe_dict_merge(updates: dict, base: dict) -> dict: + """Merge a dict with another dict, warning for conflicts. + + Args: + updates: dictionary to be added to base + base: base dictionary to be modified + + Returns: + dict: updated base + """ + # Updates base with a copy of elements in updates + for k, v in updates.items(): + if k in base and base[k] != v: + warnings.warn(f"Conflicting values for {k}: overwriting {base[k]} with {v}") + base.update(deepcopy(updates)) + return base
+ + + +
+[docs] +def default_args(**defaults) -> Callable: + """Decorate function to enumerate default arguments for collection.""" + + def inner_dec(func) -> Callable: + def inner(*args, **kwargs) -> Callable: + return func(*args, **kwargs) + + inner.defaults = dict(**defaults) + return inner + + return inner_dec
+ + + +
+[docs] +def collect_default_args(object: object) -> dict[str, Any]: + """Collect all function @default_args in an object. + + Args: + object: object with @default_args decorated functions + + Returns: + dict: dict of keyword-value pairs of default arguments + """ + defaults = {} + for name in dir(object): + if ( + callable(getattr(object, name)) + and not name.startswith("__") + and hasattr(getattr(object, name), "defaults") + ): + safe_dict_merge(getattr(object, name).defaults, defaults) + return defaults
+ + + +
+[docs] +def vectorize_nested_dict(dictionary: dict) -> np.ndarray: + """Flattens a dictionary of dicts, arrays, and scalars into a single vector.""" + values = list(dictionary.values()) + for i, value in enumerate(values): + if isinstance(value, np.ndarray): + values[i] = value.flatten() + elif isinstance(value, (float, int)): + values[i] = [value] + elif isinstance(value, dict): + values[i] = vectorize_nested_dict(value) + + return np.concatenate(values)
+ + + +
+[docs] +def aliveness_checker(func: Callable[..., bool]) -> Callable[..., bool]: + """Decorate function to evaluate when checking for satellite aliveness.""" + + def inner(*args, log_failure=False, **kwargs) -> bool: + self = args[0] + alive = func(*args, **kwargs) + if not alive and log_failure: + self.satellite.log_info(f"failed {func.__name__} check") + return alive + + inner.is_aliveness_checker = True + return inner
+ + + +
+[docs] +def check_aliveness_checkers(model: Any, log_failure=False) -> bool: + """Evaluate all functions with @aliveness_checker in a model. + + Args: + model: Model to search for checkers in + log_failure: Whether to log on checker failure + + Returns: + bool: Model aliveness status + """ + is_alive = True + for name in dir(model): + if ( + not name.startswith("__") + and not is_property(model, name) + and callable(getattr(model, name)) + and hasattr(getattr(model, name), "is_aliveness_checker") + ): + is_alive = is_alive and getattr(model, name)(log_failure=log_failure) + return is_alive
+ + + +
+[docs] +def is_property(obj: Any, attr_name: str) -> bool: + """Check if obj has an @property attr_name without calling it.""" + cls = type(obj) + attribute = getattr(cls, attr_name, None) + return attribute is not None and isinstance(attribute, property)
+ + + +
+[docs] +def configurable(cls): + """Class decorator to create class with different init defaults.""" + + @classmethod + def configure(cls, **config_kwargs): + class Configurable(cls): + def __init__(self, *args, **kwargs): + init_kwargs = deepcopy(config_kwargs) + for key in init_kwargs.keys(): + if not ( + key in inspect.getfullargspec(super().__init__).args + or key in inspect.getfullargspec(super().__init__).kwonlyargs + ): + raise KeyError( + f"{key} not a keyword argument for {cls.__name__}" + ) + for k, v in kwargs.items(): + init_kwargs[k] = v + super().__init__(*args, **init_kwargs) + + configcls = Configurable + return configcls + + cls.configure = configure + return cls
+ + + +
+[docs] +def bind(instance, func, as_name=None): + """Bind the function *func* to *instance*. + + Uses either provided name *as_name* or the existing name of *func*. The provided + *func* should accept the instance as the first argument, i.e. "self". + """ + if as_name is None: + as_name = func.__name__ + bound_method = func.__get__(instance, instance.__class__) + setattr(instance, as_name, bound_method) + return bound_method
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/utils/logging_config.html b/_modules/bsk_rl/envs/general_satellite_tasking/utils/logging_config.html new file mode 100644 index 00000000..b9c4910d --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/utils/logging_config.html @@ -0,0 +1,284 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.utils.logging_config — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.utils.logging_config

+# ruff: noqa
+import logging
+
+fstr = "\x1b[30;3m%(asctime)s\x1b[0m %(shortname)-30s %(levelname)-10s <%(sim_time)-.2f> %(message)s"
+
+colors = dict(
+    GRAY=90,
+    RED=91,
+    GREEN=92,
+    YELLOW=93,
+    BLUE=94,
+    MAGENTA=95,
+    CYAN=96,
+    WHITE=97,
+    DARK_GRAY=30,
+    DARK_RED=31,
+    DARK_GREEN=32,
+    DARK_YELLOW=33,
+    DARK_BLUE=34,
+    DARK_MAGENTA=35,
+    DARK_CYAN=36,
+    DARK_WHITE=37,
+)
+
+
+def style_string(
+    string,
+    no_format=False,
+    style_spec=None,
+    color=None,
+    background_color=None,
+    bold=False,
+    emph=False,
+    underline=False,
+):
+    if no_format:
+        return string
+
+    if style_spec is None:
+        style_spec = []
+    if color is not None:
+        style_spec.append(colors[color.upper()])
+    if background_color is not None:
+        style_spec.append(colors[background_color.upper()] + 10)
+    if bold:
+        style_spec.append(1)
+    if emph:
+        style_spec.append(3)
+    if underline:
+        style_spec.append(4)
+    return (
+        "\x1b["
+        + ";".join([str(style) for style in style_spec])
+        + "m"
+        + string
+        + "\x1b[0m"
+    )
+
+
+level_color = {
+    "DEBUG": None,
+    "INFO": None,
+    "WARNING": "YELLOW",
+    "ERROR": "RED",
+    "CRITICAL": "RED",
+}
+sat_color_cycle = [
+    "DARK_CYAN",
+    "GREEN",
+    "DARK_BLUE",
+    "MAGENTA",
+    "CYAN",
+    "DARK_GREEN",
+    "BLUE",
+    "DARK_MAGENTA",
+]
+
+
+
+[docs] +class SimFormatter(logging.Formatter): +
+[docs] + def __init__(self, *args, color_output=True, **kwargs): + super().__init__( + *args, + **kwargs, + ) + self.color_output = color_output + self.satellite_colors = {}
+ + + def set_format(self, fmt, defaults=None, style="%"): + self._style = logging._STYLES[style][0](fmt, defaults=defaults) + self._fmt = self._style._fmt + +
+[docs] + def format(self, record): + no_format = not self.color_output + fstr = "" + fstr += style_string( + "%(asctime)s ", color="GRAY", emph=True, no_format=no_format + ) + + sat_name = None + sat_color = None + try: + if record.name.split(".")[4] == "satellites": + sat_name = record.name.split(".")[5] + if sat_name not in self.satellite_colors: + self.satellite_colors[sat_name] = len(self.satellite_colors) % len( + sat_color_cycle + ) + sat_color = sat_color_cycle[self.satellite_colors[sat_name]] + except IndexError: + pass + + record.shortname = ".".join(record.name.split(".")[3:]) + fstr += style_string("%(shortname)-30s ", color=sat_color, no_format=no_format) + fstr += style_string( + "%(levelname)-10s ", + color=level_color[record.levelname], + bold=record.levelname == "CRITICAL", + no_format=no_format, + ) + if hasattr(record, "sim_time"): + fstr += style_string( + "<%(sim_time)-.2f> ", color="DARK_YELLOW", no_format=no_format + ) + if sat_name is not None: + fstr += style_string( + f"{sat_name}: ", + color=sat_color, + no_format=no_format, + ) + if record.msg.startswith("=== "): + fstr += style_string( + "%(message)s", + bold=True, + color="YELLOW", + no_format=no_format, + ) + else: + fstr += style_string( + "%(message)s", + color=level_color[record.levelname], + bold=record.levelname == "CRITICAL", + no_format=no_format, + ) + + self.set_format(fstr) + return super().format(record)
+
+ + + +
+[docs] +class ContextFilter(logging.Filter): +
+[docs] + def __init__(self, name: str = "", env=None, proc_id=None) -> None: + super().__init__(name) + self.env = env + self.proc_id = proc_id
+ + +
+[docs] + def filter(self, record): + try: + record.sim_time = self.env.simulator.sim_time + except AttributeError: + pass + return self.proc_id == record.process
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/general_satellite_tasking/utils/orbital.html b/_modules/bsk_rl/envs/general_satellite_tasking/utils/orbital.html new file mode 100644 index 00000000..68adfd42 --- /dev/null +++ b/_modules/bsk_rl/envs/general_satellite_tasking/utils/orbital.html @@ -0,0 +1,440 @@ + + + + + + bsk_rl.envs.general_satellite_tasking.utils.orbital — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.general_satellite_tasking.utils.orbital

+"""Utilities for computing orbital events."""
+
+from typing import Iterable, Optional
+
+import numpy as np
+from Basilisk import __path__
+from Basilisk.simulation import eclipse, spacecraft
+from Basilisk.utilities import SimulationBaseClass, macros, simIncludeGravBody
+from Basilisk.utilities.orbitalMotion import ClassicElements, elem2rv
+from scipy.interpolate import interp1d
+
+bskPath = __path__[0]
+
+
+
+[docs] +def random_orbit( + i: Optional[float] = 45.0, + alt: float = 500, + r_body: float = 6371, + e: float = 0, + Omega: Optional[float] = None, + omega: Optional[float] = 0, + f: Optional[float] = None, +) -> ClassicElements: + """Create a set of orbit elements. + + Parameters are fixed if specified and randomized if None. + + Args: + i: inclination [deg], randomized in [-pi, pi] + alt: altitude above r_body [km] + r_body: body radius [km] + e: eccentricity + Omega: LAN [deg], randomized in [0, 2pi] + omega: Argument of periapsis [deg], randomized in [0, 2pi] + f: true anomaly [deg], randomized in [0, 2pi] + + Returns: + ClassicElements: orbital elements + """ + oe = ClassicElements() + oe.a = (r_body + alt) * 1e3 + oe.e = e + oe.i = np.radians(i) if i is not None else np.random.uniform(-np.pi, np.pi) + oe.Omega = ( + np.radians(Omega) if Omega is not None else np.random.uniform(0, 2 * np.pi) + ) + oe.omega = ( + np.radians(omega) if omega is not None else np.random.uniform(0, 2 * np.pi) + ) + oe.f = np.radians(f) if f is not None else np.random.uniform(0, 2 * np.pi) + return oe
+ + + +
+[docs] +def random_epoch(start: int = 2000, end: int = 2022): + """Generate a random epoch in a year range. + + Date will always be in the first 28 days of the month. + + Args: + start: Initial year. + end: Final year. + + Returns: + Epoch in ``YYYY MMM DD HH:MM:SS.SSS (UTC)`` format + """ + year = np.random.randint(start, end) + month = np.random.choice( + [ + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEP", + "OCT", + "NOV", + "DEC", + ] + ) + day = np.random.randint(1, 28) # Assume 28 days for simplicity + hours = np.random.randint(0, 23) + minutes = np.random.randint(0, 59) + seconds = np.random.randint(0, 59) + milliseconds = np.random.randint(0, 999) + + # Combine the parts to form the datetime string + epoch = ( + f"{year} {month} {day:02d} " + + f"{hours:02d}:{minutes:02d}:{seconds:02d}.{milliseconds:03d} (UTC)" + ) + + return epoch
+ + + +
+[docs] +def elevation(r_sat: np.ndarray, r_target: np.ndarray) -> np.ndarray: + """Find the elevation angle from a target to a satellite. + + Args: + r_sat: Satellite position(s) + r_target: Target position + + Returns: + Elevation angle(s) + """ + if r_sat.ndim == 2: + return np.pi / 2 - np.arccos( + np.sum(r_target * (r_sat - r_target), 1) + / (np.linalg.norm(r_target) * np.linalg.norm(r_sat - r_target, axis=1)) + ) + else: + return np.pi / 2 - np.arccos( + np.sum(r_target * (r_sat - r_target)) + / (np.linalg.norm(r_target) * np.linalg.norm(r_sat - r_target)) + )
+ + + +class TrajectorySimulator(SimulationBaseClass.SimBaseClass): + """Class for propagating trajectory using a point mass simulation.""" + + def __init__( + self, + utc_init: str, + rN: Optional[Iterable[float]] = None, + vN: Optional[Iterable[float]] = None, + oe: Optional[ClassicElements] = None, + mu: Optional[float] = None, + dt: float = 30.0, + ) -> None: + """Initialize simulator conditions. + + Simulated under the effect of Earth's gravity. Returns interpolators for + position as well as upcoming eclipse predictions. Specify either (rN, vN) or + (oe, mu). + + Args: + utc_init: Simulation start time. + rN: Initial position [m] + vN: Initial velocity [m/s] + oe: Orbital elements. + mu: Gravitational parameter + dt: Simulation timestep. + """ + super().__init__() + self.utc_init = utc_init + self.dt = dt + rv_specified = rN is not None and vN is not None + rv_specified_partial = rN is not None or vN is not None + oe_specified = oe is not None + + if rv_specified and not oe_specified: + self.rN_init = rN + self.vN_init = vN + elif oe_specified and not rv_specified_partial: + self.rN_init, self.vN_init = elem2rv(mu, oe) + else: + raise ( + ValueError( + "Orbit is over or underspecified. " + + "Provide either (rN, vN) or (oe, mu)" + ) + ) + + self._eclipse_starts: list[float] = [] + self._eclipse_ends: list[float] = [] + self._eclipse_search_time = 0.0 + + self._init_simulator() + + def _init_simulator(self) -> None: + simTaskName = "simTask" + simProcessName = "simProcess" + dynProcess = self.CreateNewProcess(simProcessName) + simulationTimeStep = macros.sec2nano(self.dt) + dynProcess.addTask(self.CreateNewTask(simTaskName, simulationTimeStep)) + scObject = spacecraft.Spacecraft() + scObject.ModelTag = "traj-sat" + self.AddModelToTask(simTaskName, scObject) + + scObject.hub.r_CN_NInit = self.rN_init # m + scObject.hub.v_CN_NInit = self.vN_init # m/s + + # Set up gravity body + self.gravFactory = simIncludeGravBody.gravBodyFactory() + planet = self.gravFactory.createEarth() + self.gravFactory.createSun() + planet.isCentralBody = True + planet.useSphericalHarmonicsGravityModel( + bskPath + "/supportData/LocalGravData/GGM03S.txt", 10 + ) + UTCInit = self.utc_init + self.gravFactory.createSpiceInterface( + bskPath + "/supportData/EphemerisData/", UTCInit + ) + self.gravFactory.spiceObject.zeroBase = "earth" + self.AddModelToTask(simTaskName, self.gravFactory.spiceObject) + scObject.gravField.gravBodies = spacecraft.GravBodyVector( + list(self.gravFactory.gravBodies.values()) + ) + + # Set up eclipse + self.eclipseObject = eclipse.Eclipse() + self.eclipseObject.addPlanetToModel( + self.gravFactory.spiceObject.planetStateOutMsgs[0] + ) + self.eclipseObject.sunInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[1] + ) + self.AddModelToTask(simTaskName, self.eclipseObject, ModelPriority=988) + self.eclipseObject.addSpacecraftToModel(scObject.scStateOutMsg) + + # Log outputs + self.sc_state_log = scObject.scStateOutMsg.recorder() + self.planet_state_log = self.gravFactory.spiceObject.planetStateOutMsgs[ + 0 + ].recorder() + self.eclipse_log = self.eclipseObject.eclipseOutMsgs[0].recorder() + + self.AddModelToTask(simTaskName, self.sc_state_log) + self.AddModelToTask(simTaskName, self.planet_state_log) + self.AddModelToTask(simTaskName, self.eclipse_log) + + self.InitializeSimulation() + + @property + def sim_time(self) -> float: + """Current simulator end time.""" + return macros.NANO2SEC * self.TotalSim.CurrentNanos + + @property + def times(self) -> np.ndarray: + """Recorder times in seconds.""" + return np.array([macros.NANO2SEC * t for t in self.sc_state_log.times()]) + + def extend_to(self, t: float) -> None: + """Compute the trajectory of the satellite up to t. + + Args: + t: Computation end [s] + """ + if t < self.sim_time: + return + self.ConfigureStopTime(macros.sec2nano(t)) + self.ExecuteSimulation() + + def _generate_eclipses(self, t: float) -> None: + self.extend_to(t + self.dt) + upcoming_times = self.times[self.times > self._eclipse_search_time] + upcoming_eclipse = ( + self.eclipse_log.shadowFactor[self.times > self._eclipse_search_time] > 0 + ).astype(float) + for i in np.where(np.diff(upcoming_eclipse) == -1)[0]: + self._eclipse_starts.append(upcoming_times[i]) + for i in np.where(np.diff(upcoming_eclipse) == 1)[0]: + self._eclipse_ends.append(upcoming_times[i]) + + self._eclipse_search_time = t + + def next_eclipse(self, t: float, max_tries: int = 100) -> tuple[float, float]: + """Find the soonest eclipse transitions. + + The returned values are not necessarily from the same eclipse event, such as + when the search start time is in eclipse. + + Args: + t: Time to start searching [s] + max_tries: Maximum number of times to search + + Returns: + eclipse_start: Nearest upcoming eclipse beginning + eclipse_end: Nearest upcoming eclipse end + """ + for i in range(max_tries): + if any([t_start > t for t_start in self._eclipse_starts]) and any( + [t_end > t for t_end in self._eclipse_ends] + ): + eclipse_start = min( + [t_start for t_start in self._eclipse_starts if t_start > t] + ) + eclipse_end = min([t_end for t_end in self._eclipse_ends if t_end > t]) + return eclipse_start, eclipse_end + + self._generate_eclipses(t + i * self.dt * 10) + + return 1.0, 1.0 + + @property + def r_BN_N(self) -> interp1d: + """Interpolator for r_BN_N.""" + if self.sim_time < self.dt * 3: + self.extend_to(self.dt * 3) + return interp1d( + self.times, + self.sc_state_log.r_BN_N, + kind="cubic", + axis=0, + fill_value="extrapolate", + ) + + @property + def r_BP_P(self) -> interp1d: + """Interpolator for r_BP_P.""" + if self.sim_time < self.dt * 3: + self.extend_to(self.dt * 3) + return interp1d( + self.times, + [ + np.matmul(dcm, pos) + for dcm, pos in zip( + self.planet_state_log.J20002Pfix, self.sc_state_log.r_BN_N + ) + ], + kind="cubic", + axis=0, + fill_value="extrapolate", + ) + + def __del__(self) -> None: + """Unload spice kernels when object is deleted.""" + try: + self.gravFactory.unloadSpiceKernels() + except AttributeError: + pass +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/dynamics.html b/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/dynamics.html new file mode 100644 index 00000000..c8cfe1b3 --- /dev/null +++ b/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/dynamics.html @@ -0,0 +1,620 @@ + + + + + + bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics

+from Basilisk.simulation import (
+    ReactionWheelPower,
+    facetDragDynamicEffector,
+    partitionedStorageUnit,
+    simpleBattery,
+    simpleInstrument,
+    simpleNav,
+    simplePowerSink,
+    simpleSolarPanel,
+    spacecraft,
+    spacecraftLocation,
+    spaceToGroundTransmitter,
+)
+from Basilisk.utilities import macros as mc
+from Basilisk.utilities import unitTestSupport
+
+from bsk_rl.utilities.effector_primitives import actuator_primitives as ap
+
+
+
+[docs] +class DynamicModel: + """ + Defines the Dynamics class. + """ + +
+[docs] + def __init__(self, SimBase, dynRate, spacecraftIndex, singleSat=False): + # Define class variables + self.spacecraftIndex = spacecraftIndex + self.dynRate = dynRate + + # Define process name, task name and task time-step + self.taskName = "DynamicsTask" + str(spacecraftIndex) + self.processTasksTimeStep = mc.sec2nano(self.dynRate) + + # Create task + SimBase.dynProc[spacecraftIndex].addTask( + SimBase.CreateNewTask(self.taskName, self.processTasksTimeStep) + ) + + # Initialize all modules and write init one-time messages + self.InitAllDynObjects(SimBase) + + # Assign initialized modules to tasks + SimBase.AddModelToTask(self.taskName, self.dragEffector, ModelPriority=999) + SimBase.AddModelToTask(self.taskName, self.simpleNavObject, ModelPriority=1400) + SimBase.AddModelToTask(self.taskName, self.rwStateEffector, ModelPriority=997) + SimBase.AddModelToTask(self.taskName, self.thrusterSet, ModelPriority=996) + SimBase.AddModelToTask(self.taskName, self.scObject, ModelPriority=2000) + SimBase.AddModelToTask(self.taskName, self.solarPanel, ModelPriority=898) + SimBase.AddModelToTask( + self.taskName, self.instrumentPowerSink, ModelPriority=897 + ) + SimBase.AddModelToTask( + self.taskName, self.transmitterPowerSink, ModelPriority=896 + ) + SimBase.AddModelToTask(self.taskName, self.instrument, ModelPriority=895) + SimBase.AddModelToTask(self.taskName, self.powerMonitor, ModelPriority=799) + SimBase.AddModelToTask(self.taskName, self.transmitter, ModelPriority=798) + SimBase.AddModelToTask(self.taskName, self.storageUnit, ModelPriority=699) + for ind in range(self.rwFactory.getNumOfDevices()): + SimBase.AddModelToTask( + self.taskName, self.rwPowerList[ind], ModelPriority=(987 - ind) + ) + if not singleSat: + SimBase.AddModelToTask(self.taskName, self.losComms, ModelPriority=500)
+ + + # These are module-initialization methods + +
+[docs] + def SetSpacecraftHub(self, SimBase): + """ + Defines the spacecraft object properties. + """ + self.scObject = spacecraft.Spacecraft() + self.scObject.ModelTag = "sat-" + str(self.spacecraftIndex) + # Grab the mass for readability in inertia computation + mass = SimBase.initial_conditions[str(self.spacecraftIndex)].get("mass") + # Get the spacecraft geometric properties + self.width = SimBase.initial_conditions[str(self.spacecraftIndex)].get("width") + self.depth = SimBase.initial_conditions[str(self.spacecraftIndex)].get("depth") + self.height = SimBase.initial_conditions[str(self.spacecraftIndex)].get( + "height" + ) + + self.I_mat = [ + 1.0 / 12.0 * mass * (self.width**2.0 + self.depth**2.0), + 0.0, + 0.0, + 0.0, + 1.0 / 12.0 * mass * (self.depth**2.0 + self.height**2.0), + 0.0, + 0.0, + 0.0, + 1.0 / 12.0 * mass * (self.width**2.0 + self.height**2.0), + ] + + self.scObject.hub.mHub = mass # kg + self.scObject.hub.IHubPntBc_B = unitTestSupport.np2EigenMatrix3d(self.I_mat) + + # Set the initial attitude and position + self.scObject.hub.sigma_BNInit = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("sigma_init") + self.scObject.hub.omega_BN_BInit = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("omega_init") + self.scObject.hub.r_CN_NInit = unitTestSupport.np2EigenVectorXd( + SimBase.initial_conditions[str(self.spacecraftIndex)].get("rN") + ) + self.scObject.hub.v_CN_NInit = unitTestSupport.np2EigenVectorXd( + SimBase.initial_conditions[str(self.spacecraftIndex)].get("vN") + )
+ + +
+[docs] + def SetGravityBodies(self, SimBase): + """ + Specify what gravitational bodies to include in the simulation + """ + # Attach the gravity body + self.scObject.gravField.gravBodies = spacecraft.GravBodyVector( + list(SimBase.EnvModel.gravFactory.gravBodies.values()) + )
+ + +
+[docs] + def SetDisturbanceTorque(self, SimBase): + """ + Attach the disturbance torque to the spacecraft object + """ + self.scObject.addDynamicEffector( + SimBase.EnvModel.extForceTorqueObjectList[self.spacecraftIndex] + )
+ + +
+[docs] + def SetDensityModel(self, SimBase): + """ + Attaches the density model effector to the spacecraft + """ + SimBase.EnvModel.densityModel.addSpacecraftToModel(self.scObject.scStateOutMsg)
+ + +
+[docs] + def SetDragEffector(self, SimBase): + """ + Set the drag effector + """ + self.dragEffector = facetDragDynamicEffector.FacetDragDynamicEffector() + self.dragEffector.ModelTag = "FacetDrag" + # Set up the geometry of a small satellite, starting w/ bus + self.dragEffector.addFacet( + self.width * self.depth, 2.2, [1, 0, 0], [self.height / 2, 0.0, 0] + ) + self.dragEffector.addFacet( + self.width * self.depth, 2.2, [-1, 0, 0], [self.height / 2, 0.0, 0] + ) + self.dragEffector.addFacet( + self.height * self.width, 2.2, [0, 1, 0], [0, self.depth / 2, 0] + ) + self.dragEffector.addFacet( + self.height * self.width, 2.2, [0, -1, 0], [0, -self.depth / 2, 0] + ) + self.dragEffector.addFacet( + self.height * self.depth, 2.2, [0, 0, 1], [0, 0, self.width / 2] + ) + self.dragEffector.addFacet( + self.height * self.depth, 2.2, [0, 0, -1], [0, 0, -self.width / 2] + ) + # Add solar panels + self.dragEffector.addFacet( + SimBase.initial_conditions[str(self.spacecraftIndex)].get("panelArea") / 2, + 2.2, + [0, 1, 0], + [0, self.height, 0], + ) + self.dragEffector.addFacet( + SimBase.initial_conditions[str(self.spacecraftIndex)].get("panelArea") / 2, + 2.2, + [0, -1, 0], + [0, self.height, 0], + ) + self.dragEffector.atmoDensInMsg.subscribeTo( + SimBase.EnvModel.densityModel.envOutMsgs[-1] + ) + self.scObject.addDynamicEffector(self.dragEffector)
+ + +
+[docs] + def SetGroundLocations(self, SimBase): + """ + Adds the spacecraft to the ground location modules. + """ + SimBase.EnvModel.boulderGroundStation.addSpacecraftToModel( + self.scObject.scStateOutMsg + ) + SimBase.EnvModel.merrittGroundStation.addSpacecraftToModel( + self.scObject.scStateOutMsg + ) + SimBase.EnvModel.singaporeGroundStation.addSpacecraftToModel( + self.scObject.scStateOutMsg + ) + SimBase.EnvModel.weilheimGroundStation.addSpacecraftToModel( + self.scObject.scStateOutMsg + ) + SimBase.EnvModel.santiagoGroundStation.addSpacecraftToModel( + self.scObject.scStateOutMsg + ) + SimBase.EnvModel.dongaraGroundStation.addSpacecraftToModel( + self.scObject.scStateOutMsg + ) + SimBase.EnvModel.hawaiiGroundStation.addSpacecraftToModel( + self.scObject.scStateOutMsg + ) + SimBase.EnvModel.imagingTargetList[self.spacecraftIndex].addSpacecraftToModel( + self.scObject.scStateOutMsg + )
+ + +
+[docs] + def SetEclipseObject(self, SimBase): + """ + Adds the spacecraft to the eclipse module. + """ + SimBase.EnvModel.eclipseObject.addSpacecraftToModel(self.scObject.scStateOutMsg)
+ + +
+[docs] + def SetSimpleNavObject(self): + """ + Defines the navigation module. + """ + self.simpleNavObject = simpleNav.SimpleNav() + self.simpleNavObject.ModelTag = "SimpleNav" + self.simpleNavObject.scStateInMsg.subscribeTo(self.scObject.scStateOutMsg)
+ + +
+[docs] + def SetReactionWheelDynEffector(self, SimBase): + """ + Defines the RW state effector. + """ + self.rwStateEffector, self.rwFactory, initWheelSpeeds = ap.balancedHR16Triad( + useRandom=False, + randomBounds=(-800, 800), + wheelSpeeds=SimBase.initial_conditions[str(self.spacecraftIndex)].get( + "wheelSpeeds" + ), + ) + self.rwFactory.addToSpacecraft( + "ReactionWheels", self.rwStateEffector, self.scObject + )
+ + +
+[docs] + def SetThrusterDynEffector(self): + """ + Defines the thruster state effector. + """ + self.thrusterSet, self.thrFactory = ap.idealMonarc1Octet() + thrModelTag = "ACSThrusterDynamics" + self.thrFactory.addToSpacecraft(thrModelTag, self.thrusterSet, self.scObject)
+ + +
+[docs] + def SetSolarPanel(self, SimBase): + """ + Sets the solar panel + """ + self.solarPanel = simpleSolarPanel.SimpleSolarPanel() + self.solarPanel.ModelTag = "solarPanel" + str(self.spacecraftIndex) + self.solarPanel.stateInMsg.subscribeTo(self.scObject.scStateOutMsg) + self.solarPanel.sunEclipseInMsg.subscribeTo( + SimBase.EnvModel.eclipseObject.eclipseOutMsgs[self.spacecraftIndex] + ) + self.solarPanel.sunInMsg.subscribeTo( + SimBase.EnvModel.gravFactory.spiceObject.planetStateOutMsgs[ + SimBase.EnvModel.sun + ] + ) + self.solarPanel.setPanelParameters( + unitTestSupport.np2EigenVectorXd( + SimBase.initial_conditions[str(self.spacecraftIndex)].get("nHat_B") + ), + SimBase.initial_conditions[str(self.spacecraftIndex)].get("panelArea"), + SimBase.initial_conditions[str(self.spacecraftIndex)].get( + "panelEfficiency" + ), + )
+ + +
+[docs] + def SetInstrumentPowerSink(self, SimBase): + """ + Defines the instrument power sink parameters + """ + self.instrumentPowerSink = simplePowerSink.SimplePowerSink() + self.instrumentPowerSink.ModelTag = "insPowerSink" + str(self.spacecraftIndex) + self.instrumentPowerSink.nodePowerOut = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get( + "instrumentPowerDraw" + ) # Watts
+ + +
+[docs] + def SetTransmitterPowerSink(self, SimBase): + """ + Defines the trasmitter power sink parameters + """ + self.transmitterPowerSink = simplePowerSink.SimplePowerSink() + self.transmitterPowerSink.ModelTag = "transPowerSink" + str( + self.spacecraftIndex + ) + self.transmitterPowerSink.nodePowerOut = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get( + "transmitterPowerDraw" + ) # Watts
+ + +
+[docs] + def SetReactionWheelPower(self, SimBase): + """ + Defines the reaction wheel power draw + """ + self.rwPowerList = [] + for ind in range(self.rwFactory.getNumOfDevices()): + powerRW = ReactionWheelPower.ReactionWheelPower() + powerRW.ModelTag = "rwPower" + str(ind) + powerRW.basePowerNeed = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get( + "rwBasePower" + ) # baseline power draw, Watts + powerRW.rwStateInMsg.subscribeTo(self.rwStateEffector.rwOutMsgs[ind]) + powerRW.mechToElecEfficiency = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("rwMechToElecEfficiency") + powerRW.elecToMechEfficiency = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("rwElecToMechEfficiency") + self.rwPowerList.append(powerRW)
+ + +
+[docs] + def SetBattery(self, SimBase): + """ + Sets up the battery with all the power components + """ + self.powerMonitor = simpleBattery.SimpleBattery() + self.powerMonitor.ModelTag = "powerMonitor" + self.powerMonitor.storageCapacity = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("batteryStorageCapacity") + self.powerMonitor.storedCharge_Init = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("storedCharge_Init") + self.powerMonitor.addPowerNodeToModel(self.solarPanel.nodePowerOutMsg) + self.powerMonitor.addPowerNodeToModel(self.instrumentPowerSink.nodePowerOutMsg) + self.powerMonitor.addPowerNodeToModel(self.transmitterPowerSink.nodePowerOutMsg) + for powerRW in self.rwPowerList: + self.powerMonitor.addPowerNodeToModel(powerRW.nodePowerOutMsg)
+ + +
+[docs] + def SetInstrument(self, SimBase): + """ + Create the instrument + """ + self.instrument = simpleInstrument.SimpleInstrument() + self.instrument.ModelTag = "instrument" + str(self.spacecraftIndex) + self.instrument.nodeBaudRate = ( + SimBase.initial_conditions[str(self.spacecraftIndex)].get( + "instrumentBaudRate" + ) + / self.dynRate + ) # baud + self.instrument.nodeDataName = "Instrument" + str(self.spacecraftIndex)
+ + +
+[docs] + def SetTransmitter(self, SimBase): + """ + Create the transmitter + """ + self.transmitter = spaceToGroundTransmitter.SpaceToGroundTransmitter() + self.transmitter.ModelTag = "transmitter" + str(self.spacecraftIndex) + self.transmitter.nodeBaudRate = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get( + "transmitterBaudRate" + ) # baud + self.transmitter.packetSize = -SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get( + "instrumentBaudRate" + ) # bits, set packet size equal to the size of a single image + self.transmitter.numBuffers = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("transmitterNumBuffers") + self.transmitter.addAccessMsgToTransmitter( + SimBase.EnvModel.boulderGroundStation.accessOutMsgs[-1] + ) + self.transmitter.addAccessMsgToTransmitter( + SimBase.EnvModel.merrittGroundStation.accessOutMsgs[-1] + ) + self.transmitter.addAccessMsgToTransmitter( + SimBase.EnvModel.singaporeGroundStation.accessOutMsgs[-1] + ) + self.transmitter.addAccessMsgToTransmitter( + SimBase.EnvModel.weilheimGroundStation.accessOutMsgs[-1] + ) + self.transmitter.addAccessMsgToTransmitter( + SimBase.EnvModel.santiagoGroundStation.accessOutMsgs[-1] + ) + self.transmitter.addAccessMsgToTransmitter( + SimBase.EnvModel.dongaraGroundStation.accessOutMsgs[-1] + ) + self.transmitter.addAccessMsgToTransmitter( + SimBase.EnvModel.hawaiiGroundStation.accessOutMsgs[-1] + )
+ + + def SetStorageUnit(self, SimBase): + self.storageUnit = partitionedStorageUnit.PartitionedStorageUnit() + self.storageUnit.ModelTag = "storageUnit" + str(self.spacecraftIndex) + self.storageUnit.storageCapacity = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get( + "dataStorageCapacity" + ) # bits (1 GB) + self.storageUnit.addDataNodeToModel(self.instrument.nodeDataOutMsg) + self.storageUnit.addDataNodeToModel(self.transmitter.nodeDataOutMsg) + # Add all of the targets to the data buffer + for idx in range( + SimBase.initial_conditions[str(self.spacecraftIndex)].get( + "transmitterNumBuffers" + ) + ): + self.storageUnit.addPartition(str(idx)) + + # Add the storage unit to the transmitter + self.transmitter.addStorageUnitToTransmitter( + self.storageUnit.storageUnitDataOutMsg + ) + + def SetLosComms(self, SimBase): + self.losComms = spacecraftLocation.SpacecraftLocation() + self.losComms.ModelTag = "losComms" + self.losComms.primaryScStateInMsg.subscribeTo(self.scObject.scStateOutMsg) + self.losComms.planetInMsg.subscribeTo( + SimBase.EnvModel.gravFactory.spiceObject.planetStateOutMsgs[ + SimBase.EnvModel.earth + ] + ) + self.losComms.rEquator = SimBase.EnvModel.planet.radEquator + self.losComms.rPolar = SimBase.EnvModel.planet.radEquator * 0.98 + self.losComms.maximumRange = -1.0 # m, unlimited + + # Global call to initialize every module +
+[docs] + def InitAllDynObjects(self, SimBase): + """ + Initializes all dynamic objects. + """ + self.SetSpacecraftHub(SimBase) + self.SetGravityBodies(SimBase) + self.SetDensityModel(SimBase) + self.SetDragEffector(SimBase) + self.SetReactionWheelDynEffector(SimBase) + self.SetThrusterDynEffector() + self.SetSimpleNavObject() + self.SetGroundLocations(SimBase) + self.SetEclipseObject(SimBase) + self.SetReactionWheelPower(SimBase) + self.SetSolarPanel(SimBase) + self.SetInstrumentPowerSink(SimBase) + self.SetTransmitterPowerSink(SimBase) + self.SetBattery(SimBase) + self.SetInstrument(SimBase) + self.SetTransmitter(SimBase) + self.SetStorageUnit(SimBase) + self.SetLosComms(SimBase) + self.SetDisturbanceTorque(SimBase)
+ + + def ConnectLosComms(self, SatList): + for sat in SatList: + if sat != self.scObject: + self.losComms.addSpacecraftToModel(sat.scStateOutMsg)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/environment.html b/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/environment.html new file mode 100644 index 00000000..497a5bf7 --- /dev/null +++ b/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/environment.html @@ -0,0 +1,464 @@ + + + + + + bsk_rl.envs.multisat_agile_eos.bsk_models.environment — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.multisat_agile_eos.bsk_models.environment

+import numpy as np
+from Basilisk import __path__
+from Basilisk.simulation import (
+    eclipse,
+    ephemerisConverter,
+    exponentialAtmosphere,
+    extForceTorque,
+    groundLocation,
+)
+from Basilisk.utilities import macros as mc
+from Basilisk.utilities import simIncludeGravBody
+
+bskPath = __path__[0]
+
+
+
+[docs] +class EnvironmentModel: + """Defines the Earth Environment.""" + +
+[docs] + def __init__(self, SimBase, envRate): + # Define class variables + self.imagingTargetList = [] + self.extForceTorqueObjectList = [] + + # Define process name, task name and task time-step + self.envTaskName = "EnvironmentTask" + processTasksTimeStep = mc.sec2nano(envRate) + + # Create task + SimBase.envProc.addTask( + SimBase.CreateNewTask(self.envTaskName, processTasksTimeStep) + ) + + # Initialize all modules and write init one-time messages + self.InitAllEnvObjects(SimBase) + + # Add modules to environment task + SimBase.AddModelToTask( + self.envTaskName, self.gravFactory.spiceObject, ModelPriority=1100 + ) + SimBase.AddModelToTask( + self.envTaskName, self.boulderGroundStation, ModelPriority=1399 + ) + SimBase.AddModelToTask( + self.envTaskName, self.merrittGroundStation, ModelPriority=1398 + ) + SimBase.AddModelToTask( + self.envTaskName, self.singaporeGroundStation, ModelPriority=1397 + ) + SimBase.AddModelToTask( + self.envTaskName, self.weilheimGroundStation, ModelPriority=1396 + ) + SimBase.AddModelToTask( + self.envTaskName, self.santiagoGroundStation, ModelPriority=1395 + ) + SimBase.AddModelToTask( + self.envTaskName, self.dongaraGroundStation, ModelPriority=1394 + ) + SimBase.AddModelToTask( + self.envTaskName, self.hawaiiGroundStation, ModelPriority=1393 + ) + SimBase.AddModelToTask(self.envTaskName, self.eclipseObject, ModelPriority=988) + SimBase.AddModelToTask(self.envTaskName, self.ephemConverter, ModelPriority=988) + SimBase.AddModelToTask(self.envTaskName, self.densityModel, ModelPriority=1000) + for ind in range(SimBase.n_spacecraft): + SimBase.AddModelToTask( + self.envTaskName, self.imagingTargetList[ind], ModelPriority=2000 + )
+ + +
+[docs] + def SetGravityBodies(self, SimBase): + """ + Specify what gravitational bodies to include in the simulation. + """ + self.gravFactory = simIncludeGravBody.gravBodyFactory() + self.gravFactory.createSun() + self.planet = self.gravFactory.createEarth() + self.sun = 0 + self.earth = 1 + + self.planet.isCentralBody = ( + True # ensure this is the central gravitational body + ) + self.planet.useSphericalHarmParams = True + simIncludeGravBody.loadGravFromFile( + bskPath + "/supportData/LocalGravData/GGM03S.txt", self.planet.spherHarm, 10 + ) + + # setup Spice interface for some solar system bodies + timeInitString = SimBase.initial_conditions["0"].get("utc_init") + self.gravFactory.createSpiceInterface( + bskPath + "/supportData/EphemerisData/", timeInitString + ) + + self.gravFactory.spiceObject.zeroBase = ( + "earth" # Make sure that the Earth is the zero base + )
+ + +
+[docs] + def SetEpochObject(self): + """ + Add the ephemeris object to use with the SPICE library. + """ + self.ephemConverter = ephemerisConverter.EphemerisConverter() + self.ephemConverter.ModelTag = "ephemConverter" + self.ephemConverter.addSpiceInputMsg( + self.gravFactory.spiceObject.planetStateOutMsgs[self.sun] + ) + self.ephemConverter.addSpiceInputMsg( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + )
+ + +
+[docs] + def SetEclipseObject(self): + """ + Specify what celestial object is causing an eclipse message. + """ + self.eclipseObject = eclipse.Eclipse() + self.eclipseObject.addPlanetToModel( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + ) + self.eclipseObject.sunInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.sun] + )
+ + + def SetAtmosphereDensityModel(self, SimBase): + self.densityModel = exponentialAtmosphere.ExponentialAtmosphere() + self.densityModel.ModelTag = "expDensity" + self.densityModel.planetRadius = SimBase.initial_conditions["env_params"].get( + "planetRadius" + ) + self.densityModel.baseDensity = SimBase.initial_conditions["env_params"].get( + "baseDensity" + ) + self.densityModel.scaleHeight = SimBase.initial_conditions["env_params"].get( + "scaleHeight" + ) + self.densityModel.planetPosInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + ) + + def SetDisturbanceTorque(self, SimBase): + # Loop through every spacecraft to get the disturbance torque + for ind in range(SimBase.n_spacecraft): + disturbance_magnitude = SimBase.initial_conditions[str(ind)].get( + "disturbance_magnitude" + ) + disturbance_vector = SimBase.initial_conditions[str(ind)].get( + "disturbance_vector" + ) + unit_disturbance = disturbance_vector / np.linalg.norm(disturbance_vector) + extForceTorqueObject = extForceTorque.ExtForceTorque() + extForceTorqueObject.ModelTag = "DisturbanceTorque" + extForceTorqueObject.extTorquePntB_B = ( + disturbance_magnitude * unit_disturbance + ) + self.extForceTorqueObjectList.append(extForceTorqueObject) + +
+[docs] + def SetGroundLocations(self, SimBase): + """ + Specify which ground locations are of interest. + """ + # Create a Boulder-based ground station + self.boulderGroundStation = groundLocation.GroundLocation() + self.boulderGroundStation.ModelTag = "GroundStation1" + self.boulderGroundStation.planetRadius = SimBase.initial_conditions[ + "env_params" + ].get("groundLocationPlanetRadius") + self.boulderGroundStation.specifyLocation( + SimBase.initial_conditions["env_params"].get("boulderGroundStationLat"), + SimBase.initial_conditions["env_params"].get("boulderGroundStationLong"), + SimBase.initial_conditions["env_params"].get("boulderGroundStationAlt"), + ) + self.boulderGroundStation.planetInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + ) + self.boulderGroundStation.minimumElevation = SimBase.initial_conditions[ + "env_params" + ].get("boulderMinimumElevation") + self.boulderGroundStation.maximumRange = SimBase.initial_conditions[ + "env_params" + ].get("boulderMaximumRange") + + # Create a Merritt-Island ground station (NASA's Near Earth Network) + self.merrittGroundStation = groundLocation.GroundLocation() + self.merrittGroundStation.ModelTag = "GroundStation2" + self.merrittGroundStation.planetRadius = SimBase.initial_conditions[ + "env_params" + ].get("groundLocationPlanetRadius") + self.merrittGroundStation.specifyLocation( + SimBase.initial_conditions["env_params"].get("merrittGroundStationLat"), + SimBase.initial_conditions["env_params"].get("merrittGroundStationLong"), + SimBase.initial_conditions["env_params"].get("merrittGroundStationAlt"), + ) + self.merrittGroundStation.planetInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + ) + self.merrittGroundStation.minimumElevation = SimBase.initial_conditions[ + "env_params" + ].get("merrittMinimumElevation") + self.merrittGroundStation.maximumRange = SimBase.initial_conditions[ + "env_params" + ].get("merrittMaximumRange") + + # Create a Singapore ground station (NASA's Near Earth Network) + self.singaporeGroundStation = groundLocation.GroundLocation() + self.singaporeGroundStation.ModelTag = "GroundStation3" + self.singaporeGroundStation.planetRadius = SimBase.initial_conditions[ + "env_params" + ].get("groundLocationPlanetRadius") + self.singaporeGroundStation.specifyLocation( + SimBase.initial_conditions["env_params"].get("singaporeGroundStationLat"), + SimBase.initial_conditions["env_params"].get("singaporeGroundStationLong"), + SimBase.initial_conditions["env_params"].get("singaporeGroundStationAlt"), + ) + self.singaporeGroundStation.planetInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + ) + self.singaporeGroundStation.minimumElevation = SimBase.initial_conditions[ + "env_params" + ].get("singaporeMinimumElevation") + self.singaporeGroundStation.maximumRange = SimBase.initial_conditions[ + "env_params" + ].get("singaporeMaximumRange") + + # Create a Weilheim Germany ground station (NASA's Near Earth Network) + self.weilheimGroundStation = groundLocation.GroundLocation() + self.weilheimGroundStation.ModelTag = "GroundStation4" + self.weilheimGroundStation.planetRadius = SimBase.initial_conditions[ + "env_params" + ].get("groundLocationPlanetRadius") + self.weilheimGroundStation.specifyLocation( + SimBase.initial_conditions["env_params"].get("weilheimGroundStationLat"), + SimBase.initial_conditions["env_params"].get("weilheimGroundStationLong"), + SimBase.initial_conditions["env_params"].get("weilheimGroundStationAlt"), + ) + self.weilheimGroundStation.planetInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + ) + self.weilheimGroundStation.minimumElevation = SimBase.initial_conditions[ + "env_params" + ].get("weilheimMinimumElevation") + self.weilheimGroundStation.maximumRange = SimBase.initial_conditions[ + "env_params" + ].get("weilheimMaximumRange") + + # Create a Santiago, Chile ground station (NASA's Near Earth Network) + self.santiagoGroundStation = groundLocation.GroundLocation() + self.santiagoGroundStation.ModelTag = "GroundStation5" + self.santiagoGroundStation.planetRadius = SimBase.initial_conditions[ + "env_params" + ].get("groundLocationPlanetRadius") + self.santiagoGroundStation.specifyLocation( + SimBase.initial_conditions["env_params"].get("santiagoGroundStationLat"), + SimBase.initial_conditions["env_params"].get("santiagoGroundStationLong"), + SimBase.initial_conditions["env_params"].get("santiagoGroundStationAlt"), + ) + self.santiagoGroundStation.planetInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + ) + self.santiagoGroundStation.minimumElevation = SimBase.initial_conditions[ + "env_params" + ].get("santiagoMinimumElevation") + self.santiagoGroundStation.maximumRange = SimBase.initial_conditions[ + "env_params" + ].get("santiagoMaximumRange") + + # Create a Dongara, Australia ground station (NASA's Near Earth Network) + self.dongaraGroundStation = groundLocation.GroundLocation() + self.dongaraGroundStation.ModelTag = "GroundStation6" + self.dongaraGroundStation.planetRadius = SimBase.initial_conditions[ + "env_params" + ].get("groundLocationPlanetRadius") + self.dongaraGroundStation.specifyLocation( + SimBase.initial_conditions["env_params"].get("dongaraGroundStationLat"), + SimBase.initial_conditions["env_params"].get("dongaraGroundStationLong"), + SimBase.initial_conditions["env_params"].get("dongaraGroundStationAlt"), + ) + self.dongaraGroundStation.planetInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + ) + self.dongaraGroundStation.minimumElevation = SimBase.initial_conditions[ + "env_params" + ].get("dongaraMinimumElevation") + self.dongaraGroundStation.maximumRange = SimBase.initial_conditions[ + "env_params" + ].get("dongaraMaximumRange") + + # Create a Dongara, Australia ground station (NASA's Near Earth Network) + self.hawaiiGroundStation = groundLocation.GroundLocation() + self.hawaiiGroundStation.ModelTag = "GroundStation7" + self.hawaiiGroundStation.planetRadius = SimBase.initial_conditions[ + "env_params" + ].get("groundLocationPlanetRadius") + self.hawaiiGroundStation.specifyLocation( + SimBase.initial_conditions["env_params"].get("hawaiiGroundStationLat"), + SimBase.initial_conditions["env_params"].get("hawaiiGroundStationLong"), + SimBase.initial_conditions["env_params"].get("hawaiiGroundStationAlt"), + ) + self.hawaiiGroundStation.planetInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + ) + self.hawaiiGroundStation.minimumElevation = SimBase.initial_conditions[ + "env_params" + ].get("hawaiiMinimumElevation") + self.hawaiiGroundStation.maximumRange = SimBase.initial_conditions[ + "env_params" + ].get("hawaiiMaximumRange")
+ + + def SetImagingTarget(self, SimBase): + # Create one imaging target per spacecraft + for ind in range(SimBase.n_spacecraft): + imagingTarget = groundLocation.GroundLocation() + imagingTarget.ModelTag = "ImagingTarget" + imagingTarget.planetRadius = SimBase.initial_conditions["env_params"].get( + "groundLocationPlanetRadius" + ) + # Just initialize to Hawaii... will get re-initialized with target during + # step + imagingTarget.specifyLocation( + SimBase.initial_conditions["env_params"].get("hawaiiGroundStationLat"), + SimBase.initial_conditions["env_params"].get("hawaiiGroundStationLong"), + SimBase.initial_conditions["env_params"].get("hawaiiGroundStationAlt"), + ) + imagingTarget.planetInMsg.subscribeTo( + self.gravFactory.spiceObject.planetStateOutMsgs[self.earth] + ) + imagingTarget.minimumElevation = SimBase.initial_conditions[str(ind)].get( + "imageTargetMinimumElevation" + ) + imagingTarget.maximumRange = SimBase.initial_conditions[str(ind)].get( + "imageTargetMaximumRange" + ) + self.imagingTargetList.append(imagingTarget) + + # Global call to initialize every module + def InitAllEnvObjects(self, SimBase): + self.SetGravityBodies(SimBase) + self.SetEpochObject() + self.SetEclipseObject() + self.SetGroundLocations(SimBase) + self.SetImagingTarget(SimBase) + self.SetAtmosphereDensityModel(SimBase) + self.SetDisturbanceTorque(SimBase)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/fsw.html b/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/fsw.html new file mode 100644 index 00000000..640f8fd3 --- /dev/null +++ b/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/fsw.html @@ -0,0 +1,595 @@ + + + + + + bsk_rl.envs.multisat_agile_eos.bsk_models.fsw — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.multisat_agile_eos.bsk_models.fsw

+from Basilisk.architecture import cMsgCInterfacePy as cMsgPy
+from Basilisk.architecture import messaging
+from Basilisk.fswAlgorithms import (
+    attTrackingError,
+    hillPoint,
+    locationPointing,
+    mrpFeedback,
+    rwMotorTorque,
+    simpleInstrumentController,
+    thrForceMapping,
+    thrMomentumDumping,
+    thrMomentumManagement,
+)
+from Basilisk.utilities import macros as mc
+
+
+
+[docs] +class FSWModel: + """Defines the FSW class""" + +
+[docs] + def __init__(self, SimBase, fswRate, spacecraftIndex): + # define empty class variables + self.spacecraftIndex = spacecraftIndex + self.modeRequest = "0" + + self.vcConfigMsg = None + self.thrusterConfigMsg = None + self.fswRwConfigMsg = None + self.attRefMsg = None + self.attGuidMsg = None + + # Define process name and default time-step for all FSW tasks defined later on + self.processName = SimBase.FSWProcessName[spacecraftIndex] + self.processTasksTimeStep = mc.sec2nano(fswRate) + + # Create tasks + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "sunPointTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=99, + ) + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "nadirPointTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=98, + ) + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "rwDesatTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=1000, + ) + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "locPointTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=96, + ) + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "trackingErrTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=90, + ) + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "mrpControlTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=80, + ) + + # Create module data and module wraps + # Sun pointing configuration + self.sunPointData = locationPointing.locationPointingConfig() + self.sunPointWrap = SimBase.setModelDataWrap(self.sunPointData) + self.sunPointWrap.ModelTag = "sunPoint" + + # Earth pointing configuration + self.hillPointData = hillPoint.hillPointConfig() + self.hillPointWrap = SimBase.setModelDataWrap(self.hillPointData) + self.hillPointWrap.ModelTag = "hillPoint" + + # Location pointing configuration + self.locPointConfig = locationPointing.locationPointingConfig() + self.locPointWrap = SimBase.setModelDataWrap(self.locPointConfig) + self.locPointWrap.ModelTag = "locPoint" + + # Attitude error configuration + self.trackingErrorData = attTrackingError.attTrackingErrorConfig() + self.trackingErrorWrap = SimBase.setModelDataWrap(self.trackingErrorData) + self.trackingErrorWrap.ModelTag = "trackingError" + + # Attitude controller configuration + self.mrpFeedbackControlData = mrpFeedback.mrpFeedbackConfig() + self.mrpFeedbackControlWrap = SimBase.setModelDataWrap( + self.mrpFeedbackControlData + ) + self.mrpFeedbackControlWrap.ModelTag = "mrpFeedbackControl" + + # add module that maps the Lr control torque into the RW motor torques + self.rwMotorTorqueConfig = rwMotorTorque.rwMotorTorqueConfig() + self.rwMotorTorqueWrap = SimBase.setModelDataWrap(self.rwMotorTorqueConfig) + self.rwMotorTorqueWrap.ModelTag = "rwMotorTorque" + + # Momentum dumping configuration + self.thrDesatControlConfig = thrMomentumManagement.thrMomentumManagementConfig() + self.thrDesatControlWrap = SimBase.setModelDataWrap(self.thrDesatControlConfig) + self.thrDesatControlWrap.ModelTag = "thrMomentumManagement" + + self.thrDumpConfig = thrMomentumDumping.thrMomentumDumpingConfig() + self.thrDumpWrap = SimBase.setModelDataWrap(self.thrDumpConfig) + self.thrDumpWrap.ModelTag = "thrDump" + + # setup the thruster force mapping module + self.thrForceMappingConfig = thrForceMapping.thrForceMappingConfig() + self.thrForceMappingWrap = SimBase.setModelDataWrap(self.thrForceMappingConfig) + self.thrForceMappingWrap.ModelTag = "thrForceMapping" + + # setup the simpleInstrumentController module + self.simpleInsControlConfig = ( + simpleInstrumentController.simpleInstrumentControllerConfig() + ) + self.simpleInsControlWrap = SimBase.setModelDataWrap( + self.simpleInsControlConfig + ) + self.simpleInsControlWrap.ModelTag = "instrumentController" + + # create the FSW module gateway messages + self.setupGatewayMsgs(SimBase) + + # Initialize all modules + self.InitAllFSWObjects(SimBase) + + # Assign initialized modules to tasks + SimBase.AddModelToTask( + "sunPointTask" + str(spacecraftIndex), + self.sunPointWrap, + self.sunPointData, + ModelPriority=1200, + ) + SimBase.AddModelToTask( + "nadirPointTask" + str(spacecraftIndex), + self.hillPointWrap, + self.hillPointData, + ModelPriority=1199, + ) + SimBase.AddModelToTask( + "locPointTask" + str(spacecraftIndex), + self.locPointWrap, + self.locPointConfig, + ModelPriority=1198, + ) + SimBase.AddModelToTask( + "trackingErrTask" + str(spacecraftIndex), + self.trackingErrorWrap, + self.trackingErrorData, + ModelPriority=1197, + ) + SimBase.AddModelToTask( + "mrpControlTask" + str(spacecraftIndex), + self.mrpFeedbackControlWrap, + self.mrpFeedbackControlData, + ModelPriority=1196, + ) + SimBase.AddModelToTask( + "mrpControlTask" + str(spacecraftIndex), + self.rwMotorTorqueWrap, + self.rwMotorTorqueConfig, + ModelPriority=1195, + ) + SimBase.AddModelToTask( + "rwDesatTask" + str(spacecraftIndex), + self.thrDesatControlWrap, + self.thrDesatControlConfig, + ModelPriority=1194, + ) + SimBase.AddModelToTask( + "rwDesatTask" + str(spacecraftIndex), + self.thrForceMappingWrap, + self.thrForceMappingConfig, + ModelPriority=1193, + ) + SimBase.AddModelToTask( + "rwDesatTask" + str(spacecraftIndex), + self.thrDumpWrap, + self.thrDumpConfig, + ModelPriority=1192, + ) + SimBase.AddModelToTask( + "mrpControlTask" + str(spacecraftIndex), + self.simpleInsControlWrap, + self.simpleInsControlConfig, + ModelPriority=987, + ) + + # Create events to be called for triggering GN&C maneuvers + SimBase.fswProc[spacecraftIndex].disableAllTasks()
+ + + # These are module-initialization methods +
+[docs] + def SetSunPointGuidance(self, SimBase): + """ + Defines the Sun pointing guidance module. + """ + self.sunPointData.pHat_B = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ]["nHat_B"] + self.sunPointData.scAttInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.attOutMsg + ) + self.sunPointData.scTransInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.transOutMsg + ) + self.sunPointData.celBodyInMsg.subscribeTo( + SimBase.EnvModel.ephemConverter.ephemOutMsgs[0] + ) + self.sunPointData.useBoresightRateDamping = 1 + cMsgPy.AttGuidMsg_C_addAuthor(self.sunPointData.attGuidOutMsg, self.attGuidMsg)
+ + +
+[docs] + def SetNadirPointGuidance(self, SimBase): + """ + Defines the nadir pointing guidance module. + """ + self.hillPointData.transNavInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.transOutMsg + ) + self.hillPointData.celBodyInMsg.subscribeTo( + SimBase.EnvModel.ephemConverter.ephemOutMsgs[1] + ) + cMsgPy.AttRefMsg_C_addAuthor(self.hillPointData.attRefOutMsg, self.attRefMsg)
+ + +
+[docs] + def SetLocationPointGuidance(self, SimBase): + """ + Defines the Earth location pointing guidance module. + """ + self.locPointConfig.pHat_B = [0, 0, 1] + self.locPointConfig.scAttInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.attOutMsg + ) + self.locPointConfig.scTransInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.transOutMsg + ) + self.locPointConfig.locationInMsg.subscribeTo( + SimBase.EnvModel.imagingTargetList[ + self.spacecraftIndex + ].currentGroundStateOutMsg + ) + self.locPointConfig.useBoresightRateDamping = 1 + cMsgPy.AttGuidMsg_C_addAuthor( + self.locPointConfig.attGuidOutMsg, self.attGuidMsg + )
+ + +
+[docs] + def SetMomentumDumping(self, SimBase): + """ + Defines the momentum dumping configuration. + """ + self.thrDesatControlConfig.hs_min = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get( + "hs_min" + ) # Nms + self.thrDesatControlConfig.rwSpeedsInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].rwStateEffector.rwSpeedOutMsg + ) + self.thrDesatControlConfig.rwConfigDataInMsg.subscribeTo(self.fswRwConfigMsg) + + self.thrDumpConfig.deltaHInMsg.subscribeTo( + self.thrDesatControlConfig.deltaHOutMsg + ) + self.thrDumpConfig.thrusterImpulseInMsg.subscribeTo( + self.thrForceMappingConfig.thrForceCmdOutMsg + ) + self.thrDumpConfig.thrusterConfInMsg.subscribeTo(self.thrusterConfigMsg) + self.thrDumpConfig.maxCounterValue = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("maxCounterValue") + self.thrDumpConfig.thrMinFireTime = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("thrMinFireTime")
+ + +
+[docs] + def SetAttitudeTrackingError(self, SimBase): + """ + Defines the module that converts a reference message into a guidance message. + """ + self.trackingErrorData.attNavInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.attOutMsg + ) + self.trackingErrorData.attRefInMsg.subscribeTo(self.attRefMsg) + cMsgPy.AttGuidMsg_C_addAuthor( + self.trackingErrorData.attGuidOutMsg, self.attGuidMsg + )
+ + +
+[docs] + def SetMRPFeedbackRWA(self, SimBase): + """ + Defines the control properties. + """ + self.mrpFeedbackControlData.guidInMsg.subscribeTo(self.attGuidMsg) + self.mrpFeedbackControlData.vehConfigInMsg.subscribeTo(self.vcConfigMsg) + self.mrpFeedbackControlData.K = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("K") + self.mrpFeedbackControlData.Ki = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("Ki") + self.mrpFeedbackControlData.P = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("P") + self.mrpFeedbackControlData.integralLimit = ( + 2.0 / self.mrpFeedbackControlData.Ki * 0.1 + )
+ + +
+[docs] + def SetThrusterMapping(self, SimBase): + """ + Defines the thrusters mapping. + """ + self.thrForceMappingConfig.cmdTorqueInMsg.subscribeTo( + self.thrDesatControlConfig.deltaHOutMsg + ) + self.thrForceMappingConfig.thrConfigInMsg.subscribeTo(self.thrusterConfigMsg) + self.thrForceMappingConfig.vehConfigInMsg.subscribeTo(self.vcConfigMsg) + self.thrForceMappingConfig.controlAxes_B = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("controlAxes_B") + self.thrForceMappingConfig.thrForceSign = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("thrForceSign") + self.thrForceMappingConfig.angErrThresh = 3.15
+ + +
+[docs] + def SetRWConfigMsg(self, SimBase): + """ + Imports the RWs configuration information. + """ + # Configure RW pyramid exactly as it is in the Dynamics + # (i.e. FSW with perfect knowledge) + # the same msg is used here for both spacecraft + self.fswRwConfigMsg = SimBase.DynModels[ + self.spacecraftIndex + ].rwFactory.getConfigMessage()
+ + +
+[docs] + def SetThrustersConfigMsg(self, SimBase): + """ + Imports the thrusters configuration information. + """ + self.thrusterConfigMsg = SimBase.DynModels[ + self.spacecraftIndex + ].thrFactory.getConfigMessage()
+ + +
+[docs] + def SetVehicleConfigMsg(self, SimBase): + """ + Set the vehicle configuration message. + """ + # Specify the vehicle configuration message to tell things what the vehicle + # inertia is + vehicleConfigOut = messaging.VehicleConfigMsgPayload() + + # Use the same inertia in the FSW algorithm as in the simulation + vehicleConfigOut.ISCPntB_B = SimBase.DynModels[self.spacecraftIndex].I + self.vcConfigMsg = messaging.VehicleConfigMsg().write(vehicleConfigOut)
+ + +
+[docs] + def SetRWMotorTorque(self, SimBase): + """ + Defines the motor torque from the control law. + """ + self.rwMotorTorqueConfig.rwParamsInMsg.subscribeTo(self.fswRwConfigMsg) + self.rwMotorTorqueConfig.vehControlInMsg.subscribeTo( + self.mrpFeedbackControlData.cmdTorqueOutMsg + ) + self.rwMotorTorqueConfig.controlAxes_B = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("controlAxes_B")
+ + +
+[docs] + def SetInstrumentController(self, SimBase): + """ + Defines the instrument controller. + """ + self.simpleInsControlConfig.attErrTolerance = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("imageAttErrorRequirement") + if ( + "imageRateErrorRequirement" + in SimBase.initial_conditions[str(self.spacecraftIndex)].keys() + and SimBase.initial_conditions[str(self.spacecraftIndex)][ + "imageRateErrorRequirement" + ] + != 1 + ): + self.simpleInsControlConfig.useRateTolerance = 1 + self.simpleInsControlConfig.rateErrTolerance = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("imageRateErrorRequirement") + self.simpleInsControlConfig.attGuidInMsg.subscribeTo(self.attGuidMsg) + self.simpleInsControlConfig.locationAccessInMsg.subscribeTo( + SimBase.EnvModel.imagingTargetList[self.spacecraftIndex].accessOutMsgs[-1] + )
+ + + # Global call to initialize every module +
+[docs] + def InitAllFSWObjects(self, SimBase): + """ + Initializes all FSW objects. + """ + self.SetSunPointGuidance(SimBase) + self.SetNadirPointGuidance(SimBase) + self.SetLocationPointGuidance(SimBase) + self.SetAttitudeTrackingError(SimBase) + self.SetRWConfigMsg(SimBase) + self.SetThrustersConfigMsg(SimBase) + self.SetVehicleConfigMsg(SimBase) + self.SetMRPFeedbackRWA(SimBase) + self.SetThrusterMapping(SimBase) + self.SetMomentumDumping(SimBase) + self.SetRWMotorTorque(SimBase) + self.SetInstrumentController(SimBase)
+ + +
+[docs] + def setupGatewayMsgs(self, SimBase): + """create C-wrapped gateway messages such that different modules can write to + this message and provide a common input msg for down-stream modules""" + self.attRefMsg = cMsgPy.AttRefMsg_C() + self.attGuidMsg = cMsgPy.AttGuidMsg_C() + + self.zeroGateWayMsgs() + + # connect gateway FSW effector command msgs with the dynamics + SimBase.DynModels[ + self.spacecraftIndex + ].rwStateEffector.rwMotorCmdInMsg.subscribeTo( + self.rwMotorTorqueConfig.rwMotorTorqueOutMsg + ) + SimBase.DynModels[self.spacecraftIndex].instrument.nodeStatusInMsg.subscribeTo( + self.simpleInsControlConfig.deviceCmdOutMsg + ) + SimBase.DynModels[self.spacecraftIndex].thrusterSet.cmdsInMsg.subscribeTo( + self.thrDumpConfig.thrusterOnTimeOutMsg + )
+ + +
+[docs] + def zeroGateWayMsgs(self): + """Zero all the FSW gateway message payloads""" + self.attRefMsg.write(messaging.AttRefMsgPayload()) + self.attGuidMsg.write(messaging.AttGuidMsgPayload())
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/fsw_steering.html b/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/fsw_steering.html new file mode 100644 index 00000000..fcd9f95a --- /dev/null +++ b/_modules/bsk_rl/envs/multisat_agile_eos/bsk_models/fsw_steering.html @@ -0,0 +1,614 @@ + + + + + + bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering

+from Basilisk.architecture import cMsgCInterfacePy as cMsgPy
+from Basilisk.architecture import messaging
+from Basilisk.fswAlgorithms import (
+    attTrackingError,
+    hillPoint,
+    locationPointing,
+    mrpSteering,
+    rateServoFullNonlinear,
+    rwMotorTorque,
+    simpleInstrumentController,
+    thrForceMapping,
+    thrMomentumDumping,
+    thrMomentumManagement,
+)
+from Basilisk.utilities import macros as mc
+
+
+
+[docs] +class FSWModel: + """Defines the FSW class""" + +
+[docs] + def __init__(self, SimBase, fswRate, spacecraftIndex): + # define empty class variables + self.spacecraftIndex = spacecraftIndex + self.modeRequest = "0" + + self.vcConfigMsg = None + self.thrusterConfigMsg = None + self.fswRwConfigMsg = None + self.attRefMsg = None + self.attGuidMsg = None + + # Define process name and default time-step for all FSW tasks defined later on + self.processName = SimBase.FSWProcessName[spacecraftIndex] + self.processTasksTimeStep = mc.sec2nano(fswRate) + + # Create tasks + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "sunPointTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=99, + ) + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "nadirPointTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=98, + ) + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "rwDesatTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=97, + ) + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "locPointTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=96, + ) + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "trackingErrTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=90, + ) + SimBase.fswProc[spacecraftIndex].addTask( + SimBase.CreateNewTask( + "mrpControlTask" + str(spacecraftIndex), self.processTasksTimeStep + ), + taskPriority=80, + ) + + # Create module data and module wraps + # Sun pointing configuration + self.sunPointData = locationPointing.locationPointingConfig() + self.sunPointWrap = SimBase.setModelDataWrap(self.sunPointData) + self.sunPointWrap.ModelTag = "sunPoint" + + # Earth pointing configuration + self.hillPointData = hillPoint.hillPointConfig() + self.hillPointWrap = SimBase.setModelDataWrap(self.hillPointData) + self.hillPointWrap.ModelTag = "hillPoint" + + # Location pointing configuration + self.locPointConfig = locationPointing.locationPointingConfig() + self.locPointWrap = SimBase.setModelDataWrap(self.locPointConfig) + self.locPointWrap.ModelTag = "locPoint" + + # Attitude error configuration + self.trackingErrorData = attTrackingError.attTrackingErrorConfig() + self.trackingErrorWrap = SimBase.setModelDataWrap(self.trackingErrorData) + self.trackingErrorWrap.ModelTag = "trackingError" + + # Attitude controller configuration + self.mrpSteeringControlData = mrpSteering.mrpSteeringConfig() + self.mrpSteeringControlWrap = SimBase.setModelDataWrap( + self.mrpSteeringControlData + ) + self.mrpSteeringControlWrap.ModelTag = "mrpSteeringControl" + + # Rate servo + self.servoData = rateServoFullNonlinear.rateServoFullNonlinearConfig() + self.servoWrap = SimBase.setModelDataWrap(self.servoData) + self.servoWrap.ModelTag = "rateServo" + + # add module that maps the Lr control torque into the RW motor torques + self.rwMotorTorqueConfig = rwMotorTorque.rwMotorTorqueConfig() + self.rwMotorTorqueWrap = SimBase.setModelDataWrap(self.rwMotorTorqueConfig) + self.rwMotorTorqueWrap.ModelTag = "rwMotorTorque" + + # Momentum dumping configuration + self.thrDesatControlConfig = thrMomentumManagement.thrMomentumManagementConfig() + self.thrDesatControlWrap = SimBase.setModelDataWrap(self.thrDesatControlConfig) + self.thrDesatControlWrap.ModelTag = "thrMomentumManagement" + + self.thrDumpConfig = thrMomentumDumping.thrMomentumDumpingConfig() + self.thrDumpWrap = SimBase.setModelDataWrap(self.thrDumpConfig) + self.thrDumpWrap.ModelTag = "thrDump" + + # setup the thruster force mapping module + self.thrForceMappingConfig = thrForceMapping.thrForceMappingConfig() + self.thrForceMappingWrap = SimBase.setModelDataWrap(self.thrForceMappingConfig) + self.thrForceMappingWrap.ModelTag = "thrForceMapping" + + # setup the simpleInstrumentController module + self.simpleInsControlConfig = ( + simpleInstrumentController.simpleInstrumentControllerConfig() + ) + self.simpleInsControlWrap = SimBase.setModelDataWrap( + self.simpleInsControlConfig + ) + self.simpleInsControlWrap.ModelTag = "instrumentController" + + # create the FSW module gateway messages + self.setupGatewayMsgs(SimBase) + + # Initialize all modules + self.InitAllFSWObjects(SimBase) + + # Assign initialized modules to tasks + SimBase.AddModelToTask( + "sunPointTask" + str(spacecraftIndex), + self.sunPointWrap, + self.sunPointData, + ModelPriority=1200, + ) + SimBase.AddModelToTask( + "nadirPointTask" + str(spacecraftIndex), + self.hillPointWrap, + self.hillPointData, + ModelPriority=1199, + ) + SimBase.AddModelToTask( + "locPointTask" + str(spacecraftIndex), + self.locPointWrap, + self.locPointConfig, + ModelPriority=1198, + ) + SimBase.AddModelToTask( + "trackingErrTask" + str(spacecraftIndex), + self.trackingErrorWrap, + self.trackingErrorData, + ModelPriority=1197, + ) + SimBase.AddModelToTask( + "mrpControlTask" + str(spacecraftIndex), + self.mrpSteeringControlWrap, + self.mrpSteeringControlData, + ModelPriority=1196, + ) + SimBase.AddModelToTask( + "mrpControlTask" + str(spacecraftIndex), + self.servoWrap, + self.servoData, + ModelPriority=1195, + ) + SimBase.AddModelToTask( + "mrpControlTask" + str(spacecraftIndex), + self.rwMotorTorqueWrap, + self.rwMotorTorqueConfig, + ModelPriority=1194, + ) + SimBase.AddModelToTask( + "rwDesatTask" + str(spacecraftIndex), + self.thrDesatControlWrap, + self.thrDesatControlConfig, + ModelPriority=1193, + ) + SimBase.AddModelToTask( + "rwDesatTask" + str(spacecraftIndex), + self.thrForceMappingWrap, + self.thrForceMappingConfig, + ModelPriority=1192, + ) + SimBase.AddModelToTask( + "rwDesatTask" + str(spacecraftIndex), + self.thrDumpWrap, + self.thrDumpConfig, + ModelPriority=1191, + ) + SimBase.AddModelToTask( + "locPointTask" + str(spacecraftIndex), + self.simpleInsControlWrap, + self.simpleInsControlConfig, + ModelPriority=987, + ) + + # Create events to be called for triggering GN&C maneuvers + SimBase.fswProc[spacecraftIndex].disableAllTasks()
+ + + # These are module-initialization methods +
+[docs] + def SetSunPointGuidance(self, SimBase): + """ + Defines the Sun pointing guidance module. + """ + self.sunPointData.pHat_B = [0, 0, 1] + self.sunPointData.scAttInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.attOutMsg + ) + self.sunPointData.scTransInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.transOutMsg + ) + self.sunPointData.celBodyInMsg.subscribeTo( + SimBase.EnvModel.ephemConverter.ephemOutMsgs[0] + ) + cMsgPy.AttGuidMsg_C_addAuthor(self.sunPointData.attGuidOutMsg, self.attGuidMsg)
+ + +
+[docs] + def SetNadirPointGuidance(self, SimBase): + """ + Defines the nadir pointing guidance module. + """ + self.hillPointData.transNavInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.transOutMsg + ) + self.hillPointData.celBodyInMsg.subscribeTo( + SimBase.EnvModel.ephemConverter.ephemOutMsgs[1] + ) + cMsgPy.AttRefMsg_C_addAuthor(self.hillPointData.attRefOutMsg, self.attRefMsg)
+ + +
+[docs] + def SetLocationPointGuidance(self, SimBase): + """ + Defines the Earth location pointing guidance module. + """ + self.locPointConfig.pHat_B = [0, 0, 1] + self.locPointConfig.scAttInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.attOutMsg + ) + self.locPointConfig.scTransInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.transOutMsg + ) + self.locPointConfig.locationInMsg.subscribeTo( + SimBase.EnvModel.imagingTargetList[ + self.spacecraftIndex + ].currentGroundStateOutMsg + ) + self.locPointConfig.useBoresightRateDamping = 1 + cMsgPy.AttGuidMsg_C_addAuthor( + self.locPointConfig.attGuidOutMsg, self.attGuidMsg + )
+ + +
+[docs] + def SetMomentumDumping(self, SimBase): + """ + Defines the momentum dumping configuration. + """ + self.thrDesatControlConfig.hs_min = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get( + "hs_min" + ) # Nms + self.thrDesatControlConfig.rwSpeedsInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].rwStateEffector.rwSpeedOutMsg + ) + self.thrDesatControlConfig.rwConfigDataInMsg.subscribeTo(self.fswRwConfigMsg) + + self.thrDumpConfig.deltaHInMsg.subscribeTo( + self.thrDesatControlConfig.deltaHOutMsg + ) + self.thrDumpConfig.thrusterImpulseInMsg.subscribeTo( + self.thrForceMappingConfig.thrForceCmdOutMsg + ) + self.thrDumpConfig.thrusterConfInMsg.subscribeTo(self.thrusterConfigMsg) + self.thrDumpConfig.maxCounterValue = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("maxCounterValue") + self.thrDumpConfig.thrMinFireTime = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("thrMinFireTime")
+ + +
+[docs] + def SetAttitudeTrackingError(self, SimBase): + """ + Defines the module that converts a reference message into a guidance message. + """ + self.trackingErrorData.attNavInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].simpleNavObject.attOutMsg + ) + self.trackingErrorData.attRefInMsg.subscribeTo(self.attRefMsg) + cMsgPy.AttGuidMsg_C_addAuthor( + self.trackingErrorData.attGuidOutMsg, self.attGuidMsg + )
+ + +
+[docs] + def SetMRPSteeringRWA(self, SimBase): + """ + Defines the control properties. + """ + self.mrpSteeringControlData.guidInMsg.subscribeTo(self.attGuidMsg) + self.mrpSteeringControlData.K1 = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("K1") + self.mrpSteeringControlData.K3 = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("K3") + self.mrpSteeringControlData.omega_max = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("omega_max") + self.mrpSteeringControlData.ignoreOuterLoopFeedforward = False + + self.servoData.Ki = SimBase.initial_conditions[str(self.spacecraftIndex)].get( + "servo_Ki" + ) + self.servoData.P = SimBase.initial_conditions[str(self.spacecraftIndex)].get( + "servo_P" + ) + self.servoData.integralLimit = 2.0 / self.servoData.Ki * 0.1 + self.servoData.knownTorquePntB_B = [0.0, 0.0, 0.0] + self.servoData.guidInMsg.subscribeTo(self.attGuidMsg) + self.servoData.vehConfigInMsg.subscribeTo(self.vcConfigMsg) + self.servoData.rwParamsInMsg.subscribeTo(self.fswRwConfigMsg) + self.servoData.rwSpeedsInMsg.subscribeTo( + SimBase.DynModels[self.spacecraftIndex].rwStateEffector.rwSpeedOutMsg + ) + self.servoData.rateSteeringInMsg.subscribeTo( + self.mrpSteeringControlData.rateCmdOutMsg + )
+ + +
+[docs] + def SetThrusterMapping(self, SimBase): + """ + Defines the thrusters mapping. + """ + self.thrForceMappingConfig.cmdTorqueInMsg.subscribeTo( + self.thrDesatControlConfig.deltaHOutMsg + ) + self.thrForceMappingConfig.thrConfigInMsg.subscribeTo(self.thrusterConfigMsg) + self.thrForceMappingConfig.vehConfigInMsg.subscribeTo(self.vcConfigMsg) + self.thrForceMappingConfig.controlAxes_B = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("controlAxes_B") + self.thrForceMappingConfig.thrForceSign = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("thrForceSign")
+ + +
+[docs] + def SetRWConfigMsg(self, SimBase): + """ + Imports the RWs configuration information. + """ + # Configure RW pyramid exactly as it is in the Dynamics (i.e. FSW with perfect + # knowledge) + # the same msg is used here for both spacecraft + self.fswRwConfigMsg = SimBase.DynModels[ + self.spacecraftIndex + ].rwFactory.getConfigMessage()
+ + +
+[docs] + def SetThrustersConfigMsg(self, SimBase): + """ + Imports the thrusters configuration information. + """ + self.thrusterConfigMsg = SimBase.DynModels[ + self.spacecraftIndex + ].thrFactory.getConfigMessage()
+ + +
+[docs] + def SetVehicleConfigMsg(self, SimBase): + """ + Set the vehicle configuration message. + """ + # Specify the vehicle configuration message to tell things what the vehicle + # inertia is + vehicleConfigOut = messaging.VehicleConfigMsgPayload() + + # Use the same inertia in the FSW algorithm as in the simulation + vehicleConfigOut.ISCPntB_B = SimBase.DynModels[self.spacecraftIndex].I + self.vcConfigMsg = messaging.VehicleConfigMsg().write(vehicleConfigOut)
+ + +
+[docs] + def SetRWMotorTorque(self, SimBase): + """ + Defines the motor torque from the control law. + """ + self.rwMotorTorqueConfig.rwParamsInMsg.subscribeTo(self.fswRwConfigMsg) + self.rwMotorTorqueConfig.vehControlInMsg.subscribeTo( + self.servoData.cmdTorqueOutMsg + ) + self.rwMotorTorqueConfig.controlAxes_B = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("controlAxes_B")
+ + +
+[docs] + def SetInstrumentController(self, SimBase): + """ + Defines the instrument controller. + """ + self.simpleInsControlConfig.attErrTolerance = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("imageAttErrorRequirement") + if ( + "imageRateErrorRequirement" + in SimBase.initial_conditions[str(self.spacecraftIndex)].keys() + ): + self.simpleInsControlConfig.useRateTolerance = 1 + self.simpleInsControlConfig.rateErrTolerance = SimBase.initial_conditions[ + str(self.spacecraftIndex) + ].get("imageRateErrorRequirement") + self.simpleInsControlConfig.attGuidInMsg.subscribeTo(self.attGuidMsg) + self.simpleInsControlConfig.locationAccessInMsg.subscribeTo( + SimBase.EnvModel.imagingTargetList[self.spacecraftIndex].accessOutMsgs[-1] + )
+ + + # Global call to initialize every module +
+[docs] + def InitAllFSWObjects(self, SimBase): + """ + Initializes all FSW objects. + """ + self.SetSunPointGuidance(SimBase) + self.SetNadirPointGuidance(SimBase) + self.SetLocationPointGuidance(SimBase) + self.SetAttitudeTrackingError(SimBase) + self.SetRWConfigMsg(SimBase) + self.SetThrustersConfigMsg(SimBase) + self.SetVehicleConfigMsg(SimBase) + self.SetMRPSteeringRWA(SimBase) + self.SetThrusterMapping(SimBase) + self.SetMomentumDumping(SimBase) + self.SetRWMotorTorque(SimBase) + self.SetInstrumentController(SimBase)
+ + +
+[docs] + def setupGatewayMsgs(self, SimBase): + """create C-wrapped gateway messages such that different modules can write to + this message and provide a common input msg for down-stream modules""" + self.attRefMsg = cMsgPy.AttRefMsg_C() + self.attGuidMsg = cMsgPy.AttGuidMsg_C() + + self.zeroGateWayMsgs() + + # connect gateway FSW effector command msgs with the dynamics + SimBase.DynModels[ + self.spacecraftIndex + ].rwStateEffector.rwMotorCmdInMsg.subscribeTo( + self.rwMotorTorqueConfig.rwMotorTorqueOutMsg + ) + SimBase.DynModels[self.spacecraftIndex].instrument.nodeStatusInMsg.subscribeTo( + self.simpleInsControlConfig.deviceCmdOutMsg + ) + SimBase.DynModels[self.spacecraftIndex].thrusterSet.cmdsInMsg.subscribeTo( + self.thrDumpConfig.thrusterOnTimeOutMsg + )
+ + +
+[docs] + def zeroGateWayMsgs(self): + """Zero all the FSW gateway message payloads""" + self.attRefMsg.write(messaging.AttRefMsgPayload()) + self.attGuidMsg.write(messaging.AttGuidMsgPayload())
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/multisat_agile_eos/gym_env.html b/_modules/bsk_rl/envs/multisat_agile_eos/gym_env.html new file mode 100644 index 00000000..ab5bfabf --- /dev/null +++ b/_modules/bsk_rl/envs/multisat_agile_eos/gym_env.html @@ -0,0 +1,639 @@ + + + + + + bsk_rl.envs.multisat_agile_eos.gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.multisat_agile_eos.gym_env

+import inspect
+
+import gymnasium as gym
+import numpy as np
+from Basilisk.utilities import macros as mc
+from gymnasium import spaces
+
+from bsk_rl.envs.multisat_agile_eos import env_settings
+from bsk_rl.envs.multisat_agile_eos.bsk_sim import MultiSatAgileEOSSimulator
+
+gym.utils.passive_env_checker.logger.setLevel(
+    40
+)  # Disable annoying gym warnings, we know what's good for us
+
+
+
+[docs] +class MultiSatAgileEOS(gym.Env): + """ + This Gymnasium environment is designed to simulate the multi-satellite agile EOS + scheduling problem in which K satellites in a low-Earth orbit Walker-delta formation + attempt to maximize the number of targets imaged and downlinked while avoiding + resource constraint violations. Satellites update their local target lists through + communication with one another. Resource constraint violations include: + + 1. Power: The spacecraft must keep its battery charge above zero + 2. Reaction Wheel Saturation: The spacecraft must keep its reaction wheels within + their speed limits + 3. Data Buffer: The spacecraft must keep its data buffer from overflowing (i.e. + exceeding or meeting the maximum buffer size) + + Each spacecraft must decide between pointing at any one of J number of ground + targets for imaging, pointing at the sun to charge, desaturating reaction wheels, + or downlinking data. This is referred to as the MultiSatAgileEOS environment. + + Action Space (MultiDiscrete): + For each spacecraft: + 0 - Charging mode + 1 - Downlink mode + 2 - Desat mode + 3:J+3 - Image target j + + Observation Space: + For each spacecraft: + ECEF position and velocity - indices 0-5 + Attitude error and attitude rate - indices 6-7 + Reaction wheel speeds - indices 8-11 + Battery charge - indices 12 + Eclipse indicator - indices 13 + Stored data onboard spacecraft - indices 14 + Data transmitted over interval - indices 15 + Amount of time ground stations were accessible (s) - 16-22 + Target Tuples (4 values each) - priority and Hill frame pos + + Reward Function: + r = +A/priority for for each tgt downlinked for first time + r = +B/priority for for each tgt imaged for first time + r = -C if failure + + No reward is given for imaging or downlinking the same target twice + """ + +
+[docs] + def __init__(self): + self.__version__ = "0.0.1" + print( + "Basilisk MultiSatAgileEOS Environment - Version {}".format( + self.__version__ + ) + ) + + # General variables defining the environment + self.max_length = float(270.0) # Maximum number of minutes + self.max_steps = 45 # Maximum number of steps + self.render = False + + # Tell the environment that it doesn't have a sim attribute... + self.simulator_init = 0 + self.simulator = None + self.reward_total = 0 + + # Set initial conditions to none (gets assigned in reset) + self.initial_conditions = None + + # Set the dynRate for the env, which is passed into the simulator + self.envRate = 1.0 + self.dynRate = 1.0 + self.fswRate = 1.0 + + # Set up options, constants for this environment + self.step_duration = ( + 6 * 60.0 + ) # seconds, tune as desired; can be updated mid-simulation + self.reward_mult = 1.0 + self.failure_penalty = 1 + self.image_reward_fn = lambda priority: 0.1 / priority / 45 + self.downlink_reward_fn = lambda priority: 1.0 / priority / 45 + self.comm_method = "free" + assert self.comm_method in [ + "free", + "los", + "los-multi", + "none", + ], f"comm_method {self.comm_method} not valid!" + + # Set the number of spacecraft + self._n_spacecraft = 2 + + # Keep track of rewarded targets + self.rewarded_targets = [] + self.target_duplication = 0 + self.rewarded_downlinks = [] + self.downlink_duplication = 0 + + # Set up targets and action, observation spaces + self._n_targets = ( + 3 # Assumes 3 targets, three other actions (charge, desat, downlink) + ) + self.target_tuple_size = 4 # Number of elements in target definition + self.action_space = spaces.MultiDiscrete( + [3 + self.n_targets] * self.n_spacecraft + ) + low = -1e16 + high = 1e16 + self.observation_space = spaces.Box( + low, + high, + shape=(self.n_spacecraft, 22 + self.n_targets * self.target_tuple_size), + ) + self.obs = np.zeros( + [self.n_spacecraft, 22 + self.n_targets * self.target_tuple_size] + ) + self.obs_full = np.zeros( + [self.n_spacecraft, 22 + self.n_targets * self.target_tuple_size] + ) + + # Store what the agent tried + self.curr_episode = -1 + self.action_episode_memory = [] + self.curr_step = 0 + self.episode_over = False + self.failure = np.zeros(self.n_spacecraft) + + # Parameters not set yet + self.params_set = False
+ + + @property + def n_spacecraft(self): + return self._n_spacecraft + + @n_spacecraft.setter + def n_spacecraft(self, n_spacecraft): + self._n_spacecraft = n_spacecraft + self.update_spaces() + + @property + def n_targets(self): + return self._n_targets + + @n_targets.setter + def n_targets(self, n_targets): + self._n_targets = n_targets + self.update_spaces() + +
+[docs] + def sim_attrs(self): + """ + Creates keyword arguments for instantiating the simulator. If an attribute is + present that matches a simulatormkeyword, pass it in. + """ + attrs = inspect.signature(MultiSatAgileEOSSimulator.__init__).parameters.keys() + return { + attr: getattr(self, attr) + for attr in attrs + if attr != "self" and hasattr(self, attr) + }
+ + +
+[docs] + def set_env_params(self, **kwargs): + """ + Set arbitrary environment variables. Can be used to override simulator defaults. + """ + for arg, val in kwargs.items(): + setattr(self, arg, val)
+ + +
+[docs] + def set_params( + self, + n_spacecraft, + n_planes, + rel_phasing, + inc, + global_tgts, + priorities, + comm_method, + **kwargs, + ): + """ + Updates the constellation and target parameters in the environment. Environment + must be reset afterwards. Reset is not called within this function so user can + choose between reset and reset_init. + """ + # Set these parameters in the environment + self.set_env_params( + n_spacecraft=n_spacecraft, + n_planes=n_planes, + rel_phasing=rel_phasing, + inc=inc, + global_tgts=global_tgts, + priorities=priorities, + comm_method=comm_method, + params_set=True, + **kwargs, + )
+ + +
+[docs] + def update_spaces(self): + """ + Updates the size of action and observation spaces and preallocations. + """ + self.action_space = spaces.MultiDiscrete( + [3 + self.n_targets] * self.n_spacecraft + ) + low = -1e16 + high = 1e16 + self.observation_space = spaces.Box( + low, + high, + shape=(self.n_spacecraft, 22 + self.n_targets * self.target_tuple_size), + ) + self.obs = np.zeros( + [self.n_spacecraft, 22 + self.n_targets * self.target_tuple_size] + ) + self.obs_full = np.zeros( + [self.n_spacecraft, 22 + self.n_targets * self.target_tuple_size] + ) + self.failure = np.zeros(self.n_spacecraft)
+ + + def _seed(self): + np.random.seed() + return + +
+[docs] + def step(self, action, return_obs=True): + """ + :param action: 1 x n_spacecraft list of actions + :param return_obs: whether or not to return observations + :return ob: n_spacecraft x dim_obs nparray of observations + :return reward: 1 x (n_spacecraft + 1) nparray of rewards, last index is global + reward, other are local rewards + :return episode over: True/False if episode is over + :return info: dictionary of info for debugging purposes + """ + # Check if the simulator has been initialized or not + if self.simulator_init == 0: + self.simulator = MultiSatAgileEOSSimulator(**self.sim_attrs()) + self.obs = self.simulator.obs + self.simulator_init = 1 + + # If the simTime in minutes is greater than the planning interval in minutes, + # end the sim + if (self.simulator.simTime / 60.0) >= self.max_length: + print("End of simulation reached", self.simulator.simTime / 60) + self.episode_over = True + + # Save the previous observations + prev_ob = self.obs_full + + # Take the action + downlinked, imaged = self._take_action(action, return_obs) + + if return_obs: + # Loop through each spacecraft's observations + for idx in range(0, self.n_spacecraft): + observation = self.obs_full[idx, :] + # If the wheel speeds get too large, end the episode. + if any( + speeds + > self.simulator.initial_conditions[str(idx)]["maxSpeed"] * mc.RPM + for speeds in observation[8:11] + ): + self.episode_over = True + self.failure[0, idx] = True + print( + "Spacecraft " + + str(idx) + + " died from wheel explosion. RPMs were norm:" + + str(observation[8:11]) + + ", limit is " + + str(6000 * mc.RPM) + + ", body rate was " + + str(observation[7]) + + "action taken was " + + str(action[idx]) + + ", env step" + + str(self.curr_step) + ) + print( + "Prior state was RPM:" + + str(prev_ob[idx, 8:11]) + + " . body rate was: " + + str(prev_ob[idx, 7]) + ) + # If we run out of power, end the episode. + elif observation[11] == 0: + self.failure[0, idx] = True + self.episode_over = True + print( + "Spacecraft " + + str(idx) + + " ran out of power. Battery level at: " + + str(observation[11]) + + ", env step " + + str(self.curr_step) + + ", action taken was " + + str(action[idx]) + ) + # If we overflow the buffer, end the episode. + elif ( + observation[13] + >= self.simulator.initial_conditions[str(idx)][ + "dataStorageCapacity" + ] + and action[idx] >= 3 + ): + self.failure[0, idx] = True + self.episode_over = True + print( + "Spacecraft " + + str(idx) + + " data buffer overflow. Data storage level at:" + + str(observation[13]) + + ", env step, " + + str(self.curr_step) + + ", action taken was " + + str(action[idx]) + ) + elif self.sim_over: + self.episode_over = True + print( + "Spacecraft " + + str(idx) + + " orbit decayed - no penalty, but this one is over." + ) + else: + self.failure[0, idx] = False + + if self.episode_over: + info = { + "episode": {"r": self.reward_total, "l": self.curr_step}, + "obs": self._get_state(), + } + else: + info = {"obs": self._get_state()} + + reward = self._get_reward(downlinked, imaged) + self.reward_total = np.add(self.reward_total, reward) + self.curr_step += 1 + + return ( + self._get_state(), + reward, + self.episode_over, + [False] * self.n_spacecraft, + info, + )
+ + + def _take_action(self, action, return_obs=True): + """ + :param action: 1 x n_spacecraft list of actions + :param return_obs: whether or not to return observation + :return downlinked: n_spacecraft x m list of downlinked targets + :return imaged: n_spacecraft x p list of imaged targets + + Actions: + 0 - Charging Mode + 1 - Desaturation Mode + 2 - Downlinked Mode + >= 3 - Imaging Mode + """ + self.action_episode_memory.append(action) + ( + self.obs, + self.sim_over, + self.obs_full, + downlinked, + imaged, + ) = self.simulator.run_sim(action, return_obs) + + return downlinked, imaged + + def _get_reward(self, downlinked, imaged): + """ + :param downlinked: n_spacecraft x m list of downlinked targets + :param imaged: n_spacecraft x p list of imaged targets + :return reward: 1 x (n_spacecraft + 1) nparray of rewards, last index is global + reward, other are local rewards + """ + reward = np.zeros((1, self.n_spacecraft + 1)) + for i in range(0, self.n_spacecraft): + if self.failure[0, i]: + reward[0, i] = -self.failure_penalty + reward[ + 0, self.n_spacecraft + ] -= self.failure_penalty # Add failure to global reward + else: + for data in downlinked[i]: + if data not in self.rewarded_downlinks: + self.rewarded_downlinks.append(data) + r = self.downlink_reward_fn( + float( + self.simulator.initial_conditions["env_params"][ + "globalPriorities" + ][data] + ) + ) + # Add to global reward + reward[0, i] += r + reward[0, self.n_spacecraft] += r + else: + self.downlink_duplication += 1 + for image in imaged[i]: + if image not in self.rewarded_targets: + self.rewarded_targets.append(image) + r = self.image_reward_fn( + float( + self.simulator.initial_conditions["env_params"][ + "globalPriorities" + ][image] + ) + ) + # Add to global reward + reward[0, i] += r + reward[0, self.n_spacecraft] += r + else: + self.target_duplication += 1 + + return reward + +
+[docs] + def reset(self, seed=None, options=None): + """ + Reset the state of the environment and returns an initial observation. + :return ob: n_spacecraft x dim_obs nparray of observations + """ + if self.initial_conditions is not None: + del self.simulator + + if options is not None: + if "initial_conditions" in options: + self.initial_conditions = options["initial_conditions"] + + # Check if params were set + if not self.params_set: + self.environment_settings = env_settings.env_settings() + if self.initial_conditions is not None: + tgt_pos = self.initial_conditions["env_params"]["globalTargets"] + tgt_priority = self.initial_conditions["env_params"]["globalPriorities"] + else: + ( + tgt_pos, + tgt_priority, + ) = self.environment_settings.generate_global_targets() + self.set_params( + n_spacecraft=self.environment_settings.n_spacecraft, + n_planes=self.environment_settings.n_planes, + rel_phasing=self.environment_settings.rel_phasing, + inc=self.environment_settings.inc, + global_tgts=tgt_pos, + priorities=tgt_priority, + comm_method=self.environment_settings.comm_method, + ) + self.update_spaces() + + self.action_episode_memory = [] + self.episode_over = False + self.failure = np.zeros((1, self.n_spacecraft)) + self.curr_step = 0 + self.reward_total = 0 + + # Create the simulator + self.simulator = MultiSatAgileEOSSimulator(**self.sim_attrs()) + + # Extract initial conditions from instantiation of simulator + self.initial_conditions = self.simulator.initial_conditions + self.simulator_init = 1 + self._seed() + self.obs = self.simulator.obs + + return self.obs
+ + + def _render(self, mode="human", close=False): + return + + def _get_state(self): + """ + Return the non-normalized observation to the environment + :return ob: n_spacecraft x dim_obs np.array of observations + """ + return self.obs
+ + + +if __name__ == "__main__": + env = gym.make("MultiSatAgileEOS-v0") + + env.reset() + + reward_sum = 0 + for idx in range(0, env.max_steps): + action = env.action_space.sample() + ob, reward, episode_over, truncated, info = env.step(action) + reward_sum += reward + + if episode_over: + print("Episode over at step " + str(idx)) + break + + print("Reward total: " + str(reward_sum)) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/multisensor_eos/bsk_sim.html b/_modules/bsk_rl/envs/multisensor_eos/bsk_sim.html new file mode 100644 index 00000000..49485acc --- /dev/null +++ b/_modules/bsk_rl/envs/multisensor_eos/bsk_sim.html @@ -0,0 +1,1040 @@ + + + + + + bsk_rl.envs.multisensor_eos.bsk_sim — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.multisensor_eos.bsk_sim

+import Basilisk.architecture.cMsgCInterfacePy as cMsgPy
+import numpy as np
+from Basilisk import __path__
+from Basilisk.architecture import messaging
+from Basilisk.fswAlgorithms import (
+    attTrackingError,
+    locationPointing,
+    mrpFeedback,
+    rwMotorTorque,
+    thrForceMapping,
+    thrMomentumDumping,
+    thrMomentumManagement,
+)
+from Basilisk.simulation import (
+    ReactionWheelPower,
+    eclipse,
+    ephemerisConverter,
+    extForceTorque,
+    groundLocation,
+    simpleBattery,
+    simpleNav,
+    simplePowerSink,
+    simpleSolarPanel,
+    spacecraft,
+)
+from Basilisk.utilities import RigidBodyKinematics as rbk
+from Basilisk.utilities import SimulationBaseClass
+from Basilisk.utilities import macros as mc
+from Basilisk.utilities import simIncludeGravBody, unitTestSupport, vizSupport
+
+from bsk_rl.utilities.effector_primitives import actuator_primitives as ap
+
+bskPath = __path__[0]
+
+
+class MultiSensorEOSSimulator(SimulationBaseClass.SimBaseClass):
+    """
+    Simulates ground observations by a single spacecraft in LEO.
+
+    Dynamics Components
+
+    * Forces: J2, Atmospheric Drag w/ COM offset
+    * Environment: Exponential density model; eclipse
+    * Actuators: ExternalForceTorque
+    * Sensors: SimpleNav
+    * Systems: SimpleBattery, SimpleSink, SimpleSolarPanel
+
+    FSW Components:
+
+    * mrpFeedback controller
+    * inertial3d (sun pointing), hillPoint (nadir pointing)
+
+    :return:
+    """
+
+    def __init__(
+        self,
+        dyn_step,
+        fsw_step,
+        mode_duration,
+        max_simtime,
+        init_epoch="2021 MAY 04 06:47:48.965 (UTC)",
+        initial_conditions={},
+        render=False,
+        settings=None,
+    ):
+        """
+        Creates the simulation, but does not initialize the initial conditions.
+        """
+        self.dyn_step = dyn_step
+        self.fsw_step = fsw_step
+        self.mode_duration = mode_duration
+        self.max_simtime = max_simtime
+
+        super().__init__()
+
+        # define class variables that are assigned later on
+        self.attRefMsg = None
+        self.has_access_rec = None
+        self.img_modes = settings.img_modes
+
+        self.sim_time = 0.0
+        self.sim_over = False
+
+        # If no initial conditions are defined yet, set ICs
+        if initial_conditions:
+            self.initial_conditions = initial_conditions
+        else:
+            self.initial_conditions = settings.INITIAL_CONDITIONS
+
+        #   Specify some simulation parameters
+        self.init_epoch = self.initial_conditions["utc_init"]
+        self.mass = self.initial_conditions.get("mass")  # kg
+        self.powerDraw = self.initial_conditions.get("powerDraw")  # W
+        self.imaged_targets = np.zeros(self.initial_conditions["n_targets"])
+        self.upcoming_tgts = np.arange(0, self.initial_conditions["n_targets"])
+
+        self.dyn_models = []
+        self.fsw_models = []
+
+        #   Initialize the dynamics+fsw task groups, modules
+
+        self.dyn_proc_name = "DynamicsProcess"  # Create simulation process name
+        self.dyn_proc = self.CreateNewProcess(self.dyn_proc_name)  # Create process
+        self.dyn_task_name = "dyn_task"
+        self.env_task_name = "env_task"
+        self.dyn_task = self.dyn_proc.addTask(
+            self.CreateNewTask(self.dyn_task_name, mc.sec2nano(self.dyn_step)),
+            taskPriority=200,
+        )
+        self.env_task = self.dyn_proc.addTask(
+            self.CreateNewTask(self.env_task_name, mc.sec2nano(self.dyn_step)),
+            taskPriority=199,
+        )
+
+        self.set_env_dynamics()
+
+        self.set_sc_dynamics()
+        self.setup_gateway_msgs()
+        if render:
+            self.setup_viz()
+        self.set_fsw()
+
+        self.set_logging()
+        self.Init_sc_mode = 2
+
+        self.mode_request = None
+        self.img_mode = None
+        self.data_buffer = None
+        self.InitializeSimulation()
+
+        self._sim_state = self.get_sim_state(init=True)
+
+        return
+
+    def set_env_dynamics(self):
+        """
+        Sets up environmental dynamics for the sim, including:
+
+        * SPICE
+        * Eclipse
+        * Planetary atmosphere
+        * Gravity
+        * Spherical harmonics
+        """
+        # clear prior gravitational body and SPICE setup definitions
+        self.gravFactory = simIncludeGravBody.gravBodyFactory()
+
+        self.sun = 0
+        self.central_body = 1
+        body_name = self.initial_conditions.get("central_body")
+        gravBodies = self.gravFactory.createBodies(["sun", body_name])
+        gravBodies[
+            body_name
+        ].isCentralBody = True  # ensure this is the central gravitational body
+
+        self.mu = gravBodies[body_name].mu
+        self.radEquator = gravBodies[body_name].radEquator
+
+        # setup Spice interface for some solar system bodies
+        timeInitString = self.init_epoch
+        self.gravFactory.createSpiceInterface(
+            bskPath + "/supportData/EphemerisData/", timeInitString
+        )
+
+        self.gravFactory.spiceObject.zeroBase = (
+            body_name  # Make sure that the central body is the zero base
+        )
+
+        self.ephemConverter = ephemerisConverter.EphemerisConverter()
+        self.ephemConverter.ModelTag = "ephemConverter"
+        self.ephemConverter.addSpiceInputMsg(
+            self.gravFactory.spiceObject.planetStateOutMsgs[self.sun]
+        )
+        self.ephemConverter.addSpiceInputMsg(
+            self.gravFactory.spiceObject.planetStateOutMsgs[self.central_body]
+        )
+
+        # Create the ground location
+        self.groundLocation = groundLocation.GroundLocation()
+        self.groundLocation.ModelTag = "groundTarget"
+        self.groundLocation.planetRadius = self.radEquator
+        self.groundLocation.specifyLocationPCPF(
+            unitTestSupport.np2EigenVectorXd(
+                self.initial_conditions["targetLocation"][:, 0]
+            )
+        )
+        self.groundLocation.planetInMsg.subscribeTo(
+            self.gravFactory.spiceObject.planetStateOutMsgs[self.central_body]
+        )
+        self.groundLocation.minimumElevation = np.radians(
+            self.initial_conditions.get("minElev")
+        )
+        self.groundLocation.maximumRange = self.initial_conditions.get("maxRange")
+        self.AddModelToTask(self.dyn_task_name, self.groundLocation)
+        self.AddModelToTask(self.dyn_task_name, self.gravFactory.spiceObject)
+        self.AddModelToTask(self.dyn_task_name, self.ephemConverter)
+
+    def set_sc_dynamics(self):
+        """
+        Sets up the dynamics modules for the sim. This simulator runs:
+        scObject (spacecraft dynamics simulation)
+        EclipseObject (simulates eclipse for simpleSolarPanel)
+        extForceTorque (attitude actuation)
+        simpleNav (attitude determination/sensing)
+        simpleSolarPanel (attitude-dependent power generation)
+        simpleBattery (power storage)
+        simplePowerNode (constant power draw)
+
+        By default, parameters are set to those for a 6U cubesat.
+        :return:
+        """
+        sc_number = 0
+        #   Spacecraft, Planet Setup
+        self.scObject = spacecraft.Spacecraft()
+        self.scObject.ModelTag = "spacecraft"
+
+        # attach gravity model to spaceCraftPlus
+        self.scObject.gravField.gravBodies = spacecraft.GravBodyVector(
+            list(self.gravFactory.gravBodies.values())
+        )
+
+        #   Make sure cross-coupling is done
+        self.groundLocation.addSpacecraftToModel(self.scObject.scStateOutMsg)
+
+        rN = self.initial_conditions.get("rN")
+        vN = self.initial_conditions.get("vN")
+
+        width = self.initial_conditions.get("width")
+        depth = self.initial_conditions.get("depth")
+        height = self.initial_conditions.get("height")
+
+        self.Inertia_mat = [
+            1.0 / 12.0 * self.mass * (width**2.0 + depth**2.0),
+            0.0,
+            0.0,
+            0.0,
+            1.0 / 12.0 * self.mass * (depth**2.0 + height**2.0),
+            0.0,
+            0.0,
+            0.0,
+            1.0 / 12.0 * self.mass * (width**2.0 + height**2.0),
+        ]
+
+        self.scObject.hub.mHub = self.mass  # kg
+        self.scObject.hub.IHubPntBc_B = unitTestSupport.np2EigenMatrix3d(
+            self.Inertia_mat
+        )
+
+        self.scObject.hub.r_CN_NInit = unitTestSupport.np2EigenVectorXd(rN)
+        self.scObject.hub.v_CN_NInit = unitTestSupport.np2EigenVectorXd(vN)
+
+        sigma_init = self.initial_conditions.get("sigma_init")
+        omega_init = self.initial_conditions.get("omega_init")
+
+        self.scObject.hub.sigma_BNInit = sigma_init  # sigma_BN_B
+        self.scObject.hub.omega_BN_BInit = omega_init
+
+        self.eclipseObject = eclipse.Eclipse()
+        self.eclipseObject.addSpacecraftToModel(self.scObject.scStateOutMsg)
+        self.eclipseObject.addPlanetToModel(
+            self.gravFactory.spiceObject.planetStateOutMsgs[self.central_body]
+        )
+        self.eclipseObject.sunInMsg.subscribeTo(
+            self.gravFactory.spiceObject.planetStateOutMsgs[self.sun]
+        )
+
+        #   Disturbance Torque Setup
+        disturbance_magnitude = self.initial_conditions.get("disturbance_magnitude")
+        disturbance_vector = self.initial_conditions.get("disturbance_vector")
+        unit_disturbance = disturbance_vector / np.linalg.norm(disturbance_vector)
+        self.extForceTorqueObject = extForceTorque.ExtForceTorque()
+        self.extForceTorqueObject.extTorquePntB_B = (
+            disturbance_magnitude * unit_disturbance
+        )
+        self.extForceTorqueObject.ModelTag = "DisturbanceTorque"
+        self.scObject.addDynamicEffector(self.extForceTorqueObject)
+
+        # Add reaction wheels to the spacecraft
+        self.rwStateEffector, rwFactory, initWheelSpeeds = ap.balancedHR16Triad(
+            useRandom=True, randomBounds=(-800, 800)
+        )
+        # Change the wheel speeds
+        rwFactory.rwList["RW1"].Omega = self.initial_conditions.get("wheelSpeeds")[
+            0
+        ]  # rad/s
+        rwFactory.rwList["RW2"].Omega = self.initial_conditions.get("wheelSpeeds")[
+            1
+        ]  # rad/s
+        rwFactory.rwList["RW3"].Omega = self.initial_conditions.get("wheelSpeeds")[
+            2
+        ]  # rad/s
+        rwFactory.addToSpacecraft("ReactionWheels", self.rwStateEffector, self.scObject)
+        self.rwConfigMsg = rwFactory.getConfigMessage()
+
+        #   Add thrusters to the spacecraft
+        self.thrusterSet, thrFactory = ap.idealMonarc1Octet()
+        thrModelTag = "ACSThrusterDynamics"
+        self.thrusterConfigMsg = thrFactory.getConfigMessage()
+        thrFactory.addToSpacecraft(thrModelTag, self.thrusterSet, self.scObject)
+
+        #   Add simpleNav as a mock estimator to the spacecraft
+        self.simpleNavObject = simpleNav.SimpleNav()
+        self.simpleNavObject.ModelTag = "SimpleNav"
+        self.simpleNavObject.scStateInMsg.subscribeTo(self.scObject.scStateOutMsg)
+
+        #   Power Setup
+        self.solarPanel = simpleSolarPanel.SimpleSolarPanel()
+        self.solarPanel.ModelTag = "solarPanel" + str(sc_number)
+        self.solarPanel.stateInMsg.subscribeTo(self.scObject.scStateOutMsg)
+        self.solarPanel.sunEclipseInMsg.subscribeTo(
+            self.eclipseObject.eclipseOutMsgs[sc_number]
+        )
+        self.solarPanel.sunInMsg.subscribeTo(
+            self.gravFactory.spiceObject.planetStateOutMsgs[self.sun]
+        )
+        self.solarPanel.setPanelParameters(
+            unitTestSupport.np2EigenVectorXd(self.initial_conditions.get("nHat_B")),
+            self.initial_conditions.get("panelArea"),
+            self.initial_conditions.get("panelEfficiency"),
+        )
+
+        self.nominalPowerSink = simplePowerSink.SimplePowerSink()
+        self.nominalPowerSink.ModelTag = "nominalPowerSink" + str(sc_number)
+        self.nominalPowerSink.nodePowerOut = self.powerDraw  # Watts
+
+        self.sensorPowerSink = simplePowerSink.SimplePowerSink()
+        self.sensorPowerSink.ModelTag = "sensorPowerSink" + str(sc_number)
+        self.sensorPowerSink.nodePowerOut = self.powerDraw  # Watts
+        self.sensorPowerSink.powerStatus = 0
+
+        self.rwPowerList = []
+        for ind in range(rwFactory.getNumOfDevices()):
+            rwPower = ReactionWheelPower.ReactionWheelPower()
+            rwPower.ModelTag = f"rwPower_{ind}"
+            rwPower.basePowerNeed = 1.0
+            rwPower.elecToMechEfficiency = 0.9
+            rwPower.mechToElecEfficiency = 0.5
+            rwPower.rwStateInMsg.subscribeTo(self.rwStateEffector.rwOutMsgs[ind])
+            rwPower.nodePowerOut = self.powerDraw  # Watts
+            self.rwPowerList.append(rwPower)
+
+        self.powerMonitor = simpleBattery.SimpleBattery()
+        self.powerMonitor.ModelTag = "powerMonitor"
+        self.powerMonitor.storageCapacity = self.initial_conditions.get(
+            "storageCapacity"
+        )
+        self.powerMonitor.storedCharge_Init = self.initial_conditions.get(
+            "storedCharge_Init"
+        )
+        self.powerMonitor.addPowerNodeToModel(self.solarPanel.nodePowerOutMsg)
+        self.powerMonitor.addPowerNodeToModel(self.nominalPowerSink.nodePowerOutMsg)
+        self.powerMonitor.addPowerNodeToModel(self.sensorPowerSink.nodePowerOutMsg)
+        for rwPower in self.rwPowerList:
+            self.powerMonitor.addPowerNodeToModel(rwPower.nodePowerOutMsg)
+
+        #   Add all the models to the dynamics task
+        self.AddModelToTask(self.dyn_task_name, self.scObject, ModelPriority=200)
+        self.AddModelToTask(self.dyn_task_name, self.simpleNavObject, ModelPriority=199)
+        self.AddModelToTask(self.dyn_task_name, self.rwStateEffector, ModelPriority=198)
+        self.AddModelToTask(self.dyn_task_name, self.thrusterSet, ModelPriority=197)
+        self.AddModelToTask(self.env_task_name, self.eclipseObject, ModelPriority=196)
+        self.AddModelToTask(self.env_task_name, self.solarPanel, ModelPriority=195)
+        self.AddModelToTask(self.env_task_name, self.powerMonitor, ModelPriority=194)
+        self.AddModelToTask(
+            self.env_task_name, self.nominalPowerSink, ModelPriority=193
+        )
+        self.AddModelToTask(self.env_task_name, self.sensorPowerSink, ModelPriority=192)
+        for rwPower in self.rwPowerList:
+            self.AddModelToTask(self.env_task_name, rwPower)
+
+        return
+
+    def setup_viz(self):
+        """
+        Initializes a vizSupport instance and logs all RW/thruster/spacecraft state
+        messages.
+        """
+        from datetime import datetime
+
+        fileName = f"earth_obs_env-v3_{datetime.today()}"
+
+        self.vizInterface = vizSupport.enableUnityVisualization(
+            self,
+            self.dyn_task_name,
+            self.scObject,
+            rwEffectorList=self.rwStateEffector,
+            thrEffectorList=self.thrusterSet,
+            saveFile=fileName,
+        )
+        vizSupport.addLocation(
+            self.vizInterface,
+            stationName=self.initial_conditions.get("target_name"),
+            parentBodyName=self.initial_conditions.get("central_body") + "_planet_data",
+            r_GP_P=self.groundLocation.r_LP_P_Init,
+            fieldOfView=2 * (np.pi / 2 - self.groundLocation.minimumElevation),
+            color="pink",
+            range=self.groundLocation.maximumRange,  # meters
+        )
+        self.vizInterface.settings.spacecraftSizeMultiplier = 1.5
+        self.vizInterface.settings.showLocationCommLines = 1
+        self.vizInterface.settings.showLocationCones = 1
+        self.vizInterface.settings.showLocationLabels = 1
+
+    def set_fsw(self):
+        """
+        Sets up the attitude guidance stack for the simulation.
+
+        This simulator runs:
+
+        * inertial3Dpoint - Sets the attitude guidance objective to point the main panel
+          at the sun.
+        * hillPointTask: Sets the attitude guidance objective to point a "camera"
+          boresight towards nadir.
+        * attitudeTrackingError: Computes the difference between estimated and guidance
+          attitudes
+        * mrpFeedbackControl: Computes an appropriate control torque given an attitude
+          error
+
+        """
+        self.dyn_proc.addTask(
+            self.CreateNewTask("sunPointTask", mc.sec2nano(self.fsw_step)),
+            taskPriority=100,
+        )
+        self.dyn_proc.addTask(
+            self.CreateNewTask("nonSunPointTask", mc.sec2nano(self.fsw_step)),
+            taskPriority=100,
+        )
+        self.dyn_proc.addTask(
+            self.CreateNewTask("nadirPointTask", mc.sec2nano(self.fsw_step)),
+            taskPriority=100,
+        )
+        self.dyn_proc.addTask(
+            self.CreateNewTask("mrpControlTask", mc.sec2nano(self.fsw_step)),
+            taskPriority=50,
+        )
+        self.dyn_proc.addTask(
+            self.CreateNewTask("rwDesatTask", mc.sec2nano(self.fsw_step)),
+            taskPriority=25,
+        )
+
+        # Specify the vehicle configuration message to tell things what the vehicle
+        # inertia is
+        vehicleConfigOut = messaging.VehicleConfigMsgPayload()
+        # use the same inertia in the FSW algorithm as in the simulation
+        #   Set inertia properties to those of a solid 6U cubeoid:
+        vehicleConfigOut.ISCPntB_B = self.Inertia_mat
+        # adcs_config_data -> vcConfigMsg
+        self.vcConfigMsg = messaging.VehicleConfigMsg().write(vehicleConfigOut)
+
+        #   Sun pointing configuration
+        self.sunPointData = locationPointing.locationPointingConfig()
+        self.sunPointWrap = self.setModelDataWrap(self.sunPointData)
+        self.sunPointWrap.ModelTag = "sunPoint"
+        cMsgPy.AttRefMsg_C_addAuthor(self.sunPointData.attRefOutMsg, self.attRefMsg)
+        self.sunPointData.pHat_B = unitTestSupport.EigenVector3d2np(
+            self.solarPanel.nHat_B
+        )
+        self.sunPointData.scTransInMsg.subscribeTo(self.simpleNavObject.transOutMsg)
+        self.sunPointData.scAttInMsg.subscribeTo(self.simpleNavObject.attOutMsg)
+        self.sunPointData.celBodyInMsg.subscribeTo(
+            self.ephemConverter.ephemOutMsgs[self.sun]
+        )
+        self.sunPointData.useBoresightRateDamping = 1
+
+        #   Non-Sun pointing configuration
+        self.nonSunPointData = locationPointing.locationPointingConfig()
+        self.nonSunPointWrap = self.setModelDataWrap(self.nonSunPointData)
+        self.nonSunPointWrap.ModelTag = "nonSunPoint"
+        cMsgPy.AttRefMsg_C_addAuthor(self.nonSunPointData.attRefOutMsg, self.attRefMsg)
+        self.nonSunPointData.pHat_B = -unitTestSupport.EigenVector3d2np(
+            self.solarPanel.nHat_B
+        )
+        self.nonSunPointData.scTransInMsg.subscribeTo(self.simpleNavObject.transOutMsg)
+        self.nonSunPointData.scAttInMsg.subscribeTo(self.simpleNavObject.attOutMsg)
+        self.nonSunPointData.celBodyInMsg.subscribeTo(
+            self.ephemConverter.ephemOutMsgs[self.sun]
+        )
+        self.nonSunPointData.useBoresightRateDamping = 1
+
+        #   Nadir pointing configuration
+        self.nadirPointData = locationPointing.locationPointingConfig()
+        self.nadirPointWrap = self.setModelDataWrap(self.nadirPointData)
+        self.nadirPointWrap.ModelTag = "nadirPoint"
+        cMsgPy.AttRefMsg_C_addAuthor(self.nadirPointData.attRefOutMsg, self.attRefMsg)
+        self.nadirPointData.pHat_B = unitTestSupport.EigenVector3d2np(
+            self.solarPanel.nHat_B
+        )
+        self.nadirPointData.scTransInMsg.subscribeTo(self.simpleNavObject.transOutMsg)
+        self.nadirPointData.scAttInMsg.subscribeTo(self.simpleNavObject.attOutMsg)
+        self.nadirPointData.celBodyInMsg.subscribeTo(
+            self.ephemConverter.ephemOutMsgs[self.central_body]
+        )
+        self.nadirPointData.useBoresightRateDamping = 1
+
+        #   Attitude error configuration
+        self.trackingErrorData = attTrackingError.attTrackingErrorConfig()
+        self.trackingErrorWrap = self.setModelDataWrap(self.trackingErrorData)
+        self.trackingErrorWrap.ModelTag = "trackingError"
+        self.trackingErrorData.attNavInMsg.subscribeTo(self.simpleNavObject.attOutMsg)
+        self.trackingErrorData.attRefInMsg.subscribeTo(self.attRefMsg)
+        self.trackingErrorData.sigma_R0R = rbk.C2MRP(
+            self.initial_conditions.get("C_R0R")
+        )
+
+        #   Attitude controller configuration
+        self.mrpFeedbackControlData = mrpFeedback.mrpFeedbackConfig()
+        self.mrpFeedbackControlWrap = self.setModelDataWrap(self.mrpFeedbackControlData)
+        self.mrpFeedbackControlWrap.ModelTag = "mrpFeedbackControl"
+        self.mrpFeedbackControlData.guidInMsg.subscribeTo(
+            self.trackingErrorData.attGuidOutMsg
+        )
+        self.mrpFeedbackControlData.vehConfigInMsg.subscribeTo(self.vcConfigMsg)
+        self.mrpFeedbackControlData.K = self.initial_conditions.get("K")
+        self.mrpFeedbackControlData.Ki = self.initial_conditions.get("Ki")
+        self.mrpFeedbackControlData.P = self.initial_conditions.get("P")
+        self.mrpFeedbackControlData.integralLimit = (
+            2.0 / self.mrpFeedbackControlData.Ki * 0.1
+        )
+
+        # add module that maps the Lr control torque into the RW motor torques
+        self.rwMotorTorqueConfig = rwMotorTorque.rwMotorTorqueConfig()
+        self.rwMotorTorqueWrap = self.setModelDataWrap(self.rwMotorTorqueConfig)
+        self.rwMotorTorqueWrap.ModelTag = "rwMotorTorque"
+        self.rwStateEffector.rwMotorCmdInMsg.subscribeTo(
+            self.rwMotorTorqueConfig.rwMotorTorqueOutMsg
+        )
+        self.rwMotorTorqueConfig.rwParamsInMsg.subscribeTo(self.rwConfigMsg)
+        self.rwMotorTorqueConfig.vehControlInMsg.subscribeTo(
+            self.mrpFeedbackControlData.cmdTorqueOutMsg
+        )
+        self.rwMotorTorqueConfig.controlAxes_B = self.initial_conditions.get(
+            "controlAxes_B"
+        )
+        self.rwStateEffector.rwMotorCmdInMsg.subscribeTo(
+            self.rwMotorTorqueConfig.rwMotorTorqueOutMsg
+        )
+
+        #   Momentum dumping configuration
+        self.thrDesatControlConfig = thrMomentumManagement.thrMomentumManagementConfig()
+        self.thrDesatControlWrap = self.setModelDataWrap(self.thrDesatControlConfig)
+        self.thrDesatControlWrap.ModelTag = "thrMomentumManagement"
+        self.thrDesatControlConfig.hs_min = self.initial_conditions.get("hs_min")  # Nms
+        self.thrDesatControlConfig.rwSpeedsInMsg.subscribeTo(
+            self.rwStateEffector.rwSpeedOutMsg
+        )
+        self.thrDesatControlConfig.rwConfigDataInMsg.subscribeTo(self.rwConfigMsg)
+
+        # setup the thruster force mapping module
+        self.thrForceMappingConfig = thrForceMapping.thrForceMappingConfig()
+        self.thrForceMappingWrap = self.setModelDataWrap(self.thrForceMappingConfig)
+        self.thrForceMappingWrap.ModelTag = "thrForceMapping"
+        self.thrForceMappingConfig.cmdTorqueInMsg.subscribeTo(
+            self.thrDesatControlConfig.deltaHOutMsg
+        )
+        self.thrForceMappingConfig.thrConfigInMsg.subscribeTo(self.thrusterConfigMsg)
+        self.thrForceMappingConfig.vehConfigInMsg.subscribeTo(self.vcConfigMsg)
+        self.thrForceMappingConfig.controlAxes_B = self.initial_conditions.get(
+            "controlAxes_B"
+        )
+        self.thrForceMappingConfig.thrForceSign = self.initial_conditions.get(
+            "thrForceSign"
+        )
+        self.thrForceMappingConfig.angErrThresh = 3.15
+
+        self.thrDumpConfig = thrMomentumDumping.thrMomentumDumpingConfig()
+        self.thrDumpWrap = self.setModelDataWrap(self.thrDumpConfig)
+        self.thrDumpConfig.deltaHInMsg.subscribeTo(
+            self.thrDesatControlConfig.deltaHOutMsg
+        )
+        self.thrDumpConfig.thrusterImpulseInMsg.subscribeTo(
+            self.thrForceMappingConfig.thrForceCmdOutMsg
+        )
+        self.thrusterSet.cmdsInMsg.subscribeTo(self.thrDumpConfig.thrusterOnTimeOutMsg)
+        self.thrDumpConfig.thrusterConfInMsg.subscribeTo(self.thrusterConfigMsg)
+        self.thrDumpConfig.maxCounterValue = self.initial_conditions.get(
+            "maxCounterValue"
+        )
+        self.thrDumpConfig.thrMinFireTime = self.initial_conditions.get(
+            "thrMinFireTime"
+        )
+
+        #   Add models to tasks
+        self.AddModelToTask(
+            "sunPointTask", self.sunPointWrap, self.sunPointData, ModelPriority=10
+        )
+        self.AddModelToTask(
+            "nonSunPointTask",
+            self.nonSunPointWrap,
+            self.nonSunPointData,
+            ModelPriority=10,
+        )
+        self.AddModelToTask(
+            "nadirPointTask", self.nadirPointWrap, self.nadirPointData, ModelPriority=10
+        )
+
+        self.AddModelToTask(
+            "mrpControlTask",
+            self.mrpFeedbackControlWrap,
+            self.mrpFeedbackControlData,
+            ModelPriority=3,
+        )
+        self.AddModelToTask(
+            "mrpControlTask",
+            self.trackingErrorWrap,
+            self.trackingErrorData,
+            ModelPriority=9,
+        )
+        self.AddModelToTask(
+            "mrpControlTask",
+            self.rwMotorTorqueWrap,
+            self.rwMotorTorqueConfig,
+            ModelPriority=1,
+        )
+
+        self.AddModelToTask(
+            "rwDesatTask",
+            self.thrDesatControlWrap,
+            self.thrDesatControlConfig,
+            ModelPriority=3,
+        )
+        self.AddModelToTask(
+            "rwDesatTask",
+            self.thrForceMappingWrap,
+            self.thrForceMappingConfig,
+            ModelPriority=2,
+        )
+        self.AddModelToTask(
+            "rwDesatTask", self.thrDumpWrap, self.thrDumpConfig, ModelPriority=1
+        )
+
+    def set_logging(self):
+        """
+        Logs simulation outputs to return as observations. This simulator observes:
+        mrp_bn - inertial to body MRP
+        error_mrp - Attitude error given current guidance objective
+        power_level - current W-Hr from the battery
+        r_bn - inertial position of the s/c relative to Earth
+        :return:
+        """
+        # Set the sampling time to the duration of a timestep:
+        samplingTime = mc.sec2nano(self.mode_duration)
+
+        self.has_access_rec = self.groundLocation.accessOutMsgs[-1].recorder()
+        self.onTimeLog = self.thrDumpConfig.thrusterOnTimeOutMsg.recorder()
+        self.thrMapLog = self.thrForceMappingConfig.thrForceCmdOutMsg.recorder(
+            samplingTime
+        )
+
+        self.AddModelToTask("mrpControlTask", self.thrMapLog)
+        self.AddModelToTask("mrpControlTask", self.has_access_rec)
+        self.AddModelToTask("mrpControlTask", self.onTimeLog)
+        return
+
+    def setup_gateway_msgs(self):
+        """create C-wrapped gateway messages such that different modules can write to
+        this message
+        and provide a common input msg for down-stream modules"""
+        self.attRefMsg = cMsgPy.AttRefMsg_C()
+        self.zeroGateWayMsgs()
+
+    def zeroGateWayMsgs(self):
+        """Zero all the FSW gateway message payloads"""
+        self.attRefMsg.write(messaging.AttRefMsgPayload())
+
+    def run_sim(self, action):
+        """
+        Executes the sim for a specified duration given a mode command.
+
+        Args:
+            action:
+                * 0 - Point solar panels at the sun
+                * 1 - Desaturate reaction wheels
+                * >1 - Image types
+
+        Returns:
+            sim_state - simulation states generated
+            sim_over - episode over flag
+        """
+
+        self.mode_request = action
+
+        currentResetTime = mc.sec2nano(self.sim_time)
+        self.zeroGateWayMsgs()
+        if self.mode_request == 0:
+            #   Set up a sun pointing mode
+            self.dyn_proc.enableAllTasks()
+            self.sunPointWrap.Reset(currentResetTime)
+            self.trackingErrorWrap.Reset(currentResetTime)
+
+            self.disableTask("nadirPointTask")
+            self.disableTask("nonSunPointTask")
+            self.disableTask("rwDesatTask")
+
+            self.enableTask("sunPointTask")
+            self.enableTask("mrpControlTask")
+            self.sensorPowerSink.powerStatus = 0
+
+        elif self.mode_request == 1:
+            #   Set up a desat mode
+            self.dyn_proc.enableAllTasks()
+            self.nonSunPointWrap.Reset(currentResetTime)
+            self.trackingErrorWrap.Reset(currentResetTime)
+
+            self.thrDesatControlWrap.Reset(currentResetTime)
+            self.thrDumpWrap.Reset(currentResetTime)
+            self.thrForceMappingWrap.Reset(currentResetTime)
+
+            self.disableTask("nadirPointTask")
+            self.disableTask("sunPointTask")
+
+            self.enableTask("nonSunPointTask")
+            self.enableTask("mrpControlTask")
+            self.enableTask("rwDesatTask")
+            self.sensorPowerSink.powerStatus = 0
+
+        elif (self.mode_request - 2) in range(self.img_modes):
+            #   Set up a nadir pointing mode
+            self.dyn_proc.enableAllTasks()
+            self.nadirPointWrap.Reset(currentResetTime)
+            self.trackingErrorWrap.Reset(currentResetTime)
+
+            self.disableTask("sunPointTask")
+            self.disableTask("nonSunPointTask")
+            self.disableTask("rwDesatTask")
+
+            self.enableTask("nadirPointTask")
+            self.enableTask("mrpControlTask")
+            self.sensorPowerSink.powerStatus = 1
+            self.data_buffer += 1
+
+        else:
+            raise invalid_action
+
+        self.sim_time += self.mode_duration
+        simulationTime = mc.sec2nano(self.sim_time)
+
+        #   Execute the sim
+        self.has_access_rec.clear()  # purge the recorder history
+        self.onTimeLog.clear()
+        self.thrMapLog.clear()
+        self.ConfigureStopTime(simulationTime)
+        self.ExecuteSimulation()
+
+        #   Simulation States
+        self._sim_state = self.get_sim_state()
+
+        #   Check if sim is over
+        sc_pos_inertial = np.array(
+            [
+                self._sim_state.get("rx_sc_N"),
+                self._sim_state.get("ry_sc_N"),
+                self._sim_state.get("rz_sc_N"),
+            ]
+        )
+        if np.linalg.norm(sc_pos_inertial) < (self.radEquator):
+            self.sim_over = True
+            print("Spacecraft crashed into Body.")
+        elif self.sim_time >= self.max_simtime:
+            self.sim_over = True
+
+        return self._sim_state
+
+    def get_sim_state(self, init=False):
+        # Check if the target was imaged
+        if any(self.has_access_rec.hasAccess) and not init:
+            self.imaged_targets[self.upcoming_tgts[0]] = 1
+
+        # Update list of upcoming targets
+        self.upcoming_tgts = self.check_target_switch()
+
+        # Update the groundLocation with the next target
+        self.groundLocation.specifyLocationPCPF(
+            unitTestSupport.np2EigenVectorXd(
+                self.initial_conditions["targetLocation"][:, self.upcoming_tgts[0]]
+            )
+        )
+
+        self.img_mode = self.initial_conditions["instrumentSpecification"][
+            self.upcoming_tgts[0]
+        ]
+
+        if init:
+            r_target_N = np.array(self.groundLocation.r_LP_P_Init).T[0]
+            r_sc_N = self.initial_conditions.get("rN")
+            att_err = np.linalg.norm(self.scObject.hub.sigma_BNInit)
+            att_rate = np.linalg.norm(self.scObject.hub.omega_BN_BInit)
+            wheel_speed = np.linalg.norm(self.initial_conditions.get("wheelSpeeds"))
+            stored_charge = self.powerMonitor.storedCharge_Init
+            sun_indicator = self.eclipseObject.eclipseOutMsgs[0].read().shadowFactor
+            r_target_sc_N = r_sc_N - r_target_N
+            access_indicator = int(
+                np.arccos(
+                    np.dot(r_target_N, r_target_sc_N)
+                    / (np.linalg.norm(r_target_N) * np.linalg.norm(r_target_sc_N))
+                )
+                <= np.deg2rad(90.0 - self.initial_conditions.get("minElev"))
+            )
+            self.data_buffer = 0
+            r_LN_N = [0, 0, 0]
+            r_LN_N_norm = 1
+        else:
+            # Call update state on the ground location class to update the target
+            self.groundLocation.UpdateState(mc.sec2nano(self.sim_time))
+            r_target_N = self.groundLocation.currentGroundStateOutMsg.read().r_LN_N
+            r_sc_N = self.scObject.scStateOutMsg.read().r_BN_N
+            att_err = np.linalg.norm(
+                self.trackingErrorData.attGuidOutMsg.read().sigma_BR
+            )
+            att_rate = np.linalg.norm(self.simpleNavObject.attOutMsg.read().omega_BN_B)
+            wheel_speed = np.linalg.norm(
+                self.rwStateEffector.rwSpeedOutMsg.read().wheelSpeeds[0:3]
+            )
+            stored_charge = self.powerMonitor.batPowerOutMsg.read().storageLevel
+            sun_indicator = self.eclipseObject.eclipseOutMsgs[0].read().shadowFactor
+            has_access = self.has_access_rec.hasAccess
+            if any(has_access):
+                access_indicator = 1
+            else:
+                access_indicator = 0
+
+            r_LN_N = self.groundLocation.currentGroundStateOutMsg.read().r_LN_N
+            r_LN_N_norm = np.linalg.norm(r_LN_N)
+
+        azimuth_angle = self.groundLocation.accessOutMsgs[-1].read().azimuth
+        elevation_angle = self.groundLocation.accessOutMsgs[-1].read().elevation
+        azimuth_rate = self.groundLocation.accessOutMsgs[-1].read().az_dot
+        elevation_rate = self.groundLocation.accessOutMsgs[-1].read().el_dot
+        rx_BL_L = self.groundLocation.accessOutMsgs[-1].read().r_BL_L[0]
+        ry_BL_L = self.groundLocation.accessOutMsgs[-1].read().r_BL_L[1]
+        rz_BL_L = self.groundLocation.accessOutMsgs[-1].read().r_BL_L[2]
+        rxy_2norm_BL_L = np.linalg.norm(
+            self.groundLocation.accessOutMsgs[-1].read().r_BL_L[0:2]
+        )
+        xDot_BL_L = self.groundLocation.accessOutMsgs[-1].read().v_BL_L[0]
+        yDot_BL_L = self.groundLocation.accessOutMsgs[-1].read().v_BL_L[1]
+        zDot_BL_L = self.groundLocation.accessOutMsgs[-1].read().v_BL_L[2]
+        v_can = np.sqrt(
+            self.mu / self.radEquator
+        )  # canonical velocity normalizing constant
+        rot_ang_mom = unitTestSupport.EigenVector3d2np(
+            self.scObject.totRotAngMomPntC_N
+        )  # rotational angular momentum about CoM in N-frame coords
+        current_sim_state = {
+            "rx_target_N": r_target_N[0],
+            "ry_target_N": r_target_N[1],
+            "rz_target_N": r_target_N[2],
+            "rx_sc_N": r_sc_N[0],
+            "ry_sc_N": r_sc_N[1],
+            "rz_sc_N": r_sc_N[2],
+            "sc_az": azimuth_angle,
+            "sc_el": elevation_angle,
+            "sc_az_dot": azimuth_rate,
+            "sc_el_dot": elevation_rate,
+            "rx_BL_L": rx_BL_L,
+            "ry_BL_L": ry_BL_L,
+            "rz_BL_L": rz_BL_L,
+            "rx_canonical_BL_L": rx_BL_L / self.radEquator,
+            "ry_canonical_BL_L": ry_BL_L / self.radEquator,
+            "rz_canonical_BL_L": rz_BL_L / self.radEquator,
+            "rxy_2norm_canonical_BL_L": rxy_2norm_BL_L / self.radEquator,
+            "xDot_BL_L": xDot_BL_L,
+            "yDot_BL_L": yDot_BL_L,
+            "zDot_BL_L": zDot_BL_L,
+            "xDot_canonical_BL_L": xDot_BL_L / v_can,
+            "yDot_canonical_BL_L": yDot_BL_L / v_can,
+            "zDot_canonical_BL_L": zDot_BL_L / v_can,
+            "att_err": att_err,
+            "att_rate": att_rate,
+            "wheel_speed": wheel_speed,
+            "stored_charge": stored_charge,
+            "sun_indicator": sun_indicator,
+            "access_indicator": access_indicator,
+            "sc_mode": self.mode_request,
+            "rxhat_target_N": r_LN_N[0] / r_LN_N_norm,
+            "ryhat_target_N": r_LN_N[1] / r_LN_N_norm,
+            "rzhat_target_N": r_LN_N[2] / r_LN_N_norm,
+            "rot_ang_mom_x": rot_ang_mom[0],
+            "rot_ang_mom_y": rot_ang_mom[1],
+            "rot_ang_mom_z": rot_ang_mom[2],
+            "data_buffer": self.data_buffer,
+            "img_mode": self.img_mode,
+            "img_mode_norm": self.img_mode / self.img_modes,
+        }
+
+        return current_sim_state
+
+    def check_target_switch(self):
+        """
+        Grabs the index(s) of the next upcoming target(s)
+        """
+        times = self.initial_conditions.get("target_times")
+        idx = 0
+        upcoming_tgts = []
+        for idx, time in enumerate(times):
+            # If less than simTime, add to upcoming targets
+            if self.sim_time < time:
+                if not self.imaged_targets[idx]:
+                    upcoming_tgts.append(idx)
+                # return idx
+
+        # Check that the list has at least as many upcoming targets as n_targets
+        # (num in action space)
+        # If not, backfill with last target
+        if len(upcoming_tgts) < self.initial_conditions["n_targets"]:
+            for tgt in range(self.initial_conditions["n_targets"] - len(upcoming_tgts)):
+                # Append the last target
+                upcoming_tgts.append(idx)
+
+        return upcoming_tgts
+
+    def __del__(self):
+        """
+        Deletes the simulation instance and calls the spice kernel unloader
+        :return:
+        """
+        self.close_gracefully()
+        return
+
+    def close_gracefully(self):
+        """
+        makes sure spice gets shut down right when we close.
+        :return:
+        """
+        self.gravFactory.unloadSpiceKernels()
+        return
+
+
+
+[docs] +class invalid_action(Exception): + def __str__(self): + return "Invalid mode selection"
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/multisensor_eos/env_settings.html b/_modules/bsk_rl/envs/multisensor_eos/env_settings.html new file mode 100644 index 00000000..2079bff4 --- /dev/null +++ b/_modules/bsk_rl/envs/multisensor_eos/env_settings.html @@ -0,0 +1,273 @@ + + + + + + bsk_rl.envs.multisensor_eos.env_settings — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.multisensor_eos.env_settings

+import random
+
+import numpy as np
+from Basilisk.utilities import macros as mc
+from Basilisk.utilities import orbitalMotion
+
+from bsk_rl.utilities.initial_conditions import leo_orbit
+
+
+
+[docs] +class Settings: + """ + To be used as settings for the MultiSensorEOS gymnasium environment and bsk sim. + """ + +
+[docs] + def __init__(self): + # Instrument Settings + self.img_modes = 2 + + # Simulation parameters + self.SIM_TIME = int(90) # number of planning intervals + self.N_TGTS = 50 + self.STEP_DURATION = 180.0 # [sec] length of planning interval + self.DYN_STEP = 0.5 # [sec] + self.FSW_STEP = 1.0 # [sec] + self.RENDER = False # will render every episode if used in training + + # Spacecraft Attributes + self.MASS = 330.0 # [kg] + self.POWER_DRAW = -5.0 # [W] + self.WHEEL_LIM = 3000 * mc.RPM # [rad/s] + self.POWER_MAX = 50.0 * 3600.0 # J + + # Learning Parameters + self.REWARD_MULTIPLIER = 1.0 + + # Observation Space (each obs element is a scalar value) + self.OBSERVATIONS = [ + # "rx_target_N", + # "ry_target_N", + # "rz_target_N", + # "rx_sc_N", + # "ry_sc_N", + # "rz_sc_N", + # "sc_az", + # "sc_el", + # "sc_az_dot", + # "sc_el_dot", + # "rx_BL_L", + # "ry_BL_L", + # "rz_BL_L", + "rx_canonical_BL_L", + "ry_canonical_BL_L", + "rz_canonical_BL_L", + # "rxy_2norm_canonical_BL_L", + # "xDot_BL_L", + # "yDot_BL_L", + # "zDot_BL_L", + "xDot_canonical_BL_L", + "yDot_canonical_BL_L", + "zDot_canonical_BL_L", + # "rxhat_target_N", + # "ryhat_target_N", + # "rzhat_target_N", + "att_err", + "att_rate", + "wheel_speed", + "stored_charge", + "sun_indicator", + "access_indicator", + # "sc_mode", + # "data_buffer", + "img_mode_norm", + ] + + self.UTC_INIT = "2021 MAY 04 06:47:48.965 (UTC)" + + self.CENTRAL_BODY = "earth" + + # Attitude rate + self.maxSpinRate = 0.001
+ + + def generate_new_ic(self): + oe, rN, vN = leo_orbit.sampled_400km() + + targets, times = leo_orbit.create_ground_tgts( + self.N_TGTS, rN, vN, self.SIM_TIME * self.STEP_DURATION / 60, self.UTC_INIT + ) + + # Sample random values + sigma_init = np.array([random.uniform(0, 1.0) for _ in range(3)]) + omega_init = np.array( + [random.uniform(-i, i) for i in self.maxSpinRate * np.ones(3)] + ) + disturbance_vector = np.array([random.gauss(0, 1) for _ in range(3)]) + wheelSpeeds = np.array( + [random.uniform(-i, i) for i in 0.5 * self.WHEEL_LIM * np.ones(3)] + ) + storedCharge_Init = random.uniform(0.3 * self.POWER_MAX, self.POWER_MAX) + + # Dict of initial conditions + self.INITIAL_CONDITIONS = { + # Initialize the start time of the sim + "utc_init": self.UTC_INIT, + # Mass + "mass": self.MASS, # kg + # Orbital parameters + "central_body": self.CENTRAL_BODY, + "oe": oe, + "rN": rN, + "vN": vN, + # Spacecraft dimensions + "width": 1.38, + "depth": 1.04, + "height": 1.58, + # Attitude and rate initialization + "sigma_init": sigma_init, + "omega_init": omega_init, + # Atmospheric density + "planetRadius": orbitalMotion.REQ_EARTH * 1000.0, + "baseDensity": 1.22, # kg/m^3 + "scaleHeight": 8e3, # m + # Disturbance Torque + "disturbance_magnitude": 5e-3, + "disturbance_vector": disturbance_vector + / np.linalg.norm(disturbance_vector), + # Reaction Wheel speeds + "wheelSpeeds": wheelSpeeds, # rad/s + # Solar Panel Parameters + "nHat_B": np.array([0, 0, 1]), + "panelArea": 2 * 0.15 * 0.3, + "panelEfficiency": 0.20, + # Power Sink Parameters + "powerDraw": self.POWER_DRAW, # W + # Battery Parameters + "storageCapacity": self.POWER_MAX, + "storedCharge_Init": storedCharge_Init, + # Pointing Configuration (Solar panels & cameras) + "C_R0R": np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]).T, + # RW motor torque and thruster force mapping FSW config + "controlAxes_B": [1, 0, 0, 0, 1, 0, 0, 0, 1], + # Attitude controller FSW config + "K": 7, + "Ki": -1.0, # Note: make value negative to turn off integral feedback + "P": 35, + # Momentum dumping config + "hs_min": 0.0, # Nms + # Thruster force mapping FSW module + "thrForceSign": 1, + # Thruster momentum dumping FSW config + "maxCounterValue": 4, + "thrMinFireTime": 0.02, # Seconds + # Ground target locations + "targetLocation": targets, # m + "instrumentSpecification": np.random.randint( + 1, 1 + self.img_modes, self.N_TGTS + ), + "target_times": times, # seconds + "minElev": 60.0, # [degrees] + "maxRange": 5.0e7, # [meters} + "n_targets": self.N_TGTS, + }
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/multisensor_eos/gym_env.html b/_modules/bsk_rl/envs/multisensor_eos/gym_env.html new file mode 100644 index 00000000..373ec8af --- /dev/null +++ b/_modules/bsk_rl/envs/multisensor_eos/gym_env.html @@ -0,0 +1,422 @@ + + + + + + bsk_rl.envs.multisensor_eos.gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.multisensor_eos.gym_env

+from copy import deepcopy
+
+import gymnasium as gym
+import numpy as np
+from gymnasium import spaces
+
+from bsk_rl.envs.multisensor_eos.bsk_sim import MultiSensorEOSSimulator
+from bsk_rl.envs.multisensor_eos.env_settings import Settings
+
+
+
+[docs] +class MultiSensorEOS(gym.Env): + """ + Earth observation environment - simulates a spacecraft with variable imager modes + attempting to image a ground location. + Agent must choose between charging, desaturating, and image type(s); also needs to + choose an appropriate imaging type. + Taking the image type corresponding to the ground location's required sensor type + results in full reward, other image types results in no reward. + + Action Space (discrete): + + * 0 - Points solar panels at the sun. + * 1 - Desaturates the reaction wheels. + * >1 - Orients the s/c towards the earth; takes image of type _. + + Observation Space: + + * r_sc_I - float[3,] - spacecraft position. + * v_sc - float[3,] - spacecraft velocity in PCPF. + * sigma_RB - float [0,1] - norm of the spacecraft error MRP with respect to the + last reference frame specified. + * omega_BN - float - norm of the total spacecraft bus rotational velocity with + respect to the inertial frame. + * omega_RW - float - norm of the reaction wheel rotational velocities. + * storedCharge - float [0,batCapacity] - indicates the s/c battery charge level in + W-s. + * sun_indicator - float [0, 1] - indicates the flux mitigator due to eclipse. + * access indicator - access to the next target + * img_mode norm - float [0,1] - indicates the required imaging mode. + + Reward Function: + r = 1/(1+ | sigma_RB|) if correct sensor + + Intended to provide a rich reward in action 1 when the spacecraft is pointed + towards the earth, decaying as sigma^2 as the pointing error increases. + """ + +
+[docs] + def __init__(self): + self.__version__ = "1.0.0" + print( + "Earth Observation Sim, State Guarded Actions - Version {}".format( + self.__version__ + ) + ) + + # Set up simulation parameters + self.settings = Settings() + self.step_duration = self.settings.STEP_DURATION + self.max_steps = self.settings.SIM_TIME + self.dyn_step = self.settings.DYN_STEP + self.fsw_step = self.settings.FSW_STEP + + # Set up environment parameters + self.curr_step = None + self.reward_total = None + self.initial_conditions = None + self.simulator = None + self.episode_over = None + self.curr_episode = -1 + self.ob = None + self.state_machine_state = None + self.prev_ins_spec = None + self.prev_sim_state = None + self.sim_state = None + self.info = {} + + # Set up setting variables locally + self.wheel_lim = self.settings.WHEEL_LIM + self.power_max = self.settings.POWER_MAX + self.obs_defn = self.settings.OBSERVATIONS + + # Reward function parameters + self.max_observations = self.settings.N_TGTS + self.reward_mult = ( + self.settings.REWARD_MULTIPLIER / self.max_observations + ) # Normalize reward to episode duration; '1' represents 100% target + # observation with 100% accuracy + self.failure_penalty = 1 # episode reward of 0 or less is a failed episode + self.img_modes = self.settings.img_modes + + self.failure = False + + # Set observation space + low = -1e16 + high = 1e16 + self.observation_space = spaces.Box( + low, high, shape=(len(self.obs_defn),), dtype=np.float64 + ) + + print("Observation space: ", self.observation_space.shape) + + # Action Space description + # 0 - sun pointing (power objective) + # 1 - desaturation (required for long-term pointing) + # >1 - imaging types + self.action_space = spaces.Discrete(2 + self.img_modes) + self.action_episode_memory = [] + + print("Action space: ", self.action_space.n) + + self.render = self.settings.RENDER + + self.return_obs = True
+ + +
+[docs] + def step(self, action): + """ + The agent takes a step in the environment. Note that the simulator must be + initialized + + Args: + action: int + + Returns: + + * ob (object): an environment-specific object representing your observation of + the environment. + * reward (float): amount of reward achieved by the previous action. The scale + varies between environments, but the goal is always to increase + your total reward. + * episode_over (bool): whether it's time to reset the environment again. Most (but not + all) tasks are divided up into well-defined episodes, and done + being True indicates the episode has terminated. (For example, + perhaps the pole tipped too far, or you lost your last life.) + * truncated (truncated): set to false. Gymnasium requirement. + * info (dict): diagnostic information useful for debugging. It can sometimes + be useful for learning (for example, it might contain the raw + probabilities behind the environment's last state change). + However, official evaluations of your agent are not allowed to + use this for learning. + + """ + + self.curr_step += 1 + self.prev_sim_state = deepcopy(self.sim_state) + self.prev_ins_spec = self.simulator.img_mode + self._take_action(action) + + # If the wheel speeds get too large, end the episode. + if self.sim_state.get("wheel_speed") > self.wheel_lim: + self.episode_over = True + self.failure = True + print("Died from wheel explosion.") + elif self.sim_state.get("stored_charge") == 0: + self.episode_over = True + self.failure = True + print("Ran out of power.") + elif self.simulator.sim_over: + self.episode_over = True + + reward = self._get_reward() + self.reward_total += reward + + self.info = { + "episode": {"r": self.reward_total, "l": self.curr_step}, + "obs": self.ob, + "fsm": self.prev_ins_spec, + } + + self.info["metrics"] = { + "sim_length": self.simulator.sim_time / 60, + "num_imaged": self._get_num_imaged(), + } + + return self.ob, reward, self.episode_over, False, self.info
+ + + def _take_action(self, action): + """ + Interfaces with the simulator to + :param action: + :return: + """ + + self.action_episode_memory[self.curr_episode].append(action) + + # Let the simulator handle action management: + self.sim_state = self.simulator.run_sim(action) + self.ob = self._get_ob() + + def _get_reward(self): + """ + Reward is based on time spent with the inertial attitude pointed towards the + ground within a given tolerance. + + """ + reward = 0 + last_action = self.action_episode_memory[self.curr_episode][-1] + if self.failure: + reward = -self.failure_penalty + elif (last_action > 1) and self.prev_sim_state.get("access_indicator"): + # Attitude contribution: + att_reward = self.reward_mult / ( + 1.0 + self.prev_sim_state.get("att_err") ** 2.0 + ) + if last_action == ( + self.prev_ins_spec + 1 + ): # If the obs taken matches the correction insturment action type + freq_mult = 1.0 + else: + freq_mult = 0.0 + reward = att_reward * freq_mult + + return reward + + def _get_ob(self): + """Get the observation. + WIP: Work out which error representation to give the algo.""" + ob = np.zeros(len(self.obs_defn)) + for i, ob_key in enumerate(self.obs_defn): + ob[i] = self.sim_state.get(ob_key) + if ob_key == "wheel_speed": + ob[ + i + ] /= ( + self.wheel_lim + ) # Normalize reaction wheel speed to fraction of limit + elif ob_key == "stored_charge": + ob[ + i + ] /= ( + self.power_max + ) # Normalize current power to fraction of total power + + return ob + +
+[docs] + def reset(self, seed=None, options=None): + """ + Reset the state of the environment and returns an initial observation. + Returns + ------- + observation (object): the initial observation of the space. + """ + super().reset(seed=seed) + self.curr_episode += 1 + self.action_episode_memory.append([]) + self.curr_step = -1 + self.reward_total = 0 + del ( + self.simulator + ) # Force delete the sim to make sure nothing funky happens under the hood + tFinal = self.max_steps * self.step_duration + + if options is None: + self.settings.generate_new_ic() + self.initial_conditions = self.settings.INITIAL_CONDITIONS + else: + if "initial_conditions" not in options: + self.settings.generate_new_ic() + self.initial_conditions = self.settings.INITIAL_CONDITIONS + else: + self.initial_conditions = options["initial_conditions"] + + self.simulator = MultiSensorEOSSimulator( + self.dyn_step, + self.fsw_step, + self.step_duration, + tFinal, + initial_conditions=self.initial_conditions, + render=self.render, + settings=self.settings, + ) + self.episode_over = self.simulator.sim_over + self.failure = False + self.sim_state = self.simulator.get_sim_state(init=True) + self.ob = self._get_ob() + + return self.ob, self.info
+ + + def _render(self, mode="human", close=False): + self.render = True + return + + def _get_num_imaged(self): + num_imaged = 0 + for idx in range(len(self.simulator.imaged_targets)): + if self.simulator.imaged_targets[idx] >= 1.0: + num_imaged += 1
+ + + +if __name__ == "__main__": + env = gym.make("MultiSensorEOS-v0") + + env.reset() + + reward_sum = 0 + for idx in range(0, env.max_steps): + action = env.action_space.sample() + ob, reward, episode_over, truncated, info = env.step(action) + reward_sum += reward + + if episode_over: + print("Episode over at step " + str(idx)) + break + + print("Reward total: " + str(reward_sum)) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/simple_eos/gym_env.html b/_modules/bsk_rl/envs/simple_eos/gym_env.html new file mode 100644 index 00000000..60d90cd6 --- /dev/null +++ b/_modules/bsk_rl/envs/simple_eos/gym_env.html @@ -0,0 +1,424 @@ + + + + + + bsk_rl.envs.simple_eos.gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.simple_eos.gym_env

+import gymnasium as gym
+import numpy as np
+from Basilisk.utilities import macros as mc
+from gymnasium import spaces
+
+from bsk_rl.envs.simple_eos import bsk_sim
+
+
+
+[docs] +class SimpleEOS(gym.Env): + """ + The spacecraft must decide between pointing at the ground to collect science data, + pointing at the sun to charge, desaturating reaction wheels, and downlinking data. + This is referred to as the "simple" simulator as science data is simply collected + by nadir pointing. Specific imaging targets are not considered. + + Action Space (discrete, 0 or 1): + * 0 - Imaging mode + * 1 - Charging mode + * 2 - Desat mode + * 3 - Downlink mode + + Observation Space: + * Inertial position and velocity - indices 0-5 + * Attitude error and attitude rate - indices 6-7 + * Reaction wheel speeds - indices 8-11 + * Battery charge - indices 12 + * Eclipse indicator - indices 13 + * Stored data onboard spacecraft - indices 14 + * Data transmitted over interval - indices 15 + * Amount of time ground stations were accessible (s) - 16-22 + * Percent through planning interval - 23 + + Reward Function: + r = +1 for each MB downlinked and no failure + r = +1 for each MB downlinked and no failure and +1 if t > t_max + r = - 1000 if failure (battery drained, buffer overflow, reaction wheel speeds over max) + """ + +
+[docs] + def __init__(self): + self.__version__ = "0.0.1" + print("SimpleEOS Environment - Version {}".format(self.__version__)) + + # General variables defining the environment + self.max_length = int(270) # Specify the maximum number of minutes + self.max_steps = 45 + self.render = False + + # Tell the environment that it doesn't have a sim attribute... + self.simulator_init = 0 + self.simulator = None + self.reward_total = 0 + + # Set initial conditions to none (gets assigned in reset) + self.initial_conditions = None + + # Set the dynRate for the env, which is passed into the simulator + self.dynRate = 1.0 + self.fswRate = 1.0 + + # Set up options, constants for this environment + self.step_duration = 6 * 60.0 # seconds, tune as desired + self.reward_mult = 1.0 + self.failure_penalty = 1000 + low = -1e16 + high = 1e16 + self.observation_space = spaces.Box(low, high, shape=(23,), dtype=np.float64) + self.obs = np.zeros(23) + self.obs_full = np.zeros(23) + + self.action_space = spaces.Discrete(4) + + # Store what the agent tried + self.curr_episode = -1 + self.action_episode_memory = [] + self.curr_step = 0 + self.episode_over = False + self.failure = False + + self.return_obs = True
+ + + def _seed(self): + np.random.seed() + return + +
+[docs] + def step(self, action): + """ + The agent takes a step in the environment. + Parameters + ---------- + action : int + Returns + ------- + ob, reward, episode_over, info : tuple + ob (object) : + an environment-specific object representing your observation of + the environment. + reward (float) : + amount of reward achieved by the previous action. The scale + varies between environments, but the goal is always to increase + your total reward. + episode_over (bool) : + whether it's time to reset the environment again. Most (but not + all) tasks are divided up into well-defined episodes, and done + being True indicates the episode has terminated. (For example, + perhaps the pole tipped too far, or you lost your last life.) + info (dict) : + diagnostic information useful for debugging. It can sometimes + be useful for learning (for example, it might contain the raw + probabilities behind the environment's last state change). + However, official evaluations of your agent are not allowed to + use this for learning. + """ + + # If the simTime in minutes is greater than the planning interval in minutes, + # end the sim + if (self.simulator.simTime / 60) >= self.max_length: + print("End of simulation reached", self.simulator.simTime / 60) + self.episode_over = True + + prev_ob = self.obs_full + self._take_action(action) + + # If we want to return observations, do the following + if self.return_obs: + reward = 0 + ob = self._get_state() + + # If the wheel speeds get too large, end the episode. + if any(speeds > 6000 * mc.RPM for speeds in self.obs_full[8:10]): + self.episode_over = True + self.failure = True + reward -= self.failure_penalty + self.reward_total -= self.failure_penalty + print( + "Died from wheel explosion. RPMs were: " + + self.obs_full[8:10] + + ", limit is " + + str(6000 * mc.RPM) + + ", body rate was " + + str(self.obs_full[7]) + + ", action taken was " + + str(action) + + ", env step " + + str(self.curr_step) + ) + print( + "Prior state was RPM:" + + prev_ob[8:10] + + " . body rate was:" + + str(prev_ob[7]) + ) + + # If we run out of power, end the episode. + elif self.obs_full[11] == 0: + self.failure = True + self.episode_over = True + reward -= self.failure_penalty + self.reward_total -= self.failure_penalty + print( + "Ran out of power. Battery level at: " + + str(self.obs_full[11]) + + ", env step " + + str(self.curr_step) + + ", action taken was " + + str(action) + ) + + # If we overflow the buffer, end the episode. + elif self.obs_full[13] >= self.simulator.storageUnit.storageCapacity: + self.failure = True + self.episode_over = True + reward -= self.failure_penalty + self.reward_total -= self.failure_penalty + print( + "Data buffer overflow. Data storage level at: " + + str(self.obs_full[13]) + + ", env step " + + str(self.curr_step) + + ", action taken was " + + str(action) + ) + + elif self.sim_over: + self.episode_over = True + print("Orbit decayed - no penalty, but this one is over.") + + else: + self.failure = False + + if self.episode_over: + info = { + "episode": {"r": self.reward_total, "l": self.curr_step}, + "obs": ob, + } + else: + info = {"obs": ob} + reward = self._get_reward() + self.reward_total += reward + + # Otherwise, return nothing + else: + ob = [] + reward = 0 + info = {} + + info["metrics"] = { + "downlinked": self.simulator.downlinked, + "sim_length": self.simulator.simTime / 60, + "total_access": self.simulator.total_access, + "utilized_access": self.simulator.utilized_access, + } + + self.curr_step += 1 + return ob.flatten(), reward, self.episode_over, False, info
+ + + def _take_action(self, action): + """ + Interfaces with the simulator to + :param action: + :return: + """ + + self.action_episode_memory[self.curr_episode].append(action) + self.obs, self.sim_over, self.obs_full = self.simulator.run_sim( + action, self.return_obs + ) + + def _get_reward(self): + """ + Reward is based on time spent with the inertial attitude pointed towards the + ground within a given tolerance. + + """ + if self.failure: + reward = -self.failure_penalty + elif self.episode_over: + reward = (-self.obs_full[14][0]) * (self.reward_mult**self.curr_step) + 1 + else: + reward = -self.obs_full[14][0] * (self.reward_mult**self.curr_step) + + return reward + +
+[docs] + def reset(self, seed=None, options=None): + """ + Reset the state of the environment and returns an initial observation. + Returns + ------- + observation (object): the initial observation of the space. + """ + super().reset(seed=seed) + + if self.simulator is not None: + del self.simulator + + if options is not None: + if "initial_conditions" in options: + self.initial_conditions = options["initial_conditions"] + + self.action_episode_memory.append([]) + self.episode_over = False + self.failure = False + self.curr_step = 0 + self.reward_total = 0 + + # Create the simulator + self.simulator = bsk_sim.SimpleEOSSimulator( + self.dynRate, + self.fswRate, + self.step_duration, + initial_conditions=self.initial_conditions, + render=self.render, + ) + + # Extract initial conditions from instantiation of simulator + self.initial_conditions = self.simulator.initial_conditions + self.simulator.max_steps = self.max_steps + self.simulator.max_length = self.max_length + self.simulator_init = 1 + + return self.simulator.obs.flatten(), {}
+ + + def _render(self, mode="human", close=False): + return + + def _get_state(self): + """Return the non-normalized observation from the simulator""" + + return self.simulator.obs
+ + + +if __name__ == "__main__": + env = gym.make("SimpleEOS-v0") + + env.reset() + + reward_sum = 0 + for idx in range(0, env.max_steps): + action = env.action_space.sample() + ob, reward, episode_over, truncated, info = env.step(action) + reward_sum += reward + + if episode_over: + print("Episode over at step " + str(idx)) + break + + print("Reward total: " + str(reward_sum)) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/small_body_science/gym_env.html b/_modules/bsk_rl/envs/small_body_science/gym_env.html new file mode 100644 index 00000000..e4c7322e --- /dev/null +++ b/_modules/bsk_rl/envs/small_body_science/gym_env.html @@ -0,0 +1,465 @@ + + + + + + bsk_rl.envs.small_body_science.gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.small_body_science.gym_env

+import gymnasium as gym
+import numpy as np
+from gymnasium import spaces
+
+from bsk_rl.envs.small_body_science.bsk_sim import SmallBodyScienceSimulator
+
+
+
+[docs] +class SmallBodyScience(gym.Env): + """ + Small body gym environment where an agent can transition between different + waypoints defined in the sun anti-momentum frame to image candidate landing sites + or collect spectroscopy map data while avoiding resource constraint violations. + Resource constraint violations include: + * Fuel + * Power + * Data storage + * Collision with the body (not necessarilly a resource, but considered a + failure condition) + + Action Space (Discrete): + * 0 - Charging Mode + * 1 - 8 - Transition to waypoint 1-8 + * 9 - Map + * 10 - Downlink + * 11 - Image + + Observation Space (Box): + * 0-2: Hill-frame position + * 3-5: Hill-frame velocity + * 6: Eclipse + * 7: Data buffer storage + * 8: Battery level + * 9: dV consumed + * 10: Downlink availability + * 11-13: Current waypoint + * 14-16: Last waypoint + * 17: Imaged targets + * 18: Downlinked targets + * 19-21: Next closest unimaged target position in Hill frame + * 22-30: Map regions collected + + Reward Function: + * r = +A each tgt downlinked for first time + * r = +B for each tgt imaged for first time + * r = +C for each map region downlinked for first time + * r = +D for each map region collected for first time + * r = -E for failure + """ + +
+[docs] + def __init__( + self, + failure_penalty=1, + target_component=0.25, + target_downlink_component=0.25, + map_component=0.25, + map_downlink_component=0.25, + ): + self.__version__ = "0.0.1" + print("Basilisk Small Body Science Sim - Version {}".format(self.__version__)) + + # Set the fidelity of the environment + self.fidelity = "high" + + # General variables defining the environment + self.max_length = 10000.0 # Specify the maximum number of minutes + self.max_steps = 200 + self.render = False + + # Tell the environment that it doesn't have a sim attribute... + self.simulator_init = 0 + self.simulator = None + self.reward_total = 0 + + # Set initial conditions to none (gets assigned in reset) + self.initial_conditions = None + + # Set the dynRate for the env, which is passed into the simulator + if self.fidelity == "high": + self.dynRate = 2.0 + self.fswRate = 2.0 + self.mapRate = 180.0 + elif self.fidelity == "low": + self.dynRate = 1.0 + self.fswRate = 1.0 + self.mapRate = 180.0 + else: + print( + "Invalid fidelity, choose either low or high. Selected = ", + self.fidelity, + ) + + # Set up options, constants for this environment + self.step_duration = 10000.0 # seconds, tune as desired + self.reward_mult = 1.0 + + self.failure_penalty = failure_penalty + self.target_component = target_component + self.target_downlink_component = target_downlink_component + self.map_component = map_component + self.map_downlink_component = map_downlink_component + + # Define number of image targets + self.n_targets = 10 + + # Define number of map targets + self.n_maps = 3 + self.n_map_points = 500 # Number of grid points per map + + self.phi_c = None + self.lambda_c = None + + # Define observation space + self.n_states = 31 + self.obs = np.zeros(self.n_states) + self.obs_full = np.zeros(self.n_states) + self.observation_space = spaces.Box(-1e16, 1e16, shape=(self.n_states,)) + + # Define the action space + self.action_space = spaces.Discrete(12) + + # Store what the agent tried + self.curr_episode = -1 + self.action_episode_memory = [] + self.curr_step = 0 + self.episode_over = False + self.failure = False + + self.return_obs = True
+ + +
+[docs] + def step(self, action): + """ + The agent takes a step in the environment. + Parameters + ---------- + action : int + Returns + ------- + ob, reward, episode_over, truncated, info : tuple + ob (object) : + an environment-specific object representing your observation of + the environment. + reward (float) : + amount of reward achieved by the previous action. The scale + varies between environments, but the goal is always to increase + your total reward. + episode_over (bool) : + whether it's time to reset the environment again. Most (but not + all) tasks are divided up into well-defined episodes, and done + being True indicates the episode has terminated. (For example, + perhaps the pole tipped too far, or you lost your last life.) + """ + + # If the simTime in minutes is greater than the planning interval in minutes, + # end the sim + if (self.simulator.simTime / 60.0) >= self.max_length: + print("End of simulation reached", self.simulator.simTime / 60) + self.episode_over = True + + downlinked_images, downlinked_maps, imaged, mapped = self._take_action(action) + + # If we want to return observations, do the following + if self.return_obs: + ob = self._get_state() + + if any(self.simulator.powerLevel == 0): + self.failure = True + self.episode_over = True + print( + "Ran out of power. Battery level at: " + + str(self.simulator.powerLevel[-1]) + + ", env step " + + str(self.curr_step) + + ", action taken was " + + str(action) + ) + # If we overflow the buffer, end the episode. + elif ( + self.simulator.storageLevel + >= self.simulator.dataStorageUnit.storageCapacity + ): + self.failure = True + self.episode_over = True + print( + "Data buffer overflow. Data storage level at:" + + str(self.simulator.storageLevel) + + ", env step, " + + str(self.curr_step) + + ", action taken was " + + str(action) + ) + elif self.simulator.dV >= self.simulator.initial_conditions["max_dV"]: + self.failure = True + self.episode_over = True + print( + "Ran out of fuel. Total dV consumed: " + + str(self.simulator.dV) + + ", env step " + + str(self.curr_step) + ) + elif self.simulator.collision: + self.failure = True + self.episode_over = True + print("Collided with the body, env step " + str(self.curr_step)) + else: + self.failure = False + + reward = self._get_reward( + downlinked_images, downlinked_maps, imaged, mapped + ) + self.reward_total += reward + + # Otherwise, return nothing + else: + ob = [] + reward = 0 + + info = {} + info["metrics"] = { + "imaged_targets": self.simulator.imaged_targets, + "downlinked_targets": self.simulator.downlinked_targets, + "imaged_maps": self.simulator.imaged_maps, + "downlinked_maps": self.simulator.downlinked_maps, + "sim_length": self.simulator.simTime / 60, + } + + self.curr_step += 1 + return ob, reward, self.episode_over, False, info
+ + + def _take_action(self, action): + """ + Interfaces with the simulator to + :param action: + :return: + """ + + self.action_episode_memory[self.curr_episode].append(action) + ( + self.obs, + self.sim_over, + self.obs_full, + downlinked_images, + downlinked_maps, + imaged, + mapped, + ) = self.simulator.run_sim(action) + + return downlinked_images, downlinked_maps, imaged, mapped + + def _get_reward(self, downlinked_images, downlinked_maps, imaged, mapped): + """ + Reward is based on the total amount of imaged data downlinked in MB. + + """ + reward = 0 + if self.failure: + reward = -self.failure_penalty + else: + # Map image reward + reward += ( + self.map_component + / (self.simulator.n_maps * self.simulator.n_map_points) + ) * len(mapped) + # Map downlink reward + reward += ( + self.map_downlink_component + / (self.simulator.n_maps * self.simulator.n_map_points) + ) * len(downlinked_maps) + # Target imaging reward + reward += (self.target_component / self.simulator.n_targets) * len(imaged) + # Target downlink reward + reward += (self.target_downlink_component / self.simulator.n_targets) * len( + downlinked_images + ) + + return reward + +
+[docs] + def reset(self, seed=None, options=None): + """ + Reset the state of the environment and returns an initial observation. + Returns + ------- + observation (object): the initial observation of the space. + """ + self.action_episode_memory.append([]) + self.episode_over = False + self.failure = False + self.curr_step = 0 + self.reward_total = 0 + + # If initial conditions are passed in, use those + if options is not None: + if "initial_conditions" in options: + self.initial_conditions = options["initial_conditions"] + + if self.simulator is not None: + del self.simulator + + # Create the simulator + self.simulator = SmallBodyScienceSimulator( + self.dynRate, + self.fswRate, + self.mapRate, + self.step_duration, + self.initial_conditions, + render=self.render, + n_targets=self.n_targets, + n_map_points=self.n_map_points, + max_length=self.max_length, + n_states=self.n_states, + n_maps=self.n_maps, + phi_c=self.phi_c, + lambda_c=self.lambda_c, + fidelity=self.fidelity, + ) + + self.simulator.init_tasks_and_processes() + + # Extract initial conditions from instantiation of simulator + self.initial_conditions = self.simulator.initial_conditions + self.simulator.max_steps = self.max_steps + self.simulator_init = 1 + + return self.simulator.obs, {}
+ + + def _get_state(self): + """Get the observation. + WIP: Work out which error representation to give the algo.""" + + return self.simulator.obs
+ + + +if __name__ == "__main__": + env = gym.make("SmallBodyScience-v0") + + env.reset() + + reward_sum = 0 + for idx in range(0, env.max_steps): + action = env.action_space.sample() + ob, reward, episode_over, truncated, info = env.step(action) + reward_sum += reward + + if episode_over: + print("Episode over at step " + str(idx)) + break + + print("Reward total: " + str(reward_sum)) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/envs/small_body_science_pomdp/gym_env.html b/_modules/bsk_rl/envs/small_body_science_pomdp/gym_env.html new file mode 100644 index 00000000..9281c19d --- /dev/null +++ b/_modules/bsk_rl/envs/small_body_science_pomdp/gym_env.html @@ -0,0 +1,271 @@ + + + + + + bsk_rl.envs.small_body_science_pomdp.gym_env — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.envs.small_body_science_pomdp.gym_env

+import gymnasium as gym
+import numpy as np
+from gymnasium import spaces
+
+from bsk_rl.envs.small_body_science.gym_env import SmallBodyScience
+from bsk_rl.envs.small_body_science_pomdp.bsk_sim import SmallBodySciencePOMDPSimulator
+
+
+
+[docs] +class SmallBodySciencePOMDP(SmallBodyScience): + """ + Small body gym environment where an agent can transition between different + waypoints defined in the sun anti-momentum frame to image candidate landing sites + or collect spectroscopy map data while avoiding resource constraint violations. As + opposed to the SmallBodyScience environment, this environment is utilizes an EKF + filter for the observation space to simulate a POMDP, which provides a belief state + for the POMDP. + + Resource constraint violations include: + * Fuel + * Power + * Data storage + * Collision with the body (not necessarily a resource, but considered a + failure condition) + + Action Space (Discrete): + * 0 - Charging Mode + * 1 - 8 - Transition to waypoint 1-8 + * 9 - Map + * 10 - Downlink + * 11 - Image + * 12 - Navigation Mode + + Observation Space (Box): + * 0-2: Hill-frame position + * 3-5: Hill-frame velocity + * 6: Eclipse + * 7: Data buffer storage + * 8: Battery level + * 9: dV consumed + * 10: Downlink availability + * 11-13: Current waypoint + * 14-16: Last waypoint + * 17-20: Location of the next target for imaging + * 20-26: Filter covariance diagonals + + Reward Function: + * r = +A each tgt downlinked for first time + * r = +B for each tgt imaged for first time + * r = +C for each map region downlinked for first time + * r = +D for each map region collected for first time + * r = -E for failure + """ + +
+[docs] + def __init__(self): + super().__init__() + + # Set the version + self.__version__ = "0.0.0" + print( + "Small Body Science POMDP Environment - Version {}".format(self.__version__) + ) + + # Modify the observation space + self.n_states = 26 + self.obs = np.zeros(self.n_states) + self.obs_full = np.zeros(self.n_states) + self.observation_space = spaces.Box(-1e16, 1e16, shape=(self.n_states,)) + + # Modify the action space to include the navigation mode + self.action_space = spaces.Discrete(self.action_space.n + 1)
+ + +
+[docs] + def step(self, action, return_obs=True): + ob, reward, self.episode_over, info = super().step(action, return_obs=True) + + return self.modify_ob(ob), reward, self.episode_over, info
+ + +
+[docs] + def modify_ob(self, ob): + """ + Modifies the observation of the MDP such that it conforms to the POMDP + specification. + :param ob: + :return: + """ + return ob
+ + +
+[docs] + def reset(self, seed=None, options=None): + """ + Reset the state of the environment and returns an initial observation. + Returns + ------- + observation (object): the initial observation of the space. + """ + self.action_episode_memory.append([]) + self.episode_over = False + self.failure = False + self.curr_step = 0 + self.reward_total = 0 + + # If initial conditions are passed in, use those + if options is not None: + if "initial_conditions" in options: + self.initial_conditions = options["initial_conditions"] + + if self.simulator is not None: + del self.simulator + + # Create the simulator + self.simulator = SmallBodySciencePOMDPSimulator( + self.dynRate, + self.fswRate, + self.mapRate, + self.step_duration, + self.initial_conditions, + render=self.render, + n_targets=self.n_targets, + n_map_points=self.n_map_points, + max_length=self.max_length, + n_states=self.n_states, + n_maps=self.n_maps, + phi_c=self.phi_c, + lambda_c=self.lambda_c, + fidelity=self.fidelity, + ) + + self.simulator.init_tasks_and_processes() + + # Extract initial conditions from instantiation of simulator + self.initial_conditions = self.simulator.initial_conditions + self.simulator.max_steps = self.max_steps + self.simulator_init = 1 + + return self.simulator.obs, {}
+
+ + + +if __name__ == "__main__": + env = gym.make("SmallBodySciencePOMDP-v0") + + env.reset() + + reward_sum = 0 + for idx in range(0, env.max_steps): + action = env.action_space.sample() + ob, reward, episode_over, truncated, info = env.step(action) + reward_sum += reward + + if episode_over: + print("Episode over at step " + str(idx)) + break + + print("Reward total: " + str(reward_sum)) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/training/mcts/mcts_train.html b/_modules/bsk_rl/training/mcts/mcts_train.html new file mode 100644 index 00000000..bdc280ed --- /dev/null +++ b/_modules/bsk_rl/training/mcts/mcts_train.html @@ -0,0 +1,764 @@ + + + + + + bsk_rl.training.mcts.mcts_train — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.training.mcts.mcts_train

+import os
+import time
+from pathlib import Path
+
+import gymnasium as gym
+import matplotlib.pyplot as plt
+import numpy as np
+from sklearn.metrics import mean_absolute_error, mean_squared_error
+from sklearn.model_selection import train_test_split
+from tensorflow.keras.layers import Dense, Dropout, LeakyReLU
+from tensorflow.keras.models import Sequential
+
+from bsk_rl.agents.mcts import MCTS
+from bsk_rl.agents.state_machine import StateMachine
+from bsk_rl.utilities.mcts.rollout_policies import (
+    AgileEOSRolloutPolicy,
+    MultiSensorEOSRolloutPolicy,
+    SimpleEOSRolloutPolicy,
+    SmallBodyRolloutPolicy,
+)
+
+
+
+[docs] +def mcts_batch( + data_directory, + data_indicator, + c=50, + num_sims=50, + initial_conditions=None, + result_list=None, + render=False, + env_name="SimpleEOS-v0", + num_steps=45, + t_final=270.0, +): + """ + The function performs a single run of MCTS over a planning horizon, generating \ + performance and training data + :param data_directory: Data directory to store training data + :param data_indicator: Data indicator to append to filename + :param c: MCTS exploration constant + :param num_sims: number of simulations-per-step + :param initial_conditions: Dictionary of initial conditions + :param result_list: Results list + :param render: T/F to render BSK sim using Vizard + :param env_name: environment name + :return: N/A + """ + np.random.seed(int(data_indicator.split("_")[-1])) + # Create env + env = gym.make(env_name) + env.max_length = t_final + env.max_steps = num_steps + + env.render = render + + # Run an MCTS episode, returning Q, N, reward sum, and action history + Q, N, reward, act_hist, exec_time, final_info, metrics = run_episode( + env, num_steps, t_final, c, num_sims, initial_conditions, env_name + ) + + # Grab the performance metrics from the environment (downlink utilization, etc) + performance_metrics = metrics + performance_metrics["reward_sum"] = reward + performance_metrics["action_history"] = act_hist + performance_metrics["exec_time"] = exec_time + + # Grab the states and value functions after the training cycle + states = np.array(list(Q.keys())) + state_action_output = [] + for state_actions in Q.values(): + state_action_output.append(list(state_actions.values())) + state_action_output = np.array(state_action_output) + + num_visited_output = [] + for num_visited in N.values(): + num_visited_output.append(list(num_visited.values())) + num_visited_output = np.array(num_visited_output) + + # Add to the data dictionary + data = { + "states": states, + "action_value": state_action_output, + "num_visited": num_visited_output, + "ic": env.simulator.initial_conditions, + "info": final_info, + } + + # Save the training data + os.makedirs(data_directory + "/Training Data/", exist_ok=True) + os.makedirs(data_directory + "/Validation Plots/", exist_ok=True) + np.save( + data_directory + + "/Training Data/" + + "action_value_all_info_" + + data_indicator.replace(".", "__") + + ".npy", + data, + ) + + if result_list is not None: + # return performance_metrics as a dictionary + result_list.append( + {(c, num_sims, int(data_indicator.split("_")[-1])): performance_metrics} + ) + return + else: + return {(c, num_sims, int(data_indicator.split("_")[-1])): performance_metrics}
+ + + +
+[docs] +def run_episode(env, num_steps, t_final, c, num_sims, initial_conditions, env_name): + """ + Runs an episode of MCTS. + :param env: Gym environment + :param num_steps: number of steps to take + :param t_final: Final time + :param c: Exploration constant + :param num_sims: Number of simulations-per-step + :param initial_conditions: Dictionary of initial conditions + :param env_name: environment name + :return Q: state-action value estimates + :return N: Number of times the state-action pairs were visited + :return reward: Reward sum + :return actHist: history of actions + :return exec_time: execution time + :return final_info: final infor from env + """ + + # Call reset on the environment + ob, info = env.reset() + + # Create rollout policies automatically + state_machine = StateMachine() + abs_path = os.path.dirname(os.path.abspath(__file__)) + if "AgileEOS" in env_name: + state_machine.loadTransferConditions( + os.path.join(abs_path, "../../utilities/state_machine/agile_eos_ops.adv") + ) + rollout_policy = AgileEOSRolloutPolicy(env=env, state_machine=state_machine) + elif "SimpleEOS" in env_name: + # Get the path relative to directory + state_machine.loadTransferConditions( + os.path.join(abs_path, "../../utilities/state_machine/simple_eos_ops.adv") + ) + rollout_policy = SimpleEOSRolloutPolicy(state_machine=state_machine) + elif "SmallBodyScience" in env_name: + rollout_policy = SmallBodyRolloutPolicy(env=env, state_machine=state_machine) + elif "MultiSensorEOS" in env_name: + state_machine.loadTransferConditions( + os.path.join( + abs_path, "../../utilities/state_machine/multisensor_eos_ops.adv" + ) + ) + rollout_policy = MultiSensorEOSRolloutPolicy( + env=env, state_machine=state_machine + ) + else: + print( + "Environment name " + + env_name + + " not found while instantiating state machine" + ) + + # Create an MCTS agent + MCTS_Agent = MCTS(c=c, num_sims=num_sims, rollout_policy=rollout_policy) + + # Set the initial conditions if they don't exist + if initial_conditions is not None: + env.initial_conditions = initial_conditions + + # Reset with the initial conditions + ob, info = env.reset(options={"initial_conditions": env.initial_conditions}) + ob_hist = [ob] + + # Set the type of environment in the MCTS agent + MCTS_Agent.setEnv( + env_name, env.initial_conditions, max_steps=num_steps, max_length=t_final + ) + + actHist = [] + + # Total reward + reward_sum = 0.0 + + # Start the execution timer + start_time = time.time() + + # Loop through each time step + for ind in range(0, num_steps): + # Set the depth to be the end of the environment + d = num_steps - ind + + # Select new action + act = MCTS_Agent.selectAction(ob, d, actHist) + + # Reset with the initial conditions + env.reset(options={"initial_conditions": env.initial_conditions}) + + # Step through env to take it to current place + env.return_obs = False + for stepAct in actHist: + _, _, _, _, _ = env.step(stepAct) + env.return_obs = True + + # Append last action to action list + actHist.append(act) + + print("Actual Action Taken: ", act) + print("Real Environment Step: ", ind) + + # Take the step in the environment + ob, reward, episode_over, _, info = env.step(act) + ob_hist.append(ob) + print("Reward: ", reward) + + # Sum the reward, add to rewards array + reward_sum = reward_sum + reward + + # Append to the trajectory + MCTS_Agent.trajectory.append( + [tuple(ob_hist[-2].reshape(1, -1)[0]), act, reward, reward_sum, info] + ) + + # If the episode is over, end the simulation + if episode_over: + print("episode over") + break + + # End the execution timer + end_time = time.time() + exec_time = end_time - start_time + + # Backup the trajectory along the main tree + MCTS_Agent.backup_tree() + + # Append Q + Q = MCTS_Agent.Q_main + N = MCTS_Agent.N_main + final_info = MCTS_Agent.info + reward = reward_sum + + return Q, N, reward, actHist, exec_time, final_info, info["metrics"]
+ + + +
+[docs] +def data_number(x): + """ + Splits the data indicator string to return the data number + :param x: data indicator string + :return: data number + """ + return int(((x.rsplit("_")[-1]).rsplit("."))[0])
+ + + +
+[docs] +def create_model( + hidden_layer_num, net_size, activation, num_states, dropout, alpha, num_actions +): + """ + Creates a feedforward neural network subject to various hyperparameters. + :param hidden_layer_num: Number of hidden layers + :param net_size: Widths of hidden layers + :param activation: activation function, either Leaky ReLU or tanh + :param num_states: Number of states + :param dropout: Dropout rate + :param alpha: alpha-parameter for Leaky ReLU activation function + :param num_actions: number of actions + :return: model + """ + # Create model + model = Sequential() + + # Add layers + for layer in range(0, hidden_layer_num): + if layer == 0: + if activation == "tanh": + model.add( + Dense(net_size, input_shape=(num_states,), activation=activation) + ) + elif activation == "LeakyReLU": + model.add(Dense(net_size, input_shape=(num_states,))) + model.add(LeakyReLU(alpha=alpha)) + else: + if activation == "tanh": + model.add(Dense(net_size, activation=activation)) + elif activation == "LeakyReLU": + model.add(Dense(net_size)) + model.add(LeakyReLU(alpha=alpha)) + + # Add dropout layers + if dropout is not None: + model.add(Dropout(dropout)) + + # Add the output layer and compile + model.add(Dense(num_actions, activation="linear")) + model.compile( + loss="mse", + optimizer="Adam", + metrics=["mean_squared_error", "mean_absolute_error"], + ) + model.summary() + + return model
+ + + +
+[docs] +def load_and_modify_data(data_directory, modified_states=[]): + """ + Loads AND modifies the training data + :param data_directory: data directory to load data from + :param modified_states: modified states. First entry is a list of indices to keep.\ + Next entries are dictionary keys + for info. + :return: train-test split of data + """ + data = [] + + # Load the data + for count, filename in enumerate( + sorted( + Path(data_directory + "/Training Data/").iterdir(), key=os.path.getmtime + ), + start=0, + ): + print(count, filename) + # if filename.startswith('AlphaZero'): + data.append(np.load(filename, allow_pickle=True)) + + for idx in range(0, len(data)): + data[idx] = data[idx].item() + + states = None + + # Load the data + for idx2 in range(0, len(data)): + if all(act_val < 0 for act_val in data[idx2]["action_value"][1, :]): + print(data[idx2]["action_value"][1, :]) + continue + elif states is None: + if len(modified_states) > 0: + for idx3, elem in enumerate(modified_states): + if idx3 == 0: + states = data[idx2]["states"][:, elem] + else: + states_to_add = [ + list(data[idx2]["info"].values())[0][elem].reshape( + list(data[idx2]["info"].values())[0][elem].size + ) + ] + for idx4 in range(1, len(list(data[idx2]["info"].values()))): + states_to_add = np.concatenate( + ( + states_to_add, + [ + list(data[idx2]["info"].values())[idx4][ + elem + ].reshape( + list(data[idx2]["info"].values())[idx4][ + elem + ].size + ) + ], + ) + ) + states = np.concatenate((states, states_to_add), axis=1) + print(states.shape) + else: + states = data[idx2]["states"] + action_value = data[idx2]["action_value"] + else: + if len(modified_states) > 0: + for idx3, elem in enumerate(modified_states): + if idx3 == 0: + states_2 = data[idx2]["states"][:, elem] + else: + states_to_add = [ + list(data[idx2]["info"].values())[0][elem].reshape( + list(data[idx2]["info"].values())[0][elem].size + ) + ] + for idx4 in range(1, len(list(data[idx2]["info"].values()))): + states_to_add = np.concatenate( + ( + states_to_add, + [ + list(data[idx2]["info"].values())[idx4][ + elem + ].reshape( + list(data[idx2]["info"].values())[idx4][ + elem + ].size + ) + ], + ) + ) + print(elem) + print(states_to_add) + states_2 = np.concatenate((states_2, states_to_add), axis=1) + print("States to add: ", states_2.shape) + states = np.concatenate((states, states_2)) + print("Full states: ", states.shape) + else: + states = np.concatenate((states, data[idx2]["states"])) + + action_value = np.concatenate((action_value, data[idx2]["action_value"])) + + return train_test_split(states, action_value, test_size=0.1, random_state=42)
+ + + +
+[docs] +def load_data(data_directory): + """ + Loads the data to train with. + :param data_directory: Data directory to load data from. + :return: train-test split of training data. + """ + data = [] + + # Load the data + for count, filename in enumerate( + sorted( + Path(data_directory + "/Training Data/").iterdir(), key=os.path.getmtime + ), + start=0, + ): + print(count, filename) + # if filename.startswith('AlphaZero'): + data.append(np.load(filename, allow_pickle=True)) + + for idx in range(0, len(data)): + data[idx] = data[idx].item() + print(data[idx]) + + states = None + + # Load the data + for idx2 in range(0, len(data)): + # print(data[idx2]['action_value'][1,:]) + if all(act_val < 0.1 for act_val in data[idx2]["action_value"][1, :]): + # print(data[idx2]['action_value'][1,:]) + continue + elif states is None: + states = data[idx2]["states"] + action_value = data[idx2]["action_value"] + else: + states = np.concatenate((states, data[idx2]["states"])) + action_value = np.concatenate((action_value, data[idx2]["action_value"])) + + # split the training and test data, shuffle around the data to decorrelate + return train_test_split(states, action_value, test_size=0.1, random_state=42)
+ + + +
+[docs] +def run_experiment(data_directory, parameters, modified_states=[], batch_sizes=None): + """ + Runs a hyperparameter search over neural network hyperparameters + :param data_directory: Data directory to load data from and save networks, \ + training plots. + :param parameters: dictionary of network hyperparameters. + :param modified_states (optional): Modified states + :return: + """ + net_sizes = parameters["net_sizes"] + layers = parameters["layers"] + activations = parameters["activations"] + dropouts = parameters["dropouts"] + alphas = parameters["alphas"] + epoch_num = parameters["epoch_num"] + + ( + states_train, + states_test, + action_value_train, + action_value_test, + ) = load_and_modify_data(data_directory, modified_states) + + master_data = [] + num_states = len(states_train[0, :]) + + if batch_sizes is None: + batch_sizes = [len(states_train)] + + net_idx = 0 + + # Search loop + for hidden_layer_num in layers: + for net_size in net_sizes: + for activation in activations: + for dropout in dropouts: + for batch_size in batch_sizes: + for epoch in epoch_num: + for alpha_idx, alpha in enumerate(alphas): + # Break out of the loop if on second alpha for tanh + if alpha_idx > 0 and activation == "tanh": + break + print( + "Hyperparam combination: ", + [ + hidden_layer_num, + net_size, + activation, + dropout, + alpha, + ], + ) + + model = create_model( + hidden_layer_num, + net_size, + activation, + num_states, + dropout, + alpha, + len(action_value_test[0, :]), + ) + + history = model.fit( + states_train, + action_value_train, + epochs=epoch, + batch_size=batch_size, + verbose=2, + validation_data=(states_test, action_value_test), + ) + os.makedirs( + data_directory + "/Network History", exist_ok=True + ) + np.save( + data_directory + + "/Network History/" + + "network_hist_" + + str(net_idx) + + ".npy", + history.history, + ) + + os.makedirs( + data_directory + "/Networks/", exist_ok=True + ) + model.save( + data_directory + + "/Networks/" + + "network_" + + str(net_idx) + ) + + prediction = model.predict(states_test) + + final_mse_mean = np.average( + [ + mean_squared_error( + action_value_test[:, i], prediction[:, i] + ) + for i in range(0, len(action_value_test[0, :])) + ] + ) + final_mae_mean = np.average( + [ + mean_absolute_error( + action_value_test[:, i], prediction[:, i] + ) + for i in range(0, len(action_value_test[0, :])) + ] + ) + + master_data.append( + { + "file_name": "network_" + str(net_idx), + "hidden_layer_num": hidden_layer_num, + "net_size": net_size, + "activation": activation, + "dropout": dropout, + "alpha": alpha, + "batch_size": batch_size, + "epochs": epoch, + "final_mse_mean": final_mse_mean, + "final_mae_mean": final_mae_mean, + } + ) + + os.makedirs( + data_directory + "/Training Plots/", exist_ok=True + ) + + plt.rc("xtick", labelsize=14) + plt.rc("ytick", labelsize=14) + + plt.figure(figsize=(8, 6)) + plt.plot( + history.history["mean_squared_error"], + label="Training Set", + ) + plt.plot( + history.history["val_mean_squared_error"], + label="Validation Set", + ) + plt.legend(loc="upper right", fontsize=16) + plt.grid(which="both", linestyle="dotted") + plt.minorticks_on + plt.xlabel("Epochs", fontsize=16) + plt.ylabel("Mean Squared Error", fontsize=16) + plt.yticks(fontsize=14) + plt.xticks(fontsize=14) + plt.yscale("log") + plt.savefig( + data_directory + + "/Training Plots" + + "/network_" + + str(net_idx) + + "_mse.pdf", + dpi=300, + format="pdf", + ) + + plt.figure(figsize=(8, 6)) + plt.plot( + history.history["mean_absolute_error"], + label="Training Set", + ) + plt.plot( + history.history["val_mean_absolute_error"], + label="Validation Set", + ) + plt.xlabel("Epochs", fontsize=16) + plt.ylabel("Mean Absolute Error", fontsize=16) + plt.yticks(fontsize=14) + plt.xticks(fontsize=14) + plt.legend(loc="upper right", fontsize=16) + plt.grid(linestyle="dotted") + plt.yscale("log") + plt.savefig( + data_directory + + "/Training Plots" + + "/network_" + + str(net_idx) + + "_mae.pdf", + dpi=300, + format="pdf", + ) + + net_idx += 1 + + np.save(data_directory + "/network_results.npy", master_data)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/training/sb3/experiments.html b/_modules/bsk_rl/training/sb3/experiments.html new file mode 100644 index 00000000..de54625d --- /dev/null +++ b/_modules/bsk_rl/training/sb3/experiments.html @@ -0,0 +1,850 @@ + + + + + + bsk_rl.training.sb3.experiments — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.training.sb3.experiments

+import os
+
+import gymnasium as gym
+import numpy as np
+import torch.nn as nn
+from stable_baselines3 import A2C, DQN, PPO
+from stable_baselines3.common.logger import configure
+from stable_baselines3.common.vec_env import SubprocVecEnv, VecMonitor
+
+from bsk_rl.utilities.sb3.custom_sb3_policies import CustomActorCriticPolicy
+from bsk_rl.utilities.sb3.shielded_policies import (
+    CustomActorCriticShieldedAgileEOSPolicy,
+    CustomActorCriticShieldedMultiSensorEOSPolicy,
+)
+
+SEP = os.path.sep
+
+
+def create_ppo_kwargs_list(**kwargs):
+    activation_functions = kwargs.get("activation_functions", [nn.LeakyReLU])
+    dropouts = kwargs.get("dropouts", [None])
+    alphas = kwargs.get("alphas", [0.1])
+    learning_rates = kwargs.get("learning_rates", [3e-4])
+    clip_ranges = kwargs.get("clip_ranges", [0.1])
+    entropy_coeffs = kwargs.get("entropy_coeffs", [0.01])
+    widths = kwargs.get("widths", [20])
+    depths = kwargs.get("depths", [4])
+    batch_sizes = kwargs.get("batch_sizes", [64])
+    n_epochs = kwargs.get("n_epochs", [50])
+    max_grad_norms = kwargs.get("max_grad_norms", [0.5])
+    n_experiments = kwargs.get("n_experiments", 1)
+
+    kwargs_list = []
+
+    # Set the experiment ID to zero
+    experiment_ID = -1
+
+    # Get the cartesian product of hyperparameter values
+    for activation_fn in activation_functions:
+        for dropout in dropouts:
+            for alpha in alphas:
+                for lr in learning_rates:
+                    for clip_range in clip_ranges:
+                        for ent_coef in entropy_coeffs:
+                            for width in widths:
+                                for depth in depths:
+                                    for batch_size in batch_sizes:
+                                        for epoch in n_epochs:
+                                            for max_grad_norm in max_grad_norms:
+                                                # Update the experiment ID
+                                                experiment_ID += 1
+                                                for experiment_num in range(
+                                                    n_experiments
+                                                ):
+                                                    kwargs = {
+                                                        "activation_fn": activation_fn,
+                                                        "dropout": dropout,
+                                                        "alpha": alpha,
+                                                        "lr": lr,
+                                                        "clip_range": clip_range,
+                                                        "ent_coef": ent_coef,
+                                                        "width": width,
+                                                        "depth": depth,
+                                                        "batch_size": batch_size,
+                                                        "epoch": epoch,
+                                                        "max_grad_norm": max_grad_norm,
+                                                        "experiment_ID": experiment_ID,
+                                                    }
+                                                    kwargs_list.append(kwargs)
+
+        return kwargs_list
+
+
+def create_a2c_kwargs_list(**kwargs):
+    activation_functions = kwargs.get("activation_functions", [nn.LeakyReLU])
+    widths = kwargs.get("widths", [20])
+    depths = kwargs.get("depths", [4])
+    dropouts = kwargs.get("dropouts", [None])
+    alphas = kwargs.get("alphas", [0.1])
+    learning_rates = kwargs.get("learning_rates", [3e-4])
+    entropy_coeffs = kwargs.get("entropy_coeffs", [0.01])
+    n_steps_ = kwargs.get("n_steps_", [45])
+    n_experiments = kwargs.get("n_experiments", 1)
+
+    kwargs_list = []
+
+    experiment_ID = -1
+
+    for activation_fn in activation_functions:
+        for width in widths:
+            for depth in depths:
+                for dropout in dropouts:
+                    for alpha in alphas:
+                        for lr in learning_rates:
+                            for ent_coef in entropy_coeffs:
+                                for n_steps in n_steps_:
+                                    experiment_ID += 1
+                                    for experiment_num in range(n_experiments):
+                                        kwargs = {
+                                            "width": width,
+                                            "depth": depth,
+                                            "dropout": dropout,
+                                            "alpha": alpha,
+                                            "lr": lr,
+                                            "ent_coef": ent_coef,
+                                            "n_steps": n_steps,
+                                            "activation_fn": activation_fn,
+                                            "experiment_ID": experiment_ID,
+                                        }
+                                        kwargs_list.append(kwargs)
+
+    return kwargs_list
+
+
+def create_dqn_kwargs_list(**kwargs):
+    learning_rates = kwargs.get("learning_rates", [1e-4])
+    depths = kwargs.get("depths", [4])
+    widths = kwargs.get("widths", [20])
+    batch_sizes = kwargs.get("batch_sizes", [64])
+    buffer_sizes = kwargs.get("buffer_sizes", [5e5])
+    n_experiments = kwargs.get("n_experiments", 1)
+
+    kwargs_list = []
+
+    experiment_ID = -1
+
+    for lr in learning_rates:
+        for depth in depths:
+            for width in widths:
+                for batch_size in batch_sizes:
+                    for buffer_size in buffer_sizes:
+                        experiment_ID += 1
+                        for experiment_num in range(n_experiments):
+                            kwargs = {
+                                "lr": lr,
+                                "depth": depth,
+                                "width": width,
+                                "batch_size": batch_size,
+                                "buffer_size": buffer_size,
+                                "experiment_ID": experiment_ID,
+                            }
+                            kwargs_list.append(kwargs)
+
+    return kwargs_list
+
+
+
+[docs] +def ppo_experiment( + policy_kwargs, + learning_rate, + clip_range, + ent_coef, + batch_size, + epoch, + max_grad_norm, + idx, + agent_dir, + n_its=10, + base_steps=1020, + shielded=False, + env_name="MultiSensorEOS-v0", + n_steps=90, + num_cores=4, +): + """ + Run a PPO experiment with the given hyperparameters + :param policy_kwargs: (dict) Policy kwargs + :param learning_rate: (float) Learning rate + :param clip_range: (float) Clip range + :param ent_coef: (float) Entropy coefficient + :param batch_size: (int) Batch size + :param epoch: (int) Number of epochs + :param idx: (int) Index of the experiment + :param agent_dir: (str) Directory where to save the agent + :param n_its: (int) Number of iterations + :param shielded: (bool) Whether to use the shielded policy + :param env_name: (str) Name of the environment + :param n_steps: (int) Number of steps + """ + network_dir = agent_dir + "/network_" + str(idx) + SEP + + validation_reward = [] + + total_step = int(base_steps * n_its * n_steps) + + print("Base steps: ", base_steps) + print("Iterations: ", n_its) + print("Total steps: ", total_step) + + os.makedirs(network_dir + "logs/", exist_ok=True) + os.makedirs(network_dir + "logger/", exist_ok=True) + multienv = SubprocVecEnv( + [lambda: gym.make(env_name) for _ in range(num_cores)], start_method="spawn" + ) + multienv = VecMonitor(multienv, network_dir + "logs/") + + # set up logger + new_logger = configure(network_dir + "logger/", ["stdout", "csv", "tensorboard"]) + + if shielded: + if env_name == "MultiSensorEOS-v0": + model = PPO( + CustomActorCriticShieldedMultiSensorEOSPolicy, + multienv, + device="cuda", + verbose=2, + tensorboard_log=network_dir, + n_epochs=epoch, + n_steps=n_steps, + batch_size=batch_size, + learning_rate=learning_rate, + max_grad_norm=max_grad_norm, + clip_range=clip_range, + ent_coef=ent_coef, + gamma=0.999, + policy_kwargs=policy_kwargs, + ) + elif env_name == "AgileEOS-v0": + model = PPO( + CustomActorCriticShieldedAgileEOSPolicy, + multienv, + device="cuda", + verbose=2, + tensorboard_log=network_dir, + n_epochs=epoch, + n_steps=n_steps, + batch_size=batch_size, + learning_rate=learning_rate, + max_grad_norm=max_grad_norm, + clip_range=clip_range, + ent_coef=ent_coef, + gamma=0.999, + policy_kwargs=policy_kwargs, + ) + else: + raise ValueError("Shielding not implemented for this environment", env_name) + else: + model = PPO( + CustomActorCriticPolicy, + multienv, + device="cuda", + verbose=2, + tensorboard_log=network_dir, + n_epochs=epoch, + n_steps=n_steps, + batch_size=batch_size, + learning_rate=learning_rate, + max_grad_norm=max_grad_norm, + clip_range=clip_range, + ent_coef=ent_coef, + gamma=0.999, + policy_kwargs=policy_kwargs, + ) + + # Set new logger + model.set_logger(new_logger) + + for i in range(0, n_its): + model.set_env(multienv) + model.learn(total_timesteps=int(total_step / n_its), reset_num_timesteps=False) + + multienv.close() + del multienv + + os.rename( + network_dir + "logs/monitor.csv", + network_dir + "logs/monitor_" + str(i) + ".csv", + ) + + multienv = SubprocVecEnv( + [lambda: gym.make(env_name) for _ in range(num_cores)], start_method="spawn" + ) + multienv = VecMonitor(multienv, network_dir + "logs/") + + model.save(network_dir + "final_network_" + str(idx)) + + # run environment + for _ in range(0, 3): + obs = multienv.reset() + reward_sum = np.zeros(num_cores) + for _ in range(0, n_steps): + action, _states = model.predict(obs, deterministic=True) + obs, rewards, dones, info = multienv.step(action) + reward_sum = np.add(reward_sum, np.array(rewards)) + + for r in reward_sum: + validation_reward.append(r) + + print("Average Reward: ", np.average(validation_reward)) + + multienv.close() + del multienv + del model + + return validation_reward, "final_network_" + str(idx)
+ + + +
+[docs] +def a2c_experiment( + agent_dir, + policy_kwargs, + learning_rate=0.0007, + ent_coef=0.01, + idx=0, + n_its=10, + base_steps=1020, + env_name="MultiSensorEOS-v0", + max_steps=90, + n_steps=45, + num_cores=4, +): + """ + Run an A2C experiment with the given hyperparameters + :param policy_kwargs: (dict) Policy kwargs + :param learning_rate: (float) Learning rate + :param ent_coef: (float) Entropy coefficient + :param idx: (int) Index of the experiment + :param agent_dir: (str) Directory where to save the agent + :param n_its: (int) Number of iterations + :param env_name: (str) Name of the environment + :param max_steps: (int) Maximum number of steps in the environment + :param n_steps: (int) Number of steps before update + :param num_cores: (int) Number of cores""" + + network_dir = agent_dir + "/network_" + str(idx) + SEP + + validation_reward = [] + + total_step = int(base_steps * n_its * max_steps) + + print("Base steps: ", base_steps) + print("Iterations: ", n_its) + print("Total steps: ", total_step) + + os.makedirs(network_dir + "/logs/", exist_ok=True) + os.makedirs(network_dir + "/logger/", exist_ok=True) + multienv = SubprocVecEnv( + [lambda: gym.make(env_name) for _ in range(num_cores)], start_method="spawn" + ) + multienv = VecMonitor(multienv, network_dir + "/logs/") + + # set up logger + new_logger = configure(network_dir + "/logger/", ["stdout", "csv", "tensorboard"]) + + model = A2C( + CustomActorCriticPolicy, + multienv, + device="cpu", + verbose=2, + tensorboard_log=network_dir, + n_steps=n_steps, + learning_rate=learning_rate, + ent_coef=ent_coef, + gamma=0.999, + policy_kwargs=policy_kwargs, + ) + + # Set new logger + model.set_logger(new_logger) + + for i in range(0, n_its): + model.set_env(multienv) + model.learn( + total_timesteps=int(total_step / n_its), + reset_num_timesteps=False, + log_interval=10, + ) + + multienv.close() + del multienv + + os.rename( + network_dir + "/logs/monitor.csv", + network_dir + "/logs/monitor_" + str(i) + ".csv", + ) + + multienv = SubprocVecEnv( + [lambda: gym.make(env_name) for _ in range(num_cores)], start_method="spawn" + ) + multienv = VecMonitor(multienv, network_dir + "/logs/") + + model.save(network_dir + "/final_network_" + str(idx)) + + # run environment + for _ in range(0, 3): + obs = multienv.reset() + reward_sum = np.zeros(num_cores) + for _ in range(0, max_steps): + action, _states = model.predict(obs, deterministic=True) + obs, rewards, dones, info = multienv.step(action) + reward_sum = np.add(reward_sum, np.array(rewards)) + + for r in reward_sum: + validation_reward.append(r) + + print("Average Reward: ", np.average(validation_reward)) + + multienv.close() + del multienv + del model + + return validation_reward, "final_network_" + str(idx)
+ + + +def dqn_experiment( + agent_dir, + policy_kwargs, + idx, + n_its, + base_steps, + learning_rate=1e-4, + batch_size=64, + buffer_size=5e5, + num_cores=4, + n_steps=90, + env_name="MultiSensorEOS-v0", +): + network_dir = agent_dir + "/network_" + str(idx) + SEP + + validation_reward = [] + + total_step = int(base_steps * n_its * n_steps) + + print("Policy Kwargs: ", policy_kwargs) + print("Learning Rate: ", learning_rate) + print("Batch Size: ", batch_size) + print("Buffer Size: ", buffer_size) + print("Num Cores: ", num_cores) + print("Num Steps: ", total_step) + + os.makedirs(network_dir + "logs/", exist_ok=True) + os.makedirs(network_dir + "logger/", exist_ok=True) + multienv = SubprocVecEnv( + [lambda: gym.make(env_name) for _ in range(num_cores)], start_method="spawn" + ) + multienv = VecMonitor(multienv, network_dir + "logs/") + + # set up logger + new_logger = configure(network_dir + "logger/", ["stdout", "csv", "tensorboard"]) + + model = DQN( + "MlpPolicy", + multienv, + verbose=2, + tensorboard_log=network_dir, + batch_size=batch_size, + learning_rate=learning_rate, + gamma=0.999, + buffer_size=buffer_size, + policy_kwargs=policy_kwargs, + train_freq=1, + learning_starts=1, + target_update_interval=1, + ) + + # Set new logger + model.set_logger(new_logger) + + for i in range(0, n_its): + model.set_env(multienv) + model.learn( + total_timesteps=int(total_step / n_its), + reset_num_timesteps=False, + log_interval=100, + ) + + multienv.close() + del multienv + + os.rename( + network_dir + "logs/monitor.csv", + network_dir + "logs/monitor_" + str(i) + ".csv", + ) + + multienv = SubprocVecEnv( + [lambda: gym.make(env_name) for _ in range(num_cores)], start_method="spawn" + ) + multienv = VecMonitor(multienv, network_dir + "logs/") + + model.save(network_dir + "final_network_" + str(idx)) + + # run environment + for _ in range(0, 3): + obs = multienv.reset() + reward_sum = np.zeros(num_cores) + for _ in range(0, n_steps): + action, _states = model.predict(obs, deterministic=True) + obs, rewards, dones, info = multienv.step(action) + reward_sum = np.add(reward_sum, np.array(rewards)) + + for r in reward_sum: + validation_reward.append(r) + + print("Average Reward: ", np.average(validation_reward)) + + multienv.close() + del multienv + del model + + return validation_reward, "final_network_" + str(idx) + + +
+[docs] +def run_ppo_experiments( + agent_dir, + kwargs_list, + n_its=10, + base_steps=1020, + index=None, + env_name="MultiSensorEOS-v0", + n_steps=45, + num_cores=4, + shielded=False, +): + """ + Run PPO experiments with the given hyperparameters + :param agent_dir: (str) Directory where to save the agent + :param n_its: (int) Number of iterations + :param kwargs_list: (list) List of dictionaries containing hyperparameters + :param index: (int) Index of the hyperparameter dictionary to use + :param env_name: (str) Name of the environment + :param n_steps: (int) Number of steps + :param num_cores: (int) Number of cores + :param shielded: (bool) Whether to use shielded policy] + """ + results = {} + idx = 0 + + if index is not None: + kwargs_list = [kwargs_list[index]] + idx = index + + for kwargs in kwargs_list: + print(kwargs) + activation_fn = kwargs.get("activation_fn", nn.LeakyReLU) + width = kwargs.get("width", 20) + depth = kwargs.get("depth", 4) + dropout = kwargs.get("dropout", None) + alpha = kwargs.get("alpha", 0.1) + lr = kwargs.get("lr", 3e-4) + clip_range = kwargs.get("clip_range", 0.1) + ent_coef = kwargs.get("ent_coef", 0.01) + epoch = kwargs.get("epoch", 50) + batch_size = kwargs.get("batch_size", 64) + max_grad_norm = kwargs.get("max_grad_norm", 0.5) + experiment_ID = kwargs.get("experiment_ID", None) + + # Create the policy kwargs + policy_kwargs = dict( + activation_fn=activation_fn, + net_arch={ + "width": width, + "depth": depth, + "dropout": dropout, + "alpha": alpha, + }, + ) + + # Call the training function + reward, model_name = ppo_experiment( + policy_kwargs, + lr, + clip_range, + ent_coef, + batch_size, + epoch, + max_grad_norm, + idx, + agent_dir, + n_its, + base_steps, + env_name=env_name, + n_steps=n_steps, + num_cores=num_cores, + shielded=shielded, + ) + + # Append to the results + results.update( + { + model_name: { + "validation_reward": reward, + "policy_kwargs": policy_kwargs, + "lr": lr, + "clip_range": clip_range, + "ent_coef": ent_coef, + "batch_size": batch_size, + "n_epochs": epoch, + "max_grad_norm": max_grad_norm, + "experiment_ID": experiment_ID, + } + } + ) + + # Intermittently save the results + np.save(agent_dir + SEP + "results_" + str(idx) + ".npy", results) + + # Increment the index + idx += 1
+ + + +def run_a2c_experiments( + agent_dir, + kwargs_list, + n_its=10, + base_steps=1020, + index=None, + env_name="MultiSensorEOS-v0", + max_steps=90, + num_cores=4, +): + results = {} + idx = 0 + + if index is not None: + kwargs_list = [kwargs_list[index]] + idx = index + + for kwargs in kwargs_list: + print(kwargs) + activation_fn = kwargs.get("activation_fn", nn.LeakyReLU) + width = kwargs.get("width", 20) + depth = kwargs.get("depth", 4) + dropout = kwargs.get("dropout", None) + alpha = kwargs.get("alpha", 0.1) + lr = kwargs.get("lr", 3e-4) + ent_coef = kwargs.get("ent_coef", 0.01) + n_steps = kwargs.get("n_steps", 5) + + # Create the policy kwargs + policy_kwargs = dict( + activation_fn=activation_fn, + net_arch={ + "width": width, + "depth": depth, + "dropout": dropout, + "alpha": alpha, + }, + ) + + # Call the training function + reward, model_name = a2c_experiment( + agent_dir, + policy_kwargs, + lr, + ent_coef, + idx, + n_its, + base_steps, + env_name=env_name, + max_steps=max_steps, + n_steps=n_steps, + num_cores=num_cores, + ) + + # Append to the results + results.update( + { + model_name: { + "validation_reward": reward, + "policy_kwargs": policy_kwargs, + "lr": lr, + "ent_coef": ent_coef, + "n_steps": n_steps, + } + } + ) + + # Intermittently save the results + np.save(agent_dir + SEP + "results_" + str(idx) + ".npy", results) + + # Increment the index + idx += 1 + + +def run_dqn_experiments( + agent_dir, + kwargs_list, + n_its=10, + base_steps=1020, + index=None, + env_name="MultiSensorEOS-v0", + max_steps=90, + num_cores=4, +): + results = {} + idx = 0 + + if index is not None: + kwargs_list = [kwargs_list[index]] + idx = index + + for kwargs in kwargs_list: + print(kwargs) + width = kwargs.get("width", 20) + depth = kwargs.get("depth", 4) + lr = kwargs.get("lr", 1e-4) + batch_size = kwargs.get("batch_size", 64) + buffer_size = kwargs.get("buffer_size", 5e5) + + sizes = [width] * depth + + # Create the policy kwargs + policy_kwargs = dict(net_arch=sizes) + + # Call the training function + reward, model_name = dqn_experiment( + agent_dir, + policy_kwargs, + idx, + n_its, + base_steps, + learning_rate=lr, + batch_size=batch_size, + buffer_size=buffer_size, + num_cores=num_cores, + n_steps=max_steps, + env_name=env_name, + ) + + # Append to the results + results.update( + { + model_name: { + "validation_reward": reward, + "policy_kwargs": policy_kwargs, + "lr": lr, + "batch_size": batch_size, + "buffer_size": buffer_size, + } + } + ) + + # Intermittently save the results + np.save(agent_dir + SEP + "results_" + str(idx) + ".npy", results) + + # Increment the index + idx += 1 +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/utilities/effector_primitives/actuator_primitives.html b/_modules/bsk_rl/utilities/effector_primitives/actuator_primitives.html new file mode 100644 index 00000000..cb34bb27 --- /dev/null +++ b/_modules/bsk_rl/utilities/effector_primitives/actuator_primitives.html @@ -0,0 +1,180 @@ + + + + + + bsk_rl.utilities.effector_primitives.actuator_primitives — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.utilities.effector_primitives.actuator_primitives

+import numpy as np
+from Basilisk.simulation import reactionWheelStateEffector, thrusterDynamicEffector
+from Basilisk.utilities import simIncludeRW, simIncludeThruster
+
+
+
+[docs] +def balancedHR16Triad( + useRandom=False, randomBounds=(-400, 400), wheelSpeeds=[500, 500, 500] +): + """ + Creates a set of three HR16 reaction wheels. + Returns a set of thrusters and thrusterFac instance to add thrusters to a + spacecraft. + :return thrusterSet: thruster dynamic effector instance + :return thrusterFac: factory containing defined thrusters + """ + rwFactory = simIncludeRW.rwFactory() + if useRandom: + wheelSpeeds = np.random.uniform(randomBounds[0], randomBounds[1], 3) + + rwFactory.create( + "Honeywell_HR16", [1, 0, 0], maxMomentum=50.0, Omega=wheelSpeeds[0] # RPM + ) + rwFactory.create( + "Honeywell_HR16", [0, 1, 0], maxMomentum=50.0, Omega=wheelSpeeds[1] # RPM + ) + rwFactory.create( + "Honeywell_HR16", [0, 0, 1], maxMomentum=50.0, Omega=wheelSpeeds[2] # RPM + ) + + rwStateEffector = reactionWheelStateEffector.ReactionWheelStateEffector() + + return rwStateEffector, rwFactory, wheelSpeeds
+ + + +
+[docs] +def idealMonarc1Octet(): + """ + Creates a set of eight ADCS thrusters using MOOG Monarc-1 attributes. + Returns a set of thrusters and thrusterFac instance to add thrusters to a + spacecraft. + :return thrusterSet: thruster dynamic effector instance + :return thrusterFac: factory containing defined thrusters + """ + location = [ + [3.874945160902288e-2, -1.206182747348013, 0.85245], + [3.874945160902288e-2, -1.206182747348013, -0.85245], + [-3.8749451609022656e-2, -1.206182747348013, 0.85245], + [-3.8749451609022656e-2, -1.206182747348013, -0.85245], + [-3.874945160902288e-2, 1.206182747348013, 0.85245], + [-3.874945160902288e-2, 1.206182747348013, -0.85245], + [3.8749451609022656e-2, 1.206182747348013, 0.85245], + [3.8749451609022656e-2, 1.206182747348013, -0.85245], + ] + + direction = [ + [-0.7071067811865476, 0.7071067811865475, 0.0], + [-0.7071067811865476, 0.7071067811865475, 0.0], + [0.7071067811865475, 0.7071067811865476, 0.0], + [0.7071067811865475, 0.7071067811865476, 0.0], + [0.7071067811865476, -0.7071067811865475, 0.0], + [0.7071067811865476, -0.7071067811865475, 0.0], + [-0.7071067811865475, -0.7071067811865476, 0.0], + [-0.7071067811865475, -0.7071067811865476, 0.0], + ] + thrusterSet = thrusterDynamicEffector.ThrusterDynamicEffector() + thFactory = simIncludeThruster.thrusterFactory() + for pos_B, dir_B in zip(location, direction): + thFactory.create("MOOG_Monarc_1", pos_B, dir_B) + return thrusterSet, thFactory
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/utilities/genetic_algorithm/experiments.html b/_modules/bsk_rl/utilities/genetic_algorithm/experiments.html new file mode 100644 index 00000000..042e97ad --- /dev/null +++ b/_modules/bsk_rl/utilities/genetic_algorithm/experiments.html @@ -0,0 +1,193 @@ + + + + + + bsk_rl.utilities.genetic_algorithm.experiments — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.utilities.genetic_algorithm.experiments

+import os
+
+import numpy as np
+
+from bsk_rl.agents.genetic_algorithm import ga_env_solver
+
+SEP = os.path.sep
+
+
+def create_ga_hp_kwargs_list(**kwargs):
+    generations = kwargs.get("generations", [100, 200])
+    gen_sizes = kwargs.get("gen_sizes", [10, 20])
+    n_experiments = kwargs.get("n_experiments", 1)
+
+    # Create the hyperparameter list
+    ga_kwargs = []
+
+    # Set the experiment ID to -1
+    experiment_ID = -1
+
+    # Loop over the number of experiments
+    for gens in generations:
+        for gen_size in gen_sizes:
+            experiment_ID += 1
+            for i in range(n_experiments):
+                ga_kwargs.append(
+                    {
+                        "n_gens": gens,
+                        "gen_size": gen_size,
+                        "experiment_ID": experiment_ID,
+                    }
+                )
+
+    return ga_kwargs
+
+
+
+[docs] +def run_ga_hp_experiment( + ga_dir, + ga_kwargs, + index=None, + num_cores=4, + env_name="AgileEOS-v0", +): + """ + Runs a genetic algorithm experiment hyperparameter search experiment over the + number of generations and population size.""" + + # Set the results dictionary + results = {} + idx = 0 + + if index is not None: + ga_kwargs = [ga_kwargs[index]] + idx = index + + for kwargs in ga_kwargs: + n_gens = kwargs["n_gens"] + gen_size = kwargs["gen_size"] + + # Create the solver + solver = ga_env_solver( + env_name, + n_gens, + gen_size, + ga_dir=ga_dir + SEP + "ga_" + str(idx) + SEP, + num_cores=num_cores, + ) + + # Run the solver + max_reward, metrics = solver.optimize() + + # Save the results + results[idx] = { + "n_gens": n_gens, + "gen_size": gen_size, + "max_reward": max_reward, + "metrics": metrics, + } + + # Intermittently save the results + np.save(ga_dir + SEP + "results_" + str(idx) + ".npy", results) + + # Increment the index + idx += 1
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/utilities/initial_conditions/leo_orbit.html b/_modules/bsk_rl/utilities/initial_conditions/leo_orbit.html new file mode 100644 index 00000000..cd942e1c --- /dev/null +++ b/_modules/bsk_rl/utilities/initial_conditions/leo_orbit.html @@ -0,0 +1,644 @@ + + + + + + bsk_rl.utilities.initial_conditions.leo_orbit — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.utilities.initial_conditions.leo_orbit

+import math as m
+import random
+
+import numpy as np
+from Basilisk import __path__
+from Basilisk.simulation import spacecraft
+from Basilisk.utilities import SimulationBaseClass
+from Basilisk.utilities import macros as mc
+from Basilisk.utilities import orbitalMotion, simIncludeGravBody
+
+bskPath = __path__[0]
+
+mu = 0.3986004415e15
+
+
+
+[docs] +def inclined_circular_300km(): + """ + Returns an inclined, circular LEO orbit. + :return: + """ + + oe = orbitalMotion.ClassicElements() + oe.a = 6371 * 1000.0 + 300.0 * 1000 + oe.e = 0.0 + oe.i = 45.0 * mc.D2R + + oe.Omega = 0.0 * mc.D2R + oe.omega = 0.0 * mc.D2R + oe.f = 0.0 * mc.D2R + rN, vN = orbitalMotion.elem2rv(mu, oe) + + return oe, rN, vN
+ + + +
+[docs] +def random_inclined_circular_300km(): + """ + Returns an inclined, circular LEO orbit. + :return: + """ + + oe = orbitalMotion.ClassicElements() + oe.a = 6371 * 1000.0 + np.random.uniform(290e3, 310e3) + oe.e = 0.0 + oe.i = 45.0 * mc.D2R + + oe.Omega = 0.0 * mc.D2R + oe.omega = 0.0 * mc.D2R + oe.f = 0.0 * mc.D2R + rN, vN = orbitalMotion.elem2rv(mu, oe) + + return oe, rN, vN
+ + + +
+[docs] +def sampled_400km(): + """ + Returns an elliptical, prograde LEO orbit with an SMA of 400km. + :return: + """ + oe = orbitalMotion.ClassicElements() + oe.a = 6371 * 1000.0 + 400.0 * 1000 + oe.e = np.random.uniform(0, 0.001, 1) + oe.i = np.random.uniform(-90 * mc.D2R, 90 * mc.D2R, 1) + oe.Omega = np.random.uniform(0 * mc.D2R, 360 * mc.D2R, 1) + oe.omega = np.random.uniform(0 * mc.D2R, 360 * mc.D2R, 1) + oe.f = np.random.uniform(0 * mc.D2R, 360 * mc.D2R, 1) + rN, vN = orbitalMotion.elem2rv(mu, oe) + + return oe, rN, vN
+ + + +
+[docs] +def sampled_500km_boulder_gs(): + """ + Returns an elliptical, prograde LEO orbit with an SMA of 500km. + Inclination is bounded so the spacecraft can communicate with Boulder. + :return: + """ + mu = 0.3986004415e15 + oe = orbitalMotion.ClassicElements() + oe.a = 6371 * 1000.0 + 500.0 * 1000 + oe.e = np.random.uniform(0, 0.01, 1) + # oe.i = np.random.uniform(40*mc.D2R, 60*mc.D2R,1) + oe.i = np.random.uniform(40 * mc.D2R, 60 * mc.D2R, 1) + oe.Omega = np.random.uniform(0 * mc.D2R, 20 * mc.D2R, 1) + oe.omega = np.random.uniform(0 * mc.D2R, 20 * mc.D2R, 1) + oe.f = np.random.uniform(0 * mc.D2R, 360 * mc.D2R, 1) + rN, vN = orbitalMotion.elem2rv(mu, oe) + + return oe, rN, vN
+ + + +
+[docs] +def sampled_boulder_gs(nominal_radius): + """ + Returns an elliptical, prograde LEO orbit with an SMA of 500km. + Inclination is bounded so the spacecraft can communicate with Boulder. + :return: + """ + mu = 0.3986004415e15 + oe = orbitalMotion.ClassicElements() + oe.a = nominal_radius + oe.e = np.random.uniform(0, 0.01, 1) + # oe.i = np.random.uniform(40*mc.D2R, 60*mc.D2R,1) + oe.i = np.random.uniform(40 * mc.D2R, 60 * mc.D2R, 1) + oe.Omega = np.random.uniform(0 * mc.D2R, 360 * mc.D2R, 1) + oe.omega = np.random.uniform(0 * mc.D2R, 360 * mc.D2R, 1) + oe.f = np.random.uniform(0 * mc.D2R, 360 * mc.D2R, 1) + rN, vN = orbitalMotion.elem2rv(mu, oe) + + return oe, rN, vN
+ + + +def coordinated_pass_1(): + r_sc1 = (6378.0 + 500.0) * 1000 # meters + oe_sc1 = orbitalMotion.ClassicElements() + oe_sc1.a = r_sc1 + oe_sc1.e = 0.00001 + oe_sc1.i = 70.0 * mc.D2R + oe_sc1.Omega = 135.0 * mc.D2R + oe_sc1.omega = 184.8 * mc.D2R + oe_sc1.f = 85.3 * mc.D2R + rN, vN = orbitalMotion.elem2rv(mu, oe_sc1) + + return oe_sc1, rN, vN + + +def coordinated_pass_2(): + r_sc2 = (6378.0 + 2000.0) * 1000 # meters + oe_sc2 = orbitalMotion.ClassicElements() + oe_sc2.a = r_sc2 + oe_sc2.e = 0.00001 + oe_sc2.i = 53.0 * mc.D2R + oe_sc2.Omega = 115.0 * mc.D2R + oe_sc2.omega = 5.0 * mc.D2R + oe_sc2.f = 240.0 * mc.D2R + rN, vN = orbitalMotion.elem2rv(mu, oe_sc2) + + return oe_sc2, rN, vN + + +def coordinated_pass_3(): + r_sc2 = (6378.0 + 7500.0) * 1000 # meters + oe_sc2 = orbitalMotion.ClassicElements() + oe_sc2.a = r_sc2 + oe_sc2.e = 0.00001 + oe_sc2.i = 53.0 * mc.D2R + oe_sc2.Omega = 115.0 * mc.D2R + oe_sc2.omega = 5.0 * mc.D2R + oe_sc2.f = 240.0 * mc.D2R + rN, vN = orbitalMotion.elem2rv(mu, oe_sc2) + + return oe_sc2, rN, vN + + +def sso_Boulder(): + r_sc = 42164125 # meters + oe_sc = orbitalMotion.ClassicElements() + oe_sc.a = r_sc + oe_sc.e = 0.00001 + oe_sc.i = 53.0 * mc.D2R + oe_sc.Omega = 115.0 * mc.D2R + oe_sc.omega = 5.0 * mc.D2R + oe_sc.f = 75.0 * mc.D2R + rN, vN = orbitalMotion.elem2rv(mu, oe_sc) + + return oe_sc, rN, vN + + +
+[docs] +def inclined_400km(): + """ + Returns an elliptical, prograde LEO orbit with an SMA of 400km. + :return: + """ + mu = 0.3986004415e15 + oe = orbitalMotion.ClassicElements() + oe.a = 6371 * 1000.0 + 500.0 * 1000 + oe.e = 0.0001 + oe.i = mc.D2R * 45.0 + oe.Omega = mc.D2R * 45.0 + oe.omega = 0.0 + oe.f = 0.0 + rN, vN = orbitalMotion.elem2rv(mu, oe) + + return oe, rN, vN
+ + + +
+[docs] +def create_ground_tgts(n_targets, rN, vN, sim_length, utc_init): + """ + Returns a set of targets based on the orbital parameters by running a simplified + BSK scenario + :param n_targets: number of targets to generate + :param rN: Initial inertial position + :param vN: Initial inertial velocity + :param sim_length: simulation length + :param uct_init: time initialization string + :return targets: + """ + + # Create simulation variable names + simTaskName = "simTask" + simProcessName = "simProcess" + + # Create a sim module as an empty container + scSim = SimulationBaseClass.SimBaseClass() + + # create the simulation process + dynProcess = scSim.CreateNewProcess(simProcessName) + + # Create the dynamics task and specify the integration update time + simulationTimeStep = mc.sec2nano(10.0) + dynProcess.addTask(scSim.CreateNewTask(simTaskName, simulationTimeStep)) + + # Setup the simulation tasks/objects, initialize spacecraft object + # and set properties + scObject = spacecraft.Spacecraft() + scObject.ModelTag = "bsk-Sat" + + # Add spacecraft object to the simulation process + scSim.AddModelToTask(simTaskName, scObject) + + # Setup Gravity Body + gravFactory = simIncludeGravBody.gravBodyFactory() + planet = gravFactory.createEarth() + planet.isCentralBody = True + + planet.useSphericalHarmParams = True + simIncludeGravBody.loadGravFromFile( + bskPath + "/supportData/LocalGravData/GGM03S.txt", planet.spherHarm, 10 + ) + + # Set up spice with spice time + UTCInit = utc_init + gravFactory.createSpiceInterface( + bskPath + "/supportData/EphemerisData/", UTCInit, epochInMsg=True + ) + gravFactory.spiceObject.zeroBase = ( + "earth" # Make sure that the Earth is the zero base + ) + scSim.AddModelToTask(simTaskName, gravFactory.spiceObject) + + # Finally, the gravitational body must be connected to the spacecraft object. + scObject.gravField.gravBodies = spacecraft.GravBodyVector( + list(gravFactory.gravBodies.values()) + ) + + # To set the spacecraft initial conditions, the following initial position and + # velocity variables are set: + scObject.hub.r_CN_NInit = rN # m - r_BN_N + scObject.hub.v_CN_NInit = vN # m/s - v_BN_N + + # Set the simulation time + simulationTime = mc.sec2nano(sim_length * 60.0) + + # create a logging task object of the spacecraft output message at the desired + # down sampling ratio + dataRec1 = scObject.scStateOutMsg.recorder() + dataRec2 = gravFactory.spiceObject.planetStateOutMsgs[0].recorder() + scSim.AddModelToTask(simTaskName, dataRec1) + scSim.AddModelToTask(simTaskName, dataRec2) + + scSim.InitializeSimulation() + + # configure a simulation stop time time and execute the simulation run + scSim.ConfigureStopTime(simulationTime) + scSim.ExecuteSimulation() + + posData = dataRec1.r_BN_N + dcm_PN = dataRec2.J20002Pfix + + pcpf_positions = [] + + # Compute the position in the planet-centered, planet-fixed frame + for idx, pos in enumerate(posData): + pcpf_positions.append(np.matmul(dcm_PN[idx], pos)) + + # Grab random PCPF targets + candidate_position_indices = random.sample(range(0, len(posData)), k=n_targets) + candidate_position_indices = np.sort( + candidate_position_indices + ) # list of the indices of the ordered targets + candidate_position_times = [ + 10 * idx for idx in candidate_position_indices + ] # list of the ordered times of the targets in seconds + + # Initialize targets + targets = [] + for idx in candidate_position_indices: + # Add noise to s/c position vector + temp_pos = np.array(pcpf_positions[idx]) + np.random.uniform(-1.0e5, 1.0e5, 3) + # Normalize and multiply by Earth's radius + targets.append(6378.0 * 1000.0 * temp_pos / np.linalg.norm(np.array(temp_pos))) + + return np.array(targets).T, candidate_position_times
+ + + +
+[docs] +def walker_delta( + n_spacecraft, n_planes, rel_phasing, altitude, inc, clustersize=1, clusterspacing=0 +): + """ + Computes the initial orbit conditions of a constellation of spacecraft in the + walker delta pattern + :param n_spacecraft: number of spacecraft in the constellation + :param n_planes: number of orbital planes + :param rel_phasing: relative phasing between the planes [0, 1) + :param altitude: Altitude of the s/c (m) + :param inc: Inclination of the orbit (deg) + :param clustersize: Size of satellite groups + :param clusterspacing: True anomaly spacing within cluster (deg) + :return oe_all: n_spacecraft x 1 list of BSK oe elements + """ + oe_all = [] + + # Loop through s/c + for idx in range(0, n_spacecraft): + # Instantiate orbital elements + oe = orbitalMotion.ClassicElements() + + # Define altitude, eccentricity, and inclination + oe.a = 6371 * 1000.0 + altitude + oe.e = 0.0 + oe.i = mc.D2R * inc + + # Define the plane number + spacecraft_per_plane = float(n_spacecraft / n_planes) + plane_num = float(int(idx / spacecraft_per_plane)) + + # Compute longitude of ascending node + oe.Omega = mc.D2R * (plane_num * 360.0 / n_planes % 360) + + # Set argument of periapsis using relative phasing + dPhi_rel = plane_num * rel_phasing * 360.0 / n_planes + oe.omega = mc.D2R * dPhi_rel + + # Define true anomoly using in-plane phasing + dPhi_inplane = 360.0 / (spacecraft_per_plane / clustersize) + oe.f = mc.D2R * ( + (int((idx % spacecraft_per_plane) / clustersize) * dPhi_inplane) + + clusterspacing * (idx % clustersize) + ) + + # Append to oe_all + oe_all.append(oe) + + return oe_all
+ + + +
+[docs] +def distribute_tgts(rN, vN, sim_length, utc_init, global_tgts, dt=60.0): + """ + :param rN: + :param vN: + :param sim_length: [m] + :param utc_init: + :param global_tgts: np.array of global tgts in ECEF coordinates + :param dt: [s] + :return local_tgts: list of indexes into global tgts + :return local_tgt_times: local time each global tgt in local_tgts is encountered + """ + + local_tgts = [] + local_tgt_times = [] + + # Create simulation variable names + simTaskName = "simTask" + simProcessName = "simProcess" + + # Create a sim module as an empty container + scSim = SimulationBaseClass.SimBaseClass() + + # create the simulation process + dynProcess = scSim.CreateNewProcess(simProcessName) + + # Create the dynamics task and specify the integration update time + simulationTimeStep = mc.sec2nano(dt) + dynProcess.addTask(scSim.CreateNewTask(simTaskName, simulationTimeStep)) + + # Setup the simulation tasks/objects, initialize spacecraft object and + # set properties + scObject = spacecraft.Spacecraft() + scObject.ModelTag = "bsk-Sat" + + # Add spacecraft object to the simulation process + scSim.AddModelToTask(simTaskName, scObject) + + # Setup Gravity Body + gravFactory = simIncludeGravBody.gravBodyFactory() + planet = gravFactory.createEarth() + gravFactory.createSun() + planet.isCentralBody = True + planet.useSphericalHarmParams = True + simIncludeGravBody.loadGravFromFile( + bskPath + "/supportData/LocalGravData/GGM03S.txt", planet.spherHarm, 10 + ) + + # Set up spice with spice time + UTCInit = utc_init + gravFactory.createSpiceInterface( + bskPath + "/supportData/EphemerisData/", UTCInit, epochInMsg=True + ) + gravFactory.spiceObject.zeroBase = ( + "earth" # Make sure that the Earth is the zero base + ) + scSim.AddModelToTask(simTaskName, gravFactory.spiceObject) + + # Finally, the gravitational body must be connected to the spacecraft object. + scObject.gravField.gravBodies = spacecraft.GravBodyVector( + list(gravFactory.gravBodies.values()) + ) + + # To set the spacecraft initial conditions, the following initial position and + # velocity variables are set: + scObject.hub.r_CN_NInit = rN # m - r_BN_N + scObject.hub.v_CN_NInit = vN # m/s - v_BN_N + + # Set the simulation time + simulationTime = mc.sec2nano(sim_length * 60.0) + + # create a logging task object of the spacecraft output message + dataRec1 = scObject.scStateOutMsg.recorder() + dataRec2 = gravFactory.spiceObject.planetStateOutMsgs[0].recorder() + scSim.AddModelToTask(simTaskName, dataRec1) + scSim.AddModelToTask(simTaskName, dataRec2) + + scSim.InitializeSimulation() + + # configure a simulation stop time time and execute the simulation run + scSim.ConfigureStopTime(simulationTime) + scSim.ExecuteSimulation() + + posData = dataRec1.r_BN_N + dcm_PN = dataRec2.J20002Pfix + + pcpf_positions = [] + local_tgt_locations = [] + + # Compute the position in the planet-centered, planet-fixed frame + for i, pos in enumerate(posData): + # Compute the pcpf position of the s/c + pcpf_pos = np.matmul(dcm_PN[i], pos) + pcpf_positions.append(pcpf_pos) + + # Loop through every target to check if within azelrange requirements + for j, tgt in enumerate(global_tgts): + if ( + np.linalg.norm(pcpf_pos - tgt) < 750e3 and j not in local_tgts + ): # Perform a quick check - ensure difference is less than ~500km/cosd(45) + local_tgts.append(j) # Append the target idx + local_tgt_times.append( + dt / 2 + dt * i + ) # Append the time the target is encountered + local_tgt_locations.append(tgt) + + gravFactory.unloadSpiceKernels() + + return local_tgts, local_tgt_times, pcpf_positions, local_tgt_locations
+ + + +
+[docs] +def elrange_req(sc_pos, tgt_pos): + """ + Determines if the spacecraft is within the elevation and range requirements of + a target + + Args: + sc_pos: spacecraft position expressed in the ECEF frame + tgt_pos: tgt_pos expressed in the ECEF frame + Returns: + T/F - within el, range requirements or not + """ + + # Import relevant library + import pyproj + + # Set the elevation and range requirements + el_req = 75 # deg + range_req = 1e9 # m + + # get the lat, long, and altitude of the target (assumes WGS84 ellipsoid) + ecef = pyproj.Proj(proj="geocent", ellps="WGS84", datum="WGS84") + lla = pyproj.Proj(proj="latlong", ellps="WGS84", datum="WGS84") + lon, lat, alt = pyproj.transform( + ecef, lla, tgt_pos[0], tgt_pos[1], tgt_pos[2], radians=True + ) # rad, rad, m + + # Compute the line of sight vector + los_ecef = np.array(sc_pos) - np.array(tgt_pos) + + # Normalize the vector + los_ecef_norm = los_ecef / np.linalg.norm(los_ecef) + + # Compute the transformation from ECEF to ENU + ECEF2ENU = np.array( + [ + [-m.sin(lon), m.cos(lon), 0], + [-m.sin(lat) * m.cos(lon), -m.sin(lat) * m.sin(lon), m.cos(lat)], + [m.cos(lat) * m.cos(lon), m.cos(lat) * m.sin(lon), m.sin(lat)], + ] + ) + + # Compute the los vector in ENU coordinates + los_enu = np.matmul(ECEF2ENU, los_ecef_norm) + + # Compute the elevation + el = m.degrees(m.asin(los_enu[2])) + + # Compute the range + range = np.linalg.norm(los_ecef) # m + + if (el > el_req) and (range < range_req): + return True + else: + return False
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/utilities/initial_conditions/sc_attitudes.html b/_modules/bsk_rl/utilities/initial_conditions/sc_attitudes.html new file mode 100644 index 00000000..90890068 --- /dev/null +++ b/_modules/bsk_rl/utilities/initial_conditions/sc_attitudes.html @@ -0,0 +1,158 @@ + + + + + + bsk_rl.utilities.initial_conditions.sc_attitudes — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.utilities.initial_conditions.sc_attitudes

+import numpy as np
+
+
+
+[docs] +def random_tumble(maxSpinRate=0.001): + """ + Simulates a spacecraft in a random tumble with uniformly sampled initial conditions. + :return: sigma_bn + :return: omega_bn + """ + + sigma_bn = np.random.uniform( + 0, + 1.0, + [ + 3, + ], + ) + omega_bn = np.random.uniform( + -maxSpinRate, + maxSpinRate, + [ + 3, + ], + ) + + return sigma_bn, omega_bn
+ + + +
+[docs] +def static_inertial(): + """ + Simulates a spacecraft in a sidereal stare fixed to the inertial origin. + :return: + """ + + sigma_bn = np.zeros( + [ + 3, + ] + ) + omega_bn = np.zeros( + [ + 3, + ] + ) + + return sigma_bn, omega_bn
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/utilities/initial_conditions/small_body.html b/_modules/bsk_rl/utilities/initial_conditions/small_body.html new file mode 100644 index 00000000..1d5cb5b7 --- /dev/null +++ b/_modules/bsk_rl/utilities/initial_conditions/small_body.html @@ -0,0 +1,195 @@ + + + + + + bsk_rl.utilities.initial_conditions.small_body — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.utilities.initial_conditions.small_body

+import math as m
+
+import numpy as np
+
+
+
+[docs] +def generate_waypoints(num_spheres, num_lat, num_lon, radius): + """ + Generates a number of spheres of waypoints, each sphere is at [1...n]*radius, + where n is the num_spheres + """ + + for idx in range(num_spheres): + u1, v1 = np.mgrid[0 : 2 * np.pi : (num_lon * 1j), 0 : np.pi : (num_lat * 1j)] + x1 = (idx + 1) * radius * np.cos(u1) * np.sin(v1) + y1 = (idx + 1) * radius * np.sin(u1) * np.sin(v1) + z1 = (idx + 1) * radius * np.cos(v1) + + x1 = x1.reshape(x1.size) + y1 = y1.reshape(y1.size) + z1 = z1.reshape(z1.size) + + if idx == 0: + waypoints = np.array([x1, y1, z1]) + else: + waypoints = np.concatenate((waypoints, [x1, y1, z1]), axis=1) + + waypoints = waypoints.T + repeats = [] + + # Check for duplicates + for idx1, row1 in enumerate(waypoints): + for idx2, row2 in enumerate(waypoints): + if idx1 == idx2: + continue + else: + if np.linalg.norm(row1 - row2) < 1e-8: + if idx2 > idx1: + repeats.append(idx2) + + waypoints = np.delete(waypoints, repeats, axis=0) + + return waypoints
+ + + +
+[docs] +def generate_mapping_points(num_points, radius): + """Generates a number of mapping points on the surface of the body using a + Fibonnaci sphere Algorithm from: + https://stackoverflow.com/questions/9600801/evenly-distributing-n-points-on-a-sphere + """ + + points = [] + phi = m.pi * (3.0 - m.sqrt(5.0)) # golden angle in radians + + for i in range(num_points): + y = 1 - (i / float(num_points - 1)) * 2 # y goes from 1 to -1 + r = m.sqrt(1 - y * y) # radius at y + + theta = phi * i # golden angle increment + + x = m.cos(theta) * r + z = m.sin(theta) * r + + points.append( + radius + * np.matmul( + np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]]), np.array([x, y, z]) + ) + ) + + return np.array(points)
+ + + +
+[docs] +def generate_imaging_points(num_points, radius): + """Generates a number of random imaging points on the surface of the body""" + points = np.random.uniform(-1.0, 1.0, size=(num_points, 3)) + + for idx in range(num_points): + points[idx, :] = radius * points[idx, :] / np.linalg.norm(points[idx, :]) + + return points
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/utilities/sb3/custom_sb3_policies.html b/_modules/bsk_rl/utilities/sb3/custom_sb3_policies.html new file mode 100644 index 00000000..c14c6d84 --- /dev/null +++ b/_modules/bsk_rl/utilities/sb3/custom_sb3_policies.html @@ -0,0 +1,243 @@ + + + + + + bsk_rl.utilities.sb3.custom_sb3_policies — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.utilities.sb3.custom_sb3_policies

+from typing import Callable, Dict, Tuple, Type
+
+import gymnasium as gym
+import torch as th
+from stable_baselines3.common.policies import ActorCriticPolicy
+from torch import nn
+
+
+
+[docs] +class CustomNetwork(nn.Module): + """ + Custom network for policy and value function. + It receives as input the features extracted by the feature extractor. + + :param feature_dim: dimension of the features extracted with the features_extractor + (e.g. features from a CNN) + :param last_layer_dim_pi: (int) number of units for the last layer of the policy + network + :param last_layer_dim_vf: (int) number of units for the last layer of the value + network + """ + +
+[docs] + def __init__( + self, + num_states=12, + num_actions=4, + width=100, + depth=1, + dropout=None, + activation_function=nn.LeakyReLU, + alpha=None, + ): + super(CustomNetwork, self).__init__() + + # IMPORTANT: + # Save output dimensions, used to create the distributions + self.latent_dim_pi = width + self.latent_dim_vf = width + + layers = [] + + # Add layers + for layer in range(0, depth): + if layer == 0: + layers.append(nn.Linear(num_states, width)) + else: + layers.append(nn.Linear(width, width)) + + if activation_function == nn.Tanh: + layers.append(nn.Tanh()) + elif activation_function == nn.LeakyReLU: + layers.append(nn.LeakyReLU(negative_slope=alpha)) + + # Add dropout layers + if dropout is not None: + layers.append(nn.Dropout(p=dropout, inplace=True)) + + # Policy network + self.policy_net = nn.Sequential(*layers) + # Value network + self.value_net = nn.Sequential(*layers)
+ + +
+[docs] + def forward(self, features: th.Tensor) -> Tuple[th.Tensor, th.Tensor]: + """ + :return: (th.Tensor, th.Tensor) latent_policy, latent_value of the specified + network. + If all layers are shared, then ``latent_policy == latent_value`` + """ + # print('Feature shape: ', features.shape) + return self.policy_net(features), self.value_net(features)
+ + + def forward_actor(self, features: th.Tensor) -> th.Tensor: + return self.policy_net(features) + + def forward_critic(self, features: th.Tensor) -> th.Tensor: + return self.value_net(features)
+ + + +
+[docs] +class CustomActorCriticPolicy(ActorCriticPolicy): +
+[docs] + def __init__( + self, + observation_space: gym.spaces.Space, + action_space: gym.spaces.Space, + lr_schedule: Callable[[float], float], + net_arch: Dict = None, + activation_fn: Type[nn.Module] = nn.Tanh, + *args, + **kwargs, + ): + # Initialize the network parameters + self.num_states = observation_space.shape[0] + self.num_actions = action_space.n + self.width = net_arch["width"] + self.depth = net_arch["depth"] + self.dropout = net_arch["dropout"] + self.activation_function = activation_fn + self.alpha = net_arch["alpha"] + + self.features_dim = self.width + + super(CustomActorCriticPolicy, self).__init__( + observation_space, + action_space, + lr_schedule, + net_arch, + activation_fn, + # Pass remaining arguments to base class + *args, + **kwargs, + ) + # Disable orthogonal initialization + self.ortho_init = False
+ + + def _build_mlp_extractor(self) -> None: + self.mlp_extractor = CustomNetwork( + self.num_states, + self.num_actions, + self.width, + self.depth, + self.dropout, + self.activation_fn, + self.alpha, + )
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/utilities/sb3/shielded_policies.html b/_modules/bsk_rl/utilities/sb3/shielded_policies.html new file mode 100644 index 00000000..40df0686 --- /dev/null +++ b/_modules/bsk_rl/utilities/sb3/shielded_policies.html @@ -0,0 +1,283 @@ + + + + + + bsk_rl.utilities.sb3.shielded_policies — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for bsk_rl.utilities.sb3.shielded_policies

+from typing import Callable, Dict, Tuple, Type
+
+import gymnasium as gym
+import torch as th
+from stable_baselines3.common.policies import ActorCriticPolicy
+from torch import nn
+
+from bsk_rl.utilities.sb3 import custom_sb3_policies, shields
+
+
+
+[docs] +class CustomActorCriticShieldedPolicy(ActorCriticPolicy): + """ + Custom actor critic policy with a shield. Made for AgileEOS environment. + """ + +
+[docs] + def __init__( + self, + observation_space: gym.spaces.Space, + action_space: gym.spaces.Space, + lr_schedule: Callable[[float], float], + net_arch: Dict = None, + activation_fn: Type[nn.Module] = nn.Tanh, + *args, + **kwargs, + ): + # Initialize the network parameters + self.num_states = observation_space.shape[0] + self.num_actions = action_space.n + self.width = net_arch["width"] + self.depth = net_arch["depth"] + self.dropout = net_arch["dropout"] + self.activation_function = activation_fn + self.alpha = net_arch["alpha"] + + self.features_dim = self.width + + # Create the shield + # self.shield = shields.AgileEOSShield() + + super(CustomActorCriticShieldedPolicy, self).__init__( + observation_space, + action_space, + lr_schedule, + net_arch, + activation_fn, + # Pass remaining arguments to base class + *args, + **kwargs, + ) + # Disable orthogonal initialization + self.ortho_init = False
+ + + def _build_mlp_extractor(self) -> None: + self.mlp_extractor = custom_sb3_policies.CustomNetwork( + self.num_states, + self.num_actions, + self.width, + self.depth, + self.dropout, + self.activation_fn, + self.alpha, + ) + + def _predict( + self, observation: th.Tensor, deterministic: bool = False + ) -> th.Tensor: + """ + Get the action according to the policy for a given observation. + + :param observation: + :param deterministic: Whether to use stochastic or deterministic actions + :return: Taken action according to the policy + """ + actions = self.get_distribution(observation).get_actions( + deterministic=deterministic + ) + actions = self.shield.shield_actions(observation, actions) + return actions + +
+[docs] + def forward( + self, obs: th.Tensor, deterministic: bool = False + ) -> Tuple[th.Tensor, th.Tensor, th.Tensor]: + """ + Forward pass in all the networks (actor and critic) + + :param obs: Observation + :param deterministic: Whether to sample or use deterministic actions + :return: action, value and log probability of the action + """ + # Preprocess the observation if needed + features = self.extract_features(obs) + latent_pi, latent_vf = self.mlp_extractor(features) + # Evaluate the values for the given observations + values = self.value_net(latent_vf) + distribution = self._get_action_dist_from_latent(latent_pi) + actions = distribution.get_actions(deterministic=deterministic) + # print('old actions: ', actions) + + # Override the actions here + actions = self.shield.shield_actions(obs, actions) + + log_prob = distribution.log_prob(actions) + actions = actions.reshape((-1,) + self.action_space.shape) + return actions, values, log_prob
+
+ + + +
+[docs] +class CustomActorCriticShieldedAgileEOSPolicy(CustomActorCriticShieldedPolicy): +
+[docs] + def __init__( + self, + observation_space: gym.spaces.Space, + action_space: gym.spaces.Space, + lr_schedule: Callable[[float], float], + net_arch: Dict = None, + activation_fn: Type[nn.Module] = nn.Tanh, + *args, + **kwargs, + ): + # Create the shield + self.shield = shields.AgileEOSShield() + + super(CustomActorCriticShieldedAgileEOSPolicy, self).__init__( + observation_space, + action_space, + lr_schedule, + net_arch, + activation_fn, + # Pass remaining arguments to base class + *args, + **kwargs, + )
+
+ + + +
+[docs] +class CustomActorCriticShieldedMultiSensorEOSPolicy(CustomActorCriticShieldedPolicy): +
+[docs] + def __init__( + self, + observation_space: gym.spaces.Space, + action_space: gym.spaces.Space, + lr_schedule: Callable[[float], float], + net_arch: Dict = None, + activation_fn: Type[nn.Module] = nn.Tanh, + *args, + **kwargs, + ): + # Create the shield + self.shield = shields.MultiSensorEOSShield() + + super(CustomActorCriticShieldedMultiSensorEOSPolicy, self).__init__( + observation_space, + action_space, + lr_schedule, + net_arch, + activation_fn, + # Pass remaining arguments to base class + *args, + **kwargs, + )
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/bsk_rl/utilities/sb3/shields.html b/_modules/bsk_rl/utilities/sb3/shields.html new file mode 100644 index 00000000..0cfc3d42 --- /dev/null +++ b/_modules/bsk_rl/utilities/sb3/shields.html @@ -0,0 +1,206 @@ + + + + + + bsk_rl.utilities.sb3.shields — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for bsk_rl.utilities.sb3.shields

+import os
+
+import torch as th
+
+from bsk_rl.agents.state_machine import StateMachine
+
+abs_path = os.path.dirname(os.path.abspath(__file__))
+
+
+
+[docs] +class AgileEOSShield: + """Custom shield layer + :param: size_in -> input size, should be equal to the number of actions + :param: size_out -> output size, should be equal to the number of actions""" + +
+[docs] + def __init__(self): + self.state_machine = StateMachine() + self.state_machine.loadTransferConditions( + os.path.join(abs_path, "../state_machine/agile_eos_ops.adv") + )
+ + + def shield_actions(self, obs, actions): + batch_size = obs.shape[0] + new_actions = th.ones(batch_size, dtype=th.int32, device="cpu") + + for batch_num in range(0, batch_size): + # Define the state + s = obs[batch_num, :] + + # Pass the state to the shield + discretized_state = self.state_machine.SimpleEOSDiscretizer( + s.cpu().detach().numpy() + ) + + # Grab the action from the shield + shield_act = self.state_machine.selectAction(discretized_state) + + # If nominal state, only modify if we have a downlink window + if shield_act == 3: + # Downlink if data is in the buffer and a ground station is available + if (s[13] > 5e-5) and any(s[15:22]): + # Randomly choose between downlink and imaging + shield_act = th.randint(2, 4, [1]) + + # If the action is image, let the network do what it wants + if shield_act >= 3: + new_actions[batch_num] = actions[batch_num] + # If the action is not nominal, let the shield override + else: + new_actions[batch_num] = shield_act + + return new_actions
+ + + +
+[docs] +class MultiSensorEOSShield: + """Custom shield layer + :param: size_in -> input size, should be equal to the number of actions + :param: size_out -> output size, should be equal to the number of actions""" + +
+[docs] + def __init__(self): + self.state_machine = StateMachine() + self.state_machine.loadTransferConditions( + os.path.join(abs_path, "../state_machine/multisensor_eos_ops.adv") + )
+ + + def shield_actions(self, obs, actions): + batch_size = obs.shape[0] + new_actions = th.ones(batch_size, dtype=th.int32, device="cpu") + + for batch_num in range(0, batch_size): + # Define the state + s = obs[batch_num, :] + + # Pass the state to the shield + discretized_state = self.state_machine.earthObsEnvDiscretizer( + s.cpu().detach().numpy() + ) + + # Grab the action from the shield + shield_act = self.state_machine.selectAction(discretized_state) + + # If the action is image, let the network do what it wants + if shield_act >= 2: + new_actions[batch_num] = actions[batch_num] + # If the action is not nominal, let the shield override + else: + new_actions[batch_num] = shield_act + + return new_actions
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/examples/general_satellite_tasking/multisat_aeos.html b/_modules/examples/general_satellite_tasking/multisat_aeos.html new file mode 100644 index 00000000..9ab72b58 --- /dev/null +++ b/_modules/examples/general_satellite_tasking/multisat_aeos.html @@ -0,0 +1,232 @@ + + + + + + examples.general_satellite_tasking.multisat_aeos — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for examples.general_satellite_tasking.multisat_aeos

+"""
+Multisat AEOS
+=============
+
+some text here
+"""
+
+import gymnasium as gym
+import numpy as np
+
+from bsk_rl.envs.general_satellite_tasking.scenario import communication, data
+from bsk_rl.envs.general_satellite_tasking.scenario import satellites as sats
+from bsk_rl.envs.general_satellite_tasking.scenario.environment_features import (
+    CityTargets,
+)
+from bsk_rl.envs.general_satellite_tasking.simulation import environment
+from bsk_rl.utilities.initial_conditions import leo_orbit
+
+
+
+[docs] +def run(): + """Demonstrate the configuration of an environment with multiple imaging satellites.""" + # Data environment contains 5000 targets located near random cities, which are + # randomized on reset() + env_features = CityTargets(n_targets=500, location_offset=10e3) + # Data manager records and rewards uniquely imaged targets + data_manager = data.UniqueImagingManager(env_features) + + # Generate orbital parameters for each satellite in the constellation + oes = leo_orbit.walker_delta( + n_spacecraft=3, # Number of satellites + n_planes=1, + rel_phasing=0, + altitude=500 * 1e3, + inc=45, + clustersize=3, # Cluster all 3 satellites together + clusterspacing=30, # Space satellites by a true anomaly of 30 degrees + ) + + # Construct satellites of the FullFeaturedSatellite type + satellites = [] + sat_type = sats.FullFeaturedSatellite + for i, oe in enumerate(oes): + # Satellite configuration arguments are inferred from the satellite type. The + # function default_sat_args collects all of the parameters that must be set for FSW + # and dynamics in the Basilisk simulation. Any parameters that are to be overridden + # can be set as arguments to default_sat_args, and an error will be raised if the + # parameter is not valid for the satellite type. + + sat_args = sat_type.default_sat_args( + oe=oe, + imageAttErrorRequirement=0.01, # Change a default parameter + imageRateErrorRequirement=0.01, + # Parameters can also be set as a function that is called each time the + # environment is reset + panelEfficiency=lambda: 0.2 + np.random.uniform(-0.01, 0.01), + ) + + # As an example, look at the arguments for one of the satellites + if i == 0: + print(sat_args) + + # Instantiate the satellite object. Arguments to the satellite class are set here. + satellite = sat_type( + "EO" + str(i + 1), sat_args, n_ahead_observe=15, n_ahead_act=15 + ) + satellites.append(satellite) + + # Instantiate the communication method + communicator = communication.LOSMultiCommunication(satellites) + + # Make the environment with Gymnasium + env = gym.make( + "GeneralSatelliteTasking-v1", + satellites=satellites, + # Pick the type for the Basilisk environment model. Note that it is not instantiated + # here. + env_type=environment.GroundStationEnvModel, + # Like default_sat_args, default_env_args infers model parameters from the type and + # specific parameters can be overridden or randomized. + env_args=environment.GroundStationEnvModel.default_env_args(), + # Pass configuration objects + env_features=env_features, + data_manager=data_manager, + communicator=communicator, + # Integration frequency in seconds + sim_rate=0.5, + # Environment will be propagated by at most max_step_duration before needing new + # actions selected; however, some satellites will instead end the step when the + # current task is finished + max_step_duration=600.0, + # Set 3-orbit long episodes + time_limit=95 * 60, + log_level="INFO", + ) + + # Run the simulation until timeout or agent failure + total_reward = 0.0 + observation, info = env.reset() + + while True: + """ + Task random actions. Look at the set_action function for the chosen satellite type + to see what actions do. In this case, the action mapping is as follows: + - 0: charge + - 1: desaturate + - 2: downlink + - 3+: image the (n-3)th upcoming target + + """ + observation, reward, terminated, truncated, info = env.step( + env.action_space.sample() + ) + + total_reward += reward + print(f"\tReward: {reward:.3f} ({total_reward:.3f} cumulative)") + + if terminated or truncated: + print("Episode complete.") + break
+ + + +if __name__ == "__main__": + run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/examples/mcts/network_validation_multiprocessing.html b/_modules/examples/mcts/network_validation_multiprocessing.html new file mode 100644 index 00000000..96672806 --- /dev/null +++ b/_modules/examples/mcts/network_validation_multiprocessing.html @@ -0,0 +1,456 @@ + + + + + + examples.mcts.network_validation_multiprocessing — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for examples.mcts.network_validation_multiprocessing

+import os
+import time
+from multiprocessing import Manager, Process
+from pathlib import Path
+
+import gymnasium as gym
+import numpy as np
+
+from bsk_rl.envs.agile_eos.gym_env import AgileEOS  # noqa: F401; needed for gym
+
+os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
+
+SEP = os.path.sep
+
+
+
+[docs] +def modify_observation(obs, info, modified_states): + """This function modifies the observation from the environment if this is required. + :param obs: environment observation + :param info: info that may be add to the observation + :param modified states: a list of state indices to keep and dictionary keys + :return obs: modified observation + """ + # Loop through each element in modified_states + for idx3, elem in enumerate(modified_states): + # If its the first element, this is the array of indices to keep + if idx3 == 0: + obs = obs[elem] + # If it's not the first element, it's a dictionary key + else: + obs_to_add = info[elem].reshape(info[elem].size) + obs = np.concatenate((obs, obs_to_add)) + + return obs
+ + + +
+[docs] +def run_simulator( + network, + reward_specific, + success_specific, + downlink_util_specific, + exec_time_specific, + imaged_specific, + downlinked_specific, + modified_states, + ic, +): + """ + This function is utilized to a.) load the network, b.) run the network in the + environment, and c.) update performance metrics + :param network: File name of neural network + :param reward_specific: List of reward metrics + :param success_specific: List of success metrics + :param downlink_util_specific: List of downlink utilization metrics + :param exec_time_specific: List of execution time metrics + :param imaged_specific: List of image metric + :param downlinked_specific: List of downlinked metric + :param modified_states: List containing indices of states to keep and entries of + the info dictionary + :param ic: initial conditions + """ + + # Import keras here + import tensorflow.keras as keras + + # Create env + env = gym.make("AgileEOS-v0") + + # Set num steps, max length + tFinal = float(270) + numSteps = int(tFinal / (env.step_duration / 60.0)) + env.max_length = tFinal + env.max_steps = numSteps + + # Initialize action history + actHist = [] + + # Total reward + reward_sum = 0.0 + exec_time_sum = 0.0 + + # Reset the environment to initial conditions + ob, info = env.reset(options={"initial_conditions": ic}) + + # Load model + model = keras.models.load_model(network, custom_objects=None, compile=True) + + # Loop through each time step + for ind in range(0, numSteps): + # Start the clock + start = time.perf_counter() + + # Select action + action_value = model.predict(ob.reshape(1, -1)) + + # End the clock + end = time.perf_counter() + + # Add to exec_time + exec_time_sum += end - start + + # Select new action + act = np.argmax(action_value) + + # Append last action to action list + actHist.append(act) + + # Print out some information on the action and environment step + print("Actual Action Taken: ", act) + print("Real Environment Step: ", ind) + + # Take the step in the environment + ob, reward, episode_over, _, info = env.step(act) + + # Print reward + print("Reward: ", reward) + + # Sum the reward, add to rewards array + reward_sum = reward_sum + reward + + # If the episode is over, end the simulation + if episode_over: + print("episode over") + break + + # Pull the total access + total_access = env.simulator.total_access + + # Pull the utilized access + utilized_access = env.simulator.utilized_access + + # Update the performance metrics + reward_specific.append(reward_sum) + downlink_util_specific.append(100 * utilized_access / total_access) + exec_time_specific.append(exec_time_sum) + if env.simulator.simTime / 60 >= 270 and reward >= -0.00001: + success_specific.append(1) + else: + success_specific.append(0) + + # Update the number of imaged and downlinked performance metrics + num_imaged = 0 + num_downlinked = 0 + for idx in range(len(env.simulator.imaged_targets)): + if env.simulator.imaged_targets[idx] >= 1.0: + num_imaged += 1 + + if env.simulator.downlinked_targets[idx] >= 1.0: + num_downlinked += 1 + imaged_specific.append(num_imaged) + downlinked_specific.append(num_downlinked)
+ + + +def run_experiment(data_directory, ident, initial_conditions_list, N, batch_num): + # Load the network history + net_hist = np.load(data_directory + "/network_results.npy", allow_pickle=True) + # net_hist = net_hist.item() + print(net_hist) + + # Initialize lists for each metric + reward_master = [] + success_master = [] + downlink_util_master = [] + exec_time_master = [] + imaged_master = [] + downlinked_master = [] + + # Create master dictionary + data_master = {} + + # Initialize manager for creating lists + manager = Manager() + + # Initialize a dictionary for each model + models = {} + + # Initialize another results dictionary + results = {} + + # Load the networks + for count, filename in enumerate( + sorted(Path(data_directory + "/Networks/").iterdir(), key=os.path.getmtime), + start=0, + ): + print(str(filename)) + if "network" in str(filename): + print(count, filename) + models.update({count: filename}) + + # Loop through each model + for key, model in models.items(): + # Initialize lists for each metric using the manager + reward_specific = manager.list() + success_specific = manager.list() + downlink_util_specific = manager.list() + exec_time_specific = manager.list() + imaged_specific = manager.list() + downlinked_specific = manager.list() + + # Set the initial condition index + ic_idx = 0 + + # Loop through the batches + for j in range(batch_num): + # Initialize the lists of processes + processes = [] + + # Loop through N + for idx in range(0, N): + # Grab the initial condition + ic = initial_conditions_list[str(ic_idx)] + # ic = env.simulator.initial_conditions + ic_idx += 1 + # Append process to processes + processes.append( + Process( + target=run_simulator, + args=( + model, + reward_specific, + success_specific, + downlink_util_specific, + exec_time_specific, + imaged_specific, + downlinked_specific, + [], + ic, + ), + ) + ) + # Start each process + for idx in range(0, N): + processes[idx].start() + # Join each process + for process in processes: + process.join() + + # Append the specific data to the master metrics + reward_master.append(list(reward_specific)) + imaged_master.append(list(imaged_specific)) + downlinked_master.append(list(downlinked_specific)) + downlink_util_master.append(list(downlink_util_specific)) + exec_time_master.append(list(exec_time_specific)) + success_master.append(100 * np.average(success_specific)) + + # Update the master data dictionary with the metrics + data_master.update( + { + key: { + "reward": reward_master[-1], + "downlink": downlink_util_master[-1], + "exec_time": exec_time_master[-1], + "success": success_master[-1], + "downlinked": downlinked_master[-1], + "imaged": imaged_master[-1], + } + } + ) + + f_name = "network_" + str(key) + policy_kwargs = dict( + activation_fn=net_hist[key]["activation"], + net_arch={ + "width": net_hist[key]["net_size"], + "depth": net_hist[key]["hidden_layer_num"], + "dropout": net_hist[key]["dropout"], + "alpha": net_hist[key]["alpha"], + }, + ) + + # Update the master results + results.update( + { + f_name: { + "validation_reward": reward_master[-1], + "policy_kwargs": policy_kwargs, + "batch_size": net_hist[key]["batch_size"], + "n_epochs": net_hist[key]["epochs"], + } + } + ) + + # Print the averages of each metric + print("Averages: ") + for key, value in data_master.items(): + print( + key, + np.average(data_master[key]["reward"]), + np.average(data_master[key]["downlink"]), + np.average(data_master[key]["exec_time"]), + ) + + # Uncomment to save data + np.save(data_directory + "/validation_results_" + ident + ".npy", data_master) + np.save(data_directory + "/bar_plot_validation_results_" + ident + ".npy", results) + + +if __name__ == "__main__": + """This script is used to validate and benchmark trained networks for the + multiTgtEarthEnvironment in terms of average reward, downlink utilization, success, + and execution time. This implementation does utilize multi-processing. Before + running this script, ensure that agents have been trained and placed in the + 'data_directory.' Furthermore, be sure to specify a dictionary of initial + conditions. + + A bar plot of these validation results can be generated using the plotting tools + in `utilities/plotting_tools/` + """ + + # Set the data directory + data_directory = ( + ".." + + SEP + + ".." + + SEP + + "bsk_rl" + + SEP + + "results" + + SEP + + "mcts" + + SEP + + "AgileEOS" + + SEP + + "MCTS-Train Test" + + SEP + ) + + data_directory = str(Path(__file__).parent.resolve() / data_directory) + + # Set the number of simulations and number of batches + N = 10 + batch_num = 1 + + # Data identifier + ident = "benchmark_3_tgt" + + # Load initial conditions + initial_conditions_list = np.load( + str(Path(__file__).parent.resolve() / "initial_conditions.npy"), + allow_pickle=True, + ) + initial_conditions_list = initial_conditions_list.item() + + # Run the experiment + run_experiment(data_directory, ident, initial_conditions_list, N, batch_num) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/examples/plotting_tools/process_ga_curves.html b/_modules/examples/plotting_tools/process_ga_curves.html new file mode 100644 index 00000000..c5bf1ceb --- /dev/null +++ b/_modules/examples/plotting_tools/process_ga_curves.html @@ -0,0 +1,196 @@ + + + + + + examples.plotting_tools.process_ga_curves — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for examples.plotting_tools.process_ga_curves

+import os
+import pickle
+from pathlib import Path
+
+from deap import base, creator
+from matplotlib import pyplot as plt
+
+creator.create("FitnessMax", base.Fitness, weights=(1.0,))
+creator.create("Individual", list, fitness=creator.FitnessMax)
+
+SEP = os.path.sep
+
+
+
+[docs] +def process_ga_curve(run_dir, env_name): + """ + Generates plots of GA convergence, performance, and final population vector behavior + :param checkpoint_names: list of checkpoint names, assumed to be pickle files. + :return: + """ + # Pull data out of the pickles + gen_list = [] + min_reward = [] + max_reward = [] + mean_reward = [] + + # Find all of pkl files + n_gens = len([name for name in os.listdir(run_dir) if name.endswith(".pkl")]) + + checkpoint_names = [run_dir + env_name + f"_{gen}.pkl" for gen in range(1, n_gens)] + + for name in checkpoint_names: + with open(name, "rb") as file: + result = pickle.load(file) + gen_list.append(result["generation"]) + tmp_log = result["logbook"] + mean_reward.append(tmp_log[-1]["avg"]) + min_reward.append(tmp_log[-1]["min"]) + max_reward.append(tmp_log[-1]["max"]) + + fig, ax = plt.subplots(figsize=(7, 5)) + plt.plot(gen_list, mean_reward, label="Mean Reward") + plt.plot(gen_list, max_reward, label="Max Reward") + plt.plot(gen_list, min_reward, label="Min Reward", alpha=0.4) + plt.grid() + plt.ylabel("Reward", fontsize=16) + plt.xlabel("Generation", fontsize=16) + plt.ylim([-1, 1]) + plt.xticks(fontsize=12) + plt.yticks(fontsize=12) + plt.legend(fontsize=12) + plt.savefig( + run_dir + env_name + "_curve.pdf", + dpi=300, + pad_inches=0.1, + bbox_inches="tight", + transparent=True, + )
+ + + +if __name__ == "__main__": + # Define the directory + ga_dir = ( + ".." + + SEP + + ".." + + SEP + + "bsk_rl" + + SEP + + "results" + + SEP + + "GA" + + SEP + + "MultiSensorEOS-v0" + + SEP + + "GA Test" + + SEP + ) + ga_dir = str(Path(__file__).parent.resolve() / ga_dir) + + # Make a list of every folder in the directory + folders = os.listdir(ga_dir) + + # Loop through each folder + for folder in folders: + # Check if the folder is a directory + if os.path.isdir(ga_dir + SEP + folder): + process_ga_curve(ga_dir + SEP + folder + SEP, "MultiSensorEOS-v0") +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 00000000..d6d3c074 --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,145 @@ + + + + + + Overview: module code — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ +

All modules for which code is available

+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_sources/API Reference/agents/genetic_algorithm.rst.txt b/_sources/API Reference/agents/genetic_algorithm.rst.txt new file mode 100644 index 00000000..b28518f0 --- /dev/null +++ b/_sources/API Reference/agents/genetic_algorithm.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.agents.genetic_algorithm: + +genetic_algorithm +================= + +``bsk_rl.agents.genetic_algorithm`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.agents.genetic_algorithm + :members: + :show-inheritance: + diff --git a/_sources/API Reference/agents/index.rst.txt b/_sources/API Reference/agents/index.rst.txt new file mode 100644 index 00000000..83e17b12 --- /dev/null +++ b/_sources/API Reference/agents/index.rst.txt @@ -0,0 +1,25 @@ +.. _bsk_rl.agents: + +agents +====== + +``bsk_rl.agents`` + +.. automodule:: bsk_rl.agents + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + genetic_algorithm + mcts + state_machine + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/agents/mcts.rst.txt b/_sources/API Reference/agents/mcts.rst.txt new file mode 100644 index 00000000..9ba27f1c --- /dev/null +++ b/_sources/API Reference/agents/mcts.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.agents.mcts: + +mcts +==== + +``bsk_rl.agents.mcts`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.agents.mcts + :members: + :show-inheritance: + diff --git a/_sources/API Reference/agents/state_machine.rst.txt b/_sources/API Reference/agents/state_machine.rst.txt new file mode 100644 index 00000000..98bfba64 --- /dev/null +++ b/_sources/API Reference/agents/state_machine.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.agents.state_machine: + +state_machine +============= + +``bsk_rl.agents.state_machine`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.agents.state_machine + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/agile_eos/bsk_sim.rst.txt b/_sources/API Reference/envs/agile_eos/bsk_sim.rst.txt new file mode 100644 index 00000000..8ee0390a --- /dev/null +++ b/_sources/API Reference/envs/agile_eos/bsk_sim.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.agile_eos.bsk_sim: + +bsk_sim +======= + +``bsk_rl.envs.agile_eos.bsk_sim`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.agile_eos.bsk_sim + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/agile_eos/gym_env.rst.txt b/_sources/API Reference/envs/agile_eos/gym_env.rst.txt new file mode 100644 index 00000000..a439d871 --- /dev/null +++ b/_sources/API Reference/envs/agile_eos/gym_env.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.agile_eos.gym_env: + +gym_env +======= + +``bsk_rl.envs.agile_eos.gym_env`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.agile_eos.gym_env + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/agile_eos/index.rst.txt b/_sources/API Reference/envs/agile_eos/index.rst.txt new file mode 100644 index 00000000..ebf064e2 --- /dev/null +++ b/_sources/API Reference/envs/agile_eos/index.rst.txt @@ -0,0 +1,24 @@ +.. _bsk_rl.envs.agile_eos: + +agile_eos +========= + +``bsk_rl.envs.agile_eos`` + +.. automodule:: bsk_rl.envs.agile_eos + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + bsk_sim + gym_env + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/gym_env.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/gym_env.rst.txt new file mode 100644 index 00000000..45808778 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/gym_env.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.gym_env: + +gym_env +======= + +``bsk_rl.envs.general_satellite_tasking.gym_env`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.gym_env + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/index.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/index.rst.txt new file mode 100644 index 00000000..b69bf03f --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/index.rst.txt @@ -0,0 +1,27 @@ +.. _bsk_rl.envs.general_satellite_tasking: + +general_satellite_tasking +========================= + +``bsk_rl.envs.general_satellite_tasking`` + +.. automodule:: bsk_rl.envs.general_satellite_tasking + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + gym_env + types + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + + scenario/index + simulation/index + utils/index diff --git a/_sources/API Reference/envs/general_satellite_tasking/scenario/communication.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/scenario/communication.rst.txt new file mode 100644 index 00000000..e9a94095 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/scenario/communication.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.scenario.communication: + +communication +============= + +``bsk_rl.envs.general_satellite_tasking.scenario.communication`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.scenario.communication + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/scenario/data.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/scenario/data.rst.txt new file mode 100644 index 00000000..6c389af9 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/scenario/data.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.scenario.data: + +data +==== + +``bsk_rl.envs.general_satellite_tasking.scenario.data`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.scenario.data + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/scenario/environment_features.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/scenario/environment_features.rst.txt new file mode 100644 index 00000000..06484fd1 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/scenario/environment_features.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.scenario.environment_features: + +environment_features +==================== + +``bsk_rl.envs.general_satellite_tasking.scenario.environment_features`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.scenario.environment_features + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/scenario/index.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/scenario/index.rst.txt new file mode 100644 index 00000000..9baa1e2a --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/scenario/index.rst.txt @@ -0,0 +1,28 @@ +.. _bsk_rl.envs.general_satellite_tasking.scenario: + +scenario +======== + +``bsk_rl.envs.general_satellite_tasking.scenario`` + +.. automodule:: bsk_rl.envs.general_satellite_tasking.scenario + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + communication + data + environment_features + sat_actions + sat_observations + satellites + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/scenario/sat_actions.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/scenario/sat_actions.rst.txt new file mode 100644 index 00000000..b25d38a1 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/scenario/sat_actions.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.scenario.sat_actions: + +sat_actions +=========== + +``bsk_rl.envs.general_satellite_tasking.scenario.sat_actions`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.scenario.sat_actions + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/scenario/sat_observations.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/scenario/sat_observations.rst.txt new file mode 100644 index 00000000..03170d8b --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/scenario/sat_observations.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.scenario.sat_observations: + +sat_observations +================ + +``bsk_rl.envs.general_satellite_tasking.scenario.sat_observations`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.scenario.sat_observations + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/scenario/satellites.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/scenario/satellites.rst.txt new file mode 100644 index 00000000..94695658 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/scenario/satellites.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.scenario.satellites: + +satellites +========== + +``bsk_rl.envs.general_satellite_tasking.scenario.satellites`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.scenario.satellites + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/simulation/dynamics.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/simulation/dynamics.rst.txt new file mode 100644 index 00000000..4132054d --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/simulation/dynamics.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.simulation.dynamics: + +dynamics +======== + +``bsk_rl.envs.general_satellite_tasking.simulation.dynamics`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.simulation.dynamics + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/simulation/environment.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/simulation/environment.rst.txt new file mode 100644 index 00000000..e932d2bf --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/simulation/environment.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.simulation.environment: + +environment +=========== + +``bsk_rl.envs.general_satellite_tasking.simulation.environment`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.simulation.environment + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/simulation/fsw.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/simulation/fsw.rst.txt new file mode 100644 index 00000000..4f39ead4 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/simulation/fsw.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.simulation.fsw: + +fsw +=== + +``bsk_rl.envs.general_satellite_tasking.simulation.fsw`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.simulation.fsw + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/simulation/index.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/simulation/index.rst.txt new file mode 100644 index 00000000..76def5a3 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/simulation/index.rst.txt @@ -0,0 +1,26 @@ +.. _bsk_rl.envs.general_satellite_tasking.simulation: + +simulation +========== + +``bsk_rl.envs.general_satellite_tasking.simulation`` + +.. automodule:: bsk_rl.envs.general_satellite_tasking.simulation + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + dynamics + environment + fsw + simulator + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/simulation/simulator.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/simulation/simulator.rst.txt new file mode 100644 index 00000000..071d9289 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/simulation/simulator.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.simulation.simulator: + +simulator +========= + +``bsk_rl.envs.general_satellite_tasking.simulation.simulator`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.simulation.simulator + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/types.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/types.rst.txt new file mode 100644 index 00000000..e0deab27 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/types.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.types: + +types +===== + +``bsk_rl.envs.general_satellite_tasking.types`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.types + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/utils/functional.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/utils/functional.rst.txt new file mode 100644 index 00000000..a6abf246 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/utils/functional.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.utils.functional: + +functional +========== + +``bsk_rl.envs.general_satellite_tasking.utils.functional`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.utils.functional + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/utils/index.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/utils/index.rst.txt new file mode 100644 index 00000000..3e01391f --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/utils/index.rst.txt @@ -0,0 +1,25 @@ +.. _bsk_rl.envs.general_satellite_tasking.utils: + +utils +===== + +``bsk_rl.envs.general_satellite_tasking.utils`` + +.. automodule:: bsk_rl.envs.general_satellite_tasking.utils + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + functional + logging_config + orbital + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/utils/logging_config.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/utils/logging_config.rst.txt new file mode 100644 index 00000000..159a1841 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/utils/logging_config.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.utils.logging_config: + +logging_config +============== + +``bsk_rl.envs.general_satellite_tasking.utils.logging_config`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.utils.logging_config + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/general_satellite_tasking/utils/orbital.rst.txt b/_sources/API Reference/envs/general_satellite_tasking/utils/orbital.rst.txt new file mode 100644 index 00000000..bfd99420 --- /dev/null +++ b/_sources/API Reference/envs/general_satellite_tasking/utils/orbital.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.general_satellite_tasking.utils.orbital: + +orbital +======= + +``bsk_rl.envs.general_satellite_tasking.utils.orbital`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.general_satellite_tasking.utils.orbital + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/index.rst.txt b/_sources/API Reference/envs/index.rst.txt new file mode 100644 index 00000000..f880c844 --- /dev/null +++ b/_sources/API Reference/envs/index.rst.txt @@ -0,0 +1,29 @@ +.. _bsk_rl.envs: + +envs +==== + +``bsk_rl.envs`` + +.. automodule:: bsk_rl.envs + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + + agile_eos/index + general_satellite_tasking/index + multisat_agile_eos/index + multisensor_eos/index + simple_eos/index + small_body_science/index + small_body_science_pomdp/index diff --git a/_sources/API Reference/envs/multisat_agile_eos/bsk_models/dynamics.rst.txt b/_sources/API Reference/envs/multisat_agile_eos/bsk_models/dynamics.rst.txt new file mode 100644 index 00000000..b6e04c49 --- /dev/null +++ b/_sources/API Reference/envs/multisat_agile_eos/bsk_models/dynamics.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics: + +dynamics +======== + +``bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/multisat_agile_eos/bsk_models/environment.rst.txt b/_sources/API Reference/envs/multisat_agile_eos/bsk_models/environment.rst.txt new file mode 100644 index 00000000..15807709 --- /dev/null +++ b/_sources/API Reference/envs/multisat_agile_eos/bsk_models/environment.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.multisat_agile_eos.bsk_models.environment: + +environment +=========== + +``bsk_rl.envs.multisat_agile_eos.bsk_models.environment`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.multisat_agile_eos.bsk_models.environment + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/multisat_agile_eos/bsk_models/fsw.rst.txt b/_sources/API Reference/envs/multisat_agile_eos/bsk_models/fsw.rst.txt new file mode 100644 index 00000000..ee715822 --- /dev/null +++ b/_sources/API Reference/envs/multisat_agile_eos/bsk_models/fsw.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.multisat_agile_eos.bsk_models.fsw: + +fsw +=== + +``bsk_rl.envs.multisat_agile_eos.bsk_models.fsw`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.multisat_agile_eos.bsk_models.fsw + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/multisat_agile_eos/bsk_models/fsw_steering.rst.txt b/_sources/API Reference/envs/multisat_agile_eos/bsk_models/fsw_steering.rst.txt new file mode 100644 index 00000000..3cf78cf7 --- /dev/null +++ b/_sources/API Reference/envs/multisat_agile_eos/bsk_models/fsw_steering.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering: + +fsw_steering +============ + +``bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/multisat_agile_eos/bsk_models/index.rst.txt b/_sources/API Reference/envs/multisat_agile_eos/bsk_models/index.rst.txt new file mode 100644 index 00000000..35b4630d --- /dev/null +++ b/_sources/API Reference/envs/multisat_agile_eos/bsk_models/index.rst.txt @@ -0,0 +1,26 @@ +.. _bsk_rl.envs.multisat_agile_eos.bsk_models: + +bsk_models +========== + +``bsk_rl.envs.multisat_agile_eos.bsk_models`` + +.. automodule:: bsk_rl.envs.multisat_agile_eos.bsk_models + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + dynamics + environment + fsw + fsw_steering + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/envs/multisat_agile_eos/bsk_sim.rst.txt b/_sources/API Reference/envs/multisat_agile_eos/bsk_sim.rst.txt new file mode 100644 index 00000000..2f4afcb5 --- /dev/null +++ b/_sources/API Reference/envs/multisat_agile_eos/bsk_sim.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.multisat_agile_eos.bsk_sim: + +bsk_sim +======= + +``bsk_rl.envs.multisat_agile_eos.bsk_sim`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.multisat_agile_eos.bsk_sim + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/multisat_agile_eos/env_settings.rst.txt b/_sources/API Reference/envs/multisat_agile_eos/env_settings.rst.txt new file mode 100644 index 00000000..3b75cfea --- /dev/null +++ b/_sources/API Reference/envs/multisat_agile_eos/env_settings.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.multisat_agile_eos.env_settings: + +env_settings +============ + +``bsk_rl.envs.multisat_agile_eos.env_settings`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.multisat_agile_eos.env_settings + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/multisat_agile_eos/gym_env.rst.txt b/_sources/API Reference/envs/multisat_agile_eos/gym_env.rst.txt new file mode 100644 index 00000000..6c5fac17 --- /dev/null +++ b/_sources/API Reference/envs/multisat_agile_eos/gym_env.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.multisat_agile_eos.gym_env: + +gym_env +======= + +``bsk_rl.envs.multisat_agile_eos.gym_env`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.multisat_agile_eos.gym_env + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/multisat_agile_eos/index.rst.txt b/_sources/API Reference/envs/multisat_agile_eos/index.rst.txt new file mode 100644 index 00000000..900084eb --- /dev/null +++ b/_sources/API Reference/envs/multisat_agile_eos/index.rst.txt @@ -0,0 +1,26 @@ +.. _bsk_rl.envs.multisat_agile_eos: + +multisat_agile_eos +================== + +``bsk_rl.envs.multisat_agile_eos`` + +.. automodule:: bsk_rl.envs.multisat_agile_eos + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + bsk_sim + env_settings + gym_env + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + + bsk_models/index diff --git a/_sources/API Reference/envs/multisensor_eos/bsk_sim.rst.txt b/_sources/API Reference/envs/multisensor_eos/bsk_sim.rst.txt new file mode 100644 index 00000000..1db8c462 --- /dev/null +++ b/_sources/API Reference/envs/multisensor_eos/bsk_sim.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.multisensor_eos.bsk_sim: + +bsk_sim +======= + +``bsk_rl.envs.multisensor_eos.bsk_sim`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.multisensor_eos.bsk_sim + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/multisensor_eos/env_settings.rst.txt b/_sources/API Reference/envs/multisensor_eos/env_settings.rst.txt new file mode 100644 index 00000000..190e65d8 --- /dev/null +++ b/_sources/API Reference/envs/multisensor_eos/env_settings.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.multisensor_eos.env_settings: + +env_settings +============ + +``bsk_rl.envs.multisensor_eos.env_settings`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.multisensor_eos.env_settings + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/multisensor_eos/gym_env.rst.txt b/_sources/API Reference/envs/multisensor_eos/gym_env.rst.txt new file mode 100644 index 00000000..060ea7a8 --- /dev/null +++ b/_sources/API Reference/envs/multisensor_eos/gym_env.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.multisensor_eos.gym_env: + +gym_env +======= + +``bsk_rl.envs.multisensor_eos.gym_env`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.multisensor_eos.gym_env + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/multisensor_eos/index.rst.txt b/_sources/API Reference/envs/multisensor_eos/index.rst.txt new file mode 100644 index 00000000..e216e10f --- /dev/null +++ b/_sources/API Reference/envs/multisensor_eos/index.rst.txt @@ -0,0 +1,25 @@ +.. _bsk_rl.envs.multisensor_eos: + +multisensor_eos +=============== + +``bsk_rl.envs.multisensor_eos`` + +.. automodule:: bsk_rl.envs.multisensor_eos + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + bsk_sim + env_settings + gym_env + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/envs/simple_eos/bsk_sim.rst.txt b/_sources/API Reference/envs/simple_eos/bsk_sim.rst.txt new file mode 100644 index 00000000..9871856d --- /dev/null +++ b/_sources/API Reference/envs/simple_eos/bsk_sim.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.simple_eos.bsk_sim: + +bsk_sim +======= + +``bsk_rl.envs.simple_eos.bsk_sim`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.simple_eos.bsk_sim + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/simple_eos/gym_env.rst.txt b/_sources/API Reference/envs/simple_eos/gym_env.rst.txt new file mode 100644 index 00000000..384ae35b --- /dev/null +++ b/_sources/API Reference/envs/simple_eos/gym_env.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.simple_eos.gym_env: + +gym_env +======= + +``bsk_rl.envs.simple_eos.gym_env`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.simple_eos.gym_env + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/simple_eos/index.rst.txt b/_sources/API Reference/envs/simple_eos/index.rst.txt new file mode 100644 index 00000000..493b6019 --- /dev/null +++ b/_sources/API Reference/envs/simple_eos/index.rst.txt @@ -0,0 +1,24 @@ +.. _bsk_rl.envs.simple_eos: + +simple_eos +========== + +``bsk_rl.envs.simple_eos`` + +.. automodule:: bsk_rl.envs.simple_eos + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + bsk_sim + gym_env + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/envs/small_body_science/bsk_sim.rst.txt b/_sources/API Reference/envs/small_body_science/bsk_sim.rst.txt new file mode 100644 index 00000000..d6b4fbb5 --- /dev/null +++ b/_sources/API Reference/envs/small_body_science/bsk_sim.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.small_body_science.bsk_sim: + +bsk_sim +======= + +``bsk_rl.envs.small_body_science.bsk_sim`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.small_body_science.bsk_sim + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/small_body_science/gym_env.rst.txt b/_sources/API Reference/envs/small_body_science/gym_env.rst.txt new file mode 100644 index 00000000..5dd4a100 --- /dev/null +++ b/_sources/API Reference/envs/small_body_science/gym_env.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.small_body_science.gym_env: + +gym_env +======= + +``bsk_rl.envs.small_body_science.gym_env`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.small_body_science.gym_env + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/small_body_science/index.rst.txt b/_sources/API Reference/envs/small_body_science/index.rst.txt new file mode 100644 index 00000000..1aeed812 --- /dev/null +++ b/_sources/API Reference/envs/small_body_science/index.rst.txt @@ -0,0 +1,24 @@ +.. _bsk_rl.envs.small_body_science: + +small_body_science +================== + +``bsk_rl.envs.small_body_science`` + +.. automodule:: bsk_rl.envs.small_body_science + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + bsk_sim + gym_env + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/envs/small_body_science_pomdp/bsk_sim.rst.txt b/_sources/API Reference/envs/small_body_science_pomdp/bsk_sim.rst.txt new file mode 100644 index 00000000..7fc8cde7 --- /dev/null +++ b/_sources/API Reference/envs/small_body_science_pomdp/bsk_sim.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.small_body_science_pomdp.bsk_sim: + +bsk_sim +======= + +``bsk_rl.envs.small_body_science_pomdp.bsk_sim`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.small_body_science_pomdp.bsk_sim + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/small_body_science_pomdp/gym_env.rst.txt b/_sources/API Reference/envs/small_body_science_pomdp/gym_env.rst.txt new file mode 100644 index 00000000..b66eafe2 --- /dev/null +++ b/_sources/API Reference/envs/small_body_science_pomdp/gym_env.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.envs.small_body_science_pomdp.gym_env: + +gym_env +======= + +``bsk_rl.envs.small_body_science_pomdp.gym_env`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.envs.small_body_science_pomdp.gym_env + :members: + :show-inheritance: + diff --git a/_sources/API Reference/envs/small_body_science_pomdp/index.rst.txt b/_sources/API Reference/envs/small_body_science_pomdp/index.rst.txt new file mode 100644 index 00000000..8505ce86 --- /dev/null +++ b/_sources/API Reference/envs/small_body_science_pomdp/index.rst.txt @@ -0,0 +1,24 @@ +.. _bsk_rl.envs.small_body_science_pomdp: + +small_body_science_pomdp +======================== + +``bsk_rl.envs.small_body_science_pomdp`` + +.. automodule:: bsk_rl.envs.small_body_science_pomdp + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + bsk_sim + gym_env + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/index.rst.txt b/_sources/API Reference/index.rst.txt new file mode 100644 index 00000000..10b61a1b --- /dev/null +++ b/_sources/API Reference/index.rst.txt @@ -0,0 +1,26 @@ +.. _bsk_rl: + +API Reference +============= + +``bsk_rl`` + +.. automodule:: bsk_rl + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + + agents/index + envs/index + training/index + utilities/index diff --git a/_sources/API Reference/training/index.rst.txt b/_sources/API Reference/training/index.rst.txt new file mode 100644 index 00000000..125bf341 --- /dev/null +++ b/_sources/API Reference/training/index.rst.txt @@ -0,0 +1,24 @@ +.. _bsk_rl.training: + +training +======== + +``bsk_rl.training`` + +.. automodule:: bsk_rl.training + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + + mcts/index + sb3/index diff --git a/_sources/API Reference/training/mcts/index.rst.txt b/_sources/API Reference/training/mcts/index.rst.txt new file mode 100644 index 00000000..16353610 --- /dev/null +++ b/_sources/API Reference/training/mcts/index.rst.txt @@ -0,0 +1,23 @@ +.. _bsk_rl.training.mcts: + +mcts +==== + +``bsk_rl.training.mcts`` + +.. automodule:: bsk_rl.training.mcts + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + mcts_train + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/training/mcts/mcts_train.rst.txt b/_sources/API Reference/training/mcts/mcts_train.rst.txt new file mode 100644 index 00000000..06faf7d6 --- /dev/null +++ b/_sources/API Reference/training/mcts/mcts_train.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.training.mcts.mcts_train: + +mcts_train +========== + +``bsk_rl.training.mcts.mcts_train`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.training.mcts.mcts_train + :members: + :show-inheritance: + diff --git a/_sources/API Reference/training/sb3/experiments.rst.txt b/_sources/API Reference/training/sb3/experiments.rst.txt new file mode 100644 index 00000000..c0e39400 --- /dev/null +++ b/_sources/API Reference/training/sb3/experiments.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.training.sb3.experiments: + +experiments +=========== + +``bsk_rl.training.sb3.experiments`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.training.sb3.experiments + :members: + :show-inheritance: + diff --git a/_sources/API Reference/training/sb3/index.rst.txt b/_sources/API Reference/training/sb3/index.rst.txt new file mode 100644 index 00000000..d482c2cc --- /dev/null +++ b/_sources/API Reference/training/sb3/index.rst.txt @@ -0,0 +1,23 @@ +.. _bsk_rl.training.sb3: + +sb3 +=== + +``bsk_rl.training.sb3`` + +.. automodule:: bsk_rl.training.sb3 + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + experiments + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/utilities/effector_primitives/actuator_primitives.rst.txt b/_sources/API Reference/utilities/effector_primitives/actuator_primitives.rst.txt new file mode 100644 index 00000000..75a484f5 --- /dev/null +++ b/_sources/API Reference/utilities/effector_primitives/actuator_primitives.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.utilities.effector_primitives.actuator_primitives: + +actuator_primitives +=================== + +``bsk_rl.utilities.effector_primitives.actuator_primitives`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.utilities.effector_primitives.actuator_primitives + :members: + :show-inheritance: + diff --git a/_sources/API Reference/utilities/effector_primitives/index.rst.txt b/_sources/API Reference/utilities/effector_primitives/index.rst.txt new file mode 100644 index 00000000..bf9476b1 --- /dev/null +++ b/_sources/API Reference/utilities/effector_primitives/index.rst.txt @@ -0,0 +1,23 @@ +.. _bsk_rl.utilities.effector_primitives: + +effector_primitives +=================== + +``bsk_rl.utilities.effector_primitives`` + +.. automodule:: bsk_rl.utilities.effector_primitives + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + actuator_primitives + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/utilities/genetic_algorithm/experiments.rst.txt b/_sources/API Reference/utilities/genetic_algorithm/experiments.rst.txt new file mode 100644 index 00000000..c147cee6 --- /dev/null +++ b/_sources/API Reference/utilities/genetic_algorithm/experiments.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.utilities.genetic_algorithm.experiments: + +experiments +=========== + +``bsk_rl.utilities.genetic_algorithm.experiments`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.utilities.genetic_algorithm.experiments + :members: + :show-inheritance: + diff --git a/_sources/API Reference/utilities/genetic_algorithm/index.rst.txt b/_sources/API Reference/utilities/genetic_algorithm/index.rst.txt new file mode 100644 index 00000000..1a6fe8c8 --- /dev/null +++ b/_sources/API Reference/utilities/genetic_algorithm/index.rst.txt @@ -0,0 +1,23 @@ +.. _bsk_rl.utilities.genetic_algorithm: + +genetic_algorithm +================= + +``bsk_rl.utilities.genetic_algorithm`` + +.. automodule:: bsk_rl.utilities.genetic_algorithm + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + experiments + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/utilities/index.rst.txt b/_sources/API Reference/utilities/index.rst.txt new file mode 100644 index 00000000..866cc4f2 --- /dev/null +++ b/_sources/API Reference/utilities/index.rst.txt @@ -0,0 +1,28 @@ +.. _bsk_rl.utilities: + +utilities +========= + +``bsk_rl.utilities`` + +.. automodule:: bsk_rl.utilities + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + + effector_primitives/index + genetic_algorithm/index + initial_conditions/index + mcts/index + sb3/index + state_machine/index diff --git a/_sources/API Reference/utilities/initial_conditions/index.rst.txt b/_sources/API Reference/utilities/initial_conditions/index.rst.txt new file mode 100644 index 00000000..5026a537 --- /dev/null +++ b/_sources/API Reference/utilities/initial_conditions/index.rst.txt @@ -0,0 +1,26 @@ +.. _bsk_rl.utilities.initial_conditions: + +initial_conditions +================== + +``bsk_rl.utilities.initial_conditions`` + +.. automodule:: bsk_rl.utilities.initial_conditions + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + leo_initial_conditions + leo_orbit + sc_attitudes + small_body + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/utilities/initial_conditions/leo_initial_conditions.rst.txt b/_sources/API Reference/utilities/initial_conditions/leo_initial_conditions.rst.txt new file mode 100644 index 00000000..671d832b --- /dev/null +++ b/_sources/API Reference/utilities/initial_conditions/leo_initial_conditions.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.utilities.initial_conditions.leo_initial_conditions: + +leo_initial_conditions +====================== + +``bsk_rl.utilities.initial_conditions.leo_initial_conditions`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.utilities.initial_conditions.leo_initial_conditions + :members: + :show-inheritance: + diff --git a/_sources/API Reference/utilities/initial_conditions/leo_orbit.rst.txt b/_sources/API Reference/utilities/initial_conditions/leo_orbit.rst.txt new file mode 100644 index 00000000..151caf46 --- /dev/null +++ b/_sources/API Reference/utilities/initial_conditions/leo_orbit.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.utilities.initial_conditions.leo_orbit: + +leo_orbit +========= + +``bsk_rl.utilities.initial_conditions.leo_orbit`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.utilities.initial_conditions.leo_orbit + :members: + :show-inheritance: + diff --git a/_sources/API Reference/utilities/initial_conditions/sc_attitudes.rst.txt b/_sources/API Reference/utilities/initial_conditions/sc_attitudes.rst.txt new file mode 100644 index 00000000..5c8daf35 --- /dev/null +++ b/_sources/API Reference/utilities/initial_conditions/sc_attitudes.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.utilities.initial_conditions.sc_attitudes: + +sc_attitudes +============ + +``bsk_rl.utilities.initial_conditions.sc_attitudes`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.utilities.initial_conditions.sc_attitudes + :members: + :show-inheritance: + diff --git a/_sources/API Reference/utilities/initial_conditions/small_body.rst.txt b/_sources/API Reference/utilities/initial_conditions/small_body.rst.txt new file mode 100644 index 00000000..5c68ba88 --- /dev/null +++ b/_sources/API Reference/utilities/initial_conditions/small_body.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.utilities.initial_conditions.small_body: + +small_body +========== + +``bsk_rl.utilities.initial_conditions.small_body`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.utilities.initial_conditions.small_body + :members: + :show-inheritance: + diff --git a/_sources/API Reference/utilities/mcts/index.rst.txt b/_sources/API Reference/utilities/mcts/index.rst.txt new file mode 100644 index 00000000..2668b514 --- /dev/null +++ b/_sources/API Reference/utilities/mcts/index.rst.txt @@ -0,0 +1,23 @@ +.. _bsk_rl.utilities.mcts: + +mcts +==== + +``bsk_rl.utilities.mcts`` + +.. automodule:: bsk_rl.utilities.mcts + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + rollout_policies + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/utilities/mcts/rollout_policies.rst.txt b/_sources/API Reference/utilities/mcts/rollout_policies.rst.txt new file mode 100644 index 00000000..c397614f --- /dev/null +++ b/_sources/API Reference/utilities/mcts/rollout_policies.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.utilities.mcts.rollout_policies: + +rollout_policies +================ + +``bsk_rl.utilities.mcts.rollout_policies`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.utilities.mcts.rollout_policies + :members: + :show-inheritance: + diff --git a/_sources/API Reference/utilities/sb3/custom_sb3_policies.rst.txt b/_sources/API Reference/utilities/sb3/custom_sb3_policies.rst.txt new file mode 100644 index 00000000..c20c306c --- /dev/null +++ b/_sources/API Reference/utilities/sb3/custom_sb3_policies.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.utilities.sb3.custom_sb3_policies: + +custom_sb3_policies +=================== + +``bsk_rl.utilities.sb3.custom_sb3_policies`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.utilities.sb3.custom_sb3_policies + :members: + :show-inheritance: + diff --git a/_sources/API Reference/utilities/sb3/index.rst.txt b/_sources/API Reference/utilities/sb3/index.rst.txt new file mode 100644 index 00000000..66159bf9 --- /dev/null +++ b/_sources/API Reference/utilities/sb3/index.rst.txt @@ -0,0 +1,25 @@ +.. _bsk_rl.utilities.sb3: + +sb3 +=== + +``bsk_rl.utilities.sb3`` + +.. automodule:: bsk_rl.utilities.sb3 + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + custom_sb3_policies + shielded_policies + shields + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/API Reference/utilities/sb3/shielded_policies.rst.txt b/_sources/API Reference/utilities/sb3/shielded_policies.rst.txt new file mode 100644 index 00000000..f49e7407 --- /dev/null +++ b/_sources/API Reference/utilities/sb3/shielded_policies.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.utilities.sb3.shielded_policies: + +shielded_policies +================= + +``bsk_rl.utilities.sb3.shielded_policies`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.utilities.sb3.shielded_policies + :members: + :show-inheritance: + diff --git a/_sources/API Reference/utilities/sb3/shields.rst.txt b/_sources/API Reference/utilities/sb3/shields.rst.txt new file mode 100644 index 00000000..02c9c842 --- /dev/null +++ b/_sources/API Reference/utilities/sb3/shields.rst.txt @@ -0,0 +1,15 @@ +.. _bsk_rl.utilities.sb3.shields: + +shields +======= + +``bsk_rl.utilities.sb3.shields`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: bsk_rl.utilities.sb3.shields + :members: + :show-inheritance: + diff --git a/_sources/API Reference/utilities/state_machine/index.rst.txt b/_sources/API Reference/utilities/state_machine/index.rst.txt new file mode 100644 index 00000000..6ed55ecd --- /dev/null +++ b/_sources/API Reference/utilities/state_machine/index.rst.txt @@ -0,0 +1,22 @@ +.. _bsk_rl.utilities.state_machine: + +state_machine +============= + +``bsk_rl.utilities.state_machine`` + +.. automodule:: bsk_rl.utilities.state_machine + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/Examples/general_satellite_tasking/index.rst.txt b/_sources/Examples/general_satellite_tasking/index.rst.txt new file mode 100644 index 00000000..ab98b4a7 --- /dev/null +++ b/_sources/Examples/general_satellite_tasking/index.rst.txt @@ -0,0 +1,25 @@ +.. _examples.general_satellite_tasking: + +general_satellite_tasking +========================= + +``examples.general_satellite_tasking`` + +.. automodule:: examples.general_satellite_tasking + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + multisat_aeos + satellite_customization + single_sat + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/Examples/general_satellite_tasking/multisat_aeos.rst.txt b/_sources/Examples/general_satellite_tasking/multisat_aeos.rst.txt new file mode 100644 index 00000000..7c0a256a --- /dev/null +++ b/_sources/Examples/general_satellite_tasking/multisat_aeos.rst.txt @@ -0,0 +1,15 @@ +.. _examples.general_satellite_tasking.multisat_aeos: + +multisat_aeos +============= + +``examples.general_satellite_tasking.multisat_aeos`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.general_satellite_tasking.multisat_aeos + :members: + :show-inheritance: + diff --git a/_sources/Examples/general_satellite_tasking/satellite_customization.rst.txt b/_sources/Examples/general_satellite_tasking/satellite_customization.rst.txt new file mode 100644 index 00000000..9ea73bcd --- /dev/null +++ b/_sources/Examples/general_satellite_tasking/satellite_customization.rst.txt @@ -0,0 +1,15 @@ +.. _examples.general_satellite_tasking.satellite_customization: + +satellite_customization +======================= + +``examples.general_satellite_tasking.satellite_customization`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.general_satellite_tasking.satellite_customization + :members: + :show-inheritance: + diff --git a/_sources/Examples/general_satellite_tasking/single_sat.rst.txt b/_sources/Examples/general_satellite_tasking/single_sat.rst.txt new file mode 100644 index 00000000..60e55ad3 --- /dev/null +++ b/_sources/Examples/general_satellite_tasking/single_sat.rst.txt @@ -0,0 +1,15 @@ +.. _examples.general_satellite_tasking.single_sat: + +single_sat +========== + +``examples.general_satellite_tasking.single_sat`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.general_satellite_tasking.single_sat + :members: + :show-inheritance: + diff --git a/_sources/Examples/genetic_algorithm/ga_hp_solver.rst.txt b/_sources/Examples/genetic_algorithm/ga_hp_solver.rst.txt new file mode 100644 index 00000000..f0e7616e --- /dev/null +++ b/_sources/Examples/genetic_algorithm/ga_hp_solver.rst.txt @@ -0,0 +1,15 @@ +.. _examples.genetic_algorithm.ga_hp_solver: + +ga_hp_solver +============ + +``examples.genetic_algorithm.ga_hp_solver`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.genetic_algorithm.ga_hp_solver + :members: + :show-inheritance: + diff --git a/_sources/Examples/genetic_algorithm/index.rst.txt b/_sources/Examples/genetic_algorithm/index.rst.txt new file mode 100644 index 00000000..80a4c2c6 --- /dev/null +++ b/_sources/Examples/genetic_algorithm/index.rst.txt @@ -0,0 +1,23 @@ +.. _examples.genetic_algorithm: + +genetic_algorithm +================= + +``examples.genetic_algorithm`` + +.. automodule:: examples.genetic_algorithm + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + ga_hp_solver + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/Examples/index.rst.txt b/_sources/Examples/index.rst.txt new file mode 100644 index 00000000..0c90e303 --- /dev/null +++ b/_sources/Examples/index.rst.txt @@ -0,0 +1,28 @@ +.. _examples: + +Examples +======== + +``examples`` + +.. automodule:: examples + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + + general_satellite_tasking/index + genetic_algorithm/index + mcts/index + plotting_tools/index + sb3/index + state_machine/index diff --git a/_sources/Examples/mcts/index.rst.txt b/_sources/Examples/mcts/index.rst.txt new file mode 100644 index 00000000..bf08fada --- /dev/null +++ b/_sources/Examples/mcts/index.rst.txt @@ -0,0 +1,25 @@ +.. _examples.mcts: + +mcts +==== + +``examples.mcts`` + +.. automodule:: examples.mcts + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + mcts_data_generator + network_hyperparam_search + network_validation_multiprocessing + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/Examples/mcts/mcts_data_generator.rst.txt b/_sources/Examples/mcts/mcts_data_generator.rst.txt new file mode 100644 index 00000000..94e91faa --- /dev/null +++ b/_sources/Examples/mcts/mcts_data_generator.rst.txt @@ -0,0 +1,15 @@ +.. _examples.mcts.mcts_data_generator: + +mcts_data_generator +=================== + +``examples.mcts.mcts_data_generator`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.mcts.mcts_data_generator + :members: + :show-inheritance: + diff --git a/_sources/Examples/mcts/network_hyperparam_search.rst.txt b/_sources/Examples/mcts/network_hyperparam_search.rst.txt new file mode 100644 index 00000000..0cb5fa0d --- /dev/null +++ b/_sources/Examples/mcts/network_hyperparam_search.rst.txt @@ -0,0 +1,15 @@ +.. _examples.mcts.network_hyperparam_search: + +network_hyperparam_search +========================= + +``examples.mcts.network_hyperparam_search`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.mcts.network_hyperparam_search + :members: + :show-inheritance: + diff --git a/_sources/Examples/mcts/network_validation_multiprocessing.rst.txt b/_sources/Examples/mcts/network_validation_multiprocessing.rst.txt new file mode 100644 index 00000000..27d7c1aa --- /dev/null +++ b/_sources/Examples/mcts/network_validation_multiprocessing.rst.txt @@ -0,0 +1,15 @@ +.. _examples.mcts.network_validation_multiprocessing: + +network_validation_multiprocessing +================================== + +``examples.mcts.network_validation_multiprocessing`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.mcts.network_validation_multiprocessing + :members: + :show-inheritance: + diff --git a/_sources/Examples/plotting_tools/index.rst.txt b/_sources/Examples/plotting_tools/index.rst.txt new file mode 100644 index 00000000..6350320e --- /dev/null +++ b/_sources/Examples/plotting_tools/index.rst.txt @@ -0,0 +1,29 @@ +.. _examples.plotting_tools: + +plotting_tools +============== + +``examples.plotting_tools`` + +.. automodule:: examples.plotting_tools + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + plot_a2c_hyperparams + plot_dqn_hyperparams + plot_ga_hyperparams + plot_mcts_hyperparams + plot_ppo_hyperparams + process_ga_curves + process_sb3_curves + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/Examples/plotting_tools/plot_a2c_hyperparams.rst.txt b/_sources/Examples/plotting_tools/plot_a2c_hyperparams.rst.txt new file mode 100644 index 00000000..865b38a9 --- /dev/null +++ b/_sources/Examples/plotting_tools/plot_a2c_hyperparams.rst.txt @@ -0,0 +1,15 @@ +.. _examples.plotting_tools.plot_a2c_hyperparams: + +plot_a2c_hyperparams +==================== + +``examples.plotting_tools.plot_a2c_hyperparams`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.plotting_tools.plot_a2c_hyperparams + :members: + :show-inheritance: + diff --git a/_sources/Examples/plotting_tools/plot_dqn_hyperparams.rst.txt b/_sources/Examples/plotting_tools/plot_dqn_hyperparams.rst.txt new file mode 100644 index 00000000..44938aa6 --- /dev/null +++ b/_sources/Examples/plotting_tools/plot_dqn_hyperparams.rst.txt @@ -0,0 +1,15 @@ +.. _examples.plotting_tools.plot_dqn_hyperparams: + +plot_dqn_hyperparams +==================== + +``examples.plotting_tools.plot_dqn_hyperparams`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.plotting_tools.plot_dqn_hyperparams + :members: + :show-inheritance: + diff --git a/_sources/Examples/plotting_tools/plot_ga_hyperparams.rst.txt b/_sources/Examples/plotting_tools/plot_ga_hyperparams.rst.txt new file mode 100644 index 00000000..fa4ba061 --- /dev/null +++ b/_sources/Examples/plotting_tools/plot_ga_hyperparams.rst.txt @@ -0,0 +1,15 @@ +.. _examples.plotting_tools.plot_ga_hyperparams: + +plot_ga_hyperparams +=================== + +``examples.plotting_tools.plot_ga_hyperparams`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.plotting_tools.plot_ga_hyperparams + :members: + :show-inheritance: + diff --git a/_sources/Examples/plotting_tools/plot_mcts_hyperparams.rst.txt b/_sources/Examples/plotting_tools/plot_mcts_hyperparams.rst.txt new file mode 100644 index 00000000..a9d305e4 --- /dev/null +++ b/_sources/Examples/plotting_tools/plot_mcts_hyperparams.rst.txt @@ -0,0 +1,15 @@ +.. _examples.plotting_tools.plot_mcts_hyperparams: + +plot_mcts_hyperparams +===================== + +``examples.plotting_tools.plot_mcts_hyperparams`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.plotting_tools.plot_mcts_hyperparams + :members: + :show-inheritance: + diff --git a/_sources/Examples/plotting_tools/plot_ppo_hyperparams.rst.txt b/_sources/Examples/plotting_tools/plot_ppo_hyperparams.rst.txt new file mode 100644 index 00000000..a7f82801 --- /dev/null +++ b/_sources/Examples/plotting_tools/plot_ppo_hyperparams.rst.txt @@ -0,0 +1,15 @@ +.. _examples.plotting_tools.plot_ppo_hyperparams: + +plot_ppo_hyperparams +==================== + +``examples.plotting_tools.plot_ppo_hyperparams`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.plotting_tools.plot_ppo_hyperparams + :members: + :show-inheritance: + diff --git a/_sources/Examples/plotting_tools/process_ga_curves.rst.txt b/_sources/Examples/plotting_tools/process_ga_curves.rst.txt new file mode 100644 index 00000000..8664ee61 --- /dev/null +++ b/_sources/Examples/plotting_tools/process_ga_curves.rst.txt @@ -0,0 +1,15 @@ +.. _examples.plotting_tools.process_ga_curves: + +process_ga_curves +================= + +``examples.plotting_tools.process_ga_curves`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.plotting_tools.process_ga_curves + :members: + :show-inheritance: + diff --git a/_sources/Examples/plotting_tools/process_sb3_curves.rst.txt b/_sources/Examples/plotting_tools/process_sb3_curves.rst.txt new file mode 100644 index 00000000..a37bce76 --- /dev/null +++ b/_sources/Examples/plotting_tools/process_sb3_curves.rst.txt @@ -0,0 +1,15 @@ +.. _examples.plotting_tools.process_sb3_curves: + +process_sb3_curves +================== + +``examples.plotting_tools.process_sb3_curves`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.plotting_tools.process_sb3_curves + :members: + :show-inheritance: + diff --git a/_sources/Examples/sb3/a2c_hyperparam_search.rst.txt b/_sources/Examples/sb3/a2c_hyperparam_search.rst.txt new file mode 100644 index 00000000..a048068b --- /dev/null +++ b/_sources/Examples/sb3/a2c_hyperparam_search.rst.txt @@ -0,0 +1,15 @@ +.. _examples.sb3.a2c_hyperparam_search: + +a2c_hyperparam_search +===================== + +``examples.sb3.a2c_hyperparam_search`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.sb3.a2c_hyperparam_search + :members: + :show-inheritance: + diff --git a/_sources/Examples/sb3/dqn_hyperparam_search.rst.txt b/_sources/Examples/sb3/dqn_hyperparam_search.rst.txt new file mode 100644 index 00000000..68b1f384 --- /dev/null +++ b/_sources/Examples/sb3/dqn_hyperparam_search.rst.txt @@ -0,0 +1,15 @@ +.. _examples.sb3.dqn_hyperparam_search: + +dqn_hyperparam_search +===================== + +``examples.sb3.dqn_hyperparam_search`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.sb3.dqn_hyperparam_search + :members: + :show-inheritance: + diff --git a/_sources/Examples/sb3/index.rst.txt b/_sources/Examples/sb3/index.rst.txt new file mode 100644 index 00000000..a3aec118 --- /dev/null +++ b/_sources/Examples/sb3/index.rst.txt @@ -0,0 +1,26 @@ +.. _examples.sb3: + +sb3 +=== + +``examples.sb3`` + +.. automodule:: examples.sb3 + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + a2c_hyperparam_search + dqn_hyperparam_search + ppo_hyperparam_search + sppo_hyperparam_search + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/Examples/sb3/ppo_hyperparam_search.rst.txt b/_sources/Examples/sb3/ppo_hyperparam_search.rst.txt new file mode 100644 index 00000000..6817eff0 --- /dev/null +++ b/_sources/Examples/sb3/ppo_hyperparam_search.rst.txt @@ -0,0 +1,15 @@ +.. _examples.sb3.ppo_hyperparam_search: + +ppo_hyperparam_search +===================== + +``examples.sb3.ppo_hyperparam_search`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.sb3.ppo_hyperparam_search + :members: + :show-inheritance: + diff --git a/_sources/Examples/sb3/sppo_hyperparam_search.rst.txt b/_sources/Examples/sb3/sppo_hyperparam_search.rst.txt new file mode 100644 index 00000000..5ac3e216 --- /dev/null +++ b/_sources/Examples/sb3/sppo_hyperparam_search.rst.txt @@ -0,0 +1,15 @@ +.. _examples.sb3.sppo_hyperparam_search: + +sppo_hyperparam_search +====================== + +``examples.sb3.sppo_hyperparam_search`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.sb3.sppo_hyperparam_search + :members: + :show-inheritance: + diff --git a/_sources/Examples/state_machine/index.rst.txt b/_sources/Examples/state_machine/index.rst.txt new file mode 100644 index 00000000..7e528072 --- /dev/null +++ b/_sources/Examples/state_machine/index.rst.txt @@ -0,0 +1,23 @@ +.. _examples.state_machine: + +state_machine +============= + +``examples.state_machine`` + +.. automodule:: examples.state_machine + :members: + :show-inheritance: + + + +.. toctree:: + :maxdepth: 1 + :caption: Files: + + state_machine_example + +.. toctree:: + :maxdepth: 1 + :caption: Directories: + diff --git a/_sources/Examples/state_machine/state_machine_example.rst.txt b/_sources/Examples/state_machine/state_machine_example.rst.txt new file mode 100644 index 00000000..6fa25835 --- /dev/null +++ b/_sources/Examples/state_machine/state_machine_example.rst.txt @@ -0,0 +1,15 @@ +.. _examples.state_machine.state_machine_example: + +state_machine_example +===================== + +``examples.state_machine.state_machine_example`` + +.. toctree:: + :maxdepth: 1 + :caption: Files: + +.. automodule:: examples.state_machine.state_machine_example + :members: + :show-inheritance: + diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 00000000..9a10e6f9 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,23 @@ +Welcome to bsk_rl's documentation! +================================== + +`bsk-rl` is a Python package consisting of various `Gymnasium `_ environments, agents, training scripts, and examples for spacecraft planning and scheduling problems, with an emphasis on reinforcement learning. + +Installation instruction can be found at :doc:`install`. + +New environments should be based on :ref:`bsk_rl.envs.general_satellite_tasking`. + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + install + API Reference/index + Examples/index + + +.. Indices +.. ======= + +.. * :ref:`genindex` +.. * :ref:`modindex` diff --git a/_sources/install.rst.txt b/_sources/install.rst.txt new file mode 100644 index 00000000..18e06d83 --- /dev/null +++ b/_sources/install.rst.txt @@ -0,0 +1,31 @@ +Installation +============ + +.. note:: + `bsk-rl` requires `Basilisk `_, a spacecraft simulation framework package, to be installed. Instructions for installing and compiling Basilisk may be found `here `_. + + +To install bsk_rl, clone the repo + +.. code-block:: console + + $ git clone git@github.com:AVSLab/bsk_rl.git + +and run the following command in your virtual environment: + +.. code-block:: console + + (.venv) $ python -m pip install -e . && finish_install + +while in the base directory. This will install `pip` dependencies and download data dependencies. + +.. note:: + See `#51 `_ for issues with `chebpy` installation on Silicon Macs. + +Test the installation by running + +.. code-block:: console + + pytest tests/examples + +in the base directory. \ No newline at end of file diff --git a/_static/Basilisk-Logo.png b/_static/Basilisk-Logo.png new file mode 100644 index 00000000..d0b4cbd5 Binary files /dev/null and b/_static/Basilisk-Logo.png differ diff --git a/_static/_sphinx_javascript_frameworks_compat.js b/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..81415803 --- /dev/null +++ b/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..30fee9d0 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff b/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff b/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_static/css/fonts/fontawesome-webfont.eot b/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_static/css/fonts/fontawesome-webfont.svg b/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/css/fonts/fontawesome-webfont.ttf b/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_static/css/fonts/fontawesome-webfont.woff b/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_static/css/fonts/fontawesome-webfont.woff2 b/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/css/fonts/lato-bold-italic.woff b/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_static/css/fonts/lato-bold-italic.woff2 b/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_static/css/fonts/lato-bold.woff b/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/_static/css/fonts/lato-bold.woff differ diff --git a/_static/css/fonts/lato-bold.woff2 b/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff2 differ diff --git a/_static/css/fonts/lato-normal-italic.woff b/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_static/css/fonts/lato-normal-italic.woff2 b/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_static/css/fonts/lato-normal.woff b/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/_static/css/fonts/lato-normal.woff differ diff --git a/_static/css/fonts/lato-normal.woff2 b/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff2 differ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/_static/custom.css b/_static/custom.css new file mode 100644 index 00000000..27004ba8 --- /dev/null +++ b/_static/custom.css @@ -0,0 +1,209 @@ +div.textblock a, div.textblock a:visited, p a, p a:visited, +a, a:hover, a:visited, +a.reference, a.internal, a.current { + color: #cfb87c; + font-weight: bold; +} + +a.icon-home, a.icon-home:visited { + color: #666; +} + +div.wy-menu > p.caption > span.caption-text { + color: white; + font-weight: bold; +} +a.el, a.el:visited { + color: #565A5C; +} + +.wy-side-nav-search>div.version { + color: #565A5C; # CU dark gray +} + +.wy-nav-content { + max-width: none; +} + +code span.pre, code { + color: #cb7ccf; +} + +th.head, .wy-nav-top { + color: white; + background-color: #565A5C; +} + +th.head p { + margin: 0px; +} + +tr td p, th.head p { + font-size: small; +} + +img.logo { + filter: drop-shadow(0px 0px 8px #fff); +} +/* override table no-wrap */ +.wy-table-responsive table td, .wy-table-responsive table th { + white-space: normal; +} + +.math { + text-align: left; +} +.eqno { + float: right; +} + +body, h1, h2, h3, h4, h5, .rst-content, .sidebar, .sidebar-title, p.caption { + font-family: system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", + "Lucida Grande", "Segoe UI" !important; +} + +:root { + color-scheme: light dark; +} + +.sidebar { + max-width: 500px; +} + +code, .rst-content tt, .rst-content code { + color: #E74C3C; +} + +ul.simple li, aside.sidebar ul li { + all: revert; +} + +ul.simple li p, aside.sidebar ul li p { + all: revert; + line-height: 24px; + font-size: 16px; + margin: 0px; +} + +ul.simple ul li { + list-style-type: circle; + margin-left: 1.5em; +} + +ul.simple, aside.sidebar ul { + all: revert; + padding-left: 1.5em; +} + +figure { + text-align: center; +} + +@media (prefers-color-scheme: dark) { + .wy-nav-content, .wy-body-for-nav, .wy-nav-content-wrap, math, span[id*='MathJax-Span'] { + background-color: black; + color: #ccc; + } + + .highlight .go { + color: #ccc; + } + + img.logo { + filter: drop-shadow(0px 0px 8px #000); + } + + .rst-content code { + background: #0004; + } + html.writer-html4 .rst-content dl:not(.docutils)>dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt, .rst-content .note { + background: #2D4151; + } + + .rst-content .warning, .rst-content .caution, .rst-content .attention { + background: #51402F; + } + + .rst-content .important, .rst-content .hint, .rst-content .tip { + background: #275145; + } + + .rst-content .danger, .rst-content .error { + background: #523A37; + } + + /* sidebar formatting */ + .sidebar { + border-color: #666; + } + .rst-content .sidebar { + background: #222; + } + .rst-content .sidebar .sidebar-title { + background: #666; + } + + + .btn-neutral, .btn-neutral:hover, .btn:visited { + background: #333 !important; + color: #ccc !important; + } + + .highlight { + background: #4448; + } + + .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td { + background-color: #222; + } + + .rst-content pre.literal-block, .rst-content div[class^='highlight'], .rst-content code, .rst-content table.docutils, .wy-table thead th, .rst-content table.docutils thead th, .rst-content table.field-list thead th, .wy-table-bordered-all td, .rst-content table.docutils td { + border-color: gray; + } + + img[src$="svg"] { + background-color: white; + filter: invert(100%) hue-rotate(180deg) saturate(200%);; + } + + img[src$="jpg"], img[src$="png"] { + border-radius: 5px; + } + + .rst-content dl:not(.docutils) dt { + background-color: #2D4151; + } + + .rst-content dl:not(.docutils) { + padding-top: 1em; + } + + .rst-content dl:not(.docutils) code.descclassname, .rst-content dl:not(.docutils) code.descname { + color: #ccc; + } + + html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt, .rst-content dl:not(.docutils) dl dt { + background-color: #333; + color: #ccc; + } + + .wy-table caption, .rst-content table.docutils caption, .rst-content table.field-list caption { + color: inherit; + } + + span.vm, span.nf, span.nn { + color:#66f !important; + } + + span.normal { + color: #333 !important; + } + + td.linenos pre { + background: #ccc !important; + } + + .rst-content .highlighted { + background-color: #333; + } +} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000..976fa38d --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '0.0.0', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/jquery.js b/_static/jquery.js new file mode 100644 index 00000000..c4c6022f --- /dev/null +++ b/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/html5shiv.min.js b/_static/js/html5shiv.min.js new file mode 100644 index 00000000..cd1c674f --- /dev/null +++ b/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/theme.js b/_static/js/theme.js new file mode 100644 index 00000000..1fddb6ee --- /dev/null +++ b/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 00000000..84ab3030 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #9C6500 } /* Comment.Preproc */ +.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #E40000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #008400 } /* Generic.Inserted */ +.highlight .go { color: #717171 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #687822 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #767600 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sa { color: #BA2121 } /* Literal.String.Affix */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #A45A77 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #0000FF } /* Name.Function.Magic */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .vm { color: #19177C } /* Name.Variable.Magic */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 00000000..7918c3fa --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/genindex.html b/genindex.html new file mode 100644 index 00000000..64c40fce --- /dev/null +++ b/genindex.html @@ -0,0 +1,2034 @@ + + + + + + Index — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ _ + | A + | B + | C + | D + | E + | F + | G + | I + | L + | M + | N + | O + | P + | R + | S + | T + | U + | V + | W + | Z + +
+

_

+ + +
+ +

A

+ + + +
+ +

B

+ + + +
    +
  • + bsk_rl.envs.multisat_agile_eos.bsk_models.fsw + +
  • +
  • + bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering + +
  • +
  • + bsk_rl.envs.multisat_agile_eos.bsk_sim + +
  • +
  • + bsk_rl.envs.multisat_agile_eos.env_settings + +
  • +
  • + bsk_rl.envs.multisat_agile_eos.gym_env + +
  • +
  • + bsk_rl.envs.multisensor_eos + +
  • +
  • + bsk_rl.envs.multisensor_eos.bsk_sim + +
  • +
  • + bsk_rl.envs.multisensor_eos.env_settings + +
  • +
  • + bsk_rl.envs.multisensor_eos.gym_env + +
  • +
  • + bsk_rl.envs.simple_eos + +
  • +
  • + bsk_rl.envs.simple_eos.bsk_sim + +
  • +
  • + bsk_rl.envs.simple_eos.gym_env + +
  • +
  • + bsk_rl.envs.small_body_science + +
  • +
  • + bsk_rl.envs.small_body_science.bsk_sim + +
  • +
  • + bsk_rl.envs.small_body_science.gym_env + +
  • +
  • + bsk_rl.envs.small_body_science_pomdp + +
  • +
  • + bsk_rl.envs.small_body_science_pomdp.bsk_sim + +
  • +
  • + bsk_rl.envs.small_body_science_pomdp.gym_env + +
  • +
  • + bsk_rl.training + +
  • +
  • + bsk_rl.training.mcts + +
  • +
  • + bsk_rl.training.mcts.mcts_train + +
  • +
  • + bsk_rl.training.sb3 + +
  • +
  • + bsk_rl.training.sb3.experiments + +
  • +
  • + bsk_rl.utilities + +
  • +
  • + bsk_rl.utilities.effector_primitives + +
  • +
  • + bsk_rl.utilities.effector_primitives.actuator_primitives + +
  • +
  • + bsk_rl.utilities.genetic_algorithm + +
  • +
  • + bsk_rl.utilities.genetic_algorithm.experiments + +
  • +
  • + bsk_rl.utilities.initial_conditions + +
  • +
  • + bsk_rl.utilities.initial_conditions.leo_initial_conditions + +
  • +
  • + bsk_rl.utilities.initial_conditions.leo_orbit + +
  • +
  • + bsk_rl.utilities.initial_conditions.sc_attitudes + +
  • +
  • + bsk_rl.utilities.initial_conditions.small_body + +
  • +
  • + bsk_rl.utilities.mcts + +
  • +
  • + bsk_rl.utilities.mcts.rollout_policies + +
  • +
  • + bsk_rl.utilities.sb3 + +
  • +
  • + bsk_rl.utilities.sb3.custom_sb3_policies + +
  • +
  • + bsk_rl.utilities.sb3.shielded_policies + +
  • +
  • + bsk_rl.utilities.sb3.shields + +
  • +
  • + bsk_rl.utilities.state_machine + +
  • +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
    +
  • + examples.mcts.network_validation_multiprocessing + +
  • +
  • + examples.plotting_tools + +
  • +
  • + examples.plotting_tools.plot_a2c_hyperparams + +
  • +
  • + examples.plotting_tools.plot_dqn_hyperparams + +
  • +
  • + examples.plotting_tools.plot_ga_hyperparams + +
  • +
  • + examples.plotting_tools.plot_mcts_hyperparams + +
  • +
  • + examples.plotting_tools.plot_ppo_hyperparams + +
  • +
  • + examples.plotting_tools.process_ga_curves + +
  • +
  • + examples.plotting_tools.process_sb3_curves + +
  • +
  • + examples.sb3 + +
  • +
  • + examples.sb3.a2c_hyperparam_search + +
  • +
  • + examples.sb3.dqn_hyperparam_search + +
  • +
  • + examples.sb3.ppo_hyperparam_search + +
  • +
  • + examples.sb3.sppo_hyperparam_search + +
  • +
  • + examples.state_machine + +
  • +
  • + examples.state_machine.state_machine_example + +
  • +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

I

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ +

Z

+ + +
+ + + +
+
+
+ +
+ +
+

© Copyright 2024, Autonomous Vehicle Systems (AVS) Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..853e38c7 --- /dev/null +++ b/index.html @@ -0,0 +1,136 @@ + + + + + + + Welcome to bsk_rl’s documentation! — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Welcome to bsk_rl’s documentation!

+

bsk-rl is a Python package consisting of various Gymnasium environments, agents, training scripts, and examples for spacecraft planning and scheduling problems, with an emphasis on reinforcement learning.

+

Installation instruction can be found at Installation.

+

New environments should be based on general_satellite_tasking.

+ +
+ + +
+
+
+ +
+ +
+

© Copyright 2024, Autonomous Vehicle Systems (AVS) Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/install.html b/install.html new file mode 100644 index 00000000..823484dd --- /dev/null +++ b/install.html @@ -0,0 +1,136 @@ + + + + + + + Installation — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Installation

+
+

Note

+

bsk-rl requires Basilisk, a spacecraft simulation framework package, to be installed. Instructions for installing and compiling Basilisk may be found here.

+
+

To install bsk_rl, clone the repo

+
$ git clone git@github.com:AVSLab/bsk_rl.git
+
+
+

and run the following command in your virtual environment:

+
(.venv) $ python -m pip install -e . && finish_install
+
+
+

while in the base directory. This will install pip dependencies and download data dependencies.

+
+

Note

+

See #51 for issues with chebpy installation on Silicon Macs.

+
+

Test the installation by running

+
pytest tests/examples
+
+
+

in the base directory.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 00000000..4709c2c6 Binary files /dev/null and b/objects.inv differ diff --git a/py-modindex.html b/py-modindex.html new file mode 100644 index 00000000..43427756 --- /dev/null +++ b/py-modindex.html @@ -0,0 +1,615 @@ + + + + + + Python Module Index — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Python Module Index

+ +
+ b | + e +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ b
+ bsk_rl +
    + bsk_rl.agents +
    + bsk_rl.agents.genetic_algorithm +
    + bsk_rl.agents.mcts +
    + bsk_rl.agents.state_machine +
    + bsk_rl.envs +
    + bsk_rl.envs.agile_eos +
    + bsk_rl.envs.agile_eos.bsk_sim +
    + bsk_rl.envs.agile_eos.gym_env +
    + bsk_rl.envs.general_satellite_tasking +
    + bsk_rl.envs.general_satellite_tasking.gym_env +
    + bsk_rl.envs.general_satellite_tasking.scenario +
    + bsk_rl.envs.general_satellite_tasking.scenario.communication +
    + bsk_rl.envs.general_satellite_tasking.scenario.data +
    + bsk_rl.envs.general_satellite_tasking.scenario.environment_features +
    + bsk_rl.envs.general_satellite_tasking.scenario.sat_actions +
    + bsk_rl.envs.general_satellite_tasking.scenario.sat_observations +
    + bsk_rl.envs.general_satellite_tasking.scenario.satellites +
    + bsk_rl.envs.general_satellite_tasking.simulation +
    + bsk_rl.envs.general_satellite_tasking.simulation.dynamics +
    + bsk_rl.envs.general_satellite_tasking.simulation.environment +
    + bsk_rl.envs.general_satellite_tasking.simulation.fsw +
    + bsk_rl.envs.general_satellite_tasking.simulation.simulator +
    + bsk_rl.envs.general_satellite_tasking.types +
    + bsk_rl.envs.general_satellite_tasking.utils +
    + bsk_rl.envs.general_satellite_tasking.utils.functional +
    + bsk_rl.envs.general_satellite_tasking.utils.logging_config +
    + bsk_rl.envs.general_satellite_tasking.utils.orbital +
    + bsk_rl.envs.multisat_agile_eos +
    + bsk_rl.envs.multisat_agile_eos.bsk_models +
    + bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics +
    + bsk_rl.envs.multisat_agile_eos.bsk_models.environment +
    + bsk_rl.envs.multisat_agile_eos.bsk_models.fsw +
    + bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering +
    + bsk_rl.envs.multisat_agile_eos.bsk_sim +
    + bsk_rl.envs.multisat_agile_eos.env_settings +
    + bsk_rl.envs.multisat_agile_eos.gym_env +
    + bsk_rl.envs.multisensor_eos +
    + bsk_rl.envs.multisensor_eos.bsk_sim +
    + bsk_rl.envs.multisensor_eos.env_settings +
    + bsk_rl.envs.multisensor_eos.gym_env +
    + bsk_rl.envs.simple_eos +
    + bsk_rl.envs.simple_eos.bsk_sim +
    + bsk_rl.envs.simple_eos.gym_env +
    + bsk_rl.envs.small_body_science +
    + bsk_rl.envs.small_body_science.bsk_sim +
    + bsk_rl.envs.small_body_science.gym_env +
    + bsk_rl.envs.small_body_science_pomdp +
    + bsk_rl.envs.small_body_science_pomdp.bsk_sim +
    + bsk_rl.envs.small_body_science_pomdp.gym_env +
    + bsk_rl.training +
    + bsk_rl.training.mcts +
    + bsk_rl.training.mcts.mcts_train +
    + bsk_rl.training.sb3 +
    + bsk_rl.training.sb3.experiments +
    + bsk_rl.utilities +
    + bsk_rl.utilities.effector_primitives +
    + bsk_rl.utilities.effector_primitives.actuator_primitives +
    + bsk_rl.utilities.genetic_algorithm +
    + bsk_rl.utilities.genetic_algorithm.experiments +
    + bsk_rl.utilities.initial_conditions +
    + bsk_rl.utilities.initial_conditions.leo_initial_conditions +
    + bsk_rl.utilities.initial_conditions.leo_orbit +
    + bsk_rl.utilities.initial_conditions.sc_attitudes +
    + bsk_rl.utilities.initial_conditions.small_body +
    + bsk_rl.utilities.mcts +
    + bsk_rl.utilities.mcts.rollout_policies +
    + bsk_rl.utilities.sb3 +
    + bsk_rl.utilities.sb3.custom_sb3_policies +
    + bsk_rl.utilities.sb3.shielded_policies +
    + bsk_rl.utilities.sb3.shields +
    + bsk_rl.utilities.state_machine +
 
+ e
+ examples +
    + examples.general_satellite_tasking +
    + examples.general_satellite_tasking.multisat_aeos +
    + examples.general_satellite_tasking.satellite_customization +
    + examples.general_satellite_tasking.single_sat +
    + examples.genetic_algorithm +
    + examples.genetic_algorithm.ga_hp_solver +
    + examples.mcts +
    + examples.mcts.mcts_data_generator +
    + examples.mcts.network_hyperparam_search +
    + examples.mcts.network_validation_multiprocessing +
    + examples.plotting_tools +
    + examples.plotting_tools.plot_a2c_hyperparams +
    + examples.plotting_tools.plot_dqn_hyperparams +
    + examples.plotting_tools.plot_ga_hyperparams +
    + examples.plotting_tools.plot_mcts_hyperparams +
    + examples.plotting_tools.plot_ppo_hyperparams +
    + examples.plotting_tools.process_ga_curves +
    + examples.plotting_tools.process_sb3_curves +
    + examples.sb3 +
    + examples.sb3.a2c_hyperparam_search +
    + examples.sb3.dqn_hyperparam_search +
    + examples.sb3.ppo_hyperparam_search +
    + examples.sb3.sppo_hyperparam_search +
    + examples.state_machine +
    + examples.state_machine.state_machine_example +
+ + +
+
+
+ +
+ +
+

© Copyright 2024, Autonomous Vehicle Systems (AVS) Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 00000000..e9251412 --- /dev/null +++ b/search.html @@ -0,0 +1,125 @@ + + + + + + Search — bsk_rl 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2024, Autonomous Vehicle Systems (AVS) Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000..b810a28a --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["API Reference/agents/genetic_algorithm", "API Reference/agents/index", "API Reference/agents/mcts", "API Reference/agents/state_machine", "API Reference/envs/agile_eos/bsk_sim", "API Reference/envs/agile_eos/gym_env", "API Reference/envs/agile_eos/index", "API Reference/envs/general_satellite_tasking/gym_env", "API Reference/envs/general_satellite_tasking/index", "API Reference/envs/general_satellite_tasking/scenario/communication", "API Reference/envs/general_satellite_tasking/scenario/data", "API Reference/envs/general_satellite_tasking/scenario/environment_features", "API Reference/envs/general_satellite_tasking/scenario/index", "API Reference/envs/general_satellite_tasking/scenario/sat_actions", "API Reference/envs/general_satellite_tasking/scenario/sat_observations", "API Reference/envs/general_satellite_tasking/scenario/satellites", "API Reference/envs/general_satellite_tasking/simulation/dynamics", "API Reference/envs/general_satellite_tasking/simulation/environment", "API Reference/envs/general_satellite_tasking/simulation/fsw", "API Reference/envs/general_satellite_tasking/simulation/index", "API Reference/envs/general_satellite_tasking/simulation/simulator", "API Reference/envs/general_satellite_tasking/types", "API Reference/envs/general_satellite_tasking/utils/functional", "API Reference/envs/general_satellite_tasking/utils/index", "API Reference/envs/general_satellite_tasking/utils/logging_config", "API Reference/envs/general_satellite_tasking/utils/orbital", "API Reference/envs/index", "API Reference/envs/multisat_agile_eos/bsk_models/dynamics", "API Reference/envs/multisat_agile_eos/bsk_models/environment", "API Reference/envs/multisat_agile_eos/bsk_models/fsw", "API Reference/envs/multisat_agile_eos/bsk_models/fsw_steering", "API Reference/envs/multisat_agile_eos/bsk_models/index", "API Reference/envs/multisat_agile_eos/bsk_sim", "API Reference/envs/multisat_agile_eos/env_settings", "API Reference/envs/multisat_agile_eos/gym_env", "API Reference/envs/multisat_agile_eos/index", "API Reference/envs/multisensor_eos/bsk_sim", "API Reference/envs/multisensor_eos/env_settings", "API Reference/envs/multisensor_eos/gym_env", "API Reference/envs/multisensor_eos/index", "API Reference/envs/simple_eos/bsk_sim", "API Reference/envs/simple_eos/gym_env", "API Reference/envs/simple_eos/index", "API Reference/envs/small_body_science/bsk_sim", "API Reference/envs/small_body_science/gym_env", "API Reference/envs/small_body_science/index", "API Reference/envs/small_body_science_pomdp/bsk_sim", "API Reference/envs/small_body_science_pomdp/gym_env", "API Reference/envs/small_body_science_pomdp/index", "API Reference/index", "API Reference/training/index", "API Reference/training/mcts/index", "API Reference/training/mcts/mcts_train", "API Reference/training/sb3/experiments", "API Reference/training/sb3/index", "API Reference/utilities/effector_primitives/actuator_primitives", "API Reference/utilities/effector_primitives/index", "API Reference/utilities/genetic_algorithm/experiments", "API Reference/utilities/genetic_algorithm/index", "API Reference/utilities/index", "API Reference/utilities/initial_conditions/index", "API Reference/utilities/initial_conditions/leo_initial_conditions", "API Reference/utilities/initial_conditions/leo_orbit", "API Reference/utilities/initial_conditions/sc_attitudes", "API Reference/utilities/initial_conditions/small_body", "API Reference/utilities/mcts/index", "API Reference/utilities/mcts/rollout_policies", "API Reference/utilities/sb3/custom_sb3_policies", "API Reference/utilities/sb3/index", "API Reference/utilities/sb3/shielded_policies", "API Reference/utilities/sb3/shields", "API Reference/utilities/state_machine/index", "Examples/general_satellite_tasking/index", "Examples/general_satellite_tasking/multisat_aeos", "Examples/general_satellite_tasking/satellite_customization", "Examples/general_satellite_tasking/single_sat", "Examples/genetic_algorithm/ga_hp_solver", "Examples/genetic_algorithm/index", "Examples/index", "Examples/mcts/index", "Examples/mcts/mcts_data_generator", "Examples/mcts/network_hyperparam_search", "Examples/mcts/network_validation_multiprocessing", "Examples/plotting_tools/index", "Examples/plotting_tools/plot_a2c_hyperparams", "Examples/plotting_tools/plot_dqn_hyperparams", "Examples/plotting_tools/plot_ga_hyperparams", "Examples/plotting_tools/plot_mcts_hyperparams", "Examples/plotting_tools/plot_ppo_hyperparams", "Examples/plotting_tools/process_ga_curves", "Examples/plotting_tools/process_sb3_curves", "Examples/sb3/a2c_hyperparam_search", "Examples/sb3/dqn_hyperparam_search", "Examples/sb3/index", "Examples/sb3/ppo_hyperparam_search", "Examples/sb3/sppo_hyperparam_search", "Examples/state_machine/index", "Examples/state_machine/state_machine_example", "index", "install"], "filenames": ["API Reference/agents/genetic_algorithm.rst", "API Reference/agents/index.rst", "API Reference/agents/mcts.rst", "API Reference/agents/state_machine.rst", "API Reference/envs/agile_eos/bsk_sim.rst", "API Reference/envs/agile_eos/gym_env.rst", "API Reference/envs/agile_eos/index.rst", "API Reference/envs/general_satellite_tasking/gym_env.rst", "API Reference/envs/general_satellite_tasking/index.rst", "API Reference/envs/general_satellite_tasking/scenario/communication.rst", "API Reference/envs/general_satellite_tasking/scenario/data.rst", "API Reference/envs/general_satellite_tasking/scenario/environment_features.rst", "API Reference/envs/general_satellite_tasking/scenario/index.rst", "API Reference/envs/general_satellite_tasking/scenario/sat_actions.rst", "API Reference/envs/general_satellite_tasking/scenario/sat_observations.rst", "API Reference/envs/general_satellite_tasking/scenario/satellites.rst", "API Reference/envs/general_satellite_tasking/simulation/dynamics.rst", "API Reference/envs/general_satellite_tasking/simulation/environment.rst", "API Reference/envs/general_satellite_tasking/simulation/fsw.rst", "API Reference/envs/general_satellite_tasking/simulation/index.rst", "API Reference/envs/general_satellite_tasking/simulation/simulator.rst", "API Reference/envs/general_satellite_tasking/types.rst", "API Reference/envs/general_satellite_tasking/utils/functional.rst", "API Reference/envs/general_satellite_tasking/utils/index.rst", "API Reference/envs/general_satellite_tasking/utils/logging_config.rst", "API Reference/envs/general_satellite_tasking/utils/orbital.rst", "API Reference/envs/index.rst", "API Reference/envs/multisat_agile_eos/bsk_models/dynamics.rst", "API Reference/envs/multisat_agile_eos/bsk_models/environment.rst", "API Reference/envs/multisat_agile_eos/bsk_models/fsw.rst", "API Reference/envs/multisat_agile_eos/bsk_models/fsw_steering.rst", "API Reference/envs/multisat_agile_eos/bsk_models/index.rst", "API Reference/envs/multisat_agile_eos/bsk_sim.rst", "API Reference/envs/multisat_agile_eos/env_settings.rst", "API Reference/envs/multisat_agile_eos/gym_env.rst", "API Reference/envs/multisat_agile_eos/index.rst", "API Reference/envs/multisensor_eos/bsk_sim.rst", "API Reference/envs/multisensor_eos/env_settings.rst", "API Reference/envs/multisensor_eos/gym_env.rst", "API Reference/envs/multisensor_eos/index.rst", "API Reference/envs/simple_eos/bsk_sim.rst", "API Reference/envs/simple_eos/gym_env.rst", "API Reference/envs/simple_eos/index.rst", "API Reference/envs/small_body_science/bsk_sim.rst", "API Reference/envs/small_body_science/gym_env.rst", "API Reference/envs/small_body_science/index.rst", "API Reference/envs/small_body_science_pomdp/bsk_sim.rst", "API Reference/envs/small_body_science_pomdp/gym_env.rst", "API Reference/envs/small_body_science_pomdp/index.rst", "API Reference/index.rst", "API Reference/training/index.rst", "API Reference/training/mcts/index.rst", "API Reference/training/mcts/mcts_train.rst", "API Reference/training/sb3/experiments.rst", "API Reference/training/sb3/index.rst", "API Reference/utilities/effector_primitives/actuator_primitives.rst", "API Reference/utilities/effector_primitives/index.rst", "API Reference/utilities/genetic_algorithm/experiments.rst", "API Reference/utilities/genetic_algorithm/index.rst", "API Reference/utilities/index.rst", "API Reference/utilities/initial_conditions/index.rst", "API Reference/utilities/initial_conditions/leo_initial_conditions.rst", "API Reference/utilities/initial_conditions/leo_orbit.rst", "API Reference/utilities/initial_conditions/sc_attitudes.rst", "API Reference/utilities/initial_conditions/small_body.rst", "API Reference/utilities/mcts/index.rst", "API Reference/utilities/mcts/rollout_policies.rst", "API Reference/utilities/sb3/custom_sb3_policies.rst", "API Reference/utilities/sb3/index.rst", "API Reference/utilities/sb3/shielded_policies.rst", "API Reference/utilities/sb3/shields.rst", "API Reference/utilities/state_machine/index.rst", "Examples/general_satellite_tasking/index.rst", "Examples/general_satellite_tasking/multisat_aeos.rst", "Examples/general_satellite_tasking/satellite_customization.rst", "Examples/general_satellite_tasking/single_sat.rst", "Examples/genetic_algorithm/ga_hp_solver.rst", "Examples/genetic_algorithm/index.rst", "Examples/index.rst", "Examples/mcts/index.rst", "Examples/mcts/mcts_data_generator.rst", "Examples/mcts/network_hyperparam_search.rst", "Examples/mcts/network_validation_multiprocessing.rst", "Examples/plotting_tools/index.rst", "Examples/plotting_tools/plot_a2c_hyperparams.rst", "Examples/plotting_tools/plot_dqn_hyperparams.rst", "Examples/plotting_tools/plot_ga_hyperparams.rst", "Examples/plotting_tools/plot_mcts_hyperparams.rst", "Examples/plotting_tools/plot_ppo_hyperparams.rst", "Examples/plotting_tools/process_ga_curves.rst", "Examples/plotting_tools/process_sb3_curves.rst", "Examples/sb3/a2c_hyperparam_search.rst", "Examples/sb3/dqn_hyperparam_search.rst", "Examples/sb3/index.rst", "Examples/sb3/ppo_hyperparam_search.rst", "Examples/sb3/sppo_hyperparam_search.rst", "Examples/state_machine/index.rst", "Examples/state_machine/state_machine_example.rst", "index.rst", "install.rst"], "titles": ["genetic_algorithm", "agents", "mcts", "state_machine", "bsk_sim", "gym_env", "agile_eos", "gym_env", "general_satellite_tasking", "communication", "data", "environment_features", "scenario", "sat_actions", "sat_observations", "satellites", "dynamics", "environment", "fsw", "simulation", "simulator", "types", "functional", "utils", "logging_config", "orbital", "envs", "dynamics", "environment", "fsw", "fsw_steering", "bsk_models", "bsk_sim", "env_settings", "gym_env", "multisat_agile_eos", "bsk_sim", "env_settings", "gym_env", "multisensor_eos", "bsk_sim", "gym_env", "simple_eos", "bsk_sim", "gym_env", "small_body_science", "bsk_sim", "gym_env", "small_body_science_pomdp", "API Reference", "training", "mcts", "mcts_train", "experiments", "sb3", "actuator_primitives", "effector_primitives", "experiments", "genetic_algorithm", "utilities", "initial_conditions", "leo_initial_conditions", "leo_orbit", "sc_attitudes", "small_body", "mcts", "rollout_policies", "custom_sb3_policies", "sb3", "shielded_policies", "shields", "state_machine", "general_satellite_tasking", "multisat_aeos", "satellite_customization", "single_sat", "ga_hp_solver", "genetic_algorithm", "Examples", "mcts", "mcts_data_generator", "network_hyperparam_search", "network_validation_multiprocessing", "plotting_tools", "plot_a2c_hyperparams", "plot_dqn_hyperparams", "plot_ga_hyperparams", "plot_mcts_hyperparams", "plot_ppo_hyperparams", "process_ga_curves", "process_sb3_curves", "a2c_hyperparam_search", "dqn_hyperparam_search", "sb3", "ppo_hyperparam_search", "sppo_hyperparam_search", "state_machine", "state_machine_example", "Welcome to bsk_rl\u2019s documentation!", "Installation"], "terms": {"bsk_rl": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 99], "agent": [0, 2, 3, 5, 7, 13, 15, 38, 41, 44, 47, 49, 53, 98], "class": [0, 2, 5, 7, 9, 10, 11, 13, 14, 15, 16, 17, 18, 22, 24, 27, 28, 29, 30, 34, 37, 38, 41, 44, 47, 67, 69, 70], "env2opt_problem": 0, "env_nam": [0, 2, 52, 53, 57, 89], "initial_condit": [0, 2, 52, 59, 61, 62, 63, 64], "none": [0, 2, 5, 7, 9, 10, 11, 13, 14, 15, 16, 17, 18, 22, 24, 25, 34, 38, 41, 44, 47, 52, 53, 57, 67, 69], "sourc": [0, 2, 5, 7, 9, 10, 11, 13, 14, 15, 16, 17, 18, 22, 24, 25, 27, 28, 29, 30, 34, 36, 37, 38, 41, 44, 47, 52, 53, 55, 57, 62, 63, 64, 67, 69, 70, 73, 82, 89], "base": [0, 2, 5, 7, 9, 10, 11, 13, 14, 15, 16, 17, 18, 22, 24, 27, 28, 29, 30, 34, 36, 37, 38, 41, 44, 47, 62, 67, 69, 70, 98, 99], "object": [0, 2, 5, 7, 11, 15, 22, 27, 28, 29, 30, 37, 38, 41, 44, 47, 70], "thi": [0, 2, 5, 7, 15, 16, 17, 18, 29, 30, 34, 38, 41, 47, 82, 99], "provid": [0, 2, 22, 29, 30, 38, 47], "gener": [0, 7, 10, 11, 13, 14, 15, 18, 22, 25, 52, 57, 62, 64, 89], "interfac": 0, "recast": 0, "gymnasium": [0, 5, 7, 34, 37, 38, 67, 69, 98], "environ": [0, 2, 5, 7, 10, 11, 15, 16, 18, 19, 20, 31, 34, 37, 38, 41, 44, 47, 52, 53, 69, 73, 82, 98, 99], "total": [0, 5, 38, 41, 44, 47], "reward": [0, 5, 7, 10, 11, 34, 38, 41, 44, 47, 52, 82], "maxim": [0, 5, 34], "problem": [0, 5, 7, 34, 98], "__init__": [0, 2, 5, 7, 9, 10, 11, 13, 14, 15, 16, 17, 18, 24, 27, 28, 29, 30, 34, 37, 38, 41, 44, 47, 67, 69, 70], "evalu": [0, 5, 15, 16, 22, 38, 41], "action_set": 0, "full": [0, 38], "run": [0, 18, 52, 53, 57, 62, 73, 82, 99], "given": [0, 34, 53], "list": [0, 7, 9, 10, 14, 15, 34, 52, 53, 62, 82, 89], "action": [0, 2, 5, 7, 13, 15, 16, 18, 34, 38, 41, 44, 47, 52, 69, 70], "mutuniformintlist": 0, "individu": 0, "num_sampl": 0, "2": [0, 5, 24, 34, 38, 41, 44, 47], "low": [0, 5, 34], "0": [0, 2, 5, 7, 10, 11, 13, 14, 15, 25, 34, 38, 41, 44, 47, 52, 53, 62, 63], "up": [0, 2, 5, 27, 38, 41, 44, 47], "5": [0, 5, 34, 41, 44, 47], "indpb": 0, "3": [0, 5, 24, 34, 38, 41, 44, 47], "function": [0, 5, 7, 10, 11, 13, 14, 15, 18, 23, 34, 38, 41, 44, 47, 52, 67, 82], "i": [0, 2, 5, 7, 10, 14, 15, 16, 17, 18, 22, 24, 25, 28, 34, 38, 41, 44, 47, 52, 62, 64, 82, 98], "design": [0, 5, 34], "mutat": 0, "integ": [0, 13], "rather": 0, "than": [0, 15], "singl": [0, 7, 15, 22, 52], "param": [0, 5, 41, 44, 47, 52, 53, 62, 70, 82, 89], "The": [0, 2, 5, 7, 22, 24, 34, 38, 41, 44, 47, 52], "number": [0, 2, 5, 7, 11, 13, 14, 15, 34, 52, 53, 57, 62, 64, 67, 70], "sampl": [0, 63, 69], "lower": 0, "bound": [0, 15, 62], "upper": 0, "probabl": [0, 5, 38, 41, 69], "return": [0, 5, 7, 10, 11, 13, 14, 15, 16, 18, 22, 24, 25, 34, 38, 41, 44, 47, 52, 55, 62, 63, 67, 69, 82, 89], "A": [0, 5, 7, 34, 44, 47, 52], "genetic_algorithm": [1, 57, 59, 76, 78, 98], "mct": [1, 50, 52, 59, 66, 78, 80, 81, 82, 98], "state_machin": [1, 2, 59, 78, 97, 98], "c": [2, 5, 9, 29, 30, 34, 38, 44, 47, 52, 62, 82], "1": [2, 5, 7, 11, 14, 34, 38, 41, 44, 47, 55, 62, 64, 67], "num_sim": [2, 52], "10": [2, 13, 15, 44, 47, 53], "max_length": 2, "270": [2, 52], "max_step": [2, 53], "45": [2, 25, 52, 53], "rollout_polici": [2, 65], "backup_typ": 2, "max": [2, 41], "determinist": [2, 69], "To": [2, 37, 99], "us": [2, 5, 7, 9, 13, 14, 15, 17, 18, 22, 24, 28, 34, 37, 38, 41, 52, 53, 55, 64, 69], "uct": 2, "set": [2, 7, 11, 14, 15, 25, 27, 29, 30, 34, 37, 38, 55, 62], "rollout": 2, "type": [2, 5, 7, 8, 9, 10, 11, 13, 14, 15, 18, 22, 25, 38, 41, 44, 47, 67, 69], "either": [2, 22, 24, 52], "heurist": 2, "random": [2, 7, 15, 25, 63, 64], "If": [2, 13, 14, 15, 16, 18, 24, 34, 67], "creat": [2, 10, 13, 15, 16, 17, 18, 22, 25, 27, 29, 30, 34, 52, 55], "polici": [2, 53, 67, 69], "follow": [2, 99], "two": 2, "line": [2, 9, 16], "code": [2, 14], "statemachinemct": 2, "statemachin": 2, "loadtransfercondit": 2, "agile_eos_op": 2, "adv": 2, "agileeosrolloutpolici": 2, "env": [2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 52, 98], "Then": 2, "load": [2, 52, 82], "dure": [2, 15], "initi": [2, 5, 9, 15, 24, 25, 27, 29, 30, 34, 38, 41, 44, 47, 52, 62, 63, 67, 69, 82], "mcts_agent": 2, "condit": [2, 44, 47, 52, 62, 63, 82], "must": [2, 5, 34, 38, 41], "after": [2, 9, 15], "algorithm": [2, 57, 64], "automat": [2, 14], "restart": 2, "sim": [2, 7, 14, 37, 52], "step": [2, 5, 7, 9, 10, 24, 34, 38, 41, 44, 47, 52, 53], "forward": [2, 67, 69], "last": [2, 5, 15, 34, 38, 41, 44, 47, 67], "state": [2, 5, 7, 14, 27, 34, 38, 41, 44, 47, 52, 67, 69, 82], "due": [2, 38], "limit": [2, 5, 34], "copi": 2, "basilisk": [2, 7, 15, 16, 17, 18, 20, 99], "setenv": 2, "num_step": [2, 52], "t_final": [2, 52], "paramet": [2, 7, 9, 10, 11, 13, 14, 15, 16, 17, 18, 22, 24, 25, 27, 34, 38, 52, 62, 67, 69], "scale": [2, 5, 38, 41, 44, 47], "explor": [2, 52], "bonu": 2, "simul": [2, 5, 7, 8, 9, 10, 14, 15, 16, 17, 18, 27, 28, 34, 38, 41, 47, 52, 62, 63, 99], "per": [2, 7, 10, 11, 14, 52], "call": [2, 7, 10, 13, 14, 15, 16, 18, 22, 24, 34], "selectact": 2, "backup_tre": 2, "back": [2, 10], "valu": [2, 5, 7, 11, 14, 15, 22, 34, 52, 67, 69], "along": 2, "main": 2, "tree": 2, "onc": [2, 9, 14], "ha": [2, 5, 16, 18, 22, 38, 41, 44, 47], "termin": [2, 5, 7, 15, 38, 41, 44, 47], "": [2, 5, 7, 10, 14, 15, 16, 17, 18, 24, 25, 34, 38, 41, 44, 47, 62], "d": [2, 44, 47], "execut": [2, 52, 82], "desir": [2, 22], "depth": [2, 67], "end": [2, 14, 15, 25], "acthist": [2, 52], "select": [2, 13, 15], "next": [2, 14, 15, 38, 44, 47, 52], "true": [2, 5, 13, 15, 24, 25, 34, 38, 41, 44, 47, 62], "through": [2, 13, 14, 15, 24, 34, 41], "envtyp": 2, "30": [2, 7, 44], "90": [2, 18, 53], "trajectori": 2, "updat": [2, 7, 10, 14, 22, 34, 53, 82], "q_search": 2, "agile_eo": [4, 5, 26], "agileeo": [5, 57, 69], "failure_penalti": [5, 7, 44], "image_compon": 5, "downlink_compon": 5, "9": [5, 44, 47], "an": [5, 11, 13, 14, 15, 16, 18, 22, 24, 28, 34, 38, 41, 44, 47, 52, 53, 62, 73, 98], "agil": [5, 15, 34], "eo": [5, 34], "schedul": [5, 34, 98], "which": [5, 7, 9, 24, 28, 34, 47], "satellit": [5, 7, 9, 10, 11, 12, 13, 14, 16, 18, 22, 25, 34, 62, 73], "earth": [5, 11, 28, 29, 30, 34, 38], "orbit": [5, 14, 15, 23, 34, 62], "attempt": [5, 15, 34, 38], "target": [5, 7, 10, 11, 13, 14, 15, 18, 25, 34, 38, 41, 44, 47, 62], "imag": [5, 7, 10, 11, 13, 15, 16, 34, 38, 41, 44, 47, 64, 73, 82], "downlink": [5, 14, 17, 34, 41, 44, 47, 82], "while": [5, 34, 44, 47, 99], "avoid": [5, 13, 34, 44, 47], "resourc": [5, 34, 44, 47], "constraint": [5, 34, 44, 47], "violat": [5, 15, 34, 44, 47], "includ": [5, 7, 13, 14, 15, 17, 27, 28, 34, 44, 47], "power": [5, 16, 18, 27, 34, 44, 47], "spacecraft": [5, 27, 34, 38, 41, 55, 62, 63, 98, 99], "keep": [5, 18, 34, 52, 82], "its": [5, 24, 34], "batteri": [5, 16, 27, 34, 38, 41, 44, 47], "charg": [5, 16, 34, 38, 41, 44, 47], "abov": [5, 24, 25, 34], "zero": [5, 29, 30, 34], "reaction": [5, 18, 27, 34, 38, 41, 55], "wheel": [5, 16, 18, 27, 34, 38, 41, 55], "satur": [5, 34], "within": [5, 34, 62], "speed": [5, 16, 34, 41], "data": [5, 7, 9, 11, 12, 34, 41, 44, 47, 52, 99], "buffer": [5, 15, 34, 41, 44, 47], "from": [5, 9, 10, 11, 13, 14, 15, 25, 29, 30, 34, 52, 64, 67, 82], "overflow": [5, 34, 41], "e": [5, 7, 22, 25, 34, 44, 47, 67, 99], "exceed": [5, 34], "meet": [5, 34], "maximum": [5, 7, 15, 16, 34, 53], "size": [5, 7, 34, 53, 57, 62, 70], "decid": [5, 34, 41], "between": [5, 7, 9, 16, 34, 38, 41, 44, 47, 62], "point": [5, 10, 18, 29, 30, 34, 38, 41, 64], "ani": [5, 7, 11, 13, 14, 15, 16, 17, 18, 22, 34], "one": [5, 7, 24, 34], "j": [5, 34], "ground": [5, 11, 14, 15, 16, 17, 27, 28, 34, 38, 41], "sun": [5, 18, 29, 30, 34, 38, 41, 44, 47], "desatur": [5, 18, 34, 38, 41], "refer": [5, 7, 13, 16, 18, 29, 30, 34, 38, 41, 98], "space": [5, 7, 13, 15, 34, 38, 41, 44, 47, 62, 67, 69], "discret": [5, 13, 38, 41, 44, 47], "mode": [5, 13, 34, 38, 41, 44, 47], "desat": [5, 34, 41], "observ": [5, 7, 14, 15, 34, 38, 41, 44, 47, 69, 82], "ecef": [5, 34, 62], "posit": [5, 16, 25, 34, 38, 41, 44, 47, 62], "veloc": [5, 16, 17, 34, 38, 41, 44, 47, 62], "indic": [5, 34, 38, 41, 44, 47, 52, 82], "attitud": [5, 16, 18, 34, 41], "error": [5, 34, 38, 41], "rate": [5, 7, 15, 16, 17, 18, 34, 41, 52, 53], "6": [5, 34, 41, 44, 47], "7": [5, 34, 41, 44, 47], "8": [5, 34, 41, 44, 47], "11": [5, 34, 41, 44, 47], "12": [5, 34, 41, 47, 67], "eclips": [5, 14, 27, 28, 34, 38, 41, 44, 47], "13": [5, 34, 41, 44, 47], "store": [5, 10, 34, 41, 52], "onboard": [5, 34, 41], "14": [5, 34, 41, 44, 47], "transmit": [5, 34, 41], "over": [5, 11, 34, 41, 52, 57], "interv": [5, 34, 41], "15": [5, 34, 41], "amount": [5, 11, 34, 38, 41, 44, 47], "time": [5, 7, 9, 10, 13, 14, 15, 16, 17, 18, 24, 34, 38, 41, 44, 47, 52, 62, 82], "station": [5, 14, 16, 17, 34, 41], "were": [5, 34, 41, 52], "access": [5, 13, 14, 15, 34, 38, 41], "16": [5, 34, 41, 44, 47], "22": [5, 34, 41, 44], "tupl": [5, 7, 11, 14, 15, 34, 41, 44, 47, 67, 69], "4": [5, 34, 53, 57, 67], "each": [5, 7, 13, 15, 16, 17, 18, 34, 41, 44, 47, 62, 64], "prioriti": [5, 10, 11, 14, 16, 17, 18, 34], "hill": [5, 34, 44, 47], "frame": [5, 16, 17, 18, 34, 38, 44, 47, 62], "po": [5, 34], "r": [5, 34, 38, 41, 44, 47], "tgt": [5, 34, 44, 47, 62], "first": [5, 15, 22, 25, 34, 44, 47, 52], "b": [5, 9, 34, 44, 47, 82], "failur": [5, 7, 22, 34, 41, 44, 47], "reset": [5, 7, 9, 10, 11, 15, 16, 18, 34, 38, 41, 44, 47], "seed": [5, 7, 34, 38, 41, 44, 47], "option": [5, 7, 14, 24, 34, 38, 41, 44, 47, 52], "rtype": [5, 38, 41, 44, 47], "take": [5, 13, 38, 41, 44, 47, 52], "int": [5, 7, 10, 11, 13, 14, 15, 16, 17, 18, 25, 38, 41, 44, 47, 53, 67], "ob": [5, 14, 34, 38, 41, 44, 47, 69, 82], "episode_ov": [5, 38, 41, 44, 47], "info": [5, 7, 15, 34, 38, 41, 44, 47, 52, 82], "specif": [5, 38, 41, 44, 47], "repres": [5, 38, 41, 44, 47], "your": [5, 24, 38, 41, 44, 47, 99], "float": [5, 7, 10, 11, 13, 14, 15, 16, 17, 18, 25, 38, 41, 44, 47, 53, 67, 69], "achiev": [5, 38, 41, 44, 47], "previou": [5, 10, 13, 15, 38, 41, 44, 47], "vari": [5, 38, 41, 44, 47], "goal": [5, 38, 41, 44, 47], "alwai": [5, 25, 38, 41, 44, 47], "increas": [5, 13, 38, 41, 44, 47], "bool": [5, 7, 13, 15, 16, 18, 22, 38, 41, 44, 47, 53, 69], "whether": [5, 22, 34, 38, 41, 44, 47, 53, 69], "again": [5, 38, 41, 44, 47], "most": [5, 11, 38, 41, 44, 47], "all": [5, 7, 15, 18, 22, 27, 29, 30, 38, 41, 44, 47, 67, 69], "task": [5, 7, 13, 15, 18, 38, 41, 44, 47], "ar": [5, 7, 10, 13, 14, 15, 16, 24, 25, 28, 34, 38, 41, 44, 47, 52, 67], "divid": [5, 38, 41, 44, 47], "well": [5, 38, 41, 44, 47], "defin": [5, 9, 11, 18, 27, 28, 29, 30, 38, 41, 44, 47, 55], "episod": [5, 10, 11, 16, 18, 34, 38, 41, 44, 47, 52], "done": [5, 38, 41, 44, 47], "being": [5, 7, 10, 38, 41, 44, 47], "For": [5, 7, 9, 16, 34, 38, 41, 44, 47], "exampl": [5, 7, 9, 38, 41, 44, 47, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99], "perhap": [5, 38, 41, 44, 47], "pole": [5, 38, 41, 44, 47], "tip": [5, 38, 41, 44, 47], "too": [5, 38, 41, 44, 47], "far": [5, 38, 41, 44, 47], "you": [5, 24, 38, 41, 44, 47], "lost": [5, 38, 41, 44, 47], "life": [5, 38, 41, 44, 47], "dict": [5, 7, 10, 13, 14, 15, 17, 22, 38, 41, 53, 67, 69], "diagnost": [5, 38, 41], "inform": [5, 7, 10, 14, 15, 24, 29, 30, 38, 41], "debug": [5, 7, 34, 38, 41], "It": [5, 38, 41, 67], "can": [5, 7, 10, 13, 14, 15, 18, 29, 30, 34, 38, 41, 44, 47, 62, 98], "sometim": [5, 38, 41], "learn": [5, 38, 41, 53, 98], "might": [5, 38, 41], "contain": [5, 7, 38, 41, 53, 55, 82], "raw": [5, 38, 41], "behind": [5, 38, 41], "chang": [5, 24, 38, 41], "howev": [5, 38, 41], "offici": [5, 38, 41], "allow": [5, 10, 13, 24, 38, 41], "bsk_sim": [6, 35, 39, 42, 45, 48], "gym_env": [6, 8, 35, 39, 42, 45, 48], "general_satellite_task": [7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 73, 74, 75, 78, 98], "framework": [7, 99], "rl": [7, 98, 99], "generalsatellitetask": [7, 20], "env_typ": 7, "environmentmodel": [7, 16, 17, 18, 28], "env_featur": [7, 10], "environmentfeatur": [7, 10, 11], "data_manag": [7, 10], "datamanag": [7, 10], "env_arg": 7, "str": [7, 10, 11, 13, 14, 15, 17, 22, 24, 53], "commun": [7, 12, 16, 34, 62], "communicationmethod": [7, 9], "sim_rat": 7, "max_step_dur": 7, "600": 7, "100": [7, 15, 18, 67], "time_limit": [7, 15], "inf": 7, "terminate_on_time_limit": 7, "fals": [7, 15, 16, 18, 22, 24, 27, 34, 38, 52, 53, 55, 69], "log_level": 7, "log_dir": 7, "render_mod": 7, "satob": 7, "satact": [7, 13], "adapt": 7, "wide": [7, 10], "rang": [7, 11, 25, 53, 62], "These": 7, "involv": 7, "complet": 7, "maintain": 7, "aliv": [7, 15, 16, 18, 22], "often": 7, "collect": [7, 10, 11, 22, 41, 44, 47], "configur": [7, 15, 22, 29, 30, 73], "heterogen": 7, "constel": [7, 34, 62], "other": [7, 15, 34, 38], "aspect": 7, "featur": [7, 11, 15, 67], "g": [7, 67], "record": [7, 10, 15, 24], "intersatellit": 7, "assign": 7, "prefer": 7, "method": [7, 15], "instanti": [7, 16, 17, 18, 34], "make": [7, 13, 15], "v1": 7, "pass": [7, 13, 14, 15, 18, 34, 69], "kwarg": [7, 13, 14, 15, 16, 17, 18, 24, 34, 53, 67, 69], "In": 7, "some": [7, 14, 73], "case": 7, "multiprocess": 7, "vector": [7, 14, 22, 89], "necessari": [7, 16, 17, 18], "compat": 7, "instead": [7, 18], "regist": 7, "new": [7, 10, 11, 15, 16, 17, 18, 98], "see": [7, 99], "should": [7, 15, 22, 24, 70, 98], "built": 7, "construct": [7, 9, 10, 11, 13, 14, 15, 16, 17, 18], "model": [7, 13, 15, 16, 17, 18, 22, 27, 52], "argument": [7, 13, 15, 22, 24, 25, 34], "kei": [7, 13, 15, 52, 82], "where": [7, 15, 44, 47, 53, 64], "about": [7, 10, 14], "manag": [7, 9, 10], "propag": 7, "nonposit": 7, "truncat": [7, 38, 44, 47], "send": 7, "signal": 7, "just": 7, "log": [7, 9, 10, 15, 22, 24, 69], "level": [7, 16, 38, 44, 47], "default": [7, 14, 15, 17, 18, 22, 24, 34], "warn": [7, 22], "directori": [7, 52, 53, 99], "write": [7, 29, 30], "addit": [7, 13, 15], "consol": 7, "unus": 7, "properti": [7, 11, 13, 14, 15, 16, 17, 18, 22, 27, 29, 30], "action_spac": [7, 13, 15, 67, 69], "iter": [7, 11, 53], "compos": [7, 9, 13, 14], "joint": 7, "close": [7, 15], "try": 7, "cleanli": 7, "delet": 7, "everyth": 7, "delete_simul": 7, "onli": [7, 9, 14, 15], "self": [7, 22], "strong": 7, "bsk": [7, 13, 37, 52, 62, 98, 99], "so": [7, 14, 34, 62], "enabl": [7, 15, 18], "verifi": 7, "fsw": [7, 13, 14, 15, 16, 19, 30, 31], "dynam": [7, 14, 15, 18, 19, 31, 55], "observation_spac": [7, 15, 67, 69], "note": [7, 15, 38], "expens": 7, "determin": [7, 9, 15, 24, 62], "render": [7, 52], "No": [7, 34], "implement": [7, 9], "reconstruct": 7, "wipe": 7, "get": [7, 11, 15, 24], "multiagentsatellitetask": 7, "parallelenv": 7, "agentid": 7, "pettingzoo": 7, "parallel": 7, "api": [7, 98], "certain": [7, 15], "current": [7, 15, 44, 47], "max_num_ag": 7, "possibl": 7, "num_ag": 7, "box": [7, 15, 44, 47], "possible_ag": 7, "previously_dead": 7, "di": 7, "least": 7, "ago": 7, "format": [7, 14, 24, 25, 34], "singlesatellitetask": 7, "arg": [7, 13, 14, 15, 24, 67, 69], "special": [7, 24], "standard": 7, "train": [7, 49, 51, 52, 53, 54, 98], "directli": 7, "expos": 7, "wrap": [7, 29, 30], "scenario": [8, 9, 10, 11, 13, 14, 15, 62], "util": [8, 22, 24, 25, 47, 49, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 82, 98], "abc": [9, 10, 11, 15, 16, 17, 18], "share": [9, 67, 69], "subclass": [9, 13, 14, 18], "wai": 9, "pair": [9, 22, 52], "freecommun": 9, "everi": [9, 24], "loscommun": 9, "direct": [9, 18], "sight": [9, 16], "todo": [9, 10], "befor": [9, 15, 24, 53], "latest": 9, "lo": 9, "sigh": 9, "clear": 9, "add": [9, 10, 13, 14, 15, 18, 27, 28, 55, 82], "logger": [9, 24], "track": 9, "losmulticommun": 9, "multidegreecommun": 9, "multidegre": 9, "anoth": [9, 10, 22, 34], "multi": [9, 34], "degre": 9, "also": [9, 38], "nocommun": 9, "calcul": [10, 15], "handl": [10, 15], "creation": [10, 18], "composit": 10, "multipl": [10, 73], "create_data_stor": 10, "refresh": 10, "cumul": 10, "new_data_dict": 10, "datatyp": [10, 14], "_calc_reward": 10, "datastor": 10, "One": [10, 16, 17, 18], "report": 10, "communication_upd": 10, "stage": 10, "external_data": 10, "internal_upd": 10, "stage_communicated_data": 10, "prepar": 10, "ad": [10, 13, 22, 24], "don": 10, "t": [10, 41, 52, 62], "yet": [10, 15], "unit": [10, 16, 67], "nadirscanningmanag": 10, "reward_fn": 10, "callabl": [10, 11, 14, 18, 22, 67, 69], "spent": 10, "scan": [10, 18], "nadir": [10, 11, 16, 18, 29, 30, 41], "alia": [10, 13, 15], "scanningnadirtimestor": 10, "spend": 10, "nadirscanningtimedata": 10, "scanning_tim": 10, "nodata": 10, "nodatamanag": 10, "nodatastor": 10, "uniqueimagedata": 10, "duplic": [10, 15], "uniqu": [10, 11, 15, 18], "known": 10, "count": 10, "uniqueimagestor": 10, "uniqueimagingmanag": 10, "lambda": 10, "avail": [11, 44, 47], "citytarget": 11, "n_target": [11, 62], "n_select_from": 11, "9223372036854775807": 11, "location_offset": 11, "priority_distribut": 11, "radiu": [11, 25, 64], "magicmock": [11, 25], "name": [11, 13, 15, 18, 22, 24, 25, 52, 53, 82, 89], "mock": [11, 25], "orbitalmot": 11, "req_earth": 11, "__mul__": 11, "id": [11, 13, 15, 25], "140255136257776": 11, "statictarget": 11, "distribut": [11, 64], "around": 11, "popul": [11, 57, 89], "center": 11, "static": 11, "top": 11, "n": [11, 15, 52, 64], "offset": 11, "randomli": 11, "citi": 11, "m": [11, 15, 16, 62, 99], "place": [11, 24], "bodi": [11, 16, 25, 27, 28, 44, 47, 64], "regenerate_target": 11, "regener": 11, "uniformli": [11, 63], "evenli": [11, 64], "locat": [11, 14, 15, 27, 28, 29, 30, 38, 47], "associ": 11, "identifi": [11, 15], "doe": [11, 15], "need": [11, 15, 38], "pcpf": [11, 15, 38], "metric": [11, 82], "human": [11, 14, 15], "readabl": [11, 14, 15], "uniformnadirfeatur": 11, "value_per_second": 11, "planet": [11, 16, 17, 18], "uniform": 11, "surfac": [11, 64], "second": 11, "lla2ecef": 11, "lat": 11, "long": 11, "project": 11, "lla": 11, "fix": [11, 25, 63], "deg": [11, 25, 62], "environment_featur": 12, "sat_act": 12, "sat_observ": 12, "chargingact": 13, "fswaction": [13, 15], "desatact": 13, "discretesatact": 13, "index": [13, 15, 34, 53, 57, 62], "order": [13, 15], "infer": [13, 14], "add_act": 13, "act_fn": 13, "act_nam": 13, "n_action": 13, "map": [13, 15, 29, 30, 44, 47, 64], "when": [13, 14, 15, 18, 22, 38], "keyword": [13, 22, 34], "prev_action_kei": 13, "retask": 13, "accept": [13, 22], "string": [13, 22, 24, 52, 62], "subsequ": 13, "generate_indexed_act": 13, "set_act": [13, 15], "my": 13, "downlinkact": 13, "driftact": 13, "imagingact": [13, 15], "n_ahead_act": [13, 15], "imagingsatellit": [13, 14, 15], "upcom": [13, 14, 15], "activ": [13, 52, 67, 69], "term": 13, "nadirimagingact": 13, "sat_arg": [13, 15], "variable_interv": [13, 15], "fsw_action_gen": 13, "fsw_action": 13, "action_dur": [13, 15], "1000000000": [13, 15], "eclipsest": 14, "orbit_period": 14, "5700": [14, 15], "satobserv": 14, "normal": [14, 16], "start": [14, 25], "factor": 14, "eclipse_st": 14, "groundstationst": 14, "n_ahead_observe_downlink": 14, "downlink_window_properti": 14, "accesssatellit": [14, 15], "opportun": [14, 15], "consid": [14, 41, 44, 47], "prop": 14, "prop_nam": 14, "norm": [14, 38], "specifi": [14, 24, 25, 27, 28, 38, 67], "choos": [14, 34, 38], "window_open": 14, "window_mid": 14, "window_clos": 14, "ground_station_obs_gener": 14, "ground_station_ob": 14, "spec": 14, "reset_post_sim": [14, 15], "checker": [14, 15, 22], "normdpropertyst": 14, "obs_properti": 14, "found": [14, 15, 98, 99], "append": [14, 24, 52], "form": 14, "block": 14, "python": [14, 98, 99], "modul": [14, 27, 29, 30, 67, 69], "add_prop_funct": 14, "queri": [14, 15], "hold": 14, "obs_typ": 14, "numpi": 14, "ndarrai": [14, 15, 22, 25], "add_to_observ": 14, "obs_el": 14, "get_ob": [14, 15], "obs_dict": 14, "cach": 14, "comput": [14, 15, 24, 25, 62], "timestep": 14, "obs_list": 14, "obs_ndarrai": 14, "targetst": 14, "n_ahead_observ": 14, "target_properti": 14, "target_obs_gener": 14, "target_ob": 14, "timest": [14, 15], "normalization_tim": 14, "durat": [14, 15], "normalized_tim": 14, "autodetect": 14, "generation_dur": 15, "initial_generation_dur": 15, "access_dist_threshold": 15, "4000000": 15, "detect": 15, "window": 15, "exhaust": 15, "unless": 15, "infinit": 15, "distanc": 15, "more": 15, "exactli": 15, "4e6": 15, "captur": 15, "elev": [15, 25, 62], "500": [15, 25, 55], "km": [15, 25], "constructor": 15, "add_location_for_access_check": 15, "min_elev": 15, "futur": 15, "calculate_additional_window": 15, "minimum": [15, 16, 17, 18], "angl": [15, 25], "rad": [15, 16, 17], "categori": 15, "multiroot": 15, "find": [15, 25], "find_next_opportun": 15, "pad": 15, "max_lookahead": 15, "filter": [15, 24, 47], "nearest": 15, "sort": 15, "less": 15, "exclud": 15, "dictionari": [15, 22, 24, 34, 52, 53, 82], "next_opportunities_dict": 15, "open": 15, "opportunities_dict": 15, "reset_pre_sim": 15, "upcoming_opportun": 15, "have": [15, 24], "upcoming_opportunities_dict": 15, "donothingsatellit": 15, "conveni": [15, 16, 18], "noth": 15, "dyn_typ": 15, "basicdynamicsmodel": [15, 16], "fsw_type": 15, "basicfswmodel": [15, 18], "fbimagersatellit": 15, "feedback": [15, 18], "control": [15, 18, 29, 30], "fullfeatureddynmodel": [15, 16], "imagingfswmodel": [15, 18], "fullfeaturedsatellit": 15, "steeringimagersatellit": 15, "common": [15, 29, 30], "imageaheadsatellit": 15, "capabl": 15, "stop": 15, "miss": 15, "imagingdynmodel": [15, 16], "enable_target_window": 15, "event": [15, 24, 25], "next_window": 15, "soonest": 15, "non": 15, "parse_target_select": 15, "target_queri": 15, "pars": 15, "taret": 15, "task_target_for_imag": 15, "upcoming_target": 15, "look": 15, "ahead": 15, "upcoming_window": 15, "via": 15, "abstract": [15, 16, 17, 18], "ignor": [15, 16, 17], "gymanisium": 15, "classmethod": [15, 17], "default_sat_arg": 15, "compil": [15, 17, 99], "is_al": [15, 16, 18], "log_failur": [15, 16, 18, 22], "check": [15, 16, 18, 22], "requir": [15, 16, 18, 38, 62, 82, 99], "log_info": 15, "process": [15, 18], "command": [15, 99], "among": 15, "thing": 15, "set_dynam": 15, "dyn_rat": [15, 16], "dynamicsmodel": [15, 16, 18], "set_fsw": 15, "fsw_rate": [15, 18], "fswmodel": [15, 18, 29, 30], "flight": [15, 18], "softwar": [15, 18], "set_simul": 15, "mrp": [15, 16, 18, 38], "steer": [15, 18], "steeringimagerfswmodel": [15, 18], "200": 16, "basic": [16, 17, 18], "compon": [16, 17, 18, 27], "bn": 16, "rel": [16, 17, 62], "inerti": [16, 17, 38, 41, 62, 63], "rotat": [16, 17, 38], "matrix": [16, 17], "bp": 16, "fream": 16, "battery_charg": 16, "w": [16, 38], "battery_charge_fract": 16, "fraction": 16, "capac": 16, "omega_bn_b": 16, "omega_bp_p": 16, "angular": [16, 17], "plant": 16, "r_bn_n": 16, "origin": [16, 63], "r_bn_p": 16, "sigma_bn": [16, 63], "v_bn_n": 16, "v_bn_p": 16, "p": 16, "deriv": 16, "r_bn": 16, "wheel_spe": 16, "wheel_speeds_fract": 16, "continuousimagingdynmodel": 16, "equip": 16, "continu": [16, 18], "instrument": [16, 18, 27, 29, 30], "storag": [16, 44, 47], "transmitt": [16, 27], "fail": [16, 18], "still": [16, 18], "reset_for_act": [16, 18], "whenev": 16, "groundstationdynmodel": 16, "loscommdynmodel": 16, "comm": 16, "connect": 16, "shut": 16, "off": 16, "sink": [16, 27], "storage_level": 16, "bit": 16, "storage_level_fract": 16, "basicenvironmentmodel": 17, "env_rat": 17, "300": 17, "pn": 17, "omega_pn_n": 17, "default_env_arg": 17, "argment": 17, "groundstationenvmodel": 17, "mrpcontroltask": 18, "80": 18, "templat": [18, 24], "contribut": 18, "nadirpointtask": 18, "98": 18, "rwdesattask": 18, "97": 18, "disabl": 18, "draw": [18, 27], "thruster": [18, 27, 29, 30, 55], "sunpointtask": 18, "99": 18, "trackingerrortask": 18, "convert": [18, 22, 29, 30], "guidanc": [18, 29, 30], "continuousimagingfswmodel": 18, "locpointtask": 18, "96": 18, "trigger": 18, "extend": [18, 20], "c_hat_p": 18, "steeringfswmodel": 18, "create_task": 18, "housekeep": 18, "overridden": 18, "func": [18, 22], "decor": [18, 22], "simbaseclass": 20, "aliveness_check": 22, "bind": 22, "instanc": [22, 55], "as_nam": 22, "exist": 22, "check_aliveness_check": 22, "search": [22, 52, 57], "statu": 22, "collect_default_arg": 22, "default_arg": 22, "cl": 22, "differ": [22, 29, 30, 44, 47], "init": 22, "enumer": 22, "is_properti": 22, "obj": 22, "attr_nam": 22, "without": 22, "safe_dict_merg": 22, "merg": 22, "conflict": 22, "modifi": [22, 24, 47, 52, 82], "valid_func_nam": 22, "valid": 22, "sanit": 22, "vectorize_nested_dict": 22, "flatten": 22, "arrai": [22, 62], "scalar": 22, "logging_config": 23, "contextfilt": 24, "proc_id": 24, "togeth": 24, "children": 24, "otherwis": 24, "deem": 24, "appropri": [24, 38], "mai": [24, 82, 99], "simformatt": 24, "color_output": 24, "formatt": 24, "describ": 24, "date": [24, 25], "datefmt": 24, "omit": 24, "iso8601": 24, "like": 24, "rfc": 24, "3339": 24, "style": 24, "want": 24, "version": 24, "text": [24, 73], "attribut": [24, 34, 55], "operand": 24, "oper": 24, "yield": 24, "coupl": 24, "preparatori": 24, "carri": 24, "out": 24, "messag": [24, 28, 29, 30], "logrecord": 24, "getmessag": 24, "usestim": 24, "formattim": 24, "except": [24, 36], "formatexcept": 24, "r_sat": 25, "r_target": 25, "random_epoch": 25, "2000": 25, "2022": 25, "epoch": [25, 53], "year": 25, "28": 25, "dai": 25, "month": 25, "final": [25, 52, 89], "yyyi": 25, "mmm": 25, "dd": 25, "hh": 25, "mm": 25, "ss": 25, "sss": 25, "utc": 25, "random_orbit": 25, "alt": 25, "r_bodi": 25, "6371": 25, "omega": 25, "f": [25, 52, 62], "classicel": 25, "140255387338736": 25, "element": [25, 62], "inclin": [25, 62], "pi": 25, "altitud": [25, 62], "eccentr": 25, "lan": 25, "2pi": 25, "periapsi": 25, "anomali": [25, 62], "multisat_agile_eo": [26, 27, 28, 29, 30, 31, 32, 33, 34], "multisensor_eo": [26, 36, 37, 38], "simple_eo": [26, 40, 41], "small_body_sci": [26, 43, 44], "small_body_science_pomdp": [26, 46, 47], "bsk_model": [27, 28, 29, 30, 35], "dynamicmodel": 27, "simbas": [27, 28, 29, 30], "dynrat": 27, "spacecraftindex": [27, 29, 30], "singlesat": 27, "initalldynobject": 27, "setbatteri": 27, "setdensitymodel": 27, "attach": 27, "densiti": 27, "effector": [27, 55], "setdisturbancetorqu": 27, "disturb": 27, "torqu": [27, 29, 30], "setdrageffector": 27, "drag": 27, "seteclipseobject": [27, 28], "setgravitybodi": [27, 28], "what": [27, 28], "gravit": [27, 28], "setgroundloc": [27, 28], "setinstru": 27, "setinstrumentpowersink": 27, "setreactionwheeldyneffector": 27, "rw": [27, 29, 30], "setreactionwheelpow": 27, "setsimplenavobject": 27, "navig": [27, 47], "setsolarpanel": 27, "solar": [27, 38], "panel": [27, 38], "setspacecrafthub": 27, "setthrusterdyneffector": 27, "settransmitt": 27, "settransmitterpowersink": 27, "trasmitt": 27, "envrat": 28, "celesti": 28, "caus": 28, "setepochobject": 28, "ephemeri": 28, "spice": 28, "librari": 28, "interest": 28, "fswrate": [29, 30], "initallfswobject": [29, 30], "setattitudetrackingerror": [29, 30], "setinstrumentcontrol": [29, 30], "setlocationpointguid": [29, 30], "setmrpfeedbackrwa": 29, "setmomentumdump": [29, 30], "momentum": [29, 30, 44, 47], "dump": [29, 30], "setnadirpointguid": [29, 30], "setrwconfigmsg": [29, 30], "import": [29, 30], "setrwmotortorqu": [29, 30], "motor": [29, 30], "law": [29, 30], "setsunpointguid": [29, 30], "setthrustermap": [29, 30], "setthrustersconfigmsg": [29, 30], "setvehicleconfigmsg": [29, 30], "vehicl": [29, 30], "setupgatewaymsg": [29, 30], "gatewai": [29, 30], "input": [29, 30, 67, 70], "msg": [29, 30], "down": [29, 30], "stream": [29, 30], "zerogatewaymsg": [29, 30], "payload": [29, 30], "setmrpsteeringrwa": 30, "fsw_steer": 31, "multisatagileeo": 34, "k": 34, "walker": [34, 62], "delta": [34, 62], "local": [34, 62], "multidiscret": 34, "same": 34, "twice": 34, "n_spacecraft": [34, 62], "x": [34, 52, 62], "dim_ob": 34, "nparrai": 34, "set_env_param": 34, "arbitrari": 34, "variabl": [34, 38], "overrid": 34, "set_param": 34, "n_plane": [34, 62], "rel_phas": [34, 62], "inc": [34, 62], "global_tgt": [34, 62], "comm_method": 34, "afterward": 34, "user": 34, "reset_init": 34, "sim_attr": 34, "present": 34, "match": 34, "simulatormkeyword": 34, "return_ob": [34, 47], "global": [34, 62], "purpos": 34, "update_spac": 34, "prealloc": 34, "env_set": [35, 39], "invalid_act": 36, "multisensoreo": [37, 38, 53], "correspond": 38, "sensor": 38, "result": [38, 52], "orient": 38, "toward": 38, "_": 38, "r_sc_i": 38, "v_sc": 38, "sigma_rb": 38, "respect": 38, "omega_bn": [38, 63], "bu": 38, "omega_rw": 38, "storedcharg": 38, "batcapac": 38, "sun_ind": 38, "flux": 38, "mitig": 38, "img_mod": 38, "correct": 38, "intend": 38, "rich": 38, "decai": 38, "sigma": 38, "simpleeo": [41, 52], "scienc": 41, "simpl": 41, "simpli": 41, "percent": 41, "plan": [41, 52, 98], "23": 41, "mb": 41, "t_max": 41, "1000": 41, "drain": 41, "smallbodysci": [44, 47], "target_compon": 44, "25": 44, "target_downlink_compon": 44, "map_compon": 44, "map_downlink_compon": 44, "small": [44, 47], "gym": [44, 47, 52], "transit": [44, 47], "waypoint": [44, 47, 64], "anti": [44, 47], "candid": [44, 47], "land": [44, 47], "site": [44, 47], "spectroscopi": [44, 47], "fuel": [44, 47], "collis": [44, 47], "necessarilli": 44, "dv": [44, 47], "consum": [44, 47], "17": [44, 47], "18": 44, "19": 44, "21": 44, "closest": 44, "unimag": 44, "region": [44, 47], "smallbodysciencepomdp": 47, "As": 47, "oppos": 47, "ekf": 47, "pomdp": 47, "belief": 47, "necessarili": 47, "20": 47, "26": 47, "covari": 47, "diagon": 47, "modify_ob": 47, "mdp": 47, "conform": 47, "sb3": [50, 53, 59, 67, 69, 70, 78, 91, 92, 94, 95, 98], "mcts_train": 51, "create_model": 52, "hidden_layer_num": 52, "net_siz": 52, "num_stat": [52, 67], "dropout": [52, 67], "alpha": [52, 67], "num_act": [52, 67], "feedforward": 52, "neural": [52, 82], "network": [52, 67, 69, 82], "subject": 52, "variou": [52, 98], "hyperparamet": [52, 53, 57], "hidden": 52, "layer": [52, 67, 70], "width": [52, 67], "leaki": 52, "relu": 52, "tanh": [52, 67, 69], "data_numb": 52, "split": 52, "load_and_modify_data": 52, "data_directori": 52, "modified_st": [52, 82], "AND": 52, "entri": [52, 82], "test": [52, 99], "load_data": 52, "mcts_batch": 52, "data_ind": 52, "50": 52, "result_list": 52, "v0": [52, 53, 57], "perform": [52, 82, 89], "horizon": 52, "filenam": 52, "constant": 52, "vizard": 52, "run_episod": 52, "q": 52, "estim": 52, "visit": 52, "sum": 52, "histori": 52, "exec_tim": 52, "final_info": 52, "infor": 52, "run_experi": 52, "batch_siz": [52, 53], "save": [52, 53], "plot": [52, 89], "a2c_experi": 53, "agent_dir": 53, "policy_kwarg": 53, "learning_r": 53, "0007": 53, "ent_coef": 53, "01": 53, "idx": 53, "n_it": 53, "base_step": 53, "1020": 53, "n_step": 53, "num_cor": [53, 57], "a2c": 53, "entropi": 53, "coeffici": 53, "core": 53, "ppo_experi": 53, "clip_rang": 53, "max_grad_norm": 53, "shield": [53, 68, 69], "ppo": 53, "clip": 53, "batch": 53, "run_ppo_experi": 53, "kwargs_list": 53, "experi": [54, 58], "effector_primit": [55, 59], "balancedhr16triad": 55, "userandom": 55, "randombound": 55, "400": 55, "wheelspe": 55, "three": 55, "hr16": 55, "thrusterfac": 55, "thrusterset": 55, "factori": 55, "idealmonarc1octet": 55, "eight": 55, "adc": 55, "moog": 55, "monarc": 55, "actuator_primit": 56, "run_ga_hp_experi": 57, "ga_dir": 57, "ga_kwarg": 57, "genet": 57, "leo_initial_condit": 60, "leo_orbit": 60, "sc_attitud": 60, "small_bodi": 60, "create_ground_tgt": 62, "rn": 62, "vn": 62, "sim_length": 62, "utc_init": 62, "simplifi": 62, "length": 62, "uct_init": 62, "distribute_tgt": 62, "dt": 62, "60": 62, "np": 62, "coordin": 62, "local_tgt": 62, "local_tgt_tim": 62, "encount": 62, "elrange_req": 62, "sc_po": 62, "tgt_po": 62, "express": 62, "el": 62, "inclined_400km": 62, "ellipt": 62, "prograd": 62, "leo": 62, "sma": 62, "400km": 62, "inclined_circular_300km": 62, "circular": 62, "random_inclined_circular_300km": 62, "sampled_400km": 62, "sampled_500km_boulder_g": 62, "500km": 62, "boulder": 62, "sampled_boulder_g": 62, "nominal_radiu": 62, "walker_delta": 62, "clusters": 62, "clusterspac": 62, "pattern": 62, "plane": 62, "phase": 62, "group": 62, "cluster": 62, "oe_al": 62, "oe": 62, "random_tumbl": 63, "maxspinr": 63, "001": 63, "tumbl": 63, "static_inerti": 63, "sider": 63, "stare": 63, "generate_imaging_point": 64, "num_point": 64, "generate_mapping_point": 64, "fibonnaci": 64, "sphere": 64, "http": 64, "stackoverflow": 64, "com": [64, 99], "question": 64, "9600801": 64, "generate_waypoint": 64, "num_spher": 64, "num_lat": 64, "num_lon": 64, "customactorcriticpolici": 67, "lr_schedul": [67, 69], "net_arch": [67, 69], "activation_fn": [67, 69], "torch": [67, 69], "nn": [67, 69], "actorcriticpolici": [67, 69], "intern": [67, 69], "both": [67, 69], "scriptmodul": [67, 69], "customnetwork": 67, "activation_funct": 67, "leakyrelu": 67, "custom": [67, 69, 70], "receiv": 67, "extract": 67, "extractor": 67, "feature_dim": 67, "dimens": 67, "features_extractor": 67, "cnn": 67, "last_layer_dim_pi": 67, "last_layer_dim_vf": 67, "tensor": [67, 69], "th": 67, "latent_polici": 67, "latent_valu": 67, "custom_sb3_polici": 68, "shielded_polici": 68, "customactorcriticshieldedagileeospolici": 69, "customactorcriticshieldedpolici": 69, "customactorcriticshieldedmultisensoreospolici": 69, "actor": 69, "critic": 69, "made": 69, "agileeosshield": 70, "size_in": 70, "equal": 70, "size_out": 70, "output": 70, "multisensoreosshield": 70, "multisat_aeo": 72, "satellite_custom": 72, "single_sat": 72, "here": [73, 99], "demonstr": 73, "ga_hp_solv": 77, "plotting_tool": [78, 84, 85, 86, 87, 88, 89, 90, 98], "mcts_data_gener": 79, "network_hyperparam_search": 79, "network_validation_multiprocess": 79, "modify_observ": 82, "run_simul": 82, "reward_specif": 82, "success_specif": 82, "downlink_util_specif": 82, "exec_time_specif": 82, "imaged_specif": 82, "downlinked_specif": 82, "ic": 82, "file": [82, 89], "success": 82, "plot_a2c_hyperparam": 83, "plot_dqn_hyperparam": 83, "plot_ga_hyperparam": 83, "plot_mcts_hyperparam": 83, "plot_ppo_hyperparam": 83, "process_ga_curv": 83, "process_sb3_curv": 83, "run_dir": 89, "ga": 89, "converg": 89, "behavior": 89, "checkpoint_nam": 89, "checkpoint": 89, "assum": 89, "pickl": 89, "a2c_hyperparam_search": 93, "dqn_hyperparam_search": 93, "ppo_hyperparam_search": 93, "sppo_hyperparam_search": 93, "state_machine_exampl": 96, "packag": [98, 99], "consist": 98, "script": 98, "emphasi": 98, "reinforc": 98, "instal": 98, "instruct": [98, 99], "clone": 99, "repo": 99, "git": 99, "github": 99, "avslab": 99, "virtual": 99, "venv": 99, "pip": 99, "finish_instal": 99, "depend": 99, "download": 99, "51": 99, "issu": 99, "chebpi": 99, "silicon": 99, "mac": 99, "pytest": 99}, "objects": {"": [[49, 0, 0, "-", "bsk_rl"], [78, 0, 0, "-", "examples"]], "bsk_rl": [[1, 0, 0, "-", "agents"], [26, 0, 0, "-", "envs"], [50, 0, 0, "-", "training"], [59, 0, 0, "-", "utilities"]], "bsk_rl.agents": [[0, 0, 0, "-", "genetic_algorithm"], [2, 0, 0, "-", "mcts"], [3, 0, 0, "-", "state_machine"]], "bsk_rl.agents.genetic_algorithm": [[0, 1, 1, "", "env2opt_problem"], [0, 3, 1, "", "mutUniformIntList"]], "bsk_rl.agents.genetic_algorithm.env2opt_problem": [[0, 2, 1, "", "__init__"], [0, 2, 1, "", "evaluate"]], "bsk_rl.agents.mcts": [[2, 1, 1, "", "MCTS"]], "bsk_rl.agents.mcts.MCTS": [[2, 2, 1, "", "__init__"], [2, 2, 1, "", "backup_tree"], [2, 2, 1, "", "rollout"], [2, 2, 1, "", "selectAction"], [2, 2, 1, "", "setEnv"], [2, 2, 1, "", "simulate"]], "bsk_rl.envs": [[6, 0, 0, "-", "agile_eos"], [8, 0, 0, "-", "general_satellite_tasking"], [35, 0, 0, "-", "multisat_agile_eos"], [39, 0, 0, "-", "multisensor_eos"], [42, 0, 0, "-", "simple_eos"], [45, 0, 0, "-", "small_body_science"], [48, 0, 0, "-", "small_body_science_pomdp"]], "bsk_rl.envs.agile_eos": [[4, 0, 0, "-", "bsk_sim"], [5, 0, 0, "-", "gym_env"]], "bsk_rl.envs.agile_eos.gym_env": [[5, 1, 1, "", "AgileEOS"]], "bsk_rl.envs.agile_eos.gym_env.AgileEOS": [[5, 2, 1, "", "__init__"], [5, 2, 1, "", "reset"], [5, 2, 1, "", "step"]], "bsk_rl.envs.general_satellite_tasking": [[7, 0, 0, "-", "gym_env"], [12, 0, 0, "-", "scenario"], [19, 0, 0, "-", "simulation"], [21, 0, 0, "-", "types"], [23, 0, 0, "-", "utils"]], "bsk_rl.envs.general_satellite_tasking.gym_env": [[7, 1, 1, "", "GeneralSatelliteTasking"], [7, 1, 1, "", "MultiagentSatelliteTasking"], [7, 1, 1, "", "SingleSatelliteTasking"]], "bsk_rl.envs.general_satellite_tasking.gym_env.GeneralSatelliteTasking": [[7, 2, 1, "", "__init__"], [7, 4, 1, "", "action_space"], [7, 2, 1, "", "close"], [7, 2, 1, "", "delete_simulator"], [7, 4, 1, "", "observation_space"], [7, 2, 1, "", "render"], [7, 2, 1, "", "reset"], [7, 2, 1, "", "step"]], "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking": [[7, 2, 1, "", "action_space"], [7, 4, 1, "", "action_spaces"], [7, 4, 1, "", "agents"], [7, 4, 1, "", "max_num_agents"], [7, 4, 1, "", "num_agents"], [7, 2, 1, "", "observation_space"], [7, 4, 1, "", "observation_spaces"], [7, 4, 1, "", "possible_agents"], [7, 4, 1, "", "previously_dead"], [7, 2, 1, "", "reset"], [7, 2, 1, "", "step"]], "bsk_rl.envs.general_satellite_tasking.gym_env.SingleSatelliteTasking": [[7, 2, 1, "", "__init__"], [7, 4, 1, "", "action_space"], [7, 4, 1, "", "observation_space"], [7, 4, 1, "", "satellite"], [7, 2, 1, "", "step"]], "bsk_rl.envs.general_satellite_tasking.scenario": [[9, 0, 0, "-", "communication"], [10, 0, 0, "-", "data"], [11, 0, 0, "-", "environment_features"], [13, 0, 0, "-", "sat_actions"], [14, 0, 0, "-", "sat_observations"], [15, 0, 0, "-", "satellites"]], "bsk_rl.envs.general_satellite_tasking.scenario.communication": [[9, 1, 1, "", "CommunicationMethod"], [9, 1, 1, "", "FreeCommunication"], [9, 1, 1, "", "LOSCommunication"], [9, 1, 1, "", "LOSMultiCommunication"], [9, 1, 1, "", "MultiDegreeCommunication"], [9, 1, 1, "", "NoCommunication"]], "bsk_rl.envs.general_satellite_tasking.scenario.communication.CommunicationMethod": [[9, 2, 1, "", "__init__"], [9, 2, 1, "", "communicate"], [9, 2, 1, "", "reset"]], "bsk_rl.envs.general_satellite_tasking.scenario.communication.LOSCommunication": [[9, 2, 1, "", "__init__"], [9, 2, 1, "", "communicate"], [9, 2, 1, "", "reset"]], "bsk_rl.envs.general_satellite_tasking.scenario.data": [[10, 1, 1, "", "DataManager"], [10, 1, 1, "", "DataStore"], [10, 1, 1, "", "DataType"], [10, 1, 1, "", "NadirScanningManager"], [10, 1, 1, "", "NadirScanningTimeData"], [10, 1, 1, "", "NoData"], [10, 1, 1, "", "NoDataManager"], [10, 1, 1, "", "NoDataStore"], [10, 1, 1, "", "ScanningNadirTimeStore"], [10, 1, 1, "", "UniqueImageData"], [10, 1, 1, "", "UniqueImageStore"], [10, 1, 1, "", "UniqueImagingManager"]], "bsk_rl.envs.general_satellite_tasking.scenario.data.DataManager": [[10, 2, 1, "", "__init__"], [10, 2, 1, "", "create_data_store"], [10, 2, 1, "", "reset"], [10, 2, 1, "", "reward"]], "bsk_rl.envs.general_satellite_tasking.scenario.data.DataStore": [[10, 2, 1, "", "__init__"], [10, 2, 1, "", "communication_update"], [10, 2, 1, "", "internal_update"], [10, 2, 1, "", "stage_communicated_data"]], "bsk_rl.envs.general_satellite_tasking.scenario.data.NadirScanningManager": [[10, 5, 1, "", "DataStore"], [10, 2, 1, "", "__init__"]], "bsk_rl.envs.general_satellite_tasking.scenario.data.NadirScanningTimeData": [[10, 2, 1, "", "__init__"]], "bsk_rl.envs.general_satellite_tasking.scenario.data.NoDataManager": [[10, 5, 1, "", "DataStore"]], "bsk_rl.envs.general_satellite_tasking.scenario.data.NoDataStore": [[10, 5, 1, "", "DataType"]], "bsk_rl.envs.general_satellite_tasking.scenario.data.ScanningNadirTimeStore": [[10, 5, 1, "", "DataType"]], "bsk_rl.envs.general_satellite_tasking.scenario.data.UniqueImageData": [[10, 2, 1, "", "__init__"]], "bsk_rl.envs.general_satellite_tasking.scenario.data.UniqueImageStore": [[10, 5, 1, "", "DataType"]], "bsk_rl.envs.general_satellite_tasking.scenario.data.UniqueImagingManager": [[10, 5, 1, "", "DataStore"], [10, 2, 1, "", "__init__"]], "bsk_rl.envs.general_satellite_tasking.scenario.environment_features": [[11, 1, 1, "", "CityTargets"], [11, 1, 1, "", "EnvironmentFeatures"], [11, 1, 1, "", "StaticTargets"], [11, 1, 1, "", "Target"], [11, 1, 1, "", "UniformNadirFeature"], [11, 3, 1, "", "lla2ecef"]], "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.CityTargets": [[11, 2, 1, "", "__init__"], [11, 2, 1, "", "regenerate_targets"]], "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.EnvironmentFeatures": [[11, 2, 1, "", "reset"]], "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.StaticTargets": [[11, 2, 1, "", "__init__"], [11, 2, 1, "", "regenerate_targets"], [11, 2, 1, "", "reset"]], "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.Target": [[11, 2, 1, "", "__init__"], [11, 4, 1, "", "id"]], "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.UniformNadirFeature": [[11, 2, 1, "", "__init__"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions": [[13, 5, 1, "", "ChargingAction"], [13, 5, 1, "", "DesatAction"], [13, 1, 1, "", "DiscreteSatAction"], [13, 5, 1, "", "DownlinkAction"], [13, 5, 1, "", "DriftAction"], [13, 1, 1, "", "ImagingActions"], [13, 5, 1, "", "NadirImagingAction"], [13, 1, 1, "", "SatAction"], [13, 3, 1, "", "fsw_action_gen"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.DiscreteSatAction": [[13, 2, 1, "", "__init__"], [13, 4, 1, "", "action_space"], [13, 2, 1, "", "add_action"], [13, 2, 1, "", "generate_indexed_action"], [13, 2, 1, "", "set_action"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.ImagingActions": [[13, 2, 1, "", "__init__"], [13, 2, 1, "", "image"], [13, 2, 1, "", "set_action"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations": [[14, 1, 1, "", "EclipseState"], [14, 1, 1, "", "GroundStationState"], [14, 1, 1, "", "NormdPropertyState"], [14, 1, 1, "", "SatObservation"], [14, 1, 1, "", "TargetState"], [14, 1, 1, "", "TimeState"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.EclipseState": [[14, 2, 1, "", "__init__"], [14, 2, 1, "", "eclipse_state"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.GroundStationState": [[14, 2, 1, "", "__init__"], [14, 2, 1, "", "ground_station_obs_generator"], [14, 2, 1, "", "reset_post_sim"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.NormdPropertyState": [[14, 2, 1, "", "__init__"], [14, 2, 1, "", "add_prop_function"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.SatObservation": [[14, 2, 1, "", "__init__"], [14, 2, 1, "", "add_to_observation"], [14, 2, 1, "", "get_obs"], [14, 4, 1, "", "obs_dict"], [14, 4, 1, "", "obs_list"], [14, 4, 1, "", "obs_ndarray"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.TargetState": [[14, 2, 1, "", "__init__"], [14, 2, 1, "", "target_obs_generator"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.TimeState": [[14, 2, 1, "", "__init__"], [14, 2, 1, "", "normalized_time"], [14, 2, 1, "", "reset_post_sim"]], "bsk_rl.envs.general_satellite_tasking.scenario.satellites": [[15, 1, 1, "", "AccessSatellite"], [15, 1, 1, "", "DoNothingSatellite"], [15, 1, 1, "", "FBImagerSatellite"], [15, 1, 1, "", "FullFeaturedSatellite"], [15, 1, 1, "", "ImageAheadSatellite"], [15, 1, 1, "", "ImagingSatellite"], [15, 1, 1, "", "Satellite"], [15, 1, 1, "", "SteeringImagerSatellite"]], "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite": [[15, 2, 1, "", "__init__"], [15, 2, 1, "", "add_location_for_access_checking"], [15, 2, 1, "", "calculate_additional_windows"], [15, 2, 1, "", "find_next_opportunities"], [15, 2, 1, "", "next_opportunities_dict"], [15, 2, 1, "", "opportunities_dict"], [15, 2, 1, "", "reset_post_sim"], [15, 2, 1, "", "reset_pre_sim"], [15, 4, 1, "", "upcoming_opportunities"], [15, 2, 1, "", "upcoming_opportunities_dict"]], "bsk_rl.envs.general_satellite_tasking.scenario.satellites.DoNothingSatellite": [[15, 5, 1, "", "dyn_type"], [15, 5, 1, "", "fsw_type"]], "bsk_rl.envs.general_satellite_tasking.scenario.satellites.FBImagerSatellite": [[15, 5, 1, "", "dyn_type"], [15, 5, 1, "", "fsw_type"]], "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite": [[15, 2, 1, "", "__init__"], [15, 5, 1, "", "dyn_type"], [15, 2, 1, "", "enable_target_window"], [15, 5, 1, "", "fsw_type"], [15, 4, 1, "", "next_windows"], [15, 2, 1, "", "parse_target_selection"], [15, 2, 1, "", "reset_post_sim"], [15, 2, 1, "", "reset_pre_sim"], [15, 2, 1, "", "task_target_for_imaging"], [15, 2, 1, "", "upcoming_targets"], [15, 4, 1, "", "upcoming_windows"], [15, 4, 1, "", "windows"]], "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite": [[15, 2, 1, "", "__init__"], [15, 4, 1, "", "action_space"], [15, 2, 1, "", "default_sat_args"], [15, 2, 1, "", "get_obs"], [15, 4, 1, "", "id"], [15, 2, 1, "", "is_alive"], [15, 2, 1, "", "log_info"], [15, 4, 1, "", "observation_space"], [15, 2, 1, "", "reset_post_sim"], [15, 2, 1, "", "reset_pre_sim"], [15, 2, 1, "", "set_action"], [15, 2, 1, "", "set_dynamics"], [15, 2, 1, "", "set_fsw"], [15, 2, 1, "", "set_simulator"]], "bsk_rl.envs.general_satellite_tasking.scenario.satellites.SteeringImagerSatellite": [[15, 5, 1, "", "dyn_type"], [15, 5, 1, "", "fsw_type"]], "bsk_rl.envs.general_satellite_tasking.simulation": [[16, 0, 0, "-", "dynamics"], [17, 0, 0, "-", "environment"], [18, 0, 0, "-", "fsw"], [20, 0, 0, "-", "simulator"]], "bsk_rl.envs.general_satellite_tasking.simulation.dynamics": [[16, 1, 1, "", "BasicDynamicsModel"], [16, 1, 1, "", "ContinuousImagingDynModel"], [16, 1, 1, "", "DynamicsModel"], [16, 1, 1, "", "FullFeaturedDynModel"], [16, 1, 1, "", "GroundStationDynModel"], [16, 1, 1, "", "ImagingDynModel"], [16, 1, 1, "", "LOSCommDynModel"]], "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel": [[16, 4, 1, "", "BN"], [16, 4, 1, "", "BP"], [16, 4, 1, "", "battery_charge"], [16, 4, 1, "", "battery_charge_fraction"], [16, 4, 1, "", "omega_BN_B"], [16, 4, 1, "", "omega_BP_P"], [16, 4, 1, "", "r_BN_N"], [16, 4, 1, "", "r_BN_P"], [16, 4, 1, "", "sigma_BN"], [16, 4, 1, "", "v_BN_N"], [16, 4, 1, "", "v_BN_P"], [16, 4, 1, "", "wheel_speeds"], [16, 4, 1, "", "wheel_speeds_fraction"]], "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.DynamicsModel": [[16, 2, 1, "", "__init__"], [16, 4, 1, "", "environment"], [16, 2, 1, "", "is_alive"], [16, 2, 1, "", "reset_for_action"], [16, 4, 1, "", "simulator"]], "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.ImagingDynModel": [[16, 2, 1, "", "reset_for_action"], [16, 4, 1, "", "storage_level"], [16, 4, 1, "", "storage_level_fraction"]], "bsk_rl.envs.general_satellite_tasking.simulation.environment": [[17, 1, 1, "", "BasicEnvironmentModel"], [17, 1, 1, "", "EnvironmentModel"], [17, 1, 1, "", "GroundStationEnvModel"]], "bsk_rl.envs.general_satellite_tasking.simulation.environment.BasicEnvironmentModel": [[17, 4, 1, "", "PN"], [17, 4, 1, "", "omega_PN_N"]], "bsk_rl.envs.general_satellite_tasking.simulation.environment.EnvironmentModel": [[17, 2, 1, "", "__init__"], [17, 2, 1, "", "default_env_args"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw": [[18, 1, 1, "", "BasicFSWModel"], [18, 1, 1, "", "ContinuousImagingFSWModel"], [18, 1, 1, "", "FSWModel"], [18, 1, 1, "", "ImagingFSWModel"], [18, 1, 1, "", "SteeringFSWModel"], [18, 1, 1, "", "SteeringImagerFSWModel"], [18, 1, 1, "", "Task"], [18, 3, 1, "", "action"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel": [[18, 1, 1, "", "MRPControlTask"], [18, 1, 1, "", "NadirPointTask"], [18, 1, 1, "", "RWDesatTask"], [18, 1, 1, "", "SunPointTask"], [18, 1, 1, "", "TrackingErrorTask"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.MRPControlTask": [[18, 2, 1, "", "__init__"], [18, 2, 1, "", "reset_for_action"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.NadirPointTask": [[18, 2, 1, "", "__init__"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.RWDesatTask": [[18, 2, 1, "", "__init__"], [18, 2, 1, "", "reset_for_action"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.SunPointTask": [[18, 2, 1, "", "__init__"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.TrackingErrorTask": [[18, 2, 1, "", "__init__"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ContinuousImagingFSWModel": [[18, 1, 1, "", "LocPointTask"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ContinuousImagingFSWModel.LocPointTask": [[18, 2, 1, "", "reset_for_action"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.FSWModel": [[18, 2, 1, "", "__init__"], [18, 4, 1, "", "dynamics"], [18, 4, 1, "", "environment"], [18, 2, 1, "", "is_alive"], [18, 4, 1, "", "simulator"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ImagingFSWModel": [[18, 1, 1, "", "LocPointTask"], [18, 4, 1, "", "c_hat_P"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ImagingFSWModel.LocPointTask": [[18, 2, 1, "", "__init__"], [18, 2, 1, "", "reset_for_action"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.SteeringFSWModel": [[18, 1, 1, "", "MRPControlTask"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.SteeringFSWModel.MRPControlTask": [[18, 2, 1, "", "__init__"], [18, 2, 1, "", "reset_for_action"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw.Task": [[18, 2, 1, "", "__init__"], [18, 2, 1, "", "create_task"], [18, 2, 1, "", "reset_for_action"]], "bsk_rl.envs.general_satellite_tasking.utils": [[22, 0, 0, "-", "functional"], [24, 0, 0, "-", "logging_config"], [25, 0, 0, "-", "orbital"]], "bsk_rl.envs.general_satellite_tasking.utils.functional": [[22, 3, 1, "", "aliveness_checker"], [22, 3, 1, "", "bind"], [22, 3, 1, "", "check_aliveness_checkers"], [22, 3, 1, "", "collect_default_args"], [22, 3, 1, "", "configurable"], [22, 3, 1, "", "default_args"], [22, 3, 1, "", "is_property"], [22, 3, 1, "", "safe_dict_merge"], [22, 3, 1, "", "valid_func_name"], [22, 3, 1, "", "vectorize_nested_dict"]], "bsk_rl.envs.general_satellite_tasking.utils.logging_config": [[24, 1, 1, "", "ContextFilter"], [24, 1, 1, "", "SimFormatter"]], "bsk_rl.envs.general_satellite_tasking.utils.logging_config.ContextFilter": [[24, 2, 1, "", "__init__"], [24, 2, 1, "", "filter"]], "bsk_rl.envs.general_satellite_tasking.utils.logging_config.SimFormatter": [[24, 2, 1, "", "__init__"], [24, 2, 1, "", "format"]], "bsk_rl.envs.general_satellite_tasking.utils.orbital": [[25, 3, 1, "", "elevation"], [25, 3, 1, "", "random_epoch"], [25, 3, 1, "", "random_orbit"]], "bsk_rl.envs.multisat_agile_eos": [[31, 0, 0, "-", "bsk_models"], [32, 0, 0, "-", "bsk_sim"], [33, 0, 0, "-", "env_settings"], [34, 0, 0, "-", "gym_env"]], "bsk_rl.envs.multisat_agile_eos.bsk_models": [[27, 0, 0, "-", "dynamics"], [28, 0, 0, "-", "environment"], [29, 0, 0, "-", "fsw"], [30, 0, 0, "-", "fsw_steering"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics": [[27, 1, 1, "", "DynamicModel"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel": [[27, 2, 1, "", "InitAllDynObjects"], [27, 2, 1, "", "SetBattery"], [27, 2, 1, "", "SetDensityModel"], [27, 2, 1, "", "SetDisturbanceTorque"], [27, 2, 1, "", "SetDragEffector"], [27, 2, 1, "", "SetEclipseObject"], [27, 2, 1, "", "SetGravityBodies"], [27, 2, 1, "", "SetGroundLocations"], [27, 2, 1, "", "SetInstrument"], [27, 2, 1, "", "SetInstrumentPowerSink"], [27, 2, 1, "", "SetReactionWheelDynEffector"], [27, 2, 1, "", "SetReactionWheelPower"], [27, 2, 1, "", "SetSimpleNavObject"], [27, 2, 1, "", "SetSolarPanel"], [27, 2, 1, "", "SetSpacecraftHub"], [27, 2, 1, "", "SetThrusterDynEffector"], [27, 2, 1, "", "SetTransmitter"], [27, 2, 1, "", "SetTransmitterPowerSink"], [27, 2, 1, "", "__init__"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.environment": [[28, 1, 1, "", "EnvironmentModel"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.environment.EnvironmentModel": [[28, 2, 1, "", "SetEclipseObject"], [28, 2, 1, "", "SetEpochObject"], [28, 2, 1, "", "SetGravityBodies"], [28, 2, 1, "", "SetGroundLocations"], [28, 2, 1, "", "__init__"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw": [[29, 1, 1, "", "FSWModel"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel": [[29, 2, 1, "", "InitAllFSWObjects"], [29, 2, 1, "", "SetAttitudeTrackingError"], [29, 2, 1, "", "SetInstrumentController"], [29, 2, 1, "", "SetLocationPointGuidance"], [29, 2, 1, "", "SetMRPFeedbackRWA"], [29, 2, 1, "", "SetMomentumDumping"], [29, 2, 1, "", "SetNadirPointGuidance"], [29, 2, 1, "", "SetRWConfigMsg"], [29, 2, 1, "", "SetRWMotorTorque"], [29, 2, 1, "", "SetSunPointGuidance"], [29, 2, 1, "", "SetThrusterMapping"], [29, 2, 1, "", "SetThrustersConfigMsg"], [29, 2, 1, "", "SetVehicleConfigMsg"], [29, 2, 1, "", "__init__"], [29, 2, 1, "", "setupGatewayMsgs"], [29, 2, 1, "", "zeroGateWayMsgs"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering": [[30, 1, 1, "", "FSWModel"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel": [[30, 2, 1, "", "InitAllFSWObjects"], [30, 2, 1, "", "SetAttitudeTrackingError"], [30, 2, 1, "", "SetInstrumentController"], [30, 2, 1, "", "SetLocationPointGuidance"], [30, 2, 1, "", "SetMRPSteeringRWA"], [30, 2, 1, "", "SetMomentumDumping"], [30, 2, 1, "", "SetNadirPointGuidance"], [30, 2, 1, "", "SetRWConfigMsg"], [30, 2, 1, "", "SetRWMotorTorque"], [30, 2, 1, "", "SetSunPointGuidance"], [30, 2, 1, "", "SetThrusterMapping"], [30, 2, 1, "", "SetThrustersConfigMsg"], [30, 2, 1, "", "SetVehicleConfigMsg"], [30, 2, 1, "", "__init__"], [30, 2, 1, "", "setupGatewayMsgs"], [30, 2, 1, "", "zeroGateWayMsgs"]], "bsk_rl.envs.multisat_agile_eos.gym_env": [[34, 1, 1, "", "MultiSatAgileEOS"]], "bsk_rl.envs.multisat_agile_eos.gym_env.MultiSatAgileEOS": [[34, 2, 1, "", "__init__"], [34, 2, 1, "", "reset"], [34, 2, 1, "", "set_env_params"], [34, 2, 1, "", "set_params"], [34, 2, 1, "", "sim_attrs"], [34, 2, 1, "", "step"], [34, 2, 1, "", "update_spaces"]], "bsk_rl.envs.multisensor_eos": [[36, 0, 0, "-", "bsk_sim"], [37, 0, 0, "-", "env_settings"], [38, 0, 0, "-", "gym_env"]], "bsk_rl.envs.multisensor_eos.bsk_sim": [[36, 6, 1, "", "invalid_action"]], "bsk_rl.envs.multisensor_eos.env_settings": [[37, 1, 1, "", "Settings"]], "bsk_rl.envs.multisensor_eos.env_settings.Settings": [[37, 2, 1, "", "__init__"]], "bsk_rl.envs.multisensor_eos.gym_env": [[38, 1, 1, "", "MultiSensorEOS"]], "bsk_rl.envs.multisensor_eos.gym_env.MultiSensorEOS": [[38, 2, 1, "", "__init__"], [38, 2, 1, "", "reset"], [38, 2, 1, "", "step"]], "bsk_rl.envs.simple_eos": [[40, 0, 0, "-", "bsk_sim"], [41, 0, 0, "-", "gym_env"]], "bsk_rl.envs.simple_eos.gym_env": [[41, 1, 1, "", "SimpleEOS"]], "bsk_rl.envs.simple_eos.gym_env.SimpleEOS": [[41, 2, 1, "", "__init__"], [41, 2, 1, "", "reset"], [41, 2, 1, "", "step"]], "bsk_rl.envs.small_body_science": [[43, 0, 0, "-", "bsk_sim"], [44, 0, 0, "-", "gym_env"]], "bsk_rl.envs.small_body_science.gym_env": [[44, 1, 1, "", "SmallBodyScience"]], "bsk_rl.envs.small_body_science.gym_env.SmallBodyScience": [[44, 2, 1, "", "__init__"], [44, 2, 1, "", "reset"], [44, 2, 1, "", "step"]], "bsk_rl.envs.small_body_science_pomdp": [[46, 0, 0, "-", "bsk_sim"], [47, 0, 0, "-", "gym_env"]], "bsk_rl.envs.small_body_science_pomdp.gym_env": [[47, 1, 1, "", "SmallBodySciencePOMDP"]], "bsk_rl.envs.small_body_science_pomdp.gym_env.SmallBodySciencePOMDP": [[47, 2, 1, "", "__init__"], [47, 2, 1, "", "modify_ob"], [47, 2, 1, "", "reset"], [47, 2, 1, "", "step"]], "bsk_rl.training": [[51, 0, 0, "-", "mcts"], [54, 0, 0, "-", "sb3"]], "bsk_rl.training.mcts": [[52, 0, 0, "-", "mcts_train"]], "bsk_rl.training.mcts.mcts_train": [[52, 3, 1, "", "create_model"], [52, 3, 1, "", "data_number"], [52, 3, 1, "", "load_and_modify_data"], [52, 3, 1, "", "load_data"], [52, 3, 1, "", "mcts_batch"], [52, 3, 1, "", "run_episode"], [52, 3, 1, "", "run_experiment"]], "bsk_rl.training.sb3": [[53, 0, 0, "-", "experiments"]], "bsk_rl.training.sb3.experiments": [[53, 3, 1, "", "a2c_experiment"], [53, 3, 1, "", "ppo_experiment"], [53, 3, 1, "", "run_ppo_experiments"]], "bsk_rl.utilities": [[56, 0, 0, "-", "effector_primitives"], [58, 0, 0, "-", "genetic_algorithm"], [60, 0, 0, "-", "initial_conditions"], [65, 0, 0, "-", "mcts"], [68, 0, 0, "-", "sb3"], [71, 0, 0, "-", "state_machine"]], "bsk_rl.utilities.effector_primitives": [[55, 0, 0, "-", "actuator_primitives"]], "bsk_rl.utilities.effector_primitives.actuator_primitives": [[55, 3, 1, "", "balancedHR16Triad"], [55, 3, 1, "", "idealMonarc1Octet"]], "bsk_rl.utilities.genetic_algorithm": [[57, 0, 0, "-", "experiments"]], "bsk_rl.utilities.genetic_algorithm.experiments": [[57, 3, 1, "", "run_ga_hp_experiment"]], "bsk_rl.utilities.initial_conditions": [[61, 0, 0, "-", "leo_initial_conditions"], [62, 0, 0, "-", "leo_orbit"], [63, 0, 0, "-", "sc_attitudes"], [64, 0, 0, "-", "small_body"]], "bsk_rl.utilities.initial_conditions.leo_orbit": [[62, 3, 1, "", "create_ground_tgts"], [62, 3, 1, "", "distribute_tgts"], [62, 3, 1, "", "elrange_req"], [62, 3, 1, "", "inclined_400km"], [62, 3, 1, "", "inclined_circular_300km"], [62, 3, 1, "", "random_inclined_circular_300km"], [62, 3, 1, "", "sampled_400km"], [62, 3, 1, "", "sampled_500km_boulder_gs"], [62, 3, 1, "", "sampled_boulder_gs"], [62, 3, 1, "", "walker_delta"]], "bsk_rl.utilities.initial_conditions.sc_attitudes": [[63, 3, 1, "", "random_tumble"], [63, 3, 1, "", "static_inertial"]], "bsk_rl.utilities.initial_conditions.small_body": [[64, 3, 1, "", "generate_imaging_points"], [64, 3, 1, "", "generate_mapping_points"], [64, 3, 1, "", "generate_waypoints"]], "bsk_rl.utilities.mcts": [[66, 0, 0, "-", "rollout_policies"]], "bsk_rl.utilities.sb3": [[67, 0, 0, "-", "custom_sb3_policies"], [69, 0, 0, "-", "shielded_policies"], [70, 0, 0, "-", "shields"]], "bsk_rl.utilities.sb3.custom_sb3_policies": [[67, 1, 1, "", "CustomActorCriticPolicy"], [67, 1, 1, "", "CustomNetwork"]], "bsk_rl.utilities.sb3.custom_sb3_policies.CustomActorCriticPolicy": [[67, 2, 1, "", "__init__"]], "bsk_rl.utilities.sb3.custom_sb3_policies.CustomNetwork": [[67, 2, 1, "", "__init__"], [67, 2, 1, "", "forward"]], "bsk_rl.utilities.sb3.shielded_policies": [[69, 1, 1, "", "CustomActorCriticShieldedAgileEOSPolicy"], [69, 1, 1, "", "CustomActorCriticShieldedMultiSensorEOSPolicy"], [69, 1, 1, "", "CustomActorCriticShieldedPolicy"]], "bsk_rl.utilities.sb3.shielded_policies.CustomActorCriticShieldedAgileEOSPolicy": [[69, 2, 1, "", "__init__"]], "bsk_rl.utilities.sb3.shielded_policies.CustomActorCriticShieldedMultiSensorEOSPolicy": [[69, 2, 1, "", "__init__"]], "bsk_rl.utilities.sb3.shielded_policies.CustomActorCriticShieldedPolicy": [[69, 2, 1, "", "__init__"], [69, 2, 1, "", "forward"]], "bsk_rl.utilities.sb3.shields": [[70, 1, 1, "", "AgileEOSShield"], [70, 1, 1, "", "MultiSensorEOSShield"]], "bsk_rl.utilities.sb3.shields.AgileEOSShield": [[70, 2, 1, "", "__init__"]], "bsk_rl.utilities.sb3.shields.MultiSensorEOSShield": [[70, 2, 1, "", "__init__"]], "examples": [[72, 0, 0, "-", "general_satellite_tasking"], [77, 0, 0, "-", "genetic_algorithm"], [79, 0, 0, "-", "mcts"], [83, 0, 0, "-", "plotting_tools"], [93, 0, 0, "-", "sb3"], [96, 0, 0, "-", "state_machine"]], "examples.general_satellite_tasking": [[73, 0, 0, "-", "multisat_aeos"], [74, 0, 0, "-", "satellite_customization"], [75, 0, 0, "-", "single_sat"]], "examples.general_satellite_tasking.multisat_aeos": [[73, 3, 1, "", "run"]], "examples.genetic_algorithm": [[76, 0, 0, "-", "ga_hp_solver"]], "examples.mcts": [[80, 0, 0, "-", "mcts_data_generator"], [81, 0, 0, "-", "network_hyperparam_search"], [82, 0, 0, "-", "network_validation_multiprocessing"]], "examples.mcts.network_validation_multiprocessing": [[82, 3, 1, "", "modify_observation"], [82, 3, 1, "", "run_simulator"]], "examples.plotting_tools": [[84, 0, 0, "-", "plot_a2c_hyperparams"], [85, 0, 0, "-", "plot_dqn_hyperparams"], [86, 0, 0, "-", "plot_ga_hyperparams"], [87, 0, 0, "-", "plot_mcts_hyperparams"], [88, 0, 0, "-", "plot_ppo_hyperparams"], [89, 0, 0, "-", "process_ga_curves"], [90, 0, 0, "-", "process_sb3_curves"]], "examples.plotting_tools.process_ga_curves": [[89, 3, 1, "", "process_ga_curve"]], "examples.sb3": [[91, 0, 0, "-", "a2c_hyperparam_search"], [92, 0, 0, "-", "dqn_hyperparam_search"], [94, 0, 0, "-", "ppo_hyperparam_search"], [95, 0, 0, "-", "sppo_hyperparam_search"]], "examples.state_machine": [[97, 0, 0, "-", "state_machine_example"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:function", "4": "py:property", "5": "py:attribute", "6": "py:exception"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "function", "Python function"], "4": ["py", "property", "Python property"], "5": ["py", "attribute", "Python attribute"], "6": ["py", "exception", "Python exception"]}, "titleterms": {"genetic_algorithm": [0, 58, 77], "agent": 1, "file": [1, 6, 8, 12, 19, 23, 31, 35, 39, 42, 45, 48, 51, 54, 56, 58, 60, 65, 68, 72, 77, 79, 83, 93, 96], "mct": [2, 51, 65, 79], "state_machin": [3, 71, 96], "bsk_sim": [4, 32, 36, 40, 43, 46], "gym_env": [5, 7, 34, 38, 41, 44, 47], "agile_eo": 6, "general_satellite_task": [8, 72], "directori": [8, 26, 35, 49, 50, 59, 78], "commun": 9, "data": 10, "environment_featur": 11, "scenario": 12, "sat_act": 13, "sat_observ": 14, "satellit": 15, "dynam": [16, 27], "environ": [17, 28], "fsw": [18, 29], "simul": [19, 20], "type": 21, "function": 22, "util": [23, 59], "logging_config": 24, "orbit": 25, "env": 26, "fsw_steer": 30, "bsk_model": 31, "env_set": [33, 37], "multisat_agile_eo": 35, "multisensor_eo": 39, "simple_eo": 42, "small_body_sci": 45, "small_body_science_pomdp": 48, "api": 49, "refer": 49, "train": 50, "mcts_train": 52, "experi": [53, 57], "sb3": [54, 68, 93], "actuator_primit": 55, "effector_primit": 56, "initial_condit": 60, "leo_initial_condit": 61, "leo_orbit": 62, "sc_attitud": 63, "small_bodi": 64, "rollout_polici": 66, "custom_sb3_polici": 67, "shielded_polici": 69, "shield": 70, "multisat_aeo": 73, "multisat": 73, "aeo": 73, "satellite_custom": 74, "single_sat": 75, "ga_hp_solv": 76, "exampl": 78, "mcts_data_gener": 80, "network_hyperparam_search": 81, "network_validation_multiprocess": 82, "plotting_tool": 83, "plot_a2c_hyperparam": 84, "plot_dqn_hyperparam": 85, "plot_ga_hyperparam": 86, "plot_mcts_hyperparam": 87, "plot_ppo_hyperparam": 88, "process_ga_curv": 89, "process_sb3_curv": 90, "a2c_hyperparam_search": 91, "dqn_hyperparam_search": 92, "ppo_hyperparam_search": 94, "sppo_hyperparam_search": 95, "state_machine_exampl": 97, "welcom": 98, "bsk_rl": 98, "": 98, "document": 98, "instal": 99}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx.ext.viewcode": 1, "sphinx": 60}, "alltitles": {"genetic_algorithm": [[0, "genetic-algorithm"], [58, "genetic-algorithm"], [77, "genetic-algorithm"]], "agents": [[1, "agents"]], "Files:": [[1, null], [6, null], [8, null], [12, null], [19, null], [23, null], [31, null], [35, null], [39, null], [42, null], [45, null], [48, null], [51, null], [54, null], [56, null], [58, null], [60, null], [65, null], [68, null], [72, null], [77, null], [79, null], [83, null], [93, null], [96, null]], "mcts": [[2, "mcts"], [51, "mcts"], [65, "mcts"], [79, "mcts"]], "state_machine": [[3, "state-machine"], [71, "state-machine"], [96, "state-machine"]], "bsk_sim": [[4, "bsk-sim"], [32, "bsk-sim"], [36, "bsk-sim"], [40, "bsk-sim"], [43, "bsk-sim"], [46, "bsk-sim"]], "gym_env": [[5, "gym-env"], [7, "gym-env"], [34, "gym-env"], [38, "gym-env"], [41, "gym-env"], [44, "gym-env"], [47, "gym-env"]], "agile_eos": [[6, "agile-eos"]], "general_satellite_tasking": [[8, "general-satellite-tasking"], [72, "general-satellite-tasking"]], "Directories:": [[8, null], [26, null], [35, null], [49, null], [50, null], [59, null], [78, null]], "communication": [[9, "communication"]], "data": [[10, "data"]], "environment_features": [[11, "environment-features"]], "scenario": [[12, "scenario"]], "sat_actions": [[13, "sat-actions"]], "sat_observations": [[14, "sat-observations"]], "satellites": [[15, "satellites"]], "dynamics": [[16, "dynamics"], [27, "dynamics"]], "environment": [[17, "environment"], [28, "environment"]], "fsw": [[18, "fsw"], [29, "fsw"]], "simulation": [[19, "simulation"]], "simulator": [[20, "simulator"]], "types": [[21, "types"]], "functional": [[22, "functional"]], "utils": [[23, "utils"]], "logging_config": [[24, "logging-config"]], "orbital": [[25, "orbital"]], "envs": [[26, "envs"]], "fsw_steering": [[30, "fsw-steering"]], "bsk_models": [[31, "bsk-models"]], "env_settings": [[33, "env-settings"], [37, "env-settings"]], "multisat_agile_eos": [[35, "multisat-agile-eos"]], "multisensor_eos": [[39, "multisensor-eos"]], "simple_eos": [[42, "simple-eos"]], "small_body_science": [[45, "small-body-science"]], "small_body_science_pomdp": [[48, "small-body-science-pomdp"]], "API Reference": [[49, "api-reference"]], "training": [[50, "training"]], "mcts_train": [[52, "mcts-train"]], "experiments": [[53, "experiments"], [57, "experiments"]], "sb3": [[54, "sb3"], [68, "sb3"], [93, "sb3"]], "actuator_primitives": [[55, "actuator-primitives"]], "effector_primitives": [[56, "effector-primitives"]], "utilities": [[59, "utilities"]], "initial_conditions": [[60, "initial-conditions"]], "leo_initial_conditions": [[61, "leo-initial-conditions"]], "leo_orbit": [[62, "leo-orbit"]], "sc_attitudes": [[63, "sc-attitudes"]], "small_body": [[64, "small-body"]], "rollout_policies": [[66, "rollout-policies"]], "custom_sb3_policies": [[67, "custom-sb3-policies"]], "shielded_policies": [[69, "shielded-policies"]], "shields": [[70, "shields"]], "multisat_aeos": [[73, "multisat-aeos"]], "Multisat AEOS": [[73, "module-examples.general_satellite_tasking.multisat_aeos"]], "satellite_customization": [[74, "satellite-customization"]], "single_sat": [[75, "single-sat"]], "ga_hp_solver": [[76, "ga-hp-solver"]], "Examples": [[78, "examples"]], "mcts_data_generator": [[80, "mcts-data-generator"]], "network_hyperparam_search": [[81, "network-hyperparam-search"]], "network_validation_multiprocessing": [[82, "network-validation-multiprocessing"]], "plotting_tools": [[83, "plotting-tools"]], "plot_a2c_hyperparams": [[84, "plot-a2c-hyperparams"]], "plot_dqn_hyperparams": [[85, "plot-dqn-hyperparams"]], "plot_ga_hyperparams": [[86, "plot-ga-hyperparams"]], "plot_mcts_hyperparams": [[87, "plot-mcts-hyperparams"]], "plot_ppo_hyperparams": [[88, "plot-ppo-hyperparams"]], "process_ga_curves": [[89, "process-ga-curves"]], "process_sb3_curves": [[90, "process-sb3-curves"]], "a2c_hyperparam_search": [[91, "a2c-hyperparam-search"]], "dqn_hyperparam_search": [[92, "dqn-hyperparam-search"]], "ppo_hyperparam_search": [[94, "ppo-hyperparam-search"]], "sppo_hyperparam_search": [[95, "sppo-hyperparam-search"]], "state_machine_example": [[97, "state-machine-example"]], "Welcome to bsk_rl\u2019s documentation!": [[98, "welcome-to-bsk-rl-s-documentation"]], "Installation": [[99, "installation"]]}, "indexentries": {"__init__() (env2opt_problem method)": [[0, "bsk_rl.agents.genetic_algorithm.env2opt_problem.__init__"]], "bsk_rl.agents.genetic_algorithm": [[0, "module-bsk_rl.agents.genetic_algorithm"]], "env2opt_problem (class in bsk_rl.agents.genetic_algorithm)": [[0, "bsk_rl.agents.genetic_algorithm.env2opt_problem"]], "evaluate() (env2opt_problem method)": [[0, "bsk_rl.agents.genetic_algorithm.env2opt_problem.evaluate"]], "module": [[0, "module-bsk_rl.agents.genetic_algorithm"], [1, "module-bsk_rl.agents"], [2, "module-bsk_rl.agents.mcts"], [3, "module-bsk_rl.agents.state_machine"], [4, "module-bsk_rl.envs.agile_eos.bsk_sim"], [5, "module-bsk_rl.envs.agile_eos.gym_env"], [6, "module-bsk_rl.envs.agile_eos"], [7, "module-bsk_rl.envs.general_satellite_tasking.gym_env"], [8, "module-bsk_rl.envs.general_satellite_tasking"], [9, "module-bsk_rl.envs.general_satellite_tasking.scenario.communication"], [10, "module-bsk_rl.envs.general_satellite_tasking.scenario.data"], [11, "module-bsk_rl.envs.general_satellite_tasking.scenario.environment_features"], [12, "module-bsk_rl.envs.general_satellite_tasking.scenario"], [13, "module-bsk_rl.envs.general_satellite_tasking.scenario.sat_actions"], [14, "module-bsk_rl.envs.general_satellite_tasking.scenario.sat_observations"], [15, "module-bsk_rl.envs.general_satellite_tasking.scenario.satellites"], [16, "module-bsk_rl.envs.general_satellite_tasking.simulation.dynamics"], [17, "module-bsk_rl.envs.general_satellite_tasking.simulation.environment"], [18, "module-bsk_rl.envs.general_satellite_tasking.simulation.fsw"], [19, "module-bsk_rl.envs.general_satellite_tasking.simulation"], [20, "module-bsk_rl.envs.general_satellite_tasking.simulation.simulator"], [21, "module-bsk_rl.envs.general_satellite_tasking.types"], [22, "module-bsk_rl.envs.general_satellite_tasking.utils.functional"], [23, "module-bsk_rl.envs.general_satellite_tasking.utils"], [24, "module-bsk_rl.envs.general_satellite_tasking.utils.logging_config"], [25, "module-bsk_rl.envs.general_satellite_tasking.utils.orbital"], [26, "module-bsk_rl.envs"], [27, "module-bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics"], [28, "module-bsk_rl.envs.multisat_agile_eos.bsk_models.environment"], [29, "module-bsk_rl.envs.multisat_agile_eos.bsk_models.fsw"], [30, "module-bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering"], [31, "module-bsk_rl.envs.multisat_agile_eos.bsk_models"], [32, "module-bsk_rl.envs.multisat_agile_eos.bsk_sim"], [33, "module-bsk_rl.envs.multisat_agile_eos.env_settings"], [34, "module-bsk_rl.envs.multisat_agile_eos.gym_env"], [35, "module-bsk_rl.envs.multisat_agile_eos"], [36, "module-bsk_rl.envs.multisensor_eos.bsk_sim"], [37, "module-bsk_rl.envs.multisensor_eos.env_settings"], [38, "module-bsk_rl.envs.multisensor_eos.gym_env"], [39, "module-bsk_rl.envs.multisensor_eos"], [40, "module-bsk_rl.envs.simple_eos.bsk_sim"], [41, "module-bsk_rl.envs.simple_eos.gym_env"], [42, "module-bsk_rl.envs.simple_eos"], [43, "module-bsk_rl.envs.small_body_science.bsk_sim"], [44, "module-bsk_rl.envs.small_body_science.gym_env"], [45, "module-bsk_rl.envs.small_body_science"], [46, "module-bsk_rl.envs.small_body_science_pomdp.bsk_sim"], [47, "module-bsk_rl.envs.small_body_science_pomdp.gym_env"], [48, "module-bsk_rl.envs.small_body_science_pomdp"], [49, "module-bsk_rl"], [50, "module-bsk_rl.training"], [51, "module-bsk_rl.training.mcts"], [52, "module-bsk_rl.training.mcts.mcts_train"], [53, "module-bsk_rl.training.sb3.experiments"], [54, "module-bsk_rl.training.sb3"], [55, "module-bsk_rl.utilities.effector_primitives.actuator_primitives"], [56, "module-bsk_rl.utilities.effector_primitives"], [57, "module-bsk_rl.utilities.genetic_algorithm.experiments"], [58, "module-bsk_rl.utilities.genetic_algorithm"], [59, "module-bsk_rl.utilities"], [60, "module-bsk_rl.utilities.initial_conditions"], [61, "module-bsk_rl.utilities.initial_conditions.leo_initial_conditions"], [62, "module-bsk_rl.utilities.initial_conditions.leo_orbit"], [63, "module-bsk_rl.utilities.initial_conditions.sc_attitudes"], [64, "module-bsk_rl.utilities.initial_conditions.small_body"], [65, "module-bsk_rl.utilities.mcts"], [66, "module-bsk_rl.utilities.mcts.rollout_policies"], [67, "module-bsk_rl.utilities.sb3.custom_sb3_policies"], [68, "module-bsk_rl.utilities.sb3"], [69, "module-bsk_rl.utilities.sb3.shielded_policies"], [70, "module-bsk_rl.utilities.sb3.shields"], [71, "module-bsk_rl.utilities.state_machine"], [72, "module-examples.general_satellite_tasking"], [73, "module-examples.general_satellite_tasking.multisat_aeos"], [74, "module-examples.general_satellite_tasking.satellite_customization"], [75, "module-examples.general_satellite_tasking.single_sat"], [76, "module-examples.genetic_algorithm.ga_hp_solver"], [77, "module-examples.genetic_algorithm"], [78, "module-examples"], [79, "module-examples.mcts"], [80, "module-examples.mcts.mcts_data_generator"], [81, "module-examples.mcts.network_hyperparam_search"], [82, "module-examples.mcts.network_validation_multiprocessing"], [83, "module-examples.plotting_tools"], [84, "module-examples.plotting_tools.plot_a2c_hyperparams"], [85, "module-examples.plotting_tools.plot_dqn_hyperparams"], [86, "module-examples.plotting_tools.plot_ga_hyperparams"], [87, "module-examples.plotting_tools.plot_mcts_hyperparams"], [88, "module-examples.plotting_tools.plot_ppo_hyperparams"], [89, "module-examples.plotting_tools.process_ga_curves"], [90, "module-examples.plotting_tools.process_sb3_curves"], [91, "module-examples.sb3.a2c_hyperparam_search"], [92, "module-examples.sb3.dqn_hyperparam_search"], [93, "module-examples.sb3"], [94, "module-examples.sb3.ppo_hyperparam_search"], [95, "module-examples.sb3.sppo_hyperparam_search"], [96, "module-examples.state_machine"], [97, "module-examples.state_machine.state_machine_example"]], "mutuniformintlist() (in module bsk_rl.agents.genetic_algorithm)": [[0, "bsk_rl.agents.genetic_algorithm.mutUniformIntList"]], "bsk_rl.agents": [[1, "module-bsk_rl.agents"]], "mcts (class in bsk_rl.agents.mcts)": [[2, "bsk_rl.agents.mcts.MCTS"]], "__init__() (mcts method)": [[2, "bsk_rl.agents.mcts.MCTS.__init__"]], "backup_tree() (mcts method)": [[2, "bsk_rl.agents.mcts.MCTS.backup_tree"]], "bsk_rl.agents.mcts": [[2, "module-bsk_rl.agents.mcts"]], "rollout() (mcts method)": [[2, "bsk_rl.agents.mcts.MCTS.rollout"]], "selectaction() (mcts method)": [[2, "bsk_rl.agents.mcts.MCTS.selectAction"]], "setenv() (mcts method)": [[2, "bsk_rl.agents.mcts.MCTS.setEnv"]], "simulate() (mcts method)": [[2, "bsk_rl.agents.mcts.MCTS.simulate"]], "bsk_rl.agents.state_machine": [[3, "module-bsk_rl.agents.state_machine"]], "bsk_rl.envs.agile_eos.bsk_sim": [[4, "module-bsk_rl.envs.agile_eos.bsk_sim"]], "agileeos (class in bsk_rl.envs.agile_eos.gym_env)": [[5, "bsk_rl.envs.agile_eos.gym_env.AgileEOS"]], "__init__() (agileeos method)": [[5, "bsk_rl.envs.agile_eos.gym_env.AgileEOS.__init__"]], "bsk_rl.envs.agile_eos.gym_env": [[5, "module-bsk_rl.envs.agile_eos.gym_env"]], "reset() (agileeos method)": [[5, "bsk_rl.envs.agile_eos.gym_env.AgileEOS.reset"]], "step() (agileeos method)": [[5, "bsk_rl.envs.agile_eos.gym_env.AgileEOS.step"]], "bsk_rl.envs.agile_eos": [[6, "module-bsk_rl.envs.agile_eos"]], "generalsatellitetasking (class in bsk_rl.envs.general_satellite_tasking.gym_env)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.GeneralSatelliteTasking"]], "multiagentsatellitetasking (class in bsk_rl.envs.general_satellite_tasking.gym_env)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking"]], "singlesatellitetasking (class in bsk_rl.envs.general_satellite_tasking.gym_env)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.SingleSatelliteTasking"]], "__init__() (generalsatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.GeneralSatelliteTasking.__init__"]], "__init__() (singlesatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.SingleSatelliteTasking.__init__"]], "action_space (generalsatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.GeneralSatelliteTasking.action_space"]], "action_space (singlesatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.SingleSatelliteTasking.action_space"]], "action_space() (multiagentsatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.action_space"]], "action_spaces (multiagentsatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.action_spaces"]], "agents (multiagentsatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.agents"]], "bsk_rl.envs.general_satellite_tasking.gym_env": [[7, "module-bsk_rl.envs.general_satellite_tasking.gym_env"]], "close() (generalsatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.GeneralSatelliteTasking.close"]], "delete_simulator() (generalsatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.GeneralSatelliteTasking.delete_simulator"]], "max_num_agents (multiagentsatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.max_num_agents"]], "num_agents (multiagentsatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.num_agents"]], "observation_space (generalsatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.GeneralSatelliteTasking.observation_space"]], "observation_space (singlesatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.SingleSatelliteTasking.observation_space"]], "observation_space() (multiagentsatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.observation_space"]], "observation_spaces (multiagentsatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.observation_spaces"]], "possible_agents (multiagentsatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.possible_agents"]], "previously_dead (multiagentsatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.previously_dead"]], "render() (generalsatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.GeneralSatelliteTasking.render"]], "reset() (generalsatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.GeneralSatelliteTasking.reset"]], "reset() (multiagentsatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.reset"]], "satellite (singlesatellitetasking property)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.SingleSatelliteTasking.satellite"]], "step() (generalsatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.GeneralSatelliteTasking.step"]], "step() (multiagentsatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.MultiagentSatelliteTasking.step"]], "step() (singlesatellitetasking method)": [[7, "bsk_rl.envs.general_satellite_tasking.gym_env.SingleSatelliteTasking.step"]], "bsk_rl.envs.general_satellite_tasking": [[8, "module-bsk_rl.envs.general_satellite_tasking"]], "communicationmethod (class in bsk_rl.envs.general_satellite_tasking.scenario.communication)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.CommunicationMethod"]], "freecommunication (class in bsk_rl.envs.general_satellite_tasking.scenario.communication)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.FreeCommunication"]], "loscommunication (class in bsk_rl.envs.general_satellite_tasking.scenario.communication)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.LOSCommunication"]], "losmulticommunication (class in bsk_rl.envs.general_satellite_tasking.scenario.communication)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.LOSMultiCommunication"]], "multidegreecommunication (class in bsk_rl.envs.general_satellite_tasking.scenario.communication)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.MultiDegreeCommunication"]], "nocommunication (class in bsk_rl.envs.general_satellite_tasking.scenario.communication)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.NoCommunication"]], "__init__() (communicationmethod method)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.CommunicationMethod.__init__"]], "__init__() (loscommunication method)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.LOSCommunication.__init__"]], "bsk_rl.envs.general_satellite_tasking.scenario.communication": [[9, "module-bsk_rl.envs.general_satellite_tasking.scenario.communication"]], "communicate() (communicationmethod method)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.CommunicationMethod.communicate"]], "communicate() (loscommunication method)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.LOSCommunication.communicate"]], "reset() (communicationmethod method)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.CommunicationMethod.reset"]], "reset() (loscommunication method)": [[9, "bsk_rl.envs.general_satellite_tasking.scenario.communication.LOSCommunication.reset"]], "datamanager (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataManager"]], "datastore (nadirscanningmanager attribute)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.NadirScanningManager.DataStore"]], "datastore (nodatamanager attribute)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.NoDataManager.DataStore"]], "datastore (uniqueimagingmanager attribute)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.UniqueImagingManager.DataStore"]], "datastore (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataStore"]], "datatype (nodatastore attribute)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.NoDataStore.DataType"]], "datatype (scanningnadirtimestore attribute)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.ScanningNadirTimeStore.DataType"]], "datatype (uniqueimagestore attribute)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.UniqueImageStore.DataType"]], "datatype (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataType"]], "nadirscanningmanager (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.NadirScanningManager"]], "nadirscanningtimedata (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.NadirScanningTimeData"]], "nodata (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.NoData"]], "nodatamanager (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.NoDataManager"]], "nodatastore (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.NoDataStore"]], "scanningnadirtimestore (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.ScanningNadirTimeStore"]], "uniqueimagedata (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.UniqueImageData"]], "uniqueimagestore (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.UniqueImageStore"]], "uniqueimagingmanager (class in bsk_rl.envs.general_satellite_tasking.scenario.data)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.UniqueImagingManager"]], "__init__() (datamanager method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataManager.__init__"]], "__init__() (datastore method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataStore.__init__"]], "__init__() (nadirscanningmanager method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.NadirScanningManager.__init__"]], "__init__() (nadirscanningtimedata method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.NadirScanningTimeData.__init__"]], "__init__() (uniqueimagedata method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.UniqueImageData.__init__"]], "__init__() (uniqueimagingmanager method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.UniqueImagingManager.__init__"]], "bsk_rl.envs.general_satellite_tasking.scenario.data": [[10, "module-bsk_rl.envs.general_satellite_tasking.scenario.data"]], "communication_update() (datastore method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataStore.communication_update"]], "create_data_store() (datamanager method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataManager.create_data_store"]], "internal_update() (datastore method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataStore.internal_update"]], "reset() (datamanager method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataManager.reset"]], "reward() (datamanager method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataManager.reward"]], "stage_communicated_data() (datastore method)": [[10, "bsk_rl.envs.general_satellite_tasking.scenario.data.DataStore.stage_communicated_data"]], "citytargets (class in bsk_rl.envs.general_satellite_tasking.scenario.environment_features)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.CityTargets"]], "environmentfeatures (class in bsk_rl.envs.general_satellite_tasking.scenario.environment_features)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.EnvironmentFeatures"]], "statictargets (class in bsk_rl.envs.general_satellite_tasking.scenario.environment_features)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.StaticTargets"]], "target (class in bsk_rl.envs.general_satellite_tasking.scenario.environment_features)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.Target"]], "uniformnadirfeature (class in bsk_rl.envs.general_satellite_tasking.scenario.environment_features)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.UniformNadirFeature"]], "__init__() (citytargets method)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.CityTargets.__init__"]], "__init__() (statictargets method)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.StaticTargets.__init__"]], "__init__() (target method)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.Target.__init__"]], "__init__() (uniformnadirfeature method)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.UniformNadirFeature.__init__"]], "bsk_rl.envs.general_satellite_tasking.scenario.environment_features": [[11, "module-bsk_rl.envs.general_satellite_tasking.scenario.environment_features"]], "id (target property)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.Target.id"]], "lla2ecef() (in module bsk_rl.envs.general_satellite_tasking.scenario.environment_features)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.lla2ecef"]], "regenerate_targets() (citytargets method)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.CityTargets.regenerate_targets"]], "regenerate_targets() (statictargets method)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.StaticTargets.regenerate_targets"]], "reset() (environmentfeatures method)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.EnvironmentFeatures.reset"]], "reset() (statictargets method)": [[11, "bsk_rl.envs.general_satellite_tasking.scenario.environment_features.StaticTargets.reset"]], "bsk_rl.envs.general_satellite_tasking.scenario": [[12, "module-bsk_rl.envs.general_satellite_tasking.scenario"]], "chargingaction (in module bsk_rl.envs.general_satellite_tasking.scenario.sat_actions)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.ChargingAction"]], "desataction (in module bsk_rl.envs.general_satellite_tasking.scenario.sat_actions)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.DesatAction"]], "discretesataction (class in bsk_rl.envs.general_satellite_tasking.scenario.sat_actions)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.DiscreteSatAction"]], "downlinkaction (in module bsk_rl.envs.general_satellite_tasking.scenario.sat_actions)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.DownlinkAction"]], "driftaction (in module bsk_rl.envs.general_satellite_tasking.scenario.sat_actions)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.DriftAction"]], "imagingactions (class in bsk_rl.envs.general_satellite_tasking.scenario.sat_actions)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.ImagingActions"]], "nadirimagingaction (in module bsk_rl.envs.general_satellite_tasking.scenario.sat_actions)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.NadirImagingAction"]], "sataction (class in bsk_rl.envs.general_satellite_tasking.scenario.sat_actions)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.SatAction"]], "__init__() (discretesataction method)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.DiscreteSatAction.__init__"]], "__init__() (imagingactions method)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.ImagingActions.__init__"]], "action_space (discretesataction property)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.DiscreteSatAction.action_space"]], "add_action() (discretesataction method)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.DiscreteSatAction.add_action"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions": [[13, "module-bsk_rl.envs.general_satellite_tasking.scenario.sat_actions"]], "fsw_action_gen() (in module bsk_rl.envs.general_satellite_tasking.scenario.sat_actions)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.fsw_action_gen"]], "generate_indexed_action() (discretesataction method)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.DiscreteSatAction.generate_indexed_action"]], "image() (imagingactions method)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.ImagingActions.image"]], "set_action() (discretesataction method)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.DiscreteSatAction.set_action"]], "set_action() (imagingactions method)": [[13, "bsk_rl.envs.general_satellite_tasking.scenario.sat_actions.ImagingActions.set_action"]], "eclipsestate (class in bsk_rl.envs.general_satellite_tasking.scenario.sat_observations)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.EclipseState"]], "groundstationstate (class in bsk_rl.envs.general_satellite_tasking.scenario.sat_observations)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.GroundStationState"]], "normdpropertystate (class in bsk_rl.envs.general_satellite_tasking.scenario.sat_observations)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.NormdPropertyState"]], "satobservation (class in bsk_rl.envs.general_satellite_tasking.scenario.sat_observations)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.SatObservation"]], "targetstate (class in bsk_rl.envs.general_satellite_tasking.scenario.sat_observations)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.TargetState"]], "timestate (class in bsk_rl.envs.general_satellite_tasking.scenario.sat_observations)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.TimeState"]], "__init__() (eclipsestate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.EclipseState.__init__"]], "__init__() (groundstationstate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.GroundStationState.__init__"]], "__init__() (normdpropertystate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.NormdPropertyState.__init__"]], "__init__() (satobservation method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.SatObservation.__init__"]], "__init__() (targetstate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.TargetState.__init__"]], "__init__() (timestate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.TimeState.__init__"]], "add_prop_function() (normdpropertystate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.NormdPropertyState.add_prop_function"]], "add_to_observation() (satobservation method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.SatObservation.add_to_observation"]], "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations": [[14, "module-bsk_rl.envs.general_satellite_tasking.scenario.sat_observations"]], "eclipse_state() (eclipsestate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.EclipseState.eclipse_state"]], "get_obs() (satobservation method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.SatObservation.get_obs"]], "ground_station_obs_generator() (groundstationstate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.GroundStationState.ground_station_obs_generator"]], "normalized_time() (timestate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.TimeState.normalized_time"]], "obs_dict (satobservation property)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.SatObservation.obs_dict"]], "obs_list (satobservation property)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.SatObservation.obs_list"]], "obs_ndarray (satobservation property)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.SatObservation.obs_ndarray"]], "reset_post_sim() (groundstationstate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.GroundStationState.reset_post_sim"]], "reset_post_sim() (timestate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.TimeState.reset_post_sim"]], "target_obs_generator() (targetstate method)": [[14, "bsk_rl.envs.general_satellite_tasking.scenario.sat_observations.TargetState.target_obs_generator"]], "accesssatellite (class in bsk_rl.envs.general_satellite_tasking.scenario.satellites)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite"]], "donothingsatellite (class in bsk_rl.envs.general_satellite_tasking.scenario.satellites)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.DoNothingSatellite"]], "fbimagersatellite (class in bsk_rl.envs.general_satellite_tasking.scenario.satellites)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.FBImagerSatellite"]], "fullfeaturedsatellite (class in bsk_rl.envs.general_satellite_tasking.scenario.satellites)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.FullFeaturedSatellite"]], "imageaheadsatellite (class in bsk_rl.envs.general_satellite_tasking.scenario.satellites)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImageAheadSatellite"]], "imagingsatellite (class in bsk_rl.envs.general_satellite_tasking.scenario.satellites)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite"]], "satellite (class in bsk_rl.envs.general_satellite_tasking.scenario.satellites)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite"]], "steeringimagersatellite (class in bsk_rl.envs.general_satellite_tasking.scenario.satellites)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.SteeringImagerSatellite"]], "__init__() (accesssatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite.__init__"]], "__init__() (imagingsatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.__init__"]], "__init__() (satellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.__init__"]], "action_space (satellite property)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.action_space"]], "add_location_for_access_checking() (accesssatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite.add_location_for_access_checking"]], "bsk_rl.envs.general_satellite_tasking.scenario.satellites": [[15, "module-bsk_rl.envs.general_satellite_tasking.scenario.satellites"]], "calculate_additional_windows() (accesssatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite.calculate_additional_windows"]], "default_sat_args() (satellite class method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.default_sat_args"]], "dyn_type (donothingsatellite attribute)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.DoNothingSatellite.dyn_type"]], "dyn_type (fbimagersatellite attribute)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.FBImagerSatellite.dyn_type"]], "dyn_type (imagingsatellite attribute)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.dyn_type"]], "dyn_type (steeringimagersatellite attribute)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.SteeringImagerSatellite.dyn_type"]], "enable_target_window() (imagingsatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.enable_target_window"]], "find_next_opportunities() (accesssatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite.find_next_opportunities"]], "fsw_type (donothingsatellite attribute)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.DoNothingSatellite.fsw_type"]], "fsw_type (fbimagersatellite attribute)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.FBImagerSatellite.fsw_type"]], "fsw_type (imagingsatellite attribute)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.fsw_type"]], "fsw_type (steeringimagersatellite attribute)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.SteeringImagerSatellite.fsw_type"]], "get_obs() (satellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.get_obs"]], "id (satellite property)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.id"]], "is_alive() (satellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.is_alive"]], "log_info() (satellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.log_info"]], "next_opportunities_dict() (accesssatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite.next_opportunities_dict"]], "next_windows (imagingsatellite property)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.next_windows"]], "observation_space (satellite property)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.observation_space"]], "opportunities_dict() (accesssatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite.opportunities_dict"]], "parse_target_selection() (imagingsatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.parse_target_selection"]], "reset_post_sim() (accesssatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite.reset_post_sim"]], "reset_post_sim() (imagingsatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.reset_post_sim"]], "reset_post_sim() (satellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.reset_post_sim"]], "reset_pre_sim() (accesssatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite.reset_pre_sim"]], "reset_pre_sim() (imagingsatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.reset_pre_sim"]], "reset_pre_sim() (satellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.reset_pre_sim"]], "set_action() (satellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.set_action"]], "set_dynamics() (satellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.set_dynamics"]], "set_fsw() (satellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.set_fsw"]], "set_simulator() (satellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.Satellite.set_simulator"]], "task_target_for_imaging() (imagingsatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.task_target_for_imaging"]], "upcoming_opportunities (accesssatellite property)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite.upcoming_opportunities"]], "upcoming_opportunities_dict() (accesssatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.AccessSatellite.upcoming_opportunities_dict"]], "upcoming_targets() (imagingsatellite method)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.upcoming_targets"]], "upcoming_windows (imagingsatellite property)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.upcoming_windows"]], "windows (imagingsatellite property)": [[15, "bsk_rl.envs.general_satellite_tasking.scenario.satellites.ImagingSatellite.windows"]], "bn (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.BN"]], "bp (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.BP"]], "basicdynamicsmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.dynamics)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel"]], "continuousimagingdynmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.dynamics)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.ContinuousImagingDynModel"]], "dynamicsmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.dynamics)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.DynamicsModel"]], "fullfeatureddynmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.dynamics)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.FullFeaturedDynModel"]], "groundstationdynmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.dynamics)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.GroundStationDynModel"]], "imagingdynmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.dynamics)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.ImagingDynModel"]], "loscommdynmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.dynamics)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.LOSCommDynModel"]], "__init__() (dynamicsmodel method)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.DynamicsModel.__init__"]], "battery_charge (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.battery_charge"]], "battery_charge_fraction (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.battery_charge_fraction"]], "bsk_rl.envs.general_satellite_tasking.simulation.dynamics": [[16, "module-bsk_rl.envs.general_satellite_tasking.simulation.dynamics"]], "environment (dynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.DynamicsModel.environment"]], "is_alive() (dynamicsmodel method)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.DynamicsModel.is_alive"]], "omega_bn_b (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.omega_BN_B"]], "omega_bp_p (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.omega_BP_P"]], "r_bn_n (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.r_BN_N"]], "r_bn_p (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.r_BN_P"]], "reset_for_action() (dynamicsmodel method)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.DynamicsModel.reset_for_action"]], "reset_for_action() (imagingdynmodel method)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.ImagingDynModel.reset_for_action"]], "sigma_bn (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.sigma_BN"]], "simulator (dynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.DynamicsModel.simulator"]], "storage_level (imagingdynmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.ImagingDynModel.storage_level"]], "storage_level_fraction (imagingdynmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.ImagingDynModel.storage_level_fraction"]], "v_bn_n (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.v_BN_N"]], "v_bn_p (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.v_BN_P"]], "wheel_speeds (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.wheel_speeds"]], "wheel_speeds_fraction (basicdynamicsmodel property)": [[16, "bsk_rl.envs.general_satellite_tasking.simulation.dynamics.BasicDynamicsModel.wheel_speeds_fraction"]], "basicenvironmentmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.environment)": [[17, "bsk_rl.envs.general_satellite_tasking.simulation.environment.BasicEnvironmentModel"]], "environmentmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.environment)": [[17, "bsk_rl.envs.general_satellite_tasking.simulation.environment.EnvironmentModel"]], "groundstationenvmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.environment)": [[17, "bsk_rl.envs.general_satellite_tasking.simulation.environment.GroundStationEnvModel"]], "pn (basicenvironmentmodel property)": [[17, "bsk_rl.envs.general_satellite_tasking.simulation.environment.BasicEnvironmentModel.PN"]], "__init__() (environmentmodel method)": [[17, "bsk_rl.envs.general_satellite_tasking.simulation.environment.EnvironmentModel.__init__"], [28, "bsk_rl.envs.multisat_agile_eos.bsk_models.environment.EnvironmentModel.__init__"]], "bsk_rl.envs.general_satellite_tasking.simulation.environment": [[17, "module-bsk_rl.envs.general_satellite_tasking.simulation.environment"]], "default_env_args() (environmentmodel class method)": [[17, "bsk_rl.envs.general_satellite_tasking.simulation.environment.EnvironmentModel.default_env_args"]], "omega_pn_n (basicenvironmentmodel property)": [[17, "bsk_rl.envs.general_satellite_tasking.simulation.environment.BasicEnvironmentModel.omega_PN_N"]], "basicfswmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel"]], "basicfswmodel.mrpcontroltask (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.MRPControlTask"]], "basicfswmodel.nadirpointtask (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.NadirPointTask"]], "basicfswmodel.rwdesattask (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.RWDesatTask"]], "basicfswmodel.sunpointtask (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.SunPointTask"]], "basicfswmodel.trackingerrortask (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.TrackingErrorTask"]], "continuousimagingfswmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ContinuousImagingFSWModel"]], "continuousimagingfswmodel.locpointtask (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ContinuousImagingFSWModel.LocPointTask"]], "fswmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.FSWModel"]], "imagingfswmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ImagingFSWModel"]], "imagingfswmodel.locpointtask (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ImagingFSWModel.LocPointTask"]], "steeringfswmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.SteeringFSWModel"]], "steeringfswmodel.mrpcontroltask (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.SteeringFSWModel.MRPControlTask"]], "steeringimagerfswmodel (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.SteeringImagerFSWModel"]], "task (class in bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.Task"]], "__init__() (basicfswmodel.mrpcontroltask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.MRPControlTask.__init__"]], "__init__() (basicfswmodel.nadirpointtask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.NadirPointTask.__init__"]], "__init__() (basicfswmodel.rwdesattask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.RWDesatTask.__init__"]], "__init__() (basicfswmodel.sunpointtask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.SunPointTask.__init__"]], "__init__() (basicfswmodel.trackingerrortask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.TrackingErrorTask.__init__"]], "__init__() (fswmodel method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.FSWModel.__init__"], [29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.__init__"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.__init__"]], "__init__() (imagingfswmodel.locpointtask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ImagingFSWModel.LocPointTask.__init__"]], "__init__() (steeringfswmodel.mrpcontroltask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.SteeringFSWModel.MRPControlTask.__init__"]], "__init__() (task method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.Task.__init__"]], "action() (in module bsk_rl.envs.general_satellite_tasking.simulation.fsw)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.action"]], "bsk_rl.envs.general_satellite_tasking.simulation.fsw": [[18, "module-bsk_rl.envs.general_satellite_tasking.simulation.fsw"]], "c_hat_p (imagingfswmodel property)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ImagingFSWModel.c_hat_P"]], "create_task() (task method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.Task.create_task"]], "dynamics (fswmodel property)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.FSWModel.dynamics"]], "environment (fswmodel property)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.FSWModel.environment"]], "is_alive() (fswmodel method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.FSWModel.is_alive"]], "reset_for_action() (basicfswmodel.mrpcontroltask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.MRPControlTask.reset_for_action"]], "reset_for_action() (basicfswmodel.rwdesattask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.BasicFSWModel.RWDesatTask.reset_for_action"]], "reset_for_action() (continuousimagingfswmodel.locpointtask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ContinuousImagingFSWModel.LocPointTask.reset_for_action"]], "reset_for_action() (imagingfswmodel.locpointtask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.ImagingFSWModel.LocPointTask.reset_for_action"]], "reset_for_action() (steeringfswmodel.mrpcontroltask method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.SteeringFSWModel.MRPControlTask.reset_for_action"]], "reset_for_action() (task method)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.Task.reset_for_action"]], "simulator (fswmodel property)": [[18, "bsk_rl.envs.general_satellite_tasking.simulation.fsw.FSWModel.simulator"]], "bsk_rl.envs.general_satellite_tasking.simulation": [[19, "module-bsk_rl.envs.general_satellite_tasking.simulation"]], "bsk_rl.envs.general_satellite_tasking.simulation.simulator": [[20, "module-bsk_rl.envs.general_satellite_tasking.simulation.simulator"]], "bsk_rl.envs.general_satellite_tasking.types": [[21, "module-bsk_rl.envs.general_satellite_tasking.types"]], "aliveness_checker() (in module bsk_rl.envs.general_satellite_tasking.utils.functional)": [[22, "bsk_rl.envs.general_satellite_tasking.utils.functional.aliveness_checker"]], "bind() (in module bsk_rl.envs.general_satellite_tasking.utils.functional)": [[22, "bsk_rl.envs.general_satellite_tasking.utils.functional.bind"]], "bsk_rl.envs.general_satellite_tasking.utils.functional": [[22, "module-bsk_rl.envs.general_satellite_tasking.utils.functional"]], "check_aliveness_checkers() (in module bsk_rl.envs.general_satellite_tasking.utils.functional)": [[22, "bsk_rl.envs.general_satellite_tasking.utils.functional.check_aliveness_checkers"]], "collect_default_args() (in module bsk_rl.envs.general_satellite_tasking.utils.functional)": [[22, "bsk_rl.envs.general_satellite_tasking.utils.functional.collect_default_args"]], "configurable() (in module bsk_rl.envs.general_satellite_tasking.utils.functional)": [[22, "bsk_rl.envs.general_satellite_tasking.utils.functional.configurable"]], "default_args() (in module bsk_rl.envs.general_satellite_tasking.utils.functional)": [[22, "bsk_rl.envs.general_satellite_tasking.utils.functional.default_args"]], "is_property() (in module bsk_rl.envs.general_satellite_tasking.utils.functional)": [[22, "bsk_rl.envs.general_satellite_tasking.utils.functional.is_property"]], "safe_dict_merge() (in module bsk_rl.envs.general_satellite_tasking.utils.functional)": [[22, "bsk_rl.envs.general_satellite_tasking.utils.functional.safe_dict_merge"]], "valid_func_name() (in module bsk_rl.envs.general_satellite_tasking.utils.functional)": [[22, "bsk_rl.envs.general_satellite_tasking.utils.functional.valid_func_name"]], "vectorize_nested_dict() (in module bsk_rl.envs.general_satellite_tasking.utils.functional)": [[22, "bsk_rl.envs.general_satellite_tasking.utils.functional.vectorize_nested_dict"]], "bsk_rl.envs.general_satellite_tasking.utils": [[23, "module-bsk_rl.envs.general_satellite_tasking.utils"]], "contextfilter (class in bsk_rl.envs.general_satellite_tasking.utils.logging_config)": [[24, "bsk_rl.envs.general_satellite_tasking.utils.logging_config.ContextFilter"]], "simformatter (class in bsk_rl.envs.general_satellite_tasking.utils.logging_config)": [[24, "bsk_rl.envs.general_satellite_tasking.utils.logging_config.SimFormatter"]], "__init__() (contextfilter method)": [[24, "bsk_rl.envs.general_satellite_tasking.utils.logging_config.ContextFilter.__init__"]], "__init__() (simformatter method)": [[24, "bsk_rl.envs.general_satellite_tasking.utils.logging_config.SimFormatter.__init__"]], "bsk_rl.envs.general_satellite_tasking.utils.logging_config": [[24, "module-bsk_rl.envs.general_satellite_tasking.utils.logging_config"]], "filter() (contextfilter method)": [[24, "bsk_rl.envs.general_satellite_tasking.utils.logging_config.ContextFilter.filter"]], "format() (simformatter method)": [[24, "bsk_rl.envs.general_satellite_tasking.utils.logging_config.SimFormatter.format"]], "bsk_rl.envs.general_satellite_tasking.utils.orbital": [[25, "module-bsk_rl.envs.general_satellite_tasking.utils.orbital"]], "elevation() (in module bsk_rl.envs.general_satellite_tasking.utils.orbital)": [[25, "bsk_rl.envs.general_satellite_tasking.utils.orbital.elevation"]], "random_epoch() (in module bsk_rl.envs.general_satellite_tasking.utils.orbital)": [[25, "bsk_rl.envs.general_satellite_tasking.utils.orbital.random_epoch"]], "random_orbit() (in module bsk_rl.envs.general_satellite_tasking.utils.orbital)": [[25, "bsk_rl.envs.general_satellite_tasking.utils.orbital.random_orbit"]], "bsk_rl.envs": [[26, "module-bsk_rl.envs"]], "dynamicmodel (class in bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel"]], "initalldynobjects() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.InitAllDynObjects"]], "setbattery() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetBattery"]], "setdensitymodel() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetDensityModel"]], "setdisturbancetorque() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetDisturbanceTorque"]], "setdrageffector() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetDragEffector"]], "seteclipseobject() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetEclipseObject"]], "setgravitybodies() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetGravityBodies"]], "setgroundlocations() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetGroundLocations"]], "setinstrument() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetInstrument"]], "setinstrumentpowersink() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetInstrumentPowerSink"]], "setreactionwheeldyneffector() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetReactionWheelDynEffector"]], "setreactionwheelpower() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetReactionWheelPower"]], "setsimplenavobject() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetSimpleNavObject"]], "setsolarpanel() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetSolarPanel"]], "setspacecrafthub() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetSpacecraftHub"]], "setthrusterdyneffector() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetThrusterDynEffector"]], "settransmitter() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetTransmitter"]], "settransmitterpowersink() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.SetTransmitterPowerSink"]], "__init__() (dynamicmodel method)": [[27, "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics.DynamicModel.__init__"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics": [[27, "module-bsk_rl.envs.multisat_agile_eos.bsk_models.dynamics"]], "environmentmodel (class in bsk_rl.envs.multisat_agile_eos.bsk_models.environment)": [[28, "bsk_rl.envs.multisat_agile_eos.bsk_models.environment.EnvironmentModel"]], "seteclipseobject() (environmentmodel method)": [[28, "bsk_rl.envs.multisat_agile_eos.bsk_models.environment.EnvironmentModel.SetEclipseObject"]], "setepochobject() (environmentmodel method)": [[28, "bsk_rl.envs.multisat_agile_eos.bsk_models.environment.EnvironmentModel.SetEpochObject"]], "setgravitybodies() (environmentmodel method)": [[28, "bsk_rl.envs.multisat_agile_eos.bsk_models.environment.EnvironmentModel.SetGravityBodies"]], "setgroundlocations() (environmentmodel method)": [[28, "bsk_rl.envs.multisat_agile_eos.bsk_models.environment.EnvironmentModel.SetGroundLocations"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.environment": [[28, "module-bsk_rl.envs.multisat_agile_eos.bsk_models.environment"]], "fswmodel (class in bsk_rl.envs.multisat_agile_eos.bsk_models.fsw)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel"]], "initallfswobjects() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.InitAllFSWObjects"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.InitAllFSWObjects"]], "setattitudetrackingerror() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetAttitudeTrackingError"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetAttitudeTrackingError"]], "setinstrumentcontroller() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetInstrumentController"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetInstrumentController"]], "setlocationpointguidance() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetLocationPointGuidance"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetLocationPointGuidance"]], "setmrpfeedbackrwa() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetMRPFeedbackRWA"]], "setmomentumdumping() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetMomentumDumping"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetMomentumDumping"]], "setnadirpointguidance() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetNadirPointGuidance"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetNadirPointGuidance"]], "setrwconfigmsg() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetRWConfigMsg"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetRWConfigMsg"]], "setrwmotortorque() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetRWMotorTorque"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetRWMotorTorque"]], "setsunpointguidance() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetSunPointGuidance"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetSunPointGuidance"]], "setthrustermapping() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetThrusterMapping"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetThrusterMapping"]], "setthrustersconfigmsg() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetThrustersConfigMsg"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetThrustersConfigMsg"]], "setvehicleconfigmsg() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.SetVehicleConfigMsg"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetVehicleConfigMsg"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw": [[29, "module-bsk_rl.envs.multisat_agile_eos.bsk_models.fsw"]], "setupgatewaymsgs() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.setupGatewayMsgs"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.setupGatewayMsgs"]], "zerogatewaymsgs() (fswmodel method)": [[29, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw.FSWModel.zeroGateWayMsgs"], [30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.zeroGateWayMsgs"]], "fswmodel (class in bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering)": [[30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel"]], "setmrpsteeringrwa() (fswmodel method)": [[30, "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering.FSWModel.SetMRPSteeringRWA"]], "bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering": [[30, "module-bsk_rl.envs.multisat_agile_eos.bsk_models.fsw_steering"]], "bsk_rl.envs.multisat_agile_eos.bsk_models": [[31, "module-bsk_rl.envs.multisat_agile_eos.bsk_models"]], "bsk_rl.envs.multisat_agile_eos.bsk_sim": [[32, "module-bsk_rl.envs.multisat_agile_eos.bsk_sim"]], "bsk_rl.envs.multisat_agile_eos.env_settings": [[33, "module-bsk_rl.envs.multisat_agile_eos.env_settings"]], "multisatagileeos (class in bsk_rl.envs.multisat_agile_eos.gym_env)": [[34, "bsk_rl.envs.multisat_agile_eos.gym_env.MultiSatAgileEOS"]], "__init__() (multisatagileeos method)": [[34, "bsk_rl.envs.multisat_agile_eos.gym_env.MultiSatAgileEOS.__init__"]], "bsk_rl.envs.multisat_agile_eos.gym_env": [[34, "module-bsk_rl.envs.multisat_agile_eos.gym_env"]], "reset() (multisatagileeos method)": [[34, "bsk_rl.envs.multisat_agile_eos.gym_env.MultiSatAgileEOS.reset"]], "set_env_params() (multisatagileeos method)": [[34, "bsk_rl.envs.multisat_agile_eos.gym_env.MultiSatAgileEOS.set_env_params"]], "set_params() (multisatagileeos method)": [[34, "bsk_rl.envs.multisat_agile_eos.gym_env.MultiSatAgileEOS.set_params"]], "sim_attrs() (multisatagileeos method)": [[34, "bsk_rl.envs.multisat_agile_eos.gym_env.MultiSatAgileEOS.sim_attrs"]], "step() (multisatagileeos method)": [[34, "bsk_rl.envs.multisat_agile_eos.gym_env.MultiSatAgileEOS.step"]], "update_spaces() (multisatagileeos method)": [[34, "bsk_rl.envs.multisat_agile_eos.gym_env.MultiSatAgileEOS.update_spaces"]], "bsk_rl.envs.multisat_agile_eos": [[35, "module-bsk_rl.envs.multisat_agile_eos"]], "bsk_rl.envs.multisensor_eos.bsk_sim": [[36, "module-bsk_rl.envs.multisensor_eos.bsk_sim"]], "invalid_action": [[36, "bsk_rl.envs.multisensor_eos.bsk_sim.invalid_action"]], "settings (class in bsk_rl.envs.multisensor_eos.env_settings)": [[37, "bsk_rl.envs.multisensor_eos.env_settings.Settings"]], "__init__() (settings method)": [[37, "bsk_rl.envs.multisensor_eos.env_settings.Settings.__init__"]], "bsk_rl.envs.multisensor_eos.env_settings": [[37, "module-bsk_rl.envs.multisensor_eos.env_settings"]], "multisensoreos (class in bsk_rl.envs.multisensor_eos.gym_env)": [[38, "bsk_rl.envs.multisensor_eos.gym_env.MultiSensorEOS"]], "__init__() (multisensoreos method)": [[38, "bsk_rl.envs.multisensor_eos.gym_env.MultiSensorEOS.__init__"]], "bsk_rl.envs.multisensor_eos.gym_env": [[38, "module-bsk_rl.envs.multisensor_eos.gym_env"]], "reset() (multisensoreos method)": [[38, "bsk_rl.envs.multisensor_eos.gym_env.MultiSensorEOS.reset"]], "step() (multisensoreos method)": [[38, "bsk_rl.envs.multisensor_eos.gym_env.MultiSensorEOS.step"]], "bsk_rl.envs.multisensor_eos": [[39, "module-bsk_rl.envs.multisensor_eos"]], "bsk_rl.envs.simple_eos.bsk_sim": [[40, "module-bsk_rl.envs.simple_eos.bsk_sim"]], "simpleeos (class in bsk_rl.envs.simple_eos.gym_env)": [[41, "bsk_rl.envs.simple_eos.gym_env.SimpleEOS"]], "__init__() (simpleeos method)": [[41, "bsk_rl.envs.simple_eos.gym_env.SimpleEOS.__init__"]], "bsk_rl.envs.simple_eos.gym_env": [[41, "module-bsk_rl.envs.simple_eos.gym_env"]], "reset() (simpleeos method)": [[41, "bsk_rl.envs.simple_eos.gym_env.SimpleEOS.reset"]], "step() (simpleeos method)": [[41, "bsk_rl.envs.simple_eos.gym_env.SimpleEOS.step"]], "bsk_rl.envs.simple_eos": [[42, "module-bsk_rl.envs.simple_eos"]], "bsk_rl.envs.small_body_science.bsk_sim": [[43, "module-bsk_rl.envs.small_body_science.bsk_sim"]], "smallbodyscience (class in bsk_rl.envs.small_body_science.gym_env)": [[44, "bsk_rl.envs.small_body_science.gym_env.SmallBodyScience"]], "__init__() (smallbodyscience method)": [[44, "bsk_rl.envs.small_body_science.gym_env.SmallBodyScience.__init__"]], "bsk_rl.envs.small_body_science.gym_env": [[44, "module-bsk_rl.envs.small_body_science.gym_env"]], "reset() (smallbodyscience method)": [[44, "bsk_rl.envs.small_body_science.gym_env.SmallBodyScience.reset"]], "step() (smallbodyscience method)": [[44, "bsk_rl.envs.small_body_science.gym_env.SmallBodyScience.step"]], "bsk_rl.envs.small_body_science": [[45, "module-bsk_rl.envs.small_body_science"]], "bsk_rl.envs.small_body_science_pomdp.bsk_sim": [[46, "module-bsk_rl.envs.small_body_science_pomdp.bsk_sim"]], "smallbodysciencepomdp (class in bsk_rl.envs.small_body_science_pomdp.gym_env)": [[47, "bsk_rl.envs.small_body_science_pomdp.gym_env.SmallBodySciencePOMDP"]], "__init__() (smallbodysciencepomdp method)": [[47, "bsk_rl.envs.small_body_science_pomdp.gym_env.SmallBodySciencePOMDP.__init__"]], "bsk_rl.envs.small_body_science_pomdp.gym_env": [[47, "module-bsk_rl.envs.small_body_science_pomdp.gym_env"]], "modify_ob() (smallbodysciencepomdp method)": [[47, "bsk_rl.envs.small_body_science_pomdp.gym_env.SmallBodySciencePOMDP.modify_ob"]], "reset() (smallbodysciencepomdp method)": [[47, "bsk_rl.envs.small_body_science_pomdp.gym_env.SmallBodySciencePOMDP.reset"]], "step() (smallbodysciencepomdp method)": [[47, "bsk_rl.envs.small_body_science_pomdp.gym_env.SmallBodySciencePOMDP.step"]], "bsk_rl.envs.small_body_science_pomdp": [[48, "module-bsk_rl.envs.small_body_science_pomdp"]], "bsk_rl": [[49, "module-bsk_rl"]], "bsk_rl.training": [[50, "module-bsk_rl.training"]], "bsk_rl.training.mcts": [[51, "module-bsk_rl.training.mcts"]], "bsk_rl.training.mcts.mcts_train": [[52, "module-bsk_rl.training.mcts.mcts_train"]], "create_model() (in module bsk_rl.training.mcts.mcts_train)": [[52, "bsk_rl.training.mcts.mcts_train.create_model"]], "data_number() (in module bsk_rl.training.mcts.mcts_train)": [[52, "bsk_rl.training.mcts.mcts_train.data_number"]], "load_and_modify_data() (in module bsk_rl.training.mcts.mcts_train)": [[52, "bsk_rl.training.mcts.mcts_train.load_and_modify_data"]], "load_data() (in module bsk_rl.training.mcts.mcts_train)": [[52, "bsk_rl.training.mcts.mcts_train.load_data"]], "mcts_batch() (in module bsk_rl.training.mcts.mcts_train)": [[52, "bsk_rl.training.mcts.mcts_train.mcts_batch"]], "run_episode() (in module bsk_rl.training.mcts.mcts_train)": [[52, "bsk_rl.training.mcts.mcts_train.run_episode"]], "run_experiment() (in module bsk_rl.training.mcts.mcts_train)": [[52, "bsk_rl.training.mcts.mcts_train.run_experiment"]], "a2c_experiment() (in module bsk_rl.training.sb3.experiments)": [[53, "bsk_rl.training.sb3.experiments.a2c_experiment"]], "bsk_rl.training.sb3.experiments": [[53, "module-bsk_rl.training.sb3.experiments"]], "ppo_experiment() (in module bsk_rl.training.sb3.experiments)": [[53, "bsk_rl.training.sb3.experiments.ppo_experiment"]], "run_ppo_experiments() (in module bsk_rl.training.sb3.experiments)": [[53, "bsk_rl.training.sb3.experiments.run_ppo_experiments"]], "bsk_rl.training.sb3": [[54, "module-bsk_rl.training.sb3"]], "balancedhr16triad() (in module bsk_rl.utilities.effector_primitives.actuator_primitives)": [[55, "bsk_rl.utilities.effector_primitives.actuator_primitives.balancedHR16Triad"]], "bsk_rl.utilities.effector_primitives.actuator_primitives": [[55, "module-bsk_rl.utilities.effector_primitives.actuator_primitives"]], "idealmonarc1octet() (in module bsk_rl.utilities.effector_primitives.actuator_primitives)": [[55, "bsk_rl.utilities.effector_primitives.actuator_primitives.idealMonarc1Octet"]], "bsk_rl.utilities.effector_primitives": [[56, "module-bsk_rl.utilities.effector_primitives"]], "bsk_rl.utilities.genetic_algorithm.experiments": [[57, "module-bsk_rl.utilities.genetic_algorithm.experiments"]], "run_ga_hp_experiment() (in module bsk_rl.utilities.genetic_algorithm.experiments)": [[57, "bsk_rl.utilities.genetic_algorithm.experiments.run_ga_hp_experiment"]], "bsk_rl.utilities.genetic_algorithm": [[58, "module-bsk_rl.utilities.genetic_algorithm"]], "bsk_rl.utilities": [[59, "module-bsk_rl.utilities"]], "bsk_rl.utilities.initial_conditions": [[60, "module-bsk_rl.utilities.initial_conditions"]], "bsk_rl.utilities.initial_conditions.leo_initial_conditions": [[61, "module-bsk_rl.utilities.initial_conditions.leo_initial_conditions"]], "bsk_rl.utilities.initial_conditions.leo_orbit": [[62, "module-bsk_rl.utilities.initial_conditions.leo_orbit"]], "create_ground_tgts() (in module bsk_rl.utilities.initial_conditions.leo_orbit)": [[62, "bsk_rl.utilities.initial_conditions.leo_orbit.create_ground_tgts"]], "distribute_tgts() (in module bsk_rl.utilities.initial_conditions.leo_orbit)": [[62, "bsk_rl.utilities.initial_conditions.leo_orbit.distribute_tgts"]], "elrange_req() (in module bsk_rl.utilities.initial_conditions.leo_orbit)": [[62, "bsk_rl.utilities.initial_conditions.leo_orbit.elrange_req"]], "inclined_400km() (in module bsk_rl.utilities.initial_conditions.leo_orbit)": [[62, "bsk_rl.utilities.initial_conditions.leo_orbit.inclined_400km"]], "inclined_circular_300km() (in module bsk_rl.utilities.initial_conditions.leo_orbit)": [[62, "bsk_rl.utilities.initial_conditions.leo_orbit.inclined_circular_300km"]], "random_inclined_circular_300km() (in module bsk_rl.utilities.initial_conditions.leo_orbit)": [[62, "bsk_rl.utilities.initial_conditions.leo_orbit.random_inclined_circular_300km"]], "sampled_400km() (in module bsk_rl.utilities.initial_conditions.leo_orbit)": [[62, "bsk_rl.utilities.initial_conditions.leo_orbit.sampled_400km"]], "sampled_500km_boulder_gs() (in module bsk_rl.utilities.initial_conditions.leo_orbit)": [[62, "bsk_rl.utilities.initial_conditions.leo_orbit.sampled_500km_boulder_gs"]], "sampled_boulder_gs() (in module bsk_rl.utilities.initial_conditions.leo_orbit)": [[62, "bsk_rl.utilities.initial_conditions.leo_orbit.sampled_boulder_gs"]], "walker_delta() (in module bsk_rl.utilities.initial_conditions.leo_orbit)": [[62, "bsk_rl.utilities.initial_conditions.leo_orbit.walker_delta"]], "bsk_rl.utilities.initial_conditions.sc_attitudes": [[63, "module-bsk_rl.utilities.initial_conditions.sc_attitudes"]], "random_tumble() (in module bsk_rl.utilities.initial_conditions.sc_attitudes)": [[63, "bsk_rl.utilities.initial_conditions.sc_attitudes.random_tumble"]], "static_inertial() (in module bsk_rl.utilities.initial_conditions.sc_attitudes)": [[63, "bsk_rl.utilities.initial_conditions.sc_attitudes.static_inertial"]], "bsk_rl.utilities.initial_conditions.small_body": [[64, "module-bsk_rl.utilities.initial_conditions.small_body"]], "generate_imaging_points() (in module bsk_rl.utilities.initial_conditions.small_body)": [[64, "bsk_rl.utilities.initial_conditions.small_body.generate_imaging_points"]], "generate_mapping_points() (in module bsk_rl.utilities.initial_conditions.small_body)": [[64, "bsk_rl.utilities.initial_conditions.small_body.generate_mapping_points"]], "generate_waypoints() (in module bsk_rl.utilities.initial_conditions.small_body)": [[64, "bsk_rl.utilities.initial_conditions.small_body.generate_waypoints"]], "bsk_rl.utilities.mcts": [[65, "module-bsk_rl.utilities.mcts"]], "bsk_rl.utilities.mcts.rollout_policies": [[66, "module-bsk_rl.utilities.mcts.rollout_policies"]], "customactorcriticpolicy (class in bsk_rl.utilities.sb3.custom_sb3_policies)": [[67, "bsk_rl.utilities.sb3.custom_sb3_policies.CustomActorCriticPolicy"]], "customnetwork (class in bsk_rl.utilities.sb3.custom_sb3_policies)": [[67, "bsk_rl.utilities.sb3.custom_sb3_policies.CustomNetwork"]], "__init__() (customactorcriticpolicy method)": [[67, "bsk_rl.utilities.sb3.custom_sb3_policies.CustomActorCriticPolicy.__init__"]], "__init__() (customnetwork method)": [[67, "bsk_rl.utilities.sb3.custom_sb3_policies.CustomNetwork.__init__"]], "bsk_rl.utilities.sb3.custom_sb3_policies": [[67, "module-bsk_rl.utilities.sb3.custom_sb3_policies"]], "forward() (customnetwork method)": [[67, "bsk_rl.utilities.sb3.custom_sb3_policies.CustomNetwork.forward"]], "bsk_rl.utilities.sb3": [[68, "module-bsk_rl.utilities.sb3"]], "customactorcriticshieldedagileeospolicy (class in bsk_rl.utilities.sb3.shielded_policies)": [[69, "bsk_rl.utilities.sb3.shielded_policies.CustomActorCriticShieldedAgileEOSPolicy"]], "customactorcriticshieldedmultisensoreospolicy (class in bsk_rl.utilities.sb3.shielded_policies)": [[69, "bsk_rl.utilities.sb3.shielded_policies.CustomActorCriticShieldedMultiSensorEOSPolicy"]], "customactorcriticshieldedpolicy (class in bsk_rl.utilities.sb3.shielded_policies)": [[69, "bsk_rl.utilities.sb3.shielded_policies.CustomActorCriticShieldedPolicy"]], "__init__() (customactorcriticshieldedagileeospolicy method)": [[69, "bsk_rl.utilities.sb3.shielded_policies.CustomActorCriticShieldedAgileEOSPolicy.__init__"]], "__init__() (customactorcriticshieldedmultisensoreospolicy method)": [[69, "bsk_rl.utilities.sb3.shielded_policies.CustomActorCriticShieldedMultiSensorEOSPolicy.__init__"]], "__init__() (customactorcriticshieldedpolicy method)": [[69, "bsk_rl.utilities.sb3.shielded_policies.CustomActorCriticShieldedPolicy.__init__"]], "bsk_rl.utilities.sb3.shielded_policies": [[69, "module-bsk_rl.utilities.sb3.shielded_policies"]], "forward() (customactorcriticshieldedpolicy method)": [[69, "bsk_rl.utilities.sb3.shielded_policies.CustomActorCriticShieldedPolicy.forward"]], "agileeosshield (class in bsk_rl.utilities.sb3.shields)": [[70, "bsk_rl.utilities.sb3.shields.AgileEOSShield"]], "multisensoreosshield (class in bsk_rl.utilities.sb3.shields)": [[70, "bsk_rl.utilities.sb3.shields.MultiSensorEOSShield"]], "__init__() (agileeosshield method)": [[70, "bsk_rl.utilities.sb3.shields.AgileEOSShield.__init__"]], "__init__() (multisensoreosshield method)": [[70, "bsk_rl.utilities.sb3.shields.MultiSensorEOSShield.__init__"]], "bsk_rl.utilities.sb3.shields": [[70, "module-bsk_rl.utilities.sb3.shields"]], "bsk_rl.utilities.state_machine": [[71, "module-bsk_rl.utilities.state_machine"]], "examples.general_satellite_tasking": [[72, "module-examples.general_satellite_tasking"]], "examples.general_satellite_tasking.multisat_aeos": [[73, "module-examples.general_satellite_tasking.multisat_aeos"]], "run() (in module examples.general_satellite_tasking.multisat_aeos)": [[73, "examples.general_satellite_tasking.multisat_aeos.run"]], "examples.general_satellite_tasking.satellite_customization": [[74, "module-examples.general_satellite_tasking.satellite_customization"]], "examples.general_satellite_tasking.single_sat": [[75, "module-examples.general_satellite_tasking.single_sat"]], "examples.genetic_algorithm.ga_hp_solver": [[76, "module-examples.genetic_algorithm.ga_hp_solver"]], "examples.genetic_algorithm": [[77, "module-examples.genetic_algorithm"]], "examples": [[78, "module-examples"]], "examples.mcts": [[79, "module-examples.mcts"]], "examples.mcts.mcts_data_generator": [[80, "module-examples.mcts.mcts_data_generator"]], "examples.mcts.network_hyperparam_search": [[81, "module-examples.mcts.network_hyperparam_search"]], "examples.mcts.network_validation_multiprocessing": [[82, "module-examples.mcts.network_validation_multiprocessing"]], "modify_observation() (in module examples.mcts.network_validation_multiprocessing)": [[82, "examples.mcts.network_validation_multiprocessing.modify_observation"]], "run_simulator() (in module examples.mcts.network_validation_multiprocessing)": [[82, "examples.mcts.network_validation_multiprocessing.run_simulator"]], "examples.plotting_tools": [[83, "module-examples.plotting_tools"]], "examples.plotting_tools.plot_a2c_hyperparams": [[84, "module-examples.plotting_tools.plot_a2c_hyperparams"]], "examples.plotting_tools.plot_dqn_hyperparams": [[85, "module-examples.plotting_tools.plot_dqn_hyperparams"]], "examples.plotting_tools.plot_ga_hyperparams": [[86, "module-examples.plotting_tools.plot_ga_hyperparams"]], "examples.plotting_tools.plot_mcts_hyperparams": [[87, "module-examples.plotting_tools.plot_mcts_hyperparams"]], "examples.plotting_tools.plot_ppo_hyperparams": [[88, "module-examples.plotting_tools.plot_ppo_hyperparams"]], "examples.plotting_tools.process_ga_curves": [[89, "module-examples.plotting_tools.process_ga_curves"]], "process_ga_curve() (in module examples.plotting_tools.process_ga_curves)": [[89, "examples.plotting_tools.process_ga_curves.process_ga_curve"]], "examples.plotting_tools.process_sb3_curves": [[90, "module-examples.plotting_tools.process_sb3_curves"]], "examples.sb3.a2c_hyperparam_search": [[91, "module-examples.sb3.a2c_hyperparam_search"]], "examples.sb3.dqn_hyperparam_search": [[92, "module-examples.sb3.dqn_hyperparam_search"]], "examples.sb3": [[93, "module-examples.sb3"]], "examples.sb3.ppo_hyperparam_search": [[94, "module-examples.sb3.ppo_hyperparam_search"]], "examples.sb3.sppo_hyperparam_search": [[95, "module-examples.sb3.sppo_hyperparam_search"]], "examples.state_machine": [[96, "module-examples.state_machine"]], "examples.state_machine.state_machine_example": [[97, "module-examples.state_machine.state_machine_example"]]}}) \ No newline at end of file