fiqus 2025.12.0__py3-none-any.whl → 2026.1.1__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 +4 -8
- fiqus/data/DataConductor.py +108 -11
- fiqus/data/DataFiQuS.py +2 -1
- fiqus/data/DataFiQuSConductorAC_CC.py +345 -0
- fiqus/data/DataFiQuSConductorAC_Strand.py +3 -3
- fiqus/data/DataFiQuSMultipole.py +363 -165
- 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/GeometryConductorAC_CC.py +1906 -0
- fiqus/geom_generators/GeometryMultipole.py +751 -54
- fiqus/getdp_runners/RunGetdpConductorAC_CC.py +123 -0
- fiqus/getdp_runners/RunGetdpMultipole.py +181 -31
- fiqus/mains/MainConductorAC_CC.py +148 -0
- fiqus/mains/MainMultipole.py +109 -17
- fiqus/mesh_generators/MeshCCT.py +209 -209
- fiqus/mesh_generators/MeshConductorAC_CC.py +1305 -0
- 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/PostProcessAC_CC.py +65 -0
- 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/CAC_CC_template.pro +542 -0
- fiqus/pro_templates/combined/CC_Module.pro +1213 -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-2025.12.0.dist-info → fiqus-2026.1.1.dist-info}/METADATA +81 -77
- {fiqus-2025.12.0.dist-info → fiqus-2026.1.1.dist-info}/RECORD +52 -44
- {fiqus-2025.12.0.dist-info → fiqus-2026.1.1.dist-info}/WHEEL +1 -1
- tests/test_geometry_generators.py +47 -30
- tests/test_mesh_generators.py +69 -30
- tests/test_solvers.py +67 -29
- tests/utils/fiqus_test_classes.py +396 -147
- tests/utils/generate_reference_files_ConductorAC.py +57 -57
- tests/utils/helpers.py +76 -1
- /fiqus/pro_templates/combined/{ConductorACRutherford_template.pro → CAC_Rutherford_template.pro} +0 -0
- /fiqus/pro_templates/combined/{ConductorAC_template.pro → CAC_Strand_template.pro} +0 -0
- {fiqus-2025.12.0.dist-info → fiqus-2026.1.1.dist-info/licenses}/LICENSE.txt +0 -0
- {fiqus-2025.12.0.dist-info → fiqus-2026.1.1.dist-info}/top_level.txt +0 -0
fiqus/mains/MainMultipole.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import os
|
|
2
3
|
import gmsh
|
|
3
4
|
import time
|
|
4
5
|
|
|
6
|
+
from fiqus.plotters.PlotPythonMultipole import PlotPythonMultipole
|
|
5
7
|
from fiqus.utils.Utils import GmshUtils
|
|
6
8
|
from fiqus.utils.Utils import FilesAndFolders as Util
|
|
7
9
|
from fiqus.data import DataFiQuS as dF
|
|
@@ -11,11 +13,10 @@ from fiqus.mesh_generators.MeshMultipole import Mesh
|
|
|
11
13
|
from fiqus.getdp_runners.RunGetdpMultipole import RunGetdpMultipole
|
|
12
14
|
from fiqus.getdp_runners.RunGetdpMultipole import AssignNaming
|
|
13
15
|
from fiqus.post_processors.PostProcessMultipole import PostProcess
|
|
14
|
-
from fiqus.plotters.PlotPythonMultipole import PlotPythonMultipole
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class MainMultipole:
|
|
18
|
-
def __init__(self, fdm: dF.FDM = None, rgd_path: str = None, verbose: bool = None):
|
|
19
|
+
def __init__(self, fdm: dF.FDM = None, rgd_path: str = None, verbose: bool = None, inputs_folder_path = None):
|
|
19
20
|
"""
|
|
20
21
|
Main class for working with simulations for multipole type magnets
|
|
21
22
|
:param fdm: FiQuS data model
|
|
@@ -30,11 +31,13 @@ class MainMultipole:
|
|
|
30
31
|
self.geom_folder = None
|
|
31
32
|
self.mesh_folder = None
|
|
32
33
|
self.solution_folder = None
|
|
34
|
+
self.inputs_folder_path = inputs_folder_path
|
|
33
35
|
|
|
34
36
|
def force_symmetry(self):
|
|
35
37
|
fdm = self.fdm.__deepcopy__()
|
|
36
38
|
fdm.magnet.geometry.electromagnetics.symmetry = 'x'
|
|
37
39
|
return fdm
|
|
40
|
+
|
|
38
41
|
def generate_geometry(self, gui: bool = False):
|
|
39
42
|
geom = Util.read_data_from_yaml(self.rgd, FiQuSGeometry)
|
|
40
43
|
fdm = self.force_symmetry() if 'solenoid' in geom.Roxie_Data.coil.coils[1].type else self.fdm # todo: this should be handled by pydantic
|
|
@@ -43,14 +46,16 @@ class MainMultipole:
|
|
|
43
46
|
plotter.plot_coil_wedges()
|
|
44
47
|
gg = Geometry(data=fdm, geom=geom, geom_folder=self.geom_folder, verbose=self.verbose)
|
|
45
48
|
gg.saveHalfTurnCornerPositions()
|
|
49
|
+
|
|
46
50
|
geometry_settings = {'EM': fdm.magnet.geometry.electromagnetics, 'TH': self.fdm.magnet.geometry.thermal}
|
|
47
51
|
geometry_type_list = []
|
|
48
|
-
|
|
49
|
-
if
|
|
52
|
+
|
|
53
|
+
if geometry_settings['EM'].create: geometry_type_list.append('EM')
|
|
54
|
+
if geometry_settings['TH'].create: geometry_type_list.append('TH')
|
|
50
55
|
for geometry_type in geometry_type_list:
|
|
51
56
|
gg.saveStrandPositions(geometry_type)
|
|
52
|
-
if geometry_settings[geometry_type].
|
|
53
|
-
gg.constructIronGeometry(geometry_settings[geometry_type].symmetry if geometry_type == 'EM' else 'none')
|
|
57
|
+
if any(geometry_settings[geometry_type].areas):
|
|
58
|
+
gg.constructIronGeometry(geometry_settings[geometry_type].symmetry if geometry_type == 'EM' else 'none', geometry_settings[geometry_type], run_type = geometry_type)
|
|
54
59
|
gg.constructCoilGeometry(geometry_type)
|
|
55
60
|
if geometry_settings[geometry_type].with_wedges:
|
|
56
61
|
gg.constructWedgeGeometry(geometry_settings[geometry_type].use_TSA if geometry_type == 'TH' else False)
|
|
@@ -60,9 +65,17 @@ class MainMultipole:
|
|
|
60
65
|
gg.constructThinShells(geometry_settings[geometry_type].with_wedges)
|
|
61
66
|
else:
|
|
62
67
|
gg.constructInsulationGeometry()
|
|
68
|
+
if geometry_settings[geometry_type].use_TSA_new:
|
|
69
|
+
gg.constructAdditionalThinShells()
|
|
70
|
+
|
|
63
71
|
gg.buildDomains(geometry_type, geometry_settings[geometry_type].symmetry if geometry_type == 'EM' else 'none')
|
|
64
72
|
if geometry_type == 'EM':
|
|
65
73
|
gg.fragment()
|
|
74
|
+
if geometry_type =='TH' and 'poles' in geometry_settings[geometry_type].areas:
|
|
75
|
+
# make sure geometry is connected
|
|
76
|
+
gmsh.model.occ.removeAllDuplicates()
|
|
77
|
+
gmsh.model.occ.synchronize()
|
|
78
|
+
|
|
66
79
|
gg.saveBoundaryRepresentationFile(geometry_type)
|
|
67
80
|
gg.loadBoundaryRepresentationFile(geometry_type)
|
|
68
81
|
gg.updateTags(geometry_type, geometry_settings[geometry_type].symmetry if geometry_type == 'EM' else 'none')
|
|
@@ -91,29 +104,84 @@ class MainMultipole:
|
|
|
91
104
|
gmsh.open(model_file + f'_{run_type}.brep')
|
|
92
105
|
|
|
93
106
|
def mesh(self, gui: bool = False):
|
|
94
|
-
|
|
107
|
+
def _create_physical_group_for_reference(self):
|
|
108
|
+
"""
|
|
109
|
+
This code generates the reference models for the FALCOND_C
|
|
110
|
+
"""
|
|
111
|
+
### hardcoded, we need only one reference
|
|
112
|
+
if self.fdm.general.magnet_name == 'TEST_MULTIPOLE_FALCOND_C_TSA_COLLAR_POLE':
|
|
113
|
+
CUT_REFERENCE = True # self specify loop and surf
|
|
114
|
+
|
|
115
|
+
L_col = [56, 57, 58, 35, 16, 49, 48, 47]
|
|
116
|
+
l1 = gmsh.model.occ.addLine(746,48)
|
|
117
|
+
l2 = gmsh.model.occ.addLine(41,691)
|
|
118
|
+
L_inner = list(range(854, 754-1, -1))
|
|
119
|
+
loop1 = gmsh.model.occ.addCurveLoop([l1] + L_col + [l2] + L_inner)
|
|
120
|
+
|
|
121
|
+
R_col = [52, 53, 54, 26, 6, 45, 44, 43]
|
|
122
|
+
r1 = gmsh.model.occ.addLine(38,902)
|
|
123
|
+
r2 = gmsh.model.occ.addLine(847,45)
|
|
124
|
+
R_inner = list(range(910, 1010+1))
|
|
125
|
+
loop2 = gmsh.model.occ.addCurveLoop([r2]+ R_col + [r1] + R_inner)
|
|
126
|
+
|
|
127
|
+
surf1 = gmsh.model.occ.addPlaneSurface([loop1])
|
|
128
|
+
surf2 = gmsh.model.occ.addPlaneSurface([loop2])
|
|
129
|
+
surf = [surf1, surf2] # tag
|
|
130
|
+
|
|
131
|
+
else: raise Exception("Reference meshing is not implemented for this magnet.")
|
|
132
|
+
gmsh.model.occ.synchronize()
|
|
133
|
+
|
|
134
|
+
#add to physical groups / domains -> write to aux file
|
|
135
|
+
file = os.path.join(self.geom_folder, self.fdm.general.magnet_name + '_TH.aux')
|
|
136
|
+
with open(file) as f:
|
|
137
|
+
lines = f.readlines()
|
|
138
|
+
updated_lines = []
|
|
139
|
+
flag = 0
|
|
140
|
+
for line in lines:
|
|
141
|
+
updated_lines.append(line)
|
|
142
|
+
if flag == 0 and 'groups_entities:' in line:
|
|
143
|
+
flag = 1
|
|
144
|
+
if flag==1 and ('ref_mesh: {}' in line):
|
|
145
|
+
if type(surf) == list:
|
|
146
|
+
updated_lines[-1] = f' ref_mesh:\n {self.fdm.magnet.solve.thermal.insulation_TSA.between_collar.material}: {surf}\n'
|
|
147
|
+
else:
|
|
148
|
+
updated_lines[-1] = f' ref_mesh:\n {self.fdm.magnet.solve.thermal.insulation_TSA.between_collar.material}: [{surf}]\n'
|
|
149
|
+
#if not CUT_REFERENCE else f' ref_mesh:\n {self.fdm.magnet.solve.thermal.insulation_TSA.between_collar.material}: '+ str(surf) +'\n'
|
|
150
|
+
flag = -1
|
|
151
|
+
|
|
152
|
+
with open(file, 'w') as f:
|
|
153
|
+
f.writelines(updated_lines)
|
|
154
|
+
logger = logging.getLogger('FiQuS')
|
|
155
|
+
logger.warning("Overwrite the .aux file to include the new domain")
|
|
156
|
+
|
|
157
|
+
mm = Mesh(data=self.fdm, mesh_folder=self.mesh_folder, verbose=self.verbose) ## same mesh object is used for both thermal and EM
|
|
95
158
|
geom = Util.read_data_from_yaml(self.rgd, FiQuSGeometry)
|
|
96
159
|
fdm = self.force_symmetry() if 'solenoid' in geom.Roxie_Data.coil.coils[1].type else self.fdm
|
|
97
160
|
geometry_settings = {'EM': fdm.magnet.geometry.electromagnetics, 'TH': self.fdm.magnet.geometry.thermal}
|
|
98
161
|
mesh_settings = {'EM': fdm.magnet.mesh.electromagnetics, 'TH': fdm.magnet.mesh.thermal}
|
|
162
|
+
|
|
99
163
|
mesh_type_list = []
|
|
100
|
-
if
|
|
101
|
-
if
|
|
164
|
+
if mesh_settings['EM'].create: mesh_type_list.append('EM')
|
|
165
|
+
if mesh_settings['TH'].create: mesh_type_list.append('TH')
|
|
102
166
|
for physics_solved in mesh_type_list:
|
|
103
167
|
self.load_geometry_for_mesh(physics_solved)
|
|
104
|
-
if physics_solved == 'TH' and
|
|
105
|
-
|
|
168
|
+
if physics_solved == 'TH' and mesh_settings['TH'].reference.enabled and 'collar' in geometry_settings['TH'].areas:
|
|
169
|
+
if self.fdm.magnet.geometry.thermal.use_TSA_new or self.fdm.magnet.geometry.thermal.use_TSA:
|
|
170
|
+
raise Exception('Reference solution is not implemented for collar with TSA')
|
|
171
|
+
if 'iron_yoke' in geometry_settings['TH'].areas:
|
|
172
|
+
raise Exception('Reference solution is intended (read: hardcoded) without iron yoke')
|
|
173
|
+
_create_physical_group_for_reference(self)
|
|
106
174
|
mm.loadAuxiliaryFile(physics_solved)
|
|
107
|
-
if geometry_settings[physics_solved].
|
|
108
|
-
mm.getIronCurvesTags()
|
|
175
|
+
if any(geometry_settings[physics_solved].areas):
|
|
176
|
+
mm.getIronCurvesTags(physics_solved)
|
|
109
177
|
mm.defineMesh(geometry_settings[physics_solved], mesh_settings[physics_solved], physics_solved)
|
|
110
178
|
mm.createPhysicalGroups(geometry_settings[physics_solved])
|
|
111
179
|
mm.updateAuxiliaryFile(physics_solved)
|
|
112
180
|
if geometry_settings[physics_solved].model_dump().get('use_TSA', False):
|
|
113
|
-
mm.rearrangeThinShellsData()
|
|
181
|
+
mm.rearrangeThinShellsData() # rearrange data for the pro file, technically optional
|
|
114
182
|
mm.assignRegionsTags(geometry_settings[physics_solved], mesh_settings[physics_solved])
|
|
115
183
|
mm.saveRegionFile(physics_solved)
|
|
116
|
-
mm.setMeshOptions(
|
|
184
|
+
mm.setMeshOptions()
|
|
117
185
|
mm.generateMesh()
|
|
118
186
|
mm.checkMeshQuality()
|
|
119
187
|
mm.saveMeshFile(physics_solved)
|
|
@@ -121,7 +189,10 @@ class MainMultipole:
|
|
|
121
189
|
mm.saveClosestNeighboursList()
|
|
122
190
|
if self.fdm.magnet.mesh.thermal.isothermal_conductors: mm.selectMeshNodes(elements='conductors')
|
|
123
191
|
if self.fdm.magnet.geometry.thermal.with_wedges and self.fdm.magnet.mesh.thermal.isothermal_wedges: mm.selectMeshNodes(elements='wedges')
|
|
124
|
-
|
|
192
|
+
if geometry_settings[physics_solved].model_dump().get('use_TSA_new', False):
|
|
193
|
+
mm.saveClosestNeighboursList_new_TSA()
|
|
194
|
+
mm.saveHalfTurnCornerPositions()
|
|
195
|
+
mm.saveRegionCoordinateFile(physics_solved)
|
|
125
196
|
mm.clear()
|
|
126
197
|
mm.ending_step(gui)
|
|
127
198
|
return mm.mesh_parameters
|
|
@@ -134,16 +205,37 @@ class MainMultipole:
|
|
|
134
205
|
|
|
135
206
|
def solve_and_postprocess_getdp(self, gui: bool = False):
|
|
136
207
|
an = AssignNaming(data=self.fdm)
|
|
137
|
-
rg = RunGetdpMultipole(data=an, solution_folder=self.solution_folder, GetDP_path=self.GetDP_path,
|
|
208
|
+
rg = RunGetdpMultipole(data=an, solution_folder=self.solution_folder, GetDP_path=self.GetDP_path,
|
|
209
|
+
verbose=self.verbose)
|
|
210
|
+
rg.loadRegionFiles()
|
|
211
|
+
if self.fdm.magnet.solve.thermal.solve_type and self.fdm.magnet.geometry.thermal.use_TSA:
|
|
212
|
+
rg.loadRegionCoordinateFile()
|
|
213
|
+
rg.assemblePro()
|
|
214
|
+
start_time = time.time()
|
|
215
|
+
rg.solve_and_postprocess()
|
|
216
|
+
rg.ending_step(gui)
|
|
217
|
+
return time.time() - start_time
|
|
218
|
+
|
|
219
|
+
def solve_and_postprocess_getdp(self, gui: bool = False):
|
|
220
|
+
an = AssignNaming(data=self.fdm)
|
|
221
|
+
rg = RunGetdpMultipole(data=an, solution_folder=self.solution_folder, GetDP_path=self.GetDP_path,
|
|
222
|
+
verbose=self.verbose)
|
|
138
223
|
rg.loadRegionFiles()
|
|
139
224
|
if self.fdm.magnet.solve.thermal.solve_type and self.fdm.magnet.geometry.thermal.use_TSA:
|
|
140
225
|
rg.loadRegionCoordinateFile()
|
|
226
|
+
rg.read_aux_file(os.path.join(self.mesh_folder, f"{self.fdm.general.magnet_name}_EM.aux"))
|
|
227
|
+
rg.extract_half_turn_blocks()
|
|
228
|
+
if self.fdm.magnet.geometry.thermal.use_TSA_new:
|
|
229
|
+
rg.read_aux_file(os.path.join(self.mesh_folder,
|
|
230
|
+
f"{self.fdm.general.magnet_name}_TH.aux")) # now load the thermal aux file
|
|
231
|
+
rg.extract_specific_TSA_lines()
|
|
141
232
|
rg.assemblePro()
|
|
142
233
|
start_time = time.time()
|
|
143
234
|
rg.solve_and_postprocess()
|
|
144
235
|
rg.ending_step(gui)
|
|
145
236
|
return time.time() - start_time
|
|
146
237
|
|
|
238
|
+
|
|
147
239
|
def post_process_getdp(self, gui: bool = False):
|
|
148
240
|
an = AssignNaming(data=self.fdm)
|
|
149
241
|
rg = RunGetdpMultipole(data=an, solution_folder=self.solution_folder, GetDP_path=self.GetDP_path, verbose=self.verbose)
|
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()
|