From 1b746b38f3cdeae6654a9501f37fde5e56e59288 Mon Sep 17 00:00:00 2001 From: Christophe Bourcier Date: Tue, 4 Jun 2024 15:41:46 +0200 Subject: [PATCH] Add test for .mesh file format --- src/MEDLoader/Swig/MeshFormatWriterTest1.py | 304 ++++++++++++++++++++ src/MEDLoader/Swig/tests.set | 1 + 2 files changed, 305 insertions(+) create mode 100644 src/MEDLoader/Swig/MeshFormatWriterTest1.py diff --git a/src/MEDLoader/Swig/MeshFormatWriterTest1.py b/src/MEDLoader/Swig/MeshFormatWriterTest1.py new file mode 100644 index 000000000..ec7cb633e --- /dev/null +++ b/src/MEDLoader/Swig/MeshFormatWriterTest1.py @@ -0,0 +1,304 @@ +# Copyright (C) 2007-2024 CEA, EDF +# +# 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 + +from MEDLoader import * +import unittest +from MEDLoaderDataForTest import MEDLoaderDataForTest,WriteInTmpDir + +class MeshFormatWriterTest2(unittest.TestCase): + + def createMesh(self, nb_seg): + + # Create mesh + mesh_dim = 3 + self.bounding_box_coords = [(0, 100)]*mesh_dim + # with 25 segs per side, time of test run + # 9.12: 7.8 s + # 9.13: 0.1 s + + # with 100 nb_segs per side: + # 9.12: more than 3 h + # 9.13: 8.14 s + + nb_segs = [nb_seg]*mesh_dim + box_sizes = [size_coords[1]-size_coords[0] for size_coords in self.bounding_box_coords] + print("box_sizes: ", box_sizes) + box_steps = [box_sizes[i]/nb_segs[i] for i in range(mesh_dim)] + l_nb_nodes = [nb_segs_i+1 for nb_segs_i in nb_segs] + l_start = [size_coords[0] for size_coords in self.bounding_box_coords] + l_end = [size_coords[1] for size_coords in self.bounding_box_coords] + + mesh = MEDCouplingIMesh("Mesh", mesh_dim, l_nb_nodes, l_start, box_steps) + self.mesh = mesh.buildUnstructured() + pass + + def createVolumeGroups(self): + nb_cells = self.mesh.getNumberOfCells() + nb_half_cells = int(round(nb_cells/2)) + grp0 = DataArrayInt(list(range(nb_half_cells))) + grp0.setName("half1") + grp1 = DataArrayInt(list(range(nb_half_cells, nb_cells))) + grp1.setName("half2") + self.volumeGroups = [grp0, grp1] + pass + + def createSkinGroups(self): + # create groups on each side of skin mesh + nb_faces = self.skinMesh.getNumberOfCells() + #xMin, xMax, yMin, yMax, zMin, zMax + xMin, xMax = self.bounding_box_coords[0] + yMin, yMax = self.bounding_box_coords[1] + zMin, zMax = self.bounding_box_coords[2] + tol = 1e-10 + barycenters = self.skinMesh.computeIsoBarycenterOfNodesPerCell() + left = [] + right = [] + bottom = [] + top = [] + back = [] + front = [] + for i in range(nb_faces): + coord = barycenters[i] + x, y, z = coord.getValues() + if abs(x-xMin) < tol: + left.append(i) + elif abs(x-xMax) < tol: + right.append(i) + elif abs(y-yMin) < tol: + back.append(i) + elif abs(y-yMax) < tol: + front.append(i) + elif abs(z-zMin) < tol: + bottom.append(i) + elif abs(z-zMax) < tol: + top.append(i) + + grp_left = DataArrayInt(left) + grp_left.setName("left") + grp_right = DataArrayInt(right) + grp_right.setName("right") + grp_back = DataArrayInt(back) + grp_back.setName("back") + grp_front = DataArrayInt(front) + grp_front.setName("front") + grp_bottom = DataArrayInt(bottom) + grp_bottom.setName("bottom") + grp_top = DataArrayInt(top) + grp_top.setName("top") + self.skinGroups = [grp_left, grp_right, grp_back, grp_front, grp_bottom, grp_top] + pass + + def createField(self): + # create a field on nodes with 1 component + coords = self.mesh.getCoords() + coords_z = coords[:,2] + zMin, zMax = self.bounding_box_coords[2] + coords_z_normed = coords_z/(zMax-zMin) + size_min = 1e-4 + size_max = 1e-3 + coords_z_normed.applyFuncOnThis('(%f-%f)*tanh(x)/tanh(1)+%f'%(size_max, size_min, size_min)) + + # Create the field with this array + self.field = MEDCouplingFieldDouble(ON_NODES,ONE_TIME) + self.field.setName("Elevation") + self.field.setMesh(self.mesh) + self.field.setTime(0,1,1) + self.field.setArray(coords_z_normed) + pass + + def createMEDMeshFile(self): + self.meshMEDFile = MEDFileUMesh() + self.meshMEDFile.setMeshAtLevel(0, self.mesh) + self.meshMEDFile.setGroupsAtLevel(0, self.volumeGroups) + self.meshMEDFile.setMeshAtLevel(-1, self.skinMesh) + self.meshMEDFile.setGroupsAtLevel(-1, self.skinGroups) + pass + + def setMeshInMEDFileData(self): + # Set mesh in file data structure + ms=MEDFileMeshes() + ms.pushMesh(self.meshMEDFile) + self.medFileData = MEDFileData() + self.medFileData.setMeshes(ms) + pass + + def setFieldInMEDFileData(self): + mf=MEDFileFields() + fmts0=MEDFileFieldMultiTS() + mf.pushField(fmts0) + f1ts=MEDFileField1TS() + f1ts.setFieldNoProfileSBT(self.field) + fmts0.pushBackTimeStep(f1ts) + self.medFileData.setFields(mf) + pass + + def writeToMeshFile(self, meshFileName): + tmpMeshWriter = MeshFormatWriter() + tmpMeshWriter.setMeshFileName(meshFileName) + tmpMeshWriter.setMEDFileDS(self.medFileData) + tmpMeshWriter.write() + pass + + def readMeshFile(self, meshFileName): + meshFormatReader = MeshFormatReader() + meshFormatReader.setFile(meshFileName) + medFileData = meshFormatReader.loadInMedFileDS() + meshes = medFileData.getMeshes() + meshNames = meshes.getMeshesNames() + assert len(meshNames) == 1 + self.meshMEDFileOut = meshes.getMeshWithName(meshNames[0]) + + def compareFamilies(self, levels): + meshRef = self.meshMEDFile + meshRead = self.meshMEDFileOut + # compare families on levels + for level in levels: + print("level: ", level) + # ids of families at this level + referenceFamilyIds = meshRef.getFamilyFieldAtLevel(level).getDifferentValues().getValues() + print("referenceFamilyIds; ", referenceFamilyIds) + readFamilyIds = meshRead.getFamilyFieldAtLevel(level).getDifferentValues().getValues() + print("readFamilyIds: ", readFamilyIds) + assert len(readFamilyIds) == len(readFamilyIds) + + for ref_id in referenceFamilyIds: + # by convention, the id in the .mesh file is the abs of the family + read_id = abs(ref_id) + referenceName = meshRef.getFamilyNameGivenId(ref_id) + readName = meshRead.getFamilyNameGivenId(read_id) + + referenceFamilyArr = meshRef.getFamilyArr(level, referenceName) + readFamilyArr = meshRead.getFamilyArr(level, readName) + + # compare family arrays + referenceFamilyArr = meshRef.getFamilyArr(level, referenceName) + readFamilyArr = meshRead.getFamilyArr(level, readName) + referenceFamilyArr.isEqualWithoutConsideringStr(readFamilyArr) + #print(readFamilyArr_i) + + # compare family meshes + referenceFamily = meshRef.getFamily(level, referenceName) + readFamily = meshRead.getFamily(level, readName) + + assert referenceFamily.isEqualWithoutConsideringStr(readFamily, 1e-12) + + @WriteInTmpDir + def testMeshHexaWithoutField(self): + """ + Test writing .mesh without field does not crash (as it did before 9.13) + """ + + nb_seg = 3 + self.createMesh(nb_seg) + + # Create groups + self.createVolumeGroups() + # Build 1D mesh and create groups of faces + self.skinMesh = self.mesh.computeSkin() + self.createSkinGroups() + self.createField() + self.createMEDMeshFile() + + self.setMeshInMEDFileData() + + # write to med (to debug if needed) + #medFileData.write("Mesh3D_hexa.med", 2) + + # write to .mesh + self.writeToMeshFile("Mesh3D_hexa_%i.mesh"%nb_seg) + # test succeeds if there is no crash + pass + + @WriteInTmpDir + def testMeshHexaWithField(self): + """ + Test writing .mesh is not too slow (more than 9 seconds before 9.13) + """ + + nb_seg = 25 + self.createMesh(nb_seg) + + # Create groups + self.createVolumeGroups() + # Build 1D mesh and create groups of faces + self.skinMesh = self.mesh.computeSkin() + self.createSkinGroups() + self.createField() + self.createMEDMeshFile() + + # Set mesh in file data structure + self.setMeshInMEDFileData() + # Set field in file data structure + self.setFieldInMEDFileData() + + # Write to med (to debug if needed) + #medFileData.write("Mesh3D_hexa.med", 2) + + # Write to .mesh + meshFileName = "Mesh3D_hexa_%i.mesh"%nb_seg + self.writeToMeshFile(meshFileName) + + # Read Mesh File + self.readMeshFile(meshFileName) + + # Compare families at levels + self.compareFamilies([0, -1]) + + pass + + @WriteInTmpDir + def testMeshTetraWithField(self): + """ + Test writing .mesh tetra + """ + + nb_seg = 3 + self.createMesh(nb_seg) + + self.mesh = self.mesh.tetrahedrize(PLANAR_FACE_5)[0].buildUnstructured() + + # Create groups + self.createVolumeGroups() + # Build 1D mesh and create groups of faces + self.skinMesh = self.mesh.computeSkin() + self.createSkinGroups() + self.createField() + self.createMEDMeshFile() + + # Set mesh in file data structure + self.setMeshInMEDFileData() + # Set field in file data structure + self.setFieldInMEDFileData() + + # Write to med (to debug if needed) + #medFileData.write("Mesh3D_tetra.med", 2) + + # Write to .mesh + meshFileName = "Mesh3D_hexa_%i.mesh"%nb_seg + self.writeToMeshFile(meshFileName) + + # Read Mesh File + self.readMeshFile(meshFileName) + + # Compare families at levels + self.compareFamilies([0, -1]) + + pass + +if __name__ == '__main__': + unittest.main() diff --git a/src/MEDLoader/Swig/tests.set b/src/MEDLoader/Swig/tests.set index fb403aa4e..2e58e3739 100644 --- a/src/MEDLoader/Swig/tests.set +++ b/src/MEDLoader/Swig/tests.set @@ -22,6 +22,7 @@ SET(BASE_TESTS MEDLoaderTest4.py MEDLoaderExamplesTest.py UsersGuideExamplesTest_ML.py + MeshFormatWriterTest1.py ) # if numpy is used -- 2.39.2