fiqus 2024.7.0__py3-none-any.whl → 2024.12.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fiqus/MainFiQuS.py +290 -134
- fiqus/data/DataConductor.py +301 -301
- fiqus/data/DataFiQuS.py +128 -84
- fiqus/data/DataFiQuSCCT.py +150 -150
- fiqus/data/DataFiQuSConductor.py +84 -84
- fiqus/data/DataFiQuSConductorAC_Strand.py +565 -565
- fiqus/data/DataFiQuSMultipole.py +716 -42
- fiqus/data/DataFiQuSPancake3D.py +737 -278
- fiqus/data/DataMultipole.py +180 -15
- fiqus/data/DataRoxieParser.py +90 -51
- fiqus/data/DataSettings.py +121 -0
- fiqus/data/DataWindingsCCT.py +37 -37
- fiqus/data/RegionsModelFiQuS.py +18 -6
- fiqus/geom_generators/GeometryCCT.py +905 -905
- fiqus/geom_generators/GeometryConductorAC_Strand.py +1391 -1391
- fiqus/geom_generators/GeometryMultipole.py +1827 -227
- fiqus/geom_generators/GeometryPancake3D.py +316 -117
- fiqus/geom_generators/GeometryPancake3DUtils.py +549 -0
- fiqus/getdp_runners/RunGetdpCCT.py +4 -4
- fiqus/getdp_runners/RunGetdpConductorAC_Strand.py +201 -201
- fiqus/getdp_runners/RunGetdpMultipole.py +115 -42
- fiqus/getdp_runners/RunGetdpPancake3D.py +28 -6
- fiqus/mains/MainCCT.py +2 -2
- fiqus/mains/MainConductorAC_Strand.py +132 -132
- fiqus/mains/MainMultipole.py +113 -62
- fiqus/mains/MainPancake3D.py +63 -23
- fiqus/mesh_generators/MeshCCT.py +209 -209
- fiqus/mesh_generators/MeshConductorAC_Strand.py +656 -656
- fiqus/mesh_generators/MeshMultipole.py +1243 -181
- fiqus/mesh_generators/MeshPancake3D.py +275 -192
- fiqus/parsers/ParserCOND.py +825 -0
- fiqus/parsers/ParserDAT.py +16 -16
- fiqus/parsers/ParserGetDPOnSection.py +212 -212
- fiqus/parsers/ParserGetDPTimeTable.py +134 -134
- fiqus/parsers/ParserMSH.py +53 -53
- fiqus/parsers/ParserPOS.py +214 -214
- fiqus/parsers/ParserRES.py +142 -142
- fiqus/plotters/PlotPythonCCT.py +133 -133
- fiqus/plotters/PlotPythonConductorAC.py +855 -855
- fiqus/plotters/PlotPythonMultipole.py +18 -18
- fiqus/post_processors/PostProcessCCT.py +440 -440
- fiqus/post_processors/PostProcessConductorAC.py +49 -49
- fiqus/post_processors/PostProcessMultipole.py +353 -229
- fiqus/post_processors/PostProcessPancake3D.py +8 -13
- fiqus/pre_processors/PreProcessCCT.py +175 -175
- fiqus/pro_assemblers/ProAssembler.py +14 -6
- fiqus/pro_material_functions/ironBHcurves.pro +246 -246
- fiqus/pro_templates/combined/CCT_template.pro +274 -274
- fiqus/pro_templates/combined/ConductorAC_template.pro +1025 -1025
- fiqus/pro_templates/combined/Multipole_template.pro +1694 -126
- fiqus/pro_templates/combined/Pancake3D_template.pro +2294 -1103
- fiqus/pro_templates/combined/TSA_materials.pro +162 -0
- fiqus/pro_templates/combined/materials.pro +36 -18
- fiqus/utils/Utils.py +508 -110
- fiqus/utils/update_data_settings.py +33 -0
- fiqus-2024.12.0.dist-info/METADATA +130 -0
- fiqus-2024.12.0.dist-info/RECORD +84 -0
- {fiqus-2024.7.0.dist-info → fiqus-2024.12.0.dist-info}/WHEEL +1 -1
- tests/test_FiQuS.py +1 -1
- tests/test_geometry_generators.py +101 -2
- tests/test_mesh_generators.py +154 -1
- tests/test_solvers.py +115 -21
- tests/utils/fiqus_test_classes.py +85 -21
- tests/utils/generate_reference_files_ConductorAC.py +57 -57
- tests/utils/generate_reference_files_Pancake3D.py +4 -5
- tests/utils/helpers.py +97 -97
- fiqus-2024.7.0.dist-info/METADATA +0 -103
- fiqus-2024.7.0.dist-info/RECORD +0 -79
- {fiqus-2024.7.0.dist-info → fiqus-2024.12.0.dist-info}/top_level.txt +0 -0
|
@@ -3,74 +3,118 @@ from pathlib import Path
|
|
|
3
3
|
import gmsh
|
|
4
4
|
import json
|
|
5
5
|
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
6
7
|
import matplotlib.pyplot as plt
|
|
7
8
|
import matplotlib.lines as lines
|
|
9
|
+
import matplotlib.patches as patches
|
|
10
|
+
from matplotlib.collections import PatchCollection
|
|
8
11
|
|
|
9
12
|
from fiqus.utils.Utils import GmshUtils
|
|
10
13
|
from fiqus.utils.Utils import GeometricFunctions as Func
|
|
11
|
-
from fiqus.utils.Utils import RoxieParsers
|
|
14
|
+
from fiqus.utils.Utils import RoxieParsers
|
|
15
|
+
from fiqus.utils.Utils import FilesAndFolders as Util
|
|
12
16
|
from fiqus.data import DataFiQuS as dF
|
|
17
|
+
from fiqus.data import DataMultipole as dM
|
|
18
|
+
from fiqus.data import RegionsModelFiQuS as rM
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
class PostProcess:
|
|
16
|
-
def __init__(self, data: dF.FDM() = None,
|
|
17
|
-
verbose: bool = False):
|
|
22
|
+
def __init__(self, data: dF.FDM() = None, solution_folder: str = None, verbose: bool = False):
|
|
18
23
|
"""
|
|
19
24
|
Class to post process results
|
|
20
25
|
:param data: FiQuS data model
|
|
21
|
-
:param sett: settings data model
|
|
22
26
|
:param verbose: If True more information is printed in python console.
|
|
23
27
|
"""
|
|
24
28
|
self.data: dF.FDM() = data
|
|
25
|
-
self.set: dF.FiQuSSettings() = sett
|
|
26
29
|
self.solution_folder = solution_folder
|
|
27
30
|
self.verbose: bool = verbose
|
|
31
|
+
self.md = dM.MultipoleData()
|
|
32
|
+
self.rm = rM.RegionsModel()
|
|
28
33
|
|
|
29
34
|
self.gu = GmshUtils(self.solution_folder, self.verbose)
|
|
30
|
-
self.gu.initialize()
|
|
35
|
+
self.gu.initialize(verbosity_Gmsh=self.data.run.verbosity_Gmsh)
|
|
31
36
|
|
|
32
37
|
self.brep_iron_curves = {1: set(), 2: set(), 3: set(), 4: set()}
|
|
33
38
|
self.strands = None
|
|
34
39
|
self.crns = None
|
|
35
|
-
self.
|
|
36
|
-
self.BB_err_min = []
|
|
37
|
-
self.BB_err_max = []
|
|
40
|
+
self.avg_temperatures = pd.DataFrame()
|
|
38
41
|
self.postprocess_parameters = dict.fromkeys(['overall_error', 'minimum_diff', 'maximum_diff'])
|
|
39
|
-
self.
|
|
40
|
-
self.
|
|
41
|
-
|
|
42
|
-
self.
|
|
43
|
-
|
|
42
|
+
self.mesh_folder = os.path.dirname(self.solution_folder)
|
|
43
|
+
self.geom_files = os.path.join(os.path.dirname(self.mesh_folder), self.data.general.magnet_name)
|
|
44
|
+
self.mesh_files = os.path.join(self.mesh_folder, self.data.general.magnet_name)
|
|
45
|
+
self.model_file = os.path.join(self.solution_folder, self.data.general.magnet_name)
|
|
46
|
+
self.postproc_settings = pd.DataFrame()
|
|
47
|
+
|
|
48
|
+
self.supported_variables = {'magnetic_flux_density': 'b',
|
|
49
|
+
'temperature': 'T'}
|
|
50
|
+
if any([var not in self.supported_variables.values()
|
|
51
|
+
for var in self.data.magnet.postproc.electromagnetics.variables + self.data.magnet.postproc.thermal.variables]):
|
|
52
|
+
pass
|
|
53
|
+
# raise Exception(f"The interpolation of the field at the strands locations can not be executed: "
|
|
54
|
+
# f"a variable listed in 'post_processors' -> 'variables' is not supported. "
|
|
55
|
+
# f"Supported variables are: {self.supported_variables.values()}")
|
|
56
|
+
self.physical_quantities_abbreviations = \
|
|
57
|
+
{'magnetic_flux_density': ('BX/T', 'BY/T'),
|
|
58
|
+
'temperature': ('T/K', '-')}
|
|
59
|
+
self.physical_quantity = None
|
|
60
|
+
self.formatted_headline = "{0:>5}{1:>8}{2:>7}{3:>12}{4:>13}{5:>8}{6:>11}{7:>16}{8:>8}{9:>10}\n\n"
|
|
61
|
+
self.formatted_content = "{0:>6}{1:>6}{2:>7}{3:>13}{4:>13}{5:>11}{6:>11}{7:>11}{8:>9}{9:>8}\n"
|
|
62
|
+
self.map2d_headline_names = []
|
|
63
|
+
|
|
64
|
+
def prepare_settings(self, settings):
|
|
65
|
+
self.postproc_settings = pd.DataFrame({
|
|
66
|
+
'variables': settings.variables,
|
|
67
|
+
'volumes': settings.volumes})
|
|
68
|
+
if 'compare_to_ROXIE' in settings.dict():
|
|
69
|
+
self.physical_quantity = 'magnetic_flux_density'
|
|
70
|
+
else:
|
|
71
|
+
self.physical_quantity = 'temperature'
|
|
72
|
+
self.map2d_headline_names = ['BL.', 'COND.', 'NO.', 'X-POS/MM', 'Y-POS/MM'] + \
|
|
73
|
+
[abbr for abbr in self.physical_quantities_abbreviations[self.physical_quantity]] + \
|
|
74
|
+
['AREA/MM**2', 'CURRENT', 'FILL FAC.']
|
|
44
75
|
|
|
45
|
-
if
|
|
76
|
+
if settings.plot_all != 'false':
|
|
46
77
|
self.fiqus = None
|
|
47
78
|
self.roxie = None
|
|
48
|
-
plt.figure(1)
|
|
49
|
-
self.ax =
|
|
50
|
-
self.ax.set_xlabel('x [
|
|
51
|
-
self.ax.set_ylabel('y [
|
|
52
|
-
self.ax.set_xlim(0, 0.09)
|
|
53
|
-
self.ax.set_ylim(0, 0.
|
|
54
|
-
|
|
55
|
-
if
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
fig1 = plt.figure(1)
|
|
80
|
+
self.ax = fig1.add_subplot()
|
|
81
|
+
self.ax.set_xlabel('x [cm]') # adjust other plots to cm
|
|
82
|
+
self.ax.set_ylabel('y [cm]')
|
|
83
|
+
# self.ax.set_xlim(0, 0.09) # todo
|
|
84
|
+
# self.ax.set_ylim(0, 0.09)
|
|
85
|
+
|
|
86
|
+
if not settings.dict().get('take_average_conductor_temperature', False):
|
|
87
|
+
if settings.dict().get('compare_to_ROXIE', False):
|
|
88
|
+
fig2 = plt.figure(2)
|
|
89
|
+
self.ax2 = fig2.add_subplot(projection='3d')
|
|
90
|
+
self.ax2.set_xlabel('x [m]')
|
|
91
|
+
self.ax2.set_ylabel('y [m]')
|
|
92
|
+
self.ax2.set_zlabel('Absolute Error [T]')
|
|
93
|
+
self.fig4 = plt.figure(4)
|
|
94
|
+
self.ax4 = plt.axes()
|
|
95
|
+
self.ax4.set_xlabel('x [cm]')
|
|
96
|
+
self.ax4.set_ylabel('y [cm]')
|
|
97
|
+
self.ax4.set_aspect('equal', 'box')
|
|
98
|
+
fig3 = plt.figure(3)
|
|
99
|
+
self.ax3 = fig3.add_subplot(projection='3d')
|
|
100
|
+
self.ax3.set_xlabel('x [m]')
|
|
101
|
+
self.ax3.set_ylabel('y [m]')
|
|
102
|
+
self.ax3.set_zlabel('norm(B) [T]' if 'compare_to_ROXIE' in settings.dict() else '')
|
|
103
|
+
|
|
104
|
+
if 'compare_to_ROXIE' in settings.dict() and 'b' in settings.variables:
|
|
105
|
+
b_index = settings.variables.index('b')
|
|
106
|
+
file_to_open = os.path.join(self.solution_folder, f"b_{settings.volumes[b_index]}.pos")
|
|
107
|
+
elif 'T' in settings.variables:
|
|
108
|
+
T_index = settings.variables.index('T')
|
|
109
|
+
file_to_open = os.path.join(self.solution_folder, f"T_{settings.volumes[T_index]}.pos")
|
|
110
|
+
|
|
111
|
+
gmsh.open(file_to_open)
|
|
112
|
+
|
|
113
|
+
def clear(self):
|
|
114
|
+
self.md = dM.MultipoleData()
|
|
115
|
+
self.rm = rM.RegionsModel()
|
|
116
|
+
plt.close('all')
|
|
117
|
+
gmsh.clear()
|
|
74
118
|
|
|
75
119
|
def ending_step(self, gui: bool = False):
|
|
76
120
|
if gui:
|
|
@@ -79,208 +123,288 @@ class PostProcess:
|
|
|
79
123
|
gmsh.clear()
|
|
80
124
|
gmsh.finalize()
|
|
81
125
|
|
|
82
|
-
def
|
|
83
|
-
self.
|
|
126
|
+
def loadAuxiliaryFile(self, run_type):
|
|
127
|
+
self.md = Util.read_data_from_yaml(f"{self.mesh_files}_{run_type}.aux", dM.MultipoleData)
|
|
128
|
+
|
|
129
|
+
def loadRegionFile(self):
|
|
130
|
+
self.rm = Util.read_data_from_yaml(f"{self.mesh_files}_TH.reg", rM.RegionsModel)
|
|
131
|
+
|
|
132
|
+
def loadStrandPositions(self, run_type):
|
|
133
|
+
self.strands = json.load(open(f"{self.geom_files}_{run_type}.strs"))
|
|
84
134
|
|
|
85
135
|
def loadHalfTurnCornerPositions(self):
|
|
86
|
-
self.crns = json.load(open(f"{
|
|
87
|
-
|
|
88
|
-
def plotHalfTurnGeometry(self):
|
|
89
|
-
for i in range(len(self.crns['
|
|
90
|
-
self.ax.add_line(lines.Line2D([self.crns['
|
|
91
|
-
[self.crns['
|
|
92
|
-
self.ax.add_line(lines.Line2D([self.crns['
|
|
93
|
-
[self.crns['
|
|
94
|
-
self.ax.add_line(lines.Line2D([self.crns['
|
|
95
|
-
[self.crns['
|
|
96
|
-
self.ax.add_line(lines.Line2D([self.crns['
|
|
97
|
-
[self.crns['
|
|
98
|
-
cc_fiqus = Func.centroid([self.crns['
|
|
99
|
-
self.crns['
|
|
100
|
-
[self.crns['
|
|
101
|
-
self.crns['
|
|
102
|
-
|
|
103
|
-
if
|
|
104
|
-
self.ax.add_line(lines.Line2D([self.crns['
|
|
105
|
-
[self.crns['
|
|
136
|
+
self.crns = json.load(open(f"{self.geom_files}.crns"))
|
|
137
|
+
|
|
138
|
+
def plotHalfTurnGeometry(self, compare_to_ROXIE):
|
|
139
|
+
for i in range(len(self.crns['iH'])):
|
|
140
|
+
self.ax.add_line(lines.Line2D([self.crns['iH'][i][0], self.crns['iL'][i][0]],
|
|
141
|
+
[self.crns['iH'][i][1], self.crns['iL'][i][1]], color='green'))
|
|
142
|
+
self.ax.add_line(lines.Line2D([self.crns['oH'][i][0], self.crns['oL'][i][0]],
|
|
143
|
+
[self.crns['oH'][i][1], self.crns['oL'][i][1]], color='green'))
|
|
144
|
+
self.ax.add_line(lines.Line2D([self.crns['oL'][i][0], self.crns['iL'][i][0]],
|
|
145
|
+
[self.crns['oL'][i][1], self.crns['iL'][i][1]], color='green'))
|
|
146
|
+
self.ax.add_line(lines.Line2D([self.crns['iH'][i][0], self.crns['oH'][i][0]],
|
|
147
|
+
[self.crns['iH'][i][1], self.crns['oH'][i][1]], color='green'))
|
|
148
|
+
cc_fiqus = Func.centroid([self.crns['iH'][i][0], self.crns['iL'][i][0],
|
|
149
|
+
self.crns['oL'][i][0], self.crns['oH'][i][0]],
|
|
150
|
+
[self.crns['iH'][i][1], self.crns['iL'][i][1],
|
|
151
|
+
self.crns['oL'][i][1], self.crns['oH'][i][1]])
|
|
152
|
+
|
|
153
|
+
if compare_to_ROXIE:
|
|
154
|
+
self.ax.add_line(lines.Line2D([self.crns['iHr'][i][0], self.crns['iLr'][i][0]],
|
|
155
|
+
[self.crns['iHr'][i][1], self.crns['iLr'][i][1]],
|
|
106
156
|
color='red', linestyle='dashed'))
|
|
107
|
-
self.ax.add_line(lines.Line2D([self.crns['
|
|
108
|
-
[self.crns['
|
|
157
|
+
self.ax.add_line(lines.Line2D([self.crns['oHr'][i][0], self.crns['oLr'][i][0]],
|
|
158
|
+
[self.crns['oHr'][i][1], self.crns['oLr'][i][1]],
|
|
109
159
|
color='red', linestyle='dashed'))
|
|
110
|
-
self.ax.add_line(lines.Line2D([self.crns['
|
|
111
|
-
[self.crns['
|
|
160
|
+
self.ax.add_line(lines.Line2D([self.crns['oLr'][i][0], self.crns['iLr'][i][0]],
|
|
161
|
+
[self.crns['oLr'][i][1], self.crns['iLr'][i][1]],
|
|
112
162
|
color='red', linestyle='dashed'))
|
|
113
|
-
self.ax.add_line(lines.Line2D([self.crns['
|
|
114
|
-
[self.crns['
|
|
163
|
+
self.ax.add_line(lines.Line2D([self.crns['iHr'][i][0], self.crns['oHr'][i][0]],
|
|
164
|
+
[self.crns['iHr'][i][1], self.crns['oHr'][i][1]],
|
|
115
165
|
color='red', linestyle='dashed'))
|
|
166
|
+
self.ax.text((self.crns['oLr'][i][0] + self.crns['iLr'][i][0]) / 2,
|
|
167
|
+
(self.crns['oLr'][i][1] + self.crns['iLr'][i][1]) / 2,
|
|
168
|
+
'R' + str(i + 1), style='italic', bbox={'facecolor': 'red', 'pad': 2})
|
|
169
|
+
self.ax.text((self.crns['iHr'][i][0] + self.crns['oHr'][i][0]) / 2,
|
|
170
|
+
(self.crns['iHr'][i][1] + self.crns['oHr'][i][1]) / 2,
|
|
171
|
+
'L' + str(i + 1), style='italic', bbox={'facecolor': 'red', 'pad': 2})
|
|
116
172
|
cc_roxie = Func.centroid(
|
|
117
|
-
[self.crns['
|
|
118
|
-
[self.crns['
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
"%] Interpolating within block" + f"{str(bb)}")
|
|
129
|
-
|
|
130
|
-
def _fetchRoxieData():
|
|
131
|
-
roxie_x.append(matrix[row, 3])
|
|
132
|
-
roxie_y.append(matrix[row, 4])
|
|
133
|
-
strands_area.append(matrix[row, 7])
|
|
134
|
-
BB_roxie_x.append(matrix[row, 5])
|
|
135
|
-
BB_roxie_y.append(matrix[row, 6])
|
|
136
|
-
BB_roxie.append(np.linalg.norm(np.array([matrix[row, 5], matrix[row, 6]])))
|
|
137
|
-
|
|
138
|
-
def _probeFromView():
|
|
139
|
-
BB_x = []
|
|
140
|
-
BB_y = []
|
|
141
|
-
BB = []
|
|
142
|
-
b_list = [b for b, field in enumerate(self.data.magnet.postproc.variables) if field == 'b']
|
|
143
|
-
if not b_list:
|
|
144
|
-
raise Exception("The interpolation of the field at the strands locations can not be executed: "
|
|
145
|
-
"the field 'b' is not listed in 'post_processors' -> 'variables'")
|
|
146
|
-
b_field_index = 0
|
|
147
|
-
while self.data.magnet.postproc.volumes[b_list[b_field_index]] != 'Omega_p':
|
|
148
|
-
b_field_index += 1
|
|
149
|
-
# self.data.magnet.post_proc.variables.index('b')
|
|
150
|
-
for ss in range(len(strands_x)):
|
|
151
|
-
probe_data = gmsh.view.probe(gmsh.view.getTags()[0] if len(b_list) == 1 else b_list[b_field_index],
|
|
152
|
-
strands_x[ss], strands_y[ss], 0)[0]
|
|
153
|
-
BB_x.append(probe_data[0])
|
|
154
|
-
BB_y.append(probe_data[1])
|
|
155
|
-
BB.append(np.linalg.norm(np.array([BB_x[-1], BB_y[-1]])))
|
|
156
|
-
return BB_x, BB_y, BB
|
|
157
|
-
|
|
158
|
-
def _updateMap2dFile(blk_nr, ht_nr):
|
|
159
|
-
with open(self.model_file, 'a') as f:
|
|
160
|
-
content = []
|
|
161
|
-
s = row - strands
|
|
162
|
-
for x, y, Bx, By in zip(strands_x, strands_y, BB_strands_x, BB_strands_y):
|
|
163
|
-
s += 1
|
|
164
|
-
content.append(f" {blk_nr} {ht_nr} {s} {x * 1e3:.4f} "
|
|
165
|
-
f"{y * 1e3:.4f} {Bx:.4f} {By:.4f} {1.0} "
|
|
166
|
-
f"{self.II / strands:.2f} {1.0}\n")
|
|
167
|
-
f.writelines(content)
|
|
168
|
-
|
|
169
|
-
def _computeError():
|
|
170
|
-
BB_err = BB_strands - np.array(BB_roxie)
|
|
171
|
-
self.BB_err_mean.append(np.mean(abs(BB_err)))
|
|
172
|
-
self.BB_err_min.append(np.min(abs(BB_err)))
|
|
173
|
-
self.BB_err_min.append(np.max(abs(BB_err)))
|
|
174
|
-
return BB_err
|
|
175
|
-
|
|
176
|
-
def _plotData():
|
|
177
|
-
map2d = None
|
|
178
|
-
pos_roxie = None
|
|
179
|
-
if self.data.magnet.postproc.compare_to_ROXIE:
|
|
180
|
-
map2d = self.ax.scatter(roxie_x, roxie_y, edgecolor='black', facecolor='black', s=10)
|
|
181
|
-
corners = conductorPositionsList[c + cond_nr].xyCorner
|
|
182
|
-
for corner in range(len(corners)):
|
|
183
|
-
self.ax.scatter(corners[corner][0] / 1e3, corners[corner][1] / 1e3, edgecolor='black',
|
|
184
|
-
facecolor='black', s=10)
|
|
185
|
-
if flag_contraction:
|
|
186
|
-
self.ax.scatter([x * (1 - 0.002) for x in parser_x],
|
|
187
|
-
[y * (1 - 0.002) for y in parser_y], c='r', s=10)
|
|
188
|
-
else:
|
|
189
|
-
self.ax.scatter(parser_x, parser_y, c='r', s=10)
|
|
190
|
-
self.ax2.scatter3D(roxie_x, roxie_y, BB_abs_err, c=BB_abs_err, cmap='viridis') # , vmin=-0.2, vmax=0.2)
|
|
191
|
-
self.ax4.scatter(np.array(roxie_x) * 1e2, np.array(roxie_y) * 1e2, s=1, c=np.array(BB_abs_err) * 1e3, cmap='viridis')
|
|
192
|
-
pos_roxie = self.ax3.scatter3D(roxie_x, roxie_y, BB_roxie, c=BB_roxie, cmap='Reds', vmin=0, vmax=10)
|
|
193
|
-
pos = self.ax3.scatter3D(strands_x, strands_y, BB_strands, c=BB_strands, cmap='Greens', vmin=0, vmax=10)
|
|
194
|
-
return map2d, pos_roxie, pos
|
|
195
|
-
|
|
196
|
-
print(f"Info : {self.data.general.magnet_name} - I n t e r p o l a t i n g . . .")
|
|
197
|
-
print("Info : Interpolating magnetic flux density ...")
|
|
198
|
-
|
|
199
|
-
if self.data.magnet.postproc.compare_to_ROXIE:
|
|
200
|
-
roxie_path = self.data.magnet.postproc.compare_to_ROXIE # f"C:\\Users\\avitrano\\PycharmProjects\\steam_sdk\\tests\\builders\\model_library\\magnets\\{self.data.general.magnet_name}\\input"
|
|
201
|
-
flag_contraction = False
|
|
173
|
+
[self.crns['iHr'][i][0], self.crns['iLr'][i][0], self.crns['oLr'][i][0], self.crns['oHr'][i][0]],
|
|
174
|
+
[self.crns['iHr'][i][1], self.crns['iLr'][i][1], self.crns['oLr'][i][1], self.crns['oHr'][i][1]])
|
|
175
|
+
self.roxie = self.ax.scatter(cc_roxie[0], cc_roxie[1], edgecolor='r', facecolor='none')
|
|
176
|
+
|
|
177
|
+
self.fiqus = self.ax.scatter(cc_fiqus[0], cc_fiqus[1], c="green")
|
|
178
|
+
|
|
179
|
+
def postProcess(self, postproc):
|
|
180
|
+
df_ref = pd.DataFrame()
|
|
181
|
+
model_file_extension = 'EM' if 'compare_to_ROXIE' in postproc.dict() else 'TH'
|
|
182
|
+
|
|
183
|
+
if postproc.dict().get('compare_to_ROXIE', False):
|
|
202
184
|
# flag_self_field = False
|
|
203
|
-
path_map2d = Path(
|
|
204
|
-
# path_map2d = Path(roxie_path, "MQXA_All_" +
|
|
185
|
+
# path_map2d = Path(postproc.compare_to_ROXIE, "MQXA_All_" +
|
|
205
186
|
# f"{'WithIron_' if self.data.magnet.geometry.with_iron_yoke else 'NoIron_'}" +
|
|
206
187
|
# f"{'WithSelfField' if flag_self_field else 'NoSelfField'}" +
|
|
207
188
|
# f"{'' if flag_contraction else '_no_contraction'}" + ".map2d")
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if
|
|
211
|
-
path_cond2d = Path(os.path.join(os.path.dirname(
|
|
212
|
-
# path_cond2d = Path(os.path.dirname(
|
|
189
|
+
df_ref = RoxieParsers.parseMap2d(map2dFile=Path(postproc.compare_to_ROXIE), physical_quantity='magnetic_flux_density')
|
|
190
|
+
BB_roxie = np.linalg.norm(df_ref[['BX/T', 'BY/T']].values, axis=1)
|
|
191
|
+
if postproc.plot_all != 'false':
|
|
192
|
+
path_cond2d = Path(os.path.join(os.path.dirname(postproc.compare_to_ROXIE), self.data.general.magnet_name + ".cond2d"))
|
|
193
|
+
# path_cond2d = Path(os.path.dirname(postproc.compare_to_ROXIE), "MQXA_All_NoIron_NoSelfField" +
|
|
213
194
|
# f"{'' if flag_contraction else '_no_contraction'}" + ".cond2d")
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
self.
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
195
|
+
if os.path.isfile(path_cond2d):
|
|
196
|
+
conductorPositionsList = RoxieParsers.parseCond2d(path_cond2d)
|
|
197
|
+
|
|
198
|
+
# Collect strands coordinates
|
|
199
|
+
strands_x = df_ref['X-POS/MM'] / 1e3 if postproc.dict().get('compare_to_ROXIE', False) else self.strands['x']
|
|
200
|
+
strands_y = df_ref['Y-POS/MM'] / 1e3 if postproc.dict().get('compare_to_ROXIE', False) else self.strands['y']
|
|
201
|
+
|
|
202
|
+
# Probe physical quantity values from view and region areas
|
|
203
|
+
physical_quantity_values = {'x': [], 'y': []}
|
|
204
|
+
cond_areas, current_signs = [], []
|
|
205
|
+
if postproc.dict().get('take_average_conductor_temperature', False):
|
|
206
|
+
half_turns = {name[:-3]: str(values.vol.numbers[i])
|
|
207
|
+
for group, values in self.rm.powered.items() for i, name in enumerate(values.vol.names)}
|
|
208
|
+
self.avg_temperatures = pd.concat([pd.read_csv(os.path.join(self.solution_folder, 'T_avg', 'T_avg_0.txt'),
|
|
209
|
+
delimiter=r'\s+', header=None, usecols=[0], names=['Time'])] +
|
|
210
|
+
[pd.read_csv(os.path.join(self.solution_folder, 'T_avg', f'T_avg_{i}.txt'),
|
|
211
|
+
delimiter=r'\s+', header=None, usecols=[1], names=[ht.upper()]) for i, ht in enumerate(half_turns)], axis=1)
|
|
212
|
+
self.avg_temperatures['Time'] = pd.read_csv(os.path.join(self.solution_folder, 'T_avg', 'T_avg_0.txt'),
|
|
213
|
+
delimiter=r'\s+', header=None, usecols=[0], names=['Time'])['Time']
|
|
214
|
+
self.avg_temperatures = self.avg_temperatures[['Time'] + ['HT' + str(i) for i in range(1, self.strands['ht'][-1] + 1)]]
|
|
215
|
+
columns_to_format = self.avg_temperatures.columns[1:]
|
|
216
|
+
self.avg_temperatures[columns_to_format] = self.avg_temperatures[columns_to_format].round(4)
|
|
217
|
+
self.avg_temperatures.to_csv(os.path.join(self.solution_folder, 'half_turn_temperatures_over_time.csv'), index=False)
|
|
218
|
+
else:
|
|
219
|
+
print(f"Info : {self.data.general.magnet_name} - I n t e r p o l a t i n g . . .")
|
|
220
|
+
print(f"Info : Interpolating {'magnetic flux density' if 'compare_to_ROXIE' in postproc.dict() else 'temperature'} ...")
|
|
221
|
+
|
|
222
|
+
# view = gmsh.view.getTags()[0] if len(postproc.variables) == 1 else self.postproc_settings[
|
|
223
|
+
# (self.postproc_settings['variables'] == self.supported_variables[self.physical_quantity]) &
|
|
224
|
+
# (self.postproc_settings['volumes'] == 'Omega_p')].index[0]
|
|
225
|
+
|
|
226
|
+
view = gmsh.view.getTags()[0]
|
|
227
|
+
for i in range(len(strands_x)):
|
|
228
|
+
is_new_conductor = i == 0 or self.strands['ht'][i] != self.strands['ht'][i - 1]
|
|
229
|
+
is_new_block = i == 0 or self.strands['block'][i] != self.strands['block'][i - 1]
|
|
230
|
+
|
|
231
|
+
# Print update
|
|
232
|
+
if is_new_block:
|
|
233
|
+
perc = round(self.strands['block'][i] / self.strands['block'][-1] * 100)
|
|
234
|
+
print(f"Info : [{' ' if perc < 10 else ''}{' ' if perc < 100 else ''}{perc}%] Interpolating within block {self.strands['block'][i]}")
|
|
235
|
+
|
|
236
|
+
# Probe
|
|
237
|
+
probe_data = gmsh.view.probe(view, strands_x[i], strands_y[i], 0)[0]
|
|
238
|
+
if 'compare_to_ROXIE' in postproc.dict():
|
|
239
|
+
physical_quantity_values['x'].append(probe_data[0])
|
|
240
|
+
physical_quantity_values['y'].append(probe_data[1])
|
|
241
|
+
else:
|
|
242
|
+
physical_quantity_values['x'].append(probe_data[0])
|
|
243
|
+
physical_quantity_values['y'].append(0)
|
|
244
|
+
|
|
245
|
+
# Plot conductor and block identifiers
|
|
246
|
+
if postproc.dict().get('compare_to_ROXIE', False) and postproc.plot_all != 'false':
|
|
247
|
+
if is_new_conductor:
|
|
248
|
+
self.ax.text(df_ref['X-POS/MM'][i] / 1e3, df_ref['Y-POS/MM'][i] / 1e3, str(self.strands['ht'][i]),
|
|
249
|
+
style='italic', bbox={'facecolor': 'blue', 'pad': 3})
|
|
250
|
+
if is_new_block:
|
|
251
|
+
mid_strand_index = round(self.strands['ht'].count(self.strands['ht'][i]) / 2)
|
|
252
|
+
self.ax.text(df_ref['X-POS/MM'][i + mid_strand_index] / 1e3, df_ref['Y-POS/MM'][i + mid_strand_index] / 1e3,
|
|
253
|
+
str(self.strands['block'][i]), style='italic', bbox={'facecolor': 'green', 'pad': 3})
|
|
254
|
+
|
|
255
|
+
# Get current sign
|
|
256
|
+
current_signs.append(self.md.domains.physical_groups.blocks[self.strands['block'][i]].current_sign)
|
|
257
|
+
|
|
258
|
+
# Get region area
|
|
259
|
+
if is_new_conductor:
|
|
260
|
+
gmsh.plugin.setNumber("MeshVolume", "Dimension", 2)
|
|
261
|
+
gmsh.plugin.setNumber("MeshVolume", "PhysicalGroup",
|
|
262
|
+
self.md.domains.physical_groups.blocks[self.strands['block'][i]].half_turns[self.strands['ht'][i]].tag)
|
|
263
|
+
gmsh.plugin.run("MeshVolume")
|
|
264
|
+
cond_areas.append(gmsh.view.getListData(gmsh.view.getTags()[-1])[2][-1][-1])
|
|
265
|
+
else:
|
|
266
|
+
cond_areas.append(cond_areas[-1])
|
|
267
|
+
|
|
268
|
+
print(f"Info : {self.data.general.magnet_name} - E n d I n t e r p o l a t i n g")
|
|
269
|
+
|
|
270
|
+
# Assemble map2d content
|
|
271
|
+
strands_nr = 0
|
|
272
|
+
content = []
|
|
273
|
+
for i, ht in enumerate(self.strands['ht']):
|
|
274
|
+
if i == 0 or ht != self.strands['ht'][i - 1]:
|
|
275
|
+
strands_nr = self.strands['ht'].count(ht)
|
|
276
|
+
content.append(self.formatted_content.format(
|
|
277
|
+
int(self.strands['block'][i]), # bl
|
|
278
|
+
int(ht), # cond
|
|
279
|
+
int(i + 1), # no
|
|
280
|
+
f"{strands_x[i] * 1e3:.4f}", # x
|
|
281
|
+
f"{strands_y[i] * 1e3:.4f}", # y
|
|
282
|
+
f"{physical_quantity_values['x'][i]:.4f}", # pq_x
|
|
283
|
+
f"{physical_quantity_values['y'][i]:.4f}", # pq_y
|
|
284
|
+
f"{cond_areas[i] / strands_nr * 1e6:.4f}", # area
|
|
285
|
+
f"{current_signs[i] * self.data.power_supply.I_initial / strands_nr:.2f}", # curr
|
|
286
|
+
f"{df_ref['FILL FAC.'][i] if postproc.dict().get('compare_to_ROXIE', False) else 0:.4f}")) # fill_fac
|
|
287
|
+
|
|
288
|
+
# Save map2d file
|
|
289
|
+
with open(f"{self.model_file}_{model_file_extension}.map2d", 'w') as file:
|
|
290
|
+
file.write(self.formatted_headline.format(*self.map2d_headline_names))
|
|
291
|
+
file.writelines(content)
|
|
292
|
+
print(f"Info : Map2D file saved.")
|
|
293
|
+
print(f"WARNING : [Map2D] All strand surface areas are equal within a conductor. Refer to the ROXIE map2d file for actual values")
|
|
294
|
+
if not postproc.dict().get('compare_to_ROXIE', True):
|
|
295
|
+
print(f"WARNING : [Map2D] No data is available for Filling Factor. Refer to the ROXIE map2d file for correct values")
|
|
296
|
+
|
|
297
|
+
# Compute errors
|
|
298
|
+
pq = np.linalg.norm(np.column_stack((np.array(physical_quantity_values['x']), np.array(physical_quantity_values['y']))), axis=1)
|
|
299
|
+
if postproc.dict().get('compare_to_ROXIE', False):
|
|
300
|
+
BB_err = pq - BB_roxie
|
|
301
|
+
self.postprocess_parameters['overall_error'] = np.mean(abs(BB_err))
|
|
302
|
+
self.postprocess_parameters['minimum_diff'] = np.min(BB_err)
|
|
303
|
+
self.postprocess_parameters['maximum_diff'] = np.max(BB_err)
|
|
304
|
+
|
|
305
|
+
if postproc.plot_all != 'false':
|
|
306
|
+
if postproc.dict().get('take_average_conductor_temperature', False):
|
|
307
|
+
min_value = self.avg_temperatures.iloc[:, 1:].min().min()
|
|
308
|
+
max_value = self.avg_temperatures.iloc[:, 1:].max().max()
|
|
309
|
+
ht_polygons = [patches.Polygon(np.array([(self.crns['iHr'][i][0], self.crns['iHr'][i][1]),
|
|
310
|
+
(self.crns['iLr'][i][0], self.crns['iLr'][i][1]),
|
|
311
|
+
(self.crns['oLr'][i][0], self.crns['oLr'][i][1]),
|
|
312
|
+
(self.crns['oHr'][i][0], self.crns['oHr'][i][1])]) * 1e2,
|
|
313
|
+
closed=True) for i in range(len(self.crns['iHr']))]
|
|
314
|
+
collection = PatchCollection(ht_polygons)
|
|
315
|
+
self.ax.add_collection(collection)
|
|
316
|
+
cmap = plt.get_cmap('plasma')
|
|
317
|
+
norm = plt.Normalize(vmin=min_value, vmax=max_value)
|
|
318
|
+
cbar = plt.colorbar(plt.cm.ScalarMappable(cmap=cmap, norm=norm), ax=self.ax)
|
|
319
|
+
cbar.set_label('Temperature [K]')
|
|
320
|
+
self.ax.autoscale_view()
|
|
321
|
+
for i in range(self.avg_temperatures['Time'].size):
|
|
322
|
+
collection.set_facecolor(cmap(norm(self.avg_temperatures.iloc[i, 1:])))
|
|
323
|
+
if postproc.plot_all == 'true':
|
|
324
|
+
plt.pause(0.05)
|
|
325
|
+
|
|
326
|
+
else:
|
|
327
|
+
self.plotHalfTurnGeometry(postproc.dict().get('compare_to_ROXIE', False))
|
|
328
|
+
map2d_strands = self.ax.scatter(strands_x, strands_y, edgecolor='black', facecolor='black', s=10)
|
|
329
|
+
|
|
330
|
+
scatter3D_pos = self.ax3.scatter3D(strands_x, strands_y, pq, c=pq, cmap='Greens', vmin=0, vmax=10)
|
|
331
|
+
|
|
332
|
+
if postproc.dict().get('compare_to_ROXIE', False):
|
|
333
|
+
if os.path.isfile(path_cond2d):
|
|
334
|
+
conductors_corners = [condPos.xyCorner for condPos in conductorPositionsList]
|
|
335
|
+
for corners in conductors_corners:
|
|
336
|
+
for corner in range(len(corners)):
|
|
337
|
+
self.ax.scatter(corners[corner][0] / 1e3, corners[corner][1] / 1e3, edgecolor='black', facecolor='black', s=10)
|
|
338
|
+
|
|
339
|
+
self.ax2.scatter3D(strands_x, strands_y, BB_err, c=BB_err, cmap='viridis') # , vmin=-0.2, vmax=0.2)
|
|
340
|
+
scatter4 = self.ax4.scatter(np.array(strands_x) * 1e2, np.array(strands_y) * 1e2, s=1, c=np.array(BB_err) * 1e3, cmap='viridis')
|
|
341
|
+
scatter3D_pos_roxie = self.ax3.scatter3D(strands_x, strands_y, BB_roxie, c=BB_roxie, cmap='Reds', vmin=0, vmax=10)
|
|
342
|
+
|
|
343
|
+
cax4 = self.fig4.add_axes((self.ax4.get_position().x1 + 0.02, self.ax4.get_position().y0,
|
|
344
|
+
0.02, self.ax4.get_position().height))
|
|
345
|
+
cbar = plt.colorbar(scatter4, cax=cax4)
|
|
346
|
+
cbar.ax.set_ylabel('Absolute error [mT]', rotation=270)
|
|
347
|
+
self.ax3.legend([scatter3D_pos, scatter3D_pos_roxie], ['FiQuS', 'ROXIE'], numpoints=1)
|
|
348
|
+
self.ax.legend([self.fiqus, self.roxie, map2d_strands], ['FiQuS', 'ROXIE'], numpoints=1)
|
|
349
|
+
self.fig4.savefig(f"{os.path.join(self.solution_folder, self.data.general.magnet_name)}.svg", bbox_inches='tight')
|
|
350
|
+
|
|
351
|
+
if postproc.plot_all == 'true':
|
|
282
352
|
plt.show()
|
|
283
353
|
|
|
284
354
|
# os.remove(os.path.join(self.solution_folder, 'b_Omega_p.pos'))
|
|
285
355
|
# os.remove(f"{os.path.join(self.solution_folder, self.data.general.magnet_name)}.pre")
|
|
286
356
|
# os.remove(f"{os.path.join(os.path.dirname(self.solution_folder), self.data.general.magnet_name)}.msh")
|
|
357
|
+
|
|
358
|
+
def completeMap2d(self):
|
|
359
|
+
def _quadrant(x, y):
|
|
360
|
+
if x < 0 and y < 0: return 3
|
|
361
|
+
elif x < 0: return 2
|
|
362
|
+
elif y < 0: return 4
|
|
363
|
+
else: return 1
|
|
364
|
+
|
|
365
|
+
if self.data.magnet.geometry.electromagnetics.symmetry == 'xy':
|
|
366
|
+
if self.strands['poles'] == 2:
|
|
367
|
+
mirror_components = {2: [-1, 1], 3: [1, 1], 4: [-1, 1]}
|
|
368
|
+
elif self.strands['poles'] == 4:
|
|
369
|
+
mirror_components = {2: [1, -1], 3: [-1, -1], 4: [-1, 1]}
|
|
370
|
+
elif self.data.magnet.geometry.electromagnetics.symmetry == 'x':
|
|
371
|
+
if self.strands['poles'] == 2:
|
|
372
|
+
mirror_components = {3: [-1, 1], 4: [-1, 1]}
|
|
373
|
+
elif self.strands['poles'] == 4:
|
|
374
|
+
mirror_components = {3: [-1, 1], 4: [-1, 1]}
|
|
375
|
+
elif self.data.magnet.geometry.electromagnetics.symmetry == 'y':
|
|
376
|
+
if self.strands['poles'] == 2:
|
|
377
|
+
mirror_components = {2: [-1, 1], 3: [-1, 1]}
|
|
378
|
+
elif self.strands['poles'] == 4:
|
|
379
|
+
mirror_components = {2: [1, -1], 3: [1, -1]}
|
|
380
|
+
else:
|
|
381
|
+
mirror_components = {}
|
|
382
|
+
|
|
383
|
+
print(f"Info : {self.data.general.magnet_name} - M i r r o r i n g . . .")
|
|
384
|
+
print(f"Info : Mirroring by symmetry ...")
|
|
385
|
+
blocks_nr = self.strands['block'][-1]
|
|
386
|
+
|
|
387
|
+
with open(f"{self.model_file}_EM.map2d", 'r') as file:
|
|
388
|
+
file_content = file.read()
|
|
389
|
+
content_by_row = file_content.split('\n')
|
|
390
|
+
new_content = [content_by_row[0] + '\n' + content_by_row[1] + '\n']
|
|
391
|
+
prev_block: int = 0
|
|
392
|
+
for row in content_by_row[2:-1]:
|
|
393
|
+
entries = row.split()
|
|
394
|
+
str_nr, x_coord, y_coord = entries[2], float(entries[3]), float(entries[4])
|
|
395
|
+
qdr = _quadrant(x_coord, y_coord)
|
|
396
|
+
if qdr in mirror_components:
|
|
397
|
+
#found = re.search(f" {str(abs(x_coord))} +{str(abs(y_coord))}", file_content)
|
|
398
|
+
#BB = [row_ref for row_ref in content_by_row if f" {abs(x_coord):.4f} {abs(y_coord):.4f}" in row_ref][0].split()[5:7]
|
|
399
|
+
BB = content_by_row[self.strands['mirrored'][str_nr] + 1].split()[5:7]
|
|
400
|
+
row = row.replace(entries[5], f'{mirror_components[qdr][0] * float(BB[0]):.4f}')
|
|
401
|
+
row = row.replace(entries[6], f'{mirror_components[qdr][1] * float(BB[1]):.4f}')
|
|
402
|
+
if int(entries[0]) > prev_block:
|
|
403
|
+
perc = round(int(entries[0]) / blocks_nr * 100)
|
|
404
|
+
print("Info : [" + f"{' ' if perc < 10 else ''}" + f"{' ' if perc < 100 else ''}" + f"{perc}" +
|
|
405
|
+
"%] Mirroring within block" + f"{entries[0]}")
|
|
406
|
+
prev_block = int(entries[0])
|
|
407
|
+
new_content.append(row + '\n')
|
|
408
|
+
with open(f"{self.model_file}_EM.map2d", 'w') as file:
|
|
409
|
+
file.writelines(new_content)
|
|
410
|
+
print(f"Info : {self.data.general.magnet_name} - E n d M i r r o r i n g")
|