def get_middle(self): """Return the point at the middle of the arc Parameters ---------- self : Arc1 An Arc1 object Returns ------- Zmid: complex Complex coordinates of the middle of the Arc1 """ # We use the complex representation of the point z1 = self.begin z2 = self.end zc = self.get_center() # Geometric transformation : center is the origine, angle(begin) = 0 Zstart = (z1 - zc) * exp(-1j * np_angle(z1 - zc)) # Generation of the point by rotation alpha = self.get_angle() Zmid = Zstart * exp(1j * alpha / 2) # Geometric transformation : return to the main axis Zmid = Zmid * exp(1j * np_angle(z1 - zc)) + zc # Return (0,0) if the point is too close from 0 if np_abs(Zmid) < 1e-6: Zmid = 0 return Zmid
def get_hole(self): """Generate the HoleUD object corresponding to the selected surfaces Parameters ---------- self : DXF_Hole a DXF_Hole object Returns ------- hole : HoleUD User defined hole according to selected surfaces """ hole = HoleUD(surf_list=self.surf_list) # Set labels Nmag = 0 for ii in range(self.w_surface_list.rowCount()): if self.w_surface_list.cellWidget(ii, TYPE_COL).currentIndex() == 0: hole.surf_list[ii].label = "Hole" else: hole.surf_list[ii].label = "HoleMagnet" Nmag += 1 # Create magnet objects hole.magnet_dict = dict() for ii in range(Nmag): hole.magnet_dict["magnet_" + str(ii)] = Magnet() # Sort the surfaces angles = [np_angle(surf.point_ref) for surf in hole.surf_list] idx = sorted(range(len(angles)), key=lambda k: angles[k]) surf_list_sorted = [hole.surf_list[ii] for ii in idx] hole.surf_list = surf_list_sorted # Rotation Zref = sum([surf.point_ref for surf in hole.surf_list]) for surf in hole.surf_list: surf.rotate(-1 * np_angle(Zref)) # Set metadata hole.Zh = self.si_Zh.value() for magnet in hole.magnet_dict.values(): magnet.Lmag = self.lf_mag_len.value() # Remove all materials => To be set in GUI hole.mat_void = None for magnet in hole.magnet_dict.values(): magnet.mat_type = None return hole
def discretize(self, nb_point=ARC_NPOINT_D): """Return the discretize version of the Arc. Begin and end are always returned Parameters ---------- self : Arc1 The Arc1 object to discretize nb_point : Number of points to add to discretize the arc (Default value = ARC_NPOINT_D) Returns ------- list_point: list list of complex coordinate of the points Raises ------ NbPointArc1DError nb_point must be an integer >=0 """ # Check that the Arc is correct self.check() if not isinstance(nb_point, int): raise NbPointArc1DError("discretize : nb_point must be an integer") if nb_point < 0: raise NbPointArc1DError("nb_point must be >=0") # We use the complex representation of the point z1 = self.begin z2 = self.end zc = self.get_center() # Geometric transformation : center is the origin, angle(begin) = 0 Zstart = (z1 - zc) * exp(-1j * np_angle(z1 - zc)) Zend = (z2 - zc) * exp(-1j * np_angle(z1 - zc)) # Generation of the point by rotation if self.is_trigo_direction: sign = 1 else: sign = -1 t = linspace(0, self.get_angle(), nb_point + 2) list_point = Zstart * exp(1j * t) # Geometric transformation : return to the main axis list_point = list_point * exp(1j * np_angle(z1 - zc)) + zc return list_point
def get_middle(self): """Return the point at the middle of the arc Parameters ---------- self : Arc3 An Arc3 object Returns ------- Zmid: complex Complex coordinates of the middle of the Arc3 """ # We use the complex representation of the point z1 = self.begin zc = self.get_center() R = self.comp_radius() # Generation of the point by rotation if self.is_trigo_direction: # Top Zmid = R * exp(1j * pi / 2.0) else: # Bottom Zmid = R * exp(-1j * pi / 2.0) # Geometric transformation : return to the main axis Zmid = Zmid * exp(1j * np_angle(z1 - zc)) + zc # Return (0,0) if the point is too close from 0 if np_abs(Zmid) < 1e-6: Zmid = 0 return Zmid
def get_hole(self): """Generate the HoleUD object corresponding to the selected surfaces Parameters ---------- self : DXF_Surf a DXF_Surf object Returns ------- hole : HoleUD User defined hole according to selected surfaces """ if self.lf_scaling.value() == 0: # Avoid error self.lf_scaling.setValue(1) surf = self.get_surface() surf.scale(self.lf_scaling.value()) surf.label = HOLEV_LAB hole = HoleUD(surf_list=[surf]) # Translate if self.Zcenter != 0: surf.translate(-self.Zcenter * self.lf_scaling.value()) # Rotation surf.rotate(-1 * np_angle(surf.point_ref)) # Set metadata hole.Zh = self.si_Zh.value() # Remove materials => To be set in GUI hole.mat_void = None return hole
def comp_angle_d_axis(self, is_plot=False): """Compute the angle between the X axis and the first d+ axis By convention a "Tooth" is centered on the X axis Parameters ---------- self : LamSlotWind A LamSlotWind object is_plot : bool True to plot d axis position regarding unit mmf Returns ------- d_angle : float angle between the X axis and the first d+ axis """ if self.winding is None or self.winding.qs == 0 or self.winding.conductor is None: return 0 p = self.get_pole_pair_number() MMF, _ = self.comp_mmf_unit(Nt=1, Na=400 * p) # Get angle values results1 = MMF.get_along("angle[oneperiod]") angle_stator = results1["angle"] # Get the unit mmf FFT and wavenumbers results = MMF.get_along("wavenumber") wavenumber = results["wavenumber"] mmf_ft = results[MMF.symbol] # Find the fundamental harmonic of MMF indr_fund = np_abs(wavenumber - p).argmin() phimax = np_angle(mmf_ft[indr_fund]) magmax = np_abs(mmf_ft[indr_fund]) # Reconstruct fundamental MMF wave mmf_waveform = magmax * cos(p * angle_stator + phimax) # Get the first angle where mmf is max d_angle = angle_stator[argmax(mmf_waveform)] if is_plot: import matplotlib.pyplot as plt from numpy import squeeze fig, ax = plt.subplots() ax.plot(angle_stator, squeeze(MMF.get_along("angle[oneperiod]")[MMF.symbol]), "k") ax.plot(angle_stator, mmf_waveform, "r") ax.plot([d_angle, d_angle], [-magmax, magmax], "--k") plt.show() return d_angle
def discretize(self, nb_point=ARC_NPOINT_D): """Return the discretize version of the Arc. Begin and end are always returned Parameters ---------- self : Arc2 An Arc2 object nb_point : int Number of points to add to discretize the arc (Default value = ARC_NPOINT_D) Returns ------- list_point: list list of complex coordinate of the points Raises ------ NbPointArc2DError nb_point must be an integer >=0 """ self.check() if not isinstance(nb_point, int): raise NbPointArc2DError("discretize : nb_point must be an integer") if nb_point < 0: raise NbPointArc2DError("nb_point must be >=0") # We use the complex representation of the point z1 = self.begin zc = self.center # Geometric transformation : center is the origine, angle(begin) = 0 Zstart = (z1 - zc) * exp(-1j * np_angle(z1 - zc)) # Generation of the point by rotation t = linspace(0, self.angle, nb_point + 2) list_point = Zstart * exp(1j * t) # Geometric transformation : return to the main axis list_point = list_point * exp(1j * np_angle(z1 - zc)) + zc return list_point
def get_center(self): """Return the center of the arc Parameters ---------- self : Arc1 An Arc1 object Returns ------- Zc: complex Complex coordinates of the center of the Arc1 """ self.check() # The center is on the bisection of [begin, end] z1 = self.begin z2 = self.end R = self.radius # Centre at the middle of begin and end (distance(Z1, Z2) = diameter ) if abs(abs(z2 - z1) - abs(2 * R)) < 1e-6: Zc = (z2 + z1) / 2.0 else: # Alpha is the opening angle (Begin-Center-End) alpha = 2 * arcsin(abs(z2 - z1) / (2 * R)) if R > 0: Zc = z2 + R * exp(1j * (np_angle(z2 - z1) % (2 * pi))) * exp(1j * (pi / 2 + np_abs(alpha) / 2)) else: Zc = z1 - R * exp(1j * (np_angle(z1 - z2) % (2 * pi))) * exp(1j * (pi / 2 + np_abs(alpha) / 2)) # Return (0,0) if the point is too close from 0 if np_abs(Zc) < 1e-6: Zc = 0 return Zc
def comp_phase(values): """Computes the phase of the Fourier Transform Parameters ---------- values: ndarray ndarray of the field Returns ------- Phase of the Fourier Transform """ return np_angle(_comp_fft(values))
def comp_angle_d_axis(self): """Compute the angle between the X axis and the first d+ axis By convention a "Tooth" is centered on the X axis Parameters ---------- self : LamSlotWind A LamSlotWind object Returns ------- d_angle : float angle between the X axis and the first d+ axis """ if self.winding is None: return 0 p = self.get_pole_pair_number() MMF = self.comp_mmf_unit(Nt=1, Na=400 * p) # Get angle values results1 = MMF.get_along("angle[oneperiod]") angle_stator = results1["angle"] # Get the unit mmf FFT and wavenumbers results = MMF.get_along("wavenumber") wavenumber = results["wavenumber"] mmf_ft = results[MMF.symbol] # Find the angle where the FFT is max indr_fund = np_abs(wavenumber - p).argmin() phimax = np_angle(mmf_ft[indr_fund]) magmax = np_abs(mmf_ft[indr_fund]) # Reconstruct fundamental MMF wave mmf_waveform = magmax * cos(p * angle_stator + phimax) # Get the first angle where mmf is max d_angle = angle_stator[argmax(mmf_waveform)] # fig, ax = plt.subplots() # ax.plot(angle_stator, squeeze(MMF.get_along("angle[oneperiod]")[MMF.symbol]), "k") # ax.plot(angle_stator, mmf_waveform, "r") # ax.plot([d_angle, d_angle], [-magmax, magmax], "--k") # plt.show() return d_angle
def discretize(self, nb_point=ARC_NPOINT_D): """Return the discretize version of the Arc. Begin and end are always return Parameters ---------- self : Arc3 An Arc3 object nb_point : int Number of points to add to discretize the arc (Default value = ARC_NPOINT_D) Returns ------- list_point: list list of complex coordinate of the points Raises ------ NbPointArc1DError nb_point must be an integer >=0 """ # Check that the Arc is correct self.check() if not isinstance(nb_point, int): raise NbPointArc3DError("discretize : nb_point must be an integer") if nb_point < 0: raise NbPointArc3DError("nb_point must be >=0") # We use the complex representation of the point z1 = self.begin zc = self.get_center() R = self.comp_radius() # Generation of the point by rotation if self.is_trigo_direction: # Top t = linspace(0, pi, nb_point + 2) else: # Bottom t = linspace(0, -pi, nb_point + 2) list_point = R * exp(1j * t) # Geometric transformation : return to the main axis list_point = list_point * exp(1j * np_angle(z1 - zc)) + zc return list_point
def get_phase_along(self, *args, unit="SI", is_norm=False, axis_data=[]): """Returns the ndarray of the magnitude of the FT, using conversions and symmetries if needed. Parameters ---------- self: Data a Data object *args: list of strings List of axes requested by the user, their units and values (optional) unit: str Unit requested by the user ("SI" by default) is_norm: bool Boolean indicating if the field must be normalized (False by default) axis_data: list list of ndarray corresponding to user-input data Returns ------- list of 1Darray of axes values, ndarray of magnitude values """ if len(args) == 1 and type(args[0]) == tuple: args = args[0] # if called from another script with *args return_dict = self.get_along(args, axis_data=axis_data) values = return_dict[self.symbol] # Compute magnitude values = np_angle(values) # Convert into right unit (apart because of degree conversion) if unit == self.unit or unit == "SI": if is_norm: try: values = values / self.normalizations.get("ref") except: raise NormError( "ERROR: Reference value not specified for normalization" ) elif unit == "°": values = convert(values, "rad", "°") elif unit in self.normalizations: values = values / self.normalizations.get(unit) else: values = convert(values, self.unit, unit) return_dict[self.symbol] = values return return_dict
def xyz_to_rphiz(values): """Converts axis values from cartesian coordinates into cylindrical coordinates Parameters ---------- values: array Values of the axis to convert (Nx3) Returns ------- ndarray of the axis (Nx3) """ x = values[:, 0] y = values[:, 1] z = values[:, 2] affixe = x + 1j * y r = np_abs(affixe) phi = (np_angle(affixe) + 2 * pi) % (2 * pi) return column_stack((r, phi, z))
def get_center(self): """Return the center of the arc Parameters ---------- self : Arc1 An Arc1 object Returns ------- Zc: complex Complex coordinates of the center of the Arc1 """ self.check() # The center is on the bisection of [begin, end] z1 = self.begin z2 = self.end R = self.radius D12 = np_abs(z2 - z1) # length of segment [begin,end] # Centre at the middle of begin and end (distance(Z1, Z2) = diameter ) if np_abs(D12 - np_abs(2 * R)) < 1e-6: Zc = (z2 + z1) / 2.0 else: # In the coordinate system begin on center and end on X > 0 axis if R > 0: # Center is above the segment Zc = D12 / 2 + 1j * sqrt(R**2 - (D12 / 2)**2) else: Zc = D12 / 2 - 1j * sqrt(R**2 - (D12 / 2)**2) # Go back to the original coordinate system Zc = Zc * exp(1j * np_angle(z2 - z1)) + z1 # Return (0,0) if the point is too close from 0 if np_abs(Zc) < 1e-6: Zc = 0 return Zc
def comp_angle_d_axis(self): """Compute the angle between the X axis and the first d+ axis By convention a "Tooth" is centered on the X axis Parameters ---------- self : LamSlotWind A LamSlotWind object Returns ------- d_angle : float angle between the X axis and the first d+ axis """ MMF = self.comp_mmf_unit() p = self.get_pole_pair_number() # Get the unit mmf FFT and angle values results = MMF.get_along("angle") angle_rotor = results["angle"] results = MMF.get_along("wavenumber") wavenumber = results["wavenumber"] mmf_ft = results[MMF.symbol] # Find the angle where the FFT is max indr_fund = np_abs(wavenumber - p).argmin() phimax = np_angle(mmf_ft[indr_fund]) magmax = np_abs(mmf_ft[indr_fund]) mmf_waveform = magmax * cos(p * angle_rotor + phimax) ind_max = argmax(mmf_waveform) d_angle = angle_rotor[ind_max] # Get the first angle according to symmetry (sym, _) = self.comp_sym() return d_angle % (2 * pi / sym)
def get_slot(self): """Generate the SlotUD object corresponding to the selected lines Parameters ---------- self : DXF_Slot a DXF_Slot object Returns ------- sot : SlotUD User defined slot according to selected lines """ if self.lf_scaling.value() == 0: # Avoid error self.lf_scaling.setValue(1) # Get all the selected lines line_list = list() point_list = list() for ii, line in enumerate(self.line_list): if self.selected_list[ii]: line_list.append(line.copy()) line_list[-1].scale(self.lf_scaling.value()) point_list.append(line_list[-1].get_begin()) point_list.append(line_list[-1].get_end()) # Find begin point single_list = list() for p1 in point_list: count = 0 for p2 in point_list: if abs(p1 - p2) < Z_TOL: count += 1 if count == 1: single_list.append(p1) assert len(single_list) == 2 Zbegin = single_list[argmin(np_angle(array(single_list)))] # Get begin line id_list = list() id_list.extend([ ii for ii, line in enumerate(line_list) if abs(line.get_begin() - Zbegin) < Z_TOL or abs(line.get_end() - Zbegin) < Z_TOL ]) # Sort the lines (begin = end) curve_list = list() curve_list.append(line_list.pop(id_list[0])) if abs(curve_list[0].get_end() - Zbegin) < Z_TOL: # Reverse begin line if line end matches with begin point curve_list[0].reverse() while len(line_list) > 0: end = curve_list[-1].get_end() for ii in range(len(line_list)): if abs(line_list[ii].get_begin() - end) < Z_TOL: break if abs(line_list[ii].get_end() - end) < Z_TOL: line_list[ii].reverse() break curve_list.append(line_list.pop(ii)) # Create the Slot object slot = SlotUD(line_list=curve_list) slot.type_line_wind = self.c_type_line.currentIndex() begin_id = self.si_wind_begin_index.value() end_id = self.si_wind_end_index.value() if (begin_id < len(curve_list) and end_id < len(curve_list) and begin_id < end_id): slot.wind_begin_index = begin_id slot.wind_end_index = end_id else: slot.wind_begin_index = None slot.wind_end_index = None # Translate if self.Zcenter != 0: for line in curve_list: line.translate(-self.Zcenter * self.lf_scaling.value()) # Rotation Z1 = curve_list[0].get_begin() Z2 = curve_list[-1].get_end() alpha = (np_angle(Z2) + np_angle(Z1)) / 2 for line in curve_list: line.rotate(-1 * alpha) # Set metadata slot.Zs = self.si_Zs.value() return slot
def solve_FEA(self, output, sym, angle, time, angle_rotor, Is, Ir): """ Solve Elmer model to calculate airgap flux density, torque instantaneous/average/ripple values, flux induced in stator windings and flux density, field and permeability maps Parameters ---------- self: MagElmer A MagElmer object output: Output An Output object sym: int Spatial symmetry factor time: ndarray Time vector for calculation angle: ndarray Angle vector for calculation Is : ndarray Stator current matrix (qs,Nt) [A] Ir : ndarray Stator current matrix (qs,Nt) [A] angle_rotor: ndarray Rotor angular position vector (Nt,) """ project_name = self.get_path_save_fea(output) elmermesh_folder = project_name mesh_names_file = join(project_name, "mesh.names") boundaries = {} bodies = {} machine = output.simu.machine BHs = output.geo.stator.BH_curve # Stator B(H) curve BHr = output.geo.rotor.BH_curve # Rotor B(H) curve # Is = output.elec.Is # Stator currents waveforms # Ir = output.elec.Ir # Rotor currents waveforms Speed = output.elec.N0 rotor_mat_file = join(project_name, "rotor_material.pmf") stator_mat_file = join(project_name, "stator_material.pmf") # TO-DO: Time vector must be greater than one timesize_str = np.array2string( np.diff(time), separator=" ", formatter={"float_kind": lambda x: "%.2e" % x}) timelen = len(time) - 1 ones_str = np.array2string(np.ones(timelen), separator=" ", formatter={"int": lambda x: "%d" % x}) timeinterval_str = ones_str.replace(".", "") with open(mesh_names_file, "rt") as f: for line in f: fields = line.strip().split() if fields[0] == "$": field_name = fields[1] field_value = fields[3] # update dictionary # _settings['Geometry'][field_name] = field_value if field_name.count("BOUNDARY"): boundaries[field_name] = field_value else: bodies[field_name] = { "id": field_value, "mat": 1, # Air by Default "eq": 1, # RigidMeshMapper by Default "bf": None, "tg": None, } with open(rotor_mat_file, "wt") as ro: ro.write("! File Generated by pyleecan v{0}\n".format(__version__)) ro.write("! Material Name: {0}\n" "! B-H Curve Rotor Material\n" "Electric Conductivity = 0\n" "H-B Curve = Variable coupled iter\n" " Real\t\tCubic Monotone\n".format( machine.rotor.mat_type.name)) for ii in range(BHr.shape[0]): ro.write(" {0}\t\t{1}\n".format(BHr[ii][1], BHr[ii][0])) ro.write("End\n") with open(stator_mat_file, "wt") as ro: ro.write("! File Generated by pyleecan v{0}\n".format(__version__)) ro.write("! Material Name: {0}\n" "! B-H Curve Stator Material\n" "Electric Conductivity = 0\n" "H-B Curve = Variable coupled iter\n" " Real\t\tCubic Monotone\n".format( machine.stator.mat_type.name)) for ii in range(BHs.shape[0]): ro.write(" {0}\t\t{1}\n".format(BHs[ii][1], BHs[ii][0])) ro.write("End\n") elmer_sim_file = join(project_name, "pyleecan_elmer.sif") pp = machine.stator.winding.p wind_mat = machine.stator.winding.comp_connection_mat( machine.stator.slot.Zs) Swire = machine.stator.winding.conductor.comp_surface() ror = machine.rotor.comp_radius_mec() sir = machine.stator.comp_radius_mec() with open(elmer_sim_file, "wt") as fo: fo.write("! File Generated by pyleecan v{0}\n".format(__version__)) fo.write("$ WM = 2*pi*{0}/60 ! Mechanical Frequency [rad/s]\n". format(Speed)) fo.write("$ PP = {0} ! Pole pairs\n".format(pp)) fo.write("$ WE = PP*WM ! Electrical Frequency [Hz]\n") magnet_dict = machine.rotor.hole[0].get_magnet_dict() magnet_0 = magnet_dict["magnet_0"] surf_list = machine.build_geometry(sym=1) pm_index = 6 Mangle = list() Ncond_Aplus = 1 Ncond_Aminus = 1 Ncond_Bplus = 1 Ncond_Bminus = 1 Ncond_Cplus = 1 Ncond_Cminus = 1 Ncond_Dplus = 1 Ncond_Dminus = 1 Ncond_Eplus = 1 Ncond_Eminus = 1 Ncond_Fplus = 1 Ncond_Fminus = 1 for surf in surf_list: label = surface_label.get(surf.label, "UNKNOWN") if "MAGNET" in label: point_ref = surf.point_ref if "RAD" in label and "_N_" in label: # Radial magnetization mag = "theta" # North pole magnet magnetization_type = "radial" elif "RAD" in label: mag = "theta + 180" # South pole magnet magnetization_type = "radial" elif "PAR" in label and "_N_" in label: mag = np_angle(point_ref) * 180 / pi # North pole magnet magnetization_type = "parallel" elif "PAR" in label: mag = np_angle( point_ref) * 180 / pi + 180 # South pole magnet magnetization_type = "parallel" elif "HALL" in label: Zs = machine.rotor.slot.Zs mag = str(-(Zs / 2 - 1)) + " * theta + 90 " magnetization_type = "hallback" else: continue if bodies.get(label, None) is not None: Mangle.append(mag) bodies[label]["mat"] = pm_index bodies[label]["eq"] = 1 bodies[label]["bf"] = 1 bodies[label]["tg"] = 1 pm_index = pm_index + 1 elif "W_STA" in label: st = label.split("_") Nrad_id = int(st[2][1:]) # zone radial coordinate Ntan_id = int(st[3][1:]) # zone tangential coordinate Zs_id = int(st[4][1:]) # Zone slot number coordinate # Get the phase value in the correct slot zone q_id = get_phase_id(wind_mat, Nrad_id, Ntan_id, Zs_id) Ncond = wind_mat[Nrad_id, Ntan_id, Zs_id, q_id] s = sign(Ncond) if bodies.get(label, None) is not None: bodies[label]["mat"] = 5 bodies[label]["eq"] = 1 if q_id == 0 and s == 1: bodies[label]["bf"] = 2 Ncond_Aplus = abs(Ncond) elif q_id == 0 and s == -1: bodies[label]["bf"] = 3 Ncond_Aminus = abs(Ncond) elif q_id == 1 and s == 1: bodies[label]["bf"] = 4 Ncond_Bplus = abs(Ncond) elif q_id == 1 and s == -1: bodies[label]["bf"] = 5 Ncond_Bminus = abs(Ncond) elif q_id == 2 and s == 1: bodies[label]["bf"] = 6 Ncond_Cplus = abs(Ncond) elif q_id == 2 and s == -1: bodies[label]["bf"] = 7 Ncond_Cminus = abs(Ncond) elif q_id == 3 and s == 1: bodies[label]["bf"] = 8 Ncond_Dplus = abs(Ncond) elif q_id == 3 and s == -1: bodies[label]["bf"] = 9 Ncond_Dminus = abs(Ncond) elif q_id == 4 and s == 1: bodies[label]["bf"] = 10 Ncond_Eplus = abs(Ncond) elif q_id == 4 and s == -1: bodies[label]["bf"] = 11 Ncond_Eminus = abs(Ncond) elif q_id == 5 and s == 1: bodies[label]["bf"] = 12 Ncond_Fplus = abs(Ncond) elif q_id == 5 and s == -1: bodies[label]["bf"] = 13 Ncond_Fminus = abs(Ncond) else: pass elif "ROTOR_LAM" in label and bodies.get(label, None) is not None: bodies[label]["mat"] = 4 bodies[label]["eq"] = 1 bodies[label]["bf"] = 1 bodies[label]["tg"] = 1 elif "STATOR_LAM" in label and bodies.get(label, None) is not None: bodies[label]["mat"] = 3 bodies[label]["eq"] = 1 elif "SHAFT" in label and bodies.get(label, None) is not None: bodies[label]["mat"] = 1 bodies[label]["eq"] = 1 bodies[label]["bf"] = 1 bodies[label]["tg"] = 1 elif "H_ROTOR" in label and bodies.get(label, None) is not None: bodies[label]["mat"] = 1 bodies[label]["eq"] = 1 bodies[label]["bf"] = 1 bodies[label]["tg"] = 1 else: pass # The following bodies are not in the dictionary bodies["AG_INT"]["bf"] = 1 bodies["SB_INT"]["bf"] = 1 No_Magnets = pm_index - 6 magnet_temp = 20.0 # Magnet Temperature Fixed for now Hcm20 = magnet_0.mat_type.mag.Hc Brm20 = magnet_0.mat_type.mag.Brm20 kt = 0.01 # Br Temperature Coefficient fixed for now Br = Brm20 * (1 + kt * 0.01 * (magnet_temp - 20.0)) magnet_permeability = magnet_0.mat_type.mag.mur_lin rho20_m = magnet_0.mat_type.elec.rho kt_m = 0.01 # Rho Temperature Coefficient fixed for now rho_m = rho20_m * (1 + kt_m * (magnet_temp - 20.0)) conductivity_m = 1.0 / rho_m skip_steps = 1 # Fixed for now degrees_step = 1 # Fixed for now current_angle = 0 - pp * degrees_step * skip_steps angle_shift = self.angle_rotor_shift - self.angle_stator_shift rotor_init_pos = angle_shift - degrees_step * skip_steps Ncond = 1 # Fixed for Now Cp = 1 # Fixed for Now qs = len(machine.stator.get_name_phase()) fo.write("$ H_PM = {0} ! Magnetization [A/m]\n".format( round(Hcm20, 2))) fo.write( "$ Shift = 2*pi/{0} ! N-phase machine [rad]\n".format(qs)) fo.write("$ Gamma = {0}*pi/180 ! Current Angle [rad]\n".format( round(current_angle, 2))) fo.write( "$ Ncond = {0} ! Conductors per coil\n".format(Ncond)) fo.write("$ Cp = {0} ! Parallel paths\n".format(Cp)) fo.write( "$ Is = {0} ! Stator current [A]\n".format(0.0)) fo.write("$ Aaxis = {0} ! Axis Coil A [deg]\n".format(0.0)) fo.write("$ Carea = {0} ! Coil Side Conductor Area [m2]\n". format(Swire)) for mm in range(1, No_Magnets + 1): fo.write( "$ Mangle{0} = {1} ! Magnetization Angle [deg]\n".format( mm, round(Mangle[mm - 1], 2))) fo.write("$ Nsteps = {0} !\n".format(2)) fo.write("$ StepDegrees = {0} !\n".format(degrees_step)) fo.write("$ DegreesPerSec = WM*180.0/pi !\n") fo.write("$ RotorInitPos = Aaxis - 360 / (4*PP) + {}!\n".format( round(rotor_init_pos, 2))) fo.write("\nHeader\n" "\tCHECK KEYWORDS Warn\n" '\tMesh DB "{0}"\n' '\tInclude Path "."\n' '\tResults Directory "{1}"\n' "End\n".format(elmermesh_folder, elmermesh_folder)) fo.write("\nConstants\n" "\tPermittivity of Vacuum = 8.8542e-12\n" "End\n") fo.write( "\nSimulation\n" "\tMax Output Level = 4\n" "\tCoordinate System = Cartesian 2D\n" "\tCoordinate Scaling = {0}\n" "\tSimulation Type = Transient\n" "\tTimestepping Method = BDF\n" "\tBDF Order = 2\n" # "\tTimestep Sizes = $ (StepDegrees / DegreesPerSec) ! sampling time\n" # "\tTimestep Intervals = $ Nsteps ! steps\n" # "\tOutput Intervals = 1\n" "\tTimestep Sizes({1}) = {2}\n" "\tTimestep Intervals({1}) = {3}\n" "\tUse Mesh Names = Logical True\n" "End\n".format(1.0, timelen, timesize_str[1:-1], timeinterval_str[1:-1])) fo.write("\n!--- MATERIALS ---\n") fo.write("Material 1\n" '\tName = "Air"\n' "\tRelative Permeability = 1\n" "\tElectric Conductivity = 0\n" "End\n") fo.write("\nMaterial 2\n" '\tName = "Insulation"\n' "\tRelative Permeability = 1\n" "\tElectric Conductivity = 0\n" "End\n") fo.write("\nMaterial 3\n" '\tName = "StatorMaterial"\n' '\tInclude "{0}"\n' "End\n".format(stator_mat_file)) fo.write("\nMaterial 4\n" '\tName = "RotorMaterial"\n' '\tInclude "{0}"\n' "End\n".format(rotor_mat_file)) winding_temp = 20.0 # Fixed for Now rho20 = machine.stator.winding.conductor.cond_mat.elec.rho kt = 0.01 # Br Temperature Coefficient fixed for now rho = rho20 * (1 + kt * (winding_temp - 20.0)) conductivity = 1.0 / rho fo.write("\nMaterial 5\n" '\tName = "Copper"\n' "\tRelative Permeability = 1\n" "\tElectric Conductivity = {0}\n" "End\n".format(round(conductivity, 2))) magnets_per_pole = No_Magnets # TO-DO: Assumes only one pole drawn for m in range(1, magnets_per_pole + 1): mat_number = 5 + m if magnetization_type == "parallel": fo.write( "\nMaterial {0}\n" '\tName = "PM_{1}"\n' "\tRelative Permeability = {2}\n" "\tMagnetization 1 = Variable time, timestep size\n" '\t\tReal MATC "H_PM*cos(WM*(tx(0)-tx(1)) + {3}*pi/PP + {3}*pi + Aaxis*pi/180 + (Mangle{1}*pi/180))"\n' "\tMagnetization 2 = Variable time, timestep size\n" '\t\tReal MATC "H_PM*sin(WM*(tx(0)-tx(1)) + {3}*pi/PP + {3}*pi + Aaxis*pi/180 + (Mangle{1}*pi/180))"\n' "\tElectric Conductivity = {4}\n" "End\n".format( mat_number, m, magnet_permeability, int((m - 1) / magnets_per_pole), round(conductivity_m, 2), )) elif magnetization_type == "radial": fo.write( "\nMaterial {0}\n" '\tName = "PM_{1}"\n' "\tRelative Permeability = {2}\n" "\tMagnetization 1 = Variable Coordinate\n" '\t\tReal MATC "H_PM*cos(atan2(tx(1),tx(0)) + {3}*pi)"\n' "\tMagnetization 2 = Variable Coordinate\n" '\t\tReal MATC "H_PM*sin(atan2(tx(1),tx(0)) + {3}*pi)"\n' "\tElectric Conductivity = {4}\n" "End\n".format( mat_number, m, magnet_permeability, m - 1, round(conductivity_m, 2), )) elif magnetization_type == "perpendicular": fo.write( "\nMaterial {0}\n" '\tName = "PM_{1}"\n' "\tRelative Permeability = {2}\n" "\tMagnetization 1 = Variable time, timestep size\n" '\t\tReal MATC "H_PM*cos(WM*(tx(0)-tx(1)) + {3}*pi/PP + {3}*pi + Aaxis*pi/180 + (Mangle{1}*pi/180))"\n' "\tMagnetization 2 = Variable time, timestep size\n" '\t\tReal MATC "H_PM*sin(WM*(tx(0)-tx(1)) + {3}*pi/PP + {3}*pi + Aaxis*pi/180 + (Mangle{1}*pi/180))"\n' "\tElectric Conductivity = {4}\n" "End\n".format( mat_number, m, magnet_permeability, int((m - 1) / magnets_per_pole), round(conductivity_m, 2), )) else: fo.write("\nMaterial {0}\n" '\tName = "PM_{1}"\n' "\tRelative Permeability = {2}\n" "\tElectric Conductivity = {4}\n" "End\n".format(mat_number, m, magnet_permeability, round(conductivity_m, 2))) fo.write("\n!--- BODY FORCES ---\n") # fo.write("Body Force 1\n" # "\tName = \"BodyForce_Rotation\"\n" # "\t$omega = (180/pi)*WM\n" # "\tMesh Rotate 3 = Variable time, timestep size\n" # "\t\tReal MATC \"omega*(tx(0)-tx(1)) + RotorInitPos\"\n" # "End\n") fo.write("Body Force 1\n" '\tName = "BodyForce_Rotation"\n' "\tMesh Rotate 3 = Variable time\n" "\t\tReal\n") for tt in range(0, timelen + 1): fo.write("\t\t{:.2e}\t\t{:.3f}\n".format(time[tt], angle[tt] * 180.0 / pi)) fo.write("\tEnd\n" "End\n") # fo.write("Body Force 2\n" # "\tName = \"J_A_PLUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) + Gamma)\"\n" # "End\n".format(Ncond_Aplus)) # fo.write("Body Force 3\n" # "\tName = \"J_A_MINUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"-(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) + Gamma)\"\n" # "End\n".format(Ncond_Aminus)) # fo.write("Body Force 4\n" # "\tName = \"J_B_PLUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) - Shift + Gamma)\"\n" # "End\n".format(Ncond_Bplus)) # # fo.write("Body Force 5\n" # "\tName = \"J_B_MINUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"-(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) - Shift + Gamma)\"\n" # "End\n".format(Ncond_Bminus)) # # fo.write("Body Force 6\n" # "\tName = \"J_C_PLUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) - 2*Shift + Gamma)\"\n" # "End\n".format(Ncond_Cplus)) # # fo.write("Body Force 7\n" # "\tName = \"J_C_MINUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"-(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) - 2*Shift + Gamma)\"\n" # "End\n".format(Ncond_Cminus)) # # fo.write("Body Force 8\n" # "\tName = \"J_D_PLUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) - 3*Shift + Gamma)\"\n" # "End\n".format(Ncond_Dplus)) # # fo.write("Body Force 9\n" # "\tName = \"J_D_MINUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"-(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) - 3*Shift + Gamma)\"\n" # "End\n".format(Ncond_Dminus)) # # fo.write("Body Force 10\n" # "\tName = \"J_E_PLUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) - 4*Shift + Gamma)\"\n" # "End\n".format(Ncond_Eplus)) # # fo.write("Body Force 11\n" # "\tName = \"J_E_MINUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"-(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) - 4*Shift + Gamma)\"\n" # "End\n".format(Ncond_Eminus)) # # fo.write("Body Force 12\n" # "\tName = \"J_F_PLUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) - 5*Shift + Gamma)\"\n" # "End\n".format(Ncond_Fplus)) # # fo.write("Body Force 13\n" # "\tName = \"J_F_MINUS\"\n" # "\tCurrent Density = Variable time, timestep size\n" # "\t\tReal MATC \"-(Is/Carea) * ({0}/Cp) * sin(WE * (tx(0)-tx(1)) - 5*Shift + Gamma)\"\n" # "End\n".format(Ncond_Fminus)) fo.write("Body Force 2\n" '\tName = "J_A_PLUS"\n' "\tCurrent Density = Variable time\n" "\t\tReal\n") for tt in range(0, timelen + 1): fo.write("\t\t{:.2e}\t\t{:.3f}\n".format(time[tt], Is[0, tt])) fo.write("\tEnd\n" "End\n") fo.write("Body Force 3\n" '\tName = "J_A_MINUS"\n' "\tCurrent Density = Variable time\n" "\t\tReal\n") for tt in range(0, timelen + 1): fo.write("\t\t{:.2e}\t\t{:.3f}\n".format(time[tt], -Is[0, tt])) fo.write("\tEnd\n" "End\n") fo.write("Body Force 4\n" '\tName = "J_B_PLUS"\n' "\tCurrent Density = Variable time\n" "\t\tReal\n") for tt in range(0, timelen + 1): fo.write("\t\t{:.2e}\t\t{:.3f}\n".format(time[tt], Is[1, tt])) fo.write("\tEnd\n" "End\n") fo.write("Body Force 5\n" '\tName = "J_B_MINUS"\n' "\tCurrent Density = Variable time\n" "\t\tReal\n") for tt in range(0, timelen + 1): fo.write("\t\t{:.2e}\t\t{:.3f}\n".format(time[tt], -Is[1, tt])) fo.write("\tEnd\n" "End\n") fo.write("Body Force 6\n" '\tName = "J_C_PLUS"\n' "\tCurrent Density = Variable time\n" "\t\tReal\n") for tt in range(0, timelen + 1): fo.write("\t\t{:.2e}\t\t{:.3f}\n".format(time[tt], Is[2, tt])) fo.write("\tEnd\n" "End\n") fo.write("Body Force 7\n" '\tName = "J_C_MINUS"\n' "\tCurrent Density = Variable time\n" "\t\tReal\n") for tt in range(0, timelen + 1): fo.write("\t\t{:.2e}\t\t{:.3f}\n".format(time[tt], -Is[2, tt])) fo.write("\tEnd\n" "End\n") fo.write("\n!--- BODIES ---\n") for k, v in bodies.items(): bid = bodies[k]["id"] beq = bodies[k]["eq"] bmat = bodies[k]["mat"] bf = bodies[k]["bf"] btg = bodies[k]["tg"] fo.write("Body {0}\n" "\tName = {1}\n" "\tEquation = {2}\n" "\tMaterial = {3}\n".format(bid, k, beq, bmat)) if bf is not None: fo.write("\tBody Force = {0}\n".format(bf)) if btg is not None: fo.write("\tTorque Groups = Integer {0}\n".format(btg)) if k == "SB_INT": fo.write("\tR Inner = Real {0}\n" "\tR Outer = Real {1}\n".format(ror, sir)) fo.write("End\n\n") fo.write("Equation 1\n" '\tName = "Model_Domain"\n' "\tActive Solvers(6) = 1 2 3 4 5 6\n" "End\n") fo.write("\n!--- SOLVERS ---\n") fo.write("Solver 1\n" "\tExec Solver = Before Timestep\n" "\tEquation = MeshDeform\n" '\tProcedure = "RigidMeshMapper" "RigidMeshMapper"\n' "End\n") fo.write("\nSolver 2\n" "\tEquation = MgDyn2D\n" '\tProcedure = "MagnetoDynamics2D" "MagnetoDynamics2D"\n' "\tExec Solver = Always\n" "\tVariable = A\n") fo.write( "\tNonlinear System Convergence Tolerance = {0}\n".format(1e-6)) fo.write("\tNonlinear System Max Iterations = {0}\n".format(100)) fo.write("\tNonlinear System Min Iterations = {0}\n".format(1)) fo.write( "\tNonlinear System Newton After Iterations = {0}\n".format(5)) fo.write("\tNonlinear System Relaxation Factor = {0}\n".format(0.9)) fo.write("\tNonlinear System Convergence Without Constraints = {0}\n". format("Logical True")) fo.write("\tExport Lagrange Multiplier = {0}\n".format("Logical True")) fo.write("\tLinear System Abort Not Converged = {0}\n".format( "Logical False")) fo.write("\tLinear System Solver = {0}\n".format("Direct")) fo.write("\tLinear System Direct Method = {0}\n".format("umfpack")) fo.write("\tOptimize Bandwidth = {0}\n".format("Logical True")) fo.write("\tLinear System Preconditioning = {0}\n".format("ILU2")) fo.write("\tLinear System Max Iterations = {0}\n".format(5000)) fo.write("\tLinear System Residual Output = {0}\n".format(20)) fo.write("\tLinear System Convergence Tolerance = {0}\n".format(1e-7)) fo.write("\tMortar BCs Additive = {0}\n".format("Logical True")) fo.write("End\n") fo.write( "\nSolver 3\n" "\tExec Solver = Always\n" "\tEquation = CalcFields\n" '\tPotential Variable = "A"\n' '\tProcedure = "MagnetoDynamics" "MagnetoDynamicsCalcFields"\n' "\tCalculate Nodal Forces = Logical True\n" "\tCalculate Magnetic Vector Potential = Logical True\n" "\tCalculate Winding Voltage = Logical True\n" "\tCalculate Current Density = Logical True\n" "\tCalculate Maxwell Stress = Logical True\n" "\tCalculate JxB = Logical True\n" "\tCalculate Magnetic Field Strength = Logical True\n" "End\n") fo.write("\nSolver 4\n" "\tExec Solver = After Timestep\n" '\tProcedure = "ResultOutputSolve" "ResultOutputSolver"\n' '\tOutput File Name = "{0}"\n' "\tVtu Format = True\n" "\tBinary Output = True\n" "\tSingle Precision = True\n" "\tSave Geometry Ids = True\n" "\tShow Variables = True\n" "End\n".format("step")) fo.write("\nSolver 5\n" "\tExec Solver = After Timestep\n" "\tEquation = SaveLine\n" '\tFilename = "{0}"\n' '\tProcedure = "SaveData" "SaveLine"\n' "\tVariable 1 = Magnetic Flux Density 1\n" "\tVariable 2 = Magnetic Flux Density 2\n" "\tVariable 3 = Magnetic Flux Density 3\n" "\tVariable 4 = Magnetic Flux Density e 1\n" "\tVariable 5 = Magnetic Flux Density e 2\n" "\tVariable 6 = Magnetic Flux Density e 3\n" "End\n".format("lines.dat")) fo.write("\nSolver 6\n" "\tExec Solver = After Timestep\n" '\tFilename = "{0}"\n' '\tProcedure = "SaveData" "SaveScalars"\n' "\tShow Norm Index = 1\n" "End\n".format("scalars.dat")) fo.write("\n!--- BOUNDARIES ---\n") for k, v in boundaries.items(): if k == "VP0_BOUNDARY": fo.write("Boundary Condition {0}\n" "\tName = {1}\n" "\tA = Real 0\n" "End\n\n".format(v, k)) elif k == "MASTER_STATOR_BOUNDARY": for k1, v1 in boundaries.items(): if k1 == "SLAVE_STATOR_BOUNDARY": slave = v1 break if not self.is_periodicity_a: fo.write("Boundary Condition {0}\n" "\tName = {1}\n" "\tMortar BC = Integer {2}\n" "\tMortar BC Static = Logical True\n" "\tRadial Projector = Logical True\n" "\tGalerkin Projector = Logical True\n" "End\n\n".format(v, k, slave)) else: fo.write("Boundary Condition {0}\n" "\tName = {1}\n" "\tMortar BC = Integer {2}\n" "\tMortar BC Static = Logical True\n" "\tAnti Radial Projector = Logical True\n" "\tGalerkin Projector = Logical True\n" "End\n\n".format(v, k, slave)) elif k == "MASTER_ROTOR_BOUNDARY": for k1, v1 in boundaries.items(): if k1 == "SLAVE_ROTOR_BOUNDARY": slave = v1 break if not self.is_periodicity_a: fo.write("Boundary Condition {0}\n" "\tName = {1}\n" "\tMortar BC = Integer {2}\n" "\tMortar BC Static = Logical True\n" "\tRadial Projector = Logical True\n" "\tGalerkin Projector = Logical True\n" "End\n\n".format(v, k, slave)) else: fo.write("Boundary Condition {0}\n" "\tName = {1}\n" "\tMortar BC = Integer {2}\n" "\tMortar BC Static = Logical True\n" "\tAnti Radial Projector = Logical True\n" "\tGalerkin Projector = Logical True\n" "End\n\n".format(v, k, slave)) elif k == "SB_STATOR_BOUNDARY": for k1, v1 in boundaries.items(): if k1 == "SB_ROTOR_BOUNDARY": slave = v1 break if not self.is_periodicity_a: fo.write("Boundary Condition {0}\n" "\tName = {1}\n" "\tMortar BC = Integer {2}\n" "\tRotational Projector = Logical True\n" "\tGalerkin Projector = Logical True\n" "End\n\n".format(v, k, slave)) else: fo.write("Boundary Condition {0}\n" "\tName = {1}\n" "\tMortar BC = Integer {2}\n" "\tAnti Rotational Projector = Logical True\n" "\tGalerkin Projector = Logical True\n" "End\n\n".format(v, k, slave)) elif k == "AIRGAP_ARC_BOUNDARY": fo.write("Boundary Condition {0}\n" "\tName = {1}\n" "\tSave Line = True\n" "End\n\n".format(v, k)) else: fo.write("Boundary Condition {0}\n" "\tName = {1}\n" "End\n\n".format(v, k)) # setup Elmer solver # ElmerSolver v8.4 must be installed and in the PATH elmer_settings = join(project_name, "pyleecan_elmer.sif") ElmerSolver_binary = get_path_binary("ElmerSolver") cmd_elmersolver = [ ElmerSolver_binary, elmer_settings, ] self.get_logger().info("Calling ElmerSolver: " + " ".join(map(str, cmd_elmersolver))) elmersolver = subprocess.Popen(cmd_elmersolver, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = elmersolver.communicate() elmersolver.wait() self.get_logger().info(stdout.decode("UTF-8")) if elmersolver.returncode != 0: self.get_logger().info("ElmerSolver [Error]: " + stderr.decode("UTF-8")) return False elmersolver.terminate() self.get_logger().info("ElmerSolver call complete!") self.get_meshsolution() Na = angle.size Nt = time.size # Loading parameters for readibility L1 = output.simu.machine.stator.comp_length() save_path = self.get_path_save(output) # FEM_dict = output.mag.FEM_dict # if (hasattr(output.simu.machine.stator, "winding") and output.simu.machine.stator.winding is not None): qs = output.simu.machine.stator.winding.qs # Winding phase number Phi_wind_stator = zeros((Nt, qs)) else: Phi_wind_stator = None # Initialize results matrix Br = zeros((Nt, Na)) Bt = zeros((Nt, Na)) Bz = zeros((Nt, Na)) Tem = zeros((Nt)) # Phi_wind_stator = zeros((Nt, qs)) # compute the data for each time step # TODO Other than FEMM, in Elmer I think it's possible to compute # all time steps at once self.get_logger().debug("Solving Simulation") # run the computation if self.nb_worker > 1: # TODO run solver in parallel pass else: # TODO run solver 'normal' pass # get the air gap flux result # TODO add function (or method) # ii -> Time, jj -> Angle # Br[ii, jj], Bt[ii, jj] = get_airgap_flux() # get the torque # TODO add function (or method) # Tem[ii] = comp_Elmer_torque(FEM_dict, sym=sym) # flux linkage computation # if Phi_wind_stator is not None: # # TODO # # Phi_wind[ii, :] = comp_Elmer_Phi_wind() # pass return Br, Bt, Bz, Tem, Phi_wind_stator
def get_hole(self): """Generate the HoleUD object corresponding to the selected surfaces Parameters ---------- self : DXF_Hole a DXF_Hole object Returns ------- hole : HoleUD User defined hole according to selected surfaces """ if self.lf_scaling.value() == 0: # Avoid error self.lf_scaling.setValue(1) hole = HoleUD(surf_list=[]) bottom_list = list() offset_list = list() # Set labels Nmag = 0 for ii in range(self.w_surface_list.rowCount()): hole.surf_list.append(self.surf_list[ii].copy()) hole.surf_list[ii].scale(self.lf_scaling.value()) if self.w_surface_list.cellWidget(ii, TYPE_COL).currentIndex() == 0: hole.surf_list[ii].label = "Hole" else: hole.surf_list[ii].label = "HoleMagnet" Nmag += 1 bottom_list.append(self.line_list[int( self.w_surface_list.cellWidget(ii, REF_COL).currentText())]) offset_list.append( self.w_surface_list.cellWidget(ii, OFF_COL).value()) # Create magnet objects hole.magnet_dict = dict() for ii in range(Nmag): hole.magnet_dict["magnet_" + str(ii)] = Magnet(type_magnetization=1) # Sort the surfaces angles = [np_angle(surf.point_ref) for surf in hole.surf_list] idx = sorted(range(len(angles)), key=lambda k: angles[k]) surf_list_sorted = [hole.surf_list[ii] for ii in idx] bottom_list_sorted = [bottom_list[ii] for ii in idx] offset_list_sorted = [offset_list[ii] for ii in idx] hole.surf_list = surf_list_sorted # Rotation Zref = sum([surf.point_ref for surf in hole.surf_list]) for surf in hole.surf_list: surf.rotate(-1 * np_angle(Zref)) # Magnetization dict mag_dict = dict() Nmag = 0 for ii in range(len(hole.surf_list)): if "Magnet" in hole.surf_list[ii].label: line = bottom_list_sorted[ii].copy() line.rotate(-1 * np_angle(Zref)) mag_dict["magnet_" + str(Nmag)] = line.comp_normal() mag_dict["magnet_" + str(Nmag)] += offset_list_sorted[ii] * pi / 180 Nmag += 1 hole.magnetization_dict_offset = mag_dict # Set metadata hole.Zh = self.si_Zh.value() for magnet in hole.magnet_dict.values(): magnet.Lmag = self.lf_mag_len.value() # Remove all materials => To be set in GUI hole.mat_void = None for magnet in hole.magnet_dict.values(): magnet.mat_type = None return hole
def Phase(self): return np_unwrap(np_angle(self.amp))
def PhaseTrim(self): return np_unwrap(np_angle(self.ampTrim))
def xy_to_rphi(x, y): affixe = x + 1j * y r = np_abs(affixe) phi = (np_angle(affixe) + 2 * pi) % (2 * pi) return (r, phi)
def get_slot(self): """Generate the SlotUD object corresponding to the selected lines Parameters ---------- self : DXF_Slot a DXF_Slot object Returns ------- sot : SlotUD User defined slot according to selected lines """ if self.lf_scaling.value() == 0: # Avoid error self.lf_scaling.setValue(1) # Get all the selected lines line_list = list() point_list = list() for ii, line in enumerate(self.line_list): if self.selected_list[ii]: line_list.append(line.copy()) line_list[-1].scale(self.lf_scaling.value()) point_list.append(line_list[-1].get_begin()) point_list.append(line_list[-1].get_end()) # Find begin point single_list = list() for p1 in point_list: count = 0 for p2 in point_list: if abs(p1 - p2) < Z_TOL: count += 1 if count == 1: single_list.append(p1) assert len(single_list) == 2 Zbegin = single_list[argmin(np_angle(array(single_list)))] # Get begin line id_list = list() id_list.extend( [ ii for ii, line in enumerate(line_list) if abs(line.get_begin() - Zbegin) < Z_TOL or abs(line.get_end() - Zbegin) < Z_TOL ] ) # Sort the lines (begin = end) curve_list = list() curve_list.append(line_list.pop(id_list[0])) if abs(curve_list[0].get_end() - Zbegin) < Z_TOL: # Reverse begin line if line end matches with begin point curve_list[0].reverse() while len(line_list) > 0: end = curve_list[-1].get_end() for ii in range(len(line_list)): if abs(line_list[ii].get_begin() - end) < Z_TOL: break if abs(line_list[ii].get_end() - end) < Z_TOL: line_list[ii].reverse() break curve_list.append(line_list.pop(ii)) # Translate if self.Zcenter != 0: for line in curve_list: line.translate(-self.Zcenter * self.lf_scaling.value()) # Check the first and last point are matching Rint Rbo = self.lam.get_Rbo() Zbegin = curve_list[0].get_begin() Zend = curve_list[-1].get_end() if abs(abs(Zbegin) - Rbo) > Z_TOL: QMessageBox().critical( self, self.tr("Error"), self.tr( "First point of the slot is not on the bore radius:\nBore radius=" + str(Rbo) + ", abs(First point)=" + str(abs(Zbegin)) ), ) return None if abs(abs(Zend) - Rbo) > Z_TOL: QMessageBox().critical( self, self.tr("Error"), self.tr( "Last point of the slot is not on the bore radius:\nBore radius=" + str(Rbo) + ", abs(Last point)=" + str(abs(Zend)) ), ) return None # Rotation Z1 = curve_list[0].get_begin() Z2 = curve_list[-1].get_end() alpha = (np_angle(Z2) + np_angle(Z1)) / 2 for line in curve_list: line.rotate(-1 * alpha) # Enforce perfect match with Bore radius by adding Segments in needed Zbegin = curve_list[0].get_begin() Zb2 = Rbo * exp(1j * angle(Zbegin)) if abs(Zb2 - Zbegin) > 1e-9: curve_list.insert(0, Segment(begin=Zb2, end=Zbegin)) Zend = curve_list[-1].get_end() Ze2 = Rbo * exp(1j * angle(Zend)) if abs(Ze2 - Zend) > 1e-9: curve_list.append(Segment(begin=Zend, end=Ze2)) # Create the Slot object slot = SlotUD(line_list=curve_list) slot.type_line_wind = self.c_type_line.currentIndex() begin_id = self.si_wind_begin_index.value() end_id = self.si_wind_end_index.value() if ( begin_id < len(curve_list) and end_id < len(curve_list) # and begin_id < end_id ): slot.wind_begin_index = begin_id slot.wind_end_index = end_id else: slot.wind_begin_index = None slot.wind_end_index = None slot.Zs = self.si_Zs.value() return slot
def get_hole(self): """Generate the HoleUD object corresponding to the selected surfaces Parameters ---------- self : DXF_Hole a DXF_Hole object Returns ------- hole : HoleUD User defined hole according to selected surfaces """ if self.lf_scaling.value() == 0: # Avoid error self.lf_scaling.setValue(1) hole = HoleUD(surf_list=[]) bottom_list = list() offset_list = list() # Set labels Nmag = 0 for ii in range(self.w_surface_list.rowCount()): hole.surf_list.append(self.surf_list[ii].copy()) hole.surf_list[ii].scale(self.lf_scaling.value()) if self.w_surface_list.cellWidget(ii, TYPE_COL).currentIndex() == 0: hole.surf_list[ii].label = "Hole" else: hole.surf_list[ii].label = "HoleMagnet" Nmag += 1 bottom_list.append(self.line_list[int( self.w_surface_list.cellWidget(ii, REF_COL).currentText())]) offset_list.append( self.w_surface_list.cellWidget(ii, OFF_COL).value()) # Create magnet objects hole.magnet_dict = dict() for ii in range(Nmag): hole.magnet_dict["magnet_" + str(ii)] = Magnet(type_magnetization=1) # Sort the surfaces angles = [np_angle(surf.point_ref) for surf in hole.surf_list] idx = sorted(range(len(angles)), key=lambda k: angles[k]) surf_list_sorted = [hole.surf_list[ii] for ii in idx] bottom_list_sorted = [bottom_list[ii] for ii in idx] offset_list_sorted = [offset_list[ii] for ii in idx] hole.surf_list = surf_list_sorted # Rotation Zref = sum([surf.point_ref for surf in hole.surf_list]) for surf in hole.surf_list: surf.rotate(-1 * np_angle(Zref)) # Magnetization dict mag_dict = dict() Nmag = 0 for ii in range(len(hole.surf_list)): if "Magnet" in hole.surf_list[ii].label: line = bottom_list_sorted[ii].copy() line.rotate(-1 * np_angle(Zref)) mag_dict["magnet_" + str(Nmag)] = line.comp_normal() mag_dict["magnet_" + str(Nmag)] += offset_list_sorted[ii] * pi / 180 Nmag += 1 hole.magnetization_dict_offset = mag_dict # Set metadata hole.Zh = self.si_Zh.value() for magnet in hole.magnet_dict.values(): magnet.Lmag = self.lf_mag_len.value() # Remove all materials => To be set in GUI hole.mat_void = None for magnet in hole.magnet_dict.values(): magnet.mat_type = None # Sort Hole then magnets # (for plot when Magnets are inside Hole surface) mag_list = list() hole_list = list() for surf in hole.surf_list: if "HoleMagnet" in surf.label: mag_list.append(surf) else: hole_list.append(surf) hole.surf_list = hole_list + mag_list # Correct hole ref_point (when Magnets are inside Hole surface) for surf in hole.surf_list: if "HoleMagnet" not in surf.label: line_list = surf.get_lines() # Get middle list middle_array = array([line.get_middle() for line in line_list]) # Get the extrema line on the top or bottom of the hole if np_min(middle_array.imag) > 0 and np_max( middle_array.imag) > 0: start_idx = argmax(middle_array.imag) else: start_idx = argmin(middle_array.imag) # Get the two lines middle besides the extrema line middle if start_idx == 0: ref_mid = [ middle_array[-1], middle_array[0], middle_array[1] ] elif start_idx == len(line_list) - 1: ref_mid = [ middle_array[-2], middle_array[-1], middle_array[0] ] else: ref_mid = [ middle_array[start_idx - 1], middle_array[start_idx], middle_array[start_idx + 1], ] # Barycenter of these middles as new reference surf.point_ref = sum(ref_mid) / 3 return hole
def get_yoke_side_line(self, sym, vent_surf_list, ZBR=None, ZTR=None, ZBL=None, ZTL=None): """Define the Yoke Side lines of a Lamination by taking into account sym and vent Parameters: self: Lamination a Lamination object sym : int Symmetry factor (1= full machine, 2= half of the machine...) vent_surf_list : List of the ventilation surfaces ZBR : Complex Yoke Side Limit point Bottom Right ZTR : Complex Yoke Side Limit point Top Right ZBL : Complex Yoke Side Limit point Bottom Left ZTL : Complex Yoke Side Limit point Top Left Returns: right_list, left_list: ([Line], [Line]) List of the lines to draw the left and right side of the yoke """ # Find the ventilation lines that collide with the Yoke Side inter_line_list_R, inter_line_list_L = list(), list() for surf in vent_surf_list: for line in surf.get_lines(): if (line.prop_dict is not None and BOUNDARY_PROP_LAB in line.prop_dict and YS_LAB in line.prop_dict[BOUNDARY_PROP_LAB]): # Find if the line collide on right or left if abs(np_angle(line.get_middle())) < DELTA: inter_line_list_R.append(line) else: inter_line_list_L.append(line) # Yoke Limit point if ZBR is None: alpha = 2 * pi / sym ZBR = self.Rint ZTR = self.Rext ZBL = ZBR * exp(1j * alpha) ZTL = ZTR * exp(1j * alpha) lam_lab = self.get_label() if self.is_internal: right_list = merge_line_list(ZBR, ZTR, lam_lab + "_" + YSR_LAB, inter_line_list_R) left_list = merge_line_list(ZTL, ZBL, lam_lab + "_" + YSL_LAB, inter_line_list_L) else: left_list = merge_line_list(ZBL, ZTL, lam_lab + "_" + YSL_LAB, inter_line_list_L) right_list = merge_line_list(ZTR, ZBR, lam_lab + "_" + YSR_LAB, inter_line_list_R) return right_list, left_list
def plot_schematics( self, is_default=False, is_add_point_label=False, is_add_schematics=True, is_add_main_line=True, type_add_active=True, save_path=None, is_show_fig=True, ): """Plot the schematics of the slot Parameters ---------- self : VentilationPolar A VentilationPolar object is_default : bool True: plot default schematics, else use current slot values is_add_point_label : bool True to display the name of the points (Z1, Z2....) is_add_schematics : bool True to display the schematics information (W0, H0...) is_add_main_line : bool True to display "main lines" (slot opening and 0x axis) type_add_active : int 0: No active surface, 1: active surface as winding, 2: active surface as magnet save_path : str full path including folder, name and extension of the file to save if save_path is not None is_show_fig : bool To call show at the end of the method """ # Use some default parameter if is_default: hole = type(self)( H0=0.125, Zh=8, Alpha0=0.3, D0=0.05, W1=2 * pi / 16, ) lam = LamHole(Rint=0.1, Rext=0.2, is_internal=True, is_stator=False, hole=[hole]) hole.plot_schematics( is_default=False, is_add_point_label=is_add_point_label, is_add_schematics=is_add_schematics, is_add_main_line=is_add_main_line, type_add_active=type_add_active, save_path=save_path, is_show_fig=is_show_fig, ) else: # Getting the main plot if self.parent is None: raise ParentMissingError( "Error: The hole is not inside a Lamination") lam = self.parent lam.plot( alpha=0, is_show_fig=False, is_lam_only=True, # No magnet ) # center hole on Ox axis fig = plt.gcf() ax = plt.gca() point_dict = self._comp_point_coordinate() # Adding point label if is_add_point_label: for name, Z in point_dict.items(): ax.text( Z.real, Z.imag, name, fontsize=P_FONT_SIZE, bbox=TEXT_BOX, ) # Adding schematics if is_add_schematics: # H0 line = Segment(0, point_dict["Z1"]) line.plot( fig=fig, ax=ax, color=ARROW_COLOR, linewidth=ARROW_WIDTH, label="H0", offset_label=self.D0 / 4 * 1j, is_arrow=True, fontsize=SC_FONT_SIZE, ) # D0 line = Segment( point_dict["Z1"] * exp(1j * 2 * pi / self.Zh), point_dict["Z2"] * exp(1j * 2 * pi / self.Zh), ) line.plot( fig=fig, ax=ax, color=ARROW_COLOR, linewidth=ARROW_WIDTH, label="D0", offset_label=self.D0 / 4, is_arrow=True, fontsize=SC_FONT_SIZE, ) # Alpha0 line = Arc1( begin=self.H0 + self.D0 / 2, end=point_dict["Zc"], radius=self.H0 + self.D0 / 2, is_trigo_direction=True, ) line.plot( fig=fig, ax=ax, color=ARROW_COLOR, linewidth=ARROW_WIDTH, label="Alpha0", offset_label=self.D0 / 4 * (1 - 1.5j), fontsize=SC_FONT_SIZE, ) # W1 Rtop = self.H0 + self.D0 Rarc = (Rtop + lam.Rext) / 2 line = Arc1( begin=Rarc * exp(1j * (self.Alpha0 - self.W1 / 2)), end=Rarc * exp(1j * (self.Alpha0 + self.W1 / 2)), radius=Rarc, is_trigo_direction=True, ) line.plot( fig=fig, ax=ax, color=ARROW_COLOR, linewidth=ARROW_WIDTH, label="W1", offset_label=self.D0 / 4, fontsize=SC_FONT_SIZE, ) if is_add_main_line: # Ox axis line = Segment(0, lam.Rext * 1.5) line.plot( fig=fig, ax=ax, color=MAIN_LINE_COLOR, linestyle=MAIN_LINE_STYLE, linewidth=MAIN_LINE_WIDTH, ) # Center axis line = Segment(0, lam.Rext * 1.5 * exp(1j * self.Alpha0)) line.plot( fig=fig, ax=ax, color=MAIN_LINE_COLOR, linestyle=MAIN_LINE_STYLE, linewidth=MAIN_LINE_WIDTH, ) # H0 radius line = Arc1( begin=self.H0 * exp(-1j * pi / 2 * 0.9), end=self.H0 * exp(1j * pi / 2 * 0.9), radius=self.H0, is_trigo_direction=True, ) line.plot( fig=fig, ax=ax, color=MAIN_LINE_COLOR, linestyle=MAIN_LINE_STYLE, linewidth=MAIN_LINE_WIDTH, ) # H0+D0 radius line = Arc1( begin=(self.H0 + self.D0) * exp(-1j * pi / 2 * 0.9), end=(self.H0 + self.D0) * exp(1j * pi / 2 * 0.9), radius=(self.H0 + self.D0), is_trigo_direction=True, ) line.plot( fig=fig, ax=ax, color=MAIN_LINE_COLOR, linestyle=MAIN_LINE_STYLE, linewidth=MAIN_LINE_WIDTH, ) # Vent side 1 axis line = Segment( 0, lam.Rext * 1.5 * exp(1j * np_angle(point_dict["Z1"]))) line.plot( fig=fig, ax=ax, color=MAIN_LINE_COLOR, linestyle=MAIN_LINE_STYLE, linewidth=MAIN_LINE_WIDTH, ) # Vent side 2 axis line = Segment( 0, lam.Rext * 1.5 * exp(1j * np_angle(point_dict["Z3"]))) line.plot( fig=fig, ax=ax, color=MAIN_LINE_COLOR, linestyle=MAIN_LINE_STYLE, linewidth=MAIN_LINE_WIDTH, ) # Zooming and cleaning W = abs(point_dict["Z2"].imag) * 1.3 Rint = self.parent.Rint Rext = self.parent.Rext plt.axis("equal") ax.set_ylim(-Rext / 10, Rext * 0.9) ax.set_xlim(Rext / 10, Rext) manager = plt.get_current_fig_manager() if manager is not None: manager.set_window_title(type(self).__name__ + " Schematics") ax.set_title("") ax.get_legend().remove() ax.set_axis_off() # Save / Show if save_path is not None: fig.savefig(save_path) plt.close() if is_show_fig: fig.show()