Dans la version actuelle de Arcane (3.x), les connectivités des entités et des groupes d'entités sont gérés comme si tout était non-structuré même si le maillage est cartésien ou structuré. Notamment, on conserve toutes les informations de connectivités entre les entités ce qui consomme de la mémoire. Ce coût mémoire est difficilement réductible lorsque le maillage est vraiment non structuré, mais il pourrait l'être pour les maillages structurés et cartésiens. Particulièrement pour ces derniers cas, on a souvent beaucoup de mailles et peu de variables et proportionnellement ce cout mémoire de conservation des connectivités est important.
Il a donc été décidé de modifier la gestion interne à Arcane de ces informations de connectivité afin de réduire la consommation mémoire et de permettre des optimisations supplémentaires.
Ces optimisations doivent répondre aux contraintes suivantes :
Les optimisations envisagées partent du principe que le schéma des connectivités et des groupes est souvent le même pour un grand nombre d'entités. Les optimisations proposées se décomposent en deux groupes :
Actuellement, les connectivités sont gérées par la classe mesh::IncrementalItemConnectivity et il y a trois tableaux (de Int32) pour conserver la connectivité d'une entité vers une autre :
L'optimisation proposée part du principe que pour une entité donnée les localId()
des entités qui lui sont connectées sont souvent les mêmes relativement au localId()
de la première entité connectée. Au lieu de conserver toute la connectivité, on peut donc ne conserver que le schéma de la connectivité ainsi que le localId() de la première entité.
Pour cette optimisation, il faut donc :
L'opération (2) aura un cout négligeable en temps de calcul, car la valeur à ajouter sera conservée lors de l'itération de la même manière que le nombre d'entités connectées. Il reste donc pour (1) l'ajout d'un 'Int32' pour chaque entité, mais cela sera compensé par la réutilisation de la connectivité.
Par exemple, pour un maillage cartésien de 2 lignes et 4 colonnes, on a actuellement la numérotation suivante :
Si je prends la connectivité maille/nœuds, les trois tableaux contiennent les valeurs suivantes :
Si j'applique l'optimisation, j'ajoute le tableau suivant contenant le localId() de la première entité :
Je retranche de (1) la valeur associée de (4)
On voit donc que pour ce cas (idéal), le schéma est le même. On peut donc ne le conserver qu'une fois et on aura les valeurs suivantes pour la connectivité :
Si N
est le nombre de mailles, on passe donc de d'une consommation mémoire de (N*4 + N + N)
à (4 + N + N +N)
soit de 6*N
à 3*N
. Dans le cas 3D, on passe de (N*8 + N + N)
à (8 + N + N + N)
soit 10*N
à 3*N
.
Dans les maillages cartésiens, le schéma pour les mailles et les nœuds est indépendant du nombre de mailles et de noeuds. Par contre, pour les faces, il y a un schéma par ligne et un par colonne. Donc par exemple pour un maillage 100x30x20 il y a 32x20 schémas pour les faces soit 640 valeurs au lieu de 60000 sans l'optimisation.
Outre une réduction de la consommation mémoire cela permettra de mieux utiliser le cache.
Dans le pire des cas s'il n'y a pas de schéma récurrent, la connectivité consommera N
Int32 supplémentaires. A priori cela n'est le cas que pour les maillages composés de triangles (2D) ou tétraèdres (3D) quelconques ce qui n'est pas le cas des applications CEA et IFPEN.
Ces mécanismes peuvent aussi s'appliquer aux classes gérant spécifiquement le cartésien qui ont aussi des schémas d'accès similaires.
Afin de pouvoir procéder à ces optimisations de manière transparente il faut un itérateur sur les connectivités différent de l'itérateur sur les entités ce qui n'est pas le cas actuellement, car les deux utilisent ItemVectorView et ItemEnumerator comme conteneur et itérateur. Cela permet de coder comme suit :
Cela devra donc être interdit pour les connectivités. On pourra ajouter une macro spécifique pour énumérer sur les connectivités ou aussi remplacer par le for-loop
:
Le même principe que pour les connectivités peut être appliqué aux groupes. Actuellement, on conserve une liste d'indirection simple. Pour un groupe avec M éléments, il faut conserver M Int32.
Il serait possible de décomposer la liste des entités en blocs et conserver pour chaque bloc 3 valeurs correspondantes aux tableaux (2), (3) et (4) des connectivités. Éventuellement le nombre d'éléments dans chaque bloc peut aussi être mutualisé dans la liste d'indirection.
Avec par exemple une taille de bloc de 128, il faut conserver (3*M/128) valeurs pour les informations d'indirection. Mais dans le cas où les valeurs du tableau sont contigues, il faut juste conserver en plus 128 valeurs. La encore cela permet d'économiser de la mémoire et de mieux utiliser le cache. Ce mécanisme a aussi l'avantage d'être facilement utilisable sur accélérateur.
Cela nécessite cependant deux modifications dans Arcane:
localIds()
des groupesENUMERATE_
pour faire deux boucles : une boucle sur les blocs suivie d'une boucle pour chaque bloc. Cela nécessite donc de changer la classe ItemEnumerator pour gérer les blocs ou d'en faire une autre. Une possibilité est par exemple d'avoir deux nouvelles classes ItemBlockVectorView
et ItemBlockEnumerator
. Le cas actuel utilisant ItemVectorView et ItemEnumerator serait un cas spécifique de bloc dont le nombre de valeurs correspondrait au nombre d'éléments du vecteur et l'offset de localId()
serait zéro.Il doit être possible d'utiliser toujours une double boucle dans ENUMERATE_
quitte à ce que la deuxième boucle soit de taille fixée à la compilation à 1 dans le cas des ItemVectorView par exemple.
Les modifications pour changer ces connectivités commenceront dans la version 3.10 de Arcane (juin 2023).
La première optimisation envisagée concernerait les connectivités des entités. Dans ce but, les modifications suivantes sont effectuées :
localId()
des connectivités seront rendues obsolètes. Cela concerne les classes ItemEnumerator, ItemEnumeratorBase, ItemConnectedListView.En général les codes utilisateurs de Arcane sont peu impactés par le point (1) car les structures concernées sont plutôt internes à Arcane. Comme il est nécessaire de supprimer ces méthodes pour mettre en place connectivités compressées, il est prévu de supprimer définitivement ces méthodes en décembre 2023.
Pour le point (2) qui concerne potentiellement plus de parties de code, il est prévu de supprimer les méthodes concernées en juin 2024.
La deuxième phase d'optimisation concernant les entités des groupes interviendra ensuite.