Source code for Tests.Plot.test_ICEM_2020

from os import makedirs
from os.path import join, isdir
import pytest
from shutil import copyfile

import matplotlib.pyplot as plt
from numpy import array, linspace, ones, pi, zeros

from pyleecan.Classes.import_all import *

try:
    from pyleecan.Functions.GMSH.gen_3D_mesh import gen_3D_mesh
except ImportError as error:
    gen_3D_mesh = error
from Tests import save_plot_path
from Tests.Plot.LamWind import wind_mat
from pyleecan.Functions.load import load
from pyleecan.Classes.InputCurrent import InputCurrent
from pyleecan.Classes.MagFEMM import MagFEMM
from pyleecan.Classes.Simu1 import Simu1
from pyleecan.Classes.Output import Output
from pyleecan.Classes.OptiDesignVar import OptiDesignVar
from pyleecan.Classes.OptiObjective import OptiObjective
from pyleecan.Classes.OptiProblem import OptiProblem
from pyleecan.Classes.ImportMatrixVal import ImportMatrixVal
from pyleecan.Classes.ImportGenVectLin import ImportGenVectLin
from pyleecan.Classes.OptiGenAlgNsga2Deap import OptiGenAlgNsga2Deap
from pyleecan.Methods.Machine.Winding import WindingError
from pyleecan.Methods.Machine.WindingCW2LT import WindingT1DefMsError
from pyleecan.Methods.Machine.WindingCW1L import WindingT2DefNtError

import numpy as np
import random
from pyleecan.Functions.load import load
from pyleecan.definitions import DATA_DIR

# Gather results in the same folder
save_path = join(save_plot_path, "ICEM_2020")
if not isdir(save_path):
    makedirs(save_path)


"""This test gather all the images/project for the ICEM 2020 publication:
"Design optimization of innovative electrical machines topologies based
on Pyleecan open-source object-oriented software"
"""


[docs]@pytest.mark.MagFEMM @pytest.mark.SCIM @pytest.mark.periodicity @pytest.mark.SingleOP def test_FEMM_sym(): """Figure 9: Check that the FEMM can handle symmetry From pyleecan/Tests/Validation/Simulation/test_EM_SCIM_NL_006.py """ SCIM_006 = load(join(DATA_DIR, "Machine", "SCIM_006.json")) simu = Simu1(name="test_ICEM_2020", machine=SCIM_006) simu.machine.name = "fig_09_FEMM_sym" # Definition of the enforced output of the electrical module N0 = 1500 Is = ImportMatrixVal(value=array([[20, -10, -10]])) Ir = ImportMatrixVal(value=zeros((1, 28))) Nt_tot = 1 Na_tot = 4096 simu.input = InputCurrent( Is=Is, Ir=Ir, # zero current for the rotor N0=N0, angle_rotor=None, # Will be computed Nt_tot=Nt_tot, Na_tot=Na_tot, angle_rotor_initial=0.2244, ) # Definition of the magnetic simulation # 2 sym + antiperiodicity = 1/4 Lamination simu.mag = MagFEMM(type_BH_stator=2, type_BH_rotor=2, is_periodicity_a=True) # Stop after magnetic computation simu.force = None simu.struct = None # Run simulation out = Output(simu=simu) simu.run() # FEMM files (mesh and results) are available in Results folder copyfile( join(out.path_result, "Femm", "fig_09_FEMM_sym_model.ans"), join(save_path, "fig_09_FEMM_sym_model.ans"), ) copyfile( join(out.path_result, "Femm", "fig_09_FEMM_sym_model.fem"), join(save_path, "fig_09_FEMM_sym_model.fem"), )
[docs]@pytest.mark.GMSH def test_gmsh_mesh_dict(): """Figure 10: Generate a 3D mesh with Gmsh by setting the number of element on each lines """ if isinstance(gen_3D_mesh, ImportError): raise ImportError("Fail to import gen_3D_mesh (gmsh package missing)") # Stator definition stator = LamSlotWind( Rint=0.1325, Rext=0.2, Nrvd=0, L1=0.35, Kf1=0.95, is_internal=False, is_stator=True, ) stator.slot = SlotW10( Zs=36, H0=1e-3, H1=1.5e-3, H2=30e-3, W0=12e-3, W1=14e-3, W2=12e-3 ) # Plot, check and save stator.plot(is_lam_only=True, is_show_fig=False) fig = plt.gcf() fig.savefig(join(save_path, "fig_10_ref_lamination.png")) fig.savefig(join(save_path, "fig_10_ref_lamination.svg"), format="svg") assert len(fig.axes[0].patches) == 2 # Definition of the number of each element on each line mesh_dict = { "Tooth_Yoke_Side_Right": 5, "Tooth_Yoke_Side_Left": 5, "Tooth_Yoke_Arc": 5, "Tooth_line_3": 2, "Tooth_line_4": 8, "Tooth_line_5": 1, "Tooth_line_6": 1, "Tooth_line_7": 1, "Tooth_bore_arc_bot": 2, "Tooth_bore_arc_top": 2, "Tooth_line_10": 1, "Tooth_line_11": 1, "Tooth_line_12": 1, "Tooth_line_13": 8, "Tooth_line_14": 2, } gen_3D_mesh( lamination=stator, save_path=join(save_path, "fig_10_gmsh_mesh_dict.msh"), mesh_size=7e-3, user_mesh_dict=mesh_dict, is_rect=True, Nlayer=18, display=False, )
# To see the resulting mesh, gmsh_mesh_dict.msh need to be # opened in Gmsh
[docs]@pytest.mark.skip @pytest.mark.GMSH def test_SlotMulti_sym(): """Figure 11: Genera te a 3D mesh with GMSH for a lamination with several slot types and notches """ if isinstance(gen_3D_mesh, ImportError): raise ImportError("Fail to import gen_3D_mesh (gmsh package missing)") plt.close("all") # Rotor definition rotor = LamSlotMulti( Rint=0.2, Rext=0.7, is_internal=True, is_stator=False, L1=0.9, Nrvd=2, Wrvd=0.05 ) # Reference Slot Zs = 8 Slot1 = SlotW10( Zs=Zs, W0=50e-3, H0=30e-3, W1=100e-3, H1=30e-3, H2=100e-3, W2=120e-3 ) Slot2 = SlotW22(Zs=Zs, W0=pi / 12, H0=50e-3, W2=pi / 6, H2=125e-3) # Reference slot are duplicated to get 4 of each in alternance slot_list = list() for ii in range(Zs // 2): slot_list.append(SlotW10(init_dict=Slot1.as_dict())) slot_list.append(SlotW22(init_dict=Slot2.as_dict())) rotor.slot_list = slot_list # Set slot position as linspace rotor.alpha = linspace(0, 2 * pi, 8, endpoint=False) + pi / Zs # Set evenly distributed notches slot3 = SlotW10(Zs=Zs // 2, W0=40e-3, W1=40e-3, W2=40e-3, H0=0, H1=0, H2=25e-3) notch = NotchEvenDist(notch_shape=slot3, alpha=2 * pi / Zs) rotor.notch = [notch] # Plot, check and save rotor.plot(sym=4, is_show_fig=False) fig = plt.gcf() fig.savefig(join(save_path, "fig_11_SlotMulti_sym.png")) fig.savefig(join(save_path, "fig_11_SlotMulti_sym.svg"), format="svg") assert len(fig.axes[0].patches) == 1 # Generate the gmsh equivalent gen_3D_mesh( lamination=rotor, save_path=join(save_path, "fig_11_gmsh_SlotMulti.msh"), sym=4, mesh_size=20e-3, Nlayer=20, display=False, )
# To see the resulting mesh, gmsh_SlotMulti.msh need to be # opened in Gmsh
[docs]@pytest.mark.MachineUD def test_MachineUD(): """Figure 12: Check that you can plot a machine with 4 laminations""" machine = MachineUD() machine.name = "Machine with 4 laminations" # Main geometry parameter Rext = 170e-3 # Exterior radius of outter lamination W1 = 30e-3 # Width of first lamination A1 = 2.5e-3 # Width of the first airgap W2 = 20e-3 A2 = 10e-3 W3 = 20e-3 A3 = 2.5e-3 W4 = 60e-3 # Outer stator lam1 = LamSlotWind(Rext=Rext, Rint=Rext - W1, is_internal=False, is_stator=True) lam1.slot = SlotW22( Zs=12, W0=2 * pi / 12 * 0.75, W2=2 * pi / 12 * 0.75, H0=0, H2=W1 * 0.65 ) lam1.winding = WindingCW2LT(qs=3, p=3) # Outer rotor lam2 = LamSlot( Rext=lam1.Rint - A1, Rint=lam1.Rint - A1 - W2, is_internal=True, is_stator=False ) lam2.slot = SlotW10(Zs=22, W0=25e-3, W1=25e-3, W2=15e-3, H0=0, H1=0, H2=W2 * 0.75) # Inner rotor lam3 = LamSlot( Rext=lam2.Rint - A2, Rint=lam2.Rint - A2 - W3, is_internal=False, is_stator=False, ) lam3.slot = SlotW10( Zs=22, W0=17.5e-3, W1=17.5e-3, W2=12.5e-3, H0=0, H1=0, H2=W3 * 0.75 ) # Inner stator lam4 = LamSlotWind( Rext=lam3.Rint - A3, Rint=lam3.Rint - A3 - W4, is_internal=True, is_stator=True ) lam4.slot = SlotW10(Zs=12, W0=25e-3, W1=25e-3, W2=1e-3, H0=0, H1=0, H2=W4 * 0.75) lam4.winding = WindingCW2LT(qs=3, p=3) # Machine definition machine.lam_list = [lam1, lam2, lam3, lam4] # Plot, check and save machine.plot(is_show_fig=False) fig = plt.gcf() fig.savefig(join(save_path, "fig_12_MachineUD.png")) fig.savefig(join(save_path, "fig_12_MachineUD.svg"), format="svg") assert len(fig.axes[0].patches) == 57 machine.frame = None machine.name = None machine.plot(is_show_fig=False) fig = plt.gcf() fig.savefig(join(save_path, "fig_12_MachineUD_no_frame_no_name.png")) fig.savefig(join(save_path, "fig_12_MachineUD_no_frame_no_name.svg"), format="svg") assert len(fig.axes[0].patches) == 57 """Check that comp_connection_mat can raise a WindingT1DefMsError""" lam4.winding = WindingCW2LT(qs=16, p=3) with pytest.raises(WindingT1DefMsError) as context: lam4.winding.comp_connection_mat(Zs=10) """Check that comp_connection_mat can raise a WindingError""" winding = WindingCW2LT(qs=3, p=3) with pytest.raises(WindingError) as context: winding.comp_connection_mat(Zs=None) lam4.winding = WindingCW2LT(qs=3, p=3) lam4.slot = None with pytest.raises(WindingError) as context: lam4.winding.comp_connection_mat(Zs=None) # FOR WindingCW1L comp_connection_mat """Check that comp_connection_mat can raise a WindingT2DefNtError""" lam4.winding = WindingCW1L(qs=2, p=3) lam4.slot = SlotW10(Zs=12, W0=25e-3, W1=25e-3, W2=1e-3, H0=0, H1=0, H2=W4 * 0.75) with pytest.raises(WindingT2DefNtError) as context: lam4.winding.comp_connection_mat(Zs=17) lam4.winding = WindingCW1L(qs=2, p=3) lam4.slot = SlotW10(Zs=12, W0=25e-3, W1=25e-3, W2=1e-3, H0=0, H1=0, H2=W4 * 0.75) lam4.winding.comp_connection_mat(Zs=None) """Check that comp_connection_mat can raise a WindingError""" lam4.winding = WindingCW1L(qs=3, p=3) lam4.slot = None with pytest.raises(WindingError) as context: lam4.winding.comp_connection_mat(Zs=None) winding = WindingCW1L(qs=3, p=3) with pytest.raises(WindingError) as context: winding.comp_connection_mat(Zs=None)
[docs]def test_SlotMulti_rotor(): """Figure 13: Check that you can plot a LamSlotMulti rotor (two slots kind + notches)""" plt.close("all") # Lamination main dimensions definition rotor = LamSlotMulti(Rint=0.2, Rext=0.7, is_internal=True, is_stator=False) # Reference slot definition Slot1 = SlotW10( Zs=10, W0=50e-3, H0=30e-3, W1=100e-3, H1=30e-3, H2=100e-3, W2=120e-3 ) Slot2 = SlotW22(Zs=12, W0=pi / 12, H0=50e-3, W2=pi / 6, H2=125e-3) # Reference slot are duplicated to get 5 of each in alternance slot_list = list() for ii in range(5): slot_list.append(SlotW10(init_dict=Slot1.as_dict())) slot_list.append(SlotW22(init_dict=Slot2.as_dict())) # Two slots in the list are modified (bigger than the others) rotor.slot_list = slot_list rotor.slot_list[0].H2 = 300e-3 rotor.slot_list[7].H2 = 300e-3 # Set slots position rotor.alpha = array([0, 29, 60, 120, 150, 180, 210, 240, 300, 330]) * pi / 180 # Evenly distributed Notch definition slot3 = SlotW10(Zs=12, W0=40e-3, W1=40e-3, W2=40e-3, H0=0, H1=0, H2=25e-3) notch = NotchEvenDist(notch_shape=slot3, alpha=15 * pi / 180) rotor.notch = [notch] # Plot, check and save rotor.plot(is_show_fig=False) fig = plt.gcf() fig.savefig(join(save_path, "fig_13_LamSlotMulti_rotor.png")) fig.savefig(join(save_path, "fig_13_LamSlotMulti_rotor.svg"), format="svg") assert len(fig.axes[0].patches) == 2
[docs]def test_SlotMulti_stator(): """Figure 13: Check that you can plot a LamSlotMulti stator (two slots kind + notches)""" plt.close("all") # Lamination main dimensions definition stator = LamSlotMulti(Rint=0.2, Rext=0.7, is_internal=False, is_stator=True) # Reference slot definition Slot1 = SlotW10( Zs=10, W0=50e-3, H0=30e-3, W1=100e-3, H1=30e-3, H2=100e-3, W2=120e-3 ) Slot2 = SlotW22(Zs=12, W0=pi / 12, H0=50e-3, W2=pi / 6, H2=125e-3) # Reference slot are duplicated to get 5 of each in alternance slot_list = list() for ii in range(5): slot_list.append(SlotW10(init_dict=Slot1.as_dict())) slot_list.append(SlotW22(init_dict=Slot2.as_dict())) # Two slots in the list are modified (bigger than the others) stator.slot_list = slot_list stator.slot_list[0].H2 = 300e-3 stator.slot_list[7].H2 = 300e-3 # Set slots position stator.alpha = array([0, 29, 60, 120, 150, 180, 210, 240, 300, 330]) * pi / 180 # Evenly distributed Notch definition slot3 = SlotW10(Zs=12, W0=40e-3, W1=40e-3, W2=40e-3, H0=0, H1=0, H2=25e-3) notch = NotchEvenDist(notch_shape=slot3, alpha=15 * pi / 180) stator.notch = [notch] # Plot, check and save stator.plot(is_show_fig=False) fig = plt.gcf() fig.savefig(join(save_path, "fig_13_LamSlotMulti_stator.png")) fig.savefig(join(save_path, "fig_13_LamSlotMulti_stator.svg"), format="svg") assert len(fig.axes[0].patches) == 2
[docs]@pytest.mark.SlotUD def test_SlotUD(): """Figure 14: User Defined slot "snowflake" """ plt.close("all") # Enfore first point on rotor bore Rrotor = abs(0.205917893677990 - 0.107339745962156j) machine = MachineSRM() machine.name = "User-Defined Slot" # Stator definintion machine.stator = LamSlotWind( Rint=Rrotor + 5e-3, Rext=Rrotor + 120e-3, is_internal=False, is_stator=True ) machine.stator.slot = SlotW21( Zs=36, W0=7e-3, H0=10e-3, H1=0, H2=70e-3, W1=30e-3, W2=0.1e-3 ) machine.stator.winding = WindingDW2L(qs=3, p=3, coil_pitch=5) # Rotor definition machine.rotor = LamSlot(Rint=0.02, Rext=Rrotor, is_internal=True, is_stator=False) machine.rotor.axial_vent = [ VentilationTrap(Zh=6, Alpha0=0, D0=0.025, H0=0.025, W1=0.015, W2=0.04) ] # Complex coordinates of half the snowflake slot point_list = [ 0.205917893677990 - 0.107339745962156j, 0.187731360198517 - 0.0968397459621556j, 0.203257639640145 - 0.0919474411167423j, 0.199329436409870 - 0.0827512886940357j, 0.174740979141750 - 0.0893397459621556j, 0.143564064605510 - 0.0713397459621556j, 0.176848674296337 - 0.0616891108675446j, 0.172822394854708 - 0.0466628314259158j, 0.146001886779019 - 0.0531173140978201j, 0.155501886779019 - 0.0366628314259158j, 0.145109581933606 - 0.0306628314259158j, 0.127109581933606 - 0.0618397459621556j, 0.0916025403784439 - 0.0413397459621556j, 0.134949327895761 - 0.0282609076372691j, 0.129324972242779 - 0.0100025773880714j, 0.0690858798800485 - 0.0283397459621556j, 0.0569615242270663 - 0.0213397459621556j, ] machine.rotor.slot = SlotUD(Zs=6) machine.rotor.slot.set_from_point_list(is_sym=True, point_list=point_list) # Plot, check and save machine.plot(is_show_fig=False) fig = plt.gcf() assert len(fig.axes[0].patches) == 83 fig.savefig(join(save_path, "fig_14_SlotUD.png")) fig.savefig(join(save_path, "fig_14_SlotUD.svg"), format="svg")
[docs]def test_WindingUD(): """Figure 16: User-defined Winding From pyleecan/Tests/Plot/LamWind/test_Slot_12_plot.py """ plt.close("all") machine = MachineDFIM() machine.name = "User Defined Winding" # Rotor definition machine.rotor = LamSlotWind( Rint=0.2, Rext=0.5, is_internal=True, is_stator=False, L1=0.9, Nrvd=2, Wrvd=0.05 ) machine.rotor.axial_vent = [ VentilationPolar(Zh=6, Alpha0=pi / 6, W1=pi / 6, D0=100e-3, H0=0.3) ] machine.rotor.slot = SlotW12(Zs=6, R2=35e-3, H0=20e-3, R1=17e-3, H1=130e-3) machine.rotor.winding = WindingUD(user_wind_mat=wind_mat, qs=4, p=4, Lewout=60e-3) machine.rotor.mat_type.mag = MatMagnetics(Wlam=0.5e-3) # Stator definion machine.stator = LamSlotWind( Rint=0.51, Rext=0.8, is_internal=False, is_stator=True, L1=0.9, Nrvd=2, Wrvd=0.05, ) machine.stator.slot = SlotW12(Zs=18, R2=25e-3, H0=30e-3, R1=0, H1=150e-3) machine.stator.winding.Lewout = 60e-3 machine.stator.winding = WindingDW2L(qs=3, p=3) machine.stator.mat_type.mag = MatMagnetics(Wlam=0.5e-3) # Shaft & frame machine.shaft = Shaft(Drsh=machine.rotor.Rint * 2, Lshaft=1) machine.frame = Frame(Rint=0.8, Rext=0.9, Lfra=1) # Plot, check and save machine.plot(is_show_fig=False) fig = plt.gcf() fig.savefig(join(save_path, "fig_16_WindingUD.png")) fig.savefig(join(save_path, "fig_16_WindingUD.svg"), format="svg") assert len(fig.axes[0].patches) == 73
[docs]def test_BoreFlower(): """Figure 18: LamHole with uneven bore shape From pyleecan/Tests/Plot/LamHole/test_Hole_50_plot.py """ # Rotor definition rotor = LamHole(is_internal=True, Rint=0.021, Rext=0.075, is_stator=False, L1=0.7) rotor.hole = list() rotor.hole.append( HoleM50( Zh=8, W0=50e-3, W1=0, W2=1e-3, W3=1e-3, W4=20.6e-3, H0=17.3e-3, H1=3e-3, H2=0.5e-3, H3=6.8e-3, H4=0, ) ) # Rotor axial ventilation ducts rotor.axial_vent = list() rotor.axial_vent.append(VentilationCirc(Zh=8, Alpha0=0, D0=5e-3, H0=40e-3)) rotor.axial_vent.append(VentilationCirc(Zh=8, Alpha0=pi / 8, D0=7e-3, H0=40e-3)) # Remove a magnet rotor.hole[0].magnet_1 = None # Rotor bore shape rotor.bore = BoreFlower(N=8, Rarc=0.05, alpha=pi / 8) # Plot, check and save rotor.plot(is_show_fig=False) fig = plt.gcf() fig.savefig(join(save_path, "fig_18_BoreFlower.png")) fig.savefig(join(save_path, "fig_18_BoreFlower.svg"), format="svg") # 2 for lam + 3*8 for holes + 16 vents assert len(fig.axes[0].patches) == 42
[docs]@pytest.mark.SPMSM @pytest.mark.MagFEMM @pytest.mark.long_5s @pytest.mark.SingleOP @pytest.mark.periodicity def test_ecc_FEMM(): """Figure 19: transfrom_list in FEMM for eccentricities""" SPMSM_015 = load(join(DATA_DIR, "Machine", "SPMSM_015.json")) simu = Simu1(name="test_ICEM_2020_ecc", machine=SPMSM_015) simu.machine.name = "fig_19_Transform_list" # Modify stator Rext to get more convincing translation SPMSM_015.stator.Rext = SPMSM_015.stator.Rext * 0.9 gap = SPMSM_015.comp_width_airgap_mec() # Definition of the enforced output of the electrical module N0 = 3000 Is = ImportMatrixVal(value=array([[0, 0, 0]])) time = ImportGenVectLin(start=0, stop=0, num=1, endpoint=True) angle = ImportGenVectLin(start=0, stop=2 * 2 * pi / 9, num=2043, endpoint=False) simu.input = InputCurrent( Is=Is, Ir=None, # No winding on the rotor N0=N0, angle_rotor=None, time=time, angle=angle, angle_rotor_initial=0, ) # Definition of the magnetic simulation (is_mmfr=False => no flux from the magnets) simu.mag = MagFEMM( type_BH_stator=0, type_BH_rotor=0, is_sliding_band=False, # Ecc => No sliding band is_periodicity_a=False, is_mmfs=False, is_get_meshsolution=True, ) simu.force = None simu.struct = None # Set two transformations # First rotate 3rd Magnet transform_list = [ {"type": "rotate", "value": 0.08, "label": "MagnetRotorRadial_S_R0_T0_S3"} ] # Then Translate the rotor transform_list.append({"type": "translate", "value": gap * 0.75, "label": "Rotor"}) simu.mag.transform_list = transform_list # Run the simulation out = Output(simu=simu) simu.run() # FEMM files (mesh and results) are available in Results folder copyfile( join(out.path_result, "Femm", "fig_19_Transform_list_model.ans"), join(save_path, "fig_19_Transform_list_model.ans"), ) copyfile( join(out.path_result, "Femm", "fig_19_Transform_list_model.fem"), join(save_path, "fig_19_Transform_list_model.fem"), ) # Plot, check, save out.mag.meshsolution.plot_mesh( save_path=join(save_path, "fig_19_transform_list.png"), is_show_fig=False )
[docs]@pytest.mark.skip @pytest.mark.long_5s @pytest.mark.SPMSM @pytest.mark.periodicity @pytest.mark.SingleOP def test_Optimization_problem(): """ Figure19: Machine topology before optimization Figure20: Individuals in the fitness space Figure21: Pareto Front in the fitness space Figure22: Topology to maximize first torque harmonic Figure22: Topology to minimize second torque harmonic WARNING: The computation takes 6 hours on a single 3GHz CPU core. The algorithm uses randomization at different steps so the results won't be exactly the same as the one in the publication """ # ------------------ # # DEFAULT SIMULATION # # ------------------ # # First, we need to define a default simulation. # This simulation will the base of every simulation during the optimization process # Load the machine SPMSM_001 = load(join(DATA_DIR, "Machine", "SPMSM_001.json")) # Definition of the enforced output of the electrical module Na_tot = 1024 # Angular steps Nt_tot = 32 # Time step Is = ImportMatrixVal( value=np.array( [ [1.73191211247099e-15, 24.4948974278318, -24.4948974278318], [-0.925435413499285, 24.9445002597334, -24.0190648462341], [-1.84987984757817, 25.3673918959653, -23.5175120483872], [-2.77234338398183, 25.7631194935712, -22.9907761095894], [-3.69183822565029, 26.1312592975275, -22.4394210718773], [-4.60737975447626, 26.4714170945114, -21.8640373400352], [-5.51798758565886, 26.7832286350338, -21.2652410493749], [-6.42268661752422, 27.0663600234871, -20.6436734059628], [-7.32050807568877, 27.3205080756888, -20.0000000000000], [-8.21049055044714, 27.5454006435389, -19.3349100930918], [-9.09168102627374, 27.7407969064430, -18.6491158801692], [-9.96313590233562, 27.9064876291883, -17.9433517268527], [-10.8239220029239, 28.0422953859991, -17.2183733830752], [-11.6731175767218, 28.1480747505277, -16.4749571738058], [-12.5098132838389, 28.2237124515809, -15.7138991677421], [-13.3331131695549, 28.2691274944141, -14.9360143248592], [-14.1421356237309, 28.2842712474619, -14.1421356237310], [-14.9360143248592, 28.2691274944141, -13.3331131695549], [-15.7138991677420, 28.2237124515809, -12.5098132838389], [-16.4749571738058, 28.1480747505277, -11.6731175767219], [-17.2183733830752, 28.0422953859991, -10.8239220029240], [-17.9433517268527, 27.9064876291883, -9.96313590233564], [-18.6491158801692, 27.7407969064430, -9.09168102627375], [-19.3349100930918, 27.5454006435389, -8.21049055044716], [-20, 27.3205080756888, -7.32050807568879], [-20.6436734059628, 27.0663600234871, -6.42268661752424], [-21.2652410493749, 26.7832286350338, -5.51798758565888], [-21.8640373400352, 26.4714170945114, -4.60737975447627], [-22.4394210718772, 26.1312592975275, -3.69183822565031], [-22.9907761095894, 25.7631194935712, -2.77234338398184], [-23.5175120483872, 25.3673918959653, -1.84987984757819], [-24.0190648462341, 24.9445002597334, -0.925435413499304], ] ) ) N0 = 400 Ir = ImportMatrixVal(value=np.zeros((Nt_tot, 28))) SPMSM_001.name = ( "Default SPMSM machine" # Rename the machine to have the good plot title ) # Definition of the simulation simu = Simu1(name="test_Optimization_problem", machine=SPMSM_001) simu.input = InputCurrent( Is=Is, Ir=Ir, # zero current for the rotor N0=N0, angle_rotor=None, # Will be computed Nt_tot=Nt_tot, Na_tot=Na_tot, angle_rotor_initial=0.39, ) # Definition of the magnetic simulation simu.mag = MagFEMM(type_BH_stator=2, type_BH_rotor=2, is_periodicity_a=True,) simu.struct = None # Default Output output = Output(simu=simu) # Modify magnet width and the slot opening height output.simu.machine.stator.slot.H0 = 0.001 output.simu.machine.rotor.slot.magnet[0].Wmag *= 0.98 # FIG21 Display default machine output.simu.machine.plot(is_show_fig=False) fig = plt.gcf() fig.savefig(join(save_path, "fig_21_Machine_topology_before_optimization.png")) fig.savefig( join(save_path, "fig_21_Machine_topology_before_optimization.svg"), format="svg" ) plt.close("all") # -------------------- # # OPTIMIZATION PROBLEM # # -------------------- # # Objective functions """Return the average torque opposite (opposite to be maximized)""" tem_av = "lambda output: -abs(output.mag.Tem_av)" """Return the torque ripple """ Tem_rip_pp = "lambda output: abs(output.mag.Tem_rip_pp)" my_objs = [ OptiObjective( name="Maximization of the average torque", symbol="Tem_av", unit="N.m", keeper=tem_av, ), OptiObjective( name="Minimization of the torque ripple", symbol="Tem_rip_pp", unit="N.m", keeper=Tem_rip_pp, ), ] # Design variables my_vars = [ OptiDesignVar( name="Stator slot opening", symbol="W0", unit="m", type_var="interval", space=[ 0.2 * output.simu.machine.stator.slot.W2, output.simu.machine.stator.slot.W2, ], get_value="lambda space: random.uniform(*space)", setter="simu.machine.stator.slot.W0", ), OptiDesignVar( name="Rotor magnet width", symbol="Wmag", unit="m", type_var="interval", space=[ 0.5 * output.simu.machine.rotor.slot.W0, 0.99 * output.simu.machine.rotor.slot.W0, ], # May generate error in FEMM get_value="lambda space: random.uniform(*space)", setter="simu.machine.rotor.slot.magnet[0].Wmag", ), ] # Problem creation my_prob = OptiProblem(output=output, design_var=my_vars, obj_func=my_objs) # Solve problem with NSGA-II solver = OptiGenAlgNsga2Deap(problem=my_prob, size_pop=12, nb_gen=40, p_mutate=0.5) res = solver.solve() # ------------- # # PLOTS RESULTS # # ------------- # res.plot_generation(x_symbol="Tem_av", y_symbol="Tem_rip_pp") fig = plt.gcf() fig.savefig(join(save_path, "fig_20_Individuals_in_fitness_space.png")) fig.savefig( join(save_path, "fig_20_Individuals_in_fitness_space.svg"), format="svg" ) res.plot_pareto(x_symbol="Tem_av", y_symbol="Tem_rip_pp") fig = plt.gcf() fig.savefig(join(save_path, "Pareto_front_in_fitness_space.png")) fig.savefig(join(save_path, "Pareto_front_in_fitness_space.svg"), format="svg") # Extraction of best topologies for every objective pareto_index = ( res.get_pareto_index() ) # Extract individual index in the pareto front idx_1 = pareto_index[0] # First objective idx_2 = pareto_index[0] # Second objective Tem_av = res["Tem_av"].result Tem_rip_pp = res["Tem_rip_pp"].result for i in pareto_index: # First objective if Tem_av[i] < Tem_av[idx_1]: idx_1 = i # Second objective if Tem_rip_pp[i] < Tem_rip_pp[idx_2]: idx_2 = i # Get corresponding simulations simu1 = res.get_simu(idx_1) simu2 = res.get_simu(idx_2) # Rename machine to modify the title name1 = "Machine that maximizes the average torque ({:.3f} Nm)".format( abs(Tem_av[idx_1]) ) simu1.machine.name = name1 name2 = "Machine that minimizes the torque ripple ({:.4f}Nm)".format( abs(Tem_rip_pp[idx_2]) ) simu2.machine.name = name2 # plot the machine simu1.machine.plot(is_show_fig=False) fig = plt.gcf() fig.savefig( join(save_path, "fig_21_Topology_to_maximize_average_torque.png"), format="png" ) fig.savefig( join(save_path, "fig_21_Topology_to_maximize_average_torque.svg"), format="svg" ) simu2.machine.plot(is_show_fig=False) fig = plt.gcf() fig.savefig( join(save_path, "fig_21_Topology_to_minimize_torque_ripple.png"), format="png" ) fig.savefig( join(save_path, "fig_21_Topology_to_minimize_torque_ripple.svg"), format="svg" )
if __name__ == "__main__": test_FEMM_sym()