-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-## Copyright (C) 2021-2023 CEA/DEN, EDF R&D, OPEN CASCADE
-##
-## This library is free software; you can redistribute it and/or
-## modify it under the terms of the GNU Lesser General Public
-## License as published by the Free Software Foundation; either
-## version 2.1 of the License, or (at your option) any later version.
-##
-## This library is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-## Lesser General Public License for more details.
-##
-## You should have received a copy of the GNU Lesser General Public
-## License along with this library; if not, write to the Free Software
-## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##
-## See http://www.salome-platform.org/ or email :
-## webmaster.salome@opencascade.com
-##
-"""
-File to run mesher from command line
-"""
-#TODO: Make the execution path independant (output files are written in current directory)
-from os import environ, path
-import sys
-import subprocess as sp
-
-from argparse import ArgumentParser
-import pydefx
-import pylauncher
-
-MESHER_HANDLED = ["NETGEN3D"]
-
-CMD_TEMPLATE = \
-"""{runner} {mesher} {mesh_file} {shape_file} {param_file} {elem_orientation_file} {new_element_file} {output_mesh_file} > {log_file} 2>&1"""
-
-PYTHON_CODE = \
-"""
-import subprocess as sp
-def _exec(cmd):
- error_code = -1
- try:
- output = sp.check_output(cmd, shell=True)
- error_code = 0
- except sp.CalledProcessError as e:
- print('Code crash')
- print(e.output)
- error_code = e.returncode
- raise e
- return error_code
-"""
-
-def create_launcher():
- """ Initialise pylauncher
- """
- launcher = pylauncher.Launcher_cpp()
- launcher.SetResourcesManager(create_resources_manager())
- return launcher
-
-def create_resources_manager():
- """ Look for the catalog file and create a ressource manager with it """
- # localhost is defined anyway, even if the catalog file does not exist.
- catalog_path = environ.get("USER_CATALOG_RESOURCES_FILE", "")
- if not path.isfile(catalog_path):
- salome_path = environ.get("ROOT_SALOME_INSTALL", "")
- catalog_path = path.join(salome_path, "CatalogResources.xml")
- if not path.isfile(catalog_path):
- catalog_path = ""
-
- return pylauncher.ResourcesManager_cpp(catalog_path)
-
-def create_job_parameters():
- """ Initialsie JobParameters """
- jparam = pylauncher.JobParameters_cpp()
- jparam.resource_required = create_resource_parameters()
- return jparam
-
-def create_resource_parameters():
- """ Init resourceParams """
- return pylauncher.resourceParams()
-
-def get_runner(mesher):
- """
- Get path to exe for mesher
-
- Arguments:
- mesher: Name of the mesher (NETGEN2D/NETGEN3D...)
-
- retuns (string) Path to the exe
- """
- if sys.platform.startswith('win'):
- ext = ".exe"
- else:
- ext = ""
-
- if mesher in ['NETGEN3D']:
- exe_path = path.join("${NETGENPLUGIN_ROOT_DIR}",
- "bin",
- "salome",
- "NETGENPlugin_Runner"+ext)
- else:
- raise Exception("Mesher {mesher} is not handled".format(mesher=mesher))
-
- return exe_path
-
-def run_local(args):
- """ Simple Local run """
- print("Local run")
- #TODO: Check on how to handle log for windows (through sp.check_output)
- cmd = CMD_TEMPLATE.format(\
- runner=get_runner(args.mesher),
- mesher=args.mesher,
- mesh_file=args.input_mesh_file,
- shape_file=args.shape_file,
- param_file=args.hypo_file,
- elem_orientation_file=args.elem_orient_file,
- new_element_file=args.new_element_file,
- log_file=path.join(path.dirname(args.shape_file), "run.log"),
- output_mesh_file=args.output_mesh_file)
- print("Executing:")
- print(cmd)
- sp.check_output(cmd, shell=True, cwd=path.dirname(args.shape_file))
-
-def run_pylauncher(args):
- """ Run exe throuhg pylauncher """
- import time
- print("Cluster run")
-
- cmd = CMD_TEMPLATE.format(\
- runner=get_runner(args.mesher),
- mesher=args.mesher,
- mesh_file="../"+path.basename(args.input_mesh_file),
- shape_file=path.basename(args.shape_file),
- param_file=path.basename(args.hypo_file),
- elem_orientation_file=path.basename(args.elem_orient_file),
- new_element_file=path.basename(args.new_element_file),
- log_file="run.log",
- output_mesh_file=path.basename(args.output_mesh_file))
-
- print("Cmd: ", cmd)
-
- # salome launcher
- launcher = create_launcher()
-
- # See SALOME_Launcher documentation for parameters
- job_params = create_job_parameters()
- # different type are:
- # command Shell out of salome session
- # command_salome Shell in salome shell
- # python_salome Python script
- # yacs_file
- job_params.job_type = "command_salome" # creates CatalogResources.xml
-
- job_params.wckey = args.wc_key
- job_params.resource_required.nb_proc = args.nb_proc
- job_params.resource_required.nb_proc_per_node = args.nb_proc_per_node
- job_params.resource_required.nb_node = args.nb_node
-
- # job_params.pre_command = pre_command # command to run on frontal
- # script to run in batch mode
- run_script = path.join(path.dirname(args.shape_file), "run.sh")
- with open(run_script, "w") as f:
- f.write("#!/bin/bash\n")
- f.write(cmd)
- job_params.job_file = run_script
-
- local_dir = path.dirname(args.shape_file)
-
- # files to copy to remote working dir
- # Directories are copied recursively.
- # job_file script is automaticaly copied.
- job_params.in_files = [args.shape_file,
- args.hypo_file,
- args.elem_orient_file]
-
- print("in_files", job_params.in_files)
- # local path for in_files
- job_params.local_directory = local_dir
- # result files you want to bring back with getJobResults
- # TODO: replace run.log by argument ? by path
- out_files = ["run.log"]
- if args.new_element_file != "NONE":
- out_files.append(path.relpath(args.new_element_file, local_dir))
- if args.output_mesh_file != "NONE":
- out_files.append(path.relpath(args.output_mesh_file, local_dir))
- job_params.out_files = out_files
- print("out_files", job_params.out_files)
- # local path where to copy out_files
- job_params.result_directory = local_dir
-
- job_params.job_name = "SMESH_parallel"
- job_params.resource_required.name = args.resource
-
- # Extra parameters
- # String that is directly added to the job submission file
- # job_params.extra_params = "#SBATCH --nodes=2"
-
- # remote job directory
- # Retrieve working dir from catalog
- res_manager = create_resources_manager()
- res_params = res_manager.GetResourceDefinition(args.resource)
- job_params.work_directory = path.join(\
- res_params.working_directory,
- path.basename(path.dirname(path.dirname(args.shape_file))),
- path.basename(path.dirname(args.shape_file)))
- print("work directory", job_params.work_directory)
-
- job_id = launcher.createJob(job_params) #SALOME id of the job
- launcher.launchJob(job_id) # copy files, run pre_command, submit job
-
- # wait for the end of the job
- job_state = launcher.getJobState(job_id)
- print("Job %d state: %s" % (job_id, job_state))
- while job_state not in ["FINISHED", "FAILED"]:
- time.sleep(3)
- job_state = launcher.getJobState(job_id)
-
- if job_state == "FAILED":
- raise Exception("Job failed")
- else:
- # verify the return code of the execution
- if(launcher.getJobWorkFile(job_id,
- "logs/exit_code.log",
- job_params.result_directory)):
- exit_code_file = path.join(job_params.result_directory,
- "exit_code.log")
- exit_code = ""
- if path.isfile(exit_code_file):
- with open(exit_code_file) as myfile:
- exit_code = myfile.read()
- exit_code = exit_code.strip()
- if exit_code != "0":
- raise Exception(\
- "An error occured during the execution of the job.")
- else:
- raise Exception("Failed to get the exit code of the job.")
-
- # Retrieve result files
- launcher.getJobResults(job_id, "")
-
- # Delete remote working dir
- launcher.clearJobWorkingDir(job_id)
-
-def def_arg():
- """ Define and parse arguments for the script """
- parser = ArgumentParser()
- parser.add_argument("mesher",
- choices=MESHER_HANDLED,
- help="mesher to use from ("+",".join(MESHER_HANDLED)+")")
- parser.add_argument("input_mesh_file",\
- help="MED File containing lower-dimension-elements already meshed")
- parser.add_argument("shape_file",
- help="STEP file containing the shape to mesh")
- parser.add_argument("hypo_file",
- help="Ascii file containint the list of parameters")
- parser.add_argument("--elem-orient-file",\
- help="binary file containing the list of elements from "\
- "INPUT_MESH_FILE associated to the shape and their orientation")
- # Output file parameters
- output = parser.add_argument_group("Output files", "Possible output files")
- output.add_argument("--new-element-file",
- default="NONE",
- help="contains elements and nodes added by the meshing")
- output.add_argument(\
- "--output-mesh-file",
- default="NONE",
- help="MED File containing the mesh after the run of the mesher")
-
- # Run parameters
- run_param = parser.add_argument_group(\
- "Run parameters",
- "Parameters for the run of the mesher")
- run_param.add_argument("--method",
- default="local",
- choices=["local", "cluster"],
- help="Running method (default: local)")
-
- run_param.add_argument("--resource",
- help="resource from SALOME Catalog")
- run_param.add_argument("--nb-proc",
- default=1,
- type=int,
- help="Number of processors")
- run_param.add_argument("--nb-proc-per-node",
- default=1,
- type=int,
- help="Number of processeor per node")
- run_param.add_argument("--nb-node",
- default=1,
- type=int,
- help="Number of node")
- run_param.add_argument("--wc-key",
- default="P11N0:SALOME",
- help="wc-key for job submission (default P11N0:SALOME)")
-
- args = parser.parse_args()
-
- return args
-
-def main():
- """ Main function """
- args = def_arg()
- if args.method == "local":
- run_local(args)
- elif args.method == "cluster":
- run_pylauncher(args)
- else:
- raise Exception("Unknown method {}".format(args.method))
-
-if __name__ == "__main__":
- main()