Coverage for fiqus/mains/MainMultipole.py: 73%
154 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-10-22 09:18 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2025-10-22 09:18 +0000
1import os
2import gmsh
3import time
5from fiqus.utils.Utils import GmshUtils
6from fiqus.utils.Utils import FilesAndFolders as Util
7from fiqus.data import DataFiQuS as dF
8from fiqus.data.DataRoxieParser import FiQuSGeometry
9from fiqus.geom_generators.GeometryMultipole import Geometry
10from fiqus.mesh_generators.MeshMultipole import Mesh
11from fiqus.getdp_runners.RunGetdpMultipole import RunGetdpMultipole
12from fiqus.getdp_runners.RunGetdpMultipole import AssignNaming
13from fiqus.post_processors.PostProcessMultipole import PostProcess
14from fiqus.plotters.PlotPythonMultipole import PlotPythonMultipole
17class MainMultipole:
18 def __init__(self, fdm: dF.FDM = None, rgd_path: str = None, verbose: bool = None):
19 """
20 Main class for working with simulations for multipole type magnets
21 :param fdm: FiQuS data model
22 :param rgd_path: ROXIE geometry data path
23 :param verbose: if True, more info is printed in the console
24 """
25 self.fdm = fdm
26 self.rgd = rgd_path
27 self.verbose = verbose
29 self.GetDP_path = None
30 self.geom_folder = None
31 self.mesh_folder = None
32 self.solution_folder = None
34 def force_symmetry(self):
35 fdm = self.fdm.__deepcopy__()
36 fdm.magnet.geometry.electromagnetics.symmetry = 'x'
37 return fdm
38 def generate_geometry(self, gui: bool = False):
39 geom = Util.read_data_from_yaml(self.rgd, FiQuSGeometry)
40 fdm = self.force_symmetry() if 'solenoid' in geom.Roxie_Data.coil.coils[1].type else self.fdm # todo: this should be handled by pydantic
41 if self.fdm.magnet.geometry.plot_preview:
42 plotter = PlotPythonMultipole(geom, self.fdm)
43 plotter.plot_coil_wedges()
44 gg = Geometry(data=fdm, geom=geom, geom_folder=self.geom_folder, verbose=self.verbose)
45 gg.saveHalfTurnCornerPositions()
46 geometry_settings = {'EM': fdm.magnet.geometry.electromagnetics, 'TH': self.fdm.magnet.geometry.thermal}
47 geometry_type_list = []
48 if fdm.magnet.geometry.electromagnetics.create: geometry_type_list.append('EM')
49 if fdm.magnet.geometry.thermal.create: geometry_type_list.append('TH')
50 for geometry_type in geometry_type_list:
51 gg.saveStrandPositions(geometry_type)
52 if geometry_settings[geometry_type].with_iron_yoke:
53 gg.constructIronGeometry(geometry_settings[geometry_type].symmetry if geometry_type == 'EM' else 'none')
54 gg.constructCoilGeometry(geometry_type)
55 if geometry_settings[geometry_type].with_wedges:
56 gg.constructWedgeGeometry(geometry_settings[geometry_type].use_TSA if geometry_type == 'TH' else False)
57 gmsh.model.occ.synchronize()
58 if geometry_type == 'TH':
59 if geometry_settings[geometry_type].use_TSA:
60 gg.constructThinShells(geometry_settings[geometry_type].with_wedges)
61 else:
62 gg.constructInsulationGeometry()
63 gg.buildDomains(geometry_type, geometry_settings[geometry_type].symmetry if geometry_type == 'EM' else 'none')
64 if geometry_type == 'EM':
65 gg.fragment()
66 gg.saveBoundaryRepresentationFile(geometry_type)
67 gg.loadBoundaryRepresentationFile(geometry_type)
68 gg.updateTags(geometry_type, geometry_settings[geometry_type].symmetry if geometry_type == 'EM' else 'none')
69 gg.saveAuxiliaryFile(geometry_type)
70 gg.clear()
71 gg.ending_step(gui)
73 def load_geometry(self, gui: bool = False):
74 pass
75 # gu = GmshUtils(self.geom_folder, self.verbose)
76 # gu.initialize(verbosity_Gmsh=self.fdm.run.verbosity_Gmsh)
77 # model_file = os.path.join(self.geom_folder, self.fdm.general.magnet_name)
78 # gmsh.option.setString(name='Geometry.OCCTargetUnit', value='M') # set units to meters
79 # gmsh.open(model_file + '_EM.brep')
80 # gmsh.open(model_file + '_TH.brep')
81 # if gui: gu.launch_interactive_GUI()
83 def pre_process(self, gui: bool = False):
84 pass
86 def load_geometry_for_mesh(self, run_type):
87 gu = GmshUtils(self.geom_folder, self.verbose)
88 gu.initialize(verbosity_Gmsh=self.fdm.run.verbosity_Gmsh)
89 model_file = os.path.join(self.geom_folder, self.fdm.general.magnet_name)
90 gmsh.option.setString(name='Geometry.OCCTargetUnit', value='M') # set units to meters
91 gmsh.open(model_file + f'_{run_type}.brep')
93 def mesh(self, gui: bool = False):
94 mm = Mesh(data=self.fdm, mesh_folder=self.mesh_folder, verbose=self.verbose)
95 geom = Util.read_data_from_yaml(self.rgd, FiQuSGeometry)
96 fdm = self.force_symmetry() if 'solenoid' in geom.Roxie_Data.coil.coils[1].type else self.fdm
97 geometry_settings = {'EM': fdm.magnet.geometry.electromagnetics, 'TH': self.fdm.magnet.geometry.thermal}
98 mesh_settings = {'EM': fdm.magnet.mesh.electromagnetics, 'TH': fdm.magnet.mesh.thermal}
99 mesh_type_list = []
100 if fdm.magnet.mesh.electromagnetics.create: mesh_type_list.append('EM')
101 if fdm.magnet.mesh.thermal.create: mesh_type_list.append('TH')
102 for physics_solved in mesh_type_list:
103 self.load_geometry_for_mesh(physics_solved)
104 if physics_solved == 'TH' and self.fdm.magnet.geometry.thermal.use_TSA:
105 mm.loadStrandPositions(physics_solved)
106 mm.loadAuxiliaryFile(physics_solved)
107 if geometry_settings[physics_solved].with_iron_yoke:
108 mm.getIronCurvesTags()
109 mm.defineMesh(geometry_settings[physics_solved], mesh_settings[physics_solved], physics_solved)
110 mm.createPhysicalGroups(geometry_settings[physics_solved])
111 mm.updateAuxiliaryFile(physics_solved)
112 if geometry_settings[physics_solved].model_dump().get('use_TSA', False):
113 mm.rearrangeThinShellsData()
114 mm.assignRegionsTags(geometry_settings[physics_solved], mesh_settings[physics_solved])
115 mm.saveRegionFile(physics_solved)
116 mm.setMeshOptions(physics_solved)
117 mm.generateMesh()
118 mm.checkMeshQuality()
119 mm.saveMeshFile(physics_solved)
120 if geometry_settings[physics_solved].model_dump().get('use_TSA', False):
121 mm.saveClosestNeighboursList()
122 if self.fdm.magnet.mesh.thermal.isothermal_conductors: mm.selectMeshNodes(elements='conductors')
123 if self.fdm.magnet.geometry.thermal.with_wedges and self.fdm.magnet.mesh.thermal.isothermal_wedges: mm.selectMeshNodes(elements='wedges')
124 mm.saveRegionCoordinateFile(physics_solved)
125 mm.clear()
126 mm.ending_step(gui)
127 return mm.mesh_parameters
129 def load_mesh(self, gui: bool = False):
130 gu = GmshUtils(self.geom_folder, self.verbose)
131 gu.initialize(verbosity_Gmsh=self.fdm.run.verbosity_Gmsh)
132 gmsh.open(f"{os.path.join(self.mesh_folder, self.fdm.general.magnet_name)}.msh")
133 if gui: gu.launch_interactive_GUI()
135 def solve_and_postprocess_getdp(self, gui: bool = False):
136 an = AssignNaming(data=self.fdm)
137 rg = RunGetdpMultipole(data=an, solution_folder=self.solution_folder, GetDP_path=self.GetDP_path, verbose=self.verbose)
138 rg.loadRegionFiles()
139 if self.fdm.magnet.solve.thermal.solve_type and self.fdm.magnet.geometry.thermal.use_TSA:
140 rg.loadRegionCoordinateFile()
141 rg.assemblePro()
142 start_time = time.time()
143 rg.solve_and_postprocess()
144 rg.ending_step(gui)
145 return time.time() - start_time
147 def post_process_getdp(self, gui: bool = False):
148 an = AssignNaming(data=self.fdm)
149 rg = RunGetdpMultipole(data=an, solution_folder=self.solution_folder, GetDP_path=self.GetDP_path, verbose=self.verbose)
150 rg.loadRegionFiles()
151 if self.fdm.magnet.solve.thermal.solve_type and self.fdm.magnet.geometry.thermal.use_TSA:
152 rg.loadRegionCoordinateFile()
153 rg.assemblePro()
154 rg.postprocess()
155 rg.ending_step(gui)
157 def post_process_python(self, gui: bool = False):
158 if self.fdm.run.type == 'post_process_python_only':
159 an = AssignNaming(data=self.fdm)
160 data = an.data
161 else: data = self.fdm
163 run_types = []
164 if self.fdm.magnet.solve.electromagnetics.solve_type: run_types.append('EM')
165 if self.fdm.magnet.solve.thermal.solve_type: run_types.append('TH')
166 pp_settings = {'EM': self.fdm.magnet.postproc.electromagnetics, 'TH': self.fdm.magnet.postproc.thermal}
167 pp = PostProcess(data=data, solution_folder=self.solution_folder, verbose=self.verbose)
168 for run_type in run_types:
169 pp.prepare_settings(pp_settings[run_type])
170 pp.loadStrandPositions(run_type)
171 pp.loadAuxiliaryFile(run_type)
172 if pp_settings[run_type].plot_all != 'False': pp.loadHalfTurnCornerPositions()
173 if pp_settings[run_type].model_dump().get('take_average_conductor_temperature', False): pp.loadRegionFile()
174 pp.postProcess(pp_settings[run_type])
175 if run_type == 'EM' and self.fdm.magnet.geometry.electromagnetics.symmetry != 'none': pp.completeMap2d()
176 pp.clear()
177 pp.ending_step(gui)
178 return pp.postprocess_parameters
180 def plot_python(self):
181 os.chdir(self.solution_folder)
182 p = PlotPythonMultipole(self.fdm, self.fdm)
183 p.plot_coil_wedges()