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.
Files changed (42) hide show
  1. fiqus/MainFiQuS.py +1 -8
  2. fiqus/data/DataConductor.py +4 -8
  3. fiqus/data/DataFiQuSMultipole.py +358 -167
  4. fiqus/data/DataModelCommon.py +30 -15
  5. fiqus/data/DataMultipole.py +33 -10
  6. fiqus/data/DataWindingsCCT.py +37 -37
  7. fiqus/data/RegionsModelFiQuS.py +1 -1
  8. fiqus/geom_generators/GeometryMultipole.py +751 -54
  9. fiqus/getdp_runners/RunGetdpMultipole.py +181 -31
  10. fiqus/mains/MainMultipole.py +109 -17
  11. fiqus/mesh_generators/MeshCCT.py +209 -209
  12. fiqus/mesh_generators/MeshMultipole.py +938 -263
  13. fiqus/parsers/ParserCOND.py +2 -1
  14. fiqus/parsers/ParserDAT.py +16 -16
  15. fiqus/parsers/ParserGetDPOnSection.py +212 -212
  16. fiqus/parsers/ParserGetDPTimeTable.py +134 -134
  17. fiqus/parsers/ParserMSH.py +53 -53
  18. fiqus/parsers/ParserRES.py +142 -142
  19. fiqus/plotters/PlotPythonCCT.py +133 -133
  20. fiqus/plotters/PlotPythonMultipole.py +18 -18
  21. fiqus/post_processors/PostProcessMultipole.py +16 -6
  22. fiqus/pre_processors/PreProcessCCT.py +175 -175
  23. fiqus/pro_assemblers/ProAssembler.py +3 -3
  24. fiqus/pro_material_functions/ironBHcurves.pro +246 -246
  25. fiqus/pro_templates/combined/CC_Module.pro +1213 -0
  26. fiqus/pro_templates/combined/ConductorAC_template.pro +1025 -0
  27. fiqus/pro_templates/combined/Multipole_template.pro +2738 -1338
  28. fiqus/pro_templates/combined/TSA_materials.pro +102 -2
  29. fiqus/pro_templates/combined/materials.pro +54 -3
  30. fiqus/utils/Utils.py +18 -25
  31. fiqus/utils/update_data_settings.py +1 -1
  32. {fiqus-2026.1.0.dist-info → fiqus-2026.1.2.dist-info}/METADATA +64 -68
  33. {fiqus-2026.1.0.dist-info → fiqus-2026.1.2.dist-info}/RECORD +42 -40
  34. {fiqus-2026.1.0.dist-info → fiqus-2026.1.2.dist-info}/WHEEL +1 -1
  35. tests/test_geometry_generators.py +29 -32
  36. tests/test_mesh_generators.py +35 -34
  37. tests/test_solvers.py +32 -31
  38. tests/utils/fiqus_test_classes.py +396 -147
  39. tests/utils/generate_reference_files_ConductorAC.py +57 -57
  40. tests/utils/helpers.py +76 -1
  41. {fiqus-2026.1.0.dist-info → fiqus-2026.1.2.dist-info}/LICENSE.txt +0 -0
  42. {fiqus-2026.1.0.dist-info → fiqus-2026.1.2.dist-info}/top_level.txt +0 -0
@@ -1,209 +1,209 @@
1
- import math
2
- import os
3
- import timeit
4
- import json
5
- from typing import List, Any
6
- from pathlib import Path
7
-
8
- import gmsh
9
- import numpy as np
10
- from fiqus.utils.Utils import FilesAndFolders as uff
11
- from fiqus.utils.Utils import GmshUtils
12
- from fiqus.data.DataWindingsCCT import WindingsInformation # for volume information
13
- from fiqus.data.RegionsModelFiQuS import RegionsModel
14
-
15
-
16
- class Mesh:
17
- def __init__(self, fdm, verbose=True):
18
- """
19
- Class to preparing brep files by adding terminals.
20
- :param fdm: FiQuS data model
21
- :param verbose: If True more information is printed in python console.
22
- """
23
- self.cctdm = fdm.magnet
24
- self.model_folder = os.path.join(os.getcwd())
25
- self.magnet_name = fdm.general.magnet_name
26
-
27
- self.geom_folder = Path(self.model_folder).parent
28
-
29
- self.verbose = verbose
30
- regions_file = os.path.join(self.geom_folder, f'{self.magnet_name}.regions')
31
- self.cctrm = uff.read_data_from_yaml(regions_file, RegionsModel)
32
- winding_info_file = os.path.join(self.geom_folder, f'{self.magnet_name}.wi')
33
- self.cctwi = uff.read_data_from_yaml(winding_info_file, WindingsInformation)
34
- self.gu = GmshUtils(self.model_folder, self.verbose)
35
- self.gu.initialize()
36
- self.model_file = f"{os.path.join(self.model_folder, self.magnet_name)}.msh"
37
- self.formers = []
38
- self.powered_vols = []
39
- self.air_boundary_tags = []
40
-
41
- def _find_surf(self, volume_tag):
42
- for surf in gmsh.model.getBoundary([(3, volume_tag)], oriented=False):
43
- _, _, zmin, _, _, zmax = gmsh.model.occ.getBoundingBox(*surf)
44
- z = (zmin + zmax) / 2
45
- if math.isclose(z, self.cctdm.geometry.air.z_min, rel_tol=1e-5) or math.isclose(z, self.cctdm.geometry.air.z_max, rel_tol=1e-5):
46
- return surf[1]
47
-
48
- def generate_physical_groups(self, gui=False):
49
- if self.verbose:
50
- print('Generating Physical Groups Started')
51
- start_time = timeit.default_timer()
52
- r_types = ['w' for _ in self.cctwi.w_names] + ['f' for _ in self.cctwi.f_names] # needed for picking different pow_surf later on
53
- vol_max_loop = 0
54
-
55
- for i, (f_name, r_type, r_name, r_tag) in enumerate(zip(self.cctwi.w_names + self.cctwi.f_names, r_types, self.cctrm.powered['cct'].vol.names, self.cctrm.powered['cct'].vol.numbers)):
56
- vol_dict = json.load(open(f"{os.path.join(self.geom_folder, f_name)}.vi"))
57
- volumes_file = np.array(vol_dict['all'])
58
- vol_max_file = np.max(volumes_file)
59
- vols_to_use = volumes_file + vol_max_loop
60
- v_tags = (list(map(int, vols_to_use)))
61
- vol_max_loop = vol_max_file + vol_max_loop
62
- self.powered_vols.extend(v_tags) # used later for meshing
63
- gmsh.model.addPhysicalGroup(dim=3, tags=v_tags, tag=r_tag)
64
- gmsh.model.setPhysicalName(dim=3, tag=r_tag, name=r_name)
65
- powered_in_surf = self._find_surf(v_tags[0])
66
- gmsh.model.addPhysicalGroup(dim=2, tags=[powered_in_surf], tag=self.cctrm.powered['cct'].surf_in.numbers[i])
67
- gmsh.model.setPhysicalName(dim=2, tag=self.cctrm.powered['cct'].surf_in.numbers[i], name=self.cctrm.powered['cct'].surf_in.names[i])
68
- powered_out_surf = self._find_surf(v_tags[-1])
69
- gmsh.model.addPhysicalGroup(dim=2, tags=[powered_out_surf], tag=self.cctrm.powered['cct'].surf_out.numbers[i])
70
- gmsh.model.setPhysicalName(dim=2, tag=self.cctrm.powered['cct'].surf_out.numbers[i], name=self.cctrm.powered['cct'].surf_out.names[i])
71
-
72
- vol_max_loop = v_tags[-1]
73
-
74
- for r_name, r_tag in zip(self.cctrm.induced['cct'].vol.names, self.cctrm.induced['cct'].vol.numbers):
75
- vol_max_loop += 1
76
- self.formers.append(vol_max_loop)
77
- gmsh.model.addPhysicalGroup(dim=3, tags=[vol_max_loop], tag=r_tag)
78
- gmsh.model.setPhysicalName(dim=3, tag=r_tag, name=r_name)
79
-
80
- vol_max_loop += 1
81
- gmsh.model.addPhysicalGroup(dim=3, tags=[vol_max_loop], tag=self.cctrm.air.vol.number)
82
- gmsh.model.setPhysicalName(dim=3, tag=self.cctrm.air.vol.number, name=self.cctrm.air.vol.name)
83
- abt = gmsh.model.getEntities(2)[-3:]
84
- self.air_boundary_tags = [surf[1] for surf in abt]
85
- gmsh.model.addPhysicalGroup(dim=2, tags=self.air_boundary_tags, tag=self.cctrm.air.surf.number)
86
- gmsh.model.setPhysicalName(dim=2, tag=self.cctrm.air.surf.number, name=self.cctrm.air.surf.name)
87
-
88
- # air_line_tags = []
89
- # for air_boundary_tag in self.air_boundary_tags:
90
- # air_line_tags.extend(gmsh.model.getBoundary([(2, air_boundary_tag)], oriented=False)[1])
91
- # self.air_center_line_tags = [int(np.max(air_line_tags) + 1)] # this assumes that the above found the lines of air boundary but not the one in the middle that is just with the subsequent tag
92
- # gmsh.model.addPhysicalGroup(dim=1, tags=self.air_center_line_tags, tag=self.cctrm.air.line.number)
93
- # gmsh.model.setPhysicalName(dim=1, tag=self.cctrm.air.line.number, name=self.cctrm.air.line.name)
94
-
95
- gmsh.model.occ.synchronize()
96
- if gui:
97
- self.gu.launch_interactive_GUI()
98
- if self.verbose:
99
- print(f'Generating Physical Groups Took {timeit.default_timer() - start_time:.2f} s')
100
-
101
- def generate_mesh(self, gui=False):
102
- if self.verbose:
103
- print('Generating Mesh Started')
104
- start_time = timeit.default_timer()
105
- # gmsh.option.setNumber("Mesh.AngleToleranceFacetOverlap", 0.01)
106
- gmsh.option.setNumber("Mesh.Algorithm", 5)
107
- gmsh.option.setNumber("Mesh.Algorithm3D", 10)
108
- gmsh.option.setNumber("Mesh.AllowSwapAngle", 20)
109
- line_tags_transfinite = []
110
- num_div_transfinite = []
111
- line_tags_mesh: List[Any] = []
112
- point_tags_mesh = []
113
- for vol_tag in self.powered_vols:
114
- vol_surf_tags = gmsh.model.getAdjacencies(3, vol_tag)[1]
115
- for surf_tag in vol_surf_tags:
116
- line_tags = gmsh.model.getAdjacencies(2, surf_tag)[1]
117
- # line_tags_mesh.extend(line_tags)
118
- line_lengths = []
119
- for line_tag in line_tags:
120
- point_tags = gmsh.model.getAdjacencies(1, line_tag)[1]
121
- if line_tag not in line_tags_mesh:
122
- line_tags_mesh.append(line_tag)
123
- x = []
124
- y = []
125
- z = []
126
- for p, point_tag in enumerate(point_tags):
127
- xmin, ymin, zmin, xmax, ymax, zmax = gmsh.model.occ.getBoundingBox(0, point_tag)
128
- x.append((xmin + xmax) / 2)
129
- y.append((ymin + ymax) / 2)
130
- z.append((zmin + zmax) / 2)
131
- if point_tag not in point_tags_mesh:
132
- point_tags_mesh.append(point_tag)
133
- line_lengths.append(math.sqrt((x[0] - x[1]) ** 2 + (y[0] - y[1]) ** 2 + (z[0] - z[1]) ** 2))
134
- # num_div = math.ceil(dist / self.cctdm.mesh_generators.MeshSizeWindings) + 1
135
- l_length_min = np.min(line_lengths)
136
- for line_tag, l_length in zip(line_tags, line_lengths):
137
- aspect = l_length / l_length_min
138
- if aspect > self.cctdm.mesh.MaxAspectWindings:
139
- num_div = math.ceil(l_length / (l_length_min * self.cctdm.mesh.MaxAspectWindings)) + 1
140
- if line_tag in line_tags_transfinite:
141
- idx = line_tags_transfinite.index(line_tag)
142
- num_div_set = num_div_transfinite[idx]
143
- if num_div_set < num_div:
144
- num_div_transfinite[idx] = num_div
145
- else:
146
- line_tags_transfinite.append(line_tag)
147
- num_div_transfinite.append(num_div)
148
- for line_tag, num_div in zip(line_tags_transfinite, num_div_transfinite):
149
- gmsh.model.mesh.setTransfiniteCurve(line_tag, num_div)
150
-
151
- gmsh.model.setColor([(1, i) for i in line_tags_mesh], 255, 0, 0) # , recursive=True) # Red
152
-
153
- # gmsh.model.mesh.setTransfiniteCurve(self.air_center_line_tags[0], 15)
154
- # gmsh.model.setColor([(1, i) for i in self.air_center_line_tags], 0, 0, 0)
155
-
156
- sld = gmsh.model.mesh.field.add("Distance") # straight line distance
157
- gmsh.model.mesh.field.setNumbers(sld, "CurvesList", line_tags_mesh)
158
- # gmsh.model.mesh_generators.field.setNumbers(1, "PointsList", point_tags_mesh)
159
- gmsh.model.mesh.field.setNumber(sld, "Sampling", 100)
160
- slt = gmsh.model.mesh.field.add("Threshold") # straight line threshold
161
- gmsh.model.mesh.field.setNumber(slt, "InField", sld)
162
- gmsh.model.mesh.field.setNumber(slt, "SizeMin", self.cctdm.mesh.ThresholdSizeMin)
163
- gmsh.model.mesh.field.setNumber(slt, "SizeMax", self.cctdm.mesh.ThresholdSizeMax)
164
- gmsh.model.mesh.field.setNumber(slt, "DistMin", self.cctdm.mesh.ThresholdDistMin)
165
- gmsh.model.mesh.field.setNumber(slt, "DistMax", self.cctdm.mesh.ThresholdDistMax)
166
- # gmsh.model.mesh_generators.field.add("Min", 7)
167
- # gmsh.model.mesh_generators.field.setNumbers(7, "FieldsList", [slt])
168
- gmsh.model.mesh.field.setAsBackgroundMesh(slt)
169
- gmsh.option.setNumber("Mesh.MeshSizeFromCurvature", 0)
170
- gmsh.option.setNumber("Mesh.MeshSizeFromPoints", 0)
171
- gmsh.option.setNumber("Mesh.MeshSizeExtendFromBoundary", 0)
172
- gmsh.option.setNumber("Mesh.OptimizeNetgen", 0)
173
- gmsh.model.mesh.generate(3)
174
- if self.verbose:
175
- print(f'Generating Mesh Took {timeit.default_timer() - start_time:.2f} s')
176
- if gui:
177
- self.gu.launch_interactive_GUI()
178
-
179
- def generate_cuts(self, gui=False):
180
- if self.verbose:
181
- print('Generating Cuts Started')
182
- start_time = timeit.default_timer()
183
- for vol, surf_in, surf_out in zip(self.cctrm.powered['cct'].vol.numbers, self.cctrm.powered['cct'].surf_in.numbers, self.cctrm.powered['cct'].surf_out.numbers):
184
- gmsh.model.mesh.addHomologyRequest("Cohomology", domainTags=[vol], subdomainTags=[surf_in, surf_out], dims=[1, 2, 3])
185
- for vol in self.cctrm.induced['cct'].vol.numbers:
186
- gmsh.model.mesh.addHomologyRequest("Cohomology", domainTags=[vol], dims=[1, 2, 3])
187
- gmsh.model.mesh.computeHomology()
188
- if self.verbose:
189
- print(f'Generating Cuts Took {timeit.default_timer() - start_time:.2f} s')
190
- if gui:
191
- self.gu.launch_interactive_GUI()
192
-
193
- def save_mesh(self, gui=False):
194
- if self.verbose:
195
- print('Saving Mesh Started')
196
- start_time = timeit.default_timer()
197
- gmsh.write(self.model_file)
198
- if self.verbose:
199
- print(f'Saving Mesh Took {timeit.default_timer() - start_time:.2f} s')
200
- if gui:
201
- self.gu.launch_interactive_GUI()
202
- else:
203
- gmsh.clear()
204
- gmsh.finalize()
205
-
206
- def load_mesh(self, gui=False):
207
- gmsh.open(self.model_file)
208
- if gui:
209
- self.gu.launch_interactive_GUI()
1
+ import math
2
+ import os
3
+ import timeit
4
+ import json
5
+ from typing import List, Any
6
+ from pathlib import Path
7
+
8
+ import gmsh
9
+ import numpy as np
10
+ from fiqus.utils.Utils import FilesAndFolders as uff
11
+ from fiqus.utils.Utils import GmshUtils
12
+ from fiqus.data.DataWindingsCCT import WindingsInformation # for volume information
13
+ from fiqus.data.RegionsModelFiQuS import RegionsModel
14
+
15
+
16
+ class Mesh:
17
+ def __init__(self, fdm, verbose=True):
18
+ """
19
+ Class to preparing brep files by adding terminals.
20
+ :param fdm: FiQuS data model
21
+ :param verbose: If True more information is printed in python console.
22
+ """
23
+ self.cctdm = fdm.magnet
24
+ self.model_folder = os.path.join(os.getcwd())
25
+ self.magnet_name = fdm.general.magnet_name
26
+
27
+ self.geom_folder = Path(self.model_folder).parent
28
+
29
+ self.verbose = verbose
30
+ regions_file = os.path.join(self.geom_folder, f'{self.magnet_name}.regions')
31
+ self.cctrm = uff.read_data_from_yaml(regions_file, RegionsModel)
32
+ winding_info_file = os.path.join(self.geom_folder, f'{self.magnet_name}.wi')
33
+ self.cctwi = uff.read_data_from_yaml(winding_info_file, WindingsInformation)
34
+ self.gu = GmshUtils(self.model_folder, self.verbose)
35
+ self.gu.initialize()
36
+ self.model_file = f"{os.path.join(self.model_folder, self.magnet_name)}.msh"
37
+ self.formers = []
38
+ self.powered_vols = []
39
+ self.air_boundary_tags = []
40
+
41
+ def _find_surf(self, volume_tag):
42
+ for surf in gmsh.model.getBoundary([(3, volume_tag)], oriented=False):
43
+ _, _, zmin, _, _, zmax = gmsh.model.occ.getBoundingBox(*surf)
44
+ z = (zmin + zmax) / 2
45
+ if math.isclose(z, self.cctdm.geometry.air.z_min, rel_tol=1e-5) or math.isclose(z, self.cctdm.geometry.air.z_max, rel_tol=1e-5):
46
+ return surf[1]
47
+
48
+ def generate_physical_groups(self, gui=False):
49
+ if self.verbose:
50
+ print('Generating Physical Groups Started')
51
+ start_time = timeit.default_timer()
52
+ r_types = ['w' for _ in self.cctwi.w_names] + ['f' for _ in self.cctwi.f_names] # needed for picking different pow_surf later on
53
+ vol_max_loop = 0
54
+
55
+ for i, (f_name, r_type, r_name, r_tag) in enumerate(zip(self.cctwi.w_names + self.cctwi.f_names, r_types, self.cctrm.powered['cct'].vol.names, self.cctrm.powered['cct'].vol.numbers)):
56
+ vol_dict = json.load(open(f"{os.path.join(self.geom_folder, f_name)}.vi"))
57
+ volumes_file = np.array(vol_dict['all'])
58
+ vol_max_file = np.max(volumes_file)
59
+ vols_to_use = volumes_file + vol_max_loop
60
+ v_tags = (list(map(int, vols_to_use)))
61
+ vol_max_loop = vol_max_file + vol_max_loop
62
+ self.powered_vols.extend(v_tags) # used later for meshing
63
+ gmsh.model.addPhysicalGroup(dim=3, tags=v_tags, tag=r_tag)
64
+ gmsh.model.setPhysicalName(dim=3, tag=r_tag, name=r_name)
65
+ powered_in_surf = self._find_surf(v_tags[0])
66
+ gmsh.model.addPhysicalGroup(dim=2, tags=[powered_in_surf], tag=self.cctrm.powered['cct'].surf_in.numbers[i])
67
+ gmsh.model.setPhysicalName(dim=2, tag=self.cctrm.powered['cct'].surf_in.numbers[i], name=self.cctrm.powered['cct'].surf_in.names[i])
68
+ powered_out_surf = self._find_surf(v_tags[-1])
69
+ gmsh.model.addPhysicalGroup(dim=2, tags=[powered_out_surf], tag=self.cctrm.powered['cct'].surf_out.numbers[i])
70
+ gmsh.model.setPhysicalName(dim=2, tag=self.cctrm.powered['cct'].surf_out.numbers[i], name=self.cctrm.powered['cct'].surf_out.names[i])
71
+
72
+ vol_max_loop = v_tags[-1]
73
+
74
+ for r_name, r_tag in zip(self.cctrm.induced['cct'].vol.names, self.cctrm.induced['cct'].vol.numbers):
75
+ vol_max_loop += 1
76
+ self.formers.append(vol_max_loop)
77
+ gmsh.model.addPhysicalGroup(dim=3, tags=[vol_max_loop], tag=r_tag)
78
+ gmsh.model.setPhysicalName(dim=3, tag=r_tag, name=r_name)
79
+
80
+ vol_max_loop += 1
81
+ gmsh.model.addPhysicalGroup(dim=3, tags=[vol_max_loop], tag=self.cctrm.air.vol.number)
82
+ gmsh.model.setPhysicalName(dim=3, tag=self.cctrm.air.vol.number, name=self.cctrm.air.vol.name)
83
+ abt = gmsh.model.getEntities(2)[-3:]
84
+ self.air_boundary_tags = [surf[1] for surf in abt]
85
+ gmsh.model.addPhysicalGroup(dim=2, tags=self.air_boundary_tags, tag=self.cctrm.air.surf.number)
86
+ gmsh.model.setPhysicalName(dim=2, tag=self.cctrm.air.surf.number, name=self.cctrm.air.surf.name)
87
+
88
+ # air_line_tags = []
89
+ # for air_boundary_tag in self.air_boundary_tags:
90
+ # air_line_tags.extend(gmsh.model.getBoundary([(2, air_boundary_tag)], oriented=False)[1])
91
+ # self.air_center_line_tags = [int(np.max(air_line_tags) + 1)] # this assumes that the above found the lines of air boundary but not the one in the middle that is just with the subsequent tag
92
+ # gmsh.model.addPhysicalGroup(dim=1, tags=self.air_center_line_tags, tag=self.cctrm.air.line.number)
93
+ # gmsh.model.setPhysicalName(dim=1, tag=self.cctrm.air.line.number, name=self.cctrm.air.line.name)
94
+
95
+ gmsh.model.occ.synchronize()
96
+ if gui:
97
+ self.gu.launch_interactive_GUI()
98
+ if self.verbose:
99
+ print(f'Generating Physical Groups Took {timeit.default_timer() - start_time:.2f} s')
100
+
101
+ def generate_mesh(self, gui=False):
102
+ if self.verbose:
103
+ print('Generating Mesh Started')
104
+ start_time = timeit.default_timer()
105
+ # gmsh.option.setNumber("Mesh.AngleToleranceFacetOverlap", 0.01)
106
+ gmsh.option.setNumber("Mesh.Algorithm", 5)
107
+ gmsh.option.setNumber("Mesh.Algorithm3D", 10)
108
+ gmsh.option.setNumber("Mesh.AllowSwapAngle", 20)
109
+ line_tags_transfinite = []
110
+ num_div_transfinite = []
111
+ line_tags_mesh: List[Any] = []
112
+ point_tags_mesh = []
113
+ for vol_tag in self.powered_vols:
114
+ vol_surf_tags = gmsh.model.getAdjacencies(3, vol_tag)[1]
115
+ for surf_tag in vol_surf_tags:
116
+ line_tags = gmsh.model.getAdjacencies(2, surf_tag)[1]
117
+ # line_tags_mesh.extend(line_tags)
118
+ line_lengths = []
119
+ for line_tag in line_tags:
120
+ point_tags = gmsh.model.getAdjacencies(1, line_tag)[1]
121
+ if line_tag not in line_tags_mesh:
122
+ line_tags_mesh.append(line_tag)
123
+ x = []
124
+ y = []
125
+ z = []
126
+ for p, point_tag in enumerate(point_tags):
127
+ xmin, ymin, zmin, xmax, ymax, zmax = gmsh.model.occ.getBoundingBox(0, point_tag)
128
+ x.append((xmin + xmax) / 2)
129
+ y.append((ymin + ymax) / 2)
130
+ z.append((zmin + zmax) / 2)
131
+ if point_tag not in point_tags_mesh:
132
+ point_tags_mesh.append(point_tag)
133
+ line_lengths.append(math.sqrt((x[0] - x[1]) ** 2 + (y[0] - y[1]) ** 2 + (z[0] - z[1]) ** 2))
134
+ # num_div = math.ceil(dist / self.cctdm.mesh_generators.MeshSizeWindings) + 1
135
+ l_length_min = np.min(line_lengths)
136
+ for line_tag, l_length in zip(line_tags, line_lengths):
137
+ aspect = l_length / l_length_min
138
+ if aspect > self.cctdm.mesh.MaxAspectWindings:
139
+ num_div = math.ceil(l_length / (l_length_min * self.cctdm.mesh.MaxAspectWindings)) + 1
140
+ if line_tag in line_tags_transfinite:
141
+ idx = line_tags_transfinite.index(line_tag)
142
+ num_div_set = num_div_transfinite[idx]
143
+ if num_div_set < num_div:
144
+ num_div_transfinite[idx] = num_div
145
+ else:
146
+ line_tags_transfinite.append(line_tag)
147
+ num_div_transfinite.append(num_div)
148
+ for line_tag, num_div in zip(line_tags_transfinite, num_div_transfinite):
149
+ gmsh.model.mesh.setTransfiniteCurve(line_tag, num_div)
150
+
151
+ gmsh.model.setColor([(1, i) for i in line_tags_mesh], 255, 0, 0) # , recursive=True) # Red
152
+
153
+ # gmsh.model.mesh.setTransfiniteCurve(self.air_center_line_tags[0], 15)
154
+ # gmsh.model.setColor([(1, i) for i in self.air_center_line_tags], 0, 0, 0)
155
+
156
+ sld = gmsh.model.mesh.field.add("Distance") # straight line distance
157
+ gmsh.model.mesh.field.setNumbers(sld, "CurvesList", line_tags_mesh)
158
+ # gmsh.model.mesh_generators.field.setNumbers(1, "PointsList", point_tags_mesh)
159
+ gmsh.model.mesh.field.setNumber(sld, "Sampling", 100)
160
+ slt = gmsh.model.mesh.field.add("Threshold") # straight line threshold
161
+ gmsh.model.mesh.field.setNumber(slt, "InField", sld)
162
+ gmsh.model.mesh.field.setNumber(slt, "SizeMin", self.cctdm.mesh.ThresholdSizeMin)
163
+ gmsh.model.mesh.field.setNumber(slt, "SizeMax", self.cctdm.mesh.ThresholdSizeMax)
164
+ gmsh.model.mesh.field.setNumber(slt, "DistMin", self.cctdm.mesh.ThresholdDistMin)
165
+ gmsh.model.mesh.field.setNumber(slt, "DistMax", self.cctdm.mesh.ThresholdDistMax)
166
+ # gmsh.model.mesh_generators.field.add("Min", 7)
167
+ # gmsh.model.mesh_generators.field.setNumbers(7, "FieldsList", [slt])
168
+ gmsh.model.mesh.field.setAsBackgroundMesh(slt)
169
+ gmsh.option.setNumber("Mesh.MeshSizeFromCurvature", 0)
170
+ gmsh.option.setNumber("Mesh.MeshSizeFromPoints", 0)
171
+ gmsh.option.setNumber("Mesh.MeshSizeExtendFromBoundary", 0)
172
+ gmsh.option.setNumber("Mesh.OptimizeNetgen", 0)
173
+ gmsh.model.mesh.generate(3)
174
+ if self.verbose:
175
+ print(f'Generating Mesh Took {timeit.default_timer() - start_time:.2f} s')
176
+ if gui:
177
+ self.gu.launch_interactive_GUI()
178
+
179
+ def generate_cuts(self, gui=False):
180
+ if self.verbose:
181
+ print('Generating Cuts Started')
182
+ start_time = timeit.default_timer()
183
+ for vol, surf_in, surf_out in zip(self.cctrm.powered['cct'].vol.numbers, self.cctrm.powered['cct'].surf_in.numbers, self.cctrm.powered['cct'].surf_out.numbers):
184
+ gmsh.model.mesh.addHomologyRequest("Cohomology", domainTags=[vol], subdomainTags=[surf_in, surf_out], dims=[1, 2, 3])
185
+ for vol in self.cctrm.induced['cct'].vol.numbers:
186
+ gmsh.model.mesh.addHomologyRequest("Cohomology", domainTags=[vol], dims=[1, 2, 3])
187
+ gmsh.model.mesh.computeHomology()
188
+ if self.verbose:
189
+ print(f'Generating Cuts Took {timeit.default_timer() - start_time:.2f} s')
190
+ if gui:
191
+ self.gu.launch_interactive_GUI()
192
+
193
+ def save_mesh(self, gui=False):
194
+ if self.verbose:
195
+ print('Saving Mesh Started')
196
+ start_time = timeit.default_timer()
197
+ gmsh.write(self.model_file)
198
+ if self.verbose:
199
+ print(f'Saving Mesh Took {timeit.default_timer() - start_time:.2f} s')
200
+ if gui:
201
+ self.gu.launch_interactive_GUI()
202
+ else:
203
+ gmsh.clear()
204
+ gmsh.finalize()
205
+
206
+ def load_mesh(self, gui=False):
207
+ gmsh.open(self.model_file)
208
+ if gui:
209
+ self.gu.launch_interactive_GUI()