2 # -*- coding: utf-8 -*-
4 # %% LICENSE_SALOME_CEA_BEGIN
5 # Copyright (C) 2008-2016 CEA/DEN
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 # See http://www.salome-platform.org or email : webmaster.salome@opencascade.com
26 run coherency tests on one and some mesh.
27 initially used for test output(s) mg_tetra_hpc_mpi.exe
29 WARNING: is for small meshes, obviously no optimisation.
30 WARNING: printing and .mesh indices are 1 to n when stored list python 0 to n-1
34 ./testMesh.py --verbose --testall --files ./GHS3DPRL_out.000001.mesh ./GHS3DPRL_out.000002.mesh
35 ./testMesh.py -a -f /tmp/GHS3DPRL_out.00000?.mesh
42 import pprint as PP # pretty print
53 #########################################
56 def okToSys(aResult, verbose=False):
57 """to get windows or linux result of script"""
59 def extendList(alist):
60 """utility extend list of lists of string results with ok or KO"""
61 # bad: list(itertools.chain.from_list(alist)) iterate on str
63 if type(alist) != list:
70 res.extend(extendList(i))
73 resList = extendList(aResult)
75 if verbose: print("WARNING: result no clear: []")
84 if verbose: print("INFO: result: %s" % rr)
90 def getDirAndName(datafile):
91 path, namefile = os.path.split(os.path.realpath(datafile))
92 rootpath = os.getcwd()
93 return (path, rootpath, namefile)
95 def resumeList(aList):
100 res = [aList[0], "...", aList[-1]]
103 def resumeLines(aList, ilines):
104 if verbose: print("INFO: resumeLines", ilines)
111 if i != None: # if not existing tetrahedra for example
112 resi = [ii.strip("\n") for ii in aList[i:i + 4]]
118 #########################################
120 """Vertices, Nodes"""
121 def __init__(self, x, y, z, color=0, indexglobal=0):
126 self.indexglobal = indexglobal
128 def compare(self, vb, args, withAll=True):
129 if self.x != vb.x: return False
130 if self.y != vb.y: return False
131 if self.z != vb.z: return False
134 if self.color != vb.color: return False
136 if self.indexglobal != vb.indexglobal: return False
139 def __eq__(self, vb):
140 """equality test without color or indexglobal"""
141 # print "vertice equality"
142 if self.x != vb.x: return False
143 if self.y != vb.y: return False
144 if self.z != vb.z: return False
147 def __ne__(self, vb):
148 """inequality test without color or indexglobal"""
149 # print "vertice inequality"
150 if self.x == vb.x and self.y == vb.y and self.z != vb.z:
155 return "XXVert(%.4f %.4f %.4f (%i %i))" % \
156 (self.x, self.y, self.z, self.color, self.indexglobal)
159 return "(%s %s %s (%i %i))" % \
160 (self.x, self.y, self.z, self.color, self.indexglobal)
163 res = (self.x - vb.x) ** 2 + (self.y - vb.y) ** 2 + (self.z - vb.z) ** 2
167 #########################################
170 def __init__(self, a, b, color=0, indexglobal=0):
174 self.indexglobal = indexglobal
176 def compare(self, eb, args):
177 res = self.a.compare(eb.a, args) and \
178 self.b.compare(eb.b, args)
181 if self.color != eb.color: return False
183 if self.indexglobal != eb.indexglobal: return False
187 return "XXEdge(%i %i (%i %i))" % \
188 (self.a, self.b, self.color, self.indexglobal)
191 return "(%i %i (%i %i))" % \
192 (self.a, self.b, self.color, self.indexglobal)
194 def inTria(self, tria, args):
195 t = [tria.a, tria.b, tria.c]
196 if not self.a in t: return False
197 if not self.b in t: return False
200 def getVertices(self, mesh):
201 v1 = mesh.verts[self.a - 1]
202 v2 = mesh.verts[self.b - 1]
206 #########################################
208 """Triangles, Faces, 3 nodes"""
209 def __init__(self, a, b, c, color=0, indexglobal=0):
214 self.indexglobal = indexglobal
216 def compare(self, trb, args):
217 res = self.a.compare(trb.a, args) and \
218 self.b.compare(trb.b, args) and \
219 self.c.compare(trb.c, args)
222 if self.color != trb.color: return False
224 if self.indexglobal != trb.indexglobal: return False
228 return "XXTria(%i %i %i (%i %i))" % \
229 (self.a, self.b, self.c, self.color, self.indexglobal)
232 return "(%i %i %i (%i %i))" % \
233 (self.a, self.b, self.c, self.color, self.indexglobal)
235 def inTetra(self, tetra, args):
236 t = [tetra.a, tetra.b, tetra.c, tetra.d]
237 if not self.a in t: return False
238 if not self.b in t: return False
239 if not self.c in t: return False
242 def getVertices(self, mesh):
243 v1 = mesh.verts[self.a - 1]
244 v2 = mesh.verts[self.b - 1]
245 v3 = mesh.verts[self.c - 1]
249 #########################################
252 def __init__(self, a, b, c, d, color=0, indexglobal=0):
258 self.indexglobal = indexglobal
260 def compare(self, teb, args):
261 res = self.a.compare(teb.a, args) and \
262 self.b.compare(teb.b, args) and \
263 self.c.compare(teb.c, args) and \
264 self.d.compare(teb.d, args)
267 if self.color != teb.color: return False
269 if self.indexglobal != teb.indexglobal: return False
273 return "XXTetra(%i %i %i %i (%i %i))" % \
274 (self.a, self.b, self.c, self.d, self.color, self.indexglobal)
277 return "(%i %i %i %i (%i %i))" % \
278 (self.a, self.b, self.c, self.d, self.color, self.indexglobal)
280 def getVertices(self, mesh):
281 v1 = mesh.verts[self.a - 1]
282 v2 = mesh.verts[self.b - 1]
283 v3 = mesh.verts[self.c - 1]
284 v4 = mesh.verts[self.d - 1]
285 return [v1, v2, v3, v4]
288 #########################################
290 """Mesh: vertices, edges, triangles, tetrahedra"""
298 def initFromFileMesh(self, fileName, args, withGlobal=True):
299 if not os.path.isfile(fileName):
300 raise Exception("ERROR: inexisting file '%s'" % fileName)
301 with open(fileName, "r") as f:
302 lines = f.readlines()
303 iverts, iedges, itrias, itetras = self.getIndexInMeshFile(lines)
304 self.verts = self.getMeshVerts(lines, iverts)
305 self.edges = self.getMeshEdges(lines, iedges)
306 self.trias = self.getMeshTrias(lines, itrias)
307 self.tetras = self.getMeshTetras(lines, itetras)
308 self.nameFile = fileName
309 if args.globalNumerotation == True and withGlobal == True:
310 self.initFromFileGlobal(fileName, args)
312 print("\nINFO: initFromFileMesh: read file: %s" % str(self))
313 print(self.strResume())
314 print(PP.pformat(resumeLines(lines, [iverts, iedges, itrias, itetras])))
316 def initFromFileGlobal(self, fileNameMeshOrGlobal, args):
317 shortname, extension = os.path.splitext(fileNameMeshOrGlobal)
318 if extension == ".mesh":
319 fileName = shortname + ".global"
320 elif extension == "global":
321 fileName = fileNameMeshOrGlobal
323 raise Exception("ERROR: initFromFileGlobal: unexpected file '%s'" % fileName)
324 if not os.path.isfile(fileName):
325 raise Exception("ERROR: initFromFileGlobal: inexisting file '%s'" % fileName)
327 with open(fileName, "r") as f:
328 lines = f.readlines()
329 nbverts, nbedges, nbtrias, nbtetras = [int(i) for i in lines[0].split()]
331 print("\nINFO: initFromFileGlobal: read file: %s" % str(self))
332 print(" nbverts %i\n nbedges %i\n nbtrias %i\n nbtetras %i" % (nbverts, nbedges, nbtrias, nbtetras))
333 if nbverts != len(self.verts):
334 raise Exception("ERROR: in file '%s' unexpected number of Vertices %i<>%i" % (fileName, nbverts, len(self.verts)))
335 if nbedges != len(self.edges):
336 raise Exception("ERROR: in file '%s' unexpected number of Edges %i<>%i" % (fileName, nbedges, len(self.edges)))
337 if nbtrias != len(self.trias):
338 raise Exception("ERROR: in file '%s' unexpected number of Triangles %i<>%i" % (fileName, nbtrias, len(self.trias)))
339 if nbtetras != len(self.tetras):
340 raise Exception("ERROR: in file '%s' unexpected number of Tetrahedra %i<>%i" % (fileName, nbtetras, len(self.tetras)))
341 i = 1 # begin index line 1
342 for ii in range(nbverts):
343 self.verts[ii].indexglobal = int(lines[i])
345 for ii in range(nbedges):
346 self.edges[ii].indexglobal = int(lines[i])
348 for ii in range(nbtrias):
349 self.trias[ii].indexglobal = int(lines[i])
351 for ii in range(nbtetras):
352 self.tetras[ii].indexglobal = int(lines[i])
357 return "XXMesh(nameFile='%s', nbverts=%i, nbedges=%i, nbtrias=%i, nbtetras=%i)" % \
358 (self.nameFile, len(self.verts), len(self.edges), len(self.trias), len(self.tetras))
363 "Vertices": resumeList(self.verts),
364 "Edges": resumeList(self.edges),
365 "Triangles": resumeList(self.trias),
366 "Tetrahedra": resumeList(self.tetras),
368 res = res + "\n" + PP.pformat(contents)
371 def getIndexInMeshFile(self, lines):
373 for s in ["Vertices", "Edges", "Triangles", "Tetrahedra"]:
375 i = lines.index(s + "\n")
381 def getMeshVerts(self, lines, i):
385 ilen = int(lines[i + 1])
387 for line in lines[idep:ifin]:
389 x, y, z, color = float(li[0]), float(li[1]), float(li[2]), int(li[3])
390 res.append(XXVert(x, y, z, color))
395 def getMeshEdges(self, lines, i):
399 ilen = int(lines[i + 1])
401 for line in lines[idep:ifin]:
403 a, b, color = int(li[0]), int(li[1]), int(li[2])
404 res.append(XXEdge(a, b, color))
409 def getMeshTrias(self, lines, i):
413 ilen = int(lines[i + 1])
415 for line in lines[idep:ifin]:
417 a, b, c, color = int(li[0]), int(li[1]), int(li[2]), int(li[3])
418 res.append(XXTria(a, b, c, color))
423 def getMeshTetras(self, lines, i):
427 ilen = int(lines[i + 1])
429 for line in lines[idep:ifin]:
431 a, b, c, d, color = int(li[0]), int(li[1]), int(li[2]), int(li[3]), int(li[4])
432 res.append(XXTetra(a, b, c, d, color))
437 def haveVertsDistinct(self, args):
438 """stop a first KO"""
441 for v1 in verts[:-1]:
446 if v1.compare(v2, args):
447 # printing indices 1 to n
448 print("ERROR: %s vert[%i] equal vert[%i]: v1=%s v2=%s" % (self.nameFile, i, j, v1, v2))
449 return KO + " ERROR: %s some equal vertices" % self.nameFile # stop a first KO
450 return OK + " INFO: no equal vertices"
452 def getVertices(self, elem):
453 """functionnal raccourci to XXElem.getVertices(XXMesh)"""
454 return elem.getVertices(self)
456 def compareListOfVertices(self, v1s, v2s, ordered=False):
457 """not ordered for now"""
459 res = [i for i, j in zip(v1s, v2s) if i == j]
460 return len(res) == len(v1s)
468 return res == len(v1s)
471 def getCommonVerts(self, mesh, args):
473 for v1 in self.verts:
474 for v2 in mesh.verts:
475 if v1.compare(v2, args, withAll=False):
479 def getCommonEdges(self, mesh, args):
481 for e1 in self.edges:
482 v1s = self.getVertices(e1)
483 for e2 in mesh.edges:
484 v2s = mesh.getVertices(e2)
485 if self.compareListOfVertices(v1s, v2s):
489 def getCommonTriangles(self, mesh, args):
491 for e1 in self.trias:
492 v1s = self.getVertices(e1)
493 for e2 in mesh.trias:
494 v2s = mesh.getVertices(e2)
495 if self.compareListOfVertices(v1s, v2s):
499 def getCommonTetras(self, mesh, args):
501 for e1 in self.tetras:
502 v1s = self.getVertices(e1)
503 for e2 in mesh.tetras:
504 v2s = mesh.getVertices(e2)
505 if self.compareListOfVertices(v1s, v2s):
509 def areEdgesInTrias(self, args):
510 """stop a first KO"""
515 res = OK + " INFO: %s all edges in trias" % self.nameFile
522 if e.inTria(t, args):
523 # if verbose: print("INFO: %s edges[%i] in trias[%i]: edge=%s tria=%s" % (self.nameFile, i, j, e, t))
527 print("ERROR: %s edges[%i] not in trias: edge=%s" % (self.nameFile, i, e))
528 if verbose and not done:
529 print("Triangles:\n%s" % PP.pformat(self.trias))
531 res = KO + " ERROR: %s some edges not in trias" % (self.nameFile)
535 def areTriasInTetras(self, args):
536 """no stop a first KO"""
541 if tetras == []: # supposed skin without tetrahedra
542 res = OK + " WARNING: %s no tetrahedra in mesh" % (self.nameFile)
544 res = OK + " INFO: %s all trias in tetras" % self.nameFile
551 if t.inTetra(h, args):
552 # if verbose: print("INFO: %s trias[%i] in tetras[%i]: tria=%s tetra=%s" % (self.nameFile, i, j, t, h))
556 if verbose: print("ERROR: %s trias[%i] not in tetras: tria=%s" % (self.nameFile, i, t))
557 if verbose and not done:
558 print("INFO: Tetrahedra:\n%s" % PP.pformat(self.tetras))
560 res = KO + " ERROR: %s some trias not in tetras" % (self.nameFile)
563 def testIntersection(self, mesh, args):
564 """intersection coherency between self and mesh"""
566 def storeAndInfoIntersection():
567 """used as macro: avoid duplicate code"""
568 # store info in args to use later...
569 args.intersections[title + name] = commons
571 res.append(OK + " INFO: no %s" % title + name)
573 res.append(OK + " INFO: existing %s" % title + name)
577 name = "%s<->%s" % (self.nameFile, mesh.nameFile)
579 title = "Vertices intersection: "
580 commons = self.getCommonVerts(mesh, args)
581 storeAndInfoIntersection()
583 title = "Edges intersection: "
584 commons = self.getCommonEdges(mesh, args)
585 storeAndInfoIntersection()
587 title = "Triangles intersection: "
588 commons = self.getCommonTriangles(mesh, args)
589 storeAndInfoIntersection()
591 title = "Tetrahedra intersection: "
592 commons = self.getCommonTetras(mesh, args)
593 storeAndInfoIntersection()
597 def testIndexGlobal(self, mesh, args):
598 """global index coherency between self and mesh"""
600 def storeAndInfoIndexGlobal():
601 """used as macro: avoid duplicate code"""
602 # store info in args to use later...
603 args.indexglobal[title + name] = problems
604 if verbose: print("\nINFO: %s\n%s" % (title + name, PP.pformat(problems)))
606 res.append(OK + " INFO: coherent %s" % title + name)
608 res.append(KO + " ERROR: some problems %s" % title + name)
611 def testIndexGlobal():
612 """used as macro: avoid duplicate code"""
613 nameElem = title.split(' ')[0]
614 # something like 'Vertices intersection: /tmp/GHS3DPRL_out.000002.mesh<->/tmp/GHS3DPRL_out.000003.mesh'
615 commonsTitle = nameElem + " intersection: " + name
616 # if verbose: print "testIndexGlobal",title,commonsTitle
618 intersection = args.intersections[commonsTitle]
622 for ii, jj in intersection:
623 if ii.indexglobal != jj.indexglobal:
624 problems.append((ii, jj))
628 name = "%s<->%s" % (self.nameFile, mesh.nameFile)
630 title = "Vertices indexglobal: "
631 problems = testIndexGlobal()
632 storeAndInfoIndexGlobal()
634 title = "Edges indexglobal: "
635 problems = testIndexGlobal()
636 storeAndInfoIndexGlobal()
638 title = "Triangles indexglobal: "
639 problems = testIndexGlobal()
640 storeAndInfoIndexGlobal()
642 title = "Tetrahedra indexglobal: "
643 problems = testIndexGlobal()
644 storeAndInfoIndexGlobal()
649 #########################################
653 """test all on meshes from tetra_hpc_mpi"""
655 if verbose: print("\n*****testAll*****\n")
657 if args.skinInputFile != None:
658 args.skinMesh = XXMesh()
659 # a priori no global numerotation file.global for input tetra_hpc_mpi mesh
660 args.skinMesh.initFromFileMesh(args.skinInputFile, args, withGlobal=False)
661 res.append(testStandaloneMesh(args.skinMesh, args))
662 print("\nINFO: testAll skin input file:\n%s" % (PP.pformat(args.skinMesh)))
665 for fileName in args.files:
667 xxmesh.initFromFileMesh(fileName, args)
668 meshes.append(xxmesh)
669 print("\nINFO: testAll ouput files:\n%s\n" % (PP.pformat(meshes)))
670 # test coherence of one by one meshes
672 res.append(testStandaloneMesh(mesh, args))
673 # test coherence of intersections an global numerotation of tetra_hpc_mpi output meshes
674 res.append(testParallelMesh(meshes, args))
675 res.append(testParallelMeshAndSkin(meshes, args))
676 res.append(testParallelMeshAndSkinColor(meshes, args))
680 def testStandaloneMesh(mesh, args):
681 """test coherence of one mesh alone"""
682 if verbose: print("\nINFO: testStandaloneMesh:\n%s" % PP.pformat(mesh))
684 res.append(mesh.haveVertsDistinct(args))
685 res.append(mesh.areEdgesInTrias(args))
686 res.append(mesh.areTriasInTetras(args))
690 def testParallelMesh(meshes, args):
691 """test intersection and overriding in tetra_hpc_mpi outputs GHS3DPRL_out.00000?.mesh"""
694 args.intersections = {}
695 args.indexglobal = {}
696 for m1 in meshes[:-1]:
698 for m2 in meshes[i:]:
699 res.append(m1.testIntersection(m2, args))
700 res.append(m1.testIndexGlobal(m2, args))
702 print("\nINFO: intersections\n%s" % PP.pformat(args.intersections))
703 print("\nINFO: indexglobal\n%s" % PP.pformat(args.indexglobal))
706 def testParallelMeshAndSkin(meshes, args):
707 """test coherency between input skin and tetra_hpc_mpi outputs GHS3DPRL_out.00000?.mesh"""
709 if args.skinMesh == None:
710 print("INFO: no skin Mesh for testing intersectionsSkin\n")
711 res = OK + "INFO: no skin Mesh for testing intersectionsSkin"
713 nbtriasskin = len(args.skinMesh.trias)
715 res.append(args.skinMesh.testIntersection(m1, args))
716 res.append(args.skinMesh.testIndexGlobal(m1, args))
718 # test total Triangles in output parallel meshes vs input skin mesh
722 for k in list(args.intersections.keys()):
723 if args.skinMesh.nameFile in k:
724 ll = len(args.intersections[k])
725 if "Triangles intersection" in k:
727 kk[k] = len(args.intersections[k])
728 print("INFO: skin intersections\n%s\n" % PP.pformat(kk))
729 if nbtriaspara < nbtriasskin:
730 res.append(KO + " ERROR: problem all skin triangles not in parallel meshes: %i<->%i" % (nbtriasskin, nbtriaspara))
733 def testParallelMeshAndSkinColor(meshes, args):
734 """test coherency between color input skin and tetra_hpc_mpi outputs GHS3DPRL_out.00000?.mesh"""
736 if args.color == True:
737 res.append(KO + " ERROR: test color TODO!!!")
739 res.append(OK + " WARNING: test color not done")
742 if __name__ == '__main__':
743 parser = AP.ArgumentParser(description='launch test(s) on tetra_hpc_mpi mesh(es)', argument_default=None)
746 help='test all on all meshes',
751 help='set verbose, for deep debug',
755 '-g', '--globalNumerotation',
756 help='read and set files .global, if associated',
761 help='read and test with color',
766 help='launch test(s) on file(s)',
768 metavar='.../file.mesh'
771 '-s', '--skinInputFile',
772 help='launch test(s) on tetra_hpc_mpi input file',
774 metavar='.../skinInputFile.mesh'
778 '-x', '--xoneargument',
782 help='one argument, for example',
789 args is Namespace, use it as global to store
790 parameters, data, used arrays and results and other...
792 args = parser.parse_args()
794 verbose = args.verbose
795 if verbose: print("INFO: args:\n%s" % PP.pformat(args))
797 if len(sys.argv) == 1: # no args as --help
801 if args.files == None:
802 print("\nERROR: Nothing to do: no files\n%s" % PP.pformat(args))
807 result = testAll(args)
810 print("\nERROR: Nothing to do:\n%s" % PP.pformat(args))
811 sys.exit(okToSys(result, verbose=True))