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
fiqus/mesh_generators/MeshCCT.py
CHANGED
|
@@ -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()
|