Salome HOME
96e30e7f26ae52a385c4c5a70d5dd0550aac3ba3
[plugins/ghs3dprlplugin.git] / src / tools / testMesh.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 # Copyright (C) 2008-2023  CEA, EDF
5 #
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
10 #
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 #
20 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 #
22
23 """
24 run coherency tests on one and some mesh.
25 initially used for test output(s) mg_tetra_hpc_mpi.exe
26
27 WARNING: is for small meshes, obviously no optimisation.
28 WARNING: printing and .mesh indices are 1 to n when stored list python 0 to n-1
29
30 example linux usage:
31 - simple run:
32   ./testMesh.py --verbose --testall --files ./GHS3DPRL_out.000001.mesh ./GHS3DPRL_out.000002.mesh
33   ./testMesh.py -a -f /tmp/GHS3DPRL_out.00000?.mesh
34 """
35
36 import os
37 import sys
38
39 import argparse as AP
40 import pprint as PP  # pretty print
41
42
43 verbose = False
44
45 OK = "ok"
46 KO = "KO"
47 OKSYS = 0  # for linux
48 KOSYS = 1  # for linux
49
50
51 #########################################
52 # utilities
53
54 def okToSys(aResult, verbose=False):
55   """to get windows or linux result of script"""
56
57   def extendList(alist):
58     """utility extend list of lists of string results with ok or KO"""
59     # bad: list(itertools.chain.from_list(alist)) iterate on str
60     res = []
61     if type(alist) != list:
62       return [alist]
63     else:
64       for i in alist:
65         if type(i) == str:
66            res.append(i)
67         else:
68            res.extend(extendList(i))
69     return res
70
71   resList = extendList(aResult)
72   if resList == []:
73     if verbose: print("WARNING: result no clear: []")
74     return KOSYS
75
76   rr = OK
77   for ri in resList:
78     if ri[0:2] != OK:
79       if verbose: print(ri)
80       rr = KO
81
82   if verbose: print("INFO: result: %s" % rr)
83   if rr == OK:
84     return OKSYS
85   else:
86     return KOSYS
87
88 def getDirAndName(datafile):
89   path, namefile = os.path.split(os.path.realpath(datafile))
90   rootpath = os.getcwd()
91   return (path, rootpath, namefile)
92
93 def resumeList(aList):
94   if len(aList) == 0:
95     return []
96   if len(aList) < 3:
97     return aList
98   res = [aList[0], "...", aList[-1]]
99   return res
100
101 def resumeLines(aList, ilines):
102   if verbose: print("INFO: resumeLines", ilines)
103   if len(aList) == 0:
104     return []
105   if len(aList) < 3:
106     return aList
107   res = []
108   for i in ilines:
109     if i != None:  # if not existing tetrahedra for example
110       resi = [ii.strip("\n") for ii in aList[i:i + 4]]
111       resi.append("...")
112       res.append(resi)
113   return res
114
115
116 #########################################
117 class XXVert:
118   """Vertices, Nodes"""
119   def __init__(self, x, y, z, color=0, indexglobal=0):
120     self.x = x
121     self.y = y
122     self.z = z
123     self.color = color
124     self.indexglobal = indexglobal
125
126   def compare(self, vb, args, withAll=True):
127     if self.x != vb.x: return False
128     if self.y != vb.y: return False
129     if self.z != vb.z: return False
130     if withAll:
131       if args.withColor:
132         if self.color != vb.color: return False
133       if args.withIndex:
134         if self.indexglobal != vb.indexglobal: return False
135     return True
136
137   def __eq__(self, vb):
138     """equality test without color or indexglobal"""
139     # print "vertice equality"
140     if self.x != vb.x: return False
141     if self.y != vb.y: return False
142     if self.z != vb.z: return False
143     return True
144
145   def __ne__(self, vb):
146     """inequality test without color or indexglobal"""
147     # print "vertice inequality"
148     if self.x == vb.x and self.y == vb.y and self.z != vb.z:
149       return True
150     return False
151
152   def __repr__(self):
153     return "XXVert(%.4f %.4f %.4f (%i %i))" % \
154            (self.x, self.y, self.z, self.color, self.indexglobal)
155
156   def __str__(self):
157     return "(%s %s %s (%i %i))" % \
158            (self.x, self.y, self.z, self.color, self.indexglobal)
159
160   def dist(self, vb):
161     res = (self.x - vb.x) ** 2 + (self.y - vb.y) ** 2 + (self.z - vb.z) ** 2
162     return res ** .5
163
164
165 #########################################
166 class XXEdge:
167   """Edges, 2 Nodes"""
168   def __init__(self, a, b, color=0, indexglobal=0):
169     self.a = a
170     self.b = b
171     self.color = color
172     self.indexglobal = indexglobal
173
174   def compare(self, eb, args):
175     res = self.a.compare(eb.a, args) and \
176           self.b.compare(eb.b, args)
177     if res:
178       if args.withColor:
179         if self.color != eb.color: return False
180       if args.withIndex:
181         if self.indexglobal != eb.indexglobal: return False
182     return res
183
184   def __repr__(self):
185     return "XXEdge(%i %i (%i %i))" % \
186            (self.a, self.b, self.color, self.indexglobal)
187
188   def __str__(self):
189     return "(%i %i (%i %i))" % \
190            (self.a, self.b, self.color, self.indexglobal)
191
192   def inTria(self, tria, args):
193     t = [tria.a, tria.b, tria.c]
194     if not self.a in t: return False
195     if not self.b in t: return False
196     return True
197
198   def getVertices(self, mesh):
199     v1 = mesh.verts[self.a - 1]
200     v2 = mesh.verts[self.b - 1]
201     return [v1, v2]
202
203
204 #########################################
205 class XXTria:
206   """Triangles, Faces, 3 nodes"""
207   def __init__(self, a, b, c, color=0, indexglobal=0):
208     self.a = a
209     self.b = b
210     self.c = c
211     self.color = color
212     self.indexglobal = indexglobal
213
214   def compare(self, trb, args):
215     res = self.a.compare(trb.a, args) and \
216           self.b.compare(trb.b, args) and \
217           self.c.compare(trb.c, args)
218     if res:
219       if args.withColor:
220         if self.color != trb.color: return False
221       if args.withIndex:
222         if self.indexglobal != trb.indexglobal: return False
223     return res
224
225   def __repr__(self):
226     return "XXTria(%i %i %i (%i %i))" % \
227            (self.a, self.b, self.c, self.color, self.indexglobal)
228
229   def __str__(self):
230     return "(%i %i %i (%i %i))" % \
231            (self.a, self.b, self.c, self.color, self.indexglobal)
232
233   def inTetra(self, tetra, args):
234     t = [tetra.a, tetra.b, tetra.c, tetra.d]
235     if not self.a in t: return False
236     if not self.b in t: return False
237     if not self.c in t: return False
238     return True
239
240   def getVertices(self, mesh):
241     v1 = mesh.verts[self.a - 1]
242     v2 = mesh.verts[self.b - 1]
243     v3 = mesh.verts[self.c - 1]
244     return [v1, v2, v3]
245
246
247 #########################################
248 class XXTetra:
249   """Tetra, 4 nodes"""
250   def __init__(self, a, b, c, d, color=0, indexglobal=0):
251     self.a = a
252     self.b = b
253     self.c = c
254     self.d = d
255     self.color = color
256     self.indexglobal = indexglobal
257
258   def compare(self, teb, args):
259     res = self.a.compare(teb.a, args) and \
260           self.b.compare(teb.b, args) and \
261           self.c.compare(teb.c, args) and \
262           self.d.compare(teb.d, args)
263     if res:
264       if args.withColor:
265         if self.color != teb.color: return False
266       if args.withIndex:
267         if self.indexglobal != teb.indexglobal: return False
268     return res
269
270   def __repr__(self):
271     return "XXTetra(%i %i %i %i (%i %i))" % \
272            (self.a, self.b, self.c, self.d, self.color, self.indexglobal)
273
274   def __str__(self):
275     return "(%i %i %i %i (%i %i))" % \
276            (self.a, self.b, self.c, self.d, self.color, self.indexglobal)
277
278   def getVertices(self, mesh):
279     v1 = mesh.verts[self.a - 1]
280     v2 = mesh.verts[self.b - 1]
281     v3 = mesh.verts[self.c - 1]
282     v4 = mesh.verts[self.d - 1]
283     return [v1, v2, v3, v4]
284
285
286 #########################################
287 class XXMesh:
288   """Mesh: vertices, edges, triangles, tetrahedra"""
289   def __init__(self):
290     self.nameFile = ""
291     self.verts = []
292     self.edges = []
293     self.trias = []
294     self.tetras = []
295
296   def initFromFileMesh(self, fileName, args, withGlobal=True):
297     if not os.path.isfile(fileName):
298       raise Exception("ERROR: inexisting file '%s'" % fileName)
299     with open(fileName, "r") as f:
300       lines = f.readlines()
301     iverts, iedges, itrias, itetras = self.getIndexInMeshFile(lines)
302     self.verts = self.getMeshVerts(lines, iverts)
303     self.edges = self.getMeshEdges(lines, iedges)
304     self.trias = self.getMeshTrias(lines, itrias)
305     self.tetras = self.getMeshTetras(lines, itetras)
306     self.nameFile = fileName
307     if args.globalNumerotation == True and withGlobal == True:
308       self.initFromFileGlobal(fileName, args)
309     if verbose:
310       print("\nINFO: initFromFileMesh: read file: %s" % str(self))
311       print(self.strResume())
312       print(PP.pformat(resumeLines(lines, [iverts, iedges, itrias, itetras])))
313
314   def initFromFileGlobal(self, fileNameMeshOrGlobal, args):
315     shortname, extension = os.path.splitext(fileNameMeshOrGlobal)
316     if extension == ".mesh":
317       fileName = shortname + ".global"
318     elif extension == "global":
319       fileName = fileNameMeshOrGlobal
320     else:
321       raise Exception("ERROR: initFromFileGlobal: unexpected file '%s'" % fileName)
322     if not os.path.isfile(fileName):
323       raise Exception("ERROR: initFromFileGlobal: inexisting file '%s'" % fileName)
324
325     with open(fileName, "r") as f:
326       lines = f.readlines()
327     nbverts, nbedges, nbtrias, nbtetras = [int(i) for i in lines[0].split()]
328     if verbose:
329       print("\nINFO: initFromFileGlobal: read file: %s" % str(self))
330       print("  nbverts %i\n  nbedges %i\n  nbtrias %i\n  nbtetras %i" % (nbverts, nbedges, nbtrias, nbtetras))
331     if nbverts != len(self.verts):
332       raise Exception("ERROR: in file '%s' unexpected number of Vertices %i<>%i" % (fileName, nbverts, len(self.verts)))
333     if nbedges != len(self.edges):
334       raise Exception("ERROR: in file '%s' unexpected number of Edges %i<>%i" % (fileName, nbedges, len(self.edges)))
335     if nbtrias != len(self.trias):
336       raise Exception("ERROR: in file '%s' unexpected number of Triangles %i<>%i" % (fileName, nbtrias, len(self.trias)))
337     if nbtetras != len(self.tetras):
338       raise Exception("ERROR: in file '%s' unexpected number of Tetrahedra %i<>%i" % (fileName, nbtetras, len(self.tetras)))
339     i = 1  # begin index line 1
340     for ii in range(nbverts):
341       self.verts[ii].indexglobal = int(lines[i])
342       i += 1
343     for ii in range(nbedges):
344       self.edges[ii].indexglobal = int(lines[i])
345       i += 1
346     for ii in range(nbtrias):
347       self.trias[ii].indexglobal = int(lines[i])
348       i += 1
349     for ii in range(nbtetras):
350       self.tetras[ii].indexglobal = int(lines[i])
351       i += 1
352
353
354   def __repr__(self):
355     return "XXMesh(nameFile='%s', nbverts=%i, nbedges=%i, nbtrias=%i, nbtetras=%i)" % \
356            (self.nameFile, len(self.verts), len(self.edges), len(self.trias), len(self.tetras))
357
358   def strResume(self):
359     res = str(self)
360     contents = {
361       "Vertices": resumeList(self.verts),
362       "Edges": resumeList(self.edges),
363       "Triangles": resumeList(self.trias),
364       "Tetrahedra": resumeList(self.tetras),
365     }
366     res = res + "\n" + PP.pformat(contents)
367     return res
368
369   def getIndexInMeshFile(self, lines):
370     res = []
371     for s in ["Vertices", "Edges", "Triangles", "Tetrahedra"]:
372       try:
373         i = lines.index(s + "\n")
374       except:
375         i = None
376       res.append(i)
377     return res
378
379   def getMeshVerts(self, lines, i):
380     res = []
381     try:
382       idep = i + 2
383       ilen = int(lines[i + 1])
384       ifin = idep + ilen
385       for line in lines[idep:ifin]:
386         li = line.split(" ")
387         x, y, z, color = float(li[0]), float(li[1]), float(li[2]), int(li[3])
388         res.append(XXVert(x, y, z, color))
389       return res
390     except:
391       return res
392
393   def getMeshEdges(self, lines, i):
394     res = []
395     try:
396       idep = i + 2
397       ilen = int(lines[i + 1])
398       ifin = idep + ilen
399       for line in lines[idep:ifin]:
400         li = line.split(" ")
401         a, b, color = int(li[0]), int(li[1]), int(li[2])
402         res.append(XXEdge(a, b, color))
403       return res
404     except:
405       return res
406
407   def getMeshTrias(self, lines, i):
408     res = []
409     try:
410       idep = i + 2
411       ilen = int(lines[i + 1])
412       ifin = idep + ilen
413       for line in lines[idep:ifin]:
414         li = line.split(" ")
415         a, b, c, color = int(li[0]), int(li[1]), int(li[2]), int(li[3])
416         res.append(XXTria(a, b, c, color))
417       return res
418     except:
419       return res
420
421   def getMeshTetras(self, lines, i):
422     res = []
423     try:
424       idep = i + 2
425       ilen = int(lines[i + 1])
426       ifin = idep + ilen
427       for line in lines[idep:ifin]:
428         li = line.split(" ")
429         a, b, c, d, color = int(li[0]), int(li[1]), int(li[2]), int(li[3]), int(li[4])
430         res.append(XXTetra(a, b, c, d, color))
431       return res
432     except:
433       return res
434
435   def haveVertsDistinct(self, args):
436     """stop a first KO"""
437     i = 0
438     verts = self.verts
439     for v1 in verts[:-1]:
440       i += 1
441       j = i
442       for v2 in verts[i:]:
443         j += 1
444         if v1.compare(v2, args):
445           # printing indices 1 to n
446           print("ERROR: %s vert[%i] equal vert[%i]: v1=%s v2=%s" % (self.nameFile, i, j, v1, v2))
447           return KO + " ERROR: %s some equal vertices" % self.nameFile  # stop a first KO
448     return OK + " INFO: no equal vertices"
449
450   def getVertices(self, elem):
451     """functionnal raccourci to XXElem.getVertices(XXMesh)"""
452     return elem.getVertices(self)
453
454   def compareListOfVertices(self, v1s, v2s, ordered=False):
455     """not ordered for now"""
456     if ordered:
457       res = [i for i, j in zip(v1s, v2s) if i == j]
458       return len(res) == len(v1s)
459     else:
460       res = 0
461       for i in v1s:
462         for j in v2s:
463           if i == j:
464             res += 1
465             break
466       return res == len(v1s)
467
468
469   def getCommonVerts(self, mesh, args):
470     res = []
471     for v1 in self.verts:
472       for v2 in mesh.verts:
473         if v1.compare(v2, args, withAll=False):
474           res.append((v1, v2))
475     return res
476
477   def getCommonEdges(self, mesh, args):
478     res = []
479     for e1 in self.edges:
480       v1s = self.getVertices(e1)
481       for e2 in mesh.edges:
482         v2s = mesh.getVertices(e2)
483         if self.compareListOfVertices(v1s, v2s):
484           res.append((e1, e2))
485     return res
486
487   def getCommonTriangles(self, mesh, args):
488     res = []
489     for e1 in self.trias:
490       v1s = self.getVertices(e1)
491       for e2 in mesh.trias:
492         v2s = mesh.getVertices(e2)
493         if self.compareListOfVertices(v1s, v2s):
494           res.append((e1, e2))
495     return res
496
497   def getCommonTetras(self, mesh, args):
498     res = []
499     for e1 in self.tetras:
500       v1s = self.getVertices(e1)
501       for e2 in mesh.tetras:
502         v2s = mesh.getVertices(e2)
503         if self.compareListOfVertices(v1s, v2s):
504           res.append((e1, e2))
505     return res
506
507   def areEdgesInTrias(self, args):
508     """stop a first KO"""
509     done = False
510     i = 0
511     edges = self.edges
512     trias = self.trias
513     res = OK + " INFO: %s all edges in trias" % self.nameFile
514     for e in edges:
515       i += 1
516       j = 0
517       found = False
518       for t in trias:
519         j += 1
520         if e.inTria(t, args):
521           # if verbose: print("INFO: %s edges[%i] in trias[%i]: edge=%s tria=%s" % (self.nameFile, i, j, e, t))
522           found = True
523           break
524       if not found:
525         print("ERROR: %s edges[%i] not in trias: edge=%s" % (self.nameFile, i, e))
526         if verbose and not done:
527           print("Triangles:\n%s" % PP.pformat(self.trias))
528           done = True
529         res = KO + " ERROR: %s some edges not in trias" % (self.nameFile)
530     return res
531
532
533   def areTriasInTetras(self, args):
534     """no stop a first KO"""
535     done = False
536     i = 0
537     trias = self.trias
538     tetras = self.tetras
539     if tetras == []:  # supposed skin without tetrahedra
540       res = OK + " WARNING: %s no tetrahedra in mesh" % (self.nameFile)
541       return res
542     res = OK + " INFO: %s all trias in tetras" % self.nameFile
543     for t in trias:
544       i += 1
545       j = 0
546       found = False
547       for h in tetras:
548         j += 1
549         if t.inTetra(h, args):
550           # if verbose: print("INFO: %s trias[%i] in tetras[%i]: tria=%s tetra=%s" % (self.nameFile, i, j, t, h))
551           found = True
552           break
553       if not found:
554         if verbose: print("ERROR: %s trias[%i] not in tetras: tria=%s" % (self.nameFile, i, t))
555         if verbose and not done:
556           print("INFO: Tetrahedra:\n%s" % PP.pformat(self.tetras))
557           done = True
558         res = KO + " ERROR: %s some trias not in tetras" % (self.nameFile)
559     return res
560
561   def testIntersection(self, mesh, args):
562     """intersection coherency between self and mesh"""
563
564     def storeAndInfoIntersection():
565       """used as macro: avoid duplicate code"""
566       # store info in args to use later...
567       args.intersections[title + name] = commons
568       if commons == []:
569         res.append(OK + " INFO: no %s" % title + name)
570       else:
571         res.append(OK + " INFO: existing %s" % title + name)
572       return
573
574     res = []
575     name = "%s<->%s" % (self.nameFile, mesh.nameFile)
576
577     title = "Vertices intersection: "
578     commons = self.getCommonVerts(mesh, args)
579     storeAndInfoIntersection()
580
581     title = "Edges intersection: "
582     commons = self.getCommonEdges(mesh, args)
583     storeAndInfoIntersection()
584
585     title = "Triangles intersection: "
586     commons = self.getCommonTriangles(mesh, args)
587     storeAndInfoIntersection()
588
589     title = "Tetrahedra intersection: "
590     commons = self.getCommonTetras(mesh, args)
591     storeAndInfoIntersection()
592
593     return res
594
595   def testIndexGlobal(self, mesh, args):
596     """global index coherency between self and mesh"""
597
598     def storeAndInfoIndexGlobal():
599       """used as macro: avoid duplicate code"""
600       # store info in args to use later...
601       args.indexglobal[title + name] = problems
602       if verbose: print("\nINFO: %s\n%s" % (title + name, PP.pformat(problems)))
603       if problems == []:
604         res.append(OK + " INFO: coherent %s" % title + name)
605       else:
606         res.append(KO + " ERROR: some problems %s" % title + name)
607       return
608
609     def testIndexGlobal():
610       """used as macro: avoid duplicate code"""
611       nameElem = title.split(' ')[0]
612       # something like 'Vertices intersection: /tmp/GHS3DPRL_out.000002.mesh<->/tmp/GHS3DPRL_out.000003.mesh'
613       commonsTitle = nameElem + " intersection: " + name
614       # if verbose: print "testIndexGlobal",title,commonsTitle
615       try:
616         intersection = args.intersections[commonsTitle]
617       except:
618         intersection = []
619       problems = []
620       for ii, jj in intersection:
621         if ii.indexglobal != jj.indexglobal:
622           problems.append((ii, jj))
623       return problems
624
625     res = []
626     name = "%s<->%s" % (self.nameFile, mesh.nameFile)
627
628     title = "Vertices indexglobal: "
629     problems = testIndexGlobal()
630     storeAndInfoIndexGlobal()
631
632     title = "Edges indexglobal: "
633     problems = testIndexGlobal()
634     storeAndInfoIndexGlobal()
635
636     title = "Triangles indexglobal: "
637     problems = testIndexGlobal()
638     storeAndInfoIndexGlobal()
639
640     title = "Tetrahedra indexglobal: "
641     problems = testIndexGlobal()
642     storeAndInfoIndexGlobal()
643
644     return res
645
646
647 #########################################
648 # tests
649
650 def testAll(args):
651   """test all on meshes from tetra_hpc_mpi"""
652   res = []
653   if verbose: print("\n*****testAll*****\n")
654   args.skinMesh = None
655   if args.skinInputFile != None:
656     args.skinMesh = XXMesh()
657     # a priori no global numerotation file.global for input tetra_hpc_mpi mesh
658     args.skinMesh.initFromFileMesh(args.skinInputFile, args, withGlobal=False)
659     res.append(testStandaloneMesh(args.skinMesh, args))
660     print("\nINFO: testAll skin input file:\n%s" % (PP.pformat(args.skinMesh)))
661
662   meshes = []
663   for fileName in args.files:
664     xxmesh = XXMesh()
665     xxmesh.initFromFileMesh(fileName, args)
666     meshes.append(xxmesh)
667   print("\nINFO: testAll ouput files:\n%s\n" % (PP.pformat(meshes)))
668   # test coherence of one by one meshes
669   for mesh in meshes:
670     res.append(testStandaloneMesh(mesh, args))
671   # test coherence of intersections an global numerotation of tetra_hpc_mpi output meshes
672   res.append(testParallelMesh(meshes, args))
673   res.append(testParallelMeshAndSkin(meshes, args))
674   res.append(testParallelMeshAndSkinColor(meshes, args))
675   return res
676
677
678 def testStandaloneMesh(mesh, args):
679   """test coherence of one mesh alone"""
680   if verbose: print("\nINFO: testStandaloneMesh:\n%s" % PP.pformat(mesh))
681   res = []
682   res.append(mesh.haveVertsDistinct(args))
683   res.append(mesh.areEdgesInTrias(args))
684   res.append(mesh.areTriasInTetras(args))
685   return res
686
687
688 def testParallelMesh(meshes, args):
689   """test intersection and overriding in tetra_hpc_mpi outputs GHS3DPRL_out.00000?.mesh"""
690   i = 0
691   res = []
692   args.intersections = {}
693   args.indexglobal = {}
694   for m1 in meshes[:-1]:
695     i += 1
696     for m2 in meshes[i:]:
697       res.append(m1.testIntersection(m2, args))
698       res.append(m1.testIndexGlobal(m2, args))
699   if verbose:
700     print("\nINFO: intersections\n%s" % PP.pformat(args.intersections))
701     print("\nINFO: indexglobal\n%s" % PP.pformat(args.indexglobal))
702   return res
703
704 def testParallelMeshAndSkin(meshes, args):
705   """test coherency between input skin and tetra_hpc_mpi outputs GHS3DPRL_out.00000?.mesh"""
706   res = []
707   if args.skinMesh == None:
708     print("INFO: no skin Mesh for testing intersectionsSkin\n")
709     res = OK + "INFO: no skin Mesh for testing intersectionsSkin"
710     return res
711   nbtriasskin = len(args.skinMesh.trias)
712   for m1 in meshes:
713     res.append(args.skinMesh.testIntersection(m1, args))
714     res.append(args.skinMesh.testIndexGlobal(m1, args))
715
716   # test total Triangles in output parallel meshes vs input skin mesh
717   if True:
718     kk = {}
719     nbtriaspara = 0
720     for k in list(args.intersections.keys()):
721       if args.skinMesh.nameFile in k:
722         ll = len(args.intersections[k])
723         if "Triangles intersection" in k:
724           nbtriaspara += ll
725         kk[k] = len(args.intersections[k])
726     print("INFO: skin intersections\n%s\n" % PP.pformat(kk))
727     if nbtriaspara < nbtriasskin:
728       res.append(KO + " ERROR: problem all skin triangles not in parallel meshes: %i<->%i" % (nbtriasskin, nbtriaspara))
729   return res
730
731 def testParallelMeshAndSkinColor(meshes, args):
732   """test coherency between color input skin and tetra_hpc_mpi outputs GHS3DPRL_out.00000?.mesh"""
733   res = []
734   if args.color == True:
735     res.append(KO + " ERROR: test color TODO!!!")
736   else:
737     res.append(OK + " WARNING: test color not done")
738   return res
739
740 if __name__ == '__main__':
741   parser = AP.ArgumentParser(description='launch test(s) on tetra_hpc_mpi mesh(es)', argument_default=None)
742   parser.add_argument(
743     '-a', '--testAll',
744     help='test all on all meshes',
745     action='store_true',
746   )
747   parser.add_argument(
748     '-v', '--verbose',
749     help='set verbose, for deep debug',
750     action='store_true',
751   )
752   parser.add_argument(
753     '-g', '--globalNumerotation',
754     help='read and set files .global, if associated',
755     action='store_true',
756   )
757   parser.add_argument(
758     '-c', '--color',
759     help='read and test with color',
760     action='store_true',
761   )
762   parser.add_argument(
763     '-f', '--files',
764     help='launch test(s) on file(s)',
765     nargs='*',
766     metavar='.../file.mesh'
767   )
768   parser.add_argument(
769     '-s', '--skinInputFile',
770     help='launch test(s) on tetra_hpc_mpi input file',
771     nargs='?',
772     metavar='.../skinInputFile.mesh'
773   )
774   """
775   parser.add_argument(
776     '-x', '--xoneargument',
777     nargs='?',
778     metavar='0|1',
779     choices=['0', '1'],
780     help='one argument, for example',
781     default='0'
782   )
783   """
784
785
786   """
787   args is Namespace, use it as global to store
788   parameters, data, used arrays and results and other...
789   """
790   args = parser.parse_args()
791
792   verbose = args.verbose
793   if verbose: print("INFO: args:\n%s" % PP.pformat(args))
794
795   if len(sys.argv) == 1:  # no args as --help
796     parser.print_help()
797     sys.exit(KOSYS)
798
799   if args.files == None:
800     print("\nERROR: Nothing to do: no files\n%s" % PP.pformat(args))
801     parser.print_help()
802     sys.exit(KOSYS)
803
804   if args.testAll:
805     result = testAll(args)
806   else:
807     result = KO
808     print("\nERROR: Nothing to do:\n%s" % PP.pformat(args))
809   sys.exit(okToSys(result, verbose=True))
810