Skip to content

Commit bc7f2f7

Browse files
committed
add reluctance model recalculation in optimization
1 parent 1a97279 commit bc7f2f7

3 files changed

Lines changed: 282 additions & 123 deletions

File tree

femmt/optimization/io.py

Lines changed: 133 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ def start_proceed_study(config: InductorOptimizationDTO, number_trials: int | No
390390
# simulation for a given number of target trials
391391
if len(study_in_storage.trials) < target_number_trials:
392392
study_in_memory = optuna.create_study(directions=['minimize', 'minimize'], study_name=config.inductor_study_name, sampler=sampler)
393-
print(f"Sampler is {study_in_memory.sampler.__class__.__name__}")
393+
logger.info(f"Sampler is {study_in_memory.sampler.__class__.__name__}")
394394
study_in_memory.add_trials(study_in_storage.trials)
395395
number_trials = target_number_trials - len(study_in_memory.trials)
396396
study_in_memory.optimize(func, n_trials=number_trials, show_progress_bar=True)
@@ -597,6 +597,75 @@ def df_from_trial_numbers(df: pd.DataFrame, trial_number_list: list[int]) -> pd.
597597

598598
return df_trial_numbers
599599

600+
@staticmethod
601+
def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_config_filepath: str) -> tuple:
602+
"""
603+
Reluctance model (hysteresis losses, winding losses) for geometries from df_geometry.
604+
605+
:param df_geometry: Pandas dataframe with geometries
606+
:type df_geometry: pd.DataFrame
607+
:param current_waveform: Current waveform to simulate
608+
:type current_waveform: list
609+
:param inductor_config_filepath: Filepath of the inductor optimization configuration file
610+
:type inductor_config_filepath: str
611+
:return: volume, loss
612+
:rtype: tuple
613+
"""
614+
for index, _ in df_geometry.iterrows():
615+
616+
local_config = InductorOptimization.ReluctanceModel.load_config(inductor_config_filepath)
617+
618+
if local_config.core_name_list is not None:
619+
# using fixed core sizes from the database with flexible height.
620+
core_name = df_geometry['params_core_name'][index]
621+
core = ff.core_database()[core_name]
622+
core_inner_diameter = core["core_inner_diameter"]
623+
window_w = core["window_w"]
624+
else:
625+
core_inner_diameter = df_geometry['params_core_inner_diameter'][index]
626+
window_w = df_geometry['params_window_w'][index]
627+
628+
# overwrite the old time-current vector with the new one
629+
local_config.time_current_vec = current_waveform
630+
target_and_fix_parameters = InductorOptimization.ReluctanceModel.calculate_fix_parameters(local_config)
631+
632+
litz_wire = ff.litz_database()[df_geometry['params_litz_wire_name'][index]]
633+
litz_wire_diameter = 2 * litz_wire["conductor_radii"]
634+
635+
# material properties
636+
material_db = mdb.MaterialDatabase(is_silent=True)
637+
638+
material_dto: mdb.MaterialCurve = material_db.material_data_interpolation_to_dto(
639+
df_geometry['params_material_name'][index], target_and_fix_parameters.fundamental_frequency, local_config.temperature)
640+
# instantiate material-specific model
641+
magnet_material_model: mh.loss.LossModel = mh.loss.LossModel(material=df_geometry['params_material_name'][index], team="paderborn")
642+
643+
reluctance_model_input = ReluctanceModelInput(
644+
core_inner_diameter=core_inner_diameter,
645+
window_w=window_w,
646+
window_h=df_geometry["params_window_h"][index],
647+
turns=int(df_geometry['params_turns'][index].item()),
648+
target_inductance=local_config.target_inductance,
649+
litz_wire_name=df_geometry['params_litz_wire_name'][index],
650+
litz_wire_diameter=litz_wire_diameter,
651+
652+
insulations=local_config.insulations,
653+
material_dto=material_dto,
654+
magnet_material_model=magnet_material_model,
655+
656+
temperature=local_config.temperature,
657+
current_extracted_vec=target_and_fix_parameters.current_extracted_vec,
658+
fundamental_frequency=target_and_fix_parameters.fundamental_frequency,
659+
fft_frequency_list=target_and_fix_parameters.fft_frequency_list,
660+
fft_amplitude_list=target_and_fix_parameters.fft_amplitude_list,
661+
fft_phases_list=target_and_fix_parameters.fft_phases_list
662+
)
663+
664+
reluctance_output: ReluctanceModelOutput = InductorOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_input)
665+
666+
p_total = reluctance_output.p_loss_total
667+
return reluctance_output.volume, p_total, reluctance_output.area_to_heat_sink
668+
600669
class FemSimulation:
601670
"""Contains methods to perform FEM simulations or process their results."""
602671

@@ -854,6 +923,26 @@ def single_fem_simulation(fem_input: FemInput, show_visual_outputs: bool = False
854923
)
855924
return fem_output
856925

926+
@staticmethod
927+
def filter_combined_loss_list_df(df: pd.DataFrame, factor_min_dc_losses: float = 1.2, factor_max_dc_losses: float = 10) -> pd.DataFrame:
928+
"""
929+
Remove designs with too high losses compared to the minimum losses.
930+
931+
:param df: pandas dataframe with study results
932+
:type df: pd.DataFrame
933+
:param factor_min_dc_losses: filter factor for the minimum dc losses
934+
:type factor_min_dc_losses: float
935+
:param factor_max_dc_losses: dc_max_loss = factor_max_dc_losses * min_available_dc_losses_in_pareto_front
936+
:type factor_max_dc_losses: float
937+
:returns: pandas dataframe with Pareto front near points
938+
:rtype: pd.DataFrame
939+
"""
940+
df = df.drop(df[df["combined_losses"].isna()].index)
941+
filtered_df = InductorOptimization.filter_df(df, x="values_0", y="combined_losses", factor_min_dc_losses=factor_min_dc_losses,
942+
factor_max_dc_losses=factor_max_dc_losses)
943+
944+
return filtered_df
945+
857946
@staticmethod
858947
def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_config_filepath: str, process_number: int = 1,
859948
print_derivations: bool = False) -> tuple:
@@ -897,33 +986,33 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
897986
working_directory = os.path.join(
898987
target_and_fix_parameters.working_directories.fem_working_directory, f"process_{process_number}")
899988

900-
# fem_input = FemInput(
901-
# # general parameters
902-
# working_directory=working_directory,
903-
# simulation_name='xx',
904-
905-
# # material and geometry parameters
906-
# material_name=df_geometry['params_material_name'][index],
907-
# litz_wire_name=df_geometry['params_litz_wire_name'][index],
908-
# core_inner_diameter=core_inner_diameter,
909-
# window_w=window_w,
910-
# window_h=df_geometry["params_window_h"][index],
911-
# air_gap_length=df_geometry['user_attrs_l_air_gap'][index],
912-
# turns=int(df_geometry['params_turns'][index].item()),
913-
# insulations=local_config.insulations,
914-
915-
# # data sources
916-
# material_data_sources=local_config.material_data_sources,
917-
918-
# # operating point conditions
919-
# temperature=local_config.temperature,
920-
# fundamental_frequency=target_and_fix_parameters.fundamental_frequency,
921-
# fft_frequency_list=target_and_fix_parameters.fft_frequency_list,
922-
# fft_amplitude_list=target_and_fix_parameters.fft_amplitude_list,
923-
# fft_phases_list=target_and_fix_parameters.fft_phases_list
924-
# )
925-
926-
# fem_output = InductorOptimization.FemSimulation.single_fem_simulation(fem_input, False)
989+
fem_input = FemInput(
990+
# general parameters
991+
working_directory=working_directory,
992+
simulation_name='xx',
993+
994+
# material and geometry parameters
995+
material_name=df_geometry['params_material_name'][index],
996+
litz_wire_name=df_geometry['params_litz_wire_name'][index],
997+
core_inner_diameter=core_inner_diameter,
998+
window_w=window_w,
999+
window_h=df_geometry["params_window_h"][index],
1000+
air_gap_length=df_geometry['user_attrs_l_air_gap'][index],
1001+
turns=int(df_geometry['params_turns'][index].item()),
1002+
insulations=local_config.insulations,
1003+
1004+
# data sources
1005+
material_data_sources=local_config.material_data_sources,
1006+
1007+
# operating point conditions
1008+
temperature=local_config.temperature,
1009+
fundamental_frequency=target_and_fix_parameters.fundamental_frequency,
1010+
fft_frequency_list=target_and_fix_parameters.fft_frequency_list,
1011+
fft_amplitude_list=target_and_fix_parameters.fft_amplitude_list,
1012+
fft_phases_list=target_and_fix_parameters.fft_phases_list
1013+
)
1014+
1015+
fem_output = InductorOptimization.FemSimulation.single_fem_simulation(fem_input, False)
9271016

9281017
litz_wire = ff.litz_database()[df_geometry['params_litz_wire_name'][index]]
9291018
litz_wire_diameter = 2 * litz_wire["conductor_radii"]
@@ -959,42 +1048,21 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
9591048

9601049
reluctance_output: ReluctanceModelOutput = InductorOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_input)
9611050

962-
# p_total = reluctance_output.p_hyst + fem_output.fem_eddy_core + fem_output.fem_p_loss_winding
963-
# workaround
964-
p_total = reluctance_output.p_loss_total
965-
966-
# if print_derivations:
967-
# print(f"Inductance reluctance: {local_config.target_inductance}")
968-
# print(f"Inductance FEM: {fem_output.fem_inductance}")
969-
# print(f"Inductance derivation: {(fem_output.fem_inductance - local_config.target_inductance) / local_config.target_inductance * 100} %")
970-
# print(f"Volume reluctance: {reluctance_output.volume}")
971-
# print(f"Volume FEM: {fem_output.volume}")
972-
# print(f"Volume derivation: {(reluctance_output.volume - fem_output.volume) / reluctance_output.volume * 100} %")
973-
# print(f"P_winding reluctance: {reluctance_output.p_winding}")
974-
# print(f"P_winding FEM: {fem_output.fem_p_loss_winding}")
975-
# print(f"P_winding derivation: {(fem_output.fem_p_loss_winding - reluctance_output.p_winding) / fem_output.fem_p_loss_winding * 100}")
976-
# print(f"P_hyst reluctance: {reluctance_output.p_hyst}")
977-
# print(f"P_hyst FEM: {fem_output.fem_core_total}")
978-
# print(f"P_hyst derivation: {(reluctance_output.p_hyst - fem_output.fem_core_total) / reluctance_output.p_hyst * 100}")
1051+
p_total = reluctance_output.p_hyst + fem_output.fem_eddy_core + fem_output.fem_p_loss_winding
1052+
1053+
if print_derivations:
1054+
logger.info(f"Inductance reluctance: {local_config.target_inductance}")
1055+
logger.info(f"Inductance FEM: {fem_output.fem_inductance}")
1056+
logger.info(f"Inductance derivation: "
1057+
f"{(fem_output.fem_inductance - local_config.target_inductance) / local_config.target_inductance * 100} %")
1058+
logger.info(f"Volume reluctance: {reluctance_output.volume}")
1059+
logger.info(f"Volume FEM: {fem_output.volume}")
1060+
logger.info(f"Volume derivation: {(reluctance_output.volume - fem_output.volume) / reluctance_output.volume * 100} %")
1061+
logger.info(f"P_winding reluctance: {reluctance_output.p_winding}")
1062+
logger.info(f"P_winding FEM: {fem_output.fem_p_loss_winding}")
1063+
logger.info(f"P_winding derivation: {(fem_output.fem_p_loss_winding - reluctance_output.p_winding) / fem_output.fem_p_loss_winding * 100}")
1064+
logger.info(f"P_hyst reluctance: {reluctance_output.p_hyst}")
1065+
logger.info(f"P_hyst FEM: {fem_output.fem_core_total}")
1066+
logger.info(f"P_hyst derivation: {(reluctance_output.p_hyst - fem_output.fem_core_total) / reluctance_output.p_hyst * 100}")
9791067

9801068
return reluctance_output.volume, p_total, reluctance_output.area_to_heat_sink
981-
982-
@staticmethod
983-
def filter_combined_loss_list_df(df: pd.DataFrame, factor_min_dc_losses: float = 1.2, factor_max_dc_losses: float = 10) -> pd.DataFrame:
984-
"""
985-
Remove designs with too high losses compared to the minimum losses.
986-
987-
:param df: pandas dataframe with study results
988-
:type df: pd.DataFrame
989-
:param factor_min_dc_losses: filter factor for the minimum dc losses
990-
:type factor_min_dc_losses: float
991-
:param factor_max_dc_losses: dc_max_loss = factor_max_dc_losses * min_available_dc_losses_in_pareto_front
992-
:type factor_max_dc_losses: float
993-
:returns: pandas dataframe with Pareto front near points
994-
:rtype: pd.DataFrame
995-
"""
996-
df = df.drop(df[df["combined_losses"].isna()].index)
997-
filtered_df = InductorOptimization.filter_df(df, x="values_0", y="combined_losses", factor_min_dc_losses=factor_min_dc_losses,
998-
factor_max_dc_losses=factor_max_dc_losses)
999-
1000-
return filtered_df

0 commit comments

Comments
 (0)