diff --git a/femmt/optimization/sto.py b/femmt/optimization/sto.py index 3c846d56..b8ddcd10 100644 --- a/femmt/optimization/sto.py +++ b/femmt/optimization/sto.py @@ -116,6 +116,11 @@ def objective(trial, config: StoSingleInputConfig, :type show_geometries: bool :param process_number: process number. Important for parallel computing, each simulation works in a separate folder :type process_number: int + :return: returns volume, loss and absolute error of inductances in % + if number_objectives == 3: + total_volume, total_loss, 100 * (abs(difference_l_h / config.l_h_target) + abs(difference_l_s12 / config.l_s12_target)) + elif number_objectives == 4: + return total_volume, total_loss, 100 * abs(difference_l_h), 100 * abs(difference_l_s12) """ # suggest core geometry 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]) @@ -282,10 +287,10 @@ def objective(trial, config: StoSingleInputConfig, # norm_total_loss, norm_difference_l_h, norm_difference_l_s12 = total_loss/10, abs(difference_l_h/config.l_h_target), abs(difference_l_s12/config.l_s12_target) # return norm_total_loss, norm_difference_l_h, norm_difference_l_s12 if number_objectives == 3: - return total_volume, total_loss, abs(difference_l_h / config.l_h_target) + abs( - difference_l_s12 / config.l_s12_target) + return total_volume, total_loss, 100 * (abs(difference_l_h / config.l_h_target) + abs( + difference_l_s12 / config.l_s12_target)) elif number_objectives == 4: - return total_volume, total_loss, abs(difference_l_h), abs(difference_l_s12) + return total_volume, total_loss, 100 * abs(difference_l_h), 100 * abs(difference_l_s12) except Exception as e: print(e) @@ -524,7 +529,7 @@ def show_study_results(study_name: str, config: StoSingleInputConfig, @staticmethod def show_study_results3(study_name: str, config: StoSingleInputConfig, - error_difference_inductance_sum, storage: str = 'sqlite') -> None: + error_difference_inductance_sum_percent, storage: str = 'sqlite') -> None: """ Show the results of a study. @@ -534,8 +539,8 @@ def show_study_results3(study_name: str, config: StoSingleInputConfig, :type study_name: str :param config: Integrated transformer configuration file :type config: ItoSingleInputConfig - :param error_difference_inductance_sum: e.g. 0.05 for 5% - :type error_difference_inductance_sum: float + :param error_difference_inductance_sum_percent: |err(L_s12) + err(L_h)| in % + :type error_difference_inductance_sum_percent: float :param storage: storage, e.g. 'sqlite' or path to postgresql-database :type storage: str @@ -552,16 +557,16 @@ def show_study_results3(study_name: str, config: StoSingleInputConfig, time_stop = datetime.datetime.now() print(f"Finished loading study {study_name} from database in time: {time_stop - time_start}") - print(f"{error_difference_inductance_sum = }") + print(f"{error_difference_inductance_sum_percent = }") time_start = datetime.datetime.now() print(f"start generating Pareto front....") - fig = optuna.visualization.plot_pareto_front(study, targets=lambda t: (t.values[0] if error_difference_inductance_sum > t.values[2] else None, t.values[1] if error_difference_inductance_sum > t.values[2] else None), target_names=["volume in m³", "loss in W"]) - fig.update_layout(title=f"{study_name}: Filtering {error_difference_inductance_sum * 100} % of |err(Ls_12)| + |err(L_h)|") + fig = optuna.visualization.plot_pareto_front(study, targets=lambda t: (t.values[0] if error_difference_inductance_sum_percent > t.values[2] else None, t.values[1] if error_difference_inductance_sum_percent > t.values[2] else None), target_names=["volume in m³", "loss in W"]) + fig.update_layout(title=f"{study_name}: Filtering {error_difference_inductance_sum_percent} % of |err(Ls_12)| + |err(L_h)|") time_stop = datetime.datetime.now() print(f"Finished generating Pareto front in time: {time_stop - time_start}") - fig.write_html(f"{config.working_directory}/{study_name}_error_diff_{error_difference_inductance_sum}_{datetime.datetime.now().isoformat(timespec='minutes')}.html") + fig.write_html(f"{config.working_directory}/{study_name}_error_diff_{error_difference_inductance_sum_percent}%_{datetime.datetime.now().isoformat(timespec='minutes')}.html") fig.show() @staticmethod @@ -906,18 +911,18 @@ def thermal_simulation_from_geo(geo, thermal_config: ThermalConfig, flag_insulat colors_geometry=femmt.colors_geometry_ba_jonas, flag_insulation=flag_insulation) @staticmethod - def df_plot_pareto_front(df: pd.DataFrame, sum_inductance_error: float): + def df_plot_pareto_front(df: pd.DataFrame, sum_inductance_error_percent: float): """ Plots an interactive Pareto diagram (losses vs. volume) to select the transformers to re-simulate. :param df: Dataframe, generated from an optuna study (exported by optuna) :type df: pd.Dataframe - :param sum_inductance_error: maximum allowed error of |error(L_s12)| + |error(L_h)| - :type sum_inductance_error: float + :param sum_inductance_error_percent: maximum allowed error of |error(L_s12)| + |error(L_h)| in % + :type sum_inductance_error_percent: float """ print(df.head()) - df_pareto = df[df["values_2"] < sum_inductance_error] + df_pareto = df[df["values_2"] < sum_inductance_error_percent] names = df_pareto["number"].to_numpy() fig, ax = plt.subplots() @@ -952,7 +957,7 @@ def hover(event): plt.xlabel('Volume in m³') plt.ylabel('Losses in W') - plt.title(f"|error(L_s12)| + |error(L_h)| < {sum_inductance_error} %") + plt.title(f"|error(L_s12)| + |error(L_h)| < {sum_inductance_error_percent} %") plt.grid() plt.show() diff --git a/tests/integration/fixtures/results/thermal_transformer_5_windings.json b/tests/integration/fixtures/results/thermal_transformer_5_windings.json index af7edf09..4c643c0f 100644 --- a/tests/integration/fixtures/results/thermal_transformer_5_windings.json +++ b/tests/integration/fixtures/results/thermal_transformer_5_windings.json @@ -1,210 +1,215 @@ { "core_parts": { "core_part_1": { - "min": 22.92825004550824, - "max": 43.27512987849097, - "mean": 34.60804139121339 + "min": 22.95433725837616, + "max": 43.89662651821714, + "mean": 34.881033758318985 }, "total": { - "min": 22.92825004550824, - "max": 43.27512987849097, - "mean": 34.60804139121339 + "min": 22.95433725837616, + "max": 43.89662651821714, + "mean": 34.881033758318985 } }, "windings": { "winding_0_0": { - "min": 2464.622987622317, - "max": 2464.625267910403, - "mean": 2464.624166582381 + "min": 32.46969088518171, + "max": 32.47228956383554, + "mean": 32.471278101733795 }, "winding_0_1": { - "min": 2470.371956026039, - "max": 2470.374532744722, - "mean": 2470.373158084463 + "min": 36.5775538369669, + "max": 36.57901602206849, + "mean": 36.57834066944631 }, "winding_0_2": { - "min": 2477.248374770164, - "max": 2477.251139602545, - "mean": 2477.2497544339285 + "min": 39.51619974051405, + "max": 39.51731053236967, + "mean": 39.516780843014345 }, "winding_0_3": { - "min": 2483.905606963324, - "max": 2483.908037920709, - "mean": 2483.906888560786 + "min": 41.74011979248609, + "max": 41.74135137029185, + "mean": 41.74079942493729 }, "winding_0_4": { - "min": 2489.218620076731, - "max": 2489.220336221918, - "mean": 2489.219589118021 + "min": 43.43350684920263, + "max": 43.43496031767983, + "mean": 43.43431283987183 }, "winding_0_5": { - "min": 2492.39300449571, - "max": 2492.393823717064, - "mean": 2492.393522147772 + "min": 44.68179623459834, + "max": 44.68337132301919, + "mean": 44.68268021154097 }, "winding_0_6": { - "min": 2492.691452686723, - "max": 2492.692445454184, - "mean": 2492.6920301767764 + "min": 45.48009496592619, + "max": 45.48170770433286, + "mean": 45.48100554030618 }, "winding_0_7": { - "min": 2488.976319010141, - "max": 2488.978470883644, - "mean": 2488.9775431427506 + "min": 45.63856152963693, + "max": 45.63962312265074, + "mean": 45.63925092352275 }, "winding_0_8": { - "min": 2482.223762850147, - "max": 2482.227091591252, - "mean": 2482.225566952801 + "min": 45.75380277290472, + "max": 45.75485856688088, + "mean": 45.754462591788766 }, "winding_0_9": { - "min": 2472.741819118157, - "max": 2472.746150525667, - "mean": 2472.7440990433806 + "min": 45.61736126311623, + "max": 45.61837180835362, + "mean": 45.6179734743146 }, "winding_0_10": { - "min": 2461.001969326565, - "max": 2461.007084814581, - "mean": 2461.0046119740814 + "min": 45.2328782987868, + "max": 45.23378069012698, + "mean": 45.23341331272183 }, "winding_0_11": { - "min": 2447.702835199451, - "max": 2447.708361365698, - "mean": 2447.7056138058474 + "min": 44.55687818695807, + "max": 44.55764094993858, + "mean": 44.557314793118834 }, "winding_0_12": { - "min": 2433.963551025305, - "max": 2433.96898851516, - "mean": 2433.966194290475 + "min": 43.53204889650706, + "max": 43.53263648297864, + "mean": 43.53235522896999 }, "winding_0_13": { - "min": 2421.411361748649, - "max": 2421.415935241971, - "mean": 2421.4134703125815 + "min": 42.12037292746778, + "max": 42.12107785647889, + "mean": 42.12074040030956 }, "winding_0_14": { - "min": 2411.658586503392, - "max": 2411.661596644385, - "mean": 2411.6597593717233 + "min": 40.24862692846933, + "max": 40.24946910894522, + "mean": 40.24904215657611 }, "winding_0_15": { - "min": 2462.589952915303, - "max": 2462.592362272446, - "mean": 2462.591343167411 + "min": 31.33131603269113, + "max": 31.3342286105505, + "mean": 31.332980326017747 }, "winding_0_16": { - "min": 2468.524174438603, - "max": 2468.527140408961, - "mean": 2468.5255320946685 + "min": 36.97510546533365, + "max": 36.97711201957079, + "mean": 36.97618895530999 }, "winding_0_17": { - "min": 2476.667320604713, - "max": 2476.670672492523, - "mean": 2476.6690209640046 + "min": 41.10981353812058, + "max": 41.11131874633569, + "mean": 41.11060441036244 }, "winding_0_18": { - "min": 2484.309530469007, - "max": 2484.312419414024, - "mean": 2484.311058369641 + "min": 44.08917239724664, + "max": 44.09029784074088, + "mean": 44.08975083369402 }, "winding_0_19": { - "min": 2490.251716424458, - "max": 2490.253713351461, - "mean": 2490.252824340566 + "min": 46.22191675862916, + "max": 46.22290486519357, + "mean": 46.222444184047326 }, "winding_0_20": { - "min": 2493.919383707341, - "max": 2493.920496235528, - "mean": 2493.9200028737614 + "min": 47.68187375095892, + "max": 47.68283899879056, + "mean": 47.68240871473582 }, "winding_0_21": { - "min": 2494.9620626245, - "max": 2494.963101824575, - "mean": 2494.9625286071987 + "min": 48.50807546332715, + "max": 48.5090644104509, + "mean": 48.50861849512869 }, "winding_1_0": { - "min": 2449.331542327825, - "max": 2449.340423543304, - "mean": 2449.3372504112526 + "min": 31.7560262724195, + "max": 31.76085077765494, + "mean": 31.758764977802375 }, "winding_1_1": { - "min": 2463.198764014782, - "max": 2463.206425958142, - "mean": 2463.2024048091594 + "min": 39.3761325820728, + "max": 39.37935821642702, + "mean": 39.377740103981374 }, "winding_1_2": { - "min": 2479.628037600093, - "max": 2479.634536202971, - "mean": 2479.631518469704 + "min": 45.26577009223739, + "max": 45.26795501715243, + "mean": 45.26689774417915 }, "winding_1_3": { - "min": 2491.016577494271, - "max": 2491.020736376096, - "mean": 2491.0188580729964 + "min": 48.79634625041055, + "max": 48.79762282455627, + "mean": 48.796968166708666 }, "winding_1_4": { - "min": 2497.55133211461, - "max": 2497.553355853142, - "mean": 2497.552520478547 + "min": 50.73675682742959, + "max": 50.73766944432063, + "mean": 50.73730938292935 }, "winding_1_5": { - "min": 2499.637235344508, - "max": 2499.637680009987, - "mean": 2499.637530356642 + "min": 51.39153990347307, + "max": 51.39233900227744, + "mean": 51.39214310201355 }, "winding_2_0": { - "min": 2492.744284306458, - "max": 2492.745644665979, - "mean": 2492.7451399813813 + "min": 55.61754251676955, + "max": 55.61838609459338, + "mean": 55.618034926590575 }, "winding_2_1": { - "min": 2486.653296707275, - "max": 2486.656380397912, - "mean": 2486.6549576485745 + "min": 56.6392961701875, + "max": 56.63990987555569, + "mean": 56.63974287868686 }, "winding_2_2": { - "min": 2476.359005538744, - "max": 2476.363658407392, - "mean": 2476.3614666315134 + "min": 56.60291683313284, + "max": 56.60352999026215, + "mean": 56.60335849232446 }, "winding_2_3": { - "min": 2462.028992409631, - "max": 2462.035177366829, - "mean": 2462.0321954857895 + "min": 55.54399805170948, + "max": 55.54479542365297, + "mean": 55.54444303952271 }, "winding_2_4": { - "min": 2443.548306836435, - "max": 2443.556103820271, - "mean": 2443.5523283104512 + "min": 53.28001078696334, + "max": 53.2811854459856, + "mean": 53.28059655397327 }, "winding_2_5": { - "min": 2420.648276806302, - "max": 2420.658056319677, - "mean": 2420.653384911554 + "min": 49.3243606000016, + "max": 49.3264268971334, + "mean": 49.32547154152814 }, "winding_3_0": { - "min": 2396.816412593339, - "max": 2396.827067049417, - "mean": 2396.8212290000383 + "min": 43.45287651978335, + "max": 43.45500318562692, + "mean": 43.453681749016724 }, "winding_4_0": { - "min": 2413.164399948718, - "max": 2413.180792950681, - "mean": 2413.1742922436774 + "min": 27.40032878084305, + "max": 27.4019323331449, + "mean": 27.401238193999237 }, "winding_4_1": { - "min": 2436.567908962225, - "max": 2436.575005521358, - "mean": 2436.571856769563 + "min": 30.23908770222705, + "max": 30.24077981904784, + "mean": 30.2397760835027 }, "total": { - "min": 2396.816412593339, - "max": 2499.637680009987, - "mean": 2466.765816540429 + "min": 27.40032878084305, + "max": 56.63990987555569, + "mean": 43.99915982076293 } }, "misc": { "case_volume": 0.00010625000000000001, "case_weight": -1 + }, + "insulations": { + "min": 23.74415143054456, + "max": 45.17151765974866, + "mean": 36.693880802270165 } } \ No newline at end of file diff --git a/tests/integration/test_femmt.py b/tests/integration/test_femmt.py index c427fd37..b4d00d34 100644 --- a/tests/integration/test_femmt.py +++ b/tests/integration/test_femmt.py @@ -1287,9 +1287,6 @@ def femmt_simulation_transformer_5_windings(temp_folder): # Set onelab path manually geo.file_data.onelab_folder_path = onelab_folder - # This line is for automated pytest running on github only. Please ignore this line! - if onelab_folder is not None: geo.file_data.onelab_folder_path = onelab_folder - # 2. set core parameters core_dimensions = fmt.dtos.SingleCoreDimensions(window_h=16.1e-3, window_w=(22.5 - 12) / 2 * 1e-3, core_inner_diameter=12e-3, core_h=22e-3) @@ -1416,119 +1413,7 @@ def femmt_simulation_transformer_5_windings(temp_folder): case_gap_right, case_gap_bot, show_thermal_simulation_results=False, color_scheme=fmt.colors_ba_jonas, colors_geometry=fmt.colors_geometry_ba_jonas, - flag_insulation=False) - - except Exception as e: - print("An error occurred while creating the femmt mesh files:", e) - except KeyboardInterrupt: - print("Keyboard interrupt..") - - electromagnetoquasistatic_result = os.path.join(temp_folder_path, "results", "log_electro_magnetic.json") - thermal_result = os.path.join(temp_folder_path, "results", "results_thermal.json") - - return electromagnetoquasistatic_result, thermal_result - - -@pytest.fixture -def thermal_simulation(temp_folder): - temp_folder_path, onelab_folder = temp_folder - - # Create new temp folder, build model and simulate - try: - working_directory = temp_folder_path - if not os.path.exists(working_directory): - os.mkdir(working_directory) - - geo = fmt.MagneticComponent(component_type=fmt.ComponentType.Inductor, - working_directory=working_directory, verbosity=fmt.Verbosity.Silent, is_gui=True) - - # Set onelab path manually - geo.file_data.onelab_folder_path = onelab_folder - - core_db = fmt.core_database()["PQ 40/40"] - core_dimensions = fmt.dtos.SingleCoreDimensions(core_inner_diameter=core_db["core_inner_diameter"], - window_w=core_db["window_w"], - window_h=core_db["window_h"], - core_h=core_db["core_h"]) - core = fmt.Core(core_type=fmt.CoreType.Single, core_dimensions=core_dimensions, - mu_r_abs=3100, phi_mu_deg=12, - sigma=0., - non_linear=False, - permeability_datasource=fmt.MaterialDataSource.Custom, - permittivity_datasource=fmt.MaterialDataSource.Custom - ) - geo.set_core(core) - - air_gaps = fmt.AirGaps(fmt.AirGapMethod.Center, core) - air_gaps.add_air_gap(fmt.AirGapLegPosition.CenterLeg, 0.0005) - geo.set_air_gaps(air_gaps) - - insulation = fmt.Insulation() - insulation.add_core_insulations(0.001, 0.001, 0.002, 0.001) - insulation.add_winding_insulations([[0.0001]]) - geo.set_insulation(insulation) - - winding_window = fmt.WindingWindow(core, insulation) - vww = winding_window.split_window(fmt.WindingWindowSplit.NoSplit) - - winding = fmt.Conductor(0, fmt.Conductivity.Copper, winding_material_temperature=25) - winding.set_solid_round_conductor(conductor_radius=0.0015, - conductor_arrangement=fmt.ConductorArrangement.Square) - - vww.set_winding(winding, 8, None) - geo.set_winding_windows([winding_window]) - - geo.create_model(freq=100000, pre_visualize_geometry=False, save_png=False) - geo.single_simulation(freq=100000, current=[3], show_fem_simulation_results=False) - - thermal_conductivity_dict = { - "air": 1.57, # potting epoxy resign - "case": { - "top": 1.57, - "top_right": 1.57, - "right": 1.57, - "bot_right": 1.57, - "bot": 1.57 - }, - "core": 5, # ferrite - "winding": 400, # copper - "air_gaps": 1.57, - "insulation": 1.57 - } - - case_gap_top = 0.002 - case_gap_right = 0.0025 - case_gap_bot = 0.002 - - boundary_temperatures = { - "value_boundary_top": 20, - "value_boundary_top_right": 20, - "value_boundary_right_top": 20, - "value_boundary_right": 20, - "value_boundary_right_bottom": 20, - "value_boundary_bottom_right": 20, - "value_boundary_bottom": 20 - } - - boundary_flags = { - "flag_boundary_top": 1, - "flag_boundary_top_right": 1, - "flag_boundary_right_top": 1, - "flag_boundary_right": 1, - "flag_boundary_right_bottom": 1, - "flag_boundary_bottom_right": 1, - "flag_boundary_bottom": 1 - } - - # color_scheme = fmt.colors_ba_jonas - # colors_geometry = fmt.colors_geometry_ba_jonas - color_scheme = fmt.colors_ba_jonas - colors_geometry = fmt.colors_geometry_draw_only_lines - - geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, - case_gap_right, - case_gap_bot, show_thermal_simulation_results=False, pre_visualize_geometry=False, color_scheme=color_scheme, - colors_geometry=colors_geometry) + flag_insulation=True) except Exception as e: print("An error occurred while creating the femmt mesh files:", e) @@ -1726,7 +1611,7 @@ def test_simulation_transformer_5_windings(femmt_simulation_transformer_5_windin # check thermal simulation results # assert os.path.exists(thermal_result_log), "Thermal simulation did not work!" # fixture_result_log = os.path.join(os.path.dirname(__file__), "fixtures", "results", "thermal_transformer_5_windings.json") - # compare_thermal_result_logs(thermal_result_log, fixture_result_log, significant_digits=3) + # compare_thermal_result_logs(thermal_result_log, fixture_result_log, significant_digits=2) def test_load_files(temp_folder, femmt_simulation_inductor_core_material_database,