From f2dd979943d3ec1026c73a9927f2b429002de4fa Mon Sep 17 00:00:00 2001 From: Christian Van Wambeke Date: Wed, 26 Feb 2020 10:07:01 +0100 Subject: [PATCH] ok mpi and multithread, see example/ghs3dprh_multithread_cube_one_face.py --- bin/mg-tetra_hpc.py | 287 +++++++++++++----- doc/help_mg-tetra_hpc_mpi.txt | 1 + example/ghs3dprh_multithread_cube_one_face.py | 100 ++++++ .../GHS3DPRLPlugin_GHS3DPRL.cxx | 16 +- src/tepal2med/ghs3dprl_mesh_wrap.cxx | 217 +++++++++---- src/tepal2med/ghs3dprl_mesh_wrap.h | 2 + src/tepal2med/tetrahpc2med.cxx | 185 ++++++++--- 7 files changed, 623 insertions(+), 185 deletions(-) mode change 100644 => 100755 bin/mg-tetra_hpc.py create mode 100644 doc/help_mg-tetra_hpc_mpi.txt create mode 100644 example/ghs3dprh_multithread_cube_one_face.py diff --git a/bin/mg-tetra_hpc.py b/bin/mg-tetra_hpc.py old mode 100644 new mode 100755 index 30bb1e5..b244d13 --- a/bin/mg-tetra_hpc.py +++ b/bin/mg-tetra_hpc.py @@ -25,9 +25,18 @@ run mg_tetra_hpc.exe or mg_tetra_hpc_mpi.exe example linux usage: -- simple run: - ./mg-tetra_hpc.py --help - ./mg-tetra_hpc.py -n 3 --in /tmp/GHS3DPRL.mesh --out /tmp/GHS3DPRL_out.mesh --gradation 1.05 --min_size 0.001 --max_size 1.1 --multithread no > /tmp/tetrahpc.log +| ./mg-tetra_hpc.py --help +| ./mg-tetra_hpc.py -n 3 --in /tmp/GHS3DPRL.mesh --out /tmp/GHS3DPRL_out.mesh --gradation 1.05 --min_size 0.001 --max_size 1.1 --multithread no > /tmp/tetrahpc.log + +note: +| openmpi environment have to be set, may be as user choice +| example for centos7/redhat7: +| module load mpi/openmpi-x86_64 +| which mpicc +| example without module load (old): +| # may be prefer set before salome launch +| OPENMPI_INSTALL_DIR = ".../openmpi-1.8.4/FROM_nothing/bin" +| export PATH=${OPENMPI_INSTALL_DIR}:${PATH} """ import os @@ -41,14 +50,14 @@ import pprint as PP # pretty print import subprocess as SP # Popen -verbose = False +debug = False -OK = "ok" +OK = "OK" KO = "KO" OKSYS = 0 # for linux KOSYS = 1 # for linux -NB_PROCS = MP.cpu_count() # current cpu number of proc +NB_PROCS = MP.cpu_count() # current cpu number of proc NAME_OS = platform.system() # 'Linux' or 'Windows' @@ -56,8 +65,42 @@ NAME_OS = platform.system() # 'Linux' or 'Windows' # utilities ########################################################################## + +########################################################################## +def log_debug(msg): + if args.verbose: + log_print("DEBUG", msg) + +def log_info(msg): + log_print("INFO", msg) + +def log_warning(msg): + log_print("WARNING", msg) + +def log_error(msg): + log_print("ERROR", msg) + +def log_print(level, msg): + print("%-7s : %s" % (level, indent(msg))) + +def indent(msg, ind='\n | '): + if '\n' in msg: + return msg.replace('\n', ind) + else: + return msg + +def test_log(msg): + log_debug(msg) + log_info(msg) + log_warning(msg) + log_error(msg) + + +########################################################################## def okToSys(aResult, verbose=False): - """to get windows or linux result of script""" + """ + to get windows or linux result of script + """ def extendList(alist): """utility extend list of lists of string results with ok or KO""" @@ -75,25 +118,29 @@ def okToSys(aResult, verbose=False): resList = extendList(aResult) if resList == []: - if verbose: print("WARNING: result no clear: []") + log_error("result no clear with empty list of OK/KO") return KOSYS rr = OK for ri in resList: - if ri[0:2] != OK: - if verbose: print(ri) + if ri[0:2].upper() != OK: + log_debug("KO in '%s'" % ri) rr = KO - if verbose: print(("INFO: result: %s" % rr)) + log_info("result is %s" % rr) if rr == OK: return OKSYS else: return KOSYS + ########################################################################## def getDirAndName(datafile): - path, namefile = os.path.split(os.path.realpath(datafile)) + """ + returns (directory_realpath, os.getcwd(), name_file) + """ rootpath = os.getcwd() + path, namefile = os.path.split(os.path.realpath(datafile)) return (path, rootpath, namefile) @@ -112,74 +159,89 @@ class ArgRange(object): def __repr__(self): return "[%s,%s]" % (self.start, self.end) - ########################################################################## def exec_command(cmd, verbose=False): """Exec ONE command with popen""" time.sleep(3) # wait for (MPI) flush files - if verbose: print(("launch process:\n %s" % cmd)) + log_debug("launch subprocess:\n%s" % cmd) try: - pipe = SP.Popen(cmd, shell=True, stdout=SP.PIPE, stderr=SP.PIPE) + pipe = SP.Popen(cmd, shell=True, stdout=SP.PIPE, stderr=SP.STDOUT) except Exception as e: - result = KO + " ERROR: we have a problem popen on: %s" % PP.pformat(cmd) + log_error("Problem launching subprocess:\n%s" % cmd) + result = "KO Problem launching subprocess" return result (out, error) = pipe.communicate() pipe.wait() - print(out) - print(error) - - result = OK + " INFO: seems final ok for: %s" % PP.pformat(cmd) + log_info("subprocess log:\n%s" % out.decode("utf-8")) time.sleep(3) # wait for (MPI) flush files - return result + if pipe.returncode == 0: # return code of last command + result = "OK subprocess result (of last command)" + log_debug(result) + else: + log_error("KO subprocess result (of last command): %s" % pipe.returncode) + result = "KO for:\n%s" % cmd + + if error is not None: + log_error("KO subprocess stderr:\n%s" % error.decode("utf-8")) + result = "KO for:\n%s" % cmd + return result ########################################################################## def force_DISTENE_LICENSE_FILE(): """ conditionaly overriding/set environ variable DISTENE_LICENSE_FILE, from/if existing FORCE_DISTENE_LICENSE_FILE environ variable - (for test new version MeshGems etc...) - """ - """ - #example: - DISTENE_LICENSE_FILE=Use global envvar: DLIM8VAR - DLIM8VAR=dlim8 1:1:29030@132.166.151.49/84c419b8::87af196ab2a936ab31363624539bff8096fbe1f3c83028c8f6b399b0a904ef85 - overriden by - FORCE_DISTENE_LICENSE_FILE=/export/home/wambeke/essai_meshgems2.3/dlim8.key + (useful when test new version MeshGems with local DISTENE_LICENSE_FILE) + + example: + DISTENE_LICENSE_FILE=Use global envvar: DLIM8VAR + DLIM8VAR=dlim8 1:1:29030@132.166.151.49/84c419b8::87af... etc. + overriden by + FORCE_DISTENE_LICENSE_FILE=/home/$USER/licence_meshgems2.3/dlim8.key """ force = os.getenv("FORCE_DISTENE_LICENSE_FILE") if force != None: os.environ["DISTENE_LICENSE_FILE"] = force os.environ["DLIM8VAR"] = "NOTHING" - """ - #export PATH=/export/home/prerequisites_SALOME_780_LAURENT/openmpi-1.8.4/FROM_nothing/bin:$PATH - #do not work prefer set before salome launch - OPENMPI_INSTALL_DIR = "/export/home/prerequisites_SALOME_780_LAURENT/openmpi-1.8.4/FROM_nothing/bin" - sys.path.insert(0, OPENMPI_INSTALL_DIR) - #INSTALL_DIR = /export/home/prerequisites_SALOME_780_LAURENT/openmpi-1.8.4/FROM_nothing - for i in sys.path[0:10]: print "PATH",i - """ - - ########################################################################## def launchMultithread(args): - if verbose: print(("INFO: launchMultithread for %s" % NAME_OS)) + log_info("launch multithread for %s" % NAME_OS) if NAME_OS == 'Linux': # --out is ONE file: basename_tetra_hpc.mesh - outputMulti = os.path.splitext(args.inputFile)[0] + "_tetra_hpc.mesh" # only one file if Multithread - outputs = os.path.splitext(args.outputFiles)[0] - outputMultiAsMpi = os.path.splitext(args.outputFiles)[0] + ".000001.mesh" # create one output file named as only one from mpi - cmd = "mg-tetra_hpc.exe --max_number_of_threads %i --in %s --gradation %s --max_size %s --min_size %s; cp %s %s; ls -alt %s*; " % \ - (args.number, args.inputFile, args.gradation, args.max_size, args.min_size, outputMulti, outputMultiAsMpi, outputs) + args.outputs = os.path.splitext(args.outputFiles)[0] # use args.__dict__ + args.currentdir = os.path.splitext(args.outputFiles)[0] # use args.__dict__ + + # args.outputMulti = os.path.splitext(args.inputFile)[0] + "_tetra_hpc.mesh" # only one file if mg-tetra_hpc.exe multithread + args.outputMultiAsMpi = os.path.splitext(args.outputFiles)[0] + ".000001.mesh" # create one output file named as mpi (as only one process) + + cmd = """ +set -x + +# mpirun mg-tetra_hpc_mpi.exe + rm %(outputs)s* # clean previous case + mg-tetra_hpc.exe \ +--max_number_of_threads %(number)s \ +--in %(inputFile)s \ +--out %(outputFiles)s \ +--gradation %(gradation)s \ +--max_size %(max_size)s \ +--min_size %(min_size)s + # create force symbolic link as no duplicate multithread output file as MPI output file (as only one process) + ln -sf %(outputFiles)s %(outputMultiAsMpi)s +""" % args.__dict__ + # args.number, args.inputFile, args.gradation, args.max_size, args.min_size, outputMulti, outputMultiAsMpi, outputs else: - return KO + " ERROR: unknown operating system: %s" % NAME_OS + msg = "unknown operating system: %s" % NAME_OS + log_error(msg) + return KO + msg result = exec_command(cmd, verbose=True) return result @@ -188,48 +250,77 @@ def launchMultithread(args): ########################################################################## def launchMpi(args): - if verbose: print(("INFO: launchMpi for %s" % NAME_OS)) + log_info("launch MPI for %s" % NAME_OS) if NAME_OS == 'Linux': - cmd = "" - - """ compile libmeshgems_mpi.so: no needs - COMPILDIR=os.getenv("MESHGEMSHOME") + "/stubs" - TARGETDIR=os.getenv("MESHGEMSHOME") + "/lib/Linux_64" - cmd = "which mg-tetra_hpc_mpi.exe; which mpicc; rm /tmp/GHS3DPRL_out*; " - cmd += "cd %s; mpicc meshgems_mpi.c -DMESHGEMS_LINUX_BUILD -I../include -shared -fPIC -o %s/libmeshgems_mpi.so; " % (COMPILDIR, TARGETDIR) - """ - - outputs = os.path.splitext(args.outputFiles)[0] - cmd += "mpirun -n %i mg-tetra_hpc_mpi.exe --in %s --out %s --gradation %s --max_size %s --min_size %s; ls -alt %s*; " % \ - (args.number, args.inputFile, args.outputFiles, args.gradation, args.max_size, args.min_size, outputs) + args.outputs = os.path.splitext(args.outputFiles)[0] # use args.__dict__ + args.currentdir = os.path.splitext(args.outputFiles)[0] # use args.__dict__ + cmd = """ +set -x + + which mg-tetra_hpc_mpi.exe + if [ $? -ne 0 ] # exit if not found + then + exit 1 + fi + + # needed as openmpi environment have to be set, may be as user or root (for cluster) choice + which mpirun || module load mpi/openmpi-x86_64 # example for centos7/redhat7 + +# compile libmeshgems_mpi.so if needed (i.e. if empty stubs) + mg-tetra_hpc_mpi.exe --help &> /tmp/help_mg-tetra_hpc_mpi_${USER}.txt + if [ $? -ne 0 ] # if empty MPI stubs library, have to compile libmeshgems_mpi.so + then + # SALOME env var MESHGEMSHOME is something like .../INSTALL/MeshGems + MESHGEMSHOME=${MESHGEMSHOME:-/tmp/MeshGems} # default value if unset + COMPILDIR=$MESHGEMSHOME/stubs + TARGETDIR=$MESHGEMSHOME/lib/Linux_64 + cd ${COMPILDIR} + mpicc meshgems_mpi.c -DMESHGEMS_LINUX_BUILD -I../include -shared -fPIC -o ${TARGETDIR}/libmeshgems_mpi.so + fi + +# mpirun mg-tetra_hpc_mpi.exe + rm %(outputs)s* # clean previous case + cd %(outputDir)s + mpirun --n %(number)s mg-tetra_hpc_mpi.exe \ +--in %(inputFile)s \ +--out %(outputFiles)s \ +--gradation %(gradation)s \ +--max_size %(max_size)s \ +--min_size %(min_size)s + # ls -alt %(outputs)s* +""" % args.__dict__ + # args.number, args.inputFile, args.outputFiles, args.gradation, args.max_size, args.min_size, outputs else: - return KO + " ERROR: unknown operating system: %s" % NAME_OS + msg = "unknown operating system: %s" % NAME_OS + log_error(msg) + return KO + msg result = exec_command(cmd, verbose=True) return result ########################################################################## -# main -########################################################################## - -if __name__ == '__main__': - parser = AP.ArgumentParser(description='launch tetra_hpc.exe or tetra_hpc_mpi.exe mesh computation', argument_default=None) - # ./mg-tetra_hpc.py -n 3 --in=/tmp/GHS3DPRL.mesh --out=/tmp/GHS3DPRL_out.mesh --gradation=1.05 --min_size=0.001 --max_size=1.1 --multithread no > /tmp/tetrahpc.log +def getParser(): + parser = AP.ArgumentParser(description='launch tetra_hpc.exe or tetra_hpc_mpi.exe for mesh computation', argument_default=None) parser.add_argument( '-v', '--verbose', help='set verbose, for debug', action='store_true', ) + parser.add_argument( + '-t', '--test', + help='make test, for script debug', + action='store_true', + ) parser.add_argument( '-n', '--number', help='if multithread: number of threads, else distributed: number of processes MPI', choices=[ArgRange(1, 999999)], type=int, metavar='integer >= 0', - default=1, + default=NB_PROCS # as automatic, no more local number of cpu (multithread or MPI) ) parser.add_argument( '-m', '--multithread', @@ -265,15 +356,18 @@ if __name__ == '__main__': '-i', '--inputFile', help='input file name', # nargs='?', - metavar='.../inputFile.mesh' + metavar='.../inputFile.mesh', + default='/tmp/GHS3DPRL.mesh' ) parser.add_argument( '-o', '--outputFiles', help='output basename file(s) name', # nargs='?', - metavar='.../outputFile.mesh' + metavar='.../outputFile.mesh', + default='/tmp/GHS3DPRL_out.mesh' ) """ + # example parser.add_argument( '-x', '--xoneargument', nargs='?', @@ -283,39 +377,72 @@ if __name__ == '__main__': default='0' ) """ + # help(parser) + return parser +########################################################################## +# main +########################################################################## +if __name__ == '__main__': """ - args is Namespace, may use it as global to store - parameters, data, used arrays and results and other... + args is 'Namespace' class, may use it as global to store + parameters, data, used arrays and results, and other... """ + parser = getParser() args = parser.parse_args() verbose = args.verbose - if verbose: print(("INFO: args:\n%s" % PP.pformat(args.__dict__))) + log_debug("%s arguments are:\n%s" % (__file__, PP.pformat(args.__dict__))) if len(sys.argv) == 1: # no args as --help parser.print_help() sys.exit(KOSYS) + if args.test is True: + test_log('one line message') + test_log('first line\nsecond line') + sys.exit(OKSYS) + if args.inputFile == None: - print(("\nERROR: Nothing to do: no input files\n\n%s\n" % PP.pformat(args))) - parser.print_help() + log_error("no --inputFile defined in arguments:\n%s" % PP.pformat(args.__dict__)) + log_info("arguments should be:\n%s" % parser.format_help()) + # parser.print_help() + sys.exit(KOSYS) + + if not os.path.isfile(args.inputFile): + log_error("inexisting input file:\n%s" % os.path.realpath(args.inputFile)) sys.exit(KOSYS) if args.outputFiles == None: tmp, _ = os.path.splitext(args.inputFile) args.outputFiles = tmp + "_out.mesh" - print(("\nWARNING: Default ouput files: %s" % args.outputFiles)) - - force_DISTENE_LICENSE_FILE() - - print(("INFO: mg-tetra_hpc.py assume licence file set:\n DLIM8VAR=%s\n DISTENE_LICENSE_FILE=%s" % \ - (os.getenv("DLIM8VAR"), os.getenv("DISTENE_LICENSE_FILE")))) + + tmp, _ = os.path.split(args.outputFiles) + args.outputDir = os.path.realpath(tmp) + + log_info("output directory:\n%s" % args.outputDir) + + force_DISTENE_LICENSE_FILE() # if FORCE_DISTENE_LICENSE_FILE environ variable exists, manually set by user + + DLIM8VAR = os.getenv("DLIM8VAR") + DISTENE_LICENSE_FILE = os.getenv("DISTENE_LICENSE_FILE") + msg = """\ +%s assume distene licence file set: +DLIM8VAR=%s +DISTENE_LICENSE_FILE=%s +""" % (__file__, DLIM8VAR, DISTENE_LICENSE_FILE) + + if None in [DLIM8VAR, DISTENE_LICENSE_FILE]: + log_error(msg + "Abandon.") + sys.exit(KOSYS) + else: + log_info(msg) if args.multithread == "yes": result = launchMultithread(args) else: result = launchMpi(args) + sys.exit(okToSys(result, verbose=True)) diff --git a/doc/help_mg-tetra_hpc_mpi.txt b/doc/help_mg-tetra_hpc_mpi.txt new file mode 100644 index 0000000..638deef --- /dev/null +++ b/doc/help_mg-tetra_hpc_mpi.txt @@ -0,0 +1 @@ + You are using an empty MPI stubs library. Please read the documentation diff --git a/example/ghs3dprh_multithread_cube_one_face.py b/example/ghs3dprh_multithread_cube_one_face.py new file mode 100644 index 0000000..5899c3a --- /dev/null +++ b/example/ghs3dprh_multithread_cube_one_face.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python + +### +### This file is generated automatically by SALOME v9.4.0 with dump python functionality +### + +import sys +import salome + +salome.salome_init() +import salome_notebook +notebook = salome_notebook.NoteBook() +sys.path.insert(0, r'/volatile2/wambeke/SALOME-master-CO7-SRC') + +### +### GEOM component +### + +import GEOM +from salome.geom import geomBuilder +import math +import SALOMEDS + + +geompy = geomBuilder.New() + +O = geompy.MakeVertex(0, 0, 0) +OX = geompy.MakeVectorDXDYDZ(1, 0, 0) +OY = geompy.MakeVectorDXDYDZ(0, 1, 0) +OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) +Box_1 = geompy.MakeBoxDXDYDZ(200, 200, 200) +Group_1 = geompy.CreateGroup(Box_1, geompy.ShapeType["FACE"]) +geompy.UnionIDs(Group_1, [13]) +[Group_1] = geompy.GetExistingSubObjects(Box_1, False) +geompy.addToStudy( O, 'O' ) +geompy.addToStudy( OX, 'OX' ) +geompy.addToStudy( OY, 'OY' ) +geompy.addToStudy( OZ, 'OZ' ) +geompy.addToStudy( Box_1, 'Box_1' ) +geompy.addToStudyInFather( Box_1, Group_1, 'Group_1' ) + +### +### SMESH component +### + +import SMESH, SALOMEDS +from salome.smesh import smeshBuilder + +smesh = smeshBuilder.New() +#smesh.SetEnablePublish( False ) # Set to False to avoid publish in study if not needed or in some particular situations: + # multiples meshes built in parallel, complex and numerous mesh edition (performance) + +Mesh_1 = smesh.Mesh(Box_1) +NETGEN_1D_2D = Mesh_1.Triangle(algo=smeshBuilder.NETGEN_1D2D) +NETGEN_2D_Simple_Parameters_1 = NETGEN_1D_2D.Parameters(smeshBuilder.SIMPLE) +NETGEN_2D_Simple_Parameters_1.SetNumberOfSegments( 8 ) +NETGEN_2D_Simple_Parameters_1.SetMaxElementArea( 1200 ) +NETGEN_2D_Simple_Parameters_1.SetAllowQuadrangles( 0 ) +MG_Tetra_HPC = Mesh_1.Tetrahedron(algo=smeshBuilder.MG_Tetra_Parallel) +MG_Tetra_HPC_Parameters_1 = MG_Tetra_HPC.Parameters() +MG_Tetra_HPC_Parameters_1.SetMEDName( 'DOMAIN' ) +MG_Tetra_HPC_Parameters_1.SetNbPart( 4 ) +MG_Tetra_HPC_Parameters_1.SetKeepFiles( 1 ) +MG_Tetra_HPC_Parameters_1.SetBackground( 0 ) +MG_Tetra_HPC_Parameters_1.SetMultithread( 1 ) +MG_Tetra_HPC_Parameters_1.SetGradation( 1.05 ) +MG_Tetra_HPC_Parameters_1.SetMinSize( 0 ) +MG_Tetra_HPC_Parameters_1.SetMaxSize( 0 ) +Group_1_1 = Mesh_1.GroupOnGeom(Group_1,'Group_1',SMESH.FACE) +isDone = Mesh_1.Compute() +[ Group_1_1 ] = Mesh_1.GetGroups() +([SKIN_INITIAL], status) = smesh.CreateMeshesFromMED(r'/tmp/DOMAIN_skin.med') +[ Group_1_2, Group_Of_All_Faces, Group_Of_All_Edges, Group_Of_All_Nodes ] = SKIN_INITIAL.GetGroups() +([DOMAIN_1], status) = smesh.CreateMeshesFromMED(r'/tmp/DOMAIN_1.med') +[ All_Faces, Group_1_3, Skin_Group_Of_All_Faces, New_Tetrahedra, All_Nodes, New_Nodes ] = DOMAIN_1.GetGroups() + + +## Set names of Mesh objects +smesh.SetName(Group_Of_All_Edges, 'Group_Of_All_Edges') +smesh.SetName(All_Nodes, 'All_Nodes') +smesh.SetName(New_Nodes, 'New_Nodes') +smesh.SetName(NETGEN_1D_2D.GetAlgorithm(), 'NETGEN 1D-2D') +smesh.SetName(MG_Tetra_HPC.GetAlgorithm(), 'MG-Tetra_HPC') +smesh.SetName(Group_Of_All_Nodes, 'Group_Of_All_Nodes') +smesh.SetName(MG_Tetra_HPC_Parameters_1, 'MG-Tetra_HPC Parameters_1') +smesh.SetName(NETGEN_2D_Simple_Parameters_1, 'NETGEN 2D Simple Parameters_1') +smesh.SetName(Group_1_1, 'Group_1') +smesh.SetName(Mesh_1.GetMesh(), 'Mesh_1') +smesh.SetName(DOMAIN_1.GetMesh(), 'DOMAIN_1') +smesh.SetName(SKIN_INITIAL.GetMesh(), 'SKIN_INITIAL') +smesh.SetName(New_Tetrahedra, 'New_Tetrahedra') +smesh.SetName(Group_1_3, 'Group_1') +smesh.SetName(Skin_Group_Of_All_Faces, 'Skin_Group_Of_All_Faces') +smesh.SetName(All_Faces, 'All_Faces') +smesh.SetName(Group_Of_All_Faces, 'Group_Of_All_Faces') +smesh.SetName(Group_1_2, 'Group_1') + + +if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser() diff --git a/src/GHS3DPRLPlugin/GHS3DPRLPlugin_GHS3DPRL.cxx b/src/GHS3DPRLPlugin/GHS3DPRLPlugin_GHS3DPRL.cxx index 6e6b0e0..cc1fe0e 100644 --- a/src/GHS3DPRLPlugin/GHS3DPRLPlugin_GHS3DPRL.cxx +++ b/src/GHS3DPRLPlugin/GHS3DPRLPlugin_GHS3DPRL.cxx @@ -261,6 +261,7 @@ bool GHS3DPRLPlugin_GHS3DPRL::Compute(SMESH_Mesh& theMesh, fileskinmesh(""), path, casenamemed; //_MEDName.c_str()); + int res = 0; // 0 is OK casenamemed += (char *)_MEDName.c_str(); int n=casenamemed.SearchFromEnd('/'); @@ -363,13 +364,20 @@ bool GHS3DPRLPlugin_GHS3DPRL::Compute(SMESH_Mesh& theMesh, //sometimes it is better to wait flushing files on slow filesystem... system( "sleep 3" ); //launch tetrahpc2med which launch mg-tetra_hpc.py which launch mg-tetra_hpc(_mpi?).exe - system( run_GHS3DPRL.ToCString() ); + res = system( run_GHS3DPRL.ToCString() ); + if (res > 0) + { + pluginerror = pluginerror + "PROBLEM tetrahpc2med command"; + cout<=6)std::cout<<"Read file '"<=6) std::cout<<"Read file '"<>vert>>edge>>tria>>tetr; - std::cout<<"First line "<>vert>>edge>>tria>>tetr; + std::cout<<"Global numerotation nb verts "<>tmint[i]; - if (verbose>4) std::cout<<"Vertices ("<>tmint[i]; + if (verbose>4) std::cout<<"Vertices ("<nofile); @@ -711,7 +715,7 @@ bool ghs3dprl_mesh_wrap::ReadFileGLOBAL(const QString FileName) count=edge; tmint=new med_int[count]; - for (int i=0; i>tmint[i]; + for (long i=0; i>tmint[i]; if (verbose>4) std::cout<<"Edges ("<>tmint[i]; + for (long i=0; i>tmint[i]; if (verbose>4) std::cout<<"Triangles ("<>tmint[i]; + for (long i=0; i>tmint[i]; if (verbose>4) std::cout<<"Tetrahedra ("<4) std::cout<<"Default Vertices ("<nofile); + ok=this->insert_key(tmp,montab); + + count=edge; + tmint=new med_int[count]; + for (long i=0; i4) std::cout<<"Default Edges ("<nofile); + ok=this->insert_key(tmp,montab); + + count=tria; + tmint=new med_int[count]; + for (long i=0; i4) std::cout<<"Default Triangles ("<nofile); + ok=this->insert_key(tmp,montab); + + count=tetr; + tmint=new med_int[count]; + for (long i=0; i4) std::cout<<"Default Tetrahedra ("<nofile); + ok=this->insert_key(tmp,montab); + + return true; +} + //************************************ bool ghs3dprl_mesh_wrap::ReadFileFACES(const QString FileName) //read file .faces (wrap) @@ -871,42 +927,47 @@ bool ghs3dprl_mesh_wrap::ReadFileMESH(const QString FileName) getline(Ff,line); getline(Ff,line); + + getline(Ff,line); // get Edges or Triangle, because sometimes Edges absent - if (!(getline(Ff,line) && (line.find("Edges")==0))) - { - std::cerr<<"Problem on line 'Edges' of file '"<>tmint[i]>>tmint[i+1]>>garbage; + count=Medge; + tmint=new med_int[count*2]; //*3 + for (int i=0; i>tmint[i]>>tmint[i+1]>>garbage; + } + if (verbose>4) std::cout<<"Edges ("<nofile); //TODO see if it could serve + ok=this->insert_key(tmp,montab); + + getline(Ff,line); + getline(Ff,line); + getline(Ff,line); } - if (verbose>4) std::cout<<"Edges ("<nofile); //TODO see if it could serve - ok=this->insert_key(tmp,montab); - - getline(Ff,line); - getline(Ff,line); - if (!(getline(Ff,line) && (line.find("Triangles")==0))) + if (!line.find("Triangles")==0) { std::cerr<<"Problem on line 'Triangles' of file '"<nbfiles<nbfiles; ifile >= 1; ifile--) for (int ineig=this->nbfiles; ineig >= ifile+1; ineig--) { @@ -1702,7 +1769,7 @@ bool ghs3dprl_mesh_wrap::Write_masterxmlMEDfile() { QString tmp; - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!first call + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!first call create xml doc node if (idom==1) { //define master file (.xml) in memory @@ -1721,7 +1788,7 @@ bool ghs3dprl_mesh_wrap::Write_masterxmlMEDfile() med_int majeur,mineur,release; //Quelle version de MED est utilisee MEDlibraryNumVersion(&majeur,&mineur,&release); - if (verbose>0) fprintf(stdout,"Files write with MED V%d.%d.%d\n",majeur,mineur,release); + if (verbose>0) fprintf(stdout,"File write %s with MED V%d.%d.%d\n",filemaster.c_str(),majeur,mineur,release); node = xmlNewChild(root_node, 0, BAD_CAST "version",0); //xmlNewProp(node, BAD_CAST "maj", BAD_CAST int2string2(majeur).c_str()); xmlNewProp(node, BAD_CAST "maj", BAD_CAST i2a(majeur).c_str()); @@ -1730,7 +1797,8 @@ bool ghs3dprl_mesh_wrap::Write_masterxmlMEDfile() //Description tag node = xmlNewChild(root_node,0, BAD_CAST "description",0); - xmlNewProp(node, BAD_CAST "what", BAD_CAST "tetrahedral mesh by MeshGems-Tetra-hpc (formerly tepal)"); + // .../INSTALL/MeshGems/include/meshgems/meshgems.h:11:#define MESHGEMS_VERSION_LONG "2.9-6" + xmlNewProp(node, BAD_CAST "what", BAD_CAST "tetrahedral mesh by MeshGems-Tetra-hpc 2.9-6 2019"); #ifdef WIN32 SYSTEMTIME present; GetLocalTime ( &present ); @@ -1770,12 +1838,14 @@ bool ghs3dprl_mesh_wrap::Write_masterxmlMEDfile() xmlNewProp(mesh_node, BAD_CAST "name", BAD_CAST domainname.c_str()); } - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!all calls + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!all calls add xml idom node { + fprintf(stdout,"Xml node write %s idom %d\n",filemaster.c_str(), idom); char *hostname = getenv("HOSTNAME"); node = xmlNewChild(files_node,0,BAD_CAST "subfile",0); xmlNewProp(node, BAD_CAST "id", BAD_CAST i2a(idom).c_str()); node2 = xmlNewChild(node, 0, BAD_CAST "name", BAD_CAST distfilename); + if (hostname == NULL) node2 = xmlNewChild(node, 0, BAD_CAST "machine",BAD_CAST "localhost"); else @@ -1801,14 +1871,17 @@ bool ghs3dprl_mesh_wrap::Write_masterxmlMEDfile() //xmlNewProp(node2, BAD_CAST "number", BAD_CAST i2a(nbtetra4).c_str()); //tepal2med_info about joints of one subdomain - xmlAddChild(node,joints_node); + fprintf(stdout,"MeshGems 2.9-6 tetra-hpc joints are not implemented\n"); //MeshGems 2.9-6 Salome 9.5.0 jan 2020 + // not implemented ... empty joints ... does NOT work ... xmlAddChild(node,joints_node); //tepal2med_info about groups and families of one subdomain xmlAddChild(node,families.xml_groups()); } //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!last call + fprintf(stdout,"xml node idom %d/%d nb tetras total %d\n", idom, nbfilestot, nbtetrastotal); if (idom==nbfilestot) { + fprintf(stdout,"File write %s as last idom nb tetras total %d\n",filemaster.c_str(), nbtetrastotal); node2 = xmlNewChild(info_node, 0, BAD_CAST "global",0); xmlNewProp(node2, BAD_CAST "tetrahedra_number", BAD_CAST i2a(nbtetrastotal).c_str()); //save masterfile @@ -1926,11 +1999,19 @@ bool ghs3dprl_mesh_wrap::Write_MEDfiles_v2(bool deletekeys) //for (idom=1; idom<=nbfilestot; idom++) { if (for_multithread) { nbfilestot=1; - std::cout<<"\nset Number0fFiles as multithread="<"<0){ - if (verbose>2) std::cout<2) { + std::cout<\n"; } @@ -1964,20 +2045,24 @@ bool ghs3dprl_mesh_wrap::Write_MEDfiles_v2(bool deletekeys) if (verbose>4) std::cout<<"\nEnd of Faces ***\n"<4) std::cout<<"\nEnd of Tetrahedra ***\n"<6){std::cout<<"\nFinalsFamilies\n"; families.write();} //for nodes families nb=create_families(fid,1); - if (verbose>5)std::cout<<"NumberOfFamiliesNodes="<5)std::cout<<"NumberOfFamiliesNodes="<8) std::cout<<"MEDmeshEntityFamilyNumberWr nodes "<ReadFileMESH(tmp); + if (for_multithread) { // inexisting file GHS3DPRL_out.000001.global + this->ReadFileDefaultGLOBAL(this->nbvert, this->nbedge, this->nbtria, this->nbtetr); + } } tab=this->restore_key(key); //tab1=this->mestab[key1]; if (!tab) return false; @@ -2045,7 +2133,8 @@ bool ghs3dprl_mesh_wrap::idom_nodes() tmp=tmp.sprintf("NB%d SN",idom); //qt3 xx=this->remove_key_mesh_wrap(QRegExp(tmp,true,true)); xx=this->remove_key_mesh_wrap(QRegExp(tmp,Qt::CaseSensitive,QRegExp::RegExp)); - nbnodes=tab->size/3; + nbnodes=this->nbvert; // for current idom + err=MEDmeshNodeCoordinateWr(fid,nomfinal,MED_NO_DT,MED_NO_IT,0.,MED_FULL_INTERLACE,nbnodes,tab->tmflo); if (err<0) {std::cerr<<"Problem MEDmeshNodeCoordinateWr"<4) std::cout<<"NumberOfNodes="<restore_key(key1); //tab1=this->mestab[key1]; if (!tab1) { @@ -2206,6 +2296,7 @@ bool ghs3dprl_mesh_wrap::idom_edges() bool ok=true; QString tmp; nbseg2=0; + this->nbedge=0; return ok; } @@ -2228,6 +2319,8 @@ bool ghs3dprl_mesh_wrap::idom_faces() if (!tab1) return false; } nbtria3=tab1->size/3; + this->nbtria=nbtria3; // for current idom + if (verbose>4) std::cout<<"NumberOfTriangles="<restore_key(key1); //tab1=this->mestab[key1]; if (nbtria3!=tab1->size){std::cerr<<"Problem size GLi FA!=nbtria3!"<restore_key(key); //tab1=this->mestab[key1]; - //nbnodes=tab->size/3; + nbnodes=tab->size/3; //writing correspondence nodes-nodes //two indices for one correspondence @@ -2598,6 +2692,8 @@ bool ghs3dprl_mesh_wrap::idom_tetras() key1=key1.sprintf("NB%d EV",idom); //files.NoBoite Elements Vertices (tetra only) tab1=this->restore_key(key1); //tab1=this->mestab[key1]; nbtetra4=tab1->size/4; + this->nbtetr=nbtetra4; // for current idom + nbtetrastotal=nbtetrastotal + nbtetra4; if (verbose>5)std::cout<<"NumberOftetrahedra="<tmint); @@ -2614,7 +2710,8 @@ bool ghs3dprl_mesh_wrap::idom_tetras() famtetra4=new med_int[nbtetra4]; for (i=0; iverbose>3){ /* mg-tetra_hpc_mpi.exe --help - ================================================= - MG-Tetra_HPC -- MeshGems 2.1-11 (September, 2015) - ================================================= + ============================================= + MG-Tetra_HPC -- MeshGems 2.9-6 (August, 2019) + ============================================= Distene SAS Campus Teratec @@ -483,11 +483,11 @@ mg-tetra_hpc_mpi.exe --help Phone: +33(0)970-650-219 Fax: +33(0)169-269-033 EMail: - Running MG-Tetra_HPC (Copyright 2014 by Distene SAS) - date of run: 31-May-2016 AT 09:05:29 - running on : Linux 2.6.32-431.11.2.el6.centos.plus.x86_64 x86_64 + Running MG-Tetra_HPC (Copyright 2014-2019 by Distene SAS) + date of run: 25-Feb-2020 AT 08:47:20 + running on : Linux 3.10.0-1062.9.1.el7.x86_64 x86_64 using modules: - MeshGems-Core 2.1-11 + MeshGems-Core 2.9-6 MeshGems is a Registered Trademark of Distene SAS @@ -503,6 +503,14 @@ Options: | | / v v v + --components + Selects which mesh components to process. + If is: + all : all components are to be meshed. + outside_components : only the main (outermost) component is to be + meshed. + Default: all + --gradation Sets the size gradation value. is the desired maximum ratio between 2 adjacent @@ -510,39 +518,128 @@ Options: will be. Default: 1.05 + --gradation_mode + Sets the gradation behaviour. + Possible values for are : + without_size: apply gradation only when no size is provided by + the input sizemap(s) + always: always apply the gradation. This can partially smooth the + provided input sizemap(s) + Default: without_size + --help Prints this help. - + --in Sets the input file. (MANDATORY) + --max_edge_length + Sets the desired maximum accepted edge length. + Default: 0 (no maximum length). + --max_size Sets the desired maximum cell size value. Default: 0 (no maximum size). + --metric + Sets the type of metric governing the mesh generation. + Possible values for are : + isotropic: the metric induces the same size in all directions. + anisotropic: the metric induces different sizes depending on the + directions. + Default: isotropic + + --min_edge_length + Sets the desired minimum accepted edge length. + Default: 0 (no minimum length). + --min_size - Default: 0 (no minimum size). Sets the desired minimum cell size value. + Default: 0 (no minimum size). + + --optimisation + Sets whether to optimise mesh quality or not. + Default: yes. + + --optimisation_level + Sets the desired optimisation level for mesh quality. + Possible values for are (in increasing order of quality vs + speed ratio): light, standard, strong + Default: standard. --out Sets the output file. + Using an existing file is not allowed. + Using the same file as --in is not allowed. If unset, _tetra_hpc is appended to the input file basename. - Using an existing file is forbidden. - Using the same file as --in is forbidden. + --parallel_strategy + Sets the desired parallel strategy, influencing the level of + reproducibility of the result and the potential performances. + Possible values for are (in decreasing order for + reproducibility and increasing order for performances): + reproducible: result is entirely reproducible but performances + may not be optimal. + aggressive: result may not be reproducible but all parallel + optimizations are allowed. + Default: reproducible. + + --sizemap + Sets the optional input sizemap file. The sizemap must provide the + requested size at the input surface or volume mesh vertices. + Default : none. + + --split_overconstrained_edges + Sets whether to split over-constrained edges or not. An edge is + considered as over-constrained when its two vertices belong to the + surface. + If is: + yes: correction is applied upon mesh generation/optimisation + no: no correction is applied. + Default: no + + --split_overconstrained_elements + Sets whether to split over-constrained elements or not. An edge is + considered as over-constrained when its two vertices belong to the + surface. A tetrahedron is considered as over-constrained when at + least two of its faces belong to the surface. + If is: + yes: correction is applied upon mesh generation/optimisation + no: no correction is applied. + Default: no + + --split_overconstrained_tetrahedra + Sets whether to split over-constrained tetrahedra or not. A + tetrahedron is considered as over-constrained when at least two of + its faces belong to the surface. + If is: + yes: correction is applied upon mesh generation/optimisation + no: no correction is applied. + Default: no + --verbose Set the verbosity level, increasing from 0 to 10. - values are increasing from 0 to 10 : - 0 : no details - 10 : very detailed - Default: 3 + Possible values are increasing from 0 to 10 : + 0 : no details. + 10 : very detailed. + Default: 3. + + --volume_proximity_layers + Sets the desired minimum number of tetrahedra layers inside the + volume. + Default: 0 (no minimum). + + --write_sizemap + Sets the optional output sizemap file. + Using an existing file is not allowed. + If unset, the output sizemap will not be written. ================================================================================ - MG-Tetra_HPC -- MeshGems 2.1-11 (September, 2015) - END OF SESSION - MG-Tetra_HPC (Copyright 2014 by Distene SAS) - compiled Sep 3 2015 12:50:47 on Linux_64 + MG-Tetra_HPC -- MeshGems 2.9-6 (August, 2019) + END OF SESSION - MG-Tetra_HPC (Copyright 2014-2019 by Distene SAS) + compiled Sep 2 2019 09:58:40 on Linux_64 MeshGems is a Registered Trademark of Distene SAS ================================================================================ ( Distene SAS @@ -555,7 +652,7 @@ Options: int main(int argc, char *argv[]) { bool ok; - int i,nb,nbfiles,limit_swap,nbelem_limit_swap,limit_swap_defaut,verbose; + int i,nb,nbfiles,limit_swap,nbelem_limit_swap,limit_swap_defaut,verbose,res; float gradation,min_size,max_size; QString path,pathini,casename,casenamemed,fileskinmed, tmp,cmd,format,format_tetra, @@ -785,7 +882,7 @@ int main(int argc, char *argv[]) if (launchtetra=="yes"){ - //call tetra_hpc.py is pthon script which assumes mpirun or else if no multithread + //call tetra_hpc.py is python script which assumes mpirun or else if no multithread //after compilation openmpi or else acrobatic DISTENE_LICENCE change... cmd="mg-tetra_hpc.py --number=" + QString::number(nbfiles)+ @@ -828,7 +925,12 @@ int main(int argc, char *argv[]) if (launchtetra=="yes"){ //sometimes it is better to wait flushing files on slow filesystem... system("sleep 3"); - system(cmd.toLatin1().constData()); // run + res = system(cmd.toLatin1().constData()); // run + if (res>0) + { + std::cout<0)std::cout<<"Initial skin file <"< does not exist\n"; } -//if test quickly read all files before (or only small files) - if (test=="yes"){ - if (verbose>0) std::cout<<"\nReading output files of tetrahpc as input files of tetrahpc2med...\n"; - //only read beginning of files .xxxxx.mesh - //supposed big files big arrays so only see first lines - mymailw->nbfiles=0; - for (int i=1; i<=nbfiles; i++){ - mymailw->nofile=i; - tmp=pathini+casename+tmp.sprintf(format_tetra.toLatin1().constData(),i)+".mesh"; - if (verbose>0) std::cout<<"FileName="<TestExistingFileMESHnew(tmp); - } - if (verbose>0) - std::cout<<"NumberOfFilesMESHTested="<nbfiles<<": ok\n\n"; - if (mymailw->nbfiles != nbfiles){ - std::cerr<<"NumberOfFiles != NumberOfFilesTested is unexpected\n\n"; - return 1; - } - } //end if test + //if test quickly read all files before (or only small files) + if (test=="yes"){ + if (verbose>0) std::cout<<"\nReading output files of tetrahpc as input files of tetrahpc2med...\n"; + //only read beginning of files .xxxxx.mesh + //supposed big files big arrays so only see first lines + mymailw->nbfiles=0; + for (int i=1; i<=nbfiles; i++){ + mymailw->nofile=i; + tmp=pathini+casename+tmp.sprintf(format_tetra.toLatin1().constData(),i)+".mesh"; + if (verbose>0) std::cout<<"FileName="<TestExistingFileMESHnew(tmp); + } + if (verbose>0) + std::cout<<"NumberOfFilesMESHTested="<nbfiles<<": ok\n\n"; + if (mymailw->nbfiles != nbfiles){ + std::cerr<<"NumberOfFiles != NumberOfFilesTested is unexpected\n\n"; + return 1; + } + } //end if test ok=mymailw->Write_MEDfiles_v2(true); //deletekeys=true nb=mymailw->remove_all_keys_mesh_wrap(); if (verbose>3)std::cout<<"***remove_all_key_mesh_wrap*** "<0)std::cout<=0)std::cout<