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 = InCurrent( 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"), )
def test_InCurrent_Ok(self): """Check that the input current can return a correct output """ test_obj = Simulation(machine=M3) output = Output(simu=test_obj) time = ImportGenVectLin(0, 1, 16) angle = ImportGenVectLin(0, 2 * pi, 20) Is = ImportGenMatrixSin(is_transpose=True) Is.init_vector(f=[2, 2, 2], A=[2, 2, 2], Phi=[pi / 2, 0, -pi / 2], N=16, Tf=1) S = sqrt(2) Is_exp = transpose( array([ [2, S, 0, -S, -2, -S, 0, S, 2, S, 0, -S, -2, -S, 0, S], [0, S, 2, S, 0, -S, -2, -S, 0, S, 2, S, 0, -S, -2, -S], [-2, -S, 0, S, 2, S, 0, -S, -2, -S, 0, S, 2, S, 0, -S], ])) Ir = ImportGenMatrixSin(is_transpose=True) Ir.init_vector(f=[2, 2], A=[2, 2], Phi=[0, -pi / 2], N=16, Tf=1) Ir_exp = transpose( array([ [0, S, 2, S, 0, -S, -2, -S, 0, S, 2, S, 0, -S, -2, -S], [-2, -S, 0, S, 2, S, 0, -S, -2, -S, 0, S, 2, S, 0, -S], ])) angle_rotor = ImportGenVectLin(0, 2 * pi, 16) Nr = ImportMatrixVal(value=ones(16) * 10) test_obj.input = InCurrent(time=time, angle=angle, Is=Is, Ir=Ir, angle_rotor=angle_rotor, Nr=Nr) test_obj.input.gen_input() assert_array_almost_equal(output.elec.time, linspace(0, 1, 16)) assert_array_almost_equal(output.elec.angle, linspace(0, 2 * pi, 20)) assert_array_almost_equal(output.elec.Is, Is_exp) assert_array_almost_equal(output.elec.Ir, Ir_exp) assert_array_almost_equal(output.elec.angle_rotor, linspace(0, 2 * pi, 16)) assert_array_almost_equal(output.elec.Nr, ones(16) * 10)
simu = Simu1(name="EM_SIPMSM_AL_001", machine=SIPMSM_001) # Definition of the enforced output of the electrical module Nr = ImportMatrixVal(value=ones(2) * 150) Is = ImportMatrixVal( value=array([[14.1421, -7.0711, -7.0711], [-14.1421, 7.0711, 7.0711]]) ) time = ImportGenVectLin(start=0, stop=0.1, num=2, endpoint=True) angle = ImportGenVectLin(start=0, stop=2 * pi, num=1024, endpoint=False) Ar = ImportMatrixVal(value=array([2.5219, 0.9511]) + pi / 6) simu.input = InCurrent( Is=Is, Ir=None, # No winding on the rotor Nr=None, angle_rotor=Ar, # Will be computed 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=2, is_rotor_linear_BH=2, is_symmetry_a=False, is_mmfr=False, angle_stator=-pi / 6, ) simu.struct = None # Just load the Output and ends (we could also have directly filled the Output object)
from pyleecan.Tests import DATA_DIR simu = Simu1(name="EM_SCIM_NL_006", machine=SCIM_006) # 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 = InCurrent( 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 (no symmetry) simu.mag = MagFEMM(is_stator_linear_BH=2, is_rotor_linear_BH=2, is_symmetry_a=False, is_antiper_a=True) simu.struct = None # Copy the simu and activate the symmetry simu_sym = Simu1(init_dict=simu.as_dict()) simu_sym.mag.is_symmetry_a = True simu_sym.mag.sym_a = 2
Is = zeros((Nt_tot, qs)) for q in range(qs): Is[:, q] = Imax * cos(2 * pi * freq0 * time - q * 2 * pi / qs + Phi) Is_list.append(Is) # Definition of the main simulation simu = Simu1(name="EM_SynRM_FL_001", machine=SynRM_001) time_obj = ImportMatrixVal(value=time) angle = ImportGenVectLin(start=0, stop=2 * pi, num=2016, endpoint=False) alpha_rotor = ImportMatrixVal(value=array([0, pi / 9, 2 * pi / 9]) + 2.6180) simu.input = InCurrent( Is=None, Ir=None, # No winding on the rotor Nr=None, angle_rotor=alpha_rotor, time=time_obj, angle=angle, angle_rotor_initial=0, ) # Definition of the magnetic simulation (1/2 symmetry) simu.mag = MagFEMM( is_stator_linear_BH=0, is_rotor_linear_BH=0, is_symmetry_a=True, is_antiper_a=True, sym_a=2, ) simu.struct = None # Expected results
M1.stator = LamSlotWind() M1.stator.winding.qs = 3 # Winding rotor only M2 = Machine() M2.rotor = LamSlotWind() M2.rotor.winding.qs = 2 # Winding rotor + stator M3 = Machine() M3.stator = LamSlotWind() M3.stator.winding.qs = 3 M3.rotor = LamSlotWind() M3.rotor.winding.qs = 2 # Wrong time test_obj = Simulation() test_obj.input = InCurrent(time=None) InCurrent_Error_test.append({ "test_obj": test_obj, "exp": "ERROR: InCurrent.time missing" }) test_obj = Simulation() test_obj.input = InCurrent(time=time_wrong) InCurrent_Error_test.append({ "test_obj": test_obj, "exp": "ERROR: InCurrent.time should be a vector, (10, 2) shape found", }) # Wrong angle test_obj = Simulation() test_obj.input = InCurrent(time=time, angle=None)
def test_zdt3(): # ### Defining reference Output # Definition of the enforced output of the electrical module Nt = 2 Nr = ImportMatrixVal(value=np.ones(Nt) * 3000) Is = ImportMatrixVal(value=np.array([ [6.97244193e-06, 2.25353053e02, -2.25353060e02], [-2.60215295e02, 1.30107654e02, 1.30107642e02], # [-6.97244208e-06, -2.25353053e02, 2.25353060e02], # [2.60215295e02, -1.30107654e02, -1.30107642e02], ])) Ir = ImportMatrixVal(value=np.zeros(30)) time = ImportGenVectLin(start=0, stop=0.015, num=Nt, endpoint=True) angle = ImportGenVectLin(start=0, stop=2 * np.pi, num=64, endpoint=False) # num=1024 # Definition of the simulation simu = Simu1(name="Test_machine", machine=SCIM_001) simu.input = InCurrent( 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.5216 + np.pi, ) # 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.Kmesh_fineness = 0.01 # simu.mag.Kgeo_fineness=0.02 simu.mag.sym_a = 4 simu.struct = None output = Output(simu=simu) # ### Design variable my_vars = {} for i in range(30): my_vars["var_" + str(i)] = OptiDesignVar( name="output.simu.input.Ir.value[" + str(i) + "]", type_var="interval", space=[0, 1], function=lambda space: np.random.uniform(*space), ) # ### Objectives objs = { "obj1": OptiObjFunc( description="Maximization of the torque average", func=lambda output: output.mag.Tem_av, ), "obj2": OptiObjFunc( description="Minimization of the torque ripple", func=lambda output: output.mag.Tem_rip, ), } # ### Evaluation def evaluate(output): x = output.simu.input.Ir.value f1 = lambda x: x[0] g = lambda x: 1 + (9 / 29) * np.sum(x[1:]) h = lambda f1, g: 1 - np.sqrt(f1 / g) - (f1 / g) * np.sin(10 * np.pi * f1) output.mag.Tem_av = f1(x) output.mag.Tem_rip = g(x) * h(f1(x), g(x)) # ### Defining the problem my_prob = OptiProblem(output=output, design_var=my_vars, obj_func=objs, eval_func=evaluate) solver = OptiGenAlgNsga2Deap( problem=my_prob, size_pop=40, nb_gen=100, p_mutate=0.5, ) res = solver.solve() def plot_pareto(self): """Plot every fitness values with the pareto front for 2 fitness Parameters ---------- self : OutputMultiOpti """ # TODO Add a feature to return the design_varibles of each indiv from the Pareto front # Get fitness and ngen is_valid = np.array(self.is_valid) fitness = np.array(self.fitness) ngen = np.array(self.ngen) # Keep only valid values indx = np.where(is_valid)[0] fitness = fitness[indx] ngen = ngen[indx] # Get pareto front pareto = list(np.unique(fitness, axis=0)) # Get dominated values to_remove = [] N = len(pareto) for i in range(N): for j in range(N): if all(pareto[j] <= pareto[i]) and any(pareto[j] < pareto[i]): to_remove.append(pareto[i]) break # Remove dominated values for i in to_remove: for l in range(len(pareto)): if all(i == pareto[l]): pareto.pop(l) break pareto = np.array(pareto) fig, axs = plt.subplots(1, 2, figsize=(16, 6)) # Plot Pareto front axs[0].scatter( pareto[:, 0], pareto[:, 1], facecolors="b", edgecolors="b", s=0.8, label="Pareto Front", ) axs[0].autoscale() axs[0].legend() axs[0].set_title("Pyleecan results") axs[0].set_xlabel(r"$f_1(x)$") axs[0].set_ylabel(r"$f_2(x)$") try: img_to_find = img.imread( "pyleecan\\Tests\\Validation\\Optimization\\zdt3.jpg", format="jpg") axs[1].imshow(img_to_find, aspect="auto") axs[1].axis("off") axs[1].set_title("Pareto front of the problem") except TypeError: print("Pillow is needed to import jpg files") return fig fig = plot_pareto(res) plt.savefig("pyleecan\\Tests\\Results\\Validation\\test_zdt3.png")
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 = InCurrent( 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", )
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 = InCurrent( 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")
simu = Simu1(name="EM_SPMSM_NL_001", machine=SPMSM_015) # 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 = InCurrent( 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_symmetry_a=True, is_mmfs=False, sym_a=9, ) simu.struct = None # Just load the Output and ends (we could also have directly filled the Output object)