diff --git a/femmt/component.py b/femmt/component.py index be606499..42855a82 100644 --- a/femmt/component.py +++ b/femmt/component.py @@ -30,6 +30,7 @@ from femmt.dtos import * import femmt.functions_reluctance as fr + class MagneticComponent: """ A MagneticComponent is the main object for all simulation purposes in femmt. @@ -61,7 +62,7 @@ def __init__(self, component_type: ComponentType = ComponentType.Inductor, worki :type is_gui: bool :param simulation_name: name without any effect. Will just be displayed in the result-log file :type simulation_name: str - """ + """ # Get caller filepath when no working_directory was set if working_directory is None: caller_filename = inspect.stack()[1].filename @@ -93,9 +94,9 @@ def __init__(self, component_type: ComponentType = ComponentType.Inductor, worki self.silent = True self.femmt_print(f"\n" - f"Initialized a new Magnetic Component of type {component_type.name}\n" - f"--- --- --- ---") - + f"Initialized a new Magnetic Component of type {component_type.name}\n" + f"--- --- --- ---") + # To make sure femm is only imported once self.femm_is_imported = False @@ -105,12 +106,12 @@ def __init__(self, component_type: ComponentType = ComponentType.Inductor, worki # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Components - self.core = None # Contains all information about the cores - self.air_gaps = None # Contains every air gap - self.windings = None # List of the different winding objects which the following structure: windings[0]: primary, windings[1]: secondary, windings[2]: tertiary .... - self.insulation = None # Contains information about the needed insulations - self.winding_windows = None # Contains a list of every winding_window which was created containing a list of virtual_winding_windows - self.stray_path = None # Contains information about the stray_path (only for integrated transformers) + self.core = None # Contains all information about the cores + self.air_gaps = None # Contains every air gap + self.windings = None # List of the different winding objects which the following structure: windings[0]: primary, windings[1]: secondary, windings[2]: tertiary .... + self.insulation = None # Contains information about the needed insulations + self.winding_windows = None # Contains a list of every winding_window which was created containing a list of virtual_winding_windows + self.stray_path = None # Contains information about the stray_path (only for integrated transformers) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Control Flags @@ -121,12 +122,12 @@ def __init__(self, component_type: ComponentType = ComponentType.Inductor, worki # Empty lists will be set when a winding window is added to the magnetic component self.imposed_reduced_frequency = None self.flag_excitation_type = None - self.current = [] # Defined for every conductor - self.current_density = [] # Defined for every conductor - self.voltage = [] # Defined for every conductor + self.current = [] # Defined for every conductor + self.current_density = [] # Defined for every conductor + self.voltage = [] # Defined for every conductor self.frequency = None - self.phase_deg = None # Default is zero, Defined for every conductor - self.red_freq = None # [] * self.n_windings # Defined for every conductor + self.phase_deg = None # Default is zero, Defined for every conductor + self.red_freq = None # [] * self.n_windings # Defined for every conductor self.delta = None # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -191,8 +192,10 @@ def femmt_print(self, text: str): # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Thermal simulation - def thermal_simulation(self, thermal_conductivity_dict: Dict, boundary_temperatures_dict: Dict, boundary_flags_dict: Dict, case_gap_top: float, - case_gap_right: float, case_gap_bot: float, show_thermal_simulation_results: bool = True, pre_visualize_geometry: bool = False, color_scheme: Dict = ff.colors_femmt_default, + def thermal_simulation(self, thermal_conductivity_dict: Dict, boundary_temperatures_dict: Dict, + boundary_flags_dict: Dict, case_gap_top: float, + case_gap_right: float, case_gap_bot: float, show_thermal_simulation_results: bool = True, + pre_visualize_geometry: bool = False, color_scheme: Dict = ff.colors_femmt_default, colors_geometry: Dict = ff.colors_geometry_femmt_default, flag_insulation: bool = True): """ Starts the thermal simulation using thermal_simulation.py @@ -221,16 +224,15 @@ def thermal_simulation(self, thermal_conductivity_dict: Dict, boundary_temperatu # Create necessary folders self.file_data.create_folders(self.file_data.thermal_results_folder_path) - self.mesh.generate_thermal_mesh(case_gap_top, case_gap_right, case_gap_bot, color_scheme, colors_geometry, pre_visualize_geometry) - - - + self.mesh.generate_thermal_mesh(case_gap_top, case_gap_right, case_gap_bot, color_scheme, colors_geometry, + pre_visualize_geometry) - #insulation_tag = self.mesh.ps_insulation if flag_insulation and len(self.insulation.core_cond) == 4 else None + # insulation_tag = self.mesh.ps_insulation if flag_insulation and len(self.insulation.core_cond) == 4 else None if not os.path.exists(self.file_data.e_m_results_log_path): # Simulation results file not created - raise Exception("Cannot run thermal simulation -> Magnetic simulation needs to run first (no results_log.json found") + raise Exception( + "Cannot run thermal simulation -> Magnetic simulation needs to run first (no results_log.json found") # Check if the results log path simulation settings fit the current simulation settings current_settings = MagneticComponent.encode_settings(self) @@ -249,17 +251,21 @@ def thermal_simulation(self, thermal_conductivity_dict: Dict, boundary_temperatu Please re-run the magnetic simulation.") tags = { - "core_tag": self.mesh.ps_core, + "core_tags": self.mesh.ps_core, "background_tag": self.mesh.ps_air, "winding_tags": self.mesh.ps_cond, "air_gaps_tag": self.mesh.ps_air_gaps if self.air_gaps.number > 0 else None, "boundary_regions": self.mesh.thermal_boundary_region_tags, - "insulations_tag": self.mesh.ps_insulation if flag_insulation and len(self.insulation.core_cond) == 4 else None + "insulations_tag": self.mesh.ps_insulation if flag_insulation and len( + self.insulation.core_cond) == 4 else None } # Core area -> Is needed to estimate the heat flux # Power density for volumes W/m^3 - core_area = self.calculate_core_volume() + #core_area = self.calculate_core_volume() + core_area = self.calculate_core_parts_volume() + #core_area = ff.calculate_cylinder_volume() + # Set wire radii wire_radii = [winding.conductor_radius for winding in self.windings] @@ -283,7 +289,7 @@ def thermal_simulation(self, thermal_conductivity_dict: Dict, boundary_temperatu "case_volume": self.core.r_outer * case_gap_top + self.core.core_h * case_gap_right + self.core.r_outer * case_gap_bot, "show_thermal_fem_results": show_thermal_simulation_results, "print_sensor_values": False, - "silent": self.verbosity == Verbosity.Silent, # Add verbosity for thermal simulation + "silent": self.verbosity == Verbosity.Silent, # Add verbosity for thermal simulation "flag_insulation": flag_insulation } @@ -323,7 +329,8 @@ def onelab_setup(self, is_gui: bool): return while onelab_path_wrong: - onelab_path = os.path.normpath(input("Enter the path of onelab's parent folder (path to folder which contains getdp, onelab executables): ")) + onelab_path = os.path.normpath(input( + "Enter the path of onelab's parent folder (path to folder which contains getdp, onelab executables): ")) if os.path.exists(onelab_path): onelab_path_wrong = False @@ -351,16 +358,16 @@ def high_level_geo_gen(self, frequency: float = None, skin_mesh_factor: float = self.mesh_data.update_data(frequency, skin_mesh_factor) # Create model - self.two_d_axi = TwoDaxiSymmetric(self.core, self.mesh_data, self.air_gaps, self.winding_windows, self.stray_path, - self.insulation, self.component_type, len(self.windings), self.verbosity, self.logger) + self.two_d_axi = TwoDaxiSymmetric(self.core, self.mesh_data, self.air_gaps, self.winding_windows, + self.stray_path, + self.insulation, self.component_type, len(self.windings), self.verbosity, + self.logger) self.two_d_axi.draw_model() - # Create mesh - self.mesh = Mesh(self.two_d_axi, self.windings, self.core.correct_outer_leg, self.file_data, self.verbosity, self.logger, None) - #self.mesh = Mesh(self.two_d_axi, self.windings, self.core.correct_outer_leg, self.file_data, None, ff.silent) - - + self.mesh = Mesh(self.two_d_axi, self.windings, self.core.correct_outer_leg, self.file_data, self.verbosity, + self.logger, None) + # self.mesh = Mesh(self.two_d_axi, self.windings, self.core.correct_outer_leg, self.file_data, None, ff.silent) def mesh(self, frequency: float = None, skin_mesh_factor: float = None): """Generates model and mesh. @@ -374,7 +381,6 @@ def mesh(self, frequency: float = None, skin_mesh_factor: float = None): self.mesh.generate_hybrid_mesh() # create the mesh itself with gmsh self.mesh.generate_electro_magnetic_mesh() # assign the physical entities/domains to the mesh - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Create Model def set_insulation(self, insulation: Insulation): @@ -433,18 +439,18 @@ def set_winding_windows(self, winding_windows: List[WindingWindow], mesh_accurac # print(f"{winding_window.virtual_winding_windows = }") # print(f"{windings = }") - self.windings = sorted(windings, key = lambda x: x.winding_number) + self.windings = sorted(windings, key=lambda x: x.winding_number) # Print statement was moved here so the silence functionality is not needed in Conductors class. # TODO Can this be even removed? for winding in self.windings: if winding.conductor_type == ConductorType.RoundLitz: self.femmt_print(f"Updated Litz Configuration: \n" - f" ff: {winding.ff} \n" - f" Number of layers/strands: {winding.n_layers}/{winding.n_strands} \n" - f" Strand radius: {winding.strand_radius} \n" - f" Conductor radius: {winding.conductor_radius}\n" - f"---") + f" ff: {winding.ff} \n" + f" Number of layers/strands: {winding.n_layers}/{winding.n_strands} \n" + f" Strand radius: {winding.strand_radius} \n" + f" Conductor radius: {winding.conductor_radius}\n" + f"---") # Set excitation parameter lists self.current = [None] * len(windings) @@ -511,14 +517,16 @@ def create_model(self, freq: float, skin_mesh_factor: float = 0.5, pre_visualize self.high_level_geo_gen(frequency=freq, skin_mesh_factor=skin_mesh_factor) high_level_geo_gen_time = time.time() - start_time start_time = time.time() - self.mesh.generate_hybrid_mesh(visualize_before=pre_visualize_geometry, save_png=save_png, color_scheme=color_scheme, colors_geometry=colors_geometry) + self.mesh.generate_hybrid_mesh(visualize_before=pre_visualize_geometry, save_png=save_png, + color_scheme=color_scheme, colors_geometry=colors_geometry) generate_hybrid_mesh_time = time.time() - start_time return high_level_geo_gen_time, generate_hybrid_mesh_time else: self.high_level_geo_gen(frequency=freq, skin_mesh_factor=skin_mesh_factor) - self.mesh.generate_hybrid_mesh(visualize_before=pre_visualize_geometry, save_png=save_png, color_scheme=color_scheme, colors_geometry=colors_geometry) - + self.mesh.generate_hybrid_mesh(visualize_before=pre_visualize_geometry, save_png=save_png, + color_scheme=color_scheme, colors_geometry=colors_geometry) + def get_single_complex_permeability(self): """ Function returns the complex permeability. @@ -527,10 +535,13 @@ def get_single_complex_permeability(self): """ if self.core.permeability_type == PermeabilityType.FromData: # take datasheet value from database - complex_permeability = mu_0 * mdb.MaterialDatabase(self.verbosity == Verbosity.Silent).get_material_attribute(material_name=self.core.material, attribute="initial_permeability") + complex_permeability = mu_0 * mdb.MaterialDatabase( + self.verbosity == Verbosity.Silent).get_material_attribute(material_name=self.core.material, + attribute="initial_permeability") self.femmt_print(f"{complex_permeability = }") if self.core.permeability_type == PermeabilityType.FixedLossAngle: - complex_permeability = mu_0 * self.core.mu_r_abs * complex(np.cos(np.deg2rad(self.core.phi_mu_deg)), np.sin(np.deg2rad(self.core.phi_mu_deg))) + complex_permeability = mu_0 * self.core.mu_r_abs * complex(np.cos(np.deg2rad(self.core.phi_mu_deg)), + np.sin(np.deg2rad(self.core.phi_mu_deg))) if self.core.permeability_type == PermeabilityType.RealValue: complex_permeability = mu_0 * self.core.mu_r_abs return complex_permeability @@ -546,25 +557,32 @@ def check_model_mqs_condition(self) -> None: :return: None """ if self.frequency != 0: - if self.core.permittivity["datasource"] == "measurements" or self.core.permittivity["datasource"] == "datasheet": - epsilon_r, epsilon_phi_deg = mdb.MaterialDatabase(self.verbosity == Verbosity.Silent).get_permittivity(temperature=self.core.temperature, frequency=self.frequency, - material_name=self.core.material, - datasource=self.core.permittivity["datasource"], - datatype=self.core.permittivity["datatype"], - measurement_setup=self.core.permittivity["measurement_setup"], - interpolation_type="linear") - - complex_permittivity = epsilon_0 * epsilon_r * complex(np.cos(np.deg2rad(epsilon_phi_deg)), np.sin(np.deg2rad(epsilon_phi_deg))) + if self.core.permittivity["datasource"] == "measurements" or self.core.permittivity[ + "datasource"] == "datasheet": + epsilon_r, epsilon_phi_deg = mdb.MaterialDatabase(self.verbosity == Verbosity.Silent).get_permittivity( + temperature=self.core.temperature, frequency=self.frequency, + material_name=self.core.material, + datasource=self.core.permittivity["datasource"], + datatype=self.core.permittivity["datatype"], + measurement_setup=self.core.permittivity["measurement_setup"], + interpolation_type="linear") + + complex_permittivity = epsilon_0 * epsilon_r * complex(np.cos(np.deg2rad(epsilon_phi_deg)), + np.sin(np.deg2rad(epsilon_phi_deg))) self.femmt_print(f"{complex_permittivity = }\n" f"{epsilon_r = }\n" f"{epsilon_phi_deg = }") - ff.check_mqs_condition(radius=self.core.core_inner_diameter/2, frequency=self.frequency, complex_permeability=self.get_single_complex_permeability(), - complex_permittivity=complex_permittivity, conductivity=self.core.sigma, relative_margin_to_first_resonance=0.5, silent=self.silent) + ff.check_mqs_condition(radius=self.core.core_inner_diameter / 2, frequency=self.frequency, + complex_permeability=self.get_single_complex_permeability(), + complex_permittivity=complex_permittivity, conductivity=self.core.sigma, + relative_margin_to_first_resonance=0.5, silent=self.silent) else: - ff.check_mqs_condition(radius=self.core.core_inner_diameter/2, frequency=self.frequency, complex_permeability=self.get_single_complex_permeability(), - complex_permittivity=0, conductivity=self.core.sigma, relative_margin_to_first_resonance=0.5, silent=self.silent) + ff.check_mqs_condition(radius=self.core.core_inner_diameter / 2, frequency=self.frequency, + complex_permeability=self.get_single_complex_permeability(), + complex_permittivity=0, conductivity=self.core.sigma, + relative_margin_to_first_resonance=0.5, silent=self.silent) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Miscellaneous @@ -581,7 +599,7 @@ def calculate_core_volume_with_air(self) -> float: core_width = self.core.r_outer - return np.pi * core_width**2 * core_height + return np.pi * core_width ** 2 * core_height def calculate_core_volume(self) -> float: """Calculates the volume of the core excluding air. @@ -589,12 +607,14 @@ def calculate_core_volume(self) -> float: :return: Volume of the core. :rtype: float """ + core_height = None + winding_height = None if self.core.core_type == CoreType.Single: core_height = self.core.window_h + self.core.core_inner_diameter / 2 winding_height = self.core.window_h elif self.core.core_type == CoreType.Stacked: - core_height = self.core.window_h_bot + self.core.window_h_top + self.core.core_inner_diameter * 3 / 4 # TODO: could also be done arbitrarily - winding_height = self.core.window_h_bot + self.core.window_h_top # TODO: could also be done arbitrarily + core_height = self.core.window_h_bot + self.core.window_h_top + self.core.core_inner_diameter * 3 / 4 # TODO: could also be done arbitrarily + winding_height = self.core.window_h_bot + self.core.window_h_top # TODO: could also be done arbitrarily core_width = self.core.r_outer @@ -602,13 +622,15 @@ def calculate_core_volume(self) -> float: air_gap_volume = 0 inner_leg_width = self.core.r_inner - winding_width + + for leg_position, position_value, height in self.air_gaps.midpoints: width = 0 if leg_position == AirGapLegPosition.LeftLeg.value: - # left leg - # TODO this is wrong since the air gap is not centered on the y axis - width = core_width - self.core.r_inner + # left leg + # TODO this is wrong since the air gap is not centered on the y axis + width = core_width - self.core.r_inner elif leg_position == AirGapLegPosition.CenterLeg.value: # center leg width = inner_leg_width @@ -619,9 +641,181 @@ def calculate_core_volume(self) -> float: else: raise Exception(f"Invalid leg position tag {leg_position} used for an air gap.") - air_gap_volume += np.pi * width**2 * height + air_gap_volume += np.pi * width ** 2 * height + + return np.pi * (core_width ** 2 * core_height - ( + inner_leg_width + winding_width) ** 2 * winding_height + inner_leg_width ** 2 * winding_height) - air_gap_volume + + + def calculate_core_parts_volume(self) -> list: + + """Calculates the volume of the core excluding air. + + :return: Volume of the core. + :rtype: list + """ + heights = [point[2] for point in self.air_gaps.midpoints] + core_part_volume = [] + + def get_width(part_number): + if self.stray_path: + if self.stray_path.start_index == 0: + if part_number == 2: + return self.core.core_inner_diameter / 2 + elif part_number == 3: + return self.stray_path.length + elif self.stray_path.start_index == 1: + if part_number == 2: + return self.stray_path.length + elif part_number == 3: + return self.core.core_inner_diameter / 2 + return self.core.core_inner_diameter / 2 + + if self.core.core_type == CoreType.Single: + if self.component_type == ComponentType.IntegratedTransformer: + + # Calculate heights dynamically + sorted_midpoints = sorted(self.air_gaps.midpoints, key=lambda x: x[1]) + #finding position of first airgap + bottommost_airgap_position = sorted_midpoints[0][1] + bottommost_airgap_height = sorted_midpoints[0][2] + #finding position of last airgap + topmost_airgap_position = sorted_midpoints[-1][1] + topmost_airgap_height = sorted_midpoints[-1][2] + # finding position to get the distance between two airgaps + second_topmost_airgap_position = sorted_midpoints[-2][1] + second_topmost_airgap_height = sorted_midpoints[-2][2] + # finding position to get the distance between two airgaps + third_topmost_airgap_position = sorted_midpoints[-3][1] + third_topmost_airgap_height = sorted_midpoints[-3][2] + + + + subpart1_1_height = bottommost_airgap_position + self.core.window_h / 2 - bottommost_airgap_height / 2 + self.core.core_inner_diameter / 4 + subpart1_1_width = self.core.core_inner_diameter / 2 + subpart1_1_volume = np.pi * subpart1_1_width ** 2 * subpart1_1_height + + #subpart2 + subpart1_2_height = self.core.core_inner_diameter / 4 + subpart1_2_width = self.core.window_w + subpart1_2_volume = np.pi * subpart1_2_width ** 2 * subpart1_2_height + + #subpart2 + subpart1_3_height = self.core.window_h + self.core.core_inner_diameter / 2 + subpart1_3_width = self.core.r_outer - self.core.r_inner + subpart1_3_volume = np.pi * subpart1_3_width ** 2 * subpart1_3_height + + #subpart4 + subpart1_4_height = self.core.core_inner_diameter / 4 + subpart1_4_width = self.core.window_w + subpart1_4_volume = np.pi * subpart1_4_width ** 2 * subpart1_4_height + + #subpart1_5_height = self.air_gaps.midpoints[self.stray_path.start_index+1][1] - self.air_gaps.midpoints[self.stray_path.start_index+1][2] / 2 + subpart1_5_height = self.core.window_h / 2 - topmost_airgap_position - topmost_airgap_height / 2 + self.core.core_inner_diameter / 4 + subpart1_5_width = self.core.core_inner_diameter / 2 + subpart1_5_volume = np.pi * subpart1_5_width ** 2 * subpart1_5_height + + core_part_1_volume = subpart1_1_volume + subpart1_2_volume + subpart1_3_volume + subpart1_4_volume + subpart1_5_volume + core_part_volume.append(core_part_1_volume) + + # #core_part_2 + if len(sorted_midpoints) > 1: + core_part_2_height = topmost_airgap_position - topmost_airgap_height / 2 - (second_topmost_airgap_position + second_topmost_airgap_height / 2) + core_part_2_width = get_width(2) + + core_part_2_volume = np.pi * core_part_2_width ** 2 * core_part_2_height + core_part_volume.append(core_part_2_volume) - return np.pi*(core_width**2 * core_height - (inner_leg_width+winding_width)**2 * winding_height + inner_leg_width**2 * winding_height) - air_gap_volume + #core_part_3 + if len(sorted_midpoints) > 2: + core_part_3_height = second_topmost_airgap_position - second_topmost_airgap_height / 2 - (third_topmost_airgap_position + third_topmost_airgap_height / 2) + core_part_3_width = get_width(3) + + core_part_3_volume = np.pi * core_part_3_width ** 2 * core_part_3_height + core_part_volume.append(core_part_3_volume) + + + return core_part_volume + + + else: + return [self.calculate_core_volume()] + + elif self.core.core_type == CoreType.Stacked: + + + # core_part_1 + # core_part_1 is divided into 3 subparts + # subpart_1 + subpart1_1_height = self.core.window_h_bot / 2 + self.core.core_inner_diameter / 4 - heights[0] / 2 + subpart1_1_width = self.core.core_inner_diameter / 2 + subpart1_1_volume = np.pi * subpart1_1_width ** 2 * subpart1_1_height + + # subpart_2 + subpart1_2_height = self.core.core_inner_diameter / 4 + subpart1_2_width = self.core.window_w + subpart1_2_volume = np.pi * subpart1_2_width ** 2 * subpart1_2_height + + # subpart 3 + subpart1_3_height = self.core.window_h_bot + self.core.core_inner_diameter / 4 + subpart1_3_width = self.core.r_outer - self.core.r_inner + subpart1_3_volume = np.pi * subpart1_3_width ** 2 * subpart1_3_height + + core_part_1_volume = subpart1_1_volume + subpart1_2_volume + subpart1_3_volume + core_part_volume.append(core_part_1_volume) + + # core_part_2 + core_part_2_height = self.core.window_h_bot / 2 - heights[0] / 2 + core_part_2_width = self.core.core_inner_diameter / 2 + core_part_2_volume = np.pi * core_part_2_width ** 2 * core_part_2_height + core_part_volume.append(core_part_2_volume) + + # core_part_3 + core_part_3_height = self.core.core_inner_diameter / 4 + core_part_3_width = self.core.r_inner + core_part_3_volume = np.pi * core_part_3_width ** 2 * core_part_3_height + core_part_volume.append(core_part_3_volume) + + # core_part_4 + core_part_4_height = self.core.core_inner_diameter / 4 + core_part_4_width = self.core.r_outer - self.core.r_inner + core_part_4_volume = np.pi * core_part_4_width ** 2 * core_part_4_height + core_part_volume.append(core_part_4_volume) + + # core_part_5 + # core_part_5 is divided into 3 parts + # subpart_1 + subpart5_1_height = self.core.window_h_top + self.core.core_inner_diameter / 4 - heights[1] / 2 + subpart5_1_width = self.core.r_inner - self.core.window_w + subpart5_1_volume = np.pi * subpart5_1_width ** 2 * subpart5_1_height + + # subpart_2 + subpart5_2_height = self.core.core_inner_diameter / 4 + subpart5_2_width = self.core.window_w + subpart5_2_volume = np.pi * subpart5_2_width ** 2 * subpart5_2_height + + # subpart 3 + subpart5_3_height = self.core.window_h_top + self.core.core_inner_diameter / 4 + subpart5_3_width = self.core.r_outer - self.core.r_inner + subpart5_3_volume = np.pi * subpart5_3_width ** 2 * subpart5_3_height + + core_part_5_volume = subpart5_1_volume + subpart5_2_volume + subpart5_3_volume + core_part_volume.append(core_part_5_volume) + + return core_part_volume + # if self.core.core_type == CoreType.Single: + # cylinder_height = self.core.window_h + self.core.core_inner_diameter / 2 + # elif self.core.core_type == CoreType.Stacked: + # cylinder_height = self.core.window_h_bot + self.core.window_h_top + self.core.core_inner_diameter * 3 / 4 + # cylinder_diameter = self.core.r_outer + # + # core_volumes = [] # Initialize list to store each volume + # + # for _ in self.mesh.plane_surface_core: + # volume = ff.calculate_cylinder_volume(cylinder_diameter, cylinder_height) + # core_volumes.append(volume) + # + # return core_volumes # Return the list of volumes def calculate_core_weight(self) -> float: """ @@ -630,29 +824,53 @@ def calculate_core_weight(self) -> float: """ if self.core.material == 'custom': volumetric_mass_density = 0 - warnings.warn("Volumetric mass density not implemented for custom cores. Returns '0' in log-file: Core cost will also result to 0.") + warnings.warn( + "Volumetric mass density not implemented for custom cores. Returns '0' in log-file: Core cost will also result to 0.") else: - volumetric_mass_density = self.core.material_database.get_material_attribute(material_name=self.core.material, attribute="volumetric_mass_density") + volumetric_mass_density = self.core.material_database.get_material_attribute( + material_name=self.core.material, attribute="volumetric_mass_density") return self.calculate_core_volume() * volumetric_mass_density + def get_wire_distances(self) -> List[List[float]]: """Helper function which returns the distance (radius) of each conductor to the y-axis :return: Wire distances :rtype: List[List[float]] """ + # wire_distance = [] + # for winding in self.two_d_axi.p_conductor: + # # 5 points are for 1 wire + # num_points = len(winding) + # num_windings = num_points // 5 + # winding_list = [] + # for i in range(num_windings): + # winding_list.append(winding[i * 5][0]) + # wire_distance.append(winding_list) + # + # return wire_distance + wire_distance = [] - for winding in self.two_d_axi.p_conductor: - # 5 points are for 1 wire - num_points = len(winding) - num_windings = num_points//5 + for num, conductor in enumerate(self.two_d_axi.p_conductor): + # Check if the winding is parallel and calculate points accordingly + if self.windings[num].parallel: # as in center_tapped transformer, RectangularSolid is used in parallel winding + num_points = len(conductor) + num_turns = num_points // 4 + point_increment = 4 + else: + num_points = len(conductor) + num_turns = num_points // 5 + point_increment = 5 + winding_list = [] - for i in range(num_windings): - winding_list.append(winding[i*5][0]) + for i in range(num_turns): + winding_list.append(conductor[i * point_increment][0]) wire_distance.append(winding_list) return wire_distance + + def calculate_wire_lengths(self) -> List[float]: distances = self.get_wire_distances() lengths = [] @@ -688,7 +906,8 @@ def calculate_wire_volumes(self) -> List[float]: if wrap_para_type == WrapParaType.FixedThickness: cross_section_area = self.core.window_h * winding.thickness elif wrap_para_type == WrapParaType.Interpolate: - cross_section_area = self.core.window_h * self.core.window_w / vww.turns[vww_index] + cross_section_area = self.core.window_h * self.core.window_w / vww.turns[ + vww_index] else: raise Exception(f"Unknown wrap para type {wrap_para_type}") else: @@ -748,16 +967,16 @@ def excitation(self, frequency: float, amplitude_list: List, phase_deg_list: Lis "Negative currents are not allowed. Use the phase + 180 degree to generate a negative current.") self.femmt_print(f"\n---\n" - f"Excitation: \n" - f"Frequency: {frequency}\n" - f"Current(s): {amplitude_list}\n" - f"Phase(s): {phase_deg_list}\n") - + f"Excitation: \n" + f"Frequency: {frequency}\n" + f"Current(s): {amplitude_list}\n" + f"Phase(s): {phase_deg_list}\n") # -- Excitation -- self.flag_excitation_type = ex_type # 'current', 'current_density', 'voltage' if self.core.permeability["datasource"] != MaterialDataSource.Custom: - self.core.update_core_material_pro_file(frequency, self.file_data.electro_magnetic_folder_path, plot_interpolation) # frequency update to core class + self.core.update_core_material_pro_file(frequency, self.file_data.electro_magnetic_folder_path, + plot_interpolation) # frequency update to core class if self.core.permittivity["datasource"] != MaterialDataSource.Custom: self.core.update_sigma(frequency) # Has the user provided a list of phase angles? @@ -779,8 +998,8 @@ def excitation(self, frequency: float, amplitude_list: List, phase_deg_list: Lis else: self.phase_deg = phase_deg_list # Define complex current phasor as excitation - self.current[num] = complex(amplitude_list[num]*np.cos(np.deg2rad(phase_deg_list[num])), - amplitude_list[num]*np.sin(np.deg2rad(phase_deg_list[num]))) + self.current[num] = complex(amplitude_list[num] * np.cos(np.deg2rad(phase_deg_list[num])), + amplitude_list[num] * np.sin(np.deg2rad(phase_deg_list[num]))) # Imposed current density if self.flag_excitation_type == 'current_density': @@ -790,7 +1009,6 @@ def excitation(self, frequency: float, amplitude_list: List, phase_deg_list: Lis if self.flag_excitation_type == 'voltage': raise NotImplementedError - # -- Frequency -- self.frequency = frequency # in Hz @@ -802,7 +1020,8 @@ def excitation(self, frequency: float, amplitude_list: List, phase_deg_list: Lis self.red_freq.append([]) if self.frequency != 0: - self.delta = np.sqrt(2 / (2 * self.frequency * np.pi * self.windings[0].cond_sigma * mu_0)) # TODO: distinguish between material conductivities + self.delta = np.sqrt(2 / (2 * self.frequency * np.pi * self.windings[ + 0].cond_sigma * mu_0)) # TODO: distinguish between material conductivities for num in range(len(self.windings)): if self.windings[num].conductor_type == ConductorType.RoundLitz: self.red_freq[num] = self.windings[num].strand_radius / self.delta @@ -811,7 +1030,8 @@ def excitation(self, frequency: float, amplitude_list: List, phase_deg_list: Lis else: self.femmt_print("Reduced Frequency does not have a physical value here") self.femmt_print(self.windings[num].conductor_type) - self.red_freq[num] = 1 # TODO: doesn't make sense like this -> rewrite fore conductor windings shape + self.red_freq[ + num] = 1 # TODO: doesn't make sense like this -> rewrite fore conductor windings shape else: # DC case self.delta = 1e20 # random huge value @@ -823,8 +1043,8 @@ def simulate(self): Initializes an onelab client. Provides the GetDP based solver with the created mesh file. """ self.femmt_print(f"\n---\n" - f"Initialize ONELAB API\n" - f"Run Simulation\n") + f"Initialize ONELAB API\n" + f"Run Simulation\n") # -- Simulation -- # create a new onelab client @@ -848,7 +1068,8 @@ def simulate(self): # Run simulations as sub clients (non-blocking??) getdp_filepath = os.path.join(self.file_data.onelab_folder_path, "getdp") - self.onelab_client.runSubClient("myGetDP", getdp_filepath + " " + solver + " -msh " + self.file_data.e_m_mesh_file + " -solve Analysis -v2 " + verbose + to_file_str) + self.onelab_client.runSubClient("myGetDP", + getdp_filepath + " " + solver + " -msh " + self.file_data.e_m_mesh_file + " -solve Analysis -v2 " + verbose + to_file_str) def write_simulation_parameters_to_pro_files(self): """ @@ -862,7 +1083,7 @@ def write_simulation_parameters_to_pro_files(self): """ # All shared control variables and parameters are passed to a temporary Prolog file self.femmt_print(f"\n---\n" - f"Write simulation parameters to .pro files (file communication).\n") + f"Write simulation parameters to .pro files (file communication).\n") # Write initialization parameters for simulation in 'Parameter.pro' file self.write_electro_magnetic_parameter_pro() @@ -885,7 +1106,7 @@ def overwrite_conductors_with_air(self, physical_surfaces_to_overwrite: list): for ps in physical_surfaces_to_overwrite: # mesh_data = mesh_data.replace(f'1 {ps} 4', f'1 {ps+1000000} 4') - mesh_data = mesh_data.replace(f'1 {ps} 4', f'1 {ps+1000000} 4') + mesh_data = mesh_data.replace(f'1 {ps} 4', f'1 {ps + 1000000} 4') with open(os.path.join(os.path.join(self.file_data.e_m_mesh_file)), "w") as mesh_file: mesh_file.write(mesh_data) @@ -904,13 +1125,14 @@ def overwrite_air_conductors_with_conductors(self, physical_surfaces_to_overwrit mesh_data = mesh_file.read() for ps in physical_surfaces_to_overwrite: - mesh_data = mesh_data.replace(f'1 {ps} 4', f'1 {ps-1000000} 4') + mesh_data = mesh_data.replace(f'1 {ps} 4', f'1 {ps - 1000000} 4') with open(os.path.join(os.path.join(self.file_data.e_m_mesh_file)), "w") as mesh_file: mesh_file.write(mesh_data) def single_simulation(self, freq: float, current: List[float], phi_deg: List[float] = None, - plot_interpolation: bool = False, show_fem_simulation_results: bool = True, benchmark: bool = False): + plot_interpolation: bool = False, show_fem_simulation_results: bool = True, + benchmark: bool = False): """ Start a _single_ electromagnetic ONELAB simulation. @@ -933,7 +1155,6 @@ def single_simulation(self, freq: float, current: List[float], phi_deg: List[flo raise ValueError( "Negative currents are not allowed. Use the phase + 180 degree to generate a negative current.") - phi_deg = phi_deg or [] if benchmark: start_time = time.time() @@ -941,7 +1162,8 @@ def single_simulation(self, freq: float, current: List[float], phi_deg: List[flo generate_electro_magnetic_mesh_time = time.time() - start_time start_time = time.time() - self.excitation(frequency=freq, amplitude_list=current, phase_deg_list=phi_deg, plot_interpolation=plot_interpolation) # frequency and current + self.excitation(frequency=freq, amplitude_list=current, phase_deg_list=phi_deg, + plot_interpolation=plot_interpolation) # frequency and current self.check_model_mqs_condition() self.write_simulation_parameters_to_pro_files() self.generate_load_litz_approximation_parameters() @@ -971,7 +1193,6 @@ def single_simulation(self, freq: float, current: List[float], phi_deg: List[flo if show_fem_simulation_results: self.visualize() - def excitation_sweep(self, frequency_list: List, current_list_list: List, phi_deg_list_list: List, show_last_fem_simulation: bool = False, excitation_meshing_type: ExcitationMeshingType = None, skin_mesh_factor: float = 0.5, @@ -1047,11 +1268,13 @@ def excitation_sweep(self, frequency_list: List, current_list_list: List, phi_de if excitation_meshing_type == ExcitationMeshingType.MeshEachFrequency: for count_frequency, _ in enumerate(frequency_list): self.high_level_geo_gen(frequency=frequency_list[count_frequency], skin_mesh_factor=skin_mesh_factor) - self.mesh.generate_hybrid_mesh(color_scheme, colors_geometry, visualize_before=visualize_before, save_png=save_png) + self.mesh.generate_hybrid_mesh(color_scheme, colors_geometry, visualize_before=visualize_before, + save_png=save_png) self.mesh.generate_electro_magnetic_mesh() - self.excitation(frequency=frequency_list[count_frequency], amplitude_list=current_list_list[count_frequency], - phase_deg_list=phi_deg_list_list[count_frequency]) # frequency and current + self.excitation(frequency=frequency_list[count_frequency], + amplitude_list=current_list_list[count_frequency], + phase_deg_list=phi_deg_list_list[count_frequency]) # frequency and current if count_frequency == 0: self.check_model_mqs_condition() self.write_simulation_parameters_to_pro_files() self.generate_load_litz_approximation_parameters() @@ -1063,13 +1286,14 @@ def excitation_sweep(self, frequency_list: List, current_list_list: List, phi_de self.high_level_geo_gen(frequency=min(frequency_list), skin_mesh_factor=skin_mesh_factor) else: raise Exception(f"Unknown excitation meshing type {excitation_meshing_type}") - self.mesh.generate_hybrid_mesh(color_scheme, colors_geometry, visualize_before=visualize_before, save_png=save_png) + self.mesh.generate_hybrid_mesh(color_scheme, colors_geometry, visualize_before=visualize_before, + save_png=save_png) self.mesh.generate_electro_magnetic_mesh() - check_model_mqs_condition_already_performerd = False for count_frequency, value_frequency in enumerate(range(0, len(frequency_list))): - self.excitation(frequency=frequency_list[count_frequency], amplitude_list=current_list_list[count_frequency], + self.excitation(frequency=frequency_list[count_frequency], + amplitude_list=current_list_list[count_frequency], phase_deg_list=phi_deg_list_list[count_frequency]) # frequency and current if value_frequency != 0 and not check_model_mqs_condition_already_performerd: self.check_model_mqs_condition() @@ -1101,7 +1325,6 @@ def component_study(self, time_current_vectors: List[List[List[float]]], fft_fil hyst_loss_phases_deg = [] hyst_frequency = 1 / (time_current_vectors[0][0][-1]) for time_current_vector in time_current_vectors: - # collect winding losses simulation input parameters [frequency_list, amplitude, phi_rad] = ff.fft(time_current_vector, mode='time', filter_value_factor=fft_filter_value_factor) phi_deg = np.rad2deg(phi_rad) @@ -1109,11 +1332,13 @@ def component_study(self, time_current_vectors: List[List[List[float]]], fft_fil # collect hysteresis loss simulation input parameters hyst_loss_amplitudes.append(fr.max_value_from_value_vec(time_current_vector[1])[0]) - hyst_loss_phases_deg.append(fr.phases_deg_from_time_current(time_current_vector[0], time_current_vector[1])[0]) + hyst_loss_phases_deg.append( + fr.phases_deg_from_time_current(time_current_vector[0], time_current_vector[1])[0]) # check if all frequency vectors include the same frequencies for count in range(len(frequency_current_phase_deg_list) - 1): - if not np.array_equal(frequency_current_phase_deg_list[count][0],frequency_current_phase_deg_list[count + 1][0]): + if not np.array_equal(frequency_current_phase_deg_list[count][0], + frequency_current_phase_deg_list[count + 1][0]): raise ValueError("Frequency vectors for different currents are not the same!") # transfer format from fft()-output to excitation_sweep()-input @@ -1129,7 +1354,7 @@ def component_study(self, time_current_vectors: List[List[List[float]]], fft_fil phi_deg_list_list.append(phi_deg_single_frequency) # get the inductance - inductance_dict = self.get_inductances(I0=1, op_frequency=hyst_frequency, skin_mesh_factor = 1) + inductance_dict = self.get_inductances(I0=1, op_frequency=hyst_frequency, skin_mesh_factor=1) # calculate hysteresis losses # use a single simulation @@ -1191,12 +1416,13 @@ def hysteresis_loss_excitation(input_time_current_vectors): for time_current_vector in input_time_current_vectors: # collect hysteresis loss simulation input parameters hyst_loss_amplitudes.append(fr.max_value_from_value_vec(time_current_vector[1])[0]) - hyst_loss_phases_deg.append(fr.phases_deg_from_time_current(time_current_vector[0], time_current_vector[1])[0]) + hyst_loss_phases_deg.append( + fr.phases_deg_from_time_current(time_current_vector[0], time_current_vector[1])[0]) return hyst_frequency, hyst_loss_amplitudes, hyst_loss_phases_deg def split_hysteresis_loss_excitation_center_tapped(hyst_frequency, hyst_loss_amplitudes, hyst_loss_phases_deg): # print(f"{hyst_frequency, hyst_loss_amplitudes, hyst_loss_phases_deg = }") - hyst_loss_amplitudes[-1] = hyst_loss_amplitudes[-1]/2 + hyst_loss_amplitudes[-1] = hyst_loss_amplitudes[-1] / 2 hyst_loss_amplitudes.append(hyst_loss_amplitudes[-1]) hyst_loss_phases_deg.append(hyst_loss_phases_deg[-1]) # print(f"{hyst_frequency, hyst_loss_amplitudes, hyst_loss_phases_deg = }") @@ -1250,19 +1476,24 @@ def linear_loss_excitation(time_current_vectors: List[List[List[float]]], fft_fi # TODO: recalculate the fft at the "missing frequencies and add their values... all_frequencies = set() for count in range(len(frequency_current_phase_deg_list) - 1): - if not np.array_equal(frequency_current_phase_deg_list[count][0],frequency_current_phase_deg_list[count + 1][0]): + if not np.array_equal(frequency_current_phase_deg_list[count][0], + frequency_current_phase_deg_list[count + 1][0]): # raise ValueError("Frequency vectors for different currents are not the same!") # print("Frequency vectors for different currents are not the same!") - all_frequencies = all_frequencies | set(frequency_current_phase_deg_list[count][0]) | set(frequency_current_phase_deg_list[count + 1][0]) + all_frequencies = all_frequencies | set(frequency_current_phase_deg_list[count][0]) | set( + frequency_current_phase_deg_list[count + 1][0]) # print(f"Original: {frequency_current_phase_deg_list = }") for frequency in list(all_frequencies): for count in range(0, len(frequency_current_phase_deg_list)): if frequency not in frequency_current_phase_deg_list[count][0]: ii = np.searchsorted(frequency_current_phase_deg_list[count][0], frequency) - frequency_current_phase_deg_list[count][0] = np.insert(frequency_current_phase_deg_list[count][0], ii, frequency) - frequency_current_phase_deg_list[count][1] = np.insert(frequency_current_phase_deg_list[count][1], ii, 0) - frequency_current_phase_deg_list[count][2] = np.insert(frequency_current_phase_deg_list[count][2], ii, 0) + frequency_current_phase_deg_list[count][0] = np.insert( + frequency_current_phase_deg_list[count][0], ii, frequency) + frequency_current_phase_deg_list[count][1] = np.insert( + frequency_current_phase_deg_list[count][1], ii, 0) + frequency_current_phase_deg_list[count][2] = np.insert( + frequency_current_phase_deg_list[count][2], ii, 0) # print(f"Corrected: {frequency_current_phase_deg_list = }") return frequency_list, frequency_current_phase_deg_list @@ -1288,12 +1519,15 @@ def linear_loss_excitation(time_current_vectors: List[List[List[float]]], fft_fi # Hysteresis Loss Excitation time_current_vectors[1][1] = time_current_vectors[1][1] * (-1) hyst_frequency, hyst_loss_amplitudes, hyst_loss_phases_deg = hysteresis_loss_excitation(time_current_vectors) - hyst_frequency, hyst_loss_amplitudes, hyst_loss_phases_deg = split_hysteresis_loss_excitation_center_tapped(hyst_frequency, hyst_loss_amplitudes, hyst_loss_phases_deg) + hyst_frequency, hyst_loss_amplitudes, hyst_loss_phases_deg = split_hysteresis_loss_excitation_center_tapped( + hyst_frequency, hyst_loss_amplitudes, hyst_loss_phases_deg) center_tapped_study_excitation["hysteresis"]["frequency"] = hyst_frequency if plot_waveforms: - i_1 = hyst_loss_amplitudes[0] * np.cos(time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[0])) - i_2 = hyst_loss_amplitudes[1] * np.cos(time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[1])) + i_1 = hyst_loss_amplitudes[0] * np.cos( + time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[0])) + i_2 = hyst_loss_amplitudes[1] * np.cos( + time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[1])) plt.plot(time_current_vectors[0][0], i_1, label="i_1") plt.plot(time_current_vectors[0][0], i_2, "-", label="i_2") plt.xlabel("time / s") @@ -1304,7 +1538,8 @@ def linear_loss_excitation(time_current_vectors: List[List[List[float]]], fft_fi # calculate hysteresis losses in the xfmr xfmr_scale = 1.7 - center_tapped_study_excitation["hysteresis"]["transformer"]["current_amplitudes"] = list(np.array(hyst_loss_amplitudes) * xfmr_scale) + center_tapped_study_excitation["hysteresis"]["transformer"]["current_amplitudes"] = list( + np.array(hyst_loss_amplitudes) * xfmr_scale) center_tapped_study_excitation["hysteresis"]["transformer"]["current_phases_deg"] = hyst_loss_phases_deg # calculate hysteresis losses in the choke @@ -1319,9 +1554,12 @@ def linear_loss_excitation(time_current_vectors: List[List[List[float]]], fft_fi frequency_list, frequency_current_phase_deg_list = linear_loss_excitation(time_current_vectors, fft_filter_value_factor) if plot_waveforms: - i_1 = hyst_loss_amplitudes[0] * np.cos(time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[0])) - i_2 = hyst_loss_amplitudes[1] * np.cos(time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[1])) - i_3 = hyst_loss_amplitudes[2] * np.cos(time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[2])) + i_1 = hyst_loss_amplitudes[0] * np.cos( + time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[0])) + i_2 = hyst_loss_amplitudes[1] * np.cos( + time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[1])) + i_3 = hyst_loss_amplitudes[2] * np.cos( + time_current_vectors[0][0] * 2 * np.pi * hyst_frequency - np.deg2rad(hyst_loss_phases_deg[2])) plt.plot(time_current_vectors[0][0], i_1, label="i_1") plt.plot(time_current_vectors[0][0], i_2, "-", label="i_2") plt.plot(time_current_vectors[0][0], i_3, "--", label="i_3") @@ -1367,9 +1605,8 @@ def factor_triangular_hysteresis_loss_iGSE(D, alpha): denominator = np.pi ** (alpha - 1) * np.trapz(integrant, x=theta) return nominator / denominator - # get the inductance - inductance_dict = self.get_inductances(I0=1, skin_mesh_factor = 1, + inductance_dict = self.get_inductances(I0=1, skin_mesh_factor=1, op_frequency=center_tapped_study_excitation["hysteresis"]["frequency"], silent=self.silent) @@ -1377,12 +1614,13 @@ def factor_triangular_hysteresis_loss_iGSE(D, alpha): p_hyst = 0 # print(f"{p_hyst = }") - ps_primary_coil_turns = [150000 + i for i in range(number_primary_coil_turns)] self.overwrite_conductors_with_air(ps_primary_coil_turns) self.excitation(frequency=center_tapped_study_excitation["hysteresis"]["frequency"], - amplitude_list=center_tapped_study_excitation["hysteresis"]["transformer"]["current_amplitudes"], - phase_deg_list=center_tapped_study_excitation["hysteresis"]["transformer"]["current_phases_deg"], + amplitude_list=center_tapped_study_excitation["hysteresis"]["transformer"][ + "current_amplitudes"], + phase_deg_list=center_tapped_study_excitation["hysteresis"]["transformer"][ + "current_phases_deg"], plot_interpolation=False) self.write_simulation_parameters_to_pro_files() self.generate_load_litz_approximation_parameters() @@ -1405,7 +1643,7 @@ def factor_triangular_hysteresis_loss_iGSE(D, alpha): ps_primary_coil_turns = [150000 + i for i in range(number_primary_coil_turns)] - self.overwrite_air_conductors_with_conductors(list(np.array(ps_primary_coil_turns)+1000000)) + self.overwrite_air_conductors_with_conductors(list(np.array(ps_primary_coil_turns) + 1000000)) self.excitation(frequency=center_tapped_study_excitation["hysteresis"]["frequency"], amplitude_list=center_tapped_study_excitation["hysteresis"]["choke"]["current_amplitudes"], phase_deg_list=center_tapped_study_excitation["hysteresis"]["choke"]["current_phases_deg"], @@ -1457,13 +1695,16 @@ def get_inductances(self, I0: float, op_frequency: float = 0, skin_mesh_factor: :type silent: bool """ if len(self.windings) == 1: - raise NotImplementedError("For inductor, this function will not be implemented. See 'flux_over_current' in 'log_electro_magnetic.json' ") + raise NotImplementedError( + "For inductor, this function will not be implemented. See 'flux_over_current' in 'log_electro_magnetic.json' ") else: # Data-generation with FEM simulations self.high_level_geo_gen(frequency=op_frequency, skin_mesh_factor=skin_mesh_factor) - frequencies, currents, phases = ff.create_open_circuit_excitation_sweep(I0, len(self.windings), op_frequency) - self.excitation_sweep(frequency_list=frequencies, current_list_list=currents, phi_deg_list_list=phases, show_last_fem_simulation=visualize_last_fem_simulation) + frequencies, currents, phases = ff.create_open_circuit_excitation_sweep(I0, len(self.windings), + op_frequency) + self.excitation_sweep(frequency_list=frequencies, current_list_list=currents, phi_deg_list_list=phases, + show_last_fem_simulation=visualize_last_fem_simulation) # Post-Processing log = self.read_log() @@ -1535,23 +1776,23 @@ def get_inductances(self, I0: float, op_frequency: float = 0, skin_mesh_factor: self.L_h_conc = self.M ** 2 / self.L_2_2 self.femmt_print(f"\n" - f"T-ECD (primary side concentrated):\n" - f"[Underdetermined System: n := M / L_2_2 --> L_s2 = L_2_2 - M / n = 0]\n" - f" - Transformation Ratio: n\n" - f" - (Primary) Stray Inductance: L_s1\n" - f" - Primary Side Main Inductance: L_h\n" - f"n := M / L_2_2 = k * Sqrt(L_1_1 / L_2_2) = {self.n_conc}\n" - f"L_s1 = (1 - k^2) * L_1_1 = {self.L_s_conc}\n" - f"L_h = M^2 / L_2_2 = k^2 * L_1_1 = {self.L_h_conc}\n" - ) - - inductance = TransformerInductance( - l_h_conc = self.L_h_conc, - l_s_conc = self.L_s_conc, - n_conc = self.n_conc, - M = self.M, - L_1_1 = self.L_1_1, - L_2_2 = self.L_2_2, + f"T-ECD (primary side concentrated):\n" + f"[Underdetermined System: n := M / L_2_2 --> L_s2 = L_2_2 - M / n = 0]\n" + f" - Transformation Ratio: n\n" + f" - (Primary) Stray Inductance: L_s1\n" + f" - Primary Side Main Inductance: L_h\n" + f"n := M / L_2_2 = k * Sqrt(L_1_1 / L_2_2) = {self.n_conc}\n" + f"L_s1 = (1 - k^2) * L_1_1 = {self.L_s_conc}\n" + f"L_h = M^2 / L_2_2 = k^2 * L_1_1 = {self.L_h_conc}\n" + ) + + inductance = TransformerInductance( + l_h_conc=self.L_h_conc, + l_s_conc=self.L_s_conc, + n_conc=self.n_conc, + M=self.M, + L_1_1=self.L_1_1, + L_2_2=self.L_2_2, ) return dataclasses.asdict(inductance) @@ -1572,35 +1813,35 @@ def get_inductances(self, I0: float, op_frequency: float = 0, skin_mesh_factor: self.L_s2 = self.L_2_2 - (self.M_12 * self.M_23) / self.M_13 self.L_s3 = self.L_3_3 - (self.M_13 * self.M_23) / self.M_12 self.L_h = (self.M_12 * self.M_13) / self.M_23 - self.n_12 = np.sqrt(self.L_1_1/self.L_2_2) # self.M_13 / self.M_23 - self.n_13 = np.sqrt(self.L_1_1/self.L_3_3) # self.M_12 / self.M_23 - self.n_23 = np.sqrt(self.L_2_2/self.L_3_3) + self.n_12 = np.sqrt(self.L_1_1 / self.L_2_2) # self.M_13 / self.M_23 + self.n_13 = np.sqrt(self.L_1_1 / self.L_3_3) # self.M_12 / self.M_23 + self.n_23 = np.sqrt(self.L_2_2 / self.L_3_3) # Shortcut Inductances - self.L_s12 = self.L_s1 + self.n_12**2 * self.L_s2 - self.L_s13 = self.L_s1 + self.n_13**2 * self.L_s3 - self.L_s23 = self.L_s2 + (self.n_13/self.n_12)**2 * self.L_s3 + self.L_s12 = self.L_s1 + self.n_12 ** 2 * self.L_s2 + self.L_s13 = self.L_s1 + self.n_13 ** 2 * self.L_s3 + self.L_s23 = self.L_s2 + (self.n_13 / self.n_12) ** 2 * self.L_s3 self.femmt_print(f"\n" - f"T-ECD (Lh on primary side):\n" - f" - Primary Side Stray Inductance: L_s1\n" - f" - Secondary Side Stray Inductance: L_s2\n" - f" - Tertiary Side Stray Inductance: L_s3\n" - f" - Transformation Ratio with respect to the primary and the Secondary: n2\n" - f" - Transformation Ratio with respect to the primary and the Tertiary: n3\n" - f" - Primary Side Main Inductance: L_h\n" - f"L_s1 = L_1_1 - M_12 * M_13 / M_23 = {self.L_s1}\n" - f"L_s2 = L_2_2 - M_12 * M_23 / M_13 = {self.L_s2}\n" - f"L_s3 = L_3_3 - M_13 * M_23 / M_12 = {self.L_s3}\n" - f"n_12 = np.sqrt(self.L_1_1/self.L_2_2) = {self.n_12}\n" - f"n_13 = np.sqrt(self.L_1_1/self.L_3_3) = {self.n_13}\n" - f"n_23 = np.sqrt(self.L_2_2/self.L_3_3) = {self.n_23}\n" - f"L_h = M_12 * M_13 / M_23 = {self.L_h}\n\n" - f"Shortcut Inductances L_snm measured on winding n with short applied to winding m\n" - f"L_s12 = L_s1 + n_12**2 * L_s2 = {self.L_s12}\n" - f"L_s13 = L_s1 + n_13**2 * L_s3 = {self.L_s13}\n" - f"L_s23 = L_s2 + (n_13/n_12)**2 * L_s3 = {self.L_s23}\n" - ) + f"T-ECD (Lh on primary side):\n" + f" - Primary Side Stray Inductance: L_s1\n" + f" - Secondary Side Stray Inductance: L_s2\n" + f" - Tertiary Side Stray Inductance: L_s3\n" + f" - Transformation Ratio with respect to the primary and the Secondary: n2\n" + f" - Transformation Ratio with respect to the primary and the Tertiary: n3\n" + f" - Primary Side Main Inductance: L_h\n" + f"L_s1 = L_1_1 - M_12 * M_13 / M_23 = {self.L_s1}\n" + f"L_s2 = L_2_2 - M_12 * M_23 / M_13 = {self.L_s2}\n" + f"L_s3 = L_3_3 - M_13 * M_23 / M_12 = {self.L_s3}\n" + f"n_12 = np.sqrt(self.L_1_1/self.L_2_2) = {self.n_12}\n" + f"n_13 = np.sqrt(self.L_1_1/self.L_3_3) = {self.n_13}\n" + f"n_23 = np.sqrt(self.L_2_2/self.L_3_3) = {self.n_23}\n" + f"L_h = M_12 * M_13 / M_23 = {self.L_h}\n\n" + f"Shortcut Inductances L_snm measured on winding n with short applied to winding m\n" + f"L_s12 = L_s1 + n_12**2 * L_s2 = {self.L_s12}\n" + f"L_s13 = L_s1 + n_13**2 * L_s3 = {self.L_s13}\n" + f"L_s23 = L_s2 + (n_13/n_12)**2 * L_s3 = {self.L_s23}\n" + ) """ # Stray Inductance concentrated on Primary Side self.n_conc = self.M / self.L_2_2 @@ -1620,25 +1861,26 @@ def get_inductances(self, I0: float, op_frequency: float = 0, skin_mesh_factor: """ inductances = ThreeWindingTransformerInductance( - M_12 = self.M_12, - M_13 = self.M_13, - M_23 = self.M_23, - L_s1 = self.L_s1, - L_s2 = self.L_s2, - L_s3 = self.L_s3, - L_h = self.L_h, - n_12 = self.n_12, - n_13 = self.n_13, - n_23 = self.n_23, - L_s12 = self.L_s12, - L_s13 = self.L_s13, - L_s23 = self.L_s23 + M_12=self.M_12, + M_13=self.M_13, + M_23=self.M_23, + L_s1=self.L_s1, + L_s2=self.L_s2, + L_s3=self.L_s3, + L_h=self.L_h, + n_12=self.n_12, + n_13=self.n_13, + n_23=self.n_23, + L_s12=self.L_s12, + L_s13=self.L_s13, + L_s23=self.L_s23 ) return dataclasses.asdict(inductances) # self.visualize() - def get_steinmetz_loss(self, peak_current: float = None, ki: float = 1, alpha: float = 1.2, beta: float = 2.2, t_rise: float = 3e-6, t_fall: float = 3e-6, + def get_steinmetz_loss(self, peak_current: float = None, ki: float = 1, alpha: float = 1.2, beta: float = 2.2, + t_rise: float = 3e-6, t_fall: float = 3e-6, f_switch: float = 100000, skin_mesh_factor: float = 0.5): """ @@ -1670,11 +1912,11 @@ def get_steinmetz_loss(self, peak_current: float = None, ki: float = 1, alpha: f # Call Simulation # self.high_level_geo_gen(frequency=0, skin_mesh_factor=skin_mesh_factor) # self.mesh.generate_mesh() - self.excitation(frequency=f_switch, amplitude_list=peak_current, phase_deg_list=[0, 180]) # frequency and current + self.excitation(frequency=f_switch, amplitude_list=peak_current, + phase_deg_list=[0, 180]) # frequency and current self.check_model_mqs_condition() self.write_simulation_parameters_to_pro_files() - def write_electro_magnetic_parameter_pro(self): """ Write materials and other parameters to the "Parameter.pro" file. @@ -1688,14 +1930,12 @@ def write_electro_magnetic_parameter_pro(self): if self.component_type == ComponentType.Inductor: text_file.write(f"Number_of_Windings = {len(self.windings)};\n") - if self.component_type == ComponentType.Transformer: text_file.write(f"Number_of_Windings = {len(self.windings)};\n") if self.component_type == ComponentType.IntegratedTransformer: text_file.write(f"Number_of_Windings = {len(self.windings)};\n") - # Frequency text_file.write("Freq = %s;\n" % self.frequency) text_file.write(f"delta = {self.delta};\n") @@ -1740,16 +1980,16 @@ def write_electro_magnetic_parameter_pro(self): # Core Parts text_file.write(f"nCoreParts = {len(self.mesh.plane_surface_core)};\n") - turns = ff.get_number_of_turns_of_winding(winding_windows=self.winding_windows, windings=self.windings, winding_number=winding_number) + turns = ff.get_number_of_turns_of_winding(winding_windows=self.winding_windows, windings=self.windings, + winding_number=winding_number) if self.windings[winding_number].parallel: text_file.write(f"NbrCond_{winding_number + 1} = 1;\n") - text_file.write(f"AreaCell_{winding_number + 1} = {self.windings[winding_number].a_cell*turns};\n") + text_file.write(f"AreaCell_{winding_number + 1} = {self.windings[winding_number].a_cell * turns};\n") else: text_file.write(f"NbrCond_{winding_number + 1} = {turns};\n") text_file.write(f"AreaCell_{winding_number + 1} = {self.windings[winding_number].a_cell};\n") - # For stranded Conductors: # text_file.write(f"NbrstrandedCond = {self.turns};\n") # redundant if self.windings[winding_number].conductor_type == ConductorType.RoundLitz: @@ -1768,7 +2008,8 @@ def write_electro_magnetic_parameter_pro(self): if self.flag_excitation_type == 'current': text_file.write(f"Val_EE_{winding_number + 1} = {abs(self.current[winding_number])};\n") text_file.write(f"Phase_{winding_number + 1} = {np.deg2rad(self.phase_deg[winding_number])};\n") - text_file.write(f"Parallel_{winding_number + 1} = {int(self.windings[winding_number].parallel==True)};\n") + text_file.write( + f"Parallel_{winding_number + 1} = {int(self.windings[winding_number].parallel == True)};\n") if self.flag_excitation_type == 'current_density': text_file.write(f"Val_EE_{winding_number + 1} = {self.current_density[winding_number]};\n") @@ -1779,9 +2020,10 @@ def write_electro_magnetic_parameter_pro(self): raise NotImplementedError self.femmt_print(f"Cell surface area: {self.windings[winding_number].a_cell} \n" - f"Reduced frequency: {self.red_freq[winding_number]}") + f"Reduced frequency: {self.red_freq[winding_number]}") - if self.red_freq[winding_number] > 1.25 and self.windings[winding_number].conductor_type == ConductorType.RoundLitz: + if self.red_freq[winding_number] > 1.25 and self.windings[ + winding_number].conductor_type == ConductorType.RoundLitz: # TODO: Allow higher reduced frequencies self.femmt_print(f"Litz Coefficients only implemented for X<=1.25") raise Warning @@ -1805,7 +2047,8 @@ def write_electro_magnetic_parameter_pro(self): # if self.frequency == 0: if self.core.non_linear: text_file.write(f"Flag_NL = 1;\n") - text_file.write(f"Core_Material = {self.core.material};\n") # relative permeability is defined at simulation runtime text_file.write(f"Flag_NL = 0;\n") + text_file.write( + f"Core_Material = {self.core.material};\n") # relative permeability is defined at simulation runtime text_file.write(f"Flag_NL = 0;\n") else: text_file.write(f"Flag_NL = 0;\n") text_file.write(f"mur = {self.core.mu_r_abs};\n") # mur is predefined to a fixed value @@ -1814,12 +2057,17 @@ def write_electro_magnetic_parameter_pro(self): else: text_file.write(f"Flag_Permeability_From_Data = 0;\n") # mur is predefined to a fixed value if self.core.permeability_type == PermeabilityType.FixedLossAngle: - text_file.write(f"phi_mu_deg = {self.core.phi_mu_deg};\n") # loss angle for complex representation of hysteresis loss - text_file.write(f"mur_real = {self.core.mu_r_abs * np.cos(np.deg2rad(self.core.phi_mu_deg))};\n") # Real part of complex permeability - text_file.write(f"mur_imag = {self.core.mu_r_abs * np.sin(np.deg2rad(self.core.phi_mu_deg))};\n") # Imaginary part of complex permeability - text_file.write(f"Flag_Fixed_Loss_Angle = 1;\n") # loss angle for complex representation of hysteresis loss + text_file.write( + f"phi_mu_deg = {self.core.phi_mu_deg};\n") # loss angle for complex representation of hysteresis loss + text_file.write( + f"mur_real = {self.core.mu_r_abs * np.cos(np.deg2rad(self.core.phi_mu_deg))};\n") # Real part of complex permeability + text_file.write( + f"mur_imag = {self.core.mu_r_abs * np.sin(np.deg2rad(self.core.phi_mu_deg))};\n") # Imaginary part of complex permeability + text_file.write( + f"Flag_Fixed_Loss_Angle = 1;\n") # loss angle for complex representation of hysteresis loss else: - text_file.write(f"Flag_Fixed_Loss_Angle = 0;\n") # loss angle for complex representation of hysteresis loss + text_file.write( + f"Flag_Fixed_Loss_Angle = 0;\n") # loss angle for complex representation of hysteresis loss # if self.frequency != 0: # text_file.write(f"Flag_NL = 0;\n") @@ -1838,14 +2086,17 @@ def write_electro_magnetic_post_pro(self): text_file.write(f"DirRes = \"{self.file_data.results_folder_path.replace(backslash, '/')}/\";\n") text_file.write(f"DirResFields = \"{self.file_data.e_m_fields_folder_path.replace(backslash, '/')}/\";\n") text_file.write(f"DirResVals = \"{self.file_data.e_m_values_folder_path.replace(backslash, '/')}/\";\n") - text_file.write(f"DirResValsCore = \"{self.file_data.e_m_values_folder_path.replace(backslash, '/')}/core_parts/\";\n") + text_file.write( + f"DirResValsCore = \"{self.file_data.e_m_values_folder_path.replace(backslash, '/')}/core_parts/\";\n") for i in range(1, len(self.windings) + 1): - text_file.write(f"DirResValsWinding_{i} = \"{self.file_data.e_m_values_folder_path.replace(backslash, '/')}/Winding_{i}/\";\n") - #text_file.write(f"DirResValsSecondary = \"{self.file_data.e_m_values_folder_path.replace(backslash, '/')}/Secondary/\";\n") - #text_file.write(f"DirResValsTertiary = \"{self.file_data.e_m_values_folder_path.replace(backslash, '/')}/Tertiary/\";\n") + text_file.write( + f"DirResValsWinding_{i} = \"{self.file_data.e_m_values_folder_path.replace(backslash, '/')}/Winding_{i}/\";\n") + # text_file.write(f"DirResValsSecondary = \"{self.file_data.e_m_values_folder_path.replace(backslash, '/')}/Secondary/\";\n") + # text_file.write(f"DirResValsTertiary = \"{self.file_data.e_m_values_folder_path.replace(backslash, '/')}/Tertiary/\";\n") text_file.write(f"DirResCirc = \"{self.file_data.e_m_circuit_folder_path.replace(backslash, '/')}/\";\n") text_file.write(f"OptionPos = \"{self.file_data.results_folder_path.replace(backslash, '/')}/option.pos\";\n") - text_file.write(f"DirStrandCoeff = \"{self.file_data.e_m_strands_coefficients_folder_path.replace(backslash, '/')}/\";\n") + text_file.write( + f"DirStrandCoeff = \"{self.file_data.e_m_strands_coefficients_folder_path.replace(backslash, '/')}/\";\n") # Visualisation if self.plot_fields == "standard": @@ -1921,7 +2172,8 @@ def calculate_and_write_log(self, sweep_number: int = 1, currents: List = None, "V": []} # Number turns - turns = ff.get_number_of_turns_of_winding(winding_windows=self.winding_windows, windings=self.windings, winding_number=winding_number) + turns = ff.get_number_of_turns_of_winding(winding_windows=self.winding_windows, windings=self.windings, + winding_number=winding_number) winding_dict["number_turns"] = turns @@ -1936,31 +2188,40 @@ def calculate_and_write_log(self, sweep_number: int = 1, currents: List = None, # Store complex value as list in json (because json is not natively capable of complex values) winding_dict["I"] = [complex_current_phasor.real, complex_current_phasor.imag] - - # Case litz: Load homogenized results if self.windings[winding_number].conductor_type == ConductorType.RoundLitz: - winding_dict["winding_losses"] = self.load_result(res_name=f"j2H_{winding_number + 1}", last_n=sweep_number)[sweep_run] + winding_dict["winding_losses"] = \ + self.load_result(res_name=f"j2H_{winding_number + 1}", last_n=sweep_number)[sweep_run] for turn in range(0, winding_dict["number_turns"]): - winding_dict["turn_losses"].append(self.load_result(res_name=winding_name[winding_number] + f"/Losses_turn_{turn + 1}", last_n=sweep_number)[sweep_run]) + winding_dict["turn_losses"].append( + self.load_result(res_name=winding_name[winding_number] + f"/Losses_turn_{turn + 1}", + last_n=sweep_number)[sweep_run]) # Case Solid: Load results, (pitfall for parallel windings results are only stored in one turn!) else: - winding_dict["winding_losses"] = self.load_result(res_name=f"j2F_{winding_number + 1}", last_n=sweep_number)[sweep_run] + winding_dict["winding_losses"] = \ + self.load_result(res_name=f"j2F_{winding_number + 1}", last_n=sweep_number)[sweep_run] if self.windings[winding_number].parallel: - winding_dict["turn_losses"].append(self.load_result(res_name=winding_name[winding_number] + f"/Losses_turn_{1}", last_n=sweep_number)[sweep_run]) + winding_dict["turn_losses"].append( + self.load_result(res_name=winding_name[winding_number] + f"/Losses_turn_{1}", + last_n=sweep_number)[sweep_run]) else: for turn in range(0, winding_dict["number_turns"]): - winding_dict["turn_losses"].append(self.load_result(res_name=winding_name[winding_number] + f"/Losses_turn_{turn + 1}", last_n=sweep_number)[sweep_run]) - + winding_dict["turn_losses"].append( + self.load_result(res_name=winding_name[winding_number] + f"/Losses_turn_{turn + 1}", + last_n=sweep_number)[sweep_run]) # Magnetic Field Energy # winding_dict["mag_field_energy"].append(self.load_result(res_name=f"ME", last_n=sweep_number)[sweep_run]) # winding_dict["mag_field_energy"].append(self.load_result(res_name=f"ME", part="imaginary", last_n=sweep_number)[sweep_run]) # Voltage - winding_dict["V"].append(self.load_result(res_name=f"Voltage_{winding_number + 1}", part="real", last_n=sweep_number)[sweep_run]) - winding_dict["V"].append(self.load_result(res_name=f"Voltage_{winding_number + 1}", part="imaginary", last_n=sweep_number)[sweep_run]) + winding_dict["V"].append( + self.load_result(res_name=f"Voltage_{winding_number + 1}", part="real", last_n=sweep_number)[ + sweep_run]) + winding_dict["V"].append( + self.load_result(res_name=f"Voltage_{winding_number + 1}", part="imaginary", last_n=sweep_number)[ + sweep_run]) complex_voltage_phasor = complex(winding_dict["V"][0], winding_dict["V"][1]) # Inductance @@ -1971,16 +2232,20 @@ def calculate_and_write_log(self, sweep_number: int = 1, currents: List = None, if complex_current_phasor == 0 or sweep_dict["f"] == 0: # if-statement to avoid div by zero error winding_dict["flux_over_current"] = [0, 0] else: - winding_dict["flux_over_current"].append((complex_voltage_phasor / (complex(0, 1) * 2*np.pi*complex_current_phasor * sweep_dict["f"])).real) - winding_dict["flux_over_current"].append((complex_voltage_phasor / (complex(0, 1) * 2*np.pi*complex_current_phasor * sweep_dict["f"])).imag) - + winding_dict["flux_over_current"].append((complex_voltage_phasor / ( + complex(0, 1) * 2 * np.pi * complex_current_phasor * sweep_dict["f"])).real) + winding_dict["flux_over_current"].append((complex_voltage_phasor / ( + complex(0, 1) * 2 * np.pi * complex_current_phasor * sweep_dict["f"])).imag) # Flux - winding_dict["flux"].append(self.load_result(res_name=f"Flux_Linkage_{winding_number + 1}", last_n=sweep_number)[sweep_run]) - winding_dict["flux"].append(self.load_result(res_name=f"Flux_Linkage_{winding_number + 1}", part="imaginary", last_n=sweep_number)[sweep_run]) + winding_dict["flux"].append( + self.load_result(res_name=f"Flux_Linkage_{winding_number + 1}", last_n=sweep_number)[sweep_run]) + winding_dict["flux"].append( + self.load_result(res_name=f"Flux_Linkage_{winding_number + 1}", part="imaginary", + last_n=sweep_number)[sweep_run]) # Flux from voltage - #winding_dict["flux"].append((complex(winding_dict["self_inductance"][-2], winding_dict["self_inductance"][-1])*self.current[winding]).real) # (L*I).real - #winding_dict["flux"].append((complex(winding_dict["self_inductance"][-2], winding_dict["self_inductance"][-1])*self.current[winding]).imag) # (L*I).imag + # winding_dict["flux"].append((complex(winding_dict["self_inductance"][-2], winding_dict["self_inductance"][-1])*self.current[winding]).real) # (L*I).real + # winding_dict["flux"].append((complex(winding_dict["self_inductance"][-2], winding_dict["self_inductance"][-1])*self.current[winding]).imag) # (L*I).imag # Power # using 'winding_dict["V"][0]' to get first element (real part) of V. Use winding_dict["I"][0] to avoid typeerror @@ -1988,22 +2253,36 @@ def calculate_and_write_log(self, sweep_number: int = 1, currents: List = None, winding_dict["Q"] = (complex_voltage_phasor * complex_current_phasor.conjugate() / 2).imag winding_dict["S"] = np.sqrt(winding_dict["P"] ** 2 + winding_dict["Q"] ** 2) - sweep_dict[f"winding{winding_number+1}"] = winding_dict + sweep_dict[f"winding{winding_number + 1}"] = winding_dict # Core losses TODO: Choose between Steinmetz or complex core losses - sweep_dict["core_eddy_losses"] = self.load_result(res_name="CoreEddyCurrentLosses", last_n=sweep_number)[sweep_run] + sweep_dict["core_eddy_losses"] = self.load_result(res_name="CoreEddyCurrentLosses", last_n=sweep_number)[ + sweep_run] sweep_dict["core_hyst_losses"] = self.load_result(res_name="p_hyst", last_n=sweep_number)[sweep_run] # Core Part losses if len(self.mesh.plane_surface_core) > 1: sweep_dict["core_parts"] = {} for i in range(0, len(self.mesh.plane_surface_core)): - sweep_dict["core_parts"][f"core_part_{i+1}"] = {} - sweep_dict["core_parts"][f"core_part_{i + 1}"]["eddy_losses"] = self.load_result(res_name=f"core_parts/CoreEddyCurrentLosses_{i+1}", last_n=sweep_number)[sweep_run] - sweep_dict["core_parts"][f"core_part_{i + 1}"]["hyst_losses"] = self.load_result(res_name=f"core_parts/p_hyst_{i+1}", last_n=sweep_number)[sweep_run] + sweep_dict["core_parts"][f"core_part_{i + 1}"] = {} + sweep_dict["core_parts"][f"core_part_{i + 1}"]["eddy_losses"] = \ + self.load_result(res_name=f"core_parts/CoreEddyCurrentLosses_{i + 1}", last_n=sweep_number)[sweep_run] + sweep_dict["core_parts"][f"core_part_{i + 1}"]["hyst_losses"] = \ + self.load_result(res_name=f"core_parts/p_hyst_{i + 1}", last_n=sweep_number)[sweep_run] + # finding the total losses for every core_part + eddy = sweep_dict["core_parts"][f"core_part_{i + 1}"]["eddy_losses"] + hyst = sweep_dict["core_parts"][f"core_part_{i + 1}"]["hyst_losses"] + sweep_dict["core_parts"][f"core_part_{i + 1}"][f"total_core_part_{i + 1}"] = eddy + hyst + + else: + # if I have only one core_part + sweep_dict["core_parts"] = {} # parent dictionary is initialized first + sweep_dict["core_parts"]["core_part_1"] = {} + sweep_dict["core_parts"]["core_part_1"]["total_core_part_1"] = sweep_dict["core_eddy_losses"] + sweep_dict["core_hyst_losses"] # Sum losses of all windings of one single run - sweep_dict["all_winding_losses"] = sum(sweep_dict[f"winding{d+1}"]["winding_losses"] for d in range(len(self.windings))) + sweep_dict["all_winding_losses"] = sum( + sweep_dict[f"winding{d + 1}"]["winding_losses"] for d in range(len(self.windings))) log_dict["single_sweeps"].append(sweep_dict) @@ -2022,35 +2301,52 @@ def calculate_and_write_log(self, sweep_number: int = 1, currents: List = None, turns += vww.turns[conductor.winding_number] log_dict["total_losses"][f"winding{winding_number + 1}"] = { - "total": sum(sum(log_dict["single_sweeps"][d][f"winding{winding_number+1}"]["turn_losses"]) for d in range(len(log_dict["single_sweeps"]))), + "total": sum(sum(log_dict["single_sweeps"][d][f"winding{winding_number + 1}"]["turn_losses"]) for d in + range(len(log_dict["single_sweeps"]))), "turns": [] } if self.windings[winding_number].parallel: log_dict["total_losses"][f"winding{winding_number + 1}"]["turns"].append( - sum(log_dict["single_sweeps"][d][f"winding{winding_number + 1}"]["turn_losses"][0] for d in range(len(log_dict["single_sweeps"])))) + sum(log_dict["single_sweeps"][d][f"winding{winding_number + 1}"]["turn_losses"][0] for d in + range(len(log_dict["single_sweeps"])))) else: for turn in range(0, turns): log_dict["total_losses"][f"winding{winding_number + 1}"]["turns"].append( - sum(log_dict["single_sweeps"][d][f"winding{winding_number + 1}"]["turn_losses"][turn] for d in range(len(log_dict["single_sweeps"])))) + sum(log_dict["single_sweeps"][d][f"winding{winding_number + 1}"]["turn_losses"][turn] for d in + range(len(log_dict["single_sweeps"])))) # Winding (all windings) - log_dict["total_losses"]["all_windings"] = sum(log_dict["single_sweeps"][d]["all_winding_losses"] for d in range(len(log_dict["single_sweeps"]))) + log_dict["total_losses"]["all_windings"] = sum( + log_dict["single_sweeps"][d]["all_winding_losses"] for d in range(len(log_dict["single_sweeps"]))) # Core - log_dict["total_losses"]["eddy_core"] = sum(log_dict["single_sweeps"][d]["core_eddy_losses"] for d in range(len(log_dict["single_sweeps"]))) - # For core losses just use hyst_losses of the fundamental frequency. When using single_simulation, the fundamental frequency is at [0] - # => just an approximation for excitation sweeps! - # In case of given external core_hyst_losses value from another simulation, the external value is used. + log_dict["total_losses"]["eddy_core"] = sum( + log_dict["single_sweeps"][d]["core_eddy_losses"] for d in range(len(log_dict["single_sweeps"]))) + # setting the total for every core_part in total losses dict + if len(self.mesh.plane_surface_core) > 1: + for i in range(len(self.mesh.plane_surface_core)): + log_dict["total_losses"][f"total_core_part_{i + 1}"] = sweep_dict["core_parts"][f"core_part_{i + 1}"][ + f"total_core_part_{i + 1}"] + if len(self.mesh.plane_surface_core) == 1: # core and core_part_1 will be the same + + log_dict["total_losses"]["total_core_part_1"] = sweep_dict["core_parts"]["core_part_1"]["total_core_part_1"] + + if isinstance(core_hyst_losses, float) or isinstance(core_hyst_losses, int): log_dict["total_losses"]["hyst_core_fundamental_freq"] = core_hyst_losses elif core_hyst_losses is not None: raise ValueError("External core hysteresis losses are given in non-float format") else: - log_dict["total_losses"]["hyst_core_fundamental_freq"] = log_dict["single_sweeps"][fundamental_index]["core_hyst_losses"] + log_dict["total_losses"]["hyst_core_fundamental_freq"] = log_dict["single_sweeps"][fundamental_index][ + "core_hyst_losses"] # Total losses of inductive component according to single or sweep simulation - log_dict["total_losses"]["core"] = log_dict["total_losses"]["hyst_core_fundamental_freq"] + log_dict["total_losses"]["eddy_core"] - log_dict["total_losses"]["total_losses"] = log_dict["total_losses"]["hyst_core_fundamental_freq"] + log_dict["total_losses"]["eddy_core"] + log_dict["total_losses"]["all_windings"] + log_dict["total_losses"]["core"] = log_dict["total_losses"]["hyst_core_fundamental_freq"] + \ + log_dict["total_losses"]["eddy_core"] + + log_dict["total_losses"]["total_losses"] = log_dict["total_losses"]["hyst_core_fundamental_freq"] + \ + log_dict["total_losses"]["eddy_core"] + log_dict["total_losses"][ + "all_windings"] # ---- Introduce calculations for writing the misc-dict into the result-log ---- wire_type_list = [] @@ -2070,15 +2366,19 @@ def calculate_and_write_log(self, sweep_number: int = 1, currents: List = None, # ---- Miscellaneous ---- log_dict["misc"] = { - "core_2daxi_volume": self.calculate_core_volume(), - "core_2daxi_total_volume":self.calculate_core_volume_with_air(), + "core_2daxi_volume": self.calculate_core_volume(), #self.calculate_core_volume(), + "core_2daxi_total_volume": self.calculate_core_volume_with_air(), "core_2daxi_weight": core_weight, "wire_lengths": self.calculate_wire_lengths(), "wire_volumes": self.calculate_wire_volumes(), "wire_weight": wire_weight_list, - "core_cost": ff.cost_function_core(core_weight, core_type = "ferrite"), - "winding_cost": ff.cost_function_winding(wire_weight_list= wire_weight_list, wire_type_list= wire_type_list, single_strand_cross_section_list = single_strand_cross_section_list), - "total_cost_incl_margin": ff.cost_function_total(core_weight, core_type="ferrite", wire_weight_list= wire_weight_list, wire_type_list=wire_type_list, single_strand_cross_section_list = single_strand_cross_section_list) + "core_cost": ff.cost_function_core(core_weight, core_type="ferrite"), + "winding_cost": ff.cost_function_winding(wire_weight_list=wire_weight_list, wire_type_list=wire_type_list, + single_strand_cross_section_list=single_strand_cross_section_list), + "total_cost_incl_margin": ff.cost_function_total(core_weight, core_type="ferrite", + wire_weight_list=wire_weight_list, + wire_type_list=wire_type_list, + single_strand_cross_section_list=single_strand_cross_section_list) } # ---- Print current configuration ---- @@ -2111,7 +2411,7 @@ def visualize(self): """ # ---------------------------------------- Visualization in gmsh --------------------------------------- self.femmt_print(f"\n---\n" - f"Visualize fields in GMSH front end:\n") + f"Visualize fields in GMSH front end:\n") # gmsh.initialize() epsilon = 1e-9 @@ -2211,7 +2511,8 @@ def get_loss_data(self, last_n_values: int, loss_type: str = 'litz_loss'): data = list(reader) return data[-last_n_values:-1] + [data[-1]] - def load_result(self, res_name: str, res_type: str = "value", last_n: int = 1, part:str = "real", position: int = 0): + def load_result(self, res_name: str, res_type: str = "value", last_n: int = 1, part: str = "real", + position: int = 0): """ Loads the "last_n" parameters from a result file of the scalar quantity "res_name". Either the real or imaginary part can be chosen. @@ -2223,20 +2524,19 @@ def load_result(self, res_name: str, res_type: str = "value", last_n: int = 1, p :return: last_n entries of the chosen result file :rtype: list """ - if res_type=="value": - res_path=self.file_data.e_m_values_folder_path - if res_type=="circuit": - res_path=self.file_data.e_m_circuit_folder_path - + if res_type == "value": + res_path = self.file_data.e_m_values_folder_path + if res_type == "circuit": + res_path = self.file_data.e_m_circuit_folder_path with open(os.path.join(res_path, f"{res_name}.dat")) as fd: lines = fd.readlines()[-last_n:] if part == "real": - result = [float(line.split(sep=' ')[1 + 2*position + 1]) for n, line in enumerate(lines)] + result = [float(line.split(sep=' ')[1 + 2 * position + 1]) for n, line in enumerate(lines)] if part == "imaginary": - result = [float(line.split(sep=' ')[2 + 2*position + 1]) for n, line in enumerate(lines)] + result = [float(line.split(sep=' ')[2 + 2 * position + 1]) for n, line in enumerate(lines)] return result @@ -2256,7 +2556,8 @@ def generate_load_litz_approximation_parameters(self): # That's why here a hard-coded 4 is implemented # if os.path.isfile(self.path + # f"/Strands_Coefficients/coeff/pB_RS_la{self.windings[num].ff}_{self.n_layers[num]}layer.dat"): - if os.path.exists(os.path.join(self.file_data.e_m_strands_coefficients_folder_path, "coeff", f"pB_RS_la{self.windings[num].ff}_4layer.dat")): + if os.path.exists(os.path.join(self.file_data.e_m_strands_coefficients_folder_path, "coeff", + f"pB_RS_la{self.windings[num].ff}_4layer.dat")): self.femmt_print("Coefficients for stands approximation are found.") else: @@ -2280,9 +2581,9 @@ def create_strand_coeff(self, winding_number: int) -> None: :type winding_number: int """ self.femmt_print(f"\n" - f"Pre-Simulation\n" - f"-----------------------------------------\n" - f"Create coefficients for strands approximation\n") + f"Pre-Simulation\n" + f"-----------------------------------------\n" + f"Create coefficients for strands approximation\n") text_file = open(os.path.join(self.file_data.e_m_strands_coefficients_folder_path, "PreParameter.pro"), "w") @@ -2306,7 +2607,8 @@ def create_strand_coeff(self, winding_number: int) -> None: for mode in modes: for rf in reduced_frequencies: # -- Pre-Simulation Settings -- - text_file = open(os.path.join(self.file_data.e_m_strands_coefficients_folder_path, "PreParameter.pro"), "w") + text_file = open(os.path.join(self.file_data.e_m_strands_coefficients_folder_path, "PreParameter.pro"), + "w") text_file.write(f"Rr_cell = {rf};\n") text_file.write(f"Mode = {mode};\n") # Litz Approximation Coefficients are created with 4 layers @@ -2314,17 +2616,18 @@ def create_strand_coeff(self, winding_number: int) -> None: # text_file.write(f"NbrLayers = {self.n_layers[num]};\n") text_file.write(f"NbrLayers = 4;\n") text_file.write(f"Fill = {self.windings[winding_number].ff};\n") - text_file.write(f"Rc = {self.windings[winding_number].strand_radius};\n") # double named!!! must be changed + text_file.write( + f"Rc = {self.windings[winding_number].strand_radius};\n") # double named!!! must be changed text_file.close() # get model file names with correct path input_file = os.path.join(self.file_data.e_m_strands_coefficients_folder_path, "cell_dat.pro") cell = os.path.join(self.file_data.e_m_strands_coefficients_folder_path, "cell.pro") - # Run simulations as sub clients mygetdp = os.path.join(self.file_data.onelab_folder_path, "getdp") - self.onelab_client.runSubClient("myGetDP", mygetdp + " " + cell + " -input " + input_file + " -solve MagDyn_a " + verbose) + self.onelab_client.runSubClient("myGetDP", + mygetdp + " " + cell + " -input " + input_file + " -solve MagDyn_a " + verbose) # Formatting stuff # Litz Approximation Coefficients are created with 4 layers @@ -2384,7 +2687,6 @@ def femm_reference(self, freq: float, current: float, sign: bool = None, non_vis raise Exception('You are using a computer that is not running windows. ' 'This command is only executable on Windows computers.') - self.file_data.create_folders(self.file_data.femm_folder_path) sign = sign or [1] @@ -2407,114 +2709,117 @@ def femm_reference(self, freq: float, current: float, sign: bool = None, non_vis # self.core.sigma = 2 * np.pi * self.frequency * epsilon_0 * f_N95_er_imag(f=self.frequency) + 1 / 6 self.core.sigma = 1 / 6 - self.femmt_print(f"{self.core.permeability_type=}, {self.core.sigma=}") if self.core.permeability_type == PermeabilityType.FixedLossAngle: - femm.mi_addmaterial('Ferrite', self.core.mu_r_abs, self.core.mu_r_abs, 0, 0, self.core.sigma / 1e6, 0, 0, 1, 0, self.core.phi_mu_deg, self.core.phi_mu_deg) + femm.mi_addmaterial('Ferrite', self.core.mu_r_abs, self.core.mu_r_abs, 0, 0, self.core.sigma / 1e6, 0, 0, 1, + 0, self.core.phi_mu_deg, self.core.phi_mu_deg) elif self.core.permeability_type == PermeabilityType.RealValue: - femm.mi_addmaterial('Ferrite', self.core.mu_r_abs, self.core.mu_r_abs, 0, 0, self.core.sigma / 1e6, 0, 0, 1, 0, self.core.phi_mu_deg, self.core.phi_mu_deg) + femm.mi_addmaterial('Ferrite', self.core.mu_r_abs, self.core.mu_r_abs, 0, 0, self.core.sigma / 1e6, 0, 0, 1, + 0, self.core.phi_mu_deg, self.core.phi_mu_deg) else: - femm.mi_addmaterial('Ferrite', self.core.mu_r_abs, self.core.mu_r_abs, 0, 0, self.core.sigma / 1e6, 0, 0, 1, 0, 0, 0) + femm.mi_addmaterial('Ferrite', self.core.mu_r_abs, self.core.mu_r_abs, 0, 0, self.core.sigma / 1e6, 0, 0, 1, + 0, 0, 0) femm.mi_addmaterial('Air', 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0) for i in range(0, len(self.windings)): if self.windings[i].conductor_type == ConductorType.RoundLitz: - femm.mi_addmaterial('Litz', 1, 1, 0, 0, self.windings[i].cond_sigma/1e6, 0, 0, 1, 5, 0, 0, self.windings[i].n_strands, 2 * 1000 * self.windings[i].strand_radius) # type := 5. last argument + femm.mi_addmaterial('Litz', 1, 1, 0, 0, self.windings[i].cond_sigma / 1e6, 0, 0, 1, 5, 0, 0, + self.windings[i].n_strands, + 2 * 1000 * self.windings[i].strand_radius) # type := 5. last argument self.femmt_print(f"Number of strands: {self.windings[i].n_strands}") self.femmt_print(f"Diameter of strands in mm: {2 * 1000 * self.windings[i].strand_radius}") if self.windings[i].conductor_type == ConductorType.RoundSolid: - femm.mi_addmaterial('Copper', 1, 1, 0, 0, self.windings[i].cond_sigma/1e6, 0, 0, 1, 0, 0, 0, 0, 0) + femm.mi_addmaterial('Copper', 1, 1, 0, 0, self.windings[i].cond_sigma / 1e6, 0, 0, 1, 0, 0, 0, 0, 0) # == Circuit == # coil as seen from the terminals. for i in range(len(self.windings)): femm.mi_addcircprop('Winding' + str(i + 1), current[i] * sign[i], int(not self.windings[i].parallel)) - # == Geometry == # Add core if self.air_gaps.number == 0: femm.mi_drawline(self.two_d_axi.p_window[4, 0], - self.two_d_axi.p_window[4, 1], - self.two_d_axi.p_window[5, 0], - self.two_d_axi.p_window[5, 1]) + self.two_d_axi.p_window[4, 1], + self.two_d_axi.p_window[5, 0], + self.two_d_axi.p_window[5, 1]) femm.mi_drawline(self.two_d_axi.p_window[5, 0], - self.two_d_axi.p_window[5, 1], - self.two_d_axi.p_window[7, 0], - self.two_d_axi.p_window[7, 1]) + self.two_d_axi.p_window[5, 1], + self.two_d_axi.p_window[7, 0], + self.two_d_axi.p_window[7, 1]) femm.mi_drawline(self.two_d_axi.p_window[7, 0], - self.two_d_axi.p_window[7, 1], - self.two_d_axi.p_window[6, 0], - self.two_d_axi.p_window[6, 1]) + self.two_d_axi.p_window[7, 1], + self.two_d_axi.p_window[6, 0], + self.two_d_axi.p_window[6, 1]) femm.mi_drawline(self.two_d_axi.p_window[6, 0], - self.two_d_axi.p_window[6, 1], - self.two_d_axi.p_window[4, 0], - self.two_d_axi.p_window[4, 1]) + self.two_d_axi.p_window[6, 1], + self.two_d_axi.p_window[4, 0], + self.two_d_axi.p_window[4, 1]) femm.mi_drawline(0, - self.two_d_axi.p_outer[2, 1], - self.two_d_axi.p_outer[3, 0], - self.two_d_axi.p_outer[3, 1]) + self.two_d_axi.p_outer[2, 1], + self.two_d_axi.p_outer[3, 0], + self.two_d_axi.p_outer[3, 1]) femm.mi_drawline(self.two_d_axi.p_outer[3, 0], - self.two_d_axi.p_outer[3, 1], - self.two_d_axi.p_outer[1, 0], - self.two_d_axi.p_outer[1, 1]) + self.two_d_axi.p_outer[3, 1], + self.two_d_axi.p_outer[1, 0], + self.two_d_axi.p_outer[1, 1]) femm.mi_drawline(self.two_d_axi.p_outer[1, 0], - self.two_d_axi.p_outer[1, 1], - 0, - self.two_d_axi.p_outer[0, 1]) + self.two_d_axi.p_outer[1, 1], + 0, + self.two_d_axi.p_outer[0, 1]) femm.mi_drawline(0, - self.two_d_axi.p_outer[0, 1], - 0, - self.two_d_axi.p_outer[2, 1]) + self.two_d_axi.p_outer[0, 1], + 0, + self.two_d_axi.p_outer[2, 1]) elif self.air_gaps.number > 0: femm.mi_drawline(0, - self.two_d_axi.p_air_gaps[0, 1], - self.two_d_axi.p_air_gaps[1, 0], - self.two_d_axi.p_air_gaps[1, 1]) + self.two_d_axi.p_air_gaps[0, 1], + self.two_d_axi.p_air_gaps[1, 0], + self.two_d_axi.p_air_gaps[1, 1]) femm.mi_drawline(self.two_d_axi.p_air_gaps[1, 0], - self.two_d_axi.p_air_gaps[1, 1], - self.two_d_axi.p_window[4, 0], - self.two_d_axi.p_window[4, 1]) + self.two_d_axi.p_air_gaps[1, 1], + self.two_d_axi.p_window[4, 0], + self.two_d_axi.p_window[4, 1]) femm.mi_drawline(self.two_d_axi.p_window[4, 0], - self.two_d_axi.p_window[4, 1], - self.two_d_axi.p_window[5, 0], - self.two_d_axi.p_window[5, 1]) + self.two_d_axi.p_window[4, 1], + self.two_d_axi.p_window[5, 0], + self.two_d_axi.p_window[5, 1]) femm.mi_drawline(self.two_d_axi.p_window[5, 0], - self.two_d_axi.p_window[5, 1], - self.two_d_axi.p_window[7, 0], - self.two_d_axi.p_window[7, 1]) + self.two_d_axi.p_window[5, 1], + self.two_d_axi.p_window[7, 0], + self.two_d_axi.p_window[7, 1]) femm.mi_drawline(self.two_d_axi.p_window[7, 0], - self.two_d_axi.p_window[7, 1], - self.two_d_axi.p_window[6, 0], - self.two_d_axi.p_window[6, 1]) + self.two_d_axi.p_window[7, 1], + self.two_d_axi.p_window[6, 0], + self.two_d_axi.p_window[6, 1]) femm.mi_drawline(self.two_d_axi.p_window[6, 0], - self.two_d_axi.p_window[6, 1], - self.two_d_axi.p_air_gaps[3, 0], - self.two_d_axi.p_air_gaps[3, 1]) + self.two_d_axi.p_window[6, 1], + self.two_d_axi.p_air_gaps[3, 0], + self.two_d_axi.p_air_gaps[3, 1]) femm.mi_drawline(self.two_d_axi.p_air_gaps[3, 0], - self.two_d_axi.p_air_gaps[3, 1], - 0, - self.two_d_axi.p_air_gaps[2, 1]) + self.two_d_axi.p_air_gaps[3, 1], + 0, + self.two_d_axi.p_air_gaps[2, 1]) femm.mi_drawline(0, - self.two_d_axi.p_air_gaps[2, 1], - 0, - self.two_d_axi.p_outer[2, 1]) + self.two_d_axi.p_air_gaps[2, 1], + 0, + self.two_d_axi.p_outer[2, 1]) femm.mi_drawline(0, - self.two_d_axi.p_outer[2, 1], - self.two_d_axi.p_outer[3, 0], - self.two_d_axi.p_outer[3, 1]) + self.two_d_axi.p_outer[2, 1], + self.two_d_axi.p_outer[3, 0], + self.two_d_axi.p_outer[3, 1]) femm.mi_drawline(self.two_d_axi.p_outer[3, 0], - self.two_d_axi.p_outer[3, 1], - self.two_d_axi.p_outer[1, 0], - self.two_d_axi.p_outer[1, 1]) + self.two_d_axi.p_outer[3, 1], + self.two_d_axi.p_outer[1, 0], + self.two_d_axi.p_outer[1, 1]) femm.mi_drawline(self.two_d_axi.p_outer[1, 0], - self.two_d_axi.p_outer[1, 1], - 0, - self.two_d_axi.p_outer[0, 1]) + self.two_d_axi.p_outer[1, 1], + 0, + self.two_d_axi.p_outer[0, 1]) femm.mi_drawline(0, - self.two_d_axi.p_outer[0, 1], - 0, - self.two_d_axi.p_air_gaps[0, 1]) + self.two_d_axi.p_outer[0, 1], + 0, + self.two_d_axi.p_air_gaps[0, 1]) else: raise Exception("Negative air gap number is not allowed") # Add Coil @@ -2542,23 +2847,22 @@ def femm_reference(self, freq: float, current: float, sign: bool = None, non_vis self.two_d_axi.p_conductor[num][5 * i + 3][0], self.two_d_axi.p_conductor[num][5 * i + 3][1], 180, 2.5) femm.mi_addarc(self.two_d_axi.p_conductor[num][5 * i + 3][0], - self.two_d_axi.p_conductor[num][5 * i + 3][1], - self.two_d_axi.p_conductor[num][5 * i + 1][0], - self.two_d_axi.p_conductor[num][5 * i + 1][1], 180, 2.5) + self.two_d_axi.p_conductor[num][5 * i + 3][1], + self.two_d_axi.p_conductor[num][5 * i + 1][0], + self.two_d_axi.p_conductor[num][5 * i + 1][1], 180, 2.5) femm.mi_addblocklabel(self.two_d_axi.p_conductor[num][5 * i][0], + self.two_d_axi.p_conductor[num][5 * i][1]) + femm.mi_selectlabel(self.two_d_axi.p_conductor[num][5 * i][0], self.two_d_axi.p_conductor[num][5 * i][1]) - femm.mi_selectlabel(self.two_d_axi.p_conductor[num][5 * i][0], self.two_d_axi.p_conductor[num][5 * i][1]) - winding_name = 'Winding' + str(num + 1) if self.windings[num].conductor_type == ConductorType.RoundLitz: - femm.mi_setblockprop('Litz', 1, 0, winding_name, 0, num + 2, 1) + femm.mi_setblockprop('Litz', 1, 0, winding_name, 0, num + 2, 1) else: - femm.mi_setblockprop('Copper', 1, 0, winding_name, 0, num + 2, 1) + femm.mi_setblockprop('Copper', 1, 0, winding_name, 0, num + 2, 1) femm.mi_clearselected() - # Define an "open" boundary condition using the built-in function: femm.mi_makeABC() """ @@ -2643,8 +2947,6 @@ def femm_reference(self, freq: float, current: float, sign: bool = None, non_vis # When the analysis is completed, FEMM can be shut down. # femm.closefemm() - - def write_femm_log(self): """TODO Doc """ @@ -2681,9 +2983,9 @@ def write_femm_log(self): log["Primary Voltage"] = [circuit_properties_primary[1].real, circuit_properties_primary[1].imag] log["Primary Flux"] = [circuit_properties_primary[2].real, circuit_properties_primary[2].imag] log["Primary Self Inductance"] = [circuit_properties_primary[2].real / circuit_properties_primary[0], - circuit_properties_primary[2].imag / circuit_properties_primary[0]] - log["Primary Mean Power"] = [0.5*circuit_properties_primary[1].real*circuit_properties_primary[0], - 0.5*circuit_properties_primary[1].imag*circuit_properties_primary[0]] + circuit_properties_primary[2].imag / circuit_properties_primary[0]] + log["Primary Mean Power"] = [0.5 * circuit_properties_primary[1].real * circuit_properties_primary[0], + 0.5 * circuit_properties_primary[1].imag * circuit_properties_primary[0]] for i in range(len(self.windings)): circuit_properties = femm.mo_getcircuitproperties('Winding' + str(i + 1)) log["Winding" + str(i + 1) + " Current"] = circuit_properties[0] @@ -2702,7 +3004,6 @@ def write_femm_log(self): log["Winding" + str(i + 1) + " Losses"] = femm.mo_blockintegral(6).real femm.mo_clearblock() - json.dump(log, file, indent=2, ensure_ascii=False) file.close() @@ -2724,7 +3025,8 @@ def calculate_point_average(x1: float, y1: float, x2: float, y2: float) -> Tuple # TODO Move to femmt_functions return (x1 + x2) / 2, (y1 + y2) / 2 - def femm_thermal_validation(self, thermal_conductivity_dict: Dict, boundary_temperature: Dict, case_gap_top: float, case_gap_right: float, case_gap_bot: float): + def femm_thermal_validation(self, thermal_conductivity_dict: Dict, boundary_temperature: Dict, case_gap_top: float, + case_gap_right: float, case_gap_bot: float): """Creates a thermal model in femm and simulates it with the given thermal conductivities :param thermal_conductivity_dict: Dict containing conductivities for air, winding, case, core @@ -2747,7 +3049,7 @@ def femm_thermal_validation(self, thermal_conductivity_dict: Dict, boundary_temp self.femm_is_imported = True else: raise Exception('You are using a computer that is not running windows. ' - 'This command is only executable on Windows computers.') + 'This command is only executable on Windows computers.') # Get paths femm_model_file_path = os.path.join(self.file_data.femm_folder_path, "thermal-validation.FEH") @@ -2784,7 +3086,8 @@ def femm_thermal_validation(self, thermal_conductivity_dict: Dict, boundary_temp c_wire = 0 # Case - k_case = thermal_conductivity_dict["case"]["top"] # Does not matter when the regions all have the same thermal conductivity. + k_case = thermal_conductivity_dict["case"][ + "top"] # Does not matter when the regions all have the same thermal conductivity. q_vol_case = 0 # c_case = 0.01 c_case = 0 @@ -2814,7 +3117,9 @@ def femm_thermal_validation(self, thermal_conductivity_dict: Dict, boundary_temp for winding_index, winding in enumerate(winding_losses_list): for i in range(len(winding)): # Add a new material to FEMM with Litz conductor properties - femm.hi_addmaterial(f'Wire_{winding_index}_{i}', k_wire, k_wire, calculate_heat_flux_round_wire(winding[i], wire_radii[winding_index], wire_distances[winding_index][i]), c_wire) + femm.hi_addmaterial(f'Wire_{winding_index}_{i}', k_wire, k_wire, + calculate_heat_flux_round_wire(winding[i], wire_radii[winding_index], + wire_distances[winding_index][i]), c_wire) femm.hi_addmaterial('Case', k_case, k_case, q_vol_case, c_case) # Add boundary condition @@ -2826,121 +3131,131 @@ def femm_thermal_validation(self, thermal_conductivity_dict: Dict, boundary_temp # Add core if self.air_gaps.number == 0: femm.hi_drawline(self.two_d_axi.p_window[4, 0], - self.two_d_axi.p_window[4, 1], - self.two_d_axi.p_window[5, 0], - self.two_d_axi.p_window[5, 1]) + self.two_d_axi.p_window[4, 1], + self.two_d_axi.p_window[5, 0], + self.two_d_axi.p_window[5, 1]) femm.hi_drawline(self.two_d_axi.p_window[5, 0], - self.two_d_axi.p_window[5, 1], - self.two_d_axi.p_window[7, 0], - self.two_d_axi.p_window[7, 1]) + self.two_d_axi.p_window[5, 1], + self.two_d_axi.p_window[7, 0], + self.two_d_axi.p_window[7, 1]) femm.hi_drawline(self.two_d_axi.p_window[7, 0], - self.two_d_axi.p_window[7, 1], - self.two_d_axi.p_window[6, 0], - self.two_d_axi.p_window[6, 1]) + self.two_d_axi.p_window[7, 1], + self.two_d_axi.p_window[6, 0], + self.two_d_axi.p_window[6, 1]) femm.hi_drawline(self.two_d_axi.p_window[6, 0], - self.two_d_axi.p_window[6, 1], - self.two_d_axi.p_window[4, 0], - self.two_d_axi.p_window[4, 1]) + self.two_d_axi.p_window[6, 1], + self.two_d_axi.p_window[4, 0], + self.two_d_axi.p_window[4, 1]) femm.hi_drawline(0, - self.two_d_axi.p_outer[2, 1], - self.two_d_axi.p_outer[3, 0], - self.two_d_axi.p_outer[3, 1]) + self.two_d_axi.p_outer[2, 1], + self.two_d_axi.p_outer[3, 0], + self.two_d_axi.p_outer[3, 1]) femm.hi_drawline(self.two_d_axi.p_outer[3, 0], - self.two_d_axi.p_outer[3, 1], - self.two_d_axi.p_outer[1, 0], - self.two_d_axi.p_outer[1, 1]) + self.two_d_axi.p_outer[3, 1], + self.two_d_axi.p_outer[1, 0], + self.two_d_axi.p_outer[1, 1]) femm.hi_drawline(self.two_d_axi.p_outer[1, 0], - self.two_d_axi.p_outer[1, 1], - 0, - self.two_d_axi.p_outer[0, 1]) + self.two_d_axi.p_outer[1, 1], + 0, + self.two_d_axi.p_outer[0, 1]) femm.hi_drawline(0, - self.two_d_axi.p_outer[0, 1], - 0, - self.two_d_axi.p_outer[2, 1]) + self.two_d_axi.p_outer[0, 1], + 0, + self.two_d_axi.p_outer[2, 1]) elif self.air_gaps.number > 0: femm.hi_drawline(0, - self.two_d_axi.p_air_gaps[0, 1], - self.two_d_axi.p_air_gaps[1, 0], - self.two_d_axi.p_air_gaps[1, 1]) + self.two_d_axi.p_air_gaps[0, 1], + self.two_d_axi.p_air_gaps[1, 0], + self.two_d_axi.p_air_gaps[1, 1]) femm.hi_drawline(self.two_d_axi.p_air_gaps[1, 0], - self.two_d_axi.p_air_gaps[1, 1], - self.two_d_axi.p_window[4, 0], - self.two_d_axi.p_window[4, 1]) + self.two_d_axi.p_air_gaps[1, 1], + self.two_d_axi.p_window[4, 0], + self.two_d_axi.p_window[4, 1]) femm.hi_drawline(self.two_d_axi.p_window[4, 0], - self.two_d_axi.p_window[4, 1], - self.two_d_axi.p_window[5, 0], - self.two_d_axi.p_window[5, 1]) + self.two_d_axi.p_window[4, 1], + self.two_d_axi.p_window[5, 0], + self.two_d_axi.p_window[5, 1]) femm.hi_drawline(self.two_d_axi.p_window[5, 0], - self.two_d_axi.p_window[5, 1], - self.two_d_axi.p_window[7, 0], - self.two_d_axi.p_window[7, 1]) + self.two_d_axi.p_window[5, 1], + self.two_d_axi.p_window[7, 0], + self.two_d_axi.p_window[7, 1]) femm.hi_drawline(self.two_d_axi.p_window[7, 0], - self.two_d_axi.p_window[7, 1], - self.two_d_axi.p_window[6, 0], - self.two_d_axi.p_window[6, 1]) + self.two_d_axi.p_window[7, 1], + self.two_d_axi.p_window[6, 0], + self.two_d_axi.p_window[6, 1]) femm.hi_drawline(self.two_d_axi.p_window[6, 0], - self.two_d_axi.p_window[6, 1], - self.two_d_axi.p_air_gaps[3, 0], - self.two_d_axi.p_air_gaps[3, 1]) + self.two_d_axi.p_window[6, 1], + self.two_d_axi.p_air_gaps[3, 0], + self.two_d_axi.p_air_gaps[3, 1]) femm.hi_drawline(self.two_d_axi.p_air_gaps[3, 0], - self.two_d_axi.p_air_gaps[3, 1], - 0, - self.two_d_axi.p_air_gaps[2, 1]) + self.two_d_axi.p_air_gaps[3, 1], + 0, + self.two_d_axi.p_air_gaps[2, 1]) femm.hi_drawline(0, - self.two_d_axi.p_air_gaps[2, 1], - 0, - self.two_d_axi.p_outer[2, 1]) + self.two_d_axi.p_air_gaps[2, 1], + 0, + self.two_d_axi.p_outer[2, 1]) femm.hi_drawline(0, - self.two_d_axi.p_outer[2, 1], - self.two_d_axi.p_outer[3, 0], - self.two_d_axi.p_outer[3, 1]) + self.two_d_axi.p_outer[2, 1], + self.two_d_axi.p_outer[3, 0], + self.two_d_axi.p_outer[3, 1]) femm.hi_drawline(self.two_d_axi.p_outer[3, 0], - self.two_d_axi.p_outer[3, 1], - self.two_d_axi.p_outer[1, 0], - self.two_d_axi.p_outer[1, 1]) + self.two_d_axi.p_outer[3, 1], + self.two_d_axi.p_outer[1, 0], + self.two_d_axi.p_outer[1, 1]) femm.hi_drawline(self.two_d_axi.p_outer[1, 0], - self.two_d_axi.p_outer[1, 1], - 0, - self.two_d_axi.p_outer[0, 1]) + self.two_d_axi.p_outer[1, 1], + 0, + self.two_d_axi.p_outer[0, 1]) femm.hi_drawline(0, - self.two_d_axi.p_outer[0, 1], - 0, - self.two_d_axi.p_air_gaps[0, 1]) + self.two_d_axi.p_outer[0, 1], + 0, + self.two_d_axi.p_air_gaps[0, 1]) # In order for the simulation to work the air_gap must be closed: femm.hi_drawline(0, self.two_d_axi.p_air_gaps[0, 1], 0, self.two_d_axi.p_air_gaps[2, 1]) # Close air gap to separate from air femm.hi_drawline(self.two_d_axi.p_air_gaps[1, 0], self.two_d_axi.p_air_gaps[1, 1], - self.two_d_axi.p_air_gaps[3, 0], self.two_d_axi.p_air_gaps[3, 1]) + self.two_d_axi.p_air_gaps[3, 0], self.two_d_axi.p_air_gaps[3, 1]) else: raise Exception("Negative air gap number is not allowed") # Add case - femm.hi_drawline(0, self.two_d_axi.p_outer[2, 1], 0, self.two_d_axi.p_outer[2, 1] + case_gap_top) # Top left line - femm.hi_drawline(0, self.two_d_axi.p_outer[2, 1] + case_gap_top, self.two_d_axi.p_outer[3, 0] + case_gap_right, self.two_d_axi.p_outer[3, 1] + case_gap_top) # Top line - femm.hi_drawline(self.two_d_axi.p_outer[3, 0] + case_gap_right, self.two_d_axi.p_outer[3, 1] + case_gap_top, self.two_d_axi.p_outer[1, 0] + case_gap_right, - self.two_d_axi.p_outer[1, 1] - case_gap_bot) # Right line - femm.hi_drawline(self.two_d_axi.p_outer[1, 0] + case_gap_right, self.two_d_axi.p_outer[1, 1] - case_gap_bot, 0, self.two_d_axi.p_outer[0, 1] - case_gap_bot) # Bottom line - femm.hi_drawline(0, self.two_d_axi.p_outer[0, 1] - case_gap_bot, 0, self.two_d_axi.p_outer[0, 1]) # Bottom right line + femm.hi_drawline(0, self.two_d_axi.p_outer[2, 1], 0, + self.two_d_axi.p_outer[2, 1] + case_gap_top) # Top left line + femm.hi_drawline(0, self.two_d_axi.p_outer[2, 1] + case_gap_top, self.two_d_axi.p_outer[3, 0] + case_gap_right, + self.two_d_axi.p_outer[3, 1] + case_gap_top) # Top line + femm.hi_drawline(self.two_d_axi.p_outer[3, 0] + case_gap_right, self.two_d_axi.p_outer[3, 1] + case_gap_top, + self.two_d_axi.p_outer[1, 0] + case_gap_right, + self.two_d_axi.p_outer[1, 1] - case_gap_bot) # Right line + femm.hi_drawline(self.two_d_axi.p_outer[1, 0] + case_gap_right, self.two_d_axi.p_outer[1, 1] - case_gap_bot, 0, + self.two_d_axi.p_outer[0, 1] - case_gap_bot) # Bottom line + femm.hi_drawline(0, self.two_d_axi.p_outer[0, 1] - case_gap_bot, 0, + self.two_d_axi.p_outer[0, 1]) # Bottom right line # Create boundary # femm.hi_selectsegment(*self.calculatePointAverage(0, self.two_d_axi.p_outer[2, 1], 0, self.two_d_axi.p_outer[2, 1] + caseGapTop)) - femm.hi_selectsegment(*MagneticComponent.calculate_point_average(0, self.two_d_axi.p_outer[2, 1] + case_gap_top, self.two_d_axi.p_outer[3, 0] + case_gap_right, - self.two_d_axi.p_outer[3, 1] + case_gap_top)) + femm.hi_selectsegment(*MagneticComponent.calculate_point_average(0, self.two_d_axi.p_outer[2, 1] + case_gap_top, + self.two_d_axi.p_outer[3, 0] + case_gap_right, + self.two_d_axi.p_outer[3, 1] + case_gap_top)) femm.hi_setsegmentprop("NeumannBoundary", 0, 1, 0, 2, "") femm.hi_clearselected() - femm.hi_selectsegment(*MagneticComponent.calculate_point_average(self.two_d_axi.p_outer[3, 0] + case_gap_right, self.two_d_axi.p_outer[3, 1] + case_gap_top, - self.two_d_axi.p_outer[1, 0] + case_gap_right, self.two_d_axi.p_outer[1, 1] - case_gap_bot)) - femm.hi_selectsegment(*MagneticComponent.calculate_point_average(self.two_d_axi.p_outer[1, 0] + case_gap_right, self.two_d_axi.p_outer[1, 1] - case_gap_bot, 0, - self.two_d_axi.p_outer[0, 1] - case_gap_bot)) + femm.hi_selectsegment(*MagneticComponent.calculate_point_average(self.two_d_axi.p_outer[3, 0] + case_gap_right, + self.two_d_axi.p_outer[3, 1] + case_gap_top, + self.two_d_axi.p_outer[1, 0] + case_gap_right, + self.two_d_axi.p_outer[1, 1] - case_gap_bot)) + femm.hi_selectsegment(*MagneticComponent.calculate_point_average(self.two_d_axi.p_outer[1, 0] + case_gap_right, + self.two_d_axi.p_outer[1, 1] - case_gap_bot, 0, + self.two_d_axi.p_outer[0, 1] - case_gap_bot)) # femm.hi_selectsegment(*self.calculatePointAverage(0, self.two_d_axi.p_outer[0, 1] - caseGapBot, 0, self.two_d_axi.p_outer[0, 1])) femm.hi_setsegmentprop("Boundary", 0, 1, 0, 2, "") femm.hi_clearselected() # Add case material - material_x, material_y = self.calculate_point_average(0, self.two_d_axi.p_outer[2, 1], 0, self.two_d_axi.p_outer[2, 1] + case_gap_top) + material_x, material_y = self.calculate_point_average(0, self.two_d_axi.p_outer[2, 1], 0, + self.two_d_axi.p_outer[2, 1] + case_gap_top) femm.hi_addblocklabel(material_x + 0.001, material_y) femm.hi_selectlabel(material_x + 0.001, material_y) femm.hi_setblockprop('Case', 1, 0, 0) @@ -2955,12 +3270,13 @@ def femm_thermal_validation(self, thermal_conductivity_dict: Dict, boundary_temp self.two_d_axi.p_conductor[num][5 * i + 3][0], self.two_d_axi.p_conductor[num][5 * i + 3][1], 180, 2.5) femm.hi_addarc(self.two_d_axi.p_conductor[num][5 * i + 3][0], - self.two_d_axi.p_conductor[num][5 * i + 3][1], - self.two_d_axi.p_conductor[num][5 * i + 1][0], - self.two_d_axi.p_conductor[num][5 * i + 1][1], 180, 2.5) + self.two_d_axi.p_conductor[num][5 * i + 3][1], + self.two_d_axi.p_conductor[num][5 * i + 1][0], + self.two_d_axi.p_conductor[num][5 * i + 1][1], 180, 2.5) femm.hi_addblocklabel(self.two_d_axi.p_conductor[num][5 * i][0], + self.two_d_axi.p_conductor[num][5 * i][1]) + femm.hi_selectlabel(self.two_d_axi.p_conductor[num][5 * i][0], self.two_d_axi.p_conductor[num][5 * i][1]) - femm.hi_selectlabel(self.two_d_axi.p_conductor[num][5 * i][0], self.two_d_axi.p_conductor[num][5 * i][1]) if num == 0: femm.hi_setblockprop(f'Wire_{num}_{i}', 1, 0, 1) if num == 1: @@ -3064,8 +3380,8 @@ def decode_settings_from_log(log_file_path: str, working_directory: str = None, settings["core"]["loss_approach"] = LossApproach[settings["core"]["loss_approach"]] core_dimensions = SingleCoreDimensions(core_inner_diameter=settings["core"]["core_inner_diameter"], - window_w=settings["core"]["window_w"], - window_h=settings["core"]["window_h"]) + window_w=settings["core"]["window_w"], + window_h=settings["core"]["window_h"]) core = Core(core_dimensions=core_dimensions, **settings["core"]) geo.set_core(core) @@ -3073,13 +3389,15 @@ def decode_settings_from_log(log_file_path: str, working_directory: str = None, if "air_gaps" in settings: air_gaps = AirGaps(AirGapMethod[settings["air_gaps"]["method"]], core) for air_gap in settings["air_gaps"]["air_gaps"]: - air_gaps.add_air_gap(AirGapLegPosition[air_gap["leg_position"]], air_gap["height"], air_gap["position_value"],) + air_gaps.add_air_gap(AirGapLegPosition[air_gap["leg_position"]], air_gap["height"], + air_gap["position_value"], ) geo.set_air_gaps(air_gaps) if "insulation" in settings: insulation = Insulation() insulation.add_core_insulations(*settings["insulation"]["core_insulations"]) - insulation.add_winding_insulations(settings["insulation"]["inner_winding_insulations"], settings["insulation"]["vww_insulation"]) + insulation.add_winding_insulations(settings["insulation"]["inner_winding_insulations"], + settings["insulation"]["vww_insulation"]) geo.set_insulation(insulation) if "stray_path" in settings: @@ -3101,22 +3419,28 @@ def decode_settings_from_log(log_file_path: str, working_directory: str = None, elif conductor_type == ConductorType.RoundLitz: # 3 of 4 wire preferences are allowed, so fill-factor is set to None, even the value is known from the log. conductor.set_litz_round_conductor(winding["conductor_radius"], winding["number_strands"], - winding["strand_radius"], None, ConductorArrangement[winding["conductor_arrangement"]]) + winding["strand_radius"], None, + ConductorArrangement[winding["conductor_arrangement"]]) elif conductor_type == ConductorType.RoundSolid: - conductor.set_solid_round_conductor(winding["conductor_radius"], ConductorArrangement[winding["conductor_arrangement"]]) + conductor.set_solid_round_conductor(winding["conductor_radius"], + ConductorArrangement[winding["conductor_arrangement"]]) else: raise Exception(f"Unknown conductor type {conductor_type.name}") conductors.append(conductor) - new_vww = VirtualWindingWindow(vww["bot_bound"], vww["top_bound"], vww["left_bound"], vww["right_bound"]) + new_vww = VirtualWindingWindow(vww["bot_bound"], vww["top_bound"], vww["left_bound"], + vww["right_bound"]) winding_type = WindingType[vww["winding_type"]] if winding_type == WindingType.Single: - winding_scheme = WindingScheme[vww["winding_scheme"]] if vww["winding_scheme"] is not None else None + winding_scheme = WindingScheme[vww["winding_scheme"]] if vww[ + "winding_scheme"] is not None else None wrap_para_type = WrapParaType[vww["wrap_para"]] if vww["wrap_para"] is not None else None new_vww.set_winding(conductors[0], turns[0], winding_scheme, wrap_para_type) elif winding_type == WindingType.TwoInterleaved: - new_vww.set_interleaved_winding(conductors[0], turns[0], conductors[1], turns[1], InterleavedWindingScheme[vww["winding_scheme"]], vww["winding_insulation"]) + new_vww.set_interleaved_winding(conductors[0], turns[0], conductors[1], turns[1], + InterleavedWindingScheme[vww["winding_scheme"]], + vww["winding_insulation"]) else: raise Exception(f"Winding type {winding_type} is not implemented") new_virtual_winding_windows.append(new_vww) @@ -3135,4 +3459,3 @@ def decode_settings_from_log(log_file_path: str, working_directory: str = None, - diff --git a/femmt/examples/basic_inductor.py b/femmt/examples/basic_inductor.py index cb552d9c..734c950d 100644 --- a/femmt/examples/basic_inductor.py +++ b/femmt/examples/basic_inductor.py @@ -3,7 +3,7 @@ import os def basic_example_inductor(onelab_folder: str = None, show_visual_outputs: bool = True, is_test: bool = False): - def example_thermal_simulation(show_visual_outputs: bool = True): + def example_thermal_simulation(show_visual_outputs: bool = True, flag_insulation: bool = True): # Thermal simulation: # The losses calculated by the magnetics simulation can be used to calculate the heat distribution of the given magnetic component # In order to use the thermal simulation, thermal conductivities for each material can be entered as well as a boundary temperature @@ -23,7 +23,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): "core": 5, # ferrite "winding": 400, # copper "air_gaps": 180, # aluminiumnitride - "insulation": 0.42 # polyethylen + "insulation": 0.42 if flag_insulation else None # polyethylen } # Here the case size can be determined @@ -66,7 +66,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # Obviously when the model is modified and the losses can be out of date and therefore the geo.single_simulation needs to run again. geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, case_gap_right, case_gap_bot, show_visual_outputs, color_scheme=fmt.colors_ba_jonas, - colors_geometry=fmt.colors_geometry_ba_jonas) + colors_geometry=fmt.colors_geometry_ba_jonas, flag_insulation=flag_insulation) example_results_folder = os.path.join(os.path.dirname(__file__), "example_results") @@ -116,7 +116,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.set_air_gaps(air_gaps) # 4. set insulations - insulation = fmt.Insulation() + insulation = fmt.Insulation(flag_insulation=True) insulation.add_core_insulations(0.001, 0.001, 0.004, 0.001) insulation.add_winding_insulations([[0.0005]]) geo.set_insulation(insulation) @@ -133,7 +133,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # fill_factor=None, conductor_arrangement=fmt.ConductorArrangement.Square) # 7. add conductor to vww and add winding window to MagneticComponent - vww.set_winding(winding, 9, None) + vww.set_winding(winding, 7, None) geo.set_winding_windows([winding_window]) # 8. create the model @@ -154,7 +154,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # 9. start simulation # 7. prepare and start thermal simulation - example_thermal_simulation(show_visual_outputs) + example_thermal_simulation(show_visual_outputs, flag_insulation=True) if __name__ == "__main__": basic_example_inductor(show_visual_outputs=True) \ No newline at end of file diff --git a/femmt/examples/basic_transformer.py b/femmt/examples/basic_transformer.py index 448b2863..00d7e222 100644 --- a/femmt/examples/basic_transformer.py +++ b/femmt/examples/basic_transformer.py @@ -4,7 +4,7 @@ def basic_example_transformer(onelab_folder: str = None, show_visual_outputs: bool = True, is_test: bool = False): - def example_thermal_simulation(show_visual_outputs: bool = True): + def example_thermal_simulation(show_visual_outputs: bool = True, flag_insulation: bool =True): # Thermal simulation: # The losses calculated by the magnetics simulation can be used to calculate the heat distribution of the given magnetic component # In order to use the thermal simulation, thermal conductivities for each material can be entered as well as a boundary temperature @@ -24,7 +24,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): "core": 5, # ferrite "winding": 400, # copper "air_gaps": 180, # aluminiumnitride - "insulation": 0.42 # polyethylen + "insulation": 0.42 if flag_insulation else None # polyethylen } # Here the case size can be determined @@ -67,7 +67,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # Obviously when the model is modified and the losses can be out of date and therefore the geo.single_simulation needs to run again. geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, case_gap_right, case_gap_bot, show_visual_outputs, color_scheme=fmt.colors_ba_jonas, - colors_geometry=fmt.colors_geometry_ba_jonas) + colors_geometry=fmt.colors_geometry_ba_jonas, flag_insulation= flag_insulation) example_results_folder = os.path.join(os.path.dirname(__file__), "example_results") if not os.path.exists(example_results_folder): @@ -101,7 +101,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.set_air_gaps(air_gaps) # 4. set insulation - insulation = fmt.Insulation() + insulation = fmt.Insulation(flag_insulation=True) insulation.add_core_insulations(0.001, 0.001, 0.002, 0.001) insulation.add_winding_insulations([[0.0002, 0.001], [0.001, 0.0002]]) @@ -135,7 +135,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.create_model(freq=200000, pre_visualize_geometry=show_visual_outputs) geo.single_simulation(freq=200000, current=[2, 2], phi_deg=[0, 180], show_fem_simulation_results=show_visual_outputs) - example_thermal_simulation(show_visual_outputs) + example_thermal_simulation(show_visual_outputs, flag_insulation= True) if __name__ == "__main__": diff --git a/femmt/examples/basic_transformer_center_tapped.py b/femmt/examples/basic_transformer_center_tapped.py index 1de74c5b..457e299f 100644 --- a/femmt/examples/basic_transformer_center_tapped.py +++ b/femmt/examples/basic_transformer_center_tapped.py @@ -2,7 +2,7 @@ import os def basic_example_transformer_center_tapped(onelab_folder: str = None, show_visual_outputs: bool = True, is_test: bool = False): - def example_thermal_simulation(show_visual_outputs: bool = True): + def example_thermal_simulation(show_visual_outputs: bool = True, flag_insulation:bool = True): # Thermal simulation: # The losses calculated by the magnetics simulation can be used to calculate the heat distribution of the given magnetic component # In order to use the thermal simulation, thermal conductivities for each material can be entered as well as a boundary temperature @@ -22,7 +22,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): "core": 5, # ferrite "winding": 400, # copper "air_gaps": 180, # aluminiumnitride - "insulation": 0.42 # polyethylen + "insulation": 0.42 if flag_insulation else None # polyethylen } # Here the case size can be determined @@ -64,7 +64,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # order for the thermal simulation to work (geo.single_simulation is not needed). # Obviously when the model is modified and the losses can be out of date and therefore the geo.single_simulation needs to run again. geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, - case_gap_right, case_gap_bot, show_visual_outputs, color_scheme=fmt.colors_ba_jonas, colors_geometry=fmt.colors_geometry_ba_jonas) + case_gap_right, case_gap_bot, show_visual_outputs, color_scheme=fmt.colors_ba_jonas, colors_geometry=fmt.colors_geometry_ba_jonas, flag_insulation=flag_insulation) example_results_folder = os.path.join(os.path.dirname(__file__), "example_results") if not os.path.exists(example_results_folder): @@ -108,6 +108,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.create_model(freq=200000, pre_visualize_geometry=show_visual_outputs) geo.single_simulation(freq=200000, current=[20, 120, 120], phi_deg=[0, 180, 180], show_fem_simulation_results=show_visual_outputs) + example_thermal_simulation(show_visual_outputs, flag_insulation=False) if __name__ == "__main__": basic_example_transformer_center_tapped(show_visual_outputs=True) \ No newline at end of file diff --git a/femmt/examples/basic_transformer_integrated.py b/femmt/examples/basic_transformer_integrated.py index c1fdd49a..38bff4b1 100644 --- a/femmt/examples/basic_transformer_integrated.py +++ b/femmt/examples/basic_transformer_integrated.py @@ -2,7 +2,7 @@ import os def basic_example_transformer_intergrated(onelab_folder: str = None, show_visual_outputs: bool = True, is_test: bool = False): - def example_thermal_simulation(show_visual_outputs: bool = True): + def example_thermal_simulation(show_visual_outputs: bool = True, flag_insulation: bool = True): # Thermal simulation: # The losses calculated by the magnetics simulation can be used to calculate the heat distribution of the given magnetic component # In order to use the thermal simulation, thermal conductivities for each material can be entered as well as a boundary temperature @@ -22,7 +22,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): "core": 5, # ferrite "winding": 400, # copper "air_gaps": 180, # aluminiumnitride - "insulation": 0.42 # polyethylen + "insulation": 0.42 if flag_insulation else None # polyethylen } # Here the case size can be determined @@ -65,7 +65,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # Obviously when the model is modified and the losses can be out of date and therefore the geo.single_simulation needs to run again. geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, case_gap_right, case_gap_bot, show_visual_outputs, color_scheme=fmt.colors_ba_jonas, - colors_geometry=fmt.colors_geometry_ba_jonas) + colors_geometry=fmt.colors_geometry_ba_jonas, flag_insulation=flag_insulation) example_results_folder = os.path.join(os.path.dirname(__file__), "example_results") @@ -103,7 +103,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.set_air_gaps(air_gaps) # 4. set insulations - insulation = fmt.Insulation() + insulation = fmt.Insulation(flag_insulation=False) insulation.add_core_insulations(0.001, 0.001, 0.002, 0.001) insulation.add_winding_insulations([[0.0002, 0.001], [0.001, 0.0002]]) @@ -134,6 +134,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # other simulation options: # ------------------------- # geo.get_inductances(I0=10, op_frequency=100000, skin_mesh_factor=0.5) + example_thermal_simulation(show_visual_outputs, flag_insulation=False) if __name__ == "__main__": diff --git a/femmt/examples/basic_transformer_interleaved.py b/femmt/examples/basic_transformer_interleaved.py index 9d912416..06cac511 100644 --- a/femmt/examples/basic_transformer_interleaved.py +++ b/femmt/examples/basic_transformer_interleaved.py @@ -2,7 +2,7 @@ import os def basic_example_transformer_interleaved(onelab_folder: str = None, show_visual_outputs: bool = True, is_test: bool = False): - def example_thermal_simulation(show_visual_outputs: bool = True): + def example_thermal_simulation(show_visual_outputs: bool = True, flag_insulation: bool = True): # Thermal simulation: # The losses calculated by the magnetics simulation can be used to calculate the heat distribution of the given magnetic component # In order to use the thermal simulation, thermal conductivities for each material can be entered as well as a boundary temperature @@ -22,7 +22,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): "core": 5, # ferrite "winding": 400, # copper "air_gaps": 180, # aluminiumnitride - "insulation": 0.42 # polyethylen + "insulation": 0.42 if flag_insulation else None # polyethylen } # Here the case size can be determined @@ -65,7 +65,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # Obviously when the model is modified and the losses can be out of date and therefore the geo.single_simulation needs to run again. geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, case_gap_right, case_gap_bot, show_visual_outputs, color_scheme=fmt.colors_ba_jonas, - colors_geometry=fmt.colors_geometry_ba_jonas) + colors_geometry=fmt.colors_geometry_ba_jonas, flag_insulation=flag_insulation) example_results_folder = os.path.join(os.path.dirname(__file__), "example_results") @@ -131,7 +131,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): visualize_last_fem_simulation=show_visual_outputs) # 9. start thermal simulation - example_thermal_simulation(show_visual_outputs) + example_thermal_simulation(show_visual_outputs, flag_insulation=True) if __name__ == "__main__": diff --git a/femmt/examples/basic_transformer_n_winding.py b/femmt/examples/basic_transformer_n_winding.py index ce92ad09..ffd80b7f 100644 --- a/femmt/examples/basic_transformer_n_winding.py +++ b/femmt/examples/basic_transformer_n_winding.py @@ -4,7 +4,7 @@ def basic_example_transformer_n_winding(onelab_folder: str = None, show_visual_outputs: bool = True, is_test: bool = False): - def example_thermal_simulation(show_visual_outputs: bool = True): + def example_thermal_simulation(show_visual_outputs: bool = True, flag_insulation: bool = True): # Thermal simulation: @@ -26,7 +26,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): "core": 5, # ferrite "winding": 400, # copper "air_gaps": 180, # aluminiumnitride - "insulation": 0.42 # polyethylen + "insulation": 0.42 if flag_insulation else None # polyethylen } # Here the case size can be determined @@ -69,7 +69,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # Obviously when the model is modified and the losses can be out of date and therefore the geo.single_simulation needs to run again. geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, case_gap_right, case_gap_bot, show_visual_outputs, color_scheme=fmt.colors_ba_jonas, - colors_geometry=fmt.colors_geometry_ba_jonas) + colors_geometry=fmt.colors_geometry_ba_jonas, flag_insulation=flag_insulation) example_results_folder = os.path.join(os.path.dirname(__file__), "example_results") @@ -101,7 +101,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.set_air_gaps(air_gaps) # 4. set insulation - insulation = fmt.Insulation() + insulation = fmt.Insulation(flag_insulation=True) insulation.add_core_insulations(0.001, 0.001, 0.002, 0.001) # insulation.add_winding_insulations([0.0002, 0.0002, 0.0002, 0.0002, 0.0002, 0.0002, 0.0002, 0.0002, 0.0002, 0.0002], 0.0005) insulation.add_winding_insulations( @@ -199,7 +199,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.single_simulation(freq=250000, current=[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], phi_deg=[0, 180, 0, 180, 0, 180, 0, 180, 0, 180, 0, 180], show_fem_simulation_results=show_visual_outputs) # 7. prepare and start thermal simulation - example_thermal_simulation(show_visual_outputs=show_visual_outputs) + example_thermal_simulation(show_visual_outputs=show_visual_outputs, flag_insulation=True) # read inductances # geo.get_inductances(I0=4, op_frequency=250000, skin_mesh_factor=0.5, visualize=False) diff --git a/femmt/examples/basic_transformer_stacked.py b/femmt/examples/basic_transformer_stacked.py index c67d2f07..7704a1bd 100644 --- a/femmt/examples/basic_transformer_stacked.py +++ b/femmt/examples/basic_transformer_stacked.py @@ -5,7 +5,7 @@ def basic_example_transformer_stacked(onelab_folder: str = None, show_visual_outputs: bool = True, is_test: bool = False): - def example_thermal_simulation(show_visual_outputs: bool = True): + def example_thermal_simulation(show_visual_outputs: bool = True, flag_insulation: bool = True): # Thermal simulation: # The losses calculated by the magnetics simulation can be used to calculate the heat distribution of the given magnetic component # In order to use the thermal simulation, thermal conductivities for each material can be entered as well as a boundary temperature @@ -25,7 +25,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): "core": 5, # ferrite "winding": 400, # copper "air_gaps": 180, # aluminiumnitride - "insulation": 0.42 # polyethylen + "insulation": 0.42 if flag_insulation else None # polyethylen } # Here the case size can be determined @@ -68,7 +68,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # Obviously when the model is modified and the losses can be out of date and therefore the geo.single_simulation needs to run again. geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, case_gap_right, case_gap_bot, show_visual_outputs, color_scheme=fmt.colors_ba_jonas, - colors_geometry=fmt.colors_geometry_ba_jonas) + colors_geometry=fmt.colors_geometry_ba_jonas, flag_insulation=flag_insulation) example_results_folder = os.path.join(os.path.dirname(__file__), "example_results") @@ -102,7 +102,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.set_air_gaps(air_gaps) # 4. set insulations - insulation = fmt.Insulation() + insulation = fmt.Insulation(flag_insulation=False) # insulation.add_core_insulations(0.001, 0.001, 0.002, 0.001) # TODO: needed for upper and lower winding window? insulation.add_core_insulations(0.001, 0.001, 0.001, 0.001) # [bot, top, left, right] insulation.add_winding_insulations([[0.0002, 0.001], @@ -135,6 +135,8 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # other simulation options: # ------------------------- # geo.get_inductances(I0=10, op_frequency=100000, skin_mesh_factor=0.5) + # 7. prepare and start thermal simulation + example_thermal_simulation(show_visual_outputs, flag_insulation=False) if __name__ == "__main__": basic_example_transformer_stacked(show_visual_outputs=True) \ No newline at end of file diff --git a/femmt/examples/basic_transformer_stacked_center_tapped.py b/femmt/examples/basic_transformer_stacked_center_tapped.py index 7c216824..0d8dead6 100644 --- a/femmt/examples/basic_transformer_stacked_center_tapped.py +++ b/femmt/examples/basic_transformer_stacked_center_tapped.py @@ -5,7 +5,7 @@ def basic_example_transformer_stacked_center_tapped(onelab_folder: str = None, show_visual_outputs: bool = True, is_test: bool = False): - def example_thermal_simulation(show_visual_outputs: bool = True): + def example_thermal_simulation(show_visual_outputs: bool = True, flag_insulation: bool = True): # Thermal simulation: # The losses calculated by the magnetics simulation can be used to calculate the heat distribution of the given magnetic component # In order to use the thermal simulation, thermal conductivities for each material can be entered as well as a boundary temperature @@ -25,7 +25,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): "core": 5, # ferrite "winding": 400, # copper "air_gaps": 180, # aluminiumnitride - "insulation": 0.42 # polyethylen + "insulation": 0.42 if flag_insulation else None# polyethylen } # Here the case size can be determined @@ -68,7 +68,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # Obviously when the model is modified and the losses can be out of date and therefore the geo.single_simulation needs to run again. geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, case_gap_right, case_gap_bot, show_visual_outputs, color_scheme=fmt.colors_ba_jonas, - colors_geometry=fmt.colors_geometry_ba_jonas) + colors_geometry=fmt.colors_geometry_ba_jonas, flag_insulation=flag_insulation) example_results_folder = os.path.join(os.path.dirname(__file__), "example_results") @@ -130,6 +130,8 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.single_simulation(freq=200000, current=[20, 120, 120], phi_deg=[0, 180, 180], show_fem_simulation_results=show_visual_outputs) geo.get_inductances(I0=1, op_frequency=200000) + # 7. prepare and start thermal simulation + example_thermal_simulation(show_visual_outputs, flag_insulation=False) if __name__ == "__main__": basic_example_transformer_stacked_center_tapped(show_visual_outputs=True) \ No newline at end of file diff --git a/femmt/examples/basic_transformer_three_winding.py b/femmt/examples/basic_transformer_three_winding.py index b61b6f06..e60a389e 100644 --- a/femmt/examples/basic_transformer_three_winding.py +++ b/femmt/examples/basic_transformer_three_winding.py @@ -2,7 +2,7 @@ import os def basic_example_transformer_three_winding(onelab_folder: str = None, show_visual_outputs: bool = True, is_test: bool = False): - def example_thermal_simulation(show_visual_outputs: bool = True): + def example_thermal_simulation(show_visual_outputs: bool = True, flag_insulation: bool =True): # Thermal simulation: @@ -24,7 +24,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): "core": 5, # ferrite "winding": 400, # copper "air_gaps": 180, # aluminiumnitride - "insulation": 0.42 # polyethylen + "insulation": 0.42 if flag_insulation else None # polyethylen } # Here the case size can be determined @@ -67,7 +67,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): # Obviously when the model is modified and the losses can be out of date and therefore the geo.single_simulation needs to run again. geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, case_gap_right, case_gap_bot, show_visual_outputs, color_scheme=fmt.colors_ba_jonas, - colors_geometry=fmt.colors_geometry_ba_jonas) + colors_geometry=fmt.colors_geometry_ba_jonas, flag_insulation=flag_insulation) example_results_folder = os.path.join(os.path.dirname(__file__), "example_results") @@ -99,7 +99,7 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.set_air_gaps(air_gaps) # 4. set insulation - insulation = fmt.Insulation() + insulation = fmt.Insulation(flag_insulation=False) insulation.add_core_insulations(0.001, 0.001, 0.002, 0.001) insulation.add_winding_insulations([[0.0002, 0.0004, 0.0004], [0.0004, 0.0002, 0.0004], @@ -131,6 +131,9 @@ def example_thermal_simulation(show_visual_outputs: bool = True): geo.create_model(freq=250000, pre_visualize_geometry=show_visual_outputs) geo.single_simulation(freq=250000, current=[4, 4, 4], phi_deg=[0, 180, 0], show_fem_simulation_results=show_visual_outputs) + # 7. prepare and start thermal simulation + example_thermal_simulation(show_visual_outputs, flag_insulation=False) + if __name__ == "__main__": basic_example_transformer_three_winding(show_visual_outputs=True) \ No newline at end of file diff --git a/femmt/functions_topologies.py b/femmt/functions_topologies.py index f0dab146..b30f1d94 100644 --- a/femmt/functions_topologies.py +++ b/femmt/functions_topologies.py @@ -189,7 +189,7 @@ def set_center_tapped_windings(core, :return: """ def define_insulations(): - insulation = Insulation() + insulation = Insulation(flag_insulation=False) insulation.add_core_insulations(iso_top_core, iso_bot_core, iso_left_core, iso_right_core) insulation.add_winding_insulations([[iso_primary_to_primary, iso_primary_to_secondary, iso_primary_to_secondary], [iso_primary_to_secondary, iso_secondary_to_secondary, iso_primary_to_secondary], diff --git a/femmt/mesh.py b/femmt/mesh.py index 3e941c89..dcfedbda 100644 --- a/femmt/mesh.py +++ b/femmt/mesh.py @@ -1415,83 +1415,164 @@ def set_physical_line_bound(): with open(self.gmsh_log, "w") as fd: fd.write(text) - def generate_thermal_mesh(self, case_gap_top, case_gap_right, case_gap_bot, color_scheme, colors_geometry, visualize_before): + def generate_thermal_mesh(self, case_gap_top, case_gap_right, case_gap_bot, color_scheme, colors_geometry, visualize_before): self.femmt_print("Thermal Mesh Generation in Gmsh (write physical entities)") gmsh.open(self.model_geo_file) + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + # Create case around the core + if self.model.core.core_type == CoreType.Single: + + + # Core point and line tags + core_point_tags = [] + core_line_tags = [] + if self.model.air_gaps.number == 0: # TODO... + core_point_tags = [4, 3, 2, 1] + core_line_tags = [4, 3, 2] + else: + core_point_tags = [7, 6, 5, 4, 3, 2] + core_line_tags = [7, 6, 5, 4, 3] + + tl_point = core_point_tags[0] # Top left - default 5 + tr_point = core_point_tags[2] # Top right - default 4 + br_point = core_point_tags[3] # Bottom right - default 3 + bl_point = core_point_tags[5] # Bottom left - default 2 + + top_lines = [core_line_tags[0], core_line_tags[1]] # default 4 + right_line = core_line_tags[2] # default 3 + bottom_lines = [core_line_tags[3], core_line_tags[4]] # default 2 + + # Get positions from points + tl_point_pos = gmsh.model.getValue(0, tl_point, []) + tr_point_pos = gmsh.model.getValue(0, tr_point, []) + br_point_pos = gmsh.model.getValue(0, br_point, []) + bl_point_pos = gmsh.model.getValue(0, bl_point, []) + + mesh = self.mesh_data.c_core * 4 # It typically does not need to be the same size as c_core, but it shouldn't be too big either + + # Create 5 new areas: top, top right, right, bottom right, bottom + # top + top_case_left_point = gmsh.model.geo.addPoint(tl_point_pos[0], tl_point_pos[1] + case_gap_top,tl_point_pos[2], mesh) + top_case_right_point = gmsh.model.geo.addPoint(tr_point_pos[0], tr_point_pos[1] + case_gap_top,tr_point_pos[2], mesh) + top_case_left_line = gmsh.model.geo.addLine(tl_point, top_case_left_point) + top_case_top_line = gmsh.model.geo.addLine(top_case_left_point, top_case_right_point) + top_case_right_line = gmsh.model.geo.addLine(top_case_right_point, tr_point) + top_case_curve_loop = gmsh.model.geo.addCurveLoop([top_case_left_line, top_case_top_line, top_case_right_line] + top_lines) + top_case_surface = gmsh.model.geo.addPlaneSurface([top_case_curve_loop]) + + # top right + top_right_case_top_right_point = gmsh.model.geo.addPoint(tr_point_pos[0] + case_gap_right,tr_point_pos[1] + case_gap_top, tr_point_pos[2], mesh) + top_right_case_right_point = gmsh.model.geo.addPoint(tr_point_pos[0] + case_gap_right, tr_point_pos[1],tr_point_pos[2], mesh) + top_right_case_bottom_line = gmsh.model.geo.addLine(tr_point, top_right_case_right_point) + top_right_case_right_line = gmsh.model.geo.addLine(top_right_case_right_point,top_right_case_top_right_point) + top_right_case_top_line = gmsh.model.geo.addLine(top_right_case_top_right_point, top_case_right_point) + top_right_case_curve_loop = gmsh.model.geo.addCurveLoop([top_case_right_line, top_right_case_bottom_line, top_right_case_right_line, top_right_case_top_line]) + top_right_case_surface = gmsh.model.geo.addPlaneSurface([top_right_case_curve_loop]) + + # right + right_case_bottom_point = gmsh.model.geo.addPoint(br_point_pos[0] + case_gap_right, br_point_pos[1],br_point_pos[2], mesh) + right_case_right_line = gmsh.model.geo.addLine(top_right_case_right_point, right_case_bottom_point) + right_case_bottom_line = gmsh.model.geo.addLine(right_case_bottom_point, br_point) + right_case_curve_loop = gmsh.model.geo.addCurveLoop([top_right_case_bottom_line, right_case_right_line, right_case_bottom_line, right_line]) + right_case_surface = gmsh.model.geo.addPlaneSurface([right_case_curve_loop]) + + # bottom right + bottom_right_case_bottom_right_point = gmsh.model.geo.addPoint(br_point_pos[0] + case_gap_right,br_point_pos[1] - case_gap_bot, br_point_pos[2], mesh) + bottom_right_case_bottom_point = gmsh.model.geo.addPoint(br_point_pos[0], br_point_pos[1] - case_gap_bot,br_point_pos[2], mesh) + bottom_right_case_left_line = gmsh.model.geo.addLine(br_point, bottom_right_case_bottom_point) + bottom_right_case_bottom_line = gmsh.model.geo.addLine(bottom_right_case_bottom_point,bottom_right_case_bottom_right_point) + bottom_right_case_right_line = gmsh.model.geo.addLine(bottom_right_case_bottom_right_point,right_case_bottom_point) + bottom_right_case_curve_loop = gmsh.model.geo.addCurveLoop([right_case_bottom_line, bottom_right_case_left_line, bottom_right_case_bottom_line,bottom_right_case_right_line]) + bottom_right_case_surface = gmsh.model.geo.addPlaneSurface([bottom_right_case_curve_loop]) + + # bottom + bottom_case_bottom_left_point = gmsh.model.geo.addPoint(bl_point_pos[0], bl_point_pos[1] - case_gap_bot,bl_point_pos[2], mesh) + bottom_case_bottom_line = gmsh.model.geo.addLine(bottom_right_case_bottom_point, bottom_case_bottom_left_point) + bottom_case_left_line = gmsh.model.geo.addLine(bottom_case_bottom_left_point, bl_point) + bottom_case_curve_loop = gmsh.model.geo.addCurveLoop([bottom_case_bottom_line, bottom_case_left_line, bottom_right_case_left_line] + bottom_lines) + bottom_case_surface = gmsh.model.geo.addPlaneSurface([bottom_case_curve_loop]) + + + + + + + elif self.model.core.core_type == CoreType.Stacked: + # Core point and line tags + core_point_tags = [] + core_line_tags = [] + if self.model.air_gaps.number == 0: # TODO... + core_point_tags = [11, 10, 9, 4, 3, 2] + core_line_tags = [6, 5, 4, 3, 2] + else: + core_point_tags = [11, 10, 9, 4, 3, 2] + core_line_tags = [6, 5, 4, 3, 2] + + tl_point = core_point_tags[0] # Top left default 11 + tr_point = core_point_tags[1] # Top right default 10 + br_point = core_point_tags[4] # Bottom right default 3 + bl_point = core_point_tags[5] # Bottom left default 2 + + top_lines = core_line_tags[0] # default 6 + right_line = [core_line_tags[1], core_line_tags[2], core_line_tags[3]] # default 5 +4 +3 + bottom_lines = core_line_tags[4] # default 2 + + # Get positions from points + tl_point_pos = gmsh.model.getValue(0, tl_point, []) + tr_point_pos = gmsh.model.getValue(0, tr_point, []) + br_point_pos = gmsh.model.getValue(0, br_point, []) + bl_point_pos = gmsh.model.getValue(0, bl_point, []) + + mesh = self.mesh_data.c_core * 4 + # Create 5 new areas: top, top right, right, bottom right, bottom + # top + top_case_left_point = gmsh.model.geo.addPoint(tl_point_pos[0], tl_point_pos[1] + case_gap_top,tl_point_pos[2], mesh) + top_case_right_point = gmsh.model.geo.addPoint(tr_point_pos[0], tr_point_pos[1] + case_gap_top,tr_point_pos[2], mesh) + top_case_left_line = gmsh.model.geo.addLine(tl_point, top_case_left_point) + top_case_top_line = gmsh.model.geo.addLine(top_case_left_point, top_case_right_point) + top_case_right_line = gmsh.model.geo.addLine(top_case_right_point, tr_point) + top_case_curve_loop = gmsh.model.geo.addCurveLoop([top_case_left_line, top_case_top_line, top_case_right_line, top_lines]) + top_case_surface = gmsh.model.geo.addPlaneSurface([top_case_curve_loop]) + + # top right + top_right_case_top_right_point = gmsh.model.geo.addPoint(tr_point_pos[0] + case_gap_right,tr_point_pos[1] + case_gap_top, tr_point_pos[2],mesh) + top_right_case_right_point = gmsh.model.geo.addPoint(tr_point_pos[0] + case_gap_right, tr_point_pos[1],tr_point_pos[2], mesh) + top_right_case_bottom_line = gmsh.model.geo.addLine(tr_point, top_right_case_right_point) + top_right_case_right_line = gmsh.model.geo.addLine(top_right_case_right_point,top_right_case_top_right_point) + top_right_case_top_line = gmsh.model.geo.addLine(top_right_case_top_right_point, top_case_right_point) + top_right_case_curve_loop = gmsh.model.geo.addCurveLoop([top_case_right_line, top_right_case_bottom_line, top_right_case_right_line, top_right_case_top_line]) + top_right_case_surface = gmsh.model.geo.addPlaneSurface([top_right_case_curve_loop]) + + # right + right_case_bottom_point = gmsh.model.geo.addPoint(br_point_pos[0] + case_gap_right, br_point_pos[1], br_point_pos[2], mesh) + right_case_right_line = gmsh.model.geo.addLine(top_right_case_right_point, right_case_bottom_point) + right_case_bottom_line = gmsh.model.geo.addLine(right_case_bottom_point, br_point) + right_case_curve_loop = gmsh.model.geo.addCurveLoop([top_right_case_bottom_line, right_case_right_line, right_case_bottom_line] + right_line) + right_case_surface = gmsh.model.geo.addPlaneSurface([right_case_curve_loop]) + + # bottom right + bottom_right_case_bottom_right_point = gmsh.model.geo.addPoint(br_point_pos[0] + case_gap_right,br_point_pos[1] - case_gap_bot,br_point_pos[2], mesh) + bottom_right_case_bottom_point = gmsh.model.geo.addPoint(br_point_pos[0], br_point_pos[1] - case_gap_bot,br_point_pos[2], mesh) + bottom_right_case_left_line = gmsh.model.geo.addLine(br_point, bottom_right_case_bottom_point) + bottom_right_case_bottom_line = gmsh.model.geo.addLine(bottom_right_case_bottom_point,bottom_right_case_bottom_right_point) + bottom_right_case_right_line = gmsh.model.geo.addLine(bottom_right_case_bottom_right_point,right_case_bottom_point) + bottom_right_case_curve_loop = gmsh.model.geo.addCurveLoop([right_case_bottom_line, bottom_right_case_left_line, bottom_right_case_bottom_line,bottom_right_case_right_line]) + bottom_right_case_surface = gmsh.model.geo.addPlaneSurface([bottom_right_case_curve_loop]) + + # bottom + bottom_case_bottom_left_point = gmsh.model.geo.addPoint(bl_point_pos[0], bl_point_pos[1] - case_gap_bot,bl_point_pos[2], mesh) + bottom_case_bottom_line = gmsh.model.geo.addLine(bottom_right_case_bottom_point,bottom_case_bottom_left_point) + bottom_case_left_line = gmsh.model.geo.addLine(bottom_case_bottom_left_point, bl_point) + bottom_case_curve_loop = gmsh.model.geo.addCurveLoop([bottom_case_bottom_line, bottom_case_left_line, bottom_right_case_left_line, bottom_lines]) + bottom_case_surface = gmsh.model.geo.addPlaneSurface([bottom_case_curve_loop]) + + + - # Core point and line tags - core_point_tags = [] - core_line_tags = [] - if self.model.air_gaps.number == 0: # TODO... - core_point_tags = [4, 3, 2, 1] - core_line_tags = [4, 3, 2] - else: - core_point_tags = [7, 6, 5, 4, 3, 2] - core_line_tags = [7, 6, 5, 4, 3] - - tl_point = core_point_tags[0] # Top left - default 5 - tr_point = core_point_tags[2] # Top right - default 4 - br_point = core_point_tags[3] # Bottom right - default 3 - bl_point = core_point_tags[5] # Bottom left - default 2 - - top_lines = [core_line_tags[0], core_line_tags[1]] # default 4 - right_line = core_line_tags[2] # default 3 - bottom_lines = [core_line_tags[3], core_line_tags[4]] # default 2 - - # Get positions from points - tl_point_pos = gmsh.model.getValue(0, tl_point, []) - tr_point_pos = gmsh.model.getValue(0, tr_point, []) - br_point_pos = gmsh.model.getValue(0, br_point, []) - bl_point_pos = gmsh.model.getValue(0, bl_point, []) - - mesh = self.mesh_data.c_core * 4 # It typically does not need to be the same size as c_core, but it shouldn't be too big either - - # Create 5 new areas: top, top right, right, bottom right, bottom - # top - top_case_left_point = gmsh.model.geo.addPoint(tl_point_pos[0], tl_point_pos[1] + case_gap_top, tl_point_pos[2], mesh) - top_case_right_point = gmsh.model.geo.addPoint(tr_point_pos[0], tr_point_pos[1] + case_gap_top, tr_point_pos[2], mesh) - top_case_left_line = gmsh.model.geo.addLine(tl_point, top_case_left_point) - top_case_top_line = gmsh.model.geo.addLine(top_case_left_point, top_case_right_point) - top_case_right_line = gmsh.model.geo.addLine(top_case_right_point, tr_point) - top_case_curve_loop = gmsh.model.geo.addCurveLoop([top_case_left_line, top_case_top_line, top_case_right_line]+top_lines) - top_case_surface = gmsh.model.geo.addPlaneSurface([top_case_curve_loop]) - - - # top right - top_right_case_top_right_point = gmsh.model.geo.addPoint(tr_point_pos[0] + case_gap_right, tr_point_pos[1] + case_gap_top, tr_point_pos[2], mesh) - top_right_case_right_point = gmsh.model.geo.addPoint(tr_point_pos[0] + case_gap_right, tr_point_pos[1], tr_point_pos[2], mesh) - top_right_case_bottom_line = gmsh.model.geo.addLine(tr_point, top_right_case_right_point) - top_right_case_right_line = gmsh.model.geo.addLine(top_right_case_right_point, top_right_case_top_right_point) - top_right_case_top_line = gmsh.model.geo.addLine(top_right_case_top_right_point, top_case_right_point) - top_right_case_curve_loop = gmsh.model.geo.addCurveLoop([top_case_right_line, top_right_case_bottom_line, top_right_case_right_line, top_right_case_top_line]) - top_right_case_surface = gmsh.model.geo.addPlaneSurface([top_right_case_curve_loop]) - - # right - right_case_bottom_point = gmsh.model.geo.addPoint(br_point_pos[0] + case_gap_right, br_point_pos[1], br_point_pos[2], mesh) - right_case_right_line = gmsh.model.geo.addLine(top_right_case_right_point, right_case_bottom_point) - right_case_bottom_line = gmsh.model.geo.addLine(right_case_bottom_point, br_point) - right_case_curve_loop = gmsh.model.geo.addCurveLoop([top_right_case_bottom_line, right_case_right_line, right_case_bottom_line, right_line]) - right_case_surface = gmsh.model.geo.addPlaneSurface([right_case_curve_loop]) - - # bottom right - bottom_right_case_bottom_right_point = gmsh.model.geo.addPoint(br_point_pos[0] + case_gap_right, br_point_pos[1] - case_gap_bot, br_point_pos[2], mesh) - bottom_right_case_bottom_point = gmsh.model.geo.addPoint(br_point_pos[0], br_point_pos[1] - case_gap_bot, br_point_pos[2], mesh) - bottom_right_case_left_line = gmsh.model.geo.addLine(br_point, bottom_right_case_bottom_point) - bottom_right_case_bottom_line = gmsh.model.geo.addLine(bottom_right_case_bottom_point, bottom_right_case_bottom_right_point) - bottom_right_case_right_line = gmsh.model.geo.addLine(bottom_right_case_bottom_right_point, right_case_bottom_point) - bottom_right_case_curve_loop = gmsh.model.geo.addCurveLoop([right_case_bottom_line, bottom_right_case_left_line, bottom_right_case_bottom_line, bottom_right_case_right_line]) - bottom_right_case_surface = gmsh.model.geo.addPlaneSurface([bottom_right_case_curve_loop]) - - # bottom - bottom_case_bottom_left_point = gmsh.model.geo.addPoint(bl_point_pos[0], bl_point_pos[1] - case_gap_bot, bl_point_pos[2], mesh) - bottom_case_bottom_line = gmsh.model.geo.addLine(bottom_right_case_bottom_point, bottom_case_bottom_left_point) - bottom_case_left_line = gmsh.model.geo.addLine(bottom_case_bottom_left_point, bl_point) - bottom_case_curve_loop = gmsh.model.geo.addCurveLoop([bottom_case_bottom_line, bottom_case_left_line, bottom_right_case_left_line]+bottom_lines) - bottom_case_surface = gmsh.model.geo.addPlaneSurface([bottom_case_curve_loop]) gmsh.model.geo.synchronize() @@ -1499,7 +1580,10 @@ def generate_thermal_mesh(self, case_gap_top, case_gap_right, case_gap_bot, colo # Define physical Surfaces and Curves # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Core - self.ps_core = gmsh.model.geo.addPhysicalGroup(2, self.plane_surface_core, tag=120000) # TODO: for stacked (modular) core geometry + self.ps_core = [] + for i in range(0, len(self.plane_surface_core)): + self.ps_core.append(gmsh.model.geo.addPhysicalGroup(2, [self.plane_surface_core[i]], tag=120000+i)) + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Conductors @@ -1512,7 +1596,10 @@ def generate_thermal_mesh(self, case_gap_top, case_gap_right, case_gap_bot, colo for ww in self.model.winding_windows: for vww in ww.virtual_winding_windows: for index, winding in enumerate(self.windings): - flattened_turns[winding.winding_number] += vww.turns[index] + try: + flattened_turns[winding.winding_number] += vww.turns[index] + except: + pass for winding in self.windings: winding_number = winding.winding_number @@ -1533,26 +1620,27 @@ def generate_thermal_mesh(self, case_gap_top, case_gap_right, case_gap_bot, colo gmsh.model.geo.addPhysicalGroup(2, [self.plane_surface_cond[winding_number][i]], tag=130000 + 1000 * winding_number + i)) - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Air - self.ps_air = gmsh.model.geo.addPhysicalGroup(2, self.plane_surface_air, tag=110000) + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Air gaps + # air and Air gaps if self.model.core.core_type == CoreType.Single: + self.ps_air = gmsh.model.geo.addPhysicalGroup(2, self.plane_surface_air, tag=110000) self.ps_air_gaps = gmsh.model.geo.addPhysicalGroup(2, self.plane_surface_air_gaps, tag=110001) #trying by Othman for stacked transformer elif self.model.core.core_type == CoreType.Stacked: air_total = self.plane_surface_air_bot + self.plane_surface_air_top self.ps_air_gaps = gmsh.model.geo.addPhysicalGroup(2, air_total, tag=110001) + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # insulations # TODO Currently insulations can only have the same material self.ps_insulation = gmsh.model.geo.addPhysicalGroup(2, self.plane_surface_iso_core) - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Boundary self.thermal_boundary_region_tags = { "BOUNDARY_TOP": top_case_top_line, @@ -1565,7 +1653,9 @@ def generate_thermal_mesh(self, case_gap_top, case_gap_right, case_gap_bot, colo } for key in self.thermal_boundary_region_tags: - self.thermal_boundary_region_tags[key] = ff.create_physical_group(1, [self.thermal_boundary_region_tags[key]], key) + self.thermal_boundary_region_tags[key] = ff.create_physical_group(1, + [self.thermal_boundary_region_tags[key]], + key) # Add surface physical groups # INFO: The physical groups are not created in the createRectWithPhysicalGroup because it causes a bug with the index counter when @@ -1573,16 +1663,17 @@ def generate_thermal_mesh(self, case_gap_top, case_gap_right, case_gap_bot, colo top_surface_physical_group = ff.create_physical_group(2, [top_case_surface], "TopCase") top_right_surface_physical_group = ff.create_physical_group(2, [top_right_case_surface], "TopRightCase") right_surface_physical_group = ff.create_physical_group(2, [right_case_surface], "RightCase") - bottom_right_surface_physical_group = ff.create_physical_group(2, [bottom_right_case_surface], "BottomRightCase") + bottom_right_surface_physical_group = ff.create_physical_group(2, [bottom_right_case_surface], + "BottomRightCase") bottom_surface_physical_group = ff.create_physical_group(2, [bottom_case_surface], "BottomCase") self.thermal_boundary_ps_groups = [top_surface_physical_group, top_right_surface_physical_group, - right_surface_physical_group, bottom_right_surface_physical_group, bottom_surface_physical_group] - + right_surface_physical_group, bottom_right_surface_physical_group, + bottom_surface_physical_group] # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Set names [optional] - for i in range(0, len(self.plane_surface_core)): - gmsh.model.setPhysicalName(2, self.ps_core, f"CORE") # TODO: for stacked (modular) core geometry + for i in range(len(self.plane_surface_core)): + gmsh.model.setPhysicalName(2, self.ps_core[i], f"CORE{i+1}") for num in range(len(self.windings)): for i in range(len(self.ps_cond[num])): gmsh.model.setPhysicalName(2, self.ps_cond[num][i], f"COND{num + 1}") @@ -1602,7 +1693,8 @@ def generate_thermal_mesh(self, case_gap_top, case_gap_right, case_gap_bot, colo # Set case color to core color for sf in [top_case_surface, top_right_case_surface, right_case_surface, bottom_right_case_surface, bottom_case_surface]: - gmsh.model.setColor([(2, sf)], color_case[0], color_case[1], color_case[2], recursive=True) + gmsh.model.setColor([(2, sf)], color_case[0], color_case[1], color_case[2], recursive=True) + # core color for i in range(len(self.plane_surface_core)): @@ -1615,7 +1707,8 @@ def generate_thermal_mesh(self, case_gap_top, case_gap_right, case_gap_bot, colo color_air_gap[2], recursive=True) # air/potting-material inside core window - gmsh.model.setColor([(2, self.plane_surface_air[0])], color_background[0], color_background[1], color_background[2], recursive=True) + if self.model.core.core_type == CoreType.Single: + gmsh.model.setColor([(2, self.plane_surface_air[0])], color_background[0], color_background[1], color_background[2], recursive=True) # winding colors for winding_number in range(len(self.windings)): diff --git a/femmt/thermal/thermal_classes.py b/femmt/thermal/thermal_classes.py index 668d6880..558c0ac7 100644 --- a/femmt/thermal/thermal_classes.py +++ b/femmt/thermal/thermal_classes.py @@ -45,7 +45,7 @@ def create_file(self, file_path, air_gaps_enabled = False, insulation_enabled = insulation = ", insulation" fd.write(f"\tCold = Region[{{air, case_top, case_top_right, case_right, case_bot_right, case_bot{air_gaps}{insulation}}}];\n") - fd.write("\tWarm = Region[{core, windings_total}];\n") + fd.write("\tWarm = Region[{core_total, windings_total}];\n") fd.write("\tTotal = Region[{Warm, Cold}];\n") fd.write("}") diff --git a/femmt/thermal/thermal_simulation.py b/femmt/thermal/thermal_simulation.py index b403ae32..0e9c3c8d 100644 --- a/femmt/thermal/thermal_simulation.py +++ b/femmt/thermal/thermal_simulation.py @@ -3,7 +3,7 @@ import json import numpy as np import os -from typing import Dict +from typing import Dict, List # Third parry libraries import gmsh @@ -15,6 +15,8 @@ from femmt.data import FileData + + def create_case(boundary_regions, boundary_physical_groups, boundary_temperatures, boundary_flags, k_case, function_pro: FunctionPro, parameters_pro: ParametersPro, group_pro: GroupPro, constraint_pro: ConstraintPro): @@ -63,28 +65,39 @@ def create_background(background_tag, k_air, function_pro: FunctionPro, group_pr group_pro.add_regions({"air": background_tag}) -def create_core_and_air_gaps(core_tag, k_core, core_area, core_losses, air_gaps_tag, k_air_gaps, +def create_core_and_air_gaps(core_tags, k_core, core_area, core_parts_losses, air_gaps_tag, k_air_gaps, function_pro: FunctionPro, group_pro: GroupPro): - heat_flux = core_losses / core_area - print(heat_flux) + + + q_vol = {} # Dictionary to hold volumetric heat flux for each core part + k = {} # Dictionary to hold thermal conductivity for each core part + regions = {} # Dictionary to hold regions for each core part + core_total_str = "{" + + core_tags = [[tag] for tag in core_tags] + for index, tag in enumerate(core_tags): + #tag = tag_list[0] + name = f"core_part_{index + 1}" # Create a name for the core part based on its position + core_total_str += f"{name}, " + + # Compute the heat flux for the core part using its loss and area + q_vol[name] = core_parts_losses[index] / core_area[index] # TODO Core_area should be calculated for every core_part + + # Store the thermal conductivity of the core part + k[name] = k_core + + # Associate the core part name with its tag + regions[name] = tag[0] # as Tag is list of list + if air_gaps_tag is not None: - k = { - "core": k_core, - "air_gaps": k_air_gaps - } - q_vol = { - "core": heat_flux - } - group_pro.add_regions({ - "core": core_tag, - "air_gaps": air_gaps_tag - }) - function_pro.add_dicts(k, q_vol) - else: - k = {"core": k_core} - q_vol = {"core": heat_flux} - group_pro.add_regions({"core": core_tag}) - function_pro.add_dicts(k, q_vol) + k["air_gaps"] = k_air_gaps + regions["air_gaps"] = air_gaps_tag + + regions["core_total"] = core_total_str[:-2] + "}" + # Update the function_pro and group_pro objects with the newly computed dictionaries + group_pro.add_regions(regions) + function_pro.add_dicts(k, q_vol) + def create_windings(winding_tags, k_windings, winding_losses, conductor_radii, wire_distances, @@ -93,18 +106,37 @@ def create_windings(winding_tags, k_windings, winding_losses, conductor_radii, w k = {} regions = {} windings_total_str = "{" + tag_counters = {} + + + for winding_index, winding in enumerate(winding_tags): if winding is not None and len(winding) > 0: + if winding is not None and len(winding) > 0: + original_winding = winding[:] + + if len(original_winding) > len(winding_losses[winding_index]): + winding_losses[winding_index] = [winding_losses[winding_index][0] / len(original_winding) for _ in range(len(original_winding))] + + + for index, tag in enumerate(winding): name = f"winding_{winding_index}_{index}" windings_total_str += f"{name}, " q_vol[name] = thermal_f.calculate_heat_flux_round_wire(winding_losses[winding_index][index], conductor_radii[winding_index], wire_distances[winding_index][index]) + print(q_vol[name]) k[name] = k_windings - regions[name] = tag + if tag not in tag_counters: # The counter is needed here to create a single region for for every turn in case of parallel windings + tag_counters[tag] = 0 + else: + tag_counters[tag] += 1 + regions[name] = tag + tag_counters[tag] + + # Needs to be added. [:-2] removes the last ', ' regions["windings_total"] = windings_total_str[:-2] + "}" @@ -114,7 +146,7 @@ def create_windings(winding_tags, k_windings, winding_losses, conductor_radii, w def create_post_operation(thermal_file_path, thermal_influx_file_path, thermal_material_file_path, sensor_points_file, - core_file, insulation_file, winding_file, windings, print_sensor_values, + core_file, insulation_file, winding_file, windings, core_parts, print_sensor_values, post_operation_pro: PostOperationPro, flag_insulation): # Add pos file generation post_operation_pro.add_on_elements_of_statement("T", "Total", thermal_file_path) @@ -143,13 +175,30 @@ def create_post_operation(thermal_file_path, thermal_influx_file_path, thermal_m "air_gap_lower", True) # Add regions - post_operation_pro.add_on_elements_of_statement("T", "core", core_file, "SimpleTable", 0) + #core file will be GmshParsed file as we have many core parts + # for core_index, core_part in enumerate(core_parts): # Assuming core_tags is a list of core tags + # name = f"core_part_{core_index + 1}" + # post_operation_pro.add_on_elements_of_statement("T", name, core_file, "GmshParsed", 0, name, True) + core_parts = [[part] for part in core_parts] + core_append = False # Initialize the append flag for core parts + for core_index, core_part in enumerate(core_parts): + if core_part is not None and len(core_part) > 0: + #core_part_value = core_part[0] + + name = f"core_part_{core_index + 1}" + post_operation_pro.add_on_elements_of_statement("T", name, core_file, "GmshParsed", 0, name, core_append) + if not core_append: + core_append = True + + + if flag_insulation: post_operation_pro.add_on_elements_of_statement("T", "insulation", insulation_file, "SimpleTable", 0) append = False for winding_index, winding in enumerate(windings): if winding is not None and len(winding) > 0: + # Remove duplicates from region of parallel windings for index, tag in enumerate(winding): name = f"winding_{winding_index}_{index}" post_operation_pro.add_on_elements_of_statement("T", name, winding_file, "GmshParsed", 0, name, append) @@ -231,6 +280,13 @@ def parse_gmsh_parsed(file_path: str): else: raise Exception(f"Unknown line: {line}") + # Append the last set of current_values to value_dict after the loop ends + if current_values: + if len(current_values) == 1: + value_dict[current_key] = current_values[0] + else: + value_dict[current_key] = np.array(current_values) + return value_dict @@ -261,11 +317,36 @@ def post_operation(case_volume: float, output_file: str, sensor_points_file: str # Extract min/max/averages from core, insulations and windings (and air?) # core - core_values = parse_simple_table(core_file) - core_min = core_values.min() - core_max = core_values.max() - core_mean = core_values.mean() + core_values = parse_gmsh_parsed(core_file) + core_parts = {} + core_part_min = float('inf') + core_part_max = -float('inf') + mean_sum = 0 + + + for core_items, core_value in core_values.items(): + current_min = core_value.min() + current_max = core_value.max() + current_mean = core_value.mean() + core_parts[core_items] = { + "min": current_min, + "max": current_max, + "mean": current_mean + } + if current_min < core_part_min: + core_part_min = current_min + + if current_max > core_part_max: + core_part_max = current_max + + mean_sum += current_mean + core_parts["total"] = { + "min": core_part_min, + "max": core_part_max, + "mean": mean_sum / len(core_values.keys()) + } + print(len(core_values.keys())) # windings winding_values = parse_gmsh_parsed(winding_file) windings = {} @@ -298,18 +379,14 @@ def post_operation(case_volume: float, output_file: str, sensor_points_file: str "max": winding_max, "mean": mean_sum / len(winding_values.keys()) } - + print(len(winding_values.keys())) misc = { "case_volume": case_volume, "case_weight": -1, } # Fill data for json file data = { - "core": { - "min": core_min, - "max": core_max, - "mean": core_mean - }, + "core_parts": core_parts, "windings": windings, "misc": misc } @@ -339,7 +416,7 @@ def post_operation(case_volume: float, output_file: str, sensor_points_file: str def run_thermal(file_data: FileData, tags_dict: Dict, thermal_conductivity_dict: Dict, boundary_temperatures: Dict, - boundary_flags: Dict, boundary_physical_groups: Dict, core_area: float, conductor_radii: float, + boundary_flags: Dict, boundary_physical_groups: Dict, core_area: List, conductor_radii: float, wire_distances: float, case_volume: float, show_thermal_fem_results: bool, print_sensor_values: bool, silent: bool, flag_insulation: bool = True): """ @@ -418,32 +495,39 @@ def run_thermal(file_data: FileData, tags_dict: Dict, thermal_conductivity_dict: + # Extract core_parts losses as a list + core_parts_losses = [] + + core_part_keys = [key for key in losses.keys() if key.startswith("total_core_part_")] + for key in core_part_keys: + core_parts_losses.append(losses[key]) + + + - core_losses = losses["core"] # TODO All those pro classes could be used as global variables create_case(tags_dict["boundary_regions"], boundary_physical_groups, boundary_temperatures, boundary_flags, thermal_conductivity_dict["case"], function_pro, parameters_pro, group_pro, constraint_pro) create_background(tags_dict["background_tag"], thermal_conductivity_dict["air"], function_pro, group_pro) - create_core_and_air_gaps(tags_dict["core_tag"], thermal_conductivity_dict["core"], core_area, core_losses, + + create_core_and_air_gaps(tags_dict["core_tags"], thermal_conductivity_dict["core"], core_area, core_parts_losses, tags_dict["air_gaps_tag"], thermal_conductivity_dict["air_gaps"], function_pro, group_pro) create_windings(tags_dict["winding_tags"], thermal_conductivity_dict["winding"], winding_losses, conductor_radii, wire_distances, function_pro, group_pro) - create_insulation(tags_dict["insulations_tag"], thermal_conductivity_dict["insulation"], function_pro, group_pro) if flag_insulation else None - # create_post_operation(map_pos_file.replace("\\", "/"), influx_pos_file.replace("\\", "/"), material_pos_file.replace("\\", "/"), sensor_points_file, core_file, - # insulation_file, winding_file, tags_dict["winding_tags"], post_operation_pro) create_post_operation(map_pos_file, influx_pos_file, material_pos_file, sensor_points_file, core_file, - insulation_file, winding_file, tags_dict["winding_tags"], print_sensor_values, + insulation_file, winding_file, tags_dict["winding_tags"], tags_dict["core_tags"], print_sensor_values, post_operation_pro, flag_insulation) # Create files parameters_pro.create_file(parameters_file) function_pro.create_file(function_file) - group_pro.create_file(group_file, tags_dict ["air_gaps_tag"] is not None, tags_dict["insulations_tag"] is not None) + + group_pro.create_file(group_file, tags_dict["air_gaps_tag"] is not None, tags_dict["insulations_tag"] is not None) constraint_pro.create_file(constraint_file) post_operation_pro.create_file(post_operation_file) diff --git a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle.json b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle.json index b3c5f608..5fd58be1 100644 --- a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle.json +++ b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle.json @@ -4,79 +4,83 @@ "f": 100000, "winding1": { "turn_losses": [ - 0.08057736083103678, - 0.07733072579894379, - 0.04964844751630253, - 0.02073763111638337, - 0.009391229664298572, - 0.02095646453242342, - 0.05024729254017496, - 0.07868650499175549, - 0.08333939165381178 + 0.08057736083105702, + 0.07733072579898291, + 0.04964844751628478, + 0.02073763111638346, + 0.009391229664306087, + 0.02095646453242996, + 0.05024729254020058, + 0.07868650499176949, + 0.08333939165383826 ], "flux": [ - 9.353580088139323e-05, - -8.007450177064308e-07 + 9.353580088140036e-05, + -8.007450177058432e-07 ], "flux_over_current": [ - 2.0785702006433566e-05, - -1.8140655278295135e-07 + 2.0785702006435094e-05, + -1.8140655278282152e-07 ], "V": [ - 0.512914944182372, - 58.77018785080648 + 0.512914944182005, + 58.7701878508108 ], "number_turns": 9, "I": [ 4.5, 0.0 ], - "winding_losses": 0.4709150486451306, - "P": 1.154058624410337, - "Q": 132.23292266431457, - "S": 132.23795857338078 + "winding_losses": 0.4709150486452519, + "P": 1.1540586244095112, + "Q": 132.2329226643243, + "S": 132.2379585733905 }, - "core_eddy_losses": 0.01571862829606287, - "core_hyst_losses": 0.6686138218303596, + "core_eddy_losses": 0.01571862829606507, + "core_hyst_losses": 0.6686138218304594, "core_parts": { "core_part_1": { - "eddy_losses": 0.00657139049155327, - "hyst_losses": 0.4701989479225411 + "eddy_losses": 0.00657139049155419, + "hyst_losses": 0.4701989479226126, + "total_core_part_1": 0.47677033841416677 }, "core_part_2": { - "eddy_losses": 0.00914723780450959, - "hyst_losses": 0.1984148739078189 + "eddy_losses": 0.009147237804510891, + "hyst_losses": 0.1984148739078468, + "total_core_part_2": 0.20756211171235767 } }, - "all_winding_losses": 0.4709150486451306 + "all_winding_losses": 0.4709150486452519 } ], "total_losses": { "winding1": { - "total": 0.4709150486451307, + "total": 0.47091504864525247, "turns": [ - 0.08057736083103678, - 0.07733072579894379, - 0.04964844751630253, - 0.02073763111638337, - 0.009391229664298572, - 0.02095646453242342, - 0.05024729254017496, - 0.07868650499175549, - 0.08333939165381178 + 0.08057736083105702, + 0.07733072579898291, + 0.04964844751628478, + 0.02073763111638346, + 0.009391229664306087, + 0.02095646453242996, + 0.05024729254020058, + 0.07868650499176949, + 0.08333939165383826 ] }, - "all_windings": 0.4709150486451306, - "eddy_core": 0.01571862829606287, - "hyst_core_fundamental_freq": 0.6686138218303596, - "core": 0.6843324501264224, - "total_losses": 1.155247498771553 + "all_windings": 0.4709150486452519, + "eddy_core": 0.01571862829606507, + "total_core_part_1": 0.47677033841416677, + "total_core_part_2": 0.20756211171235767, + "hyst_core_fundamental_freq": 0.6686138218304594, + "core": 0.6843324501265244, + "total_losses": 1.1552474987717765 }, "simulation_settings": { "simulation_name": null, - "date": "2023-08-25 10:54:09", + "date": "2023-10-20 15:17:45", "component_type": "Inductor", - "working_directory": "/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/tests/integration/temp", + "working_directory": "C:\\Users\\samba\\PycharmProjects\\FEM_Magnetics_Toolbox\\tests\\integration\\temp", "core": { "core_inner_diameter": 0.0149, "window_w": 0.01105, diff --git a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_foil_horizontal.json b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_foil_horizontal.json index f055989e..62f096e1 100644 --- a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_foil_horizontal.json +++ b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_foil_horizontal.json @@ -4,75 +4,81 @@ "f": 100000, "winding1": { "turn_losses": [ - 0.002926614321648473, - 0.01202647879613398, - 0.0313486608531296, - 0.06067189436246943, - 0.09946534075498803, - 0.1458352784303493, - 0.1940968150775521, - 0.2335115162500874, - 0.2702535701556243, - 0.2346330428645974, - 0.07097138625542547, - 0.01538738828999806 + 0.002926614321643067, + 0.01202647879611364, + 0.03134866085309905, + 0.06067189436241932, + 0.09946534075490532, + 0.1458352784303187, + 0.1940968150774607, + 0.2335115162499131, + 0.2702535701554756, + 0.234633042864431, + 0.07097138625537025, + 0.01538738828998796 ], "flux": [ - 0.0002072748943729928, - -3.869262321510046e-06 + 0.0002072748943729242, + -3.869262321408718e-06 ], "flux_over_current": [ - 6.909160848621864e-05, - -1.2922809836602567e-06 + 6.909160848619572e-05, + -1.2922809836264764e-06 ], "V": [ - 2.435892266784512, - 130.234613787004 + 2.435892266720838, + 130.2346137869608 ], "number_turns": 12, "I": [ 3.0, 0.0 ], - "winding_losses": 1.371127986412009, - "P": 3.6538384001767685, - "Q": 195.351920680506, - "S": 195.38608816550197 + "winding_losses": 1.371127986411141, + "P": 3.6538384000812565, + "Q": 195.3519206804412, + "S": 195.38608816543538 }, - "core_eddy_losses": 0.05498444728977709, - "core_hyst_losses": 2.227725967733116, - "all_winding_losses": 1.371127986412009 + "core_eddy_losses": 0.05498444728973803, + "core_hyst_losses": 2.227725967731544, + "core_parts": { + "core_part_1": { + "total_core_part_1": 2.282710415021282 + } + }, + "all_winding_losses": 1.371127986411141 } ], "total_losses": { "winding1": { - "total": 1.3711279864120036, + "total": 1.3711279864111376, "turns": [ - 0.002926614321648473, - 0.01202647879613398, - 0.0313486608531296, - 0.06067189436246943, - 0.09946534075498803, - 0.1458352784303493, - 0.1940968150775521, - 0.2335115162500874, - 0.2702535701556243, - 0.2346330428645974, - 0.07097138625542547, - 0.01538738828999806 + 0.002926614321643067, + 0.01202647879611364, + 0.03134866085309905, + 0.06067189436241932, + 0.09946534075490532, + 0.1458352784303187, + 0.1940968150774607, + 0.2335115162499131, + 0.2702535701554756, + 0.234633042864431, + 0.07097138625537025, + 0.01538738828998796 ] }, - "all_windings": 1.371127986412009, - "eddy_core": 0.05498444728977709, - "hyst_core_fundamental_freq": 2.227725967733116, - "core": 2.2827104150228927, - "total_losses": 3.6538384014349017 + "all_windings": 1.371127986411141, + "eddy_core": 0.05498444728973803, + "total_core_part_1": 2.282710415021282, + "hyst_core_fundamental_freq": 2.227725967731544, + "core": 2.282710415021282, + "total_losses": 3.6538384014324228 }, "simulation_settings": { "simulation_name": null, - "date": "2023-08-25 11:08:42", + "date": "2023-10-20 15:21:58", "component_type": "Inductor", - "working_directory": "/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/tests/integration/temp", + "working_directory": "C:\\Users\\samba\\PycharmProjects\\FEM_Magnetics_Toolbox\\tests\\integration\\temp", "core": { "core_inner_diameter": 0.0149, "window_w": 0.01105, diff --git a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_foil_vertical.json b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_foil_vertical.json index f8bc0148..dde71c9b 100644 --- a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_foil_vertical.json +++ b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_foil_vertical.json @@ -4,61 +4,67 @@ "f": 100000, "winding1": { "turn_losses": [ - 0.08703860017239212, - 0.0217148082740151, - 0.01241587820169207, - 0.00505306816273928, - 0.001046305639598656 + 0.08703860017241397, + 0.02171480827402828, + 0.01241587820170079, + 0.005053068162739305, + 0.001046305639598696 ], "flux": [ - 3.54614125671046e-05, - -5.476756265899682e-07 + 3.546141256710918e-05, + -5.476756265531694e-07 ], "flux_over_current": [ - 1.1820455387871603e-05, - -1.8290641798530918e-07 + 1.1820455387873158e-05, + -1.829064179730445e-07 ], "V": [ - 0.3447704754222428, - 22.28103348517399 + 0.3447704753991244, + 22.28103348517692 ], "number_turns": 5, "I": [ 3.0, 0.0 ], - "winding_losses": 0.1272686604504369, - "P": 0.5171557131333642, - "Q": 33.42155022776098, - "S": 33.4255511496576 + "winding_losses": 0.1272686604504801, + "P": 0.5171557130986866, + "Q": 33.42155022776538, + "S": 33.425551149661466 }, - "core_eddy_losses": 0.00934704409965321, - "core_hyst_losses": 0.3805400084075918, - "all_winding_losses": 0.1272686604504369 + "core_eddy_losses": 0.009347044099655357, + "core_hyst_losses": 0.3805400084076812, + "core_parts": { + "core_part_1": { + "total_core_part_1": 0.3898870525073366 + } + }, + "all_winding_losses": 0.1272686604504801 } ], "total_losses": { "winding1": { - "total": 0.12726866045043722, + "total": 0.12726866045048105, "turns": [ - 0.08703860017239212, - 0.0217148082740151, - 0.01241587820169207, - 0.00505306816273928, - 0.001046305639598656 + 0.08703860017241397, + 0.02171480827402828, + 0.01241587820170079, + 0.005053068162739305, + 0.001046305639598696 ] }, - "all_windings": 0.1272686604504369, - "eddy_core": 0.00934704409965321, - "hyst_core_fundamental_freq": 0.3805400084075918, - "core": 0.389887052507245, - "total_losses": 0.5171557129576818 + "all_windings": 0.1272686604504801, + "eddy_core": 0.009347044099655357, + "total_core_part_1": 0.3898870525073366, + "hyst_core_fundamental_freq": 0.3805400084076812, + "core": 0.3898870525073366, + "total_losses": 0.5171557129578167 }, "simulation_settings": { "simulation_name": null, - "date": "2023-08-25 10:55:48", + "date": "2023-10-20 15:21:05", "component_type": "Inductor", - "working_directory": "/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/tests/integration/temp", + "working_directory": "C:\\Users\\samba\\PycharmProjects\\FEM_Magnetics_Toolbox\\tests\\integration\\temp", "core": { "core_inner_diameter": 0.0149, "window_w": 0.01105, diff --git a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_litz_wire.json b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_litz_wire.json index 28644d47..a725e327 100644 --- a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_litz_wire.json +++ b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_fixed_loss_angle_litz_wire.json @@ -4,79 +4,83 @@ "f": 100000, "winding1": { "turn_losses": [ - 0.01452916689303946, - 0.01400946595135911, - 0.01206386061129302, - 0.01046714667582749, - 0.009788275142277657, - 0.01001979414846602, - 0.01113607639552506, - 0.01321002303158861, - 0.01680378631299536 + 0.01452966795307973, + 0.01400992128334477, + 0.01206414470852072, + 0.01046729020359622, + 0.009788358897470166, + 0.0100198983091005, + 0.01113627889447178, + 0.0132104082127972, + 0.01680448789173269 ], "flux": [ - 9.701679224805312e-05, - -5.195299909702967e-07 + 9.701679210244213e-05, + -5.195320078332932e-07 ], "flux_over_current": [ - 2.1559287166234027e-05, - -1.279664413504589e-07 + 2.155928713387618e-05, + -1.2796689093883517e-07 ], "V": [ - 0.3618165888473677, - 60.95744836026617 + 0.3618178600285537, + 60.95744826877651 ], "number_turns": 9, "I": [ 4.5, 0.0 ], - "winding_losses": 0.1120275951623715, - "P": 0.8140873249065774, - "Q": 137.1542588105989, - "S": 137.15667482137832 + "winding_losses": 0.1120304563541137, + "P": 0.8140901850642458, + "Q": 137.15425860474716, + "S": 137.1566746325066 }, - "core_eddy_losses": 0.01606920614566715, - "core_hyst_losses": 0.6859905236008876, + "core_eddy_losses": 0.01606920612999203, + "core_hyst_losses": 0.6859905225794412, "core_parts": { "core_part_1": { - "eddy_losses": 0.006588393844613568, - "hyst_losses": 0.4799876774696081 + "eddy_losses": 0.006588393838709922, + "hyst_losses": 0.4799876766669126, + "total_core_part_1": 0.4865760705056225 }, "core_part_2": { - "eddy_losses": 0.009480812301053597, - "hyst_losses": 0.2060028461312795 + "eddy_losses": 0.009480812291282073, + "hyst_losses": 0.2060028459125291, + "total_core_part_2": 0.21548365820381116 } }, - "all_winding_losses": 0.1120275951623715 + "all_winding_losses": 0.1120304563541137 } ], "total_losses": { "winding1": { - "total": 0.11202759516237179, + "total": 0.1120304563541138, "turns": [ - 0.01452916689303946, - 0.01400946595135911, - 0.01206386061129302, - 0.01046714667582749, - 0.009788275142277657, - 0.01001979414846602, - 0.01113607639552506, - 0.01321002303158861, - 0.01680378631299536 + 0.01452966795307973, + 0.01400992128334477, + 0.01206414470852072, + 0.01046729020359622, + 0.009788358897470166, + 0.0100198983091005, + 0.01113627889447178, + 0.0132104082127972, + 0.01680448789173269 ] }, - "all_windings": 0.1120275951623715, - "eddy_core": 0.01606920614566715, - "hyst_core_fundamental_freq": 0.6859905236008876, - "core": 0.7020597297465548, - "total_losses": 0.8140873249089263 + "all_windings": 0.1120304563541137, + "eddy_core": 0.01606920612999203, + "total_core_part_1": 0.4865760705056225, + "total_core_part_2": 0.21548365820381116, + "hyst_core_fundamental_freq": 0.6859905225794412, + "core": 0.7020597287094332, + "total_losses": 0.8140901850635469 }, "simulation_settings": { "simulation_name": null, - "date": "2023-08-25 10:54:49", + "date": "2023-10-20 15:20:13", "component_type": "Inductor", - "working_directory": "/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/tests/integration/temp", + "working_directory": "C:\\Users\\samba\\PycharmProjects\\FEM_Magnetics_Toolbox\\tests\\integration\\temp", "core": { "core_inner_diameter": 0.0149, "window_w": 0.01105, diff --git a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_material.json b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_material.json index b88c24d1..778ace9d 100644 --- a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_material.json +++ b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_material.json @@ -4,79 +4,83 @@ "f": 100000, "winding1": { "turn_losses": [ - 0.08053028450355233, - 0.07728908353536308, - 0.04962615944716157, - 0.02073314081596513, - 0.00939374531902322, - 0.02095207127544631, - 0.05022506217548885, - 0.07864470180821359, - 0.08329089156126432 + 0.08053028450358944, + 0.07728908353543255, + 0.04962615944716423, + 0.02073314081596786, + 0.009393745319029501, + 0.02095207127545542, + 0.05022506217551787, + 0.07864470180825203, + 0.08329089156130774 ], "flux": [ - 9.349913016479193e-05, - -3.216209501642105e-07 + 9.349913016482143e-05, + -3.216209501874287e-07 ], "flux_over_current": [ - 2.077755165158173e-05, - -7.493481011443616e-08 + 2.0777551651588228e-05, + -7.493481011959625e-08 ], "V": [ - 0.2118731840582929, - 58.74714326537247 + 0.2118731840728827, + 58.74714326539084 ], "number_turns": 9, "I": [ 4.5, 0.0 ], - "winding_losses": 0.4706851404414779, - "P": 0.476714664131159, - "Q": 132.18107234708805, - "S": 132.18193198655072 + "winding_losses": 0.4706851404417164, + "P": 0.47671466416398606, + "Q": 132.1810723471294, + "S": 132.1819319865922 }, - "core_eddy_losses": 0.005238272112541359, - "core_hyst_losses": 0.1991574304417403, + "core_eddy_losses": 0.005238272112544699, + "core_hyst_losses": 0.1991574304419288, "core_parts": { "core_part_1": { - "eddy_losses": 0.002189318573992297, - "hyst_losses": 0.1365566551601681 + "eddy_losses": 0.002189318573993692, + "hyst_losses": 0.1365566551602975, + "total_core_part_1": 0.13874597373429118 }, "core_part_2": { - "eddy_losses": 0.003048953538549063, - "hyst_losses": 0.06260077528157174 + "eddy_losses": 0.003048953538551015, + "hyst_losses": 0.06260077528163152, + "total_core_part_2": 0.06564972882018254 } }, - "all_winding_losses": 0.4706851404414779 + "all_winding_losses": 0.4706851404417164 } ], "total_losses": { "winding1": { - "total": 0.47068514044147836, + "total": 0.4706851404417166, "turns": [ - 0.08053028450355233, - 0.07728908353536308, - 0.04962615944716157, - 0.02073314081596513, - 0.00939374531902322, - 0.02095207127544631, - 0.05022506217548885, - 0.07864470180821359, - 0.08329089156126432 + 0.08053028450358944, + 0.07728908353543255, + 0.04962615944716423, + 0.02073314081596786, + 0.009393745319029501, + 0.02095207127545542, + 0.05022506217551787, + 0.07864470180825203, + 0.08329089156130774 ] }, - "all_windings": 0.4706851404414779, - "eddy_core": 0.005238272112541359, - "hyst_core_fundamental_freq": 0.1991574304417403, - "core": 0.20439570255428166, - "total_losses": 0.6750808429957595 + "all_windings": 0.4706851404417164, + "eddy_core": 0.005238272112544699, + "total_core_part_1": 0.13874597373429118, + "total_core_part_2": 0.06564972882018254, + "hyst_core_fundamental_freq": 0.1991574304419288, + "core": 0.2043957025544735, + "total_losses": 0.6750808429961899 }, "simulation_settings": { "simulation_name": null, - "date": "2023-08-25 10:50:33", + "date": "2023-10-20 15:18:32", "component_type": "Inductor", - "working_directory": "/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/tests/integration/temp", + "working_directory": "C:\\Users\\samba\\PycharmProjects\\FEM_Magnetics_Toolbox\\tests\\integration\\temp", "core": { "core_inner_diameter": 0.0149, "window_w": 0.01105, diff --git a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_material_measurement.json b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_material_measurement.json index 0ae20d8e..5b95ef8d 100644 --- a/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_material_measurement.json +++ b/tests/integration/fixtures/results/log_electro_magnetic_inductor_core_material_measurement.json @@ -4,79 +4,83 @@ "f": 100000, "winding1": { "turn_losses": [ - 0.07811789012598208, - 0.07513795022513887, - 0.04831962480419095, - 0.02034351490365898, - 0.009378084304544164, - 0.02056313101450804, - 0.04891283403273235, - 0.07647069720144349, - 0.0808052733042793 + 0.07811789012601648, + 0.07513795022519928, + 0.04831962480418833, + 0.02034351490366124, + 0.009378084304557058, + 0.02056313101452742, + 0.04891283403277089, + 0.07647069720147442, + 0.08080527330429722 ], "flux": [ - 9.139573252324786e-05, - -4.27384642285096e-07 + 9.139573252326144e-05, + -4.273846423023933e-07 ], "flux_over_current": [ - 2.0310131003396858e-05, - -9.844369058721532e-08 + 2.0310131003399992e-05, + -9.844369059106052e-08 ], "V": [ - 0.2783429776269561, - 57.42554251834607 + 0.2783429776378281, + 57.42554251835494 ], "number_turns": 9, "I": [ 4.5, 0.0 ], - "winding_losses": 0.4580489999164769, - "P": 0.6262716996606512, - "Q": 129.20747066627865, - "S": 129.20898843431542 + "winding_losses": 0.4580489999166914, + "P": 0.6262716996851132, + "Q": 129.2074706662986, + "S": 129.20898843433548 }, - "core_eddy_losses": 0.005970074514340104, - "core_hyst_losses": 0.4238045669312349, + "core_eddy_losses": 0.005970074514341914, + "core_hyst_losses": 0.4238045669313867, "core_parts": { "core_part_1": { - "eddy_losses": 0.002491994027811744, - "hyst_losses": 0.2942956358669379 + "eddy_losses": 0.002491994027812486, + "hyst_losses": 0.2942956358670434, + "total_core_part_1": 0.29678762989485585 }, "core_part_2": { - "eddy_losses": 0.003478080486528357, - "hyst_losses": 0.1295089310642973 + "eddy_losses": 0.00347808048652944, + "hyst_losses": 0.1295089310643434, + "total_core_part_2": 0.13298701155087286 } }, - "all_winding_losses": 0.4580489999164769 + "all_winding_losses": 0.4580489999166914 } ], "total_losses": { "winding1": { - "total": 0.4580489999164782, + "total": 0.45804899991669235, "turns": [ - 0.07811789012598208, - 0.07513795022513887, - 0.04831962480419095, - 0.02034351490365898, - 0.009378084304544164, - 0.02056313101450804, - 0.04891283403273235, - 0.07647069720144349, - 0.0808052733042793 + 0.07811789012601648, + 0.07513795022519928, + 0.04831962480418833, + 0.02034351490366124, + 0.009378084304557058, + 0.02056313101452742, + 0.04891283403277089, + 0.07647069720147442, + 0.08080527330429722 ] }, - "all_windings": 0.4580489999164769, - "eddy_core": 0.005970074514340104, - "hyst_core_fundamental_freq": 0.4238045669312349, - "core": 0.42977464144557503, - "total_losses": 0.8878236413620519 + "all_windings": 0.4580489999166914, + "eddy_core": 0.005970074514341914, + "total_core_part_1": 0.29678762989485585, + "total_core_part_2": 0.13298701155087286, + "hyst_core_fundamental_freq": 0.4238045669313867, + "core": 0.4297746414457286, + "total_losses": 0.88782364136242 }, "simulation_settings": { "simulation_name": null, - "date": "2023-08-25 10:52:44", + "date": "2023-10-20 15:19:38", "component_type": "Inductor", - "working_directory": "/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/tests/integration/temp", + "working_directory": "C:\\Users\\samba\\PycharmProjects\\FEM_Magnetics_Toolbox\\tests\\integration\\temp", "core": { "core_inner_diameter": 0.0149, "window_w": 0.01105, diff --git a/tests/integration/fixtures/results/log_electro_magnetic_thermal.json b/tests/integration/fixtures/results/log_electro_magnetic_thermal.json index 404dc069..7f1de2b9 100644 --- a/tests/integration/fixtures/results/log_electro_magnetic_thermal.json +++ b/tests/integration/fixtures/results/log_electro_magnetic_thermal.json @@ -4,67 +4,73 @@ "f": 100000, "winding1": { "turn_losses": [ - 0.005191803070663505, - 0.02381013923074908, - 0.06068039921025378, - 0.09263788641827077, - 0.152293203412263, - 0.04825064671041769, - 0.02263980055268162, - 0.004988884101271357 + 0.005191803070657385, + 0.02381013923073857, + 0.06068039921019962, + 0.09263788641818624, + 0.1522932034121882, + 0.04825064671041221, + 0.02263980055268533, + 0.004988884101278411 ], "flux": [ - 9.13499633161381e-05, - -1.481437190961602e-06 + 9.134996331611467e-05, + -1.481437190952988e-06 ], "flux_over_current": [ - 3.044996922625107e-05, - -4.957253860059524e-07 + 3.0449969226243222e-05, + -4.957253860030809e-07 ], "V": [ - 0.9344203385245585, - 57.39683977393538 + 0.9344203385191461, + 57.39683977392059 ], "number_turns": 8, "I": [ 3.0, 0.0 ], - "winding_losses": 0.4104927627065708, - "P": 1.4016305077868378, - "Q": 86.09525966090308, - "S": 86.10666817476266 + "winding_losses": 0.4104927627063445, + "P": 1.401630507778719, + "Q": 86.09525966088088, + "S": 86.10666817474034 }, "core_eddy_losses": 0.0, - "core_hyst_losses": 0.9922305174941147, - "all_winding_losses": 0.4104927627065708 + "core_hyst_losses": 0.9922305174935993, + "core_parts": { + "core_part_1": { + "total_core_part_1": 0.9922305174935993 + } + }, + "all_winding_losses": 0.4104927627063445 } ], "total_losses": { "winding1": { - "total": 0.41049276270657076, + "total": 0.41049276270634594, "turns": [ - 0.005191803070663505, - 0.02381013923074908, - 0.06068039921025378, - 0.09263788641827077, - 0.152293203412263, - 0.04825064671041769, - 0.02263980055268162, - 0.004988884101271357 + 0.005191803070657385, + 0.02381013923073857, + 0.06068039921019962, + 0.09263788641818624, + 0.1522932034121882, + 0.04825064671041221, + 0.02263980055268533, + 0.004988884101278411 ] }, - "all_windings": 0.4104927627065708, + "all_windings": 0.4104927627063445, "eddy_core": 0.0, - "hyst_core_fundamental_freq": 0.9922305174941147, - "core": 0.9922305174941147, - "total_losses": 1.4027232802006855 + "total_core_part_1": 0.9922305174935993, + "hyst_core_fundamental_freq": 0.9922305174935993, + "core": 0.9922305174935993, + "total_losses": 1.4027232801999436 }, "simulation_settings": { "simulation_name": null, - "date": "2023-08-25 11:28:05", + "date": "2023-10-20 15:24:30", "component_type": "Inductor", - "working_directory": "/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/tests/integration/temp", + "working_directory": "C:\\Users\\samba\\PycharmProjects\\FEM_Magnetics_Toolbox\\tests\\integration\\temp", "core": { "core_inner_diameter": 0.0149, "window_w": 0.01105, diff --git a/tests/integration/fixtures/results/log_electro_magnetic_transformer_core_fixed_loss_angle.json b/tests/integration/fixtures/results/log_electro_magnetic_transformer_core_fixed_loss_angle.json index 8bc1df2d..814e6d05 100644 --- a/tests/integration/fixtures/results/log_electro_magnetic_transformer_core_fixed_loss_angle.json +++ b/tests/integration/fixtures/results/log_electro_magnetic_transformer_core_fixed_loss_angle.json @@ -4,121 +4,127 @@ "f": 250000, "winding1": { "turn_losses": [ - 0.8151200364865538, - 0.5967245714024573, - 0.3187610560944258, - 0.1233077276732152, - 0.02569372569938749, - 0.6532107937573608, - 0.4792623946019697, - 0.2612114242099259, - 0.1035863236354099, - 0.0239885741373234 + 0.8151200364865472, + 0.5967245714024684, + 0.3187610560944314, + 0.1233077276732099, + 0.02569372569938718, + 0.6532107937573823, + 0.4792623946019806, + 0.261211424209924, + 0.103586323635406, + 0.0239885741373241 ], "flux": [ - 8.308164983303328e-06, - 5.606859512698774e-06 + 8.308164983294942e-06, + 5.606859512692874e-06 ], "flux_over_current": [ - 2.0770328527066046e-06, - 1.3995822736807956e-06 + 2.0770328527045103e-06, + 1.399582273679345e-06 ], "V": [ - -8.793834778180173, - 13.05038230265544 + -8.793834778171059, + 13.05038230264228 ], "number_turns": 10, "I": [ 4.0, 0.0 ], - "winding_losses": 3.40086662769806, - "P": -17.587669556360346, - "Q": 26.10076460531088, - "S": 31.473417885663032 + "winding_losses": 3.400866627698086, + "P": -17.587669556342117, + "Q": 26.10076460528456, + "S": 31.473417885631022 }, "winding2": { "turn_losses": [ - 0.02631449060295769, - 0.1242488756277047, - 0.3189701676840874, - 0.5966077072749462, - 0.8143954297453232, - 0.02497245867708634, - 0.1044648258155699, - 0.2617020770308137, - 0.4794685434231457, - 0.6528565650336904 + 0.02631449060296689, + 0.1242488756277235, + 0.3189701676841237, + 0.5966077072750384, + 0.8143954297454146, + 0.02497245867708991, + 0.1044648258155817, + 0.2617020770308619, + 0.4794685434232213, + 0.652856565033737 ], "flux": [ - -1.19039927924422e-05, - 8.185886959235638e-06 + -1.190399279245146e-05, + 8.185886959228308e-06 ], "flux_over_current": [ - 3.0456066847554003e-06, - -1.9434973983623715e-06 + 3.0456066847576098e-06, + -1.9434973983604534e-06 ], "V": [ - -12.87175611961806, - -18.69828385216307 + -12.8717561196065, + -18.69828385217736 ], "number_turns": 10, "I": [ -3.997563308076383, 0.13959798681000457 ], - "winding_losses": 3.40400114091533, - "P": 24.42270859586441, - "Q": 38.27222234620612, - "S": 45.40078962392558 + "winding_losses": 3.404001140915766, + "P": 24.422708595840305, + "Q": 38.27222234623389, + "S": 45.40078962393602 }, - "core_eddy_losses": 0.003742574947502717, - "core_hyst_losses": 0.0302902495099854, - "all_winding_losses": 6.80486776861339 + "core_eddy_losses": 0.003742574947501271, + "core_hyst_losses": 0.03029024950997371, + "core_parts": { + "core_part_1": { + "total_core_part_1": 0.034032824457474985 + } + }, + "all_winding_losses": 6.804867768613852 } ], "total_losses": { "winding1": { - "total": 3.4008666276980293, + "total": 3.400866627698061, "turns": [ - 0.8151200364865538, - 0.5967245714024573, - 0.3187610560944258, - 0.1233077276732152, - 0.02569372569938749, - 0.6532107937573608, - 0.4792623946019697, - 0.2612114242099259, - 0.1035863236354099, - 0.0239885741373234 + 0.8151200364865472, + 0.5967245714024684, + 0.3187610560944314, + 0.1233077276732099, + 0.02569372569938718, + 0.6532107937573823, + 0.4792623946019806, + 0.261211424209924, + 0.103586323635406, + 0.0239885741373241 ] }, "winding2": { - "total": 3.4040011409153257, + "total": 3.4040011409157587, "turns": [ - 0.02631449060295769, - 0.1242488756277047, - 0.3189701676840874, - 0.5966077072749462, - 0.8143954297453232, - 0.02497245867708634, - 0.1044648258155699, - 0.2617020770308137, - 0.4794685434231457, - 0.6528565650336904 + 0.02631449060296689, + 0.1242488756277235, + 0.3189701676841237, + 0.5966077072750384, + 0.8143954297454146, + 0.02497245867708991, + 0.1044648258155817, + 0.2617020770308619, + 0.4794685434232213, + 0.652856565033737 ] }, - "all_windings": 6.80486776861339, - "eddy_core": 0.003742574947502717, - "hyst_core_fundamental_freq": 0.0302902495099854, - "core": 0.03403282445748812, - "total_losses": 6.8389005930708775 + "all_windings": 6.804867768613852, + "eddy_core": 0.003742574947501271, + "total_core_part_1": 0.034032824457474985, + "hyst_core_fundamental_freq": 0.03029024950997371, + "core": 0.034032824457474985, + "total_losses": 6.838900593071327 }, "simulation_settings": { "simulation_name": null, - "date": "2023-08-25 11:11:42", + "date": "2023-10-20 15:11:46", "component_type": "Transformer", - "working_directory": "/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/tests/integration/temp", + "working_directory": "C:\\Users\\samba\\PycharmProjects\\FEM_Magnetics_Toolbox\\tests\\integration\\temp", "core": { "core_inner_diameter": 0.015, "window_w": 0.012, diff --git a/tests/integration/fixtures/results/log_electro_magnetic_transformer_integrated_core_fixed_loss_angle.json b/tests/integration/fixtures/results/log_electro_magnetic_transformer_integrated_core_fixed_loss_angle.json index 95b4437d..91febf9a 100644 --- a/tests/integration/fixtures/results/log_electro_magnetic_transformer_integrated_core_fixed_loss_angle.json +++ b/tests/integration/fixtures/results/log_electro_magnetic_transformer_integrated_core_fixed_loss_angle.json @@ -4,115 +4,119 @@ "f": 250000, "winding1": { "turn_losses": [ - 0.1132297903436348, - 0.1440636610902788, - 0.1994321110468745, - 0.1065176928422285 + 0.113229790343635, + 0.1440636610902724, + 0.1994321110468765, + 0.1065176928422164 ], "flux": [ - 2.281527116017833e-06, - 3.050038970955152e-06 + 2.281527116016398e-06, + 3.05003897095485e-06 ], "flux_over_current": [ - 2.8518506464476425e-07, - 3.801519201737564e-07 + 2.85185064644586e-07, + 3.801519201737189e-07 ], "V": [ - -4.777129918663706, - 3.583741216006086 + -4.777129918663235, + 3.583741216003846 ], "number_turns": 4, "I": [ 8.0, 0.0 ], - "winding_losses": 0.5632432553230153, - "P": -19.108519674654826, - "Q": 14.334964864024345, - "S": 23.88779482935759 + "winding_losses": 0.5632432553230006, + "P": -19.10851967465294, + "Q": 14.334964864015385, + "S": 23.8877948293507 }, "winding2": { "turn_losses": [ - 0.09709392967840036, - 0.1385065835859177, - 0.2115343736334769, - 0.1626514945711467, - 0.07534987825001753, - 0.02476459236767516, - 0.07187698743848421, - 0.01979825453235075 + 0.09709392967840208, + 0.1385065835859171, + 0.2115343736334724, + 0.1626514945711244, + 0.07534987824999828, + 0.0247645923676682, + 0.07187698743847404, + 0.01979825453234507 ], "flux": [ - 1.59989332178133e-06, - 6.396188367850073e-06 + 1.599893321778541e-06, + 6.396188367849494e-06 ], "flux_over_current": [ - -2.5905702221446836e-07, - -1.6298406559243326e-06 + -2.59057022213792e-07, + -1.6298406559241295e-06 ], "V": [ - -10.05975863443116, - 2.514035676101347 + -10.05975863443026, + 2.514035676097002 ], "number_turns": 8, "I": [ -3.984778792366982, 0.3486229709906328 ], - "winding_losses": 0.8015760940574701, - "P": 20.48118172469541, - "Q": -3.255406551399287, - "S": 20.738285287238448 + "winding_losses": 0.8015760940574049, + "P": 20.48118172469286, + "Q": -3.255406551390787, + "S": 20.738285287234596 }, - "core_eddy_losses": 0.0008530748745437754, - "core_hyst_losses": 0.007767932471564947, + "core_eddy_losses": 0.0008530748745433899, + "core_hyst_losses": 0.007767932471561175, "core_parts": { "core_part_1": { - "eddy_losses": 0.0007634983801010015, - "hyst_losses": 0.007451774557019985 + "eddy_losses": 0.000763498380100638, + "hyst_losses": 0.007451774557016286, + "total_core_part_1": 0.008215272937116923 }, "core_part_2": { - "eddy_losses": 8.957649444277318e-05, - "hyst_losses": 0.0003161579145449672 + "eddy_losses": 8.95764944427523e-05, + "hyst_losses": 0.0003161579145449025, + "total_core_part_2": 0.00040573440898765477 } }, - "all_winding_losses": 1.3648193493804854 + "all_winding_losses": 1.3648193493804055 } ], "total_losses": { "winding1": { - "total": 0.5632432553230167, + "total": 0.5632432553230002, "turns": [ - 0.1132297903436348, - 0.1440636610902788, - 0.1994321110468745, - 0.1065176928422285 + 0.113229790343635, + 0.1440636610902724, + 0.1994321110468765, + 0.1065176928422164 ] }, "winding2": { - "total": 0.8015760940574693, + "total": 0.8015760940574015, "turns": [ - 0.09709392967840036, - 0.1385065835859177, - 0.2115343736334769, - 0.1626514945711467, - 0.07534987825001753, - 0.02476459236767516, - 0.07187698743848421, - 0.01979825453235075 + 0.09709392967840208, + 0.1385065835859171, + 0.2115343736334724, + 0.1626514945711244, + 0.07534987824999828, + 0.0247645923676682, + 0.07187698743847404, + 0.01979825453234507 ] }, - "all_windings": 1.3648193493804854, - "eddy_core": 0.0008530748745437754, - "hyst_core_fundamental_freq": 0.007767932471564947, - "core": 0.008621007346108722, - "total_losses": 1.3734403567265943 + "all_windings": 1.3648193493804055, + "eddy_core": 0.0008530748745433899, + "total_core_part_1": 0.008215272937116923, + "total_core_part_2": 0.00040573440898765477, + "hyst_core_fundamental_freq": 0.007767932471561175, + "core": 0.008621007346104565, + "total_losses": 1.37344035672651 }, "simulation_settings": { "simulation_name": null, - "date": "2023-08-25 11:13:05", + "date": "2023-10-20 15:23:11", "component_type": "IntegratedTransformer", - "working_directory": "/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/tests/integration/temp", + "working_directory": "C:\\Users\\samba\\PycharmProjects\\FEM_Magnetics_Toolbox\\tests\\integration\\temp", "core": { "core_inner_diameter": 0.02, "window_w": 0.011, diff --git a/tests/integration/fixtures/results/log_electro_magnetic_transformer_interleaved_core_fixed_loss_angle.json b/tests/integration/fixtures/results/log_electro_magnetic_transformer_interleaved_core_fixed_loss_angle.json index 525d6527..2c58ea30 100644 --- a/tests/integration/fixtures/results/log_electro_magnetic_transformer_interleaved_core_fixed_loss_angle.json +++ b/tests/integration/fixtures/results/log_electro_magnetic_transformer_interleaved_core_fixed_loss_angle.json @@ -4,137 +4,143 @@ "f": 250000, "winding1": { "turn_losses": [ - 0.06805391405234136, - 0.09145754330817611, - 0.1276053062650547, - 0.1796140314946553, - 0.2491837520793671, - 0.3388847163253579, - 0.4630515792767697, - 0.4285741209767489, - 0.2429938804775827, - 0.09153351101812283, - 0.0195162539605728, - 0.07005732004485911, - 0.08761600112636682, - 0.1123735851567892, - 0.1480627230834712, - 0.1963378846298191, - 0.2628814853184701, - 0.3648108786972347, - 0.3171244784437643, - 0.147958846576184, - 0.03503097664115825 + 0.06805391405234339, + 0.09145754330817266, + 0.1276053062650451, + 0.1796140314946336, + 0.249183752079333, + 0.3388847163253159, + 0.4630515792767378, + 0.4285741209767311, + 0.2429938804775767, + 0.09153351101812121, + 0.01951625396057305, + 0.07005732004485923, + 0.08761600112636324, + 0.1123735851567811, + 0.1480627230835676, + 0.1963378846298306, + 0.2628814853184819, + 0.3648108786973263, + 0.3171244784443976, + 0.1479588465761665, + 0.03503097664115627 ], "flux": [ - 1.183750710053008e-07, - 8.294334651791238e-08 + 1.183750710232084e-07, + 8.294334659458684e-08 ], "flux_over_current": [ - 2.959555975373038e-08, - 1.5703365777783056e-08 + 2.9595559758208808e-08, + 1.5703365796953794e-08 ], "V": [ - -0.09866715712823322, - 0.1859543862023942 + -0.09866715724868652, + 0.185954386230533 ], "number_turns": 21, "I": [ 4.0, 0.0 ], - "winding_losses": 4.042722788952844, - "P": -0.19733431425646644, - "Q": 0.3719087724047884, - "S": 0.42101896225075963 + "winding_losses": 4.042722788953492, + "P": -0.19733431449737304, + "Q": 0.371908772461066, + "S": 0.42101896241338715 }, "winding2": { "turn_losses": [ - 0.1522647042064853, - 0.174717725867139, - 0.2074324641639617, - 0.2506301956960212, - 0.3047812940412247, - 0.367882926579459, - 0.4212561506607667 + 0.1522647042064873, + 0.1747177258671355, + 0.2074324641639577, + 0.2506301956960215, + 0.3047812940412071, + 0.3678829265794413, + 0.4212561506607503 ], "flux": [ - -3.266199806235779e-06, - 6.291592099275683e-07 + -3.266199806229673e-06, + 6.291592099532839e-07 ], "flux_over_current": [ - 2.7218290198879236e-07, - -5.411330067759532e-08 + 2.7218290198828277e-07, + -5.4113300679738725e-08 ], "V": [ - -1.020011687221375, - -5.130526831924445 + -1.020011687261777, + -5.130526831914839 ], "number_turns": 7, "I": [ -12.0, 1.4695761589768238e-15 ], - "winding_losses": 1.878965461215061, - "P": 6.1200701233282455, - "Q": 30.783160991546666, - "S": 31.385637781411027 + "winding_losses": 1.878965461215006, + "P": 6.120070123570659, + "Q": 30.783160991489034, + "S": 31.385637781401773 }, - "core_eddy_losses": 0.000450816615417936, - "core_hyst_losses": 0.003942034545531867, - "all_winding_losses": 5.921688250167905 + "core_eddy_losses": 0.0004508166154179859, + "core_hyst_losses": 0.003942034545532349, + "core_parts": { + "core_part_1": { + "total_core_part_1": 0.004392851160950335 + } + }, + "all_winding_losses": 5.921688250168498 } ], "total_losses": { "winding1": { - "total": 4.042722788952866, + "total": 4.042722788953514, "turns": [ - 0.06805391405234136, - 0.09145754330817611, - 0.1276053062650547, - 0.1796140314946553, - 0.2491837520793671, - 0.3388847163253579, - 0.4630515792767697, - 0.4285741209767489, - 0.2429938804775827, - 0.09153351101812283, - 0.0195162539605728, - 0.07005732004485911, - 0.08761600112636682, - 0.1123735851567892, - 0.1480627230834712, - 0.1963378846298191, - 0.2628814853184701, - 0.3648108786972347, - 0.3171244784437643, - 0.147958846576184, - 0.03503097664115825 + 0.06805391405234339, + 0.09145754330817266, + 0.1276053062650451, + 0.1796140314946336, + 0.249183752079333, + 0.3388847163253159, + 0.4630515792767378, + 0.4285741209767311, + 0.2429938804775767, + 0.09153351101812121, + 0.01951625396057305, + 0.07005732004485923, + 0.08761600112636324, + 0.1123735851567811, + 0.1480627230835676, + 0.1963378846298306, + 0.2628814853184819, + 0.3648108786973263, + 0.3171244784443976, + 0.1479588465761665, + 0.03503097664115627 ] }, "winding2": { - "total": 1.8789654612150577, + "total": 1.8789654612150004, "turns": [ - 0.1522647042064853, - 0.174717725867139, - 0.2074324641639617, - 0.2506301956960212, - 0.3047812940412247, - 0.367882926579459, - 0.4212561506607667 + 0.1522647042064873, + 0.1747177258671355, + 0.2074324641639577, + 0.2506301956960215, + 0.3047812940412071, + 0.3678829265794413, + 0.4212561506607503 ] }, - "all_windings": 5.921688250167905, - "eddy_core": 0.000450816615417936, - "hyst_core_fundamental_freq": 0.003942034545531867, - "core": 0.004392851160949803, - "total_losses": 5.926081101328855 + "all_windings": 5.921688250168498, + "eddy_core": 0.0004508166154179859, + "total_core_part_1": 0.004392851160950335, + "hyst_core_fundamental_freq": 0.003942034545532349, + "core": 0.004392851160950335, + "total_losses": 5.926081101329448 }, "simulation_settings": { "simulation_name": null, - "date": "2023-08-25 11:12:29", + "date": "2023-10-20 15:22:34", "component_type": "Transformer", - "working_directory": "/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/tests/integration/temp", + "working_directory": "C:\\Users\\samba\\PycharmProjects\\FEM_Magnetics_Toolbox\\tests\\integration\\temp", "core": { "core_inner_diameter": 0.015, "window_w": 0.012, diff --git a/tests/integration/fixtures/results/results_thermal.json b/tests/integration/fixtures/results/results_thermal.json index 231c8421..3452f862 100644 --- a/tests/integration/fixtures/results/results_thermal.json +++ b/tests/integration/fixtures/results/results_thermal.json @@ -1,49 +1,61 @@ { - "core": { - "min": 20.15928442290696, - "max": 21.23228498341296, - "mean": 20.74054867007537 + "core_parts": { + "core_part_1": { + "min": 20.15928442290691, + "max": 21.23228498341263, + "mean": 20.74054867007518 + }, + "total": { + "min": 20.15928442290691, + "max": 21.23228498341263, + "mean": 20.74054867007518 + } }, "windings": { "winding_0_0": { - "min": 20.77722154058439, - "max": 20.78129896378552, - "mean": 20.778828605030903 + "min": 20.77722154058429, + "max": 20.78129896378544, + "mean": 20.77882860503081 }, "winding_0_1": { - "min": 20.86520324787987, - "max": 20.87066742939323, - "mean": 20.86781694397631 + "min": 20.86520324787963, + "max": 20.87066742939298, + "mean": 20.867816943976056 }, "winding_0_2": { - "min": 20.95962314654165, - "max": 20.96455114361748, - "mean": 20.962187895808697 + "min": 20.95962314654136, + "max": 20.96455114361719, + "mean": 20.96218789580841 }, "winding_0_3": { - "min": 21.03203456392492, - "max": 21.03496398969991, - "mean": 21.033754905179116 + "min": 21.03203456392462, + "max": 21.03496398969962, + "mean": 21.033754905178824 }, "winding_0_4": { - "min": 21.05902021215385, - "max": 21.06103547095926, - "mean": 21.0602539145121 + "min": 21.05902021215361, + "max": 21.06103547095902, + "mean": 21.060253914511854 }, "winding_0_5": { - "min": 20.99107579068692, - "max": 20.99535703035798, - "mean": 20.993258912906487 + "min": 20.99107579068684, + "max": 20.99535703035788, + "mean": 20.9932589129064 }, "winding_0_6": { - "min": 20.91348883851924, - "max": 20.91790978303432, - "mean": 20.91556421433843 + "min": 20.91348883851931, + "max": 20.91790978303437, + "mean": 20.915564214338495 + }, + "winding_0_7": { + "min": 20.84399557863777, + "max": 20.84724514360274, + "mean": 20.845297194030216 }, "total": { - "min": 20.77722154058439, - "max": 21.06103547095926, - "mean": 20.944523627393153 + "min": 20.77722154058429, + "max": 21.06103547095902, + "mean": 20.932120323222634 } }, "misc": { @@ -51,8 +63,8 @@ "case_weight": -1 }, "insulations": { - "min": 20.24849972466509, - "max": 21.15300382780542, - "mean": 20.698717796095803 + "min": 20.24849972466502, + "max": 21.15300382780513, + "mean": 20.69871779609566 } }