fiqus 2024.6.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 -840
  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.6.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.6.0.dist-info/METADATA +0 -103
  68. fiqus-2024.6.0.dist-info/RECORD +0 -79
  69. {fiqus-2024.6.0.dist-info → fiqus-2024.12.0.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import gmsh
3
- from numpy import square as square
4
- from numpy import sqrt as sqrt
3
+ import numpy as np
4
+ import pandas as pd
5
5
  import json
6
6
 
7
7
  from fiqus.utils.Utils import GmshUtils
@@ -9,32 +9,45 @@ from fiqus.utils.Utils import FilesAndFolders as Util
9
9
  from fiqus.utils.Utils import GeometricFunctions as Func
10
10
  from fiqus.data import DataFiQuS as dF
11
11
  from fiqus.data import DataMultipole as dM
12
+ from fiqus.data.DataRoxieParser import Corner
13
+ from fiqus.data.DataRoxieParser import Coord
12
14
 
13
15
 
14
16
  class Geometry:
15
- def __init__(self, data: dF.FDM() = None, geom: dF.FiQuSGeometry() = None, sett: dF.FiQuSSettings() = None,
17
+ def __init__(self, data: dF.FDM() = None, geom: dF.FiQuSGeometry() = None,
16
18
  geom_folder: str = None, verbose: bool = False):
17
19
  """
18
20
  Class to generate geometry
19
21
  :param data: FiQuS data model
20
22
  :param geom: ROXIE geometry data
21
- :param sett: settings data model
22
23
  :param verbose: If True more information is printed in python console.
23
24
  """
24
25
  self.data: dF.FDM() = data
25
- self.geom: dF.FiQuSGeometry() = geom
26
- self.sett: dF.FiQuSSettings() = sett
26
+ self.geom: dF.RoxieData() = geom.Roxie_Data
27
27
  self.geom_folder = geom_folder
28
28
  self.verbose: bool = verbose
29
29
 
30
30
  self.md = dM.MultipoleData()
31
31
 
32
32
  self.gu = GmshUtils(self.geom_folder, self.verbose)
33
- self.gu.initialize()
33
+ self.gu.initialize(verbosity_Gmsh=self.data.run.verbosity_Gmsh)
34
34
  self.occ = gmsh.model.occ
35
35
 
36
- self.model_file = f"{os.path.join(self.geom_folder, self.data.general.magnet_name)}.brep"
37
- self.iL, self.iR, self.oL, self.oR, self.iLr, self.iRr, self.oLr, self.oRr = [], [], [], [], [], [], [], []
36
+ self.model_file = os.path.join(self.geom_folder, self.data.general.magnet_name)
37
+
38
+ self.blk_ins_lines = {} # for meshed insulation
39
+ self.ins_wire_lines = {} # for meshed insulation
40
+ self.block_coil_mid_pole_blks = {}
41
+
42
+ if self.data.magnet.geometry.electromagnetics.symmetry != 'none':
43
+ self.symmetric_loop_lines = {'x': [], 'y': []}
44
+ self.symmetric_bnds = {'x_p': {'pnts': [], 'line_pnts': []}, 'y_p': {'pnts': [], 'line_pnts': []},
45
+ 'x_n': {'pnts': [], 'line_pnts': []}, 'y_n': {'pnts': [], 'line_pnts': []}}
46
+
47
+ def clear(self):
48
+ self.md = dM.MultipoleData()
49
+ self.block_coil_mid_pole_blks = {}
50
+ gmsh.clear()
38
51
 
39
52
  def ending_step(self, gui: bool = False):
40
53
  if gui:
@@ -44,161 +57,902 @@ class Geometry:
44
57
  gmsh.finalize()
45
58
 
46
59
  def saveHalfTurnCornerPositions(self):
47
- json.dump({'iL': self.iL, 'iR': self.iR, 'oL': self.oL, 'oR': self.oR,
48
- 'iLr': self.iLr, 'iRr': self.iRr, 'oLr': self.oLr, 'oRr': self.oRr},
49
- open(f"{os.path.join(self.geom_folder, self.data.general.magnet_name)}.crns", 'w'))
60
+ self.occ.synchronize()
61
+ iH, iL, oH, oL, iHr, iLr, oHr, oLr = [], [], [], [], [], [], [], []
62
+ for po in self.geom.coil.physical_order:
63
+ block = self.geom.coil.coils[po.coil].poles[po.pole].layers[po.layer].windings[
64
+ po.winding].blocks[po.block]
65
+ for halfTurn_nr, halfTurn in block.half_turns.items():
66
+ ht = halfTurn.corners.insulated
67
+ ht_b = halfTurn.corners.bare
68
+ iHr.append([ht_b.iH.x, ht_b.iH.y])
69
+ iLr.append([ht_b.iL.x, ht_b.iL.y])
70
+ oHr.append([ht_b.oH.x, ht_b.oH.y])
71
+ oLr.append([ht_b.oL.x, ht_b.oL.y])
72
+ iH.append([ht.iH.x, ht.iH.y])
73
+ iL.append([ht.iL.x, ht.iL.y])
74
+ oH.append([ht.oH.x, ht.oH.y])
75
+ oL.append([ht.oL.x, ht.oL.y])
76
+ json.dump({'iH': iH, 'iL': iL, 'oH': oH, 'oL': oL,
77
+ 'iHr': iHr, 'iLr': iLr, 'oHr': oHr, 'oLr': oLr}, open(f"{self.model_file}.crns", 'w'))
50
78
 
51
- def saveStrandPositions(self):
79
+ def saveStrandPositions(self, run_type):
80
+ symmetry = self.data.magnet.geometry.electromagnetics.symmetry if run_type == 'EM' else 'none'
52
81
  ht_nr = 0
53
- parser_x, parser_y, blocks, ht = [], [], [], []
54
- for eo in self.geom.Roxie_Data.coil.electrical_order:
55
- block = self.geom.Roxie_Data.coil.coils[eo.coil].poles[eo.pole].layers[eo.layer].windings[
56
- eo.winding].blocks[eo.block]
82
+ std_nr = 0
83
+ parser_x, parser_y, blocks, ht, std, pole_blocks = [], [], [], [], [], []
84
+ for po in self.geom.coil.physical_order:
85
+ block = self.geom.coil.coils[po.coil].poles[po.pole].layers[po.layer].windings[
86
+ po.winding].blocks[po.block]
87
+ if po.pole == 1: pole_blocks.append(po.block)
57
88
  for halfTurn_nr, halfTurn in block.half_turns.items():
58
89
  ht_nr += 1
59
90
  for strand_group_nr, strand_group in halfTurn.strand_groups.items():
60
91
  for strand_nr, strand in strand_group.strand_positions.items():
61
- blocks.append(eo.block)
92
+ std_nr += 1
93
+ blocks.append(po.block)
62
94
  ht.append(ht_nr)
95
+ std.append(std_nr)
63
96
  parser_x.append(strand.x)
64
97
  parser_y.append(strand.y)
65
- json.dump({'x': parser_x, 'y': parser_y, 'block': blocks, 'ht': ht},
66
- open(f"{os.path.join(self.geom_folder, self.data.general.magnet_name)}.strs", 'w'))
98
+ mirrored = {}
99
+ condition = {2: [1, -1], 3: [1, 1], 4: [-1, 1]}
100
+ if symmetry == 'xy': mirroring = {2: [-1, 1], 3: [-1, -1], 4: [1, -1]}
101
+ elif symmetry == 'x': mirroring = {3: [1, -1], 4: [1, -1]}
102
+ elif symmetry == 'y': mirroring = {2: [-1, 1], 3: [-1, 1]}
103
+ else: mirroring = {}
104
+ if mirroring:
105
+ df = pd.DataFrame({'parser_x': parser_x, 'parser_y': parser_y}, index=std)
106
+ for qdr, mrr in mirroring.items():
107
+ subdf = df[(condition[qdr][0] * df['parser_x'] < 0) & (condition[qdr][1] * df['parser_y'] < 0)]
108
+ for strand, x, y in zip(subdf.index, subdf['parser_x'], subdf['parser_y']):
109
+ mirrored[strand] = df[(df['parser_x'] == mrr[0] * x) & (df['parser_y'] == mrr[1] * y)].index.item()
110
+ json.dump({'x': parser_x, 'y': parser_y, 'block': blocks, 'ht': ht, 'mirrored': mirrored,
111
+ 'pole_1_blocks': pole_blocks, 'poles': len(self.geom.coil.coils[1].poles)},
112
+ open(f"{self.model_file}_{run_type}.strs", 'w'))
67
113
 
68
- def saveBoundaryRepresentationFile(self):
114
+ def saveBoundaryRepresentationFile(self, run_type):
69
115
  self.occ.synchronize()
70
- gmsh.write(self.model_file)
116
+ gmsh.write(f'{self.model_file}_{run_type}.brep')
71
117
  gmsh.clear()
72
118
 
73
- def loadBoundaryRepresentationFile(self):
119
+ def loadBoundaryRepresentationFile(self, run_type):
74
120
  gmsh.option.setString('Geometry.OCCTargetUnit', 'M') # set units to meters
75
- gmsh.open(self.model_file)
121
+ gmsh.open(os.path.join(f'{self.model_file}_{run_type}.brep'))
122
+
123
+ def saveAuxiliaryFile(self, run_type):
124
+ Util.write_data_to_yaml(f'{self.model_file}_{run_type}.aux', self.md.dict())
125
+
126
+ @staticmethod
127
+ def findMidLayerPoint(bc_current, bc_next, center, mean_rad):
128
+ mid_layer = [(bc_current.x + bc_next.x) / 2, (bc_current.y + bc_next.y) / 2]
129
+ mid_rad = Func.points_distance(mid_layer, [center.x, center.y])
130
+ dist_from_mid = mean_rad - mid_rad
131
+ angle = Func.arc_angle_between_point_and_abscissa(mid_layer, [center.x, center.y])
132
+ mid_layer[0] += dist_from_mid * np.cos(angle)
133
+ mid_layer[1] += dist_from_mid * np.sin(angle)
134
+ return mid_layer
76
135
 
77
- def saveAuxiliaryFile(self):
78
- Util.write_data_to_yaml(f"{os.path.join(self.geom_folder, self.data.general.magnet_name)}.aux", self.md.dict())
136
+ @staticmethod
137
+ def getMidLayerEndpoints(el_current, el_next, center, mid_layer_arc_pnt=None, coil_type='cos-theta', cable_type='Rutherford', is_for_mid_pole=False):
138
+ thin_shell_endpoints = {'higher': list, 'lower': list}
139
+ which_block = {'higher': str, 'lower': str}
140
+ angles = {'higher': float, 'lower': float}
141
+ # Check if the element crosses the x axis
142
+ angles_to_correct = []
143
+ correction_angle = 0
144
+ l_curr = Func.arc_angle_between_point_and_abscissa([el_current.iL.x, el_current.iL.y], center)
145
+ h_curr = Func.arc_angle_between_point_and_abscissa([el_current.iH.x, el_current.iH.y], center)
146
+ l_next = Func.arc_angle_between_point_and_abscissa([el_next.iL.x, el_next.iL.y], center)
147
+ h_next = Func.arc_angle_between_point_and_abscissa([el_next.iH.x, el_next.iH.y], center)
148
+ if abs(l_curr - h_curr) > np.pi:
149
+ angles_to_correct.append('current')
150
+ correction_angle = max(1.05 * (2 * np.pi - l_curr), correction_angle)
151
+ if abs(l_next - h_next) > np.pi:
152
+ angles_to_correct.append('next')
153
+ correction_angle = max(1.05 * (2 * np.pi - l_next), correction_angle)
154
+ for side in thin_shell_endpoints.keys():
155
+ if mid_layer_arc_pnt:
156
+ if side == 'higher':
157
+ mid_lyr_curr, mid_lyr_next = [el_current.oH, el_current.iH], [el_next.oH, el_next.iH]
158
+ else:
159
+ mid_lyr_curr, mid_lyr_next = [el_current.oL, el_current.iL], [el_next.oL, el_next.iL]
160
+ if cable_type in ['Mono', 'Ribbon']:
161
+ pnts_curr = Func.intersection_between_circle_and_line(
162
+ Func.line_through_two_points([mid_lyr_curr[0].x, mid_lyr_curr[0].y], [mid_lyr_curr[1].x, mid_lyr_curr[1].y]),
163
+ [center, mid_layer_arc_pnt])
164
+ pnt_curr = pnts_curr[0] if Func.points_distance(pnts_curr[0], [mid_lyr_curr[0].x, mid_lyr_curr[0].y]) <\
165
+ Func.points_distance(pnts_curr[1], [mid_lyr_curr[0].x, mid_lyr_curr[0].y]) else pnts_curr[1]
166
+ pnts_next = Func.intersection_between_circle_and_line(
167
+ Func.line_through_two_points([mid_lyr_next[0].x, mid_lyr_next[0].y], [mid_lyr_next[1].x, mid_lyr_next[1].y]),
168
+ [center, mid_layer_arc_pnt])
169
+ pnt_next = pnts_next[0] if Func.points_distance(pnts_next[0], [mid_lyr_next[0].x, mid_lyr_next[0].y]) <\
170
+ Func.points_distance(pnts_next[1], [mid_lyr_next[0].x, mid_lyr_next[0].y]) else pnts_next[1]
171
+ elif cable_type == 'Rutherford':
172
+ pnt_curr = Func.intersection_between_circle_and_line(
173
+ Func.line_through_two_points([mid_lyr_curr[0].x, mid_lyr_curr[0].y], [mid_lyr_curr[1].x, mid_lyr_curr[1].y]),
174
+ [center, mid_layer_arc_pnt], get_only_closest=True)[0]
175
+ pnt_next = Func.intersection_between_circle_and_line(
176
+ Func.line_through_two_points([mid_lyr_next[0].x, mid_lyr_next[0].y], [mid_lyr_next[1].x, mid_lyr_next[1].y]),
177
+ [center, mid_layer_arc_pnt], get_only_closest=True)[0]
178
+ else:
179
+ if cable_type == 'Rutherford':
180
+ if coil_type == 'common-block-coil':
181
+ mid_layer_x = (el_current.oH.x + el_next.iH.x) / 2
182
+ if side == 'higher':
183
+ pnt_curr, pnt_next = [mid_layer_x, el_current.iH.y], [mid_layer_x, el_next.iH.y]
184
+ else:
185
+ pnt_curr, pnt_next = [mid_layer_x, el_current.iL.y], [mid_layer_x, el_next.iL.y]
186
+ else:
187
+ mid_layer_y = (el_current.iH.y + el_next.iH.y) / 2 if is_for_mid_pole else (el_current.oH.y + el_next.iH.y) / 2
188
+ if side == 'higher':
189
+ pnt_curr, pnt_next = [el_current.iH.x, mid_layer_y], [el_next.iL.x if is_for_mid_pole else el_next.iH.x, mid_layer_y]
190
+ else:
191
+ pnt_curr, pnt_next = [el_current.iL.x, mid_layer_y], [el_next.iH.x if is_for_mid_pole else el_next.iL.x, mid_layer_y]
192
+ elif cable_type in ['Mono', 'Ribbon']:
193
+ pnt_curr = [(el_current.oH.x + el_next.iH.x) / 2, (el_current.oH.y + el_next.iH.y) / 2] if side == 'higher'\
194
+ else [(el_current.oL.x + el_next.iL.x) / 2, (el_current.oL.y + el_next.iL.y) / 2]
195
+ pnt_next = pnt_curr
196
+ angle_curr = Func.arc_angle_between_point_and_abscissa(pnt_curr, center)
197
+ angle_next = Func.arc_angle_between_point_and_abscissa(pnt_next, center)
198
+ if 'current' in angles_to_correct:
199
+ angle_curr = angle_curr + correction_angle - (2 * np.pi if side == 'lower' else 0)
200
+ elif 'next' in angles_to_correct:
201
+ if angle_curr < np.pi / 2: angle_curr += correction_angle
202
+ elif angle_curr > np.pi * 3 / 2: angle_curr = angle_curr + correction_angle - 2 * np.pi
203
+ if 'next' in angles_to_correct:
204
+ angle_next = angle_next + correction_angle - (2 * np.pi if side == 'lower' else 0)
205
+ elif 'current' in angles_to_correct:
206
+ if angle_next < np.pi / 2: angle_next += correction_angle
207
+ elif angle_next > np.pi * 3 / 2: angle_next = angle_next + correction_angle - 2 * np.pi
208
+ if abs(angle_curr - angle_next) < 1e-6: # todo: check if needed
209
+ thin_shell_endpoints[side], angles[side], which_block[side] = pnt_curr, angle_curr, 'current'
210
+ elif angle_curr * (-1 if side == 'lower' else 1) < angle_next * (-1 if side == 'lower' else 1):
211
+ thin_shell_endpoints[side], angles[side], which_block[side] = pnt_curr, angle_curr, 'current'
212
+ else:
213
+ thin_shell_endpoints[side], angles[side], which_block[side] = pnt_next, angle_next, 'next'
214
+ if angles['higher'] < angles['lower']: return None
215
+ else: return thin_shell_endpoints, which_block
79
216
 
80
- def constructIronGeometry(self):
217
+ def constructIronGeometry(self, symmetry):
81
218
  """
82
219
  Generates points, hyper lines, and curve loops for the iron yoke
83
220
  """
84
- iron = self.geom.Roxie_Data.iron
85
- self.md.geometries.iron.quadrants = {1: dM.Region(), 2: dM.Region(), 3: dM.Region(), 4: dM.Region()}
221
+ iron = self.geom.iron
222
+ if symmetry == 'xy':
223
+ self.md.geometries.iron.quadrants = {1: dM.Region()}
224
+ list_bnds = ['x_p', 'y_p']
225
+ elif symmetry == 'x':
226
+ self.md.geometries.iron.quadrants = {1: dM.Region(), 2: dM.Region()}
227
+ list_bnds = ['x_p', 'x_n']
228
+ elif symmetry == 'y':
229
+ self.md.geometries.iron.quadrants = {1: dM.Region(), 4: dM.Region()}
230
+ list_bnds = ['y_p', 'y_n']
231
+ else:
232
+ self.md.geometries.iron.quadrants = {1: dM.Region(), 2: dM.Region(), 4: dM.Region(), 3: dM.Region()}
233
+ list_bnds = []
86
234
  quadrants = self.md.geometries.iron.quadrants
87
235
 
88
236
  lc = 1e-2
89
237
  for point_name, point in iron.key_points.items():
238
+ if symmetry in ['x', 'xy']:
239
+ if point.y == 0.:
240
+ self.symmetric_bnds['x_p']['pnts'].append([point_name, point.x])
241
+ if symmetry in ['y', 'xy']:
242
+ if point.x == 0.:
243
+ self.symmetric_bnds['y_p']['pnts'].append([point_name, point.y])
90
244
  quadrants[1].points[point_name] = self.occ.addPoint(point.x, point.y, 0, lc)
91
-
92
- if point.x == 0.:
93
- quadrants[2].points[point_name] = quadrants[1].points[point_name]
94
- else:
95
- quadrants[2].points[point_name] = self.occ.copy([(0, quadrants[1].points[point_name])])[0][1]
96
- self.occ.mirror([(0, quadrants[2].points[point_name])], 1, 0, 0, 0)
97
- if point.y == 0.:
98
- quadrants[3].points[point_name] = quadrants[2].points[point_name]
99
- quadrants[4].points[point_name] = quadrants[1].points[point_name]
100
- else:
101
- quadrants[3].points[point_name] = self.occ.copy([(0, quadrants[2].points[point_name])])[0][1]
102
- self.occ.mirror([(0, quadrants[3].points[point_name])], 0, 1, 0, 0)
103
- quadrants[4].points[point_name] = self.occ.copy([(0, quadrants[1].points[point_name])])[0][1]
104
- self.occ.mirror([(0, quadrants[4].points[point_name])], 0, 1, 0, 0)
245
+ if symmetry in ['x', 'none']:
246
+ if point.x == 0.:
247
+ quadrants[2].points[point_name] = quadrants[1].points[point_name]
248
+ else:
249
+ quadrants[2].points[point_name] = self.occ.copy([(0, quadrants[1].points[point_name])])[0][1]
250
+ self.occ.mirror([(0, quadrants[2].points[point_name])], 1, 0, 0, 0)
251
+ if point.y == 0. and symmetry == 'x':
252
+ self.symmetric_bnds['x_n']['pnts'].append([point_name, point.x])
253
+ if symmetry in ['y', 'none']:
254
+ if point.y == 0.:
255
+ quadrants[4].points[point_name] = quadrants[1].points[point_name]
256
+ else:
257
+ quadrants[4].points[point_name] = self.occ.copy([(0, quadrants[1].points[point_name])])[0][1]
258
+ self.occ.mirror([(0, quadrants[4].points[point_name])], 0, 1, 0, 0)
259
+ if point.x == 0. and symmetry == 'y':
260
+ self.symmetric_bnds['y_n']['pnts'].append([point_name, point.y])
261
+ if symmetry == 'none':
262
+ if point.y == 0.:
263
+ quadrants[3].points[point_name] = quadrants[2].points[point_name]
264
+ elif point.x == 0.:
265
+ quadrants[3].points[point_name] = quadrants[4].points[point_name]
266
+ else:
267
+ quadrants[3].points[point_name] = self.occ.copy([(0, quadrants[2].points[point_name])])[0][1]
268
+ self.occ.mirror([(0, quadrants[3].points[point_name])], 0, 1, 0, 0)
105
269
 
106
270
  mirror_x = [1, -1, -1, 1]
107
271
  mirror_y = [1, 1, -1, -1]
272
+ symmetric_bnds_order = {'x': [], 'y': []}
273
+ sym_lines_tags = {'x_p': [], 'y_p': [], 'x_n': [], 'y_n': []}
108
274
  for line_name, line in iron.hyper_lines.items():
275
+ pt1 = iron.key_points[line.kp1]
276
+ pt2 = iron.key_points[line.kp2]
109
277
  if line.type == 'line':
110
278
  for quadrant, qq in quadrants.items():
111
279
  if quadrant == 1:
112
280
  qq.lines[line_name] = self.occ.addLine(qq.points[line.kp1], qq.points[line.kp2])
281
+ if pt1.y == 0. and pt2.y == 0. and 'x_p' in list_bnds:
282
+ self.symmetric_bnds['x_p']['line_pnts'].append(line.kp1 + '_' + line.kp2)
283
+ sym_lines_tags['x_p'].append(qq.lines[line_name])
284
+ symmetric_bnds_order['x'].append(min(pt1.x, pt2.x))
285
+ elif pt1.x == 0. and pt2.x == 0. and 'y_p' in list_bnds:
286
+ self.symmetric_bnds['y_p']['line_pnts'].append(line.kp1 + '_' + line.kp2)
287
+ sym_lines_tags['y_p'].append(qq.lines[line_name])
288
+ symmetric_bnds_order['y'].append(min(pt1.y, pt2.y))
113
289
  elif quadrant == 2:
114
- if iron.key_points[line.kp1].x == 0. and iron.key_points[line.kp2].x == 0.:
290
+ if pt1.x == 0. and pt2.x == 0.:
115
291
  qq.lines[line_name] = quadrants[1].lines[line_name]
116
292
  else:
117
293
  qq.lines[line_name] = self.occ.addLine(qq.points[line.kp1], qq.points[line.kp2])
118
- elif quadrant == 3:
119
- if iron.key_points[line.kp1].y == 0. and iron.key_points[line.kp2].y == 0.:
120
- qq.lines[line_name] = quadrants[2].lines[line_name]
294
+ if pt1.y == 0. and pt2.y == 0. and 'x_n' in list_bnds:
295
+ self.symmetric_bnds['x_n']['line_pnts'].append(line.kp1 + '_' + line.kp2)
296
+ sym_lines_tags['x_n'].append(qq.lines[line_name])
297
+ elif quadrant == 4:
298
+ if pt1.y == 0. and pt2.y == 0.:
299
+ qq.lines[line_name] = quadrants[1].lines[line_name]
121
300
  else:
122
301
  qq.lines[line_name] = self.occ.addLine(qq.points[line.kp1], qq.points[line.kp2])
123
- else:
124
- if iron.key_points[line.kp1].y == 0. and iron.key_points[line.kp2].y == 0.:
125
- qq.lines[line_name] = quadrants[1].lines[line_name]
302
+ if pt1.x == 0. and pt2.x == 0. and 'y_n' in list_bnds:
303
+ self.symmetric_bnds['y_n']['line_pnts'].append(line.kp1 + '_' + line.kp2)
304
+ sym_lines_tags['y_n'].append(qq.lines[line_name])
305
+ else: # 3
306
+ if pt1.y == 0. and pt2.y == 0.:
307
+ qq.lines[line_name] = quadrants[2].lines[line_name]
308
+ elif pt1.x == 0. and pt2.x == 0.:
309
+ qq.lines[line_name] = quadrants[4].lines[line_name]
126
310
  else:
127
311
  qq.lines[line_name] = self.occ.addLine(qq.points[line.kp1], qq.points[line.kp2])
128
312
 
129
313
  elif line.type == 'arc':
130
- center = Func.arc_center_from_3_points(
131
- iron.key_points[line.kp1], iron.key_points[line.kp3], iron.key_points[line.kp2])
314
+ center = Func.arc_center_from_3_points([pt1.x, pt1.y],
315
+ [iron.key_points[line.kp3].x, iron.key_points[line.kp3].y],
316
+ [pt2.x, pt2.y])
132
317
  new_point_name = 'kp' + line_name + '_center'
133
- quadrants[1].points[new_point_name] = self.occ.addPoint(center[0], center[1], 0)
134
- # gmsh.model.setEntityName(0, gm.iron.quadrants[1].points[new_point_name], 'iron_' + new_point_name)
135
- if center[0] == 0.:
136
- quadrants[2].points[new_point_name] = quadrants[1].points[new_point_name]
137
- else:
138
- quadrants[2].points[new_point_name] = self.occ.copy([(0, quadrants[1].points[new_point_name])])[0][1]
139
- self.occ.mirror([(0, quadrants[2].points[new_point_name])], 1, 0, 0, 0)
140
- if center[1] == 0.:
141
- quadrants[3].points[new_point_name] = quadrants[2].points[new_point_name]
142
- quadrants[4].points[new_point_name] = quadrants[1].points[new_point_name]
318
+ arc_coordinates1 = (pt1.x, pt1.y)
319
+ arc_coordinates2 = (pt2.x, pt2.y)
320
+ arc_coordinates3 = (iron.key_points[line.kp3].x, iron.key_points[line.kp3].y)
321
+
322
+ # This code addresses a meshing error in MQXA and MB_2COILS that occurs when an arc is defined on any of
323
+ # the axes. The issue arises because the function Func.arc_center_from_3_points does not return exactly
324
+ # zero but a value with a magnitude of approximately 10^-17 when the two points are placed on the axes.
325
+ # Consequently, when using the method self.occ.addCircleArc(), which only takes in three points without
326
+ # specifying a direction, a problem arises. The addCircleArc() function always creates the arc with the
327
+ # smallest angle. However, since center point can be slightly above or below the axis, the arc can
328
+ # inadvertently be drawn in the wrong quadrant, leading to an incorrect result.
329
+ # -----------------------
330
+ # Check that arcs with points on the x-axis are drawn in the first quadrant
331
+ if arc_coordinates3[1] > 0 and arc_coordinates2[1] == 0 and arc_coordinates1[1] == 0 and center[1] > 0:
332
+ quadrants[1].points[new_point_name] = self.occ.addPoint(center[0], -center[1], 0)
333
+ # Check that arcs with points on the y-axis are drawn in the first quadrant
334
+ elif arc_coordinates3[0] > 0 and arc_coordinates2[0] == 0 and arc_coordinates1[0] == 0 and center[0] > 0:
335
+ quadrants[1].points[new_point_name] = self.occ.addPoint(-center[0], center[1], 0)
143
336
  else:
144
- quadrants[3].points[new_point_name] = self.occ.copy([(0, quadrants[2].points[new_point_name])])[0][1]
145
- self.occ.mirror([(0, quadrants[3].points[new_point_name])], 0, 1, 0, 0)
146
- quadrants[4].points[new_point_name] = self.occ.copy([(0, quadrants[1].points[new_point_name])])[0][1]
147
- self.occ.mirror([(0, quadrants[4].points[new_point_name])], 0, 1, 0, 0)
337
+ quadrants[1].points[new_point_name] = self.occ.addPoint(center[0], center[1], 0)
338
+ # -----------------------
339
+ # gmsh.model.setEntityName(0, gm.iron.quadrants[1].points[new_point_name], 'iron_' + new_point_name)
340
+ if symmetry in ['x', 'none']:
341
+ if center[0] == 0.:
342
+ quadrants[2].points[new_point_name] = quadrants[1].points[new_point_name]
343
+ else:
344
+ quadrants[2].points[new_point_name] = self.occ.copy([(0, quadrants[1].points[new_point_name])])[0][1]
345
+ self.occ.mirror([(0, quadrants[2].points[new_point_name])], 1, 0, 0, 0)
346
+ if symmetry in ['y', 'none']:
347
+ if center[1] == 0.:
348
+ quadrants[4].points[new_point_name] = quadrants[1].points[new_point_name]
349
+ else:
350
+ quadrants[4].points[new_point_name] = self.occ.copy([(0, quadrants[1].points[new_point_name])])[0][1]
351
+ self.occ.mirror([(0, quadrants[4].points[new_point_name])], 0, 1, 0, 0)
352
+ if symmetry == 'none':
353
+ if center[1] == 0.:
354
+ quadrants[3].points[new_point_name] = quadrants[2].points[new_point_name]
355
+ else:
356
+ quadrants[3].points[new_point_name] = self.occ.copy([(0, quadrants[2].points[new_point_name])])[0][1]
357
+ self.occ.mirror([(0, quadrants[3].points[new_point_name])], 0, 1, 0, 0)
148
358
 
149
359
  for quadrant, qq in quadrants.items():
150
360
  qq.lines[line_name] = self.occ.addCircleArc(
151
361
  qq.points[line.kp1], qq.points[new_point_name], qq.points[line.kp2])
152
362
 
153
363
  elif line.type == 'circle':
154
- pt1 = iron.key_points[line.kp1]
155
- pt2 = iron.key_points[line.kp2]
156
364
  center = [(pt1.x + pt2.x) / 2, (pt1.y + pt2.y) / 2]
157
- radius = (sqrt(square(pt1.x - center[0]) + square(pt1.y - center[1])) +
158
- sqrt(square(pt2.x - center[0]) + square(pt2.y - center[1]))) / 2
365
+ radius = (np.sqrt(np.square(pt1.x - center[0]) + np.square(pt1.y - center[1])) +
366
+ np.sqrt(np.square(pt2.x - center[0]) + np.square(pt2.y - center[1]))) / 2
159
367
 
160
368
  for quadrant, qq in quadrants.items():
161
369
  qq.lines[line_name] = self.occ.addCircle(
162
370
  mirror_x[quadrant - 1] * center[0], mirror_y[quadrant - 1] * center[1], 0, radius)
163
371
  qq.points['kp' + line_name] = len(qq.points) + 1
164
372
 
373
+ elif line.type == 'ellipticArc':
374
+ a, b = line.arg1, line.arg2
375
+ x1, y1 = pt1.x, pt1.y
376
+ x2, y2 = pt2.x, pt2.y
377
+ x3 = np.power(x1, 2.0)
378
+ y3 = np.power(y1, 2.0)
379
+ x4 = np.power(x2, 2.0)
380
+ y4 = np.power(y2, 2.0)
381
+ a2 = np.power(a, 2.0)
382
+ b2 = np.power(b, 2.0)
383
+ expression = -4.0 * a2 * b2 + a2 * y3 - 2.0 * a2 * y1 * y2 + a2 * y4 + b2 * x3 - 2.0 * b2 * x1 * x2 + b2 * x4
384
+ xc = x1 / 2.0 + x2 / 2.0 - a * np.power(- expression / (a2 * y3 - 2.0 * a2 * y1 * y2 + a2 * y4 + b2 * x3 -
385
+ 2.0 * b2 * x1 * x2 + b2 * x4), 0.5) * (y1 - y2) / (2.0 * b)
386
+ yc = y1 / 2.0 + y2 / 2.0 + b * np.power(- expression / (a2 * y3 - 2.0 * a2 * y1 * y2 + a2 * y4 + b2 * x3
387
+ - 2.0 * b2 * x1 * x2 + b2 * x4), 0.5) * (x1 - x2) / (2.0 * a)
388
+
389
+ center = self.occ.addPoint(xc, yc, 0, lc)
390
+ axis_point_a = self.occ.addPoint(xc + a, yc, 0, lc)
391
+ axis_point_b = self.occ.addPoint(xc, yc + b, 0, lc)
392
+
393
+ new_point_name = 'kp' + line_name + '_center'
394
+ new_axis_a_point_name = 'kp' + line_name + '_a'
395
+ new_axis_b_point_name = 'kp' + line_name + '_b'
396
+
397
+ quadrants[1].points[new_point_name] = center
398
+ quadrants[1].points[new_axis_a_point_name] = axis_point_a
399
+ quadrants[1].points[new_axis_b_point_name] = axis_point_b
400
+
401
+ if symmetry in ['x', 'none']:
402
+ if xc == 0.: # Least amount of possible points.
403
+ quadrants[2].points[new_point_name] = quadrants[1].points[new_point_name]
404
+ quadrants[2].points[new_axis_a_point_name] = quadrants[1].points[new_axis_a_point_name]
405
+ quadrants[2].points[new_axis_b_point_name] = quadrants[1].points[new_axis_b_point_name]
406
+ else:
407
+ quadrants[2].points[new_point_name] = self.occ.copy([(0, quadrants[1].points[new_point_name])])[0][1]
408
+ quadrants[2].points[new_axis_a_point_name] = self.occ.copy([(0, quadrants[1].points[new_axis_a_point_name])])[0][1]
409
+ quadrants[2].points[new_axis_b_point_name] = self.occ.copy([(0, quadrants[1].points[new_axis_b_point_name])])[0][1]
410
+ self.occ.mirror([(0, quadrants[2].points[new_point_name])], 1, 0, 0, 0)
411
+ self.occ.mirror([(0, quadrants[2].points[new_axis_a_point_name])], 1, 0, 0, 0)
412
+ self.occ.mirror([(0, quadrants[2].points[new_axis_b_point_name])], 1, 0, 0, 0)
413
+ if symmetry in ['y', 'none']:
414
+ if yc == 0.:
415
+ quadrants[4].points[new_point_name] = quadrants[1].points[new_point_name]
416
+ quadrants[4].points[new_axis_a_point_name] = quadrants[1].points[new_axis_a_point_name]
417
+ quadrants[4].points[new_axis_b_point_name] = quadrants[1].points[new_axis_b_point_name]
418
+ else:
419
+ quadrants[4].points[new_point_name] = self.occ.copy([(0, quadrants[1].points[new_point_name])])[0][1]
420
+ self.occ.mirror([(0, quadrants[4].points[new_point_name])], 0, 1, 0, 0)
421
+ quadrants[4].points[new_axis_a_point_name] = self.occ.copy([(0, quadrants[1].points[new_axis_a_point_name])])[0][1]
422
+ self.occ.mirror([(0, quadrants[4].points[new_axis_a_point_name])], 0, 1, 0, 0)
423
+ quadrants[4].points[new_axis_b_point_name] = self.occ.copy([(0, quadrants[1].points[new_axis_b_point_name])])[0][1]
424
+ self.occ.mirror([(0, quadrants[4].points[new_axis_b_point_name])], 0, 1, 0, 0)
425
+ if symmetry == 'none':
426
+ if yc == 0.:
427
+ quadrants[3].points[new_point_name] = quadrants[2].points[new_point_name]
428
+ quadrants[3].points[new_axis_a_point_name] = quadrants[2].points[new_axis_a_point_name]
429
+ quadrants[3].points[new_axis_b_point_name] = quadrants[2].points[new_axis_b_point_name]
430
+ else:
431
+ quadrants[3].points[new_point_name] = self.occ.copy([(0, quadrants[2].points[new_point_name])])[0][1]
432
+ self.occ.mirror([(0, quadrants[3].points[new_point_name])], 0, 1, 0, 0)
433
+ quadrants[3].points[new_axis_a_point_name] = self.occ.copy([(0, quadrants[2].points[new_axis_a_point_name])])[0][1]
434
+ self.occ.mirror([(0, quadrants[3].points[new_axis_a_point_name])], 0, 1, 0, 0)
435
+ quadrants[3].points[new_axis_b_point_name] = self.occ.copy([(0, quadrants[2].points[new_axis_b_point_name])])[0][1]
436
+ self.occ.mirror([(0, quadrants[3].points[new_axis_b_point_name])], 0, 1, 0, 0)
437
+
438
+ for quadrant, qq in quadrants.items():
439
+ qq.lines[line_name] = self.occ.addEllipseArc(
440
+ qq.points[line.kp1], qq.points[new_point_name], qq.points[new_axis_a_point_name if a > b else new_axis_b_point_name],
441
+ qq.points[line.kp2])
442
+
165
443
  else:
166
444
  raise ValueError('Hyper line {} not supported'.format(line.type))
167
445
 
446
+ if symmetry != 'none':
447
+ indexes = {'x_p': 1, 'y_p': 1, 'x_n': 1, 'y_n': 1}
448
+ self.md.geometries.air_inf.points['center'] = self.occ.addPoint(0, 0, 0)
449
+ for sym in list_bnds:
450
+ if sym in ['x_p', 'y_p']:
451
+ quadrant = 1
452
+ elif sym == 'x_n':
453
+ quadrant = 2
454
+ else: # 'y_n'
455
+ quadrant = 4
456
+ sym_lines_tags[sym] = [x for _, x in sorted(zip(symmetric_bnds_order[sym[0]], sym_lines_tags[sym]))]
457
+
458
+ self.symmetric_bnds[sym]['pnts'].append(['center', 0])
459
+ self.symmetric_bnds[sym]['pnts'].sort(key=lambda x: x[1])
460
+ self.md.geometries.symmetric_boundaries.lines[sym + '_center'] = self.occ.addLine(
461
+ self.md.geometries.air_inf.points['center'], quadrants[quadrant].points[self.symmetric_bnds[sym]['pnts'][1][0]])
462
+ sym_lines_tags[sym].insert(0, self.md.geometries.symmetric_boundaries.lines[sym + '_center'])
463
+ for i, pnt in enumerate(self.symmetric_bnds[sym]['pnts'][1:-1]):
464
+ pnt_next = self.symmetric_bnds[sym]['pnts'][i + 2][0]
465
+ if not any(pnt[0] in s and pnt_next in s for s in self.symmetric_bnds[sym]['line_pnts']):
466
+ self.md.geometries.symmetric_boundaries.lines[sym + '_' + pnt[0]] =\
467
+ self.occ.addLine(quadrants[quadrant].points[pnt[0]], quadrants[quadrant].points[pnt_next])
468
+ sym_lines_tags[sym].insert(indexes[sym], self.md.geometries.symmetric_boundaries.lines[sym + '_' + pnt[0]])
469
+ indexes[sym] += 1
470
+ if symmetry == 'xy':
471
+ self.symmetric_loop_lines['x'] = sym_lines_tags['x_p']
472
+ sym_lines_tags['y_p'].reverse()
473
+ self.symmetric_loop_lines['y'] = sym_lines_tags['y_p']
474
+ elif symmetry == 'x':
475
+ sym_lines_tags['x_n'].reverse()
476
+ self.symmetric_loop_lines['x'] = sym_lines_tags['x_n'] + sym_lines_tags['x_p']
477
+ elif symmetry == 'y':
478
+ sym_lines_tags['y_p'].reverse()
479
+ self.symmetric_loop_lines['y'] = sym_lines_tags['y_p'] + sym_lines_tags['y_n']
480
+
168
481
  for quadrant, qq in quadrants.items():
169
482
  for area_name, area in iron.hyper_areas.items():
170
483
  qq.areas[area_name] = dM.Area(loop=self.occ.addCurveLoop([qq.lines[line] for line in area.lines]))
171
- if (iron.hyper_areas[area_name].material not in self.md.domains.groups_surfaces and
484
+ if (iron.hyper_areas[area_name].material not in self.md.domains.groups_entities.iron and
172
485
  iron.hyper_areas[area_name].material != 'BH_air'):
173
- self.md.domains.groups_surfaces[iron.hyper_areas[area_name].material] = []
486
+ self.md.domains.groups_entities.iron[iron.hyper_areas[area_name].material] = []
174
487
 
175
- def constructWedgeGeometry(self):
488
+ def constructWedgeGeometry(self, use_TSA):
176
489
  """
177
490
  Generates points, hyper lines, and curve loops for the wedges
178
491
  """
179
- wedges = self.geom.Roxie_Data.wedges
180
- for i in wedges:
181
- kp0_inner = self.occ.addPoint(wedges[i].corrected_center.inner.x, wedges[i].corrected_center.inner.y, 0)
182
- kp0_outer = self.occ.addPoint(wedges[i].corrected_center.outer.x, wedges[i].corrected_center.outer.y, 0)
183
- arg = [self.occ.addPoint(wedges[i].corners.iL.x, wedges[i].corners.iL.y, 0),
184
- self.occ.addPoint(wedges[i].corners.iR.x, wedges[i].corners.iR.y, 0),
185
- self.occ.addPoint(wedges[i].corners.oL.x, wedges[i].corners.oL.y, 0),
186
- self.occ.addPoint(wedges[i].corners.oR.x, wedges[i].corners.oR.y, 0)]
187
-
188
- left = self.occ.addLine(arg[0], arg[2])
189
- right = self.occ.addLine(arg[1], arg[3])
190
- inner = self.occ.addCircleArc(arg[0], kp0_inner, arg[1])
191
- outer = self.occ.addCircleArc(arg[2], kp0_outer, arg[3])
192
- self.md.geometries.wedges.areas[i] = dM.Area(loop=self.occ.addCurveLoop([inner, right, outer, left]))
193
-
194
- def constructCoilGeometry(self):
492
+ def _addMidLayerThinShellPoints(wedge_current):
493
+ def __addThinShellPoints(side_case, mid_layer_ts):
494
+ if side_case == 'outer':
495
+ mean_rad_current = (Func.points_distance([wedge_current.oH.x, wedge_current.oH.y], wedge_center) +
496
+ Func.points_distance([wedge_current.oL.x, wedge_current.oL.y], wedge_center)) / 2
497
+ else:
498
+ mean_rad_current = (Func.points_distance([wedge_current.iH.x, wedge_current.iH.y], wedge_center) +
499
+ Func.points_distance([wedge_current.iL.x, wedge_current.iL.y], wedge_center)) / 2
500
+ are_endpoints = {}
501
+ for wnd_nr, wnd in pole.layers[wedge.order_l.layer + (1 if side_case == 'outer' else -1)].windings.items():
502
+ blk_nr_next = list(wnd.blocks.keys())[blk_list_current.index(wedge.order_l.block)]
503
+ blk_next = wnd.blocks[blk_nr_next]
504
+ ht_list_next = (list(blk_next.half_turns.keys()) if blk_nr_next == list(wnd.blocks.keys())[0] else list(
505
+ reversed(blk_next.half_turns.keys())))
506
+ hh = blk_next.half_turns[ht_list_next[-1]].corners.bare
507
+ ll = blk_next.half_turns[ht_list_next[0]].corners.bare
508
+ bc_next = Corner(oH=hh.oH, iH=hh.iH, oL=ll.oL, iL=ll.iL)
509
+ if side_case == 'outer':
510
+ block_list = self.md.geometries.coil.anticlockwise_order.coils[wedge.order_l.coil].layers[wedge.order_l.layer + 1]
511
+ blk_index = [blk.block for blk in block_list].index(blk_nr_next)
512
+ if blk_index + 1 == len(block_list): blk_index = -1
513
+ for blk in block_list[blk_index + 1:] + block_list[:blk_index + 1]:
514
+ if blk.winding == block_list[blk_index].winding:
515
+ ht_index = -1
516
+ break
517
+ elif blk.pole != block_list[blk_index].pole:
518
+ ht_index = 0
519
+ break
520
+ hh = blk_next.half_turns[ht_list_next[ht_index]].corners.bare
521
+ ll = blk_next.half_turns[ht_list_next[0 if ht_index == -1 else -1]].corners.bare
522
+ mean_rad_next = (Func.points_distance([hh.iH.x, hh.iH.y], wedge_center) +
523
+ Func.points_distance([ll.iL.x, ll.iL.y], wedge_center)) / 2
524
+ else:
525
+ mean_rad_next = (Func.points_distance([bc_next.oH.x, bc_next.oH.y], wedge_center) +
526
+ Func.points_distance([bc_next.oL.x, bc_next.oL.y], wedge_center)) / 2
527
+ mean_rad = (mean_rad_current + mean_rad_next) / 2
528
+ mid_layer = self.findMidLayerPoint(wedge_current.oH, bc_next.iH, wedge.corrected_center.outer, mean_rad)\
529
+ if side_case == 'outer' else self.findMidLayerPoint(wedge_current.iH, bc_next.oH, wedge.corrected_center.inner, mean_rad)
530
+ are_endpoints[wnd_nr] = self.getMidLayerEndpoints(wedge_current, bc_next, wedge_center, mid_layer_arc_pnt=mid_layer)
531
+ for wnd_nr, wnd in pole.layers[wedge.order_l.layer + (1 if side_case == 'outer' else -1)].windings.items():
532
+ blk_nr_next = list(wnd.blocks.keys())[blk_list_current.index(wedge.order_l.block)]
533
+ blk_next = wnd.blocks[blk_nr_next]
534
+ is_first_blk_next = blk_nr_next == list(wnd.blocks.keys())[0]
535
+ ht_list_next = (list(blk_next.half_turns.keys()) if is_first_blk_next else list(
536
+ reversed(blk_next.half_turns.keys())))
537
+ if are_endpoints[wnd_nr]: # this is empty if the wedge and the block are not radially adjacent
538
+ endpoints = are_endpoints[wnd_nr][0]
539
+ which_entity = are_endpoints[wnd_nr][1]
540
+ mid_layer_name = 'w' + str(wedge_nr) + '_' + str(blk_nr_next)
541
+ mid_layer_ts[mid_layer_name] = dM.Region()
542
+ ts_wdg = mid_layer_ts[mid_layer_name]
543
+ beg = ('w' + str(wedge_nr) if which_entity['lower'] == 'current' else str(ht_list_next[0])) + 'l'
544
+ ts_wdg.points[beg] = self.occ.addPoint(endpoints['lower'][0], endpoints['lower'][1], 0)
545
+ ht_lower_angles = {}
546
+ for ht_nr, ht in (blk_next.half_turns.items() if is_first_blk_next else reversed(blk_next.half_turns.items())):
547
+ for pnt1, pnt2, side in zip([[ht.corners.bare.iL.x, ht.corners.bare.iL.y], [ht.corners.bare.iH.x, ht.corners.bare.iH.y]],
548
+ [[ht.corners.bare.oL.x, ht.corners.bare.oL.y], [ht.corners.bare.oH.x, ht.corners.bare.oH.y]],
549
+ ['l', 'h']):
550
+ line_pars_current = Func.line_through_two_points(pnt1, pnt2)
551
+ intersect_prev = Func.intersection_between_arc_and_line(
552
+ line_pars_current, [wedge_center, endpoints['higher'], endpoints['lower']])
553
+ if intersect_prev:
554
+ ts_wdg.points[str(ht_nr) + side] = self.occ.addPoint(intersect_prev[0][0], intersect_prev[0][1], 0)
555
+ elif side == 'l':
556
+ intrsc = Func.intersection_between_circle_and_line(line_pars_current, [wedge_center, endpoints['lower']], get_only_closest=True)[0]
557
+ ht_lower_angles[ht_nr] = Func.arc_angle_between_point_and_abscissa([intrsc[0], intrsc[1]], wedge_center)
558
+ end = ('w' + str(wedge_nr) if which_entity['higher'] == 'current' else str(ht_list_next[-1])) + 'h'
559
+ if all('w' in pnt_name for pnt_name in list(ts_wdg.points.keys())): # only one thin-shell 'within' the facing half-turn
560
+ wdg_angle_il = Func.arc_angle_between_point_and_abscissa([endpoints['lower'][0], endpoints['lower'][1]], wedge_center)
561
+ for ht_nr, ht in (blk_next.half_turns.items() if is_first_blk_next else reversed(blk_next.half_turns.items())):
562
+ if ht_lower_angles[ht_nr] > wdg_angle_il: break
563
+ prev_nr = str(ht_nr)
564
+ end = prev_nr + 'h'
565
+ ts_wdg.points[end] = self.occ.addPoint(endpoints['higher'][0], endpoints['higher'][1], 0)
566
+
567
+ # Create auxiliary thin shells for outliers
568
+ # if both corners belong to thin shells, continue
569
+ used_wdg_corners = [False, False]
570
+ for ep in are_endpoints.values():
571
+ if ep is not None:
572
+ if ep[1]['higher'] == 'current': used_wdg_corners[1] = True
573
+ if ep[1]['lower'] == 'current': used_wdg_corners[0] = True
574
+ if side_case == 'inner':
575
+ for ts_name in self.md.geometries.thin_shells.mid_layers_wdg_to_wdg.keys():
576
+ if ts_name[ts_name.index('_') + 1:] == 'w' + str(wedge_nr):
577
+ for ep_key, ep in are_endpoints_wdg[int(ts_name[1:ts_name.index('_')])].items():
578
+ if ep is not None:
579
+ if ep[1]['higher'] == 'next': used_wdg_corners[1] = True
580
+ if ep[1]['lower'] == 'next': used_wdg_corners[0] = True
581
+ else:
582
+ if wedge_nr in are_endpoints_wdg:
583
+ for ep in are_endpoints_wdg[wedge_nr].values():
584
+ if ep is not None:
585
+ if ep[1]['higher'] == 'current': used_wdg_corners[1] = True
586
+ if ep[1]['lower'] == 'current': used_wdg_corners[0] = True
587
+ if not used_wdg_corners[1]:
588
+ for wdg_nr, wdg in self.geom.wedges.items():
589
+ if blk_nr_next == wdg.order_l.block: used_wdg_corners[1] = True
590
+ if not used_wdg_corners[0]:
591
+ for wdg_nr, wdg in self.geom.wedges.items():
592
+ if blk_nr_next == wdg.order_h.block: used_wdg_corners[0] = True
593
+ if not all(used_wdg_corners):
594
+ def ___create_aux_mid_layer_point(ss, points):
595
+ mid_layer_ts_aux[mid_layer_name] = dM.Region()
596
+ circle_pnt = [endpoints[ss][0], endpoints[ss][1]]
597
+ inter_pnt = Func.intersection_between_circle_and_line(Func.line_through_two_points(points[0], points[1]),
598
+ [[wedge.corrected_center.outer.x, wedge.corrected_center.outer.y], circle_pnt], get_only_closest=True)[0]
599
+ mid_layer_ts_aux[mid_layer_name].points[str(wedge_nr) + ss[0]] = self.occ.addPoint(inter_pnt[0], inter_pnt[1], 0)
600
+ mid_layer_ts_aux[mid_layer_name].points['center'] = self.occ.addPoint(wedge_data[wedge_nr][1].x, wedge_data[wedge_nr][1].y, 0)
601
+ mid_layer_ts_aux[mid_layer_name].lines['w' + str(wedge_nr)] = 0
602
+ if which_entity['higher'] == 'current' and which_entity['lower'] != 'current':
603
+ ___create_aux_mid_layer_point('lower', [[wedge_current.iL.x, wedge_current.iL.y],
604
+ [wedge_current.oL.x, wedge_current.oL.y]])
605
+ elif which_entity['higher'] != 'current' and which_entity['lower'] == 'current':
606
+ ___create_aux_mid_layer_point('higher', [[wedge_current.iH.x, wedge_current.iH.y],
607
+ [wedge_current.oH.x, wedge_current.oH.y]])
608
+ else: # whole block 'within' the facing wedge
609
+ for wdg_nr, wdg in self.geom.wedges.items():
610
+ if blk_nr_next == wdg.order_h.block:
611
+ ___create_aux_mid_layer_point('higher', [[wedge_current.iH.x, wedge_current.iH.y],
612
+ [wedge_current.oH.x, wedge_current.oH.y]])
613
+ break
614
+ elif blk_nr_next == wdg.order_l.block:
615
+ ___create_aux_mid_layer_point('lower', [[wedge_current.iL.x, wedge_current.iL.y],
616
+ [wedge_current.oL.x, wedge_current.oL.y]])
617
+ break
618
+
619
+ pole = self.geom.coil.coils[wedge.order_l.coil].poles[wedge.order_l.pole]
620
+ blk_list_current = list(pole.layers[wedge.order_l.layer].windings[wedge.order_l.winding].blocks.keys())
621
+ if wedge.order_l.layer < len(pole.layers):
622
+ __addThinShellPoints('outer', self.md.geometries.thin_shells.mid_layers_wdg_to_ht)
623
+ if wedge.order_l.layer > 1:
624
+ __addThinShellPoints('inner', self.md.geometries.thin_shells.mid_layers_ht_to_wdg)
625
+
626
+ wedges = self.md.geometries.wedges
627
+ mid_layer_ts_aux = self.md.geometries.thin_shells.mid_layers_aux
628
+ wedge_data = {}
629
+
630
+ wdgs_corners = {}
631
+ for wedge_nr, wedge in self.geom.wedges.items():
632
+ wdgs_corners[wedge_nr] = {}
633
+ corners = wdgs_corners[wedge_nr]
634
+ if wedge.order_l.coil not in wedges.coils:
635
+ wedges.coils[wedge.order_l.coil] = dM.WedgeLayer()
636
+ if wedge.order_l.layer not in wedges.coils[wedge.order_l.coil].layers:
637
+ wedges.coils[wedge.order_l.coil].layers[wedge.order_l.layer] = dM.WedgeRegion()
638
+ wedge_layer = wedges.coils[wedge.order_l.coil].layers[wedge.order_l.layer]
639
+ wedge_layer.wedges[wedge_nr] = dM.Region()
640
+ wedge_reg = wedge_layer.wedges[wedge_nr]
641
+ wedge_layer.block_prev[wedge_nr] = wedge.order_l.block
642
+ wedge_layer.block_next[wedge_nr] = wedge.order_h.block
643
+ wnd = self.geom.coil.coils[wedge.order_l.coil].poles[wedge.order_l.pole].layers[
644
+ wedge.order_l.layer].windings[wedge.order_l.winding]
645
+ wnd_next = self.geom.coil.coils[wedge.order_h.coil].poles[wedge.order_h.pole].layers[
646
+ wedge.order_h.layer].windings[wedge.order_h.winding]
647
+ block = wnd.blocks[wedge.order_l.block]
648
+ block_next = wnd_next.blocks[wedge.order_h.block]
649
+ corners['last_ht'] = int(list(self.md.geometries.coil.coils[wedge.order_l.coil].poles[wedge.order_l.pole].layers[
650
+ wedge.order_l.layer].windings[wedge.order_l.winding].blocks[wedge.order_l.block].half_turns.areas.keys())[-1])
651
+ corners['first_ht'] = int(list(self.md.geometries.coil.coils[wedge.order_h.coil].poles[wedge.order_h.pole].layers[
652
+ wedge.order_h.layer].windings[wedge.order_h.winding].blocks[wedge.order_h.block].half_turns.areas.keys())[0])
653
+ ht_current = block.half_turns[corners['last_ht']].corners.bare
654
+ ht_next = block_next.half_turns[corners['first_ht']].corners.bare
655
+ d_current = self.data.conductors[wnd.conductor_name].cable.th_insulation_along_width * 2
656
+ d_next = self.data.conductors[wnd_next.conductor_name].cable.th_insulation_along_width * 2
657
+ for pnt_close, pnt_far, wdg_corner, d in zip([ht_current.iH, ht_current.oH, ht_next.iL, ht_next.oL],
658
+ [ht_current.iL, ht_current.oL, ht_next.iH, ht_next.oH],
659
+ ['il', 'ol', 'ih', 'oh'], [d_current, d_current, d_next, d_next]):
660
+ if abs(pnt_far.x - pnt_close.x) > 0.:
661
+ m = (pnt_far.y - pnt_close.y) / (pnt_far.x - pnt_close.x)
662
+ b = pnt_close.y - m * pnt_close.x
663
+ root = np.sqrt(- pnt_close.x ** 2 * m ** 2 - 2 * pnt_close.x * b * m + 2 * pnt_close.x * pnt_close.y * m
664
+ - b ** 2 + 2 * b * pnt_close.y - pnt_close.y ** 2 + d ** 2 * m ** 2 + d ** 2)
665
+ pnt1_x = (pnt_close.x - b * m + pnt_close.y * m + root) / (m ** 2 + 1)
666
+ pnt1_y = m * pnt1_x + b
667
+ pnt2_x = (pnt_close.x - b * m + pnt_close.y * m - root) / (m ** 2 + 1)
668
+ pnt2_y = m * pnt2_x + b
669
+ corners[wdg_corner] = Coord(x=pnt1_x, y=pnt1_y) if Func.points_distance([pnt1_x, pnt1_y], [pnt_far.x, pnt_far.y]) >\
670
+ Func.points_distance([pnt_close.x, pnt_close.y], [pnt_far.x, pnt_far.y]) else Coord(x=pnt2_x, y=pnt2_y)
671
+ else:
672
+ bore_cnt_x = self.geom.coil.coils[wedge.order_l.coil].bore_center.x
673
+ pnt1_y, pnt2_y = pnt_close.y + d, pnt_close.y - d
674
+ corners[wdg_corner] = Coord(x=pnt_close.x,
675
+ y=pnt1_y if (wdg_corner[-1] == 'l' and pnt_close.x > bore_cnt_x) or
676
+ (wdg_corner[-1] == 'h' and pnt_close.x < bore_cnt_x) else pnt2_y)
677
+ wedge_reg.points[wdg_corner] = self.occ.addPoint(corners[wdg_corner].x, corners[wdg_corner].y, 0)
678
+ inner = Func.corrected_arc_center([self.md.geometries.coil.coils[wedge.order_l.coil].bore_center.x,
679
+ self.md.geometries.coil.coils[wedge.order_l.coil].bore_center.y],
680
+ [corners['ih'].x, corners['ih'].y], [corners['il'].x, corners['il'].y])
681
+ outer = Func.corrected_arc_center([self.md.geometries.coil.coils[wedge.order_l.coil].bore_center.x,
682
+ self.md.geometries.coil.coils[wedge.order_l.coil].bore_center.y],
683
+ [corners['oh'].x, corners['oh'].y], [corners['ol'].x, corners['ol'].y])
684
+ wedge_data[wedge_nr] = [Corner(iH=corners['ih'], oH=corners['oh'], iL=corners['il'], oL=corners['ol']), wedge.corrected_center.outer]
685
+ wedge_reg.points['inner_center'] = self.occ.addPoint(inner[0], inner[1], 0)
686
+ wedge_reg.points['outer_center'] = self.occ.addPoint(outer[0], outer[1], 0)
687
+ wedge_reg.lines['h'] = self.occ.addLine(wedge_reg.points['ih'], wedge_reg.points['oh'])
688
+ wedge_reg.lines['l'] = self.occ.addLine(wedge_reg.points['il'], wedge_reg.points['ol'])
689
+ wedge_reg.lines['i'] = self.occ.addCircleArc(wedge_reg.points['ih'], wedge_reg.points['inner_center'], wedge_reg.points['il'])
690
+ wedge_reg.lines['o'] = self.occ.addCircleArc(wedge_reg.points['oh'], wedge_reg.points['outer_center'], wedge_reg.points['ol'])
691
+ wedge_reg.areas[str(wedge_nr)] = dM.Area(loop=self.occ.addCurveLoop(
692
+ [wedge_reg.lines['i'], wedge_reg.lines['l'], wedge_reg.lines['o'], wedge_reg.lines['h']]))
693
+
694
+ if use_TSA:
695
+ # Wedge thin shells
696
+ mid_layer_ts = self.md.geometries.thin_shells.mid_layers_wdg_to_wdg
697
+ are_endpoints_wdg = {}
698
+ for coil_nr, coil in self.md.geometries.wedges.coils.items():
699
+ layer_list = list(coil.layers.keys())
700
+ for layer_nr, layer in coil.layers.items():
701
+ if layer_list.index(layer_nr) + 1 < len(layer_list):
702
+ for wedge_nr, wedge in layer.wedges.items():
703
+ are_endpoints_wdg[wedge_nr] = {}
704
+ are_endpoints = are_endpoints_wdg[wedge_nr]
705
+ wedge_current = wedge_data[wedge_nr][0]
706
+ wedge_center = [wedge_data[wedge_nr][1].x, wedge_data[wedge_nr][1].y]
707
+ mean_rad_current = (Func.points_distance([wedge_current.oH.x, wedge_current.oH.y], wedge_center) +
708
+ Func.points_distance([wedge_current.oL.x, wedge_current.oL.y], wedge_center)) / 2
709
+ for wdg_next_nr, wdg_next in coil.layers[layer_nr + 1].wedges.items():
710
+ if self.geom.wedges[wedge_nr].order_l.pole == self.geom.wedges[wdg_next_nr].order_l.pole:
711
+ wedge_next = wedge_data[wdg_next_nr][0]
712
+ mean_rad_next = (Func.points_distance([wedge_next.iH.x, wedge_next.iH.y], wedge_center) +
713
+ Func.points_distance([wedge_next.iL.x, wedge_next.iL.y], wedge_center)) / 2
714
+ mean_rad = (mean_rad_current + mean_rad_next) / 2
715
+ mid_layer = self.findMidLayerPoint(wedge_current.oH, wedge_next.iH, wedge_data[wedge_nr][1], mean_rad)
716
+ are_endpoints[wdg_next_nr] = self.getMidLayerEndpoints(wedge_current, wedge_next, wedge_center, mid_layer_arc_pnt=mid_layer)
717
+ if are_endpoints[wdg_next_nr]: # this is empty if the wedges are not radially adjacent
718
+ endpoints = are_endpoints[wdg_next_nr][0]
719
+ mid_layer_name = 'w' + str(wedge_nr) + '_w' + str(wdg_next_nr)
720
+ mid_layer_ts[mid_layer_name] = dM.Region()
721
+ ts = mid_layer_ts[mid_layer_name]
722
+ ts.points['center'] = self.occ.addPoint(wedge_center[0], wedge_center[1], 0)
723
+ ts.points['beg'] = self.occ.addPoint(endpoints['lower'][0], endpoints['lower'][1], 0)
724
+ end = 'w' + str(wedge_nr if are_endpoints[wdg_next_nr][1] == 'current' else wdg_next_nr)
725
+ ts.points[end] = self.occ.addPoint(endpoints['higher'][0], endpoints['higher'][1], 0)
726
+
727
+ # Half-turn thin shells
728
+ for wedge_nr, wedge in self.geom.wedges.items():
729
+ corners = wdgs_corners[wedge_nr]
730
+ # Mid layer lines
731
+ wedge_center = [self.md.geometries.coil.coils[wedge.order_l.coil].bore_center.x,
732
+ self.md.geometries.coil.coils[wedge.order_l.coil].bore_center.y]
733
+ _addMidLayerThinShellPoints(Corner(iH=corners['ih'], oH=corners['oh'], iL=corners['il'], oL=corners['ol']))
734
+ # Mid wedge-turn lines
735
+ mid_turn_ts = self.md.geometries.thin_shells.mid_wedge_turn
736
+ for adj_blk, ht, inner, outer in zip([wedge.order_l, wedge.order_h], [corners['last_ht'], corners['first_ht']],
737
+ [corners['il'], corners['ih']], [corners['ol'], corners['oh']]):
738
+ mid_turn_ts['w' + str(wedge_nr) + '_' + str(adj_blk.block)] = dM.Region()
739
+ ts = mid_turn_ts['w' + str(wedge_nr) + '_' + str(adj_blk.block)]
740
+ ht_corners = self.geom.coil.coils[adj_blk.coil].poles[adj_blk.pole].layers[
741
+ adj_blk.layer].windings[adj_blk.winding].blocks[adj_blk.block].half_turns[ht].corners.bare
742
+ ht_corners_i = ht_corners.iH if ht == corners['last_ht'] else ht_corners.iL
743
+ ht_corners_o = ht_corners.oH if ht == corners['last_ht'] else ht_corners.oL
744
+ mid_inner = [(inner.x + ht_corners_i.x) / 2, (inner.y + ht_corners_i.y) / 2]
745
+ mid_outer = [(outer.x + ht_corners_o.x) / 2, (outer.y + ht_corners_o.y) / 2]
746
+ line_name = 'w' + str(wedge_nr) + '_' + str(ht)
747
+ ts.points[line_name + '_i'] = self.occ.addPoint(mid_inner[0], mid_inner[1], 0)
748
+ ts.points[line_name + '_o'] = self.occ.addPoint(mid_outer[0], mid_outer[1], 0)
749
+
750
+ def constructCoilGeometry(self, run_type):
195
751
  """
196
752
  Generates points, hyper lines, and curve loops for the coil half-turns
197
753
  """
198
- frac = 1 # self.frac if self.frac else 1
199
- for coil_nr, coil in self.geom.Roxie_Data.coil.coils.items():
754
+ symmetry = self.data.magnet.geometry.electromagnetics.symmetry if run_type == 'EM' else 'none'
755
+ # Sub domains angles: first key means 'from 0 to x'; second key means 'from x to 2*pi'
756
+ if symmetry == 'xy':
757
+ angle_range = {'to': np.pi / 2, 'from': 2 * np.pi}
758
+ elif symmetry == 'x':
759
+ angle_range = {'to': np.pi, 'from': 2 * np.pi}
760
+ elif symmetry == 'y':
761
+ angle_range = {'to': np.pi / 2, 'from': 3 / 2 * np.pi}
762
+ elif symmetry == 'none':
763
+ angle_range = {'to': 2 * np.pi, 'from': 0}
764
+ else:
765
+ raise Exception('Symmetry plane not supported.')
766
+
767
+ def _addMidLayerThinShellPoints(pnt_params, ss, name, case):
768
+ endpnts, cnt = ts_endpoints[name]
769
+ if len(pnt_params) == 3: # line parameters (cos-theta Rutherford)
770
+ intersect[name] = Func.intersection_between_arc_and_line(pnt_params, [cnt, endpnts['higher'], endpnts['lower']])
771
+ if intersect[name]:
772
+ intersect[name] = intersect[name][0]
773
+ pnt_angle = Func.arc_angle_between_point_and_abscissa(intersect[name], cnt)
774
+ elif len(pnt_params) == 4: # points coordinates (cos-theta Mono)
775
+ wnd_next = list(pole.layers[layer_nr + (1 if case == 'current' else -1)].windings.keys())[
776
+ list(pole.layers[layer_nr].windings.keys()).index(winding_nr)]
777
+ blk_next = pole.layers[layer_nr + (1 if case == 'current' else -1)].windings[wnd_next].blocks[
778
+ int(ts_name[ts_name.index('_') + 1:] if case == 'current' else ts_name[:ts_name.index('_')])]
779
+ ht_next = blk_next.half_turns[list(blk_next.half_turns.keys() if is_first_blk else reversed(blk_next.half_turns.keys()))[ht_list.index(halfTurn_nr)]].corners.bare
780
+ coord_next = (ht_next.iL if ss == 'l' else ht_next.iH) if case == 'current' else (ht_next.oL if ss == 'l' else ht_next.oH)
781
+ pnt = [(pnt_params[2 if case == 'current' else 0] + coord_next.x) / 2, (pnt_params[3 if case == 'current' else 1] + coord_next.y) / 2]
782
+ pnt_angle = Func.arc_angle_between_point_and_abscissa(pnt, cnt)
783
+ pnt_angle_h = Func.arc_angle_between_point_and_abscissa(endpnts['higher'], cnt)
784
+ pnt_angle_l = Func.arc_angle_between_point_and_abscissa(endpnts['lower'], cnt)
785
+ intersect[name] = pnt if pnt_angle_h > pnt_angle > pnt_angle_l else None
786
+ else: # point coordinates (block-coil)
787
+ pnt = [endpnts['higher'][0], pnt_params[1]] if coil.type == 'common-block-coil' else [pnt_params[0], endpnts['higher'][1]]
788
+ if abs(endpnts['higher'][1]) > 1e-6:
789
+ pnt_angle = Func.arc_angle_between_point_and_abscissa(pnt, cnt)
790
+ pnt_angle_h = Func.arc_angle_between_point_and_abscissa(endpnts['higher'], cnt)
791
+ pnt_angle_l = Func.arc_angle_between_point_and_abscissa(endpnts['lower'], cnt)
792
+ else:
793
+ pnt_angle = abs(pnt_params[0])
794
+ pnt_angle_h = abs(endpnts['higher'][0])
795
+ pnt_angle_l = abs(endpnts['lower'][0])
796
+ intersect[name] = pnt if pnt_angle_h > pnt_angle > pnt_angle_l else None
797
+ if intersect[name]:
798
+ mid_layer_ts[name].mid_layers.points[str(halfTurn_nr) + ss] = \
799
+ self.occ.addPoint(intersect[name][0], intersect[name][1], 0)
800
+ mid_layer_ts[name].point_angles[str(halfTurn_nr) + ss] = Func.sig_dig(pnt_angle)
801
+ if len(pnt_params) == 2 and not intersect[name] and (abs(pnt_angle - pnt_angle_h) < 1e-6 or abs(pnt_angle - pnt_angle_l) < 1e-6):
802
+ intersect[name] = pnt
803
+ return intersect
804
+
805
+ def _addMidLayerThinShellGroup(cl, for_mid_pole=False, mid_coil=False):
806
+ is_first_blk_next = block_nr_next == list(winding_next.blocks.keys())[0]
807
+ if 'solenoid' in cl.type:
808
+ ht_list_next = list(reversed(block_next.half_turns.keys()) if layer_nr % 2 == 0 else list(block_next.half_turns.keys()))
809
+ elif cl.type == 'reversed-block-coil':
810
+ ht_list_next = (list(block_next.half_turns.keys()) if not is_first_blk_next else list(reversed(block_next.half_turns.keys())))
811
+ else:
812
+ ht_list_next = (list(block_next.half_turns.keys()) if is_first_blk_next else list(reversed(block_next.half_turns.keys())))
813
+ hh = block_next.half_turns[ht_list_next[-1]].corners.bare
814
+ ll = block_next.half_turns[ht_list_next[0]].corners.bare
815
+ bc_next = Corner(oH=hh.oH, iH=hh.iH, oL=ll.oL, iL=ll.iL)
816
+ if 'block-coil' in cl.type or (cable_type_curr in ['Mono', 'Ribbon'] and not mid_coil):
817
+ center = [cl.bore_center.x, cl.bore_center.y]
818
+ are_endpoints = self.getMidLayerEndpoints(bc_current, bc_next, center, coil_type=cl.type, cable_type=cable_type_curr, is_for_mid_pole=for_mid_pole)
819
+ else:
820
+ mean_rad_next = (Func.points_distance([bc_next.iH.x, bc_next.iH.y], [cl.bore_center.x, cl.bore_center.y]) +
821
+ Func.points_distance([bc_next.iL.x, bc_next.iL.y], [cl.bore_center.x, cl.bore_center.y])) / 2
822
+ mean_rad = (mean_rad_current + mean_rad_next) / 2
823
+ mid_layer_h = self.findMidLayerPoint(bc_current.oH, bc_next.iH, cl.bore_center, mean_rad)
824
+ mid_layer_l = self.findMidLayerPoint(bc_current.oL, bc_next.iL, cl.bore_center, mean_rad)
825
+ mid_ht_next_i = int(len(ht_list_next) / 2) if len(ht_list_next) % 2 == 0 else round(len(ht_list_next) / 2)
826
+ mid_ht_next = block_next.half_turns[ht_list_next[mid_ht_next_i - 1]].corners.insulated
827
+ mid_layer_m = self.findMidLayerPoint(mid_ht_current.oH, mid_ht_next.iH, cl.bore_center, mean_rad)
828
+ center = Func.arc_center_from_3_points(mid_layer_h, mid_layer_m, mid_layer_l)
829
+ are_endpoints = self.getMidLayerEndpoints(bc_current, bc_next, center, mid_layer_arc_pnt=mid_layer_h, cable_type=cable_type_curr)
830
+ if are_endpoints: # this is empty if the blocks are not radially adjacent
831
+ endpoints = are_endpoints[0]
832
+ which_block = are_endpoints[1]
833
+ mid_layer_name = blk_nr + '_' + str(block_nr_next)
834
+ if for_mid_pole:
835
+ block_coil_mid_pole_next_blks_list[block_nr_next].append(mid_layer_name)
836
+ block_coil_ts_endpoints[mid_layer_name] = [endpoints, center]
837
+ else:
838
+ if block_nr_next not in list(next_blks_list.keys()):
839
+ next_blks_list[block_nr_next] = []
840
+ next_blks_list[block_nr_next].append(mid_layer_name)
841
+ ts_endpoints[mid_layer_name] = [endpoints, center]
842
+ mid_layer_ts[mid_layer_name] = dM.MidLayer()
843
+ mid_layer_ts[mid_layer_name].half_turn_lists[blk_nr] = ht_list
844
+ mid_layer_ts[mid_layer_name].half_turn_lists[str(block_nr_next)] = ht_list_next
845
+ beg = (str(ht_list[0]) if which_block['lower'] == 'current' else str(ht_list_next[0])) + 'l'
846
+ mid_layer_ts[mid_layer_name].mid_layers.points[beg] = \
847
+ self.occ.addPoint(endpoints['lower'][0], endpoints['lower'][1], 0)
848
+ end = (str(ht_list[-1]) if which_block['higher'] == 'current' else str(ht_list_next[-1])) + 'h'
849
+ mid_layer_ts[mid_layer_name].mid_layers.points[end] = \
850
+ self.occ.addPoint(endpoints['higher'][0], endpoints['higher'][1], 0)
851
+ if not for_mid_pole or (for_mid_pole and abs(endpoints['higher'][1]) > 1e-6):
852
+ mid_layer_ts[mid_layer_name].point_angles[beg] =\
853
+ Func.sig_dig(Func.arc_angle_between_point_and_abscissa(endpoints['lower'], center))
854
+ mid_layer_ts[mid_layer_name].point_angles[end] =\
855
+ Func.sig_dig(Func.arc_angle_between_point_and_abscissa(endpoints['higher'], center))
856
+ else:
857
+ mid_layer_ts[mid_layer_name].point_angles[beg] = abs(endpoints['lower'][0])
858
+ mid_layer_ts[mid_layer_name].point_angles[end] = abs(endpoints['higher'][0])
859
+
860
+ # Create anticlockwise order of blocks
861
+ present_blocks = []
862
+ block_corner_angles = {}
863
+ concentric_coils = self.md.geometries.coil.concentric_coils
864
+ acw_order = self.md.geometries.coil.anticlockwise_order.coils
865
+ self.md.geometries.coil.physical_order = self.geom.coil.physical_order
866
+ for coil_nr, coil in self.geom.coil.coils.items():
867
+ # if coil_nr not in block_corner_angles:
868
+ block_corner_angles[coil_nr] = {}
869
+ if (coil.bore_center.x, coil.bore_center.y) not in concentric_coils:
870
+ concentric_coils[(coil.bore_center.x, coil.bore_center.y)] = []
871
+ concentric_coils[(coil.bore_center.x, coil.bore_center.y)].append(coil_nr)
872
+ for pole_nr, pole in coil.poles.items():
873
+ for layer_nr, layer in pole.layers.items():
874
+ if layer_nr not in block_corner_angles[coil_nr]:
875
+ block_corner_angles[coil_nr][layer_nr] = {}
876
+ blk_angles = block_corner_angles[coil_nr][layer_nr]
877
+ for winding_nr, winding in layer.windings.items():
878
+ for block_nr, block in winding.blocks.items():
879
+ blk_angles[block_nr] = {'angle': Func.sig_dig(Func.arc_angle_between_point_and_abscissa(
880
+ [block.block_corners.iL.x, block.block_corners.iL.y],
881
+ [coil.bore_center.x, coil.bore_center.y])), 'keys': [pole_nr, winding_nr]}
882
+ higher_angle = Func.sig_dig(Func.arc_angle_between_point_and_abscissa(
883
+ [block.block_corners.iH.x, block.block_corners.iH.y],
884
+ [coil.bore_center.x, coil.bore_center.y]))
885
+ if ((blk_angles[block_nr]['angle'] <= angle_range['to'] and higher_angle <= angle_range['to']) or
886
+ (angle_range['from'] <= blk_angles[block_nr]['angle'] and angle_range['from'] <= higher_angle)):
887
+ present_blocks.append(block_nr)
888
+ for coil_nr, coil in block_corner_angles.items():
889
+ acw_order[coil_nr] = dM.LayerOrder()
890
+ for layer_nr, layer in coil.items():
891
+ acw_order[coil_nr].layers[layer_nr] = []
892
+ ordered_blocks = [[block_nr, block['angle'], block['keys']] for block_nr, block in layer.items()]
893
+ ordered_blocks.sort(key=lambda x: x[1])
894
+ for blk in ordered_blocks:
895
+ if blk[0] in present_blocks:
896
+ acw_order[coil_nr].layers[layer_nr].append(dM.AnticlockwiseOrder(pole=blk[2][0], winding=blk[2][1], block=blk[0]))
897
+
898
+ # Check if there are concentric coils
899
+ for bore_center, coils in concentric_coils.items():
900
+ if len(coils) > 1:
901
+ radii = []
902
+ for coil_nr in coils:
903
+ lyr = self.geom.coil.coils[coil_nr].poles[1].layers[1]
904
+ blk = list(lyr.windings.keys())[0]
905
+ radii.append([coil_nr, Func.points_distance(bore_center, [lyr.windings[blk].blocks[blk].block_corners.iL.x, lyr.windings[blk].blocks[blk].block_corners.iL.y])])
906
+ radii.sort(key=lambda x: x[1])
907
+ concentric_coils[bore_center] = [rad[0] for rad in radii]
908
+
909
+ if run_type == 'TH' and self.data.magnet.geometry.thermal.use_TSA:
910
+ mid_layer_ts = self.md.geometries.thin_shells.mid_layers_ht_to_ht
911
+ # Collect block couples for block-coil mid-pole thin shells
912
+ block_coil_mid_pole_next_blks_list = {}
913
+ block_coil_ts_endpoints = {}
914
+ for coil_nr, coil in self.md.geometries.coil.anticlockwise_order.coils.items():
915
+ if self.geom.coil.coils[coil_nr].type in ['block-coil', 'reversed-block-coil']:
916
+ self.block_coil_mid_pole_blks[coil_nr] = []
917
+ first_lyr = list(coil.layers.keys())[0]
918
+ layer = coil.layers[first_lyr]
919
+ for nr, block_order in enumerate(layer):
920
+ blk_next_index = nr + 1 if nr + 1 < len(layer) else 0
921
+ if layer[blk_next_index].pole != block_order.pole:
922
+ self.block_coil_mid_pole_blks[coil_nr].append([block_order, layer[blk_next_index]])
923
+ block_coil_mid_pole_next_blks_list[layer[blk_next_index].block] = []
924
+ # Mid pole lines for block-coils
925
+ for coil_nr, coil in self.block_coil_mid_pole_blks.items():
926
+ coil_geom = self.geom.coil.coils[coil_nr]
927
+ for mid_pole in coil:
928
+ winding = self.geom.coil.coils[coil_nr].poles[mid_pole[0].pole].layers[1].windings[mid_pole[0].winding]
929
+ cable_type_curr = self.data.conductors[winding.conductor_name].cable.type
930
+ block_nr = mid_pole[0].block
931
+ blk_nr = str(block_nr)
932
+ block = winding.blocks[block_nr]
933
+ is_first_blk = block_nr == list(winding.blocks.keys())[0]
934
+ if coil_geom.type == 'reversed-block-coil':
935
+ ht_list = (list(block.half_turns.keys()) if not is_first_blk else list(reversed(block.half_turns.keys())))
936
+ else:
937
+ ht_list = (list(block.half_turns.keys()) if is_first_blk else list(reversed(block.half_turns.keys())))
938
+ hh = block.half_turns[ht_list[-1]].corners.bare
939
+ ll = block.half_turns[ht_list[0]].corners.bare
940
+ bc_current = Corner(oH=hh.oH, iH=hh.iH, oL=ll.oL, iL=ll.iL)
941
+ winding_next = self.geom.coil.coils[coil_nr].poles[mid_pole[1].pole].layers[1].windings[mid_pole[1].winding]
942
+ block_nr_next = mid_pole[1].block
943
+ block_next = winding_next.blocks[block_nr_next]
944
+ _addMidLayerThinShellGroup(coil_geom, for_mid_pole=True)
945
+
946
+ mid_layer_ts_aux = self.md.geometries.thin_shells.mid_layers_aux
947
+ self.md.geometries.coil.physical_order = self.geom.coil.physical_order
948
+ if run_type == 'TH' and self.data.magnet.geometry.thermal.use_TSA:
949
+ next_blks_list = block_coil_mid_pole_next_blks_list.copy()
950
+ ts_endpoints = block_coil_ts_endpoints.copy()
951
+ for coil_nr, coil in self.geom.coil.coils.items():
200
952
  self.md.geometries.coil.coils[coil_nr] = dM.Pole()
201
953
  coils = self.md.geometries.coil.coils[coil_nr]
954
+ coils.type = coil.type
955
+ coils.bore_center = coil.bore_center
202
956
  for pole_nr, pole in coil.poles.items():
203
957
  coils.poles[pole_nr] = dM.Layer()
204
958
  poles = coils.poles[pole_nr]
@@ -206,129 +960,788 @@ class Geometry:
206
960
  poles.layers[layer_nr] = dM.Winding()
207
961
  layers = poles.layers[layer_nr]
208
962
  for winding_nr, winding in layer.windings.items():
209
- layers.windings[winding_nr] = dM.Block(conductor_name=winding.conductor_name,
210
- conductors_number=winding.conductors_number)
963
+ cable_type_curr = self.data.conductors[winding.conductor_name].cable.type
964
+ layers.windings[winding_nr] = dM.Block(conductor_name=winding.conductor_name, conductors_number=winding.conductors_number)
211
965
  windings = layers.windings[winding_nr]
212
- ll = self.sett.Model_Data_GS.conductors[winding.conductor_name].cable.bare_cable_height_mean
213
- for block_key, block in winding.blocks.items():
214
- windings.blocks[block_key] = dM.BlockData(current_sign=block.current_sign)
215
- hts = windings.blocks[block_key].half_turns
216
-
217
- for halfTurn_nr, halfTurn in block.half_turns.items():
218
- ht = str(halfTurn_nr)
219
- hts.areas[ht] = dM.Area()
220
- hf_current = halfTurn.corners.insulated
221
- if halfTurn_nr == 1:
222
- bc = block.block_corners
223
- if (hf_current.iL.y < 0 and block_key == max(winding.blocks.keys())) or \
224
- (hf_current.iL.y > 0 and block_key == min(winding.blocks.keys())):
225
- hts.points[ht + 'i'] = self.occ.addPoint(bc.iR.x, bc.iR.y, 0, ll / frac)
226
- hts.points[ht + 'o'] = self.occ.addPoint(bc.oR.x, bc.oR.y, 0, ll / frac)
966
+ blk_list_current = list(winding.blocks.keys())
967
+ for block_nr, block in winding.blocks.items():
968
+ if block_nr in present_blocks:
969
+ blk_nr = str(block_nr)
970
+ windings.blocks[block_nr] = dM.BlockData(current_sign=block.current_sign)
971
+ hts = windings.blocks[block_nr].half_turns
972
+ is_first_blk = block_nr == list(winding.blocks.keys())[0]
973
+ if run_type == 'TH' and self.data.magnet.geometry.thermal.use_TSA:
974
+ if 'solenoid' in coil.type:
975
+ ht_list = (list(reversed(block.half_turns.keys()) if (layer_nr - 1) % 2 == 0 else list(block.half_turns.keys())))
976
+ elif coil.type == 'reversed-block-coil':
977
+ ht_list = (list(block.half_turns.keys()) if not is_first_blk else list(reversed(block.half_turns.keys())))
227
978
  else:
228
- hts.points[ht + 'i'] = self.occ.addPoint(bc.iL.x, bc.iL.y, 0, ll / frac)
229
- hts.points[ht + 'o'] = self.occ.addPoint(bc.oL.x, bc.oL.y, 0, ll / frac)
230
- hts.lines[ht + 'r'] = self.occ.addLine(hts.points[ht + 'i'], hts.points[ht + 'o'])
979
+ ht_list = (list(block.half_turns.keys()) if is_first_blk else list(reversed(block.half_turns.keys())))
980
+ hh = block.half_turns[ht_list[-1]].corners.bare
981
+ ll = block.half_turns[ht_list[0]].corners.bare
982
+ bc_current = Corner(oH=hh.oH, iH=hh.iH, oL=ll.oL, iL=ll.iL)
983
+ # Mid layer lines
984
+ mean_rad_current = (Func.points_distance([bc_current.oH.x, bc_current.oH.y], [coil.bore_center.x, coil.bore_center.y]) +
985
+ Func.points_distance([bc_current.oL.x, bc_current.oL.y], [coil.bore_center.x, coil.bore_center.y])) / 2
986
+ mid_ht_current_i = int(len(ht_list) / 2) if len(ht_list) % 2 == 0 else round(len(ht_list) / 2)
987
+ mid_ht_current = block.half_turns[ht_list[mid_ht_current_i - 1]].corners.insulated
988
+ concentric_coil = concentric_coils[(coil.bore_center.x, coil.bore_center.y)]
989
+ if layer_nr < len(pole.layers):
990
+ for winding_nr_next, winding_next in pole.layers[layer_nr + 1].windings.items():
991
+ if cable_type_curr == 'Rutherford' or\
992
+ (cable_type_curr in ['Mono', 'Ribbon'] and
993
+ list(pole.layers[layer_nr + 1].windings.keys()).index(winding_nr_next) == list(layer.windings.keys()).index(winding_nr)):
994
+ blk_list_next = list(winding_next.blocks.keys())
995
+ block_nr_next = blk_list_next[blk_list_current.index(block_nr)]
996
+ block_next = winding_next.blocks[block_nr_next]
997
+ _addMidLayerThinShellGroup(coil)
998
+ elif concentric_coil.index(coil_nr) + 1 < len(concentric_coil):
999
+ coil_nr_next = concentric_coil[concentric_coil.index(coil_nr) + 1]
1000
+ for pole_nr_next, pole_next in self.geom.coil.coils[coil_nr_next].poles.items():
1001
+ for layer_nr_next, layer_next in pole_next.layers.items():
1002
+ if layer_nr_next == 1:
1003
+ for winding_nr_next, winding_next in layer_next.windings.items():
1004
+ for block_nr_next, block_next in winding_next.blocks.items():
1005
+ _addMidLayerThinShellGroup(coil, mid_coil=True)
1006
+ else:
1007
+ blk_ins = windings.blocks[block_nr].insulation
1008
+ blk_ins.areas[blk_nr] = dM.Area()
1009
+
1010
+ if 'solenoid' in coil.type:
1011
+ ht_items = (list(reversed(block.half_turns.items()) if layer_nr - 1 % 2 == 0 else list(block.half_turns.items())))
1012
+ elif coil.type == 'reversed-block-coil':
1013
+ ht_items = (block.half_turns.items() if not is_first_blk else reversed(block.half_turns.items()))
1014
+ else:
1015
+ ht_items = (block.half_turns.items() if is_first_blk else reversed(block.half_turns.items()))
1016
+ for halfTurn_nr, halfTurn in ht_items:
1017
+ ht_nr = str(halfTurn_nr)
1018
+ ht = halfTurn.corners.insulated
1019
+ hts.areas[ht_nr] = dM.Area()
1020
+ ht_b = halfTurn.corners.bare
1021
+
1022
+ hts.points[ht_nr + 'ih'] = self.occ.addPoint(ht_b.iH.x, ht_b.iH.y, 0)
1023
+ hts.points[ht_nr + 'il'] = self.occ.addPoint(ht_b.iL.x, ht_b.iL.y, 0)
1024
+ hts.points[ht_nr + 'oh'] = self.occ.addPoint(ht_b.oH.x, ht_b.oH.y, 0)
1025
+ hts.points[ht_nr + 'ol'] = self.occ.addPoint(ht_b.oL.x, ht_b.oL.y, 0)
231
1026
 
232
- if halfTurn_nr == winding.conductors_number:
233
- bc = block.block_corners
1027
+ hts.lines[ht_nr + 'i'] = self.occ.addLine(hts.points[ht_nr + 'ih'], hts.points[ht_nr + 'il'])
1028
+ hts.lines[ht_nr + 'o'] = self.occ.addLine(hts.points[ht_nr + 'oh'], hts.points[ht_nr + 'ol'])
1029
+ hts.lines[ht_nr + 'l'] = self.occ.addLine(hts.points[ht_nr + 'il'], hts.points[ht_nr + 'ol'])
1030
+ hts.lines[ht_nr + 'h'] = self.occ.addLine(hts.points[ht_nr + 'ih'], hts.points[ht_nr + 'oh'])
234
1031
 
235
- if (hf_current.iL.y < 0 and block_key == max(winding.blocks.keys())) or \
236
- (hf_current.iL.y > 0 and block_key == min(winding.blocks.keys())):
237
- hts.points['end_i'] = self.occ.addPoint(bc.iL.x, bc.iL.y, 0, ll/frac)
238
- hts.points['end_o'] = self.occ.addPoint(bc.oL.x, bc.oL.y, 0, ll/frac)
1032
+ if run_type == 'TH' and self.data.magnet.geometry.thermal.use_TSA:
1033
+ intersection = {}
1034
+ # Create mid layer points and compute their angle to the x-axis
1035
+ for mid_lyr_type in ['current', 'previous']:
1036
+ for pnt1, pnt2, side in zip(
1037
+ [[ht_b.iH.x, ht_b.iH.y], [ht_b.iL.x, ht_b.iL.y]],
1038
+ [[ht_b.oH.x, ht_b.oH.y], [ht_b.oL.x, ht_b.oL.y]], ['h', 'l']):
1039
+ if (cable_type_curr in ['Mono', 'Ribbon'] and coil.type == 'cos-theta' and
1040
+ (layer_nr < len(pole.layers) and mid_lyr_type == 'current' or layer_nr > 1 and mid_lyr_type == 'previous')):
1041
+ pnts_input = pnt1 + pnt2
1042
+ elif coil.type == 'cos-theta' and (cable_type_curr == 'Rutherford' or cable_type_curr in ['Mono', 'Ribbon'] and\
1043
+ (layer_nr == len(pole.layers) and mid_lyr_type == 'current' or layer_nr == 1 and mid_lyr_type == 'previous')):
1044
+ pnts_input = Func.line_through_two_points(pnt1, pnt2)
1045
+ elif 'block-coil' in coil.type:
1046
+ pnts_input = pnt1
1047
+ intersect = {}
1048
+ if mid_lyr_type == 'current':
1049
+ # Current mid-layer
1050
+ for ts_name in ts_endpoints.keys():
1051
+ if blk_nr == ts_name[:ts_name.index('_')]:
1052
+ _addMidLayerThinShellPoints(pnts_input, side, ts_name, mid_lyr_type)
1053
+ elif mid_lyr_type == 'previous':
1054
+ # Previous mid-layer
1055
+ if block_nr in next_blks_list:
1056
+ for ts_name in next_blks_list[block_nr]:
1057
+ _addMidLayerThinShellPoints(pnts_input, side, ts_name, mid_lyr_type)
1058
+ for key, value in intersect.items():
1059
+ if key in intersection:
1060
+ intersection[key][side] = value
1061
+ else:
1062
+ intersection[key] = {side: value}
1063
+
1064
+ # Search for half turns that face thin shells only partially
1065
+ def __create_aux_mid_layer_point(ss, points):
1066
+ mid_layer_ts_aux[key] = dM.Region()
1067
+ if 'block-coil' in coil.type:
1068
+ inter_pnt = [points[0], ts_endpoints[key][0][ss][1]]
1069
+ else:
1070
+ inter_pnt = Func.intersection_between_circle_and_line(Func.line_through_two_points(points[0], points[1]),
1071
+ [ts_endpoints[key][1], ts_endpoints[key][0][ss]], get_only_closest=True)[0]
1072
+ mid_layer_ts_aux[key].points[str(halfTurn_nr) + ss[0]] = self.occ.addPoint(inter_pnt[0], inter_pnt[1], 0)
1073
+ mid_layer_ts_aux[key].lines[blk_nr] = 0
1074
+ for key, value in intersection.items():
1075
+ first_blk, second_blk = key.split('_')
1076
+ if 'block-coil' in coil.type: #any(int(second_blk) == blk_order.block for blk_order in acw_order[coil_nr].layers[layer_nr]): # block-coil mid-pole case
1077
+ if value['h'] and not value['l']:
1078
+ __create_aux_mid_layer_point('lower', [ht_b.iL.x, ht_b.iL.y])
1079
+ elif value['l'] and not value['h']:
1080
+ __create_aux_mid_layer_point('higher', [ht_b.iH.x, ht_b.iH.y])
1081
+ else:
1082
+ relevant_blk = int(first_blk) if second_blk == blk_nr else int(second_blk)
1083
+ if layer_nr == len(pole.layers) and blk_nr == first_blk:
1084
+ lyr_blks = acw_order[coil_nr + 1].layers[1]
1085
+ elif layer_nr == 1 and blk_nr == second_blk:
1086
+ lyr_blks = acw_order[coil_nr - 1].layers[len(acw_order[coil_nr - 1].layers)]
1087
+ else:
1088
+ lyr_blks = acw_order[coil_nr].layers[layer_nr + (1 if first_blk == blk_nr else -1)]
1089
+ for nr, block_order in enumerate(lyr_blks):
1090
+ if block_order.block == relevant_blk:
1091
+ block_order_curr = block_order
1092
+ block_order_prev = lyr_blks[-1] if nr == 0 else lyr_blks[nr - 1]
1093
+ block_order_next = lyr_blks[0] if nr + 1 == len(lyr_blks) else lyr_blks[nr + 1]
1094
+ break
1095
+ if value['h'] and not value['l'] and block_order_curr.winding == block_order_prev.winding:
1096
+ __create_aux_mid_layer_point('lower', [[ht_b.iL.x, ht_b.iL.y], [ht_b.oL.x, ht_b.oL.y]])
1097
+ elif value['l'] and not value['h'] and block_order_curr.winding == block_order_next.winding:
1098
+ __create_aux_mid_layer_point('higher', [[ht_b.iH.x, ht_b.iH.y], [ht_b.oH.x, ht_b.oH.y]])
239
1099
  else:
240
- hts.points['end_i'] = self.occ.addPoint(bc.iR.x, bc.iR.y, 0, ll/frac)
241
- hts.points['end_o'] = self.occ.addPoint(bc.oR.x, bc.oR.y, 0, ll/frac)
242
-
243
- hts.lines[ht + 'i'] = self.occ.addLine(hts.points['end_i'], hts.points[ht + 'i'])
244
- hts.lines[ht + 'o'] = self.occ.addLine(hts.points['end_o'], hts.points[ht + 'o'])
245
- hts.lines['end'] = self.occ.addLine(hts.points['end_i'], hts.points['end_o'])
246
-
247
- # For plotting only
248
- if pole_nr == 1:
249
- self.occ.synchronize()
250
- self.iL.append(list(gmsh.model.getValue(0, hts.points['end_i'], [])[:-1]))
251
- self.oL.append(list(gmsh.model.getValue(0, hts.points['end_o'], [])[:-1]))
252
- # if block_key == 1 or block_key == 3 or block_key == 5 or block_key == 6:
253
- # radius = np.sqrt(np.square(iL[0] - coil.bore_center.x) +
254
- # np.square(iL[1] - coil.bore_center.y))
255
- # self.ax.add_patch(
256
- # patches.Circle((coil.bore_center.x, coil.bore_center.y), radius=radius,
257
- # color='b', fill=False))
258
- # radius = np.sqrt(np.square(oL[0] - coil.bore_center.x) +
259
- # np.square(oL[1] - coil.bore_center.y))
260
- # self.ax.add_patch(
261
- # patches.Circle((coil.bore_center.x, coil.bore_center.y), radius=radius,
262
- # color='c', fill=False))
263
- ################
264
-
265
- left = hts.lines['end']
266
- else:
267
- hf_next = block.half_turns[halfTurn_nr + 1].corners.insulated
268
- next_ht = str(halfTurn_nr + 1)
269
- mid_point_i = [(hf_next.iR.x + hf_current.iL.x) / 2,
270
- (hf_next.iR.y + hf_current.iL.y) / 2]
271
- mid_point_o = [(hf_next.oR.x + hf_current.oL.x) / 2,
272
- (hf_next.oR.y + hf_current.oL.y) / 2]
273
- hts.points[next_ht + 'i'] = self.occ.addPoint(mid_point_i[0], mid_point_i[1], 0,
274
- ll / frac)
275
- hts.points[next_ht + 'o'] = self.occ.addPoint(mid_point_o[0], mid_point_o[1], 0,
276
- ll / frac)
277
-
278
- hts.lines[ht + 'i'] = \
279
- self.occ.addLine(hts.points[next_ht + 'i'], hts.points[ht + 'i'])
280
- hts.lines[ht + 'o'] = \
281
- self.occ.addLine(hts.points[next_ht + 'o'], hts.points[ht + 'o'])
282
- hts.lines[next_ht + 'r'] = \
283
- self.occ.addLine(hts.points[next_ht + 'i'], hts.points[next_ht + 'o'])
284
- left = hts.lines[next_ht + 'r']
285
-
286
- # For plotting only
287
- if pole_nr == 1:
288
- self.occ.synchronize()
289
- self.iL.append(list(gmsh.model.getValue(0, hts.points[next_ht + 'i'], [])[:-1]))
290
- self.oL.append(list(gmsh.model.getValue(0, hts.points[next_ht + 'o'], [])[:-1]))
291
- if pole_nr == 1:
292
- self.iR.append(list(gmsh.model.getValue(0, hts.points[ht + 'i'], [])[:-1]))
293
- self.oR.append(list(gmsh.model.getValue(0, hts.points[ht + 'o'], [])[:-1]))
294
- hti = halfTurn.corners.insulated
295
- self.iLr.append([hti.iL.x, hti.iL.y])
296
- self.iRr.append([hti.iR.x, hti.iR.y])
297
- self.oLr.append([hti.oL.x, hti.oL.y])
298
- self.oRr.append([hti.oR.x, hti.oR.y])
299
- ################
300
-
301
- hts.areas[ht].loop = self.occ.addCurveLoop([hts.lines[ht + 'i'], # inner
302
- hts.lines[ht + 'r'], # right
303
- hts.lines[ht + 'o'], # outer
304
- left]) # left
305
-
306
- self.saveHalfTurnCornerPositions()
307
-
308
- def buildDomains(self):
1100
+ blk_ins.points[ht_nr + 'ih'] = self.occ.addPoint(ht.iH.x, ht.iH.y, 0)
1101
+ blk_ins.points[ht_nr + 'il'] = self.occ.addPoint(ht.iL.x, ht.iL.y, 0)
1102
+ blk_ins.points[ht_nr + 'oh'] = self.occ.addPoint(ht.oH.x, ht.oH.y, 0)
1103
+ blk_ins.points[ht_nr + 'ol'] = self.occ.addPoint(ht.oL.x, ht.oL.y, 0)
1104
+
1105
+ hts.areas[ht_nr].loop = self.occ.addCurveLoop(
1106
+ [hts.lines[ht_nr + 'i'], # inner
1107
+ hts.lines[ht_nr + 'l'], # lower
1108
+ hts.lines[ht_nr + 'o'], # outer
1109
+ hts.lines[ht_nr + 'h']]) # higher
1110
+
1111
+ # Build wire order of the insulation lines of the current block
1112
+ if run_type == 'TH' and not self.data.magnet.geometry.thermal.use_TSA:
1113
+ ht_list = list(hts.areas.keys())
1114
+ ht_list.extend(list(reversed(ht_list))[1:])
1115
+ self.blk_ins_lines[block_nr] = ['l']
1116
+ for nr, ht_nr in enumerate(ht_list):
1117
+ if nr + 1 == winding.conductors_number: # end of first round
1118
+ self.blk_ins_lines[block_nr].extend([ht_nr + 'i', 'h', ht_nr + 'o'])
1119
+ else:
1120
+ if nr + 1 < winding.conductors_number: # within first round
1121
+ self.blk_ins_lines[block_nr].extend([ht_nr + 'i', ht_nr + 'i' + ht_list[nr + 1]])
1122
+ else: # within second round
1123
+ self.blk_ins_lines[block_nr].extend([ht_nr + 'o' + ht_list[nr - 1], ht_nr + 'o'])
1124
+
1125
+ def constructInsulationGeometry(self):
309
1126
  """
310
- Generates plane surfaces from the curve loops
1127
+ Generates points, hyper lines, and curve loops for the coil insulations
311
1128
  """
312
- iron = self.geom.Roxie_Data.iron
313
- gm = self.md.geometries
1129
+ def _createMidPoleLines(case, cnt=0):
1130
+ if 'block-coil' in geom_coil.type:
1131
+ if case == 'inner':
1132
+ group.lines['mid_pole_' + case[0]] = self.occ.addLine(ins_pnt[first_ht_curr + case[0] + 'l'], ins_pnt_opposite[last_ht_prev + case[0] + 'h'])
1133
+ ordered_lines[group_nr].append(['mid_pole_' + case[0], (len(coil.layers) * 2) * 1e3 + 5e2, group.lines['mid_pole_' + case[0]]])
1134
+ else:
1135
+ group.lines['mid_pole_' + case[0]] = self.occ.addLine(ins_pnt[last_ht_curr + 'ih'], ins_pnt_opposite[first_ht_prev + 'il'])
1136
+ ordered_lines[group_nr].append(['mid_pole_' + case[0], 0, group.lines['mid_pole_' + case[0]]])
1137
+ else:
1138
+ ht_curr = geom_coil.poles[block_order.pole].layers[layer_nr].windings[block_order.winding].blocks[
1139
+ block_order.block].half_turns[int(first_ht_curr)].corners.insulated
1140
+ ht_prev = geom_coil.poles[block_order_prev.pole].layers[layer_nr].windings[block_order_prev.winding].blocks[
1141
+ block_order_prev.block].half_turns[int(last_ht_prev)].corners.insulated
1142
+ pnt_curr = [ht_curr.iL.x, ht_curr.iL.y] if case == 'inner' else [ht_curr.oL.x, ht_curr.oL.y]
1143
+ pnt_prev = [ht_prev.iH.x, ht_prev.iH.y] if case == 'inner' else [ht_prev.oH.x, ht_prev.oH.y]
1144
+ if Func.points_distance(pnt_curr, pnt_prev) > 1e-6:
1145
+ correct_center = Func.corrected_arc_center([self.md.geometries.coil.coils[coil_nr].bore_center.x, self.md.geometries.coil.coils[coil_nr].bore_center.y],
1146
+ [ht_curr.iL.x, ht_curr.iL.y] if case == 'inner' else [ht_curr.oL.x, ht_curr.oL.y],
1147
+ [ht_prev.iH.x, ht_prev.iH.y] if case == 'inner' else [ht_prev.oH.x, ht_prev.oH.y])
1148
+ ln_name = 'mid_pole_' + str(block_order_prev.block) + '_' + str(block_order.block) + '_' + case[0]
1149
+ group.lines[ln_name] = self.occ.addCircleArc(ins_pnt[first_ht_curr + case[0] + 'l'],
1150
+ self.occ.addPoint(correct_center[0], correct_center[1], 0),
1151
+ ins_pnt_opposite[last_ht_prev + case[0] + 'h'])
1152
+ # self.occ.addLine(ins_pnt[first_ht_curr + case[0] + 'l'], ins_pnt_opposite[last_ht_prev + case[0] + 'h'])
1153
+ cnt += 1 if case == 'inner' else -1
1154
+ ordered_lines[group_nr].append([ln_name, cnt, group.lines[ln_name]])
1155
+ return cnt
314
1156
 
315
- for i in iron.key_points:
316
- gm.iron.max_radius = max(gm.iron.max_radius, max(iron.key_points[i].x, iron.key_points[i].y))
1157
+ def _createMidWindingLines(case, cnt):
1158
+ name = 'mid_wind_' + str(block_order_prev.block) + '_' + str(block_order.block) + '_' + case[0]
1159
+ # Create corrected center
1160
+ blk1 = self.geom.coil.coils[coil_nr].poles[blks_info[str(block_order.block)][0]].layers[
1161
+ blks_info[str(block_order.block)][1]].windings[blks_info[str(block_order.block)][2]].blocks[int(str(block_order.block))]
1162
+ blk2 = self.geom.coil.coils[coil_nr].poles[blks_info[str(block_order_prev.block)][0]].layers[
1163
+ blks_info[str(block_order_prev.block)][1]].windings[blks_info[str(block_order_prev.block)][2]].blocks[int(block_order_prev.block)]
1164
+ pnt1 = blk1.half_turns[int(first_ht_curr)].corners.insulated.iL if case == 'inner' else blk1.half_turns[int(first_ht_curr)].corners.insulated.oL
1165
+ pnt2 = blk2.half_turns[int(last_ht_prev)].corners.insulated.iH if case == 'inner' else blk2.half_turns[int(last_ht_prev)].corners.insulated.oH
1166
+ outer_center = Func.corrected_arc_center([self.md.geometries.coil.coils[coil_nr].bore_center.x,
1167
+ self.md.geometries.coil.coils[coil_nr].bore_center.y],
1168
+ [pnt1.x, pnt1.y], [pnt2.x, pnt2.y])
1169
+ group.lines[name] = self.occ.addCircleArc(ins_pnt[first_ht_curr + case[0] + 'l'],
1170
+ self.occ.addPoint(outer_center[0], outer_center[1], 0), ins_pnt_opposite[last_ht_prev + case[0] + 'h'])
1171
+ cnt += 1 if case == 'inner' else -1
1172
+ ordered_lines[group_nr].append([name, cnt, group.lines[name]])
1173
+ return cnt
317
1174
 
318
- # Create and build air far field
319
- radius_in = gm.iron.max_radius * (2.5 if self.data.magnet.geometry.with_iron_yoke else 6)
320
- gm.air_inf.lines['inner'] = self.occ.addCircle(0., 0., 0., radius_in)
321
- gm.air_inf.areas['inner'] = dM.Area(loop=self.occ.addCurveLoop([gm.air_inf.lines['inner']]))
322
- gm.air_inf.areas['inner'].surface = self.occ.addPlaneSurface([self.md.geometries.air_inf.areas['inner'].loop])
323
- radius_out = gm.iron.max_radius * (3.2 if self.data.magnet.geometry.with_iron_yoke else 8)
324
- gm.air_inf.lines['outer'] = self.occ.addCircle(0., 0., 0., radius_out)
325
- gm.air_inf.areas['outer'] = dM.Area(loop=self.occ.addCurveLoop([gm.air_inf.lines['outer']]))
326
- gm.air_inf.areas['outer'].surface = self.occ.addPlaneSurface([gm.air_inf.areas['outer'].loop,
327
- gm.air_inf.areas['inner'].loop])
328
- self.md.domains.groups_surfaces['air_inf'] = [gm.air_inf.areas['outer'].surface]
1175
+ def _createInnerOuterLines(case, cnt):
1176
+ # Create half turn lines
1177
+ idxs = [1, round(len(self.blk_ins_lines[block_order.block]) / 2), 1] if case == 'inner'\
1178
+ else [len(self.blk_ins_lines[block_order.block]) - 1, round(len(self.blk_ins_lines[block_order.block]) / 2), -1]
1179
+ lns = self.blk_ins_lines[block_order.block][idxs[0]:idxs[1]:idxs[2]]
1180
+ for ln_nr, ln_name in enumerate(lns):
1181
+ skip_cnt = False
1182
+ if ln_name[-1].isdigit():
1183
+ try:
1184
+ group.lines[ln_name] = self.occ.addLine(ins_pnt[ln_name[:ln_name.index(case[0])] + case[0] + 'h'],
1185
+ ins_pnt[ln_name[ln_name.index(case[0]) + 1:] + case[0] + 'l'])
1186
+ except:
1187
+ skip_cnt = True
1188
+ next_line = lns[ln_nr + 1]
1189
+ pos = 'first' if next_line[:-1] == ln_name[:ln_name.index(case[0])] else 'second'
1190
+ lns[ln_nr + 1] = next_line + (ln_name[ln_name.index(case[0]) + 1:] + 'l' if pos == 'first' else ln_name[:ln_name.index(case[0])] + 'h')
1191
+ elif ln_name[-1] in ['i', 'o']:
1192
+ group.lines[ln_name] = self.occ.addLine(ins_pnt[ln_name + 'l'], ins_pnt[ln_name + 'h'])
1193
+ else:
1194
+ group.lines[ln_name] = self.occ.addLine(ins_pnt[ln_name[:ln_name.index(case[0])] + case[0] + ln_name[-1]],
1195
+ ins_pnt[ln_name[ln_name.index(case[0]) + 1:-1] + case[0] + ln_name[-1]])
1196
+ if not skip_cnt:
1197
+ cnt += 1 if case == 'inner' else -1
1198
+ ordered_lines[group_nr].append([ln_name, cnt, group.lines[ln_name]])
1199
+ return cnt
1200
+
1201
+ def _computePointAngle(case):
1202
+ points_angles = pa_next if case == 'outer' else pa_prev
1203
+ current_ht_h = [current_ht.oH.x, current_ht.oH.y] if case == 'outer' else [current_ht.iH.x, current_ht.iH.y]
1204
+ if ht_nr == 0:
1205
+ current_ht_l = [current_ht.oL.x, current_ht.oL.y] if case == 'outer' else [current_ht.iL.x, current_ht.iL.y]
1206
+ if 'block-coil' in geom_coil.type: current_ht_l[1] = 1 if current_ht_l[1] > 0 else -1
1207
+ points_angles[str(block_order.block) + '_' + ht_name + 'l'] = Func.arc_angle_between_point_and_abscissa(current_ht_l, center)
1208
+ if ht_nr == len(ht_list) - 1:
1209
+ name = ht_name + 'h'
1210
+ coord = current_ht_h
1211
+ else: # for mid half turns, get the outer corner
1212
+ next_ht_ins = geom_hts[int(ht_list[ht_nr + 1])].corners.insulated
1213
+ next_ht = [next_ht_ins.oL.x, next_ht_ins.oL.y] if case == 'outer' else [next_ht_ins.iL.x, next_ht_ins.iL.y]
1214
+ condition = (Func.points_distance(current_ht_h, center) > Func.points_distance(next_ht, center))\
1215
+ if case == 'outer' else (Func.points_distance(current_ht_h, center) < Func.points_distance(next_ht, center))
1216
+ if condition:
1217
+ name = ht_name + 'h'
1218
+ coord = current_ht_h
1219
+ else:
1220
+ name = ht_list[ht_nr + 1] + 'l'
1221
+ coord = next_ht
1222
+ if 'block-coil' in geom_coil.type: coord[1] = 1 if coord[1] > 0 else -1
1223
+ points_angles[str(block_order.block) + '_' + name] = Func.arc_angle_between_point_and_abscissa(coord, center)
1224
+
1225
+ ins = self.md.geometries.insulation
1226
+ for coil_nr, coil in self.md.geometries.coil.anticlockwise_order.coils.items():
1227
+ aux_coil = self.md.geometries.coil.coils[coil_nr]
1228
+ geom_coil = self.geom.coil.coils[coil_nr]
1229
+ groups = len(geom_coil.poles)
1230
+ count = {}
1231
+ ordered_lines = {}
1232
+ points_angle = {}
1233
+ blks_info = {}
1234
+ ending_line = {}
1235
+ center = [geom_coil.bore_center.x, geom_coil.bore_center.y]
1236
+ if coil_nr not in ins.coils:
1237
+ ins.coils[coil_nr] = dM.InsulationGroup()
1238
+ ins_groups = ins.coils[coil_nr].group
1239
+ for layer_nr, layer in coil.layers.items():
1240
+ group_nr = 1
1241
+ wnd_nr = len(aux_coil.poles[1].layers[layer_nr].windings)
1242
+ ordered_layer = layer[wnd_nr:] + layer[:wnd_nr] if layer[0].pole != layer[-1].pole else layer
1243
+ for nr, block_order in enumerate(ordered_layer):
1244
+ blks_info[str(block_order.block)] = [block_order.pole, layer_nr, block_order.winding]
1245
+ # Get previous block in anticlockwise order
1246
+ block_order_prev = ordered_layer[-1] if nr == 0 else ordered_layer[nr - 1]
1247
+ # Update insulation group
1248
+ if block_order.winding == block_order_prev.winding:
1249
+ group_nr = group_nr + 1 if group_nr < groups else 1
1250
+ # Initialize dicts
1251
+ if group_nr not in ins_groups:
1252
+ ins_groups[group_nr] = dM.InsulationRegion()
1253
+ points_angle[group_nr] = {}
1254
+ ordered_lines[group_nr] = []
1255
+ count[group_nr] = [0, (len(coil.layers) + 1) * 1e3]
1256
+ group = ins_groups[group_nr].ins
1257
+ ins_groups[group_nr].blocks.append([block_order.pole, layer_nr, block_order.winding, block_order.block])
1258
+ # Find the wedge
1259
+ if block_order.pole == block_order_prev.pole and block_order.winding != block_order_prev.winding:
1260
+ for wdg, blk in self.md.geometries.wedges.coils[coil_nr].layers[layer_nr].block_prev.items():
1261
+ if blk == block_order_prev.block:
1262
+ ins_groups[group_nr].wedges.append([layer_nr, wdg])
1263
+ break
1264
+ if layer_nr < len(coil.layers):
1265
+ mid_layer_next = str(layer_nr) + '_' + str(layer_nr + 1)
1266
+ if mid_layer_next not in points_angle[group_nr]:
1267
+ points_angle[group_nr][mid_layer_next] = {}
1268
+ pa_next = points_angle[group_nr][mid_layer_next]
1269
+ if layer_nr > 1:
1270
+ mid_layer_prev = str(layer_nr - 1) + '_' + str(layer_nr)
1271
+ pa_prev = points_angle[group_nr][mid_layer_prev]
1272
+ # Get point tags of insulation
1273
+ ins_pnt = aux_coil.poles[block_order.pole].layers[layer_nr].windings[block_order.winding].blocks[
1274
+ block_order.block].insulation.points
1275
+ # Get relevant info for line names
1276
+ first_ht_curr = self.blk_ins_lines[block_order.block][1][:-1]
1277
+ last_ht_prev = list(aux_coil.poles[block_order_prev.pole].layers[
1278
+ layer_nr].windings[block_order_prev.winding].blocks[block_order_prev.block].half_turns.areas.keys())[-1]
1279
+ ins_pnt_opposite = aux_coil.poles[block_order_prev.pole].layers[
1280
+ layer_nr].windings[block_order_prev.winding].blocks[block_order_prev.block].insulation.points
1281
+ if 'cos-theta' == geom_coil.type:
1282
+ # Create lower and higher angle lines
1283
+ if block_order.winding == block_order_prev.winding:
1284
+ group.lines[str(layer_nr) + 'l'] = self.occ.addLine(ins_pnt[first_ht_curr + 'il'], ins_pnt[first_ht_curr + 'ol'])
1285
+ ordered_lines[group_nr].append([str(layer_nr) + 'l', (len(coil.layers) * 2 - layer_nr + 1) * 1e3, group.lines[str(layer_nr) + 'l']])
1286
+ ending_line[group_nr - 1 if group_nr > 1 else groups] =\
1287
+ [ins_pnt_opposite[last_ht_prev + 'ih'], ins_pnt_opposite[last_ht_prev + 'oh']]
1288
+ # Create inner lines of insulation group
1289
+ if layer_nr == 1:
1290
+ if block_order.pole != block_order_prev.pole:
1291
+ count[group_nr][0] = _createMidPoleLines('inner', count[group_nr][0])
1292
+ if block_order.pole == block_order_prev.pole and block_order.winding != block_order_prev.winding:
1293
+ count[group_nr][0] = _createMidWindingLines('inner', count[group_nr][0])
1294
+ count[group_nr][0] = _createInnerOuterLines('inner', count[group_nr][0])
1295
+ # Create outer lines of insulation group
1296
+ if layer_nr == len(coil.layers):
1297
+ if block_order.pole != block_order_prev.pole:
1298
+ count[group_nr][1] = _createMidPoleLines('outer', count[group_nr][1])
1299
+ if block_order.pole == block_order_prev.pole and block_order.winding != block_order_prev.winding:
1300
+ count[group_nr][1] = _createMidWindingLines('outer', count[group_nr][1])
1301
+ count[group_nr][1] = _createInnerOuterLines('outer', count[group_nr][1])
1302
+ elif 'block-coil' in geom_coil.type:
1303
+ last_ht_curr = self.blk_ins_lines[block_order.block][self.blk_ins_lines[block_order.block].index('h') - 1][:-1]
1304
+ first_ht_prev = list(aux_coil.poles[block_order_prev.pole].layers[layer_nr].windings[
1305
+ block_order_prev.winding].blocks[block_order_prev.block].half_turns.areas.keys())[0]
1306
+ # Create lower and higher angle lines
1307
+ if block_order.winding == block_order_prev.winding:
1308
+ group.lines[str(layer_nr) + 'l'] = self.occ.addLine(ins_pnt[first_ht_curr + 'il'], ins_pnt[first_ht_curr + 'ol'])
1309
+ ordered_lines[group_nr].append([str(layer_nr) + 'l', (len(coil.layers) * 4 - layer_nr + 1) * 1e3, group.lines[str(layer_nr) + 'l']])
1310
+ ending_line[group_nr - 1 if group_nr > 1 else groups] =\
1311
+ [ins_pnt_opposite[last_ht_prev + 'ih'], ins_pnt_opposite[last_ht_prev + 'oh']]
1312
+ group.lines[str(layer_nr) + 'bh'] = self.occ.addLine(ins_pnt[last_ht_curr + 'ih'], ins_pnt[last_ht_curr + 'oh'])
1313
+ ordered_lines[group_nr].append([str(layer_nr) + 'bh', (len(coil.layers) * 2 + layer_nr) * 1e3, group.lines[str(layer_nr) + 'bh']])
1314
+ # Create inner lines of insulation group
1315
+ if block_order.pole != block_order_prev.pole:
1316
+ if layer_nr == 1:
1317
+ _createMidPoleLines('inner')
1318
+ _createMidPoleLines('outer')
1319
+ group.lines[str(layer_nr) + 'bl'] = self.occ.addLine(ins_pnt[first_ht_curr + 'il'], ins_pnt[first_ht_curr + 'ol'])
1320
+ ordered_lines[group_nr].append([str(layer_nr) + 'bl', (len(coil.layers) * 2 - layer_nr + 1) * 1e3, group.lines[str(layer_nr) + 'bl']])
1321
+ # Create outer lines of insulation group
1322
+ if layer_nr == len(coil.layers):
1323
+ count[group_nr][1] = _createInnerOuterLines(
1324
+ 'outer', (len(coil.layers) * 4 - layer_nr + 1) * 1e3 if block_order.winding == block_order_prev.winding else (len(coil.layers) + 1) * 1e3)
1325
+ # Store info about the angle of each point in between layers
1326
+ ht_list = list(aux_coil.poles[block_order.pole].layers[
1327
+ layer_nr].windings[block_order.winding].blocks[block_order.block].half_turns.areas.keys())
1328
+ geom_hts = geom_coil.poles[block_order.pole].layers[
1329
+ layer_nr].windings[block_order.winding].blocks[block_order.block].half_turns
1330
+ for ht_nr, ht_name in enumerate(ht_list): # half turns in anticlockwise order
1331
+ current_ht = geom_hts[int(ht_name)].corners.insulated
1332
+ if layer_nr < len(coil.layers): # if it's not the last layer, fetch all outer corners angles
1333
+ _computePointAngle('outer')
1334
+ if layer_nr > 1: # if it's not the first layer, fetch all inner corners angles
1335
+ _computePointAngle('inner')
1336
+ # Create closing lines
1337
+ for grp_nr, grp in ending_line.items():
1338
+ ins_groups[grp_nr].ins.lines[str(layer_nr) + 'h'] = self.occ.addLine(grp[0], grp[1])
1339
+ ordered_lines[grp_nr].append([str(layer_nr) + 'h', layer_nr * 1e3, ins_groups[grp_nr].ins.lines[str(layer_nr) + 'h']])
1340
+ # Create lines connecting different layers and generate closed loops
1341
+ for group_nr, group in points_angle.items():
1342
+ ins_group = ins_groups[group_nr].ins
1343
+ for mid_l_name, mid_l in group.items():
1344
+ first_layer = mid_l_name[:mid_l_name.index('_')]
1345
+ # Correct angles if the group crosses the abscissa
1346
+ max_angle = max(mid_l.values())
1347
+ max_diff = max_angle - min(mid_l.values())
1348
+ if max_diff > np.pi:
1349
+ for pnt_name, angle in mid_l.items():
1350
+ if angle < max_diff / 2:
1351
+ mid_l[pnt_name] = angle + max_angle
1352
+ # Order points according to angle
1353
+ ordered_pnts = [[pnt_name, angle] for pnt_name, angle in mid_l.items()]
1354
+ ordered_pnts.sort(key=lambda x: x[1])
1355
+ ordered_names = [x[0] for x in ordered_pnts]
1356
+ for case in ['beg', 'end']:
1357
+ past_blocks = []
1358
+ sides = ['l', 'o', 'h', 'l'] if case == 'beg' else ['h', 'i', 'l', 'h']
1359
+ # count = int(first_layer) * 1e3 + 5e2 if case == 'end' else (len(coil.layers) * 2 - int(first_layer)) * 1e3 + 5e2
1360
+ for i in range(2 if 'block-coil' in geom_coil.type else 1):
1361
+ count = int(first_layer) * 1e3 + 5e2 if i == 0 else (len(coil.layers) * 2 + int(first_layer)) * 1e3 + 5e2
1362
+ if case == 'beg':
1363
+ pnt_position = 0 if i == 0 else int(len(ordered_names) / 2)
1364
+ else:
1365
+ pnt_position = -1 if i == 0 else int(len(ordered_names) / 2 - 1)
1366
+ first_block = ordered_names[pnt_position][:ordered_names[pnt_position].index('_')] # ordered_pnts[pnt_position][0][:ordered_pnts[pnt_position][0].index('_')] #
1367
+ ordered_search_names = ordered_names[pnt_position::1 if case == 'beg' else -1]
1368
+ for nr, pnt in enumerate(ordered_search_names[1:], 1): # enumerate(ordered_names if case == 'beg' else reversed(ordered_names)): #
1369
+ current_blk = pnt[:pnt.index('_')]
1370
+ ins_pnt = aux_coil.poles[blks_info[current_blk][0]].layers[blks_info[current_blk][1]].windings[
1371
+ blks_info[current_blk][2]].blocks[int(current_blk)].insulation.points
1372
+ prev_pnt = ordered_search_names[nr - 1] # ordered_pnts[nr - 1 if case == 'beg' else - nr][0] #
1373
+ prev_blk = prev_pnt[:prev_pnt.index('_')]
1374
+ start_pnt_name = prev_pnt[prev_pnt.index('_') + 1:-1] + ('o' if str(blks_info[prev_blk][1]) == first_layer else 'i')
1375
+ ins_pnt_prev = aux_coil.poles[blks_info[prev_blk][0]].layers[blks_info[prev_blk][1]].windings[
1376
+ blks_info[prev_blk][2]].blocks[int(prev_blk)].insulation.points
1377
+ # Create lines when you find the first edge belonging to a block of the opposite layer
1378
+ if blks_info[current_blk][1] != blks_info[first_block][1]:
1379
+ pnt_tag_name = pnt[pnt.index('_') + 1:-1] + ('o' if str(blks_info[current_blk][1]) == first_layer else 'i') + ('l' if pnt[-1] == 'l' else 'h')
1380
+ pnt_tag_name_opposite = start_pnt_name + ('l' if prev_pnt[-1] == 'l' else 'h')
1381
+ opp_blk_ins_lines = self.blk_ins_lines[int(prev_blk)]
1382
+ indexes = [opp_blk_ins_lines.index(start_pnt_name) + (1 if prev_pnt[-1] == sides[0] else 0),
1383
+ len(opp_blk_ins_lines) if case == 'beg' else opp_blk_ins_lines.index('h'), 1] if start_pnt_name[-1] == sides[1]\
1384
+ else [opp_blk_ins_lines.index(start_pnt_name) - (1 if prev_pnt[-1] == sides[0] else 0),
1385
+ 0 if case == 'beg' else opp_blk_ins_lines.index('h'), -1]
1386
+ if case == 'beg':
1387
+ if i == 0:
1388
+ count = (len(coil.layers) * (4 if 'block-coil' in geom_coil.type else 2) - int(first_layer)) * 1e3 + 5e2 - abs(indexes[0] - indexes[1])
1389
+ else:
1390
+ count = (len(coil.layers) * 2 - int(first_layer)) * 1e3 + 5e2 - abs(indexes[0] - indexes[1])
1391
+ else:
1392
+ count += 1 + abs(indexes[0] - indexes[1])
1393
+ # Create all remaining lines of the current layer block
1394
+ for line_name in opp_blk_ins_lines[indexes[0]:indexes[1]:indexes[2]]:
1395
+ if 'block-coil' in geom_coil.type:
1396
+ if not line_name[-1].isdigit():
1397
+ ins_group.lines[line_name] = self.occ.addLine(ins_pnt_prev[line_name + 'l'], ins_pnt_prev[line_name + 'h'])
1398
+ count += 1 if (case == 'beg' and i == 1) or (case == 'end' and i == 0) else -1
1399
+ ordered_lines[group_nr].append([line_name, count, ins_group.lines[line_name]])
1400
+ else:
1401
+ if line_name[-1].isdigit():
1402
+ ins_group.lines[line_name] = self.occ.addLine(
1403
+ ins_pnt_prev[line_name[:line_name.index(start_pnt_name[-1])] + start_pnt_name[-1] + 'h'],
1404
+ ins_pnt_prev[line_name[line_name.index(start_pnt_name[-1]) + 1:] + start_pnt_name[-1] + 'l'])
1405
+ else:
1406
+ ins_group.lines[line_name] = self.occ.addLine(ins_pnt_prev[line_name + 'l'], ins_pnt_prev[line_name + 'h'])
1407
+ count += 1 if case == 'beg' else -1 # if start_pnt_name[-1] == sides[1] else 1
1408
+ ordered_lines[group_nr].append([line_name, count, ins_group.lines[line_name]])
1409
+ # Create mid layer line
1410
+ if 'block-coil' in geom_coil.type:
1411
+ count_rest = -abs(indexes[0] - indexes[1]) if (case == 'beg' and i == 1) or (case == 'end' and i == 0) else 1 + abs(indexes[0] - indexes[1])
1412
+ else:
1413
+ count_rest = -abs(indexes[0] - indexes[1]) if case == 'beg' else 1 + abs(indexes[0] - indexes[1])
1414
+ line_name = 'mid_layer_' + mid_l_name + ('b' if i == 1 else '') + ('_l' if case == 'beg' else '_h')
1415
+ ins_group.lines[line_name] = self.occ.addLine(ins_pnt[pnt_tag_name], ins_pnt_prev[pnt_tag_name_opposite])
1416
+ ordered_lines[group_nr].append([line_name, count + count_rest, ins_group.lines[line_name]])
1417
+ break
1418
+ # Create all edges of the first block sticking out completely todo: might have to be extended to multiple blocks
1419
+ if current_blk != first_block and current_blk not in past_blocks:
1420
+ def __createWedgeInsulation(cnt):
1421
+ # Create the line connecting the blocks (where a wedge is)
1422
+ line_name = self.blk_ins_lines[int(current_blk)][
1423
+ (-1 if start_pnt_name[-1] == 'o' else 1) if case == 'beg'
1424
+ else (round(len(self.blk_ins_lines[int(current_blk)]) / 2) + (1 if start_pnt_name[-1] == 'o' else -1))]
1425
+ line_name_prev = self.blk_ins_lines[int(prev_blk)][
1426
+ (round(len(self.blk_ins_lines[int(prev_blk)]) / 2) + (1 if start_pnt_name[-1] == 'o' else -1)) if case == 'beg'
1427
+ else (-1 if start_pnt_name[-1] == 'o' else 1)]
1428
+ # Create corrected center
1429
+ blk1 = geom_coil.poles[blks_info[prev_blk][0]].layers[
1430
+ blks_info[prev_blk][1]].windings[blks_info[prev_blk][2]].blocks[int(prev_blk)]
1431
+ blk2 = geom_coil.poles[blks_info[current_blk][0]].layers[
1432
+ blks_info[current_blk][1]].windings[blks_info[current_blk][2]].blocks[int(current_blk)]
1433
+ pnt1 = blk1.half_turns[int(line_name_prev[:-1])].corners.insulated.oH if case == 'beg'\
1434
+ else blk1.half_turns[int(line_name_prev[:-1])].corners.insulated.oL
1435
+ pnt2 = blk2.half_turns[int(line_name[:-1])].corners.insulated.oL if case == 'beg'\
1436
+ else blk2.half_turns[int(line_name[:-1])].corners.insulated.oH
1437
+ outer_center = Func.corrected_arc_center([aux_coil.bore_center.x, aux_coil.bore_center.y],
1438
+ [pnt2.x, pnt2.y] if case == 'beg' else [pnt1.x, pnt1.y],
1439
+ [pnt1.x, pnt1.y] if case == 'beg' else [pnt2.x, pnt2.y])
1440
+ ins_group.lines[line_name_prev + line_name] =\
1441
+ self.occ.addCircleArc(ins_pnt_prev[line_name_prev + sides[2]],
1442
+ self.occ.addPoint(outer_center[0], outer_center[1], 0), ins_pnt[line_name + sides[3]])
1443
+ ordered_lines[group_nr].append([line_name_prev + line_name, cnt, ins_group.lines[line_name_prev + line_name]])
1444
+
1445
+ count = int(first_layer) * 1e3 + 5e2 if case == 'end' else (len(coil.layers) * 2 - int(first_layer)) * 1e3 + 5e2
1446
+ past_blocks.append(current_blk)
1447
+ indexes = [round(len(self.blk_ins_lines[int(prev_blk)]) / 2) + 1,
1448
+ len(self.blk_ins_lines[int(prev_blk)])] if str(blks_info[prev_blk][1]) == first_layer\
1449
+ else [1, round(len(self.blk_ins_lines[int(prev_blk)]) / 2)]
1450
+ if case == 'beg':
1451
+ count += 1
1452
+ __createWedgeInsulation(count)
1453
+ lines = self.blk_ins_lines[int(prev_blk)][indexes[0]:indexes[1]]
1454
+ side = 'o' if str(blks_info[prev_blk][1]) == first_layer else 'i'
1455
+ for line_nr, line_name in enumerate(lines):
1456
+ skip_count = False
1457
+ if line_name[-1].isdigit():
1458
+ try:
1459
+ ins_group.lines[line_name] =\
1460
+ self.occ.addLine(ins_pnt_prev[line_name[line_name.index(start_pnt_name[-1]) + 1:] + start_pnt_name[-1] + 'l'],
1461
+ ins_pnt_prev[line_name[:line_name.index(start_pnt_name[-1])] + start_pnt_name[-1] + 'h'])
1462
+ except: # points are too close to each other
1463
+ skip_count = True
1464
+ next_line = lines[line_nr + 1]
1465
+ pnt1, pnt2 = line_name.split(side)
1466
+ pos = 'first' if next_line[:-1] == pnt1 else 'second'
1467
+ lines[line_nr + 1] = next_line + (pnt2 + 'l' if pos == 'first' else pnt1 + 'h')
1468
+ elif line_name[-1] in ['i', 'o']:
1469
+ ins_group.lines[line_name] = self.occ.addLine(ins_pnt_prev[line_name + 'h'], ins_pnt_prev[line_name + 'l'])
1470
+ else:
1471
+ ins_group.lines[line_name] = self.occ.addLine(ins_pnt_prev[line_name[:line_name.index(side)] + side + line_name[-1]],
1472
+ ins_pnt_prev[line_name[line_name.index(side) + 1:-1] + side + line_name[-1]])
1473
+ if not skip_count:
1474
+ count += 1 # if start_pnt_name[-1] == sides[1] else -1
1475
+ ordered_lines[group_nr].append([line_name, count, ins_group.lines[line_name]])
1476
+ if case == 'end':
1477
+ count += 1
1478
+ __createWedgeInsulation(count)
1479
+
1480
+ # Generate closed loops
1481
+ ordered_lines[group_nr].sort(key=lambda x: x[1])
1482
+ area_name = str((coil_nr - 1) * len(ins_groups) + group_nr)
1483
+ ins_group.areas[area_name] = dM.Area()
1484
+ if len(points_angle) == 1:
1485
+ ins_group.areas['inner_loop'] = dM.Area(loop=self.occ.addCurveLoop([ins_group.lines[line] for line in [x[0] for x in ordered_lines[group_nr]]
1486
+ if 'i' in line and line[0].isdigit() or '_i' in line]))
1487
+ ins_group.areas[area_name].loop = self.occ.addCurveLoop([ins_group.lines[line] for line in [x[0] for x in ordered_lines[group_nr]]
1488
+ if 'o' in line and line[0].isdigit() or '_o' in line])
1489
+ else:
1490
+ ins_group.areas[area_name].loop = self.occ.addCurveLoop([ins_group.lines[line] for line in [x[0] for x in ordered_lines[group_nr]]])
1491
+
1492
+ def constructThinShells(self, with_wedges):
1493
+ ins_th = self.md.geometries.thin_shells.ins_thickness
1494
+ mid_pole_ts = self.md.geometries.thin_shells.mid_poles
1495
+ mid_winding_ts = self.md.geometries.thin_shells.mid_windings
1496
+ mid_turn_ts = self.md.geometries.thin_shells.mid_turn_blocks
1497
+ mid_layer_ts = self.md.geometries.thin_shells.mid_layers_ht_to_ht
1498
+ mid_layer_ts_aux = self.md.geometries.thin_shells.mid_layers_aux
1499
+
1500
+ # Create mid-pole and mid-turn thin shells
1501
+ for coil_nr, coil in self.md.geometries.coil.anticlockwise_order.coils.items():
1502
+ for layer_nr, layer in coil.layers.items():
1503
+ for nr, blk_order in enumerate(layer):
1504
+ block = self.geom.coil.coils[coil_nr].poles[blk_order.pole].layers[
1505
+ layer_nr].windings[blk_order.winding].blocks[blk_order.block]
1506
+ ht_list = list(self.md.geometries.coil.coils[coil_nr].poles[blk_order.pole].layers[
1507
+ layer_nr].windings[blk_order.winding].blocks[blk_order.block].half_turns.areas.keys())
1508
+ # Create mid-pole and mid-winding thin shells
1509
+ blk_index_next = nr + 1 if nr + 1 < len(layer) else 0
1510
+ block_order_next = layer[blk_index_next]
1511
+ block_next = self.geom.coil.coils[coil_nr].poles[block_order_next.pole].layers[
1512
+ layer_nr].windings[block_order_next.winding].blocks[block_order_next.block]
1513
+ ht_list_next = list(self.md.geometries.coil.coils[coil_nr].poles[block_order_next.pole].layers[
1514
+ layer_nr].windings[block_order_next.winding].blocks[block_order_next.block].half_turns.areas.keys())
1515
+ ht_last = int(ht_list[-1])
1516
+ ht_next_first = int(ht_list_next[0])
1517
+ iH = [block.half_turns[ht_last].corners.bare.iH.x, block.half_turns[ht_last].corners.bare.iH.y]
1518
+ iL = [block_next.half_turns[ht_next_first].corners.bare.iL.x, block_next.half_turns[ht_next_first].corners.bare.iL.y]
1519
+ oH = [block.half_turns[ht_last].corners.bare.oH.x, block.half_turns[ht_last].corners.bare.oH.y]
1520
+ oL = [block_next.half_turns[ht_next_first].corners.bare.oL.x, block_next.half_turns[ht_next_first].corners.bare.oL.y]
1521
+ ts_name = str(blk_order.block) + '_' + str(block_order_next.block)
1522
+ for ts, th, condition in zip([mid_pole_ts, mid_winding_ts], [ins_th.mid_pole, ins_th.mid_winding],
1523
+ # ['_ly' + str(layer_nr), '_wd' + str(blk_order.winding) + '_wd' + str(block_order_next.winding)],
1524
+ [self.geom.coil.coils[coil_nr].type == 'cos-theta' and block_order_next.pole != blk_order.pole,
1525
+ (not with_wedges or not self.geom.wedges) and self.geom.coil.coils[coil_nr].type in
1526
+ ['cos-theta', 'common-block-coil'] and block_order_next.pole == blk_order.pole and block_order_next.winding != blk_order.winding]):
1527
+ if condition:
1528
+ ts[ts_name] = dM.Region()
1529
+ ts[ts_name].points['i'] = self.occ.addPoint((iH[0] + iL[0]) / 2, (iH[1] + iL[1]) / 2, 0)
1530
+ ts[ts_name].points['o'] = self.occ.addPoint((oH[0] + oL[0]) / 2, (oH[1] + oL[1]) / 2, 0)
1531
+ ts[ts_name].lines[str(ht_last) + '_' + str(ht_next_first)] =\
1532
+ self.occ.addLine(ts[ts_name].points['i'], ts[ts_name].points['o'])
1533
+ # Get insulation thickness
1534
+ th[ts_name] = Func.sig_dig((Func.points_distance(iH, iL) + Func.points_distance(oH, oL)) / 2)
1535
+ # if 'cl' + str(coil_nr) + th_name not in th:
1536
+ # th['cl' + str(coil_nr) + th_name] = float((Func.points_distance(iH, iL) + Func.points_distance(oH, oL)) / 2)
1537
+ # Create mid-turn thin shells
1538
+ mid_turn_ts[str(blk_order.block)] = dM.Region()
1539
+ ts = mid_turn_ts[str(blk_order.block)]
1540
+ for nr_ht, ht in enumerate(ht_list[:-1]):
1541
+ line_name = ht + '_' + ht_list[nr_ht + 1]
1542
+ current_ht = block.half_turns[int(ht)].corners.bare
1543
+ next_ht = block.half_turns[int(ht_list[nr_ht + 1])].corners.bare
1544
+ mid_inner = [(current_ht.iH.x + next_ht.iL.x) / 2, (current_ht.iH.y + next_ht.iL.y) / 2]
1545
+ mid_outer = [(current_ht.oH.x + next_ht.oL.x) / 2, (current_ht.oH.y + next_ht.oL.y) / 2]
1546
+ mid_length = Func.points_distance(mid_inner, mid_outer)
1547
+ mid_line = Func.line_through_two_points(mid_inner, mid_outer)
1548
+ points = {'inner': list, 'outer': list}
1549
+ for case, current_h, current_l, next_h, next_l, mid_point in zip(
1550
+ ['inner', 'outer'], [current_ht.iH, current_ht.oH], [current_ht.iL, current_ht.oL],
1551
+ [next_ht.iH, next_ht.oH], [next_ht.iL, next_ht.oL], [mid_outer, mid_inner]):
1552
+ current_line = Func.line_through_two_points([current_h.x, current_h.y], [current_l.x, current_l.y])
1553
+ next_line = Func.line_through_two_points([next_h.x, next_h.y], [next_l.x, next_l.y])
1554
+ current_intersect = Func.intersection_between_two_lines(mid_line, current_line)
1555
+ next_intersect = Func.intersection_between_two_lines(mid_line, next_line)
1556
+ points[case] = current_intersect if Func.points_distance(
1557
+ current_intersect, mid_point) < mid_length else next_intersect
1558
+ ts.points[line_name + '_i'] = self.occ.addPoint(points['inner'][0], points['inner'][1], 0)
1559
+ ts.points[line_name + '_o'] = self.occ.addPoint(points['outer'][0], points['outer'][1], 0)
1560
+ ts.lines[line_name] = self.occ.addLine(ts.points[line_name + '_i'], ts.points[line_name + '_o'])
1561
+
1562
+ # Create mid-layer thin shells
1563
+ block_coil_mid_pole_list = [str(blks[0].block) + '_' + str(blks[1].block) for coil_nr, coil in self.block_coil_mid_pole_blks.items() for blks in coil]
1564
+ for ts_name, ts in mid_layer_ts.items():
1565
+ # Order mid-layer thin shell points according to their angle with respect to the x-axis to generate lines
1566
+ blk1, blk2 = ts_name.split('_')
1567
+ max_angle = max(ts.point_angles.values())
1568
+ max_diff = max_angle - min(ts.point_angles.values())
1569
+ if max_diff > np.pi:
1570
+ for pnt_name, angle in ts.point_angles.items():
1571
+ if angle < max_diff / 2:
1572
+ ts.point_angles[pnt_name] = angle + max_angle
1573
+ ordered_pnts = [[pnt_name, ts.point_angles[pnt_name], pnt] for pnt_name, pnt in ts.mid_layers.points.items()]
1574
+ ordered_pnts.sort(key=lambda x: x[1])
1575
+ for nr, pnt in enumerate(ordered_pnts[:-1]):
1576
+ pnt_current = pnt[0]
1577
+ pnt_next = ordered_pnts[nr + 1][0]
1578
+ if ((pnt_current[-1] == 'l' and pnt_next[-1] == 'h' and ts_name not in block_coil_mid_pole_list) or # cos-theta
1579
+ (ts_name in block_coil_mid_pole_list and
1580
+ ((pnt_current[-1] == pnt_next[-1] == 'h' and block_coil_mid_pole_list.index(ts_name) == 0) or # assumes a dipole block-coil
1581
+ (pnt_current[-1] == pnt_next[-1] == 'l' and block_coil_mid_pole_list.index(ts_name) == 1) or # assumes a dipole block-coil
1582
+ (pnt_current[:-1] == pnt_next[:-1])))):
1583
+ if pnt_current[:-1] == pnt_next[:-1]:
1584
+ relevant_blk = blk2 if int(pnt_current[:-1]) in ts.half_turn_lists[blk1] else blk1
1585
+ if nr > 0:
1586
+ iter_nr = nr - 1
1587
+ while int(ordered_pnts[iter_nr][0][:-1]) not in ts.half_turn_lists[relevant_blk]: iter_nr -= 1
1588
+ line_name = ordered_pnts[iter_nr][0][:-1] + '_' + pnt_current[:-1]
1589
+ else:
1590
+ if len(ordered_pnts) == 2: # todo: get right ht from relevant_blk for 1-ht blocks
1591
+ line_name = pnt_current[:-1] + '_' + str(ts.half_turn_lists[relevant_blk][0])
1592
+ else:
1593
+ iter_nr = nr + 1
1594
+ while int(ordered_pnts[iter_nr][0][:-1]) not in ts.half_turn_lists[relevant_blk]: iter_nr += 1
1595
+ line_name = pnt_current[:-1] + '_' + ordered_pnts[iter_nr][0][:-1]
1596
+ else:
1597
+ line_name = pnt_current[:-1] + '_' + pnt_next[:-1]
1598
+ ts.mid_layers.lines[line_name] = self.occ.addLine(pnt[2], ordered_pnts[nr + 1][2])
1599
+ if ts_name in mid_layer_ts_aux:
1600
+ aux_pnt = list(mid_layer_ts_aux[ts_name].points.keys())[0]
1601
+ other_pnt = ordered_pnts[0 if aux_pnt[-1] == 'l' else -1]
1602
+ other_pnt_coord = gmsh.model.getValue(0, other_pnt[2], [])[:2] # needs to be a new point
1603
+ mid_layer_ts_aux[ts_name].points[other_pnt[0]] = self.occ.addPoint(other_pnt_coord[0], other_pnt_coord[1], 0)
1604
+ line_name = list(mid_layer_ts_aux[ts_name].lines.keys())[0]
1605
+ try:
1606
+ mid_layer_ts_aux[ts_name].lines[line_name] = \
1607
+ self.occ.addLine(mid_layer_ts_aux[ts_name].points[aux_pnt], mid_layer_ts_aux[ts_name].points[other_pnt[0]])
1608
+ except:
1609
+ mid_layer_ts_aux[ts_name].lines.pop(line_name)
1610
+
1611
+ # Create wedge-to-block and block-to-wedge lines
1612
+ for wdg_ts in [self.md.geometries.thin_shells.mid_layers_wdg_to_ht, self.md.geometries.thin_shells.mid_layers_ht_to_wdg]:
1613
+ for ts_name, ts in wdg_ts.items():
1614
+ pnt_list = list(ts.points.keys())
1615
+ for nr, pnt in enumerate(pnt_list[:-1]):
1616
+ if pnt[-1] == 'l' and pnt_list[nr + 1][-1] == 'h':
1617
+ ts.lines[pnt[:-1] + '_' + pnt_list[nr + 1][:-1]] = self.occ.addLine(ts.points[pnt], ts.points[pnt_list[nr + 1]])
1618
+ if ts_name in mid_layer_ts_aux:
1619
+ aux_pnt = list(mid_layer_ts_aux[ts_name].points.keys())[
1620
+ 1 if list(mid_layer_ts_aux[ts_name].points.keys()).index('center') == 0 else 0]
1621
+ other_pnt = pnt_list[0 if aux_pnt[-1] == 'l' else -1]
1622
+ other_pnt_coord = gmsh.model.getValue(0, ts.points[other_pnt], [])[:2] # needs to be a new point
1623
+ mid_layer_ts_aux[ts_name].points[other_pnt] = self.occ.addPoint(other_pnt_coord[0], other_pnt_coord[1], 0)
1624
+ line_name = list(mid_layer_ts_aux[ts_name].lines.keys())[0]
1625
+ mid_layer_ts_aux[ts_name].lines[line_name] = self.occ.addCircleArc(
1626
+ mid_layer_ts_aux[ts_name].points[aux_pnt], mid_layer_ts_aux[ts_name].points['center'], mid_layer_ts_aux[ts_name].points[other_pnt])
1627
+
1628
+ # Create wedge-to-wedge lines
1629
+ for ts_nr, ts in self.md.geometries.thin_shells.mid_layers_wdg_to_wdg.items():
1630
+ ts.lines[ts_nr] = self.occ.addCircleArc(ts.points['beg'], ts.points['center'], ts.points[list(ts.points.keys())[-1]])
1631
+
1632
+ # Create mid wedge-turn lines
1633
+ mid_turn_ts = self.md.geometries.thin_shells.mid_wedge_turn
1634
+ for ts_nr, ts in mid_turn_ts.items():
1635
+ line_name = list(ts.points.keys())[0][:-2]
1636
+ ts.lines[line_name] = self.occ.addLine(ts.points[line_name + '_i'], ts.points[line_name + '_o'])
1637
+
1638
+ # Get insulation thickness
1639
+ for coil_nr, coil in self.md.geometries.coil.anticlockwise_order.coils.items():
1640
+ geom_coil = self.geom.coil.coils[coil_nr]
1641
+ # Get block-coil mid-pole thickness
1642
+ if coil_nr in self.block_coil_mid_pole_blks:
1643
+ for blk_orders in self.block_coil_mid_pole_blks[coil_nr]:
1644
+ block_y = geom_coil.poles[blk_orders[0].pole].layers[1].windings[blk_orders[0].winding].blocks[blk_orders[0].block].block_corners.iH.y
1645
+ block_next_y = geom_coil.poles[blk_orders[1].pole].layers[1].windings[blk_orders[1].winding].blocks[blk_orders[1].block].block_corners.iH.y
1646
+ ins_th.mid_layer[str(blk_orders[0].block) + '_' + str(blk_orders[1].block)] = Func.sig_dig(abs(block_y - block_next_y))
1647
+ # Get mid-layer thickness by intersecting the line passing through i-o of the ht of one side with the line passing through l-h of the ht of the opposite side
1648
+ for layer_nr, layer in coil.layers.items():
1649
+ for blk_order in layer:
1650
+ for ts_name, ts in mid_layer_ts.items():
1651
+ blk1, blk2 = ts_name.split('_')
1652
+ if blk1 == str(blk_order.block) and ts_name not in block_coil_mid_pole_list:
1653
+ block = geom_coil.poles[blk_order.pole].layers[layer_nr].windings[blk_order.winding].blocks[blk_order.block]
1654
+ if layer_nr < len(coil.layers):
1655
+ for blk_order_next in coil.layers[layer_nr + 1]:
1656
+ if blk_order_next.block == int(blk2):
1657
+ block_next = geom_coil.poles[blk_order_next.pole].layers[layer_nr + 1].windings[blk_order_next.winding].blocks[int(blk2)]
1658
+ break
1659
+ else:
1660
+ for blk_order_next in self.md.geometries.coil.anticlockwise_order.coils[coil_nr + 1].layers[1]:
1661
+ if blk_order_next.block == int(blk2):
1662
+ block_next = self.geom.coil.coils[coil_nr + 1].poles[blk_order_next.pole].layers[1].windings[blk_order_next.winding].blocks[int(blk2)]
1663
+ break
1664
+ distances = []
1665
+ lines = list(ts.mid_layers.lines.keys())
1666
+ for line_name in [lines[0], lines[-1]]:
1667
+ ht_1, ht_2 = int(line_name[:line_name.index('_')]), int(line_name[line_name.index('_') + 1:])
1668
+ ht_char = {'low_p': ht_1, 'high_p': ht_2,
1669
+ 'current': ht_1 if ht_1 in ts.half_turn_lists[blk1] else ht_2,
1670
+ 'next': ht_2 if ht_1 in ts.half_turn_lists[blk1] else ht_1}
1671
+ hts = {'current': block.half_turns[ht_char['current']].corners.bare,
1672
+ 'next': block_next.half_turns[ht_char['next']].corners.bare}
1673
+ hts_p = {'low_p': [hts['current'].oL, hts['current'].iL] if ht_char['low_p'] == ht_char['current'] else [hts['next'].iL, hts['next'].oL],
1674
+ 'high_p': [hts['current'].oH, hts['current'].iH] if ht_char['high_p'] == ht_char['current'] else [hts['next'].iH, hts['next'].oH],
1675
+ 'low_p_opp': [hts['next'].iL, hts['next'].iH] if ht_char['low_p'] == ht_char['current'] else [hts['current'].oL, hts['current'].oH],
1676
+ 'high_p_opp': [hts['next'].iL, hts['next'].iH] if ht_char['high_p'] == ht_char['current'] else [hts['current'].oL, hts['current'].oH]}
1677
+ low_line = Func.line_through_two_points([hts_p['low_p'][0].x, hts_p['low_p'][0].y],
1678
+ [hts_p['low_p'][1].x, hts_p['low_p'][1].y])
1679
+ high_line = Func.line_through_two_points([hts_p['high_p'][0].x, hts_p['high_p'][0].y],
1680
+ [hts_p['high_p'][1].x, hts_p['high_p'][1].y])
1681
+ distances.extend([Func.points_distance([hts_p['low_p'][0].x, hts_p['low_p'][0].y], Func.intersection_between_two_lines(
1682
+ low_line, Func.line_through_two_points([hts_p['low_p_opp'][0].x, hts_p['low_p_opp'][0].y], [hts_p['low_p_opp'][1].x, hts_p['low_p_opp'][1].y]))),
1683
+ Func.points_distance([hts_p['high_p'][0].x, hts_p['high_p'][0].y], Func.intersection_between_two_lines(
1684
+ high_line, Func.line_through_two_points([hts_p['high_p_opp'][0].x, hts_p['high_p_opp'][0].y], [hts_p['high_p_opp'][1].x, hts_p['high_p_opp'][1].y])))])
1685
+ ins_th.mid_layer[ts_name] = Func.sig_dig(min(distances))
1686
+ for ts_type, wdg_ts in enumerate([self.md.geometries.thin_shells.mid_layers_wdg_to_ht, self.md.geometries.thin_shells.mid_layers_ht_to_wdg]):
1687
+ for ts_name, ts in wdg_ts.items():
1688
+ wdg, blk = ts_name.split('_')
1689
+ if blk == str(blk_order.block):
1690
+ block = geom_coil.poles[blk_order.pole].layers[layer_nr].windings[blk_order.winding].blocks[blk_order.block]
1691
+ wedge = self.md.geometries.wedges.coils[coil_nr].layers[layer_nr + (1 if ts_type == 1 else -1)].wedges[int(wdg[1:])]
1692
+ pnt_il = gmsh.model.getValue(0, wedge.points['il'], [])[:2]
1693
+ pnt_ol = gmsh.model.getValue(0, wedge.points['ol'], [])[:2]
1694
+ pnt_ih = gmsh.model.getValue(0, wedge.points['ih'], [])[:2]
1695
+ pnt_oh = gmsh.model.getValue(0, wedge.points['oh'], [])[:2]
1696
+ low_line = Func.line_through_two_points(pnt_il, pnt_ol)
1697
+ high_line = Func.line_through_two_points(pnt_ih, pnt_oh)
1698
+ el1_l, el2_l = list(ts.lines.keys())[0].split('_')
1699
+ ht_l = block.half_turns[int(el1_l) if el2_l == wdg else int(el2_l)].corners.bare
1700
+ el1_h, el2_h = list(ts.lines.keys())[-1].split('_')
1701
+ ht_h = block.half_turns[int(el1_h) if el2_h == wdg else int(el2_h)].corners.bare
1702
+ opp_line_l = Func.line_through_two_points([ht_l.iL.x, ht_l.iL.y], [ht_l.iH.x, ht_l.iH.y]) if ts_type == 0\
1703
+ else Func.line_through_two_points([ht_l.oL.x, ht_l.oL.y], [ht_l.oH.x, ht_l.oH.y])
1704
+ opp_line_h = Func.line_through_two_points([ht_h.iL.x, ht_h.iL.y], [ht_h.iH.x, ht_h.iH.y]) if ts_type == 0 \
1705
+ else Func.line_through_two_points([ht_h.oL.x, ht_h.oL.y], [ht_h.oH.x, ht_h.oH.y])
1706
+ ins_th.mid_layer[ts_name] = Func.sig_dig(
1707
+ (Func.points_distance(pnt_ol if ts_type == 0 else pnt_il, Func.intersection_between_two_lines(low_line, opp_line_l)) +
1708
+ Func.points_distance(pnt_oh if ts_type == 0 else pnt_ih, Func.intersection_between_two_lines(high_line, opp_line_h))) / 2)
1709
+
1710
+ for coil_nr, coil in self.md.geometries.wedges.coils.items():
1711
+ # Get mid-layer thickness by intersecting the line passing through i-o of the wdg of one side with the line passing through l-h of the wdg of the opposite side
1712
+ for layer_nr, layer in coil.layers.items():
1713
+ for wedge_nr, wedge in layer.wedges.items():
1714
+ for ts_name, ts in self.md.geometries.thin_shells.mid_layers_wdg_to_wdg.items():
1715
+ wdg1, wdg2 = ts_name[1:ts_name.index('_')], ts_name[ts_name.index('_') + 2:]
1716
+ if wdg1 == str(wedge_nr):
1717
+ wedge_next = self.md.geometries.wedges.coils[coil_nr].layers[layer_nr + 1].wedges[int(wdg2)]
1718
+ # pnt_il_next = gmsh.model.getValue(0, wedge_next.points['il'], [])[:2]
1719
+ # pnt_ih_next = gmsh.model.getValue(0, wedge_next.points['ih'], [])[:2]
1720
+ pnt_il = gmsh.model.getValue(0, wedge.points['il'], [])[:2]
1721
+ pnt_ol = gmsh.model.getValue(0, wedge.points['ol'], [])[:2]
1722
+ pnt_ih = gmsh.model.getValue(0, wedge.points['ih'], [])[:2]
1723
+ pnt_oh = gmsh.model.getValue(0, wedge.points['oh'], [])[:2]
1724
+ low_line = Func.line_through_two_points(pnt_il, pnt_ol)
1725
+ high_line = Func.line_through_two_points(pnt_ih, pnt_oh)
1726
+ opp_line = Func.line_through_two_points(gmsh.model.getValue(0, wedge_next.points['il'], [])[:2],
1727
+ gmsh.model.getValue(0, wedge_next.points['ih'], [])[:2])
1728
+ ins_th.mid_layer[ts_name] = Func.sig_dig(
1729
+ (Func.points_distance(pnt_ol, Func.intersection_between_two_lines(low_line, opp_line)) +
1730
+ Func.points_distance(pnt_oh, Func.intersection_between_two_lines(high_line, opp_line))) / 2)
1731
+
1732
+ def buildDomains(self, run_type, symmetry):
1733
+ """
1734
+ Generates plane surfaces from the curve loops
1735
+ """
1736
+ iron = self.geom.iron
1737
+ gm = self.md.geometries
1738
+ with_iron_yoke = self.data.magnet.geometry.electromagnetics.with_iron_yoke if run_type == 'EM'\
1739
+ else self.data.magnet.geometry.thermal.with_iron_yoke
1740
+ with_wedges = self.data.magnet.geometry.electromagnetics.with_wedges if run_type == 'EM' \
1741
+ else self.data.magnet.geometry.thermal.with_wedges
329
1742
 
330
1743
  # Build iron yoke domains
331
- if self.data.magnet.geometry.with_iron_yoke:
1744
+ if with_iron_yoke:
332
1745
  for quadrant, qq in gm.iron.quadrants.items():
333
1746
  for area_name, area in qq.areas.items():
334
1747
  build = True
@@ -340,48 +1753,235 @@ class Geometry:
340
1753
  build = False
341
1754
  if build:
342
1755
  area.surface = self.occ.addPlaneSurface(loops)
343
- self.md.domains.groups_surfaces[iron.hyper_areas[area_name].material].append(area.surface)
1756
+ # Group areas per material type
1757
+ self.md.domains.groups_entities.iron[iron.hyper_areas[area_name].material].append(area.surface)
344
1758
 
345
1759
  # Build coil domains
346
1760
  for coil_nr, coil in gm.coil.coils.items():
347
1761
  for pole_nr, pole in coil.poles.items():
348
1762
  for layer_nr, layer in pole.layers.items():
349
1763
  for winding_nr, winding in layer.windings.items():
350
- # cable = self.set.Model_Data_GS.conductors[winding.conductor_name].cable
351
- # ht_area = cable.bare_cable_height_mean * cable.bare_cable_width
352
1764
  for block_key, block in winding.blocks.items():
353
- current_sign = '_neg' if block.current_sign < 0 else '_pos'
354
1765
  for area_name, area in block.half_turns.areas.items():
355
- ht_name = 'block' + str(block_key) + '_ht' + str(area_name) + current_sign
356
- # self.conductor_areas[ht_name] = ht_area
357
1766
  area.surface = self.occ.addPlaneSurface([area.loop])
358
- self.md.domains.groups_surfaces[ht_name] = [area.surface]
359
1767
 
360
1768
  # Build wedges domains
361
- for wedge_nr, wedge in gm.wedges.areas.items():
362
- wedge.surface = self.occ.addPlaneSurface([wedge.loop])
363
- self.md.domains.groups_surfaces['wedge_' + str(wedge_nr)] = [wedge.surface]
1769
+ if with_wedges:
1770
+ for coil_nr, coil in gm.wedges.coils.items():
1771
+ for layer_nr, layer in coil.layers.items():
1772
+ for wedge_nr, wedge in layer.wedges.items():
1773
+ wedge.areas[str(wedge_nr)].surface = self.occ.addPlaneSurface([wedge.areas[str(wedge_nr)].loop])
1774
+
1775
+ # Build insulation domains
1776
+ if run_type == 'TH' and not self.data.magnet.geometry.thermal.use_TSA:
1777
+ for coil_nr, coil in gm.insulation.coils.items():
1778
+ for group_nr, group in coil.group.items():
1779
+ holes = []
1780
+ for blk in group.blocks:
1781
+ holes.extend([ht.loop for ht_nr, ht in gm.coil.coils[
1782
+ coil_nr].poles[blk[0]].layers[blk[1]].windings[blk[2]].blocks[blk[3]].half_turns.areas.items()])
1783
+ for wdg in group.wedges:
1784
+ holes.extend([wedge.loop for wedge_nr, wedge in gm.wedges.coils[
1785
+ coil_nr].layers[wdg[0]].wedges[wdg[1]].areas.items()])
1786
+ if len(group.ins.areas) == 1:
1787
+ for area_name, area in group.ins.areas.items():
1788
+ area.surface = self.occ.addPlaneSurface([area.loop] + holes)
1789
+ else:
1790
+ for area_name, area in group.ins.areas.items():
1791
+ if area_name.isdigit():
1792
+ area.surface = self.occ.addPlaneSurface([area.loop] + holes + [group.ins.areas['inner_loop'].loop])
1793
+
1794
+ # Create and build air far field
1795
+ if run_type == 'EM':
1796
+ if self.data.magnet.geometry.electromagnetics.with_iron_yoke:
1797
+ for i in iron.key_points:
1798
+ gm.iron.max_radius = max(gm.iron.max_radius, max(iron.key_points[i].x, iron.key_points[i].y))
1799
+ greatest_radius = gm.iron.max_radius
1800
+ else: # no iron yoke data available
1801
+ for coil_nr, coil in self.geom.coil.coils.items():
1802
+ for pole_nr, pole in coil.poles.items():
1803
+ first_winding = list(pole.layers[len(pole.layers)].windings.keys())[0]
1804
+ first_block = list(pole.layers[len(pole.layers)].windings[first_winding].blocks)[0]
1805
+ gm.coil.max_radius = max(abs(pole.layers[len(pole.layers)].windings[first_winding].blocks[first_block].block_corners.oL.x),
1806
+ abs(pole.layers[len(pole.layers)].windings[first_winding].blocks[first_block].block_corners.oL.y),
1807
+ gm.coil.max_radius)
1808
+ greatest_radius = gm.coil.max_radius
1809
+ radius_in = greatest_radius * (2.5 if self.data.magnet.geometry.electromagnetics.with_iron_yoke else 6)
1810
+ radius_out = greatest_radius * (3.2 if self.data.magnet.geometry.electromagnetics.with_iron_yoke else 8)
1811
+ air_inf_center_x, air_inf_center_y = 0, 0
1812
+ for coil_nr, coil in self.md.geometries.coil.coils.items():
1813
+ air_inf_center_x += coil.bore_center.x
1814
+ air_inf_center_y += coil.bore_center.y
1815
+ gm.air.points['bore_center' + str(coil_nr)] = self.occ.addPoint(coil.bore_center.x, coil.bore_center.y, 0.)
1816
+ air_inf_center = [air_inf_center_x / len(self.md.geometries.coil.coils), air_inf_center_y / len(self.md.geometries.coil.coils)]
1817
+ if symmetry == 'none':
1818
+ gm.air_inf.lines['inner'] = self.occ.addCircle(air_inf_center[0], air_inf_center[1], 0., radius_in)
1819
+ gm.air_inf.lines['outer'] = self.occ.addCircle(air_inf_center[0], air_inf_center[1], 0., radius_out)
1820
+ gm.air_inf.areas['inner'] = dM.Area(loop=self.occ.addCurveLoop([gm.air_inf.lines['inner']]))
1821
+ gm.air_inf.areas['outer'] = dM.Area(loop=self.occ.addCurveLoop([gm.air_inf.lines['outer']]))
1822
+ gm.air_inf.areas['outer'].surface = self.occ.addPlaneSurface([gm.air_inf.areas['outer'].loop, gm.air_inf.areas['inner'].loop])
1823
+ else:
1824
+ pnt1 = [1, 0] if symmetry in ['xy', 'x'] else [0, -1]
1825
+ pnt2 = [0, 1] if symmetry in ['xy', 'y'] else [-1, 0]
1826
+ gm.air.points['pnt1'] = self.occ.addPoint(pnt1[0] * radius_in, pnt1[1] * radius_in, 0)
1827
+ gm.air.points['pnt2'] = self.occ.addPoint(pnt2[0] * radius_in, pnt2[1] * radius_in, 0)
1828
+ gm.air_inf.points['pnt1'] = self.occ.addPoint(pnt1[0] * radius_out, pnt1[1] * radius_out, 0)
1829
+ gm.air_inf.points['pnt2'] = self.occ.addPoint(pnt2[0] * radius_out, pnt2[1] * radius_out, 0)
1830
+ gm.air.lines['ln1'] = self.occ.addLine(gm.air.points['pnt1'], gm.air_inf.points['pnt1'])
1831
+ gm.air.lines['ln2'] = self.occ.addLine(gm.air.points['pnt2'], gm.air_inf.points['pnt2'])
1832
+ if not self.data.magnet.geometry.electromagnetics.with_iron_yoke:
1833
+ gm.air_inf.points['center'] = self.occ.addPoint(0, 0, 0)
1834
+ gm.air_inf.lines['inner'] = self.occ.addCircleArc(gm.air.points['pnt2'], gm.air_inf.points['center'], gm.air.points['pnt1'])
1835
+ gm.air_inf.lines['outer'] = self.occ.addCircleArc(gm.air_inf.points['pnt2'], gm.air_inf.points['center'], gm.air_inf.points['pnt1'])
1836
+
1837
+ if symmetry in ['xy', 'x']:
1838
+ gm.air.lines['x_p'] = self.occ.addLine(self.md.geometries.air_inf.points['center'] if 'solenoid' in self.geom.coil.coils[1].type else
1839
+ gm.iron.quadrants[1].points[self.symmetric_bnds['x_p']['pnts'][-1][0]], gm.air.points['pnt1'])
1840
+ self.symmetric_loop_lines['x'].append(gm.air.lines['x_p'])
1841
+ else: # y
1842
+ gm.air.lines['y_n'] = self.occ.addLine(gm.iron.quadrants[4].points[self.symmetric_bnds['y_n']['pnts'][-1][0]], gm.air.points['pnt1'])
1843
+ self.symmetric_loop_lines['y'].append(gm.air.lines['y_n'])
1844
+ if symmetry in ['xy', 'y']:
1845
+ gm.air.lines['y_p'] = self.occ.addLine(gm.iron.quadrants[1].points[self.symmetric_bnds['y_p']['pnts'][-1][0]], gm.air.points['pnt2'])
1846
+ self.symmetric_loop_lines['y'].insert(0, gm.air.lines['y_p'])
1847
+ else: # x
1848
+ gm.air.lines['x_n'] = self.occ.addLine(self.md.geometries.air_inf.points['center'] if 'solenoid' in self.geom.coil.coils[1].type else
1849
+ gm.iron.quadrants[2].points[self.symmetric_bnds['x_n']['pnts'][-1][0]], gm.air.points['pnt2'])
1850
+ self.symmetric_loop_lines['x'].insert(0, gm.air.lines['x_n'])
364
1851
 
365
- def updateTags(self):
366
- self.md.geometries.coil.electrical_order = self.geom.Roxie_Data.coil.electrical_order
367
- for coil_nr, coil in self.geom.Roxie_Data.coil.coils.items():
368
- self.md.geometries.coil.coils[coil_nr].bore_center = coil.bore_center
1852
+ inner_lines = self.symmetric_loop_lines['x'] + [gm.air_inf.lines['inner']] + self.symmetric_loop_lines['y']\
1853
+ if symmetry == 'xy' else self.symmetric_loop_lines[symmetry] + [gm.air_inf.lines['inner']]
1854
+ gm.air_inf.areas['inner'] = dM.Area(loop=self.occ.addCurveLoop(inner_lines))
1855
+ gm.air_inf.areas['outer'] = dM.Area(loop=self.occ.addCurveLoop(
1856
+ [gm.air.lines['ln1'], gm.air_inf.lines['outer'], gm.air.lines['ln2'], gm.air_inf.lines['inner']]))
1857
+ gm.air_inf.areas['outer'].surface = self.occ.addPlaneSurface([gm.air_inf.areas['outer'].loop])
1858
+ # self.md.domains.groups_entities.air_inf = [gm.air_inf.areas['outer'].surface]
1859
+ gm.air_inf.areas['inner'].surface = self.occ.addPlaneSurface([gm.air_inf.areas['inner'].loop])
1860
+
1861
+ # self.occ.synchronize()
1862
+ # self.gu.launch_interactive_GUI()
1863
+
1864
+ def fragment(self):
1865
+ """
1866
+ Fragment and group air domains
1867
+ """
1868
+ # Collect surfaces to be subtracted by background air
1869
+ holes = []
369
1870
 
1871
+ # Iron
1872
+ for group_name, surfaces in self.md.domains.groups_entities.iron.items():
1873
+ holes.extend([(2, s) for s in surfaces])
1874
+ # Coils
1875
+ for coil_nr, coil in self.md.geometries.coil.coils.items():
1876
+ for pole_nr, pole in coil.poles.items():
1877
+ for layer_nr, layer in pole.layers.items():
1878
+ for winding_nr, winding in layer.windings.items():
1879
+ for block_key, block in winding.blocks.items():
1880
+ for area_name, area in block.half_turns.areas.items():
1881
+ holes.append((2, area.surface))
1882
+ # Wedges
1883
+ for coil_nr, coil in self.md.geometries.wedges.coils.items():
1884
+ for layer_nr, layer in coil.layers.items():
1885
+ for wedge_nr, wedge in layer.wedges.items():
1886
+ for area_name, area in wedge.areas.items():
1887
+ holes.append((2, area.surface))
1888
+ # Insulation
1889
+ # if run_type == 'TH' and not self.data.magnet.geometry.thermal.use_TSA:
1890
+ # for coil_nr, coil in self.md.geometries.insulation.coils.items():
1891
+ # for group_nr, group in coil.group.items():
1892
+ # for area_name, area in group.ins.areas.items():
1893
+ # holes.append((2, area.surface))
1894
+
1895
+ # Fragment
1896
+ fragmented = self.occ.fragment([(2, self.md.geometries.air_inf.areas['inner'].surface)], holes)[1]
1897
+ self.occ.synchronize()
1898
+
1899
+ self.md.domains.groups_entities.air = []
1900
+ existing_domains = [e[0][1] for e in fragmented[1:]]
1901
+ for e in fragmented[0]:
1902
+ if e[1] not in existing_domains:
1903
+ self.md.domains.groups_entities.air.append(e[1])
1904
+
1905
+ def updateTags(self, run_type, symmetry):
1906
+
1907
+ # Update half turn line tags
370
1908
  for coil_nr, coil in self.md.geometries.coil.coils.items():
371
1909
  for pole_nr, pole in coil.poles.items():
372
1910
  for layer_nr, layer in pole.layers.items():
373
1911
  for winding_nr, winding in layer.windings.items():
374
1912
  for block_key, block in winding.blocks.items():
375
1913
  hts = block.half_turns
376
- for ht_nr, ht in hts.areas.items():
377
- lines_tags = gmsh.model.getAdjacencies(2, ht.surface)[1]
378
- first_tag = int(min(lines_tags))
379
- hts.lines[ht_nr + ('i' if ht_nr == '1' else 'r')] = first_tag
380
- hts.lines[ht_nr + ('r' if ht_nr == '1' else 'i')] = first_tag + 1
1914
+ # Get half turn ID numbers
1915
+ area_list = list(hts.areas.keys())
1916
+ for nr, ht_nr in enumerate(area_list):
1917
+ first_tag = int(min(gmsh.model.getAdjacencies(2, hts.areas[ht_nr].surface)[1]))
1918
+ hts.lines[ht_nr + 'i'] = first_tag
1919
+ hts.lines[ht_nr + 'l'] = first_tag + 1
381
1920
  hts.lines[ht_nr + 'o'] = first_tag + 2
382
- if int(ht_nr) == len(hts.areas):
383
- hts.lines['end'] = first_tag + 3
1921
+ hts.lines[ht_nr + 'h'] = first_tag + 3
1922
+
1923
+ # Update insulation line tags
1924
+ if run_type == 'TH' and not self.data.magnet.geometry.thermal.use_TSA:
1925
+ pass # todo
1926
+
1927
+ # Update wedge line tags
1928
+ for coil_nr, coil in self.md.geometries.wedges.coils.items():
1929
+ for layer_nr, layer in coil.layers.items():
1930
+ for wedge_nr, wedge in layer.wedges.items():
1931
+ lines_tags = list(gmsh.model.getAdjacencies(2, wedge.areas[str(wedge_nr)].surface)[1])
1932
+ lines_tags.sort(key=lambda x: x)
1933
+ wedge.lines['i'] = int(lines_tags[0])
1934
+ wedge.lines['l'] = int(lines_tags[1])
1935
+ wedge.lines['o'] = int(lines_tags[2])
1936
+ wedge.lines['h'] = int(lines_tags[3])
1937
+
1938
+ if run_type == 'EM':
1939
+ def _get_bnd_lines():
1940
+ return [pair[1] for pair in self.occ.getEntitiesInBoundingBox(corner_min[0], corner_min[1], corner_min[2],
1941
+ corner_max[0], corner_max[1], corner_max[2], dim=1)]
1942
+
1943
+ tol = 1e-6
1944
+ # Update tags of air and air_inf arcs and their points
1945
+ lines_tags = gmsh.model.getAdjacencies(2, self.md.geometries.air_inf.areas['outer'].surface)[1]
1946
+ self.md.geometries.air_inf.lines['outer'] = int(lines_tags[0 if symmetry == 'none' else 1])
1947
+ self.md.geometries.air_inf.lines['inner'] = int(lines_tags[1 if symmetry == 'none' else 3])
1948
+ if symmetry == 'none': # todo: check if this holds for symmetric models too
1949
+ for coil_nr, coil in self.md.geometries.coil.coils.items():
1950
+ self.md.geometries.air.points['bore_center' + str(coil_nr)] += 2
1951
+ else:
1952
+ pnt_tags = list(gmsh.model.getAdjacencies(1, self.md.geometries.air_inf.lines['outer'])[1])
1953
+ indexes = [0, 1, 0] if 'x' in symmetry else [1, 0, 1]
1954
+ pnts = [0, 1] if gmsh.model.getValue(0, pnt_tags[indexes[0]], [])[indexes[2]] >\
1955
+ gmsh.model.getValue(0, pnt_tags[indexes[1]], [])[indexes[2]] else [1, 0]
1956
+ self.md.geometries.air_inf.points['pnt1'] = int(pnt_tags[pnts[0]])
1957
+ self.md.geometries.air_inf.points['pnt2'] = int(pnt_tags[pnts[1]])
1958
+ pnt_tags = list(gmsh.model.getAdjacencies(1, self.md.geometries.air_inf.lines['inner'])[1])
1959
+ pnts = [0, 1] if gmsh.model.getValue(0, pnt_tags[indexes[0]], [])[indexes[2]] > \
1960
+ gmsh.model.getValue(0, pnt_tags[indexes[1]], [])[indexes[2]] else [1, 0]
1961
+ self.md.geometries.air.points['pnt1'] = int(pnt_tags[pnts[0]])
1962
+ self.md.geometries.air.points['pnt2'] = int(pnt_tags[pnts[1]])
1963
+ for coil_nr, coil in self.md.geometries.coil.coils.items():
1964
+ self.md.geometries.air.points['bore_center' + str(coil_nr)] =(
1965
+ self.occ.getEntitiesInBoundingBox(-tol + coil.bore_center.x, -tol + coil.bore_center.y, -tol,
1966
+ tol + coil.bore_center.x, tol + coil.bore_center.y, tol, dim=0))[0][1]
1967
+
1968
+ # Group symmetry boundary lines per type
1969
+ if symmetry == 'xy':
1970
+ corner_min = [-tol, -tol, -tol]
1971
+ corner_max = [gmsh.model.getValue(0, self.md.geometries.air_inf.points['pnt1'], [])[0] + tol, tol, tol]
1972
+ self.md.domains.groups_entities.symmetric_boundaries.x = _get_bnd_lines()
1973
+ corner_max = [tol, gmsh.model.getValue(0, self.md.geometries.air_inf.points['pnt2'], [])[1] + tol, tol]
1974
+ self.md.domains.groups_entities.symmetric_boundaries.y = _get_bnd_lines()
1975
+ elif symmetry == 'x':
1976
+ x_coord = gmsh.model.getValue(0, self.md.geometries.air_inf.points['pnt1'], [])[0]
1977
+ corner_min = [- x_coord - tol, -tol, -tol]
1978
+ corner_max = [x_coord + tol, tol, tol]
1979
+ self.md.domains.groups_entities.symmetric_boundaries.x = _get_bnd_lines()
1980
+ elif symmetry == 'y':
1981
+ y_coord = gmsh.model.getValue(0, self.md.geometries.air_inf.points['pnt2'], [])[1]
1982
+ corner_min = [-tol, - y_coord - tol, -tol]
1983
+ corner_max = [tol, y_coord + tol, tol]
1984
+ self.md.domains.groups_entities.symmetric_boundaries.y = _get_bnd_lines()
384
1985
 
385
- lines_tags = gmsh.model.getAdjacencies(2, self.md.geometries.air_inf.areas['outer'].surface)[1]
386
- self.md.geometries.air_inf.lines['outer'] = int(lines_tags[0])
387
- self.md.geometries.air_inf.lines['inner'] = int(lines_tags[1])
1986
+ # self.occ.synchronize()
1987
+ # self.gu.launch_interactive_GUI()