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.
Files changed (69) hide show
  1. fiqus/MainFiQuS.py +290 -134
  2. fiqus/data/DataConductor.py +301 -301
  3. fiqus/data/DataFiQuS.py +128 -84
  4. fiqus/data/DataFiQuSCCT.py +150 -150
  5. fiqus/data/DataFiQuSConductor.py +84 -84
  6. fiqus/data/DataFiQuSConductorAC_Strand.py +565 -565
  7. fiqus/data/DataFiQuSMultipole.py +716 -42
  8. fiqus/data/DataFiQuSPancake3D.py +737 -278
  9. fiqus/data/DataMultipole.py +180 -15
  10. fiqus/data/DataRoxieParser.py +90 -51
  11. fiqus/data/DataSettings.py +121 -0
  12. fiqus/data/DataWindingsCCT.py +37 -37
  13. fiqus/data/RegionsModelFiQuS.py +18 -6
  14. fiqus/geom_generators/GeometryCCT.py +905 -905
  15. fiqus/geom_generators/GeometryConductorAC_Strand.py +1391 -1391
  16. fiqus/geom_generators/GeometryMultipole.py +1827 -227
  17. fiqus/geom_generators/GeometryPancake3D.py +316 -117
  18. fiqus/geom_generators/GeometryPancake3DUtils.py +549 -0
  19. fiqus/getdp_runners/RunGetdpCCT.py +4 -4
  20. fiqus/getdp_runners/RunGetdpConductorAC_Strand.py +201 -201
  21. fiqus/getdp_runners/RunGetdpMultipole.py +115 -42
  22. fiqus/getdp_runners/RunGetdpPancake3D.py +28 -6
  23. fiqus/mains/MainCCT.py +2 -2
  24. fiqus/mains/MainConductorAC_Strand.py +132 -132
  25. fiqus/mains/MainMultipole.py +113 -62
  26. fiqus/mains/MainPancake3D.py +63 -23
  27. fiqus/mesh_generators/MeshCCT.py +209 -209
  28. fiqus/mesh_generators/MeshConductorAC_Strand.py +656 -656
  29. fiqus/mesh_generators/MeshMultipole.py +1243 -181
  30. fiqus/mesh_generators/MeshPancake3D.py +275 -192
  31. fiqus/parsers/ParserCOND.py +825 -0
  32. fiqus/parsers/ParserDAT.py +16 -16
  33. fiqus/parsers/ParserGetDPOnSection.py +212 -212
  34. fiqus/parsers/ParserGetDPTimeTable.py +134 -134
  35. fiqus/parsers/ParserMSH.py +53 -53
  36. fiqus/parsers/ParserPOS.py +214 -214
  37. fiqus/parsers/ParserRES.py +142 -142
  38. fiqus/plotters/PlotPythonCCT.py +133 -133
  39. fiqus/plotters/PlotPythonConductorAC.py +855 -855
  40. fiqus/plotters/PlotPythonMultipole.py +18 -18
  41. fiqus/post_processors/PostProcessCCT.py +440 -440
  42. fiqus/post_processors/PostProcessConductorAC.py +49 -49
  43. fiqus/post_processors/PostProcessMultipole.py +353 -229
  44. fiqus/post_processors/PostProcessPancake3D.py +8 -13
  45. fiqus/pre_processors/PreProcessCCT.py +175 -175
  46. fiqus/pro_assemblers/ProAssembler.py +14 -6
  47. fiqus/pro_material_functions/ironBHcurves.pro +246 -246
  48. fiqus/pro_templates/combined/CCT_template.pro +274 -274
  49. fiqus/pro_templates/combined/ConductorAC_template.pro +1025 -1025
  50. fiqus/pro_templates/combined/Multipole_template.pro +1694 -126
  51. fiqus/pro_templates/combined/Pancake3D_template.pro +2294 -1103
  52. fiqus/pro_templates/combined/TSA_materials.pro +162 -0
  53. fiqus/pro_templates/combined/materials.pro +36 -18
  54. fiqus/utils/Utils.py +508 -110
  55. fiqus/utils/update_data_settings.py +33 -0
  56. fiqus-2024.12.0.dist-info/METADATA +130 -0
  57. fiqus-2024.12.0.dist-info/RECORD +84 -0
  58. {fiqus-2024.7.0.dist-info → fiqus-2024.12.0.dist-info}/WHEEL +1 -1
  59. tests/test_FiQuS.py +1 -1
  60. tests/test_geometry_generators.py +101 -2
  61. tests/test_mesh_generators.py +154 -1
  62. tests/test_solvers.py +115 -21
  63. tests/utils/fiqus_test_classes.py +85 -21
  64. tests/utils/generate_reference_files_ConductorAC.py +57 -57
  65. tests/utils/generate_reference_files_Pancake3D.py +4 -5
  66. tests/utils/helpers.py +97 -97
  67. fiqus-2024.7.0.dist-info/METADATA +0 -103
  68. fiqus-2024.7.0.dist-info/RECORD +0 -79
  69. {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 as Pars
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, sett: dF.FiQuSSettings() = None, solution_folder: str = 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.BB_err_mean = []
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.geom_folder = os.path.dirname(os.path.dirname(self.solution_folder))
40
- self.model_file = f"{os.path.join(self.solution_folder, self.data.general.magnet_name)}.map2d"
41
-
42
- self.II = (self.set.Model_Data_GS.general_parameters.I_ref[0] if self.data.magnet.postproc.compare_to_ROXIE
43
- else self.data.magnet.solve.I_initial[0])
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 self.data.magnet.postproc.plot_all != 'False':
76
+ if settings.plot_all != 'false':
46
77
  self.fiqus = None
47
78
  self.roxie = None
48
- plt.figure(1)
49
- self.ax = plt.axes()
50
- self.ax.set_xlabel('x [m]')
51
- self.ax.set_ylabel('y [m]')
52
- self.ax.set_xlim(0, 0.09)
53
- self.ax.set_ylim(0, 0.04)
54
-
55
- if self.data.magnet.postproc.compare_to_ROXIE:
56
- fig2 = plt.figure(2)
57
- self.ax2 = fig2.add_subplot(projection='3d')
58
- self.ax2.set_xlabel('x [m]')
59
- self.ax2.set_ylabel('y [m]')
60
- self.ax2.set_zlabel('Absolute Error [T]')
61
- self.fig4 = plt.figure(4)
62
- self.ax4 = plt.axes()
63
- self.ax4.set_xlabel('x [cm]')
64
- self.ax4.set_ylabel('y [cm]')
65
- self.ax4.set_aspect('equal', 'box')
66
- fig3 = plt.figure(3)
67
- self.ax3 = fig3.add_subplot(projection='3d')
68
- self.ax3.set_xlabel('x [m]')
69
- self.ax3.set_ylabel('y [m]')
70
- self.ax3.set_zlabel('norm(B) [T]')
71
-
72
- name = 'b_Omega_p'
73
- gmsh.open(os.path.join(self.solution_folder, f"{name}.pos"))
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 loadStrandPositions(self):
83
- self.strands = json.load(open(f"{os.path.join(self.geom_folder, self.data.general.magnet_name)}.strs"))
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"{os.path.join(self.geom_folder, self.data.general.magnet_name)}.crns"))
87
-
88
- def plotHalfTurnGeometry(self):
89
- for i in range(len(self.crns['iL'])):
90
- self.ax.add_line(lines.Line2D([self.crns['iL'][i][0], self.crns['iR'][i][0]],
91
- [self.crns['iL'][i][1], self.crns['iR'][i][1]], color='green'))
92
- self.ax.add_line(lines.Line2D([self.crns['oL'][i][0], self.crns['oR'][i][0]],
93
- [self.crns['oL'][i][1], self.crns['oR'][i][1]], color='green'))
94
- self.ax.add_line(lines.Line2D([self.crns['oR'][i][0], self.crns['iR'][i][0]],
95
- [self.crns['oR'][i][1], self.crns['iR'][i][1]], color='green'))
96
- self.ax.add_line(lines.Line2D([self.crns['iL'][i][0], self.crns['oL'][i][0]],
97
- [self.crns['iL'][i][1], self.crns['oL'][i][1]], color='green'))
98
- cc_fiqus = Func.centroid([self.crns['iL'][i][0], self.crns['iR'][i][0],
99
- self.crns['oR'][i][0], self.crns['oL'][i][0]],
100
- [self.crns['iL'][i][1], self.crns['iR'][i][1],
101
- self.crns['oR'][i][1], self.crns['oL'][i][1]])
102
-
103
- if self.data.magnet.postproc.compare_to_ROXIE:
104
- self.ax.add_line(lines.Line2D([self.crns['iLr'][i][0], self.crns['iRr'][i][0]],
105
- [self.crns['iLr'][i][1], self.crns['iRr'][i][1]],
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['oLr'][i][0], self.crns['oRr'][i][0]],
108
- [self.crns['oLr'][i][1], self.crns['oRr'][i][1]],
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['oRr'][i][0], self.crns['iRr'][i][0]],
111
- [self.crns['oRr'][i][1], self.crns['iRr'][i][1]],
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['iLr'][i][0], self.crns['oLr'][i][0]],
114
- [self.crns['iLr'][i][1], self.crns['oLr'][i][1]],
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['iLr'][i][0], self.crns['iRr'][i][0], self.crns['oRr'][i][0], self.crns['oLr'][i][0]],
118
- [self.crns['iLr'][i][1], self.crns['iRr'][i][1], self.crns['oRr'][i][1], self.crns['oLr'][i][1]])
119
-
120
- self.fiqus = self.ax.scatter(cc_fiqus[0], cc_fiqus[1], c="green")
121
- if self.data.magnet.postproc.compare_to_ROXIE:
122
- self.roxie = self.ax.scatter(cc_roxie[0], cc_roxie[1], edgecolor='r', facecolor='none')
123
-
124
- def postProcess(self):
125
- def _printState(bb):
126
- perc = round(bb / blocks_nr * 100)
127
- print("Info : [" + f"{' ' if perc < 10 else ''}" + f"{' ' if perc < 100 else ''}" + f"{perc}" +
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(roxie_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
- matrix = Pars.parseMap2d(map2dFile=path_map2d)
209
-
210
- if self.data.magnet.postproc.plot_all != 'False':
211
- path_cond2d = Path(os.path.join(os.path.dirname(roxie_path), self.data.general.magnet_name + ".cond2d"))
212
- # path_cond2d = Path(os.path.dirname(roxie_path), "MQXA_All_NoIron_NoSelfField" +
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
- conductorPositionsList = Pars.parseCond2d(path_cond2d)
215
-
216
- with open(self.model_file, 'w') as file:
217
- file.write(" BL. COND. NO. X-POS/MM Y-POS/MM BX/T BY/T"
218
- " AREA/MM**2 CURRENT FILL FAC.\n\n")
219
-
220
- cond_nr = 0
221
- row = 0
222
- c_nr_list = [] # list of conductors per block
223
- blocks_nr = self.strands['block'][-1]
224
- blocks, hts = np.array(self.strands['block']), np.array(self.strands['ht'])
225
- for blk in range(blocks_nr):
226
- _printState(blk + 1)
227
- c_nr_list.append(hts[np.where(blocks == blk + 1)[0][-1]] - sum(c_nr_list))
228
- for c in range(c_nr_list[blk]):
229
- parser_x, parser_y, roxie_x, roxie_y, strands_area, BB_roxie, BB_roxie_x, BB_roxie_y = \
230
- [], [], [], [], [], [], [], []
231
- strands = 0
232
- ht = hts[row]
233
- while ht == c + 1 + cond_nr and row < len(self.strands['x']):
234
- parser_x.append(self.strands['x'][row])
235
- parser_y.append(self.strands['y'][row])
236
- if self.data.magnet.postproc.compare_to_ROXIE:
237
- _fetchRoxieData()
238
- strands += 1
239
- row += 1
240
- if row < len(self.strands['x']) - 1:
241
- ht = hts[row]
242
-
243
- strands_x = roxie_x if self.data.magnet.postproc.compare_to_ROXIE else parser_x
244
- strands_y = roxie_y if self.data.magnet.postproc.compare_to_ROXIE else parser_y
245
-
246
- BB_strands_x, BB_strands_y, BB_strands = _probeFromView()
247
-
248
- _updateMap2dFile(blk + 1, c + 1 + cond_nr)
249
-
250
- if self.data.magnet.postproc.compare_to_ROXIE:
251
- BB_abs_err = _computeError()
252
-
253
- if self.data.magnet.postproc.plot_all != 'False': # and (blk == 0 or blk == 1):
254
- if self.data.magnet.postproc.compare_to_ROXIE:
255
- map2d_strands, scatter3D_pos_roxie, scatter3D_pos = _plotData()
256
- else:
257
- scatter3D_pos = _plotData()[2]
258
-
259
- cond_nr += c_nr_list[blk]
260
-
261
- if self.data.magnet.postproc.compare_to_ROXIE:
262
- self.postprocess_parameters['overall_error'] = np.linalg.norm(self.BB_err_mean)
263
- self.postprocess_parameters['minimum_diff'] = np.min(self.BB_err_mean)
264
- self.postprocess_parameters['maximum_diff'] = np.max(self.BB_err_mean)
265
-
266
- print(f"Info : {self.data.general.magnet_name} - E n d I n t e r p o l a t i n g")
267
-
268
- if self.data.magnet.postproc.plot_all != 'False' and self.data.magnet.postproc.plot_all != False:
269
- self.plotHalfTurnGeometry()
270
- if self.data.magnet.postproc.compare_to_ROXIE:
271
- cax4 = self.fig4.add_axes([self.ax4.get_position().x1 + 0.02, self.ax4.get_position().y0,
272
- 0.02, self.ax4.get_position().height])
273
- cbar = plt.colorbar(self.ax4.get_children()[2], cax=cax4)
274
- cbar.ax.set_ylabel('Absolute error [mT]', rotation=270)
275
- self.ax3.legend([scatter3D_pos, scatter3D_pos_roxie], ['FiQuS', 'ROXIE'], numpoints=1)
276
- # pickle.dump(fig, open('Bfield.fig.pickle', 'wb'))
277
- self.ax.legend([self.fiqus, self.roxie, map2d_strands], ['FiQuS', 'ROXIEparser', 'ROXIE'], numpoints=1)
278
-
279
- self.fig4.savefig(f"{os.path.join(self.solution_folder, self.data.general.magnet_name)}.svg", bbox_inches='tight')
280
-
281
- if self.data.magnet.postproc.plot_all == 'True':
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")