2 # -*- coding: utf-8 -*-
3 ## Copyright (C) 2021-2023 CEA/DEN, EDF R&D, OPEN CASCADE
5 ## This library is free software; you can redistribute it and/or
6 ## modify it under the terms of the GNU Lesser General Public
7 ## License as published by the Free Software Foundation; either
8 ## version 2.1 of the License, or (at your option) any later version.
10 ## This library is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ## Lesser General Public License for more details.
15 ## You should have received a copy of the GNU Lesser General Public
16 ## License along with this library; if not, write to the Free Software
17 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ## See http://www.salome-platform.org/ or email :
20 ## webmaster.salome@opencascade.com
23 File to run mesher from command line
25 from os import environ, path
27 import subprocess as sp
29 from argparse import ArgumentParser
33 MESHER_HANDLED = ["NETGEN3D","NETGEN2D","NETGEN1D","NETGEN1D2D","NETGEN1D2D","GMSH3D"]
36 """{runner} {mesher} {mesh_file} {shape_file} {param_file} {elem_orientation_file} {new_element_file} {output_mesh_file} > {log_file} 2>&1"""
40 import subprocess as sp
44 output = sp.check_output(cmd, shell=True)
46 except sp.CalledProcessError as e:
49 error_code = e.returncode
54 def create_launcher():
55 """ Initialise pylauncher
57 launcher = pylauncher.Launcher_cpp()
58 launcher.SetResourcesManager(create_resources_manager())
61 def create_resources_manager():
62 """ Look for the catalog file and create a ressource manager with it """
63 # localhost is defined anyway, even if the catalog file does not exist.
64 catalog_path = environ.get("USER_CATALOG_RESOURCES_FILE", "")
65 if not path.isfile(catalog_path):
66 salome_path = environ.get("ROOT_SALOME_INSTALL", "")
67 catalog_path = path.join(salome_path, "CatalogResources.xml")
68 if not path.isfile(catalog_path):
71 return pylauncher.ResourcesManager_cpp(catalog_path)
73 def create_job_parameters():
74 """ Initialsie JobParameters """
75 jparam = pylauncher.JobParameters_cpp()
76 jparam.resource_required = create_resource_parameters()
79 def create_resource_parameters():
80 """ Init resourceParams """
81 return pylauncher.resourceParams()
83 def get_runner(mesher):
85 Get path to exe for mesher
88 mesher: Name of the mesher (NETGEN2D/NETGEN3D...)
90 retuns (string) Path to the exe
92 if sys.platform.startswith('win'):
97 if mesher in ['NETGEN3D','NETGEN2D','NETGEN1D','NETGEN1D2D','NETGEN1D2D']:
98 exe_path = path.join("${NETGENPLUGIN_ROOT_DIR}",
101 "NETGENPlugin_Runner"+ext)
102 elif mesher in ['GMSH3D']:
103 exe_path = path.join("${GMSHPLUGIN_ROOT_DIR}",
106 "GMSHPlugin_Runner"+ext)
108 raise Exception("Mesher {mesher} is not handled".format(mesher=mesher))
113 """ Simple Local run """
114 #TODO: Check on how to handle log for windows (through sp.check_output)
115 cmd = CMD_TEMPLATE.format(\
116 runner=get_runner(args.mesher),
118 mesh_file=args.input_mesh_file,
119 shape_file=args.shape_file,
120 param_file=args.hypo_file,
121 elem_orientation_file=args.elem_orient_file,
122 new_element_file=args.new_element_file,
123 log_file=path.join(path.dirname(args.shape_file), "run.log"),
124 output_mesh_file=args.output_mesh_file)
127 sp.check_output(cmd, shell=True, cwd=path.dirname(args.shape_file))
129 def run_pylauncher(args):
130 """ Run exe throuhg pylauncher """
134 cmd = CMD_TEMPLATE.format(\
135 runner=get_runner(args.mesher),
137 mesh_file="../"+path.basename(args.input_mesh_file),
138 shape_file=path.basename(args.shape_file),
139 param_file=path.basename(args.hypo_file),
140 elem_orientation_file=path.basename(args.elem_orient_file),
141 new_element_file=path.basename(args.new_element_file),
143 output_mesh_file=path.basename(args.output_mesh_file))
148 launcher = create_launcher()
150 # See SALOME_Launcher documentation for parameters
151 job_params = create_job_parameters()
152 # different type are:
153 # command Shell out of salome session
154 # command_salome Shell in salome shell
155 # python_salome Python script
157 job_params.job_type = "command_salome" # creates CatalogResources.xml
159 job_params.wckey = args.wc_key
160 job_params.resource_required.nb_proc = args.nb_proc
161 job_params.resource_required.nb_proc_per_node = args.nb_proc_per_node
162 job_params.resource_required.nb_node = args.nb_node
163 job_params.maximum_duration = args.walltime
165 # job_params.pre_command = pre_command # command to run on frontal
166 # script to run in batch mode
167 run_script = path.join(path.dirname(args.shape_file), "run.sh")
168 with open(run_script, "w") as f:
169 f.write("#!/bin/bash\n")
171 job_params.job_file = run_script
173 local_dir = path.dirname(args.shape_file)
175 # files to copy to remote working dir
176 # Directories are copied recursively.
177 # job_file script is automaticaly copied.
178 job_params.in_files = [args.shape_file,
180 args.elem_orient_file]
182 print("in_files", job_params.in_files)
183 # local path for in_files
184 job_params.local_directory = local_dir
185 # result files you want to bring back with getJobResults
186 # TODO: replace run.log by argument ? by path
187 out_files = ["run.log"]
188 if args.new_element_file != "NONE":
189 out_files.append(path.relpath(args.new_element_file, local_dir))
190 if args.output_mesh_file != "NONE":
191 out_files.append(path.relpath(args.output_mesh_file, local_dir))
192 job_params.out_files = out_files
193 print("out_files", job_params.out_files)
194 # local path where to copy out_files
195 job_params.result_directory = local_dir
197 job_params.job_name = "SMESH_parallel"
198 job_params.resource_required.name = args.resource
201 # String that is directly added to the job submission file
202 # job_params.extra_params = "#SBATCH --nodes=2"
204 # remote job directory
205 # Retrieve working dir from catalog
206 res_manager = create_resources_manager()
207 res_params = res_manager.GetResourceDefinition(args.resource)
208 job_params.work_directory = path.join(\
209 res_params.working_directory,
210 path.basename(path.dirname(path.dirname(args.shape_file))),
211 path.basename(path.dirname(args.shape_file)))
212 print("work directory", job_params.work_directory)
214 job_id = launcher.createJob(job_params) #SALOME id of the job
215 launcher.launchJob(job_id) # copy files, run pre_command, submit job
217 # wait for the end of the job
218 job_state = launcher.getJobState(job_id)
219 print("Job %d state: %s" % (job_id, job_state))
220 while job_state not in ["FINISHED", "FAILED"]:
222 job_state = launcher.getJobState(job_id)
224 if job_state == "FAILED":
225 raise Exception("Job failed")
227 # verify the return code of the execution
228 if(launcher.getJobWorkFile(job_id,
229 "logs/exit_code.log",
230 job_params.result_directory)):
231 exit_code_file = path.join(job_params.result_directory,
234 if path.isfile(exit_code_file):
235 with open(exit_code_file) as myfile:
236 exit_code = myfile.read()
237 exit_code = exit_code.strip()
240 "An error occured during the execution of the job.")
242 raise Exception("Failed to get the exit code of the job.")
244 # Retrieve result files
245 launcher.getJobResults(job_id, "")
247 # Delete remote working dir
248 del_tmp_folder = True
250 val = int(environ.get("SMESH_KEEP_TMP", "0"))
251 del_tmp_folder = val < 0
252 except Exception as e:
253 del_tmp_folder = True
256 launcher.clearJobWorkingDir(job_id)
259 """ Define and parse arguments for the script """
260 parser = ArgumentParser()
261 parser.add_argument("mesher",
262 choices=MESHER_HANDLED,
263 help="mesher to use from ("+",".join(MESHER_HANDLED)+")")
264 parser.add_argument("input_mesh_file",\
265 help="MED File containing lower-dimension-elements already meshed")
266 parser.add_argument("shape_file",
267 help="STEP file containing the shape to mesh")
268 parser.add_argument("hypo_file",
269 help="Ascii file containint the list of parameters")
270 parser.add_argument("--elem-orient-file",\
271 help="binary file containing the list of elements from "\
272 "INPUT_MESH_FILE associated to the shape and their orientation")
273 # Output file parameters
274 output = parser.add_argument_group("Output files", "Possible output files")
275 output.add_argument("--new-element-file",
277 help="contains elements and nodes added by the meshing")
278 output.add_argument(\
279 "--output-mesh-file",
281 help="MED File containing the mesh after the run of the mesher")
284 run_param = parser.add_argument_group(\
286 "Parameters for the run of the mesher")
287 run_param.add_argument("--method",
289 choices=["local", "cluster"],
290 help="Running method (default: local)")
292 run_param.add_argument("--resource",
293 help="resource from SALOME Catalog")
294 run_param.add_argument("--nb-proc",
297 help="Number of processors")
298 run_param.add_argument("--nb-proc-per-node",
301 help="Number of processeor per node")
302 run_param.add_argument("--nb-node",
305 help="Number of node")
306 run_param.add_argument("--walltime",
308 help="walltime for job submission HH:MM:SS (default 01:00:00)")
309 run_param.add_argument("--wc-key",
310 default="P11N0:SALOME",
311 help="wc-key for job submission (default P11N0:SALOME)")
313 args = parser.parse_args()
318 """ Main function """
320 if args.method == "local":
322 elif args.method == "cluster":
325 raise Exception("Unknown method {}".format(args.method))
327 if __name__ == "__main__":