-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathdata.py
More file actions
215 lines (186 loc) · 10.7 KB
/
data.py
File metadata and controls
215 lines (186 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
"""Contains information about the file structure."""
# Python standard libraries
import os
import logging
import numpy as np
# Local libraries
from femmt.enumerations import ConductorType
from femmt.model import Conductor
logger = logging.getLogger(__name__)
class FileData:
"""Contains paths to every folder and file needed in femmt."""
def __init__(self, working_directory: str, electro_magnetic_folder_path: str = None, strands_coefficients_folder_path: str = None):
if working_directory is not None:
self.update_paths(working_directory, electro_magnetic_folder_path, strands_coefficients_folder_path)
self.onelab_folder_path: str | None = None
@staticmethod
def create_folders(*args: str) -> None:
"""
Create folders for every given folder path (if it does not exist).
:param args: Folder names
:type args: str
"""
for folder in list(args):
if not os.path.exists(folder):
os.mkdir(folder)
def clear_previous_simulation_results(self):
"""
Clear all simulation results from previous simulations.
Therefore, the result-folder structure as well as some temporary files
(Parameter.pro, core_materials_temp.pro) are cleaned up.
"""
self.clean_folder_structure(self.results_folder_path)
if os.path.exists(os.path.join(self.electro_magnetic_folder_path, "core_materials_temp.pro")):
os.remove(os.path.join(self.electro_magnetic_folder_path, "core_materials_temp.pro"))
if os.path.exists(os.path.join(self.electro_magnetic_folder_path, "Parameter.pro")):
os.remove(os.path.join(self.electro_magnetic_folder_path, "Parameter.pro"))
@staticmethod
def clean_folder_structure(folder_path: str):
"""
Clean all files from a folder structure. The folder structure remains intact.
:param folder_path: folder path to clean up
:type folder_path: str
"""
try:
for root, _, files in os.walk(folder_path):
for file in files:
file_path = os.path.join(root, file)
os.remove(file_path)
# logger.info("All simulation results from previous simulations have been deleted successfully.")
except OSError:
logger.warning("Error occurred while deleting files and subdirectories.")
def update_paths(self, working_directory: str, electro_magnetic_folder_path: str = None, strands_coefficients_folder_path: str = None) -> None:
"""Set the local path based on the given working directory.
:param working_directory: working directory folder path
:type working_directory: str
:param electro_magnetic_folder_path: folder path to electro magnetic simulation folders
:type electro_magnetic_folder_path: str
:param strands_coefficients_folder_path: folder path to strand coefficients
:type strands_coefficients_folder_path: str
"""
# Setup folder paths
self.working_directory = working_directory
self.femmt_folder_path = os.path.dirname(__file__)
self.mesh_folder_path = os.path.join(self.working_directory, "mesh")
if electro_magnetic_folder_path:
self.electro_magnetic_folder_path = electro_magnetic_folder_path
else:
self.electro_magnetic_folder_path = os.path.join(self.femmt_folder_path, "electro_magnetic")
self.results_folder_path = os.path.join(self.working_directory, "results")
self.e_m_values_folder_path = os.path.join(self.results_folder_path, "values")
self.e_m_fields_folder_path = os.path.join(self.results_folder_path, "fields")
self.e_m_circuit_folder_path = os.path.join(self.results_folder_path, "circuit")
if strands_coefficients_folder_path:
self.e_m_strands_coefficients_folder_path = strands_coefficients_folder_path
else:
self.e_m_strands_coefficients_folder_path = os.path.join(self.electro_magnetic_folder_path, "Strands_Coefficients")
self.femm_folder_path = os.path.join(self.working_directory, "femm")
self.reluctance_model_folder_path = os.path.join(self.working_directory, "reluctance_model")
self.thermal_results_folder_path = os.path.join(self.results_folder_path, "thermal")
# Setup file paths
self.e_m_results_log_path = os.path.join(self.results_folder_path, "log_electro_magnetic.json")
###
# for electrostatic
self.electrostatic_results_log_path = os.path.join(self.results_folder_path, "log_electro_static.json")
self.capacitance_result_log_path = os.path.join(self.results_folder_path, "capacitance_result.json")
self.capacitance_matrix_path = os.path.join(self.results_folder_path, "log_capacitance_matrix.json")
###
self.coordinates_description_log_path = os.path.join(self.results_folder_path, "log_coordinates_description.json")
self.reluctance_log_path = os.path.join(self.results_folder_path, "log_reluctance_and_inductance.json")
self.material_log_path = os.path.join(self.results_folder_path, "log_material.json")
self.femm_results_log_path = os.path.join(self.femm_folder_path, "result_log_femm.json")
self.config_path = os.path.join(self.femmt_folder_path, "config.json")
self.e_m_mesh_file = os.path.join(self.mesh_folder_path, "electro_magnetic.msh")
self.model_geo_file = os.path.join(self.mesh_folder_path, "model.geo_unrolled")
self.hybrid_mesh_file = os.path.join(self.mesh_folder_path, "hybrid.msh")
self.hybrid_color_mesh_file = os.path.join(self.mesh_folder_path, "hybrid_color.msh")
self.hybrid_color_visualize_file = os.path.join(self.mesh_folder_path, "hybrid_color.png")
self.thermal_mesh_file = os.path.join(self.mesh_folder_path, "thermal.msh")
self.results_em_simulation = os.path.join(self.mesh_folder_path, "results.png")
self.gmsh_log = os.path.join(self.results_folder_path, "log_gmsh.txt")
self.getdp_log = os.path.join(self.results_folder_path, "log_getdp.txt")
self.femmt_log = os.path.join(self.results_folder_path, "log_femmt.txt")
# Create necessary folders
self.create_folders(self.femmt_folder_path, self.mesh_folder_path, self.electro_magnetic_folder_path,
self.results_folder_path, self.e_m_values_folder_path, self.e_m_fields_folder_path,
self.e_m_circuit_folder_path, self.e_m_strands_coefficients_folder_path)
class MeshData:
"""Contains data which is needed for the mesh generation. Is updated by high_level_geo_gen."""
padding: float # > 1
skin_mesh_factor: float
c_core: float
c_window: float
c_conductor = list[float]
c_center_conductor = list[float]
c_air_gaps: float
center_factor: float
mu0: float
core_w: float
window_w: float
windings: list["Conductor"] # This is written as string because it is a forward import
frequency: float
def __init__(self, mesh_accuracy_core: float,
mesh_accuracy_window: float,
mesh_accuracy_conductor: float,
mesh_accuracy_air_gaps: float,
padding: float,
mu0: float):
self.mesh_accuracy_core = mesh_accuracy_core
self.mesh_accuracy_window = mesh_accuracy_window
self.mesh_accuracy_conductor = mesh_accuracy_conductor
self.mesh_accuracy_air_gaps = mesh_accuracy_air_gaps
self.padding = padding
self.mu0 = mu0
# TODO This value should be set from user/outside?
# The value 4 has good impact on the runtime and does not affect the simulation results too much.
self.center_factor = 4
def update_spatial_data(self, core_w: float, window_w: float, windings: list["Conductor"]):
"""
Update geometry data of the core of the magnetic component.
:param core_w: core width
:type core_w: float
:param window_w: window width
:type window_w: float
:param windings: list of windings
:type windings: list["Conductor"]
"""
self.core_w = core_w
self.window_w = window_w
self.windings = windings
# Empty lists
self.c_conductor = [None] * len(windings)
self.c_center_conductor = [None] * len(windings)
self.c_core = core_w / 10 * self.mesh_accuracy_core
self.c_window = window_w / 30 * self.mesh_accuracy_window
self.c_air_gaps = window_w / 20 * self.mesh_accuracy_air_gaps
def update_data(self, frequency: float, skin_mesh_factor: float) -> None:
"""Update the mesh data according to the given frequency and skin_mesh_factor.
:param frequency: Frequency of the model (updates skin depth which affects the mesh)
:type frequency: float
:param skin_mesh_factor: Factor for skin mesh
:type skin_mesh_factor: float
"""
self.skin_mesh_factor = skin_mesh_factor
self.frequency = frequency
# Update Skin Depth (needed for meshing)
if frequency is not None:
if frequency == 0:
self.delta = 1e9
else:
self.delta = np.sqrt(2 / (2 * frequency * np.pi * self.windings[0].cond_sigma * self.mu0))
for i in range(len(self.windings)):
if self.windings[i].conductor_type == ConductorType.RoundSolid:
self.c_conductor[i] = min([self.delta * self.skin_mesh_factor, self.windings[i].conductor_radius / 4 * self.mesh_accuracy_conductor])
# * self.mesh.skin_mesh_factor])
self.c_center_conductor[i] = self.windings[i].conductor_radius / 4 * self.mesh_accuracy_conductor # * self.mesh.skin_mesh_factor
elif self.windings[i].conductor_type == ConductorType.RoundLitz:
self.c_conductor[i] = self.windings[i].conductor_radius / 4 * self.mesh_accuracy_conductor
self.c_center_conductor[i] = self.windings[i].conductor_radius / 4 * self.mesh_accuracy_conductor
# else:
# self.c_conductor[i] = self.windings[i].thickness / 4 * self.mesh_accuracy_conductor # TODO: dynamic implementation
# self.c_center_conductor[i] = self.center_factor * self.windings[i].thickness / 4 * self.mesh_accuracy_conductor
elif self.windings[i].conductor_type == ConductorType.RectangularSolid:
if self.windings[i].thickness is None:
continue # Skip update if thickness is not set
self.c_conductor[i] = self.windings[i].thickness / 4 * self.mesh_accuracy_conductor
self.c_center_conductor[i] = self.center_factor * self.windings[i].thickness / 4 * self.mesh_accuracy_conductor