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.
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:
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.
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).
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ératureTO | RE|RL|GV|I1
: la dérivée temporelle de la température
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:
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!!”)TO
c'est l'incrément de température ⇒ NON!On voit déjà un premier ensemble de problèmes à ce système:
…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à:
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é.
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…
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.
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:
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…
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)
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:
Key
, Lock
, etc.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.
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”.
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.
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).
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()
)
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é!
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).
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
.
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
.
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).
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 DBDofIndex
: numero interne d'un ddl dans le DofSet
.PartIndex
: numéro de partitionPartDofIndex
: 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.
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é!
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 ligneint
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!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… 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.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)
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…
DBSet
⇒ suppression de la possiblité de laisser des “trous” dans la DB.Element::generalForce
et pour le loadingSet
- éviter de passer des Fields inutiles dans le calcul des forces.int
restants.dX
est sauvé dans la DB et donc dans le Fac!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
— Romain BOMAN 2007/11/19 10:34