Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/wordlist
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,14 @@ NbSetpsPerPeriod
NbSteps
WaveformType
powerloss
StoReluctanceModelInput
StoReluctanceModelOutput
StoFemInput
StoFemOutput
IoReluctanceModelInput
IoReluctanceModelOutput
IoFemInput
IoFemOutput

# electrostatic
capacitive
Expand Down
107 changes: 68 additions & 39 deletions femmt/optimization/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import tqdm

# onw libraries
from femmt.optimization.io_dtos import (InductorOptimizationDTO, InductorOptimizationTargetAndFixedParameters, FemInput,
FemOutput, ReluctanceModelInput, ReluctanceModelOutput)
from femmt.optimization.io_dtos import (InductorOptimizationDTO, InductorOptimizationTargetAndFixedParameters, IoFemInput,
IoFemOutput, IoReluctanceModelInput, IoReluctanceModelOutput)
import femmt.functions as ff
import femmt.functions_reluctance as fr
import femmt.optimization.ito_functions as itof
Expand Down Expand Up @@ -208,7 +208,7 @@ def objective(trial: optuna.Trial, config: InductorOptimizationDTO, target_and_f
material_mu_r_abs = material_mu_r_abs_value
magnet_material_model = target_and_fixed_parameters.magnet_hub_model_list[count]

reluctance_model_input = ReluctanceModelInput(
reluctance_model_input = IoReluctanceModelInput(
core_inner_diameter=core_inner_diameter,
window_w=window_w,
window_h=window_h,
Expand All @@ -222,14 +222,15 @@ def objective(trial: optuna.Trial, config: InductorOptimizationDTO, target_and_f
magnet_material_model=magnet_material_model,

temperature=config.temperature,
time_extracted_vec=target_and_fixed_parameters.time_extracted_vec,
current_extracted_vec=target_and_fixed_parameters.current_extracted_vec,
fundamental_frequency=target_and_fixed_parameters.fundamental_frequency,
fft_frequency_list=target_and_fixed_parameters.fft_frequency_list,
fft_amplitude_list=target_and_fixed_parameters.fft_amplitude_list,
fft_phases_list=target_and_fixed_parameters.fft_phases_list
)
try:
reluctance_output: ReluctanceModelOutput = InductorOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_input)
reluctance_output: IoReluctanceModelOutput = InductorOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_input)
except ValueError as e:
logger.debug("bot air gap: No fitting air gap length")
return float('nan'), float('nan')
Expand All @@ -245,13 +246,13 @@ def objective(trial: optuna.Trial, config: InductorOptimizationDTO, target_and_f
return reluctance_output.volume, reluctance_output.p_loss_total

@staticmethod
def single_reluctance_model_simulation(reluctance_input: ReluctanceModelInput) -> ReluctanceModelOutput:
def single_reluctance_model_simulation(reluctance_input: IoReluctanceModelInput) -> IoReluctanceModelOutput:
"""Perform a single reluctance model simulation. E.g. during optimization or during a re-simulation of a single operating point.

:param reluctance_input: Input parameters for the reluctance model simulation.
:type reluctance_input: ReluctanceModelInput
:type reluctance_input: IoReluctanceModelInput
:return: Output parameters of the reluctance model simulation
:rtype: ReluctanceModelOutput
:rtype: IoReluctanceModelOutput
"""
target_total_reluctance = reluctance_input.turns ** 2 / reluctance_input.target_inductance

Expand All @@ -263,7 +264,11 @@ def single_reluctance_model_simulation(reluctance_input: ReluctanceModelInput) -

r_air_gap_target = target_total_reluctance - r_core

flux = reluctance_input.turns * reluctance_input.current_extracted_vec / target_total_reluctance
# prepare equidistant flux vector for the magnet loss simulation
time_interp = np.linspace(reluctance_input.time_extracted_vec[0], reluctance_input.time_extracted_vec[-1], 1024)
current_interp = np.interp(time_interp, reluctance_input.time_extracted_vec, reluctance_input.current_extracted_vec)

flux = reluctance_input.turns * current_interp / target_total_reluctance
core_cross_section = (reluctance_input.core_inner_diameter / 2) ** 2 * np.pi
flux_density = flux / core_cross_section

Expand Down Expand Up @@ -323,7 +328,7 @@ def single_reluctance_model_simulation(reluctance_input: ReluctanceModelInput) -

p_loss = p_winding + p_core

reluctance_model_output = ReluctanceModelOutput(
reluctance_model_output = IoReluctanceModelOutput(
p_loss_total=p_loss,
volume=volume,
area_to_heat_sink=area_to_heat_sink,
Expand Down Expand Up @@ -656,7 +661,7 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
# instantiate material-specific model
magnet_material_model: mh.loss.LossModel = mh.loss.LossModel(material=material_name, team="paderborn")

reluctance_model_input = ReluctanceModelInput(
reluctance_model_input = IoReluctanceModelInput(
core_inner_diameter=core_inner_diameter,
window_w=window_w,
window_h=df_geometry["params_window_h"][index],
Expand All @@ -670,14 +675,15 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
magnet_material_model=magnet_material_model,

temperature=local_config.temperature,
time_extracted_vec=target_and_fix_parameters.time_extracted_vec,
current_extracted_vec=target_and_fix_parameters.current_extracted_vec,
fundamental_frequency=target_and_fix_parameters.fundamental_frequency,
fft_frequency_list=target_and_fix_parameters.fft_frequency_list,
fft_amplitude_list=target_and_fix_parameters.fft_amplitude_list,
fft_phases_list=target_and_fix_parameters.fft_phases_list
)

reluctance_output: ReluctanceModelOutput = InductorOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_input)
reluctance_output: IoReluctanceModelOutput = InductorOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_input)

p_total = reluctance_output.p_loss_total

Expand Down Expand Up @@ -727,7 +733,7 @@ def fem_simulations_from_reluctance_df(reluctance_df: pd.DataFrame, config: Indu
core_inner_diameter = reluctance_df["params_core_inner_diameter"][index].item()
window_w = reluctance_df["params_window_w"][index].item()
window_h = reluctance_df["params_window_h"][index].item()
fem_input = FemInput(
fem_input = IoFemInput(
simulation_name=f"case_{reluctance_df['number'][index].item()}",
working_directory=fem_working_directory,
core_inner_diameter=core_inner_diameter,
Expand All @@ -744,15 +750,17 @@ def fem_simulations_from_reluctance_df(reluctance_df: pd.DataFrame, config: Indu
fft_frequency_list=target_and_fix_parameters.fft_frequency_list,
fft_amplitude_list=target_and_fix_parameters.fft_amplitude_list,
fft_phases_list=target_and_fix_parameters.fft_phases_list,
time_vec=target_and_fix_parameters.time_extracted_vec,
current_vec=target_and_fix_parameters.current_extracted_vec
)

# fem simulation here
fem_output = InductorOptimization.FemSimulation.single_fem_simulation(fem_input, False)

reluctance_df.loc[index, 'fem_inductance'] = fem_output.fem_inductance
reluctance_df.loc[index, 'fem_p_loss_winding'] = fem_output.fem_p_loss_winding
reluctance_df.loc[index, 'fem_eddy_core'] = fem_output.fem_eddy_core
reluctance_df.loc[index, 'fem_core'] = fem_output.fem_core_total
reluctance_df.loc[index, 'fem_inductance'] = fem_output.inductance
reluctance_df.loc[index, 'fem_p_loss_winding'] = fem_output.p_loss_winding
reluctance_df.loc[index, 'fem_eddy_core'] = fem_output.p_core_sine
reluctance_df.loc[index, 'fem_core'] = fem_output.p_core_magnet

# copy result files to result-file folder
source_json_file = os.path.join(
Expand Down Expand Up @@ -855,18 +863,18 @@ def fem_vs_reluctance(df: pd.DataFrame, config: InductorOptimizationDTO):
return df

@staticmethod
def single_fem_simulation(fem_input: FemInput, show_visual_outputs: bool = False) -> FemOutput:
def single_fem_simulation(fem_input: IoFemInput, show_visual_outputs: bool = False) -> IoFemOutput:
"""
Perform a single FEM simulation.

For parallel simulations, use different working directories.

:param fem_input: FEM input DTO
:type fem_input: FemInput
:type fem_input: IoFemInput
:param show_visual_outputs: True to show visual outputs
:type show_visual_outputs: bool
:return: FEM output DTO
:rtype: FemOutput
:rtype: IoFemOutput
"""
# 1. chose simulation type
geo = fmt.MagneticComponent(simulation_type=fmt.SimulationType.FreqDomain, component_type=fmt.ComponentType.Inductor,
Expand Down Expand Up @@ -926,16 +934,33 @@ def single_fem_simulation(fem_input: FemInput, show_visual_outputs: bool = False
current_amplitudes = [[current] for current in fem_input.fft_amplitude_list]
phases = [[phase] for phase in fem_input.fft_phases_list]

# prepare core loss simulation
peak_current = np.max(fem_input.current_vec)
custom_b_wave = 1 / peak_current * fem_input.current_vec
time_interp = np.linspace(fem_input.time_vec[0], fem_input.time_vec[-1], 1024)
current_interp = np.interp(time_interp, fem_input.time_vec, fem_input.current_vec)
normalized_current_interp = 1 / peak_current * current_interp

# perform single hysteresis loss simulation where a sinusoidal signal with the peak amplitude is used
geo.single_simulation(freq=fem_input.fundamental_frequency, current=[peak_current],
plot_interpolation=False, show_fem_simulation_results=show_visual_outputs)

# read the flux per mesh cell and transfer it into losses with the help of the magnet model
hyst_losses_custom = geo.calc_hystersis_losses_with_MagNet_model_PB_based_on_mesh_results(b_wave=fmt.WaveformType.Custom,
custom_b_wave=normalized_current_interp)

result_dict_hyst = geo.read_log()

# get the winding losses
geo.excitation_sweep(frequency_list=fem_input.fft_frequency_list, current_list_list=current_amplitudes,
phi_deg_list_list=phases, show_last_fem_simulation=show_visual_outputs)

result_dict = geo.read_log()

fem_output = FemOutput(
fem_inductance=result_dict['single_sweeps'][0]['winding1']['flux_over_current'][0],
fem_p_loss_winding=result_dict['total_losses']['winding1']['total'],
fem_eddy_core=result_dict['total_losses']['eddy_core'],
fem_core_total=result_dict['total_losses']['core'],
fem_output = IoFemOutput(
inductance=result_dict['single_sweeps'][0]['winding1']['flux_over_current'][0],
p_loss_winding=result_dict['total_losses']['winding1']['total'],
p_core_sine=result_dict_hyst['total_losses']['core'],
p_core_magnet=hyst_losses_custom,
volume=result_dict["misc"]["core_2daxi_total_volume"]
)
return fem_output
Expand Down Expand Up @@ -1017,7 +1042,7 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_

material_mu_r_abs = np.abs(np.array([mu_real_at_f + 1j * mu_imag_at_f]))

fem_input = FemInput(
fem_input = IoFemInput(
# general parameters
working_directory=working_directory,
simulation_name='xx',
Expand All @@ -1040,7 +1065,10 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
fundamental_frequency=target_and_fix_parameters.fundamental_frequency,
fft_frequency_list=target_and_fix_parameters.fft_frequency_list,
fft_amplitude_list=target_and_fix_parameters.fft_amplitude_list,
fft_phases_list=target_and_fix_parameters.fft_phases_list
fft_phases_list=target_and_fix_parameters.fft_phases_list,

time_vec=target_and_fix_parameters.time_extracted_vec,
current_vec=target_and_fix_parameters.current_extracted_vec
)

fem_output = InductorOptimization.FemSimulation.single_fem_simulation(fem_input, False)
Expand All @@ -1051,7 +1079,7 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
# instantiate material-specific model
magnet_material_model: mh.loss.LossModel = mh.loss.LossModel(material=material_name, team="paderborn")

reluctance_model_input = ReluctanceModelInput(
reluctance_model_input = IoReluctanceModelInput(
core_inner_diameter=core_inner_diameter,
window_w=window_w,
window_h=df_geometry["params_window_h"][index_number],
Expand All @@ -1065,31 +1093,32 @@ def full_simulation(df_geometry: pd.DataFrame, current_waveform: list, inductor_
magnet_material_model=magnet_material_model,

temperature=local_config.temperature,
time_extracted_vec=target_and_fix_parameters.time_extracted_vec,
current_extracted_vec=target_and_fix_parameters.current_extracted_vec,
fundamental_frequency=target_and_fix_parameters.fundamental_frequency,
fft_frequency_list=target_and_fix_parameters.fft_frequency_list,
fft_amplitude_list=target_and_fix_parameters.fft_amplitude_list,
fft_phases_list=target_and_fix_parameters.fft_phases_list
fft_phases_list=target_and_fix_parameters.fft_phases_list,
)

reluctance_output: ReluctanceModelOutput = InductorOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_input)
reluctance_output: IoReluctanceModelOutput = InductorOptimization.ReluctanceModel.single_reluctance_model_simulation(reluctance_model_input)

p_core = reluctance_output.p_hyst + fem_output.fem_eddy_core
p_total = p_core + fem_output.fem_p_loss_winding
p_core = reluctance_output.p_hyst + fem_output.p_core_sine
p_total = p_core + fem_output.p_loss_winding

if print_derivations:
logger.info(f"Inductance reluctance: {local_config.target_inductance}")
logger.info(f"Inductance FEM: {fem_output.fem_inductance}")
logger.info(f"Inductance FEM: {fem_output.inductance}")
logger.info(f"Inductance derivation: "
f"{(fem_output.fem_inductance - local_config.target_inductance) / local_config.target_inductance * 100} %")
f"{(fem_output.inductance - local_config.target_inductance) / local_config.target_inductance * 100} %")
logger.info(f"Volume reluctance: {reluctance_output.volume}")
logger.info(f"Volume FEM: {fem_output.volume}")
logger.info(f"Volume derivation: {(reluctance_output.volume - fem_output.volume) / reluctance_output.volume * 100} %")
logger.info(f"P_winding reluctance: {reluctance_output.p_winding}")
logger.info(f"P_winding FEM: {fem_output.fem_p_loss_winding}")
logger.info(f"P_winding derivation: {(fem_output.fem_p_loss_winding - reluctance_output.p_winding) / fem_output.fem_p_loss_winding * 100} %")
logger.info(f"P_winding FEM: {fem_output.p_loss_winding}")
logger.info(f"P_winding derivation: {(fem_output.p_loss_winding - reluctance_output.p_winding) / fem_output.p_loss_winding * 100} %")
logger.info(f"P_hyst reluctance: {reluctance_output.p_hyst}")
logger.info(f"P_hyst FEM: {fem_output.fem_core_total}")
logger.info(f"P_hyst derivation: {(reluctance_output.p_hyst - fem_output.fem_core_total) / reluctance_output.p_hyst * 100} %")
logger.info(f"P_hyst FEM: {fem_output.p_core_magnet}")
logger.info(f"P_hyst derivation: {(reluctance_output.p_hyst - fem_output.p_core_magnet) / reluctance_output.p_hyst * 100} %")

return reluctance_output.volume, p_total, reluctance_output.area_to_heat_sink, fem_output.fem_p_loss_winding, p_core
return reluctance_output.volume, p_total, reluctance_output.area_to_heat_sink, fem_output.p_loss_winding, p_core
21 changes: 13 additions & 8 deletions femmt/optimization/io_dtos.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class InductorOptimizationTargetAndFixedParameters:
fft_phases_list: list[float]

@dataclasses.dataclass
class FemInput:
class IoFemInput:
"""Input DTO for a FEM simulation within the inductor optimization."""

# general parameters
Expand All @@ -95,18 +95,22 @@ class FemInput:
fft_amplitude_list: list[float]
fft_phases_list: list[float]

# magnet loss model
time_vec: list[float]
current_vec: list[float]

@dataclasses.dataclass
class FemOutput:
class IoFemOutput:
"""Output DTO for a FEM simulation within the inductor optimization."""

fem_inductance: float
fem_p_loss_winding: float
fem_eddy_core: float
fem_core_total: float
inductance: float
p_loss_winding: float
p_core_sine: float
p_core_magnet: float
volume: float

@dataclasses.dataclass
class ReluctanceModelInput:
class IoReluctanceModelInput:
"""Input DTO for reluctance model simulation within the inductor optimization."""

target_inductance: float
Expand All @@ -122,14 +126,15 @@ class ReluctanceModelInput:
magnet_material_model: LossModel

temperature: float
time_extracted_vec: list
current_extracted_vec: list
fundamental_frequency: float
fft_frequency_list: list[float]
fft_amplitude_list: list[float]
fft_phases_list: list[float]

@dataclasses.dataclass
class ReluctanceModelOutput:
class IoReluctanceModelOutput:
"""output DTO for reluctance model simulation within the inductor optimization."""

volume: float
Expand Down
Loading