# -*- coding: utf-8 -*-
#
# This file is subject to the terms and conditions defined in
# file 'LICENSE.txt', which is part of this source code package.
#
from typing import Union, Optional
from pathlib import Path
from Muscat.IO.MeshWriter import WriteMesh
from Muscat.IO.MeshReader import ReadMesh
from Muscat.MeshContainers.Mesh import Mesh
from Muscat.Helpers.IO.Which import Which
from Muscat.Helpers.IO.TemporaryDirectory import TemporaryDirectory
from Muscat.MeshTools.Remesh import RegisterRemesherClass
[docs]
class ParMmgRemeshing():
def __init__(self, mesh: Mesh, solution=None, levelset=None, metric=None):
self.mesh = mesh
if levelset is not None:
raise RuntimeError(' ParMmgRemeshing does not support the argument levelset')
self.solution = solution
self.metric = metric
self.temp_out_path = None
self.temp_mesh_path = None
self.temp_sol_path = None
self.dictElemRefsToTags = {}
self.dictNodesRefsToTags = {}
def __WriteMeshAndSolution(self, temp_path: Union[str, Path] = None, binary: bool = True):
"""Write mesh and solution in a mesh file
Parameters
----------
temp_path : Union[str,Path]
path of the output mesh file (without extension)
binary : bool
"""
from Muscat.MeshTools.MeshTools import TagsToRefs
if temp_path is None:
temp_path = Path("temp_file")
solutionOnOwnFile = True
self.temp_mesh_path = Path(str(temp_path)+".mesh"+binary*"b")
self.temp_sol_path = Path(str(temp_path)+".sol"+binary*"b")
if not self.temp_out_path:
self.temp_out_path = Path(str(temp_path)+".o.mesh"+binary*"b")
if self.solution is not None:
solution = [self.solution]
elif self.metric is not None:
solution = [self.metric]
else:
solution = None
solutionOnOwnFile = False
RefByNode, self.dictNodesRefsToTags, RefByElement, self.dictElemRefsToTags = TagsToRefs(self.mesh)
WriteMesh(
str(self.temp_mesh_path), self.mesh, PointFields=solution,
solutionOnOwnFile=solutionOnOwnFile, binary=binary,
nodalRefNumber=RefByNode, elemRefNumber=RefByElement
)
def __BuildParMmgCommandLine(self, backEndOptions: dict):
"""Build command line for Parmmg execution
Parameters
----------
options : dict
keys corresponding to mmg option name
and value corresponding to value if applicable
Returns
-------
CommandLine : str
the command line for mmg execution
"""
CommandLine = ["mpirun"]
isElem3d = self.mesh.GetNumberOfElements(dim=3) > 0
if isElem3d:
CommandLine.append(Which("parmmg_O3"))
else:
raise ValueError("Only compatible for 3D remeshing")
CommandLine.append("-in")
CommandLine.append(str(self.temp_mesh_path))
if self.solution is not None:
CommandLine.append("-sol")
CommandLine.append(str(self.temp_sol_path))
elif self.metric is not None:
CommandLine.append("-met")
CommandLine.append(str(self.temp_sol_path))
for key, value in backEndOptions.items():
CommandLine.append("-"+key)
if value:
CommandLine.append(str(value))
return " ".join(CommandLine)
def __LaunchParMmg(self, CommandLine: str):
"""Launch parmmg with a subprocess using command line
Parameters
----------
CommandLine : str
the command line for parmmg execution
"""
import subprocess
print(CommandLine)
return subprocess.check_output(CommandLine, shell=True).decode("utf-8", errors="ignore")
def __ReadMesh(self, prefix="parmmg"):
"""Read mesh file produced by parmmg
Returns
-------
mesh : Mesh
parmmg resulting mesh from adaption
"""
from Muscat.MeshTools.MeshTools import RefsToTags
mesh = ReadMesh(str(self.temp_out_path), ReadRefsAsField=True)
mesh = RefsToTags(mesh, self.dictNodesRefsToTags, self.dictElemRefsToTags, prefix)
return mesh
[docs]
def Runner(self, remesher_options: dict, backEndOptions: dict):
"""Run the process to write mesh in an inria mesh file,
launch parmmg and read the resulting mesh
Notes
-----
The inria mesh file (called `temp_name`) will be writen in a temporary directory
Parameters
----------
remesher_options : dict
keys corresponding to parmmg option name
and value corresponding to value if applicable
backEndOptions: dict
Extra option for the "by file" parmmg communication
"temp_name" : str
name of the output mesh file (without extension) default : "temp_file"
"binary" : bool
defaults to `True`
"prefix" : str
defaults to "parmmg"
"keep_temp_files" : bool
defaults to `False`
"temp_dir" : str
directory to store temporary files
if none a Temporary Directory is used for temporary file, default None
Returns
-------
mesh : Mesh
parmmg resulting mesh from adaption
"""
parmmgExec = Which("parmmg_O3")
if parmmgExec == '' or parmmgExec is None:
return "skip parmmg_O3 is not in PATH"
if remesher_options is None:
remesher_options = {}
if backEndOptions is None:
backEndOptions = {}
temp_name = backEndOptions.get("temp_name", "temp_file")
binary = backEndOptions.get("binary", True)
prefix = backEndOptions.get("prefix", "parmmg")
keep_temp_files = backEndOptions.get("keep_temp_files", False)
temp_dir = backEndOptions.get("temp_dir", None)
print_logtime = backEndOptions.get("logtime", True)
out_name = remesher_options.get("out", None)
if out_name:
self.temp_out_path = Path(out_name+".mesh"+binary*"b")
if not temp_dir:
temp_dir = Path(TemporaryDirectory.GetTempPath())
temp_path = Path(temp_dir) / Path(temp_name)
self.__WriteMeshAndSolution(temp_path, binary)
CommandLine = self.__BuildParMmgCommandLine(remesher_options)
parmmg_out = self.__LaunchParMmg(CommandLine)
if print_logtime:
print(parmmg_out.split("\n")[-2].split(" ")[-1])
mesh = self.__ReadMesh(prefix)
if not keep_temp_files:
self.temp_mesh_path.unlink(missing_ok=True)
self.temp_sol_path.unlink(missing_ok=True)
self.temp_out_path.unlink(missing_ok=True)
return mesh
RegisterRemesherClass("ParMmg", ParMmgRemeshing)
RegisterRemesherClass("ParMmgByFiles", ParMmgRemeshing)
RegisterRemesherClass("ParMmgByFile", ParMmgRemeshing)
[docs]
def CheckIntegrity(GUI=False):
import time
import numpy as np
from Muscat.IO.GmshReader import ReadGmsh
from Muscat.TestData import GetTestDataPath
from Muscat.Helpers.IO.TemporaryDirectory import TemporaryDirectory
tic = time.time()
parmmgExec = Which("parmmg_O3")
if parmmgExec == '' or parmmgExec is None:
return "skip"
print("Reading mesh")
filename = GetTestDataPath()+"dent3D.msh"
mesh = ReadGmsh(filename)
mesh.ConvertDataForNativeTreatment()
print(mesh)
print("Execution time:", int(time.time()-tic), "seconds")
tic = time.time()
print("Executing parmmg3d")
obj = ParMmgRemeshing(mesh=mesh, solution=None)
mesh = obj.Runner({"hmin": 0.1}, backEndOptions={"binary": False})
obj = ParMmgRemeshing(mesh=mesh, solution=None)
mesh = obj.Runner({"hmin": 0.1}, backEndOptions={"binary": False, "temp_name": "test_parmmg"})
obj = ParMmgRemeshing(mesh=mesh, solution=None)
mesh = obj.Runner({"hmin": 0.1}, backEndOptions={"binary": False, "temp_name": "test_parmmg", "temp_dir": TemporaryDirectory.GetTempPath()})
obj = ParMmgRemeshing(mesh=mesh, solution=None)
mesh = obj.Runner({"hmin": 0.1}, backEndOptions={"binary": False, "temp_dir": TemporaryDirectory.GetTempPath()})
obj = ParMmgRemeshing(mesh=mesh, solution=np.ones(mesh.GetNumberOfNodes()))
mesh = obj.Runner({"hmin": 0.1}, backEndOptions={"binary": True})
obj = ParMmgRemeshing(mesh=mesh, solution=np.ones(mesh.GetNumberOfNodes()))
mesh = obj.Runner({"hmin": 0.1, "out": f"{TemporaryDirectory.GetTempPath()}/adapted_mesh"}, backEndOptions={"binary": True})
print(mesh)
print("Execution time:", int(time.time()-tic), "seconds")
return "ok"
if __name__ == '__main__':
print(CheckIntegrity())