diff --git a/machine_design/designs/design.py b/machine_design/designs/design.py index 8bdb757..df165fe 100644 --- a/machine_design/designs/design.py +++ b/machine_design/designs/design.py @@ -43,6 +43,12 @@ def add_rotor_barrier(self, barrier_points, segment_type=None) -> None: def add_rotor_magnet(self, magnet_points, segment_type=None) -> None: self.geometry.add_rotor_magnet(self.m2d, magnet_points, segment_type=segment_type) + def reassign_motion_setup(self) -> None: + motions = [b.name for b in self.m2d.boundaries if b.type == "Band"] + if motions: + self.m2d.omodelsetup.DeleteMotionSetup(motions) + self.geometry._assign_rotor_motion(self.m2d) + def delete_rotor(self) -> None: self.computation.delete_rotor_mesh() self.geometry.delete_rotor(self.m2d) diff --git a/machine_design/designs/geometry.py b/machine_design/designs/geometry.py index 82f8dbb..3b15d04 100644 --- a/machine_design/designs/geometry.py +++ b/machine_design/designs/geometry.py @@ -71,6 +71,8 @@ def build_rotor(self, m2d: Maxwell2d) -> None: rotor_id = modeler.create_polyline(points=self.rot_points, segment_type=["Arc", "Line", "Arc"], cover_surface=True, name="Rotor") self.rotor_id = rotor_id rotor_id.material_name = self.Fe + self.magnet_ids = [] + self.magnet_cs_ids = [] def add_rotor_barrier(self, m2d: Maxwell2d, barrier_points, segment_type=None) -> None: modeler = m2d.modeler @@ -95,6 +97,15 @@ def delete_rotor(self, m2d: Maxwell2d) -> None: assert isinstance(m2d.modeler, Modeler2D) m2d.modeler.delete(self.rotor_id) + if self.magnet_ids: + m2d.modeler.delete(self.magnet_ids) + self.magnet_ids = [] + + # Delete after the magnets, which reference them + for cs in self.magnet_cs_ids: + cs.delete() + self.magnet_cs_ids = [] + def _push_stator_variables(self, m2d: Maxwell2d) -> None: modeler = m2d.modeler assert isinstance(modeler, Modeler2D) @@ -194,38 +205,26 @@ def _assign_boundary_conditions(self, m2d: Maxwell2d) -> None: ) m2d.assign_vector_potential(assignment=id_bc_az, vector_value=0, boundary="A0") - def add_rotor_magnet(self, m2d: Maxwell2d, mag: np.ndarray, fill_height=0.9, fill_width=0.9, segment_type=None): + def add_rotor_magnet(self, m2d: Maxwell2d, magnet_points, segment_type=None) -> None: modeler = m2d.modeler + assert isinstance(modeler, Modeler2D) - if isinstance(mag, (list, tuple)): - mag = np.concatenate([np.asarray(m) for m in mag], axis=0) + if isinstance(magnet_points, (list, tuple)): + magnet_points = np.concatenate([np.asarray(m) for m in magnet_points], axis=0) - pts = np.asarray(mag) - center = pts.mean(axis=0) + magnet_points = np.round(np.asarray(magnet_points), 6) - r = np.linalg.norm(center) - if r < 1e-10: + center = magnet_points[:, :2].mean(axis=0) + if np.linalg.norm(center) < 1e-10: return + cs_angle_deg = np.degrees(np.arctan2(center[1], center[0])) - radial = center / r - long_axis = np.array([-radial[1], radial[0]]) - - pts_centered = pts - center + if magnet_points.shape[1] == 2: + magnet_points = np.hstack((magnet_points, np.zeros((len(magnet_points), 1)))) - proj_long = pts_centered @ long_axis - proj_short = pts_centered @ radial - - pts_scaled = center + (np.outer(proj_long * fill_height, long_axis) + np.outer(proj_short * fill_width, radial)) - - points = [[f"{x}mm", f"{y}mm", "0mm"] for x, y in pts_scaled] - - mag_id = modeler.create_polyline( - points=points, - close_surface=True, - cover_surface=True, - name="Magnet", - ) - cs_angle_deg = np.degrees(np.arctan2(radial[1], radial[0])) + points_str = [[str(y) for y in x] for x in magnet_points] + mag_id = modeler.create_polyline(points=points_str, segment_type=segment_type, close_surface=True, cover_surface=True, name="Magnet") + self.magnet_ids.append(mag_id) self.assign_magnet_cs(m2d, mag_id, cs_angle_deg) mag_id.material_name = self.magnet @@ -236,13 +235,14 @@ def add_rotor_magnet(self, m2d: Maxwell2d, mag: np.ndarray, fill_height=0.9, fil modeler.set_working_coordinate_system("Global") def _create_magnet_cs(self, m2d: Maxwell2d, name: str, angle_deg: float) -> None: - m2d.modeler.create_coordinate_system( + cs = m2d.modeler.create_coordinate_system( origin=[0, 0, 0], name=name, mode="axis", x_pointing=[float(np.cos(np.radians(angle_deg))), float(np.sin(np.radians(angle_deg))), 0], y_pointing=[float(-np.sin(np.radians(angle_deg))), float(np.cos(np.radians(angle_deg))), 0], ) + self.magnet_cs_ids.append(cs) def assign_magnet_cs(self, m2d: Maxwell2d, magnet_name: str, angle_deg: float) -> None: cs_name = f"CS_{magnet_name}" diff --git a/machine_design/optimization/generators.py b/machine_design/optimization/generators.py index 08e8e37..36d7e0c 100644 --- a/machine_design/optimization/generators.py +++ b/machine_design/optimization/generators.py @@ -584,14 +584,17 @@ def generate_barriers(self) -> list[np.ndarray]: barriers.append(xy_all) return barriers - def generate_magnets(self, barriers: list[np.ndarray]) -> list[np.ndarray]: + def generate_magnets(self, barriers: list[np.ndarray], margin: float = 0.0) -> list[np.ndarray]: magnets = [] - margin = 0.0 for barrier in barriers: x, y = barrier[:, 0], barrier[:, 1] mag_pts = np.column_stack((x, y)) + if margin <= 0: + magnets.append([mag_pts]) + continue + angles = np.degrees(np.arctan2(mag_pts[:, 1], mag_pts[:, 0])) center_angle = (angles.max() + angles.min()) / 2 diff --git a/machine_design/optimization/geometry.py b/machine_design/optimization/geometry.py index e628a16..159c304 100644 --- a/machine_design/optimization/geometry.py +++ b/machine_design/optimization/geometry.py @@ -14,13 +14,17 @@ def rotate(x, y, alpha, **kwargs): return xy_rot[0], xy_rot[1] -def plot_barriers(barriers, design, title=None, file_name=None): +def plot_barriers(barriers, design, title=None, file_name=None, magnets=None): plt.figure() alphas = np.linspace(0 * np.pi, 2 * np.pi / 4, 100) for r in [design.geometry.rotor_r_min, design.geometry.rotor_r_max]: plt.plot(r * np.cos(alphas), r * np.sin(alphas)) for barrier in barriers: plt.plot(barrier[:, 0], barrier[:, 1]) + if magnets is not None: + for magnet in magnets: + magnet = np.concatenate([np.asarray(m) for m in magnet]) if isinstance(magnet, (list, tuple)) else magnet + plt.plot(magnet[:, 0], magnet[:, 1]) plt.axis("equal") if title is not None: plt.title(title) diff --git a/motors/synrm_3f_36s_mag.py b/motors/synrm_3f_36s_mag.py index 808ece2..5bb4063 100644 --- a/motors/synrm_3f_36s_mag.py +++ b/motors/synrm_3f_36s_mag.py @@ -9,9 +9,12 @@ class Geometry(Geometry3f36s): + def __init__(self) -> None: + self.set_magnets() + super().__init__() + def build_stator(self, m2d: Maxwell2d) -> None: super().build_stator(m2d) - self.set_magnets() self._create_material(m2d, self.magnet, **self.magnet_props) def set_magnets(self): diff --git a/scripts/3f_torque_optimization/run_mag.py b/scripts/3f_torque_optimization/run_mag.py new file mode 100644 index 0000000..7e1c18b --- /dev/null +++ b/scripts/3f_torque_optimization/run_mag.py @@ -0,0 +1,91 @@ +# export ANSYSEM_ROOT241=/data/AnsysEM/v241/Linux64 + +import os + +import numpy as np +import pandas as pd + +from machine_design.config import load_config +from machine_design.designs import load_design +from machine_design.optimization import ( + MagnetGenerator, + analyze_results, + plot_barriers, + save_params, +) +from motors.synrm_3f_36s_mag import Computation, Geometry + +config = load_config() +aedt_version = config["aedt_version"] +num_cores = config["num_cores"] +n_designs = 1 +r_stator_end = 0.7 +offset = 0.7 / 2 +current_setpoint = (1.5, 1.5) +plot_design = True + +project_name = "SynRM_test" +design_name = "Design01" +path_data = os.path.join(os.getcwd(), "data") +path_results = "results" +for path in [path_data, path_results]: + os.makedirs(path, exist_ok=True) +file_name_aedt = f"{path_data}/{project_name}.aedt" + +geometry = Geometry() +computation = Computation(geometry) +design = load_design(file_name_aedt, project_name, design_name, aedt_version, geometry, computation) +generators = [MagnetGenerator(design, r_stator_end, offset=offset)] + +metadata = pd.DataFrame() +for i in range(0, n_designs): + for generator in generators: + # Generate a feasible design + while True: + params = generator.random_parameters() + generator.set_parameters(params) + barriers = generator.generate_barriers() + barriers = generator.split_barriers(barriers) + if generator.name == "MagnetGenerator": + magnets = generator.generate_magnets(barriers) + feasible = generator.feasible_barriers(barriers) + if feasible: + break + + # Generate the geometry + design.add_rotor() + for j, barrier in enumerate(barriers): + design.add_rotor_barrier(barrier) + if generator.name == "MagnetGenerator": + design.add_rotor_magnet(magnets[j]) + + design.reassign_motion_setup() + + # Compute the torque + Tor = design.compute(*current_setpoint, NUM_CORES=num_cores) + # Tor = design.compute(num_cores) + if Tor is None: + TorAvg, TorRippleRms = np.nan, np.nan + else: + TorAvg, _, TorRippleRms = analyze_results(Tor) + + # Delete the rotor + design.delete_rotor() + + # Potentially save the design + if plot_design: + title = f"Torque mean value: {np.round(TorAvg, 2)} Nm, ripple relative value: {np.round(TorRippleRms, 2)} %" + file_name = f"{path_results}/design_{generator.name}_{i}" + plot_barriers(barriers, design, title=title, file_name=f"{file_name}.png", magnets=magnets) + save_params(params, f"{file_name}.pkl") + + metadata_new = { + "method": generator.name, + "design": i, + "T": TorAvg, + "ripple": TorRippleRms, + } + metadata = pd.concat((metadata, pd.DataFrame([metadata_new])), ignore_index=True) + metadata.to_csv(f"{path_results}/metadata.csv", index=False) + +design.close_project()