fiqus 2026.1.0__py3-none-any.whl → 2026.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fiqus/MainFiQuS.py +1 -8
- fiqus/data/DataConductor.py +4 -8
- fiqus/data/DataFiQuSMultipole.py +358 -167
- fiqus/data/DataModelCommon.py +30 -15
- fiqus/data/DataMultipole.py +33 -10
- fiqus/data/DataWindingsCCT.py +37 -37
- fiqus/data/RegionsModelFiQuS.py +1 -1
- fiqus/geom_generators/GeometryMultipole.py +751 -54
- fiqus/getdp_runners/RunGetdpMultipole.py +181 -31
- fiqus/mains/MainMultipole.py +109 -17
- fiqus/mesh_generators/MeshCCT.py +209 -209
- fiqus/mesh_generators/MeshMultipole.py +938 -263
- fiqus/parsers/ParserCOND.py +2 -1
- fiqus/parsers/ParserDAT.py +16 -16
- fiqus/parsers/ParserGetDPOnSection.py +212 -212
- fiqus/parsers/ParserGetDPTimeTable.py +134 -134
- fiqus/parsers/ParserMSH.py +53 -53
- fiqus/parsers/ParserRES.py +142 -142
- fiqus/plotters/PlotPythonCCT.py +133 -133
- fiqus/plotters/PlotPythonMultipole.py +18 -18
- fiqus/post_processors/PostProcessMultipole.py +16 -6
- fiqus/pre_processors/PreProcessCCT.py +175 -175
- fiqus/pro_assemblers/ProAssembler.py +3 -3
- fiqus/pro_material_functions/ironBHcurves.pro +246 -246
- fiqus/pro_templates/combined/CC_Module.pro +1213 -0
- fiqus/pro_templates/combined/ConductorAC_template.pro +1025 -0
- fiqus/pro_templates/combined/Multipole_template.pro +2738 -1338
- fiqus/pro_templates/combined/TSA_materials.pro +102 -2
- fiqus/pro_templates/combined/materials.pro +54 -3
- fiqus/utils/Utils.py +18 -25
- fiqus/utils/update_data_settings.py +1 -1
- {fiqus-2026.1.0.dist-info → fiqus-2026.1.2.dist-info}/METADATA +64 -68
- {fiqus-2026.1.0.dist-info → fiqus-2026.1.2.dist-info}/RECORD +42 -40
- {fiqus-2026.1.0.dist-info → fiqus-2026.1.2.dist-info}/WHEEL +1 -1
- tests/test_geometry_generators.py +29 -32
- tests/test_mesh_generators.py +35 -34
- tests/test_solvers.py +32 -31
- tests/utils/fiqus_test_classes.py +396 -147
- tests/utils/generate_reference_files_ConductorAC.py +57 -57
- tests/utils/helpers.py +76 -1
- {fiqus-2026.1.0.dist-info → fiqus-2026.1.2.dist-info}/LICENSE.txt +0 -0
- {fiqus-2026.1.0.dist-info → fiqus-2026.1.2.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import re
|
|
3
|
+
|
|
2
4
|
import gmsh
|
|
3
5
|
import copy
|
|
4
6
|
import numpy as np
|
|
@@ -12,7 +14,7 @@ from fiqus.data import DataFiQuS as dF
|
|
|
12
14
|
from fiqus.data import DataMultipole as dM
|
|
13
15
|
from fiqus.data import RegionsModelFiQuS as rM
|
|
14
16
|
|
|
15
|
-
logger = logging.getLogger(
|
|
17
|
+
logger = logging.getLogger('FiQuS')
|
|
16
18
|
|
|
17
19
|
class Mesh:
|
|
18
20
|
def __init__(self, data: dF.FDM() = None, mesh_folder: str = None,
|
|
@@ -36,7 +38,11 @@ class Mesh:
|
|
|
36
38
|
self.occ = gmsh.model.occ
|
|
37
39
|
self.mesh = gmsh.model.mesh
|
|
38
40
|
|
|
39
|
-
self.
|
|
41
|
+
self.brep_curves = {}
|
|
42
|
+
for name in list(
|
|
43
|
+
set(self.data.magnet.geometry.electromagnetics.areas + self.data.magnet.geometry.thermal.areas)):
|
|
44
|
+
self.brep_curves[name] = {1: set(), 2: set(), 3: set(), 4: set()}
|
|
45
|
+
|
|
40
46
|
self.mesh_parameters = dict.fromkeys(['SJ', 'SICN', 'SIGE', 'Gamma', 'nodes'])
|
|
41
47
|
self.geom_files = os.path.join(os.path.dirname(self.mesh_folder), self.data.general.magnet_name)
|
|
42
48
|
self.model_file = os.path.join(self.mesh_folder, self.data.general.magnet_name)
|
|
@@ -45,9 +51,11 @@ class Mesh:
|
|
|
45
51
|
self.ins_type_cond = {}
|
|
46
52
|
# Insulation sequence involving quench heaters (outlying or mid-layer/pole)
|
|
47
53
|
qh_keys = {key: {} for key in range(1, self.data.quench_protection.quench_heaters.N_strips + 1)}
|
|
48
|
-
self.ins_type_qh = {'internal_double': {}, 'internal': copy.deepcopy(qh_keys),
|
|
54
|
+
self.ins_type_qh = {'internal_double': {}, 'internal': copy.deepcopy(qh_keys),
|
|
55
|
+
'external': copy.deepcopy(qh_keys)}
|
|
49
56
|
# Insulation sequence between blocks (layer-to-layer, pole-to-pole)
|
|
50
|
-
self.ins_type = {'mid_pole': {}, 'mid_winding': {}, 'mid_layer': {}, 'aux': {}}
|
|
57
|
+
self.ins_type = {'mid_pole': {}, 'mid_winding': {}, 'mid_layer': {}, 'aux': {}, 'collar': {}, 'poles': {}}
|
|
58
|
+
|
|
51
59
|
self.qh_data, self.wedge_cond = {}, {}
|
|
52
60
|
|
|
53
61
|
self.colors = {'wedges': [86, 180, 233], # sky blue
|
|
@@ -63,7 +71,8 @@ class Mesh:
|
|
|
63
71
|
# key
|
|
64
72
|
'BHiron3': [220, 208, 46], # dark yellow
|
|
65
73
|
# [230, 159, 0], # orange
|
|
66
|
-
#
|
|
74
|
+
'BH_air': [255, 128, 0], # also orange
|
|
75
|
+
'Air': [255, 128, 0], # also orange
|
|
67
76
|
'BHiron5': [204, 121, 167], # hopbush
|
|
68
77
|
'BHiron6': [0, 114, 178], # blue
|
|
69
78
|
'BHiron7': [204, 121, 167]} # reddish purple
|
|
@@ -72,23 +81,30 @@ class Mesh:
|
|
|
72
81
|
self.md = dM.MultipoleData()
|
|
73
82
|
self.rc = dM.MultipoleRegionCoordinate()
|
|
74
83
|
self.rm = rM.RegionsModel()
|
|
84
|
+
for name in self.brep_curves.keys():
|
|
85
|
+
self.brep_curves[name] = {1: set(), 2: set(), 3: set(), 4: set()}
|
|
75
86
|
gmsh.clear()
|
|
76
87
|
|
|
77
88
|
def ending_step(self, gui: bool = False):
|
|
78
89
|
if gui:
|
|
79
90
|
self.gu.launch_interactive_GUI()
|
|
80
91
|
else:
|
|
81
|
-
gmsh.
|
|
82
|
-
|
|
92
|
+
if gmsh.isInitialized():
|
|
93
|
+
gmsh.clear()
|
|
94
|
+
gmsh.finalize()
|
|
83
95
|
|
|
84
96
|
def loadStrandPositions(self, run_type):
|
|
85
|
-
|
|
97
|
+
with open(f"{self.geom_files}_{run_type}.strs", 'r') as f:
|
|
98
|
+
self.strands = json.load(f)
|
|
86
99
|
|
|
87
100
|
def loadAuxiliaryFile(self, run_type):
|
|
88
101
|
self.md = Util.read_data_from_yaml(f"{self.geom_files}_{run_type}.aux", dM.MultipoleData)
|
|
89
102
|
|
|
90
103
|
def updateAuxiliaryFile(self, run_type):
|
|
91
104
|
Util.write_data_to_yaml(f'{self.model_file}_{run_type}.aux', self.md.model_dump())
|
|
105
|
+
# md2 = Util.read_data_from_yaml(f"{self.geom_files}.aux", dM.MultipoleData)
|
|
106
|
+
# md2.domains.physical_groups = self.md.domains.physical_groups
|
|
107
|
+
# Util.write_data_to_yaml(f"{self.geom_files}.aux", md2.dict())
|
|
92
108
|
|
|
93
109
|
def saveMeshFile(self, run_type):
|
|
94
110
|
gmsh.write(f'{self.model_file}_{run_type}.msh')
|
|
@@ -99,11 +115,12 @@ class Mesh:
|
|
|
99
115
|
def saveRegionCoordinateFile(self, run_type):
|
|
100
116
|
Util.write_data_to_yaml(f'{self.model_file}_{run_type}.reco', self.rc.model_dump())
|
|
101
117
|
|
|
102
|
-
def getIronCurvesTags(self):
|
|
103
|
-
for
|
|
104
|
-
for
|
|
105
|
-
|
|
106
|
-
|
|
118
|
+
def getIronCurvesTags(self, physics_solved):
|
|
119
|
+
for t in self.data.magnet.geometry.electromagnetics.areas if physics_solved == 'EM' else self.data.magnet.geometry.thermal.areas:
|
|
120
|
+
for quadrant, qq in getattr(self.md.geometries, t).quadrants.items():
|
|
121
|
+
for ar_name, area in qq.areas.items():
|
|
122
|
+
if area.surface and not re.match(r"^ar.h", ar_name):
|
|
123
|
+
self.brep_curves[t][quadrant] |= set(gmsh.model.getAdjacencies(2, area.surface)[1])
|
|
107
124
|
|
|
108
125
|
def defineMesh(self, geometry, mesh, run_type):
|
|
109
126
|
thresholds = []
|
|
@@ -112,10 +129,14 @@ class Mesh:
|
|
|
112
129
|
if mesh.conductors.field.enabled:
|
|
113
130
|
distance_conductors = self.mesh.field.add("Distance")
|
|
114
131
|
self.mesh.field.setNumbers(distance_conductors, "CurvesList",
|
|
115
|
-
[line for coil_nr, coil in
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
)
|
|
132
|
+
[line for coil_nr, coil in
|
|
133
|
+
self.md.geometries.coil.anticlockwise_order.coils.items() for layer_nr, layer in
|
|
134
|
+
coil.layers.items()
|
|
135
|
+
for _, block_order in enumerate(layer) for _, line in
|
|
136
|
+
self.md.geometries.coil.coils[coil_nr].poles[block_order.pole].layers[
|
|
137
|
+
layer_nr].windings[block_order.winding].blocks[
|
|
138
|
+
block_order.block].half_turns.lines.items()]
|
|
139
|
+
)
|
|
119
140
|
self.mesh.field.setNumber(distance_conductors, "Sampling", 100)
|
|
120
141
|
|
|
121
142
|
threshold_conductors = self.mesh.field.add("Threshold")
|
|
@@ -130,8 +151,10 @@ class Mesh:
|
|
|
130
151
|
if mesh.wedges.field.enabled:
|
|
131
152
|
distance_wedges = self.mesh.field.add("Distance")
|
|
132
153
|
self.mesh.field.setNumbers(distance_wedges, "CurvesList",
|
|
133
|
-
[line for _, coil in self.md.geometries.wedges.coils.items() for _, layer in
|
|
134
|
-
|
|
154
|
+
[line for _, coil in self.md.geometries.wedges.coils.items() for _, layer in
|
|
155
|
+
coil.layers.items() for _, wdg in layer.wedges.items() for _, line in
|
|
156
|
+
wdg.lines.items()]
|
|
157
|
+
)
|
|
135
158
|
self.mesh.field.setNumber(distance_wedges, "Sampling", 100)
|
|
136
159
|
|
|
137
160
|
# raise Exception(f"cannot set threshold for wedges field: {[line for _, coil in self.md.geometries.wedges.coils.items() for _, layer in coil.layers.items() for _, wdg in layer.wedges.items() for _, line in wdg.lines.items()]}")
|
|
@@ -145,28 +168,37 @@ class Mesh:
|
|
|
145
168
|
self.mesh.field.setNumber(threshold_wedges, "StopAtDistMax", 1)
|
|
146
169
|
thresholds.append(threshold_wedges)
|
|
147
170
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
self.mesh.field.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
171
|
+
for area in geometry.areas:
|
|
172
|
+
distance = self.mesh.field.add("Distance")
|
|
173
|
+
if not (area == 'collar' and self.data.magnet.mesh.thermal.collar.Enforce_TSA_mapping and run_type == 'TH'):
|
|
174
|
+
self.mesh.field.setNumbers(distance, "CurvesList",
|
|
175
|
+
[line for _, qq in self.brep_curves[area].items() for line in qq])
|
|
176
|
+
else:
|
|
177
|
+
# make sure this does not interfere with the enforced TSA mapping. Apply threshold to the inner collar points and the cooling holes
|
|
178
|
+
vals = [x for sublist in self.md.geometries.collar.inner_boundary_tags.values() for x in
|
|
179
|
+
sublist] ## flatten
|
|
180
|
+
self.mesh.field.setNumbers(distance, "PointsList", list(set([point[1] for point in
|
|
181
|
+
gmsh.model.getBoundary(
|
|
182
|
+
[(1, line) for line in vals],
|
|
183
|
+
combined=False, oriented=False)])))
|
|
184
|
+
|
|
185
|
+
self.mesh.field.setNumber(distance, "Sampling", 100)
|
|
186
|
+
|
|
187
|
+
k = area if area != 'iron_yoke' else 'iron_field'
|
|
188
|
+
if getattr(mesh, k).enabled:
|
|
189
|
+
threshold = self.mesh.field.add("Threshold")
|
|
190
|
+
self.mesh.field.setNumber(threshold, "InField", distance)
|
|
191
|
+
self.mesh.field.setNumber(threshold, "SizeMin", getattr(mesh, k).SizeMin)
|
|
192
|
+
self.mesh.field.setNumber(threshold, "SizeMax", getattr(mesh, k).SizeMax)
|
|
193
|
+
self.mesh.field.setNumber(threshold, "DistMin", getattr(mesh, k).DistMin)
|
|
194
|
+
self.mesh.field.setNumber(threshold, "DistMax", getattr(mesh, k).DistMax)
|
|
195
|
+
thresholds.append(threshold)
|
|
165
196
|
|
|
166
197
|
if run_type == 'EM' and mesh.bore_field.enabled:
|
|
167
|
-
|
|
168
198
|
distance_bore = self.mesh.field.add("Distance")
|
|
169
|
-
self.mesh.field.setNumbers(distance_bore, "PointsList",
|
|
199
|
+
self.mesh.field.setNumbers(distance_bore, "PointsList",
|
|
200
|
+
[pnt for pnt_name, pnt in self.md.geometries.air.points.items() if
|
|
201
|
+
'bore' in pnt_name])
|
|
170
202
|
self.mesh.field.setNumber(distance_bore, "Sampling", 100)
|
|
171
203
|
|
|
172
204
|
threshold_bore = self.mesh.field.add("Threshold")
|
|
@@ -178,11 +210,34 @@ class Mesh:
|
|
|
178
210
|
self.mesh.field.setNumber(threshold_bore, "StopAtDistMax", 1)
|
|
179
211
|
thresholds.append(threshold_bore)
|
|
180
212
|
|
|
213
|
+
if run_type == 'TH' and mesh.reference.enabled: # add reference meshing between collar and insulation
|
|
214
|
+
"""
|
|
215
|
+
(hardcoded) REFERENCE MESH for the FalconD-type magnet
|
|
216
|
+
"""
|
|
217
|
+
if not 'collar' in geometry.areas:
|
|
218
|
+
raise Exception("Adding the reference segment without collar is not intended.")
|
|
219
|
+
distance_ref = self.mesh.field.add("Distance")
|
|
220
|
+
if self.data.general.magnet_name == 'TEST_MULTIPOLE_FALCOND_C_TSA_COLLAR_POLE':
|
|
221
|
+
lines = list(range(754, 855)) + list(range(910, 1011))
|
|
222
|
+
self.mesh.field.setNumbers(distance_ref, "CurvesList", lines)
|
|
223
|
+
else:
|
|
224
|
+
raise Exception("Reference meshing is not implemented for this magnet.")
|
|
225
|
+
|
|
226
|
+
self.mesh.field.setNumber(distance_ref, "Sampling", 100)
|
|
227
|
+
|
|
228
|
+
threshold_ref = self.mesh.field.add("Threshold")
|
|
229
|
+
self.mesh.field.setNumber(threshold_ref, "InField", distance_ref)
|
|
230
|
+
self.mesh.field.setNumber(threshold_ref, "SizeMin", mesh.reference.SizeMin)
|
|
231
|
+
self.mesh.field.setNumber(threshold_ref, "SizeMax", mesh.reference.SizeMax)
|
|
232
|
+
self.mesh.field.setNumber(threshold_ref, "DistMin", mesh.reference.DistMin)
|
|
233
|
+
self.mesh.field.setNumber(threshold_ref, "DistMax", mesh.reference.DistMax)
|
|
234
|
+
self.mesh.field.setNumber(threshold_ref, "StopAtDistMax", 1)
|
|
235
|
+
thresholds.append(threshold_ref)
|
|
236
|
+
|
|
181
237
|
insulation_mesh_fields = []
|
|
182
238
|
if run_type == 'TH':
|
|
183
239
|
for coil_nr, coil in self.md.geometries.insulation.coils.items():
|
|
184
240
|
for _, group in coil.group.items():
|
|
185
|
-
# Areas
|
|
186
241
|
for area_name, area in group.ins.areas.items():
|
|
187
242
|
if area_name.isdigit():
|
|
188
243
|
insulation_mesh_fields.append(self.mesh.field.add("Constant"))
|
|
@@ -206,40 +261,85 @@ class Mesh:
|
|
|
206
261
|
if mesh.model_dump().get('isothermal_conductors', False):
|
|
207
262
|
elements = 1
|
|
208
263
|
elif any([i in line_key for i in ['i', 'o']]):
|
|
209
|
-
elements = max(1, round(
|
|
264
|
+
elements = max(1, round(
|
|
265
|
+
cable.bare_cable_height_mean / mesh.conductors.transfinite.curve_target_size_height))
|
|
210
266
|
elif any([i in line_key for i in ['l', 'h']]):
|
|
211
|
-
elements = max(1, round(
|
|
212
|
-
|
|
267
|
+
elements = max(1, round(
|
|
268
|
+
cable.bare_cable_width / mesh.conductors.transfinite.curve_target_size_width))
|
|
269
|
+
|
|
213
270
|
self.mesh.setTransfiniteCurve(line, elements)
|
|
214
|
-
if mesh.conductors.transfinite.enabled_for=='curves_and_surfaces' or mesh.model_dump().get(
|
|
271
|
+
if mesh.conductors.transfinite.enabled_for == 'curves_and_surfaces' or mesh.model_dump().get(
|
|
272
|
+
'isothermal_conductors', False):
|
|
215
273
|
for _, area in winding.blocks[block_order.block].half_turns.areas.items():
|
|
216
274
|
self.mesh.setTransfiniteSurface(area.surface)
|
|
217
275
|
self.mesh.setRecombine(2, area.surface)
|
|
218
|
-
|
|
276
|
+
|
|
219
277
|
if 'insulation' in mesh.model_dump() and 'TSA' in mesh.model_dump()["insulation"]:
|
|
220
278
|
# Apply transfinite curves to thin shell lines
|
|
221
279
|
if geometry.use_TSA:
|
|
222
280
|
gts = self.md.geometries.thin_shells
|
|
223
|
-
conductor_target_sizes = {'width': mesh.conductors.transfinite.curve_target_size_width,
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
281
|
+
conductor_target_sizes = {'width': mesh.conductors.transfinite.curve_target_size_width,
|
|
282
|
+
'height': mesh.conductors.transfinite.curve_target_size_height}
|
|
283
|
+
wedge_target_sizes = {'width': mesh.wedges.transfinite.curve_target_size_width,
|
|
284
|
+
'height': mesh.wedges.transfinite.curve_target_size_height}
|
|
285
|
+
for ts_group, side in zip([gts.mid_layers_ht_to_ht, gts.mid_layers_ht_to_wdg, gts.mid_layers_wdg_to_ht,
|
|
286
|
+
gts.mid_layers_wdg_to_wdg,
|
|
287
|
+
gts.mid_poles, gts.mid_windings, gts.mid_turn_blocks, gts.mid_wedge_turn,
|
|
288
|
+
gts.mid_layers_aux],
|
|
289
|
+
['height', 'height', 'height', 'height', 'width', 'width', 'width', 'width',
|
|
290
|
+
'height']):
|
|
228
291
|
for ts_name, ts in ts_group.items():
|
|
229
292
|
for _, line in ts.lines.items() if isinstance(ts, dM.Region) else ts.mid_layers.lines.items():
|
|
230
293
|
if mesh.isothermal_conductors or mesh.isothermal_wedges:
|
|
231
294
|
elements = 1
|
|
232
295
|
else:
|
|
233
|
-
coords = gmsh.model.getValue(1, line, [i[0] for i in
|
|
234
|
-
|
|
296
|
+
coords = gmsh.model.getValue(1, line, [i[0] for i in
|
|
297
|
+
gmsh.model.getParametrizationBounds(1, line)])
|
|
298
|
+
target_size = wedge_target_sizes[side] if ts_name.count('w') == 2 else \
|
|
299
|
+
conductor_target_sizes[side]
|
|
235
300
|
elements = max(1, round(Func.points_distance(coords[:2], coords[3:-1]) / target_size))
|
|
236
|
-
|
|
237
301
|
# it's a wedge
|
|
238
|
-
if ts_name.count('w') == 2 and mesh.wedges.transfinite.enabled_for in ['curves',
|
|
302
|
+
if ts_name.count('w') == 2 and mesh.wedges.transfinite.enabled_for in ['curves',
|
|
303
|
+
'curves_and_surfaces']:
|
|
239
304
|
self.mesh.setTransfiniteCurve(line, elements)
|
|
240
|
-
elif ts_name.count('w') != 2 and mesh.conductors.transfinite.enabled_for in ['curves',
|
|
241
|
-
|
|
242
|
-
|
|
305
|
+
elif ts_name.count('w') != 2 and mesh.conductors.transfinite.enabled_for in ['curves',
|
|
306
|
+
'curves_and_surfaces']:
|
|
307
|
+
self.mesh.setTransfiniteCurve(line, elements)
|
|
308
|
+
|
|
309
|
+
if geometry.use_TSA_new:
|
|
310
|
+
if not self.data.magnet.mesh.thermal.collar.Enforce_TSA_mapping:
|
|
311
|
+
r_tmp = np.abs(Func.points_distance(coords[:2], [0, 0]))
|
|
312
|
+
gts = self.md.geometries.thin_shells.collar_layers
|
|
313
|
+
# conductor and wedge target sizes are defined above
|
|
314
|
+
collar_size = None
|
|
315
|
+
# accounts for the distance between the collar and the TSA line: should be col2 = col1*r2/r1. r_tmp is approx. distance outer ht to centre
|
|
316
|
+
for ts_name, ts in gts.items():
|
|
317
|
+
for name, line in ts.lines.items():
|
|
318
|
+
coords = gmsh.model.getValue(1, line,
|
|
319
|
+
[i[0] for i in gmsh.model.getParametrizationBounds(1, line)])
|
|
320
|
+
if collar_size is None:
|
|
321
|
+
collar_size = r_tmp / Func.points_distance(coords[:2], [0,
|
|
322
|
+
0]) * self.data.magnet.mesh.thermal.collar.SizeMin
|
|
323
|
+
target_size = min(
|
|
324
|
+
wedge_target_sizes['width'] if ts_name.startswith('w') else conductor_target_sizes[
|
|
325
|
+
'width'], collar_size)
|
|
326
|
+
elements = max(1, round(Func.points_distance(coords[:2], coords[3:-1]) / target_size))
|
|
327
|
+
|
|
328
|
+
self.mesh.setTransfiniteCurve(line, elements)
|
|
329
|
+
else: # since we force the mesh on the collar side anyway
|
|
330
|
+
gts = self.md.geometries.thin_shells.collar_layers
|
|
331
|
+
# conductor and wedge target sizes are defined above
|
|
332
|
+
collar_size = self.data.magnet.mesh.thermal.collar.SizeMin
|
|
333
|
+
for ts_name, ts in gts.items():
|
|
334
|
+
for name, line in ts.lines.items():
|
|
335
|
+
coords = gmsh.model.getValue(1, line,
|
|
336
|
+
[i[0] for i in gmsh.model.getParametrizationBounds(1, line)])
|
|
337
|
+
target_size = collar_size
|
|
338
|
+
elements = max(1, round(Func.points_distance(coords[:2], coords[3:-1]) / target_size)) + 1
|
|
339
|
+
if elements % 2 == 1: elements += 1
|
|
340
|
+
self.mesh.setTransfiniteCurve(line, elements)
|
|
341
|
+
|
|
342
|
+
# COMMENTED since this overwrites also the cable transfinite meshes and in general,
|
|
243
343
|
# restricting the insulation boundaries to be transfinite seems very restrictive due to their complex geometry
|
|
244
344
|
# Apply transfinite curves to insulation boundaries
|
|
245
345
|
# else:
|
|
@@ -264,24 +364,30 @@ class Mesh:
|
|
|
264
364
|
for layer_nr, layer in coil.layers.items():
|
|
265
365
|
for _, wedge in layer.wedges.items():
|
|
266
366
|
pnts = gmsh.model.getAdjacencies(1, wedge.lines['i'])[1]
|
|
267
|
-
inner_height = Func.points_distance(gmsh.model.getValue(0, pnts[0], []),
|
|
367
|
+
inner_height = Func.points_distance(gmsh.model.getValue(0, pnts[0], []),
|
|
368
|
+
gmsh.model.getValue(0, pnts[1], []))
|
|
268
369
|
pnts = gmsh.model.getAdjacencies(1, wedge.lines['l'])[1]
|
|
269
|
-
width = Func.points_distance(gmsh.model.getValue(0, pnts[0], []),
|
|
370
|
+
width = Func.points_distance(gmsh.model.getValue(0, pnts[0], []),
|
|
371
|
+
gmsh.model.getValue(0, pnts[1], []))
|
|
270
372
|
pnts = gmsh.model.getAdjacencies(1, wedge.lines['o'])[1]
|
|
271
|
-
outer_height = Func.points_distance(gmsh.model.getValue(0, pnts[0], []),
|
|
373
|
+
outer_height = Func.points_distance(gmsh.model.getValue(0, pnts[0], []),
|
|
374
|
+
gmsh.model.getValue(0, pnts[1], []))
|
|
272
375
|
for line_key, line in wedge.lines.items():
|
|
273
376
|
if mesh.model_dump().get('isothermal_wedges', False):
|
|
274
377
|
elements = 1
|
|
275
378
|
elif 'i' in line_key:
|
|
276
|
-
elements = max(1, round(
|
|
379
|
+
elements = max(1, round(
|
|
380
|
+
inner_height / mesh.wedges.transfinite.curve_target_size_height))
|
|
277
381
|
elif 'o' in line_key:
|
|
278
|
-
elements = max(1, round((inner_height if mesh.wedges.transfinite.enabled_for in [
|
|
279
|
-
|
|
382
|
+
elements = max(1, round((inner_height if mesh.wedges.transfinite.enabled_for in [
|
|
383
|
+
'curves', 'curves_and_surfaces']
|
|
384
|
+
else outer_height) / mesh.wedges.transfinite.curve_target_size_height))
|
|
280
385
|
elif any([i in line_key for i in ['l', 'h']]):
|
|
281
386
|
elements = max(1, round(width / mesh.wedges.transfinite.curve_target_size_width))
|
|
282
387
|
if mesh.wedges.transfinite.enabled_for in ['curves', 'curves_and_surfaces']:
|
|
283
388
|
self.mesh.setTransfiniteCurve(line, elements)
|
|
284
|
-
if mesh.wedges.transfinite.enabled_for=='curves_and_surfaces' or mesh.model_dump().get(
|
|
389
|
+
if mesh.wedges.transfinite.enabled_for == 'curves_and_surfaces' or mesh.model_dump().get(
|
|
390
|
+
'isothermal_wedges', False):
|
|
285
391
|
self.mesh.setTransfiniteSurface(list(wedge.areas.values())[0].surface)
|
|
286
392
|
self.mesh.setRecombine(2, list(wedge.areas.values())[0].surface)
|
|
287
393
|
|
|
@@ -291,31 +397,45 @@ class Mesh:
|
|
|
291
397
|
"""
|
|
292
398
|
offset: int = 1 if 'symmetry' in geometry.model_dump() else int(1e6)
|
|
293
399
|
pg_tag = offset
|
|
400
|
+
point_offset = 4000000
|
|
401
|
+
point_tag = offset
|
|
294
402
|
|
|
295
403
|
# Create physical groups of iron yoke regions and block insulation
|
|
296
404
|
pg = self.md.domains.physical_groups
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
405
|
+
ge = self.md.domains.groups_entities
|
|
406
|
+
|
|
407
|
+
# Create the physical groups of iron + set color
|
|
408
|
+
group_keys = geometry.areas + ['ref_mesh']
|
|
409
|
+
for key in group_keys:
|
|
410
|
+
group_surfaces = getattr(ge, key)
|
|
411
|
+
pg_surfaces = getattr(pg, key).surfaces
|
|
412
|
+
for group_name, surfaces in group_surfaces.items():
|
|
413
|
+
pg_surfaces[group_name] = gmsh.model.addPhysicalGroup(2, surfaces, pg_tag)
|
|
414
|
+
gmsh.model.setPhysicalName(2, pg_surfaces[group_name], group_name)
|
|
415
|
+
if group_name not in self.colors:
|
|
416
|
+
logger.warning(f"Color for group '{group_name}' not defined, using default color [0, 0, 0].")
|
|
417
|
+
color = self.colors.get(group_name, [0, 0, 0])
|
|
418
|
+
gmsh.model.setColor([(2, i) for i in surfaces], *color)
|
|
419
|
+
pg_tag += 1
|
|
303
420
|
|
|
304
|
-
# Create the physical group of air infinite
|
|
421
|
+
# Create the physical group of air infinite + set color of entities.air
|
|
305
422
|
if 'symmetry' in geometry.model_dump():
|
|
306
423
|
gmsh.model.setPhysicalName(0, gmsh.model.addPhysicalGroup(
|
|
307
|
-
0, [pnt for pnt_name, pnt in self.md.geometries.air.points.items() if 'bore_field' in pnt_name],
|
|
424
|
+
0, [pnt for pnt_name, pnt in self.md.geometries.air.points.items() if 'bore_field' in pnt_name],
|
|
425
|
+
pg_tag), 'bore_centers')
|
|
308
426
|
pg_tag += 1
|
|
309
427
|
pg.air_inf_bnd = gmsh.model.addPhysicalGroup(1, [self.md.geometries.air_inf.lines['outer']], pg_tag)
|
|
310
428
|
gmsh.model.setPhysicalName(1, pg.air_inf_bnd, 'air_inf_bnd')
|
|
311
429
|
pg_tag += 1
|
|
312
430
|
pg.air_inf = gmsh.model.addPhysicalGroup(2, [self.md.geometries.air_inf.areas['outer'].surface], pg_tag)
|
|
313
431
|
gmsh.model.setPhysicalName(2, pg.air_inf, 'air_inf')
|
|
314
|
-
gmsh.model.setColor([(2, self.md.geometries.air_inf.areas['outer'].surface)], self.colors['air_inf'][0],
|
|
432
|
+
gmsh.model.setColor([(2, self.md.geometries.air_inf.areas['outer'].surface)], self.colors['air_inf'][0],
|
|
433
|
+
self.colors['air_inf'][1], self.colors['air_inf'][2])
|
|
315
434
|
pg_tag += 1
|
|
316
|
-
pg.air = gmsh.model.addPhysicalGroup(2,
|
|
435
|
+
pg.air = gmsh.model.addPhysicalGroup(2, ge.air, pg_tag)
|
|
317
436
|
gmsh.model.setPhysicalName(2, pg.air, 'air')
|
|
318
|
-
gmsh.model.setColor([(2, i) for i in
|
|
437
|
+
gmsh.model.setColor([(2, i) for i in ge.air], self.colors['air'][0], self.colors['air'][1],
|
|
438
|
+
self.colors['air'][2])
|
|
319
439
|
pg_tag += 1
|
|
320
440
|
|
|
321
441
|
# Create physical groups of half turns
|
|
@@ -324,6 +444,7 @@ class Mesh:
|
|
|
324
444
|
lyr_list_group.extend(['cl' + str(coil_nr) + 'ly' + str(lyr) for lyr in list(coil.layers.keys())])
|
|
325
445
|
for layer_nr, layer in coil.layers.items():
|
|
326
446
|
ht_list_group = []
|
|
447
|
+
ht_nodes_group = []
|
|
327
448
|
for nr, block_order in enumerate(layer):
|
|
328
449
|
wnd = self.md.geometries.coil.coils[coil_nr].poles[block_order.pole].layers[
|
|
329
450
|
layer_nr].windings[block_order.winding]
|
|
@@ -348,35 +469,64 @@ class Mesh:
|
|
|
348
469
|
gmsh.model.setPhysicalName(2, ht_pg.tag, ht_key)
|
|
349
470
|
gmsh.model.setColor([(2, ht.surface)], color[0], color[1], color[2])
|
|
350
471
|
pg_tag += 1
|
|
472
|
+
|
|
351
473
|
# Assign thin-shell group
|
|
352
474
|
# the check for reversed block coil is not tested well
|
|
353
|
-
if geometry.model_dump().get('correct_block_coil_tsa_checkered_scheme', False) and
|
|
475
|
+
if geometry.model_dump().get('correct_block_coil_tsa_checkered_scheme', False) and \
|
|
476
|
+
self.md.geometries.coil.coils[coil_nr].type == 'reversed-block-coil':
|
|
354
477
|
azimuthal = 'a1' if list(wnd.blocks.keys()).index(block_nr) % 2 == 0 else 'a2'
|
|
355
478
|
else:
|
|
356
|
-
azimuthal = 'a1' if lyr_list_group.index(
|
|
479
|
+
azimuthal = 'a1' if lyr_list_group.index(
|
|
480
|
+
'cl' + str(coil_nr) + 'ly' + str(layer_nr)) % 2 == 0 else 'a2'
|
|
357
481
|
radial = 'r1' if ht_list_group.index(ht_key) % 2 == 0 else 'r2'
|
|
358
482
|
ht_pg.group = radial + '_' + azimuthal
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
483
|
+
|
|
484
|
+
# Create 1D physical groups of thin shells
|
|
485
|
+
for ht_line_key, ht_line in block.half_turns.lines.items():
|
|
486
|
+
ht_nr = ht_line_key[:-1]
|
|
487
|
+
# Create half turn line groups
|
|
488
|
+
line_pg = gmsh.model.addPhysicalGroup(1, [ht_line], pg_tag)
|
|
489
|
+
gmsh.model.setPhysicalName(1, line_pg, ht_line_key)
|
|
490
|
+
color = [0, 0, 0] if blk_pg.half_turns[int(ht_nr)].group[:2] == 'r1' else [150, 150, 150]
|
|
491
|
+
gmsh.model.setColor([(1, ht_line)], color[0], color[1], color[2])
|
|
492
|
+
pg_tag += 1
|
|
493
|
+
# Store thin shell tags
|
|
494
|
+
blk_pg.half_turns[int(ht_nr)].lines[ht_line_key[-1]] = line_pg
|
|
495
|
+
|
|
496
|
+
# Add single_node per half turn for EM mesh
|
|
497
|
+
for ht_key, ht in block.half_turns.areas.items():
|
|
498
|
+
inner_line = \
|
|
499
|
+
gmsh.model.getEntitiesForPhysicalGroup(1, blk_pg.half_turns[int(ht_key)].lines['i'])[0]
|
|
500
|
+
inner_nodes = gmsh.model.getBoundary([(1, inner_line)])
|
|
501
|
+
|
|
502
|
+
higher_line = \
|
|
503
|
+
gmsh.model.getEntitiesForPhysicalGroup(1, blk_pg.half_turns[int(ht_key)].lines['h'])[0]
|
|
504
|
+
higher_nodes = gmsh.model.getBoundary([(1, higher_line)])
|
|
505
|
+
|
|
506
|
+
single_node = list(set(inner_nodes) & set(higher_nodes))[0][1]
|
|
507
|
+
blk_pg.half_turns[int(ht_key)].single_node = gmsh.model.addPhysicalGroup(0, [single_node],
|
|
508
|
+
point_offset + point_tag,
|
|
509
|
+
f"{ht_key}_single_node")
|
|
510
|
+
|
|
511
|
+
point_tag += 1
|
|
371
512
|
|
|
372
513
|
# Create points region for projection
|
|
373
514
|
if 'use_TSA' in geometry.model_dump():
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
515
|
+
point_list = [gmsh.model.getAdjacencies(1, gmsh.model.getAdjacencies(2, ht.surface)[1][0])[1][0]
|
|
516
|
+
for coil_nr, coil in self.md.geometries.coil.anticlockwise_order.coils.items()
|
|
517
|
+
for layer_nr, layer in coil.layers.items() for block_order in layer
|
|
518
|
+
for ht_key, ht in self.md.geometries.coil.coils[coil_nr].poles[block_order.pole].layers[
|
|
519
|
+
layer_nr].windings[block_order.winding].blocks[
|
|
520
|
+
block_order.block].half_turns.areas.items()]
|
|
521
|
+
### add one point per wedge
|
|
522
|
+
wdg_points = []
|
|
523
|
+
for coil_nr, coil in self.md.geometries.wedges.coils.items():
|
|
524
|
+
for layer_nr, layer in coil.layers.items():
|
|
525
|
+
for wedge_nr, wedge in layer.wedges.items():
|
|
526
|
+
wdg_points.append(list(gmsh.model.getAdjacencies(2, wedge.areas[str(wedge_nr)].surface)[1])[0])
|
|
527
|
+
|
|
528
|
+
self.md.domains.physical_groups.half_turns_points = gmsh.model.addPhysicalGroup(0, wdg_points + point_list,
|
|
529
|
+
int(4e6))
|
|
380
530
|
gmsh.model.setPhysicalName(0, self.md.domains.physical_groups.half_turns_points, 'points')
|
|
381
531
|
|
|
382
532
|
# Create physical groups of insulations
|
|
@@ -388,13 +538,16 @@ class Mesh:
|
|
|
388
538
|
if area_name.isdigit():
|
|
389
539
|
pg.insulations.surfaces[area_name] = gmsh.model.addPhysicalGroup(2, [area.surface], pg_tag)
|
|
390
540
|
gmsh.model.setPhysicalName(2, pg.insulations.surfaces[area_name], 'insul_' + area_name)
|
|
391
|
-
gmsh.model.setColor([(2, area.surface)], self.colors['insul'][0], self.colors['insul'][1],
|
|
541
|
+
gmsh.model.setColor([(2, area.surface)], self.colors['insul'][0], self.colors['insul'][1],
|
|
542
|
+
self.colors['insul'][2])
|
|
392
543
|
pg_tag += 1
|
|
393
|
-
|
|
544
|
+
|
|
394
545
|
# Boundaries
|
|
395
546
|
area_name = list(group.ins.areas.keys())[0] # todo: test for Mono
|
|
396
547
|
pg.insulations.curves['ext' + area_name] = gmsh.model.addPhysicalGroup(
|
|
397
|
-
1, [bnd[1] for bnd in
|
|
548
|
+
1, [bnd[1] for bnd in
|
|
549
|
+
gmsh.model.getBoundary([(2, list(group.ins.areas.values())[0].surface)], combined=False,
|
|
550
|
+
oriented=False)[:len(group.ins.lines)]], pg_tag)
|
|
398
551
|
gmsh.model.setPhysicalName(1, pg.insulations.curves['ext' + area_name], 'insul_ext' + area_name)
|
|
399
552
|
pg_tag += 1
|
|
400
553
|
# todo: NOT COMPLETED: would work if the tags were updated in the Geometry script after saving and loading brep
|
|
@@ -424,14 +577,13 @@ class Mesh:
|
|
|
424
577
|
else:
|
|
425
578
|
prev_group = prev_block_hts[list(prev_block_hts.keys())[0]].group
|
|
426
579
|
wedge_pg.group = ('r1' if prev_group[1] == '2' else 'r2') + prev_group[prev_group.index('_'):]
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
pg_tag += 1
|
|
580
|
+
|
|
581
|
+
for line_key, line in wedge.lines.items():
|
|
582
|
+
wedge_pg.lines[line_key] = gmsh.model.addPhysicalGroup(1, [line], pg_tag)
|
|
583
|
+
gmsh.model.setPhysicalName(1, wedge_pg.lines[line_key], 'w' + str(wedge_nr) + line_key)
|
|
584
|
+
color = [0, 0, 0] if wedge_pg.group[:2] == 'r1' else [150, 150, 150]
|
|
585
|
+
gmsh.model.setColor([(1, line)], color[0], color[1], color[2])
|
|
586
|
+
pg_tag += 1
|
|
435
587
|
|
|
436
588
|
# Create physical groups of thin shells
|
|
437
589
|
if geometry.model_dump().get('use_TSA', False):
|
|
@@ -441,8 +593,11 @@ class Mesh:
|
|
|
441
593
|
for ts_name, ts in gts.mid_layers_ht_to_ht.items():
|
|
442
594
|
blk_i, blk_o = ts_name[:ts_name.index('_')], ts_name[ts_name.index('_') + 1:]
|
|
443
595
|
for coil_nr, coil in self.md.geometries.coil.anticlockwise_order.coils.items():
|
|
444
|
-
if (any(int(blk_i) == blk_order.block for blk_order in
|
|
445
|
-
|
|
596
|
+
if (any(int(blk_i) == blk_order.block for blk_order in
|
|
597
|
+
self.md.geometries.coil.anticlockwise_order.coils[coil_nr].layers[1]) and
|
|
598
|
+
any(int(blk_o) == blk_order.block for blk_order in
|
|
599
|
+
self.md.geometries.coil.anticlockwise_order.coils[coil_nr].layers[
|
|
600
|
+
1])): # block-coil mid-pole case
|
|
446
601
|
block_coil_flag = True
|
|
447
602
|
for line_name, line in ts.mid_layers.lines.items():
|
|
448
603
|
line_pg = gmsh.model.addPhysicalGroup(1, [line], pg_tag)
|
|
@@ -470,7 +625,8 @@ class Mesh:
|
|
|
470
625
|
gmsh.model.setPhysicalName(1, line_pg, line_name)
|
|
471
626
|
pg_tag += 1
|
|
472
627
|
pg.wedges[int(wdg[1:])].mid_layer_lines.outer[line_name] = line_pg
|
|
473
|
-
ht = line_name[:line_name.index('_')] if line_name[line_name.index('_') + 1:] == wdg else line_name[
|
|
628
|
+
ht = line_name[:line_name.index('_')] if line_name[line_name.index('_') + 1:] == wdg else line_name[
|
|
629
|
+
line_name.index('_') + 1:]
|
|
474
630
|
pg.blocks[int(blk)].half_turns[int(ht)].mid_layer_lines.inner[line_name] = line_pg
|
|
475
631
|
|
|
476
632
|
# Create physical groups of block-to-wedge mid-layer lines
|
|
@@ -481,7 +637,8 @@ class Mesh:
|
|
|
481
637
|
gmsh.model.setPhysicalName(1, line_pg, line_name)
|
|
482
638
|
pg_tag += 1
|
|
483
639
|
pg.wedges[int(wdg[1:])].mid_layer_lines.inner[line_name] = line_pg
|
|
484
|
-
ht = line_name[:line_name.index('_')] if line_name[line_name.index('_') + 1:] == wdg else line_name[
|
|
640
|
+
ht = line_name[:line_name.index('_')] if line_name[line_name.index('_') + 1:] == wdg else line_name[
|
|
641
|
+
line_name.index('_') + 1:]
|
|
485
642
|
pg.blocks[int(blk)].half_turns[int(ht)].mid_layer_lines.outer[line_name] = line_pg
|
|
486
643
|
|
|
487
644
|
# Create physical groups of wedge-to-wedge mid-layer lines
|
|
@@ -495,7 +652,8 @@ class Mesh:
|
|
|
495
652
|
|
|
496
653
|
# Create non-mid-layer thin shells
|
|
497
654
|
for ts_group_name, ts_group in zip(['mid_pole', 'mid_winding', 'mid_turn', 'mid_turn', 'aux'],
|
|
498
|
-
[gts.mid_poles, gts.mid_windings, gts.mid_turn_blocks,
|
|
655
|
+
[gts.mid_poles, gts.mid_windings, gts.mid_turn_blocks,
|
|
656
|
+
gts.mid_wedge_turn, gts.mid_layers_aux]):
|
|
499
657
|
for ts_name, ts in ts_group.items():
|
|
500
658
|
if '_' in ts_name:
|
|
501
659
|
el_name1, el_name2 = ts_name.split('_')
|
|
@@ -510,11 +668,81 @@ class Mesh:
|
|
|
510
668
|
ht1 = int(list(ts.points.keys())[0][:-1])
|
|
511
669
|
else:
|
|
512
670
|
ht1, ht2 = line_name.split('_')
|
|
513
|
-
pg.blocks[int(el_name2)].half_turns[int(ht2)].__dict__[ts_group_name + '_lines'][
|
|
671
|
+
pg.blocks[int(el_name2)].half_turns[int(ht2)].__dict__[ts_group_name + '_lines'][
|
|
672
|
+
line_name] = line_pg
|
|
514
673
|
if ts_name[0] == 'w':
|
|
515
674
|
pg.wedges[int(el_name1)].__dict__[ts_group_name + '_lines'][line_name] = line_pg
|
|
516
675
|
else:
|
|
517
|
-
pg.blocks[int(el_name1)].half_turns[int(ht1)].__dict__[ts_group_name + '_lines'][
|
|
676
|
+
pg.blocks[int(el_name1)].half_turns[int(ht1)].__dict__[ts_group_name + '_lines'][
|
|
677
|
+
line_name] = line_pg
|
|
678
|
+
|
|
679
|
+
# Create physical groups for TSL
|
|
680
|
+
# add the physical group inner collar lines, only nonempty for the thermal solution with collar
|
|
681
|
+
lines = []
|
|
682
|
+
for quad, tags in self.md.geometries.collar.outer_boundary_tags.items():
|
|
683
|
+
if 'poles' in self.data.magnet.geometry.thermal.areas:
|
|
684
|
+
lines.extend(tags[:-1]) # skip the last line, this is the line between the pole and collar
|
|
685
|
+
else:
|
|
686
|
+
lines.extend(tags)
|
|
687
|
+
gmsh.model.occ.synchronize()
|
|
688
|
+
tag = gmsh.model.addPhysicalGroup(1, lines)
|
|
689
|
+
gmsh.model.setPhysicalName(1, tag, "outer_col")
|
|
690
|
+
pg.outer_col = tag
|
|
691
|
+
gmsh.model.occ.synchronize()
|
|
692
|
+
|
|
693
|
+
if geometry.model_dump().get('use_TSA_new', False):
|
|
694
|
+
# line names are defined earlier when creating the geometry (so wedge and coil names are already separated)
|
|
695
|
+
# f'{ht_nr}_x' for ht to mid and f'w{wedge_idx}_x' for wdg to mid
|
|
696
|
+
# poles look like f'p{pole_idx}_x'
|
|
697
|
+
layer = self.md.geometries.thin_shells.collar_layers
|
|
698
|
+
for name, l in layer.items():
|
|
699
|
+
line = l.lines['1'] # default line name, contains only one line
|
|
700
|
+
line_pg = gmsh.model.addPhysicalGroup(1, [line])
|
|
701
|
+
gmsh.model.setPhysicalName(1, line_pg, name)
|
|
702
|
+
color = [0, 0, 0]
|
|
703
|
+
gmsh.model.setColor([(1, line)], color[0], color[1], color[2])
|
|
704
|
+
# self.ins_type_col['mid_lines'][name] = line_pg
|
|
705
|
+
self.ins_type['collar'][name] = line_pg
|
|
706
|
+
|
|
707
|
+
# only apply to TSA
|
|
708
|
+
# add the physical group inner collar lines
|
|
709
|
+
lines = []
|
|
710
|
+
for quad, tags in self.md.geometries.collar.inner_boundary_tags.items():
|
|
711
|
+
lines.extend(tags)
|
|
712
|
+
gmsh.model.occ.synchronize()
|
|
713
|
+
tag = gmsh.model.addPhysicalGroup(1, lines)
|
|
714
|
+
gmsh.model.setPhysicalName(1, tag, "inner_col")
|
|
715
|
+
pg.inner_col = tag
|
|
716
|
+
gmsh.model.occ.synchronize()
|
|
717
|
+
|
|
718
|
+
# do the same for the poles, if they are defined
|
|
719
|
+
if 'poles' in self.data.magnet.geometry.thermal.areas:
|
|
720
|
+
layer = self.md.geometries.thin_shells.pole_layers
|
|
721
|
+
for name, l in layer.items():
|
|
722
|
+
line = l.lines['1'] # default line name, contains only one line
|
|
723
|
+
line_pg = gmsh.model.addPhysicalGroup(1, [line])
|
|
724
|
+
gmsh.model.setPhysicalName(1, line_pg, name)
|
|
725
|
+
color = [0, 0, 0]
|
|
726
|
+
gmsh.model.setColor([(1, line)], color[0], color[1], color[2])
|
|
727
|
+
self.ins_type['poles'][name] = line_pg
|
|
728
|
+
|
|
729
|
+
lines = []
|
|
730
|
+
for quad, tags in self.brep_curves['poles'].items():
|
|
731
|
+
lines.extend(tags)
|
|
732
|
+
# maybe only select the lines relevant for TSA?
|
|
733
|
+
gmsh.model.occ.synchronize()
|
|
734
|
+
tag = gmsh.model.addPhysicalGroup(1, lines)
|
|
735
|
+
gmsh.model.setPhysicalName(1, tag, "pole_boundary")
|
|
736
|
+
pg.poles.curves["bdry"] = tag
|
|
737
|
+
gmsh.model.occ.synchronize()
|
|
738
|
+
|
|
739
|
+
# Create physical group of collar cooling boudnary
|
|
740
|
+
if self.data.magnet.solve.thermal.collar_cooling.enabled and 'use_TSA' in geometry.model_dump():
|
|
741
|
+
## make physical group for collar cooling
|
|
742
|
+
tag = gmsh.model.addPhysicalGroup(1, self.md.geometries.collar.cooling_tags)
|
|
743
|
+
gmsh.model.setPhysicalName(1, tag, "collar cooling")
|
|
744
|
+
pg.collar_cooling = tag
|
|
745
|
+
gmsh.model.occ.synchronize()
|
|
518
746
|
|
|
519
747
|
# Create physical groups of symmetric boundaries
|
|
520
748
|
if geometry.model_dump().get('symmetry', 'none') != 'none':
|
|
@@ -524,8 +752,8 @@ class Mesh:
|
|
|
524
752
|
line_tags_normal_free = self.md.domains.groups_entities.symmetric_boundaries.y
|
|
525
753
|
line_tags_tangent_free = self.md.domains.groups_entities.symmetric_boundaries.x
|
|
526
754
|
elif len(self.md.geometries.coil.coils[1].poles) == 4: # todo: think about other multi-pole types
|
|
527
|
-
line_tags_tangent_free = self.md.domains.groups_entities.symmetric_boundaries.x
|
|
528
|
-
|
|
755
|
+
line_tags_tangent_free = self.md.domains.groups_entities.symmetric_boundaries.x + \
|
|
756
|
+
self.md.domains.groups_entities.symmetric_boundaries.y
|
|
529
757
|
elif geometry.symmetry == 'x':
|
|
530
758
|
if 'solenoid' in self.md.geometries.coil.coils[1].type:
|
|
531
759
|
line_tags_normal_free = self.md.domains.groups_entities.symmetric_boundaries.x
|
|
@@ -551,18 +779,21 @@ class Mesh:
|
|
|
551
779
|
qh = self.data.quench_protection.quench_heaters
|
|
552
780
|
|
|
553
781
|
def _store_qh_data(position, thin_shell, ts_tag):
|
|
554
|
-
qh_ins = self.ins_type_qh[position][qh.
|
|
782
|
+
qh_ins = self.ins_type_qh[position][qh.iQH_toHalfTurn_From[ht_index]]
|
|
555
783
|
if thin_shell not in qh_ins: qh_ins[thin_shell] = []
|
|
556
784
|
qh_ins[thin_shell].append(ts_tag)
|
|
557
|
-
if thin_shell not in self.qh_data[qh.
|
|
558
|
-
self.qh_data[qh.
|
|
785
|
+
if thin_shell not in self.qh_data[qh.iQH_toHalfTurn_From[ht_index]]:
|
|
786
|
+
self.qh_data[qh.iQH_toHalfTurn_From[ht_index]][thin_shell] = {'conductor': blk_pg.conductor,
|
|
787
|
+
'ht_side': qh_side}
|
|
559
788
|
|
|
560
789
|
def _store_ts_tags(pg_el, geom_ts_name='', geom_ts_name2=None, ts_grp='', lines='', lines_side=None):
|
|
561
790
|
geom_ts = self.md.geometries.thin_shells.model_dump()[geom_ts_name]
|
|
562
|
-
for ln_name, ln_tag in (
|
|
791
|
+
for ln_name, ln_tag in (
|
|
792
|
+
pg_el.model_dump()[lines][lines_side] if lines_side else pg_el.model_dump()[lines]).items():
|
|
563
793
|
for ts_name in ts_groups[ts_grp]:
|
|
564
794
|
if ts_name in geom_ts:
|
|
565
|
-
if ln_name in (
|
|
795
|
+
if ln_name in (
|
|
796
|
+
geom_ts[ts_name][geom_ts_name2]['lines'] if geom_ts_name2 else geom_ts[ts_name]['lines']):
|
|
566
797
|
if ts_name not in self.ins_type[ts_grp]: self.ins_type[ts_grp][ts_name] = []
|
|
567
798
|
self.ins_type[ts_grp][ts_name].append(ln_tag)
|
|
568
799
|
break
|
|
@@ -570,21 +801,30 @@ class Mesh:
|
|
|
570
801
|
# Collect thin shell tags
|
|
571
802
|
# Half turns
|
|
572
803
|
for blk_pg_nr, blk_pg in pg.blocks.items():
|
|
573
|
-
ts_groups = {'mid_wedge_turn': [ts_name for ts_name in self.md.geometries.thin_shells.mid_wedge_turn if
|
|
804
|
+
ts_groups = {'mid_wedge_turn': [ts_name for ts_name in self.md.geometries.thin_shells.mid_wedge_turn if
|
|
805
|
+
blk_pg_nr == int(ts_name.split('_')[1])],
|
|
574
806
|
'aux': [ts_name for ts_name in ins_th.mid_layer if str(blk_pg_nr) in ts_name.split('_')],
|
|
575
|
-
'mid_winding': [ts_name for ts_name in ins_th.mid_winding if
|
|
576
|
-
|
|
577
|
-
'
|
|
578
|
-
|
|
579
|
-
'
|
|
807
|
+
'mid_winding': [ts_name for ts_name in ins_th.mid_winding if
|
|
808
|
+
blk_pg_nr == int(ts_name.split('_')[0])],
|
|
809
|
+
'mid_pole': [ts_name for ts_name in ins_th.mid_pole if
|
|
810
|
+
blk_pg_nr == int(ts_name.split('_')[0])],
|
|
811
|
+
'mid_layer': [ts_name for ts_name in ins_th.mid_layer if
|
|
812
|
+
ts_name[0] != 'w' and blk_pg_nr == int(ts_name.split('_')[0])
|
|
813
|
+
or ts_name[0] == 'w' and ts_name.split('_')[1][0] != 'w' and blk_pg_nr == int(
|
|
814
|
+
ts_name.split('_')[1])],
|
|
815
|
+
'mid_layer_qh_i': [ts_name for ts_name in ins_th.mid_layer if
|
|
816
|
+
ts_name.split('_')[1][0] != 'w' and blk_pg_nr == int(
|
|
817
|
+
ts_name.split('_')[1])]}
|
|
580
818
|
ht_list = list(blk_pg.half_turns.keys())
|
|
581
819
|
self.ins_type_cond[str(blk_pg_nr)] = {'inner': [], 'outer': [], 'higher': [], 'lower': [], 'mid_turn': []}
|
|
582
820
|
for ht_nr, ht in blk_pg.half_turns.items():
|
|
583
|
-
if ht_nr in qh.
|
|
584
|
-
ht_index = qh.
|
|
821
|
+
if ht_nr in qh.iQH_toHalfTurn_To and qh.N_strips > 0: # check if a quench heater strip touches the current half-turn
|
|
822
|
+
ht_index = qh.iQH_toHalfTurn_To.index(ht_nr)
|
|
585
823
|
qh_side = qh.turns_sides[ht_index]
|
|
586
|
-
if qh.
|
|
587
|
-
|
|
824
|
+
if qh.iQH_toHalfTurn_From[ht_index] not in self.qh_data: self.qh_data[
|
|
825
|
+
qh.iQH_toHalfTurn_From[ht_index]] = {}
|
|
826
|
+
else:
|
|
827
|
+
qh_side = ''
|
|
588
828
|
|
|
589
829
|
# find conductor type of ht adjacent to wedge
|
|
590
830
|
if ht_list.index(ht_nr) == len(ht_list) - 1 and ht.mid_turn_lines:
|
|
@@ -594,7 +834,8 @@ class Mesh:
|
|
|
594
834
|
self.wedge_cond[int(ts_name[1:ts_name.index('_')])] = blk_pg.conductor
|
|
595
835
|
break
|
|
596
836
|
|
|
597
|
-
self.ins_type_cond[str(blk_pg_nr)]['mid_turn'].extend(
|
|
837
|
+
self.ins_type_cond[str(blk_pg_nr)]['mid_turn'].extend(
|
|
838
|
+
list(ht.mid_turn_lines.values())) # mid-turn insulation
|
|
598
839
|
|
|
599
840
|
if ht.aux_lines: # outer mid-layer insulation
|
|
600
841
|
_store_ts_tags(ht, geom_ts_name='mid_layers_aux', ts_grp='aux', lines='aux_lines')
|
|
@@ -606,12 +847,14 @@ class Mesh:
|
|
|
606
847
|
ts_lines = self.md.geometries.thin_shells.mid_layers_ht_to_ht[ts_name].mid_layers.lines
|
|
607
848
|
elif ts_name in self.md.geometries.thin_shells.mid_layers_wdg_to_ht:
|
|
608
849
|
ts_lines = self.md.geometries.thin_shells.mid_layers_wdg_to_ht[ts_name].lines
|
|
609
|
-
else:
|
|
850
|
+
else:
|
|
851
|
+
ts_lines = []
|
|
610
852
|
if line_name in ts_lines:
|
|
611
853
|
_store_qh_data('internal', ts_name, line_tag)
|
|
612
854
|
break
|
|
613
855
|
elif ht.mid_layer_lines.inner: # block-coil (!) inner mid-layer insulation
|
|
614
|
-
_store_ts_tags(ht, geom_ts_name='mid_layers_ht_to_ht', geom_ts_name2='mid_layers',
|
|
856
|
+
_store_ts_tags(ht, geom_ts_name='mid_layers_ht_to_ht', geom_ts_name2='mid_layers',
|
|
857
|
+
ts_grp='mid_layer', lines='mid_layer_lines', lines_side='inner')
|
|
615
858
|
elif not ht.mid_layer_lines.inner and qh_side == 'i': # quench heater inner insulation
|
|
616
859
|
_store_qh_data('external', blk_pg_nr, ht.lines['i'])
|
|
617
860
|
elif not ht.mid_layer_lines.inner: # inner insulation
|
|
@@ -624,7 +867,8 @@ class Mesh:
|
|
|
624
867
|
ts_lines = self.md.geometries.thin_shells.mid_layers_ht_to_ht[ts_name].mid_layers.lines
|
|
625
868
|
elif ts_name in self.md.geometries.thin_shells.mid_layers_ht_to_wdg:
|
|
626
869
|
ts_lines = self.md.geometries.thin_shells.mid_layers_ht_to_wdg[ts_name].lines
|
|
627
|
-
else:
|
|
870
|
+
else:
|
|
871
|
+
ts_lines = []
|
|
628
872
|
if line_name in ts_lines:
|
|
629
873
|
_store_qh_data('internal', ts_name, line_tag)
|
|
630
874
|
break
|
|
@@ -635,7 +879,8 @@ class Mesh:
|
|
|
635
879
|
ts_lines = self.md.geometries.thin_shells.mid_layers_ht_to_ht[ts_name].mid_layers.lines
|
|
636
880
|
elif ts_name in self.md.geometries.thin_shells.mid_layers_ht_to_wdg:
|
|
637
881
|
ts_lines = self.md.geometries.thin_shells.mid_layers_ht_to_wdg[ts_name].lines
|
|
638
|
-
else:
|
|
882
|
+
else:
|
|
883
|
+
ts_lines = []
|
|
639
884
|
if line_name in ts_lines:
|
|
640
885
|
if ts_name not in self.ins_type['mid_layer']: self.ins_type['mid_layer'][ts_name] = []
|
|
641
886
|
self.ins_type['mid_layer'][ts_name].append(line_tag)
|
|
@@ -651,20 +896,29 @@ class Mesh:
|
|
|
651
896
|
# mid-winding insulation
|
|
652
897
|
_store_ts_tags(ht, geom_ts_name='mid_windings', ts_grp='mid_winding', lines='mid_winding_lines')
|
|
653
898
|
|
|
654
|
-
if ht_list.index(ht_nr) == 0 and len(ht.mid_turn_lines) + len(ht.mid_winding_lines) + len(
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
899
|
+
if ht_list.index(ht_nr) == 0 and len(ht.mid_turn_lines) + len(ht.mid_winding_lines) + len(
|
|
900
|
+
ht.mid_pole_lines) == 1: # lower angle external side insulation
|
|
901
|
+
if qh_side == 'l':
|
|
902
|
+
_store_qh_data('external', blk_pg_nr, ht.lines['l'])
|
|
903
|
+
else:
|
|
904
|
+
self.ins_type_cond[str(blk_pg_nr)]['lower'].append(ht.lines['l'])
|
|
905
|
+
if ht_list.index(ht_nr) == len(ht_list) - 1 and len(ht.mid_turn_lines) + len(
|
|
906
|
+
ht.mid_winding_lines) + len(ht.mid_pole_lines) == 1: # higher angle external side insulation
|
|
907
|
+
if qh_side == 'h':
|
|
908
|
+
_store_qh_data('external', blk_pg_nr, ht.lines['h'])
|
|
909
|
+
else:
|
|
910
|
+
self.ins_type_cond[str(blk_pg_nr)]['higher'].append(ht.lines['h'])
|
|
660
911
|
|
|
661
912
|
# Wedges
|
|
662
913
|
for wdg_pg_nr, wdg_pg in pg.wedges.items():
|
|
663
914
|
ts_groups = {'aux': [ts_name for ts_name in ins_th.mid_layer if 'w' + str(wdg_pg_nr) in ts_name.split('_')],
|
|
664
|
-
'mid_layer': [ts_name for ts_name in ins_th.mid_layer if
|
|
665
|
-
|
|
915
|
+
'mid_layer': [ts_name for ts_name in ins_th.mid_layer if
|
|
916
|
+
'w' + str(wdg_pg_nr) == ts_name.split('_')[0]]}
|
|
917
|
+
self.ins_type_cond['w' + str(wdg_pg_nr)] = {'inner': [], 'outer': [], 'higher': [], 'lower': [],
|
|
918
|
+
'mid_turn': []}
|
|
666
919
|
if wdg_pg.aux_lines: _store_ts_tags(wdg_pg, geom_ts_name='mid_layers_aux', ts_grp='aux', lines='aux_lines')
|
|
667
|
-
if not wdg_pg.mid_layer_lines.inner: self.ins_type_cond['w' + str(wdg_pg_nr)]['inner'].append(
|
|
920
|
+
if not wdg_pg.mid_layer_lines.inner: self.ins_type_cond['w' + str(wdg_pg_nr)]['inner'].append(
|
|
921
|
+
wdg_pg.lines['i'])
|
|
668
922
|
if wdg_pg.mid_layer_lines.outer:
|
|
669
923
|
for line_name, line_tag in wdg_pg.mid_layer_lines.outer.items():
|
|
670
924
|
for ts_name in ts_groups['mid_layer']:
|
|
@@ -672,12 +926,14 @@ class Mesh:
|
|
|
672
926
|
ts_lines = self.md.geometries.thin_shells.mid_layers_wdg_to_ht[ts_name].lines
|
|
673
927
|
elif ts_name in self.md.geometries.thin_shells.mid_layers_wdg_to_wdg:
|
|
674
928
|
ts_lines = self.md.geometries.thin_shells.mid_layers_wdg_to_wdg[ts_name].lines
|
|
675
|
-
else:
|
|
929
|
+
else:
|
|
930
|
+
ts_lines = []
|
|
676
931
|
if line_name in ts_lines:
|
|
677
932
|
if ts_name not in self.ins_type['mid_layer']: self.ins_type['mid_layer'][ts_name] = []
|
|
678
933
|
self.ins_type['mid_layer'][ts_name].append(line_tag)
|
|
679
934
|
break
|
|
680
|
-
else:
|
|
935
|
+
else:
|
|
936
|
+
self.ins_type_cond['w' + str(wdg_pg_nr)]['outer'].append(wdg_pg.lines['o'])
|
|
681
937
|
|
|
682
938
|
# Collect common thin shells for double qh mid-layers
|
|
683
939
|
for qh_nr, ts_groups in self.ins_type_qh['internal'].items():
|
|
@@ -689,22 +945,28 @@ class Mesh:
|
|
|
689
945
|
common_tags = list(set(tags) & set(tags2))
|
|
690
946
|
for tag in common_tags:
|
|
691
947
|
tags.remove(tag), tags2.remove(tag)
|
|
692
|
-
if self.qh_data[qh_nr2][ts]['ht_side'] == 'i':
|
|
693
|
-
|
|
694
|
-
|
|
948
|
+
if self.qh_data[qh_nr2][ts]['ht_side'] == 'i':
|
|
949
|
+
qh_name = str(qh_nr) + '_' + str(qh_nr2)
|
|
950
|
+
else:
|
|
951
|
+
qh_name = str(qh_nr2) + '_' + str(qh_nr)
|
|
952
|
+
if qh_name not in self.ins_type_qh['internal_double']: self.ins_type_qh['internal_double'][
|
|
953
|
+
qh_name] = {}
|
|
695
954
|
qh_ins_id = self.ins_type_qh['internal_double'][qh_name]
|
|
696
955
|
if ts not in qh_ins_id: qh_ins_id[ts] = []
|
|
697
956
|
qh_ins_id[ts].append(tag)
|
|
698
957
|
|
|
699
958
|
def assignRegionsTags(self, geometry, mesh):
|
|
700
959
|
def _get_input_insulation_data(i_name, i_type=None):
|
|
701
|
-
ow_idx = next((index for index, couple in enumerate(
|
|
960
|
+
ow_idx = next((index for index, couple in enumerate(
|
|
961
|
+
self.data.magnet.solve.thermal.insulation_TSA.block_to_block.blocks_connection_overwrite)
|
|
702
962
|
if all(element in couple for element in i_name.split('_'))), None)
|
|
703
|
-
if i_type == 'mid_winding':
|
|
963
|
+
if i_type == 'mid_winding':
|
|
964
|
+
mid_mat, mid_th = [self.data.magnet.solve.wedges.material], []
|
|
704
965
|
elif ow_idx is not None:
|
|
705
966
|
mid_mat = self.data.magnet.solve.thermal.insulation_TSA.block_to_block.materials_overwrite[ow_idx]
|
|
706
967
|
mid_th = self.data.magnet.solve.thermal.insulation_TSA.block_to_block.thicknesses_overwrite[ow_idx]
|
|
707
|
-
else:
|
|
968
|
+
else:
|
|
969
|
+
mid_mat, mid_th = [self.data.magnet.solve.thermal.insulation_TSA.block_to_block.material], []
|
|
708
970
|
return mid_mat, mid_th
|
|
709
971
|
|
|
710
972
|
def _compute_insulation_thicknesses(tot_th, known_ins_th):
|
|
@@ -712,12 +974,17 @@ class Mesh:
|
|
|
712
974
|
mid_lyrs = [Func.sig_dig(tot_th - known_ins_th) / len(mid_materials)] * len(mid_materials)
|
|
713
975
|
elif None in mid_thicknesses:
|
|
714
976
|
input_ths = sum([th for th in mid_thicknesses if th is not None])
|
|
715
|
-
mid_lyrs = [
|
|
716
|
-
|
|
977
|
+
mid_lyrs = [
|
|
978
|
+
th if th is not None else Func.sig_dig(tot_th - known_ins_th - input_ths) / mid_thicknesses.count(
|
|
979
|
+
None) for th in mid_thicknesses]
|
|
980
|
+
else:
|
|
981
|
+
mid_lyrs = mid_thicknesses
|
|
717
982
|
zeros = [nbr for nbr, th in enumerate(mid_lyrs) if th < 1e-8]
|
|
718
983
|
if tot_th - known_ins_th - sum(mid_lyrs) < -1e-8:
|
|
719
|
-
raise ValueError(
|
|
720
|
-
|
|
984
|
+
raise ValueError(
|
|
985
|
+
"Layer-to-layer insulation exceeds the space between blocks: check 'solve'->'insulation_TSA'->'block_to_block'->'thicknesses_overwrite'")
|
|
986
|
+
else:
|
|
987
|
+
return mid_lyrs, zeros
|
|
721
988
|
|
|
722
989
|
pg = self.md.domains.physical_groups
|
|
723
990
|
qh = self.data.quench_protection.quench_heaters
|
|
@@ -725,9 +992,9 @@ class Mesh:
|
|
|
725
992
|
# Air and air far field
|
|
726
993
|
if 'bore_field' in mesh.model_dump():
|
|
727
994
|
self.rm.air_far_field.vol.radius_out = float(abs(max(gmsh.model.getValue(0, gmsh.model.getAdjacencies(
|
|
728
|
-
|
|
995
|
+
1, self.md.geometries.air_inf.lines['outer'])[1][0], []), key=abs)))
|
|
729
996
|
self.rm.air_far_field.vol.radius_in = float(abs(max(gmsh.model.getValue(0, gmsh.model.getAdjacencies(
|
|
730
|
-
|
|
997
|
+
1, self.md.geometries.air_inf.lines['inner'])[1][0], []), key=abs)))
|
|
731
998
|
self.rm.air.vol.name = "Air"
|
|
732
999
|
self.rm.air.vol.number = pg.air
|
|
733
1000
|
self.rm.air_far_field.vol.names = ["AirInf"]
|
|
@@ -757,31 +1024,46 @@ class Mesh:
|
|
|
757
1024
|
if 'bore_field' in mesh.model_dump():
|
|
758
1025
|
initial_current = self.data.power_supply.I_initial
|
|
759
1026
|
self.rm.powered[group].vol.currents = []
|
|
1027
|
+
self.rm.powered[group].curve.names = []
|
|
1028
|
+
self.rm.powered[group].curve.numbers = []
|
|
1029
|
+
self.rm.powered[group].surf_in.names = []
|
|
1030
|
+
self.rm.powered[group].surf_in.numbers = []
|
|
1031
|
+
if geometry.with_wedges:
|
|
1032
|
+
self.rm.induced[group].surf_in.names = []
|
|
1033
|
+
self.rm.induced[group].surf_in.numbers = []
|
|
760
1034
|
if geometry.model_dump().get('use_TSA', False):
|
|
761
|
-
self.rm.powered[group].surf_in.names = []
|
|
762
|
-
self.rm.powered[group].surf_in.numbers = []
|
|
763
1035
|
self.rm.powered[group].surf_out.names = []
|
|
764
1036
|
self.rm.powered[group].surf_out.numbers = []
|
|
765
1037
|
if geometry.with_wedges:
|
|
766
|
-
self.rm.induced[group].surf_in.names = []
|
|
767
|
-
self.rm.induced[group].surf_in.numbers = []
|
|
768
1038
|
self.rm.induced[group].surf_out.names = []
|
|
769
1039
|
self.rm.induced[group].surf_out.numbers = []
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
self.rm.
|
|
1040
|
+
|
|
1041
|
+
for attr in geometry.areas:
|
|
1042
|
+
h = getattr(self.rm, attr).vol
|
|
1043
|
+
h.names = []
|
|
1044
|
+
h.numbers = []
|
|
1045
|
+
|
|
1046
|
+
# initialise reference
|
|
1047
|
+
if self.data.magnet.mesh.thermal.reference.enabled:
|
|
1048
|
+
self.rm.ref_mesh.vol.names = []
|
|
1049
|
+
self.rm.ref_mesh.vol.numbers = []
|
|
1050
|
+
|
|
1051
|
+
self.rm.thin_shells.normals_directed['azimuthally'] = []
|
|
1052
|
+
self.rm.thin_shells.normals_directed['radially'] = []
|
|
1053
|
+
|
|
773
1054
|
if geometry.model_dump().get('use_TSA', False):
|
|
774
1055
|
unique_thin_shells = []
|
|
775
1056
|
self.rm.thin_shells.second_group_is_next['azimuthally'] = []
|
|
776
1057
|
self.rm.thin_shells.second_group_is_next['radially'] = []
|
|
777
|
-
self.rm.thin_shells.normals_directed['azimuthally'] = []
|
|
778
|
-
self.rm.thin_shells.normals_directed['radially'] = []
|
|
779
1058
|
else:
|
|
780
1059
|
self.rm.insulator.vol.names = []
|
|
781
1060
|
self.rm.insulator.vol.numbers = []
|
|
782
1061
|
self.rm.insulator.surf.names = []
|
|
783
1062
|
self.rm.insulator.surf.numbers = []
|
|
784
1063
|
|
|
1064
|
+
# always
|
|
1065
|
+
if 'collar' in geometry.areas:
|
|
1066
|
+
self.rm.thin_shells.bdry_curves['outer_collar'] = [pg.outer_col]
|
|
785
1067
|
if geometry.model_dump().get('use_TSA', False):
|
|
786
1068
|
# Categorize insulation types
|
|
787
1069
|
min_h = mesh.insulation.global_size
|
|
@@ -790,36 +1072,80 @@ class Mesh:
|
|
|
790
1072
|
# min_h = min([self.data.conductors[conductor].cable.th_insulation_along_height,
|
|
791
1073
|
# self.data.conductors[conductor].cable.th_insulation_along_width, min_h])
|
|
792
1074
|
min_h_QH = mesh.insulation.TSA.global_size_QH if mesh.insulation.TSA.global_size_QH else min_h
|
|
1075
|
+
min_h_COL = mesh.insulation.TSA.global_size_COL if mesh.insulation.TSA.global_size_QH else min_h
|
|
793
1076
|
|
|
794
1077
|
# Conductor insulation layers
|
|
1078
|
+
max_layer = len(
|
|
1079
|
+
[k for k in self.md.geometries.coil.coils[1].poles[1].layers.keys()]) # todo: more elegant way ?
|
|
795
1080
|
for el, ins in self.ins_type_cond.items():
|
|
796
|
-
cond = self.data.conductors[self.wedge_cond[int(el[1:])]].cable if 'w' in el else self.data.conductors[
|
|
1081
|
+
cond = self.data.conductors[self.wedge_cond[int(el[1:])]].cable if 'w' in el else self.data.conductors[
|
|
1082
|
+
pg.blocks[int(el)].conductor].cable
|
|
797
1083
|
for ins_side, tags in ins.items():
|
|
798
1084
|
if tags:
|
|
799
1085
|
side_ins_type = [cond.material_insulation]
|
|
800
|
-
if ins_side in ['inner', 'outer']:
|
|
801
|
-
|
|
1086
|
+
if ins_side in ['inner', 'outer']:
|
|
1087
|
+
side_ins = [cond.th_insulation_along_width]
|
|
1088
|
+
elif ins_side in ['higher', 'lower']:
|
|
1089
|
+
side_ins = [cond.th_insulation_along_height]
|
|
802
1090
|
else: # mid_turn
|
|
803
1091
|
side_ins = [cond.th_insulation_along_height, cond.th_insulation_along_height]
|
|
804
1092
|
side_ins_type.append(cond.material_insulation)
|
|
805
|
-
if ins_side[0] in 'iohl' and el + ins_side[
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
1093
|
+
if ins_side[0] in 'iohl' and el + ins_side[
|
|
1094
|
+
0] in self.data.magnet.solve.thermal.insulation_TSA.exterior.blocks:
|
|
1095
|
+
add_mat_idx = self.data.magnet.solve.thermal.insulation_TSA.exterior.blocks.index(
|
|
1096
|
+
el + ins_side[0])
|
|
1097
|
+
side_ins.extend(
|
|
1098
|
+
self.data.magnet.solve.thermal.insulation_TSA.exterior.thicknesses_append[add_mat_idx])
|
|
1099
|
+
side_ins_type.extend(
|
|
1100
|
+
self.data.magnet.solve.thermal.insulation_TSA.exterior.materials_append[add_mat_idx])
|
|
809
1101
|
if ins_side[0] in 'il': side_ins.reverse(), side_ins_type.reverse()
|
|
810
1102
|
self.rm.thin_shells.insulation_types.layers_number.append(0)
|
|
811
1103
|
self.rm.thin_shells.insulation_types.thin_shells.append(list(set(tags)))
|
|
812
1104
|
self.rm.thin_shells.insulation_types.thicknesses.append([])
|
|
813
1105
|
self.rm.thin_shells.insulation_types.layers_material.append([])
|
|
1106
|
+
if ins_side == 'outer': # scale thin shell lines linked to the collar
|
|
1107
|
+
if el[0] == 'w': # no wedge correction
|
|
1108
|
+
DUMMY = 1.0
|
|
1109
|
+
self.rm.thin_shells.insulation_types.correction_factors.append(DUMMY)
|
|
1110
|
+
else:
|
|
1111
|
+
bare_to_ins = (self.data.conductors[
|
|
1112
|
+
pg.blocks[int(el)].conductor].cable.bare_cable_height_high + 2 *
|
|
1113
|
+
self.data.conductors[
|
|
1114
|
+
pg.blocks[int(el)].conductor].cable.th_insulation_along_height) / \
|
|
1115
|
+
self.data.conductors[
|
|
1116
|
+
pg.blocks[int(el)].conductor].cable.bare_cable_height_high
|
|
1117
|
+
for key, ht in pg.blocks[int(el)].half_turns.items(): # try only first key
|
|
1118
|
+
if str(ht.group[-1]) == str(max_layer): # ensure outer layer !
|
|
1119
|
+
DUMMY = float(self.data.magnet.mesh.thermal.insulation.TSA.scale_factor_radial)
|
|
1120
|
+
if DUMMY < 0.0: # default value
|
|
1121
|
+
DUMMY = bare_to_ins
|
|
1122
|
+
else: # inner layer
|
|
1123
|
+
# print(ht.lines['o']) #-> without the break this prints the linetags of the desired lines
|
|
1124
|
+
# we are within the ins_side = "outer" loop so
|
|
1125
|
+
DUMMY = bare_to_ins
|
|
1126
|
+
self.rm.thin_shells.insulation_types.correction_factors.append(
|
|
1127
|
+
DUMMY) # default value if not outer layer
|
|
1128
|
+
break # break after first key
|
|
1129
|
+
elif ins_side[0] in 'hl': # hl, long ht side adjacent to the poles
|
|
1130
|
+
DUMMY = float(self.data.magnet.mesh.thermal.insulation.TSA.scale_factor_azimuthal)
|
|
1131
|
+
if DUMMY < 0.0: # default value
|
|
1132
|
+
DUMMY = 1.0
|
|
1133
|
+
self.rm.thin_shells.insulation_types.correction_factors.append(DUMMY)
|
|
1134
|
+
else:
|
|
1135
|
+
self.rm.thin_shells.insulation_types.correction_factors.append(1.0) # default value
|
|
814
1136
|
for nr, ins_lyr in enumerate(side_ins):
|
|
815
1137
|
tsa_layers = max(mesh.insulation.TSA.minimum_discretizations, round(ins_lyr / min_h))
|
|
816
1138
|
self.rm.thin_shells.insulation_types.layers_number[-1] += tsa_layers
|
|
817
|
-
self.rm.thin_shells.insulation_types.thicknesses[-1].extend(
|
|
818
|
-
|
|
1139
|
+
self.rm.thin_shells.insulation_types.thicknesses[-1].extend(
|
|
1140
|
+
[ins_lyr / tsa_layers] * tsa_layers)
|
|
1141
|
+
self.rm.thin_shells.insulation_types.layers_material[-1].extend(
|
|
1142
|
+
[side_ins_type[nr]] * tsa_layers)
|
|
819
1143
|
|
|
820
1144
|
# Mid-pole, mid-winding, and mid-layer insulation layers
|
|
821
1145
|
ins_th_dict = self.md.geometries.thin_shells.ins_thickness.model_dump()
|
|
822
1146
|
for ins_type, ins in self.ins_type.items():
|
|
1147
|
+
if ins_type in ['collar', 'poles']:
|
|
1148
|
+
continue # these are added later
|
|
823
1149
|
for ins_name, tags in ins.items():
|
|
824
1150
|
# Get conductors insulation
|
|
825
1151
|
if ins_name.count('w') == 2:
|
|
@@ -841,7 +1167,9 @@ class Mesh:
|
|
|
841
1167
|
cond_ins1, cond_ins2 = cond1.th_insulation_along_height, cond2.th_insulation_along_height
|
|
842
1168
|
# Get insulation layer thickness
|
|
843
1169
|
mid_materials, mid_thicknesses = _get_input_insulation_data(ins_name, i_type=ins_type)
|
|
844
|
-
|
|
1170
|
+
# for aux: 1/2 due to triangular insulation shape, 1/2 because the triangle height is half the radial distance between the points of the ht insulation
|
|
1171
|
+
ins_thickness = 1 / 2 * ins_th_dict['mid_layer'][ins_name] / 2 if ins_type == 'aux' else \
|
|
1172
|
+
ins_th_dict[ins_type][ins_name]
|
|
845
1173
|
mid_lyr_th, null_idx = _compute_insulation_thicknesses(ins_thickness, cond_ins1 + cond_ins2)
|
|
846
1174
|
for idx in null_idx: mid_lyr_th.pop(idx), mid_materials.pop(idx)
|
|
847
1175
|
side_ins = [cond_ins1] + mid_lyr_th + [cond_ins2]
|
|
@@ -852,11 +1180,14 @@ class Mesh:
|
|
|
852
1180
|
self.rm.thin_shells.insulation_types.thin_shells.append(list(set(tags)))
|
|
853
1181
|
self.rm.thin_shells.insulation_types.thicknesses.append([])
|
|
854
1182
|
self.rm.thin_shells.insulation_types.layers_material.append([])
|
|
1183
|
+
self.rm.thin_shells.insulation_types.correction_factors.append(1.0) # default value
|
|
1184
|
+
|
|
855
1185
|
for nr, ins_lyr in enumerate(side_ins):
|
|
856
1186
|
tsa_layers = max(mesh.insulation.TSA.minimum_discretizations, round(ins_lyr / min_h))
|
|
857
1187
|
self.rm.thin_shells.insulation_types.layers_number[-1] += tsa_layers
|
|
858
1188
|
self.rm.thin_shells.insulation_types.thicknesses[-1].extend([ins_lyr / tsa_layers] * tsa_layers)
|
|
859
|
-
self.rm.thin_shells.insulation_types.layers_material[-1].extend(
|
|
1189
|
+
self.rm.thin_shells.insulation_types.layers_material[-1].extend(
|
|
1190
|
+
[side_ins_type[nr]] * tsa_layers)
|
|
860
1191
|
|
|
861
1192
|
# Quench heater insulation layers
|
|
862
1193
|
for ins_type, ins in self.ins_type_qh.items():
|
|
@@ -866,30 +1197,54 @@ class Mesh:
|
|
|
866
1197
|
if tags:
|
|
867
1198
|
if ins_type == 'external':
|
|
868
1199
|
data = self.qh_data[qh_nr]
|
|
869
|
-
if str(ts_name) + data[ts_name][
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
1200
|
+
if str(ts_name) + data[ts_name][
|
|
1201
|
+
'ht_side'] in self.data.magnet.solve.thermal.insulation_TSA.exterior.blocks:
|
|
1202
|
+
add_mat_idx = self.data.magnet.solve.thermal.insulation_TSA.exterior.blocks.index(
|
|
1203
|
+
str(ts_name) + data[ts_name]['ht_side'])
|
|
1204
|
+
additional_ths = \
|
|
1205
|
+
self.data.magnet.solve.thermal.insulation_TSA.exterior.thicknesses_append[
|
|
1206
|
+
add_mat_idx]
|
|
1207
|
+
additional_mats = \
|
|
1208
|
+
self.data.magnet.solve.thermal.insulation_TSA.exterior.materials_append[add_mat_idx]
|
|
1209
|
+
else:
|
|
1210
|
+
additional_ths, additional_mats = [], []
|
|
874
1211
|
cond = self.data.conductors[data[ts_name]['conductor']].cable
|
|
875
|
-
ht_ins_th = cond.th_insulation_along_width if data[ts_name][
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1212
|
+
ht_ins_th = cond.th_insulation_along_width if data[ts_name][
|
|
1213
|
+
'ht_side'] in 'io' else cond.th_insulation_along_height
|
|
1214
|
+
side_ins = [ht_ins_th] + [s_ins for s_ins in qh.s_ins[qh_nr - 1]] + [
|
|
1215
|
+
qh.h[qh_nr - 1]] + [s_ins_He for s_ins_He in
|
|
1216
|
+
qh.s_ins_He[qh_nr - 1]] + additional_ths
|
|
1217
|
+
side_ins_type = [cond.material_insulation] + [type_ins for type_ins in
|
|
1218
|
+
qh.type_ins[qh_nr - 1]] + ['SS'] + \
|
|
1219
|
+
[type_ins_He for type_ins_He in
|
|
1220
|
+
qh.type_ins_He[qh_nr - 1]] + additional_mats
|
|
879
1221
|
if data[ts_name]['ht_side'] in 'il': side_ins.reverse(), side_ins_type.reverse()
|
|
880
1222
|
qh_list = [qh_nr]
|
|
881
1223
|
elif ins_type == 'internal':
|
|
882
1224
|
data = self.qh_data[qh_nr]
|
|
883
1225
|
cond = self.data.conductors[data[ts_name]['conductor']].cable
|
|
884
|
-
cond2 = self.data.conductors[
|
|
885
|
-
|
|
886
|
-
|
|
1226
|
+
cond2 = self.data.conductors[
|
|
1227
|
+
self.wedge_cond[int(ts_name.split('_')[0][1:])] if 'w' in ts_name
|
|
1228
|
+
else pg.blocks[
|
|
1229
|
+
int(ts_name.split('_')[1]) if data[ts_name]['ht_side'] == 'o' else int(
|
|
1230
|
+
ts_name.split('_')[0])].conductor].cable
|
|
1231
|
+
side_ins_qh = [s_ins for s_ins in qh.s_ins[qh_nr - 1]] + [qh.h[qh_nr - 1]] + [s_ins_He
|
|
1232
|
+
for
|
|
1233
|
+
s_ins_He
|
|
1234
|
+
in
|
|
1235
|
+
qh.s_ins_He[
|
|
1236
|
+
qh_nr - 1]]
|
|
887
1237
|
mid_lyr_th, null_idx = _compute_insulation_thicknesses(
|
|
888
|
-
ins_th_dict['mid_layer'][ts_name], sum([cond.th_insulation_along_width,
|
|
1238
|
+
ins_th_dict['mid_layer'][ts_name], sum([cond.th_insulation_along_width,
|
|
1239
|
+
cond2.th_insulation_along_width] + side_ins_qh))
|
|
889
1240
|
for idx in null_idx: mid_lyr_th.pop(idx), mid_materials.pop(idx)
|
|
890
|
-
side_ins = [cond.th_insulation_along_width] + side_ins_qh + mid_lyr_th + [
|
|
891
|
-
|
|
892
|
-
|
|
1241
|
+
side_ins = [cond.th_insulation_along_width] + side_ins_qh + mid_lyr_th + [
|
|
1242
|
+
cond2.th_insulation_along_width]
|
|
1243
|
+
side_ins_type = [cond.material_insulation] + [type_ins for type_ins in
|
|
1244
|
+
qh.type_ins[qh_nr - 1]] + ['SS'] + \
|
|
1245
|
+
[type_ins_He for type_ins_He in
|
|
1246
|
+
qh.type_ins_He[qh_nr - 1]] + mid_materials + [
|
|
1247
|
+
cond2.material_insulation]
|
|
893
1248
|
if data[ts_name]['ht_side'] == 'i': side_ins.reverse(), side_ins_type.reverse()
|
|
894
1249
|
qh_list = [qh_nr]
|
|
895
1250
|
elif ins_type == 'internal_double':
|
|
@@ -897,16 +1252,28 @@ class Mesh:
|
|
|
897
1252
|
data, data2 = self.qh_data[qh_nr1], self.qh_data[qh_nr2]
|
|
898
1253
|
cond = self.data.conductors[data[ts_name]['conductor']].cable
|
|
899
1254
|
cond2 = self.data.conductors[data2[ts_name]['conductor']].cable
|
|
900
|
-
side_ins_qh = [
|
|
901
|
-
|
|
1255
|
+
side_ins_qh = [s_ins for s_ins in qh.s_ins[qh_nr1 - 1]] + [qh.h[qh_nr1 - 1]] + [s_ins_He
|
|
1256
|
+
for
|
|
1257
|
+
s_ins_He
|
|
1258
|
+
in
|
|
1259
|
+
qh.s_ins_He[
|
|
1260
|
+
qh_nr1 - 1]]
|
|
1261
|
+
side_ins_qh2 = [s_ins_He for s_ins_He in qh.s_ins_He[qh_nr2 - 1][::-1]] + [
|
|
1262
|
+
qh.h[qh_nr2 - 1]] + [s_ins for s_ins in qh.s_ins[qh_nr2 - 1][::-1]]
|
|
902
1263
|
mid_lyr_th, null_idx = _compute_insulation_thicknesses(
|
|
903
|
-
ins_th_dict['mid_layer'][ts_name], sum([cond.th_insulation_along_width,
|
|
1264
|
+
ins_th_dict['mid_layer'][ts_name], sum([cond.th_insulation_along_width,
|
|
1265
|
+
cond2.th_insulation_along_width] + side_ins_qh + side_ins_qh2))
|
|
904
1266
|
for idx in null_idx: mid_lyr_th.pop(idx), mid_materials.pop(idx)
|
|
905
|
-
side_ins = [cond.th_insulation_along_width] + side_ins_qh + mid_lyr_th + side_ins_qh2 + [
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
[
|
|
1267
|
+
side_ins = [cond.th_insulation_along_width] + side_ins_qh + mid_lyr_th + side_ins_qh2 + [
|
|
1268
|
+
cond2.th_insulation_along_width]
|
|
1269
|
+
side_ins_type = [cond.material_insulation] + [type_ins for type_ins in
|
|
1270
|
+
qh.type_ins[qh_nr1 - 1]] + ['SS'] + \
|
|
1271
|
+
[type_ins_He for type_ins_He in
|
|
1272
|
+
qh.type_ins_He[qh_nr1 - 1]] + mid_materials + \
|
|
1273
|
+
[type_ins_He for type_ins_He in qh.type_ins_He[qh_nr2 - 1][::-1]] + [
|
|
1274
|
+
'SS'] + \
|
|
1275
|
+
[type_ins for type_ins in qh.type_ins[qh_nr2 - 1][::-1]] + [
|
|
1276
|
+
cond2.material_insulation]
|
|
910
1277
|
qh_list = [qh_nr1, qh_nr2]
|
|
911
1278
|
qh_labels = [1 if m == 'SS' else None for m in side_ins_type]
|
|
912
1279
|
ss_indexes = [index for index, value in enumerate(qh_labels) if value == 1]
|
|
@@ -916,13 +1283,148 @@ class Mesh:
|
|
|
916
1283
|
self.rm.thin_shells.quench_heaters.thicknesses.append([])
|
|
917
1284
|
self.rm.thin_shells.quench_heaters.layers_material.append([])
|
|
918
1285
|
self.rm.thin_shells.quench_heaters.label.append([])
|
|
1286
|
+
self.rm.thin_shells.quench_heaters.correction_factors.append(1.0) # default value
|
|
919
1287
|
for nr, ins_lyr in enumerate(side_ins):
|
|
920
|
-
tsa_layers = max(mesh.insulation.TSA.minimum_discretizations_QH,
|
|
1288
|
+
tsa_layers = max(mesh.insulation.TSA.minimum_discretizations_QH,
|
|
1289
|
+
round(ins_lyr / min_h_QH))
|
|
921
1290
|
self.rm.thin_shells.quench_heaters.layers_number[-1] += tsa_layers
|
|
922
|
-
self.rm.thin_shells.quench_heaters.thicknesses[-1].extend(
|
|
923
|
-
|
|
1291
|
+
self.rm.thin_shells.quench_heaters.thicknesses[-1].extend(
|
|
1292
|
+
[ins_lyr / tsa_layers] * tsa_layers)
|
|
1293
|
+
self.rm.thin_shells.quench_heaters.layers_material[-1].extend(
|
|
1294
|
+
[side_ins_type[nr]] * tsa_layers)
|
|
924
1295
|
self.rm.thin_shells.quench_heaters.label[-1].extend([qh_labels[nr]] * tsa_layers)
|
|
925
1296
|
|
|
1297
|
+
if geometry.model_dump().get('use_TSA_new', False): # collar
|
|
1298
|
+
total_ins_th_dict = self.md.geometries.thin_shells.ins_thickness.collar
|
|
1299
|
+
for ins_name, tags in self.ins_type['collar'].items(): # self.ins_type_col['mid_lines']
|
|
1300
|
+
qh_th = 0.0 # todo, correct for thickness, total ins th already takes into account the insulation layer but not qh
|
|
1301
|
+
residual_th = total_ins_th_dict[ins_name] - qh_th
|
|
1302
|
+
side_ins = [residual_th] # only one layer of insulation, as the other layer is captured in QH
|
|
1303
|
+
# Get insulation materials
|
|
1304
|
+
side_ins_type = [self.data.magnet.solve.thermal.insulation_TSA.between_collar.material]
|
|
1305
|
+
|
|
1306
|
+
self.rm.thin_shells.collar.layers_number.append(0)
|
|
1307
|
+
self.rm.thin_shells.collar.thin_shells.append([tags])
|
|
1308
|
+
self.rm.thin_shells.collar.thicknesses.append([])
|
|
1309
|
+
self.rm.thin_shells.collar.layers_material.append([])
|
|
1310
|
+
|
|
1311
|
+
cond_name = next(iter(self.data.conductors.keys()))
|
|
1312
|
+
ins_to_bare_ratio = (self.data.conductors[cond_name].cable.bare_cable_height_high + 2 *
|
|
1313
|
+
self.data.conductors[cond_name].cable.th_insulation_along_height) / \
|
|
1314
|
+
self.data.conductors[cond_name].cable.bare_cable_height_high
|
|
1315
|
+
DUMMY = float(self.data.magnet.mesh.thermal.insulation.TSA.scale_factor_radial)
|
|
1316
|
+
if DUMMY < 0.0: # default value
|
|
1317
|
+
DUMMY = ins_to_bare_ratio # ins to bare scaling
|
|
1318
|
+
self.rm.thin_shells.insulation_types.correction_factors.append(DUMMY)
|
|
1319
|
+
|
|
1320
|
+
for nr, ins_lyr in enumerate(side_ins):
|
|
1321
|
+
tsa_layers = max(mesh.insulation.TSA.minimum_discretizations_COL, round(ins_lyr / min_h_COL))
|
|
1322
|
+
self.rm.thin_shells.collar.layers_number[-1] += tsa_layers
|
|
1323
|
+
self.rm.thin_shells.collar.thicknesses[-1].extend([ins_lyr / tsa_layers] * tsa_layers)
|
|
1324
|
+
self.rm.thin_shells.collar.layers_material[-1].extend([side_ins_type[nr]] * tsa_layers)
|
|
1325
|
+
|
|
1326
|
+
# mid collar groups
|
|
1327
|
+
|
|
1328
|
+
self.rm.thin_shells.ts_collar_groups['1_1'] = []
|
|
1329
|
+
self.rm.thin_shells.ts_collar_groups['2_1'] = []
|
|
1330
|
+
self.rm.thin_shells.ts_collar_groups['1_2'] = []
|
|
1331
|
+
self.rm.thin_shells.ts_collar_groups['2_2'] = []
|
|
1332
|
+
|
|
1333
|
+
max_layer = len([k for k in self.md.geometries.coil.coils[1].poles[1].layers.keys()])
|
|
1334
|
+
for blk_nr, blk in self.md.domains.physical_groups.blocks.items(): # only need this for the outer layer :)
|
|
1335
|
+
for ht_nr, el in blk.half_turns.items():
|
|
1336
|
+
if str(el.group[-1]) == str(
|
|
1337
|
+
max_layer): #### 2nd index is swapped due to the checkboard pattern -> otherwise we have to swap it in the .pro file
|
|
1338
|
+
self.rm.thin_shells.ts_collar_groups[
|
|
1339
|
+
el.group[1] + '_' + str(1 + int(el.group[-1]) % 2)].append(
|
|
1340
|
+
self.ins_type['collar'][f'{ht_nr}_x']) # self.ins_type_col['mid_lines']
|
|
1341
|
+
|
|
1342
|
+
# wedges
|
|
1343
|
+
for wdg_nr, el in self.md.domains.physical_groups.wedges.items():
|
|
1344
|
+
if str(el.group[-1]) == str(max_layer):
|
|
1345
|
+
self.rm.thin_shells.ts_collar_groups[el.group[1] + '_' + str(1 + int(el.group[-1]) % 2)].append(
|
|
1346
|
+
self.ins_type['collar'][f'w{wdg_nr}_x']) # self.ins_type_col['mid_lines']
|
|
1347
|
+
|
|
1348
|
+
# collar
|
|
1349
|
+
self.rm.thin_shells.bdry_curves['collar'] = [pg.inner_col]
|
|
1350
|
+
|
|
1351
|
+
if geometry.model_dump().get('use_TSA', False): # poles
|
|
1352
|
+
total_ins_th_dict = self.md.geometries.thin_shells.ins_thickness.poles
|
|
1353
|
+
for ins_name, tags in self.ins_type['poles'].items():
|
|
1354
|
+
other_corrections = 0.0 # assuming the other corrections are zero #debug
|
|
1355
|
+
residual_th = total_ins_th_dict[ins_name] - other_corrections
|
|
1356
|
+
side_ins = [residual_th]
|
|
1357
|
+
side_ins_type = [self.data.magnet.solve.thermal.insulation_TSA.between_collar.material]
|
|
1358
|
+
# assuming the insulation between the pole and ht are the same as for the collar
|
|
1359
|
+
|
|
1360
|
+
self.rm.thin_shells.poles.layers_number.append(0)
|
|
1361
|
+
self.rm.thin_shells.poles.thin_shells.append([tags])
|
|
1362
|
+
self.rm.thin_shells.poles.thicknesses.append([])
|
|
1363
|
+
self.rm.thin_shells.poles.layers_material.append([])
|
|
1364
|
+
|
|
1365
|
+
# Scaling to the pole lines (2nd insulation layer)
|
|
1366
|
+
if ins_name.startswith('pw'): # wedge pole line
|
|
1367
|
+
DUMMY = 1.0 # default
|
|
1368
|
+
elif ins_name.endswith('_r'): # radial line -> halfturn
|
|
1369
|
+
DUMMY = float(self.data.magnet.mesh.thermal.insulation.TSA.scale_factor_radial)
|
|
1370
|
+
if DUMMY < 0.0: DUMMY = ins_to_bare_ratio # default value
|
|
1371
|
+
else: # pole lines
|
|
1372
|
+
DUMMY = float(self.data.magnet.mesh.thermal.insulation.TSA.scale_factor_azimuthal)
|
|
1373
|
+
if DUMMY < 0.0: DUMMY = 1.0 # default value
|
|
1374
|
+
self.rm.thin_shells.poles.correction_factors.append(DUMMY)
|
|
1375
|
+
|
|
1376
|
+
for nr, ins_lyr in enumerate(side_ins):
|
|
1377
|
+
tsa_layers = max(mesh.insulation.TSA.minimum_discretizations,
|
|
1378
|
+
round(ins_lyr / min_h)) # use default TSA
|
|
1379
|
+
self.rm.thin_shells.poles.layers_number[-1] += tsa_layers
|
|
1380
|
+
self.rm.thin_shells.poles.thicknesses[-1].extend([ins_lyr / tsa_layers] * tsa_layers)
|
|
1381
|
+
self.rm.thin_shells.poles.layers_material[-1].extend([side_ins_type[nr]] * tsa_layers)
|
|
1382
|
+
|
|
1383
|
+
# checkboard pattern to link with the hts
|
|
1384
|
+
self.rm.thin_shells.ts_pole_groups['a_1_1'] = []
|
|
1385
|
+
self.rm.thin_shells.ts_pole_groups['a_2_1'] = []
|
|
1386
|
+
self.rm.thin_shells.ts_pole_groups['a_1_2'] = []
|
|
1387
|
+
self.rm.thin_shells.ts_pole_groups['a_2_2'] = []
|
|
1388
|
+
self.rm.thin_shells.ts_pole_groups['r_1_2'] = []
|
|
1389
|
+
self.rm.thin_shells.ts_pole_groups['r_2_2'] = []
|
|
1390
|
+
self.rm.thin_shells.ts_pole_groups['r_1_1'] = [] # empty
|
|
1391
|
+
self.rm.thin_shells.ts_pole_groups['r_2_1'] = [] # empty
|
|
1392
|
+
|
|
1393
|
+
for key, tag in self.ins_type['poles'].items():
|
|
1394
|
+
alignment = key[-1] # either r or a aligned lines
|
|
1395
|
+
# find the corresponding half turn
|
|
1396
|
+
nr = key[1:key.index('_')]
|
|
1397
|
+
if nr.startswith('w'):
|
|
1398
|
+
# wedge to pole line
|
|
1399
|
+
for _, gr in self.md.domains.physical_groups.wedges.items():
|
|
1400
|
+
# for name, tag in gr.aux_lines.items():
|
|
1401
|
+
tag = gr.aux_lines.get(nr)
|
|
1402
|
+
if tag is not None:
|
|
1403
|
+
group = gr.group
|
|
1404
|
+
group = group[1] + '_' + str(1 + int(group[-1]) % 2)
|
|
1405
|
+
line_tag = self.ins_type['poles'][f'p{nr}_r'] # need to get the correct tag
|
|
1406
|
+
self.rm.thin_shells.ts_pole_groups['a_' + group].append(line_tag)
|
|
1407
|
+
|
|
1408
|
+
else:
|
|
1409
|
+
ht_nr = int(nr)
|
|
1410
|
+
for blk_nr, blk in self.md.domains.physical_groups.blocks.items(): # only need this for the outer layer :)
|
|
1411
|
+
el = blk.half_turns.get(ht_nr, None)
|
|
1412
|
+
if el is not None:
|
|
1413
|
+
break
|
|
1414
|
+
# alignment : direction of the normal vecetor
|
|
1415
|
+
if alignment == 'r': #### 2nd index is swapped -> radial difference (inner to outer)
|
|
1416
|
+
group = el.group[1] + '_' + str(
|
|
1417
|
+
1 + int(el.group[-1]) % 2) # group = el.group[1] + '_' + el.group[-1] #
|
|
1418
|
+
self.rm.thin_shells.ts_pole_groups['a_' + group].append(tag)
|
|
1419
|
+
elif alignment == 'a': #### 1st index is swapped -> azimuthal difference (left to right)
|
|
1420
|
+
group = str(1 + int(el.group[1]) % 2) + '_' + el.group[
|
|
1421
|
+
-1] # el.group[1] + '_' + el.group[-1] #
|
|
1422
|
+
self.rm.thin_shells.ts_pole_groups['r_' + group].append(tag)
|
|
1423
|
+
# save boundary line for the TSA
|
|
1424
|
+
tag = pg.poles.curves.get("bdry", None)
|
|
1425
|
+
if tag is not None:
|
|
1426
|
+
self.rm.thin_shells.bdry_curves['poles'] = [tag]
|
|
1427
|
+
|
|
926
1428
|
# Powered
|
|
927
1429
|
for blk_nr, blk in pg.blocks.items():
|
|
928
1430
|
ht_list = list(blk.half_turns.keys())
|
|
@@ -933,24 +1435,33 @@ class Mesh:
|
|
|
933
1435
|
self.rm.powered[ht.group].vol.numbers.append(ht.tag)
|
|
934
1436
|
if 'bore_field' in mesh.model_dump():
|
|
935
1437
|
self.rm.powered[ht.group].vol.currents.append(initial_current * (1 if blk.current_sign > 0 else -1))
|
|
1438
|
+
self.rm.powered[ht.group].curve.names.append(ht_name)
|
|
1439
|
+
self.rm.powered[ht.group].curve.numbers.append(ht.single_node)
|
|
1440
|
+
|
|
1441
|
+
for line in ['l', 'i', 'o', 'h']:
|
|
1442
|
+
# Bare edges
|
|
1443
|
+
self.rm.powered[ht.group].surf_in.names.append(ht_name + line)
|
|
1444
|
+
self.rm.powered[ht.group].surf_in.numbers.append(ht.lines[line])
|
|
1445
|
+
if line in 'io':
|
|
1446
|
+
self.rm.thin_shells.normals_directed['radially'].append(ht.lines[line])
|
|
1447
|
+
else:
|
|
1448
|
+
self.rm.thin_shells.normals_directed['azimuthally'].append(ht.lines[line])
|
|
1449
|
+
|
|
936
1450
|
if geometry.model_dump().get('use_TSA', False):
|
|
937
|
-
for line in ['l', 'i', 'o', 'h']:
|
|
938
|
-
# Bare edges
|
|
939
|
-
self.rm.powered[ht.group].surf_in.names.append(ht_name + line)
|
|
940
|
-
self.rm.powered[ht.group].surf_in.numbers.append(ht.lines[line])
|
|
941
|
-
if line in 'io': self.rm.thin_shells.normals_directed['radially'].append(ht.lines[line])
|
|
942
|
-
else: self.rm.thin_shells.normals_directed['azimuthally'].append(ht.lines[line])
|
|
943
1451
|
# Auxiliary thin shells
|
|
944
1452
|
for line_name, line_tag in ht.aux_lines.items():
|
|
945
|
-
|
|
946
|
-
|
|
1453
|
+
# update this must be _out instead of in to be not assigned to bare_layers_{i}_{j} in the .pro
|
|
1454
|
+
# (not used in my example, since ht.aux_lines is empty)
|
|
1455
|
+
self.rm.powered[ht.group].surf_out.names.append(line_name)
|
|
1456
|
+
self.rm.powered[ht.group].surf_out.numbers.append(line_tag)
|
|
947
1457
|
self.rm.thin_shells.normals_directed['radially'].append(line_tag)
|
|
948
1458
|
# Thin shells
|
|
949
1459
|
for line_name, line_tag in dict(ht.mid_layer_lines.inner, **ht.mid_layer_lines.outer).items():
|
|
950
1460
|
self.rm.powered[ht.group].surf_out.names.append(line_name)
|
|
951
1461
|
self.rm.powered[ht.group].surf_out.numbers.append(line_tag)
|
|
952
1462
|
self.rm.thin_shells.normals_directed['radially'].append(line_tag)
|
|
953
|
-
for line_name, line_tag in dict(ht.mid_pole_lines, **ht.mid_winding_lines,
|
|
1463
|
+
for line_name, line_tag in dict(ht.mid_pole_lines, **ht.mid_winding_lines,
|
|
1464
|
+
**ht.mid_turn_lines).items():
|
|
954
1465
|
self.rm.powered[ht.group].surf_out.names.append(line_name)
|
|
955
1466
|
self.rm.powered[ht.group].surf_out.numbers.append(line_tag)
|
|
956
1467
|
self.rm.thin_shells.normals_directed['azimuthally'].append(line_tag)
|
|
@@ -959,14 +1470,16 @@ class Mesh:
|
|
|
959
1470
|
if ht.group[1] == '2':
|
|
960
1471
|
# mid-turn thin shells precede r2
|
|
961
1472
|
for line_name, line_tag in ht.mid_turn_lines.items():
|
|
962
|
-
if (ht_list.index(ht_nr) != 0 and int(line_name[line_name.index('_') + 1:]) == ht_nr) or\
|
|
1473
|
+
if (ht_list.index(ht_nr) != 0 and int(line_name[line_name.index('_') + 1:]) == ht_nr) or \
|
|
963
1474
|
(ht_list.index(ht_nr) == 0 and 'w' in line_name):
|
|
964
1475
|
self.rm.thin_shells.second_group_is_next['azimuthally'].append(line_tag)
|
|
965
1476
|
# mid-pole thin shells precede r2
|
|
966
1477
|
if ht_list.index(ht_nr) == 0 and ht.mid_pole_lines:
|
|
967
|
-
self.rm.thin_shells.second_group_is_next['azimuthally'].append(
|
|
1478
|
+
self.rm.thin_shells.second_group_is_next['azimuthally'].append(
|
|
1479
|
+
list(ht.mid_pole_lines.values())[0])
|
|
968
1480
|
# conductor edges precede r2
|
|
969
|
-
elif ht_list.index(ht_nr) == 0 and len(ht.mid_turn_lines) + len(ht.mid_winding_lines) + len(
|
|
1481
|
+
elif ht_list.index(ht_nr) == 0 and len(ht.mid_turn_lines) + len(ht.mid_winding_lines) + len(
|
|
1482
|
+
ht.mid_pole_lines) == 1:
|
|
970
1483
|
self.rm.thin_shells.second_group_is_next['azimuthally'].append(ht.lines['l'])
|
|
971
1484
|
# mid-winding thin shells precede r2
|
|
972
1485
|
for line_name, line_tag in ht.mid_winding_lines.items():
|
|
@@ -998,19 +1511,22 @@ class Mesh:
|
|
|
998
1511
|
wdg_name = f"w{wdg_nr}_{'EM' if 'bore_field' in mesh.model_dump() else 'TH'}"
|
|
999
1512
|
self.rm.induced[wdg.group].vol.names.append(wdg_name)
|
|
1000
1513
|
self.rm.induced[wdg.group].vol.numbers.append(wdg.tag)
|
|
1514
|
+
for line in ['l', 'i', 'o', 'h']:
|
|
1515
|
+
self.rm.induced[wdg.group].surf_in.names.append(wdg_name + line)
|
|
1516
|
+
self.rm.induced[wdg.group].surf_in.numbers.append(wdg.lines[line])
|
|
1517
|
+
|
|
1001
1518
|
if geometry.model_dump().get('use_TSA', False):
|
|
1002
1519
|
# Bare edges
|
|
1003
1520
|
for line in ['l', 'i', 'o', 'h']:
|
|
1004
|
-
self.rm.induced[wdg.group].surf_in.names.append(wdg_name + line)
|
|
1005
|
-
self.rm.induced[wdg.group].surf_in.numbers.append(wdg.lines[line])
|
|
1006
1521
|
if line in 'io':
|
|
1007
1522
|
self.rm.thin_shells.normals_directed['radially'].append(wdg.lines[line])
|
|
1008
1523
|
else:
|
|
1009
1524
|
self.rm.thin_shells.normals_directed['azimuthally'].append(wdg.lines[line])
|
|
1010
1525
|
# Auxiliary thin shells
|
|
1011
1526
|
for line_name, line_tag in wdg.aux_lines.items():
|
|
1012
|
-
|
|
1013
|
-
self.rm.induced[wdg.group].
|
|
1527
|
+
# update this must be _out instead of in to be not assigned to bare_layers_{i}_{j} in the .pro
|
|
1528
|
+
self.rm.induced[wdg.group].surf_out.names.append(line_name)
|
|
1529
|
+
self.rm.induced[wdg.group].surf_out.numbers.append(line_tag)
|
|
1014
1530
|
self.rm.thin_shells.normals_directed['radially'].append(line_tag)
|
|
1015
1531
|
# Thin shells
|
|
1016
1532
|
for line_name, line_tag in dict(wdg.mid_layer_lines.inner, **wdg.mid_layer_lines.outer).items():
|
|
@@ -1045,20 +1561,29 @@ class Mesh:
|
|
|
1045
1561
|
self.rm.insulator.surf.names.append('ins' + group_name)
|
|
1046
1562
|
self.rm.insulator.surf.numbers.append(curve)
|
|
1047
1563
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1564
|
+
for attr in geometry.areas:
|
|
1565
|
+
for group_name, surface in getattr(pg, attr).surfaces.items():
|
|
1566
|
+
h = getattr(self.rm, attr).vol
|
|
1567
|
+
h.names.append(group_name)
|
|
1568
|
+
h.numbers.append(surface)
|
|
1569
|
+
|
|
1570
|
+
if self.data.magnet.mesh.thermal.reference.enabled:
|
|
1571
|
+
if not pg.ref_mesh.surfaces == {}:
|
|
1572
|
+
for name, num in pg.ref_mesh.surfaces.items():
|
|
1573
|
+
self.rm.ref_mesh.vol.names.append(name)
|
|
1574
|
+
self.rm.ref_mesh.vol.numbers.append(num)
|
|
1052
1575
|
|
|
1053
1576
|
# Boundary conditions
|
|
1054
1577
|
if 'insulation' in mesh.model_dump() and 'TSA' in mesh.model_dump()["insulation"]:
|
|
1055
1578
|
# Initialize lists
|
|
1056
|
-
for bc_data, bc_rm in zip(self.data.magnet.solve.thermal.overwrite_boundary_conditions,
|
|
1579
|
+
for bc_data, bc_rm in zip(self.data.magnet.solve.thermal.overwrite_boundary_conditions,
|
|
1580
|
+
self.rm.boundaries.thermal): # b.c. type
|
|
1057
1581
|
bc_rm[1].bc.names = []
|
|
1058
1582
|
bc_rm[1].bc.numbers = []
|
|
1059
1583
|
if bc_data[0] == 'cooling':
|
|
1060
1584
|
bc_rm[1].bc.values = []
|
|
1061
|
-
for group in ['1_r1_a1', '2_r1_a1', '1_r2_a1', '2_r2_a1', '1_r1_a2', '2_r1_a2', '1_r2_a2',
|
|
1585
|
+
for group in ['1_r1_a1', '2_r1_a1', '1_r2_a1', '2_r2_a1', '1_r1_a2', '2_r1_a2', '1_r2_a2',
|
|
1586
|
+
'2_r2_a2']:
|
|
1062
1587
|
bc_rm[1].groups[group] = []
|
|
1063
1588
|
else:
|
|
1064
1589
|
bc_rm[1].bc.value = []
|
|
@@ -1067,8 +1592,10 @@ class Mesh:
|
|
|
1067
1592
|
|
|
1068
1593
|
# Apply general cooling and adiabatic
|
|
1069
1594
|
if self.data.magnet.solve.thermal.He_cooling.enabled:
|
|
1070
|
-
cooling_side = {'i': any(coil_side in self.data.magnet.solve.thermal.He_cooling.sides for coil_side in
|
|
1071
|
-
|
|
1595
|
+
cooling_side = {'i': any(coil_side in self.data.magnet.solve.thermal.He_cooling.sides for coil_side in
|
|
1596
|
+
['inner', 'external']),
|
|
1597
|
+
'o': any(coil_side in self.data.magnet.solve.thermal.He_cooling.sides for coil_side in
|
|
1598
|
+
['outer', 'external']),
|
|
1072
1599
|
'hl': self.data.magnet.solve.thermal.He_cooling.sides == 'external'}
|
|
1073
1600
|
else:
|
|
1074
1601
|
cooling_side = {'i': False, 'o': False, 'hl': False}
|
|
@@ -1077,48 +1604,74 @@ class Mesh:
|
|
|
1077
1604
|
line_tag = tag if tag else el.lines[side]
|
|
1078
1605
|
bnd_list_names[bc_type].append(name + side)
|
|
1079
1606
|
bnd_list_numbers[bc_type].append(line_tag)
|
|
1080
|
-
if side in 'io':
|
|
1081
|
-
|
|
1607
|
+
if side in 'io':
|
|
1608
|
+
new_group = el.group[:3] + 'a1' if el.group[4] == '2' else el.group[:3] + 'a2'
|
|
1609
|
+
else:
|
|
1610
|
+
new_group = 'r1' + el.group[2:] if el.group[1] == '2' else 'r2' + el.group[2:]
|
|
1082
1611
|
bc_rm[bc_type].groups[new_group].append(line_tag)
|
|
1083
1612
|
for group_name, group in self.rm.thin_shells.groups.items():
|
|
1084
1613
|
if line_tag in group:
|
|
1085
1614
|
bc_rm[bc_type].groups[el.group[0] + '_' + new_group].append(line_tag)
|
|
1086
1615
|
break
|
|
1087
1616
|
|
|
1088
|
-
bc_rm = {'Robin': self.rm.boundaries.thermal.cooling, 'Neumann': self.rm.boundaries.thermal.heat_flux
|
|
1617
|
+
bc_rm = {'Robin': self.rm.boundaries.thermal.cooling, 'Neumann': self.rm.boundaries.thermal.heat_flux,
|
|
1618
|
+
'collar': self.rm.boundaries.thermal.collar}
|
|
1089
1619
|
bnd_list_names = {'Robin': [], 'Neumann': []}
|
|
1090
1620
|
bnd_list_numbers = {'Robin': [], 'Neumann': []}
|
|
1621
|
+
DISABLE_BNDRY_COND = False # debug: this should always be false
|
|
1091
1622
|
if geometry.model_dump().get('use_TSA', False):
|
|
1092
1623
|
# Half turn boundaries
|
|
1093
1624
|
for coil_nr, coil in self.md.geometries.coil.anticlockwise_order.coils.items():
|
|
1094
1625
|
for lyr_nr, orders in coil.layers.items():
|
|
1095
1626
|
for order in orders:
|
|
1096
1627
|
ht_list = list(pg.blocks[order.block].half_turns.keys())
|
|
1097
|
-
for ht_nr, ht in pg.blocks[
|
|
1628
|
+
for ht_nr, ht in pg.blocks[
|
|
1629
|
+
order.block].half_turns.items(): # apply bdry condition if no TSL
|
|
1098
1630
|
if not ht.mid_layer_lines.inner:
|
|
1099
|
-
__assign_bnd_tag(ht, 'ht' + str(ht_nr), 'i',
|
|
1631
|
+
__assign_bnd_tag(ht, 'ht' + str(ht_nr), 'i',
|
|
1632
|
+
'Robin' if cooling_side['i'] else 'Neumann')
|
|
1100
1633
|
if not ht.mid_layer_lines.outer:
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1634
|
+
if DISABLE_BNDRY_COND and self.data.magnet.geometry.thermal.use_TSA_new and \
|
|
1635
|
+
ht.group[4] == max_layer: # do not add new boundary condition:
|
|
1636
|
+
logger.warning("\033[93m DISABLING NEUMANN CONDITION")
|
|
1637
|
+
else:
|
|
1638
|
+
__assign_bnd_tag(ht, 'ht' + str(ht_nr), 'o',
|
|
1639
|
+
'Robin' if cooling_side['o'] else 'Neumann')
|
|
1640
|
+
if ht_list.index(ht_nr) == 0 and len(ht.mid_turn_lines) + len(
|
|
1641
|
+
ht.mid_winding_lines) + len(ht.mid_pole_lines) == 1:
|
|
1642
|
+
__assign_bnd_tag(ht, 'ht' + str(ht_nr), 'l',
|
|
1643
|
+
'Robin' if cooling_side['hl'] else 'Neumann')
|
|
1644
|
+
if ht_list.index(ht_nr) == len(ht_list) - 1 and len(ht.mid_turn_lines) + len(
|
|
1645
|
+
ht.mid_winding_lines) + len(ht.mid_pole_lines) == 1:
|
|
1646
|
+
__assign_bnd_tag(ht, 'ht' + str(ht_nr), 'h',
|
|
1647
|
+
'Robin' if cooling_side['hl'] else 'Neumann')
|
|
1106
1648
|
if ht.aux_lines:
|
|
1107
|
-
__assign_bnd_tag(ht, 'ht' + str(ht_nr), 'o',
|
|
1649
|
+
__assign_bnd_tag(ht, 'ht' + str(ht_nr), 'o',
|
|
1650
|
+
'Robin' if cooling_side['hl'] else 'Neumann',
|
|
1651
|
+
list(ht.aux_lines.values())[0])
|
|
1652
|
+
|
|
1108
1653
|
# Wedge boundaries
|
|
1109
1654
|
for wdg_nr, wdg in pg.wedges.items():
|
|
1110
1655
|
if not wdg.mid_layer_lines.inner:
|
|
1111
1656
|
__assign_bnd_tag(wdg, 'wd' + str(wdg_nr), 'i', 'Robin' if cooling_side['i'] else 'Neumann')
|
|
1112
1657
|
if not wdg.mid_layer_lines.outer:
|
|
1113
|
-
|
|
1658
|
+
if DISABLE_BNDRY_COND and self.data.magnet.geometry.thermal.use_TSA_new and wdg.group[
|
|
1659
|
+
4] == max_layer:
|
|
1660
|
+
logger.warning("\033[93m DISABLING NEUMANN CONDITION")
|
|
1661
|
+
else:
|
|
1662
|
+
__assign_bnd_tag(wdg, 'wd' + str(wdg_nr), 'o', 'Robin' if cooling_side['o'] else 'Neumann')
|
|
1114
1663
|
if wdg.aux_lines:
|
|
1115
|
-
__assign_bnd_tag(wdg, 'wd' + str(wdg_nr), 'o', 'Robin' if cooling_side['hl'] else 'Neumann',
|
|
1116
|
-
|
|
1664
|
+
__assign_bnd_tag(wdg, 'wd' + str(wdg_nr), 'o', 'Robin' if cooling_side['hl'] else 'Neumann',
|
|
1665
|
+
list(wdg.aux_lines.values())[0])
|
|
1666
|
+
|
|
1667
|
+
else: # insulation case, no TSA
|
|
1117
1668
|
for curves_group, tag in pg.insulations.curves.items():
|
|
1118
1669
|
if self.data.magnet.solve.thermal.He_cooling.enabled:
|
|
1119
|
-
if self.data.magnet.solve.thermal.He_cooling.sides == 'external':
|
|
1670
|
+
if self.data.magnet.solve.thermal.He_cooling.sides == 'external':
|
|
1671
|
+
bc_type = 'Robin'
|
|
1120
1672
|
else:
|
|
1121
|
-
raise ValueError(
|
|
1673
|
+
raise ValueError(
|
|
1674
|
+
f"Cooling side '{self.data.magnet.solve.thermal.He_cooling.sides}' is not supported for meshed insulation models.")
|
|
1122
1675
|
# bc_type = 'Robin' if (self.data.magnet.solve.thermal.He_cooling.sides == 'external' or
|
|
1123
1676
|
# ('inner' in self.data.magnet.solve.thermal.He_cooling.sides and curves_group[-1] == 'i') or
|
|
1124
1677
|
# ('outer' in self.data.magnet.solve.thermal.He_cooling.sides and curves_group[-1] == 'o')) else 'Neumann'
|
|
@@ -1126,22 +1679,33 @@ class Mesh:
|
|
|
1126
1679
|
bc_type = 'Neumann'
|
|
1127
1680
|
bnd_list_names[bc_type].append('ins' + curves_group)
|
|
1128
1681
|
bnd_list_numbers[bc_type].append(tag)
|
|
1682
|
+
|
|
1129
1683
|
if self.data.magnet.solve.thermal.He_cooling.enabled:
|
|
1130
1684
|
bc_rm['Robin'].bc.names.append(bnd_list_names['Robin'])
|
|
1131
1685
|
bc_rm['Robin'].bc.numbers.append(bnd_list_numbers['Robin'])
|
|
1132
1686
|
bc_rm['Robin'].bc.values.append([self.data.magnet.solve.thermal.He_cooling.heat_transfer_coefficient,
|
|
1133
1687
|
self.data.magnet.solve.thermal.init_temperature])
|
|
1688
|
+
|
|
1689
|
+
if self.data.magnet.solve.thermal.collar_cooling.enabled:
|
|
1690
|
+
cool = self.data.magnet.solve.thermal.collar_cooling
|
|
1691
|
+
bc_rm['collar'].bc.numbers = [pg.collar_cooling] # only one physical group for the collar cooling
|
|
1692
|
+
bc_rm['collar'].bc.values = [self.data.magnet.solve.thermal.collar_cooling.heat_transfer_coefficient,
|
|
1693
|
+
cool.ref_temperature if cool.ref_temperature is not None else self.data.magnet.solve.thermal.init_temperature] # [coef or functionname, inittemp]
|
|
1694
|
+
|
|
1695
|
+
# save the boundary names and numbers
|
|
1134
1696
|
if bnd_list_names['Neumann']:
|
|
1135
1697
|
bc_rm['Neumann'].bc.names.append(bnd_list_names['Neumann'])
|
|
1136
1698
|
bc_rm['Neumann'].bc.numbers.append(bnd_list_numbers['Neumann'])
|
|
1137
1699
|
bc_rm['Neumann'].bc.value.append(0.)
|
|
1138
1700
|
|
|
1139
1701
|
# Apply specific boundary conditions
|
|
1140
|
-
for bc_data, bc_rm in zip(self.data.magnet.solve.thermal.overwrite_boundary_conditions,
|
|
1702
|
+
for bc_data, bc_rm in zip(self.data.magnet.solve.thermal.overwrite_boundary_conditions,
|
|
1703
|
+
self.rm.boundaries.thermal): # b.c. type
|
|
1141
1704
|
# bc_data is a tuple like: ('temperature', {'const_T1': boundaries, value)})
|
|
1142
1705
|
# bc_rm is a tuple like: ('temperature', DirichletCondition(names, numbers, value))
|
|
1143
1706
|
|
|
1144
|
-
for _, bc in bc_data[
|
|
1707
|
+
for _, bc in bc_data[
|
|
1708
|
+
1].items(): # all boundary conditions of one b.c. type (e.g., Dirichlet with different temperatures)
|
|
1145
1709
|
bnd_list_names = []
|
|
1146
1710
|
bnd_list_numbers = []
|
|
1147
1711
|
if geometry.model_dump().get('use_TSA', False):
|
|
@@ -1193,17 +1757,17 @@ class Mesh:
|
|
|
1193
1757
|
bc_rm[1].bc.names.append(bnd_list_names)
|
|
1194
1758
|
bc_rm[1].bc.numbers.append(bnd_list_numbers)
|
|
1195
1759
|
if bc_data[0] == 'cooling':
|
|
1196
|
-
bc_rm[1].bc.values.append(
|
|
1760
|
+
bc_rm[1].bc.values.append(
|
|
1761
|
+
[bc.heat_transfer_coefficient, self.data.magnet.solve.thermal.init_temperature])
|
|
1197
1762
|
elif bc_data[0] == 'temperature':
|
|
1198
1763
|
bc_rm[1].bc.value.append(bc.const_temperature)
|
|
1199
1764
|
elif bc_data[0] == 'heat_flux':
|
|
1200
1765
|
bc_rm[1].bc.value.append(bc.const_heat_flux)
|
|
1201
1766
|
|
|
1202
|
-
def setMeshOptions(self
|
|
1767
|
+
def setMeshOptions(self):
|
|
1203
1768
|
"""
|
|
1204
1769
|
Meshes the generated domain
|
|
1205
1770
|
"""
|
|
1206
|
-
mesh = self.data.magnet.mesh
|
|
1207
1771
|
gmsh.option.setNumber("Mesh.MeshSizeExtendFromBoundary", 0)
|
|
1208
1772
|
gmsh.option.setNumber("Mesh.MeshSizeFromPoints", 0)
|
|
1209
1773
|
gmsh.option.setNumber("Mesh.MeshSizeFromCurvature", 0)
|
|
@@ -1227,14 +1791,6 @@ class Mesh:
|
|
|
1227
1791
|
self.mesh_parameters['Gamma'] = min(self.mesh.getElementQualities(elementTags=tags, qualityName='gamma'))
|
|
1228
1792
|
self.mesh_parameters['nodes'] = len(self.mesh.getNodes()[0])
|
|
1229
1793
|
|
|
1230
|
-
# gmsh.plugin.setNumber("AnalyseMeshQuality", "JacobianDeterminant", 1)
|
|
1231
|
-
# gmsh.plugin.setNumber("AnalyseMeshQuality", "CreateView", 100)
|
|
1232
|
-
# test = gmsh.plugin.run("AnalyseMeshQuality")
|
|
1233
|
-
# test2 = gmsh.view.getModelData(test, test)
|
|
1234
|
-
|
|
1235
|
-
# gmsh.logger.getLastError()
|
|
1236
|
-
# gmsh.logger.get()
|
|
1237
|
-
|
|
1238
1794
|
def saveClosestNeighboursList(self):
|
|
1239
1795
|
|
|
1240
1796
|
def _closest_node_on_reference(origin_points, reference_points):
|
|
@@ -1249,7 +1805,8 @@ class Mesh:
|
|
|
1249
1805
|
for x in range(0, len(origin_points), 3):
|
|
1250
1806
|
origin_point = origin_points[x:x + 3]
|
|
1251
1807
|
# Compute distance list between origin point and reference point list
|
|
1252
|
-
dist_lst = [Func.points_distance(origin_point, reference_points[y:y + 3]) for y in
|
|
1808
|
+
dist_lst = [Func.points_distance(origin_point, reference_points[y:y + 3]) for y in
|
|
1809
|
+
range(0, len(reference_points), 3)]
|
|
1253
1810
|
min_idx = 3 * np.argmin(dist_lst)
|
|
1254
1811
|
closest_node.append(origin_point + reference_points[min_idx:min_idx + 3])
|
|
1255
1812
|
return closest_node
|
|
@@ -1260,7 +1817,8 @@ class Mesh:
|
|
|
1260
1817
|
self.rc.neighbouring_nodes.groups[group].extend(
|
|
1261
1818
|
[node for node_list in _closest_node_on_reference(origin_list, reference_list) for node in node_list])
|
|
1262
1819
|
|
|
1263
|
-
logger.info(
|
|
1820
|
+
logger.info(
|
|
1821
|
+
f"Info : {self.data.general.magnet_name} - F i n d i n g C l o s e s t N e i g h b o u r s . . .")
|
|
1264
1822
|
logger.info(f"Info : Finding closest reference nodes ...")
|
|
1265
1823
|
|
|
1266
1824
|
self.rc.neighbouring_nodes.groups['1_1'] = []
|
|
@@ -1275,10 +1833,12 @@ class Mesh:
|
|
|
1275
1833
|
for line_name, mid_layer in el.mid_layer_lines.inner.items(): _get_closest_nodes('i')
|
|
1276
1834
|
for line_name, mid_layer in el.mid_layer_lines.outer.items(): _get_closest_nodes('o')
|
|
1277
1835
|
for line_name, mid_layer in el.aux_lines.items(): _get_closest_nodes('o')
|
|
1278
|
-
for line_name, mid_layer in el.mid_pole_lines.items(): _get_closest_nodes(
|
|
1279
|
-
|
|
1836
|
+
for line_name, mid_layer in el.mid_pole_lines.items(): _get_closest_nodes(
|
|
1837
|
+
'l' if ht_list.index(ht_nr) == 0 else 'h')
|
|
1838
|
+
for line_name, mid_layer in el.mid_winding_lines.items(): _get_closest_nodes(
|
|
1839
|
+
'l' if ht_list.index(ht_nr) == 0 else 'h')
|
|
1280
1840
|
for line_name, mid_layer in el.mid_turn_lines.items():
|
|
1281
|
-
high = ht_list.index(ht_nr) == len(ht_list) - 1 if 'w' in line_name\
|
|
1841
|
+
high = ht_list.index(ht_nr) == len(ht_list) - 1 if 'w' in line_name \
|
|
1282
1842
|
else int(line_name[:line_name.index('_')]) == ht_nr
|
|
1283
1843
|
_get_closest_nodes('h' if high else 'l')
|
|
1284
1844
|
for wdg_nr, el in self.md.domains.physical_groups.wedges.items():
|
|
@@ -1289,7 +1849,122 @@ class Mesh:
|
|
|
1289
1849
|
for line_name, mid_layer in el.mid_turn_lines.items():
|
|
1290
1850
|
_get_closest_nodes('l' if line_name == list(el.mid_turn_lines.keys())[0] else 'h')
|
|
1291
1851
|
|
|
1292
|
-
logger.info(
|
|
1852
|
+
logger.info(
|
|
1853
|
+
f"Info : {self.data.general.magnet_name} - E n d F i n d i n g C l o s e s t N e i g h b o u r s")
|
|
1854
|
+
|
|
1855
|
+
def saveClosestNeighboursList_new_TSA(self):
|
|
1856
|
+
def _closest_node_on_reference(origin_points, reference_points):
|
|
1857
|
+
closest_node = []
|
|
1858
|
+
for x in range(0, len(origin_points), 3):
|
|
1859
|
+
origin_point = origin_points[x:x + 3]
|
|
1860
|
+
# Compute distance list between origin point and reference point list
|
|
1861
|
+
dist_lst = [Func.points_distance(origin_point, reference_points[y:y + 3]) for y in
|
|
1862
|
+
range(0, len(reference_points), 3)]
|
|
1863
|
+
min_idx = 3 * np.argmin(dist_lst)
|
|
1864
|
+
closest_node.append(origin_point + reference_points[min_idx:min_idx + 3])
|
|
1865
|
+
if not closest_node:
|
|
1866
|
+
raise ValueError("No closest nodes found - check mesh and physical groups!")
|
|
1867
|
+
return closest_node
|
|
1868
|
+
|
|
1869
|
+
def _get_closest_nodes(name, reference_list, origin_list):
|
|
1870
|
+
self.rc.neighbouring_nodes.groups[name].extend(
|
|
1871
|
+
[node for node_list in _closest_node_on_reference(origin_list, reference_list) for node in node_list])
|
|
1872
|
+
|
|
1873
|
+
logger.info(
|
|
1874
|
+
f"Info : {self.data.general.magnet_name} - F i n d i n g C l o s e s t N e i g h b o u r s (new TSA) . . .")
|
|
1875
|
+
logger.info(f"Info : Finding closest reference nodes ...")
|
|
1876
|
+
|
|
1877
|
+
# two of these will always be empty, but depending on the layers it will either be a1 or a2
|
|
1878
|
+
self.rc.neighbouring_nodes.groups['mid2ht_1_1'] = []
|
|
1879
|
+
self.rc.neighbouring_nodes.groups['mid2ht_2_1'] = []
|
|
1880
|
+
self.rc.neighbouring_nodes.groups['mid2ht_1_2'] = []
|
|
1881
|
+
self.rc.neighbouring_nodes.groups['mid2ht_2_2'] = []
|
|
1882
|
+
# map coils to origin_list: start with outer layer of HT
|
|
1883
|
+
max_layer = len([k for k in self.md.geometries.coil.coils[1].poles[1].layers.keys()])
|
|
1884
|
+
|
|
1885
|
+
origin_all = [self.mesh.getNodesForPhysicalGroup(1, line)[1].tolist() for _, line in
|
|
1886
|
+
self.ins_type['collar'].items()]
|
|
1887
|
+
origin_all = [node for sublist in origin_all for node in sublist] # flatten the list
|
|
1888
|
+
|
|
1889
|
+
for blk_nr, blk in self.md.domains.physical_groups.blocks.items():
|
|
1890
|
+
for ht_nr, el in blk.half_turns.items():
|
|
1891
|
+
if str(el.group[-1]) == str(max_layer):
|
|
1892
|
+
group = el.group[1] + '_' + str((1 + int(el.group[-1])) % 2) # e.g. 1_2
|
|
1893
|
+
origin = self.mesh.getNodesForPhysicalGroup(1, self.ins_type['collar'][str(ht_nr) + '_x'])[
|
|
1894
|
+
1].tolist()
|
|
1895
|
+
ref_list = np.array(self.mesh.getNodesForPhysicalGroup(1, el.lines['o'])[1]).tolist()
|
|
1896
|
+
_get_closest_nodes(reference_list=ref_list, name=f'mid2ht_{group}', origin_list=origin)
|
|
1897
|
+
# collar mid
|
|
1898
|
+
self.rc.neighbouring_nodes.groups['mid2col'] = []
|
|
1899
|
+
ref = np.array(self.mesh.getNodesForPhysicalGroup(1, self.md.domains.physical_groups.inner_col)[1]).tolist()
|
|
1900
|
+
_get_closest_nodes(reference_list=ref, origin_list=origin_all, name='mid2col')
|
|
1901
|
+
# collar wedges
|
|
1902
|
+
for wdg_nr, el in self.md.domains.physical_groups.wedges.items(): ## one can conveniently add the wedges to the mid2ht groups
|
|
1903
|
+
if str(el.group[-1]) == str(max_layer):
|
|
1904
|
+
group = el.group[1] + '_' + str((1 + int(el.group[-1])) % 2)
|
|
1905
|
+
origin = self.mesh.getNodesForPhysicalGroup(1, self.ins_type['collar']['w' + str(wdg_nr) + '_x'])[
|
|
1906
|
+
1].tolist()
|
|
1907
|
+
ref_list = np.array(self.mesh.getNodesForPhysicalGroup(1, el.lines['o'])[1]).tolist()
|
|
1908
|
+
_get_closest_nodes(reference_list=ref_list, name=f'mid2ht_{group}', origin_list=origin)
|
|
1909
|
+
|
|
1910
|
+
# POLES
|
|
1911
|
+
self.rc.neighbouring_nodes.groups['pole_mid2ht_1_2'] = []
|
|
1912
|
+
self.rc.neighbouring_nodes.groups['pole_mid2ht_1_1'] = []
|
|
1913
|
+
self.rc.neighbouring_nodes.groups['pole_mid2ht_2_1'] = []
|
|
1914
|
+
self.rc.neighbouring_nodes.groups['pole_mid2ht_2_2'] = []
|
|
1915
|
+
self.rc.neighbouring_nodes.groups['mid2pol'] = []
|
|
1916
|
+
# TSA lines to poles
|
|
1917
|
+
for tsl_name in self.ins_type['poles'].keys():
|
|
1918
|
+
# first half: mid2ht (also mid2wedge)
|
|
1919
|
+
nr = tsl_name[1:tsl_name.index('_')]
|
|
1920
|
+
origin = self.mesh.getNodesForPhysicalGroup(1, self.ins_type['poles'][tsl_name])[1].tolist()
|
|
1921
|
+
if nr.startswith('w'): # this is a mid2wedge
|
|
1922
|
+
ref_list = None
|
|
1923
|
+
for i, gr in self.md.domains.physical_groups.wedges.items():
|
|
1924
|
+
# for name, tag in gr.aux_lines.items():
|
|
1925
|
+
tag = gr.aux_lines.get(nr)
|
|
1926
|
+
if tag is not None: # should only be one
|
|
1927
|
+
ref_list = self.mesh.getNodesForPhysicalGroup(1, tag)[1]
|
|
1928
|
+
ref_list = [float(x) for x in ref_list]
|
|
1929
|
+
break
|
|
1930
|
+
# alignment is always the same here, for naming later
|
|
1931
|
+
group = gr.group
|
|
1932
|
+
group = group[1] + '_' + str(1 + int(group[-1]) % 2)
|
|
1933
|
+
else:
|
|
1934
|
+
ht_nr = int(nr) # e.g. p1_a and p12_a -> 1 and 12
|
|
1935
|
+
alignment = tsl_name[-1]
|
|
1936
|
+
# reference can be the nodes from the half turn, we don't have to specify the line
|
|
1937
|
+
for blk in self.md.domains.physical_groups.blocks.values():
|
|
1938
|
+
el = blk.half_turns.get(ht_nr, None)
|
|
1939
|
+
if el is not None:
|
|
1940
|
+
ref_list = []
|
|
1941
|
+
[ref_list.extend(self.mesh.getNodesForPhysicalGroup(1, line)[1]) for line in el.lines.values()]
|
|
1942
|
+
ref_list = [float(x) for x in ref_list]
|
|
1943
|
+
break
|
|
1944
|
+
# alignment : direction of the normal vector, for naming
|
|
1945
|
+
if alignment == 'r':
|
|
1946
|
+
# group = el.group[1] + '_' + el.group[-1]
|
|
1947
|
+
group = el.group[1] + '_' + str(1 + int(el.group[-1]) % 2)
|
|
1948
|
+
elif alignment == 'a':
|
|
1949
|
+
# group = el.group[1] + '_' + el.group[-1]
|
|
1950
|
+
group = str(1 + int(el.group[1]) % 2) + '_' + el.group[-1]
|
|
1951
|
+
_get_closest_nodes(reference_list=ref_list, name=f'pole_mid2ht_{group}', origin_list=origin)
|
|
1952
|
+
|
|
1953
|
+
# second half: mid2pole
|
|
1954
|
+
origin = [float(x) for x in
|
|
1955
|
+
self.mesh.getNodesForPhysicalGroup(1, self.ins_type['poles'][tsl_name])[1].tolist()]
|
|
1956
|
+
pole_bdry = self.md.domains.physical_groups.poles.curves.get("bdry", None)
|
|
1957
|
+
###ref_list = [float(x) for x in self.mesh.getNodesForPhysicalGroup(2, self.md.domains.physical_groups.poles.surfaces['SS'])[1].tolist()]
|
|
1958
|
+
ref_list = [float(x) for x in self.mesh.getNodesForPhysicalGroup(1, pole_bdry)[1].tolist()]
|
|
1959
|
+
# just use all the nodes
|
|
1960
|
+
# todo: this can be optimized by selecting only the boundary of the pole
|
|
1961
|
+
_get_closest_nodes(reference_list=ref_list, name=f'mid2pol', origin_list=origin)
|
|
1962
|
+
|
|
1963
|
+
logger.info(
|
|
1964
|
+
f"Info : {self.data.general.magnet_name} - E n d F i n d i n g C l o s e s t N e i g h b o u r s (new TSA)")
|
|
1965
|
+
|
|
1966
|
+
def saveHalfTurnCornerPositions(self):
|
|
1967
|
+
with open(f"{self.geom_files}.crns", 'r') as f: self.rc.coordinates_per_half_turn = json.load(f)
|
|
1293
1968
|
|
|
1294
1969
|
def selectMeshNodes(self, elements: str):
|
|
1295
1970
|
|