from os import makedirs
from os.path import join
from unittest import TestCase, skip
from shutil import copyfile
import matplotlib.pyplot as plt
from numpy import array, linspace, ones, pi, zeros
from ...Classes.import_all import *
from ...Functions.GMSH.gen_3D_mesh import gen_3D_mesh
from ...Tests import save_plot_path
from ...Tests.Plot.LamWind import wind_mat
from ...Tests.Validation.Machine.SCIM_006 import SCIM_006
from ...Tests.Validation.Machine.SPMSM_015 import SPMSM_015
from ...Functions.load import load
from ...Classes.InputCurrent import InputCurrent
from ...Classes.MagFEMM import MagFEMM
from ...Classes.Simu1 import Simu1
from ...Classes.Output import Output
from ...Classes.OptiDesignVar import OptiDesignVar
from ...Classes.OptiObjFunc import OptiObjFunc
from ...Classes.OptiProblem import OptiProblem
from ...Classes.ImportMatrixVal import ImportMatrixVal
from ...Classes.ImportGenVectLin import ImportGenVectLin
from ...Classes.OptiGenAlgNsga2Deap import OptiGenAlgNsga2Deap
import numpy as np
import random
# Gather results in the same folder
save_path = join(save_plot_path, "ICEM_2020")
makedirs(save_path)
[docs]class test_ICEM_2020(TestCase):
"""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] def test_FEMM_sym(self):
"""Figure 9: Check that the FEMM can handle symmetry
From pyleecan/Tests/Validation/Simulation/test_EM_SCIM_NL_006.py
"""
simu = Simu1(name="ICEM_2020", machine=SCIM_006)
simu.machine.name = "fig_09_FEMM_sym"
# Definition of the enforced output of the electrical module
Nr = ImportMatrixVal(value=ones(1) * 1500)
Is = ImportMatrixVal(value=array([[20, -10, -10]]))
Ir = ImportMatrixVal(value=zeros((1, 28)))
time = ImportGenVectLin(start=0, stop=0, num=1, endpoint=False)
angle = ImportGenVectLin(start=0, stop=2 * pi, num=4096, endpoint=False)
simu.input = InputCurrent(
Is=Is,
Ir=Ir, # zero current for the rotor
Nr=Nr,
angle_rotor=None, # Will be computed
time=time,
angle=angle,
angle_rotor_initial=0.2244,
)
# Definition of the magnetic simulation
# 2 sym + antiperiodicity = 1/4 Lamination
simu.mag = MagFEMM(
is_stator_linear_BH=2,
is_rotor_linear_BH=2,
is_symmetry_a=True,
sym_a=2,
is_antiper_a=True,
)
# Stop after magnetic computation
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_res, "Femm", "fig_09_FEMM_sym_model.ans"),
join(save_path, "fig_09_FEMM_sym_model.ans"),
)
copyfile(
join(out.path_res, "Femm", "fig_09_FEMM_sym_model.fem"),
join(save_path, "fig_09_FEMM_sym_model.fem"),
)
[docs] def test_gmsh_mesh_dict(self):
"""Figure 10: Generate a 3D mesh with Gmsh by setting the
number of element on each lines
"""
# 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)
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")
self.assertEqual(len(fig.axes[0].patches), 2)
# Definition of the number of each element on each line
mesh_dict = {
"Tooth_Yoke_Side": 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] def test_SlotMulti_sym(self):
"""Figure 11: Generate a 3D mesh with GMSH for a lamination
with several slot types and notches
"""
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)
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")
self.assertEqual(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] def test_MachineUD(self):
"""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()
fig = plt.gcf()
fig.savefig(join(save_path, "fig_12_MachineUD.png"))
fig.savefig(join(save_path, "fig_12_MachineUD.svg"), format="svg")
self.assertEqual(len(fig.axes[0].patches), 56)
[docs] def test_SlotMulti(self):
"""Figure 13: Check that you can plot a LamSlotMulti (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()
fig = plt.gcf()
fig.savefig(join(save_path, "fig_13_LamSlotMulti.png"))
fig.savefig(join(save_path, "fig_13_LamSlotMulti.svg"), format="svg")
self.assertEqual(len(fig.axes[0].patches), 2)
[docs] def test_SlotUD(self):
"""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, is_sym=True, point_list=point_list)
# Plot, check and save
machine.plot()
fig = plt.gcf()
self.assertEqual(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(self):
"""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()
fig = plt.gcf()
fig.savefig(join(save_path, "fig_16_WindingUD.png"))
fig.savefig(join(save_path, "fig_16_WindingUD.svg"), format="svg")
self.assertEqual(len(fig.axes[0].patches), 73)
[docs] def test_BoreFlower(self):
"""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()
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
self.assertEqual(len(fig.axes[0].patches), 42)
[docs] def test_ecc_FEMM(self):
"""Figure 19: transfrom_list in FEMM for eccentricities
"""
simu = Simu1(name="ICEM_2020", 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
Nr = ImportMatrixVal(value=ones(1) * 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
Nr=Nr,
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(
is_stator_linear_BH=0,
is_rotor_linear_BH=0,
is_sliding_band=False, # Ecc => No sliding band
is_symmetry_a=False, # No sym
is_mmfs=False,
is_get_mesh=True,
is_save_FEA=True,
sym_a=1,
)
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_res, "Femm", "fig_19_Transform_list_model.ans"),
join(save_path, "fig_19_Transform_list_model.ans"),
)
copyfile(
join(out.path_res, "Femm", "fig_19_Transform_list_model.fem"),
join(save_path, "fig_19_Transform_list_model.fem"),
)
# Plot, check, save
out.plot_mesh(mesh=out.mag.meshsolution.mesh[0], title="FEMM Mesh")
fig = plt.gcf()
fig.savefig(join(save_path, "fig_19_transform_list.png"))
fig.savefig(join(save_path, "fig_19_transform_list.svg"), format="svg")
@skip
def test_Optimization_problem(self):
"""
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("pyleecan/Tests/Validation/Machine/SPMSM_001.json")
# Definition of the enforced output of the electrical module
Na = 1024 # Angular steps
Nt = 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],
]
)
)
Nr = ImportMatrixVal(value=np.ones(Nt) * 400)
Ir = ImportMatrixVal(value=np.zeros((Nt, 28)))
time = ImportGenVectLin(
start=0, stop=1 / (400 / 60) / 24, num=Nt, endpoint=False
)
angle = ImportGenVectLin(start=0, stop=2 * np.pi, num=Na, endpoint=False)
SPMSM_001.name = (
"Default SPMSM machine" # Rename the machine to have the good plot title
)
# Definition of the simulation
simu = Simu1(name="Default simulation", machine=SPMSM_001)
simu.input = InputCurrent(
Is=Is,
Ir=Ir, # zero current for the rotor
Nr=Nr,
angle_rotor=None, # Will be computed
time=time,
angle=angle,
angle_rotor_initial=0.39,
)
# Definition of the magnetic simulation
simu.mag = MagFEMM(
is_stator_linear_BH=2,
is_rotor_linear_BH=2,
is_symmetry_a=True,
is_antiper_a=False,
)
simu.mag.sym_a = 4
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()
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",
)
# -------------------- #
# OPTIMIZATION PROBLEM #
# -------------------- #
# Objective functions
def harm1(output):
"""Return the average torque opposite (opposite to be maximized)"""
N = output.simu.input.time.num
x = output.mag.Tem[:, 0]
sp = np.fft.rfft(x)
sp = 2 / N * np.abs(sp)
return -sp[0] / 2
def harm2(output):
"""Return the first torque harmonic """
N = output.simu.input.time.num
x = output.mag.Tem[:, 0]
sp = np.fft.rfft(x)
sp = 2 / N * np.abs(sp)
return sp[1]
objs = {
"Opposite average torque (Nm)": OptiObjFunc(
description="Maximization of the average torque", func=harm1
),
"First torque harmonic (Nm)": OptiObjFunc(
description="Minimization of the first torque harmonic", func=harm2
),
}
# Design variables
my_vars = {
"design var 1": OptiDesignVar(
name="output.simu.machine.stator.slot.W0",
type_var="interval",
space=[
0.2 * output.simu.machine.stator.slot.W2,
output.simu.machine.stator.slot.W2,
],
function=lambda space: random.uniform(*space),
),
"design var 2": OptiDesignVar(
name="output.simu.machine.rotor.slot.magnet[0].Wmag",
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
function=lambda space: random.uniform(*space),
),
}
# Problem creation
my_prob = OptiProblem(output=output, design_var=my_vars, obj_func=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()
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()
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 = res.get_pareto() # Extraction of the pareto front
out1 = [pareto[0]["output"], pareto[0]["fitness"]] # First objective
out2 = [pareto[0]["output"], pareto[0]["fitness"]] # Second objective
for pm in pareto:
if pm["fitness"][0] < out1[1][0]:
out1 = [pm["output"], pm["fitness"]]
if pm["fitness"][1] < out2[1][1]:
out2 = [pm["output"], pm["fitness"]]
# Rename machine to modify the title
name1 = "Machine that maximizes the average torque ({:.3f} Nm)".format(
abs(out1[1][0])
)
out1[0].simu.machine.name = name1
name2 = "Machine that minimizes the first torque harmonic ({:.4f}Nm)".format(
abs(out1[1][1])
)
out2[0].simu.machine.name = name2
# plot the machine
out1[0].simu.machine.plot()
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",
)
out2[0].simu.machine.plot()
fig = plt.gcf()
fig.savefig(
join(save_path, "fig_21_Topology_to_minimize_first_torque_harmonic.png"),
format="png",
)
fig.savefig(
join(save_path, "fig_21_Topology_to_minimize_first_torque_harmonic.svg"),
format="svg",
)