Salome HOME
Documentation reorganization
[tools/medcoupling.git] / doc / tutorial / medcouplingloaderex2_fr.rst
diff --git a/doc/tutorial/medcouplingloaderex2_fr.rst b/doc/tutorial/medcouplingloaderex2_fr.rst
new file mode 100644 (file)
index 0000000..9c24d45
--- /dev/null
@@ -0,0 +1,253 @@
+
+MEDCoupling / MEDLoader - Exemple complet 2 - RJH
+-------------------------------------------------
+
+Ici nous partons de deux fichiers MED très librement inspirés du réacteur expérimental
+RJH (Réacteur Jules Horowitz).
+
+Le premier, :download:`Fixe.med <data/Fixe.med>`, représente la partie statique du réacteur
+sans dispositif expérimental.  
+
+.. image:: images/fixm.jpg
+       :scale: 70
+
+Le deuxième, :download:`Mobile.med <data/Mobile.med>`, représente la partie mobile.
+
+.. image:: images/mobm.jpg
+       :scale: 70
+
+
+Objectif
+~~~~~~~~
+
+Le but ici est d'utiliser MEDCoupling pour:
+
+* intersecter ces deux maillages,
+* y mettre un champ,
+* et ainsi localiser les zones de recouvrement
+
+
+Début de l'implémentation
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Pour commencer l'exercice importer tout le module python MEDLoader (qui inclus MEDCoupling). ::
+
+       import MEDLoader as ml
+
+Lire et réparer le maillage statique "Fixe.med"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Avec l'API avancée lire tout le fichier "Fixe.med" et appeler ``fixm``
+l'objet de type ``MEDCouplingUMesh`` représentant le maillage statique. ::
+
+       fixe = ml.MEDFileMesh.New("Fixe.med")
+       fixm = fixe.getMeshAtLevel(0)
+
+Pour ce qui suit il faut absolument que deux cellules se touchant partagent les mêmes edges. Pour ce faire, comme on est
+en connectivité nodale, il faut absolument que les noeuds soient les mêmes. Il s'avère que cela n'est pas le cas ici.
+Fusionner le noeuds distants de moins de 1e-10 et regarder l'impact sur le nombre de noeuds de ``fixm``. ::
+
+       print "Nb of nodes in the file : %i " % (fixm.getNumberOfNodes())
+       fixm.mergeNodes(1e-10)
+       print "Nb of non duplicated nodes : %i" % (fixm.getNumberOfNodes())
+
+Même traitement pour ``Mobile.med``, le lire avec l'API avancée de MEDLoader (appeler ``mobm`` l'instance du maillage) 
+et le réparer en supprimant les noeuds dupliqués. ::
+
+       mobile = ml.MEDFileMesh.New("Mobile.med")
+       mobm = mobile.getMeshAtLevel(0)
+       mobm.mergeNodes(1e-10)
+
+Le maillage du RJH étant plus général que des ``TRI6`` et des ``QUAD8``, on a besoin
+de stocker ces cellules avec un type géométrique à ``QPOLYG`` (Quadratic Polygon) qui représente un polygone *quadratique* 
+(le terme n'est pas très heureux, encore des raisons historiques, ...), c'est-à-dire un polygone avec un nombre arbitraire
+de côtés, et potentiellement des côtés en forme d'arcs de cercles plutôt que de segments de droites.
+Ce type géométrique ``NORM_QPOLYG`` est dans MEDCoupling/MEDLoader et aussi dans MED fichier.
+
+Nous voudrions visualiser ces deux maillages dans PARAVIS/ParaView, mais nous rencontrons ici deux soucis:
+
+* les polygones non-convexes sont, par défaut, mal représentés par VTK en mode *Surface*.
+  Il faut sélectionner l'option avancée "Triangulate" dans le panneau Display de PARAVIS/ParaView pour avoir un rendu correct.
+* les arcs de cercles ne sont pas correctement supportés par ParaView. Il faut les *tesséliser*, c'est-à-dire les transformer
+  en plusieurs petits segments de droite. La méthode ``MEDCouplingUMesh.tessellate2D()`` fait ce travail, mais modifie
+  le maillage. Nous faisons donc une copie préalable. Nous passons en paramètre la finesse de découpage (0.1 est suffisant 
+  -- angle en radian). Attention donc à ne pas modifer ni ``fixm`` ni ``mobm`` ! ::
+
+       fixm2 = fixm.deepCpy()        # tessellate2D() modifies the current mesh
+       fixm2.tessellate2D(0.1)
+       fixm2.writeVTK("fixm2.vtu")
+       mobm2 = mobm.deepCpy()
+       mobm2.tessellate2D(0.1)
+       mobm2.writeVTK("mobm2.vtu")
+
+Faire une petite méthode ``displayVTK()``, faisant le travail qui nous servira souvent après. ::
+
+       def displayVTK(m,fname):
+               tmp = m.deepCpy()
+               tmp.tessellate2D(0.1)
+               tmp.writeVTK(fname)
+               return
+
+Faire des réductions et des repérages de zones
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Le maillage ``mobm`` est en 6 parties distinctes (voir l'image au dessus). On ne veut récupérer que la première partie.
+Utiliser ``MEDCouplingUMesh.partitionBySpreadZone()`` pour partitionner en zones ``mobm`` et ne prendre que la première zone.
+Appeler cette nouvelle instance ``zone1Mobm`` et lui retirer tous les noeuds orphelins (``MEDCouplingUMesh.zipCoords()``) 
+Enfin l'afficher : ::
+
+       zonesInMobm = mobm.partitionBySpreadZone()
+       print "Nb of zones in mobm : %i" % (len(zonesInMobm))
+       zone1Mobm = mobm[zonesInMobm[0]]
+       zone1Mobm.zipCoords()
+       displayVTK(zone1Mobm, "zone1Mobm.vtu")
+
+.. image:: images/zone1Mobm.jpg
+       :scale: 70
+
+Nous allons désormais travailler autour de ``zone1Mobm``. Nous allons réduire la zone de travail de ``fixm`` autour de ``zone1Mobm``.
+Pour ce faire, réduire ``fixm`` en ne prenant que les cellules dans la boîte englobante 
+de ``zone1Mobm`` (``MEDCouplingUMesh.getBoundingBox()`` et ``MEDCouplingUMesh.getCellsInBoundingBox()``).
+Appeler ce nouvel objet ``partFixm``, lui retirer ses noeuds orphelins et l'afficher. ::
+
+       ids2 = fixm.getCellsInBoundingBox(zone1Mobm.getBoundingBox(),1e-10)
+       partFixm = fixm[ids2]
+       partFixm.zipCoords()
+       displayVTK(partFixm,"partFixm.vtu")
+
+.. image:: images/partFixmAndzone1Mobm.jpg
+
+Intersecter géométriquement deux maillages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+C'est le coeur de l'exercice. Nous allons intersecter géométriquement ``partFixm`` et ``zone1Mobm``. Cela revient à 
+partitionner à minima ``partFixm`` en cellules appartenant
+soit complètement à ``partFixm`` soit à ``partFixm`` et ``zone1Mobm``. Invoquer la méthode statique 
+``MEDCouplingUMesh.Intersect2DMeshes()``, avec ``partFixm`` et ``zone1Mobm`` et mettre une précision
+de 1e-10 (seuil de détection de fusion). Cette méthode retourne 3 paramètres (voir API dans la doc) que l'on appellera 
+ici ``partFixMob``, ``iPart`` et ``iMob`` dans cet ordre.
+
+Sur ``partFixMob`` merger les noeuds à 1e-10 près. ::
+
+       partFixMob, iPart, iMob = ml.MEDCouplingUMesh.Intersect2DMeshes(partFixm,zone1Mobm,1e-10)
+       partFixMob.mergeNodes(1e-10)
+
+Récupérer et afficher la partie de ``partFixm`` qui n'est pas dans ``zone1Mobm``. Appeler ce maillage ``partFixmWithoutZone1Mobm``. ::
+
+       ids3 = iMob.getIdsEqual(-1)
+       partFixmWithoutZone1Mobm = partFixMob[ids3]
+       displayVTK(partFixmWithoutZone1Mobm,"partFixmWithoutZone1Mobm.vtu")
+
+.. image:: images/partFixmWithoutZone1Mobm.jpg
+       :scale: 70
+
+Maintenant, on va vérifier la qualité du résultat retourné par ``MEDCouplingUMesh.Intersect2DMeshes()``. 
+Pour ce faire on va passer 3 tests:
+
+ * **Check #0** la somme des aires des cellules de ``partFixm`` et égale à celle de ``partFixMob``
+ * **Check #1** la somme des aires des cellules de ``zone1Mobm`` et égale à la somme des cells de ``partFixMob`` 
+   dont l'id dans ``iMob`` est different de -1
+ * **Check #2** pour chaque cellule de ``partFixm``, son aire est égale à la somme des aires des cellules de ``partFixMob``
+
+L'aire est une valeur algébrique. Donc attention cette verification ne peut se faire que si les cellules 
+sont toutes bien orientées ou à minima toutes orientées de la même manière.
+Pour ce faire, regardons les aires des 38 cellules de ``partFixm`` (nom de variable : ``areaPartFixm``). ::
+
+       areaPartFixm = partFixm.getMeasureField(ml.ON_CELLS).getArray()
+       print areaPartFixm.getValues()
+
+On voit que toutes les valeurs sont négatives. *Bilan*: ce fichier MED ne respecte pas la convention MED fichier !
+``partFixm`` étant mal orienté, et ``MEDCouplingUMesh.Intersect2DMeshes()`` conservant l'orientation, 
+``partFixMob`` est lui aussi mal orienté.
+Bref, on va faire les comparaisons sur des tableaux de valeurs absolues. Vérifier alors **Check #0**. ::
+
+       areaPartFixm = partFixm.getMeasureField(ml.ON_CELLS).getArray()
+       areaPartFixm.abs()
+       areaPartFixMob = partFixMob.getMeasureField(ml.ON_CELLS).getArray()
+       areaPartFixMob.abs()
+       val1=areaPartFixm.accumulate()[0]
+       val2=areaPartFixMob.accumulate()[0]
+       print "Check #0 %lf == %lf with precision 1e-8? %s" % (val1,val2,str(abs(val1-val2)<1e-8))
+
+On peut passer au **Check #1**. L'esprit est le même que le **Check #0**. ::
+
+       areaZone1Mobm = zone1Mobm.getMeasureField(ml.ON_CELLS).getArray()
+       areaZone1Mobm.abs()
+       val3 = areaZone1Mobm.accumulate()[0]
+       ids4 = iMob.getIdsNotEqual(-1)
+       areaPartFixMob2 = areaPartFixMob[ids4]
+       val4 = areaPartFixMob2.accumulate()[0]
+       print "Check #1 %lf == %lf with precision 1e-8 ? %s" % (val3,val4,str(abs(val3-val4)<1e-8))
+
+Puis le **Check #2**. ::
+
+       isCheck2OK = True
+       for icell in xrange(partFixm.getNumberOfCells()):
+           ids5 = iPart.getIdsEqual(icell)
+           areaOfCells = areaPartFixMob[ids5]
+           areaOfCells.abs()
+           if abs(areaOfCells.accumulate()[0] - areaPartFixm[icell]) > 1e-9:
+               isCheck2OK = False
+               pass
+           pass
+       print "Check #2? %s" % (str(isCheck2OK))
+
+Utiliser les informations de l'intersection pour en faire des champs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+OK pour ``partFixMob``. Nous souhaitons maintenant créer un champ représentant une fonction indicatrice de la zone 
+
+Maintenant créer un champ aux cellules sur ``partFixMob`` en mettant 0 sur la partie 
+exclusive ``partFixm`` et 1 sur la partie couverte. Nous créons donc un champ représentant une fonction indicatrice. 
+Le visualiser en utilisant un fichier VTK (ne pas oublier l'option *Triangulate* de ParaView). ::
+
+       f = ml.MEDCouplingFieldDouble(ml.ON_CELLS,ml.ONE_TIME)
+       m = partFixMob.deepCpy()
+       m.tessellate2D(0.1)
+       f.setMesh(m)
+       arr = ml.DataArrayDouble(partFixMob.getNumberOfCells(),1)
+       arr[iMob.getIdsEqual(-1)] = 0.
+       arr[iMob.getIdsNotEqual(-1)] = 1.
+       f.setArray(arr)
+       f.checkCoherency()
+       f.setName("Zone")
+       ml.MEDCouplingFieldDouble.WriteVTK("Zone.vtu",[f])
+
+.. image:: images/LocationEx2.jpg
+       :scale: 100
+
+Plus généralement prendre les zones 0, 1 et 5. Faire un champ aux cellules qui vaut 0 dans la zone exclusivement de ``fixm``,
+1 dans zone #0, 2 dans la zone #1 et finalement 3 dans la zone #5. ::
+
+       zonesMobm = ml.MEDCouplingUMesh.MergeUMeshesOnSameCoords([mobm[zonesInMobm[0]], mobm[zonesInMobm[1]], mobm[zonesInMobm[5]]])
+       zonesMobm.zipCoords()
+       partFixMob2,iPart2,iMob2 = ml.MEDCouplingUMesh.Intersect2DMeshes(partFixm,zonesMobm,1e-10)
+       partFixMob2.mergeNodes(1e-10)
+       f2 = ml.MEDCouplingFieldDouble(ml.ON_CELLS, ml.ONE_TIME)
+       m2 = partFixMob2.deepCpy()
+       m2.tessellate2D(0.1)
+       f2.setMesh(m2)
+       arr = ml.DataArrayDouble(partFixMob2.getNumberOfCells(),1)
+       arr[iMob2.getIdsEqual(-1)]=0.
+       st = 0
+       end = st + len(zonesInMobm[0])
+       arr[iMob2.getIdsInRange(st,end)] = 1.
+       st += len(zonesInMobm[0]) ; 
+       end = st + len(zonesInMobm[1])
+       arr[iMob2.getIdsInRange(st,end)] = 2.
+       st += len(zonesInMobm[1])
+       end = st + len(zonesInMobm[2])
+       arr[iMob2.getIdsInRange(st,end)] = 3.
+       f2.setArray(arr)
+       f2.checkCoherency()
+       f2.setName("Zone2")
+       ml.MEDCouplingFieldDouble.WriteVTK("Zone2.vtu",[f2])
+
+Ne pas oublier l'option *Triangulate* de ParaView dans le panneau Display pour bien voir les champs:
+
+.. image:: images/zonesMobm.jpg
+
+Solution
+~~~~~~~~
+
+:ref:`python_testmedcouplingloaderex2_solution`