From f2017432cc4d3ebb52dfffaa61505cc3cc3ef9e6 Mon Sep 17 00:00:00 2001 From: haitao-ZCU Date: Tue, 8 Sep 2026 16:56:43 +0200 Subject: [PATCH 1/2] Add automatic check for Ansys reserved variable names in ComputationBase --- machine_design/designs/computation.py | 79 +++++++++++++++++++++++++++ tests/test_computation.py | 53 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 tests/test_computation.py diff --git a/machine_design/designs/computation.py b/machine_design/designs/computation.py index 20b2d74..3601f89 100644 --- a/machine_design/designs/computation.py +++ b/machine_design/designs/computation.py @@ -4,6 +4,79 @@ from .geometry import GeometryBase +# 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", + ) +) + class ComputationBase(ABC): def __init__(self, geometry: GeometryBase) -> None: @@ -13,6 +86,12 @@ def __init__(self, geometry: GeometryBase) -> None: self.set_solution_expressions() self.set_output_vars() self.set_post_params() + self._check_no_reserved_variable_names() + + def _check_no_reserved_variable_names(self) -> None: + for name in list(self.oper_params) + list(self.output_vars): + 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") @abstractmethod def set_oper_params(self): ... 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"}, {}) From ddfd3e0ddcab5f77c71d58b995527dc4864ecc1c Mon Sep 17 00:00:00 2001 From: haitao-ZCU Date: Tue, 8 Sep 2026 19:51:29 +0200 Subject: [PATCH 2/2] Extract reserved-variable check into a shared function used by both ComputationBase and GeometryBase --- machine_design/designs/computation.py | 81 +------------------- machine_design/designs/geometry.py | 3 + machine_design/designs/reserved_variables.py | 79 +++++++++++++++++++ tests/test_geometry.py | 58 ++++++++++++++ 4 files changed, 142 insertions(+), 79 deletions(-) create mode 100644 machine_design/designs/reserved_variables.py create mode 100644 tests/test_geometry.py diff --git a/machine_design/designs/computation.py b/machine_design/designs/computation.py index 3601f89..950ef8a 100644 --- a/machine_design/designs/computation.py +++ b/machine_design/designs/computation.py @@ -3,79 +3,7 @@ from ansys.aedt.core import Maxwell2d from .geometry import GeometryBase - -# 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", - ) -) +from .reserved_variables import check_no_reserved_variable_names class ComputationBase(ABC): @@ -86,12 +14,7 @@ def __init__(self, geometry: GeometryBase) -> None: self.set_solution_expressions() self.set_output_vars() self.set_post_params() - self._check_no_reserved_variable_names() - - def _check_no_reserved_variable_names(self) -> None: - for name in list(self.oper_params) + list(self.output_vars): - 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") + 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_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"}, {})