Cette question porte sur la meilleure stratégie à adopter pour mettre en œuvre la simulation suivante en C++.
J'essaie de faire une simulation dans le cadre d'un projet de recherche en physique, qui suit la dynamique d'une chaîne de nœuds dans l'espace. Chaque noeud contient une position ainsi que certains paramètres (courbure locale, vitesse, distance aux voisins etc ) qui évoluent tous dans le temps.
Chaque pas de temps peut être décomposé en quatre parties :
- Calculer les paramètres locaux. Les valeurs dépendent des voisins les plus proches dans la chaîne.
- Calculer les paramètres globaux.
- Évolution. La position de chaque nœud est légèrement déplacée, en fonction de paramètres globaux et locaux, et de champs de force aléatoires.
- Rembourrage. De nouveaux nœuds sont insérés si la distance entre deux nœuds consécutifs atteint une valeur critique.
(En outre, les nœuds peuvent être bloqués, ce qui les rend inactifs pour le reste de la simulation. Les paramètres locaux des nœuds inactifs ayant des voisins inactifs ne changent pas et ne nécessitent pas de calcul supplémentaire).
Chaque noeud contient ~ 60 octets, j'ai ~ 100 000 noeuds dans la chaîne, et je dois faire évoluer la chaîne d'environ ~ 1 000 000 pas de temps. J'aimerais cependant maximiser ces nombres, car cela augmenterait la précision de ma simulation, mais à condition que la simulation soit effectuée en un temps raisonnable (~heures). (~30 % des noeuds seront inactifs).
J'ai commencé à mettre en œuvre cette simulation sous la forme d'une liste doublement liée en C++. Cela semble naturel, car j'ai besoin d'insérer de nouveaux nœuds entre les nœuds existants, et parce que les paramètres locaux dépendent des voisins les plus proches. (J'ai ajouté un pointeur supplémentaire vers le prochain nœud actif, afin d'éviter tout calcul inutile lorsque je boucle sur l'ensemble de la chaîne).
Je ne suis pas un expert en matière de parallélisation (ou de codage d'ailleurs), mais j'ai joué avec OpenMP, et j'aime beaucoup la façon dont je peux accélérer des boucles d'opérations indépendantes avec deux lignes de code. Je ne sais pas comment faire en sorte que ma liste chaînée fasse des choses en parallèle, ni même si cela fonctionne ( ?). J'ai donc eu l'idée de travailler avec un vecteur stl. Au lieu d'avoir des pointeurs vers les voisins les plus proches, je pourrais stocker les indices des voisins et y accéder par une recherche standard. Je pourrais aussi trier le vecteur par la position de la chaîne (tous les xième pas de temps) pour obtenir une meilleure localité en mémoire. Cette approche permettrait de faire des boucles à la manière d'OpenMP.
Je suis un peu intimidé par l'idée, car je n'ai pas à m'occuper de la gestion de la mémoire. Et je suppose que l'implémentation du vecteur stl est bien meilleure que ma simple façon de gérer les nœuds de la liste avec les commandes 'new' et 'delete'. Je sais que j'aurais pu faire la même chose avec des listes stl, mais je n'aime pas la façon dont je dois accéder aux plus proches voisins avec des itérateurs.
Je vous demande donc, 1337 h4x0r et programmeurs compétents, quelle serait une meilleure conception pour ma simulation ? L'approche vectorielle esquissée ci-dessus est-elle une bonne idée ? Ou y a-t-il des astuces à jouer sur les listes chaînées pour les faire fonctionner avec OpenMP ? Ou dois-je envisager une approche totalement différente ?
La simulation sera exécutée sur un ordinateur doté de 8 cœurs et d'une mémoire vive de 48 Go, je suppose donc que je peux échanger beaucoup de mémoire contre de la vitesse.
Merci d'avance
Editer : J'ai besoin d'ajouter 1 à 2 % de nouveaux nœuds à chaque pas de temps, de sorte que leur stockage sous forme de vecteur sans indices des voisins les plus proches ne fonctionnera pas, à moins que je ne trie le vecteur à chaque pas de temps.