====== Commit 2007-11-19 ======
Ceci est un commit assez important - J'ai essayé de "vulgariser" ma description des modifs DB - ça devrait être compréhensible par un débutant - prenez donc le temps de lire le texte ci-dessous pour pouvoir modifier vos cas-tests sans mon aide.
===== Refonte du système Key/Lock - gestion des ddls =====
==== Pourquoi? ====
L'idée est d'étendre et de clarifier les choses dans la gestion des degrés de libertés. Le but premier est l'intégration des éléments XFEM 3D de Lara qui font "déborder" les Locks. Pour rappel, celles-ci sont codées sur 32 bits et sont composées de 3 parties:
{{ commit:2007:locks_desc.png |Ancien codage des Locks}}
Revenons au tout début: qu'est ce qu'une Key, qu'est ce qu'une Lock? Lisez la suite et regardez le beau schéma ci-dessus.
==== Ancien système (OE) ====
J'ai remarqué que presque personne ne comprennais l'ancien système de DB d'Oofelie. J'essaye ici de résumer la situation. Il n'est pas trop tard pour comprendre: la DB n'a pas encore disparu (ça viendra).
=== Keys ===
__Une Key__ est un moyen de coder le type d'une grandeur stockée dans la base de données (DB) d'Oofelie. Par exemple les composantes du déplacement, la température, des multiplicateurs de lagrange, etc). Ce codage est effectué en deux parties distinctes: une "Nature" et un "Set_Nature".
La partie "Set_Nature" est composée de 4 ensembles de flags. En choisissant un et un seul flag dans chacun de ces 4 ensembles, on va composer un "Set_Nature". La combinaison se fait par l'opérateur "pipe" (puisqu'il correspond en interne à un "bitwise or"). Par exemple: ''AB|RL|GV|I1'' désigne "la contribution 1 (''I1'') d'une vitesse (''GV'') d'une //valeur// absolue (''AB'') réelle (''RL'')". La partie "Nature" désigne le type de //valeur//. Donc si on ajoute ''TO'' à l'exemple précédent, on a "la contribution 1 (''I1'') de la dérivée (''GV'') d'une température absolue (''AB'') réelle (''RL'')" (ne cherchez pas à comprendre ce que ça veut dire vraiment - comme dirait Ludo, on ne fait pas de la science ici).
La partie "Nature" désigne donc de manière très abstraite, un type de champ.
Pourquoi ce codage en deux parties? simplement pour pouvoir obtenir plusieurs types de valeurs (Set_Nature) à partir d'une Nature. Par exemple, si on prend la Nature ''TO'' (le champ thermique), on peut facilement obtenir toutes les grandeurs thermiques en ajoutant un "Set_Nature" approprié:
* ''TO | AB|RL|GD|I1'' : la température "absolue" (la référence)
* ''TO | **RE**|RL|GD|I1'' : l'incrément de température
* ''TO | RE|RL|**GV**|I1'' : la dérivée temporelle de la température
* etc
Il est important à ce stade de savoir que, pour simplifier l'écriture, un malheureux système de remplissage des Keys incomplètes a été mis en place dans Oofelie. Ceci veut dire que si une clef est incomplète, elle sera automatiquement complétée par le système par la coûteuse fonction "''Key:cure''". Outre cette perte de temps passée le plus souvent à corriger des Keys qui sont complètes, ce mécanisme fait que:
* plus personne ne comprend le système (question: "dois-je mettre ''TX|GD'', ''TX|RL'' ou ''GD'' pour les déplacements?" - réponse: "n'importe: le système corrigera en ''TX|RE|RL|GD|I1'' car toutes ces Keys sont identiques!!")
* on confond la notion de "champ" ("Nature") avec sa valeur par défaut. Par exemple, ''TO'' c'est l'incrément de température => NON!
On voit déjà un premier ensemble de problèmes à ce système:
* le système possède un système de correction implicite très dangereux (pour le C++, l'implicite, c'est pas une bonne idée).
* le système se veut trop général => il est possible de créer des valeurs qui n'ont pas de sens physique (la partie imaginaire de l'incrément de température, etc).
* le système est figé à ces 4 ensembles de flags. Si on voulait ajouter des qualificatifs supplémentaires, il faut recompiler...
...et c'est bien là le problème: Nous avons ajouté depuis l'évolution de Metafor une série de choses dans ce codage (Par exemple, récemment, les degrés de libertés XFEM 2D) si bien qu'il ne reste plus de place pour stocker de nouveaux flags dans les 32 bits utilisés. Bien sûr, on pourrait se la jouer à la OE en disant: "le système est pourri mais on va arranger ça rapidement en utilisant un nouveau codage 64 bits."... Mais que fera-t-on quand les 64 bits seront remplis??
Pour comprendre que le système est pourri, il est utile de comprendre les autres concepts qui ont été introduits dans le système de Keys pour essayer très maladroitement de réutiliser ce qui existait déjà:
=== Degrés de liberté ===
__Les degrés de libertés__: dans Oofelie, un degré de liberté est obligatoirement associé à la base de données (limitation qu'on fera sauter plus tard).
Un degré de liberté = un numéro et la partie "Nature"+"Set_Nature" d'une ''Key'' (+ des flags).
Attention: la partie "Set_Nature" permet de désigner un ddl mais, par construction, des ddls qui diffèrent uniquement par le "Set_Nature" seront traités de manière identique!!
Au niveau du ddl, seule la "Nature" compte. C'est donc "un champ" dans son concept le plus vague. Par exemple "translation X" (rien n'indiquera dans l'algorithme s'il s'agit d'un ''X'' (''TX|AB''), d'un ''dX'' (''TX|RE'') ou même d'un ''dX/dt'' (''TX|GV'').
Conséquence, il est impossible d'avoir dans le même système d'équations des différentes grandeurs relatives à un même champs. Par exemple, il ne serait pas possible de définir les positions "remeshed" de l'ALE par un "Set_Nature" si on voulait faire de l'ALE couplé.
=== Flags ===
__Les flags__ : Un autre concept mélangé à tout ce qui précède est la partie bleue du schéma ci-dessus. Ce sont les flags des degrés de libertés. Cela répond par exemple à la question "le degré de liberté est-il fixé ou libre?... ou ... les deux??..."
... ceci nous amène au concept de Lock...
=== Locks ===
__Les Locks:__ initialement ce sont des "masques binaires" basés donc sur le même système de codage que les Keys. Ces Locks vont permettre de regrouper des types de grandeurs ensemble. Par exemple, si on crée une ''Lock'' qui contient ''FI|FR'', elle permettra de rassembler les degrés de libertés qu'ils soient libres ou fixés.
Idéalement les Locks ne devraient intervenir que dans une très petite partie du code.
* dans le partitionnement du système: chaque partition doit pouvoir regrouper certains types de ddls.
* dans des routines qui agissent sur plusieurs types de grandeurs à la fois. Par exemple, la définition d'une fixation ''TX|TY|TZ|RE|GD|RL|I1'' pour fixer les composantes x,y et z en une seule commande.
En pratique, ce n'est pas le cas. les locks apparaissent partout pour remplacer les coûteuses vérifications des Keys!! et, le comble:
* un degré de liberté contient une Lock!! et pas une Key (juste pour des raisons de perfs)
* les partitions sont créées avec des objets "UnionLock" puisqu'un simple masque binaire ne permet pas de dire par exemple je veux ''TX|RE'' et ''TO|AB'' dans cette partition (on risque d'avoir aussi ''TX|AB'' et ''TO|RE'') !!
En résumé, des Locks est utilisé partout où OE voulait utiliser initialement des Keys...
=== DBValue 1D et 3D ===
Un problème de cet ancien système que nous n'avons pas abordé est la gestion des types d'entrées dans la base de données. En effet: les grandeurs utilisant un ''TY'', ''TY'' ou ''TZ'' sont stockées en tant que vecteurs à 3 composantes (''Vect3''). Il a donc été mis en place un système de déduction de numéro de composante à partir d'une Key pour que, lorsqu'on donne ''TY'', le système sache qu'il s'agit de la deuxième composante d'un ''Vect3''.
Nous voulons également unifier ce système, le généraliser et pouvoir l'étendre à d'autres types (matrices, tenseurs, etc)
==== Nouveau système ====
Le nouveau système mis en place par ce commit à beaucoup d'avantages sur l'ancien même s'il n'est pas encore parfait:
Voici les idées principales:
* Redéfinition & Séparation de tous les concepts mélangés dans ''Key'', ''Lock'', etc.
* Possibilité d'extension en vue de supprimer la base de données monolitique actuelle (=> base de données diffuse)
* Typage fort de toutes les entités.
* Nombre illimité de "Nature", "Set_Nature" et "Flags" en vue de l'intégration de XFEM
* Suppression de toutes les conversions implicites.
=== NatureID/VariantID ===
Reprenons les choses depuis le début. Il faut d'abord pouvoir nommer une valeur de la base de données comme on le faisait avec la partie Nature/Set_Nature d'une Key.
Nous créons donc deux nouvelles classes: ''NatureID'' et ''VariantID''. Le suffixe ''ID'' fait référence au template des identifiacteurs dynamiques mis au point il y a quelques temps pour faire sauter toutes les enums d'Oofelie. Les mécaniqmes d'initialisation ont été testés dans le passé et permettent une initialisation fiable même à travers plusieurs DLLs.
== NatureID ==
Nous définissons donc 19 objets ''NatureID'' correspondants aux anciens 19 champs ou ddl/noeuds. c'est ici que Lara pourra ajouter ses nouveaux champs XFEM 3D..
Les objets ''NatureID'' comme ''TX'', ''TO'', ''TM'', ... se comportent exactement comme les anciennes Locks correspondantes à part que j'ai renforcé leur caratère "const".
{{ commit:2007:classnatureid_inherit_graph.jpg |}}
C'est ici qu'il faut étendre le système d'accès aux composantes des vecteurs 3D de type ''TX'', ''TY'', ''TZ''. Nous allons dériver ''NatureID'' en plusieurs types. Ces types se chargeront de l'accès aux données et gèreront en interne les composantes.
La ''NatureID'' ''TXTYTZ'' désigne une nature vectorielle et ''TX'', ''TY'', ''TZ'' deviennent des composantes scalaires de cette nature vectorielle.
== VariantID==
Pour ''VariantID'', on veut simuler le "Set_Nature". Pour faciliter les choses et éviter de jongler avec 4 ensembles de bits dont la plupart des combinaisons ne signifient rien, nous nous limiterons à un seul ensemble. Ceci n'est pas restrictif puisque nous disposons d'au maximum 2^64=18446744073709551616 ''VariantID'' au lieu des 2*2*4*3=48 anciens!
Les nouveaux ''VariantID'' seront donc:
* ''AB'', ''RE'', ''GV'', ''GA'': la même signification que leur ancienne valeur corrigée par le défaut.
* ''GF1'', ''GF2'', ''GF3'': sont des raccourcis pour les anciens codes de type ''GF|I1'' qu'on n'utilisait que pour les forces.
* ''RRE'', ''RGV'', ''RGA'': valeurs de la config "remaillée" pour l'ALE (ça me semble mieux que de les stocker dans la partie imaginaire des déplacements!).
* ''DX'': le delta de N-R. (doit être dans la DB à cause du thermomec full couplé (la résolution se fait en bloc alors que la mise à jour des inconnues se fait mecanique et thermique séparés).
=== Les nouvelles Keys = Field(NatureID, VariantID) ===
A partir de ces deux objets, nous définissons un nouvel objet qui va nous servir à qualifier les ensembles de la base de données: les ''Field''. ils sont obligatoirement composés d'une nature et d'une variante (plus de remplissage ou du ''Key::cure'' par défaut!). En interne, c'est juste 2 const pointeurs.
Chaque ensemble de la base de données possède donc son propre ''Field''. C'est donc aussi un ''Field'' qu'on passe à la routine ''findDBSet'' (ex ''get_properties()'')
{{ commit:2007:classfield_inherit_graph.jpg |}}
A partir de ces ''Field''s, on dérive des ''Field1D'' ou ''Field3D'' en fonction du type de ''NatureID'' (1D ou 3D)
Parmi ces ''Field''s seuls les ''Field1D'' peuvent être utilisés pour qualifier un degré de liberté!
=== Dof: Field1D / DofFlags ===
Nous arrivons aux degrés de libertés. Chacun de ceux-ci regroupe un ''Field1D'' (ancienne partie Nature/Set_Nature), un index dans la DB (nouvelle classe ''DBIndex'' qui remplace le ''int'') et une nouvelle classe nommée ''DofFlags'' qui contient actuellement l'attribut libre OU fixé ( OU, pas ET).
{{ commit:2007:classdof.png |}}
L'indexation des ddls dans le ''DofSet'' s'effectue toujours de la même manière mis à part le fait que le nombre de degrés de libertés maximum (''MAXNATURE'') aux noeuds est une variable lue à partir du singleton des ''NatureID''.
=== Partitions : les nouvelles Locks = DofTypeMask ===
Jusqu'à ici, nous avons remplacé le concept initial de ''Key'' par celui de ''Field'' et ''DofFlags''. Je dis initial car c'est bien le concept idéal initialement pensé par OE qui a été traduit! En pratique, nous avons remplacé beaucoup de Locks qui n'étaient là que pour des raisons de perfs afin d'éviter les ''Key::cure''.
Nous arrivons au concept de ''Lock'' (ou plutôt d' ''UnionLock'') qui se veut être un masque permettant de trier des grandeurs dans des ensembles distincts...
Nous avons codé un nouveau système basé sur la nouvelle classe ''DofTypeMask'' qui pourrait être rebaptisée simplement ''Mask''. Il s'agit d'un système générique qui va étendre les ''UnionLock'' à tout type de tests. L'idée est de créer une série de masques sous la forme d'une expression logique avec des classes dérivées de ''DofTypeMask''.
{{ commit:2007:classdoftypemask_inherit_graph.jpg |}}
Par exemple, le masque suivant sera utilisé pour regrouper les ddls non thermique et non fixés dans une partition:
new AndMask(new NotMask(new NatureMask(TO)), new FlagsMask(DofFlags(false))) )
Le système est très général et la syntaxe pourrait être réécrite en surdéfinissant les opérateurs logiques classiques (ça n'a pas encore été fait).
=== Typage fort - sécurité ===
Pour garantir un typage fort et virer tous ces "int" qui peuvent être pris les uns pour les autres, notamment dans les LOCELs, j'ai défini des classes encapsulant un ''size_t'' (index non signé 64 bits):
* ''DBIndex'' : index de la DB
* ''DofIndex'' : numero interne d'un ddl dans le ''DofSet''.
* ''PartIndex'' : numéro de partition
* ''PartDofIndex'' : numéro d'un ddl dans une partition
Ces classes suppriment tous les opérateurs classques sur les "''int''" (par exemple, on ne peut pas additionner 2 ''DofIndex''!) et surtout tous les casts implicites (leur constructeur est défini ''explict''). De plus tout est non signé, ce qui nous imunise définitivement contre les "put a minus sign"...
Il est donc impossible maintenant de prendre un numéro d'index de ddl et d'indexer la base de données sans passer par des casts explicites qui ne passent pas inaperçus.
==== Changements de syntaxe ====
__Attention:__ les nouveaux facs sont hautement incompatibles avec les anciens. La nouvelle version est incapable de charger des facs avec des anciennes Locks. La bonne nouvelle, c'est que j'ai décidé de sauvegarder les nouveaux codes au format "texte"; ce qui va améliorer la compatibilité du fac dans le futur. en particulier, si Lara ajoute ses degrés de libertés, le Fac ne sera pas perturbé!
=== Dans les cas-tests ===
* Toutes les Keys et Locks s'écrivent avec des Fields:
* ''TX|RE'' => ''Field1D(TX,RE)'' (ou ''Field(TX,RE)'' si la commande ne prend pas explicitement une valeur scalaire)
* ''TO'' => ''Field1D(TO,RE)''
* ''GF|I2'' => ''Field1D(TX,GF2)''
* ...
* ''defineRot'' prend un ''Field3D'' = ''Field3D(TXTYTZ,RE)'' et s'écrit dorénavant en une seule ligne
=== Dans le code ===
* Un beau paquet de ''int'' ont été mieux typés (soit ''size_t'', soit ''DBIndex'', soit ''DofIndex'', etc). Idéalement, je vois pas où Metafor devrait utiliser un seul ''int''! => Il y a encore du boulot!
* J'ai remplacé ''ALL'' par un pointeur NULL. En pratique, ce pointeur devrait être remplacé par AllMash() mais ça nécessite un bon gros powergrep supplémentaire (et peut être des problèmes de perfs). Bref, ce sera réglé plus tard. Autre conséquence, j'ai réécris des tests du type ''if(lock==ALL | lock=TXTYTZ)'' par ''if(lock || lock.getNature()==TXTYTZ)''. Vu que le compilateur est succeptible d'évaluer la deuxième expression avant la première, ça peut crasher, d'après la norme... mais au final, ça crashe pas...
* La Lock ''NOTHING'' a tout simplement disparu! Elle servait à retourner une Lock vide si une erreur se produisait (mais de toutes façons aucun appel ne faisait de tests en retour) => à remplacer par un système d'erreur par exceptions.
* Les ''DBSet'' ont été supprimés. Ca simplifie la gestion de la DB. Mais seront peut être réimplémentés pour une raison de sécurité (voir + bas)
* Les accès au valeurs de la DB s'écrivent:
pour un accès scalaire (via un ''Field1D''):
field1D.getValue(set.define(n));
pour un accès vectoriel:
field3D.getV3Value(set.define(n));
On voit ici qu'il y a un risque de demander par erreur un ''Vect3'' à un set scalaire. Avant, ce genre de risque existait aussi mais renvoyait un vecteur de 0 (philosophie OE face à une erreur: on ferme les yeux et on continue...). Maintenant, ça crashe à l'exécution (je préfère). L'idéal serait de réimplémenter ''DBSet3'' et d'effectuer un accès fortement typé du genre:
set3.getFilter().getV3Value(set3, n);
Sécurité maximale mais perfs moindres...
===== Divers =====
* les déplacements radiaux étaient bugués (ça marchait par hasard pour le seul test de la batterie).
===== A Faire =====
* restreindre l'utilisation du "define" de ''DBSet'' => suppression de la possiblité de laisser des "trous" dans la DB.
* Utilisation de masques pour le ''Element::generalForce'' et pour le ''loadingSet'' - éviter de passer des Fields inutiles dans le calcul des forces.
* Suppression des ''int'' restants.
* Utilisation de pointeurs dans la gestion des dofs (LOCELs, etc)
* Faire un meilleur Fac texte/XML une fois pour toute (histoire de pouvoir debuguer plus facilement)
* ...
===== Les trucs bizarres que j'ai rencontrés =====
* l'incrément ''dX'' est sauvé dans la DB et donc dans le Fac!
* la plupart des sets thermomec sont alloués quel que soit le schéma.
* Certains tests implicites-explicites rechargent une DB plus petite que l'actuelle => actuellement, les valeurs "en trop" sont conservées (j'imagine que c'est ce que Ludo veut).
* ...
===== Fichiers ajoutés/supprimés ======
Certains fichiers ne sont pas splittés. D'autres devront passer de Oofelie à Metafor.
mtFEMBase/DofFlags.cpp added
mtKernel/DBIndex.cpp added
mtKernel/DBPointer.cpp added
mtKernel/Field.cpp added
mtKernel/NatureID.cpp added
mtKernel/NatureIDList.cpp added
mtKernel/NatureIDs.cpp added
mtKernel/VariantID.cpp added
mtKernel/VariantIDList.cpp added
mtKernel/VariantIDs.cpp added
mtFEMBase/DofFlags.h added
mtFEMBase/DofIndex.h added
mtFEMBase/DofType.h added
mtFEMBase/DofTypeList.h added
mtFEMBase/PartIndex.h added
mtKernel/DBIndex.h added
mtKernel/DBPointer.h added
mtKernel/Field.h added
mtKernel/NatureID.h added
mtKernel/NatureIDList.h added
mtKernel/NatureIDs.h added
mtKernel/VariantID.h added
mtKernel/VariantIDList.h added
mtKernel/VariantIDs.h added
mtFEMBase/DofFlags.inl added
mtKernel/LockData.cpp deleted
mtKernel/LockEntry.cpp deleted
mtKernel/LockData.h deleted
mtKernel/LockEntry.h deleted
oeFEMBase/DofFlagCmd.cpp added (+)
oeFEMBase/DofFlagCmdSet.cpp added (+)
oeFEMBase/DofFlagCmd.h added (+)
oeFEMBase/DofFlagCmdSet.h added (+)
oeFEMBase/DofFlagCmdSet.inl added (+)
oeFEMBase/DofFlag.cpp deleted
oeFEMBase/DofFlagSet.cpp deleted
oeFEMBase/UnionLock.cpp deleted
oeKernel/DBLock.cpp deleted
oeKernel/DBSet3.cpp deleted
oeKernel/Field.cpp deleted
oeKernel/Key.cpp deleted
oeKernel/Lock.cpp deleted
oeKernel/Locks.cpp deleted
oeFEMBase/DofFlag.h deleted
oeFEMBase/DofFlagSet.h deleted
oeFEMBase/UnionLock.h deleted
oeKernel/DBLock.h deleted
oeKernel/DBSet3.h deleted
oeKernel/Field.h deleted
oeKernel/Key.h deleted
oeKernel/Lock.h deleted
oeKernel/Locks.h deleted
oeFEMBase/DofFlagSet.inl deleted
oeKernel/DBLock.inl deleted
oeKernel/Key.inl deleted
oeKernel/Lock.inl deleted
--- //[[r_boman@yahoo.fr|Romain BOMAN]] 2007/11/19 10:34//