Skip to content

Commit a29291d

Browse files
authored
Merge pull request #16 from ExcitingSystems/enum
Add enums
2 parents 637c497 + 2a6fe8d commit a29291d

17 files changed

Lines changed: 168 additions & 163 deletions

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ A basic routine is as simple as:
99
```py
1010
import jax.numpy as jnp
1111
import exciting_environments as excenvs
12+
from exciting_environments import EnvironmentRegistry
1213
from exciting_environments.utils import MinMaxNormalization
1314

14-
env = excenvs.make(
15-
"Pendulum-v0",
15+
env = EnvironmentRegistry.PENDULUM.make(
1616
batch_size=5,
1717
action_normalizations={"torque": MinMaxNormalization(min=-15,max=15)},
1818
tau=2e-2
19-
)
19+
)
2020
obs, state = env.vmap_reset()
2121

2222
actions = jnp.linspace(start=-1, stop=1, num=1000)[None, :, None]
@@ -45,11 +45,11 @@ alternatively, simulate full trajectories:
4545
```py
4646
import jax.numpy as jnp
4747
import exciting_environments as excenvs
48+
from exciting_environments import EnvironmentRegistry
4849
from exciting_environments.utils import MinMaxNormalization
4950
import diffrax
5051

51-
env = excenvs.make(
52-
"Pendulum-v0",
52+
env = EnvironmentRegistry.PENDULUM.make(
5353
solver=diffrax.Tsit5(),
5454
batch_size=5,
5555
action_normalizations={"torque": MinMaxNormalization(min=-15,max=15)},
@@ -76,4 +76,4 @@ which produces $5$ identical trajectories in parallel as well:
7676
![](https://github.com/ExcitingSystems/exciting-environments/blob/main/fig/excenvs_pendulum_simulation_example_advanced.png?raw=true)
7777

7878
Note that in this case the Tsit5 ODE solver instead of the default explicit Euler is used.
79-
All solvers used here are from the diffrax library (https://docs.kidger.site/diffrax/).
79+
All solvers used here are from the diffrax library (https://docs.kidger.site/diffrax/).

examples/pmsm_example.ipynb

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": 1,
5+
"execution_count": null,
66
"metadata": {},
77
"outputs": [],
88
"source": [
@@ -14,6 +14,7 @@
1414
"from typing import Callable\n",
1515
"import os\n",
1616
"from exciting_environments import PMSM\n",
17+
"from exciting_environments.pmsm import MotorVariant\n",
1718
"import matplotlib.pyplot as plt\n",
1819
"import jax_dataclasses as jdc\n",
1920
"from exciting_environments.utils import MinMaxNormalization\n",
@@ -22,14 +23,14 @@
2223
},
2324
{
2425
"cell_type": "code",
25-
"execution_count": 2,
26+
"execution_count": null,
2627
"metadata": {},
2728
"outputs": [],
2829
"source": [
2930
"BATCH_SIZE=5\n",
3031
"new_motor_env = PMSM(\n",
3132
" saturated=True,\n",
32-
" LUT_motor_name=\"BRUSA\",\n",
33+
" motor_variant=MotorVariant.BRUSA,\n",
3334
" batch_size=BATCH_SIZE,\n",
3435
" control_state=[\"torque\"]\n",
3536
" )"
@@ -48,7 +49,7 @@
4849
},
4950
{
5051
"cell_type": "code",
51-
"execution_count": 4,
52+
"execution_count": null,
5253
"metadata": {},
5354
"outputs": [],
5455
"source": [
@@ -84,7 +85,7 @@
8485
},
8586
{
8687
"cell_type": "code",
87-
"execution_count": 6,
88+
"execution_count": null,
8889
"metadata": {},
8990
"outputs": [],
9091
"source": [
@@ -138,7 +139,7 @@
138139
],
139140
"metadata": {
140141
"kernelspec": {
141-
"display_name": "Python 3",
142+
"display_name": "venv_dev",
142143
"language": "python",
143144
"name": "python3"
144145
},
@@ -152,7 +153,7 @@
152153
"name": "python",
153154
"nbconvert_exporter": "python",
154155
"pygments_lexer": "ipython3",
155-
"version": "3.11.3"
156+
"version": "3.11.9"
156157
},
157158
"orig_nbformat": 4
158159
},

exciting_environments/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
from .pendulum import Pendulum
66
from .fluid_tank import FluidTank
77
from .acrobot import Acrobot
8-
from .registration import make
8+
from .registration import EnvironmentRegistry
99
from .gym_wrapper import GymWrapper
1010
from .mujoco_wrapper import MujucoWrapper

exciting_environments/gym_wrapper.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
from functools import partial
77
import chex
88
from abc import ABC
9-
from exciting_environments import spaces
10-
from exciting_environments.registration import make
9+
from exciting_environments import spaces, EnvironmentRegistry
10+
11+
# from exciting_environments.registration import make
1112

1213

1314
class GymWrapper(ABC):
@@ -58,9 +59,9 @@ def __init__(
5859
self.generate_terminated = self.env.generate_terminated
5960

6061
@classmethod
61-
def from_name(cls, env_id: str, **env_kwargs):
62-
"""Creates GymWrapper with environment based on passed env_id."""
63-
env = make(env_id, **env_kwargs)
62+
def from_env(cls, env_type: EnvironmentRegistry, **env_kwargs):
63+
"""Creates GymWrapper with environment from EnvironmentRegistry."""
64+
env = env_type.make(**env_kwargs)
6465
return cls(env)
6566

6667
def step(self, action):
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
from .motor_parameters import default_params
1+
from .motor_parameters import MotorVariant
22
from .pmsm_env import PMSM # , PMSM_Physical

exciting_environments/pmsm/motor_parameters.py

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
from exciting_environments.utils import MinMaxNormalization
1111
from copy import deepcopy
1212

13+
from enum import Enum
14+
1315

1416
@jdc.pytree_dataclass
1517
class PhysicalNormalizations:
@@ -147,21 +149,15 @@ def default_soft_constraints(self, state, action_norm, env_properties):
147149
)
148150

149151

150-
def default_params(name):
151-
"""
152-
Returns default parameters for specified motor configurations.
153-
154-
Args:
155-
name (str): Name of the motor ("BRUSA" or "SEW").
156-
157-
Returns:
158-
MotorConfig: Configuration containing physical constraints, action constraints, static parameters, and LUT data.
159-
"""
160-
if name is None:
161-
return deepcopy(DEFAULT)
162-
elif name == "BRUSA":
163-
return deepcopy(BRUSA)
164-
elif name == "SEW":
165-
return deepcopy(SEW)
166-
else:
167-
raise ValueError(f"Motor name {name} is not known.")
152+
class MotorVariant(Enum):
153+
DEFAULT = "DEFAULT"
154+
BRUSA = "BRUSA"
155+
SEW = "SEW"
156+
157+
def get_params(self):
158+
if self is MotorVariant.BRUSA:
159+
return deepcopy(BRUSA)
160+
elif self is MotorVariant.SEW:
161+
return deepcopy(SEW)
162+
else:
163+
return deepcopy(DEFAULT)

exciting_environments/pmsm/pmsm_env.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from copy import deepcopy
1515

1616
from exciting_environments import CoreEnvironment
17-
from exciting_environments.pmsm import default_params
17+
from exciting_environments.pmsm import MotorVariant
1818

1919

2020
# only for alpha/beta -> abc
@@ -117,7 +117,7 @@ def __init__(
117117
self,
118118
batch_size: int = 8,
119119
saturated=False,
120-
LUT_motor_name: str = None,
120+
motor_variant: MotorVariant = MotorVariant.DEFAULT,
121121
physical_normalizations: dict = None,
122122
action_normalizations: dict = None,
123123
soft_constraints: Callable = None,
@@ -130,7 +130,7 @@ def __init__(
130130
Args:
131131
batch_size (int): Number of parallel environment simulations. Default: 8
132132
saturated (bool): Permanent magnet flux linkages and inductances are taken from LUT_motor_name specific LUTs. Default: False
133-
LUT_motor_name (str): Sets physical_normalizations, action_normalizations, soft_constraints and static_params to default values for the passed motor name and stores associated LUTs for the possible saturated case. Needed if saturated==True.
133+
motor_variant (MotorVariant): Sets physical_normalizations, action_normalizations, soft_constraints and static_params to default values for the passed motor variant and stores associated LUTs for the possible saturated case. Needed if saturated==True.
134134
physical_normalizations (dict): min-max normalization values of the physical state of the environment.
135135
u_d_buffer (MinMaxNormalization): Direct share of the delayed action due to system deadtime. Default: min=-2 * 400 / 3, max=2 * 400 / 3
136136
u_q_buffer (MinMaxNormalization): Quadrature share of the delayed action due to system deadtime. Default: min=-2 * 400 / 3, max=2 * 400 / 3
@@ -161,8 +161,8 @@ def __init__(
161161
self.tau = tau
162162
self._solver = solver
163163

164-
if LUT_motor_name is not None:
165-
motor_params = deepcopy(default_params(LUT_motor_name))
164+
if motor_variant != MotorVariant.DEFAULT:
165+
motor_params = motor_variant.get_params()
166166
default_physical_normalizations = motor_params.physical_normalizations.__dict__
167167
default_action_normalizations = motor_params.action_normalizations.__dict__
168168
default_static_params = motor_params.static_params.__dict__
@@ -187,7 +187,10 @@ def __init__(
187187

188188
else:
189189
if saturated:
190-
raise Exception("LUT_motor_name is needed to load LUTs.")
190+
raise ValueError(
191+
f"MotorVariant '{motor_variant.value}' is not allowed for saturated LUTs. "
192+
"Use a specific motor variant. DEFAULT is only valid for saturated=False."
193+
)
191194

192195
saturated_quants = [
193196
"L_dd",
@@ -198,7 +201,7 @@ def __init__(
198201
"Psi_q",
199202
]
200203

201-
motor_params = deepcopy(default_params(LUT_motor_name))
204+
motor_params = motor_variant.get_params()
202205
default_physical_normalizations = motor_params.physical_normalizations.__dict__
203206
default_action_normalizations = motor_params.action_normalizations.__dict__
204207
default_static_params = motor_params.static_params.__dict__

exciting_environments/registration.py

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,27 @@
66
PMSM,
77
Acrobot,
88
)
9-
10-
11-
def make(env_id: str, **env_kwargs):
12-
if env_id == "CartPole-v0":
13-
env = CartPole(**env_kwargs)
14-
15-
elif env_id == "MassSpringDamper-v0":
16-
env = MassSpringDamper(**env_kwargs)
17-
18-
elif env_id == "Pendulum-v0":
19-
env = Pendulum(**env_kwargs)
20-
21-
elif env_id == "FluidTank-v0":
22-
env = FluidTank(**env_kwargs)
23-
24-
elif env_id == "PMSM-v0":
25-
env = PMSM(**env_kwargs)
26-
27-
elif env_id == "Acrobot-v0":
28-
env = Acrobot(**env_kwargs)
29-
30-
else:
31-
print(f"No existing environments got env_id ={env_id}")
32-
env = None
33-
34-
return env
9+
from enum import Enum
10+
11+
12+
class EnvironmentRegistry(Enum):
13+
CART_POLE = "CartPole-v0"
14+
MASS_SPRING_DAMPER = "MassSpringDamper-v0"
15+
PENDULUM = "Pendulum-v0"
16+
FLUID_TANK = "FluidTank-v0"
17+
PMSM = "PMSM-v0"
18+
ACROBOT = "Acrobot-v0"
19+
20+
def make(self, **env_kwargs):
21+
env_map = {
22+
EnvironmentRegistry.CART_POLE: CartPole,
23+
EnvironmentRegistry.MASS_SPRING_DAMPER: MassSpringDamper,
24+
EnvironmentRegistry.PENDULUM: Pendulum,
25+
EnvironmentRegistry.FLUID_TANK: FluidTank,
26+
EnvironmentRegistry.PMSM: PMSM,
27+
EnvironmentRegistry.ACROBOT: Acrobot,
28+
}
29+
cls = env_map.get(self)
30+
if cls is None:
31+
raise ValueError(f"Unknown environment: {self}")
32+
return cls(**env_kwargs)

tests/envs/acrobot/test_acrobot.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
import jax.numpy as jnp
55
import numpy as np
66
import diffrax
7+
from exciting_environments import EnvironmentRegistry
78
from exciting_environments.utils import MinMaxNormalization, load_sim_properties_from_json
89
from pathlib import Path
910
import pickle
1011
import os
1112

13+
1214
jax.config.update("jax_enable_x64", True)
1315

1416

@@ -33,7 +35,7 @@ def test_default_initialization():
3335
"omega_1": MinMaxNormalization(min=-10, max=10),
3436
"omega_2": MinMaxNormalization(min=-10, max=10),
3537
}
36-
env = excenvs.make("Acrobot-v0", batch_size=batch_size)
38+
env = EnvironmentRegistry.ACROBOT.make(batch_size=batch_size)
3739
for key, value in params.items():
3840
env_value = getattr(env.env_properties.static_params, key)
3941
if isinstance(value, jnp.ndarray) or isinstance(env_value, jnp.ndarray):
@@ -101,8 +103,7 @@ def test_custom_initialization():
101103
"omega_1": MinMaxNormalization(min=-55, max=10),
102104
"omega_2": MinMaxNormalization(min=-10, max=30),
103105
}
104-
env = excenvs.make(
105-
"Acrobot-v0",
106+
env = EnvironmentRegistry.ACROBOT.make(
106107
batch_size=batch_size,
107108
static_params=params,
108109
physical_normalizations=physical_normalizations,
@@ -159,8 +160,7 @@ def test_step_results():
159160
loaded_params, loaded_action_normalizations, loaded_physical_normalizations, loaded_tau = (
160161
load_sim_properties_from_json(file_path)
161162
)
162-
env = excenvs.make(
163-
"Acrobot-v0",
163+
env = EnvironmentRegistry.ACROBOT.make(
164164
tau=loaded_tau,
165165
solver=diffrax.Euler(),
166166
static_params=loaded_params,

0 commit comments

Comments
 (0)