From d77827b9e9a72ec1b7469e68a89b8a2cb60a26b2 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Wed, 26 Feb 2025 11:57:49 +0100
Subject: [PATCH 01/15] ito: rm brute force, change dto structure
---
.../{advanced_sto.py => advanced_ct_sto.py} | 2 +-
femmt/examples/ito_optuna_example.py | 75 +-
femmt/optimization/ito.py | 1304 ++++++-----------
femmt/optimization/ito_dtos.py | 4 +-
femmt/optimization/sto_dtos.py | 2 +-
5 files changed, 489 insertions(+), 898 deletions(-)
rename femmt/examples/{advanced_sto.py => advanced_ct_sto.py} (98%)
diff --git a/femmt/examples/advanced_sto.py b/femmt/examples/advanced_ct_sto.py
similarity index 98%
rename from femmt/examples/advanced_sto.py
rename to femmt/examples/advanced_ct_sto.py
index 38f77524..3f2b2961 100644
--- a/femmt/examples/advanced_sto.py
+++ b/femmt/examples/advanced_ct_sto.py
@@ -1,5 +1,5 @@
"""
-Advanced example to show an optimization workflow for the stacked transformer.
+Advanced example to show an optimization workflow for the center-tapped stacked transformer.
A stacked transformer should be optimized. The target parameters are:
* l_s12_target=5.8e-6,
diff --git a/femmt/examples/ito_optuna_example.py b/femmt/examples/ito_optuna_example.py
index 3b383fca..7faf904b 100644
--- a/femmt/examples/ito_optuna_example.py
+++ b/femmt/examples/ito_optuna_example.py
@@ -22,6 +22,7 @@
[-0.9196195846583147, -19.598444313231134, 0.9196195846583122, 19.59844431323113, -0.9196195846583147]]
dab_transformer_config = fmt.ItoSingleInputConfig(
+ integrated_transformer_study_name="2025-02-26",
l_s_target=85e-6,
l_h_target=600e-6,
n_target=2.9,
@@ -36,55 +37,53 @@
primary_litz_wire_list=["1.4x200x0.071"],
secondary_litz_wire_list=["1.4x200x0.071"],
temperature=100,
- working_directory=os.path.join(os.path.dirname(__file__), "example_results", "optuna_integrated_transformer_optimization")
+ integrated_transformer_optimization_directory=os.path.join(os.path.dirname(__file__), "example_results", "optuna_integrated_transformer_optimization")
)
-task = 'start_study'
+# task = 'start_study'
# task = 'filter_reluctance_model'
# task = 'fem_simulation_from_filtered_reluctance_model_results'
-# task = 'plot_study_results'
-
-study_name = "workflow_2023-04-15"
+task = 'plot_study_results'
if __name__ == '__main__':
time_start = datetime.datetime.now()
if task == 'start_study':
- fmt.IntegratedTransformerOptimization.ReluctanceModel.NSGAII.start_study(study_name, dab_transformer_config, 1000, storage='sqlite')
-
- elif task == 'filter_reluctance_model':
- # load trials from reluctance model
- reluctance_result_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.NSGAII.load_study_to_dto(study_name, dab_transformer_config)
- print(f"{len(reluctance_result_list)=}")
-
- # filter air gaps
- filtered_air_gaps_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_min_air_gap_length(reluctance_result_list)
- print(f"{len(filtered_air_gaps_dto_list)=}")
-
- # filter for Pareto front
- pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_loss_list(
- filtered_air_gaps_dto_list, factor_min_dc_losses=0.5)
- print(f"{len(pareto_reluctance_dto_list)=}")
-
- fmt.IntegratedTransformerOptimization.plot(reluctance_result_list)
- fmt.IntegratedTransformerOptimization.plot(pareto_reluctance_dto_list)
-
- # save results
- fmt.IntegratedTransformerOptimization.ReluctanceModel.save_dto_list(pareto_reluctance_dto_list, os.path.join(dab_transformer_config.working_directory,
- '01_reluctance_model_results_filtered'))
-
- elif task == 'fem_simulation_from_filtered_reluctance_model_results':
- # load filtered reluctance models
- pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.load_filtered_results(dab_transformer_config.working_directory)
- print(f"{len(pareto_reluctance_dto_list)=}")
-
- # start FEM simulation
- fmt.IntegratedTransformerOptimization.FemSimulation.simulate(config_dto=dab_transformer_config,
- simulation_dto_list=pareto_reluctance_dto_list)
-
+ fmt.IntegratedTransformerOptimization.ReluctanceModel.start_proceed_study(dab_transformer_config, 100, storage='sqlite')
+
+ # elif task == 'filter_reluctance_model':
+ # # load trials from reluctance model
+ # reluctance_result_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.NSGAII.load_study_to_dto(study_name, dab_transformer_config)
+ # print(f"{len(reluctance_result_list)=}")
+ #
+ # # filter air gaps
+ # filtered_air_gaps_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_min_air_gap_length(reluctance_result_list)
+ # print(f"{len(filtered_air_gaps_dto_list)=}")
+ #
+ # # filter for Pareto front
+ # pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_loss_list(
+ # filtered_air_gaps_dto_list, factor_min_dc_losses=0.5)
+ # print(f"{len(pareto_reluctance_dto_list)=}")
+ #
+ # fmt.IntegratedTransformerOptimization.plot(reluctance_result_list)
+ # fmt.IntegratedTransformerOptimization.plot(pareto_reluctance_dto_list)
+ #
+ # # save results
+ # fmt.IntegratedTransformerOptimization.ReluctanceModel.save_dto_list(pareto_reluctance_dto_list, os.path.join(dab_transformer_config.working_directory,
+ # '01_reluctance_model_results_filtered'))
+ #
+ # elif task == 'fem_simulation_from_filtered_reluctance_model_results':
+ # # load filtered reluctance models
+ # pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.load_filtered_results(dab_transformer_config.working_directory)
+ # print(f"{len(pareto_reluctance_dto_list)=}")
+ #
+ # # start FEM simulation
+ # fmt.IntegratedTransformerOptimization.FemSimulation.simulate(config_dto=dab_transformer_config,
+ # simulation_dto_list=pareto_reluctance_dto_list)
+ #
elif task == 'plot_study_results':
- fmt.IntegratedTransformerOptimization.ReluctanceModel.NSGAII.show_study_results(study_name, dab_transformer_config)
+ fmt.IntegratedTransformerOptimization.ReluctanceModel.show_study_results(dab_transformer_config)
time_stop = datetime.datetime.now()
diff --git a/femmt/optimization/ito.py b/femmt/optimization/ito.py
index 096d003d..da4adc89 100644
--- a/femmt/optimization/ito.py
+++ b/femmt/optimization/ito.py
@@ -2,10 +2,10 @@
# Python libraries
import os
import json
-import itertools
-import shutil
import dataclasses
-from typing import List, Dict, Tuple
+from typing import List, Dict, Tuple, Optional
+import datetime
+import pickle
# 3rd party library import
import materialdatabase as mdb
@@ -175,7 +175,7 @@ def calculate_fix_parameters(config: ItoSingleInputConfig) -> ItoTargetAndFixedP
material_data_list.append(material_dto)
# set up working directories
- working_directories = itof.set_up_folder_structure(config.working_directory)
+ working_directories = itof.set_up_folder_structure(config.integrated_transformer_optimization_directory)
# finalize data to dto
target_and_fix_parameters = ItoTargetAndFixedParameters(
@@ -195,867 +195,430 @@ def calculate_fix_parameters(config: ItoSingleInputConfig) -> ItoTargetAndFixedP
class ReluctanceModel:
"""Create and calculate the reluctance model for the integrated transformer."""
- class BruteForce:
- """Brute force calculation for the integrated transformer."""
-
- #############################
- # initial optimization
- #############################
- @staticmethod
- def brute_force_calculation(config_file: ItoSingleInputConfig) -> List:
- """
- Brute force calculation for the integrated transformer.
-
- :param config_file: configuration file
- :type config_file: ItoSingleInputConfig
- :return: List of valid designs
- :rtype: List
- """
- case_number = 0
-
- # 0. Empty folder
- if os.path.exists(config_file.working_directory):
- shutil.rmtree(config_file.working_directory)
-
- material_db = mdb.MaterialDatabase(is_silent=True)
-
- sweep_dto = femmt.IntegratedTransformerOptimization.ReluctanceModel.BruteForce.calculate_sweep_tensors(config_file)
-
- wire_database = ff.wire_material_database()
- litz_database = ff.litz_database()
-
- # 1. Extract fundamental frequency from current vectors
- time_extracted, current_extracted_1_vec = fr.time_vec_current_vec_from_time_current_vec(
- sweep_dto.time_current_1_vec)
- time_extracted, current_extracted_2_vec = fr.time_vec_current_vec_from_time_current_vec(
- sweep_dto.time_current_2_vec)
- fundamental_frequency = np.around(1 / time_extracted[-1], decimals=0)
- print(f"{fundamental_frequency=}")
-
- i_rms_1 = fr.i_rms(sweep_dto.time_current_1_vec)
- i_rms_2 = fr.i_rms(sweep_dto.time_current_2_vec)
-
- # generate list of all parameter combinations
- t2_core_geometry_sweep = np.array(list(itertools.product(sweep_dto.t1_window_w, sweep_dto.t1_window_h_top,
- sweep_dto.t1_window_h_bot,
- sweep_dto.t1_core_inner_diameter)))
-
- t2_litz_sweep = np.array(
- list(itertools.product(sweep_dto.t1_primary_litz_wire_list, sweep_dto.t1_secondary_litz_wire_list)))
-
- # report simulation progress
- number_of_geometry_simulations = len(t2_core_geometry_sweep) * len(sweep_dto.t1_core_material)
-
- geometry_simulations_per_percent = int(number_of_geometry_simulations / 99)
- simulation_progress_percent = 0
-
- valid_design_list = []
-
- # initialize parameters staying same form simulation
- t2_inductance_matrix = [
- [sweep_dto.l_s_target_value + sweep_dto.l_h_target_value,
- sweep_dto.l_h_target_value / sweep_dto.n_target_value],
- [sweep_dto.l_h_target_value / sweep_dto.n_target_value,
- sweep_dto.l_h_target_value / (sweep_dto.n_target_value ** 2)]]
-
- geometry_simulation_counter = 0
- for _, material_name in enumerate(sweep_dto.t1_core_material):
- """
- outer core material loop loads material properties from material database
- * mu_r_abs
- * saturation_flux_density and calculates the dimensioning_flux_density from it
- * material vectors for mu_r_real and mu_r_imag depending on flux_density
-
- """
- mu_r_abs = material_db.get_material_attribute(material_name=material_name,
- attribute="initial_permeability")
-
- saturation_flux_density = material_db.get_saturation_flux_density(material_name=material_name)
- dimensioning_max_flux_density = saturation_flux_density * sweep_dto.factor_max_flux_density
-
- # get material data from material database.
- material_dto = material_db.material_data_interpolation_to_dto(material_name, fundamental_frequency, config_file.temperature)
-
- for count_geometry, t1d_core_geometry_material in enumerate(t2_core_geometry_sweep):
-
- window_w = t1d_core_geometry_material[0]
- window_h_top = t1d_core_geometry_material[1]
- window_h_bot = t1d_core_geometry_material[2]
- core_inner_diameter = t1d_core_geometry_material[3]
-
- # report about simulation progress
- # if geometry_simulation_counter == geometry_simulations_per_percent * simulation_progress_percent:
- # simulation_progress_percent += 1
- # print(f"{simulation_progress_percent} simulation_progress_percent")
- # geometry_simulation_counter += 1
- simulation_progress_percent = count_geometry / number_of_geometry_simulations * 100
- print(f"{simulation_progress_percent=} %")
-
- # print(geometry_simulation_counter)
-
- for primary_litz_wire, secondary_litz_wire in t2_litz_sweep:
- primary_litz = litz_database[primary_litz_wire]
- secondary_litz = litz_database[secondary_litz_wire]
-
- # cross-section comparison is according to a square for round wire.
- # this approximation is more realistic
- # insulation
- insulation_distance = 1e-3
- insulation_cross_section_top = 2 * insulation_distance * (window_w + window_h_top)
- insulation_cross_section_bot = 2 * insulation_distance * (window_w + window_h_bot)
-
- total_available_window_cross_section_top = window_h_top * window_w - insulation_cross_section_top
-
- #########################################################
- # set dynamic wire count parameters as optimization parameters
- #########################################################
- # set the winding search space dynamic
- # https://optuna.readthedocs.io/en/stable/faq.html#what-happens-when-i-dynamically-alter-a-search-space
-
- # n_p_top suggestion
- n_p_top_max = total_available_window_cross_section_top / (2 * primary_litz["conductor_radii"]) ** 2
- t1_n_p_top_max = np.arange(0, n_p_top_max + 1)
-
- for _, n_p_top in enumerate(t1_n_p_top_max):
- winding_cross_section_n_p_top = n_p_top * (2 * primary_litz["conductor_radii"]) ** 2
-
- winding_cross_section_n_p_top_max = n_p_top * (2 * primary_litz["conductor_radii"]) ** 2
- n_s_top_max = int((total_available_window_cross_section_top - winding_cross_section_n_p_top_max) / (
- 2 * secondary_litz["conductor_radii"]) ** 2)
- t1_n_s_top_max = np.arange(0, n_s_top_max + 1)
-
- for _, n_s_top in enumerate(t1_n_s_top_max):
-
- total_available_window_cross_section_bot = window_h_bot * window_w - insulation_cross_section_bot
-
- # n_p_bot suggestion
- n_p_bot_max = total_available_window_cross_section_bot / (2 * primary_litz["conductor_radii"]) ** 2
- t1_n_p_bot = np.arange(0, n_p_bot_max + 1)
-
- for _, n_p_bot in enumerate(t1_n_p_bot):
- winding_cross_section_n_p_bot = n_p_bot * (2 * primary_litz["conductor_radii"]) ** 2
-
- # n_s_bot suggestion
- winding_cross_section_n_p_bot_max = n_p_bot * (2 * primary_litz["conductor_radii"]) ** 2
- n_s_bot_max = int((total_available_window_cross_section_bot - winding_cross_section_n_p_bot_max) / (
- 2 * secondary_litz["conductor_radii"]) ** 2)
- t1_n_s_bot = np.arange(0, n_s_bot_max + 1)
-
- for _, n_s_bot in enumerate(t1_n_s_bot):
-
- core_top_bot_height = core_inner_diameter / 4
- core_cross_section = (core_inner_diameter / 2) ** 2 * np.pi
-
- # generate winding matrix
- # note that the t11 winding-matrix will be reshaped later!
- t2_winding_matrix = [[n_p_top, n_s_top], [n_p_bot, n_s_bot]]
-
- # matrix reshaping
- t2_winding_matrix_transpose = np.transpose(t2_winding_matrix, (1, 0))
-
- t2_reluctance_matrix = femmt.IntegratedTransformerOptimization.ReluctanceModel.BruteForce.\
- t2_calculate_reluctance_matrix(t2_inductance_matrix, t2_winding_matrix, t2_winding_matrix_transpose)
-
- if np.linalg.det(t2_reluctance_matrix) != 0 and np.linalg.det(
- np.transpose(t2_winding_matrix)) != 0 and np.linalg.det(t2_inductance_matrix) != 0:
- # calculate the flux
- flux_top_vec, flux_bot_vec, flux_stray_vec = fr.flux_vec_from_current_vec(
- current_extracted_1_vec,
- current_extracted_2_vec,
- t2_winding_matrix,
- t2_inductance_matrix)
-
- # calculate maximum values
- flux_top_max, flux_bot_max, flux_stray_max = fr.max_value_from_value_vec(
- flux_top_vec, flux_bot_vec,
- flux_stray_vec)
-
- flux_density_top_max = flux_top_max / core_cross_section
- flux_density_bot_max = flux_bot_max / core_cross_section
- flux_density_middle_max = flux_stray_max / core_cross_section
-
- if (flux_density_top_max < dimensioning_max_flux_density) and (
- flux_density_bot_max < dimensioning_max_flux_density) and (
- flux_density_middle_max < dimensioning_max_flux_density):
-
- # calculate target values for r_top and r_bot out of reluctance matrix
- r_core_middle_cylinder_radial = fr.r_core_top_bot_radiant(
- core_inner_diameter, window_w, mu_r_abs, core_top_bot_height)
-
- r_middle_target = -t2_reluctance_matrix[0][1]
- r_top_target = t2_reluctance_matrix[0][0] - r_middle_target
- r_bot_target = t2_reluctance_matrix[1][1] - r_middle_target
-
- # calculate the core reluctance of top and bottom and middle part
- r_core_top_cylinder_inner = fr.r_core_round(core_inner_diameter,
- window_h_top, mu_r_abs)
- r_core_top = 2 * r_core_top_cylinder_inner + r_core_middle_cylinder_radial
- r_air_gap_top_target = r_top_target - r_core_top
-
- r_core_bot_cylinder_inner = fr.r_core_round(core_inner_diameter,
- window_h_bot, mu_r_abs)
- r_core_bot = 2 * r_core_bot_cylinder_inner + r_core_middle_cylinder_radial
- r_air_gap_bot_target = r_bot_target - r_core_bot
-
- r_air_gap_middle_target = r_middle_target - r_core_middle_cylinder_radial
-
- if r_air_gap_top_target > 0 and r_air_gap_bot_target > 0 and r_air_gap_middle_target > 0:
-
- minimum_air_gap_length = 1e-6
- maximum_air_gap_length = 1e-3
- minimum_sort_out_air_gap_length = 100e-6
-
- try:
- l_top_air_gap = optimize.brentq(
- fr.r_air_gap_round_inf_sct, minimum_air_gap_length, maximum_air_gap_length,
- args=(core_inner_diameter, window_h_top, r_air_gap_top_target), full_output=True)[0]
- l_bot_air_gap = optimize.brentq(fr.r_air_gap_round_round_sct, minimum_air_gap_length,
- maximum_air_gap_length, args=(core_inner_diameter, window_h_bot / 2,
- window_h_bot / 2,
- r_air_gap_bot_target),
- full_output=True)[0]
- l_middle_air_gap = optimize.brentq(fr.r_air_gap_tablet_cylinder_sct,
- minimum_air_gap_length,
- maximum_air_gap_length, args=(core_inner_diameter,
- core_inner_diameter / 4, window_w,
- r_air_gap_middle_target),
- full_output=True)[0]
- except ValueError:
- break
-
- if l_top_air_gap > minimum_sort_out_air_gap_length and l_bot_air_gap > minimum_sort_out_air_gap_length \
- and l_middle_air_gap > minimum_sort_out_air_gap_length:
- p_hyst_top = fr.hyst_losses_core_half_mu_r_imag(core_inner_diameter,
- window_h_top,
- window_w,
- mu_r_abs,
- flux_top_max,
- fundamental_frequency,
- material_dto.material_flux_density_vec,
- material_dto.material_mu_r_imag_vec)
-
- p_hyst_middle = fr.power_losses_hysteresis_cylinder_radial_direction_mu_r_imag(
- flux_stray_max, core_inner_diameter / 4, core_inner_diameter / 2,
- core_inner_diameter / 2 + window_w, fundamental_frequency,
- mu_r_abs, material_dto.material_flux_density_vec, material_dto.material_mu_r_imag_vec)
-
- p_hyst_bot = fr.hyst_losses_core_half_mu_r_imag(core_inner_diameter,
- window_h_bot,
- window_w,
- mu_r_abs,
- flux_bot_max,
- fundamental_frequency,
- material_dto.material_flux_density_vec,
- material_dto.material_mu_r_imag_vec)
-
- p_hyst = p_hyst_top + p_hyst_bot + p_hyst_middle
-
- core_2daxi_total_volume = fr.calculate_core_2daxi_total_volume(
- core_inner_diameter,
- (window_h_bot + window_h_top + core_inner_diameter / 4),
- window_w)
-
- primary_effective_conductive_cross_section = primary_litz["strands_numbers"] * \
- primary_litz["strand_radii"] ** 2 * np.pi
- primary_effective_conductive_radius = np.sqrt(
- primary_effective_conductive_cross_section / np.pi)
- primary_resistance = fr.resistance_solid_wire(
- core_inner_diameter, window_w,
- n_p_top + n_p_bot,
- primary_effective_conductive_radius,
- material='Copper')
- primary_dc_loss = primary_resistance * i_rms_1 ** 2
-
- secondary_effective_conductive_cross_section = secondary_litz["strands_numbers"] * \
- secondary_litz["strand_radii"] ** 2 * np.pi
- secondary_effective_conductive_radius = np.sqrt(
- secondary_effective_conductive_cross_section / np.pi)
- secondary_resistance = fr.resistance_solid_wire(
- core_inner_diameter, window_w,
- n_s_top + n_s_bot,
- secondary_effective_conductive_radius,
- material='Copper')
- secondary_dc_loss = secondary_resistance * i_rms_2 ** 2
-
- total_loss = p_hyst + primary_dc_loss + secondary_dc_loss
-
- valid_design_dict = ItoSingleResultFile(
- case=case_number,
- air_gap_top=l_top_air_gap,
- air_gap_bot=l_bot_air_gap,
- air_gap_middle=l_middle_air_gap,
- n_p_top=n_p_top,
- n_p_bot=n_p_bot,
- n_s_top=n_s_top,
- n_s_bot=n_s_bot,
- window_h_top=window_h_top,
- window_h_bot=window_h_bot,
- window_w=window_w,
- core_material=material_name,
- core_inner_diameter=core_inner_diameter,
- primary_litz_wire=primary_litz_wire,
- secondary_litz_wire=secondary_litz_wire,
- # results
- flux_top_max=flux_top_max,
- flux_bot_max=flux_bot_max,
- flux_stray_max=flux_stray_max,
- flux_density_top_max=flux_density_top_max,
- flux_density_bot_max=flux_density_bot_max,
- flux_density_stray_max=flux_density_middle_max,
- p_hyst=p_hyst,
- core_2daxi_total_volume=core_2daxi_total_volume,
- primary_litz_wire_loss=primary_dc_loss,
- secondary_litz_wire_loss=secondary_dc_loss,
- total_loss=total_loss
-
- )
-
- # Add dict to list of valid designs
- valid_design_list.append(valid_design_dict)
- case_number += 1
-
- print(f"Number of valid designs: {len(valid_design_list)}")
- return valid_design_list
-
- @staticmethod
- def t2_calculate_reluctance_matrix(t2_inductance_matrix: np.array, t2_winding_matrix: np.array, t2_winding_matrix_transpose: np.array):
- """
- Calculate the inductance matrix out of reluctance matrix and winding matrix.
-
- :param t2_inductance_matrix: matrix of transformer inductance
- :type t2_inductance_matrix: np.array
- :param t2_winding_matrix: matrix of transformer windings
- :type t2_winding_matrix: np.array
- :param t2_winding_matrix_transpose: transponsed winding matrix
- :type t2_winding_matrix_transpose: np.array
-
- :return: reluctance matrix
-
- winding matrix e.g.
- N = [ [N_1a, N_2b], [N_1b, N_2b] ]
-
- inductance matrix e.g.
- L = [ [L_11, M], [M, L_22] ]
-
- returns reluctance matrix e.g.
- r = [ [], [] ]
- """
- # invert inductance matrix
- t2_inductance_matrix_invert = np.linalg.inv(t2_inductance_matrix)
-
- # Formular: L = N^T * R^-1 * N
- # Note: Be careful when trying to multiply the matrices in one single step. Some pre-tests failed.
- # The following commented example returns a different result as the code-version. The code-version is
- # verified with a 2x2 example.
- # So this line is not correct!
- # return np.einsum('...ij, ...jj, ...jk -> ...ik', t11_winding_matrix_transpose, t11_reluctance_matrix_invert,
- # t11_winding_matrix), t9_valid_design_mask
-
- # minimal example to understand the operation
- # matrix1 = np.array([[1, 2], [3, 4]])
- # matrix2 = np.array([[5, 6], [7, 8]])
- # matrix3 = np.array([[9, 10], [11, 12]])
- #
- # # reference code
- # normal_multiplication = np.matmul(np.matmul(matrix1, matrix2), matrix3)
- # print(f"{normal_multiplication = }")
- #
- # # This does not macht to the reference code!!!
- # einsum_multiplication = np.einsum('...ij, ...jj, ...jk -> ...ik', matrix1, matrix2, matrix3)
- # print(f"{einsum_multiplication = }")
- #
- # # two einsum multiplications: same result as reference code
- # einsum_multiplication_part_1 = np.einsum('...ij, ...jh -> ...ih', matrix1, matrix2)
- # einsum_multiplication_part_2 = np.einsum('...ij, ...jh -> ...ih', einsum_multiplication_part_1, matrix3)
- # print(f"{einsum_multiplication_part_2 = }")
- einsum_multiplication_part_1 = np.einsum('...ij, ...jh -> ...ih', t2_winding_matrix,
- t2_inductance_matrix_invert)
- einsum_multiplication_part_2 = np.einsum('...ij, ...jh -> ...ih', einsum_multiplication_part_1,
- t2_winding_matrix_transpose)
-
- return einsum_multiplication_part_2
-
- @staticmethod
- def calculate_sweep_tensors(input_parameters_dto: ItoSingleInputConfig) -> SweepTensor:
- """
- Calculate the SweepTensor from the integrated-transformer input config file (ItoSingleInputConfig).
-
- ItoSingleInputConfig: core_inner_diameter = [10e-3, 30e-3, 5]
- ->> SweepTensor: t1_core_inner_diameter = [10e-3, 15e-3, 20e-3, 25e-3, 30e-3]
-
- :param input_parameters_dto: integrated transformer input configuration
- :type input_parameters_dto: IntegratedTransformerOptimization
- :return: returns the sweep tensor as mentioned in the example
- :rtype: SweepTensor
- """
- sweep_tensor = SweepTensor(
- # tensors: outer core geometry and material
- t1_window_h_top=np.linspace(input_parameters_dto.window_h_top_min_max_list[0],
- input_parameters_dto.window_h_top_min_max_list[1],
- input_parameters_dto.window_h_top_min_max_list[2]),
- t1_window_h_bot=np.linspace(input_parameters_dto.window_h_bot_min_max_list[0],
- input_parameters_dto.window_h_bot_min_max_list[1],
- input_parameters_dto.window_h_bot_min_max_list[2]),
- t1_window_w=np.linspace(input_parameters_dto.window_w_min_max_list[0],
- input_parameters_dto.window_w_min_max_list[1],
- input_parameters_dto.window_w_min_max_list[2]),
- t1_core_material=input_parameters_dto.material_list,
- t1_core_inner_diameter=np.linspace(input_parameters_dto.core_inner_diameter_min_max_list[0],
- input_parameters_dto.core_inner_diameter_min_max_list[1],
- input_parameters_dto.core_inner_diameter_min_max_list[2]),
-
- time_current_1_vec=input_parameters_dto.time_current_1_vec,
- time_current_2_vec=input_parameters_dto.time_current_2_vec,
-
- l_s_target_value=input_parameters_dto.l_s_target,
- l_h_target_value=input_parameters_dto.l_h_target,
- n_target_value=input_parameters_dto.n_target,
- factor_max_flux_density=input_parameters_dto.factor_max_flux_density,
- t1_primary_litz_wire_list=input_parameters_dto.primary_litz_wire_list,
- t1_secondary_litz_wire_list=input_parameters_dto.secondary_litz_wire_list
- )
- return sweep_tensor
+ @staticmethod
+ def objective(trial: optuna.Trial, config: ItoSingleInputConfig,
+ target_and_fixed_parameters: ItoTargetAndFixedParameters) -> Tuple:
+ """
+ Objective function to optimize.
- #############################
- # filters
- #############################
+ Using optuna. Some hints:
- class NSGAII:
- """NSGAII algorithm to find the pareto front."""
-
- ##############################
- # simulation
- ##############################
-
- @staticmethod
- def objective(trial: optuna.Trial, config: ItoSingleInputConfig,
- target_and_fixed_parameters: ItoTargetAndFixedParameters) -> Tuple:
- """
- Objective function to optimize.
-
- Using optuna. Some hints:
-
- * returning failed trails by using return float('nan'), float('nan'),
- see https://optuna.readthedocs.io/en/stable/faq.html#how-are-nans-returned-by-trials-handled
- * speed up the search for NSGA-II algorithm with dynamic alter the search space, see https://optuna.readthedocs.io/en/stable/faq.html#id10
-
-
- :param trial: parameter suggesting by optuna
- :type trial: optuna.Trial
- :param config: input configuration file
- :type config: ItoSingleInputConfig
- :param target_and_fixed_parameters: target and fix parameters
- :type target_and_fixed_parameters: ItoTargetAndFixedParameters
- """
- # pass multiple arguments to the objective function used by optuna
- # https://www.kaggle.com/general/261870
-
- #########################################################
- # set core geometry optimization parameters
- #########################################################
- core_inner_diameter = trial.suggest_float("core_inner_diameter",
- config.core_inner_diameter_min_max_list[0],
- config.core_inner_diameter_min_max_list[1])
- window_w = trial.suggest_float("window_w", config.window_w_min_max_list[0],
- config.window_w_min_max_list[1])
- window_h_top = trial.suggest_float("window_h_top", config.window_h_top_min_max_list[0],
- config.window_h_top_min_max_list[1])
- window_h_bot = trial.suggest_float("window_h_bot", config.window_h_bot_min_max_list[0],
- config.window_h_bot_min_max_list[1])
-
- material = trial.suggest_categorical("material", config.material_list)
- primary_litz_wire = trial.suggest_categorical("primary_litz_wire", config.primary_litz_wire_list)
- secondary_litz_wire = trial.suggest_categorical("secondary_litz_wire", config.secondary_litz_wire_list)
-
- # cross-section comparison is according to a square for round wire.
- # this approximation is more realistic
- # insulation
- insulation_distance = 1e-3
- insulation_cross_section_top = 2 * insulation_distance * (window_w + window_h_top)
- insulation_cross_section_bot = 2 * insulation_distance * (window_w + window_h_bot)
-
- litz_database = ff.litz_database()
-
- primary_litz = litz_database[primary_litz_wire]
- secondary_litz = litz_database[secondary_litz_wire]
-
- total_available_window_cross_section_top = window_h_top * window_w - insulation_cross_section_top
- total_available_window_cross_section_bot = window_h_bot * window_w - insulation_cross_section_bot
-
- #########################################################
- # set dynamic wire count parameters as optimization parameters
- #########################################################
- # set the winding search space dynamic
- # https://optuna.readthedocs.io/en/stable/faq.html#what-happens-when-i-dynamically-alter-a-search-space
-
- # n_p_top suggestion
- n_p_top_max = total_available_window_cross_section_top / (2 * primary_litz["conductor_radii"]) ** 2
- n_p_top = trial.suggest_int("n_p_top", 0, n_p_top_max)
-
- # n_s_top_suggestion
- winding_cross_section_n_p_top_max = n_p_top * (2 * primary_litz["conductor_radii"]) ** 2
- n_s_top_max = int((total_available_window_cross_section_top - winding_cross_section_n_p_top_max) / (
- 2 * secondary_litz["conductor_radii"]) ** 2)
- n_s_top = trial.suggest_int("n_s_top", 0, n_s_top_max)
-
- # n_p_bot suggestion
- n_p_bot_max = total_available_window_cross_section_bot / (2 * primary_litz["conductor_radii"]) ** 2
- n_p_bot = trial.suggest_int("n_p_bot", 0, n_p_bot_max)
-
- # n_s_bot suggestion
- winding_cross_section_n_p_bot_max = n_p_bot * (2 * primary_litz["conductor_radii"]) ** 2
- n_s_bot_max = int((total_available_window_cross_section_bot - winding_cross_section_n_p_bot_max) / (2 * secondary_litz["conductor_radii"]) ** 2)
- n_s_bot = trial.suggest_int("n_s_bot", 0, n_s_bot_max)
-
- winding_cross_section_top = n_p_top * (2 * primary_litz["conductor_radii"]) ** 2 + n_s_top * (2 * secondary_litz["conductor_radii"]) ** 2
- winding_cross_section_bot = n_p_bot * (2 * primary_litz["conductor_radii"]) ** 2 + n_s_bot * (2 * secondary_litz["conductor_radii"]) ** 2
-
- thousand_simulations = trial.number / 1000
-
- if thousand_simulations.is_integer():
- print(f"simulation count: {trial.number}")
-
- for material_dto in target_and_fixed_parameters.material_dto_curve_list:
- if material_dto.material_name == material:
- material_data = material_dto
-
- material_mu_r_initial = material_data.material_mu_r_abs
- flux_density_data_vec = material_data.material_flux_density_vec
- mu_r_imag_data_vec = material_data.material_mu_r_imag_vec
-
- core_top_bot_height = core_inner_diameter / 4
- core_cross_section = (core_inner_diameter / 2) ** 2 * np.pi
-
- t2_winding_matrix = [[n_p_top, n_s_top], [n_p_bot, n_s_bot]]
-
- target_inductance_matrix = fr.calculate_inductance_matrix_from_ls_lh_n(config.l_s_target,
- config.l_h_target,
- config.n_target)
- t2_reluctance_matrix = fr.calculate_reluctance_matrix(t2_winding_matrix, target_inductance_matrix)
-
- core_2daxi_total_volume = fr.calculate_core_2daxi_total_volume(core_inner_diameter,
- (window_h_bot + window_h_top + core_inner_diameter / 4), window_w)
-
- if np.linalg.det(t2_reluctance_matrix) != 0 and np.linalg.det(
- np.transpose(t2_winding_matrix)) != 0 and np.linalg.det(target_inductance_matrix) != 0:
- # calculate the flux
- flux_top_vec, flux_bot_vec, flux_stray_vec = fr.flux_vec_from_current_vec(
- target_and_fixed_parameters.current_extracted_1_vec,
- target_and_fixed_parameters.current_extracted_2_vec,
- t2_winding_matrix,
- target_inductance_matrix)
-
- # calculate maximum values
- flux_top_max, flux_bot_max, flux_stray_max = fr.max_value_from_value_vec(flux_top_vec, flux_bot_vec,
- flux_stray_vec)
-
- flux_density_top_max = flux_top_max / core_cross_section
- flux_density_bot_max = flux_bot_max / core_cross_section
- flux_density_middle_max = flux_stray_max / core_cross_section
-
- # calculate target values for r_top and r_bot out of reluctance matrix
- r_core_middle_cylinder_radial = fr.r_core_top_bot_radiant(core_inner_diameter, window_w,
- material_data.material_mu_r_abs,
- core_top_bot_height)
-
- r_middle_target = -t2_reluctance_matrix[0][1]
- r_top_target = t2_reluctance_matrix[0][0] - r_middle_target
- r_bot_target = t2_reluctance_matrix[1][1] - r_middle_target
-
- # calculate the core reluctance of top and bottom and middle part
- r_core_top_cylinder_inner = fr.r_core_round(core_inner_diameter, window_h_top,
- material_data.material_mu_r_abs)
- r_core_top = 2 * r_core_top_cylinder_inner + r_core_middle_cylinder_radial
- r_air_gap_top_target = r_top_target - r_core_top
-
- r_core_bot_cylinder_inner = fr.r_core_round(core_inner_diameter, window_h_bot,
- material_data.material_mu_r_abs)
- r_core_bot = 2 * r_core_bot_cylinder_inner + r_core_middle_cylinder_radial
- r_air_gap_bot_target = r_bot_target - r_core_bot
-
- r_air_gap_middle_target = r_middle_target - r_core_middle_cylinder_radial
-
- if r_air_gap_top_target > 0 and r_air_gap_bot_target > 0 and r_air_gap_middle_target > 0:
-
- # Note: a minimum air gap length of zero is not allowed. This will lead to failure calculation
- # when trying to solve (using brentq) r_gap_round_round-function. Calculating an air gap
- # reluctance with length of zero is not realistic.
- minimum_air_gap_length = 1e-15
- maximum_air_gap_length = 5e-3
- minimum_sort_out_air_gap_length = 0
- try:
- # solving brentq needs to be in try/except statement,
- # as it can be that there is no sign changing in the given interval
- # to search for the zero.
- # Note: setting full output to true and taking object [0] is only
- # to avoid linting error!
- l_top_air_gap = optimize.brentq(fr.r_air_gap_round_inf_sct, minimum_air_gap_length, maximum_air_gap_length,
- args=(core_inner_diameter, window_h_top, r_air_gap_top_target), full_output=True)[0]
-
- l_bot_air_gap = optimize.brentq(fr.r_air_gap_round_round_sct, minimum_air_gap_length,
- maximum_air_gap_length, args=(core_inner_diameter, window_h_bot / 2, window_h_bot / 2,
- r_air_gap_bot_target), full_output=True)[0]
-
- l_middle_air_gap = optimize.brentq(fr.r_air_gap_tablet_cylinder_sct, minimum_air_gap_length,
- maximum_air_gap_length, args=(core_inner_diameter,
- core_inner_diameter / 4, window_w, r_air_gap_middle_target),
- full_output=True)[0]
-
- except ValueError:
- # ValueError is raised in case of an air gap with length of zero
- return float('nan'), float('nan')
-
- if l_top_air_gap > core_inner_diameter or l_bot_air_gap > core_inner_diameter:
- return float('nan'), float('nan')
-
- if l_top_air_gap >= minimum_sort_out_air_gap_length and l_bot_air_gap >= minimum_sort_out_air_gap_length \
- and l_middle_air_gap >= minimum_sort_out_air_gap_length:
- p_hyst_top = fr.hyst_losses_core_half_mu_r_imag(core_inner_diameter, window_h_top, window_w,
- material_data.material_mu_r_abs,
- flux_top_max,
- target_and_fixed_parameters.fundamental_frequency,
- material_data.material_flux_density_vec,
- material_data.material_mu_r_imag_vec)
-
- p_hyst_middle = fr.power_losses_hysteresis_cylinder_radial_direction_mu_r_imag(
- flux_stray_max,
- core_inner_diameter / 4,
- core_inner_diameter / 2,
- core_inner_diameter / 2 + window_w,
- target_and_fixed_parameters.fundamental_frequency,
- material_data.material_mu_r_abs,
- material_data.material_flux_density_vec,
- material_data.material_mu_r_imag_vec)
-
- p_hyst_bot = fr.hyst_losses_core_half_mu_r_imag(core_inner_diameter, window_h_bot, window_w,
- material_data.material_mu_r_abs,
- flux_bot_max,
- target_and_fixed_parameters.fundamental_frequency,
- material_data.material_flux_density_vec,
- material_data.material_mu_r_imag_vec)
-
- p_hyst = p_hyst_top + p_hyst_bot + p_hyst_middle
-
- primary_effective_conductive_cross_section = primary_litz["strands_numbers"] * primary_litz[
- "strand_radii"] ** 2 * np.pi
- primary_effective_conductive_radius = np.sqrt(
- primary_effective_conductive_cross_section / np.pi)
- primary_resistance = fr.resistance_solid_wire(core_inner_diameter, window_w,
- n_p_top + n_p_bot,
- primary_effective_conductive_radius,
- material='Copper')
- primary_dc_loss = primary_resistance * target_and_fixed_parameters.i_rms_1 ** 2
-
- secondary_effective_conductive_cross_section = secondary_litz["strands_numbers"] * secondary_litz["strand_radii"] ** 2 * np.pi
- secondary_effective_conductive_radius = np.sqrt(
- secondary_effective_conductive_cross_section / np.pi)
- secondary_resistance = fr.resistance_solid_wire(core_inner_diameter, window_w,
- n_s_top + n_s_bot,
- secondary_effective_conductive_radius,
- material='Copper')
- secondary_dc_loss = secondary_resistance * target_and_fixed_parameters.i_rms_2 ** 2
-
- total_loss = p_hyst + primary_dc_loss + secondary_dc_loss
-
- trial.set_user_attr("air_gap_top", l_top_air_gap)
- trial.set_user_attr("air_gap_bot", l_bot_air_gap)
- trial.set_user_attr("air_gap_middle", l_middle_air_gap)
-
- trial.set_user_attr("flux_top_max", flux_top_max)
- trial.set_user_attr("flux_bot_max", flux_bot_max)
- trial.set_user_attr("flux_stray_max", flux_stray_max)
- trial.set_user_attr("flux_density_top_max", flux_density_top_max)
- trial.set_user_attr("flux_density_bot_max", flux_density_bot_max)
- trial.set_user_attr("flux_density_stray_max", flux_density_middle_max)
- trial.set_user_attr("p_hyst", p_hyst)
- trial.set_user_attr("primary_litz_wire_loss", primary_dc_loss)
- trial.set_user_attr("secondary_litz_wire_loss", secondary_dc_loss)
-
- print(f"successfully calculated trial {trial.number}")
-
- valid_design_dict = ItoSingleResultFile(
- case=trial.number,
- air_gap_top=l_top_air_gap,
- air_gap_bot=l_bot_air_gap,
- air_gap_middle=l_middle_air_gap,
- n_p_top=n_p_top,
- n_p_bot=n_p_bot,
- n_s_top=n_s_top,
- n_s_bot=n_s_bot,
- window_h_top=window_h_top,
- window_h_bot=window_h_bot,
- window_w=window_w,
- core_material=material_data.material_name,
- core_inner_diameter=core_inner_diameter,
- primary_litz_wire=primary_litz_wire,
- secondary_litz_wire=secondary_litz_wire,
- # results
- flux_top_max=flux_top_max,
- flux_bot_max=flux_bot_max,
- flux_stray_max=flux_stray_max,
- flux_density_top_max=flux_density_top_max,
- flux_density_bot_max=flux_density_bot_max,
- flux_density_stray_max=flux_density_middle_max,
- p_hyst=p_hyst,
- core_2daxi_total_volume=core_2daxi_total_volume,
- primary_litz_wire_loss=primary_dc_loss,
- secondary_litz_wire_loss=secondary_dc_loss,
- total_loss=total_loss
-
- )
-
- return core_2daxi_total_volume, total_loss
- else:
- return float('nan'), float('nan')
+ * returning failed trails by using return float('nan'), float('nan'),
+ see https://optuna.readthedocs.io/en/stable/faq.html#how-are-nans-returned-by-trials-handled
+ * speed up the search for NSGA-II algorithm with dynamic alter the search space, see https://optuna.readthedocs.io/en/stable/faq.html#id10
+
+
+ :param trial: parameter suggesting by optuna
+ :type trial: optuna.Trial
+ :param config: input configuration file
+ :type config: ItoSingleInputConfig
+ :param target_and_fixed_parameters: target and fix parameters
+ :type target_and_fixed_parameters: ItoTargetAndFixedParameters
+ """
+ # pass multiple arguments to the objective function used by optuna
+ # https://www.kaggle.com/general/261870
+
+ #########################################################
+ # set core geometry optimization parameters
+ #########################################################
+ core_inner_diameter = trial.suggest_float("core_inner_diameter",
+ config.core_inner_diameter_min_max_list[0],
+ config.core_inner_diameter_min_max_list[1])
+ window_w = trial.suggest_float("window_w", config.window_w_min_max_list[0],
+ config.window_w_min_max_list[1])
+ window_h_top = trial.suggest_float("window_h_top", config.window_h_top_min_max_list[0],
+ config.window_h_top_min_max_list[1])
+ window_h_bot = trial.suggest_float("window_h_bot", config.window_h_bot_min_max_list[0],
+ config.window_h_bot_min_max_list[1])
+
+ material = trial.suggest_categorical("material", config.material_list)
+ primary_litz_wire = trial.suggest_categorical("primary_litz_wire", config.primary_litz_wire_list)
+ secondary_litz_wire = trial.suggest_categorical("secondary_litz_wire", config.secondary_litz_wire_list)
+
+ # cross-section comparison is according to a square for round wire.
+ # this approximation is more realistic
+ # insulation
+ insulation_distance = 1e-3
+ insulation_cross_section_top = 2 * insulation_distance * (window_w + window_h_top)
+ insulation_cross_section_bot = 2 * insulation_distance * (window_w + window_h_bot)
+
+ litz_database = ff.litz_database()
+
+ primary_litz = litz_database[primary_litz_wire]
+ secondary_litz = litz_database[secondary_litz_wire]
+
+ total_available_window_cross_section_top = window_h_top * window_w - insulation_cross_section_top
+ total_available_window_cross_section_bot = window_h_bot * window_w - insulation_cross_section_bot
+
+ #########################################################
+ # set dynamic wire count parameters as optimization parameters
+ #########################################################
+ # set the winding search space dynamic
+ # https://optuna.readthedocs.io/en/stable/faq.html#what-happens-when-i-dynamically-alter-a-search-space
+
+ # n_p_top suggestion
+ n_p_top_max = total_available_window_cross_section_top / (2 * primary_litz["conductor_radii"]) ** 2
+ n_p_top = trial.suggest_int("n_p_top", 0, n_p_top_max)
+
+ # n_s_top_suggestion
+ winding_cross_section_n_p_top_max = n_p_top * (2 * primary_litz["conductor_radii"]) ** 2
+ n_s_top_max = int((total_available_window_cross_section_top - winding_cross_section_n_p_top_max) / (
+ 2 * secondary_litz["conductor_radii"]) ** 2)
+ n_s_top = trial.suggest_int("n_s_top", 0, n_s_top_max)
+
+ # n_p_bot suggestion
+ n_p_bot_max = total_available_window_cross_section_bot / (2 * primary_litz["conductor_radii"]) ** 2
+ n_p_bot = trial.suggest_int("n_p_bot", 0, n_p_bot_max)
+
+ # n_s_bot suggestion
+ winding_cross_section_n_p_bot_max = n_p_bot * (2 * primary_litz["conductor_radii"]) ** 2
+ n_s_bot_max = int((total_available_window_cross_section_bot - winding_cross_section_n_p_bot_max) / (2 * secondary_litz["conductor_radii"]) ** 2)
+ n_s_bot = trial.suggest_int("n_s_bot", 0, n_s_bot_max)
+
+ winding_cross_section_top = n_p_top * (2 * primary_litz["conductor_radii"]) ** 2 + n_s_top * (2 * secondary_litz["conductor_radii"]) ** 2
+ winding_cross_section_bot = n_p_bot * (2 * primary_litz["conductor_radii"]) ** 2 + n_s_bot * (2 * secondary_litz["conductor_radii"]) ** 2
+
+ thousand_simulations = trial.number / 1000
+
+ if thousand_simulations.is_integer():
+ print(f"simulation count: {trial.number}")
+
+ for material_dto in target_and_fixed_parameters.material_dto_curve_list:
+ if material_dto.material_name == material:
+ material_data = material_dto
+
+ material_mu_r_initial = material_data.material_mu_r_abs
+ flux_density_data_vec = material_data.material_flux_density_vec
+ mu_r_imag_data_vec = material_data.material_mu_r_imag_vec
+
+ core_top_bot_height = core_inner_diameter / 4
+ core_cross_section = (core_inner_diameter / 2) ** 2 * np.pi
+
+ t2_winding_matrix = [[n_p_top, n_s_top], [n_p_bot, n_s_bot]]
+
+ target_inductance_matrix = fr.calculate_inductance_matrix_from_ls_lh_n(config.l_s_target,
+ config.l_h_target,
+ config.n_target)
+ t2_reluctance_matrix = fr.calculate_reluctance_matrix(t2_winding_matrix, target_inductance_matrix)
+
+ core_2daxi_total_volume = fr.calculate_core_2daxi_total_volume(core_inner_diameter,
+ (window_h_bot + window_h_top + core_inner_diameter / 4), window_w)
+
+ if np.linalg.det(t2_reluctance_matrix) != 0 and np.linalg.det(
+ np.transpose(t2_winding_matrix)) != 0 and np.linalg.det(target_inductance_matrix) != 0:
+ # calculate the flux
+ flux_top_vec, flux_bot_vec, flux_stray_vec = fr.flux_vec_from_current_vec(
+ target_and_fixed_parameters.current_extracted_1_vec,
+ target_and_fixed_parameters.current_extracted_2_vec,
+ t2_winding_matrix,
+ target_inductance_matrix)
+
+ # calculate maximum values
+ flux_top_max, flux_bot_max, flux_stray_max = fr.max_value_from_value_vec(flux_top_vec, flux_bot_vec,
+ flux_stray_vec)
+
+ flux_density_top_max = flux_top_max / core_cross_section
+ flux_density_bot_max = flux_bot_max / core_cross_section
+ flux_density_middle_max = flux_stray_max / core_cross_section
+
+ # calculate target values for r_top and r_bot out of reluctance matrix
+ r_core_middle_cylinder_radial = fr.r_core_top_bot_radiant(core_inner_diameter, window_w,
+ material_data.material_mu_r_abs,
+ core_top_bot_height)
+
+ r_middle_target = -t2_reluctance_matrix[0][1]
+ r_top_target = t2_reluctance_matrix[0][0] - r_middle_target
+ r_bot_target = t2_reluctance_matrix[1][1] - r_middle_target
+
+ # calculate the core reluctance of top and bottom and middle part
+ r_core_top_cylinder_inner = fr.r_core_round(core_inner_diameter, window_h_top,
+ material_data.material_mu_r_abs)
+ r_core_top = 2 * r_core_top_cylinder_inner + r_core_middle_cylinder_radial
+ r_air_gap_top_target = r_top_target - r_core_top
+
+ r_core_bot_cylinder_inner = fr.r_core_round(core_inner_diameter, window_h_bot,
+ material_data.material_mu_r_abs)
+ r_core_bot = 2 * r_core_bot_cylinder_inner + r_core_middle_cylinder_radial
+ r_air_gap_bot_target = r_bot_target - r_core_bot
+
+ r_air_gap_middle_target = r_middle_target - r_core_middle_cylinder_radial
+
+ if r_air_gap_top_target > 0 and r_air_gap_bot_target > 0 and r_air_gap_middle_target > 0:
+
+ # Note: a minimum air gap length of zero is not allowed. This will lead to failure calculation
+ # when trying to solve (using brentq) r_gap_round_round-function. Calculating an air gap
+ # reluctance with length of zero is not realistic.
+ minimum_air_gap_length = 1e-15
+ maximum_air_gap_length = 5e-3
+ minimum_sort_out_air_gap_length = 0
+ try:
+ # solving brentq needs to be in try/except statement,
+ # as it can be that there is no sign changing in the given interval
+ # to search for the zero.
+ # Note: setting full output to true and taking object [0] is only
+ # to avoid linting error!
+ l_top_air_gap = optimize.brentq(fr.r_air_gap_round_inf_sct, minimum_air_gap_length, maximum_air_gap_length,
+ args=(core_inner_diameter, window_h_top, r_air_gap_top_target), full_output=True)[0]
+
+ l_bot_air_gap = optimize.brentq(fr.r_air_gap_round_round_sct, minimum_air_gap_length,
+ maximum_air_gap_length, args=(core_inner_diameter, window_h_bot / 2, window_h_bot / 2,
+ r_air_gap_bot_target), full_output=True)[0]
+
+ l_middle_air_gap = optimize.brentq(fr.r_air_gap_tablet_cylinder_sct, minimum_air_gap_length,
+ maximum_air_gap_length, args=(core_inner_diameter,
+ core_inner_diameter / 4, window_w, r_air_gap_middle_target),
+ full_output=True)[0]
+
+ except ValueError:
+ # ValueError is raised in case of an air gap with length of zero
+ return float('nan'), float('nan')
+
+ if l_top_air_gap > core_inner_diameter or l_bot_air_gap > core_inner_diameter:
+ return float('nan'), float('nan')
+
+ if l_top_air_gap >= minimum_sort_out_air_gap_length and l_bot_air_gap >= minimum_sort_out_air_gap_length \
+ and l_middle_air_gap >= minimum_sort_out_air_gap_length:
+ p_hyst_top = fr.hyst_losses_core_half_mu_r_imag(core_inner_diameter, window_h_top, window_w,
+ material_data.material_mu_r_abs,
+ flux_top_max,
+ target_and_fixed_parameters.fundamental_frequency,
+ material_data.material_flux_density_vec,
+ material_data.material_mu_r_imag_vec)
+
+ p_hyst_middle = fr.power_losses_hysteresis_cylinder_radial_direction_mu_r_imag(
+ flux_stray_max,
+ core_inner_diameter / 4,
+ core_inner_diameter / 2,
+ core_inner_diameter / 2 + window_w,
+ target_and_fixed_parameters.fundamental_frequency,
+ material_data.material_mu_r_abs,
+ material_data.material_flux_density_vec,
+ material_data.material_mu_r_imag_vec)
+
+ p_hyst_bot = fr.hyst_losses_core_half_mu_r_imag(core_inner_diameter, window_h_bot, window_w,
+ material_data.material_mu_r_abs,
+ flux_bot_max,
+ target_and_fixed_parameters.fundamental_frequency,
+ material_data.material_flux_density_vec,
+ material_data.material_mu_r_imag_vec)
+
+ p_hyst = p_hyst_top + p_hyst_bot + p_hyst_middle
+
+ primary_effective_conductive_cross_section = primary_litz["strands_numbers"] * primary_litz[
+ "strand_radii"] ** 2 * np.pi
+ primary_effective_conductive_radius = np.sqrt(
+ primary_effective_conductive_cross_section / np.pi)
+ primary_resistance = fr.resistance_solid_wire(core_inner_diameter, window_w,
+ n_p_top + n_p_bot,
+ primary_effective_conductive_radius,
+ material='Copper')
+ primary_dc_loss = primary_resistance * target_and_fixed_parameters.i_rms_1 ** 2
+
+ secondary_effective_conductive_cross_section = secondary_litz["strands_numbers"] * secondary_litz["strand_radii"] ** 2 * np.pi
+ secondary_effective_conductive_radius = np.sqrt(
+ secondary_effective_conductive_cross_section / np.pi)
+ secondary_resistance = fr.resistance_solid_wire(core_inner_diameter, window_w,
+ n_s_top + n_s_bot,
+ secondary_effective_conductive_radius,
+ material='Copper')
+ secondary_dc_loss = secondary_resistance * target_and_fixed_parameters.i_rms_2 ** 2
+
+ total_loss = p_hyst + primary_dc_loss + secondary_dc_loss
+
+ trial.set_user_attr("air_gap_top", l_top_air_gap)
+ trial.set_user_attr("air_gap_bot", l_bot_air_gap)
+ trial.set_user_attr("air_gap_middle", l_middle_air_gap)
+
+ trial.set_user_attr("flux_top_max", flux_top_max)
+ trial.set_user_attr("flux_bot_max", flux_bot_max)
+ trial.set_user_attr("flux_stray_max", flux_stray_max)
+ trial.set_user_attr("flux_density_top_max", flux_density_top_max)
+ trial.set_user_attr("flux_density_bot_max", flux_density_bot_max)
+ trial.set_user_attr("flux_density_stray_max", flux_density_middle_max)
+ trial.set_user_attr("p_hyst", p_hyst)
+ trial.set_user_attr("primary_litz_wire_loss", primary_dc_loss)
+ trial.set_user_attr("secondary_litz_wire_loss", secondary_dc_loss)
+
+ print(f"successfully calculated trial {trial.number}")
+
+ valid_design_dict = ItoSingleResultFile(
+ case=trial.number,
+ air_gap_top=l_top_air_gap,
+ air_gap_bot=l_bot_air_gap,
+ air_gap_middle=l_middle_air_gap,
+ n_p_top=n_p_top,
+ n_p_bot=n_p_bot,
+ n_s_top=n_s_top,
+ n_s_bot=n_s_bot,
+ window_h_top=window_h_top,
+ window_h_bot=window_h_bot,
+ window_w=window_w,
+ core_material=material_data.material_name,
+ core_inner_diameter=core_inner_diameter,
+ primary_litz_wire=primary_litz_wire,
+ secondary_litz_wire=secondary_litz_wire,
+ # results
+ flux_top_max=flux_top_max,
+ flux_bot_max=flux_bot_max,
+ flux_stray_max=flux_stray_max,
+ flux_density_top_max=flux_density_top_max,
+ flux_density_bot_max=flux_density_bot_max,
+ flux_density_stray_max=flux_density_middle_max,
+ p_hyst=p_hyst,
+ core_2daxi_total_volume=core_2daxi_total_volume,
+ primary_litz_wire_loss=primary_dc_loss,
+ secondary_litz_wire_loss=secondary_dc_loss,
+ total_loss=total_loss
+
+ )
+
+ return core_2daxi_total_volume, total_loss
else:
return float('nan'), float('nan')
else:
return float('nan'), float('nan')
+ else:
+ return float('nan'), float('nan')
- @staticmethod
- def start_study(study_name: str, config: ItoSingleInputConfig, number_trials: int,
- storage: str = None) -> None:
- """
- Start a study to optimize an integrated transformer.
-
- Note: Due to performance reasons, the study is calculated in RAM.
- After finishing the study, the results are copied to sqlite or mysql database by the use of a new study.
-
- :param study_name: Name of the study
- :type study_name: str
- :param config: simulation configuration
- :type config: ItoSingleInputConfig
- :param number_trials: number of trials
- :type number_trials: int
- :param storage: "sqlite" or "mysql"
- :type storage: str
- """
- # calculate the target and fixed parameters
- # and generate the folder structure inside this function
- target_and_fixed_parameters = femmt.optimization.IntegratedTransformerOptimization.calculate_fix_parameters(config)
-
- # Wrap the objective inside a lambda and call objective inside it
- func = lambda trial: femmt.IntegratedTransformerOptimization.ReluctanceModel.NSGAII.objective(trial, config, target_and_fixed_parameters)
-
- # Pass func to Optuna studies
- study_in_memory = optuna.create_study(directions=["minimize", "minimize"],
- # sampler=optuna.samplers.TPESampler(),
- sampler=optuna.samplers.NSGAIISampler(),
- )
-
- # set logging verbosity:
- # https://optuna.readthedocs.io/en/stable/reference/generated/optuna.logging.set_verbosity.html#optuna.logging.set_verbosity
- # .INFO: all messages (default)
- # .WARNING: fails and warnings
- # .ERROR: only errors
- optuna.logging.set_verbosity(optuna.logging.ERROR)
-
+ @staticmethod
+ def start_proceed_study(config: ItoSingleInputConfig, number_trials: Optional[int] = None,
+ target_number_trials: Optional[int] = None, storage: str = 'sqlite',
+ sampler=optuna.samplers.NSGAIIISampler(),
+ ) -> None:
+ """
+ Proceed a study which is stored as sqlite database.
+
+ :param config: Simulation configuration
+ :type config: ItoSingleInputConfig
+ :param number_trials: Number of trials adding to the existing study
+ :type number_trials: int
+ :param storage: storage database, e.g. 'sqlite' or 'mysql'
+ :type storage: str
+ :param target_number_trials: Number of target trials for the existing study
+ :type target_number_trials: int
+ :param sampler: optuna.samplers.NSGAIISampler() or optuna.samplers.NSGAIIISampler(). Note about the brackets () !!
+ :type sampler: optuna.sampler-object
+ """
+ if os.path.exists(f"{config.integrated_transformer_optimization_directory}/{config.integrated_transformer_study_name}.sqlite3"):
+ print("Existing study found. Proceeding.")
+
+ target_and_fixed_parameters = IntegratedTransformerOptimization.calculate_fix_parameters(config)
+
+ # introduce study in storage, e.g. sqlite or mysql
+ if storage == 'sqlite':
+ # Note: for sqlite operation, there needs to be three slashes '///' even before the path '/home/...'
+ # Means, in total there are four slashes including the path itself '////home/.../database.sqlite3'
+ storage = f"sqlite:///{config.integrated_transformer_optimization_directory}/{config.integrated_transformer_study_name}.sqlite3"
+ elif storage == 'mysql':
+ storage = "mysql://monty@localhost/mydb",
+
+ # set logging verbosity: https://optuna.readthedocs.io/en/stable/reference/generated/optuna.logging.set_verbosity.html#optuna.logging.set_verbosity
+ # .INFO: all messages (default)
+ # .WARNING: fails and warnings
+ # .ERROR: only errors
+ optuna.logging.set_verbosity(optuna.logging.ERROR)
+
+ func = lambda trial: IntegratedTransformerOptimization.ReluctanceModel.objective(trial, config, target_and_fixed_parameters)
+
+ study_in_storage = optuna.create_study(study_name=config.integrated_transformer_study_name,
+ storage=storage,
+ directions=['minimize', 'minimize'],
+ load_if_exists=True, sampler=sampler)
+
+ if target_number_trials is not None:
+ # simulation for a given number of target trials
+ if len(study_in_storage.trials) < target_number_trials:
+ study_in_memory = optuna.create_study(directions=['minimize', 'minimize'],
+ study_name=config.integrated_transformer_study_name, sampler=sampler)
+ print(f"Sampler is {study_in_memory.sampler.__class__.__name__}")
+ study_in_memory.add_trials(study_in_storage.trials)
+ number_trials = target_number_trials - len(study_in_memory.trials)
+ study_in_memory.optimize(func, n_trials=number_trials, show_progress_bar=True)
+ study_in_storage.add_trials(study_in_memory.trials[-number_trials:])
+ print(f"Finished {number_trials} trials.")
+ print(f"current time: {datetime.datetime.now()}")
+ else:
+ print(f"Study has already {len(study_in_storage.trials)} trials, and target is {target_number_trials} trials.")
+
+ else:
+ # normal simulation with number_trials
+ study_in_memory = optuna.create_study(directions=['minimize', 'minimize'], study_name=config.integrated_transformer_study_name, sampler=sampler)
print(f"Sampler is {study_in_memory.sampler.__class__.__name__}")
- study_in_memory.optimize(func, n_trials=number_trials, n_jobs=-1, gc_after_trial=False)
-
- # in-memory calculation is shown before saving the data to database
- fig = optuna.visualization.plot_pareto_front(study_in_memory, target_names=["volume", "losses"])
- fig.show()
-
- # introduce study in storage, e.g. sqlite or mysql
- if storage == 'sqlite':
- # Note: for sqlite operation, there needs to be three slashes '///' even before the path '/home/...'
- # Means, in total there are four slashes including the path itself '////home/.../database.sqlite3'
- storage = f"sqlite:///{config.working_directory}/study_{study_name}.sqlite3"
- elif storage == 'mysql':
- storage = "mysql://monty@localhost/mydb",
-
- study_in_storage = optuna.create_study(directions=["minimize", "minimize"], study_name=study_name,
- storage=storage)
- study_in_storage.add_trials(study_in_memory.trials)
-
- @staticmethod
- def proceed_study(study_name: str, config: ItoSingleInputConfig, number_trials: int) -> None:
- """
- Proceed a study which is stored as sqlite database.
-
- :param study_name: Name of the study
- :type study_name: str
- :param config: Simulation configuration
- :type config: ItoSingleInputConfig
- :param number_trials: Number of trials adding to the existing study
- :type number_trials: int
- """
- target_and_fixed_parameters = femmt.optimization.IntegratedTransformerOptimization.calculate_fix_parameters(config)
-
- # Wrap the objective inside a lambda and call objective inside it
- func = lambda trial: femmt.optimization.IntegratedTransformerOptimization.ReluctanceModel.NSGAII.objective(trial, config,
- target_and_fixed_parameters)
-
- study = optuna.create_study(study_name=study_name, storage=f"sqlite:///study_{study_name}.sqlite3",
- load_if_exists=True)
- study.optimize(func, n_trials=number_trials)
-
- @staticmethod
- def show_study_results(study_name: str, config: ItoSingleInputConfig) -> None:
- """
- Show the results of a study.
-
- :param study_name: Name of the study
- :type study_name: str
- :param config: Integrated transformer configuration file
- :type config: ItoSingleInputConfig
- """
- study = optuna.create_study(study_name=study_name,
- storage=f"sqlite:///{config.working_directory}/study_{study_name}.sqlite3",
- load_if_exists=True)
-
- fig = optuna.visualization.plot_pareto_front(study, target_names=["volume", "losses"])
- fig.show()
-
- ##############################
- # load
- ##############################
-
- @staticmethod
- def load_study_to_dto(study_name: str, config: ItoSingleInputConfig) -> List[ItoSingleResultFile]:
- """
- Load all trials of a study to a DTO-list.
-
- :param study_name: Name of the study
- :type study_name: str
- :param config: Integrated transformer configuration file
- :type config: ItoSingleInputConfig
- :return: List of all trials
- :rtype: List[ItoSingleResultFile]
-
- """
- study = optuna.create_study(study_name=study_name,
- storage=f"sqlite:///{config.working_directory}/study_{study_name}.sqlite3",
- load_if_exists=True)
-
- dto_list = [op.OptunaFemmtParser.parse(frozen_object) for frozen_object in study.trials \
- if frozen_object.state == optuna.trial.TrialState.COMPLETE]
-
- return dto_list
-
- @staticmethod
- def load_study_best_trials_to_dto(study_name: str, config: ItoSingleInputConfig) -> List[ItoSingleResultFile]:
- """
- Load the best trials (Pareto front) of a study.
-
- :param study_name: Name of the study
- :type study_name: str
- :param config: Integrated transformer configuration file
- :type config: ItoSingleInputConfig
- :return: List of the best trials.
- :rtype: List[ItoSingleResultFile]
-
- """
- study = optuna.create_study(study_name=study_name,
- storage=f"sqlite:///{config.working_directory}/study_{study_name}.sqlite3",
- load_if_exists=True)
-
- print(study.best_trials[0])
-
- dto_list = [op.OptunaFemmtParser.parse(frozen_object) for frozen_object in study.best_trials]
-
- return dto_list
+ study_in_memory.add_trials(study_in_storage.trials)
+ study_in_memory.optimize(func, n_trials=number_trials, show_progress_bar=True)
+
+ study_in_storage.add_trials(study_in_memory.trials[-number_trials:])
+ print(f"Finished {number_trials} trials.")
+ print(f"current time: {datetime.datetime.now()}")
+ IntegratedTransformerOptimization.ReluctanceModel.save_config(config)
+
+ @staticmethod
+ def show_study_results(config: ItoSingleInputConfig) -> None:
+ """Show the results of a study.
+
+ A local .html file is generated under config.working_directory to store the interactive plotly plots on disk.
+
+ :param config: Integrated transformer configuration file
+ :type config: ItoSingleInputConfig
+ """
+ study = optuna.load_study(study_name=config.integrated_transformer_study_name,
+ storage=f"sqlite:///{config.integrated_transformer_optimization_directory}/"
+ f"{config.integrated_transformer_study_name}.sqlite3")
+
+ fig = optuna.visualization.plot_pareto_front(study, targets=lambda t: (t.values[0], t.values[1]), target_names=["volume in m³", "loss in W"])
+ fig.update_layout(title=f"{config.integrated_transformer_study_name}
{config.integrated_transformer_optimization_directory}")
+ fig.write_html(f"{config.integrated_transformer_optimization_directory}/{config.integrated_transformer_study_name}"
+ f"_{datetime.datetime.now().isoformat(timespec='minutes')}.html")
+ fig.show()
+
+ ##############################
+ # load
+ ##############################
+
+ @staticmethod
+ def load_study_to_dto(study_name: str, config: ItoSingleInputConfig) -> List[ItoSingleResultFile]:
+ """
+ Load all trials of a study to a DTO-list.
+
+ :param study_name: Name of the study
+ :type study_name: str
+ :param config: Integrated transformer configuration file
+ :type config: ItoSingleInputConfig
+ :return: List of all trials
+ :rtype: List[ItoSingleResultFile]
+
+ """
+ study = optuna.create_study(study_name=study_name,
+ storage=f"sqlite:///{config.working_directory}/study_{study_name}.sqlite3",
+ load_if_exists=True)
+
+ dto_list = [op.OptunaFemmtParser.parse(frozen_object) for frozen_object in study.trials \
+ if frozen_object.state == optuna.trial.TrialState.COMPLETE]
+
+ return dto_list
+
+ @staticmethod
+ def load_study_best_trials_to_dto(study_name: str, config: ItoSingleInputConfig) -> List[ItoSingleResultFile]:
+ """
+ Load the best trials (Pareto front) of a study.
+
+ :param study_name: Name of the study
+ :type study_name: str
+ :param config: Integrated transformer configuration file
+ :type config: ItoSingleInputConfig
+ :return: List of the best trials.
+ :rtype: List[ItoSingleResultFile]
+
+ """
+ study = optuna.create_study(study_name=study_name,
+ storage=f"sqlite:///{config.working_directory}/study_{study_name}.sqlite3",
+ load_if_exists=True)
+
+ print(study.best_trials[0])
+
+ dto_list = [op.OptunaFemmtParser.parse(frozen_object) for frozen_object in study.best_trials]
+
+ return dto_list
#############################
# filter
@@ -1142,6 +705,33 @@ def filter_min_air_gap_length(dto_list_to_filter: List[ItoSingleResultFile], min
# save and load
#############################
+ @staticmethod
+ def save_config(config: ItoSingleInputConfig) -> None:
+ """
+ Save the configuration file as pickle file on the disk.
+
+ :param config: configuration
+ :type config: InductorOptimizationDTO
+ """
+ # convert config path to an absolute filepath
+ config.inductor_optimization_directory = os.path.abspath(config.integrated_transformer_optimization_directory)
+ os.makedirs(config.integrated_transformer_optimization_directory, exist_ok=True)
+ with open(f"{config.integrated_transformer_optimization_directory}/{config.integrated_transformer_study_name}.pkl", 'wb') as output:
+ pickle.dump(config, output, pickle.HIGHEST_PROTOCOL)
+
+ @staticmethod
+ def load_config(config_pickle_filepath: str) -> ItoSingleInputConfig:
+ """
+ Load pickle configuration file from disk.
+
+ :param config_pickle_filepath: filepath to the pickle configuration file
+ :type config_pickle_filepath: str
+ :return: Configuration file as InductorOptimizationDTO object
+ :rtype: InductorOptimizationDTO
+ """
+ with open(config_pickle_filepath, 'rb') as pickle_file_data:
+ return pickle.load(pickle_file_data)
+
@staticmethod
def save_dto_list(result_dto_list: List[ItoSingleResultFile], filepath: str):
"""
diff --git a/femmt/optimization/ito_dtos.py b/femmt/optimization/ito_dtos.py
index e2a955f2..8dd09abc 100644
--- a/femmt/optimization/ito_dtos.py
+++ b/femmt/optimization/ito_dtos.py
@@ -17,6 +17,8 @@ class ItoSingleInputConfig:
Also specifies the working directory where to store the results.
"""
+ integrated_transformer_study_name: str
+
l_s_target: float
l_h_target: float
n_target: float
@@ -31,7 +33,7 @@ class ItoSingleInputConfig:
primary_litz_wire_list: list
secondary_litz_wire_list: list
temperature: float
- working_directory: str
+ integrated_transformer_optimization_directory: str
@dataclass
class WorkingDirectories:
diff --git a/femmt/optimization/sto_dtos.py b/femmt/optimization/sto_dtos.py
index c3f39dd4..59782a8c 100644
--- a/femmt/optimization/sto_dtos.py
+++ b/femmt/optimization/sto_dtos.py
@@ -110,7 +110,7 @@ class StoSingleInputConfig:
core_name_list: Optional[List[str]]
core_inner_diameter_min_max_list: Optional[List[float]]
window_w_min_max_list: Optional[List[float]]
- window_h_bot_min_max_list: list
+ window_h_bot_min_max_list: Optional[List[float]]
primary_litz_wire_list: list
secondary_litz_wire_list: list
From 441c4bfd8619c00db8a626d31fa257aca85aeda7 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Wed, 26 Feb 2025 13:49:04 +0100
Subject: [PATCH 02/15] introduce df
---
femmt/examples/ito_optuna_example.py | 43 +++---
femmt/optimization/ito.py | 188 +++++----------------------
2 files changed, 52 insertions(+), 179 deletions(-)
diff --git a/femmt/examples/ito_optuna_example.py b/femmt/examples/ito_optuna_example.py
index 7faf904b..8a9d4315 100644
--- a/femmt/examples/ito_optuna_example.py
+++ b/femmt/examples/ito_optuna_example.py
@@ -41,10 +41,10 @@
)
-# task = 'start_study'
+task = 'start_study'
# task = 'filter_reluctance_model'
# task = 'fem_simulation_from_filtered_reluctance_model_results'
-task = 'plot_study_results'
+# task = 'plot_study_results'
if __name__ == '__main__':
time_start = datetime.datetime.now()
@@ -52,27 +52,24 @@
if task == 'start_study':
fmt.IntegratedTransformerOptimization.ReluctanceModel.start_proceed_study(dab_transformer_config, 100, storage='sqlite')
- # elif task == 'filter_reluctance_model':
- # # load trials from reluctance model
- # reluctance_result_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.NSGAII.load_study_to_dto(study_name, dab_transformer_config)
- # print(f"{len(reluctance_result_list)=}")
- #
- # # filter air gaps
- # filtered_air_gaps_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_min_air_gap_length(reluctance_result_list)
- # print(f"{len(filtered_air_gaps_dto_list)=}")
- #
- # # filter for Pareto front
- # pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_loss_list(
- # filtered_air_gaps_dto_list, factor_min_dc_losses=0.5)
- # print(f"{len(pareto_reluctance_dto_list)=}")
- #
- # fmt.IntegratedTransformerOptimization.plot(reluctance_result_list)
- # fmt.IntegratedTransformerOptimization.plot(pareto_reluctance_dto_list)
- #
- # # save results
- # fmt.IntegratedTransformerOptimization.ReluctanceModel.save_dto_list(pareto_reluctance_dto_list, os.path.join(dab_transformer_config.working_directory,
- # '01_reluctance_model_results_filtered'))
- #
+ elif task == 'filter_reluctance_model':
+ # load trials from reluctance model to a pandas dataframe (df)
+ reluctance_result_df = fmt.IntegratedTransformerOptimization.ReluctanceModel.study_to_df(dab_transformer_config)
+
+ # filter air gaps
+ # filtered_air_gaps_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_min_air_gap_length(reluctance_result_df)
+
+ # filter for Pareto front
+ pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_loss_list_df(
+ reluctance_result_df, factor_min_dc_losses=0.5)
+
+ fmt.IntegratedTransformerOptimization.plot(reluctance_result_df)
+ fmt.IntegratedTransformerOptimization.plot(pareto_reluctance_dto_list)
+
+ # save results
+ fmt.IntegratedTransformerOptimization.ReluctanceModel.save_dto_list(pareto_reluctance_dto_list, os.path.join(dab_transformer_config.working_directory,
+ '01_reluctance_model_results_filtered'))
+
# elif task == 'fem_simulation_from_filtered_reluctance_model_results':
# # load filtered reluctance models
# pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.load_filtered_results(dab_transformer_config.working_directory)
diff --git a/femmt/optimization/ito.py b/femmt/optimization/ito.py
index da4adc89..6e9fecfa 100644
--- a/femmt/optimization/ito.py
+++ b/femmt/optimization/ito.py
@@ -2,15 +2,16 @@
# Python libraries
import os
import json
-import dataclasses
from typing import List, Dict, Tuple, Optional
import datetime
import pickle
+import logging
# 3rd party library import
import materialdatabase as mdb
from scipy import optimize
import optuna
+import pandas as pd
# femmt import
import femmt.functions as ff
@@ -571,77 +572,51 @@ def show_study_results(config: ItoSingleInputConfig) -> None:
f"_{datetime.datetime.now().isoformat(timespec='minutes')}.html")
fig.show()
- ##############################
- # load
- ##############################
-
- @staticmethod
- def load_study_to_dto(study_name: str, config: ItoSingleInputConfig) -> List[ItoSingleResultFile]:
- """
- Load all trials of a study to a DTO-list.
-
- :param study_name: Name of the study
- :type study_name: str
- :param config: Integrated transformer configuration file
- :type config: ItoSingleInputConfig
- :return: List of all trials
- :rtype: List[ItoSingleResultFile]
-
- """
- study = optuna.create_study(study_name=study_name,
- storage=f"sqlite:///{config.working_directory}/study_{study_name}.sqlite3",
- load_if_exists=True)
-
- dto_list = [op.OptunaFemmtParser.parse(frozen_object) for frozen_object in study.trials \
- if frozen_object.state == optuna.trial.TrialState.COMPLETE]
-
- return dto_list
-
@staticmethod
- def load_study_best_trials_to_dto(study_name: str, config: ItoSingleInputConfig) -> List[ItoSingleResultFile]:
+ def study_to_df(config: ItoSingleInputConfig) -> pd.DataFrame:
"""
- Load the best trials (Pareto front) of a study.
-
- :param study_name: Name of the study
- :type study_name: str
- :param config: Integrated transformer configuration file
- :type config: ItoSingleInputConfig
- :return: List of the best trials.
- :rtype: List[ItoSingleResultFile]
+ Create a Pandas dataframe from a study.
+ :param config: configuration
+ :type config: InductorOptimizationDTO
+ :return: Study results as Pandas Dataframe
+ :rtype: pd.DataFrame
"""
- study = optuna.create_study(study_name=study_name,
- storage=f"sqlite:///{config.working_directory}/study_{study_name}.sqlite3",
- load_if_exists=True)
-
- print(study.best_trials[0])
-
- dto_list = [op.OptunaFemmtParser.parse(frozen_object) for frozen_object in study.best_trials]
-
- return dto_list
+ database_url = f'sqlite:///{config.integrated_transformer_optimization_directory}/{config.integrated_transformer_study_name}.sqlite3'
+ if os.path.isfile(database_url.replace('sqlite:///', '')):
+ print("Existing study found.")
+ else:
+ raise ValueError(f"Can not find database: {database_url}")
+ loaded_study = optuna.load_study(study_name=config.integrated_transformer_study_name, storage=database_url)
+ df = loaded_study.trials_dataframe()
+ df.to_csv(f'{config.integrated_transformer_optimization_directory}/{config.integrated_transformer_study_name}.csv')
+ logging.info(f"Exported study as .csv file: {config.integrated_transformer_optimization_directory}/{config.integrated_transformer_study_name}.csv")
+ return df
#############################
# filter
#############################
@staticmethod
- def filter_loss_list(valid_design_list: List[ItoSingleResultFile], factor_min_dc_losses: float = 1.2) -> List[ItoSingleResultFile]:
+ def filter_loss_list_df(df: pd.DataFrame, factor_min_dc_losses: float = 1.2, factor_max_dc_losses: float = 10) -> pd.DataFrame:
"""
Remove designs with too high losses compared to the minimum losses.
- :param valid_design_list: list of valid DTOs
- :type valid_design_list: List[ItoSingleResultFile]
+ :param df: list of valid DTOs
+ :type df: List[ItoSingleResultFile]
:param factor_min_dc_losses: filter factor for the minimum dc losses
:type factor_min_dc_losses: float
+ :param factor_max_dc_losses: dc_max_loss = factor_max_dc_losses * min_available_dc_losses_in_pareto_front
+ :type factor_max_dc_losses: float
:returns: list with removed objects (too small air gaps)
:rtype: List[ItoSingleResultFile]
"""
# figure out pareto front
# pareto_volume_list, pareto_core_hyst_list, pareto_dto_list = self.pareto_front(volume_list, core_hyst_loss_list, valid_design_list)
- x_pareto_vec, y_pareto_vec = fo.pareto_front_from_dtos(valid_design_list)
+ pareto_df: pd.DataFrame = fo.pareto_front_from_df(df)
- vector_to_sort = np.array([x_pareto_vec, y_pareto_vec])
+ vector_to_sort = np.array([pareto_df["values_0"], pareto_df["values_1"]])
# sorting 2d array by 1st row
# https://stackoverflow.com/questions/49374253/sort-a-numpy-2d-array-by-1st-row-maintaining-columns
@@ -649,21 +624,18 @@ def filter_loss_list(valid_design_list: List[ItoSingleResultFile], factor_min_dc
x_pareto_vec = sorted_vector[0]
y_pareto_vec = sorted_vector[1]
- total_losses_list = []
- filtered_design_dto_list = []
-
- for dto in valid_design_list:
- total_losses_list.append(dto.total_loss)
+ total_losses_list = df["values_1"][~np.isnan(df['values_1'])].to_numpy()
min_total_dc_losses = total_losses_list[np.argmin(total_losses_list)]
loss_offset = factor_min_dc_losses * min_total_dc_losses
- for dto in valid_design_list:
- ref_loss = np.interp(dto.core_2daxi_total_volume, x_pareto_vec, y_pareto_vec) + loss_offset
- if dto.total_loss < ref_loss:
- filtered_design_dto_list.append(dto)
+ ref_loss_max = np.interp(df["values_0"], x_pareto_vec, y_pareto_vec) + loss_offset
+ # clip losses to a maximum of the minimum losses
+ ref_loss_max = np.clip(ref_loss_max, a_min=-1, a_max=factor_max_dc_losses * min_total_dc_losses)
- return filtered_design_dto_list
+ pareto_df_offset = df[df['values_1'] < ref_loss_max]
+
+ return pareto_df_offset
@staticmethod
def filter_max_air_gap_length(dto_list_to_filter: List[ItoSingleResultFile], max_air_gap_length: float = 1e-6) -> List[ItoSingleResultFile]:
@@ -732,102 +704,6 @@ def load_config(config_pickle_filepath: str) -> ItoSingleInputConfig:
with open(config_pickle_filepath, 'rb') as pickle_file_data:
return pickle.load(pickle_file_data)
- @staticmethod
- def save_dto_list(result_dto_list: List[ItoSingleResultFile], filepath: str):
- """
- Save the ItoSingleResultFile-List to the file structure.
-
- :param result_dto_list:
- :type result_dto_list: List[ItoSingleResultFile]
- :param filepath: filepath
- :type filepath: str
- """
- if not os.path.exists(filepath):
- os.mkdir(filepath)
-
- for _, dto in enumerate(result_dto_list):
- file_name = os.path.join(filepath, f"case_{dto.case}.json")
-
- result_dict = dataclasses.asdict(dto)
- with open(file_name, "w+", encoding='utf-8') as outfile:
- json.dump(result_dict, outfile, indent=2, ensure_ascii=False, cls=MyJSONEncoder)
-
- @staticmethod
- def save_unfiltered_results(config_file: ItoSingleInputConfig, result_file_list: List[ItoSingleResultFile]):
- """
- Save the results of the reluctance model into the file structure.
-
- :param config_file: integrated transformer configuration file
- :type config_file: ItoSingleInputConfig
- :param result_file_list: list of ItoSingleResultFiles
- :type result_file_list: List[ItoSingleResultFile]
- """
- # generate folder structure
- femmt.set_up_folder_structure(config_file.working_directory)
-
- # save optimization input parameters
- config_dict = dataclasses.asdict(config_file)
-
- integrated_transformer_optimization_input_parameters_file = os.path.join(config_file.working_directory, "optimization_input_parameters.json")
- integrated_transformer_reluctance_model_results_directory = os.path.join(config_file.working_directory, "01_reluctance_model_results")
-
- with open(integrated_transformer_optimization_input_parameters_file, "w+", encoding='utf-8') as outfile:
- json.dump(config_dict, outfile, indent=2, ensure_ascii=False, cls=MyJSONEncoder)
-
- # save reluctance parameters winning candidates
- femmt.IntegratedTransformerOptimization.ReluctanceModel.save_dto_list(result_file_list, integrated_transformer_reluctance_model_results_directory)
-
- @staticmethod
- def load_list(filepath: str) -> List[ItoSingleResultFile]:
- """
- Load the list of the reluctance models from the folder structure.
-
- :param filepath: filepath
- :type filepath: str
- :return: List of ItoSingleResultFiles
- :rtype: List[ItoSingleResultFile]
- """
- valid_design_list = []
- for file in os.listdir(filepath):
- if file.endswith(".json"):
- json_file_path = os.path.join(filepath, file)
- with open(json_file_path, "r") as fd:
- loaded_data_dict = json.loads(fd.read())
-
- valid_design_list.append(result_file_dict_to_dto(loaded_data_dict))
- if len(valid_design_list) == 0:
- raise ValueError("Specified file path is empty")
-
- return valid_design_list
-
- @staticmethod
- def load_unfiltered_results(working_directory: str) -> List[ItoSingleResultFile]:
- """
- Load the results of the reluctance model and returns the ItoSingleResultFiles as a list.
-
- :param working_directory: working directory
- :type working_directory: str
- :return: List of ItoSingleResultFiles
- :rtype: List[ItoSingleResultFile]
- """
- integrated_transformer_reluctance_model_results_directory = os.path.join(working_directory, "01_reluctance_model_results")
- print(f"Read results from {integrated_transformer_reluctance_model_results_directory}")
- return femmt.IntegratedTransformerOptimization.ReluctanceModel.load_list(integrated_transformer_reluctance_model_results_directory)
-
- @staticmethod
- def load_filtered_results(working_directory: str) -> List[ItoSingleResultFile]:
- """
- Load the results of the reluctance model and returns the ItoSingleResultFiles as a list.
-
- :param working_directory: working directory
- :type working_directory: str
- :return: List of ItoSingleResultFiles
- :rtype: List[ItoSingleResultFile]
- """
- integrated_transformer_reluctance_model_results_directory = os.path.join(working_directory, "01_reluctance_model_results_filtered")
- print(f"Read results from {integrated_transformer_reluctance_model_results_directory}")
- return femmt.IntegratedTransformerOptimization.ReluctanceModel.load_list(integrated_transformer_reluctance_model_results_directory)
-
class FemSimulation:
"""Group functions to perform FEM simulations."""
From c4f4b028f50d0fcf4cded65ffa07af6e15d3e238 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Wed, 26 Feb 2025 14:52:59 +0100
Subject: [PATCH 03/15] update filter
---
femmt/examples/ito_optuna_example.py | 32 ++++----
femmt/optimization/ito.py | 109 ++++++++++++++++++++++-----
2 files changed, 103 insertions(+), 38 deletions(-)
diff --git a/femmt/examples/ito_optuna_example.py b/femmt/examples/ito_optuna_example.py
index 8a9d4315..2a0818e5 100644
--- a/femmt/examples/ito_optuna_example.py
+++ b/femmt/examples/ito_optuna_example.py
@@ -41,8 +41,8 @@
)
-task = 'start_study'
-# task = 'filter_reluctance_model'
+# task = 'start_study'
+task = 'filter_reluctance_model'
# task = 'fem_simulation_from_filtered_reluctance_model_results'
# task = 'plot_study_results'
@@ -63,22 +63,18 @@
pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_loss_list_df(
reluctance_result_df, factor_min_dc_losses=0.5)
- fmt.IntegratedTransformerOptimization.plot(reluctance_result_df)
- fmt.IntegratedTransformerOptimization.plot(pareto_reluctance_dto_list)
-
- # save results
- fmt.IntegratedTransformerOptimization.ReluctanceModel.save_dto_list(pareto_reluctance_dto_list, os.path.join(dab_transformer_config.working_directory,
- '01_reluctance_model_results_filtered'))
-
- # elif task == 'fem_simulation_from_filtered_reluctance_model_results':
- # # load filtered reluctance models
- # pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.load_filtered_results(dab_transformer_config.working_directory)
- # print(f"{len(pareto_reluctance_dto_list)=}")
- #
- # # start FEM simulation
- # fmt.IntegratedTransformerOptimization.FemSimulation.simulate(config_dto=dab_transformer_config,
- # simulation_dto_list=pareto_reluctance_dto_list)
- #
+ fmt.IntegratedTransformerOptimization.ReluctanceModel.df_plot_pareto_front(
+ reluctance_result_df, pareto_reluctance_dto_list, label_list=["all", "filtered"], interactive=False)
+
+ elif task == 'fem_simulation_from_filtered_reluctance_model_results':
+ # load filtered reluctance models
+ pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.load_filtered_results(dab_transformer_config.working_directory)
+ print(f"{len(pareto_reluctance_dto_list)=}")
+
+ # start FEM simulation
+ fmt.IntegratedTransformerOptimization.FemSimulation.simulate(config_dto=dab_transformer_config,
+ simulation_dto_list=pareto_reluctance_dto_list)
+
elif task == 'plot_study_results':
fmt.IntegratedTransformerOptimization.ReluctanceModel.show_study_results(dab_transformer_config)
diff --git a/femmt/optimization/ito.py b/femmt/optimization/ito.py
index 6e9fecfa..1fd05101 100644
--- a/femmt/optimization/ito.py
+++ b/femmt/optimization/ito.py
@@ -12,13 +12,14 @@
from scipy import optimize
import optuna
import pandas as pd
+from matplotlib import pyplot as plt
+import matplotlib.patches as mpatches
# femmt import
import femmt.functions as ff
import femmt.functions_reluctance as fr
import femmt.optimization.functions_optimization as fo
from femmt.optimization.ito_dtos import *
-import femmt.optimization.optuna_femmt_parser as op
import femmt.optimization.ito_functions as itof
import femmt
@@ -553,25 +554,6 @@ def start_proceed_study(config: ItoSingleInputConfig, number_trials: Optional[in
print(f"current time: {datetime.datetime.now()}")
IntegratedTransformerOptimization.ReluctanceModel.save_config(config)
- @staticmethod
- def show_study_results(config: ItoSingleInputConfig) -> None:
- """Show the results of a study.
-
- A local .html file is generated under config.working_directory to store the interactive plotly plots on disk.
-
- :param config: Integrated transformer configuration file
- :type config: ItoSingleInputConfig
- """
- study = optuna.load_study(study_name=config.integrated_transformer_study_name,
- storage=f"sqlite:///{config.integrated_transformer_optimization_directory}/"
- f"{config.integrated_transformer_study_name}.sqlite3")
-
- fig = optuna.visualization.plot_pareto_front(study, targets=lambda t: (t.values[0], t.values[1]), target_names=["volume in m³", "loss in W"])
- fig.update_layout(title=f"{config.integrated_transformer_study_name}
{config.integrated_transformer_optimization_directory}")
- fig.write_html(f"{config.integrated_transformer_optimization_directory}/{config.integrated_transformer_study_name}"
- f"_{datetime.datetime.now().isoformat(timespec='minutes')}.html")
- fig.show()
-
@staticmethod
def study_to_df(config: ItoSingleInputConfig) -> pd.DataFrame:
"""
@@ -673,6 +655,93 @@ def filter_min_air_gap_length(dto_list_to_filter: List[ItoSingleResultFile], min
filtered_dtos.append(dto)
return filtered_dtos
+ #############################
+ # show results
+ #############################
+
+ @staticmethod
+ def show_study_results(config: ItoSingleInputConfig) -> None:
+ """Show the results of a study.
+
+ A local .html file is generated under config.working_directory to store the interactive plotly plots on disk.
+
+ :param config: Integrated transformer configuration file
+ :type config: ItoSingleInputConfig
+ """
+ study = optuna.load_study(study_name=config.integrated_transformer_study_name,
+ storage=f"sqlite:///{config.integrated_transformer_optimization_directory}/"
+ f"{config.integrated_transformer_study_name}.sqlite3")
+
+ fig = optuna.visualization.plot_pareto_front(study, targets=lambda t: (t.values[0], t.values[1]), target_names=["volume in m³", "loss in W"])
+ fig.update_layout(title=f"{config.integrated_transformer_study_name}
{config.integrated_transformer_optimization_directory}")
+ fig.write_html(f"{config.stacked_transformer_optimization_directory}/{config.stacked_transformer_study_name}"
+ f"_{datetime.datetime.now().isoformat(timespec='minutes')}.html")
+ fig.show()
+
+ @staticmethod
+ def df_plot_pareto_front(*dataframes: pd.DataFrame, label_list: list[str], color_list: list[str] = None,
+ interactive: bool = True) -> None:
+ """
+ Plot an interactive Pareto diagram (losses vs. volume) to select the transformers to re-simulate.
+
+ :param dataframes: Dataframe, generated from an optuna study (exported by optuna)
+ :type dataframes: pd.Dataframe
+ :param label_list: list of labels for the legend. Same order as df.
+ :type label_list: list[str]
+ :param color_list: list of colors for the points and legend. Same order as df.
+ :type color_list: list[str]
+ :param interactive: True to show trial numbers if one moves the mouse over it
+ :type interactive: bool
+ """
+ if color_list is None:
+ color_list = ['red', 'blue', 'green', 'grey']
+ for count, df in enumerate(dataframes):
+ # color_list was before list(ff.colors_femmt_default.keys())
+ df['color_r'], df['color_g'], df['color_b'] = ff.colors_femmt_default[color_list[count]]
+
+ df_all = pd.concat(dataframes, axis=0)
+ color_array = np.transpose(np.array([df_all['color_r'].to_numpy(), df_all['color_g'].to_numpy(), df_all['color_b'].to_numpy()])) / 255
+
+ names = df_all["number"].to_numpy()
+ fig, ax = plt.subplots()
+ legend_list = []
+ for count, label_text in enumerate(label_list):
+ legend_list.append(mpatches.Patch(color=np.array(ff.colors_femmt_default[color_list[count]]) / 255, label=label_text))
+ plt.legend(handles=legend_list)
+ sc = plt.scatter(df_all["values_0"], df_all["values_1"], s=10, c=color_array)
+
+ if interactive:
+ annot = ax.annotate("", xy=(0, 0), xytext=(20, 20), textcoords="offset points",
+ bbox=dict(boxstyle="round", fc="w"),
+ arrowprops=dict(arrowstyle="->"))
+ annot.set_visible(False)
+
+ def update_annot(ind):
+ pos = sc.get_offsets()[ind["ind"][0]]
+ annot.xy = pos
+ text = f"{[names[n] for n in ind['ind']]}"
+ annot.set_text(text)
+ annot.get_bbox_patch().set_alpha(0.4)
+
+ def hover(event):
+ vis = annot.get_visible()
+ if event.inaxes == ax:
+ cont, ind = sc.contains(event)
+ if cont:
+ update_annot(ind)
+ annot.set_visible(True)
+ fig.canvas.draw_idle()
+ else:
+ if vis:
+ annot.set_visible(False)
+ fig.canvas.draw_idle()
+
+ fig.canvas.mpl_connect("motion_notify_event", hover)
+ plt.xlabel('Volume in m³')
+ plt.ylabel('Losses in W')
+ plt.grid()
+ plt.show()
+
#############################
# save and load
#############################
From d184b547d781da7ce7bba637cb731dff3a8783fa Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Thu, 27 Feb 2025 10:27:21 +0100
Subject: [PATCH 04/15] update ito
---
femmt/examples/ito_brute_force_example.py | 138 ----
femmt/examples/ito_optuna_example.py | 60 +-
femmt/functions_reluctance.py | 2 +-
femmt/optimization/ito.py | 741 +++++++++++++---------
femmt/optimization/ito_dtos.py | 163 ++++-
femmt/optimization/sto.py | 10 +-
6 files changed, 647 insertions(+), 467 deletions(-)
delete mode 100644 femmt/examples/ito_brute_force_example.py
diff --git a/femmt/examples/ito_brute_force_example.py b/femmt/examples/ito_brute_force_example.py
deleted file mode 100644
index bfad044f..00000000
--- a/femmt/examples/ito_brute_force_example.py
+++ /dev/null
@@ -1,138 +0,0 @@
-"""Example how to perform a brute-force optimization."""
-import femmt as fmt
-import numpy as np
-import os
-
-core_database = fmt.core_database()
-pq2016 = core_database["PQ 20/16"]
-pq3230 = core_database["PQ 32/30"]
-pq4040 = core_database["PQ 40/40"]
-pq5050 = core_database["PQ 50/50"]
-pq6560 = core_database["PQ 65/60"]
-
-
-i_1 = [[0.0, 3.265248131976911e-07, 2.5e-06, 2.8265248131976912e-06, 5e-06],
- [-0.9996115022426437, 4.975792579275104, 0.9996115022426446, -4.975792579275103, -0.9996115022426437]]
-i_2 = [[0.0, 3.265248131976911e-07, 2.5e-06, 2.8265248131976912e-06, 5e-06],
- [-0.9196195846583147, -19.598444313231134, 0.9196195846583122, 19.59844431323113, -0.9196195846583147]]
-
-dab_transformer_config = fmt.ItoSingleInputConfig(
- l_s_target=85e-6,
- l_h_target=600e-6,
- n_target=2.9,
- time_current_1_vec=np.array(i_1),
- time_current_2_vec=np.array(i_2),
- material_list=["N95"],
- core_inner_diameter_min_max_list=[pq2016["core_inner_diameter"], pq4040["core_inner_diameter"], 2],
- window_w_min_max_list=[pq2016["window_w"], pq4040["window_w"], 3],
- window_h_top_min_max_list=[5 / 6 * pq2016["window_h"], 5 / 6 * pq3230["window_h"], 2],
- window_h_bot_min_max_list=[1 / 6 * pq2016["window_h"], 1 / 6 * pq3230["window_h"], 2],
- factor_max_flux_density=1,
- primary_litz_wire_list=["1.4x200x0.071"],
- secondary_litz_wire_list=["1.4x200x0.071"],
- temperature=100,
- working_directory=os.path.join(os.path.dirname(__file__), "example_results", "integrated_transformer_optimization")
-)
-
-# task = 'simulation_reluctance'
-task = 'load_reluctance_and_filter'
-# task = 'load_reluctance_filter_and_simulate_fem'
-# task = 'plot_and_filter_fem_simulations_results'
-# task = "single_fem_simulation_from_reluctance_result"
-# task = 'load_fem_simulation_results_and_perform_thermal_simulations'
-# task = 'load_and_filter_thermal_simulations'
-# task = 'plot_thermal_fem_simulation_results'
-
-
-if task == 'simulation_reluctance':
-
- # reluctance model brute force calculation
- valid_reluctance_model_designs = fmt.IntegratedTransformerOptimization.ReluctanceModel.BruteForce.brute_force_calculation(dab_transformer_config)
-
- # save all calculated and valid reluctance model calculations
- fmt.IntegratedTransformerOptimization.ReluctanceModel.save_unfiltered_results(config_file=dab_transformer_config,
- result_file_list=valid_reluctance_model_designs)
-
-elif task == 'load_reluctance_and_filter':
- # load all calculated and valid reluctance model calculations
- valid_reluctance_model_designs = fmt.IntegratedTransformerOptimization.ReluctanceModel.load_unfiltered_results(dab_transformer_config.working_directory)
- print(f"{len(valid_reluctance_model_designs)=}")
-
- # filter air gaps
- filtered_air_gaps_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_min_air_gap_length(valid_reluctance_model_designs)
- print(f"{len(filtered_air_gaps_dto_list)=}")
-
- # filter for Pareto front
- pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.filter_loss_list(filtered_air_gaps_dto_list, factor_min_dc_losses=0.5)
- print(f"{len(pareto_reluctance_dto_list)=}")
-
- # save results
- fmt.IntegratedTransformerOptimization.ReluctanceModel.save_dto_list(pareto_reluctance_dto_list, os.path.join(dab_transformer_config.working_directory,
- '01_reluctance_model_results_filtered'))
-
- # plot unfiltered and filtered Pareto planes
- fmt.IntegratedTransformerOptimization.plot(valid_reluctance_model_designs)
- fmt.IntegratedTransformerOptimization.plot(pareto_reluctance_dto_list)
-
-
-elif task == 'load_reluctance_filter_and_simulate_fem':
-
- # load filtered reluctance models
- pareto_reluctance_dto_list = fmt.IntegratedTransformerOptimization.ReluctanceModel.load_filtered_results(dab_transformer_config.working_directory)
- print(f"{len(pareto_reluctance_dto_list)=}")
-
- # start FEM simulation
- fmt.IntegratedTransformerOptimization.FemSimulation.simulate(config_dto=dab_transformer_config,
- simulation_dto_list=pareto_reluctance_dto_list)
-
-elif task == 'plot_and_filter_fem_simulations_results':
-
- # load unfiltered results
- unfiltered_fem_results = fmt.IntegratedTransformerOptimization.FemSimulation.load_unfiltered_results(dab_transformer_config.working_directory)
- print(f"{len(unfiltered_fem_results)=}")
-
- # plot unfiltered results
- fmt.IntegratedTransformerOptimization.FemSimulation.plot(unfiltered_fem_results)
-
- # filter results
- filtered_fem_results = fmt.IntegratedTransformerOptimization.FemSimulation.filter_loss_list(unfiltered_fem_results, factor_min_dc_losses=0.1)
- print(f"{len(filtered_fem_results)=}")
-
- # save filtered results
- # fmt.IntegratedTransformerOptimization.FemSimulation.save_filtered_results(filtered_fem_results, dab_transformer_config.working_directory)
-
- # plot filtered results
- fmt.IntegratedTransformerOptimization.FemSimulation.plot(filtered_fem_results)
-
-elif task == 'load_fem_simulation_results_and_perform_thermal_simulations':
-
- # load filtered FEM simulation results
- filtered_fem_simulation_results = fmt.IntegratedTransformerOptimization.FemSimulation.load_filtered_results(dab_transformer_config.working_directory)
-
- # start thermal FEM simulation
- fmt.IntegratedTransformerOptimization.ThermalSimulation.simulation(config_dto=dab_transformer_config, result_log_dict_list=filtered_fem_simulation_results)
-
-elif task == 'plot_thermal_fem_simulation_results':
- # load thermal simulation results
- unfiltered_thermal_fem_results = fmt.IntegratedTransformerOptimization.ThermalSimulation.load_unfiltered_simulations(
- dab_transformer_config.working_directory)
- print(f"{len(unfiltered_thermal_fem_results)=}")
-
- # filter thermal FEM simulations
- filtered_thermal_fem_results = fmt.IntegratedTransformerOptimization.ThermalSimulation.filter_max_temperature(unfiltered_thermal_fem_results, 125, 125)
- print(f"{len(filtered_thermal_fem_results)=}")
-
- # load filtered FEM simulation results
- unfiltered_fem_simulation_results = fmt.IntegratedTransformerOptimization.FemSimulation.load_unfiltered_results(
- dab_transformer_config.working_directory)
-
- # find common cases of loss vs. volume and temperature vs. volume
- # du to the plot will contain the loss vs. volume area, so non-working cases of temperature vs. volume need
- # to be removed in loss vs. volume plane.
- valid_thermal_simulations = fmt.IntegratedTransformerOptimization.ThermalSimulation.find_common_cases(
- unfiltered_fem_simulation_results, filtered_thermal_fem_results)
- print(f"{len(valid_thermal_simulations)=}")
-
- # plot all thermal simulation results, and plot
- fmt.IntegratedTransformerOptimization.FemSimulation.plot(unfiltered_thermal_fem_results)
- fmt.IntegratedTransformerOptimization.FemSimulation.plot(valid_thermal_simulations)
diff --git a/femmt/examples/ito_optuna_example.py b/femmt/examples/ito_optuna_example.py
index 2a0818e5..a5301f26 100644
--- a/femmt/examples/ito_optuna_example.py
+++ b/femmt/examples/ito_optuna_example.py
@@ -21,36 +21,78 @@
i_2 = [[0.0, 3.265248131976911e-07, 2.5e-06, 2.8265248131976912e-06, 5e-06],
[-0.9196195846583147, -19.598444313231134, 0.9196195846583122, 19.59844431323113, -0.9196195846583147]]
+ito_insulations = fmt.ItoInsulation(
+ # insulation for top core window
+ iso_window_top_core_top=1e-3,
+ iso_window_top_core_bot=1e-3,
+ iso_window_top_core_left=1e-3,
+ iso_window_top_core_right=1e-3,
+ # insulation for bottom core window
+ iso_window_bot_core_top=1e-3,
+ iso_window_bot_core_bot=1e-3,
+ iso_window_bot_core_left=1e-3,
+ iso_window_bot_core_right=1e-3,
+ # winding-to-winding insulation
+ iso_primary_to_primary=10e-6,
+ iso_secondary_to_secondary=10e-6,
+ iso_primary_to_secondary=10e-6,
+)
+
+material_data_sources = fmt.IntegratedTransformerMaterialDataSources(
+ permeability_datasource=fmt.MaterialDataSource.Measurement,
+ permeability_datatype=fmt.MeasurementDataType.ComplexPermeability,
+ permeability_measurement_setup=fmt.MeasurementSetup.MagNet,
+ permittivity_datasource=fmt.MaterialDataSource.ManufacturerDatasheet,
+ permittivity_datatype=fmt.MeasurementDataType.ComplexPermittivity,
+ permittivity_measurement_setup=fmt.MeasurementSetup.LEA_MTB_small_signal
+)
+
dab_transformer_config = fmt.ItoSingleInputConfig(
integrated_transformer_study_name="2025-02-26",
- l_s_target=85e-6,
+ integrated_transformer_optimization_directory=os.path.join(os.path.dirname(__file__), "example_results", "optuna_integrated_transformer_optimization"),
+
+ # target parameters
+ l_s12_target=85e-6,
l_h_target=600e-6,
n_target=2.9,
+
+ # fix parameters
time_current_1_vec=np.array(i_1),
time_current_2_vec=np.array(i_2),
- material_list=["N95"],
- core_inner_diameter_min_max_list=[pq3230["core_inner_diameter"], pq5050["core_inner_diameter"]],
- window_w_min_max_list=[pq3230["window_w"], pq5050["window_w"]],
- window_h_top_min_max_list=[5 / 6 * pq3230["window_h"], 5 / 6 * pq5050["window_h"]],
+ insulations=ito_insulations,
+
+ # optimization parameters
+ material_list=["3C95"],
+ core_name_list=["PQ 40/40"],
+ core_inner_diameter_min_max_list=None,
+ window_w_min_max_list=None,
+ window_h_top_min_max_list=None,
window_h_bot_min_max_list=[1 / 6 * pq3230["window_h"], 1 / 6 * pq5050["window_h"]],
+
+ n_1_top_min_max_list=[1, 30],
+ n_1_bot_min_max_list=[1, 30],
+ n_2_top_min_max_list=[1, 30],
+ n_2_bot_min_max_list=[1, 30],
factor_max_flux_density=1,
primary_litz_wire_list=["1.4x200x0.071"],
secondary_litz_wire_list=["1.4x200x0.071"],
temperature=100,
- integrated_transformer_optimization_directory=os.path.join(os.path.dirname(__file__), "example_results", "optuna_integrated_transformer_optimization")
+
+ material_data_sources=material_data_sources,
+
)
# task = 'start_study'
-task = 'filter_reluctance_model'
+# task = 'filter_reluctance_model'
# task = 'fem_simulation_from_filtered_reluctance_model_results'
-# task = 'plot_study_results'
+task = 'plot_study_results'
if __name__ == '__main__':
time_start = datetime.datetime.now()
if task == 'start_study':
- fmt.IntegratedTransformerOptimization.ReluctanceModel.start_proceed_study(dab_transformer_config, 100, storage='sqlite')
+ fmt.IntegratedTransformerOptimization.ReluctanceModel.start_proceed_study(dab_transformer_config, 10000, storage='sqlite')
elif task == 'filter_reluctance_model':
# load trials from reluctance model to a pandas dataframe (df)
diff --git a/femmt/functions_reluctance.py b/femmt/functions_reluctance.py
index 3a3f06d7..718a8437 100644
--- a/femmt/functions_reluctance.py
+++ b/femmt/functions_reluctance.py
@@ -439,7 +439,7 @@ def calculate_flux_matrix(reluctance_matrix: Union[float, np.array], winding_mat
return np.matmul(np.matmul(reluctance_matrix_invert, winding_matrix), current_matrix)
-def time_vec_current_vec_from_time_current_vec(time_current_vec: List[List[float]]):
+def time_vec_current_vec_from_time_current_vec(time_current_vec: List[List[float]] | np.array):
"""
Split a time-current vector into time and current vector.
diff --git a/femmt/optimization/ito.py b/femmt/optimization/ito.py
index 1fd05101..f2141d21 100644
--- a/femmt/optimization/ito.py
+++ b/femmt/optimization/ito.py
@@ -2,7 +2,7 @@
# Python libraries
import os
import json
-from typing import List, Dict, Tuple, Optional
+from typing import List, Dict, Optional
import datetime
import pickle
import logging
@@ -14,6 +14,7 @@
import pandas as pd
from matplotlib import pyplot as plt
import matplotlib.patches as mpatches
+import magnethub as mh
# femmt import
import femmt.functions as ff
@@ -133,8 +134,7 @@ def is_pareto_efficient_dumb(costs: np.array) -> np.array:
@staticmethod
def calculate_fix_parameters(config: ItoSingleInputConfig) -> ItoTargetAndFixedParameters:
- """
- Calculate fix parameters what can be derived from the input configuration.
+ """Calculate fix parameters what can be derived from the input configuration.
return values are:
@@ -164,17 +164,34 @@ def calculate_fix_parameters(config: ItoSingleInputConfig) -> ItoTargetAndFixedP
i_rms_1 = fr.i_rms(config.time_current_1_vec)
i_rms_2 = fr.i_rms(config.time_current_2_vec)
+ i_peak_1, i_peak_2 = fr.max_value_from_value_vec(current_extracted_1_vec, current_extracted_2_vec)
+ phi_deg_1, phi_deg_2 = fr.phases_deg_from_time_current(time_extracted, current_extracted_1_vec,
+ current_extracted_2_vec)
+
+ # phi_deg_2 = phi_deg_2 - 180
+
# target inductances
- target_inductance_matrix = fr.calculate_inductance_matrix_from_ls_lh_n(config.l_s_target, config.l_h_target,
+ target_inductance_matrix = fr.calculate_inductance_matrix_from_ls_lh_n(config.l_s12_target,
+ config.l_h_target,
config.n_target)
+ (fft_frequencies_1, fft_amplitudes_1, fft_phases_1) = ff.fft(
+ period_vector_t_i=config.time_current_1_vec, sample_factor=1000, plot='no', mode='time', filter_type='factor', filter_value_factor=0.03)
+
+ (fft_frequencies_2, fft_amplitudes_2, fft_phases_2) = ff.fft(
+ period_vector_t_i=config.time_current_2_vec, sample_factor=1000, plot='no', mode='time', filter_type='factor', filter_value_factor=0.03)
+
# material properties
material_db = mdb.MaterialDatabase(is_silent=True)
material_data_list = []
+ magnet_model_list = []
for material_name in config.material_list:
- material_dto = material_db.material_data_interpolation_to_dto(material_name, fundamental_frequency, config.temperature)
+ material_dto: mdb.MaterialCurve = material_db.material_data_interpolation_to_dto(material_name, fundamental_frequency, config.temperature)
material_data_list.append(material_dto)
+ # instantiate material-specific model
+ mdl: mh.loss.LossModel = mh.loss.LossModel(material=material_name, team="paderborn")
+ magnet_model_list.append(mdl)
# set up working directories
working_directories = itof.set_up_folder_structure(config.integrated_transformer_optimization_directory)
@@ -183,13 +200,27 @@ def calculate_fix_parameters(config: ItoSingleInputConfig) -> ItoTargetAndFixedP
target_and_fix_parameters = ItoTargetAndFixedParameters(
i_rms_1=i_rms_1,
i_rms_2=i_rms_2,
+ i_peak_1=i_peak_1,
+ i_peak_2=i_peak_2,
+ i_phase_deg_1=phi_deg_1,
+ i_phase_deg_2=phi_deg_2,
time_extracted_vec=time_extracted,
+ magnet_hub_model_list=magnet_model_list,
current_extracted_1_vec=current_extracted_1_vec,
current_extracted_2_vec=current_extracted_2_vec,
material_dto_curve_list=material_data_list,
fundamental_frequency=fundamental_frequency,
target_inductance_matrix=target_inductance_matrix,
- working_directories=working_directories
+ working_directories=working_directories,
+ # winding 1
+ fft_frequency_list_1=fft_frequencies_1,
+ fft_amplitude_list_1=fft_amplitudes_1,
+ fft_phases_list_1=fft_phases_1,
+
+ # winding 2
+ fft_frequency_list_2=fft_frequencies_2,
+ fft_amplitude_list_2=fft_amplitudes_2,
+ fft_phases_list_2=fft_phases_2
)
return target_and_fix_parameters
@@ -198,289 +229,431 @@ class ReluctanceModel:
"""Create and calculate the reluctance model for the integrated transformer."""
@staticmethod
- def objective(trial: optuna.Trial, config: ItoSingleInputConfig,
- target_and_fixed_parameters: ItoTargetAndFixedParameters) -> Tuple:
+ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput) -> ItoReluctanceModelOutput:
"""
- Objective function to optimize.
+ Perform a single reluctance model simulation.
- Using optuna. Some hints:
+ :param reluctance_input: Reluctance model input data.
+ :type reluctance_input: ReluctanceModelInput
+ :return: Reluctance model output data
+ :rtype: ReluctanceModelOutput
+ """
+ core_total_height = reluctance_input.window_h_top + reluctance_input.window_h_bot + reluctance_input.core_inner_diameter * 3 / 4
+ r_outer = fr.calculate_r_outer(reluctance_input.core_inner_diameter, reluctance_input.window_w)
+ volume = ff.calculate_cylinder_volume(cylinder_diameter=2 * r_outer, cylinder_height=core_total_height)
+
+ # calculate the reluctance and flux matrix
+ winding_matrix = np.array([[reluctance_input.turns_1_top, reluctance_input.turns_2_top],
+ [reluctance_input.turns_1_bot, reluctance_input.turns_2_bot]])
+
+ reluctance_matrix = fr.calculate_reluctance_matrix(winding_matrix, reluctance_input.target_inductance_matrix)
+
+ current_matrix = np.array([reluctance_input.current_extracted_vec_1, reluctance_input.current_extracted_vec_2])
+
+ flux_matrix = fr.calculate_flux_matrix(reluctance_matrix, winding_matrix, current_matrix)
+
+ flux_top = flux_matrix[0]
+ flux_bot = flux_matrix[1]
+ flux_middle = flux_bot - flux_top
+
+ core_cross_section = (reluctance_input.core_inner_diameter / 2) ** 2 * np.pi
+
+ flux_density_top = flux_top / core_cross_section
+ flux_density_bot = flux_bot / core_cross_section
+ flux_density_middle = flux_middle / core_cross_section
+
+ # calculate the core reluctance
+ core_inner_cylinder_top = fr.r_core_round(reluctance_input.core_inner_diameter, reluctance_input.window_h_top,
+ reluctance_input.material_dto.material_mu_r_abs)
+ core_inner_cylinder_bot = fr.r_core_round(reluctance_input.core_inner_diameter, reluctance_input.window_h_bot,
+ reluctance_input.material_dto.material_mu_r_abs)
+ core_top_bot_radiant = fr.r_core_top_bot_radiant(reluctance_input.core_inner_diameter, reluctance_input.window_w,
+ reluctance_input.material_dto.material_mu_r_abs, reluctance_input.core_inner_diameter / 4)
+
+ r_core_top = 2 * core_inner_cylinder_top + core_top_bot_radiant
+ r_core_bot = 2 * core_inner_cylinder_bot + core_top_bot_radiant
+ r_core_middle = core_top_bot_radiant
+
+ r_top_target = reluctance_matrix[0][0] + reluctance_matrix[0][1]
+ r_bot_target = reluctance_matrix[1][1] + reluctance_matrix[0][1]
+ r_middle_target = - reluctance_matrix[0][1]
+
+ r_air_gap_top_target = r_top_target - r_core_top
+ r_air_gap_bot_target = r_bot_target - r_core_bot
+ r_air_gap_middle_target = r_middle_target - r_core_middle
+
+ # calculate air gaps to reach the target parameters
+ minimum_air_gap_length = 0.01e-3
+ maximum_air_gap_length = 2e-3
+
+ l_top_air_gap = optimize.brentq(
+ fr.r_air_gap_round_inf_sct, minimum_air_gap_length, maximum_air_gap_length,
+ args=(reluctance_input.core_inner_diameter, reluctance_input.window_h_top, r_air_gap_top_target), full_output=True)[0]
+
+ l_bot_air_gap = optimize.brentq(
+ fr.r_air_gap_round_round_sct, minimum_air_gap_length, maximum_air_gap_length,
+ args=(reluctance_input.core_inner_diameter, reluctance_input.window_h_bot / 2, reluctance_input.window_h_bot / 2, r_air_gap_bot_target),
+ full_output=True)[0]
+
+ # Note: ideal calculation (360 degree)
+ # needs to be translated when it comes to the real setup.
+ l_middle_air_gap = optimize.brentq(
+ fr.r_air_gap_tablet_cylinder_sct, minimum_air_gap_length, maximum_air_gap_length,
+ args=(reluctance_input.core_inner_diameter, reluctance_input.core_inner_diameter/4, reluctance_input.window_w, r_air_gap_middle_target),
+ full_output=True)[0]
+
+ # calculate hysteresis losses from mag-net-hub
+ interp_points = np.arange(0, 1024) * reluctance_input.time_extracted_vec[-1] / 1024
+ flux_density_top_interp = np.interp(interp_points, reluctance_input.time_extracted_vec, flux_density_top)
+ flux_density_bot_interp = np.interp(interp_points, reluctance_input.time_extracted_vec, flux_density_bot)
+ flux_density_middle_interp = np.interp(interp_points, reluctance_input.time_extracted_vec, flux_density_middle)
+
+ # get power loss in W/m³ and estimated H wave in A/m
+ p_density_top, _ = reluctance_input.magnet_material_model(flux_density_top_interp,
+ reluctance_input.fundamental_frequency, reluctance_input.temperature)
+ p_density_bot, _ = reluctance_input.magnet_material_model(flux_density_bot_interp,
+ reluctance_input.fundamental_frequency, reluctance_input.temperature)
+ p_density_middle, _ = reluctance_input.magnet_material_model(flux_density_middle_interp,
+ reluctance_input.fundamental_frequency, reluctance_input.temperature)
+
+ volume_core_top = (2 * ff.calculate_cylinder_volume(reluctance_input.core_inner_diameter, reluctance_input.window_h_top) - \
+ ff.calculate_cylinder_volume(reluctance_input.core_inner_diameter, l_top_air_gap) + \
+ ff.calculate_cylinder_volume(2 * r_outer, reluctance_input.core_inner_diameter / 4))
+ volume_core_bot = (2 * ff.calculate_cylinder_volume(reluctance_input.core_inner_diameter, reluctance_input.window_h_bot) - \
+ ff.calculate_cylinder_volume(reluctance_input.core_inner_diameter, l_bot_air_gap) + \
+ ff.calculate_cylinder_volume(2 * r_outer, reluctance_input.core_inner_diameter / 4))
+ volume_core_middle = ff.calculate_cylinder_volume(2 * r_outer, reluctance_input.core_inner_diameter / 4)
+
+ p_top = p_density_top * volume_core_top
+ p_bot = p_density_bot * volume_core_bot
+ p_middle = p_density_middle * volume_core_middle
+
+ p_hyst = p_top + p_bot + p_middle
+
+ # calculate winding losses
+ primary_effective_conductive_cross_section = (
+ reluctance_input.primary_litz_dict["strands_numbers"] * reluctance_input.primary_litz_dict["strand_radii"] ** 2 * np.pi)
+ primary_effective_conductive_radius = np.sqrt(primary_effective_conductive_cross_section / np.pi)
+ primary_resistance_top = fr.resistance_solid_wire(
+ reluctance_input.core_inner_diameter, reluctance_input.window_w, reluctance_input.turns_1_top,
+ primary_effective_conductive_radius, material='Copper')
+
+ number_bot_prim_turns_per_column = (
+ int((reluctance_input.window_h_bot - reluctance_input.insulations.iso_window_bot_core_top - \
+ reluctance_input.insulations.iso_window_bot_core_bot + reluctance_input.insulations.iso_primary_to_primary) / \
+ (2 * reluctance_input.primary_litz_dict["conductor_radii"] + reluctance_input.insulations.iso_primary_to_primary)))
+ if number_bot_prim_turns_per_column > reluctance_input.turns_1_bot:
+ # single row window only
+ primary_resistance_bot_inner = fr.resistance_solid_wire(
+ reluctance_input.core_inner_diameter, reluctance_input.window_w, reluctance_input.turns_1_bot,
+ primary_effective_conductive_radius, material='Copper')
+ primary_resistance_bot_outer = 0
+ else:
+ # multiple row window
+ primary_resistance_bot_inner = fr.resistance_solid_wire(
+ reluctance_input.core_inner_diameter, reluctance_input.window_w, number_bot_prim_turns_per_column,
+ primary_effective_conductive_radius, material='Copper')
+
+ primary_resistance_bot_outer = fr.resistance_solid_wire(
+ reluctance_input.core_inner_diameter, reluctance_input.window_w, reluctance_input.turns_1_bot - number_bot_prim_turns_per_column,
+ primary_effective_conductive_radius, material='Copper')
+
+ secondary_effective_conductive_cross_section = (
+ reluctance_input.secondary_litz_dict["strands_numbers"] * reluctance_input.secondary_litz_dict["strand_radii"] ** 2 * np.pi)
+ secondary_effective_conductive_radius = np.sqrt(secondary_effective_conductive_cross_section / np.pi)
+ secondary_resistance = fr.resistance_solid_wire(
+ reluctance_input.core_inner_diameter, reluctance_input.window_w, reluctance_input.turns_2_bot, secondary_effective_conductive_radius,
+ material='Copper')
+
+ winding_area_1_top = (
+ 2 * reluctance_input.primary_litz_dict["conductor_radii"] * \
+ (reluctance_input.turns_1_top * 2 * reluctance_input.primary_litz_dict["conductor_radii"] + \
+ (reluctance_input.turns_1_top - 1) * reluctance_input.insulations.iso_primary_to_primary))
+
+ p_winding_1_top = 0
+ p_winding_1_bot = 0
+ for count, fft_frequency in enumerate(reluctance_input.fft_frequency_list_1):
+ proximity_factor_1_top = fr.calc_proximity_factor_air_gap(
+ litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=reluctance_input.turns_1_top,
+ r_1=reluctance_input.insulations.iso_window_top_core_left,
+ frequency=fft_frequency, winding_area=winding_area_1_top,
+ litz_wire_material_name='Copper', temperature=reluctance_input.temperature)
+
+ p_winding_1_top += proximity_factor_1_top * primary_resistance_top * reluctance_input.fft_amplitude_list_1[count] ** 2
+
+ if number_bot_prim_turns_per_column > reluctance_input.turns_1_bot:
+ winding_area_1_bot = 2 * reluctance_input.primary_litz_dict["conductor_radii"] * \
+ (reluctance_input.turns_1_bot * 2 * reluctance_input.primary_litz_dict["conductor_radii"] + \
+ (reluctance_input.turns_1_bot - 1) * reluctance_input.insulations.iso_primary_to_primary)
+
+ proximity_factor_1_bot_inner = fr.calc_proximity_factor_air_gap(
+ litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=reluctance_input.turns_1_bot,
+ r_1=reluctance_input.insulations.iso_window_bot_core_left,
+ frequency=fft_frequency, winding_area=winding_area_1_bot,
+ litz_wire_material_name='Copper', temperature=reluctance_input.temperature)
+
+ proximity_factor_1_bot_outer = 0
+ else:
+ winding_area_1_bot = (2 * reluctance_input.primary_litz_dict["conductor_radii"] * (
+ number_bot_prim_turns_per_column * 2 * reluctance_input.primary_litz_dict["conductor_radii"] + \
+ (number_bot_prim_turns_per_column - 1) * reluctance_input.insulations.iso_primary_to_primary))
+
+ proximity_factor_1_bot_inner = fr.calc_proximity_factor_air_gap(
+ litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=number_bot_prim_turns_per_column,
+ r_1=reluctance_input.insulations.iso_window_bot_core_left,
+ frequency=fft_frequency, winding_area=winding_area_1_bot,
+ litz_wire_material_name='Copper', temperature=reluctance_input.temperature)
+
+ proximity_factor_1_bot_outer = fr.calc_proximity_factor(
+ litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=reluctance_input.turns_1_bot - number_bot_prim_turns_per_column,
+ window_h=reluctance_input.window_h_bot,
+ iso_core_top=reluctance_input.insulations.iso_window_bot_core_top, iso_core_bot=reluctance_input.insulations.iso_window_bot_core_bot,
+ frequency=fft_frequency, litz_wire_material_name='Copper', temperature=reluctance_input.temperature)
+
+ p_winding_1_bot_inner = proximity_factor_1_bot_inner * primary_resistance_bot_inner * reluctance_input.fft_amplitude_list_1[count] ** 2
+ p_winding_1_bot_outer = proximity_factor_1_bot_outer * primary_resistance_bot_outer * reluctance_input.fft_amplitude_list_1[count] ** 2
+
+ p_winding_1_bot += p_winding_1_bot_inner + p_winding_1_bot_outer
+
+ p_winding_2 = 0
+ for count, fft_frequency in enumerate(reluctance_input.fft_frequency_list_2):
+ proximity_factor_assumption_2 = fr.calc_proximity_factor(
+ litz_wire_name=reluctance_input.litz_wire_name_2, number_turns=reluctance_input.turns_2_bot, window_h=reluctance_input.window_h_bot,
+ iso_core_top=reluctance_input.insulations.iso_window_bot_core_top, iso_core_bot=reluctance_input.insulations.iso_window_bot_core_bot,
+ frequency=fft_frequency, litz_wire_material_name='Copper', temperature=reluctance_input.temperature)
+
+ p_winding_2 += proximity_factor_assumption_2 * secondary_resistance * reluctance_input.fft_amplitude_list_2[count] ** 2
+
+ p_loss_total = p_hyst + p_winding_1_top + p_winding_1_bot + p_winding_2
+
+ area_to_heat_sink = r_outer ** 2 * np.pi
+
+ reluctance_output = ItoReluctanceModelOutput(
+ # set additional attributes
+ p_hyst=p_hyst,
+ p_hyst_top=p_top,
+ p_hyst_bot=p_bot,
+ p_hyst_middle=p_middle,
+ b_max_top=np.max(flux_density_top_interp),
+ b_max_bot=np.max(flux_density_bot_interp),
+ b_max_middle=np.max(flux_density_middle_interp),
+ winding_1_loss=p_winding_1_top + p_winding_1_bot,
+ winding_2_loss=p_winding_2,
+ l_top_air_gap=l_top_air_gap,
+ l_bot_air_gap=l_bot_air_gap,
+ l_middle_air_gap=l_middle_air_gap,
+ volume=volume,
+ area_to_heat_sink=area_to_heat_sink,
+ p_loss=p_loss_total,
+ )
+
+ return reluctance_output
- * returning failed trails by using return float('nan'), float('nan'),
- see https://optuna.readthedocs.io/en/stable/faq.html#how-are-nans-returned-by-trials-handled
- * speed up the search for NSGA-II algorithm with dynamic alter the search space, see https://optuna.readthedocs.io/en/stable/faq.html#id10
+ @staticmethod
+ def objective(trial: optuna.Trial, config: ItoSingleInputConfig, target_and_fixed_parameters: ItoTargetAndFixedParameters):
+ """
+ Objective funktion to optimize. Uses reluctance model calculation.
+ Once core_name_list is not None, the objective function uses fixed core sizes. Cores are picked from the core_database().
+ Otherwise, core_inner_diameter_min_max_list, window_w_min_max_list and window_h_bot_min_max_list are used.
- :param trial: parameter suggesting by optuna
+ :param trial: Optuna trial
:type trial: optuna.Trial
- :param config: input configuration file
- :type config: ItoSingleInputConfig
- :param target_and_fixed_parameters: target and fix parameters
- :type target_and_fixed_parameters: ItoTargetAndFixedParameters
- """
- # pass multiple arguments to the objective function used by optuna
- # https://www.kaggle.com/general/261870
-
- #########################################################
- # set core geometry optimization parameters
- #########################################################
- core_inner_diameter = trial.suggest_float("core_inner_diameter",
- config.core_inner_diameter_min_max_list[0],
- config.core_inner_diameter_min_max_list[1])
- window_w = trial.suggest_float("window_w", config.window_w_min_max_list[0],
- config.window_w_min_max_list[1])
- window_h_top = trial.suggest_float("window_h_top", config.window_h_top_min_max_list[0],
- config.window_h_top_min_max_list[1])
- window_h_bot = trial.suggest_float("window_h_bot", config.window_h_bot_min_max_list[0],
- config.window_h_bot_min_max_list[1])
-
- material = trial.suggest_categorical("material", config.material_list)
- primary_litz_wire = trial.suggest_categorical("primary_litz_wire", config.primary_litz_wire_list)
- secondary_litz_wire = trial.suggest_categorical("secondary_litz_wire", config.secondary_litz_wire_list)
-
- # cross-section comparison is according to a square for round wire.
- # this approximation is more realistic
- # insulation
- insulation_distance = 1e-3
- insulation_cross_section_top = 2 * insulation_distance * (window_w + window_h_top)
- insulation_cross_section_bot = 2 * insulation_distance * (window_w + window_h_bot)
-
- litz_database = ff.litz_database()
-
- primary_litz = litz_database[primary_litz_wire]
- secondary_litz = litz_database[secondary_litz_wire]
-
- total_available_window_cross_section_top = window_h_top * window_w - insulation_cross_section_top
- total_available_window_cross_section_bot = window_h_bot * window_w - insulation_cross_section_bot
-
- #########################################################
- # set dynamic wire count parameters as optimization parameters
- #########################################################
- # set the winding search space dynamic
- # https://optuna.readthedocs.io/en/stable/faq.html#what-happens-when-i-dynamically-alter-a-search-space
-
- # n_p_top suggestion
- n_p_top_max = total_available_window_cross_section_top / (2 * primary_litz["conductor_radii"]) ** 2
- n_p_top = trial.suggest_int("n_p_top", 0, n_p_top_max)
-
- # n_s_top_suggestion
- winding_cross_section_n_p_top_max = n_p_top * (2 * primary_litz["conductor_radii"]) ** 2
- n_s_top_max = int((total_available_window_cross_section_top - winding_cross_section_n_p_top_max) / (
- 2 * secondary_litz["conductor_radii"]) ** 2)
- n_s_top = trial.suggest_int("n_s_top", 0, n_s_top_max)
-
- # n_p_bot suggestion
- n_p_bot_max = total_available_window_cross_section_bot / (2 * primary_litz["conductor_radii"]) ** 2
- n_p_bot = trial.suggest_int("n_p_bot", 0, n_p_bot_max)
-
- # n_s_bot suggestion
- winding_cross_section_n_p_bot_max = n_p_bot * (2 * primary_litz["conductor_radii"]) ** 2
- n_s_bot_max = int((total_available_window_cross_section_bot - winding_cross_section_n_p_bot_max) / (2 * secondary_litz["conductor_radii"]) ** 2)
- n_s_bot = trial.suggest_int("n_s_bot", 0, n_s_bot_max)
-
- winding_cross_section_top = n_p_top * (2 * primary_litz["conductor_radii"]) ** 2 + n_s_top * (2 * secondary_litz["conductor_radii"]) ** 2
- winding_cross_section_bot = n_p_bot * (2 * primary_litz["conductor_radii"]) ** 2 + n_s_bot * (2 * secondary_litz["conductor_radii"]) ** 2
-
- thousand_simulations = trial.number / 1000
-
- if thousand_simulations.is_integer():
- print(f"simulation count: {trial.number}")
-
- for material_dto in target_and_fixed_parameters.material_dto_curve_list:
- if material_dto.material_name == material:
- material_data = material_dto
-
- material_mu_r_initial = material_data.material_mu_r_abs
- flux_density_data_vec = material_data.material_flux_density_vec
- mu_r_imag_data_vec = material_data.material_mu_r_imag_vec
-
- core_top_bot_height = core_inner_diameter / 4
- core_cross_section = (core_inner_diameter / 2) ** 2 * np.pi
-
- t2_winding_matrix = [[n_p_top, n_s_top], [n_p_bot, n_s_bot]]
-
- target_inductance_matrix = fr.calculate_inductance_matrix_from_ls_lh_n(config.l_s_target,
- config.l_h_target,
- config.n_target)
- t2_reluctance_matrix = fr.calculate_reluctance_matrix(t2_winding_matrix, target_inductance_matrix)
-
- core_2daxi_total_volume = fr.calculate_core_2daxi_total_volume(core_inner_diameter,
- (window_h_bot + window_h_top + core_inner_diameter / 4), window_w)
-
- if np.linalg.det(t2_reluctance_matrix) != 0 and np.linalg.det(
- np.transpose(t2_winding_matrix)) != 0 and np.linalg.det(target_inductance_matrix) != 0:
- # calculate the flux
- flux_top_vec, flux_bot_vec, flux_stray_vec = fr.flux_vec_from_current_vec(
- target_and_fixed_parameters.current_extracted_1_vec,
- target_and_fixed_parameters.current_extracted_2_vec,
- t2_winding_matrix,
- target_inductance_matrix)
-
- # calculate maximum values
- flux_top_max, flux_bot_max, flux_stray_max = fr.max_value_from_value_vec(flux_top_vec, flux_bot_vec,
- flux_stray_vec)
-
- flux_density_top_max = flux_top_max / core_cross_section
- flux_density_bot_max = flux_bot_max / core_cross_section
- flux_density_middle_max = flux_stray_max / core_cross_section
-
- # calculate target values for r_top and r_bot out of reluctance matrix
- r_core_middle_cylinder_radial = fr.r_core_top_bot_radiant(core_inner_diameter, window_w,
- material_data.material_mu_r_abs,
- core_top_bot_height)
-
- r_middle_target = -t2_reluctance_matrix[0][1]
- r_top_target = t2_reluctance_matrix[0][0] - r_middle_target
- r_bot_target = t2_reluctance_matrix[1][1] - r_middle_target
-
- # calculate the core reluctance of top and bottom and middle part
- r_core_top_cylinder_inner = fr.r_core_round(core_inner_diameter, window_h_top,
- material_data.material_mu_r_abs)
- r_core_top = 2 * r_core_top_cylinder_inner + r_core_middle_cylinder_radial
- r_air_gap_top_target = r_top_target - r_core_top
-
- r_core_bot_cylinder_inner = fr.r_core_round(core_inner_diameter, window_h_bot,
- material_data.material_mu_r_abs)
- r_core_bot = 2 * r_core_bot_cylinder_inner + r_core_middle_cylinder_radial
- r_air_gap_bot_target = r_bot_target - r_core_bot
-
- r_air_gap_middle_target = r_middle_target - r_core_middle_cylinder_radial
-
- if r_air_gap_top_target > 0 and r_air_gap_bot_target > 0 and r_air_gap_middle_target > 0:
-
- # Note: a minimum air gap length of zero is not allowed. This will lead to failure calculation
- # when trying to solve (using brentq) r_gap_round_round-function. Calculating an air gap
- # reluctance with length of zero is not realistic.
- minimum_air_gap_length = 1e-15
- maximum_air_gap_length = 5e-3
- minimum_sort_out_air_gap_length = 0
- try:
- # solving brentq needs to be in try/except statement,
- # as it can be that there is no sign changing in the given interval
- # to search for the zero.
- # Note: setting full output to true and taking object [0] is only
- # to avoid linting error!
- l_top_air_gap = optimize.brentq(fr.r_air_gap_round_inf_sct, minimum_air_gap_length, maximum_air_gap_length,
- args=(core_inner_diameter, window_h_top, r_air_gap_top_target), full_output=True)[0]
-
- l_bot_air_gap = optimize.brentq(fr.r_air_gap_round_round_sct, minimum_air_gap_length,
- maximum_air_gap_length, args=(core_inner_diameter, window_h_bot / 2, window_h_bot / 2,
- r_air_gap_bot_target), full_output=True)[0]
-
- l_middle_air_gap = optimize.brentq(fr.r_air_gap_tablet_cylinder_sct, minimum_air_gap_length,
- maximum_air_gap_length, args=(core_inner_diameter,
- core_inner_diameter / 4, window_w, r_air_gap_middle_target),
- full_output=True)[0]
-
- except ValueError:
- # ValueError is raised in case of an air gap with length of zero
- return float('nan'), float('nan')
-
- if l_top_air_gap > core_inner_diameter or l_bot_air_gap > core_inner_diameter:
- return float('nan'), float('nan')
-
- if l_top_air_gap >= minimum_sort_out_air_gap_length and l_bot_air_gap >= minimum_sort_out_air_gap_length \
- and l_middle_air_gap >= minimum_sort_out_air_gap_length:
- p_hyst_top = fr.hyst_losses_core_half_mu_r_imag(core_inner_diameter, window_h_top, window_w,
- material_data.material_mu_r_abs,
- flux_top_max,
- target_and_fixed_parameters.fundamental_frequency,
- material_data.material_flux_density_vec,
- material_data.material_mu_r_imag_vec)
-
- p_hyst_middle = fr.power_losses_hysteresis_cylinder_radial_direction_mu_r_imag(
- flux_stray_max,
- core_inner_diameter / 4,
- core_inner_diameter / 2,
- core_inner_diameter / 2 + window_w,
- target_and_fixed_parameters.fundamental_frequency,
- material_data.material_mu_r_abs,
- material_data.material_flux_density_vec,
- material_data.material_mu_r_imag_vec)
-
- p_hyst_bot = fr.hyst_losses_core_half_mu_r_imag(core_inner_diameter, window_h_bot, window_w,
- material_data.material_mu_r_abs,
- flux_bot_max,
- target_and_fixed_parameters.fundamental_frequency,
- material_data.material_flux_density_vec,
- material_data.material_mu_r_imag_vec)
-
- p_hyst = p_hyst_top + p_hyst_bot + p_hyst_middle
-
- primary_effective_conductive_cross_section = primary_litz["strands_numbers"] * primary_litz[
- "strand_radii"] ** 2 * np.pi
- primary_effective_conductive_radius = np.sqrt(
- primary_effective_conductive_cross_section / np.pi)
- primary_resistance = fr.resistance_solid_wire(core_inner_diameter, window_w,
- n_p_top + n_p_bot,
- primary_effective_conductive_radius,
- material='Copper')
- primary_dc_loss = primary_resistance * target_and_fixed_parameters.i_rms_1 ** 2
-
- secondary_effective_conductive_cross_section = secondary_litz["strands_numbers"] * secondary_litz["strand_radii"] ** 2 * np.pi
- secondary_effective_conductive_radius = np.sqrt(
- secondary_effective_conductive_cross_section / np.pi)
- secondary_resistance = fr.resistance_solid_wire(core_inner_diameter, window_w,
- n_s_top + n_s_bot,
- secondary_effective_conductive_radius,
- material='Copper')
- secondary_dc_loss = secondary_resistance * target_and_fixed_parameters.i_rms_2 ** 2
-
- total_loss = p_hyst + primary_dc_loss + secondary_dc_loss
-
- trial.set_user_attr("air_gap_top", l_top_air_gap)
- trial.set_user_attr("air_gap_bot", l_bot_air_gap)
- trial.set_user_attr("air_gap_middle", l_middle_air_gap)
-
- trial.set_user_attr("flux_top_max", flux_top_max)
- trial.set_user_attr("flux_bot_max", flux_bot_max)
- trial.set_user_attr("flux_stray_max", flux_stray_max)
- trial.set_user_attr("flux_density_top_max", flux_density_top_max)
- trial.set_user_attr("flux_density_bot_max", flux_density_bot_max)
- trial.set_user_attr("flux_density_stray_max", flux_density_middle_max)
- trial.set_user_attr("p_hyst", p_hyst)
- trial.set_user_attr("primary_litz_wire_loss", primary_dc_loss)
- trial.set_user_attr("secondary_litz_wire_loss", secondary_dc_loss)
-
- print(f"successfully calculated trial {trial.number}")
-
- valid_design_dict = ItoSingleResultFile(
- case=trial.number,
- air_gap_top=l_top_air_gap,
- air_gap_bot=l_bot_air_gap,
- air_gap_middle=l_middle_air_gap,
- n_p_top=n_p_top,
- n_p_bot=n_p_bot,
- n_s_top=n_s_top,
- n_s_bot=n_s_bot,
- window_h_top=window_h_top,
- window_h_bot=window_h_bot,
- window_w=window_w,
- core_material=material_data.material_name,
- core_inner_diameter=core_inner_diameter,
- primary_litz_wire=primary_litz_wire,
- secondary_litz_wire=secondary_litz_wire,
- # results
- flux_top_max=flux_top_max,
- flux_bot_max=flux_bot_max,
- flux_stray_max=flux_stray_max,
- flux_density_top_max=flux_density_top_max,
- flux_density_bot_max=flux_density_bot_max,
- flux_density_stray_max=flux_density_middle_max,
- p_hyst=p_hyst,
- core_2daxi_total_volume=core_2daxi_total_volume,
- primary_litz_wire_loss=primary_dc_loss,
- secondary_litz_wire_loss=secondary_dc_loss,
- total_loss=total_loss
-
- )
-
- return core_2daxi_total_volume, total_loss
- else:
- return float('nan'), float('nan')
- else:
- return float('nan'), float('nan')
- else:
- return float('nan'), float('nan')
+ :param config: Stacked transformer optimization configuration file
+ :type config: StoSingleInputConfig
+ :param target_and_fixed_parameters: Target and fixed parameters
+ :type target_and_fixed_parameters: StoTargetAndFixedParameters
+ """
+ # fixed cores
+ if config.core_name_list is not None:
+ # using fixed core sizes from the database with flexible height.
+ core_name = trial.suggest_categorical("core_name", config.core_name_list)
+ core = ff.core_database()[core_name]
+ core_inner_diameter = core["core_inner_diameter"]
+ window_w = core["window_w"]
+ window_h_bot = trial.suggest_float("window_h_bot", 0.3 * core["window_h"], core["window_h"])
+ trial.set_user_attr('core_inner_diameter', core_inner_diameter)
+ trial.set_user_attr('window_w', window_w)
+ trial.set_user_attr('window_h_bot', window_h_bot)
+
+ else:
+ # using arbitrary core sizes
+ core_inner_diameter = trial.suggest_float("core_inner_diameter", config.core_inner_diameter_min_max_list[0],
+ config.core_inner_diameter_min_max_list[1])
+ window_w = trial.suggest_float("window_w", config.window_w_min_max_list[0], config.window_w_min_max_list[1])
+ window_h_bot = trial.suggest_float('window_h_bot', config.window_h_bot_min_max_list[0], config.window_h_bot_min_max_list[1])
+
+ n_p_top = trial.suggest_int('n_p_top', config.n_1_top_min_max_list[0], config.n_1_top_min_max_list[1])
+ n_p_bot = trial.suggest_int('n_p_bot', config.n_1_bot_min_max_list[0], config.n_1_bot_min_max_list[1])
+ n_s_top = trial.suggest_int('n_s_top', config.n_2_top_min_max_list[0], config.n_2_top_min_max_list[1])
+ n_s_bot = trial.suggest_int('n_s_bot', config.n_2_bot_min_max_list[0], config.n_2_bot_min_max_list[1])
+
+ primary_litz_name = trial.suggest_categorical('primary_litz_name', config.primary_litz_wire_list)
+ primary_litz_dict = ff.litz_database()[primary_litz_name]
+ primary_litz_diameter = 2 * primary_litz_dict['conductor_radii']
+
+ secondary_litz_name = trial.suggest_categorical('secondary_litz_name', config.secondary_litz_wire_list)
+ secondary_litz_dict = ff.litz_database()[secondary_litz_name]
+ secondary_litz_diameter = 2 * secondary_litz_dict['conductor_radii']
+
+ material_name = trial.suggest_categorical('material_name', config.material_list)
+ for count, material_dto in enumerate(target_and_fixed_parameters.material_dto_curve_list):
+ if material_dto.material_name == material_name:
+ material_dto: mdb.MaterialCurve = material_dto
+ magnet_material_model = target_and_fixed_parameters.magnet_hub_model_list[count]
+
+ # calculate total 2D-axi symmetric volume of the core:
+ # formula: number_turns_per_row = (available_width + primary_to_primary) / (wire_diameter + primary_to_primary)
+ available_width_top = window_w - config.insulations.iso_window_top_core_left - config.insulations.iso_window_top_core_right
+ possible_number_turns_per_column_top_window = int(
+ (available_width_top + config.insulations.iso_primary_to_primary) / (primary_litz_diameter + config.insulations.iso_primary_to_primary))
+ if possible_number_turns_per_column_top_window < 1:
+ return float('nan'), float('nan')
+ number_of_rows_needed = np.ceil(n_p_top / possible_number_turns_per_column_top_window)
+ needed_height_top_wo_insulation = (number_of_rows_needed * primary_litz_diameter + \
+ (number_of_rows_needed - 1) * config.insulations.iso_primary_to_primary)
+ window_h_top = needed_height_top_wo_insulation + config.insulations.iso_window_top_core_top + config.insulations.iso_window_top_core_bot
+
+ # detailed calculation for the winding window
+ # check the area for the primary bottom winding
+ available_height_bot = window_h_bot - config.insulations.iso_window_bot_core_top - config.insulations.iso_window_bot_core_bot
+ possible_number_prim_turns_per_column_bot_window = int(
+ (available_height_bot + config.insulations.iso_primary_to_primary) / (primary_litz_diameter + config.insulations.iso_primary_to_primary))
+ if possible_number_prim_turns_per_column_bot_window < 1:
+ return float('nan'), float('nan')
+ number_of_primary_columns_bot_needed = np.ceil(n_p_bot / possible_number_prim_turns_per_column_bot_window)
+ needed_primary_width_bot_wo_insulation = (number_of_primary_columns_bot_needed * primary_litz_diameter + \
+ (number_of_primary_columns_bot_needed - 1) * config.insulations.iso_primary_to_primary)
+ area_primary_bot = needed_primary_width_bot_wo_insulation * window_h_bot
+
+ # check the area for the secondary bottom winding
+ possible_number_sec_turns_per_column_bot_window = int(
+ (available_height_bot + config.insulations.iso_secondary_to_secondary) / \
+ (secondary_litz_diameter + config.insulations.iso_secondary_to_secondary))
+ if possible_number_sec_turns_per_column_bot_window < 1:
+ return float('nan'), float('nan')
+ number_of_secondary_columns_bot_needed = np.ceil(n_s_bot / possible_number_sec_turns_per_column_bot_window)
+ needed_primary_width_bot_wo_insulation = (number_of_secondary_columns_bot_needed * secondary_litz_diameter + \
+ (number_of_secondary_columns_bot_needed - 1) * config.insulations.iso_secondary_to_secondary)
+ area_secondary_bot = needed_primary_width_bot_wo_insulation * window_h_bot
+ area_insulation_prim_sec_bot = 2 * config.insulations.iso_primary_to_secondary * window_h_bot
+
+ total_area_windings_bot = area_primary_bot + area_secondary_bot + area_insulation_prim_sec_bot
+
+ window_bot_available_height = window_h_bot - config.insulations.iso_window_bot_core_top - config.insulations.iso_window_bot_core_bot
+ window_bot_available_width = window_w - config.insulations.iso_window_bot_core_left - config.insulations.iso_window_bot_core_right
+ window_bot_available_area = window_bot_available_height * window_bot_available_width
+
+ # check the area for the primary top winding
+ available_height_top = window_h_top - config.insulations.iso_window_top_core_top - config.insulations.iso_window_top_core_bot
+ possible_number_prim_turns_per_column_top_window = int(
+ (available_height_top + config.insulations.iso_primary_to_primary) / (primary_litz_diameter + config.insulations.iso_primary_to_primary))
+ if possible_number_prim_turns_per_column_top_window < 1:
+ return float('nan'), float('nan')
+ number_of_primary_columns_top_needed = np.ceil(n_p_top / possible_number_prim_turns_per_column_top_window)
+ needed_primary_width_top_wo_insulation = (number_of_primary_columns_top_needed * primary_litz_diameter + \
+ (number_of_primary_columns_top_needed - 1) * config.insulations.iso_primary_to_primary)
+ area_primary_top = needed_primary_width_top_wo_insulation * window_h_top
+
+ # check the area for the secondary top winding
+ possible_number_sec_turns_per_column_top_window = int(
+ (available_height_top + config.insulations.iso_secondary_to_secondary) / \
+ (secondary_litz_diameter + config.insulations.iso_secondary_to_secondary))
+ if possible_number_sec_turns_per_column_top_window < 1:
+ return float('nan'), float('nan')
+ number_of_secondary_columns_top_needed = np.ceil(n_s_top / possible_number_sec_turns_per_column_top_window)
+ needed_primary_width_top_wo_insulation = (number_of_secondary_columns_top_needed * secondary_litz_diameter + \
+ (number_of_secondary_columns_top_needed - 1) * config.insulations.iso_secondary_to_secondary)
+ area_secondary_top = needed_primary_width_top_wo_insulation * window_h_top
+
+ area_insulation_prim_sec_top = 2 * config.insulations.iso_primary_to_secondary * window_h_top
+ total_area_windings_top = area_primary_top + area_secondary_top + area_insulation_prim_sec_top
+
+ window_top_available_height = window_h_top - config.insulations.iso_window_top_core_top - config.insulations.iso_window_top_core_bot
+ window_top_available_width = window_w - config.insulations.iso_window_top_core_left - config.insulations.iso_window_top_core_right
+ window_top_available_area = window_top_available_height * window_top_available_width
+
+ # as the window_h_top is adapted to the number of n_p_top, the top windings always fit into the top window.
+ if total_area_windings_bot > window_bot_available_area:
+ logging.warning("Winding window bottom too small for too many turns.")
+ return float('nan'), float('nan')
+ if total_area_windings_top > window_top_available_area:
+ logging.warning("Winding window top too small for too many turns.")
+ return float('nan'), float('nan')
+
+ reluctance_model_intput = ItoReluctanceModelInput(
+ target_inductance_matrix=target_and_fixed_parameters.target_inductance_matrix,
+ core_inner_diameter=core_inner_diameter,
+ window_w=window_w,
+ window_h_bot=window_h_bot,
+ window_h_top=window_h_top,
+ turns_1_top=n_p_top,
+ turns_1_bot=n_p_bot,
+ turns_2_top=n_s_top,
+ turns_2_bot=n_s_bot,
+ litz_wire_name_1=primary_litz_name,
+ litz_wire_diameter_1=primary_litz_diameter,
+ litz_wire_name_2=secondary_litz_name,
+ litz_wire_diameter_2=secondary_litz_diameter,
+
+ insulations=config.insulations,
+ material_dto=material_dto,
+ magnet_material_model=magnet_material_model,
+
+ temperature=config.temperature,
+ time_extracted_vec=target_and_fixed_parameters.time_extracted_vec,
+ current_extracted_vec_1=target_and_fixed_parameters.current_extracted_1_vec,
+ current_extracted_vec_2=target_and_fixed_parameters.current_extracted_2_vec,
+ fundamental_frequency=target_and_fixed_parameters.fundamental_frequency,
+ i_rms_1=target_and_fixed_parameters.i_rms_1,
+ i_rms_2=target_and_fixed_parameters.i_rms_2,
+ primary_litz_dict=primary_litz_dict,
+ secondary_litz_dict=secondary_litz_dict,
+
+ # winding 1
+ fft_frequency_list_1=target_and_fixed_parameters.fft_frequency_list_1,
+ fft_amplitude_list_1=target_and_fixed_parameters.fft_amplitude_list_1,
+ fft_phases_list_1=target_and_fixed_parameters.fft_phases_list_1,
+ # winding 2
+ fft_frequency_list_2=target_and_fixed_parameters.fft_frequency_list_2,
+ fft_amplitude_list_2=target_and_fixed_parameters.fft_amplitude_list_2,
+ fft_phases_list_2=target_and_fixed_parameters.fft_phases_list_2,
+ )
+ try:
+ reluctance_output = IntegratedTransformerOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_intput)
+ except ValueError:
+ logging.warning("No fitting air gap length")
+ return float('nan'), float('nan')
+
+ # set additional attributes
+ trial.set_user_attr('p_hyst', reluctance_output.p_hyst)
+ trial.set_user_attr('p_hyst_top', reluctance_output.p_hyst_top)
+ trial.set_user_attr('p_hyst_bot', reluctance_output.p_hyst_bot)
+ trial.set_user_attr('p_hyst_middle', reluctance_output.p_hyst_middle)
+ trial.set_user_attr('b_max_top', reluctance_output.b_max_top)
+ trial.set_user_attr('b_max_bot', reluctance_output.b_max_bot)
+ trial.set_user_attr('b_max_middle', reluctance_output.b_max_middle)
+ trial.set_user_attr('window_h_top', window_h_top)
+ trial.set_user_attr('winding_losses', reluctance_output.winding_1_loss + reluctance_output.winding_2_loss)
+ trial.set_user_attr('l_top_air_gap', reluctance_output.l_top_air_gap)
+ trial.set_user_attr('l_bot_air_gap', reluctance_output.l_bot_air_gap)
+
+ return reluctance_output.volume, reluctance_output.p_loss
+
+ #########################################################
+ # set dynamic wire count parameters as optimization parameters
+ #########################################################
+ # set the winding search space dynamic
+ # https://optuna.readthedocs.io/en/stable/faq.html#what-happens-when-i-dynamically-alter-a-search-space
+
+ # if np.linalg.det(t2_reluctance_matrix) != 0 and np.linalg.det(
+ # np.transpose(t2_winding_matrix)) != 0 and np.linalg.det(target_inductance_matrix) != 0:
+ # # calculate the flux
+ # flux_top_vec, flux_bot_vec, flux_stray_vec = fr.flux_vec_from_current_vec(
+ # target_and_fixed_parameters.current_extracted_1_vec,
+ # target_and_fixed_parameters.current_extracted_2_vec,
+ # t2_winding_matrix,
+ # target_inductance_matrix)
@staticmethod
def start_proceed_study(config: ItoSingleInputConfig, number_trials: Optional[int] = None,
@@ -674,7 +847,7 @@ def show_study_results(config: ItoSingleInputConfig) -> None:
fig = optuna.visualization.plot_pareto_front(study, targets=lambda t: (t.values[0], t.values[1]), target_names=["volume in m³", "loss in W"])
fig.update_layout(title=f"{config.integrated_transformer_study_name}
{config.integrated_transformer_optimization_directory}")
- fig.write_html(f"{config.stacked_transformer_optimization_directory}/{config.stacked_transformer_study_name}"
+ fig.write_html(f"{config.integrated_transformer_optimization_directory}/{config.integrated_transformer_study_name}"
f"_{datetime.datetime.now().isoformat(timespec='minutes')}.html")
fig.show()
diff --git a/femmt/optimization/ito_dtos.py b/femmt/optimization/ito_dtos.py
index 8dd09abc..ea1f05ea 100644
--- a/femmt/optimization/ito_dtos.py
+++ b/femmt/optimization/ito_dtos.py
@@ -6,7 +6,38 @@
# 3rd party libraries
import numpy as np
from materialdatabase.dtos import MaterialCurve
+from magnethub.loss import LossModel
+from femmt.enumerations import *
+@dataclass
+class ItoInsulation:
+ """Insulation definition for the integrated transformer optimization."""
+
+ # insulation for top core window
+ iso_window_top_core_top: float
+ iso_window_top_core_bot: float
+ iso_window_top_core_left: float
+ iso_window_top_core_right: float
+ # insulation for bottom core window
+ iso_window_bot_core_top: float
+ iso_window_bot_core_bot: float
+ iso_window_bot_core_left: float
+ iso_window_bot_core_right: float
+ # winding-to-winding insulation
+ iso_primary_to_primary: float
+ iso_secondary_to_secondary: float
+ iso_primary_to_secondary: float
+
+@dataclass
+class IntegratedTransformerMaterialDataSources:
+ """Data sources for the FEM simulation."""
+
+ permeability_datasource: MaterialDataSource
+ permeability_datatype: MeasurementDataType
+ permeability_measurement_setup: MeasurementSetup
+ permittivity_datasource: MaterialDataSource
+ permittivity_datatype: MeasurementDataType
+ permittivity_measurement_setup: MeasurementSetup
@dataclass
class ItoSingleInputConfig:
@@ -18,22 +49,38 @@ class ItoSingleInputConfig:
"""
integrated_transformer_study_name: str
+ integrated_transformer_optimization_directory: str
- l_s_target: float
+ # target parameters
+ l_s12_target: float
l_h_target: float
n_target: float
+
+ # fix input parameters
time_current_1_vec: np.ndarray
time_current_2_vec: np.ndarray
+
+ # parameters to optimize
material_list: list
- core_inner_diameter_min_max_list: list
- window_w_min_max_list: list
- window_h_top_min_max_list: list
- window_h_bot_min_max_list: list
+ core_name_list: list | None
+ core_inner_diameter_min_max_list: list | None
+ window_w_min_max_list: list | None
+ window_h_top_min_max_list: list | None
+ window_h_bot_min_max_list: list | None
+ n_1_top_min_max_list: list
+ n_1_bot_min_max_list: list
+ n_2_top_min_max_list: list
+ n_2_bot_min_max_list: list
factor_max_flux_density: float
- primary_litz_wire_list: list
- secondary_litz_wire_list: list
+ primary_litz_wire_list: list[str]
+ secondary_litz_wire_list: list[str]
temperature: float
- integrated_transformer_optimization_directory: str
+
+ # fix parameters: insulations
+ insulations: ItoInsulation
+
+ # data sources
+ material_data_sources: IntegratedTransformerMaterialDataSources
@dataclass
class WorkingDirectories:
@@ -56,7 +103,12 @@ class ItoTargetAndFixedParameters:
i_rms_1: float
i_rms_2: float
+ i_peak_1: float
+ i_peak_2: float
+ i_phase_deg_1: float
+ i_phase_deg_2: float
material_dto_curve_list: List[MaterialCurve]
+ magnet_hub_model_list: List[LossModel]
time_extracted_vec: List
current_extracted_1_vec: List
current_extracted_2_vec: List
@@ -64,29 +116,15 @@ class ItoTargetAndFixedParameters:
target_inductance_matrix: np.ndarray
working_directories: WorkingDirectories
-@dataclass
-class SweepTensor:
- """
- Dataclass contains the concrete sweep vectors.
+ # winding 1
+ fft_frequency_list_1: List[float]
+ fft_amplitude_list_1: List[float]
+ fft_phases_list_1: List[float]
- This class is calculated from the integrated-transformer input config file (ItoSingleInputConfig).
- ItoSingleInputConfig: core_inner_diameter = [10e-3, 30e-3, 5]
- ->> SweepTensor: t1_core_inner_diameter = [10e-3, 15e-3, 20e-3, 25e-3, 30e-3]
- """
-
- t1_window_h_top: np.ndarray
- t1_window_h_bot: np.ndarray
- t1_window_w: np.ndarray
- t1_core_material: list
- t1_core_inner_diameter: np.ndarray
- t1_primary_litz_wire_list: list
- t1_secondary_litz_wire_list: list
- time_current_1_vec: np.ndarray
- time_current_2_vec: np.ndarray
- l_s_target_value: float
- l_h_target_value: float
- n_target_value: float
- factor_max_flux_density: float
+ # winding 2
+ fft_frequency_list_2: List[float]
+ fft_amplitude_list_2: List[float]
+ fft_phases_list_2: List[float]
@dataclass
class ItoSingleResultFile:
@@ -125,3 +163,68 @@ class ItoSingleResultFile:
secondary_litz_wire_loss: float
core_2daxi_total_volume: float
total_loss: float
+
+@dataclass
+class ItoReluctanceModelInput:
+ """Input DTO for reluctance model simulation within the inductor optimization."""
+
+ target_inductance_matrix: np.array
+ core_inner_diameter: float
+ window_w: float
+ window_h_bot: float
+ window_h_top: float
+ turns_1_top: int
+ turns_2_top: int
+ turns_1_bot: int
+ turns_2_bot: int
+ litz_wire_name_1: str
+ litz_wire_diameter_1: float
+ litz_wire_name_2: str
+ litz_wire_diameter_2: float
+
+ insulations: ItoInsulation
+ material_dto: MaterialCurve
+ magnet_material_model: LossModel
+
+ temperature: float
+ time_extracted_vec: List
+ current_extracted_vec_1: List
+ current_extracted_vec_2: List
+ fundamental_frequency: float
+
+ i_rms_1: float
+ i_rms_2: float
+
+ primary_litz_dict: dict
+ secondary_litz_dict: dict
+
+ # winding 1
+ fft_frequency_list_1: List[float]
+ fft_amplitude_list_1: List[float]
+ fft_phases_list_1: List[float]
+
+ # winding 2
+ fft_frequency_list_2: List[float]
+ fft_amplitude_list_2: List[float]
+ fft_phases_list_2: List[float]
+
+@dataclass
+class ItoReluctanceModelOutput:
+ """output DTO for reluctance model simulation within the inductor optimization."""
+
+ # set additional attributes
+ p_hyst: float
+ p_hyst_top: float
+ p_hyst_bot: float
+ p_hyst_middle: float
+ b_max_top: float
+ b_max_bot: float
+ b_max_middle: float
+ winding_1_loss: float
+ winding_2_loss: float
+ l_top_air_gap: float
+ l_bot_air_gap: float
+ l_middle_air_gap: float
+ volume: float
+ area_to_heat_sink: float
+ p_loss: float
diff --git a/femmt/optimization/sto.py b/femmt/optimization/sto.py
index cade2e9e..16c09f62 100644
--- a/femmt/optimization/sto.py
+++ b/femmt/optimization/sto.py
@@ -424,7 +424,7 @@ def single_reluctance_model_simulation(reluctance_input: ReluctanceModelInput) -
p_winding_1_top = 0
p_winding_1_bot = 0
for count, fft_frequency in enumerate(reluctance_input.fft_frequency_list_1):
- proximity_factor_1_top = fmt.calc_proximity_factor_air_gap(
+ proximity_factor_1_top = fr.calc_proximity_factor_air_gap(
litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=reluctance_input.turns_1_top,
r_1=reluctance_input.insulations.iso_window_top_core_left,
frequency=fft_frequency, winding_area=winding_area_1_top,
@@ -437,7 +437,7 @@ def single_reluctance_model_simulation(reluctance_input: ReluctanceModelInput) -
(reluctance_input.turns_1_bot * 2 * reluctance_input.primary_litz_dict["conductor_radii"] + \
(reluctance_input.turns_1_bot - 1) * reluctance_input.insulations.iso_primary_to_primary)
- proximity_factor_1_bot_inner = fmt.calc_proximity_factor_air_gap(
+ proximity_factor_1_bot_inner = fr.calc_proximity_factor_air_gap(
litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=reluctance_input.turns_1_bot,
r_1=reluctance_input.insulations.iso_window_bot_core_left,
frequency=fft_frequency, winding_area=winding_area_1_bot,
@@ -449,13 +449,13 @@ def single_reluctance_model_simulation(reluctance_input: ReluctanceModelInput) -
number_bot_prim_turns_per_column * 2 * reluctance_input.primary_litz_dict["conductor_radii"] + \
(number_bot_prim_turns_per_column - 1) * reluctance_input.insulations.iso_primary_to_primary))
- proximity_factor_1_bot_inner = fmt.calc_proximity_factor_air_gap(
+ proximity_factor_1_bot_inner = fr.calc_proximity_factor_air_gap(
litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=number_bot_prim_turns_per_column,
r_1=reluctance_input.insulations.iso_window_bot_core_left,
frequency=fft_frequency, winding_area=winding_area_1_bot,
litz_wire_material_name='Copper', temperature=reluctance_input.temperature)
- proximity_factor_1_bot_outer = fmt.calc_proximity_factor(
+ proximity_factor_1_bot_outer = fr.calc_proximity_factor(
litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=reluctance_input.turns_1_bot - number_bot_prim_turns_per_column,
window_h=reluctance_input.window_h_bot,
iso_core_top=reluctance_input.insulations.iso_window_bot_core_top, iso_core_bot=reluctance_input.insulations.iso_window_bot_core_bot,
@@ -468,7 +468,7 @@ def single_reluctance_model_simulation(reluctance_input: ReluctanceModelInput) -
p_winding_2 = 0
for count, fft_frequency in enumerate(reluctance_input.fft_frequency_list_2):
- proximity_factor_assumption_2 = fmt.calc_proximity_factor(
+ proximity_factor_assumption_2 = fr.calc_proximity_factor(
litz_wire_name=reluctance_input.litz_wire_name_2, number_turns=reluctance_input.turns_2_bot, window_h=reluctance_input.window_h_bot,
iso_core_top=reluctance_input.insulations.iso_window_bot_core_top, iso_core_bot=reluctance_input.insulations.iso_window_bot_core_bot,
frequency=fft_frequency, litz_wire_material_name='Copper', temperature=reluctance_input.temperature)
From 087067f69fb4eda5d5d4d6aaa649fe149ccdb79d Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Thu, 27 Feb 2025 10:31:55 +0100
Subject: [PATCH 05/15] gitignore add templates
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index e82a5301..f92e8fde 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,6 +39,7 @@ femmt.egg-info/
onelab/
*/working_directory/
tests/integration/temp/
+docs/_templates/
# FEMMT: generated files
femmt/electro_magnetic/Parameter.pro
From d5bac98beca69f8d5e3eb23b6b558e83950f51c3 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Fri, 28 Feb 2025 17:26:58 +0100
Subject: [PATCH 06/15] update winding area calculation ito
---
femmt/examples/ito_optuna_example.py | 12 +-
femmt/optimization/ito.py | 176 ++++++++--------------
femmt/optimization/ito_dtos.py | 16 +-
femmt/optimization/ito_functions.py | 4 +-
femmt/optimization/optuna_femmt_parser.py | 8 +-
5 files changed, 86 insertions(+), 130 deletions(-)
diff --git a/femmt/examples/ito_optuna_example.py b/femmt/examples/ito_optuna_example.py
index a5301f26..9324750e 100644
--- a/femmt/examples/ito_optuna_example.py
+++ b/femmt/examples/ito_optuna_example.py
@@ -48,7 +48,7 @@
)
dab_transformer_config = fmt.ItoSingleInputConfig(
- integrated_transformer_study_name="2025-02-26",
+ integrated_transformer_study_name="2025-02-28",
integrated_transformer_optimization_directory=os.path.join(os.path.dirname(__file__), "example_results", "optuna_integrated_transformer_optimization"),
# target parameters
@@ -63,7 +63,7 @@
# optimization parameters
material_list=["3C95"],
- core_name_list=["PQ 40/40"],
+ core_name_list=["PQ 50/50", "PQ 40/40"],
core_inner_diameter_min_max_list=None,
window_w_min_max_list=None,
window_h_top_min_max_list=None,
@@ -74,8 +74,8 @@
n_2_top_min_max_list=[1, 30],
n_2_bot_min_max_list=[1, 30],
factor_max_flux_density=1,
- primary_litz_wire_list=["1.4x200x0.071"],
- secondary_litz_wire_list=["1.4x200x0.071"],
+ litz_wire_list_1=["1.1x60x0.1"],
+ litz_wire_list_2=["1.1x60x0.1"],
temperature=100,
material_data_sources=material_data_sources,
@@ -83,7 +83,7 @@
)
-# task = 'start_study'
+##task = 'start_proceed_study'
# task = 'filter_reluctance_model'
# task = 'fem_simulation_from_filtered_reluctance_model_results'
task = 'plot_study_results'
@@ -91,7 +91,7 @@
if __name__ == '__main__':
time_start = datetime.datetime.now()
- if task == 'start_study':
+ if task == 'start_proceed_study':
fmt.IntegratedTransformerOptimization.ReluctanceModel.start_proceed_study(dab_transformer_config, 10000, storage='sqlite')
elif task == 'filter_reluctance_model':
diff --git a/femmt/optimization/ito.py b/femmt/optimization/ito.py
index f2141d21..faf68edc 100644
--- a/femmt/optimization/ito.py
+++ b/femmt/optimization/ito.py
@@ -81,10 +81,10 @@ def result_file_dict_to_dto(result_file_dict: Dict) -> ItoSingleResultFile:
flux_density_stray_max=result_file_dict["flux_density_stray_max"],
p_hyst=result_file_dict["p_hyst"],
core_2daxi_total_volume=result_file_dict["core_2daxi_total_volume"],
- primary_litz_wire=result_file_dict["primary_litz_wire"],
- secondary_litz_wire=result_file_dict["secondary_litz_wire"],
- primary_litz_wire_loss=result_file_dict["primary_litz_wire_loss"],
- secondary_litz_wire_loss=result_file_dict["secondary_litz_wire_loss"],
+ litz_wire_name_1=result_file_dict["primary_litz_wire"],
+ litz_wire_name_2=result_file_dict["secondary_litz_wire"],
+ litz_wire_loss_1=result_file_dict["primary_litz_wire_loss"],
+ litz_wire_loss_2=result_file_dict["secondary_litz_wire_loss"],
total_loss=result_file_dict["total_loss"]
)
return result_file_dto
@@ -332,7 +332,7 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
# calculate winding losses
primary_effective_conductive_cross_section = (
- reluctance_input.primary_litz_dict["strands_numbers"] * reluctance_input.primary_litz_dict["strand_radii"] ** 2 * np.pi)
+ reluctance_input.litz_dict_1["strands_numbers"] * reluctance_input.litz_dict_1["strand_radii"] ** 2 * np.pi)
primary_effective_conductive_radius = np.sqrt(primary_effective_conductive_cross_section / np.pi)
primary_resistance_top = fr.resistance_solid_wire(
reluctance_input.core_inner_diameter, reluctance_input.window_w, reluctance_input.turns_1_top,
@@ -341,7 +341,7 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
number_bot_prim_turns_per_column = (
int((reluctance_input.window_h_bot - reluctance_input.insulations.iso_window_bot_core_top - \
reluctance_input.insulations.iso_window_bot_core_bot + reluctance_input.insulations.iso_primary_to_primary) / \
- (2 * reluctance_input.primary_litz_dict["conductor_radii"] + reluctance_input.insulations.iso_primary_to_primary)))
+ (2 * reluctance_input.litz_dict_1["conductor_radii"] + reluctance_input.insulations.iso_primary_to_primary)))
if number_bot_prim_turns_per_column > reluctance_input.turns_1_bot:
# single row window only
primary_resistance_bot_inner = fr.resistance_solid_wire(
@@ -359,16 +359,16 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
primary_effective_conductive_radius, material='Copper')
secondary_effective_conductive_cross_section = (
- reluctance_input.secondary_litz_dict["strands_numbers"] * reluctance_input.secondary_litz_dict["strand_radii"] ** 2 * np.pi)
+ reluctance_input.litz_dict_2["strands_numbers"] * reluctance_input.litz_dict_2["strand_radii"] ** 2 * np.pi)
secondary_effective_conductive_radius = np.sqrt(secondary_effective_conductive_cross_section / np.pi)
secondary_resistance = fr.resistance_solid_wire(
reluctance_input.core_inner_diameter, reluctance_input.window_w, reluctance_input.turns_2_bot, secondary_effective_conductive_radius,
material='Copper')
winding_area_1_top = (
- 2 * reluctance_input.primary_litz_dict["conductor_radii"] * \
- (reluctance_input.turns_1_top * 2 * reluctance_input.primary_litz_dict["conductor_radii"] + \
- (reluctance_input.turns_1_top - 1) * reluctance_input.insulations.iso_primary_to_primary))
+ 2 * reluctance_input.litz_dict_1["conductor_radii"] * \
+ (reluctance_input.turns_1_top * 2 * reluctance_input.litz_dict_1["conductor_radii"] + \
+ (reluctance_input.turns_1_top - 1) * reluctance_input.insulations.iso_primary_to_primary))
p_winding_1_top = 0
p_winding_1_bot = 0
@@ -382,9 +382,9 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
p_winding_1_top += proximity_factor_1_top * primary_resistance_top * reluctance_input.fft_amplitude_list_1[count] ** 2
if number_bot_prim_turns_per_column > reluctance_input.turns_1_bot:
- winding_area_1_bot = 2 * reluctance_input.primary_litz_dict["conductor_radii"] * \
- (reluctance_input.turns_1_bot * 2 * reluctance_input.primary_litz_dict["conductor_radii"] + \
- (reluctance_input.turns_1_bot - 1) * reluctance_input.insulations.iso_primary_to_primary)
+ winding_area_1_bot = 2 * reluctance_input.litz_dict_1["conductor_radii"] * \
+ (reluctance_input.turns_1_bot * 2 * reluctance_input.litz_dict_1["conductor_radii"] + \
+ (reluctance_input.turns_1_bot - 1) * reluctance_input.insulations.iso_primary_to_primary)
proximity_factor_1_bot_inner = fr.calc_proximity_factor_air_gap(
litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=reluctance_input.turns_1_bot,
@@ -394,9 +394,9 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
proximity_factor_1_bot_outer = 0
else:
- winding_area_1_bot = (2 * reluctance_input.primary_litz_dict["conductor_radii"] * (
- number_bot_prim_turns_per_column * 2 * reluctance_input.primary_litz_dict["conductor_radii"] + \
- (number_bot_prim_turns_per_column - 1) * reluctance_input.insulations.iso_primary_to_primary))
+ winding_area_1_bot = (2 * reluctance_input.litz_dict_1["conductor_radii"] * (
+ number_bot_prim_turns_per_column * 2 * reluctance_input.litz_dict_1["conductor_radii"] + \
+ (number_bot_prim_turns_per_column - 1) * reluctance_input.insulations.iso_primary_to_primary))
proximity_factor_1_bot_inner = fr.calc_proximity_factor_air_gap(
litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=number_bot_prim_turns_per_column,
@@ -471,10 +471,10 @@ def objective(trial: optuna.Trial, config: ItoSingleInputConfig, target_and_fixe
core = ff.core_database()[core_name]
core_inner_diameter = core["core_inner_diameter"]
window_w = core["window_w"]
- window_h_bot = trial.suggest_float("window_h_bot", 0.3 * core["window_h"], core["window_h"])
+ window_h_half_max = (core["window_h"] - core_inner_diameter) / 2
+
trial.set_user_attr('core_inner_diameter', core_inner_diameter)
trial.set_user_attr('window_w', window_w)
- trial.set_user_attr('window_h_bot', window_h_bot)
else:
# using arbitrary core sizes
@@ -483,102 +483,58 @@ def objective(trial: optuna.Trial, config: ItoSingleInputConfig, target_and_fixe
window_w = trial.suggest_float("window_w", config.window_w_min_max_list[0], config.window_w_min_max_list[1])
window_h_bot = trial.suggest_float('window_h_bot', config.window_h_bot_min_max_list[0], config.window_h_bot_min_max_list[1])
- n_p_top = trial.suggest_int('n_p_top', config.n_1_top_min_max_list[0], config.n_1_top_min_max_list[1])
- n_p_bot = trial.suggest_int('n_p_bot', config.n_1_bot_min_max_list[0], config.n_1_bot_min_max_list[1])
- n_s_top = trial.suggest_int('n_s_top', config.n_2_top_min_max_list[0], config.n_2_top_min_max_list[1])
- n_s_bot = trial.suggest_int('n_s_bot', config.n_2_bot_min_max_list[0], config.n_2_bot_min_max_list[1])
+ # suggest turn counts
+ n_1_top = trial.suggest_int('n_p_top', config.n_1_top_min_max_list[0], config.n_1_top_min_max_list[1])
+ n_1_bot = trial.suggest_int('n_p_bot', config.n_1_bot_min_max_list[0], config.n_1_bot_min_max_list[1])
+ n_2_top = trial.suggest_int('n_s_top', config.n_2_top_min_max_list[0], config.n_2_top_min_max_list[1])
+ n_2_bot = trial.suggest_int('n_s_bot', config.n_2_bot_min_max_list[0], config.n_2_bot_min_max_list[1])
- primary_litz_name = trial.suggest_categorical('primary_litz_name', config.primary_litz_wire_list)
- primary_litz_dict = ff.litz_database()[primary_litz_name]
- primary_litz_diameter = 2 * primary_litz_dict['conductor_radii']
+ # suggest litz wire 1
+ litz_name_1 = trial.suggest_categorical('litz_name_1', config.litz_wire_list_1)
+ litz_dict_1 = ff.litz_database()[litz_name_1]
+ litz_diameter_1 = 2 * litz_dict_1['conductor_radii']
- secondary_litz_name = trial.suggest_categorical('secondary_litz_name', config.secondary_litz_wire_list)
- secondary_litz_dict = ff.litz_database()[secondary_litz_name]
- secondary_litz_diameter = 2 * secondary_litz_dict['conductor_radii']
+ # suggest litz wire 2
+ litz_name_2 = trial.suggest_categorical('litz_name_2', config.litz_wire_list_2)
+ litz_dict_2 = ff.litz_database()[litz_name_2]
+ litz_diameter_2 = 2 * litz_dict_2['conductor_radii']
+ # suggest core material
material_name = trial.suggest_categorical('material_name', config.material_list)
for count, material_dto in enumerate(target_and_fixed_parameters.material_dto_curve_list):
if material_dto.material_name == material_name:
material_dto: mdb.MaterialCurve = material_dto
magnet_material_model = target_and_fixed_parameters.magnet_hub_model_list[count]
- # calculate total 2D-axi symmetric volume of the core:
- # formula: number_turns_per_row = (available_width + primary_to_primary) / (wire_diameter + primary_to_primary)
+ # calculation of window_h_top: assumption: winding ist stacked
available_width_top = window_w - config.insulations.iso_window_top_core_left - config.insulations.iso_window_top_core_right
- possible_number_turns_per_column_top_window = int(
- (available_width_top + config.insulations.iso_primary_to_primary) / (primary_litz_diameter + config.insulations.iso_primary_to_primary))
- if possible_number_turns_per_column_top_window < 1:
- return float('nan'), float('nan')
- number_of_rows_needed = np.ceil(n_p_top / possible_number_turns_per_column_top_window)
- needed_height_top_wo_insulation = (number_of_rows_needed * primary_litz_diameter + \
- (number_of_rows_needed - 1) * config.insulations.iso_primary_to_primary)
- window_h_top = needed_height_top_wo_insulation + config.insulations.iso_window_top_core_top + config.insulations.iso_window_top_core_bot
-
- # detailed calculation for the winding window
- # check the area for the primary bottom winding
- available_height_bot = window_h_bot - config.insulations.iso_window_bot_core_top - config.insulations.iso_window_bot_core_bot
- possible_number_prim_turns_per_column_bot_window = int(
- (available_height_bot + config.insulations.iso_primary_to_primary) / (primary_litz_diameter + config.insulations.iso_primary_to_primary))
- if possible_number_prim_turns_per_column_bot_window < 1:
- return float('nan'), float('nan')
- number_of_primary_columns_bot_needed = np.ceil(n_p_bot / possible_number_prim_turns_per_column_bot_window)
- needed_primary_width_bot_wo_insulation = (number_of_primary_columns_bot_needed * primary_litz_diameter + \
- (number_of_primary_columns_bot_needed - 1) * config.insulations.iso_primary_to_primary)
- area_primary_bot = needed_primary_width_bot_wo_insulation * window_h_bot
-
- # check the area for the secondary bottom winding
- possible_number_sec_turns_per_column_bot_window = int(
- (available_height_bot + config.insulations.iso_secondary_to_secondary) / \
- (secondary_litz_diameter + config.insulations.iso_secondary_to_secondary))
- if possible_number_sec_turns_per_column_bot_window < 1:
- return float('nan'), float('nan')
- number_of_secondary_columns_bot_needed = np.ceil(n_s_bot / possible_number_sec_turns_per_column_bot_window)
- needed_primary_width_bot_wo_insulation = (number_of_secondary_columns_bot_needed * secondary_litz_diameter + \
- (number_of_secondary_columns_bot_needed - 1) * config.insulations.iso_secondary_to_secondary)
- area_secondary_bot = needed_primary_width_bot_wo_insulation * window_h_bot
- area_insulation_prim_sec_bot = 2 * config.insulations.iso_primary_to_secondary * window_h_bot
-
- total_area_windings_bot = area_primary_bot + area_secondary_bot + area_insulation_prim_sec_bot
-
- window_bot_available_height = window_h_bot - config.insulations.iso_window_bot_core_top - config.insulations.iso_window_bot_core_bot
- window_bot_available_width = window_w - config.insulations.iso_window_bot_core_left - config.insulations.iso_window_bot_core_right
- window_bot_available_area = window_bot_available_height * window_bot_available_width
-
- # check the area for the primary top winding
- available_height_top = window_h_top - config.insulations.iso_window_top_core_top - config.insulations.iso_window_top_core_bot
- possible_number_prim_turns_per_column_top_window = int(
- (available_height_top + config.insulations.iso_primary_to_primary) / (primary_litz_diameter + config.insulations.iso_primary_to_primary))
- if possible_number_prim_turns_per_column_top_window < 1:
- return float('nan'), float('nan')
- number_of_primary_columns_top_needed = np.ceil(n_p_top / possible_number_prim_turns_per_column_top_window)
- needed_primary_width_top_wo_insulation = (number_of_primary_columns_top_needed * primary_litz_diameter + \
- (number_of_primary_columns_top_needed - 1) * config.insulations.iso_primary_to_primary)
- area_primary_top = needed_primary_width_top_wo_insulation * window_h_top
-
- # check the area for the secondary top winding
- possible_number_sec_turns_per_column_top_window = int(
- (available_height_top + config.insulations.iso_secondary_to_secondary) / \
- (secondary_litz_diameter + config.insulations.iso_secondary_to_secondary))
- if possible_number_sec_turns_per_column_top_window < 1:
- return float('nan'), float('nan')
- number_of_secondary_columns_top_needed = np.ceil(n_s_top / possible_number_sec_turns_per_column_top_window)
- needed_primary_width_top_wo_insulation = (number_of_secondary_columns_top_needed * secondary_litz_diameter + \
- (number_of_secondary_columns_top_needed - 1) * config.insulations.iso_secondary_to_secondary)
- area_secondary_top = needed_primary_width_top_wo_insulation * window_h_top
+ available_width_bot = window_w - config.insulations.iso_window_bot_core_left - config.insulations.iso_window_bot_core_right
- area_insulation_prim_sec_top = 2 * config.insulations.iso_primary_to_secondary * window_h_top
- total_area_windings_top = area_primary_top + area_secondary_top + area_insulation_prim_sec_top
+ def calc_winding_height(available_width: float, iso_winding_to_winding: float, litz_diameter: float,
+ number_turns: float):
- window_top_available_height = window_h_top - config.insulations.iso_window_top_core_top - config.insulations.iso_window_top_core_bot
- window_top_available_width = window_w - config.insulations.iso_window_top_core_left - config.insulations.iso_window_top_core_right
- window_top_available_area = window_top_available_height * window_top_available_width
- # as the window_h_top is adapted to the number of n_p_top, the top windings always fit into the top window.
- if total_area_windings_bot > window_bot_available_area:
- logging.warning("Winding window bottom too small for too many turns.")
+ number_turns_per_row = int((available_width + iso_winding_to_winding) / (litz_diameter + iso_winding_to_winding))
+ if number_turns_per_row < 1:
+ return float('nan'), float('nan')
+ number_of_rows = np.ceil(number_turns / number_turns_per_row)
+ winding_height = number_of_rows * litz_diameter + (number_of_rows -1) * iso_winding_to_winding
+ return winding_height
+
+ # height of top core needed
+ window_h_1_top = calc_winding_height(available_width_top, config.insulations.iso_primary_to_primary, litz_diameter_1, n_1_top)
+ window_h_2_top = calc_winding_height(available_width_top, config.insulations.iso_secondary_to_secondary, litz_diameter_2, n_2_top)
+ window_h_top = (window_h_1_top + window_h_2_top + config.insulations.iso_primary_to_secondary +
+ config.insulations.iso_window_top_core_top + config.insulations.iso_window_top_core_bot)
+ if window_h_top > window_h_half_max:
return float('nan'), float('nan')
- if total_area_windings_top > window_top_available_area:
- logging.warning("Winding window top too small for too many turns.")
+
+ # height of bot core needed
+ window_h_1_bot = calc_winding_height(available_width_bot, config.insulations.iso_primary_to_primary, litz_diameter_1, n_1_bot)
+ window_h_2_bot = calc_winding_height(available_width_bot, config.insulations.iso_secondary_to_secondary, litz_diameter_2, n_2_bot)
+ window_h_bot = (window_h_1_bot + window_h_2_bot + config.insulations.iso_primary_to_secondary +
+ config.insulations.iso_window_bot_core_top + config.insulations.iso_window_bot_core_bot)
+ if window_h_bot > window_h_half_max:
return float('nan'), float('nan')
reluctance_model_intput = ItoReluctanceModelInput(
@@ -587,14 +543,14 @@ def objective(trial: optuna.Trial, config: ItoSingleInputConfig, target_and_fixe
window_w=window_w,
window_h_bot=window_h_bot,
window_h_top=window_h_top,
- turns_1_top=n_p_top,
- turns_1_bot=n_p_bot,
- turns_2_top=n_s_top,
- turns_2_bot=n_s_bot,
- litz_wire_name_1=primary_litz_name,
- litz_wire_diameter_1=primary_litz_diameter,
- litz_wire_name_2=secondary_litz_name,
- litz_wire_diameter_2=secondary_litz_diameter,
+ turns_1_top=n_1_top,
+ turns_1_bot=n_1_bot,
+ turns_2_top=n_2_top,
+ turns_2_bot=n_2_bot,
+ litz_wire_name_1=litz_name_1,
+ litz_wire_diameter_1=litz_diameter_1,
+ litz_wire_name_2=litz_name_2,
+ litz_wire_diameter_2=litz_diameter_2,
insulations=config.insulations,
material_dto=material_dto,
@@ -607,8 +563,8 @@ def objective(trial: optuna.Trial, config: ItoSingleInputConfig, target_and_fixe
fundamental_frequency=target_and_fixed_parameters.fundamental_frequency,
i_rms_1=target_and_fixed_parameters.i_rms_1,
i_rms_2=target_and_fixed_parameters.i_rms_2,
- primary_litz_dict=primary_litz_dict,
- secondary_litz_dict=secondary_litz_dict,
+ litz_dict_1=litz_dict_1,
+ litz_dict_2=litz_dict_2,
# winding 1
fft_frequency_list_1=target_and_fixed_parameters.fft_frequency_list_1,
diff --git a/femmt/optimization/ito_dtos.py b/femmt/optimization/ito_dtos.py
index ea1f05ea..47227e3d 100644
--- a/femmt/optimization/ito_dtos.py
+++ b/femmt/optimization/ito_dtos.py
@@ -72,8 +72,8 @@ class ItoSingleInputConfig:
n_2_top_min_max_list: list
n_2_bot_min_max_list: list
factor_max_flux_density: float
- primary_litz_wire_list: list[str]
- secondary_litz_wire_list: list[str]
+ litz_wire_list_1: list[str]
+ litz_wire_list_2: list[str]
temperature: float
# fix parameters: insulations
@@ -148,8 +148,8 @@ class ItoSingleResultFile:
window_w: float
core_material: str
core_inner_diameter: float
- primary_litz_wire: str
- secondary_litz_wire: str
+ litz_wire_name_1: str
+ litz_wire_name_2: str
# reluctance model results
flux_top_max: float
@@ -159,8 +159,8 @@ class ItoSingleResultFile:
flux_density_bot_max: float
flux_density_stray_max: float
p_hyst: float
- primary_litz_wire_loss: float
- secondary_litz_wire_loss: float
+ litz_wire_loss_1: float
+ litz_wire_loss_2: float
core_2daxi_total_volume: float
total_loss: float
@@ -195,8 +195,8 @@ class ItoReluctanceModelInput:
i_rms_1: float
i_rms_2: float
- primary_litz_dict: dict
- secondary_litz_dict: dict
+ litz_dict_1: dict
+ litz_dict_2: dict
# winding 1
fft_frequency_list_1: List[float]
diff --git a/femmt/optimization/ito_functions.py b/femmt/optimization/ito_functions.py
index 2250fb95..e8871e1a 100644
--- a/femmt/optimization/ito_functions.py
+++ b/femmt/optimization/ito_functions.py
@@ -219,8 +219,8 @@ def integrated_transformer_fem_simulation_from_result_dto(config_dto: ItoSingleI
top, bot = winding_window.split_window(fmt.WindingWindowSplit.HorizontalSplit)
# 6. set conductor parameters
- primary_litz = ff.litz_database()[dto.primary_litz_wire]
- secondary_litz = ff.litz_database()[dto.secondary_litz_wire]
+ primary_litz = ff.litz_database()[dto.litz_wire_name_1]
+ secondary_litz = ff.litz_database()[dto.litz_wire_name_2]
winding1 = fmt.Conductor(0, fmt.Conductivity.Copper)
winding1.set_litz_round_conductor(primary_litz["conductor_radii"], primary_litz["strands_numbers"],
diff --git a/femmt/optimization/optuna_femmt_parser.py b/femmt/optimization/optuna_femmt_parser.py
index ec65bb1a..b6479cda 100644
--- a/femmt/optimization/optuna_femmt_parser.py
+++ b/femmt/optimization/optuna_femmt_parser.py
@@ -33,8 +33,8 @@ def parse(frozen_trial: optuna.trial.FrozenTrial) -> ItoSingleResultFile:
window_w=frozen_trial.params["window_w"],
core_material=frozen_trial.params["material"],
core_inner_diameter=frozen_trial.params["core_inner_diameter"],
- primary_litz_wire=frozen_trial.params["primary_litz_wire"],
- secondary_litz_wire=frozen_trial.params["secondary_litz_wire"],
+ litz_wire_name_1=frozen_trial.params["primary_litz_wire"],
+ litz_wire_name_2=frozen_trial.params["secondary_litz_wire"],
# reluctance model results
flux_top_max=frozen_trial.user_attrs["flux_top_max"],
@@ -44,8 +44,8 @@ def parse(frozen_trial: optuna.trial.FrozenTrial) -> ItoSingleResultFile:
flux_density_bot_max=frozen_trial.user_attrs["flux_density_bot_max"],
flux_density_stray_max=frozen_trial.user_attrs["flux_density_stray_max"],
p_hyst=frozen_trial.user_attrs["p_hyst"],
- primary_litz_wire_loss=frozen_trial.user_attrs["primary_litz_wire_loss"],
- secondary_litz_wire_loss=frozen_trial.user_attrs["secondary_litz_wire_loss"],
+ litz_wire_loss_1=frozen_trial.user_attrs["primary_litz_wire_loss"],
+ litz_wire_loss_2=frozen_trial.user_attrs["secondary_litz_wire_loss"],
core_2daxi_total_volume=frozen_trial.values[0],
total_loss=frozen_trial.values[1],
)
From 0f9ff59d95021d736d33d93912342b5d54b64835 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Tue, 4 Mar 2025 10:51:16 +0100
Subject: [PATCH 07/15] typos
---
femmt/functions.py | 6 +++---
femmt/optimization/ito.py | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/femmt/functions.py b/femmt/functions.py
index da3f8451..656c210c 100644
--- a/femmt/functions.py
+++ b/femmt/functions.py
@@ -1578,7 +1578,7 @@ def visualize_mean_coupling_factors(mean_coupling_factors: List, silent: bool):
def visualize_mean_mutual_inductances(inductance_matrix: np.array, silent: bool):
"""
- Print the mean mutal inductances to the terminal (or file-) output.
+ Print the mean mutual inductances to the terminal (or file-) output.
:param inductance_matrix: inductance matrix
:type inductance_matrix: np.array
@@ -1602,7 +1602,7 @@ def visualize_mean_mutual_inductances(inductance_matrix: np.array, silent: bool)
def visualize_mutual_inductances(self_inductances: List, coupling_factors: List, silent: bool):
"""
- Print the mutal inductances to the terminal (or file-) output.
+ Print the mutual inductances to the terminal (or file-) output.
:param self_inductances: Matrix with self inductances
:type self_inductances: List
@@ -1687,7 +1687,7 @@ def calculate_quadrature_integral(time_steps: List[float], data: List[float]) ->
def calculate_squared_quadrature_integral(time_steps: List[float], data: List[float]) -> float:
"""
- Calculate the integral of squared given data over specific time steps using the quad method..
+ Calculate the integral of squared given data over specific time steps using the quad method.
:param time_steps: List of time steps.
:type time_steps: List[float]
diff --git a/femmt/optimization/ito.py b/femmt/optimization/ito.py
index faf68edc..bcf67076 100644
--- a/femmt/optimization/ito.py
+++ b/femmt/optimization/ito.py
@@ -481,7 +481,7 @@ def objective(trial: optuna.Trial, config: ItoSingleInputConfig, target_and_fixe
core_inner_diameter = trial.suggest_float("core_inner_diameter", config.core_inner_diameter_min_max_list[0],
config.core_inner_diameter_min_max_list[1])
window_w = trial.suggest_float("window_w", config.window_w_min_max_list[0], config.window_w_min_max_list[1])
- window_h_bot = trial.suggest_float('window_h_bot', config.window_h_bot_min_max_list[0], config.window_h_bot_min_max_list[1])
+
# suggest turn counts
n_1_top = trial.suggest_int('n_p_top', config.n_1_top_min_max_list[0], config.n_1_top_min_max_list[1])
From d310a6a4287aafb3b84f2b575e814925ecb52c36 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Wed, 5 Mar 2025 08:49:17 +0100
Subject: [PATCH 08/15] fix max_height calculation
---
femmt/optimization/ito.py | 45 ++++++++++++++++++++++++---------------
1 file changed, 28 insertions(+), 17 deletions(-)
diff --git a/femmt/optimization/ito.py b/femmt/optimization/ito.py
index bcf67076..51c707c2 100644
--- a/femmt/optimization/ito.py
+++ b/femmt/optimization/ito.py
@@ -332,7 +332,7 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
# calculate winding losses
primary_effective_conductive_cross_section = (
- reluctance_input.litz_dict_1["strands_numbers"] * reluctance_input.litz_dict_1["strand_radii"] ** 2 * np.pi)
+ reluctance_input.litz_dict_1["strands_numbers"] * reluctance_input.litz_dict_1["strand_radii"] ** 2 * np.pi)
primary_effective_conductive_radius = np.sqrt(primary_effective_conductive_cross_section / np.pi)
primary_resistance_top = fr.resistance_solid_wire(
reluctance_input.core_inner_diameter, reluctance_input.window_w, reluctance_input.turns_1_top,
@@ -359,16 +359,16 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
primary_effective_conductive_radius, material='Copper')
secondary_effective_conductive_cross_section = (
- reluctance_input.litz_dict_2["strands_numbers"] * reluctance_input.litz_dict_2["strand_radii"] ** 2 * np.pi)
+ reluctance_input.litz_dict_2["strands_numbers"] * reluctance_input.litz_dict_2["strand_radii"] ** 2 * np.pi)
secondary_effective_conductive_radius = np.sqrt(secondary_effective_conductive_cross_section / np.pi)
secondary_resistance = fr.resistance_solid_wire(
reluctance_input.core_inner_diameter, reluctance_input.window_w, reluctance_input.turns_2_bot, secondary_effective_conductive_radius,
material='Copper')
winding_area_1_top = (
- 2 * reluctance_input.litz_dict_1["conductor_radii"] * \
- (reluctance_input.turns_1_top * 2 * reluctance_input.litz_dict_1["conductor_radii"] + \
- (reluctance_input.turns_1_top - 1) * reluctance_input.insulations.iso_primary_to_primary))
+ 2 * reluctance_input.litz_dict_1["conductor_radii"] * \
+ (reluctance_input.turns_1_top * 2 * reluctance_input.litz_dict_1["conductor_radii"] + \
+ (reluctance_input.turns_1_top - 1) * reluctance_input.insulations.iso_primary_to_primary))
p_winding_1_top = 0
p_winding_1_bot = 0
@@ -383,8 +383,8 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
if number_bot_prim_turns_per_column > reluctance_input.turns_1_bot:
winding_area_1_bot = 2 * reluctance_input.litz_dict_1["conductor_radii"] * \
- (reluctance_input.turns_1_bot * 2 * reluctance_input.litz_dict_1["conductor_radii"] + \
- (reluctance_input.turns_1_bot - 1) * reluctance_input.insulations.iso_primary_to_primary)
+ (reluctance_input.turns_1_bot * 2 * reluctance_input.litz_dict_1["conductor_radii"] + \
+ (reluctance_input.turns_1_bot - 1) * reluctance_input.insulations.iso_primary_to_primary)
proximity_factor_1_bot_inner = fr.calc_proximity_factor_air_gap(
litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=reluctance_input.turns_1_bot,
@@ -395,8 +395,8 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
proximity_factor_1_bot_outer = 0
else:
winding_area_1_bot = (2 * reluctance_input.litz_dict_1["conductor_radii"] * (
- number_bot_prim_turns_per_column * 2 * reluctance_input.litz_dict_1["conductor_radii"] + \
- (number_bot_prim_turns_per_column - 1) * reluctance_input.insulations.iso_primary_to_primary))
+ number_bot_prim_turns_per_column * 2 * reluctance_input.litz_dict_1["conductor_radii"] + \
+ (number_bot_prim_turns_per_column - 1) * reluctance_input.insulations.iso_primary_to_primary))
proximity_factor_1_bot_inner = fr.calc_proximity_factor_air_gap(
litz_wire_name=reluctance_input.litz_wire_name_1, number_turns=number_bot_prim_turns_per_column,
@@ -471,7 +471,7 @@ def objective(trial: optuna.Trial, config: ItoSingleInputConfig, target_and_fixe
core = ff.core_database()[core_name]
core_inner_diameter = core["core_inner_diameter"]
window_w = core["window_w"]
- window_h_half_max = (core["window_h"] - core_inner_diameter) / 2
+ window_h_half_max = (core["window_h"] - core_inner_diameter / 4) / 2
trial.set_user_attr('core_inner_diameter', core_inner_diameter)
trial.set_user_attr('window_w', window_w)
@@ -482,7 +482,6 @@ def objective(trial: optuna.Trial, config: ItoSingleInputConfig, target_and_fixe
config.core_inner_diameter_min_max_list[1])
window_w = trial.suggest_float("window_w", config.window_w_min_max_list[0], config.window_w_min_max_list[1])
-
# suggest turn counts
n_1_top = trial.suggest_int('n_p_top', config.n_1_top_min_max_list[0], config.n_1_top_min_max_list[1])
n_1_bot = trial.suggest_int('n_p_bot', config.n_1_bot_min_max_list[0], config.n_1_bot_min_max_list[1])
@@ -511,20 +510,32 @@ def objective(trial: optuna.Trial, config: ItoSingleInputConfig, target_and_fixe
available_width_bot = window_w - config.insulations.iso_window_bot_core_left - config.insulations.iso_window_bot_core_right
def calc_winding_height(available_width: float, iso_winding_to_winding: float, litz_diameter: float,
- number_turns: float):
-
-
+ number_turns: int) -> float:
+ """
+ Calculate the needed winding height depending on the winding geometry and available width. Takes winding-to-winding insulation into account.
+
+ :param available_width: available width of the winding window in meter
+ :type available_width: float
+ :param iso_winding_to_winding: winding-to-winding insulation in meter
+ :type iso_winding_to_winding: float
+ :param litz_diameter: litz diameter in meter
+ :type litz_diameter: float
+ :param number_turns: number of turns
+ :type number_turns: int
+ :return: needed height of the winding in meter
+ :rtype: float
+ """
number_turns_per_row = int((available_width + iso_winding_to_winding) / (litz_diameter + iso_winding_to_winding))
if number_turns_per_row < 1:
return float('nan'), float('nan')
number_of_rows = np.ceil(number_turns / number_turns_per_row)
- winding_height = number_of_rows * litz_diameter + (number_of_rows -1) * iso_winding_to_winding
+ winding_height = number_of_rows * litz_diameter + (number_of_rows - 1) * iso_winding_to_winding
return winding_height
# height of top core needed
window_h_1_top = calc_winding_height(available_width_top, config.insulations.iso_primary_to_primary, litz_diameter_1, n_1_top)
window_h_2_top = calc_winding_height(available_width_top, config.insulations.iso_secondary_to_secondary, litz_diameter_2, n_2_top)
- window_h_top = (window_h_1_top + window_h_2_top + config.insulations.iso_primary_to_secondary +
+ window_h_top = (window_h_1_top + window_h_2_top + config.insulations.iso_primary_to_secondary + \
config.insulations.iso_window_top_core_top + config.insulations.iso_window_top_core_bot)
if window_h_top > window_h_half_max:
return float('nan'), float('nan')
@@ -532,7 +543,7 @@ def calc_winding_height(available_width: float, iso_winding_to_winding: float, l
# height of bot core needed
window_h_1_bot = calc_winding_height(available_width_bot, config.insulations.iso_primary_to_primary, litz_diameter_1, n_1_bot)
window_h_2_bot = calc_winding_height(available_width_bot, config.insulations.iso_secondary_to_secondary, litz_diameter_2, n_2_bot)
- window_h_bot = (window_h_1_bot + window_h_2_bot + config.insulations.iso_primary_to_secondary +
+ window_h_bot = (window_h_1_bot + window_h_2_bot + config.insulations.iso_primary_to_secondary + \
config.insulations.iso_window_bot_core_top + config.insulations.iso_window_bot_core_bot)
if window_h_bot > window_h_half_max:
return float('nan'), float('nan')
From 268b21b3b11df28683cf16b2d3fc7ac5477f8d8b Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Wed, 5 Mar 2025 16:17:58 +0100
Subject: [PATCH 09/15] implement new winding scheme resistance calculation for
litz wire
---
femmt/functions_reluctance.py | 22 +++++++++++++++++++++-
tests/unit/test_functions_reluctance.py | 20 ++++++++++++++++++++
2 files changed, 41 insertions(+), 1 deletion(-)
create mode 100644 tests/unit/test_functions_reluctance.py
diff --git a/femmt/functions_reluctance.py b/femmt/functions_reluctance.py
index 718a8437..cb3a42d7 100644
--- a/femmt/functions_reluctance.py
+++ b/femmt/functions_reluctance.py
@@ -1116,7 +1116,27 @@ def resistance_litz_wire(core_inner_diameter: float, window_w: float, window_h:
# get the total turn length
total_turn_length = np.sum(np.multiply(windings_per_column, turn_length_per_column))
if scheme == "horizontal_first":
- raise NotImplementedError("'horizontal_first'-scheme not implemented yet.")
+ number_of_columns = (window_w - iso_core_left - iso_core_right + iso_primary_to_primary) / (litz_wire_diameter + iso_primary_to_primary)
+ length_row_per_turn = np.zeros(int(number_of_columns))
+
+ # figure out the turn length per row
+ r_inner = np.array([core_inner_diameter / 2 + iso_core_left])
+ middle_radius_per_column = np.array([])
+ for count, _ in enumerate(length_row_per_turn):
+ middle_radius_per_column = np.append(middle_radius_per_column, r_inner + count * iso_primary_to_primary + (count + 0.5) * litz_wire_diameter)
+ turn_length_per_column = 2 * middle_radius_per_column * np.pi # diameter * pi
+
+ # figure out the windings per row
+ number_of_rows = np.ceil(turns_count / possible_number_turns_per_row)
+ windings_per_row = possible_number_turns_per_row * np.ones(int(number_of_rows))
+ last_row_turns = np.mod(turns_count, possible_number_turns_per_row)
+ windings_per_row[-1] = last_row_turns
+
+ # get the total turn length
+ total_turn_length = 0
+ for windings_in_row in windings_per_row:
+ print(f"{windings_in_row=}")
+ total_turn_length += np.sum(turn_length_per_column[:int(windings_in_row)])
sigma_copper = ff.conductivity_temperature(material, temperature)
# return R = rho * l / A
diff --git a/tests/unit/test_functions_reluctance.py b/tests/unit/test_functions_reluctance.py
new file mode 100644
index 00000000..aafde1f7
--- /dev/null
+++ b/tests/unit/test_functions_reluctance.py
@@ -0,0 +1,20 @@
+"""Unit tests for the functions_reluctance.py module."""
+# 3rd party libraries
+import pytest
+
+# own modules
+import femmt.functions_reluctance as fr
+
+def test_resistance_litz_wire():
+ """Test function for resistance_litz_wire()."""
+ # horizontal winding scheme
+ resistance_horizontal = fr.resistance_litz_wire(
+ 0.01, window_w=0.01, window_h=0.012, turns_count=20, iso_core_top=1e-3, iso_core_bot=1e-3, iso_core_left=1e-3, iso_core_right=1e-3,
+ iso_primary_to_primary=10e-6, temperature=100, scheme="horizontal_first", material="Copper", litz_wire_name="1.1x60x0.1")
+ assert resistance_horizontal == pytest.approx(0.05772275287356322)
+
+ # vertical winding scheme
+ resistance_vertical = fr.resistance_litz_wire(
+ 0.01, window_w=0.01, window_h=0.012, turns_count=20, iso_core_top=1e-3, iso_core_bot=1e-3, iso_core_left=1e-3, iso_core_right=1e-3,
+ iso_primary_to_primary=10e-6, temperature=100, scheme="vertical_first", material="Copper", litz_wire_name="1.1x60x0.1")
+ assert resistance_vertical == pytest.approx(0.043211097701149434)
From eadfe13388a38c46bd5b235aaefe45f2f5b50cbd Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Thu, 6 Mar 2025 13:28:36 +0100
Subject: [PATCH 10/15] error handling
---
femmt/functions_reluctance.py | 2 ++
femmt/optimization/ito.py | 11 +++++++----
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/femmt/functions_reluctance.py b/femmt/functions_reluctance.py
index cb3a42d7..a553a93a 100644
--- a/femmt/functions_reluctance.py
+++ b/femmt/functions_reluctance.py
@@ -1137,6 +1137,8 @@ def resistance_litz_wire(core_inner_diameter: float, window_w: float, window_h:
for windings_in_row in windings_per_row:
print(f"{windings_in_row=}")
total_turn_length += np.sum(turn_length_per_column[:int(windings_in_row)])
+ else:
+ raise ValueError(f"{scheme} not defined. Must be 'horizontal_first' or 'vertical_first'.")
sigma_copper = ff.conductivity_temperature(material, temperature)
# return R = rho * l / A
diff --git a/femmt/optimization/ito.py b/femmt/optimization/ito.py
index 51c707c2..fadd1813 100644
--- a/femmt/optimization/ito.py
+++ b/femmt/optimization/ito.py
@@ -283,8 +283,9 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
r_air_gap_middle_target = r_middle_target - r_core_middle
# calculate air gaps to reach the target parameters
- minimum_air_gap_length = 0.01e-3
+ minimum_air_gap_length = 0.001e-3
maximum_air_gap_length = 2e-3
+ maximum_air_gap_length_middle = 4e-3
l_top_air_gap = optimize.brentq(
fr.r_air_gap_round_inf_sct, minimum_air_gap_length, maximum_air_gap_length,
@@ -298,7 +299,7 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
# Note: ideal calculation (360 degree)
# needs to be translated when it comes to the real setup.
l_middle_air_gap = optimize.brentq(
- fr.r_air_gap_tablet_cylinder_sct, minimum_air_gap_length, maximum_air_gap_length,
+ fr.r_air_gap_tablet_cylinder_sct, minimum_air_gap_length, maximum_air_gap_length_middle,
args=(reluctance_input.core_inner_diameter, reluctance_input.core_inner_diameter/4, reluctance_input.window_w, r_air_gap_middle_target),
full_output=True)[0]
@@ -538,6 +539,7 @@ def calc_winding_height(available_width: float, iso_winding_to_winding: float, l
window_h_top = (window_h_1_top + window_h_2_top + config.insulations.iso_primary_to_secondary + \
config.insulations.iso_window_top_core_top + config.insulations.iso_window_top_core_bot)
if window_h_top > window_h_half_max:
+ logging.warning("window_h_top > window_h_half_max")
return float('nan'), float('nan')
# height of bot core needed
@@ -546,6 +548,7 @@ def calc_winding_height(available_width: float, iso_winding_to_winding: float, l
window_h_bot = (window_h_1_bot + window_h_2_bot + config.insulations.iso_primary_to_secondary + \
config.insulations.iso_window_bot_core_top + config.insulations.iso_window_bot_core_bot)
if window_h_bot > window_h_half_max:
+ logging.warning("window_h_bot > window_h_half_max")
return float('nan'), float('nan')
reluctance_model_intput = ItoReluctanceModelInput(
@@ -588,8 +591,8 @@ def calc_winding_height(available_width: float, iso_winding_to_winding: float, l
)
try:
reluctance_output = IntegratedTransformerOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_intput)
- except ValueError:
- logging.warning("No fitting air gap length")
+ except ValueError as e:
+ print(e)
return float('nan'), float('nan')
# set additional attributes
From 7d842d9bf8264a9d237fb5c1e587d2431f996f56 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Mon, 10 Mar 2025 18:36:36 +0100
Subject: [PATCH 11/15] fix else if
---
femmt/functions_reluctance.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/femmt/functions_reluctance.py b/femmt/functions_reluctance.py
index a553a93a..46a235fb 100644
--- a/femmt/functions_reluctance.py
+++ b/femmt/functions_reluctance.py
@@ -1115,7 +1115,7 @@ def resistance_litz_wire(core_inner_diameter: float, window_w: float, window_h:
# get the total turn length
total_turn_length = np.sum(np.multiply(windings_per_column, turn_length_per_column))
- if scheme == "horizontal_first":
+ elif scheme == "horizontal_first":
number_of_columns = (window_w - iso_core_left - iso_core_right + iso_primary_to_primary) / (litz_wire_diameter + iso_primary_to_primary)
length_row_per_turn = np.zeros(int(number_of_columns))
From e2d982166eb2de66685734e9fa79cf0adb3979f4 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Fri, 16 May 2025 14:11:40 +0200
Subject: [PATCH 12/15] update
---
femmt/optimization/functions_optimization.py | 6 +++---
femmt/optimization/io.py | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/femmt/optimization/functions_optimization.py b/femmt/optimization/functions_optimization.py
index f011371e..2a48b7da 100644
--- a/femmt/optimization/functions_optimization.py
+++ b/femmt/optimization/functions_optimization.py
@@ -213,11 +213,11 @@ def pareto_front_from_df(df: pd.DataFrame) -> pd.DataFrame:
:return: Pandas dataframe with pareto efficient points
:rtype: pd.DataFrame
"""
- x_vec = df["values_0"][~np.isnan(df["values_0"])]
- y_vec = df["values_1"][~np.isnan(df["values_0"])]
+ x_vec = df["values_0"][~pd.isnull(df["values_0"])]
+ y_vec = df["values_1"][~pd.isnull(df["values_0"])]
numpy_zip = np.column_stack((x_vec, y_vec))
pareto_tuple_mask_vec = is_pareto_efficient(numpy_zip)
- pareto_df = df[~np.isnan(df['values_0'])][pareto_tuple_mask_vec]
+ pareto_df = df[~pd.isnull(df['values_0'])][pareto_tuple_mask_vec]
return pareto_df
diff --git a/femmt/optimization/io.py b/femmt/optimization/io.py
index afac8c2e..c7a8c82d 100644
--- a/femmt/optimization/io.py
+++ b/femmt/optimization/io.py
@@ -63,7 +63,7 @@ def filter_df(df: pd.DataFrame, x: str = "values_0", y: str = "values_1", factor
x_pareto_vec = sorted_vector[0]
y_pareto_vec = sorted_vector[1]
- total_losses_list = df[y][~np.isnan(df[y])].to_numpy()
+ total_losses_list = df[y][~pd.isnull(df[y])].to_numpy()
min_total_dc_losses = total_losses_list[np.argmin(total_losses_list)]
loss_offset = factor_min_dc_losses * min_total_dc_losses
@@ -221,8 +221,8 @@ def objective(trial: optuna.Trial, config: InductorOptimizationDTO, target_and_f
)
try:
reluctance_output: ReluctanceModelOutput = InductorOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_input)
- except ValueError:
- logging.warning("bot air gap: No fitting air gap length")
+ except ValueError as e:
+ logging.info("bot air gap: No fitting air gap length")
return float('nan'), float('nan')
trial.set_user_attr('p_winding', reluctance_output.p_winding)
From a4a5e8957a887c186a0c7ba4767286428ac636e3 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Fri, 16 May 2025 14:14:16 +0200
Subject: [PATCH 13/15] fix linting
---
femmt/examples/ito_optuna_example.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/femmt/examples/ito_optuna_example.py b/femmt/examples/ito_optuna_example.py
index 9324750e..6db4b9cf 100644
--- a/femmt/examples/ito_optuna_example.py
+++ b/femmt/examples/ito_optuna_example.py
@@ -83,7 +83,7 @@
)
-##task = 'start_proceed_study'
+# task = 'start_proceed_study'
# task = 'filter_reluctance_model'
# task = 'fem_simulation_from_filtered_reluctance_model_results'
task = 'plot_study_results'
From 1040a3f69f5671ec7a5b1964b0758b18a9957177 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Fri, 16 May 2025 16:08:29 +0200
Subject: [PATCH 14/15] enable pyspelling
---
.gitignore | 3 +
.pyspelling.yml | 37 ++
README.rst | 6 +-
docs/wordlist | 462 ++++++++++++++++++++++++
femmt/__init__.py | 2 +-
femmt/component.py | 16 +-
femmt/examples/__init__.py | 2 +-
femmt/examples/advanced_ct_sto.py | 2 +-
femmt/examples/femmt_benchmark.py | 6 +-
femmt/examples/inductor_optimization.py | 19 +-
femmt/functions.py | 44 +--
femmt/functions_drawing.py | 2 +-
femmt/functions_model.py | 2 +-
femmt/functions_reluctance.py | 10 +-
femmt/mesh.py | 4 +-
femmt/model.py | 4 +-
femmt/optimization/__init__.py | 2 +-
femmt/optimization/io.py | 8 +-
femmt/optimization/ito.py | 4 +-
femmt/optimization/sto.py | 14 +-
femmt/reluctance.py | 12 +-
femmt/thermal/__init__.py | 2 +-
femmt/thermal/thermal_classes.py | 8 +-
tests/unit/test_femmt_functions.py | 4 +-
24 files changed, 580 insertions(+), 95 deletions(-)
create mode 100644 .pyspelling.yml
create mode 100644 docs/wordlist
diff --git a/.gitignore b/.gitignore
index f92e8fde..073ab3a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,3 +77,6 @@ femmt/thermal/solver/PostOperation.pro
femmt/examples/paper_thermal_validation.py
!femmt/examples/example_log.json
femmt/examples/example_results
+
+# pyspelling
+dictionary.dic
diff --git a/.pyspelling.yml b/.pyspelling.yml
new file mode 100644
index 00000000..ef124fce
--- /dev/null
+++ b/.pyspelling.yml
@@ -0,0 +1,37 @@
+matrix:
+- name: Python Source
+ aspell:
+ lang: en
+ d: en_US
+ sources:
+ - femmt/*.py
+ - femmt/*/*.py
+ dictionary:
+ wordlists:
+ - docs/wordlist
+ pipeline:
+ - pyspelling.filters.python:
+ strings: true
+ comments: false
+ ignore_regexp:
+ - '.*\b(TODO|FIXME|NOTE)\b.*'
+- name: markdown
+ sources:
+ - README.rst
+ #- CHANGELOG.md
+ aspell:
+ lang: en
+ d: en_US
+ dictionary:
+ wordlists:
+ - docs/wordlist
+ pipeline:
+ - pyspelling.filters.markdown:
+ - pyspelling.filters.html:
+ comments: false
+ attributes:
+ - title
+ - alt
+ ignores:
+ - code
+ - pre
\ No newline at end of file
diff --git a/README.rst b/README.rst
index 91ddab70..c7724d29 100644
--- a/README.rst
+++ b/README.rst
@@ -39,7 +39,7 @@ Stable features
* Litz wire database
* Core geometry database
* Conductor materials: temperature curves
- * Ferrit materials: permeability / permittivity `material database `__ (datasheets and own measurements)
+ * Ferrite materials: permeability / permittivity `material database `__ (datasheets and own measurements)
* Solver features:
* Implemented using `ONELAB `__
@@ -63,7 +63,7 @@ Stable features
* Transformer equivalent diagrams for 2- and 3-winding transformer
* Optimization:
- * Parallel computing to speed up simulations (no cpu core limitation)
+ * Parallel computing to speed up simulations (no CPU core limitation)
* Examples for Pareto optimization to adapt to your own optimization problem
@@ -124,7 +124,7 @@ Further steps for macOS(ARM)
- Go to https://onelab.info/
- Download the Desktop Version for Windows
- Copy the "conveks.py" and "Onelab.py" files and paste them into the "onelab" folder
-- Go to http://getdp.info/
+- Go to https://getdp.info/
- Download the macOS(ARM) Version
- Open the downloaded folder, navigate to "bin" and copy the "getdp" application file
- Paste the copied file into your "onelab" folder
diff --git a/docs/wordlist b/docs/wordlist
new file mode 100644
index 00000000..e227b54d
--- /dev/null
+++ b/docs/wordlist
@@ -0,0 +1,462 @@
+
+femmt
+FEMMT
+onelab
+Onelab
+py
+https
+windings
+Roadmap
+gmsh
+ferrite
+Ferrite
+datasheets
+FFT
+fft
+Litz
+litz
+axi
+README
+Magnetics
+bool
+param
+params
+iso
+str
+insulations
+json
+txt
+csv
+np
+Numpy
+numpy
+optuna
+sqlite
+mysql
+localhost
+monty
+mydb
+nan
+NSGAIIISampler
+NSGAIISampler
+NSGAII
+NSGAIII
+FemSimulation
+StackedTransformerOptimization
+config
+bool
+sto
+bo
+gc
+StoCtTargetAndFixedParameters
+preconfigured
+Toroidal
+precisions
+MeshAccuracies
+num
+lm
+Tonnenwicklung
+Blockprop
+snm
+NbStepsPerPeriod
+Rr
+TimeStep
+FEH
+Uncomment
+MOGetCircuitProperties
+getb
+getcircuitproperties
+icoil
+mH
+plt
+vals
+xlabel
+ylabel
+zee
+
+SurfaceEdges
+getdp
+macOS
+PostOperationPro
+StoTargetAndFixedParameters
+InductorOptimizationTargetAndFixedParameters
+StoCtSingleInputConfig
+MouseEvent
+xdata
+smallestIndex
+WWR
+ro
+wwr
+ib
+ilm
+il
+ln
+Runtimes
+ItoSingleResultFiles
+gui
+OneDrive
+
+
+PQ
+ndarray
+paderborn
+FEMM
+matlab
+png
+Changelog
+dat
+conveks
+Pre
+inductor
+qVol
+EndIf
+pos
+GmshParsed
+SimpleTable
+Neumann
+GroupPro
+FunctionPro
+hyst
+FrozenTrial
+ItoSingleResultFile
+daxi
+iso
+df
+magnetoquasistatic
+waveforms
+geo
+ThermalConfig
+mariadb
+elif
+rtype
+rms
+dto
+vec
+attrs
+inductances
+conc
+electro
+pkl
+wb
+rb
+DTO
+FemInput
+FemOutput
+DataFrame
+plotly
+html
+pareto
+url
+changelog
+github
+msh
+myGetDP
+filepath
+Filepath
+ToSingleInputConfig
+Dataframe
+dataframe
+dataframes
+PostOperation
+UsingPost
+br
+OnElementsOf
+OnPoint
+ReluctanceModelInput
+ReluctanceModelOutput
+logifle
+ConstraintPro
+ParametersPro
+ItoTargetAndFixedParameters
+ToTargetAndFixedParameters
+StoSingleInputConfig
+stackoverflow
+postgresql
+STO
+WorkingDirectories
+numPoints
+conductivities
+raz
+addboundprop
+drawrectangle
+selectsegment
+setsegmentprop
+logfile
+TimeList
+Rc
+RrSurfaceEdges
+SaturateValues
+ShowTime
+jH
+Magb
+NbTimeStep
+coeff
+PreParameter
+myGmsh
+MagDyn
+qB
+Profil
+mqs
+
+nt
+fourier
+timestep
+Elektrisola
+
+RdYlGn
+ItoSingleInputConfig
+InductorOptimizationDTO
+DTOs
+cls
+io
+MyJSONEncoder
+fmt
+datasource
+ffT
+pytest
+args
+subdirectories
+femm
+ConductorRow
+ConductorType
+RectangularSolid
+RoundLitz
+RoundSolid
+WindingTag
+cond
+conds
+CenterTappedGroup
+ThreeWindingIsolation
+TypeA
+TypeB
+TypeC
+TypeD
+ter
+SweepData
+FileData
+SweepTypes
+Christoffel
+Muelethaler
+Mühlethaler
+Schwarz
+MagneticCircuit
+MagneticComponent
+metres
+CenterLeg
+VirtualWindingWindow
+AirGaps
+vww
+FoilVertical
+enums
+
+Butterworths
+Ferrites
+Ecklebe
+Kolar
+reluctances
+GetDP
+src
+cond
+SaveAll
+MshFileVersio
+SurfaceFaces
+RightCase
+TopRightCase
+TopCase
+BottomRightCase
+rasterization
+Rasterization
+MTB
+LK
+datasheet
+MagNet
+DMR
+AirGaps
+StrayPath
+WindingWindow
+ConductorArrangement
+SquareFullWidth
+AirGapMethod
+AirGapLegPosition
+CenterLeg
+OuterLeg
+StackedPosition
+axisymmetric
+ToEdges
+WindingScheme
+WrapParaType
+datasource
+ConductorRows
+InterleavingSchemesFoilLitz
+CenterTappedInterleavingType
+ConductorStack
+Snelling
+MagneticComponents
+addCurveLoop
+MshFileVersion
+PostView
+BottomCase
+insulationS
+NoSplit
+gapped
+ooo
+CenterOnHorizontalAxis
+CenterOnVerticalAxis
+ConductorPlacingStrategy
+FoilVerticalDistribution
+InterleavedWindingScheme
+HorizontalAndVerticalSplit
+HorizontalSplit
+VerticalSplit
+WindingWindowSplit
+vwws
+ConductorStack
+dataclass
+ki
+steinmetz
+LeftLeg
+RightLeg
+AirGap
+FoilHorizontal
+WindingType
+topologies
+FoilHorizontalDistribution
+InterleavingSchemesFoilLitz
+lh
+imag
+scipy
+AnalyticalCoreData
+Entwurf
+eines
+einstufigen
+Ladewandlers
+auf
+Basis
+eines
+LLC
+Resonanzwandlers
+Keuck
+cyl
+xy
+APEC
+Bifilar
+bifilar
+FoilHorizontal
+HorizontalAlternating
+VerticalAlternating
+VerticalStacked
+fs
+ExcitationMeshingType
+MeshEachFrequency
+MeshOnlyHighestFrequency
+colorfile
+pre
+nd
+ww
+utf
+ECD
+Sqrt
+sqrt
+Lh
+ImposedVoltageNbrStrands
+ImposedVoltage
+HomogenisedModel
+nCoreParts
+NbrStrands
+DirRes
+DirResFields
+DirResVals
+DirResValsCore
+DirStrandCoeff
+ScaleType
+pB
+pI
+nf
+qI
+NeumannBoundary
+Burkart
+npt
+NDArray
+matplotlib
+dir
+kwargs
+dicts
+rect
+si
+nanocristalline
+Enum
+enum
+tolist
+ValueError
+AreaCell
+RUPALIT
+AutomatedDesign
+
+NbrCond
+NbrLayers
+EE
+CurrentList
+NL
+mur
+postquantities
+DirResValsWinding
+DirResCirc
+OptionPos
+CoreEddyCurrentLosses
+dt
+ww
+isolations
+mult
+dest
+cpu
+os
+hpc
+len
+tmp
+xN
+onelab's
+pyfemm
+colormap
+TODO
+sublist
+superordinate
+rotationally
+mWb
+ComponentType
+accuracies
+von
+Dirichlet
+filepaths
+Prolog
+MeshOnlyLowestFrequency
+Logfile
+ohmic
+ColormapNumber
+CustomMax
+CustomMin
+IntervalsType
+NbIso
+RangeType
+ScaleType
+getNumber
+setNumber
+subdirectory
+ToConsole
+ToFile
+th
+sublist
+timemax
+NbSetpsPerPeriod
+NbSteps
+
+
+
+
+
+
+
+
+# logging
+FEMMTLogger
+asctime
+levelname
\ No newline at end of file
diff --git a/femmt/__init__.py b/femmt/__init__.py
index b3d3eb3d..4e5d59f2 100644
--- a/femmt/__init__.py
+++ b/femmt/__init__.py
@@ -1,4 +1,4 @@
-"""Init file for the FEMMT package."""
+"""Initialize file for the FEMMT package."""
from femmt.enumerations import *
from femmt.logparser import *
from femmt.data import *
diff --git a/femmt/component.py b/femmt/component.py
index 89acb668..05c13b2c 100644
--- a/femmt/component.py
+++ b/femmt/component.py
@@ -260,7 +260,7 @@ def thermal_simulation(self, thermal_conductivity_dict: Dict, boundary_temperatu
:type thermal_conductivity_dict: Dict
:param boundary_temperatures_dict: Contains the temperatures at each boundary line
:type boundary_temperatures_dict: Dict
- :param boundary_flags_dict: Sets the boundary type (dirichlet or von neumann) for each boundary line
+ :param boundary_flags_dict: Sets the boundary type (Dirichlet or von Neumann) for each boundary line
:type boundary_flags_dict: Dict
:param case_gap_top: Size of the top case
:type case_gap_top: float
@@ -390,7 +390,7 @@ def onelab_setup(self, is_gui: bool):
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): "))
+ "Enter the path of onelab's parent folder (path to folder which contains getdp, onelab executable files): "))
if os.path.exists(onelab_path):
onelab_path_wrong = False
@@ -552,14 +552,14 @@ def create_model(self, freq: float, skin_mesh_factor: float = 0.5, pre_visualize
:type freq: float
:param skin_mesh_factor: [default to 0.5]
:type skin_mesh_factor: float
- :param pre_visualize_geometry: True for a pre-visualisation (e.g. check your geometry) and after this a
+ :param pre_visualize_geometry: True for a pre-visualization (e.g. check your geometry) and after this a
simulation runs, False for a direct simulation
:type pre_visualize_geometry: bool
:param save_png: True to save a png-figure, false for no figure
:type save_png: bool
:param color_scheme: color file (definition for red, green, blue, ...)
:type color_scheme: Dict
- :param colors_geometry: definition for e.g. core is grey, winding is orange, ...
+ :param colors_geometry: definition for e.g. core is gray, winding is orange, ...
:type colors_geometry: Dict
:param benchmark: Benchmark simulation (stop time). Defaults to False.
:type benchmark: bool
@@ -1514,11 +1514,11 @@ def excitation_sweep(self, frequency_list: List, current_list_list: List, phi_de
:type phi_deg_list_list: List
:param show_last_fem_simulation: shows last simulation in gmsh if set to True
:type show_last_fem_simulation: bool
- :param visualize_before: show genarated mesh before the simulation is run
+ :param visualize_before: show generated mesh before the simulation is run
:type visualize_before: bool
:param color_scheme: colorfile (definition for red, green, blue, ...)
:type color_scheme: Dict
- :param colors_geometry: definition for e.g. core is grey, winding is orange, ...
+ :param colors_geometry: definition for e.g. core is gray, winding is orange, ...
:type colors_geometry: Dict
:param save_png: True to save a .png
:type save_png: bool
@@ -3308,7 +3308,7 @@ def write_electro_magnetic_post_pro(self):
text_file.write(
f"DirStrandCoeff = \"{self.file_data.e_m_strands_coefficients_folder_path.replace(backslash, '/')}/\";\n")
- # Visualisation
+ # visualization
if self.plot_fields == "standard":
text_file.write("Flag_show_standard_fields = 1;\n")
else:
@@ -5269,7 +5269,7 @@ def encode_settings(o) -> Dict:
@staticmethod
def decode_settings_from_log(log_file_path: str, working_directory: str = None, verbosity: Verbosity = Verbosity.Silent):
"""
- Read the given log and returns the magnetic component from th elog.
+ Read the given log and returns the magnetic component from the log.
:param log_file_path: Path to the log file
:type log_file_path: str
diff --git a/femmt/examples/__init__.py b/femmt/examples/__init__.py
index 889e426a..959dcf1f 100644
--- a/femmt/examples/__init__.py
+++ b/femmt/examples/__init__.py
@@ -1 +1 @@
-"""Init-file for the FEMMT examples."""
+"""Initialize the FEMMT examples."""
diff --git a/femmt/examples/advanced_ct_sto.py b/femmt/examples/advanced_ct_sto.py
index 3f2b2961..205b639d 100644
--- a/femmt/examples/advanced_ct_sto.py
+++ b/femmt/examples/advanced_ct_sto.py
@@ -21,7 +21,7 @@
interleaving_type_list=[fmt.CenterTappedInterleavingType.TypeC],
interleaving_scheme_list=[fmt.InterleavingSchemesFoilLitz.ter_3_4_sec_ter_4_3_sec],
-For the optimization, a genetic algorythm (e.g. NSGAII or NSGAIII) is used. The external "optuna"
+For the optimization, a genetic algorithm (e.g. NSGAII or NSGAIII) is used. The external "optuna"
toolbox is used to perform the optimization. The optimizer makes several "trials" to suggest geometry
and material parameters out of the given lists. In case of invalid designs are suggested, the trials
will fail "Trial 1 failed with value (nan, nan, nan, nan)". Others will work fine.
diff --git a/femmt/examples/femmt_benchmark.py b/femmt/examples/femmt_benchmark.py
index 146be85a..3aa74983 100644
--- a/femmt/examples/femmt_benchmark.py
+++ b/femmt/examples/femmt_benchmark.py
@@ -1,6 +1,6 @@
"""Speed up of FEMMT by using parallel processing. File to generate benchmarks of different speed-up techniques.
-It contains multiple benchmarking functions in order to analyse the runtime and the accuracy of the simulation results.
+It contains multiple benchmark functions in order to analyze the runtime and the accuracy of the simulation results.
"""
# Python standard libraries
@@ -382,7 +382,7 @@ def benchmark_rectangular_conductor_offset(working_directory):
axis[1].plot(left_bound_deltas, current_winding_losses, "o")
axis[2].plot(left_bound_deltas, current_execution_times, "o", label=f"Mesh accuracy: {mesh_accuracy}")
- axis[0].set_ylabel("|Self indutance|")
+ axis[0].set_ylabel("|Self inductance|")
axis[0].set_xticks(left_bound_deltas)
axis[0].grid()
@@ -401,7 +401,7 @@ def benchmark_rectangular_conductor_offset(working_directory):
def benchmark_rectangular_conductor(working_directory: str):
"""
- Benchmark mesh accuracies inside a rectangular condutor.
+ Benchmark mesh accuracies inside a rectangular conductor.
:param working_directory: working directory
:type working_directory: str
diff --git a/femmt/examples/inductor_optimization.py b/femmt/examples/inductor_optimization.py
index 43616b93..ff46c947 100644
--- a/femmt/examples/inductor_optimization.py
+++ b/femmt/examples/inductor_optimization.py
@@ -1223,7 +1223,7 @@ def save_automated_design_settings(self):
ad.fem_simulation()
elif task == 'load':
- working_directory = '/home/nikolasf/Dokumente/01_git/30_Python/FEMMT/femmt/examples/example_results/2023-02-28_inductor_optimization_N95_360u_5A'
+ working_directory = ''
# Load design and plot various plots for analysis
inductance, total_loss, total_volume, total_cost, annotation_list, automated_design_settings = load_fem_simulation_results(
@@ -1239,20 +1239,3 @@ def save_automated_design_settings(self):
plot_2d(x_value=plot_data[:, 1], y_value=plot_data[:, 3], z_value=plot_data[:, 2],
x_label='Volume / m\u00b3', y_label='Cost / \u20ac', z_label='Loss / W', title='Volume vs Cost',
annotations=plot_data[:, 4], plot_color='RdYlGn_r', inductance_value=plot_data[:, 0])
-
- # plot_2d(x_value=data_array[:, 1], y_value=data_array[:, 3], z_value=data_array[:, 2], x_label='Volume / m\u00b3',
- # y_label='Cost / \u20ac', z_label='Loss / W',
- # title='Volume vs Cost', plot_color='red')
-
- # plot_2d(x_value=total_volume, y_value=total_loss, x_label='Volume / m\u00b3', y_label='Loss / W',
- # title='Volume vs Loss', annotations=annotation_list, plot_color='red')
- # plot_2d(x_value=total_volume, y_value=total_cost, x_label='Volume / m\u00b3', y_label='Cost / \u20ac',
- # title='Volume vs Cost', annotations=annotation_list, plot_color='red')
- # plot_2d(x_value=total_volume, y_value=inductance, x_label='Volume / m\u00b3', y_label='Inductance / H',
- # title='Volume vs Inductance', annotations=annotation_list, plot_color='red')
- # plot_3d(x_value=total_volume, y_value=total_loss, z_value=total_cost, x_label='Volume / m\u00b3',
- # y_label='Loss / W', z_label='Cost / \u20ac', title='Volume vs Loss vs Cost',
- # annotations=annotation_list, plot_color='red')
-
- # load_from_single_file(working_directory='D:/Personal_data/MS_Paderborn/Sem4/Project_2/2022-11-27_fem_simulation_data',
- # file_name='case4.json')
diff --git a/femmt/functions.py b/femmt/functions.py
index 656c210c..b06de25b 100644
--- a/femmt/functions.py
+++ b/femmt/functions.py
@@ -28,7 +28,7 @@
"orange": (230, 97, 0),
"purple": (129, 61, 156),
"brown": (134, 94, 60),
- "grey": (119, 118, 123),
+ "gray": (119, 118, 123),
"yellow": (245, 194, 17),
"black": (0, 0, 0),
"white": (255, 255, 255)
@@ -37,11 +37,11 @@
colors_geometry_femmt_default = {
"core": "black",
"air_gap": "yellow",
- "winding": ["orange", "brown", "yellow", "green", "red", "black", "grey", "blue", "orange", "purple", "grey",
+ "winding": ["orange", "brown", "yellow", "green", "red", "black", "gray", "blue", "orange", "purple", "gray",
"blue", "orange", "purple"],
"insulation": "blue",
- "potting_inner": "grey",
- "potting_outer": "grey",
+ "potting_inner": "gray",
+ "potting_outer": "gray",
}
colors_ba_jonas = {"blue": (28, 113, 216),
@@ -50,30 +50,30 @@
"orange": (230, 97, 0),
"purple": (129, 61, 156),
"brown": (134, 94, 60),
- "grey": (193, 193, 193),
+ "gray": (193, 193, 193),
"yellow": (255, 171, 6),
"black": (58, 58, 58),
"white": (255, 255, 255),
- "grey_dark": (109, 109, 109),
- "grey_dark_dark": (50, 50, 50)
+ "gray_dark": (109, 109, 109),
+ "gray_dark_dark": (50, 50, 50)
}
colors_geometry_ba_jonas = {
"core": "black",
"air_gap": "yellow",
"winding": ["green", "red", "yellow"],
- "insulation": "grey_dark",
- "potting_inner": "grey",
- "potting_outer": "grey_dark_dark",
+ "insulation": "gray_dark",
+ "potting_inner": "gray",
+ "potting_outer": "gray_dark_dark",
}
colors_geometry_draw_only_lines = {
- "core": "grey_dark",
- "air_gap": "grey_dark",
+ "core": "gray_dark",
+ "air_gap": "gray_dark",
"winding": ["green", "green", "green"],
- "insulation": "grey_dark",
- "potting_inner": "grey_dark",
- "potting_outer": "grey_dark",
+ "insulation": "gray_dark",
+ "potting_inner": "gray_dark",
+ "potting_outer": "gray_dark",
}
@@ -390,7 +390,7 @@ def litz_database() -> Dict:
def wire_material_database() -> Dict[str, WireMaterial]:
"""
- Return wire materials e.g. copper, aluminium in a dictionary.
+ Return wire materials e.g. copper, aluminum in a dictionary.
:return: Dict with materials and conductivity
:rtype: Dict
@@ -406,8 +406,8 @@ def wire_material_database() -> Dict[str, WireMaterial]:
volumetric_mass_density=8920,
)
- wire_material["Aluminium"] = WireMaterial(
- name="aluminium",
+ wire_material["Aluminum"] = WireMaterial(
+ name="aluminum",
sigma=3.7e7,
temperature=25,
temperature_coefficient=3.9e-3,
@@ -786,7 +786,7 @@ def compare_fft_list(input_data_list: list, sample_factor: int = 1000, mode: str
:type mode: str
:param f0: fundamental frequency. Needs to be set in 'rad'- or 'deg'-mode
:type f0: float
- :param sample_factor: samle factor, defaults to 1000
+ :param sample_factor: sample factor, defaults to 1000
:type sample_factor: int
"""
out = []
@@ -985,7 +985,7 @@ def calculate_cylinder_volume(cylinder_diameter: float, cylinder_height: float):
def create_physical_group(dim: int, entities: int, name: str):
"""
- Greate a physical group, what is used inside ONELAB.
+ Create a physical group, what is used inside ONELAB.
:param dim: dim inside onelab
:type dim: int
@@ -1243,11 +1243,11 @@ def find_result_log_file(result_log_folder: str, keyword_list: list, value_min_m
"""
Find a result log-file in a folder with many result-log files.
- Check a dictornary keyword list for matching a certain value (equel, greater equal, smaller equal).
+ Check a dictionary keyword list for matching a certain value (equal, greater equal, smaller equal).
:param result_log_folder: filepath to result-log folder
:type result_log_folder: str
- :param keyword_list: list with hirarchical keywords for dictionary structure, e.g. ["simulation_settings", "core", "core_inner_diameter"]
+ :param keyword_list: list with hierarchical keywords for dictionary structure, e.g. ["simulation_settings", "core", "core_inner_diameter"]
:type keyword_list: list
:param value_min_max: value to check for
:type value_min_max: list
diff --git a/femmt/functions_drawing.py b/femmt/functions_drawing.py
index 1a3ecd2a..3561f82d 100644
--- a/femmt/functions_drawing.py
+++ b/femmt/functions_drawing.py
@@ -195,7 +195,7 @@ def group_center_tapped(primary_number_of_rows: int, secondary_number_of_rows: i
def get_height_of_group(group: CenterTappedGroup) -> float:
"""
- Return the total height of thr conductors and insulation.
+ Return the total height of the conductors and insulation.
:param group: center tapped group
:type group: CenterTappedGroup
diff --git a/femmt/functions_model.py b/femmt/functions_model.py
index 02467a8c..2327d1d9 100644
--- a/femmt/functions_model.py
+++ b/femmt/functions_model.py
@@ -11,7 +11,7 @@ def define_center_tapped_insulation(primary_to_primary: float, secondary_to_seco
:type primary_to_primary: float
:param secondary_to_secondary: Secondary winding to secondary winding insulation in m
:type secondary_to_secondary: float
- :param primary_to_secondary: Primary winding to secondary winding insulaiton in m
+ :param primary_to_secondary: Primary winding to secondary winding insulation in m
:type primary_to_secondary: float
:return:
"""
diff --git a/femmt/functions_reluctance.py b/femmt/functions_reluctance.py
index 46a235fb..8e1b974e 100644
--- a/femmt/functions_reluctance.py
+++ b/femmt/functions_reluctance.py
@@ -1023,7 +1023,7 @@ def resistance_solid_wire(core_inner_diameter: float, window_w: float, turns_cou
:type turns_count: int
:param conductor_radius: conductor radius
:type conductor_radius: float
- :param material: Material, e.g. "Copper" or "Aluminium"
+ :param material: Material, e.g. "Copper" or "Aluminum"
:type material: str
:param temperature: temperature in °C
:type temperature: float
@@ -1061,7 +1061,7 @@ def resistance_litz_wire(core_inner_diameter: float, window_w: float, window_h:
:type window_w: float
:param turns_count: number of turns
:type turns_count: int
- :param material: Material, e.g. "Copper" or "Aluminium"
+ :param material: Material, e.g. "Copper" or "Aluminum"
:type material: str
:param temperature: temperature in °C
:type temperature: float
@@ -1182,7 +1182,7 @@ def calc_skin_depth(frequency: float, material_name: str = "Copper", temperature
:param frequency: Frequency in Hz
:type frequency: float
- :param material_name: material name, e.g. 'Copper' or 'Aluminium'
+ :param material_name: material name, e.g. 'Copper' or 'Aluminum'
:type material_name: str
:param temperature: Temperature in °C
:type temperature: float
@@ -1211,7 +1211,7 @@ def calc_proximity_factor(litz_wire_name: str, number_turns: int, window_h: floa
:type iso_core_bot: float
:param frequency: Frequency in Hz
:type frequency: float
- :param litz_wire_material_name: material name, e.g. 'Copper' or 'Aluminium'
+ :param litz_wire_material_name: material name, e.g. 'Copper' or 'Aluminum'
:type litz_wire_material_name: str
:param temperature: Temperature in °C
:type temperature: float
@@ -1240,7 +1240,7 @@ def calc_proximity_factor_air_gap(litz_wire_name: str, number_turns: int, r_1: f
:type winding_area: float
:param frequency: Frequency in Hz
:type frequency: float
- :param litz_wire_material_name: material name, e.g. 'Copper' or 'Aluminium'
+ :param litz_wire_material_name: material name, e.g. 'Copper' or 'Aluminum'
:type litz_wire_material_name: str
:param temperature: Temperature in °C
:type temperature: float
diff --git a/femmt/mesh.py b/femmt/mesh.py
index c695383c..c368d23c 100644
--- a/femmt/mesh.py
+++ b/femmt/mesh.py
@@ -1142,7 +1142,7 @@ def generate_hybrid_mesh(self, color_scheme: Dict = ff.colors_femmt_default, col
visualize_before: bool = False,
save_png: bool = True, refine=0, alternative_error=0) -> None:
"""
- Generate the hybird mesh.
+ Generate the hybrid mesh.
- interaction with gmsh
- mesh generation
@@ -1841,7 +1841,7 @@ def rasterize_winding_window(left_bound, right_bound, bot_bound, top_bound):
valid = False
break
else:
- print(f"Winding window rasterization skipped becuase ConductorType {winding.conductor_type.name} is not supported.")
+ print(f"Winding window rasterization skipped because ConductorType {winding.conductor_type.name} is not supported.")
return
if not valid:
diff --git a/femmt/model.py b/femmt/model.py
index 9ae74439..a17eb686 100644
--- a/femmt/model.py
+++ b/femmt/model.py
@@ -185,7 +185,7 @@ class Core:
"""
Creates the core base for the model.
- # TODO More documentation and get rid of double initializations
+ # TODO More documentation and get rid of double initialization
frequency = 0: mu_r_abs only used if non_linear == False
frequency > 0: mu_r_abs is used
"""
@@ -1347,7 +1347,7 @@ def flexible_split(self, split_distance: float = 0,
def split_with_stack(self, stack: ConductorStack):
"""
- Split the winding window according to a ConductorStack dataclass.
+ Split the winding window according to a ConductorStack data class.
:param stack:
:return:
diff --git a/femmt/optimization/__init__.py b/femmt/optimization/__init__.py
index cba0cf0a..ae52cabd 100644
--- a/femmt/optimization/__init__.py
+++ b/femmt/optimization/__init__.py
@@ -1,4 +1,4 @@
-"""Init file for the optimization section."""
+"""Initialize file for the optimization section."""
from femmt.optimization.ito import *
from femmt.optimization.functions_optimization import *
from femmt.optimization.ito_dtos import *
diff --git a/femmt/optimization/io.py b/femmt/optimization/io.py
index c7a8c82d..477a9cea 100644
--- a/femmt/optimization/io.py
+++ b/femmt/optimization/io.py
@@ -509,7 +509,7 @@ def df_plot_pareto_front(*dataframes: list[pd.DataFrame], label_list: list[str],
:type interactive: bool
"""
if color_list is None:
- color_list = ['red', 'blue', 'green', 'grey']
+ color_list = ['red', 'blue', 'green', 'gray']
for count, df in enumerate(dataframes):
# color_list was before list(ff.colors_femmt_default.keys())
df['color_r'], df['color_g'], df['color_b'] = ff.colors_femmt_default[color_list[count]]
@@ -604,7 +604,7 @@ def fem_simulations_from_reluctance_df(reluctance_df: pd.DataFrame, config: Indu
:type reluctance_df: pandas.DataFrame
:param config: Configuration for the optimization of the transformer
:type config: InductorOptimizationDTO
- :param show_visual_outputs: Ture to show visual outputs like the geometry
+ :param show_visual_outputs: True to show visual outputs like the geometry
:type show_visual_outputs: bool
:param process_number: Process number for parallel simulations on multiple cpu cores
:type process_number: int
@@ -726,7 +726,7 @@ def fem_vs_reluctance_pareto(df: pd.DataFrame) -> None:
fig, ax = plt.subplots()
legend_list = []
plt.legend(handles=legend_list)
- plt.scatter(df["values_0"], df["values_1"], s=10, label='Relucatance Model') # c=color_array
+ plt.scatter(df["values_0"], df["values_1"], s=10, label='Reluctance Model') # c=color_array
df["fem_total_loss"] = df["fem_core"] + df["fem_p_loss_winding"]
plt.scatter(df["values_0"], df["fem_total_loss"], s=10, label='FEM simulation') # c=color_array
plt.scatter(df["values_0"], df["combined_losses"], s=10, label="combined_losses")
@@ -862,7 +862,7 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: List, inductor_
:type inductor_config_filepath: str
:param process_number: process number to run the simulation on
:type process_number: int
- :param print_derivations: True to print derivation from FEM simulaton to reluctance model
+ :param print_derivations: True to print derivation from FEM simulation to reluctance model
:type print_derivations: bool
:return: volume, loss
:rtype: tuple
diff --git a/femmt/optimization/ito.py b/femmt/optimization/ito.py
index fadd1813..9aa94297 100644
--- a/femmt/optimization/ito.py
+++ b/femmt/optimization/ito.py
@@ -453,7 +453,7 @@ def single_reluctance_model_simulation(reluctance_input: ItoReluctanceModelInput
@staticmethod
def objective(trial: optuna.Trial, config: ItoSingleInputConfig, target_and_fixed_parameters: ItoTargetAndFixedParameters):
"""
- Objective funktion to optimize. Uses reluctance model calculation.
+ Objective function to optimize. Uses reluctance model calculation.
Once core_name_list is not None, the objective function uses fixed core sizes. Cores are picked from the core_database().
Otherwise, core_inner_diameter_min_max_list, window_w_min_max_list and window_h_bot_min_max_list are used.
@@ -837,7 +837,7 @@ def df_plot_pareto_front(*dataframes: pd.DataFrame, label_list: list[str], color
:type interactive: bool
"""
if color_list is None:
- color_list = ['red', 'blue', 'green', 'grey']
+ color_list = ['red', 'blue', 'green', 'gray']
for count, df in enumerate(dataframes):
# color_list was before list(ff.colors_femmt_default.keys())
df['color_r'], df['color_g'], df['color_b'] = ff.colors_femmt_default[color_list[count]]
diff --git a/femmt/optimization/sto.py b/femmt/optimization/sto.py
index 16c09f62..57f3d8f9 100644
--- a/femmt/optimization/sto.py
+++ b/femmt/optimization/sto.py
@@ -131,7 +131,7 @@ def calculate_fix_parameters(config: StoSingleInputConfig) -> StoTargetAndFixedP
@staticmethod
def objective(trial: optuna.Trial, config: StoSingleInputConfig, target_and_fixed_parameters: StoTargetAndFixedParameters):
"""
- Objective funktion to optimize. Uses reluctance model calculation.
+ Objective function to optimize. Uses reluctance model calculation.
Once core_name_list is not None, the objective function uses fixed core sizes. Cores are picked from the core_database().
Otherwise, core_inner_diameter_min_max_list, window_w_min_max_list and window_h_bot_min_max_list are used.
@@ -643,7 +643,7 @@ def df_plot_pareto_front(*dataframes: list[pd.DataFrame], label_list: list[str],
:type interactive: bool
"""
if color_list is None:
- color_list = ['red', 'blue', 'green', 'grey']
+ color_list = ['red', 'blue', 'green', 'gray']
for count, df in enumerate(dataframes):
# color_list was before list(ff.colors_femmt_default.keys())
df['color_r'], df['color_g'], df['color_b'] = ff.colors_femmt_default[color_list[count]]
@@ -783,13 +783,13 @@ def fem_simulations_from_reluctance_df(reluctance_df: pd.DataFrame, config: StoS
"""
Perform FEM simulations from a given Pandas dataframe. The dataframe is from the reluctance model results.
- :param reluctance_df: Pandas dataframe containing relults from the relutance model
+ :param reluctance_df: Pandas dataframe containing results from the reluctance model
:type reluctance_df: pandas.DataFrame
:param config: Configuration for the optimization of the transformer
:type config: StoSingleInputConfig
- :param show_visual_outputs: Ture to show visual outputs like the geometry
+ :param show_visual_outputs: True to show visual outputs like the geometry
:type show_visual_outputs: bool
- :param process_number: Process number for parallel simulations on multiple cpu cores
+ :param process_number: Process number for parallel simulations on multiple CPU cores
:type process_number: int
"""
target_and_fix_parameters = StackedTransformerOptimization.ReluctanceModel.calculate_fix_parameters(config)
@@ -1055,9 +1055,9 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: List, stacked_t
:type stacked_transformer_config_filepath: str
:param process_number: process number to run the simulation on
:type process_number: int
- :param show_visual_outputs: True to show visual outpus (geometries)
+ :param show_visual_outputs: True to show visual outputs (geometries)
:type show_visual_outputs: bool
- :param print_derivations: True to print derivation from FEM simulaton to reluctance model
+ :param print_derivations: True to print derivation from FEM simulation to reluctance model
:type print_derivations: bool
"""
for index, _ in df_geometry.iterrows():
diff --git a/femmt/reluctance.py b/femmt/reluctance.py
index 6220554a..e82b12a4 100644
--- a/femmt/reluctance.py
+++ b/femmt/reluctance.py
@@ -68,7 +68,7 @@ def plot_r_basic():
(using Schwarz-Christoffel transformation) at page no. 35.
It plots the Reluctance formula with respect to its variables (h/l and w/l).
- It is an independent function and has been used to analyse the expression and its limitation.
+ It is an independent function and has been used to analyze the expression and its limitation.
"""
# # Uncomment this section of code if Reluctance change with respect to h/l is desired
# width = 100
@@ -217,8 +217,8 @@ def create_data_matrix(core_inner_diameter: list, window_h: list, window_w: list
:param mu_rel: Relative permeability of the core [in F/m]
:type mu_rel: list
:param mult_air_gap_type: Two types of equally distributed air-gaps (used only for air-gaps more than 1)
- Type 1: Equally distributed air-gaps including corner air-gaps (eg: air-gaps-position = [0, 50, 100] for 3 air-gaps)
- Type 2: Equally distributed air-gaps excluding corner air-gaps (eg: air-gaps-position = [25, 50, 75] for 3 air-gaps)
+ Type 1: Equally distributed air-gaps including corner air-gaps (e.g.: air-gaps-position = [0, 50, 100] for 3 air-gaps)
+ Type 2: Equally distributed air-gaps excluding corner air-gaps (e.g.: air-gaps-position = [25, 50, 75] for 3 air-gaps)
:type mult_air_gap_type: list
"""
# Structure: data_matrix = [core_inner_diameter, window_h, window_w, mu_rel, no_of_turns, n_air_gaps, air_gap_h,
@@ -284,7 +284,7 @@ def __init__(self, core_inner_diameter: list, window_h: list, window_w: list, no
air_gap_h: list, air_gap_position: list, mu_r_abs: list, mult_air_gap_type: list = None,
air_gap_method: str = 'Percent', component_type: str = 'inductor', sim_type: str = 'single'):
"""
- Init the MagneticCircuit class.
+ Initialize the MagneticCircuit class.
:param core_inner_diameter: Diameter of center leg of the core in meter
:type core_inner_diameter: list
@@ -303,8 +303,8 @@ def __init__(self, core_inner_diameter: list, window_h: list, window_w: list, no
:param mu_r_abs: Relative permeability of the core [in F/m]
:type mu_r_abs: list
:param mult_air_gap_type: Two types of equally distributed air-gaps (used only for air-gaps more than 1)
- Type 1: Equally distributed air-gaps including corner air-gaps (eg: air-gaps-position = [0, 50, 100] for 3 air-gaps)
- Type 2: Equally distributed air-gaps excluding corner air-gaps (eg: air-gaps-position = [25, 50, 75] for 3 air-gaps)
+ Type 1: Equally distributed air-gaps including corner air-gaps (e.g.: air-gaps-position = [0, 50, 100] for 3 air-gaps)
+ Type 2: Equally distributed air-gaps excluding corner air-gaps (e.g.: air-gaps-position = [25, 50, 75] for 3 air-gaps)
:type mult_air_gap_type: list
:param air_gap_h: Air-gap height [in meter]
:param air_gap_method: Input method of air gap position ( either in 'Percent', 'Center' or 'Manually')
diff --git a/femmt/thermal/__init__.py b/femmt/thermal/__init__.py
index 80610457..afb1141c 100644
--- a/femmt/thermal/__init__.py
+++ b/femmt/thermal/__init__.py
@@ -1,4 +1,4 @@
-"""Init file for the thermal section."""
+"""Initialize file for the thermal section."""
from femmt.thermal.thermal_classes import *
from femmt.thermal.thermal_functions import *
from femmt.thermal.thermal_simulation import *
diff --git a/femmt/thermal/thermal_classes.py b/femmt/thermal/thermal_classes.py
index c14e1fff..43d43136 100644
--- a/femmt/thermal/thermal_classes.py
+++ b/femmt/thermal/thermal_classes.py
@@ -141,17 +141,17 @@ def __init__(self):
self.q_vol = {}
@staticmethod
- def dict_as_function_str(name: str, dct: Dict):
+ def dict_as_function_str(name: str, dictionary: Dict):
"""
Write dictionary as a string.
:param name: name
:type name: str
- :param dct: Dictionary
- :type dct: Dict
+ :param dictionary: Dictionary
+ :type dictionary: Dict
"""
dict_as_str = ""
- for key, value in dct.items():
+ for key, value in dictionary.items():
dict_as_str += f"\t{name}[{key}] = {value};\n"
return dict_as_str
diff --git a/tests/unit/test_femmt_functions.py b/tests/unit/test_femmt_functions.py
index da622465..e4e04c17 100644
--- a/tests/unit/test_femmt_functions.py
+++ b/tests/unit/test_femmt_functions.py
@@ -162,10 +162,10 @@ def test_conductivity_temperature():
temperature = 100
copper_sigma_100_degree_calculated = femmt.conductivity_temperature("Copper", temperature)
- aluminium_sigma_100_degree_calculated = femmt.conductivity_temperature("Aluminium", temperature)
+ aluminum_sigma_100_degree_calculated = femmt.conductivity_temperature("Aluminum", temperature)
assert copper_sigma_100_degree_calculated == pytest.approx(4.4874e7, rel=1e-3)
- assert aluminium_sigma_100_degree_calculated == pytest.approx(2.8627e7, rel=1e-3)
+ assert aluminum_sigma_100_degree_calculated == pytest.approx(2.8627e7, rel=1e-3)
def test_skin_depth():
"""Unittest for calculating the skin depth."""
From 130ff3a212de9c3939ad5e832540c51ea8437a83 Mon Sep 17 00:00:00 2001
From: gituser789 <62549000+gituser789@users.noreply.github.com>
Date: Fri, 16 May 2025 16:09:10 +0200
Subject: [PATCH 15/15] enable pyspelling
---
.github/workflows/main.yml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index bf0432a5..c0e75520 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -36,6 +36,12 @@ jobs:
pip install pylint
pylint $(git ls-files '*.py')
+ - name: Install packages for spell check and perform spell check
+ run: |
+ sudo apt install aspell-en
+ pip install pyspelling
+ pyspelling
+ echo finished spell checking
- name: install femmt package
run: |