1818import tqdm
1919
2020# onw libraries
21- from femmt .optimization .io_dtos import (InductorOptimizationDTO , InductorOptimizationTargetAndFixedParameters , FemInput ,
22- FemOutput , ReluctanceModelInput , ReluctanceModelOutput )
21+ from femmt .optimization .io_dtos import (InductorOptimizationDTO , InductorOptimizationTargetAndFixedParameters , IoFemInput ,
22+ IoFemOutput , IoReluctanceModelInput , IoReluctanceModelOutput )
2323import femmt .functions as ff
2424import femmt .functions_reluctance as fr
2525import femmt .optimization .ito_functions as itof
@@ -208,7 +208,7 @@ def objective(trial: optuna.Trial, config: InductorOptimizationDTO, target_and_f
208208 material_mu_r_abs = material_mu_r_abs_value
209209 magnet_material_model = target_and_fixed_parameters .magnet_hub_model_list [count ]
210210
211- reluctance_model_input = ReluctanceModelInput (
211+ reluctance_model_input = IoReluctanceModelInput (
212212 core_inner_diameter = core_inner_diameter ,
213213 window_w = window_w ,
214214 window_h = window_h ,
@@ -222,14 +222,15 @@ def objective(trial: optuna.Trial, config: InductorOptimizationDTO, target_and_f
222222 magnet_material_model = magnet_material_model ,
223223
224224 temperature = config .temperature ,
225+ time_extracted_vec = target_and_fixed_parameters .time_extracted_vec ,
225226 current_extracted_vec = target_and_fixed_parameters .current_extracted_vec ,
226227 fundamental_frequency = target_and_fixed_parameters .fundamental_frequency ,
227228 fft_frequency_list = target_and_fixed_parameters .fft_frequency_list ,
228229 fft_amplitude_list = target_and_fixed_parameters .fft_amplitude_list ,
229230 fft_phases_list = target_and_fixed_parameters .fft_phases_list
230231 )
231232 try :
232- reluctance_output : ReluctanceModelOutput = InductorOptimization .ReluctanceModel .single_reluctance_model_simulation (reluctance_model_input )
233+ reluctance_output : IoReluctanceModelOutput = InductorOptimization .ReluctanceModel .single_reluctance_model_simulation (reluctance_model_input )
233234 except ValueError as e :
234235 logger .debug ("bot air gap: No fitting air gap length" )
235236 return float ('nan' ), float ('nan' )
@@ -245,13 +246,13 @@ def objective(trial: optuna.Trial, config: InductorOptimizationDTO, target_and_f
245246 return reluctance_output .volume , reluctance_output .p_loss_total
246247
247248 @staticmethod
248- def single_reluctance_model_simulation (reluctance_input : ReluctanceModelInput ) -> ReluctanceModelOutput :
249+ def single_reluctance_model_simulation (reluctance_input : IoReluctanceModelInput ) -> IoReluctanceModelOutput :
249250 """Perform a single reluctance model simulation. E.g. during optimization or during a re-simulation of a single operating point.
250251
251252 :param reluctance_input: Input parameters for the reluctance model simulation.
252- :type reluctance_input: ReluctanceModelInput
253+ :type reluctance_input: IoReluctanceModelInput
253254 :return: Output parameters of the reluctance model simulation
254- :rtype: ReluctanceModelOutput
255+ :rtype: IoReluctanceModelOutput
255256 """
256257 target_total_reluctance = reluctance_input .turns ** 2 / reluctance_input .target_inductance
257258
@@ -263,7 +264,11 @@ def single_reluctance_model_simulation(reluctance_input: ReluctanceModelInput) -
263264
264265 r_air_gap_target = target_total_reluctance - r_core
265266
266- flux = reluctance_input .turns * reluctance_input .current_extracted_vec / target_total_reluctance
267+ # prepare equidistant flux vector for the magnet loss simulation
268+ time_interp = np .linspace (reluctance_input .time_extracted_vec [0 ], reluctance_input .time_extracted_vec [- 1 ], 1024 )
269+ current_interp = np .interp (time_interp , reluctance_input .time_extracted_vec , reluctance_input .current_extracted_vec )
270+
271+ flux = reluctance_input .turns * current_interp / target_total_reluctance
267272 core_cross_section = (reluctance_input .core_inner_diameter / 2 ) ** 2 * np .pi
268273 flux_density = flux / core_cross_section
269274
@@ -323,7 +328,7 @@ def single_reluctance_model_simulation(reluctance_input: ReluctanceModelInput) -
323328
324329 p_loss = p_winding + p_core
325330
326- reluctance_model_output = ReluctanceModelOutput (
331+ reluctance_model_output = IoReluctanceModelOutput (
327332 p_loss_total = p_loss ,
328333 volume = volume ,
329334 area_to_heat_sink = area_to_heat_sink ,
@@ -656,7 +661,7 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
656661 # instantiate material-specific model
657662 magnet_material_model : mh .loss .LossModel = mh .loss .LossModel (material = material_name , team = "paderborn" )
658663
659- reluctance_model_input = ReluctanceModelInput (
664+ reluctance_model_input = IoReluctanceModelInput (
660665 core_inner_diameter = core_inner_diameter ,
661666 window_w = window_w ,
662667 window_h = df_geometry ["params_window_h" ][index ],
@@ -670,14 +675,15 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
670675 magnet_material_model = magnet_material_model ,
671676
672677 temperature = local_config .temperature ,
678+ time_extracted_vec = target_and_fix_parameters .time_extracted_vec ,
673679 current_extracted_vec = target_and_fix_parameters .current_extracted_vec ,
674680 fundamental_frequency = target_and_fix_parameters .fundamental_frequency ,
675681 fft_frequency_list = target_and_fix_parameters .fft_frequency_list ,
676682 fft_amplitude_list = target_and_fix_parameters .fft_amplitude_list ,
677683 fft_phases_list = target_and_fix_parameters .fft_phases_list
678684 )
679685
680- reluctance_output : ReluctanceModelOutput = InductorOptimization .ReluctanceModel .single_reluctance_model_simulation (reluctance_model_input )
686+ reluctance_output : IoReluctanceModelOutput = InductorOptimization .ReluctanceModel .single_reluctance_model_simulation (reluctance_model_input )
681687
682688 p_total = reluctance_output .p_loss_total
683689
@@ -727,7 +733,7 @@ def fem_simulations_from_reluctance_df(reluctance_df: pd.DataFrame, config: Indu
727733 core_inner_diameter = reluctance_df ["params_core_inner_diameter" ][index ].item ()
728734 window_w = reluctance_df ["params_window_w" ][index ].item ()
729735 window_h = reluctance_df ["params_window_h" ][index ].item ()
730- fem_input = FemInput (
736+ fem_input = IoFemInput (
731737 simulation_name = f"case_{ reluctance_df ['number' ][index ].item ()} " ,
732738 working_directory = fem_working_directory ,
733739 core_inner_diameter = core_inner_diameter ,
@@ -744,15 +750,17 @@ def fem_simulations_from_reluctance_df(reluctance_df: pd.DataFrame, config: Indu
744750 fft_frequency_list = target_and_fix_parameters .fft_frequency_list ,
745751 fft_amplitude_list = target_and_fix_parameters .fft_amplitude_list ,
746752 fft_phases_list = target_and_fix_parameters .fft_phases_list ,
753+ time_vec = target_and_fix_parameters .time_extracted_vec ,
754+ current_vec = target_and_fix_parameters .current_extracted_vec
747755 )
748756
749757 # fem simulation here
750758 fem_output = InductorOptimization .FemSimulation .single_fem_simulation (fem_input , False )
751759
752- reluctance_df .loc [index , 'fem_inductance' ] = fem_output .fem_inductance
753- reluctance_df .loc [index , 'fem_p_loss_winding' ] = fem_output .fem_p_loss_winding
754- reluctance_df .loc [index , 'fem_eddy_core' ] = fem_output .fem_eddy_core
755- reluctance_df .loc [index , 'fem_core' ] = fem_output .fem_core_total
760+ reluctance_df .loc [index , 'fem_inductance' ] = fem_output .inductance
761+ reluctance_df .loc [index , 'fem_p_loss_winding' ] = fem_output .p_loss_winding
762+ reluctance_df .loc [index , 'fem_eddy_core' ] = fem_output .p_core_sine
763+ reluctance_df .loc [index , 'fem_core' ] = fem_output .p_core_magnet
756764
757765 # copy result files to result-file folder
758766 source_json_file = os .path .join (
@@ -855,18 +863,18 @@ def fem_vs_reluctance(df: pd.DataFrame, config: InductorOptimizationDTO):
855863 return df
856864
857865 @staticmethod
858- def single_fem_simulation (fem_input : FemInput , show_visual_outputs : bool = False ) -> FemOutput :
866+ def single_fem_simulation (fem_input : IoFemInput , show_visual_outputs : bool = False ) -> IoFemOutput :
859867 """
860868 Perform a single FEM simulation.
861869
862870 For parallel simulations, use different working directories.
863871
864872 :param fem_input: FEM input DTO
865- :type fem_input: FemInput
873+ :type fem_input: IoFemInput
866874 :param show_visual_outputs: True to show visual outputs
867875 :type show_visual_outputs: bool
868876 :return: FEM output DTO
869- :rtype: FemOutput
877+ :rtype: IoFemOutput
870878 """
871879 # 1. chose simulation type
872880 geo = fmt .MagneticComponent (simulation_type = fmt .SimulationType .FreqDomain , component_type = fmt .ComponentType .Inductor ,
@@ -926,16 +934,33 @@ def single_fem_simulation(fem_input: FemInput, show_visual_outputs: bool = False
926934 current_amplitudes = [[current ] for current in fem_input .fft_amplitude_list ]
927935 phases = [[phase ] for phase in fem_input .fft_phases_list ]
928936
937+ # prepare core loss simulation
938+ peak_current = np .max (fem_input .current_vec )
939+ custom_b_wave = 1 / peak_current * fem_input .current_vec
940+ time_interp = np .linspace (fem_input .time_vec [0 ], fem_input .time_vec [- 1 ], 1024 )
941+ current_interp = np .interp (time_interp , fem_input .time_vec , fem_input .current_vec )
942+ normalized_current_interp = 1 / peak_current * current_interp
943+
944+ # perform single hysteresis loss simulation where a sinusoidal signal with the peak amplitude is used
945+ geo .single_simulation (freq = fem_input .fundamental_frequency , current = [peak_current ],
946+ plot_interpolation = False , show_fem_simulation_results = show_visual_outputs )
947+
948+ # read the flux per mesh cell and transfer it into losses with the help of the magnet model
949+ hyst_losses_custom = geo .calc_hystersis_losses_with_MagNet_model_PB_based_on_mesh_results (b_wave = fmt .WaveformType .Custom ,
950+ custom_b_wave = normalized_current_interp )
951+
952+ result_dict_hyst = geo .read_log ()
953+
954+ # get the winding losses
929955 geo .excitation_sweep (frequency_list = fem_input .fft_frequency_list , current_list_list = current_amplitudes ,
930956 phi_deg_list_list = phases , show_last_fem_simulation = show_visual_outputs )
931-
932957 result_dict = geo .read_log ()
933958
934- fem_output = FemOutput (
935- fem_inductance = result_dict ['single_sweeps' ][0 ]['winding1' ]['flux_over_current' ][0 ],
936- fem_p_loss_winding = result_dict ['total_losses' ]['winding1' ]['total' ],
937- fem_eddy_core = result_dict ['total_losses' ]['eddy_core ' ],
938- fem_core_total = result_dict [ 'total_losses' ][ 'core' ] ,
959+ fem_output = IoFemOutput (
960+ inductance = result_dict ['single_sweeps' ][0 ]['winding1' ]['flux_over_current' ][0 ],
961+ p_loss_winding = result_dict ['total_losses' ]['winding1' ]['total' ],
962+ p_core_sine = result_dict_hyst ['total_losses' ]['core ' ],
963+ p_core_magnet = hyst_losses_custom ,
939964 volume = result_dict ["misc" ]["core_2daxi_total_volume" ]
940965 )
941966 return fem_output
@@ -1017,7 +1042,7 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
10171042
10181043 material_mu_r_abs = np .abs (np .array ([mu_real_at_f + 1j * mu_imag_at_f ]))
10191044
1020- fem_input = FemInput (
1045+ fem_input = IoFemInput (
10211046 # general parameters
10221047 working_directory = working_directory ,
10231048 simulation_name = 'xx' ,
@@ -1040,7 +1065,10 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
10401065 fundamental_frequency = target_and_fix_parameters .fundamental_frequency ,
10411066 fft_frequency_list = target_and_fix_parameters .fft_frequency_list ,
10421067 fft_amplitude_list = target_and_fix_parameters .fft_amplitude_list ,
1043- fft_phases_list = target_and_fix_parameters .fft_phases_list
1068+ fft_phases_list = target_and_fix_parameters .fft_phases_list ,
1069+
1070+ time_vec = target_and_fix_parameters .time_extracted_vec ,
1071+ current_vec = target_and_fix_parameters .current_extracted_vec
10441072 )
10451073
10461074 fem_output = InductorOptimization .FemSimulation .single_fem_simulation (fem_input , False )
@@ -1051,7 +1079,7 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
10511079 # instantiate material-specific model
10521080 magnet_material_model : mh .loss .LossModel = mh .loss .LossModel (material = material_name , team = "paderborn" )
10531081
1054- reluctance_model_input = ReluctanceModelInput (
1082+ reluctance_model_input = IoReluctanceModelInput (
10551083 core_inner_diameter = core_inner_diameter ,
10561084 window_w = window_w ,
10571085 window_h = df_geometry ["params_window_h" ][index_number ],
@@ -1065,31 +1093,32 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
10651093 magnet_material_model = magnet_material_model ,
10661094
10671095 temperature = local_config .temperature ,
1096+ time_extracted_vec = target_and_fix_parameters .time_extracted_vec ,
10681097 current_extracted_vec = target_and_fix_parameters .current_extracted_vec ,
10691098 fundamental_frequency = target_and_fix_parameters .fundamental_frequency ,
10701099 fft_frequency_list = target_and_fix_parameters .fft_frequency_list ,
10711100 fft_amplitude_list = target_and_fix_parameters .fft_amplitude_list ,
1072- fft_phases_list = target_and_fix_parameters .fft_phases_list
1101+ fft_phases_list = target_and_fix_parameters .fft_phases_list ,
10731102 )
10741103
1075- reluctance_output : ReluctanceModelOutput = InductorOptimization .ReluctanceModel .single_reluctance_model_simulation (reluctance_model_input )
1104+ reluctance_output : IoReluctanceModelOutput = InductorOptimization .ReluctanceModel .single_reluctance_model_simulation (reluctance_model_input )
10761105
1077- p_core = reluctance_output .p_hyst + fem_output .fem_eddy_core
1078- p_total = p_core + fem_output .fem_p_loss_winding
1106+ p_core = reluctance_output .p_hyst + fem_output .p_core_sine
1107+ p_total = p_core + fem_output .p_loss_winding
10791108
10801109 if print_derivations :
10811110 logger .info (f"Inductance reluctance: { local_config .target_inductance } " )
1082- logger .info (f"Inductance FEM: { fem_output .fem_inductance } " )
1111+ logger .info (f"Inductance FEM: { fem_output .inductance } " )
10831112 logger .info (f"Inductance derivation: "
1084- f"{ (fem_output .fem_inductance - local_config .target_inductance ) / local_config .target_inductance * 100 } %" )
1113+ f"{ (fem_output .inductance - local_config .target_inductance ) / local_config .target_inductance * 100 } %" )
10851114 logger .info (f"Volume reluctance: { reluctance_output .volume } " )
10861115 logger .info (f"Volume FEM: { fem_output .volume } " )
10871116 logger .info (f"Volume derivation: { (reluctance_output .volume - fem_output .volume ) / reluctance_output .volume * 100 } %" )
10881117 logger .info (f"P_winding reluctance: { reluctance_output .p_winding } " )
1089- logger .info (f"P_winding FEM: { fem_output .fem_p_loss_winding } " )
1090- logger .info (f"P_winding derivation: { (fem_output .fem_p_loss_winding - reluctance_output .p_winding ) / fem_output .fem_p_loss_winding * 100 } %" )
1118+ logger .info (f"P_winding FEM: { fem_output .p_loss_winding } " )
1119+ logger .info (f"P_winding derivation: { (fem_output .p_loss_winding - reluctance_output .p_winding ) / fem_output .p_loss_winding * 100 } %" )
10911120 logger .info (f"P_hyst reluctance: { reluctance_output .p_hyst } " )
1092- logger .info (f"P_hyst FEM: { fem_output .fem_core_total } " )
1093- logger .info (f"P_hyst derivation: { (reluctance_output .p_hyst - fem_output .fem_core_total ) / reluctance_output .p_hyst * 100 } %" )
1121+ logger .info (f"P_hyst FEM: { fem_output .p_core_magnet } " )
1122+ logger .info (f"P_hyst derivation: { (reluctance_output .p_hyst - fem_output .p_core_magnet ) / reluctance_output .p_hyst * 100 } %" )
10941123
1095- return reluctance_output .volume , p_total , reluctance_output .area_to_heat_sink , fem_output .fem_p_loss_winding , p_core
1124+ return reluctance_output .volume , p_total , reluctance_output .area_to_heat_sink , fem_output .p_loss_winding , p_core
0 commit comments