################################################################################
# CLASS DEFINITION FOR MESHING MODELS GENERATED USING THE GMSH-PYTHON-API #
################################################################################
# Within this file, the generic Model class is defined. It is the base class
# for other, more specific classes which aim to mesh models using the Gmsh-
# Python-API. In addition to the methods defined within the Gmsh-Python-API,
# this class provides methods for all basic steps of a model generation using
# Gmsh: some of these methods are only placeholders here and - if required -
# have to be specified/overwritten for the more specialized models.
###########################
# Load required libraries #
###########################
# Standard Python libraries
import os # os for file handling (split extensions from file)
import inspect # inspect to search for classes in modules
import datetime as dt # datetime for time stamps
import tempfile as tf # tempfile for generation of temprory files and folders
import numpy as np # numpy for array computations
import pickle # pickle for saving and loading of gmshModels
import logging # logging for log messages
logger=logging.getLogger(__name__) # set logger
# additional program libraries
import gmsh # Gmsh Python-API
import meshio # meshio for mesh file format conversions
# self-defined class definitions and modules
from ..Geometry import GeometricObjects as geomObj # classes for implemented geometric objects
from ..Visualization.GeometryVisualization import GeometryVisualization, PYTHONOCC_AVAILABLE # class for geometry visualization
from ..Visualization.MeshVisualization import MeshVisualization # class for mesh visualization
from ..MeshExport import FeapExport
#############################
# Set configuration options #
#############################
SUPPORTED_GEOMETRY_FORMATS=[".brep", ".stp", ".step"] # set supported geometry formats
SUPPORTED_MESH_FORMATS=list(meshio.extension_to_filetype.keys()) # set supported mesh file formats
#############################
# Define GenericModel class #
#############################
[docs]
class GenericModel:
"""Generic class for meshing models generated using the Gmsh-Python-API
This class provides the basic mesh generation framework for Gmsh. It
implements the methods for:
(1) Setting up a geometry using basic geometric entities and boolean
operations
(2) Adding the geometric objects to Gmsh, performing the boolean operations,
defining physical groups
(3) creating a mesh with user-defined refinement fields
(4) saving and visualizing the mesh
Some of the methods used within the framework are only defined as placeholder
methods here and have to be specified in detail within the child classes.
Attributes:
-----------
dimension: int
dimension of the model instance
modelName: string
name of the Gmsh model and default name for all resulting files
gmshConfigChanges: dict
dictionary for user updates of the default Gmsh configuration
geometricObjects: list
list containing the instances of geometric objects used for the
model geometry creation
groups: dict
dictionary with group information for the model entities
booleanOperations: list
list with dictionaries defining the individual boolean operations
to perform for the model generation
physicalGroups: list
list with dictionary defining which Gmsh entities are defined as
physical groups (e.g. different materials)
refinementFields: list
list of dictionaries defining the refinement fields that have to
be added to the Gmsh model
backgroundField: int
number of the field that has to be used as the background field/mesh
for the mesh generation
"""
#########################
# Initialization method #
#########################
def __init__(self,dimension=None,gmshConfigChanges={}):
"""Initialization method of a generic GmshModel object
Parameters:
-----------
dimension: int
dimension of the model instance
gmshConfigChanges: dict
dictionary for user updates of the default Gmsh configuration
"""
# set unique model name
self.modelName="Model_"+dt.datetime.now().strftime("%Y%m%d_%H%M%S%f") # use time stamp of initialization (with microseconds) for unique model name
# set default file extensions depending on the savin method
self._defaultFileExts={
"Geometry": ".brep", # use ".brep" as default extension for saving the geometry
"Mesh": ".msh", # use ".msh" as default extension for saving meshes
"Model": ".gmshModel", # use ".gmshModel" as default extension for saving models
"Misc": ".txt" # use ".txt" as default extension for miscellaneous information
}
# initialize Gmsh-Python-API
self.gmshConfigChanges={ # default Gmsh configuration changes
"General.Terminal": 0, # deactivate console output by default (only activated for mesh generation)
"Geometry.OCCBoundsUseStl": 1, # use more accurate computation of bounding boxes (slower but advantegous for periodicity constraints)
"Geometry.Tolerance": 1e-12 # adjust geometric tolerance to be a little more precise then default (1e-8)
}
self.gmshAPI=self.initializeGmsh(gmshConfigChanges) # this assignment facilitates the usage of all methods provided by the gmsh.model class
# initialize attributes that all instances of GenericModel should have
self.dimension=dimension # set (highest) dimension of the model
self.geometricObjects=[] # initialze empty list of geomtric objects (used for model generation)
self.groups={} # initialize empty dictionary of groups (used for boolean operations adn physical groups)
self.booleanOperations=[] # initialize empty list of defined boolean operations (used to generate the model from basic geometrical objects)
self.physicalGroups=[] # initialize empty list of defined physical groups (used to identify materials and boundaries within the mesh)
self.refinementFields=[] # initialize empty list of refinement fields (used to control the mesh sizes)
self.backgroundField=None # initialize background field for the meshing algorithm (used to control the mesh sizes)
################################################################################
# MAIN METHODS FOR MODEL AND MESH GENERATION #
################################################################################
############################################
# Method to initialize the Gmsh-Python-API #
############################################
[docs]
def initializeGmsh(self,gmshConfigChanges={}):
"""Gmsh initialization method
This method initializes the Gmsh-Python-API and adds it to the GmshModel
Parameters:
-----------
gmshConfigChanges: dict
dictionary with Gmsh configuration options that have to be set
"""
gmsh.initialize('',False) # initialize Gmsh Python-API without using local .gmshrc configuration file
self.updateGmshConfiguration(gmshConfigChanges) # update default configuration with user updates and set the options
gmshAPI=gmsh.model # define gmshAPI as the model class of the Gmsh-Python-API (contains only static methods -> no instance required)
gmshAPI.add(self.modelName) # add new model to the gmshAPI
return gmshAPI # retrun gmshAPI
################################################################
# Method to set up model information and create the Gmsh model #
################################################################
[docs]
def createGmshModel(self,**geometryOptions):
"""Method to create the Gmsh Model and provide necessary information to it
This method contains the basic Gmsh model creation steps: after geoetric
objects are defined, boolean operations are performed to generate the
final geometry. Parts of the geometry are combined to physical groups in
order to be able to assign, e.g., material parameters to them. If required,
a periodicity constraint is finally added to the model.
Parameters:
-----------
geometryOptions: key-value pairs of options
key-value pairs of options required for the geometry generation
process
"""
# define geometric objects and add them to the Gmsh model
self.defineGeometricObjects(**geometryOptions) # placeholder method: has to be specified/overwritten for the individual models
self.addGeometricObjectsToGmshModel() # use Gmsh-API to add geometric information to the Gmsh model
# define boolean operations and add them to the Gmsh model (perform them)
self.defineBooleanOperations() # placeholder method: has to be specified/overwritten for the individual models
self.performBooleanOperationsForGmshModel() # use Gmsh-API to perform defined operations
# define physical groups and add them to the Gmsh model
self.definePhysicalGroups() # placeholder method: has to be specified/overwritten for the individual models
self.addPhysicalGroupsToGmshModel() # use Gmsh-API to add defined groups to the Gmsh model
# set up periodicity constraints
self.setupPeriodicity() # placeholder method: has to be specified/overwritten for the individual models if necessary
####################################################################
# Method to calculate refinement information and generate the mesh #
####################################################################
[docs]
def createMesh(self,threads=None,refinementOptions={}):
"""Method to generate the model mesh
This method contains the basic mesh generation steps for a Gmsh model:
refinement fields are calculated with user-defined options and added to
the model. Afterwards, a background field is specified and used for the
mesh size computation within Gmsh. Finally, the mesh is created.
Parameters:
-----------
threads: int
number of threads to use for the mesh generation
refinementOptions: dict
dictionary with user-defined options for the refinement field calculations
"""
if threads is not None: # set number of threads in Gmsh
self.updateGmshConfiguration({"Mesh.MaxNumThreads1D": threads,
"Mesh.MaxNumThreads2D": threads,
"Mesh.MaxNumThreads3D": threads})
# deine refinement information and add them to the Gmsh model
self.defineRefinementFields(refinementOptions=refinementOptions) # placeholder method: has to be specified/overwritten for the individual models
self.addRefinementFieldsToGmshModel() # use Gmsh-API to add defined fields to the Gmsh model
# set background field for meshing procedure (if possible)
if not self.backgroundField is None:
self.gmshAPI.mesh.field.setAsBackgroundMesh(self.backgroundField) # define background field (field which is used for mesh size determination)
# generate mesh (with activate console output)
self._gmshOutput(1) # activate Gmsh console output
self.gmshAPI.mesh.generate(self.dimension) # generate mesh using the Gmsh-API
self._gmshOutput(0) # deactivate Gmsh console output
############################################################
# Closing method to terminate the current Gmsh-API session #
############################################################
[docs]
def close(self):
"""Gmsh finalization method
The Gmsh-Python-API has to be finalized for a proper termination of the
model.
"""
gmsh.finalize()
################################################################################
# MAIN METHODS FOR LOADING AND SAVING INFORMATION #
################################################################################
########################################################
# Method to save the geometry of the model into a file #
########################################################
[docs]
def saveGeometry(self,file=None):
"""Method to save the generated geometry into a geometry file
This method allows to store geometry information into ".step" or ".brep"-
files.
"""
# get fileparts of passed file string (return defaults if nothing is passed)
fileDir,fileName,fileExt=self._getFileParts(file,"Geometry")
if fileExt in SUPPORTED_GEOMETRY_FORMATS: # check if file extension is supported by gmsh
gmsh.write(fileDir+"/"+fileName+fileExt) # write geometry to file (use Gmsh-internal "guess from extension" feature)
else:
raise ValueError("Unknown geometry file extension {}. The output geometry format must be supported by the gmsh library.".format(fileExt))
####################################################
# Method to save the mesh of the model into a file #
####################################################
[docs]
def saveMesh(self,file=None):
"""Method to save the generated mesh into a mesh file
After the mesh is generated, it has to be saved into a usable file format.
Here, all meshes that are supported by the meshio library, can be used to
save the mesh. If meshio is not available, the mesh format is restricted
"""
# get fileparts of passed file string (return defaults if nothing is passed)
fileDir,fileName,fileExt=self._getFileParts(file,"Mesh")
# create mesh file depending on the chosen file extension
os.makedirs(fileDir,exist_ok=True) # ensure that the file directory exists
if fileExt == ".msh": # file extension is ".msh"
gmsh.write(fileDir+"/"+fileName+fileExt) # -> save mesh using built-in gmsh.write method
elif fileExt == '.msh2': # file extension is ".msh2"
gmsh.option.setNumber("Mesh.MshFileVersion", 2.) # change format to msh2
gmsh.write(fileDir+"/"+fileName+".msh") # -> save mesh using built-in gmsh.write method
elif fileExt == ".feap": # file extension is ".feap" -> write feap mesh files
FeapExport(self)
else: # file extension is different from ".msh"
if fileExt in SUPPORTED_MESH_FORMATS: # -> check if file extension is supported by meshio
with tf.TemporaryDirectory() as tmpDir: # ->-> create temporary directory
tmpFile=os.path.normpath(tmpDir+"/"+self.modelName+".msh") # ->-> create temporary file
targetFile=os.path.normpath(fileDir+"/"+fileName+fileExt) # ->-> get os-specific path to target file
gmshBinaryConfig=self.getGmshOption("Mesh.Binary") # ->-> get Gmsh configuration for binary mesh export
self.setGmshOption("Mesh.Binary",1) # ->-> temporarily activate binary mesh export (reduce file size, increase speed)
gmsh.write(tmpFile) # ->-> use built-in gmsh.write method to generate binary mesh in temporary folder
self.setGmshOption("Mesh.Binary",gmshBinaryConfig) # ->-> reset Gmsh configuration
self._convertMesh(tmpFile,targetFile) # ->-> convert mesh to required file format
else: # raise error if mesh file format is not supported by meshio
raise ValueError("Unknown mesh file extension {}. The output mesh format must be supported by the meshio library.".format(fileExt))
#####################################################
# Method to save Gmsh model object to a binary file #
#####################################################
[docs]
def saveModel(self,file=None):
"""Method to save the complete model into a pickle object
In order to be able to reuse generated models, the whole model can be
saved. Within this method, the pickle module is used to save the model
to a binary file.
"""
# get file parts of passed file string (return defaultsd if nothing is passed)
fileDir,fileName,fileExt=self._getFileParts(file,"Model")
# save file
os.makedirs(fileDir,exist_ok=True) # ensure that the file directory exists
with open(fileDir+"/"+fileName+fileExt,"wb") as file: # open file with writing permissions in binary mode
pickle.dump(self,file) # save file using pickle
#################################################
# Class method to load existing model instances #
#################################################
[docs]
@classmethod # define method as a class method
def load(cls,fileName):
"""Method to load an existing GmshModel object
Objects that have been saved to a binary file using the pickle module
can be reloaded here.
"""
with open(fileName,"rb") as file: # load file
modelInstance = pickle.load(file) # load saved file with pickle module
# Use saved geometry information to rebuild the model
modelInstance.initializeGmsh(modelInstance.gmshConfigChanges) # initialize Gmsh API
modelInstance.addGeometricObjectsToGmshModel() # use Gmsh-API to add geometric information to the Gmsh
modelInstance.performBooleanOperationsForGmshModel() # use Gmsh-API to perform defined operations
modelInstance.addPhysicalGroupsToGmshModel() # use Gmsh-API to add defined groups to the Gmsh model
modelInstance.setupPeriodicity() # set up periodicity constraints
return modelInstance
################################################################################
# VISUALIZATION METHODS #
################################################################################
##########################################################
# Method to visualize the model geometry using pythonocc #
##########################################################
[docs]
def visualizeGeometry(self):
"""Method to visualize the Gmsh model geometry using pythonocc"""
if PYTHONOCC_AVAILABLE: # optional pythonocc package is available
GeometryVisualization(self) # -> visualize the geometry
else: # optional pythonocc package is unavailable
logger.warning("Geometry visualization is unavailabe due to missing packages.") # do nothing but printing a warning
############################################################
# Method to visualize the model mesh using pyvista and vtk #
############################################################
[docs]
def visualizeMesh(self):
"""Method to visualize the generated mesh using pyvista and vtk"""
MeshVisualization(self) # -> visualize the mesh
####################################################################
# Method to show the whole model in Gmsh using the Gmsh-Python-API #
####################################################################
[docs]
def showModelInGmsh(self):
"""Method to open the complete model in Gmsh"""
gmsh.fltk.run()
################################################################################
# PLACEHOLDER METHODS TO BE SPECIALIZED FOR THE INDIVIDUAL MODELS #
################################################################################
##################################################
# Method for the definition of geometric objects #
##################################################
[docs]
def defineGeometricObjects(self,**options):
"""Placeholder method for the definition of geometric objects. Has to be
specified in child classes"""
pass
###################################################
# Method for the definition of boolean operations #
###################################################
[docs]
def defineBooleanOperations(self):
"""Placeholder method for the definition of necessary boolean Operations.
Has to be specified in child classes"""
pass
################################################
# Method for the definition of physical groups #
################################################
[docs]
def definePhysicalGroups(self):
"""Placeholder method to define required physical groups. Has to be
specified in child classes"""
pass
###########################################
# Method to define refinement information #
###########################################
[docs]
def defineRefinementFields(self):
"""Placeholder method to define/compute refinement fields for the mesh
generation. Has to be specified in child classes"""
pass
###############################################################
# Method to set up periodicity constraints for the Gmsh model #
###############################################################
[docs]
def setupPeriodicity(self):
"""Placeholder method to set up periodicity constraints for RVEs. Has to
be specified in child classes, if required"""
pass
################################################################################
# INTERFACING METHODS TO PASS INFORMATION TO THE GMSH MODEL #
################################################################################
###############################################
# Method to transform Gmsh entity Tags to IDs #
###############################################
############################################################
# method to get a single Gmsh option depending on its type #
############################################################
[docs]
def getGmshOption(self,optionName):
"""Method to get the value of a Gmsh configuratio option with known name
Parameters:
-----------
optionName: string
name of the option
"""
try: # try to return option value assuming it is a string
return gmsh.option.getString(optionName) # -> use built-in gmsh.option.getString method
except: # option value was no string, so it must be a number
return gmsh.option.getNumber(optionName) # -> use built-in gmsh.option.getNumber method
############################################################
# method to set a single Gmsh option depending on its type #
############################################################
[docs]
def setGmshOption(self,optionName=None,optionValue=None):
"""Method to set a Gmsh configuration option
Parameters:
-----------
optionName: string
name of the option to set
optionValue: int/float/string
value of the option to set
"""
if isinstance(optionValue,str): # option value is a string
gmsh.option.setString(optionName,optionValue) # -> use built-in gmsh.option.setString method
elif isinstance(optionValue,int) or isinstance(optionValue,float): # optionValue is a number
gmsh.option.setNumber(optionName,optionValue) # -> use built-in gmsh.option.setNumber method
############################################################
# Method to add the model boundary to the physical entites #
############################################################
[docs]
def getBoundaryEntities(self):
"""Method to get the entities on the boundary of the Gmsh model"""
# get information for a physical entity containing the model boundary
return self.gmshAPI.getBoundary(self.gmshAPI.getEntities(self.dimension), combined=True, oriented=False, recursive=False)
###########################################
# Method to update the gmsh configuration #
###########################################
[docs]
def updateGmshConfiguration(self,configurationUpdate):
"""Method to update the Gmsh configuration options with a dictionary
of updated options
Parameters:
-----------
configurationUpdate: dict
dictionary of configuration options to be updated
"""
self.gmshConfigChanges.update(configurationUpdate) # update stored Gmsh configuration
for optionName, optionValue in self.gmshConfigChanges.items(): # loop over all configuration settings
self.setGmshOption(optionName=optionName,optionValue=optionValue) # -> activate changed configuration
#########################################################
# Method to add all geometric objects to the Gmsh model #
#########################################################
[docs]
def addGeometricObjectsToGmshModel(self):
"""Method to add Gmsh representations of the gmshModels geometric objects"""
for obj in self.geometricObjects: # loop over all geometric objects of the model
gmshTag=obj.addToGmshModel(self.gmshAPI) # -> add a Gmsh representation of the object to the model and save the correspondig tag
self.groups[obj.group].append(gmshTag) # -> add tag to the group of the geometric object
###############################################################
# Method to perform all boolean operations for the Gmsh model #
###############################################################
###############################################
# Method to add physical groups to Gmsh model #
###############################################
[docs]
def addPhysicalGroupsToGmshModel(self):
"""Method to add defined physical groups to the Gmsh model """
# loop over all physical entities of the model
for physGrp in self.physicalGroups:
# get details of the physical entity to add
grpDim=physGrp["dimension"] # get dimension of the physical group
grpName=physGrp["group"] # get the group of the physical entity (used as name)
grpNumber=physGrp["physicalNumber"] # get the number defined for the physical entity (used as material number)
grpEntIDs=self.getIDsFromTags(self.groups[grpName]) # find Gmsh representations of all group members and get IDs from their tags
# set physical groups
self.gmshAPI.addPhysicalGroup(grpDim,grpEntIDs,grpNumber) # define the entity group as physical and set correct physical number
self.gmshAPI.setPhysicalName(grpDim,grpNumber,grpName) # set corresponding name of the physical group (equal to name of the group that is declared as physical for simplicity)
#################################################
# Method to add refinement fields to Gmsh model #
#################################################
[docs]
def addRefinementFieldsToGmshModel(self):
"""Method to add defined refinement fields to the Gmsh model"""
# loop over all refinement fields defined for the model
for refineField in self.refinementFields:
# get details of the refinement field to add
fieldType=refineField["fieldType"] # get the type of refinement field
fieldInfos=refineField["fieldInfos"] # get information required for this type of refinement field
# set refinement field
fieldTag=self.gmshAPI.mesh.field.add(fieldType,tag=-1) # add new refinement field and save its number
for optName, optVal in fieldInfos.items(): # provide all necessary information for this field from fieldInfo dictionary
if isinstance(optVal,str): # -> current option value is a string
self.gmshAPI.mesh.field.setString(fieldTag,optName,optVal) # ->-> use built-in setString method of gmsh.model.mesh.field
elif isinstance(optVal,int) or isinstance(optVal,float): # -> current option value is a number
self.gmshAPI.mesh.field.setNumber(fieldTag,optName,optVal) # ->-> use built-in setNumber method of gmsh.model.mesh.field
elif isinstance(optVal,list) or isinstance(optVal,np.ndarray): # -> current option value is a list or numpy array
self.gmshAPI.mesh.field.setNumbers(fieldTag,optName,optVal) # ->-> use built-in setNumbers method of gmsh.model.mesh.field
################################################################################
# INTERFACING METHODS TO ADD GEOMETRIC OBJECTS TO THE MODEL #
################################################################################
##############################################################
# Method to add a single geometric object to the Gmsh model #
##############################################################
[docs]
def addGeometricObject(self,objClassString,**objData):
"""Method to add one of the objects that are defined within the class
geometricObjects and its child classes to the Gmsh model.
Parameters:
-----------
objClass: class
class the geometric object is defined in
objData: keyworded object data
enumeration of keyworded arguments needed for the creation of the
new geometric object of class objectClass
"""
objClass=self._getGeometricObjectClass(objClassString)
objInstance=objClass(**objData)
objGroup=objInstance.group
self.geometricObjects.append(objInstance)
self.groups.update({objGroup: []}) if objGroup not in self.groups else self.groups
################################################################################
# PRIVATE/HIDDEN METHODS FOR INTERNAL USE ONLY #
################################################################################
################################################
# Method to check file string for saving files #
################################################
def _getFileParts(self,fileString,whatToSave):
"""Internal method to get the file directory, name and extension from
a fileString
Parameters:
-----------
fileString: string
string to analyze
whatToSave: string
flag that indicates whether "geometry", "mesh" or "model" have to
be saved
"""
# check if no fileString was passed
if fileString is None: # no file string passed
fileString="" # -> set empty file string
# process passed file string
fileDir,fileName= os.path.split(fileString) # get file directory and name (with extension)
fileName,fileExt=os.path.splitext(fileName) # split file name into name and extension
if fileDir == "": # check if file directory is empty
fileDir="." # -> set default value (current directory)
if fileName == "": # check if file name is empty
fileName=self.modelName # use unique model name as file name
if fileExt == "": # check if file extension is empty
fileExt=self._defaultFileExts[whatToSave] # -> set default value (.gmshModel)
# return file parts
return fileDir, fileName, fileExt
########################################
# Method to toggle Gmsh console output #
########################################
def _gmshOutput(self,switch):
"""Method to enable/disable Gmsh console output"""
self.setGmshOption(optionName="General.Terminal",optionValue=switch)
############################################################################
# Method to return the correct boolean operation from the operation string #
############################################################################
def _getBooleanOperation(self,operation):
"""Internal method to return the correct boolean operation function
from an operation string
Parameters:
-----------
operation: string
boolean operation to be performed
"""
if operation == "cut": # operation to be performed is "cut"
return self.gmshAPI.occ.cut # -> use built-in gmsh.model.occ.cut method
elif operation == "fuse": # operation to be performed is "fuse"
return self.gmshAPI.occ.fuse # -> use built-in gmsh.model.occ.fuse method
elif operation == "fragment": # operation to be performed is "fragment"
return self.gmshAPI.occ.fragment # -> use built-in gmsh.model.occ.fragment method
elif operation == "intersect": # operation to be performed is "intersect"
return self.gmshAPI.occ.intersect # -> use built-in gmsh.model.occ.intersect method
else: # operation to be performed is something different
raise ValueError("Unknown boolean operation {}".format(operation)) # -> raise error that type of boolean operation is not known
#########################################################
# Method to get defined geometric objects from a string #
#########################################################
def _getGeometricObjectClass(self,objString):
"""Internal method to return the correct geometric object class from
an object class string
Parameters:
-----------
objString: string
required geometric object class (as a string)
"""
for objKey, objClass in inspect.getmembers(geomObj,inspect.isclass): # get all classes from the geometricObjects file
if objKey == objString: # check if class key matches the object string that was passed
return objClass # return class
###########################################################
# Method to calculate the overall Gmsh model bounding box #
###########################################################
def _getGmshModelBoundingBox(self):
"""Internal method to get the overall Gmsh model bounding box"""
entityBBoxes=np.atleast_2d([self.gmshAPI.getBoundingBox(*entTag) for entTag in self.gmshAPI.getEntities()])
modelBBox= np.array([[*np.amin(entityBBoxes[:,0:3],axis=0)], [*np.amax(entityBBoxes[:,3:6],axis=0)]])
return modelBBox
##########################################################
# Method to convert meshes into meshio-supported formats #
##########################################################
def _convertMesh(self,inFile,outFile):
"""Internal method to convert meshes between different file formats
using meshio
Parameters:
-----------
inFile: string
file string (directory/name.extension) for the input mesh file
outFile: string
file string (directory/name.extension) for the output mesh file
"""
mesh=meshio.read(inFile) # read file of mesh to convert with meshio (get mesh format from file extension)
mesh.write(outFile) # write file for converted mesh (get mesh format from file extension)