Ce commit permet d'utiliser des objets géométriques complexes (Parasolid) pour définir des matrices de contact rigides.
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?
Pour ces raisons, j'ai “découpé” le travail en deux gros morceaux (deux ensembles de libs).
PSkin
. Ce répêrtoire est nommé mtParasolid
et est composé des sources de mtParasolid.dll
(classe C++ PSkin
), _mtParasolid.dll
(class python PSkin
), mtParasolidDrawables.dll
(classes C++ implémentant la visu vtk de PSkin), _mtParasolidDrawables.dll
(interface python de la visu). 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:
Skin
qui est en fait une PSkin
grâce au polymorphisme du C++.mtParasolid*.dll
, et ceci même après compilation.METAFOR_USE_PARASOLID
à OFF
lors du CMake.mtParasolid
dans leur jeu de données (gain mémoire).Ce module est indépendant de Metafor. Il consiste en
pkiw
(parasolid kernel interface wrapper);_pkiw
);pki.viewer
);fwk
) serait la base “open source” de tous les développements basés sur l'architecture C++/python telle qu'on l'utilise pour Metafor, gen4, geniso, waves, pfem… et parasolid. Bref, le dénominateur commun de tous les gens qui gravitent autour du labo et du choix de libs qu'on a fait.
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:
Pt
et Basis
bien pratiques pour initialiser des vecteurs et systèmes d'axes. J'ai codé des opérateurs de cast implicites pour les vecteurs et points Parasolid ⇔ Pt
;PSession
qui gère la session;print
pour tous ces objets et toutes les erreurs possibles.
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).
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.
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.
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.
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:
PSkin
.PSkin
.PSkin
en translation.On ne peut pas encore:
PSkin
(je me suis focalisé sur le contact uniquement).
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)
où 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:
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:
PSkin
peut être parallélisé immédiatement! - je n'ai pas testé, mais je n'ai pas vu de isthisstaticvalueused
dans Parasolid )
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. |
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 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 |
/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
).
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