Skip to content

Commit 0f45dc7

Browse files
committed
[#323] Restructure dyn and fsw model inheritance
1 parent 5b19949 commit 0f45dc7

22 files changed

+124
-121
lines changed

docs/source/release_notes.rst

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,19 @@ Development - |version|
2020
* Allow flight software and dynamics models to be specified as lists of classes. This allows
2121
for multiple inheritance to be used for easily creating more complex satellite models.
2222
* The inheritance structure of flight software and dynamics models has changed. Most models
23-
now inherit from :class:`~bsk_rl.sim.fsw.BaseFSWModel` or :class:`~bsk_rl.sim.dyn.BaseDynModel`
24-
instead of :class:`~bsk_rl.sim.fsw.BasicFSWModel` or :class:`~bsk_rl.sim.dyn.BasicDynModel`.
25-
These are lighter-weight base classes that lack some functionality that was not always
26-
wanted.
23+
now inherit from :class:`~bsk_rl.sim.fsw.FSWModel` or :class:`~bsk_rl.sim.dyn.DynModel`,
24+
which are instantiable versions of the abstract bases :class:`~bsk_rl.sim.fsw.FSWModelABC` and
25+
:class:`~bsk_rl.sim.dyn.DynModelABC`, instead of from :class:`~bsk_rl.sim.fsw.BasicFSWModel`
26+
or :class:`~bsk_rl.sim.dyn.BasicDynModel`. These are lighter-weight base classes that lack
27+
some functionality that was not always wanted.
2728

2829
.. warning::
2930

3031
If your custom satellite configurations break as a result of this change, add
3132
:class:`~bsk_rl.sim.fsw.BasicFSWModel` and :class:`~bsk_rl.sim.dyn.BasicDynModel`
3233
to your ``fsw_type`` and ``dyn_type`` lists in your satellite classes.
3334

34-
* :class:`~bsk_rl.sim.fsw.BaseFSWModel` implements direct actuator-less attitude control.
35+
* :class:`~bsk_rl.sim.fsw.FSWModel` implements direct actuator-less attitude control.
3536
By inheriting from a FSW class that overrides the ``MRPControlTask``, such as
3637
:class:`~bsk_rl.sim.fsw.BasicFSWModel` or :class:`~bsk_rl.sim.fsw.SteeringFSWModel`,
3738
users can implement custom attitude control strategies.

examples/rso_inspection.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
" ]\n",
7777
" action_spec = [act.NadirPoint(duration=1e9)]\n",
7878
" dyn_type = (dyn.ConjunctionDynModel, dyn.RSODynModel)\n",
79-
" fsw_type = fsw.BaseFSWModel\n"
79+
" fsw_type = fsw.FSWModel\n"
8080
]
8181
},
8282
{

src/bsk_rl/act/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class MyActionSatellite(Satellite):
2424
+----------------------------+---------+-------------------------------------------------------------------------------------------------------+
2525
| **Action** |**Count**| **Description** |
2626
+----------------------------+---------+-------------------------------------------------------------------------------------------------------+
27-
| :class:`DiscreteFSWAction` | 1 | Call an arbitrary ``@action`` decorated function in the :class:`~bsk_rl.sim.fsw.FSWModel`. |
27+
| :class:`DiscreteFSWAction` | 1 | Call an arbitrary ``@action`` decorated function in the :class:`~bsk_rl.sim.fsw.FSWModelABC`. |
2828
+----------------------------+---------+-------------------------------------------------------------------------------------------------------+
2929
| :class:`Charge` | 1 | Point the solar panels at the sun. |
3030
+----------------------------+---------+-------------------------------------------------------------------------------------------------------+

src/bsk_rl/act/discrete_actions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def __init__(
120120
):
121121
"""Discrete action to task a flight software action function.
122122
123-
This action executes a function of a :class:`~bsk_rl.sim.fsw.FSWModel`
123+
This action executes a function of a :class:`~bsk_rl.sim.fsw.FSWModelABC`
124124
instance that takes no arguments, typically decorated with ``@action``.
125125
126126
Args:

src/bsk_rl/gym.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from bsk_rl.sats import Satellite
1818
from bsk_rl.scene import Scenario
1919
from bsk_rl.sim import Simulator
20-
from bsk_rl.sim.world import BaseWorldModel, WorldModel
20+
from bsk_rl.sim.world import WorldModel, WorldModelABC
2121
from bsk_rl.utils import functional, logging_config, vizard
2222

2323
logger = logging.getLogger(__name__)
@@ -57,7 +57,7 @@ def __init__(
5757
scenario: Optional[Scenario] = None,
5858
rewarder: Optional[Union[GlobalReward, list[GlobalReward]]] = None,
5959
world_type: Optional[
60-
Union[type[WorldModel], tuple[type[WorldModel], ...]]
60+
Union[type[WorldModelABC], tuple[type[WorldModelABC], ...]]
6161
] = None,
6262
world_args: Optional[dict[str, Any]] = None,
6363
communicator: Optional[CommunicationMethod] = None,
@@ -99,7 +99,7 @@ def __init__(
9999
be a function that takes a list of satellites and returns a dictionary that
100100
maps satellites to dictionaries of satellite model arguments to be overridden.
101101
world_type: Type or tuple of types of Basilisk world model to be constructed.
102-
world_args: Arguments for :class:`~bsk_rl.sim.world.WorldModel` construction.
102+
world_args: Arguments for :class:`~bsk_rl.sim.world.WorldModelABC` construction.
103103
Should be in the form of a dictionary with keys corresponding to the
104104
arguments of the constructor and values that are either the desired value
105105
or a function that takes no arguments and returns a randomized value.
@@ -184,7 +184,9 @@ def __init__(
184184
)
185185
if not isinstance(world_type, (list, tuple)):
186186
world_type = (world_type,)
187-
world_type = functional.compose_types(*world_type, WorldModel, name="World")
187+
world_type = functional.compose_types(
188+
*world_type, WorldModelABC, name="World"
189+
)
188190
self.world_type = world_type
189191
if world_args is None:
190192
world_args = self.world_type.default_world_args()
@@ -223,15 +225,15 @@ def __init__(
223225
self.render_mode = render_mode
224226
self.generate_obs_retasking_only = generate_obs_retasking_only
225227

226-
def _minimum_world_model(self) -> type[WorldModel]:
228+
def _minimum_world_model(self) -> type[WorldModelABC]:
227229
"""Determine the minimum world model required by the satellites."""
228230
world_types = set(
229231
sum(
230232
[satellite.dyn_type._requires_world() for satellite in self.satellites],
231233
[],
232234
)
233235
)
234-
return functional.compose_types(*world_types, BaseWorldModel, name="World")
236+
return functional.compose_types(*world_types, WorldModel, name="World")
235237

236238
def get_satellite(self, name: str) -> "Satellite":
237239
"""Get a satellite by name.

src/bsk_rl/sats/satellite.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ class Satellite(ABC, Resetable):
4040
"""Abstract base class for satellites."""
4141

4242
dyn_type: Union[
43-
type["dyn.DynamicsModel"], tuple[type["dyn.DynamicsModel"], ...]
43+
type["dyn.DynamicsModelABC"], tuple[type["dyn.DynamicsModelABC"], ...]
4444
] = AbstractClassProperty()
45-
fsw_type: Union[type["fsw.FSWModel"], tuple[type["fsw.FSWModel"], ...]] = (
45+
fsw_type: Union[type["fsw.FSWModelABC"], tuple[type["fsw.FSWModelABC"], ...]] = (
4646
AbstractClassProperty()
4747
)
4848
observation_spec: list["Observation"] = AbstractClassProperty()
@@ -51,7 +51,7 @@ class Satellite(ABC, Resetable):
5151
_dyn_type = None
5252

5353
@classmethod
54-
def get_dyn_type(cls) -> type["dyn.DynamicsModel"]:
54+
def get_dyn_type(cls) -> type["dyn.DynamicsModelABC"]:
5555
"""Get the dynamics model type for the satellite.
5656
5757
This should be used in class methods instead of referencing ``dyn_type``. In
@@ -65,13 +65,13 @@ def get_dyn_type(cls) -> type["dyn.DynamicsModel"]:
6565
dyn_types = cls.dyn_type
6666
else:
6767
dyn_types = (cls.dyn_type,)
68-
cls._dyn_type = compose_types(*dyn_types, dyn.BaseDynamicsModel, name="Dyn")
68+
cls._dyn_type = compose_types(*dyn_types, dyn.DynamicsModel, name="Dyn")
6969
return cls._dyn_type
7070

7171
_fsw_type = None
7272

7373
@classmethod
74-
def get_fsw_type(cls) -> type["fsw.FSWModel"]:
74+
def get_fsw_type(cls) -> type["fsw.FSWModelABC"]:
7575
"""Get the flight software model type for the satellite.
7676
7777
This should be used in class methods instead of referencing ``fsw_type``. In
@@ -85,12 +85,12 @@ def get_fsw_type(cls) -> type["fsw.FSWModel"]:
8585
fsw_types = cls.fsw_type
8686
else:
8787
fsw_types = (cls.fsw_type,)
88-
cls._fsw_type = compose_types(*fsw_types, fsw.BaseFSWModel, name="FSW")
88+
cls._fsw_type = compose_types(*fsw_types, fsw.FSWModel, name="FSW")
8989
return cls._fsw_type
9090

9191
@classmethod
9292
def default_sat_args(cls, **kwargs) -> dict[str, Any]:
93-
"""Compile default arguments for :class:`~bsk_rl.sim.dyn.DynamicsModel` and :class:`~bsk_rl.sim.fsw.FSWModel`, replacing those specified.
93+
"""Compile default arguments for :class:`~bsk_rl.sim.dyn.DynamicsModelABC` and :class:`~bsk_rl.sim.fsw.FSWModelABC`, replacing those specified.
9494
9595
Args:
9696
**kwargs: Arguments to override in the default arguments.
@@ -129,8 +129,8 @@ def __init__(
129129
130130
Args:
131131
name: Identifier for satellite; does not need to be unique.
132-
sat_args: Arguments for :class:`~bsk_rl.sim.dyn.DynamicsModel` and
133-
:class:`~bsk_rl.sim.fsw.FSWModel` construction. Should be in the form of
132+
sat_args: Arguments for :class:`~bsk_rl.sim.dyn.DynamicsModelABC` and
133+
:class:`~bsk_rl.sim.fsw.FSWModelABC` construction. Should be in the form of
134134
a dictionary with keys corresponding to the arguments of the constructor
135135
and values that are either the desired value or a function that takes no
136136
arguments and returns a randomized value.
@@ -147,8 +147,8 @@ def __init__(
147147
sat_args = self.default_sat_args()
148148
self.sat_args_generator = self.default_sat_args(**sat_args)
149149
self.simulator: "Simulator"
150-
self.fsw: "fsw.FSWModel"
151-
self.dynamics: "dyn.DynamicsModel"
150+
self.fsw: "fsw.FSWModelABC"
151+
self.dynamics: "dyn.DynamicsModelABC"
152152
self.data_store: "DataStore"
153153
self.requires_retasking: bool
154154
self.variable_interval = variable_interval
@@ -228,7 +228,7 @@ def set_simulator(self, simulator: "Simulator"):
228228
"""
229229
self.simulator = proxy(simulator)
230230

231-
def set_dynamics(self, dyn_rate: float) -> "dyn.DynamicsModel":
231+
def set_dynamics(self, dyn_rate: float) -> "dyn.DynamicsModelABC":
232232
"""Create dynamics model; called during simulator initialization.
233233
234234
Args:
@@ -243,7 +243,7 @@ def set_dynamics(self, dyn_rate: float) -> "dyn.DynamicsModel":
243243
self.dynamics = proxy(dynamics)
244244
return dynamics
245245

246-
def set_fsw(self, fsw_rate: float) -> "fsw.FSWModel":
246+
def set_fsw(self, fsw_rate: float) -> "fsw.FSWModelABC":
247247
"""Create flight software model; called during simulator initialization.
248248
249249
Args:

src/bsk_rl/sim/dyn/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@
4040

4141
from bsk_rl.sim.dyn.base import (
4242
AtmosphericDragDynModel,
43-
BaseDynamicsModel,
4443
BasicDynamicsModel,
4544
DisturbanceTorqueDynModel,
4645
DynamicsModel,
46+
DynamicsModelABC,
4747
EclipseDynModel,
4848
)
4949
from bsk_rl.sim.dyn.ground_imaging import (
@@ -72,8 +72,8 @@ def __init__(self, *args, **kwargs) -> None:
7272

7373
__doc_title__ = "Dynamics Sims"
7474
__all__ = [
75+
"DynamicsModelABC",
7576
"DynamicsModel",
76-
"BaseDynamicsModel",
7777
"BasicDynamicsModel",
7878
"EclipseDynModel",
7979
"DisturbanceTorqueDynModel",

src/bsk_rl/sim/dyn/base.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@
3535
if TYPE_CHECKING: # pragma: no cover
3636
from bsk_rl.sats import Satellite
3737
from bsk_rl.sim import Simulator
38-
from bsk_rl.sim.world import WorldModel
38+
from bsk_rl.sim.world import WorldModelABC
3939

4040

41-
class DynamicsModel(ABC, Resetable):
41+
class DynamicsModelABC(ABC, Resetable):
4242
"""Abstract Basilisk dynamics model."""
4343

4444
@classmethod
45-
def _requires_world(cls) -> list[type["WorldModel"]]:
46-
"""Define minimum :class:`~bsk_rl.sim.world.WorldModel` for compatibility."""
45+
def _requires_world(cls) -> list[type["WorldModelABC"]]:
46+
"""Define minimum :class:`~bsk_rl.sim.world.WorldModelABC` for compatibility."""
4747
return []
4848

4949
def __init__(
@@ -55,7 +55,7 @@ def __init__(
5555
) -> None:
5656
"""The abstract base dynamics model.
5757
58-
One DynamicsModel is instantiated for each satellite in the environment each
58+
One DynamicsModelABC is instantiated for each satellite in the environment each
5959
time the environment is reset and new simulator is created.
6060
6161
Args:
@@ -92,7 +92,7 @@ def simulator(self) -> "Simulator":
9292
return self.satellite.simulator
9393

9494
@property
95-
def world(self) -> "WorldModel":
95+
def world(self) -> "WorldModelABC":
9696
"""Reference to the episode world model."""
9797
return self.simulator.world
9898

@@ -123,9 +123,9 @@ def __del__(self):
123123
self.logger.debug("Basilisk dynamics deleted")
124124

125125

126-
class BaseDynamicsModel(DynamicsModel):
126+
class DynamicsModel(DynamicsModelABC):
127127
@classmethod
128-
def _requires_world(cls) -> list[type["WorldModel"]]:
128+
def _requires_world(cls) -> list[type["WorldModelABC"]]:
129129
return []
130130

131131
@property
@@ -344,7 +344,7 @@ def setup_spacecraft_hub(
344344
self.setup_gravity_bodies()
345345

346346
def setup_gravity_bodies(self) -> None:
347-
"""Set up gravitational bodies from the :class:`~bsk_rl.sim.world.WorldModel` to included in the simulation."""
347+
"""Set up gravitational bodies from the :class:`~bsk_rl.sim.world.WorldModelABC` to included in the simulation."""
348348
self.scObject.gravField.gravBodies = spacecraft.GravBodyVector(
349349
list(self.world.gravFactory.gravBodies.values())
350350
)
@@ -372,15 +372,15 @@ def altitude_valid(self) -> bool:
372372
return np.linalg.norm(self.r_BN_N) > self.min_orbital_radius
373373

374374

375-
class EclipseDynModel(BaseDynamicsModel):
375+
class EclipseDynModel(DynamicsModel):
376376
"""Dynamics model with eclipse checking."""
377377

378378
def __init__(self, *args, **kwargs) -> None:
379379
"""Dynamics model with eclipse checking."""
380380
super().__init__(*args, **kwargs)
381381

382382
@classmethod
383-
def _requires_world(cls) -> list[type["WorldModel"]]:
383+
def _requires_world(cls) -> list[type["WorldModelABC"]]:
384384
return [
385385
world.EclipseWorldModel,
386386
] + super()._requires_world()
@@ -395,7 +395,7 @@ def setup_eclipse_object(self) -> None:
395395
self.eclipse_index = len(self.world.eclipseObject.eclipseOutMsgs) - 1
396396

397397

398-
class DisturbanceTorqueDynModel(BaseDynamicsModel):
398+
class DisturbanceTorqueDynModel(DynamicsModel):
399399
"""Dynamics model with constant disturbance torque."""
400400

401401
def __init__(self, *args, **kwargs) -> None:
@@ -424,15 +424,15 @@ def setup_disturbance_torque(
424424
self.scObject.addDynamicEffector(self.extForceTorqueObject)
425425

426426

427-
class AtmosphericDragDynModel(BaseDynamicsModel):
427+
class AtmosphericDragDynModel(DynamicsModel):
428428
"""Dynamics model with atmospheric drag."""
429429

430430
def __init__(self, *args, **kwargs) -> None:
431431
"""Dynamics model with atmospheric drag."""
432432
super().__init__(*args, **kwargs)
433433

434434
@classmethod
435-
def _requires_world(cls) -> list[type["WorldModel"]]:
435+
def _requires_world(cls) -> list[type["WorldModelABC"]]:
436436
return [
437437
world.AtmosphereWorldModel,
438438
] + super()._requires_world()
@@ -523,7 +523,7 @@ class BasicDynamicsModel(
523523
EclipseDynModel,
524524
DisturbanceTorqueDynModel,
525525
AtmosphericDragDynModel,
526-
BaseDynamicsModel,
526+
DynamicsModel,
527527
):
528528
"""Basic Dynamics model with minimum necessary Basilisk components."""
529529

@@ -548,7 +548,7 @@ def __init__(self, *args, **kwargs) -> None:
548548
super().__init__(*args, **kwargs)
549549

550550
@classmethod
551-
def _requires_world(cls) -> list[type["WorldModel"]]:
551+
def _requires_world(cls) -> list[type["WorldModelABC"]]:
552552
return super()._requires_world()
553553

554554
@property
@@ -810,8 +810,8 @@ def setup_reaction_wheel_power(
810810
__doc_title__ = "Dynamics Base"
811811

812812
__all__ = [
813+
"DynamicsModelABC",
813814
"DynamicsModel",
814-
"BaseDynamicsModel",
815815
"BasicDynamicsModel",
816816
"EclipseDynModel",
817817
"DisturbanceTorqueDynModel",

src/bsk_rl/sim/dyn/ground_imaging.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from bsk_rl.utils.functional import aliveness_checker, default_args
2020

2121
if TYPE_CHECKING: # pragma: no cover
22-
from bsk_rl.sim.world import WorldModel
22+
from bsk_rl.sim.world import WorldModelABC
2323

2424

2525
class ImagingDynModel(BasicDynamicsModel):
@@ -419,7 +419,7 @@ def __init__(self, *args, **kwargs) -> None:
419419
super().__init__(*args, **kwargs)
420420

421421
@classmethod
422-
def _requires_world(cls) -> list[type["WorldModel"]]:
422+
def _requires_world(cls) -> list[type["WorldModelABC"]]:
423423
return super()._requires_world() + [world.GroundStationWorldModel]
424424

425425
def _setup_dynamics_objects(self, **kwargs) -> None:

0 commit comments

Comments
 (0)