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

1import os 

2import gmsh 

3import time 

4 

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 

15 

16 

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 

28 

29 self.GetDP_path = None 

30 self.geom_folder = None 

31 self.mesh_folder = None 

32 self.solution_folder = None 

33 

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) 

72 

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() 

82 

83 def pre_process(self, gui: bool = False): 

84 pass 

85 

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') 

92 

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 

128 

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() 

134 

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 

146 

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) 

156 

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 

162 

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 

179 

180 def plot_python(self): 

181 os.chdir(self.solution_folder) 

182 p = PlotPythonMultipole(self.fdm, self.fdm) 

183 p.plot_coil_wedges()