smesh/test/SMESH_MeshioShapes.py
Konstantin Leontev e85c9d5b6b [bos #40653][CEA] New mesh import export formats with meshio.
Added using MESHIO_VERSION env variable to detect meshio version.
Exodus format removed from a file filter on Windows.
2024-05-22 11:58:12 +01:00

266 lines
7.0 KiB
Python

# -*- coding: iso-8859-1 -*-
# Copyright (C) 2007-2024 CEA, EDF, 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
#
# =======================================
# Testing export/import of some simple shapes in different formats with meshio library
# File : SMESH_MeshioShapes.py
# Module : SMESH
import tempfile
from pathlib import Path
import salome
salome.salome_init()
import GEOM
from salome.geom import geomBuilder
import SMESH
from salome.smesh import smeshBuilder
import SALOME
import platform
# Constants
EXPORT_TITLE = 'Export'
IMPORT_TITLE = 'Import'
UNKNOWN_EXCEPTION = 'Unknown exception'
OUTPUT_DIVIDER = '\n==============================================='
geompy = geomBuilder.New()
smesh = smeshBuilder.New()
def make_plane():
"""
Makes default plane for testing.
"""
plane = geompy.MakeFaceHW(100, 100, 1)
geompy.addToStudy( plane, 'plane' )
return plane
def make_box():
"""
Makes default box for testing.
"""
box = geompy.MakeBoxDXDYDZ(200, 200, 200)
geompy.addToStudy(box, 'box')
return box
def make_mesh(shape, name):
"""
Makes a mesh from a given shape.
"""
res_mesh = smesh.Mesh(shape,name)
NETGEN_1D_2D = res_mesh.Triangle(algo=smeshBuilder.NETGEN_1D2D)
isDone = res_mesh.Compute()
assert isDone
smesh.SetName(res_mesh, name)
smesh.SetName(NETGEN_1D_2D.GetAlgorithm(), 'NETGEN 1D-2D')
smesh.SetName(res_mesh.GetMesh(), name)
return res_mesh
def file_extensions():
"""
Returns all files extensions supported by meshio.
Commented formats should be checked on next meshio release to see if the problem was fixed.
"""
extensions = [
'.avs',
'.bdf',
# '.cgns', # meshio IndexError: index 2 is out of bounds for axis 1 with size 2
# '.dat', # meshio ValueError: need at least one array to concatenate
'.dato',
'.dato.gz',
'.e',
# '.ele', # never returns from meshio convert command
'.exo',
# '.f3grid', # meshio IndexError: Replacement index 3 out of range for positional args tuple
'.fem',
# '.h5m', # meshio AttributeError: 'list' object has no attribute 'items'
'.inp',
'.mdpa',
'.med',
'.mesh',
'.meshb',
# '.msh', # meshio KeyError: "Illegal ANSYS cell type 'line'
'.nas',
# '.node', # never returns from meshio convert command
# '.obj', # meshio._exceptions.WriteError: Wavefront .obj files can only contain triangle or quad cells
# '.off', # failed on Windows only
# '.ply', # Export Warning: PLY doesn't support 64-bit integers. Casting down to 32-bit. Then import failed
'.post',
'.post.gz',
'.stl',
# '.su2', # meshio TypeError: cannot unpack non-iterable CellBlock object
# '.svg', # meshio._exceptions.WriteError: SVG can only handle flat 2D meshes
# '.ugrid', # meshio AttributeError: 'list' object has no attribute 'reshape'
'.vol',
'.vol.gz',
'.vtk',
'.vtu',
# '.wkt', # Export Warning: WTK only supports triangle cells. Skipping {", ".join(skip)} then import failed
'.xdmf',
'.xmf',
'.xml'
]
if platform.system() == 'Windows':
extensions = [ext for ext in extensions if not ext in ['.e', '.exo']] # needs to be digged out - presumably an issue about encoding.
return extensions
def exception_handle(file_name, errors, operation_type, ex_text):
"""
Pepares and saves an exception message.
"""
ext = Path(file_name).suffix.upper()
msg = '{} {} failed! File name: {}'.format(operation_type, ext, file_name)
if ex_text:
msg += ' Exception: ' + ex_text + OUTPUT_DIVIDER + '\n'
errors.append(msg)
def export_mesh(mesh, file_name, errors):
"""
Performs an export operatin.
"""
try:
print('Export to file: ', file_name)
# Here we use an empty selected filter to make things simpler
mesh.ExportMESHIO(file_name, '', mesh)
return True
except SALOME.SALOME_Exception as ex:
exception_handle(file_name, errors, EXPORT_TITLE, ex.details.text)
except:
exception_handle(file_name, errors, EXPORT_TITLE, UNKNOWN_EXCEPTION)
return False
def import_file(file_name, errors):
"""
Performs an import operatin.
"""
try:
print('Import from file: ', file_name)
([mesh], status) = smesh.CreateMeshesFromMESHIO(file_name)
return mesh
except SALOME.SALOME_Exception as ex:
exception_handle(file_name, errors, IMPORT_TITLE, ex.details.text)
except:
exception_handle(file_name, errors, IMPORT_TITLE, UNKNOWN_EXCEPTION)
return None
def print_errors(errors):
"""
Checks if we have got any saved error messages and print them.
The test failed in this case.
"""
if not len(errors):
return
print('\nErrors:\n')
for idx, err in enumerate(errors):
print('{:02}: {}'.format(idx, err))
print(OUTPUT_DIVIDER)
def perform(mesh, name, errors):
"""
Exports a given mesh and imports it back for each file format.
"""
for ext in file_extensions():
with tempfile.NamedTemporaryFile(suffix=ext, prefix=name) as file:
file.close() # prevents PermissionError on Windows
if (export_mesh(mesh, file.name, errors)):
file.close() # prevents PermissionError on Windows
import_file(file.name, errors)
def test_box(errors):
"""
Tests export / import of a mesh for a default box geometry.
"""
box = make_box()
mesh_name = 'Test_box_'
mesh = make_mesh(box, mesh_name)
perform(mesh, mesh_name, errors)
def test_plane(errors):
"""
Tests export / import of a mesh for a default plane geometry.
"""
plane = make_plane()
mesh_name = 'Test_plane_'
mesh = make_mesh(plane, mesh_name)
perform(mesh, mesh_name, errors)
def test():
"""
Creates meshes from plane and box and tries to export them to a temp files
and import them back with different formats supported by meshio library.
Prints errors if we have any.
"""
errors = []
test_plane(errors)
test_box(errors)
print_errors(errors)
assert not len(errors)
if __name__ == "__main__":
test()