Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
tillpiepenbrock committed Apr 28, 2022
2 parents e8b447b + 4185eb1 commit ce6eed3
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 53 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,7 @@ femmt/thermal/solver/Group.pro
femmt/thermal/solver/Parameters.pro

# Used for integration test
!tests/integration/fixtures/results/result_log_electro_magnetic.json
!tests/integration/fixtures/results/result_log_electro_magnetic.json

# Example files
femmt/examples/paper_thermal_validation
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- conductor material can be chosen from a small material database, used in update_conductors(), e.g. conductivity_sigma=["copper"]
- isolations for thermal simulation

### Fixed
- fix #15: Secondary to Core isolation thickness not working
Expand Down
66 changes: 55 additions & 11 deletions femmt/examples/ba_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ def example_thermal_simulation(geo):
# The case parameter sets the thermal conductivity for a case which will be set around the core.
# This could model some case in which the transformer is placed in together with a set potting material.
thermal_conductivity_dict = {
"air": 3, # potting
"air": 0.122, # potting
"case": { # epoxy resign
"top": 3,
"top_right": 3,
"right": 3,
"bot_right": 3,
"bot": 3
"top": 0.122,
"top_right": 0.122,
"right": 0.122,
"bot_right": 0.122,
"bot": 0.122
},
"core": 5, # ferrite
"winding": 400, # copper
"air_gaps": 3, # aluminium nitride
"isolation": 3 # TODO Find material
"air_gaps": 0.122, # aluminium nitride
"isolation": 0.122 # TODO Find material
}

# Here the case size can be determined
Expand Down Expand Up @@ -91,14 +91,58 @@ def basic_example():
# Add conductors
geo.update_conductors(n_turns=[[21], [7]], conductor_type=["solid", "solid"],
litz_para_type=['implicit_litz_radius', 'implicit_litz_radius'],
ff=[None, 0.6], strands_numbers=[None, 600], strand_radii=[70e-6, 35.5e-6],
ff=[None, None], strands_numbers=[None, None], strand_radii=[None, None],
conductor_radii=[0.0011, 0.0011],
winding=["interleaved"], scheme=["horizontal"],
core_cond_isolation=[0.001, 0.001, 0.002, 0.001], cond_cond_isolation=[0.0002, 0.0002, 0.0005],
conductivity_sigma=["copper", "copper"])

# Create model
geo.create_model(freq=100000, visualize_before=True, do_meshing=False)
geo.create_model(freq=250000, visualize_before=True)

#geo.single_simulation(freq=250000, current=[4, 12], phi_deg=[0, 180], show_results=True)

thermal_conductivity_dict = {
"air": 0.0263,
"case": {
"top": 1.54,
"top_right": 1.54,
"right": 1.54,
"bot_right": 1.54,
"bot": 1.54
},
"core": 5,
"winding": 400,
"air_gaps": 180,
"isolation": 0.42
}

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
}

geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, case_gap_right, case_gap_bot, True)


if __name__ == "__main__":
pq4040()
pq4040()
#basic_example()
23 changes: 12 additions & 11 deletions femmt/examples/basic_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,18 @@ def example_thermal_simulation():
# The case parameter sets the thermal conductivity for a case which will be set around the core.
# This could model some case in which the transformer is placed in together with a set potting material.
thermal_conductivity_dict = {
"air": 3,
"air": 0.0263,
"case": { # epoxy resign
"top": 3,
"top_right": 3,
"right": 3,
"bot_right": 3,
"bot": 3
"top": 0.122,
"top_right": 0.122,
"right": 0.122,
"bot_right": 0.122,
"bot": 0.122
},
"core": 5, # ferrite
"winding": 400, # copper
#"air_gaps": 180, # aluminium nitride
#"air_gaps": 5, # aluminium nitride
"air_gaps": 3,
"isolation": 3 # TODO Find material
"air_gaps": 180, # aluminiumnitride
"isolation": 0.42 # polyethylen
}

# Here the case size can be determined
Expand Down Expand Up @@ -64,7 +62,10 @@ def example_thermal_simulation():
# order for the thermal simulation to work (geo.single_simulation is not needed).
# Obviously when the model is modified and the losses can be out of date and therefore the geo.single_simulation needs to run again.
geo.thermal_simulation(thermal_conductivity_dict, boundary_temperatures, boundary_flags, case_gap_top, case_gap_right, case_gap_bot, True)
#geo.femm_thermal_validation(thermal_conductivity_dict, femm_boundary_temperature)

# Because the isolations inside of the winding window are not implemented in femm simulation.
# The validation only works when the isolations for the FEMMT thermal simulation are turned off.
# geo.femm_thermal_validation(thermal_conductivity_dict, femm_boundary_temperature, case_gap_top, case_gap_right, case_gap_bot)

component = "inductor"
# component = "transformer-interleaved"
Expand Down
21 changes: 11 additions & 10 deletions femmt/femmt_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,8 @@ def calculate_core_volume(self) -> float:

air_gap_volume += np.pi * width**2 * height

#return (core_height * core_width - winding_height * winding_width - air_gap_area)*
print("Core volume calculated:", np.pi*(core_width**2 * core_height - winding_width**2 * winding_height) - air_gap_volume, "|Core volume ansys:", 1.996159905*10**-5)
#return np.pi*(core_width**2 * core_height - winding_width**2 * winding_height) - air_gap_volume
return 1.996159905*10**-5
# TODO Is this right?
return np.pi*(core_width**2 * core_height - winding_width**2 * winding_height) - air_gap_volume

def get_wire_distances(self):
wire_distance = []
Expand Down Expand Up @@ -321,7 +319,7 @@ def thermal_simulation(self, thermal_conductivity, boundary_temperatures, bounda
"wire_distances": self.get_wire_distances(),
"show_results": show_results,
"pretty_colors": True,
"show_before_simulation": True
"show_before_simulation": False
}

run_thermal(**thermal_parameters)
Expand Down Expand Up @@ -3669,7 +3667,10 @@ def generate_hybrid_mesh(self, do_meshing=True, visualize_before=False, save_png
gmsh.model.setColor([(2, self.plane_surface_core[i])], 50, 50, 50, recursive=True) # Core in gray
#gmsh.model.setColor([(2, self.plane_surface_air[0])], 0, 0, 0, recursive=True)
#gmsh.model.setColor([(2, self.plane_surface_air[0]), (2, self.plane_surface_air_gaps[0])], 181, 181, 181, recursive=True)
gmsh.model.setColor([(2, self.plane_surface_air[0]), (2, self.plane_surface_air_gaps[0])], 100, 60, 60, recursive=True)
if self.plane_surface_air_gaps:
# only colorize air-gap in case of air gaps
gmsh.model.setColor([(2, self.plane_surface_air[0]), (2, self.plane_surface_air_gaps[0])], 100, 60,
60, recursive=True)
#gmsh.model.setColor([(2, iso) for iso in self.plane_surface_iso_core + self.plane_surface_iso_pri_sec], 100, 100, 100, recursive=True)
#gmsh.model.setColor([(2, self.plane_surface_air[0])], 181, 181, 181, recursive=True) # Air in white
for num in range(0, self.component.n_windings):
Expand Down Expand Up @@ -4978,7 +4979,7 @@ def femm_thermal_validation(self, thermal_conductivity_dict, boundary_temperatur
# == Materials ==
# Core
k_core = thermal_conductivity_dict["core"]
q_vol_core = (losses["Core_Eddy_Current"] + losses["Core_Hysteresis"]) / self.calculate_core_volume()
q_vol_core = losses["core"] / self.calculate_core_volume()
# c_core = 0.007
c_core = 0

Expand Down Expand Up @@ -5007,11 +5008,11 @@ def femm_thermal_validation(self, thermal_conductivity_dict, boundary_temperatur
# Setup winding list
winding_losses_list = []
for i in range(1, 3):
key = f"Winding_{i}"
key = f"winding{i}"
inner_winding_list = []
if key in losses:
for loss in losses[key]["Turns"]:
inner_winding_list.append(loss)
for winding in losses[key]["turns"]:
inner_winding_list.append(winding)
winding_losses_list.append(inner_winding_list)

# Setup materials
Expand Down
8 changes: 4 additions & 4 deletions femmt/femmt_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -943,10 +943,10 @@ def visualize_simulation_results(simulation_result_file_path: str, store_figure_
with open(simulation_result_file_path, "r") as fd:
loaded_results_dict = json.loads(fd.read())

inductance = loaded_results_dict["Fluxes"]["L_11"][0]
loss_core_eddy_current = loaded_results_dict["Losses"]["Core_Eddy_Current"]
loss_core_hysteresis = loaded_results_dict["Losses"]["Core_Hysteresis"]
loss_winding_1 = loaded_results_dict["Losses"]["Winding_1"]["total_winding"]
inductance = loaded_results_dict["single_sweeps"][0]["winding1"]["self_inductivity"][0]
loss_core_eddy_current = loaded_results_dict["total_losses"]["eddy_core"]
loss_core_hysteresis = loaded_results_dict["total_losses"]["hyst_core_fundamental_freq"]
loss_winding_1 = loaded_results_dict["total_losses"]["winding1"]["total"]

print(inductance)
print(loss_core_eddy_current)
Expand Down
2 changes: 1 addition & 1 deletion femmt/thermal/solver/Thermal.pro
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ PostOperation map UsingPost The {

Print[ T, OnElementsOf Total , File thermal_file];
Print[ influx, OnElementsOf Warm , File thermal_influx_file];
Print[ material, OnElementsOf Total , File "material.pos"];
Print[ material, OnElementsOf Total , File thermal_material_file];
}
6 changes: 1 addition & 5 deletions femmt/thermal/thermal_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,15 @@ def calculate_heat_flux_round_wire(power, wire_radius, wire_distance):
# Power density for volumes W/m^3
#volume = 2 * np.pi**2 * wire_radius**2 * wire_position_x
volume = 2 * np.pi**2 * wire_radius**2 * wire_distance
ansys_volume = 4.419115371*10**-7

print("Calculated winding volume:", volume, "|ANSYS winding volume:", ansys_volume)

return power/volume
#return power/2*np.pi*wire_radius

def read_results_log(results_log_file_path):
losses = {}
if not os.path.exists(results_log_file_path):
raise Exception(f"Losses file not found {results_log_file_path}.")
with open(results_log_file_path, "r") as fd:
content = json.loads(fd.read())
losses = content["Losses"]
losses = content["total_losses"]

return losses
15 changes: 9 additions & 6 deletions femmt/thermal/thermal_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def create_background(background_tag, k_air, function_pro: FunctionPro, group_pr

def create_core_and_air_gaps(core_tag, k_core, core_area, core_losses, air_gaps_tag, k_air_gaps, function_pro: FunctionPro, group_pro: GroupPro):
heat_flux = core_losses/core_area

print(heat_flux)
if air_gaps_tag is not None:
k = {
"core": k_core,
Expand Down Expand Up @@ -106,6 +106,7 @@ def create_windings(winding_tags, k_windings, winding_losses, conductor_radii, w
name = f"winding_{winding_index}_{index}"
windings_total_str += f"{name}, "
q_vol[name] = calculate_heat_flux_round_wire(winding_losses[winding_index][index], conductor_radii[winding_index], wire_distances[winding_index][index])
print(q_vol[name])
k[name] = k_windings
regions[name] = tag
for entity in gmsh.model.getEntitiesForPhysicalGroup(2, tag):
Expand Down Expand Up @@ -157,6 +158,7 @@ def run_thermal(onelab_folder_path, results_folder_path, model_mesh_file_path, r
# Relative paths
map_pos_file = path.join(results_folder_path, "thermal.pos")
influx_pos_file = path.join(results_folder_path, "thermal_influx.pos")
material_pos_file = path.join(results_folder_path, "thermal_material.pos")
solver_folder_path = path.join(os.path.dirname(__file__), "solver")
thermal_template_file = path.join(solver_folder_path, "Thermal.pro")
parameters_file = path.join(solver_folder_path, "Parameters.pro")
Expand All @@ -176,20 +178,21 @@ def run_thermal(onelab_folder_path, results_folder_path, model_mesh_file_path, r

parameters_pro.add_to_parameters({
"thermal_file": map_pos_file.replace("\\", "/"),
"thermal_influx_file": influx_pos_file.replace("\\", "/")
"thermal_influx_file": influx_pos_file.replace("\\", "/"),
"thermal_material_file": material_pos_file.replace("\\", "/")
})

# Extract losses
winding_losses = []
for i in range(1, 3):
key = f"Winding_{i}"
key = f"winding{i}"
inner_winding_list = []
if key in losses:
for loss in losses[key]["Turns"]:
inner_winding_list.append(loss)
for winding in losses[key]["turns"]:
inner_winding_list.append(winding)
winding_losses.append(inner_winding_list)

core_losses = losses["Core_Eddy_Current"] + losses["Core_Hysteresis"]
core_losses = losses["core"]

# TODO All those pro classes could be used as global variables
case_dim_tags = create_case(tags_dict["boundary_regions"], boundary_physical_groups, boundary_temperatures, boundary_flags, thermal_conductivity_dict["case"], function_pro, parameters_pro, group_pro, constraint_pro)
Expand Down
8 changes: 4 additions & 4 deletions gui/femmt_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -1275,10 +1275,10 @@ def md_action_run_simulation(self) -> None:
self.md_loss_plot_label.setMask(pixmap.mask())
self.md_loss_plot_label.show()

inductance = loaded_results_dict["Fluxes"]["L_11"][0]
loss_core_eddy_current = loaded_results_dict["Losses"]["Core_Eddy_Current"]
loss_core_hysteresis = loaded_results_dict["Losses"]["Core_Hysteresis"]
loss_winding_1 = loaded_results_dict["Losses"]["Winding_1"]["total_winding"]
inductance = loaded_results_dict["single_sweeps"][0]["winding1"]["self_inductivity"][0]
loss_core_eddy_current = loaded_results_dict["total_losses"]["eddy_core"]
loss_core_hysteresis = loaded_results_dict["total_losses"]["hyst_core_fundamental_freq"]
loss_winding_1 = loaded_results_dict["total_losses"]["winding1"]["total"]

self.md_loss_core_hysteresis_label.setText(f"Core Hysteresis loss: {loss_core_hysteresis} W")
self.md_loss_core_eddy_current_label.setText(f"Core Eddy Current loss: {loss_core_eddy_current} W")
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
'onelab>=1.0',
'scipy>=1.7.2',
'pytest',
'PyQt5>=5.15.6',
],
license="GNU General Public License v3",
long_description=readme + '\n\n' + history,
Expand Down

0 comments on commit ce6eed3

Please sign in to comment.