Table of Contents

Commit 2016-05-02

Ce commit permet d'utiliser des objets géométriques complexes (Parasolid) pour définir des matrices de contact rigides.

Contexte

Parasolid est le “noyau de modélisation géométrique” de Siemens qui est utilisé par exemple par Solid Edge, NX, etc. Pour ceux qui auraient entendu parler d'Open Cascade, c'est une lib similaire.

Parasolid est le leader du marché, sans conteste. La preuve: ce modeleur géométrique est utilisé également par les concurrents de Siemens! (Dassault p. expl. avec SolidWorks, Abaqus, etc). Parasolid est une lib commerciale dont nous disposons d'une licence académique suite aux accords récents entre le département A&M et Siemens (grâce au rachat de Samcef par Siemens). La licence académique nous permet d'utiliser Parasolid dans un contexte de recherche et enseignement uniquement.

Ajouter une lib supplémentaire au processus de compilation de Metafor est toujours un choix critique. Alors: pourquoi Parasolid?

Bref, tout semble indiquer que c'est un très bon choix. Et si, par malheur, nous n'avions plus accès à Parasolid dans le futur (si par exemple Siemens se faisait racheter par Google qui ne renouvellerait pas nos licences académiques), alors il restera la possibilité d'effectuer une traduction vers Open Cascade (oubliez la mauvaise expérience que vous avez eue avec Samcef Field - Open Cascade n'est pas Samcef Field!).

Concrètement, en passant rapidement les détails, l'interface que je viens de créer peut se résumer à un nouvel objet géométrique dans Metafor, nommé PSkin (pour “Parasolid Skin”). Ce nouvel objet prend en référence un objet Parasolid (un “body”) et va se charger de rediriger toutes les demandes géométriques de Metafor (principalement des projections dans le cas du contact) vers Parasolid et rendre le résultat aux routines de Metafor.

Puisque Parasolid n'est pas gratuit et n'est pas disponible partout, il faut impérativement pouvoir compiler Metafor sans cette interface Parasolid. De plus, j'aimerais pouvoir utiliser Parasolid dans d'autres contextes que Metafor (thèse de Kim dans waves, mailleur gen4, p expl.). Et pourquoi pas ne pas partager notre connaissance Parasolid avec d'autres personnes du département?

Dans la suite j'appelle “module”, un projet contenant plusieurs plusieurs libs qui a son propre dépôt SVN/git. Pour l'instant “oo_meta”, “oo_nda”, “mtStart” et “keygen” sont des modules.

Pour ces raisons, j'ai “découpé” le travail en deux gros morceaux (deux ensembles de libs).

Ce découpage peut paraître excessif, mais il est nécessaire si on veut pouvoir compiler avec ou sans parasolid, avec ou sans la visu et même avec ou sans Metafor!

Conséquences:

Dans la suite, je distingue Parasolid (la lib de Siemens) et parasolid (la couche C++/python que je viens de développer) par une majuscule ou minuscule du “p”.

Module "parasolid"

Ce module est indépendant de Metafor. Il consiste en

pkiw et _pkiw

Pour comprendre l'intérêt du nouveau module parasolid, par rapport à un appel direct des fonctions Parasolid dans Metafor, il faut savoir que Parasolid est écrit en C et possède une interface très riche (environ 1000 fonctions) mais volontairement très rudimentaire au niveau de la forme; ceci pour pouvoir être interfacé avec +/- n'importe quel type de code. Par exemple, la plupart des paramètres (options) des fonctions sont définies dans des structures C qui doivent être initialisées explicitement avant chaque appel. C'est le cas également des vecteurs, des points, des systèmes d'axes, etc. Définir un simple vecteur dans l'espace 3D nécessite dont 4 lignes de code (la définition de la variable et une ligne pour chaque composante). Effectuer une rotation dans l'espace 3D nécessite rapidement une page de code qui n'est qu'une succession d'initialisations (de vecteurs, de systèmes d'axes et de matrices de rotation). De plus rien n'est disponible pour imprimer simplement et clairement les structures à l'écran. La gestion des erreurs est également manuelle par défaut: il faut vérifier tous les codes de sortie de toutes les fonctions et gérer les potentielles erreurs. Enfin, beaucoup d'énums produisent des “nombres magiques” une fois imprimés à l'écran. La traduction de ces nombres en texte lisibles par un humain n'est pas incluse dans la lib.

Au niveau des “données” décrivant une géometrie, Parasolid utilise une représentation type B-REP améliorée stockée dans une sorte de base de données globale, accessible de n'importe où dans le code grâce aux fonctions de la lib, une fois que la “session” Parasolid a été démarrée correctement. La plupart des fonctions Parasolid créent et manipulent des objets géométriques et topologiques dans la mémoire de la session en cours. J'ai été tenté, au début, de créer une sorte d'arbre d'objets C++ bien typés qui seraient une image miroir du contenu de la session Parasolid. On pourrait ainsi utiliser le système de fonctions virtuelles pour appeler des fonctions de base sur des entités de haut niveau. On pourrait aussi parcourir l'arbre d'objets ainsi créé d'une entité à l'autre. J'ai vite compris que cette méthode n'aboutirait à rien; d'une part parce que la synchronisation de cet arbre et de la mémoire de Parasolid est un cauchemar et que d'autre part parce que ce n'est pas vraiment utile en pratique. J'ai donc gardé le principe d'hiérarchie d'objets (une “NURBS” est une “courbe” qui est une “entité géométrique”, qui est une “entité parasolid”) mais sans garder la l'arbre miroir (des pointeurs qui pointeraient par exemple de chaque courbe vers ses sommets, de chaque face vers sa surface et ses contours). Autrement dit, tous les types d'objets Parasolid se retrouvent dans une hiérarchie de classes du nouveau module. Par exemple PTopol représente une entité topologique, PBody représente un “body” (entité topologique de plus haut niveau) qui dérive de PTopol; mais il n'y a pas de structure d'objets en mémoire. Quand on veut manipuler un objet Parasolid, on en crée un objet de la couche C++/python à la volée et on l'utilise. Lorsque l'objet C++/python est détruit, il ne détruit pas son homologue Parasolid. On peut voir ces nouveaux objets comme des pointeurs vers la mémoire Parasolid et ils s'utilisent comme tels. On ne manipulera donc que très rarement des PBody *, puisque cet objet est déjà une sorte de pointeur. Et, bien sur, plusieurs objets peuvent référencer le même objet Parasolid.

En interne Parasolid désigne ses objets par des nombres entiers (appelés “tags”). Pour manipuler un objet à l'aide des nouvelles classes C++ du module “parasolid”, il suffit de connaitre son tag. Par exemple, si je veux manipuler le body dont le tag est 4, je peux écrire simplement (dans python p. expl.):

body = PBody(4)

l'objet body me permet alors d'appeler les fonctions interfacées. Par exemple:

body.scale(Pt(0,0,0), 10.)

qui effectue une mise à échelle du body #4 par rapport à l'origine. Il suffit d'avoir déjà vu la quantité de code correspondant à cette opération écrite avec les fonctions Parasolid pour comprendre l’intérêt du module “parasolid”. Notons qu'en utilisant les nouveaux objets, la gestion d'erreurs est transparente et propagée à l'aide d'exceptions (éventuellement jusqu'à python à travers le C++, merci SWIG!) . Par exemple, si le tag #4 ne correspond pas à un body, on recevra une erreur “propre” et explicite dans l'interpréteur python (et pas un truc du type “Erreur Parasolid 5921”).

La classe PBody permet aussi de créer des bodies basiques (bloc, cylindre, sphère, tore, rectangle et cone). Ce sera par exemple bien pratique pour créer rapidement des objets simples dont les dimensions et la position sont paramétrées dans des jeux de données Metafor.

En plus de ces classes, j'ai créé un classe PTessellator (et quelques classes annexes) qui permettent de mailler des surfaces pour la visu.

Enfin, la classe PSession permet de gérer la session Parasolid et par exemple charger des fichiers Parasolid (extensions .xmt_txt, .x_t pour les formats ASCII et .xmt_bin et .x_b pour les formats binaires). On peut également sauver le contenu de la mémoire si on a créé ou modifié des objets. Vous pouvez créer des fichiers Parasolid avec Solid Edge par exemple (je crois aussi avec FEMAP - je n'ai pas encore essayé - et peut-être bien Catia).

Si on résume: le module “parasolid” contient:

pki

C'est un module qui englobe pkiw, _pkiw et tous les utilitaires python bien pratiques (aide au chargement de fichiers) et l'interface graphique. Ce module n'est pas disponible lorsque parasolid est couplé avec Metafor… mais le but c'est qu'il le devienne bientôt (cela nécessite une refonte de la logique de compilation et d'utilisation de Metafor).

pki.viewer

Le module parasolid contient aussi une interface graphique bien pratique pour tester Parasolid. Pour la démarrer, il suffit d'executer sur parasolid/run.py (pour que ça marche, les binaires doivent être compilés dans parasolidB ou parasolid/build).

Ce script est bien plus qu'une interface graphique. L'aide de la commande run.py est obtenue avec l'option –help.

boman@garfield:~/dev/parasolid$ ./run.py --help
usage: run.py [-h] [-v] [--nogui] [-k K] [file [file ...]]

positional arguments:
  file        python/parasolid files

optional arguments:
  -h, --help  show this help message and exit
  -v, --verb  increase output verbosity
  --nogui     disable any graphical output
  -k K        nb of threads
boman@garfield:~/dev/parasolid$ 

Exemple 1: lance le script python “massprop” qui calcule la masse et la surface d'un corps 3D Parasolid. Le résultat est affiché dans l'interface graphique:

./run.py pki/tests/massprop.py

Exemple 2: lance le script python “clash” qui effectue des tests d'intersections entre objets. L'interface graphique n'est pas lancée grâce à l'option –nogui:

./run.py --nogui pki/tests/clash.py

Exemple 3: affiche un fichier contenant un “assembly” Parasolid (des corps instanciés et positionnés grâce à des matrices de transformation dans un assemblage) que j'ai généré avec Solid Edge:

./run.py pki/solidedge/gears.xmt_txt

L'interface est écrite en PyQt/VTK. C'est une QMainWindow avec des docks, des menus et une redirection de la sortie standard dans un widget. Un arbre permettant de voir la hiérarchie d'objets Parasolid en mémoire est en cours de développement. J'aimerais que ça devienne une sorte de bac à sable pour tester les fonctions les plus avancées de PyQt et VTK. Un des buts est d'améliorer l'interface de Metafor à l'aide de ces nouvelles connaissances.

pki/grabcad/vader_tie.xmt_txt

L'interface graphique tient actuellement dans un seul fichier parasolid/pki/viewer.py. J'ai mis des tas d'exemples de fichiers Parasolid dans les différents sous répertoires de parasolid/pki. C'est dans cette interface que j'ai pu tester un algorithme de projection avant de l'implémenter dans Metafor pour le contact.

Projection de points sur un tore

Batterie de tests ctest

En bonus, le module parasolid possède sa propre batterie de tests utilisant CTest. CTest est un programme de tests livré avec CMake (donc tout le monde l'a déjà sur son PC!). C'est une sorte de battery.py mais plus général. On peut donc vérifier que parasolid passe sa batterie de tests (tous les scripts de pki/tests), grâce à la commande (sous Linux):

ctest

on obtient le résultat suivant:

boman@garfield:~/dev/parasolidB$ ctest
Test project /home/boman/dev/GeonX/parasolidB
      Start  1: fwk/tests/timers.py
 1/14 Test  #1: fwk/tests/timers.py ..............   Passed    1.89 sec
      Start  2: pki/tests/projection.py
 2/14 Test  #2: pki/tests/projection.py ..........   Passed    0.48 sec
      Start  3: pki/tests/clash.py
 3/14 Test  #3: pki/tests/clash.py ...............   Passed    0.48 sec
      Start  4: pki/tests/gears.py
 4/14 Test  #4: pki/tests/gears.py ...............   Passed    0.53 sec
      Start  5: pki/tests/projection3.py
 5/14 Test  #5: pki/tests/projection3.py .........   Passed    0.53 sec
      Start  6: pki/tests/projection2.py
 6/14 Test  #6: pki/tests/projection2.py .........   Passed    0.67 sec
      Start  7: pki/tests/massprop.py
 7/14 Test  #7: pki/tests/massprop.py ............   Passed    0.48 sec
      Start  8: pki/tests/sandbox.py
 8/14 Test  #8: pki/tests/sandbox.py .............   Passed    0.98 sec
      Start  9: pki/tests/readall.py
 9/14 Test  #9: pki/tests/readall.py .............   Passed    1.76 sec
      Start 10: pki/tests/createblocks.py
10/14 Test #10: pki/tests/createblocks.py ........   Passed    0.50 sec
      Start 11: pki/tests/modelstructure.py
11/14 Test #11: pki/tests/modelstructure.py ......   Passed    0.51 sec
      Start 12: pki/tests/createparts.py
12/14 Test #12: pki/tests/createparts.py .........   Passed    0.48 sec
      Start 13: pki/tests/block.py
13/14 Test #13: pki/tests/block.py ...............   Passed    0.48 sec
      Start 14: pkread
14/14 Test #14: pkread ...........................   Passed    0.00 sec

100% tests passed, 0 tests failed out of 14

Total Test time (real) =   9.79 sec
boman@garfield:~/dev/parasolidB$ 

Autrement dit: tous les tests (il y en a 14 actuellement) sont passés sans générer d'exceptions ou d'erreurs. Sous Windows, on doit spécifier le type de build:

ctest -C Release

Inutile de dire qu'il faudra passer ces tests à chaque modification du module.

N'hésitez pas à lancer ces tests pour voir les possibilités de Parasolid. J'espère bien que je ne serai pas le seul développeur Parasolid de l'équipe.

Dossier "oo_meta/mtParasolid"

Le dossier mtParasolid de oo_meta fait le lien entre Metafor et le module précédent. Il définit une Skin particulière et son Drawable associé pour pouvoir la dessiner dans la fenêtre de visu. Actuellement, on peut:

On ne peut pas encore:

Définir une PSkin dans un jeu de données Metafor est très simple. Une fois qu'on a chargé ou créé un modèle Parasolid en mémoire, il suffit d'importer les modules:

from wrap.mtParasolid import PSkin
import wrap.mtParasolidDrawables

ensuite

pskin = PSkin(no, pbody)

no est un numéro, comme n'importe quelle entité Metafor en possède un, et pbody est un objet de type PBody du module parasolid décrit précédemment avec lequel on veut faire du contact.

Pour faire du contact, on définit une RdContactInteraction et on fait un setTool(pskin) tout simplement.

Pour translater la PSkin, il y a une astuce. En effet, l'objet Parasolid ne possède qu'une seule “configuration”, qui est donc, par nécessité, la configuration courante pour permettre les opérations de projection. J'ai donc contourné ce problème en associant un Point Metafor à la PSkin. Le point doit être stocké dans la base de données Metafor pour posséder plusieurs configurations. En cours de calcul, la PSkin observe le mouvement du point et se translate comme lui. Les rotations pourraient être traitées de la même manière avec 3 points.

Pratiquement, on définit un point (sa position initiale n'a aucune importance tant qu'on ne fait pas de rotations):

trackp = pointset.define(999, 0.0, 0.0, 0.0)

On crée la skin #1 avec le point en 3ieme argument:

pskin = PSkin(102, pbody, trackp)

On crée un chargement sur la skin (pas sur le point)

loadingset.define(skinset(102), Field1D(TZ,RE), 0.5, fct1)

On pourrait définir le point en interne à la PSkin mais je me suis dit que ce serait plus flexible de faire comme ça pour les rotations. On verra à l'usage…

Pour ceux que ça intéresse, le contact est géré à l'aide d'un nouvel opérateur de projection nommé sans surprise PSkinProjectionOperator. La méthode de projection est un peu différente de celle utilisée classiquement dans Metafor:

  1. On calcule la plus petite distance entre le point à projeter et le “body” Parasolid. Parasolid retourne la sous-entité sur laquelle le point le plus proche se situe.
  2. Si la sous-entité est une face: on calcule la normale à la face grâce à une évaluation de la surface sous-jacente.
  3. Si la sous-entité est une arête, on choisi arbitrairement la 1ere face adjacente et on fait la même chose. Autrement dit, on espère que la normale est continue à travers une arête.
  4. Si la sous-entité est un sommet, on applique aussi la technique précédente.

Question perfs, cette méthode est plus lourde que celle utilisée dans Metafor. Par exemple, sur un test d'écrasement d'un cube par un bloc Parasolid (cfr. cas-test batterie), je passe 2x plus de temps dans la détection du contact qu'avec un simple plan Metafor pour obtenir les mêmes résultats. Néanmoins:

Cas tests

J'ai ajouté des cas-tests basiques dans mtParasolid/tests:

cube simple contact d'un cube avec un plan Metafor (pour référence et jeu de données de base pour la suite)
cubeblock idem mais avec un bloc Parasolid au lieu du plan (les résultats sont identiques au test précédent).
cubecyl idem avec un cylindre paramétré créé dans le jeu de données
cubesphere idem avec une sphère Parasolid
tube test d'hydroformage similaire à apps.iso.tube où les 2 matrices de contact sont des objets Parasolid. Le moule est une conversion Solid Edge du vieux fichier STEP que j'avais créé à l'époque. L'outil de retenue est un cylindre créé directement dans le jeu de données. Les paramètres (en particulier l'épaisseur du tube) sont un petit peu plus réalistes que dans le test original.

Info sur compilation

Gestion des sources

Le module parasolid est géré par git et non par SVN (ce système est un peu plus souple que SVN mais un peu plus “geek” aussi). Vous aurez besoin d'installer git pour faire un checkout (on appelle ça un “clone” sous git - le “checkout” designant sous git un changement de branche).

Une fois ces programmes installé, vous pouvez faire un “git clone…” via le menu contextuel (clic droit): git clone

Git est plus compliqué à utiliser que SVN. Si vous voulez développer en utilisant git, il faudra lire un manuel. Si vous ne faites que suivre les verions, il suffit d'utiliser ce mini tableau de traduction:

svn status git status
svn co … git clone …
svn update git pull origin master

Compiler Metafor+parasolid

Si vous utilisez les libs de Luc, vous pouvez arrêter votre lecture ici. Téléchargez simplement les libs de Luc (/ftp/metafor/bin/VS2012_X64/LibsVS2012_2016-05-02.zip) et mettez-les à jour (python setup.py install + reboot du PC!) pour compiler Metafor.

Pour les autres:

Parasolid n'est pas disponible sur le GTAC de Siemens. L'iso fournie par Siemens est disponible sur le NAS. Vous pouvez soit tout installer grâce à l'installeur, soit copier manuellement le répertoire qui concerne votre OS.

Parasolid est installé sur blueberry, thorgal, spring et fabulous. Mettez à jour linuxbin (svn update ~/bin).

Une fois installé, reste alors à faire connaître Parasolid à CMake. Pour ce faire j'ai écrit un FindPARASOLID (dans parasolid/CMake).

A ce niveau, une remarque: sur mon PC, j'essaye d'utiliser de moins en moins les fichiers oo_meta/CMake/nom_machine.cmake. En effet, ces fichiers court-circuitent les recherches de CMake lors de la création des Makefiles et projets. C'est bien tant qu'on travaille sur un seul code (Metafor). Mais c'est moins bien quand on veut compiler des tas d'autres codes (waves, et tous mes petits programmes sur github): on doit alors copier/coller ces fichiers décrivant la config de chaque machine dans tous les codes sources. De plus en faisant ça CMake ne trouve toujours pas les libs installées pour la compilation d'autres lib qu'on voudrait compiler (j'ai eu le cas avec Trilinos).

La “bonne manière” de faire pour faire trouver des libs à CMake consiste à faire en sorte que le FIND_LIBRARY trouve les bibliothèques voulues automatiquement. Le plus simple est d'utiliser les variables d’environnement INCLUDE (recherche de .h), LIB (recherche de .lib) et PATH (recherche des .so). Bref, pour mouliner les CMakeLists.txt, je définis dans les variables d’environnement du système:

Exemple Linux:

INCLUDE=/opt/parasolid-28.1             # utile pour cmake
PATH=/opt/parasolid-28.1/shared_object  # utile pour cmake et runtime

Exemple Windows:

INCLUDE=c:\local\parasolid-28.1      :: utile pour le cmake uniquement
PATH=c:\local\parasolid-28.1\dll     :: utile pour le runtime (.dll) et .lib!
::LIB=c:\local\parasolid-28.1\dll    :: utile si .lib pas dans le PATH

Je compte étendre ça à toutes les libs sur mon PC et supprimer ainsi un bon nombre de mes *.cmake. Cette manière de faire est évidemment facultative (on peut toujours choisir de forcer la main à CMake).

Pour compiler Metafor:

svn co svn+ssh://XXXXX@clifton.ltas.ulg.ac.be/home/metafor/SVN/oo_meta/trunk
svn co svn+ssh://XXXXX@clifton.ltas.ulg.ac.be/home/metafor/SVN/oo_nda/trunk
svn co svn+ssh://XXXXX@clifton.ltas.ulg.ac.be/home/metafor/SVN/mtStart/trunk
git clone XXXXX@clifton.ltas.ulg.ac.be:/home/metafor/GIT/parasolid.git
mkdir oo_metaB
cd oo_metaB
cmake -C ../oo_meta/CMake/nom_machine.cmake ../oo_meta
make -j 12
./bin/Metafor

comp.py va être adapté (mettez à jour linuxbin par svn update ~/bin).

Compiler "parasolid" seul

Le module “parasolid” peut être compilé seul (sans Metafor) ou même en même temps que “Metafor+parasolid”. C'est actuellement le seul moyen d'avoir accès à l'interface graphique pki.viewer.

On a ainsi un parasolidB et un oo_metaB. Les bibliothèques communes sont actuellement compilées 2x à partir du même set de sources (p. expl. pkiw.dll se retrouve dans oo_metaB et parasolidB). C'est pas l'idéal mais c'est temporaire.

Sous Linux: (installez parasolid et configurez le PATH et INCLUDE)

git clone XXXXX@clifton.ltas.ulg.ac.be:/home/metafor/GIT/parasolid.git
mkdir parasolidB
cd parasolidB
cmake ../parasolid
make
ctest
cd ../parasolid
./run.py

Sous Windows: Regardez parasolid/devenv-vs2012.cmd. Adaptez une copie pour vous et commitez-la si elle diffère de la mienne. Si vous utilisez les libs de Luc:

mkdir parasolidB
cd parasolidB
cmake -G "Visual Studio 11 2012 Win64" ..\parasolid
cmake --build . --config Release
ctest -C Release

boman 2016/05/02 11:50