fiqus 2024.6.0__py3-none-any.whl → 2024.12.0__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 (69) hide show
  1. fiqus/MainFiQuS.py +290 -134
  2. fiqus/data/DataConductor.py +301 -301
  3. fiqus/data/DataFiQuS.py +128 -84
  4. fiqus/data/DataFiQuSCCT.py +150 -150
  5. fiqus/data/DataFiQuSConductor.py +84 -84
  6. fiqus/data/DataFiQuSConductorAC_Strand.py +565 -565
  7. fiqus/data/DataFiQuSMultipole.py +716 -42
  8. fiqus/data/DataFiQuSPancake3D.py +737 -278
  9. fiqus/data/DataMultipole.py +180 -15
  10. fiqus/data/DataRoxieParser.py +90 -51
  11. fiqus/data/DataSettings.py +121 -0
  12. fiqus/data/DataWindingsCCT.py +37 -37
  13. fiqus/data/RegionsModelFiQuS.py +18 -6
  14. fiqus/geom_generators/GeometryCCT.py +905 -905
  15. fiqus/geom_generators/GeometryConductorAC_Strand.py +1391 -1391
  16. fiqus/geom_generators/GeometryMultipole.py +1827 -227
  17. fiqus/geom_generators/GeometryPancake3D.py +316 -117
  18. fiqus/geom_generators/GeometryPancake3DUtils.py +549 -0
  19. fiqus/getdp_runners/RunGetdpCCT.py +4 -4
  20. fiqus/getdp_runners/RunGetdpConductorAC_Strand.py +201 -201
  21. fiqus/getdp_runners/RunGetdpMultipole.py +115 -42
  22. fiqus/getdp_runners/RunGetdpPancake3D.py +28 -6
  23. fiqus/mains/MainCCT.py +2 -2
  24. fiqus/mains/MainConductorAC_Strand.py +132 -132
  25. fiqus/mains/MainMultipole.py +113 -62
  26. fiqus/mains/MainPancake3D.py +63 -23
  27. fiqus/mesh_generators/MeshCCT.py +209 -209
  28. fiqus/mesh_generators/MeshConductorAC_Strand.py +656 -656
  29. fiqus/mesh_generators/MeshMultipole.py +1243 -181
  30. fiqus/mesh_generators/MeshPancake3D.py +275 -192
  31. fiqus/parsers/ParserCOND.py +825 -0
  32. fiqus/parsers/ParserDAT.py +16 -16
  33. fiqus/parsers/ParserGetDPOnSection.py +212 -212
  34. fiqus/parsers/ParserGetDPTimeTable.py +134 -134
  35. fiqus/parsers/ParserMSH.py +53 -53
  36. fiqus/parsers/ParserPOS.py +214 -214
  37. fiqus/parsers/ParserRES.py +142 -142
  38. fiqus/plotters/PlotPythonCCT.py +133 -133
  39. fiqus/plotters/PlotPythonConductorAC.py +855 -840
  40. fiqus/plotters/PlotPythonMultipole.py +18 -18
  41. fiqus/post_processors/PostProcessCCT.py +440 -440
  42. fiqus/post_processors/PostProcessConductorAC.py +49 -49
  43. fiqus/post_processors/PostProcessMultipole.py +353 -229
  44. fiqus/post_processors/PostProcessPancake3D.py +8 -13
  45. fiqus/pre_processors/PreProcessCCT.py +175 -175
  46. fiqus/pro_assemblers/ProAssembler.py +14 -6
  47. fiqus/pro_material_functions/ironBHcurves.pro +246 -246
  48. fiqus/pro_templates/combined/CCT_template.pro +274 -274
  49. fiqus/pro_templates/combined/ConductorAC_template.pro +1025 -1025
  50. fiqus/pro_templates/combined/Multipole_template.pro +1694 -126
  51. fiqus/pro_templates/combined/Pancake3D_template.pro +2294 -1103
  52. fiqus/pro_templates/combined/TSA_materials.pro +162 -0
  53. fiqus/pro_templates/combined/materials.pro +36 -18
  54. fiqus/utils/Utils.py +508 -110
  55. fiqus/utils/update_data_settings.py +33 -0
  56. fiqus-2024.12.0.dist-info/METADATA +130 -0
  57. fiqus-2024.12.0.dist-info/RECORD +84 -0
  58. {fiqus-2024.6.0.dist-info → fiqus-2024.12.0.dist-info}/WHEEL +1 -1
  59. tests/test_FiQuS.py +1 -1
  60. tests/test_geometry_generators.py +101 -2
  61. tests/test_mesh_generators.py +154 -1
  62. tests/test_solvers.py +115 -21
  63. tests/utils/fiqus_test_classes.py +85 -21
  64. tests/utils/generate_reference_files_ConductorAC.py +57 -57
  65. tests/utils/generate_reference_files_Pancake3D.py +4 -5
  66. tests/utils/helpers.py +97 -97
  67. fiqus-2024.6.0.dist-info/METADATA +0 -103
  68. fiqus-2024.6.0.dist-info/RECORD +0 -79
  69. {fiqus-2024.6.0.dist-info → fiqus-2024.12.0.dist-info}/top_level.txt +0 -0
fiqus/MainFiQuS.py CHANGED
@@ -1,110 +1,141 @@
1
- import os
2
- import getpass
3
- import time
4
1
  import argparse
2
+ import csv
3
+ import os
5
4
  import pathlib
6
5
  import sys
6
+ import time
7
+ import getpass
8
+ import platform
9
+ import subprocess
10
+ import json
11
+
12
+ import pandas as pd
7
13
 
8
14
  FiQuS_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
9
15
  sys.path.insert(0, FiQuS_path)
10
16
 
11
- from fiqus.utils.Utils import initialize_logger
12
17
  from fiqus.utils.Utils import FilesAndFolders as Util
13
18
  from fiqus.utils.Utils import CheckForExceptions as Check
14
- from fiqus.data import DataFiQuS as dF
15
- from fiqus.mains.MainMultipole import MainMultipole
19
+ from fiqus.utils.Utils import create_json_schema
20
+ from fiqus.utils.Utils import get_data_settings
21
+ from fiqus.utils.Utils import initialize_logger
22
+ from fiqus.data.DataFiQuS import FDM
23
+ from fiqus.data.DataSettings import DataSettings
16
24
  from fiqus.mains.MainCCT import MainCCT
25
+ from fiqus.mains.MainMultipole import MainMultipole
17
26
  from fiqus.mains.MainPancake3D import MainPancake3D
18
27
  from fiqus.mains.MainConductorAC_Strand import MainConductorAC_Strand
19
28
 
20
-
21
29
  class MainFiQuS:
30
+ """
31
+ This is the top level class of FiQuS.
32
+ """
33
+
22
34
  def __init__(
23
- self,
24
- input_file_path: str = None,
25
- model_folder: str = None,
26
- verbose: bool = True,
27
- fdm=None,
28
- GetDP_path=None,
35
+ self,
36
+ input_file_path: str = None,
37
+ model_folder: str = None,
38
+ GetDP_path=None,
39
+ fdm=None,
40
+ fds=None,
41
+ htcondor_jobid=None
29
42
  ):
30
43
  """
31
44
  Main class for working with FiQuS simulations
32
- :param input_file_path: input file name
33
- :param verbose: if True, more info is printed in the console
45
+ :param input_file_path: full path to input file yaml
46
+ :type input_file_path: str
47
+ :param model_folder: full path to the base output folder, called model folder
48
+ :type model_folder: str
49
+ :param GetDP_path: full path to GetDP executable
50
+ :type GetDP_path: str
51
+ :param fdm: FiQuS Data Model - object of fiqus DataFiQus
52
+ :type fdm: object
53
+ :param fds: FiQuS Data Settings - object of DataSettings
54
+ :type fds: object
34
55
  """
35
56
  self.time_stamp = time.strftime("%Y-%m-%d-%H-%M-%S")
36
57
 
37
58
  self.start_folder = os.getcwd()
38
59
  self.wrk_folder = model_folder
60
+ self.file_name = None
39
61
 
40
- # Intialize logger
62
+ # Load yaml input file
63
+ if not fdm:
64
+ self.fdm: FDM = Util.read_data_from_yaml(input_file_path, FDM)
65
+ copyInputFile = (
66
+ "copy"
67
+ f" {input_file_path} {os.path.join(self.wrk_folder, 'logs', f'INPUT_FILE_{self.time_stamp}.FiQuS.yaml')}"
68
+ )
69
+ subprocess.run(copyInputFile, shell=True, stdout=subprocess.DEVNULL)
70
+ else:
71
+ self.fdm: FDM = fdm
72
+ verbose = self.fdm.run.verbosity_FiQuS
41
73
  self.logger = initialize_logger(
42
74
  verbose=verbose, time_stamp=self.time_stamp, work_folder=self.wrk_folder
43
75
  )
44
-
45
- self.verbose = verbose
46
- if self.verbose:
76
+ if verbose:
47
77
  Util.print_welcome_graphics()
78
+ # Intialize logger
48
79
 
49
- # Load yaml input file
50
- if not fdm:
51
- self.fdm = Util.read_data_from_yaml(input_file_path, dF.FDM)
52
- else:
53
- self.fdm = fdm
80
+ # Create JSON schema
81
+ create_json_schema(self.fdm)
54
82
 
55
83
  # Check for input errors
56
- Check.check_inputs(self.fdm.run)
84
+ Check.check_inputs(run=self.fdm.run)
57
85
 
58
86
  # Initialize Main object
59
87
  if self.fdm.magnet.type == "CCT_straight":
60
88
  self.main_magnet = MainCCT(fdm=self.fdm, verbose=verbose)
61
-
62
- elif self.fdm.magnet.type == "multipole":
63
- # Load settings
64
- self.sdm = Util.read_data_from_yaml(
65
- f"{input_file_path[:-5]}.set", dF.FiQuSSettings
66
- )
67
-
68
- self.main_magnet = MainMultipole(
89
+ elif self.fdm.magnet.type == "CWS":
90
+ self.main_magnet = MainCWS(
69
91
  fdm=self.fdm,
70
- sdm=self.sdm,
71
- rgd_path=f"{input_file_path[:-5]}.geom",
72
- verbose=verbose,
92
+ inputs_folder_path=pathlib.Path(input_file_path).parent,
93
+ verbose=self.fdm.run.verbosity_FiQuS,
73
94
  )
74
-
75
95
  elif self.fdm.magnet.type == "Pancake3D":
76
96
  self.main_magnet = MainPancake3D(fdm=self.fdm, verbose=verbose)
77
97
  elif self.fdm.magnet.type == "CACStrand":
78
98
  self.main_magnet = MainConductorAC_Strand(fdm=self.fdm, inputs_folder_path=pathlib.Path(input_file_path).parent, outputs_folder_path=model_folder, verbose=verbose)
99
+ elif self.fdm.magnet.type == "CACRutherford":
100
+ self.main_magnet = MainConductorAC_Rutherford(fdm=self.fdm, inputs_folder_path=pathlib.Path(input_file_path).parent, verbose=verbose)
101
+ elif self.fdm.magnet.type == "Racetrack":
102
+ self.main_magnet = MainRacetrack(fdm=self.fdm, verbose=verbose)
103
+ elif self.fdm.magnet.type == "Racetrack3D":
104
+ self.main_magnet = MainRacetrack3D(fdm=self.fdm, inputs_folder_path=pathlib.Path(input_file_path).parent, verbose=verbose)
105
+ elif self.fdm.magnet.type == "multipole":
106
+ self.file_name = os.path.basename(input_file_path)[:-5]
107
+ if not self.fdm.magnet.geometry.geom_file_path:
108
+ self.fdm.magnet.geometry.geom_file_path = f"{input_file_path[:-5]}.geom"
109
+ self.main_magnet = MainMultipole(
110
+ fdm=self.fdm,
111
+ rgd_path=self.fdm.magnet.geometry.geom_file_path,
112
+ verbose=verbose,
113
+ )
114
+
79
115
  else:
80
116
  raise ValueError(
81
117
  f"FiQuS does not support magnet type: {self.fdm.magnet.type}!"
82
118
  )
83
119
 
84
120
  # Load user paths for executables and additional files
85
- user_name = getpass.getuser()
86
- if verbose:
87
- print(f"FiQuS is running on machine with user name: {user_name}")
88
- if user_name in ["root", "MP-WIN-02$"]:
89
- user_name = "SYSTEM"
90
- path_to_settings_file = os.path.join(
91
- os.path.dirname(os.path.dirname(__file__)),
92
- "tests",
93
- f"settings.{user_name}.yaml",
94
- )
95
- if verbose:
96
- print(f"FiQuS is using settings file: {path_to_settings_file}")
97
- if GetDP_path:
98
- self.main_magnet.settings = {"GetDP_path": GetDP_path}
99
- self.main_magnet.GetDP_path = GetDP_path
121
+ self.logger.info(f'{getpass.getuser()} is running on {platform.platform()}')
122
+ if not fds:
123
+ fds = get_data_settings(GetDP_path=GetDP_path)
100
124
  else:
101
- self.main_magnet.settings = Util.read_data_from_yaml(
102
- path_to_settings_file, dict
103
- )
104
- self.main_magnet.GetDP_path = self.main_magnet.settings["GetDP_path"]
125
+ fds = get_data_settings(GetDP_path=GetDP_path, settings=fds)
126
+ self.main_magnet.GetDP_path = fds.GetDP_path
127
+ self.logger.info(f"{self.main_magnet.GetDP_path} is going to be used for FE solving.")
128
+
129
+ # self.logger.info(gmsh.onelab.run(self.fdm.general.magnet_name, f"{self.main_magnet.settings['GetDP_path']} -info"))
130
+
131
+ # update htcondor csv
132
+ if htcondor_jobid:
133
+ base_path_model_files = fds.base_path_model_files
134
+ htcondor_csv_file = os.path.join(base_path_model_files, "htcondor_run_log.csv")
135
+
136
+ self.change_htcondor_run_log(htcondor_csv_file, htcondor_jobid, "Running")
105
137
 
106
138
  # Save Model/Geometry/Mesh/Solution folder paths
107
- Util.prep_folder(self.wrk_folder)
108
139
  self.save_folders()
109
140
 
110
141
  # Build magnet
@@ -121,9 +152,27 @@ class MainFiQuS:
121
152
  "maximum_diff",
122
153
  ]
123
154
  )
124
- self.build_magnet()
155
+
156
+ try:
157
+ self.build_magnet()
158
+ except Exception as e:
159
+ # update htcondor csv
160
+ if htcondor_jobid:
161
+ self.change_htcondor_run_log(htcondor_csv_file, htcondor_jobid, "Failed")
162
+
163
+ self.logger.error(f"Error: {e}")
164
+ raise e
165
+ else:
166
+ # update htcondor csv
167
+ if htcondor_jobid:
168
+ self.change_htcondor_run_log(htcondor_csv_file, htcondor_jobid, "Finished")
125
169
 
126
170
  def save_folders(self):
171
+ """
172
+ Method to make or delete folders of FiQuS
173
+ :return: Nothing, only does file and folder operation
174
+ :rtype: None
175
+ """
127
176
  def _check_and_generate_path(folder_type: str = None):
128
177
  if folder_type == "Geometry":
129
178
  folder = self.wrk_folder
@@ -147,7 +196,7 @@ class MainFiQuS:
147
196
 
148
197
  required_folder = folder_type in required_folders
149
198
  if self.fdm.run.overwrite and folder_type == (
150
- required_folders[0] if required_folders else None
199
+ required_folders[0] if required_folders else None
151
200
  ):
152
201
  Check.check_overwrite_conditions(
153
202
  folder_type=folder_type, folder=folder, folder_key=folder_key
@@ -182,10 +231,14 @@ class MainFiQuS:
182
231
  required_folders = []
183
232
 
184
233
  fdm = self.main_magnet.fdm.magnet
234
+
185
235
  self.main_magnet.geom_folder = _check_and_generate_path(folder_type="Geometry")
186
- if not self.fdm.run.type in ["geometry_only", "plot_python"]:
236
+ if not self.fdm.run.type in ["geometry_only"]:
187
237
  self.main_magnet.mesh_folder = _check_and_generate_path(folder_type="Mesh")
188
- if not (self.fdm.run.type in ["geometry_only", "mesh_only", "plot_python"]):
238
+ if not (
239
+ self.fdm.run.type == "geometry_only"
240
+ or self.fdm.run.type == "mesh_only"
241
+ ):
189
242
  self.main_magnet.solution_folder = _check_and_generate_path(
190
243
  folder_type="Solution"
191
244
  )
@@ -195,9 +248,11 @@ class MainFiQuS:
195
248
  "geometry_and_mesh",
196
249
  "geometry_only",
197
250
  ]:
198
- Util.write_data_to_yaml(
251
+ Util.write_data_model_to_yaml(
199
252
  os.path.join(self.main_magnet.geom_folder, "geometry.yaml"),
200
- fdm.geometry.dict(by_alias=True),
253
+ fdm.geometry,
254
+ by_alias=True,
255
+ with_comments=True,
201
256
  )
202
257
  if self.fdm.run.type in [
203
258
  "start_from_yaml",
@@ -205,9 +260,11 @@ class MainFiQuS:
205
260
  "mesh_and_solve_with_post_process_python",
206
261
  "mesh_only",
207
262
  ]:
208
- Util.write_data_to_yaml(
263
+ Util.write_data_model_to_yaml(
209
264
  os.path.join(self.main_magnet.mesh_folder, "mesh.yaml"),
210
- fdm.mesh.dict(by_alias=True),
265
+ fdm.mesh,
266
+ by_alias=True,
267
+ with_comments=True,
211
268
  )
212
269
  if self.fdm.run.type in [
213
270
  "start_from_yaml",
@@ -215,10 +272,13 @@ class MainFiQuS:
215
272
  "solve_with_post_process_python",
216
273
  "solve_only",
217
274
  "post_process",
275
+ "plot_python"
218
276
  ]:
219
- Util.write_data_to_yaml(
277
+ Util.write_data_model_to_yaml(
220
278
  os.path.join(self.main_magnet.solution_folder, "solve.yaml"),
221
- fdm.solve.dict(by_alias=True),
279
+ fdm.solve,
280
+ by_alias=True,
281
+ with_comments=True,
222
282
  )
223
283
  if self.fdm.run.type in [
224
284
  "start_from_yaml",
@@ -227,101 +287,163 @@ class MainFiQuS:
227
287
  "post_process_python_only",
228
288
  "post_process_getdp_only",
229
289
  "post_process",
290
+ "plot_python"
230
291
  ]:
231
- Util.write_data_to_yaml(
292
+ Util.write_data_model_to_yaml(
232
293
  os.path.join(self.main_magnet.solution_folder, "postproc.yaml"),
233
- fdm.postproc.dict(by_alias=True),
294
+ fdm.postproc,
295
+ by_alias=True,
296
+ with_comments=True,
297
+ )
298
+
299
+ try:
300
+ run_type = self.fdm.run.type
301
+ comments = self.fdm.run.comments
302
+ if self.main_magnet.geom_folder is not None:
303
+ geo_folder = os.path.relpath(self.main_magnet.geom_folder)
304
+ geo_folder = os.path.relpath(
305
+ geo_folder, os.path.join("tests", "_outputs")
306
+ )
307
+ else:
308
+ geo_folder = "-"
309
+
310
+ if self.main_magnet.mesh_folder is not None:
311
+ mesh_folder = os.path.relpath(self.main_magnet.mesh_folder)
312
+ mesh_folder = os.path.relpath(
313
+ mesh_folder, os.path.join("tests", "_outputs")
314
+ )
315
+ else:
316
+ mesh_folder = "-"
317
+
318
+ if self.main_magnet.solution_folder is not None:
319
+ solution_folder = os.path.relpath(self.main_magnet.solution_folder)
320
+ solution_folder = os.path.relpath(
321
+ solution_folder, os.path.join("tests", "_outputs")
322
+ )
323
+ else:
324
+ solution_folder = "-"
325
+
326
+ run_log_row = [
327
+ self.time_stamp,
328
+ run_type,
329
+ comments,
330
+ geo_folder,
331
+ mesh_folder,
332
+ solution_folder,
333
+ ]
334
+ self.add_to_run_log(
335
+ os.path.join(self.wrk_folder, "run_log.csv"), run_log_row
234
336
  )
337
+ except:
338
+ self.logger.warning("Run log could not be completed.")
235
339
 
236
340
  def build_magnet(self):
237
- if self.fdm.run.type == "start_from_yaml": # needs 3 files (yaml, set, geom)
341
+ """
342
+ Main method to build magnets, i.e. to run various fiqus run types and magnet types
343
+ :return: none
344
+ :rtype: none
345
+ """
346
+ if self.fdm.run.type == "start_from_yaml":
238
347
  self.main_magnet.generate_geometry()
239
348
  self.main_magnet.pre_process()
240
349
  self.main_magnet.load_geometry()
241
350
  for key, value in self.main_magnet.mesh().items():
242
351
  self.summary[key] = value
243
- self.summary[
244
- "solution_time"
245
- ] = self.main_magnet.solve_and_postprocess_getdp()
246
- for key, value in self.main_magnet.post_process_python(
247
- gui=self.main_magnet.fdm.run.launch_gui
248
- ).items():
352
+ self.summary["solution_time"] = self.main_magnet.solve_and_postprocess_getdp()
353
+ for key, value in self.main_magnet.post_process_python(gui=self.main_magnet.fdm.run.launch_gui).items():
249
354
  self.summary[key] = value
355
+ elif self.fdm.run.type == "pre_process_only":
356
+ self.main_magnet.pre_process()
357
+ for key, value in self.main_magnet.post_process_python(gui=self.main_magnet.fdm.run.launch_gui).items():
358
+ self.summary[key] = value # todo: DISABLE FOR ONE GROUP ONLY
250
359
  elif self.fdm.run.type == "geometry_only":
251
- if len(os.listdir(self.main_magnet.geom_folder)) == 1:
252
- self.main_magnet.generate_geometry() # needs 3 files (yaml, set, geom)
360
+ self.main_magnet.generate_geometry(
361
+ gui=(self.main_magnet.fdm.run.launch_gui if self.fdm.magnet.type != "CCT_straight" else False)
362
+ )
363
+ if self.fdm.magnet.type in ["CCT_straight", "CWS"]:
253
364
  self.main_magnet.pre_process(gui=self.main_magnet.fdm.run.launch_gui)
254
- else:
255
- self.main_magnet.load_geometry(
256
- gui=self.main_magnet.fdm.run.launch_gui
257
- ) # needs 2 files (yaml, brep)
258
365
  elif self.fdm.run.type == "geometry_and_mesh":
259
366
  self.main_magnet.generate_geometry()
260
367
  self.main_magnet.pre_process()
261
368
  self.main_magnet.load_geometry()
262
369
  for key, value in self.main_magnet.mesh(gui=self.main_magnet.fdm.run.launch_gui).items():
263
370
  self.summary[key] = value
264
- elif (
265
- self.fdm.run.type == "mesh_and_solve_with_post_process_python"
266
- ): # needs 5 files (yaml, strs/map2d, set, brep, aux)
371
+ elif self.fdm.run.type == "mesh_and_solve_with_post_process_python":
267
372
  self.main_magnet.load_geometry()
268
373
  for key, value in self.main_magnet.mesh().items():
269
- self.summary[key] = value
270
- self.summary[
271
- "solution_time"
272
- ] = self.main_magnet.solve_and_postprocess_getdp()
273
- for key, value in self.main_magnet.post_process_python(
274
- gui=self.main_magnet.fdm.run.launch_gui
275
- ).items():
276
- self.summary[key] = value
374
+ self.summary[key] = value
375
+ self.summary["solution_time"] = self.main_magnet.solve_and_postprocess_getdp()
376
+ for key, value in self.main_magnet.post_process_python(gui=self.main_magnet.fdm.run.launch_gui).items():
377
+ self.summary[key] = value
277
378
  elif self.fdm.run.type == "mesh_only":
278
- if len(os.listdir(self.main_magnet.mesh_folder)) == 1:
279
- self.main_magnet.load_geometry() # needs 3 files (yaml, brep, aux)
280
- for key, value in self.main_magnet.mesh(
281
- gui=self.main_magnet.fdm.run.launch_gui
282
- ).items():
283
- self.summary[key] = value
284
- else:
285
- self.main_magnet.load_mesh(
286
- gui=self.main_magnet.fdm.run.launch_gui
287
- ) # needs 2 files (yaml, msh)
288
- elif (
289
- self.fdm.run.type == "solve_with_post_process_python"
290
- ): # needs 5 files (yaml, strs/map2d, set, msh, reg)
291
- self.summary[
292
- "solution_time"
293
- ] = self.main_magnet.solve_and_postprocess_getdp()
294
- for key, value in self.main_magnet.post_process_python(
295
- gui=self.main_magnet.fdm.run.launch_gui
296
- ).items():
379
+ self.main_magnet.load_geometry()
380
+ for key, value in self.main_magnet.mesh(gui=self.main_magnet.fdm.run.launch_gui).items():
381
+ self.summary[key] = value
382
+ elif self.fdm.run.type == "solve_with_post_process_python":
383
+ self.summary["solution_time"] = (
384
+ self.main_magnet.solve_and_postprocess_getdp(gui=self.main_magnet.fdm.run.launch_gui)
385
+ )
386
+ for key, value in self.main_magnet.post_process_python(gui=self.main_magnet.fdm.run.launch_gui).items():
297
387
  self.summary[key] = value
298
- elif (
299
- self.fdm.run.type == "solve_only"
300
- ): # needs 5 files (yaml, strs/map2d, set, msh, reg)
301
- self.summary[
302
- "solution_time"
303
- ] = self.main_magnet.solve_and_postprocess_getdp(
304
- gui=self.main_magnet.fdm.run.launch_gui
388
+ elif self.fdm.run.type == "solve_only":
389
+ self.summary["solution_time"] = (
390
+ self.main_magnet.solve_and_postprocess_getdp(gui=self.main_magnet.fdm.run.launch_gui)
305
391
  )
306
392
  elif self.fdm.run.type == "post_process_getdp_only":
307
393
  self.main_magnet.post_process_getdp(gui=self.main_magnet.fdm.run.launch_gui)
308
394
  elif self.fdm.run.type == "post_process_python_only":
309
- for key, value in self.main_magnet.post_process_python(
310
- gui=self.main_magnet.fdm.run.launch_gui
311
- ).items():
395
+ for key, value in self.main_magnet.post_process_python(gui=self.main_magnet.fdm.run.launch_gui).items():
312
396
  self.summary[key] = value
313
397
  elif self.fdm.run.type == "post_process":
314
398
  self.main_magnet.post_process_getdp(gui=self.main_magnet.fdm.run.launch_gui)
315
- for key, value in self.main_magnet.post_process_python(
316
- gui=self.main_magnet.fdm.run.launch_gui
317
- ).items():
399
+ for key, value in self.main_magnet.post_process_python(gui=self.main_magnet.fdm.run.launch_gui).items():
318
400
  self.summary[key] = value
319
401
  elif self.fdm.run.type == "plot_python":
320
402
  self.main_magnet.plot_python()
403
+
321
404
  elif self.fdm.run.type == "batch_post_process_python":
322
405
  self.main_magnet.batch_post_process_python()
323
406
  os.chdir(self.start_folder)
324
407
 
408
+ if self.file_name: json.dump(self.summary, open(f"{os.path.join(self.wrk_folder, self.file_name)}.json", 'w'))
409
+ # mesh_par = self.fdm.magnet.mesh
410
+ # if self.summary['solution_time']:
411
+ # with open(r"C:\Users\avitrano\PycharmProjects\steam_sdk\tests\parsims\FiQuS_run\summary.dat", 'a') as f:
412
+ # content = (f"{mesh_par.mesh_coil.SizeMin} {mesh_par.mesh_coil.SizeMax} {mesh_par.mesh_iron.SizeMin} {mesh_par.mesh_iron.SizeMax} "
413
+ # f"{self.summary['solution_time']} {self.summary['overall_error']} {self.summary['overall_error'] * 0.999 + self.summary['solution_time'] * 0.001} "
414
+ # f"{self.summary['SJ']} {self.summary['SICN']} {self.summary['SIGE']} {self.summary['Gamma']} "
415
+ # f"{self.summary['nodes']} {self.summary['minimum_diff']} {self.summary['maximum_diff']}\n")
416
+ # f.writelines(content)
417
+
418
+ @staticmethod
419
+ def add_to_run_log(path_to_csv, run_log_row):
420
+ # If file does not exist, write the header
421
+ if not os.path.isfile(path_to_csv):
422
+ header = [
423
+ "Time Stamp",
424
+ "Run Type",
425
+ "Comments",
426
+ "Geometry Directory",
427
+ "Mesh Directory",
428
+ "Solution Directory",
429
+ ]
430
+ with open(path_to_csv, "a", newline="") as csv_file:
431
+ writer = csv.writer(csv_file)
432
+ writer.writerow(header)
433
+
434
+ # Open the CSV file in append mode
435
+ with open(path_to_csv, "a+", newline="") as csv_file:
436
+ writer = csv.writer(csv_file)
437
+ writer.writerow(run_log_row)
438
+
439
+ def change_htcondor_run_log(self, htcondor_csv_file, htcondor_jobid, new_status="None"):
440
+ try:
441
+ df = pd.read_csv(htcondor_csv_file)
442
+ df.loc[df['Job ID'] == htcondor_jobid, 'Status'] = str(new_status)
443
+ self.logger.info(f"Changed status of JobID {htcondor_jobid} to {new_status} in {htcondor_csv_file}.")
444
+ df.to_csv(htcondor_csv_file, index=False)
445
+ except:
446
+ self.logger.warning(f"Could not change status of JobID {htcondor_jobid} to {new_status} in {htcondor_csv_file}.")
325
447
 
326
448
  if __name__ == "__main__":
327
449
  parser = argparse.ArgumentParser(
@@ -340,14 +462,48 @@ if __name__ == "__main__":
340
462
  parser.add_argument(
341
463
  "--getdp", '-g', dest="GetDP_path", type=str, help="Full path to GetDP executable"
342
464
  )
465
+
466
+ parser.add_argument("--htcondor_jobid", '-j', type=int, default=0,
467
+ help="HTCondor job ID (optional)", required=False)
468
+
469
+ parser.add_argument("--fiqus_data_model", '-m', type=str,
470
+ help="Full path to FiQuS Data Model file (optional)", required=False)
471
+
472
+ parser.add_argument("--fiqus_data_settings", '-s', type=str,
473
+ help="Full path to FiQuS Data Settings file (optional)", required=False)
474
+
343
475
  args, unknown = parser.parse_known_args()
344
- # args = parser.parse_args()
345
- # print(args.full_path_input)
346
- # print(args.output_path)
347
- # print(args.GetDP_path)
348
- MainFiQuS(
349
- input_file_path=args.full_path_input,
350
- model_folder=args.output_path,
351
- GetDP_path=args.GetDP_path,
352
- )
476
+
477
+ # remove these options from sys.argv, otherwise they are passed onto Gmsh
478
+ # in Gmsh.initialize()
479
+ options_to_remove = ["-o", "-g", "-j", "-m", "-s"]
480
+ # Loop through and remove each option and its value
481
+ i = 0
482
+ while i < len(sys.argv):
483
+ if sys.argv[i] in options_to_remove:
484
+ sys.argv.pop(i) # Remove the option
485
+ if i < len(sys.argv):
486
+ sys.argv.pop(i) # Remove the associated value
487
+ else:
488
+ i += 1
489
+
490
+ if args.fiqus_data_model != None and args.fiqus_data_settings != None:
491
+ # read fdm and fds from a file (HTCondor case)
492
+ input_fdm = Util.read_data_from_yaml(args.fiqus_data_model, FDM)
493
+ input_fds = Util.read_data_from_yaml(args.fiqus_data_settings, DataSettings)
494
+
495
+ MainFiQuS(
496
+ input_file_path=args.full_path_input,
497
+ model_folder=args.output_path,
498
+ fdm=input_fdm,
499
+ fds=input_fds,
500
+ htcondor_jobid=args.htcondor_jobid
501
+ )
502
+ else:
503
+ # fdm and fds from input (STEAM SDK case)
504
+ MainFiQuS(
505
+ input_file_path=args.full_path_input,
506
+ model_folder=args.output_path,
507
+ GetDP_path=args.GetDP_path,
508
+ )
353
509
  print("FiQuS run completed")