diff --git a/machine_design/designs/computation.py b/machine_design/designs/computation.py index 20b2d74..950ef8a 100644 --- a/machine_design/designs/computation.py +++ b/machine_design/designs/computation.py @@ -3,6 +3,7 @@ from ansys.aedt.core import Maxwell2d from .geometry import GeometryBase +from .reserved_variables import check_no_reserved_variable_names class ComputationBase(ABC): @@ -13,6 +14,7 @@ def __init__(self, geometry: GeometryBase) -> None: self.set_solution_expressions() self.set_output_vars() self.set_post_params() + check_no_reserved_variable_names(self.oper_params, self.output_vars) @abstractmethod def set_oper_params(self): ... diff --git a/machine_design/designs/geometry.py b/machine_design/designs/geometry.py index 58d9dc2..37c34ad 100644 --- a/machine_design/designs/geometry.py +++ b/machine_design/designs/geometry.py @@ -4,6 +4,8 @@ from ansys.aedt.core import Maxwell2d from ansys.aedt.core.modeler.modeler_2d import Modeler2D +from .reserved_variables import check_no_reserved_variable_names + class GeometryBase(ABC): def __init__(self) -> None: @@ -15,6 +17,7 @@ def __init__(self) -> None: self.set_rot_points() self.set_derived_params() self.set_udp_par_list_stator() + check_no_reserved_variable_names(self.geom_params, self.wind_params, self.slot_params, self.mod_params) @abstractmethod def set_iron(self): ... diff --git a/machine_design/designs/reserved_variables.py b/machine_design/designs/reserved_variables.py new file mode 100644 index 0000000..397e1bc --- /dev/null +++ b/machine_design/designs/reserved_variables.py @@ -0,0 +1,79 @@ +# Ansys intrinsic/reserved variable names +reserved_variable_names = frozenset( + name.lower() + for name in ( + "_Empty", + "_I1", + "_I2", + "_I3", + "_I4", + "_I5", + "_I6", + "_I7", + "_I8", + "_I9", + "_t", + "_u", + "_v", + "_V1", + "_V2", + "_V3", + "_V4", + "_V5", + "_V6", + "_V7", + "_V8", + "_V9", + "Ang", + "Budget_Index", + "Distance", + "ElectricalDegree", + "F", + "F1", + "F2", + "F3", + "FNoi", + "Freq", + "Hmax", + "Hmin", + "Ia", + "Ib", + "Index", + "IWavePhi", + "IWaveTheta", + "Normalized Deformation", + "Normalized Distance", + "OP", + "Pass", + "Phase", + "Phi", + "Position", + "R", + "Rho", + "RSpeed", + "Spectrum", + "Speed", + "Temp", + "Tend", + "Theta", + "Time", + "Time0", + "Vac", + "Vbe", + "Vce", + "Vds", + "Vgs", + "X", + "Y", + "Z", + "ZAng", + "ZRho", + ) +) + + +def check_no_reserved_variable_names(*param_dicts: dict) -> None: + for params in param_dicts: + for name in params: + if name.lower() in reserved_variable_names: + raise ValueError(f"'{name}' is an Ansys intrinsic variable name and cannot be used as a design variable") diff --git a/tests/test_computation.py b/tests/test_computation.py new file mode 100644 index 0000000..f675f33 --- /dev/null +++ b/tests/test_computation.py @@ -0,0 +1,53 @@ +import pytest + +from machine_design.designs.computation import ComputationBase + + +class _DummyComputation(ComputationBase): + def __init__(self, geometry, oper_params, output_vars): + self._oper_params = oper_params + self._output_vars = output_vars + super().__init__(geometry) + + def set_oper_params(self): + self.oper_params = self._oper_params + + def set_solution_expressions(self): + self.solution_expressions = "Moving1.Torque" + + def set_output_vars(self): + self.output_vars = self._output_vars + + def set_post_params(self): + self.post_params = {} + + def assign_stator_coils(self, m2d): + pass + + def inductance_computation(self, m2d): + pass + + def set_variables(self, m2d, *args): + pass + + def extract_results(self, solutions): + pass + + +def test_no_reserved_names_does_not_raise(): + _DummyComputation(object(), {"Im": "1A"}, {"pos": "Moving1.Position"}) + + +def test_reserved_name_in_oper_params_raises(): + with pytest.raises(ValueError, match="F"): + _DummyComputation(object(), {"F": "50Hz"}, {}) + + +def test_reserved_name_in_output_vars_raises(): + with pytest.raises(ValueError, match="Time"): + _DummyComputation(object(), {}, {"Time": "0s"}) + + +def test_reserved_name_check_is_case_insensitive(): + with pytest.raises(ValueError, match="f"): + _DummyComputation(object(), {"f": "50Hz"}, {}) diff --git a/tests/test_geometry.py b/tests/test_geometry.py new file mode 100644 index 0000000..df95e38 --- /dev/null +++ b/tests/test_geometry.py @@ -0,0 +1,58 @@ +import pytest + +from machine_design.designs.geometry import GeometryBase + + +class _DummyGeometry(GeometryBase): + def __init__(self, geom_params, wind_params, slot_params, mod_params): + self._geom_params = geom_params + self._wind_params = wind_params + self._slot_params = slot_params + self._mod_params = mod_params + super().__init__() + + def set_iron(self): + pass + + def set_geom_params(self): + self.geom_params = self._geom_params + + def set_slot_params(self): + self.slot_params = self._slot_params + + def set_winds_params(self): + self.wind_params = self._wind_params + + def set_mod_params(self): + self.mod_params = self._mod_params + + def set_rot_points(self): + pass + + def set_derived_params(self): + pass + + def set_udp_par_list_stator(self): + pass + + def build_stator(self, m2d): + pass + + +def test_no_reserved_names_does_not_raise(): + _DummyGeometry({"DiaStatorGap": "80mm"}, {"Nc": "10"}, {"Hs0": "1mm"}, {"Poles": "4"}) + + +def test_reserved_name_in_geom_params_raises(): + with pytest.raises(ValueError, match="Distance"): + _DummyGeometry({"Distance": "80mm"}, {}, {}, {}) + + +def test_reserved_name_in_mod_params_raises(): + with pytest.raises(ValueError, match="Time"): + _DummyGeometry({}, {}, {}, {"Time": "1s"}) + + +def test_reserved_name_check_is_case_insensitive(): + with pytest.raises(ValueError, match="z"): + _DummyGeometry({}, {}, {"z": "1mm"}, {})