Développement d`un programme de simulation n corps

Transcription

Développement d`un programme de simulation n corps
Gymnase Auguste Piccard
Travail de maturité
Développement d'un programme de
simulation
Auteur :
Thibault
n
corps
Maître référent :
Wildi 3M8
28 octobre 2013
de
Schoulepnikoff
M. Laurent
Résumé
Les simulations n corps sont un outil parmi beaucoup d'autres pour étudier le
comportement de notre univers. Elles permettent de mieux comprendre certains
mécanismes comme la répartition de la matière dans l'univers, la formation des
galaxies, les collisions de galaxies, la création et l'évolution d'amas d'étoiles et
bien d'autres choses encore.
Les simulations que les astronomes font de nos jours sont d'un très grand
degré de complexité. On développe des modèles hydrodynamiques qui prennent
en considération les températures, les pressions, la composition des gaz. Ces modèles tiennent compte de la création et de la mort d'étoile, ainsi que de la matière
noire.Loin d'être de simples simulations gravitationnelles qui contiennent parfois plusieurs centaines de millions de corps, nécessitent de puissants moyens de
calcul.
Dans le cadre de ce travail, j'ai créé en langage C un programme de simulation
n corps an de pouvoir appliquer les rudiments des techniques de simulations
utilisées dans les milieux scientiques. Notamment le pas de temps dynamique,
technique qui améliore grandement les performances du programme.
Bien que le programme soit précis et ecace dans la simulation de systèmes
contenant un petit nombre de corps, il laisse à désirer dans des systèmes plus
complexes.
Il existe néanmoins bien des pistes d'amélioration, comme l'utilisation d'une
technique d'intégration plus précise, un pas de temps individuel pour chaque
corps, et des techniques de découpage de l'espace à des ns de simplication.
Table des matières
1 Introduction
3
2 Simulations
5
1.1
1.2
2.1
2.2
Présentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
n corps
Que sont les simulations n corps . . . . . . . . . . . . . . . . . .
Les simulations n corps aujourd'hui[16] . . . . . . . . . . . . . . .
3 Méthode de calcul
3.1
3.2
3.3
Méthode d'Euler[1][2] . . . .
3.1.1 Exemple . . . . . . . .
Étude du problème à n corps
Dénition de l'erreur . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Pourquoi le langage C ? . . . . . . . . . . .
Quelques notions . . . . . . . . . . . . . . .
4.2.1 Compilation . . . . . . . . . . . . . .
4.2.2 Programmation modulaire . . . . . .
4.2.3 Dénition et déclaration . . . . . . .
4.2.4 Fichier code source et chier header
4.2.5 Pointeurs . . . . . . . . . . . . . . .
4.2.6 Bibliothèque SDL . . . . . . . . . .
Structure du programme . . . . . . . . . . .
Fonctionnement basique du programme . .
Utilisation du programme . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Tests du programme . . . . . . . . . . . . . . . . . . . . .
5.1.1 Étude de l'erreur des simulations . . . . . . . . . .
5.1.2 Nombre de corps . . . . . . . . . . . . . . . . . . .
Simulation à pas de temps variable . . . . . . . . . . . . .
5.2.1 Nécessité d'un algorithme à pas de temps variable
5.2.2 Algorithme à pas de temps variable . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 Programmation
4.1
4.2
4.3
4.4
4.5
5 Résultats et analyse
5.1
5.2
1
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
5
5
8
8
9
11
13
15
15
16
16
17
17
18
18
19
19
21
21
24
24
24
31
33
33
34
Simulation n corps
5.3
5.4
Thibault Wildi - 3M8
5.2.3 Test du programme à pas de temps
Simulations de cas . . . . . . . . . . . . .
5.3.1 Figure de huit à 3 corps . . . . . .
5.3.2 Simulation d'amas . . . . . . . . .
Limitations du programme . . . . . . . . .
dynamique
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6 Conclusion
6.1
6.2
Commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Remerciements . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7 Annexe
7.1
7.2
Raccourcis clavier de l'interface graphique
Code source . . . . . . . . . . . . . . . . .
7.2.1 main.c . . . . . . . . . . . . . . . .
7.2.2 constants.h . . . . . . . . . . . . .
7.2.3 io_operations.h . . . . . . . . . . .
7.2.4 io_operations.c . . . . . . . . . . .
7.2.5 iterator.h . . . . . . . . . . . . . .
7.2.6 iterator.c . . . . . . . . . . . . . .
7.2.7 display2d.h . . . . . . . . . . . . .
7.2.8 display2d.c . . . . . . . . . . . . .
2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
34
37
37
39
40
42
42
42
46
46
46
46
48
50
52
55
56
58
60
Chapitre 1
Introduction
1.1 Présentation
Je me suis penché, dans ce travail de maturité, sur les lois qui gouvernent
la mécanique céleste, plus précisément sur l'une des méthodes utilisées actuellement pour mettre les diérentes théories astronomiques à l'épreuve : les simulations n corps. Ces simulations cherchent à reproduire l'évolution de l'univers
an de comprendre la formation des étoiles, des galaxies, des amas de galaxies.
Je me suis d'abord intéressé aux techniques actuelles de simulation n corps.
Quelles sont celles utilisées par les astronomes et de quels moyens disposentils ? Nous verrons que les techniques utilisées sont très complexes et tiennent
compte d'une multitude de facteurs dépassant de loin une simple simulation
gravitationnelle.
Aussi, quelles sont les techniques qui peuvent être utilisées dans la création
de mon programme de simulation n corps ? Nous verrons que, bien que souvent
très complexes, certains aspects des techniques modernes peuvent être utilisés
sans trop de peine.
Après cela, vient la question de l'ecacité d'un programme écrit dans le
cadre d'un travail de maturité. A quels résultats peut-on parvenir en utilisant
un ordinateur personnel, tant en matière de performance que de précision ? An
de répondre à cette question, nous testerons le programme. Nous verrons que
nous sommes malheureusement limités par certaines des méthodes utilisées, et
que pour les améliorer, il faudrait un investissement conséquent.
Nous nirons en exposant clairement les lacunes du programme et nous nous
demanderons quand et dans quelle mesure il peut être perfectionné.
1.2 Motivation
Les sciences dures et la physique en particulier ont très tôt retenu mon
attention. Très jeune, je me suis intéressé aux phénomènes qui m'entourent. Par
3
Simulation n corps
Thibault Wildi - 3M8
ailleurs, j'aime me lancer dans des projets qui présentent une certaine part de
dé.
Ce projet a été pour moi l'opportunité de fournir un travail pour lequel
la réponse ne gurait pas dans un cahier. Nous n'avions pas au départ d'idée
précise sur la quantité de travail à eectuer pour obtenir un résultat que nous
pourrions qualier de convenable. Mais cette inconnue, qui a parfois été, il est
vrai, à la source de moments diciles, a été un moteur dans d'autres cas. Et
lorsque l'on arrive à un résultat satisfaisant, la satisfaction justie amplement
le travail accompli.
4
Chapitre 2
Simulations n corps
2.1 Que sont les simulations n corps
Les simulations n corps sont des programmes informatiques où l'on simule
l'interaction d'un nombre n de corps astronomiques. C'est-à-dire de particules
ayant une certaine masse et pouvant représenter une poussière (au sens astronomique), une planète, une étoile ou une galaxie.
Elles nous permettent d'étudier la formation de l'univers, des galaxies, des
systèmes planétaire, ainsi que la répartition de la matière dans l'univers. Elles
permettent aussi de vérier les diérents modèles astronomiques en comparant
les résultats de la simulation aux observations.
2.2 Les simulations n corps aujourd'hui[16]
De nos jours, les simulations n corps existent principalement à trois échelles :
celle des systèmes planétaires, celle des amas d'étoiles, et celles des galaxies et
des amas de galaxies.
Les simulations n corps directes, c'est-à-dire où seules les forces gravitationnelles entrent en action, sont depuis longtemps dépassées. On travaille aujourd'hui sur des modèles tenant compte de l'hydrodynamique, c'est-à-dire des
phénomènes liés aux gaz. On simule la compression des gaz, leurs températures
ainsi que leur refroidissement par rayonnement, ce qui permet aux nuages de
gaz de s'eondrer sur eux-mêmes pour former des étoiles plus ou moins grosses
dont la durée de vie dépend de la masse. On tient aussi compte de l'explosion
des super-novas, ces très grosses étoiles qui, de par leur masse, se consument
très vite avant d'exploser en éjectant de la matière et en libérant de l'énergie.
Il y a donc un mécanisme d'implosion-explosion auto-régulé dans la formation
des étoiles.
Un autre facteur que l'on prend aussi en considération est la composition
dynamique des gaz et des étoiles. En eet, les réactions nucléaires au sein des
étoiles produisent de nouveaux éléments plus lourds, modiant ainsi les proprié5
Simulation n corps
Thibault Wildi - 3M8
2.1 Carte de densité d'une simulation n corps de la formation de
l'univers, n = 256 · 106 corps[17].
Figure
tés du gaz (notamment ses propriétés de refroidissement par rayonnement) et
des prochaines générations d'étoiles 1 .
Finalement, et peut-être le plus important, les modèles actuels tiennent
compte de la supposée existence de la matière noire. Matière interagissant uniquement par gravité et dont l'existence n'est suggérée que par des observations
indirectes.
Les chercheurs ont besoin pour leurs simulations d'une grande puissance de
calcul. Pour cela, ils disposent de "clusters" (littéralement "amas"). Ils sont
formé d'unités de calcul, dites c÷urs, regroupées par centaines ou milliers, et se
1. Ce phénomène peut s'observer sans problème par spectroscopie, méthode permettant
d'analyser la composition d'étoiles en fonction de la lumière émise.
6
Simulation n corps
Thibault Wildi - 3M8
répartissant les calculs.
La tailles de ces "clusters" peut varier grandement. L'EPFL, par exemple,
dispose de deux "clusters" à des ns de simulation n corps, l'un de 6'000 c÷urs
et l'autre 16'000 (mais présentant une architecture atypique). L'Observatoire de
Genève quant à lui dispose d'un "cluster" de 300 c÷urs.
Les simulations n corps n'utilisent que très rarement voire jamais la totalité
des c÷urs à la fois. Car en raison des algorithmes de répartition des tâches
entre les c÷urs, au-delà d'un certain nombre de c÷urs, le gain d'en ajouter de
nouveaux est presque nul. Cela vient du fait qu'une certaine puissance de calcul
est utilisée pour répartir et coordonner le travail entre les c÷urs, et aussi de ce
que certains c÷urs ont tendance à nir leurs tâches avant les autres.
De ce fait, une simulation type de l'ordre de n = 106 n'utilise que 16 ou
32 c÷urs. Des simulations comportant plus de corps peuvent aller jusqu'à 128,
voire 256 c÷urs. Ainsi, plusieurs simulations peuvent tourner en parallèle sur
un "cluster".
Pour ce qui est de la durée des simulations, elle peut varier de quelques
heures jusqu'à un extrême de six mois. On procède généralement à quelques
simulations d'essai avec une résolution passablement basse avant de lancer une
simulation plus longue ayant la résolution voulue.
Le travail des scientiques impliqués dans le domaine réside donc dans le
développement de modèles à la fois précis et économes en puissance de calcul.
Ils doivent aussi développer des algorithmes de calcul utilisant de la façon la
plus ecace possible les "clusters".
En ce qui concerne la maîtrise de l'erreur des simulations, celle-ci est extrêmement dicile dans les systèmes où des modèles complexes (hydrodynamique,
fusion nucléaire, etc.) entrent en jeux, car les diérents changements d'état de
l'énergie la rendent très dicile à tracer.
Néanmoins, on suit aussi l'évolution du moment cinétique, et celui-ci ne doit
varier au maximum que de quelques pour-cent sur la durée d'une simulation.
Étant donné la diculté de la chose, on m'a avoué que l'étude de l'erreur
dans les simulations n corps était quelque peu laissée de côté (ce qui, il faut le
dire, n'est pas une démarche très scientique).
7
Chapitre 3
Méthode de calcul
3.1 Méthode d'Euler[1][2]
La méthode d'Euler est une méthode de résolution par approximation des
équations diérentielles du premier ordre à partir d'une situation initiale.
{
ṙ(t) = f (t, r(t))
(3.1)
r(t0 ) = y0
où :
t est une variable
r(t) est une fonction de t
f (t, r(t)) est une fonction donnant la dérivée de r(t) au point (t; r(t))
t0 est un instant donné
y0 est la valeur connue de r(t) à l'instant donné t0
On dénit un intervalle ∆t qui sera l'écart entre chaque itération tel que
tn+1 = tn + ∆t
(3.2)
A partir de la condition initiale r(t0 ) = y0 , on cherche une estimation yn+1 de
r(tn+1 ) en montant le long de la tangente r(t) au point (tn , yn ) sur un intervalle
∆t (c.f. gure 3.1).
r(tn+1 ) ≈ yn+1 = yn + ∆tf (t, r(tn ))
(3.3)
On répète cette dernière étape en partant du point (tn+1 , yn+1 ) que l'on vient
de trouver, et ainsi de suite pour toutes les itérations suivantes. Les premiers
pas de la méthode d'Euler sont illustrés dans la gure 3.2.
On observe entre les points (tn+1 ; r(tn+1 )) et (tn+1 ; yn+1 ) un écart ∆y . Cet
écart est l'erreur produite par l'approximation dans l'équation (3.3). On remarque que plus le pas d'itération ∆t est petit, moins l'erreur ∆y est grande,
8
Simulation n corps
Figure
Thibault Wildi - 3M8
3.1 Une itération de la méthode d'Euler
car la sécante se rapproche de la tangente. Donc, plus on veut avoir une approximation précise à l'aide la méthode d'Euler, plus il faut prendre un pas
d'itération petit, au prix d'un nombre d'itérations plus important pour la même
portion de courbe.
3.1.1 Exemple
Prenons comme équation f˙ = 12 x et comme situation initiale, x0 = 1 et
f (x0 ) = 41 , ce qui nous donne l'équation suivante :
{
f˙ = 21 x
(3.4)
f (1) = 14
Bien sûr, il n'y aucun intérêt autre que celui de l'exemple à résoudre cette
équation à l'aide de la méthode d'Euler, car il est possible de la résoudre de
façon analytique. En eet, il est possible de trouver la primitive f de f˙(x) = 12 x
et ainsi de résoudre l'équation (3.4) :
{
∫
f (x) = 12 x dx = 14 x2 + c
(3.5)
f (1) = 14 ⇒ c = 0
f (x) =
9
1 2
x
4
(3.6)
Simulation n corps
Thibault Wildi - 3M8
3.2 Premières itérations de la méthode d'Euler sur une courbe du
type ax2 + b
Figure
Nous allons néanmoins résoudre cette équation à l'aide de la méthode d'Euler
an de pouvoir comparer nos résultats à la solution analytique de l'équation
(3.6).
Choisissons un intervalle ∆x = 0.5 en partant de notre valeur initiale x0 = 1,
ce qui nous donne :
x1 = x0 + ∆x = 1 + 0.5 = 1.5
(3.7)
Appliquons l'équation (3.3) :
1
1
f (x1 ) ≈ y1 = f (x0 ) + ∆xf˙(x0 ) = + 0.5 · = 0.5
(3.8)
4
2
Nous trouvons donc y1 = 0.5, alors que si nous cherchons f (x1 ) à l'aide de la
solution analytique (équation (3.6)), nous trouvons F (x1 ) = 0.5625. Nous avons
donc une erreur de 0.0625.
Continuons le processus pour quelques points encore, ce qui nous donne le
graphique proche de la gure 3.2. Relevons quelques points, ce qui nous donne
le tableau 3.1.
Nous remarquons que l'écart entre les points calculés à l'aide de la méthode
d'Euler et la courbe théorique, c'est-à-dire l'erreur (∆y dans le tableau) augmente au fur et à mesure des itérations. En eet, lorsque l'on utilise la méthode
10
Simulation n corps
Thibault Wildi - 3M8
xn
1
1.5
2
2.5
3
3.5
4
4.5
5
Table
yn
0.25
0.5
0.875
1.375
2
2.75
3.625
4.625
5.75
f (xn )
0.25
0.5625
1
1.5625
2.25
3.0625
4
5.0625
6.25
∆y
0
0.06
0.125
0.188
0.25
0.313
0.375
0.438
0.5
3.1 Méthode d'Euler pour l'équation f˙(x) = 21 x avec X0 = 1
d'Euler pour résoudre une équation diérentielle, l'erreur créée à la dernière itération s'ajoute à l'erreur de l'itération précédente. Suivant l'équation de départ,
cette erreur peut stagner voir régresser à certains moments. Mais, de manière
générale, l'erreur augmente au l des itérations.
3.2 Étude du problème à n corps
Les interactions entre les corps dans l'espace sont régies par la loi de la
gravitation universelle d'Isaac Newton, que l'on vectoriellement :
mi mj u⃗ij
F⃗ij = −G
(r⃗j − r⃗i )2
(3.9)
où :
F⃗ij est la force du corps i sur un corps j
G est la constante du gravité universelle qui vaut 6.67 · 10−11 [N m2 · kg −2 ]
u⃗ij est le vecteur unitaire allant du corps i vers le corps j
r⃗j
et
r⃗i la position respective des corps j et i
La présence du signe − devant G indique simplement que la force exercée
par le corps i sur le corps j va de j vers i et non pas le contraire.
Combinons l'équation (3.9) avec la deuxième loi du mouvement de Newton
et considérons la présence de n corps agissant sur le corps j :
{
m m u⃗
F⃗ij = −G (r⃗ij −jr⃗i )ij2
(3.10)
∑n
F⃗ij = mr⃗¨j
i=1;i̸=j
Nous obtenons :
mj r⃗¨j = −G
n
∑
i=1;i̸=j
11
mi mj u⃗ij
(r⃗j − r⃗i )2
(3.11)
Simulation n corps
Thibault Wildi - 3M8
r⃗¨j = −G
n
∑
i=1;i̸=j
mi u⃗ij
(r⃗j − r⃗i )2
(3.12)
En posant :
u⃗ij =
(r⃗j − r⃗i )
|r⃗j − r⃗i |
(3.13)
Nous arrivons à l'équation :
r⃗¨j = −G
n
∑
mi (r⃗j − r⃗i )
|r⃗j − r⃗i |3
(3.14)
i=1;i̸=j
En considérant que ⃗r¨, et donc ⃗r˙ et ⃗r, varie en fonction du temps et en instaurant une situation initiale pour chacun des corps, nous arrivons à l'équation
diérentielle suivante :

∑n
r⃗¨j (t) = −G i=1;i̸=j





r⃗1 (t0 ) = r⃗10




.


.

.
r⃗n (t0 ) = r⃗n0



˙

r⃗1 (t0 ) = v⃗10



...



˙
r⃗n (t0 ) = v⃗n0
mi (r⃗j (t)−r⃗i (t))
|r⃗j (t)−r⃗i (t)|3
(3.15)
Équation que nous allons résoudre à l'aide de la méthode d'Euler. Mais,
comme celle-ci ne nous permet de résoudre que les équations diérentielles du
premier ordre, nous allons devoir commencer par calculer les vitesses. L'équation
devient :

∑n
m (r⃗j (t)−r⃗i (t))
v⃗˙j (t) = −G i=1;i̸=j |ri⃗j (t)−

r⃗i (t)|3



v⃗j (t) = r⃗˙j (t)
(3.16)
...




j = 1, · · · , n
La formule entre chaque pas d'itération est alors :
{
∑n
m (r⃗j (t)−r⃗i (t))
v⃗j (tn+1 ) ≈ v⃗j (tn ) − ∆t · G i=1;i̸=j |ri⃗j (t)−
r⃗i (t)|3
r⃗j (tn+1 ) ≈ r⃗j (tn ) + ∆t · v⃗j (tn )
(3.17)
An d'obtenir une meilleure estimation des sécantes (c.f. gure 3.1), nous
pouvons faire la moyenne des vitesses en tn et tn+1 . Ainsi, l'écart ∆y est réduit
pour une meilleure précision :
12
Simulation n corps
{
Thibault Wildi - 3M8
r⃗j (tn+1 ) ≈ r⃗j (tn ) + ∆t ·
∑n
mi (r⃗j (t)−r⃗i (t))
i=1;i̸=j |r⃗j (t)−r⃗i (t)|3
v⃗j (tn+1 )−v⃗j (tn )
2
v⃗j (tn+1 ) ≈ v⃗j (tn ) − ∆t · G
(3.18)
Il est à noter que dans le cadre des simulations n corps, nous appellerons le
pas d'itération ∆t "pas de temps".
3.3 Dénition de l'erreur
Comme nous avons l'avons dit plus haut, la méthode d'Euler génère une
certaine erreur, et plus le pas de temps est petit plus l'erreur est réduite. Mais
plus on diminue le pas de temps, plus on augmente le temps de calcul pour une
simulation couvrant la même durée. Il faut donc trouver le meilleur compromis
entre nos exigences de précision et les capacités de calcul à disposition. Et pour
cela, nous avons besoin de pouvoir calculer l'erreur.
Nous en arrivons donc à la question suivante : comment dénir l'erreur dans
une simulation n corps ?
La réponse se trouve dans la quantité d'énergie contenue dans le système. En
eet, celle-ci, de par le principe de conservation de l'énergie, est théoriquement
constante. Mais la méthode d'Euler générant une certaine erreur, la quantité
d'énergie contenue dans le système va évoluer d'itération à itération. Nous pouvons donc comparer la quantité d'énergie calculée à un instant tn à la quantité
d'énergie contenue dans la situation initiale t0 , ce qui nous donnera une information sur l'erreur induite sur les positions calculées. Il faut en eet faire la
distinction entre l'erreur sur l'énergie totale et l'erreur sur les positions r⃗j . Bien
sûr, il se peut qu'une erreur allant dans un sens compense une erreur allant dans
l'autre, ce qui passerait inaperçu, mais nous n'allons pas tenir compte de ce cas
de gure, en gardant à l'esprit que l'erreur sur l'énergie totale ne donne qu'une
indication de l'erreur sur les positions r⃗j .
L'énergie dans notre système est contenue sous deux formes : l'énergie cinétique, que nous allons noter T , et l'énergie potentielle, que nous allons noter U ,
E étant l'énergie mécanique totale[5].
E =T +U
(3.19)
1
mv 2
2
(3.20)
mi mj
|⃗
ri − r⃗j |
(3.21)
Avec T et U :
T =
U = −G
Le zéro de l'énergie potentielle étant placé à l'inni.
13
Simulation n corps
Thibault Wildi - 3M8
En considérant n corps :
E=
n ∑
n
∑
mi mj
mj v − G
2
|⃗
r
i − r⃗j |
j=1 i>j
n
∑
1
j=1
2
(3.22)
Une autre façon de déterminer l'erreur générée par la méthode d'Euler dans
une simulation n corps consiste à l'étudier dans les cas où la solution analytique est connue, c'est-à-dire sur un problème à deux corps ou sur certains cas
particuliers de cas à trois corps.
Nous avons donc deux méthodes pour avoir une mesure de l'erreur d'une
simulation. La méthode consistant à mesurer l'énergie totale et observer sa variation, qui peut s'appliquer à toutes les simulations mais qui ne donne qu'une
indication de l'erreur sur les positions r⃗j . Et la méthode consistant à simuler
des cas dont la solution analytique est connue, qui nous donne une indication
exacte de l'erreur sur les positions r⃗j , mais qui ne s'applique qu'à certains cas
particuliers.
Les simulations n corps ne représentant un intérêt que pour résoudre des cas
dont la solution n'est pas connue, nous allons être obligé d'utiliser la méthode de
l'énergie totale. Nous allons néanmoins caractériser cette méthode en essayant
de trouver dans quelles conditions la méthode par mesure de l'énergie totale est
représentative ou non de l'erreur sur les position r⃗j .
Pour cela, nous allons comparer les deux méthodes de mesure de l'erreur sur
sur un cas dont la solution est connue en variant les paramètres de la simulation.
Nous allons examiner une situation qui nous est familière ; le cas de l'orbite
terrestre. Nous allons simuler la rotation de la Terre autour du soleil en variant
le pas de temps et en analysant l'erreur produite sur la période de révolution et
le rayon de l'orbite.
Nous étudierions aussi la façon donc varie l'erreur en fonction du temps et
quelles congurations de corps produisent le plus d'erreur lors de la simulation.
Nous aborderons aussi une méthode à pas de temps variable pour essayer de
réduire l'erreur lors de moments où celle-ci a tendance à augmenter.
14
Chapitre 4
Programmation
4.1 Pourquoi le langage C ?
Le langage C a été développé entre 1969 et 1973 par Dennis Ritchie au sein
des Laboratoires Bell. Il fut à la base conçu pour le développement du système
d'exploitation UNIX[8].
En eet, à l'époque, la grande majorité des systèmes d'exploitation étaient
écrits en langage assembleur, langage très proche et directement lié au langage
machine 1 . Le langage machine changeant entre chaque famille de processeurs,
le langage assembleur aussi. Il fallait donc réécrire un système d'opération pour
presque chaque ordinateur. C'est dans ce contexte qu'intervient le développement de UNIX, qui, à la base n'échappant pas à la règle, fut aussi écrit en
assembleur.
Certaines parties néanmoins furent écrites en langage B, un langage de haut
niveau 2 . Mais celui-ci ayant certaines lacunes, Dennis Ritchie fut amené à lui
apporter des modications. Ce langage deviendra le C. Le C possédant des
fonctionnalités d'un langage de haut niveau et des caractéristiques permettant
une gestion détaillée, la partie assembleur de UNIX fut en grande partie réécrite
en C.
Par la suite le langage continua d'évoluer et, en 1978, Brian Kernighan et
Dennis Ritchie publièrent la première édition du livre "The C Programming
Language", qui servit de norme[12]. Cette version du langage est appelée le
K&R C.
Puis, au fur et mesure de la popularité grandissante du langage, il fut développé de manière intensive et non cordonnée de façon à ce que chaque compilateur en supporte sa propre version[12]. C'est en 1989 qu'intervient la norme
développée par l'institut national américain de normalisation dite ANSI C ou
1. Le langage assembleur n'est en fait qu'une simple "traduction" du langage machine. Dans
la majorité des cas, chaque instruction correspond à une instruction du langage machine.
2. Tout est relatif bien sûr, le langage B, aujourd'hui obsolète, ainsi que le C sont considérés
comme des langages de relativement bas niveau.
15
Simulation n corps
Thibault Wildi - 3M8
C89, qui sera reprise par l'institut mondial de normalisation sous le nom de ISO
C[12].
Une nouvelle normalisation du langage sortira en 1999 sous le nom de C99
et la dernière version en date est le C11 datant de décembre 2011. C'est cette
dernière que j'ai utilisée pour mon programme.
Le C est toujours aujourd'hui l'un des langages de programmation les plus
répandus. Il a inspiré bien des langages comme JAVA, JavaScript, C++, C#,
PHP et bien d'autres[7].
L'histoire du C ci-dessus explique très bien les raisons pour lesquelles j'ai été
amener à rédiger mon programme en C. C'est un langage structuré et procédural 3 , mais possédant les outils pour gérer les ressources utilisées par la machine.
Ce qui, dans le cadre de notre programme, est particulièrement intéressant dans
l'optique d'optimisation des temps de calcul qui peuvent être relativement longs.
En utilisant le C, nous bénécions aussi de son énorme popularité dans la
mesure où une grande communauté s'est développée autour de lui. De ce fait,
il existe de nombreuses bibliothèques 4 dont nous pouvons proter ainsi qu'une
assistance certaine en cas de problèmes ou de questions.
4.2 Quelques notions
Nous allons voir quelques notions qui sont particulières au C et nécessaires
à la compréhension du programme écrit au cours de ce travail.
4.2.1 Compilation
En C, la génération d'un exécutable à partir du code se fait principalement
en deux étapes, la précompilation et la compilation, que l'on regroupe souvent
sous le nom de compilation[12].
Lors de la première étape, le préprocesseur parcourt le code et le prépare
à la compilation en procédant aux inclusions de chiers, aux remplacements
des constantes et des macros, et à la suppression des commentaires[12]. Le C
possède des commandes spéciques au préprocesseur, celles-ci se reconnaissent
au signe # qui les précède.
La deuxième étape consiste à la génération du code assembleur, de l'édition
de liens et de l'optimisation, an de générer un chier exécutable[6].
Toutes ces étapes sont eectuées par un programme appelé "compilateur".
Dans le cadre de ce projet, nous avons utiliser le compilateur C du "GNU
Compiler Collection", abrégé GCC, et qui est un logiciel libre[9].
3. Un langage procédural est un langage permettant de dénir des procédures (appelées
fonctions en C), c'est-à-dire des portions de code que l'on peut appeler à tout moment lors de
l'exécution du programme.
4. Une bibliothèque en programmation est en quelque sorte du code "pré-fabriqué" conçu
dans le but de ne pas avoir à réécrire pour chaque programme la totalité du code.
16
Simulation n corps
Thibault Wildi - 3M8
4.2.2 Programmation modulaire
Le C est un langage qui permet la programmation modulaire. C'est-à-dire
que l'on peut diviser le programme en plusieurs modules regroupant des groupes
de fonctions agissant dans un domaine semblable[10].
Cela a comme avantage d'avoir un programme structuré dont chaque partie
n'a accès qu'aux autres parties dont il a besoin, limitant ainsi grandement le
risque de comportements imprévus du programme.
En outre, lorsque l'on ne modie qu'une partie du programme, il n'est nécessaire de re-compiler que la partie qui a été modiée. Dans le cadre d'un
relativement petit programme comme le nôtre, la diérence est insigniante
mais sur de grands projets, elle est notable.
Finalement, cela permet aux parties du code qui sont d'ordre générique d'être
réutilisées dans d'autres programmes, en réutilisant les modules concernés. C'est
le principe des bibliothèques.
4.2.3 Dénition et déclaration
Il est important, pour comprendre la programmation modulaire en C, de
comprendre la diérence entre la dénition et la déclaration d'une variable ou
d'une fonction.
La dénition d'une variable ou d'une fonction est l'étape où un identiant
(le nom de la variable) et un espace mémoire sont alloués.
La déclaration est la moment où la variable ou la fonction est pour ainsi dire
"créée".
Dans le cas de variables normales, la dénition et la déclaration ont lieu en
même temps par la même instruction. Seules les variables dites extern sont
dénies à un autre emplacement que la déclaration. Le mot-clé extern signiant
simplement que la déclaration se trouve ailleurs[12].
La nuance est dicile à comprendre avec les variables, mais beaucoup plus
simple pour ce qui est des fonctions. En eet, la dénition d'une fonction est
simplement le nom de la fonction avec le type de retour et les types des paramètres. C'est ce que l'on appelle le prototype de la fonction[12]. C'est-à-dire
toutes les informations qu'il faut pour appeler la fonction. Ainsi, l'espace mémoire pour la fonction et ses paramètres est alloué. La déclaration quant à elle
contient le code contenu dans la fonction, ce que la fonction va exécuter. Bien
sûr, il faut que dénition et déclaration concordent, sinon il y aura erreur au
moment de la compilation.
Si un bout de code utilise une fonction ou une variable, il n'est nécessaire pour
lui que d'avoir accès à la dénition, c'est-à-dire à l'information lui permettant
d'accéder à la variable ou au code de la fonction, et non à la déclaration.
17
Simulation n corps
1
2
3
4
5
6
7
8
9
10
extern int
int
int
a;
add (
a,
prototype
int
int
int
int
return
a;
add (
{
a,
int
int
Thibault Wildi - 3M8
b) ;
b)
//
Definition
d ' une
variable
a
//
Definition
d ' une
fonction
add
//
Declaration
de
la
variable
//
Declaration
de
de
la
avec
son
a
fonction
add
c ;
c
= a + b;
c ;
}
Code 4.1 Exemple de dénition et de déclaration
4.2.4 Fichier code source et chier header
Comme nous l'avons vu plus haut, le C est un langage modulaire qui permet
de séparer le code en plusieurs modules. Il faut néanmoins que les diérents
modules qui en ont besoin puissent accéder les uns aux autres.
Pour cela, il existe deux types de chiers en C, les chiers *.c , dits chiers
sources, qui contiennent à proprement parler le code. Et les chiers *.h , dits
chiers headers (chiers d'en-tête), qui contiennent les dénitions nécessaires à
une utilisation du code par un autre module. Ainsi, chaque module consiste en
un chier source et un chier header qui permet l'accès à ses fonctions.
Ainsi, pour utiliser les fonctions d'un module depuis un autre, on mettra
dans ce dernier la commande pré-compilateur #include suivie du nom du header
entre guillemets, ce qui revient exactement à copier le code du header dans le
chier source.
4.2.5 Pointeurs
Le C fait ce que l'on pourrait appeler un usage abusif des pointeurs. Les
pointeurs sont un type de variables qui repèrent une autre variable[12]. C'està-dire qu'une variable de type pointeur contient l'adresse mémoire d'une autre
variable. Cela est utile, par exemple, pour le passage en paramètres de tableaux.
En eet, nous n'allons pas envoyer chaque élément du tableau à la fonction
appelée, mais le pointeur (l'adresse) du premier élément ; il est ensuite facile
d'accéder aux autres éléments sachant que les tableaux stockent leurs éléments
dans des cases mémoires consécutives.
Les pointeurs sont déclarés de la façon suivante : Le type de la variable
sur laquelle ils pointent, suivi d'un * , suivi du nom du pointeur. Pour accéder
à la variable pointée par le pointeur, on utilise le préxe * devant le nom du
pointeur[12]. Pour obtenir l'adresse d'une variable, on précède celle-ci d'un &.
La notion de pointeur étant relativement complexe et le but de ce travail
n'étant pas de faire un cours approfondi sur le C, je résumerai simplement la
chose en disant que l'on peut faire dans une certaine mesure abstraction des
pointeurs pour comprendre le code. Et que pointeur ou non, on fait en dénitif
18
Simulation n corps
int
int
1
a,b;
2
∗i ;
3
4 i = &a ;
5 ∗ i = 5;
Thibault Wildi - 3M8
//
variables
//
Pointeur
de
type
sur
un
int
int
//
Le
pointeur
i
//
La
variable
pointee
repere
maintenant
par
i
vaut
la
variable
maintenant
a
5
Code 4.2 Exemple d'utilisation de pointeurs
référence à la même variable.
4.2.6 Bibliothèque SDL
Comme nous l'avons relevé lors de notre présentation du C, l'un de ses
avantages est qu'il est très répandu et qu'il dispose d'une grande communauté de
programmeurs. De ce fait, il existe un grand nombre de bibliothèques payantes
ou gratuites pour une multitude d'usage.
Nous avons utilisé dans ce programme, an de créer une interface graphique,
la bibliothèque C SDL (Simple DirectMedia Layer). La SDL est une bibliothèque gratuite sous licence GNU LGPL[11] (licence libre). Elle permet de créer
des applications graphiques bidimensionnelles simples, ainsi que la gestion de
diérents évènements comme les actions clavier ou souris. Elle est relativement
simple à utiliser 5 et donc convient bien à ce travail dont le but n'est malgré
tout pas de créer une application graphique mais un programme de simulation
n corps.
La SDL ne permettant pas d'acher du texte de manière formatée, nous
avons aussi utilisé la bibliothèque SDL_ttf 2.0 ,bibliothèque satellite de la SDL
permettant d'acher du texte à partir d'un chier de police d'écriture.
4.3 Structure du programme
Voici les diérents modules du programme ainsi que les fonctions que contient
chacun d'entre eux. La description précise de chaque fonction ainsi que de tous
les paramètres de celles-ci se situent dans les cartouches de commentaires décrivant chaque fonction dans les chiers header des modules respectifs.
main.c
Ce module est le module principal par dénition Il ne contient que la
fonction main() et gère l'ensemble du programme. C'est aussi là que sont
déclarées et initialisées les variable globales.
int main(...)
Fonction lancée au début du programme, c'est elle qui gère
les diérentes étapes du programme en lançant par exemple les itérations et l'interface graphique à la n du programme.
5. Tout est question de point de vue bien sûr, le module relatif à la partie graphique du
programme représente quand même la majorité code.
19
Simulation n corps
Thibault Wildi - 3M8
constants.h
Ficher header rattaché à aucun chier source et contenant les différentes constantes utilisées par le programme, ainsi que que les dénitions
du type BODY et des variable globales.
io_operations.c Ce module contient les fonctions interagissant avec "l'extérieur" du programme, faisant des opérations d'entrée/sortie (Input/Output en anglais, abrégé IO).
BODY* IO_inti(void)
Fonction lisant le cher input.txt et initialisant
chacune des variables globales nécessaires aux calculs.
void IO_printBodyData_TXT(...) Fonction imprimant les paramètres
de la simulation de manière formatée au moment où elle est appelée dans un cher .txt (texte), imprimant par exemple le temps, la
position ou la vitesse de chacun des corps.
void IO_printBodyData_CONSOLE(...) Fonction identique à la précédente, à l'exception que celle-ci imprime les diérents paramètres
sur la console.
void IO_printBodyData_BIN(...) Fonction identique aux précédentes,
à l'exception que celle-ci imprime les diérents paramètres dans un
cher .bin (binaire).
iterator.c Module contenant la fonction d'itération.
void calculateNextStep(...) Fonction d'itération calculant chaque nouvelle étape à partir des paramètres existants.
Module contenant les fonctions relatives à l'interface graphique
créée pour l'achage à l'écran des résultats des simulations bidimensionnelles.
display2d.c
void display2D(...)
Fonction gérant l'interface graphique ainsi que les
évènements clavier.
void printDataOnScreen_Static(...) Fonction lisant le chier binaire
produit par la fonction void IO_printBodyData_BIN(...) an d'acher à l'écran la trajectoire statique des corps. Ne fonctionne que si
les données ont été imprimées suivant le schéma accepté par printDataOnScreen_Static(). Le schéma est déni à l'intérieur du code (c.f.
display2d.h).
void printDataOnScreen_Dynamic(...) Fonction identique à la précédente, sauf que celle-ci gère l'achage dynamique des corps.
void void printAxisOnScreen(...) Fonction achant les axes à l'écran.
Le programme une fois compilé a quand même besoin des chiers .dll (Dynamic Link Library, bibliothèque à lien dynamique en français) des bibliothèques
utilisées, ainsi que du chier de police d'écriture "consola.ttf" pour fonctionner.
Les bibliothèques utilisent des chiers .dll plutôt que d'inclure directement leur
code source à l'intérieur de l'exécutable. Cela principalement an de permettre
les mises à jour des bibliothèques sans devoir re-compiler le programme.
20
Simulation n corps
Thibault Wildi - 3M8
4.4 Fonctionnement basique du programme
Le programme procède de la façon suivante lors de son exécution :
1. Il lit le chier "Input.txt" situé dans le dossier Input et initialise les paramètres de la simulation à l'aide de la fonction IO_inti().
2. Il lance une boucle et appelle la fonction calculateNextStep() à chaque
itération avant d'imprimer les paramètres actuels de la simulation dans le
chier "Output.bin" situé dans le dossier Output à l'aide de la fonction
IO_printBodyData_BIN().
3. Une fois la simulation terminée, il imprime les spécications de la simulation dans le chier "Spec.txt" situé dans le dossier Output.
4. Ensuite, si c'est une simulation bidimensionnelle et que des points ont été
bel et bien été imprimés dans le chier "Output.bin", le programme lance
une interface graphique permettant de visualiser les résultats à l'aide de
la fonction display2D().
4.5 Utilisation du programme
Le programme nécessite donc, pour fonctionner, le chier "Input.txt" situé
dans le dossier Input. Nous allons maintenant nous pencher sur le format d'écriture des données dans ce cher "Input.txt".
BODY_NB
DIMENTIONS
G_CONST
RUN_TIME
DELTA_T
PRT_PRCT
USE_DYMC_DELTA_T
DYMC_DELTA_T_ACC
Nombre_de_corps
Nombre_de_dimensions
Constante_de_gravitation
Longueur_de_la_simulation
Pas_de_temps
Pourcentage_d'écriture
Pas_de_temps_variable
Précision_pas_de_temps_variable
C1_pos_x | C1_pos_y | C1_vit_y | C1_vit_y | C1_mass |
C2_pos_x | C2_pos_y | C2_vit_y | C2_vit_y | C2_mass |
C3_pos_x | C3_pos_y | C3_vit_y | C3_vit_y | C3_mass |
etc
Figure
4.1 Format d'entrée du chier "Input.txt"
Dans la gure 4.1, le texte en italique est à remplacer par des valeurs. Voici
les détails de chaque paramètre :
Le nombre de corps dans la simulation, permet au programme de savoir le nombre de lignes à lire plus bas dans la partie d'initialisation des paramètres des corps.
Nombre_de_corps
21
Simulation n corps
Thibault Wildi - 3M8
Nombre de dimensions. Le fonctionnement du programme n'est pas garanti pour des valeurs autres que 2 ou 3. Cette valeur
permet au programme de savoir le nombre de valeurs à lire dans la partie
d'initialisation des corps plus bas.
Nombre_de_dimensions
Constante de gravitation, généralement la
constante de gravitation universelle, soit 6.67384 · 10−11 . Peut aussi être
une valeur tout à fait arbitraire.
Constante_de_gravitation
Longueur_de_la_simulation
Longueur de la simulation en secondes [s].
Pas de temps utilisé pour la simulation en secondes [s]. Pas
de temps maximal dans le cas de simulations avec pas de temps variable.
Détermine avec la longueur de la simulation le nombre d'itérations.
Pas_de_temps
Pourcentage d'étapes dont les paramètres sont imprimés dans le chier "Output.bin". Par exemple, si le paramètre est à 1,
seule une étape est imprimée dans le chier pour cent calculées. Cela est
très utile dans le cas de grosses simulations où un nombre important de
points sont calculés an de ne pas générer un trop gros chier et de réduire
le temps d'exécution.
Pourcentage_d'écriture
Utiliser un pas de temps variable ou non ? Si oui,
la valeur vaut 1 ; si non, la valeur vaut 0.
Pas_de_temps_variable
Paramètre de précision en cas d'utilisation de pas de temps variable. Si on n'utilise pas de pas de temps
variable, cette valeur est ignorée. Nous parlerons plus tard de la signication de cette valeur et des algorithmes de simulation utilisant un pas de
temps variable.
Précision_pas_de_temps_variable
et C1_pos_y Coordonnées initiales du premier corps en mètres
[m]. En cas de simulation à trois dimensions, on ajoutera une troisième coordonnée C1_pos_z. Il ne faut pas oublier la barre verticale de séparation
entre chaque entrée ainsi qu'en n de ligne.
C1_pos_x
et C1_vit_y Vitesse initiale sur chaque axe du premier corps en
mètres par seconde [m/s]. En cas de simulation à trois dimensions, on
ajoutera la cordonnée z.
C1_vit_x
C1_mass
Masse du premier corps en kilogrammes [kg].
...
Cordonnée du deuxième corps et ainsi de suite. Même format à
chaque ligne, chacune représentant un corps.
C2_pos_x
Les paramètres Constante_de_gravitation, Longueur_de_la_simulation,
Pas_de_temps, Pourcentage_d'écriture, Précision_pas_de_temps_variable et
tous les paramètres individuels des corps acceptent la notation scientique. Le
format est le suivant : NBe ± PUISSANCE. La constante de gravitation universelle s'écrit par exemple 6.67384e − 11.
Attention, les nombres sont notés selon le format anglo-saxon ; les décimales
sont séparées par un point et non par une virgule.
22
Simulation n corps
Thibault Wildi - 3M8
Le programme ne vérie pas le format avant de lire les données. De fait,
une erreur de formatage dans le chier "Input.txt" donnera lieu à une erreur à
l'exécution du programme.
Il sut de lancer la simulation qui démarre à l'exécution du programme et qui
peut durer de moins d'une seconde à plusieurs minutes voire plusieurs heures,
suivant les paramètres de départ.
A la n du programme, celui-ci aura produit dans le dossier Output, un chier
"Output.bin" contenant les coordonnées des corps à intervalles réguliers pendant
la simulation (intervalle déni par Pourcentage_d'écriture ). Ainsi qu'un chier
"Spec.txt", contenant les coordonnées des corps au départ et à la n de la simulation, et les paramètres de la simulation.
Ensuite, si un chier "Output.bin" est produit et si la simulation est bidimensionnelle, le programme ouvre une fenêtre permettant de visualiser le résultat
de la simulation.
23
Chapitre 5
Résultats et analyse
5.1 Tests du programme
Nous allons maintenant faire passer une série de tests au programme que nous
avons conçu an de pouvoir optimiser notre utilisation et mieux interpréter le
résultat de nos simulations.
Pour cela, nous allons nous pencher sur la relation entre les paramètres
de départ d'une simulation, comme le pas de temps, le nombre de corps, leurs
positions et vitesses initiales, et le résultat de cette simulation en termes d'erreur
et de temps de calcul notamment.
5.1.1 Étude de l'erreur des simulations
Comme nous l'avons dit dans la partie théorique, nous disposons de deux
manières de mesurer l'erreur de notre simulation. La première reposant sur
le principe de conservation de l'énergie, consistant à calculer l'énergie totale
du système, censée rester constante au l du temps, et à quantier l'erreur
accumulée par la simulation à un instant t en comparant l'énergie totale du
système à cet instant t avec l'énergie dans la situation initiale de la simulation.
Cette méthode fonctionne pour tous les cas, mais ne donne qu'une indication
de l'erreur sur la position des corps r⃗j .
La seconde méthode est de simuler des cas dont nous connaissons la solution, car ils peuvent être résolus de façon analytique, et de mesurer directement
l'erreur sur les positions r⃗j .
La deuxième méthode étant limitée aux cas connus, nous allons être obligé
d'utiliser la première. Néanmoins, an de pouvoir vérier la abilité de nos simulations, nous allons tenter de dénir dans quelle mesure et à quelles conditions
l'erreur sur l'énergie totale est représentative de l'erreur sur les positions r⃗j .
Pour cela, nous allons lancer des simulations dans lesquelles la solution nous est
connue an de pouvoir comparer l'erreur sur l'énergie et l'erreur sur les positions
r⃗j .
24
Simulation n corps
Figure
Thibault Wildi - 3M8
5.1 Simulation du cas soleil-Terre - Résultats
Nous allons aussi proter des tests visant à étudier l'erreur pour observer le
comportement du temps de calcul. Ce qui sera intéressant pour pouvoir prévoir
le temps de calcul dans des simulations plus complexes où il devient important.
Cas du système soleil-Terre
Comme nous l'avons dit dans la partie théorique, nous allons simuler un cas
dont la solution nous est connue, celui de la Terre autour du soleil.
En lançant le programme avec une série de diérents pas de temps sur une
durée d'une année, nous obtenons le tableau de la gure 5.1 et le graphique de
la gure 5.2.
Comme nous pouvions nous y attendre, le temps de calcul est assez exactement inversement proportionnel au pas de temps. Autrement dit, proportionnel
au nombre d'itérations totales.
Aussi, nous voyons que l'erreur sur la distance soleil-Terre est proportionnelle
au pas de temps et que dans une certaine mesure, l'erreur énergétique aussi. Le
fait que les deux erreurs ne soient pas proportionnelles entre elles s'explique par
le fait que l'erreur énergétique est composée de l'énergie potentielle qui dépend
de l'inverse de la distance soleil-Terre, ainsi que de l'énergie cinétique dont ne
tient pas compte l'erreur sur la distance orbitale.
La mesure de l'énergie contenue dans le système au cours du temps est donc
conrmée dans ce cas particulier comme moyen de mesurer l'erreur dans une
simulation. Dans des systèmes plus complexes, elle sera notre seule façon de
quantier l'erreur.
Problème pythagoricien
Un autre moyen de tester notre programme est de l'utiliser pour résoudre
un système dont la solution a été trouvée et qui est universellement reconnue.
Nous pourrons ainsi comparer nos résultats aux résultats qui ont été publiés.
25
Simulation n corps
Figure
Thibault Wildi - 3M8
5.2 Simulation du cas soleil-Terre - Graphique
Le problème pythagoricien est une problème de gravitation bidimensionnel à
trois corps résolu en 1967 avec l'arrivée des premières simulations n corps[15].
La situation initiale est celle de la gure 5.3.
Ce problème est intéressant car il va nous permettre de tester notre programme sur un système où le mouvement des corps est plutôt chaotique, c'està-dire qu'il n'apparait aucun motif répétitif dans la trajectoire des corps.
Mentionnons aussi que la simulation utilise une constante de gravitation
valant 1[15] et que les unités sont celles du système international des unités.
Aussi les corps ont une vitesse initiale nulle.
La solution de ce problème ayant été calculée par d'autres avant nous[15],
nous aurons une base de comparaison pour nos résultats.
En lançant une série de simulations sur une durée de 6[s] ayant la situation initiale décrite par la gure 5.3, nous obtenons le tableau de la gure 5.4 représenté
graphiquement dans la gure 5.5.
Nous constatons à nouveau que le temps de calcul est inversement proportionnel au pas de temps.
Nous remarquons, par contre, que l'erreur énergétique évolue de façon totalement chaotique jusqu'à ce que le pas de temps soit inférieur à un certain seuil
audelà duquel elle varie proportionnellement au pas de temps. Nous parlerons
26
Simulation n corps
Thibault Wildi - 3M8
5.3 Problème pythagoricien - Situation initiale, The Astronomical
Journal 1967[15]
Figure
Figure
5.4 Problème pythagoricien - Résultats
27
Simulation n corps
Figure
Thibault Wildi - 3M8
5.5 Problème pythagoricien - Graphique
de l'origine de ce comportement dans la section suivante. Nous pouvons néanmoins en déduire que pour chaque simulation, il existe un certain seuil au delà
duquel l'erreur énergétique n'est pas représentative.
En eet, prenons comme exemple la simulation ayant comme pas de temps
0.125[s], l'erreur n'est que de 72% par rapport aux autres simulations ayant
un pas de temps de la même échelle. Si, ensuite, on compare cette simulation
à la simulation de pas de temps 1.91 · 10−6 [s] ayant une erreur de 79%, on
peut penser à première vue que les trajectoires devraient être très proches vu la
proximité du taux d'erreur. Dans la gure 5.6 qui illustre les diérents résultats
des simulations ainsi que la trajectoire théorique, on observe cependant que les
trajectoires sont très dissemblables.
Nous constatons qu'avec le pas de temps de 0.125[s], les corps 2 et 3 (se
référant à la numérotation de la situation initiale de la gure 5.3) se croisent et
continuent leurs chemins, tandis que dans le deuxième cas, les corps se tournent
autour avant de repartir dans la direction d'où ils sont venus ce qui est beaucoup
plus proche des trajectoires théoriques.
C'est le cas que nous avons décrit dans la partie théorique où les erreurs sur
les positions r⃗j sont dans une conguration telle que l'énergie totale du système
est proche de la valeur initiale. Les erreurs dans un sens compensant les erreurs
dans l'autre.
Pour éviter cette situation, il faut s'assurer d'avoir pris un pas de temps susamment petit pour être dans la zone où l'erreur énergétique est représentative
28
Simulation n corps
Thibault Wildi - 3M8
5.6 Problème pythagoricien - Comparaison des simulations ; de gauche
à droite : les trajectoires théoriques, la simulation de pas de temps 1.25 · 10−1 [s]
, la simulation de pas de temps 1.91 · 10−6 [s]
Figure
et, ensuite, nous pourrons moduler le pas de temps an d'obtenir le meilleur
compromis entre la précision et le temps de calcul.
Source de l'erreur
Nous pouvons aussi nous demander en regardant les résultats du tableau
de la gure 5.4 d'où vient le comportement chaotique et la si grande taille des
erreurs.
En regardant les trajectoires de gure 5.7 qui représente la simulation du
cas pythagoricien avec un pas de temps de 4.88 · 10−4 , nous constatons que les
corps 2 et 3 sont en fait éjectés lorsqu'ils passent l'un près de l'autre.
Cela s'explique par le fait que lorsque deux corps sont proches, c'est-à-dire
lorsque la distance qui les sépare devient comparable à la distance qu'ils parcourent entre chaque itération, l'erreur faite en partant du principe que l'accélération est constante tout au long de l'itération devient très importante, tant
en intensité qu'en direction. Nous verrons que c'est ce même phénomène qui est
à la base de la grande majorité de l'erreur dans toutes les simulations.
Le phénomène devient extrême dans les cas où, par le hasard du pas de
temps, deux corps se retrouvent presque superposés à la suite d'une itération.
Cela donne lieu à une accélération colossale pendant l'itération suivante, ce qui
éjectera les corps en direction opposée si bien qu'ils seront trop éloignés à la
prochaine itération pour êtres freinés par une accélération dans le sens inverse.
En réalité, si deux corps étaient passés si proches l'un de l'autre, la forte
accélération aurait été appliquée pendant seulement un très court moment et
aurait été immédiatement compensée par une accélération de la même ampleur
une fois que les corps se seraient croisés.
29
Simulation n corps
Thibault Wildi - 3M8
5.7 Problème pythagoricien - Éjection de corps, la vue inférieure est
un agrandissement de la vue supérieure
Figure
30
Simulation n corps
Thibault Wildi - 3M8
Le comportement aléatoire de l'erreur en fonction du pas temps s'explique
quant à lui par le fait que l'erreur étant générée quand deux objets se retrouvent
soudainement proches l'un de l'autre à la suite quelques itérations, elle dépend
grandement de la distance séparant les deux objets quand ils sont au plus proche.
Cette distance dépend de façon pseudo-aléatoire du pas de temps jusqu'à
ce que celui-ci devienne susamment petit pour que l'on retrouve les mêmes
congurations de rencontre entre les diérents pas de temps.
Il existe plusieurs techniques pour résoudre le problème dit des "close encounters" (que l'on traduirait approximativement par les "rencontres proches"). Il
est possible bien sûr, d'améliorer la technique d'intégration an d'obtenir une
meilleure précision entre les itérations 1 , mais cela nécessiterait un bagage mathématique que je n'ai pas encore.
Des techniques qui nous sont accessibles, il y en a deux : diminuer le pas de
temps ou introduire un paramètre dit "d'adoucissement", c'est-à-dire rajouter
une distance arbitraire entre chaque objet. Ainsi, nous sommes dans un système
"sans collision" où malgré l'ajout d'une certaine erreur sur les distances et, par
là, sur la simulation, nous réduisons drastiquement l'erreur créée par les "close
encounters".
5.1.2 Nombre de corps
An de pouvoir connaître les limites de notre programme, nous allons également nous pencher sur l'impact du nombre de corps sur le temps de calcul. Dans
une moindre mesure, nous allons regarder si le nombre de corps a un impact sur
l'erreur.
En lançant une série de simulations avec un pas de temps constant de 5 ·
10−7 [s] sur le cas pythagoricien et en ajoutant à chaque simulation un corps
dont chaque coordonnée a été tirée aléatoirement entre -5 et 5 et dont la masse
a été tirée aléatoirement entre 1 et 5, nous obtenons le tableau de la gure 5.8.
Ce nous donne ensuite le graphique de la gure 5.9.
Nous constatons que le temps de calcul dépend du carré du nombre de corps,
ce qui était prévisible car nous calculons chaque interaction et que le nombre
d'interactions dépend de n2 ou plus précisément de n(n+1)
.
2
Pour ce qui est de l'erreur, nous constatons que celle-ci varie de façon chaotique, avec peut-être une légère tendance à augmenter, la probabilité d'avoir des
"close encounters" augmentant avec le nombre de corps.
Avec ce test, nous nous rendons compte qu'il est dicile de faire des simulations avec un grand nombre de corps. Non seulement, le temps de calcul augmente considérablement mais aussi, pour contrer la probabilité d'avoir des "close
encounters", il faut encore diminuer le pas de temps ce qui augmente à nouveau
1. La méthode d'Euler est la plus simple des méthodes d'intégration mais est aussi de loin
la plus imprécise.
31
Simulation n corps
Figure
Figure
Thibault Wildi - 3M8
5.8 Étude sur le nombre de corps - Résultats
5.9 Étude sur le nombre de corps - Graphique
32
Simulation n corps
Figure
Thibault Wildi - 3M8
5.10 Problème pythagoricien - Variation de l'énergie totale
le temps de calcul. Il devient donc impératif de développer un système qui nous
permet de pouvoir réduire l'erreur créée par les "close encounters" tout en gardant un temps de calcul raisonnable.
5.2 Simulation à pas de temps variable
5.2.1 Nécessité d'un algorithme à pas de temps variable
Comme nous l'avons vu, la plupart de l'erreur est créée lors des "close encounters", mais dans quelle proportion. La graphique de la gure 5.10 nous
montre la variation de l'énergie totale du système au cours du temps dans le cas
de la simulation du problème pythagoricien avec un pas de temps de 5 · 10−7 [s].
Nous observons que l'énergie du système est constante jusqu'au temps 1.88[s]
où elle change brutalement pour aller se placer à −10.1[J] jusqu'à la n de la
simulation. L'instant 1.88[s] correspondant exactement au moment où les corps
2 et 3 passent au plus proche l'un de l'autre. Ce sont donc bien les "close
encounters" qui sont à la source de la grande majorité de l'erreur.
Comme nous l'avons vu, la solution se trouve dans la diminution du pas
de temps, mais il y a là un réel gaspillage de puissance de calcul car nous
navons besoin d'un pas de temps plus court que pendant le très court instant
(le changement de niveau d'énergie semble instantané sur le graphique) où les
corps sont au plus près. Nous en arrivons à la nécessité d'améliorer le programme
pour que celui-ci puisse diminuer le pas de temps lorsque c'est nécessaire.
33
Simulation n corps
Thibault Wildi - 3M8
5.2.2 Algorithme à pas de temps variable
Nous savons maintenant qu'il nous faut diminuer le pas de temps pendant les
"close encounters", mais à quelles valeurs se rattacher concrètement pour xer
le pas de temps à chaque itération pendant l'exécution du programme ? Il faut
que le programme puisse réagir aux brusques changements de niveau de l'énergie
totale en temps réel. Ces brusques changements peuvent s'observer par des pics
dans la variation de l'énergie entre deux itérations ou, plus correctement, dans
la dérivée de l'énergie. Nous calculons celle-ci de la façon suivante :
En+1 − En
(5.1)
∆t
Nous calculons donc la dérivée de l'énergie à chaque itération avant de la
comparer à la limite xée dans le chier Input.txt du dossier Input par le paramètre DYMC_DELTA_T_ACC. Après plusieurs essai, j'ai débouché sur la
méthode suivante suivante. Si la dérivée calculée est plus grande que la limite
xée, on réduit le pas de temps pour la prochaine itération. Si la dérivée est plus
petite que la limite et si le pas de temps est inférieur au pas de temps maximal
(paramètre DELTA_T du cher Input.txt ), on augmente le pas de temps pour
la prochaine itération.
Il faut néanmoins rajouter une limite inférieure au pas de temps. Je me suis
en eet retrouvé lors de certaines simulations de test avec des pas de temps
·1015 fois plus petits que le pas de temps initial, ce qui, bien que sur une période
extrêmement réduite, prendrait quand même plusieurs années de calcul. Après
quelques essais, il s'est avéré que xer une limite inférieure à 2 · 10−5 fois le pas
de temps de départ est un bon compromis entre précision et temps de calcul.
Ė =
5.2.3 Test du programme à pas de temps dynamique
Pour pouvoir utiliser le pas de temps dynamique au mieux, nous allons tester
cette nouvelle version du programme sur le même cas que précédemment, c'està-dire sur le problème pythagoricien. En lançant une série de simulations avec
un pas de temps de base de 5·10−7 et en faisant varier la limite supérieure sur la
dérivée de l'énergie totale (nous l'appellerons dès lors coecient de précision),
nous obtenons le graphique de la gure 5.11.
Nous observons que jusqu'à un coecient d'environ 0.5[J/s], le temps de calcul ne varie pas ou augmente de façon insigniante, tandis que l'erreur diminue
de manière drastique. Cela s'explique par le fait que la durée pendant laquelle le
pas de temps variable est appliqué est extrêmement faible mais susante pour
contrer l'erreur.
A partir d'un coecient de précision de 0.5[J/s] le temps de calcul augmente
de façon importante. Ce comportement vient du fait que le coecient de précision est devenu susamment petit pour que le pas de temps variable atteigne
le plancher xé à 2 · 10−5 du pas de temps de départ. Le coecient détermine
maintenant à quel moment le pas de temps variable va intervenir et descendre
34
Simulation n corps
Figure
Thibault Wildi - 3M8
5.11 Problème pythagoricien - Test avec pas de temps dynamique
jusqu'au plancher, et ce moment est plus sensible au coecient vu que la dérivée
change beaucoup moins rapidement.
De même, comme la majorité de l'erreur est produite pendant la "close
encounter", une fois le pas de temps plancher atteint, elle diminue beaucoup
moins vite. Le fait de diminuer le pas de temps plus tôt impactant peu sur la
quantité d'erreur, il devient à ce moment plus rentable de diminuer le pas de
temps maximal qui est directement lié au pas de temps plancher.
Nous voyons qu'il faut donc trouver pour chaque simulation un coecient
de précision qui soit adapté à la situation, l'erreur pouvant être réduite de
manière drastique jusqu'à un certain point sans inuencer ou presque sur le
temps de calcul. Le coecient sera ajusté sur quelques simulations de mise au
point sur une durée plus courte mais comprenant quand même quelques "close
encounters". Suivant nos exigences, les coecients peuvent varier, mais un bon
compromis dans ce cas pourrait se situer autour de 0.4[J/s].
Si nous nous penchons sur ce qui se passe pendant un "close encounter",
nous obtenons le graphique de la gure 5.12. Le test, a été eectué avec un pas
de temps de base de 5 · 10−7 et un coecient de précision de 0.4[J/s]. Nous
observons que le pas de temps reste à 5 · 10−7 jusqu'à ce que l'énergie varie de
façon susamment marquée pour activer le pas de temps dynamique. Ensuite
celui-ci descend an de maintenir la dérivée de l'énergie à sa valeur limite. Cela
s'observe par la pente constante de la courbe de l'énergie lorsque le pas de temps
dynamique est activé.
Nous voyons aussi que pendant le moment où les deux corps sont au plus
35
Simulation n corps
Thibault Wildi - 3M8
5.12 Problème pythagoricien - Évolution du pas de temps lors d'un
"close encounter"
Figure
près, le niveau d'énergie remonte, créant deux pics dans les pas de temps. Ils
sont dus au fait que lorsque l'énergie remonte, il y a un moment où la dérivée
de celle-ci passe à zéro, faisant augmenter le pas de temps pendant un court
instant.
Finalement, si l'on regarde attentivement, on observe que la courbe du pas
de temps forme un léger replat lorsqu'elle est au plus bas. C'est que le pas de
temps a atteint la butée xée à 2 · 10−5 du pas de temps de base. Le plancher
n'étant atteint que pendant un très court instant, il ne détériore pas la qualité
de la simulation par rapport au cas où nous n'aurions pas limité le pas de temps.
D'autre part, le fait que le plancher ne soit atteint que pendant un très court
instant prouve bel est bien qu'un coecient de précision de 0.4[J/s] est un bon
compromis pour cette simulation.
On voit sur la gure 5.13, la trajectoire des corps lors de la "close encounter".
Seul un point est aché pour 2000 calculé. Néanmoins, on remarque très bien le
rapprochement des pointe du au pas de temps diminuant, malgré la vitesse croissante des corps. On remarque aussi quatre espaces correspondant aux moments
où le pas de temps à augmenté à nouveau avant que les points se rapprochent
susamment pour donner une ligne continue correspondant au moment où le
pas de temps était au plus bas.
36
Simulation n corps
Thibault Wildi - 3M8
5.13 Problème pythagoricien - "Close encounter" avec pas de temps
dynamique
Figure
5.3 Simulations de cas
Bien que, le but de ce travail soit avant tout de développer un programme
de simulation n corps, nous avons essayé celui-ci sur quelques cas pratiques.
5.3.1 Figure de huit à 3 corps
Il existe, dans les systèmes auto-gravitant, la possibilité de trouver certains
cas avec n > 2 qui, grâce à des congurations comportant des symétries, peuvent
être résolus de manière analytique[18]. Dans certains de ces cas particuliers, les
corps parcourent la même trajectoire de manière périodique. Bien sûr, ces cas ne
fonctionnent que pour des congurations très précises et la moindre perturbation
peut s'amplier et casser l'harmonie. La simulation d'un de ces cas sera donc
aussi un bon moyen de vérier que notre programme fonctionne correctement.
Nous allons essayer de simuler un cas où trois corps dessinent un huit. La
conguration initiale est illustrée dans la gure 5.14, les valeurs précises sont
situées dans le tableau de la gure 5.15. Comme dans le cas pythagoricien, la
constante de gravitation vaut l'unité.
Après une simulation sur une période de 300[s] soit cinq minutes, ce qui
correspond à un peu moins de 50 "orbites" sachant que les corps mettent un
peut plus six secondes pour parcourir la gure de huit, les corps sont toujours sur
la bonne trajectoire. Les trajectoires dessinées par les corps au bout d'environ
300[s] sont représentées dans la gure 5.16.
37
Simulation n corps
Figure
5.14 Figure de huit - Illustration de la situation initiale[19]
Figure
Figure
Thibault Wildi - 3M8
5.15 Figure de huit - Situations initiales[19]
5.16 Figure de huit - Trajectoire des corps au temps t ≈ 300
38
Simulation n corps
Figure
Thibault Wildi - 3M8
5.17 Études des amas - Ségrégation des masses
Il est intéressant de noter qu'au bout de 300[s], l'erreur n'est que de 0.037%
alors que nous avons utilisé un pas de temps de 5 · 10−7 . Cela vient du fait que
les corps restant à distance, il n'y a jamais de "close encounter" et donc l'erreur
reste très basse. Aussi, bien que le pas de temps variable ait été activé, il ne
s'est pas déclenché.
Après coup, j'ai relancé une simulation sur une période de 3600[s] soit une
heure, après près de deux heures de calcul, la gure de huit était toujours respectée et l'erreur n'était que de 0.44%.
5.3.2 Simulation d'amas
Il est aussi intéressant d'étudier le comportement d'amas de corps.
Après de nombreux tests avec n entre 5 et 20 et bien des heures de calcul, on
voit apparaitre un phénomène récurant : La formation de sous-systèmes à deux
voire trois corps. Ces couples, qui sont composés de corps orbitant l'un autour
de l'autre sont formés par les corps lourds du système.
On observe de façon générale dans la simulation d'amas auto-gravitant, un
phénomène de ségrégation des masses. Cela est dû au fait que quand deux corps
ont une "close encounter", leur énergie cinétique a tendance à s'égaliser. Ce qui
se traduit globalement par une accélération des corps légers et un ralentissement
des corps lourds. Ainsi les corps lourds ont tendance à se regrouper au centre
du système, tandis que les corps légers sont soit éjectés soit envoyés dans des
orbites hautement elliptiques.
La gure 5.17 illustre ce phénomène dans un système à seulement quatre corps
pour plus de clarté. Les corps violet et bleu ont une masse approximativement
39
Simulation n corps
Thibault Wildi - 3M8
quatre fois supérieure aux corps rouge et jaune. On observe qu'après quelques
"close encounters", les objets légers rouge et bleu se sont fait éjecter, tandis
que les objets lourds violet et bleu se sont mis à tourner l'un autour de l'autre.
On peut noter que malgré une énergie totale du système négative, c'est-à-dire
que l'énergie potentielle a le dessus sur l'énergie cinétique, les corps légers ont
été éjectés. Une partie de l'énergie potentielle contenue entre les deux corps
lourds, ainsi qu'une partie de leur énergie cinétique a été transférée aux corps
légers, leurs permettant d'atteindre une vitesse leur permettant de se libérer du
système.
5.4 Limitations du programme
Nous nous pouvons maintenant tirer des conclusions sur les possibilités et
les limites que nous ore le programme.
Nous avons vu que le temps de calcul augmente avec le carré du nombre de
corps, ce qui limite grandement le nombre maximum de que l'on peut simuler.
De plus, comme nous l'avons vu dans la dernière section, on observe de
manière générale le regroupement des corps lourds au centre et l'éjection des
corps légers dans des orbites hautement elliptiques. Ce phénomène, bien qu'intéressant à observer, tend à créer une grande erreur. En eet, les corps lourds
évoluant très proches les uns des autres, nous avons un nombre de "close encounters" considérable. Et si nous utilisons un pas de temps dynamique, celui-ci
nit par être actif en permanence. De plus, lorsque l'on augmente le nombre de
corps, la probabilité de "close encounters" augmente aussi, réduisant l'ecacité
du programme.
Un autre inconvénient lorsque que l'on fait une simulation sur un système
avec un grand nombre de corps en utilisant un pas de temps dynamique, est que
l'on diminue le pas de temps non seulement pour calculer les trajectoires des
deux corps en "close encounter" mais aussi de tous les autres corps du système.
Ce qui devient considérablement coûteux en temps de calcul lorsque que l'on
augmente le nombre de corps.
Pour toutes ces raisons, bien que le programme puisse être précis et relativement ecace avec un nombre restreint de corps, il se prête mal à des simulations
avec un nombre de corps supérieur à quelques dizaines. Il faudrait, pour pallier
à ces problèmes, revoir nos techniques d'intégration, et utiliser des algorithmes
de simplication an que le temps de calcul n'augmente que linéairement avec
le nombre de corps. Aussi, si chaque objet avait un pas de temps distinct, cela
réduirait considérablement l'impact des "close encounters" en termes de temps
de calcul sur les systèmes qui possèdent un nombre important de corps, car nous
pourrions ne réduire le pas de temps que pour le couple d'objets concerné.
D'autre part, une fois le programme de simulation développé, il faut pouvoir
visionner les résultats. Pour cela, j'ai créé une interface graphique pouvant acher les trajectoires des corps et leurs mouvements en temps réel. Néanmoins,
40
Simulation n corps
Thibault Wildi - 3M8
cette interface reste rudimentaire, et n'est pas très ecace pour analyser les
résultats d'une simulation sur une longue durée ou contenant un nombre important de corps, l'écran devenant dicilement lisible.
Cette interface est aussi limitée à l'achage de simulations à 2 dimensions.
Bien que mon programme puisse normalement faire des simulations dans trois
dimensions, je n'ai jamais pu vérier l'exactitude des trajectoires calculées, ne
disposant pas de moyen de visualisation.
41
Chapitre 6
Conclusion
6.1 Commentaires
Mon objectif, dans ce travail de maturité, était de comprendre et d'appliquer les mécanismes de simulation n corps dans la conception d'un programme
personnel, puis dans la mesure du possible d'étudier, à l'aide de ce programme,
certain cas concrets.
Il s'est révélé que la simple conception et mise au point d'algorithme de simulation dans un programme est un travail déjà très intéressant. Les techniques
utilisées sont nombreuses et complexes, et la manière dont elles inuencent la
qualité et les performances de la simulation sont un sujet d'étude digne d'intérêt.
Bien que les performances du programme n'aient pas tout à fait été celles
espérées, je pense quand même que l'analyse du comportement du programme et
le traitement de cas simples ont été intéressants et ouvrent de nombreuses voies
pour l'amélioration celui-ci. Des solutions comme l'amélioration de la technique
d'intégration, un pas de temps individuel pour chaque corps, et des techniques
de division de l'espace en cellules pour des n de simplication peuvent être
apportée.
D'autre part, pour ce qui est de combler la lacune dans la visualisation des
résultats, je pense aujourd'hui que si je devait réécrire un programme, je le ferais
en langage python. Celui-ci possède des fonctions graphiques puissantes tout en
gardant une approche et une syntaxe proches de celles du C. Aussi, certains
outils ont été développés par des scientiques an de visualiser les résultats de
simulations n corps dans ce langage.
6.2 Remerciements
Je tiens à remercier avant tout mon maître référant, M. Laurent de Schouqui m'a suivi, aidé et conseillé tout au long de ce travail.
D'autre part, j'aimerais aussi remercier le Dr. Yves Revaz, chercheur au
laboratoire d'astrophysique de l'EPFL pour m'avoir consacré une partie de son
lepnikoff,
42
Simulation n corps
Thibault Wildi - 3M8
temps et avoir répondu à mes nombreuses questions.
43
Table des gures
2.1
Carte de densité d'une simulation n corps de la formation de
l'univers, n = 256 · 106 corps[17]. . . . . . . . . . . . . . . . . . .
3.1
3.2
Une itération de la méthode d'Euler . . . . . . . . . . . . . . . .
Premières itérations de la méthode d'Euler sur une courbe du
type ax2 + b . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
4.1
Format d'entrée du chier "Input.txt" . . . . . . . . . . . . . . .
21
5.1
5.2
5.3
Simulation du cas soleil-Terre - Résultats . . . . . . . . . . . . .
Simulation du cas soleil-Terre - Graphique . . . . . . . . . . . . .
Problème pythagoricien - Situation initiale, The Astronomical
Journal 1967[15] . . . . . . . . . . . . . . . . . . . . . . . . . . .
Problème pythagoricien - Résultats . . . . . . . . . . . . . . . . .
Problème pythagoricien - Graphique . . . . . . . . . . . . . . . .
Problème pythagoricien - Comparaison des simulations ; de gauche
à droite : les trajectoires théoriques, la simulation de pas de temps
1.25 · 10−1 [s] , la simulation de pas de temps 1.91 · 10−6 [s] . . .
Problème pythagoricien - Éjection de corps, la vue inférieure est
un agrandissement de la vue supérieure . . . . . . . . . . . . . .
Étude sur le nombre de corps - Résultats . . . . . . . . . . . . . .
Étude sur le nombre de corps - Graphique . . . . . . . . . . . . .
Problème pythagoricien - Variation de l'énergie totale . . . . . .
Problème pythagoricien - Test avec pas de temps dynamique . .
Problème pythagoricien - Évolution du pas de temps lors d'un
"close encounter" . . . . . . . . . . . . . . . . . . . . . . . . . . .
Problème pythagoricien - "Close encounter" avec pas de temps
dynamique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Figure de huit - Illustration de la situation initiale[19] . . . . . .
Figure de huit - Situations initiales[19] . . . . . . . . . . . . . . .
Figure de huit - Trajectoire des corps au temps t ≈ 300 . . . . .
Études des amas - Ségrégation des masses . . . . . . . . . . . . .
25
26
5.4
5.5
5.6
5.7
5.8
5.9
5.10
5.11
5.12
5.13
5.14
5.15
5.16
5.17
44
6
9
27
27
28
29
30
32
32
33
35
36
37
38
38
38
39
Bibliographie
://fr.wikipedia.org, Méthode d'Euler.
://en.wikipedia.org, Euler method.
://en.wikipedia.org, N-body simulation.
://en.wikipedia.org, n-body problem.
://en.wikipedia.org, Potential energy.
://fr.wikipedia.org, C (langage).
://en.wikipedia.org, C (programming language).
://www.codingunit.com/the-history-of-the-c-language, The History of
the C Language.
[9] http ://gcc.gnu.org/ GCC, the GNU Compiler Collection, site internet du
GNU Compiler Collection.
[10] http ://fr.wikipedia.org, Programmation modulaire.
[11] http ://www.libsdl.org/, Site De la bibliothèque C, SDL (Simple DirectMedia Layer).
[12] Bernard Cassagne, Introduction au langage C, 1998.
[13] Sverre J.Aarseth, Gravitational N-Body Simulations : Tools and Algorithms, Cambridge Monographs on Mathematical Physics, 2010.
[14] Mauri Valtonen & Hannu Karttunen, The Three-Body Problem, 2006.
[15] Victor Szebehely & C. Frederik Peters, Complete Solution of a General
Problem of Three Bodies, The Astronomical Journal, Volume 72, Number 7,
September 1967.
[16] Entretien datant 17 octobre 2013 avec Yves Revaz, collaborateur scientique au laboratoire d'astronomie de l'EPFL.
[17] http ://obswww.unige.ch/ revaz/pNbody/rst/Gallery.htmlrs, site dédié au
module python pNbody de visualisation de simulation n corps, développé par
le chercheur Yves Revaz .
[18] http ://www.scholarpedia.org/article/N-body_choreographies, Site présentant certain cas de gure n corps.
[19] By Alain Chenciner and Richard Montgomery, A remarkable periodic solution of the three-body problem in the case of equal masses, Annals of Mathematics, 152 (2000), 881-901.
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
http
http
http
http
http
http
http
http
45
Chapitre 7
Annexe
7.1 Raccourcis clavier de l'interface graphique
Commande globale :
Flèches directionnelles : Déplacer le graphique
+ et - du NumPad : Augmenter ou diminuer l'échelle d'achage
i : Prendre une capture d'écran (elle est sauvegardée sous Output/Image.bmp )
d : Passer au mode d'achage dynamique
s : Passer au mode d'achage statique
a : Acher ou non les axes
Esc : Quitter le programme
Commande spécique au mode de vue statique :
; et : pour respectivement diminuer et augmenter le pourcentage de points
aché à l'écran, impact sur les performances
Commande spécique au mode de vue dynamique :
; et : pour respectivement augmenter ou diminuer la vitesse d'écoulement
du temps
t : Acher ou non les trajectoires
e : Eacer les trajectoires
p : Arrêter l'écoulement du temps
r : Revenir au temps 0
7.2 Code source
7.2.1 main.c
46
Simulation n corps
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include
#include
#include
#include
#include
#include
#include
#include
/∗ ∗
Thibault Wildi - 3M8
< s t d i o . h>
//
Used
for
I /O
<math . h>
//
Used
for
rounding
Operations
<t i m e . h>
//
Used
for
time
< s t d b o o l . h>
//
Used
for
Boolean
operations
operations
functions
" c o n s t a n t s . h"
" i o _ o p e r a t i o n s . h"
" i t e r a t o r . h"
" d i s p l a y 2 d . h"
int
int
unsigned long int
double
double
double
double
double
double
double
double
double
int
int
Extern
variable
∗ ∗/
defining
BODY_NB;
DIMENTIONS ;
bool
STEP =
0;
USE_DYMC_DELTA_T;
DYMC_ACCURACY;
TIME =
0;
MAX_DELTA_T;
DELTA_T ;
RUN_TIME ;
G_CONST;
SYSTEM_ENERGY;
THEORETICAL_ENERGY ;
PRT_PRCT;
char
main
(
FILE
∗ outPutFile_BIN
{
argc ,
output
=
0;
//
Will
be
our
pointer
on
our
=
0;
//
Will
be
our
pointer
on
our
//
Will
be
our
//
Will
count
//
Initializes
//
Deleting
output
file
if
//
Deleting
output
file
if
file
∗ outPutSpec_TXT
FILE
∗∗ a r g v )
specification
file
∗ outPutEnergy_TXT
∗ bodyArray ;
FILE
BODY
clock_t
ticks
=
0;
ticks ;
for
bodyArray
time
=
array
of
body
number
of
clock
calculation
IO_inti ( ) ;
bodies
from
input
file
r e m o v e (OUTPUTFILE_BIN_NAME) ;
existing
r e m o v e (OUTPUTSPEC_TXT_NAME) ;
existing
r e m o v e ( " Output / E n e r g y . t x t " ) ;
/∗ ∗
if
Opening
∗ ∗/
files
outPutSpec_TXT =
(PRT_PRCT !=
f o p e n (OUTPUTSPEC_TXT_NAME, "w" ) ;
0)
{
outPutFile_BIN
=
f o p e n (OUTPUTFILE_BIN_NAME, "wb" ) ;
outPutEnergy_TXT =
f o p e n ( " Output / E n e r g y . t x t " , "w" ) ;
}
f p r i n t f ( outPutSpec_TXT ,
" Initial
s i t u a t i o n : \ n" ) ;
IO_printBodyData_TXT ( outPutSpec_TXT , b o d y A r r a y , t r u e ,
false ,
/∗ ∗
for
' , ' ,
Calculation
ticks
=
true ,
' | ') ;
process
∗ ∗/
clock () ;
( STEP =
//
0;
TIME < RUN_TIME ;
For
every
STEP++)
iteration
{
c a l c u l a t e N e x t S t e p ( bodyArray ) ;
if
//
(
STEP%(
//
int
Calculate
next
STEP
) r o u n d ( 1 /PRT_PRCT)
Print
only
PRT_PRCT
{
47
== 0 && PRT_PRCT !=
steps
in
output
file
0)
false ,
Simulation n corps
58
IO_printBodyData_BIN ( o u t P u t F i l e _ B I N , b o d y A r r a y , t r u e , t r u e , t r u e
, false , false ) ;
59
60
61
62
63
//
Print
data
}
if
(
STEP%(
{
int
) r o u n d ( 1 0 /PRT_PRCT)
f p r i n t f ( outPutEnergy_TXT ,
"
== 0 && PRT_PRCT !=
%.15 e
|
%.15 e
0)
|%.15 e
| \ n " , TIME ,
DELTA_T,SYSTEM_ENERGY) ;
64
65
66
67
68
69
70
}
}
ticks
/∗ ∗
c l o c k ( )− t i c k s ;
=
Printing
data
in
specification
f p r i n t f ( outPutSpec_TXT ,
" Final
file
∗ ∗/
s i t u a t i o n : \ n" ) ;
IO_printBodyData_TXT ( outPutSpec_TXT , b o d y A r r a y , t r u e ,
double
false ,
71
' , ' ,
' | ') ;
systemError
=
THEORETICAL_ENERGY
72
73
74
(THEORETICAL_ENERGY
∗
false ,
SYSTEM_ENERGY) /
f p r i n t f ( outPutSpec_TXT ,
"\ nSteps :
%d \ n " , STEP ) ;
f p r i n t f ( outPutSpec_TXT ,
" Delta
%.4 e \ n " ,MAX_DELTA_T) ;
f p r i n t f ( outPutSpec_TXT ,
" Calculation
f p r i n t f ( outPutSpec_TXT ,
" Start
THEORETICAL_ENERGY) ;
76
77
−
true ,
100;
t i c k s ) /CLOCKS_PER_SEC) ) ;
75
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
Thibault Wildi - 3M8
f p r i n t f ( outPutSpec_TXT ,
" Finish
f p r i n t f ( outPutSpec_TXT ,
" Delta
T:
−
Time :
Energy :
%.8 f
[ s ] \ n" , ( ( (
float
)
%.10 e \n" ,
− E n e r g y : % . 1 0 e \ n " , SYSTEM_ENERGY) ;
− E n e r g y : % . 1 0 e \ n " , (SYSTEM_ENERGY −
THEORETICAL_ENERGY) ) ;
f p r i n t f ( outPutSpec_TXT ,
/∗ ∗
if
Closing
files
" Error :
%.6 f %%\n " , s y s t e m E r r o r ) ;
∗ ∗/
f c l o s e ( outPutSpec_TXT ) ;
(PRT_PRCT !=
0)
{
f c l o s e ( outPutFile_BIN ) ;
f c l o s e ( outPutEnergy_TXT ) ;
}
/∗ ∗
if
Display
results
if
possible
∗ ∗/
(DIMENTIONS == 2 && PRT_PRCT !=
0)
{
d i s p l a y 2 D (OUTPUTFILE_BIN_NAME) ;
}
}
return
1;
Code 7.1 main.c
7.2.2 constants.h
1 #ifndef
2 #define
3
4 #include
5 #include
CONSTANTS_H_INCLUDED
CONSTANTS_H_INCLUDED
< s t d i o . h>
type
variable
< s t d b o o l . h>
6
7
Needed
//
Used
//
Defines
for
FILE
for
Boolean
operations
#define
MAX_DIMENTIONS 3
the
#define
9 #define
8
//
declaration
max
dimensions
accepted
( this
is
used
for
creation
of
defines
the
BODY
struct )
OUTPUTFILE_TXT_NAME " Output / Output . t x t "
file
OUTPUTSPEC_TXT_NAME " Output / S p e c . t x t "
file
//
Defines
output
//
Defines
output
name
name
48
Simulation n corps
#define
11 #define
12 #define
13 #define
14 #define
15 #define
10
Thibault Wildi - 3M8
OUTPUTFILE_BIN_NAME " Output / Output . b i n "
file
//
Defines
output
" Output / I m a g e . bmp"
//
Defines
output
" Input / Input . txt "
//
Defines
input
1820
//
Defines
screen
980
//
Defines
screen
//
How many
name
OUTPUTIMAGE_BMP
image
name
INPUTFILE_NAME
file
name
SCREEN_X
width
SCREEN_Y
hight
MAX_PT_ON_SCREEN 2 5 0 0 0
are
read
from
file
and
printed
on
screen
( spread
on
all
points
simulation
length )
16
17 / ∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
18 ∗ NAME :
BODY
19 ∗ MEMBRES :
20 ∗
d o u b l e p o s [ MAX_DIMENTIONS ]
W i l l c o n t a i n body ' s p o s i t i o n
21 ∗
22 ∗
23 ∗
24 ∗
coordinates (x , y , z )
double
at
time
t+d e l t a _ t
double
double
before
Will
flushing (
t
in
before
+=
contain
delta_t
body ' s
position
)
Will
contain
body ' s
speed
Will
contain
body ' s
speed
body ' s
mass
[m/ s ]
n e x t _ s p d [ MAX_DIMENTIONS ]
t+d e l t a _ t
double
[m]
s p d [ MAX_DIMENTIONS ]
coordinates (x , y , z )
time
in
n e x t _ p o s [ MAX_DIMENTIONS ]
flushing (
mass ;
t
+=
delta_t
Will
[ kg ]
at
)
contain
in
25 ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
26
27 {
28
p o s [ MAX_DIMENTIONS ] ;
29
n e x t _ p o s [ MAX_DIMENTIONS ] ;
30
s p d [ MAX_DIMENTIONS ] ;
31
n e x t _ s p d [ MAX_DIMENTIONS ] ;
32
mass ;
33 } BODY;
34
35 / ∗ ∗ E x t e r n a l d e c l a r a t i o n s
∗ ∗/
36
BODY_NB;
/∗ ∗
Number o f
b o d i e s t o be r e a d i n
inputfile
∗ ∗/
37
DIMENTIONS ;
/∗ ∗
Number o f d i m e n s i o n s ( e x p e c t e d 2 o r 3 )
∗ ∗/
38
b o o l USE_DYMC_DELTA_T;
is
t o be u s e d ( t r u e o r
false )
∗ ∗/
/∗ ∗
I f dynamic t i m e s t e p
39
DYMC_ACCURACY;
f a c t o r when d y n a m i c t i m e s t e p
is
u s e d ∗ ∗/
/∗ ∗
Precision
40
TIME ;
/∗ ∗
Global v a r i a b l e
f o r time i n seconds
∗ ∗/
41
DELTA_T ;
/∗ ∗
Time s t e p w i d t h ( t i m e b e t w e e n e a c h
i t e r a t i o n ) in seconds
∗ ∗/
42
MAX_DELTA_T;
/∗ ∗
Maximum t i m e s t e p w i d t h ( t i m e b e t w e e n e a c h
i t e r a t i o n ) in
seconds
∗ ∗/
43
RUN_TIME ;
/∗ ∗
Run t i m e i n s e c o n d s
∗ ∗/
44
G_CONST;
/∗ ∗
Universal
gravitational
constant ,
theoretically
6 , 6 7 4 E−11
∗ ∗/
45
SYSTEM_ENERGY;
/∗ ∗
System ' s
total
e n e r g y ∗ ∗/
46
THEORETICAL_ENERGY ;
/∗ ∗
System ' s
initial
total
energy
∗ ∗/
47
PRT_PRCT;
/∗ ∗
P e r c e n t a g e o f s t e p t o be p r i n t e d i n o u t p u t
file
( to save
size
and t i m e ) ∗ ∗ /
STEP ;
48
calculation
s t e p s ∗ ∗/
/∗ ∗
W i l l c o u n t t h e number o f
49
50
/ / CONSTANTS_H_INCLUDED
typedef struct
double
double
double
double
double
extern
extern
extern
extern
extern
extern
extern
int
int
double
double
double
double
extern
extern
extern
extern
extern
double
double
double
double
double
extern unsigned long int
#endif
49
Simulation n corps
Thibault Wildi - 3M8
Code 7.2 constants.h
7.2.3 io_operations.h
1 #ifndef
2 #define
3
4 #include
5
6 #include
IO_OPERATIONS_H_INCLUDED
IO_OPERATIONS_H_INCLUDED
< s t d b o o l . h>
//
Used
for
Boolean
operations
" c o n s t a n t s . h"
7
8 / ∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
9 ∗ NAME :
BODY∗ I O _ i n t i ( )
10 ∗
11 ∗ DESCRIPTION :
Reads t h e
initialization
( input )
file
and c r e a t e s
12 ∗
13
14
15
16
17
18
19
20
∗
∗
∗
∗
∗
∗
∗
∗
21 ∗
22 ∗
23 ∗
array
of
OUTPUTS
35 ∗
36 ∗
them
to
there
initial
:
:
Type
Value
of
NOTES
to
the
array
false
BODY∗
:
:
Expects
:
Contains
the
address
of
following
"BODY_NB
first
entity
format
in
the
input
file
( from
number_of_bodies
DIMENTIONS
number_of_dimensions
G_CONST
gravity_constant
RUN_TIME
run_time
DELTA_T
delta_t
PRT_PRCT
print_percentage
USE_DYMC_DELTA_T
use_dynamic_delta_t
−>
the
bodies
:
")
28 ∗
34 ∗
initializing
:
RETURN
27 ∗
33 ∗
before
None
26 ∗
32 ∗
objects
position
PARAMETERS
25 ∗
30 ∗
31 ∗
and
:
INPUTS
24 ∗
29 ∗
speed
mass
an
of
( True
−>
1
,
2)
DYMC_DELTA_T_ACC
dynamic_delta_t_accuracy
pos_x
|
pos_y
|
pos_z
|
spd_x
|
spd_y
|
spd_z
|
mass
|
pos_x
|
pos_y
|
pos_z
|
spd_x
|
spd_y
|
spd_z
|
mass
|
. . .
END"
After
DYMC_DELTA_T_ACC,
E x p e c t s DYMC_DELTA_T_ACC e v e n
if
use
of
each
line
static
is
an
DELTS_T,
body .
w i l l be d i s r e g a r d e d though .
37 ∗
value
38 ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
39 BODY∗ I O _ i n t i ( ) ;
40
41 / ∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
50
"
Simulation n corps
42 ∗
43 ∗
44 ∗
45
46
47
48
∗
∗
∗
∗
NAME
∗
void
coding ,
INPUTS
bool
char
DESCRIPTION
bool
dataSeparator ,
:
so
Prints
each
char ∗
IO_printBodyData_TXT (
prt_time ,
digit
the
is
prt_pos ,
char
bodies '
considered
bool
o u t P u t F i l e N a m e ,BODY
prt_spd ,
bool
bodySeparator ) ;
data
to
being
an
a
. txt
file
( ASCII
character )
:
PARAMETERS
:
FILE ∗
outPutFile
Pointer
on
output
bodyArray
Pointer
on
the
file ,
EXPECTS OPEN FILE ! ! ! !
BODY∗∗
pointers
∗
∗
∗
∗
∗
55 ∗
56
57
58
59
60
61
62
:
bodyArray ,
prt_mass ,
49 ∗
50
51
52
53
54
Thibault Wildi - 3M8
on
the
array
of
bodies
bool
prt_time
Print
bool
prt_pos
Print
position ?
bool
prt_spd
Print
Speed ?
bool
prt_mass
Print
char
dataSeparator
Char
that
will
be
used
BodySeparator
Char
that
will
be
used
to
separate
values
to
separate
Bodies
char
time ?
Mass ?
∗
∗ OUTPUTS :
∗
RETURN :
∗
none
∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
IO_printBodyData_TXT ( FILE ∗ o u t P u t F i l e ,BODY∗ b o d y A r r a y ,
bool
void
prt_time ,
char
bool
prt_pos ,
dataSeparator ,
bool
prt_spd ,
bool
char
prt_mass ,
bodySeparator ) ;
63
64 / ∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
65 ∗ NAME :
v o i d IO_printBodyData_CONSOLE (BODY∗ b o d y A r r a y ,
bool
prt_time ,
66
67
68
69
70
71
72
73
74
75
76
∗
∗
∗
∗
∗
∗
DESCRIPTION
INPUTS
prt_pos ,
char
:
prt_spd ,
bool
pr t _ m a s s ,
char
the
bodies '
data
out
on
console
:
:
BODY∗∗
pointers
∗
∗
∗
∗
∗
bool
bodySeparator ) ;
Prints
PARAMETERS
77 ∗
78
79
80
81
82
83
84
bool
dataSeparator ,
on
the
bodyArray
Pointer
on
the
array
of
bodies
bool
prt_time
Print
bool
prt_pos
Print
position ?
bool
prt_spd
Print
Speed ?
bool
prt_mass
Print
char
dataSeparator
Char
that
will
be
used
BodySeparator
Char
that
will
be
used
to
separate
values
to
separate
Bodies
char
time ?
Mass ?
∗
∗ OUTPUTS :
∗
RETURN :
∗
none
∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
IO_printBodyData_CONSOLE (BODY∗ b o d y A r r a y ,
b o o l prt_time ,
bool
void
prt_pos ,
bool
prt_spd ,
bool
prt_mass ,
bodySeparator ) ;
char
dataSeparator ,
char
85
86 / ∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
87 ∗ NAME :
v o i d IO_printBodyData_BIN ( FILE ∗ o u t P u t F i l e ,BODY∗
bodyArray ,
88
89 ∗
90 ∗
prt_spd ,
DESCRIPTION
printed
bool
bool
as
prt_time ,
bool
prt_energy ,
bool
prt_pos ,
bool
prt_mass ) ;
:
Prints
true
the
bodies '
numbers )
51
data
to
an
. bin
file
( number
are
Simulation n corps
91
92
93
94
∗
∗
∗
∗
INPUTS
95 ∗
96 ∗
97
98
99
100
101
102
103
104
105
106
107
108
109
∗
∗
∗
∗
∗
Thibault Wildi - 3M8
:
PARAMETERS
:
FILE ∗
outPutFile
Pointer
on
output
bodyArray
Pointer
on
the
file ,
EXPECTS OPEN FILE ! ! ! !
BODY∗∗
pointers
on
the
IO_DEVICE
outPutDevice
:
array
of
bodies
File ,
outPutDevice
Console
or
Out
defines
the
Both
bool
prt_time
Print
bool
prt_pos
Print
time ?
position ?
bool
prt_spd
Print
Speed ?
bool
prt_mass
Print
Mass ?
bool
prt_energy
Print
System ' s
total
energy ?
∗ OUTPUTS :
∗
RETURN :
∗
none
∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
IO_printBodyData_BIN ( FILE ∗ o u t P u t F i l e ,BODY∗ b o d y A r r a y ,
bool
void
prt_time ,
bool
prt_energy ,
bool
prt_pos ,
bool
prt_spd ,
bool
prt_mass ) ;
#endif
//
IO_OPERATIONS_H_INCLUDED
Code 7.3 io_operations.h
7.2.4 io_operations.c
1 #include
2 #include
3 #include
4 #include
5
6 #include
7 #include
< s t d i o . h>
//
Used
for
I /O
Operations
< s t d l i b . h>
//
Used
for
memory
< s t d b o o l . h>
//
Used
for
Boolean
<math . h>
//
Used
for
rounding
( file
reading / writing
)
/
allocation
processes
( malloc
calloc )
operations
operations
" c o n s t a n t s . h"
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
" i o _ o p e r a t i o n s . h"
BODY∗
IO_inti (
{
FILE
void
∗ inPutFile
double
double
Will
contain
Will
contain
Will
contain
int
)
;
//
pointer
towards
input
file
spd2 ;
//
speed
squared
for
initial
energy
calculation
sep ;
purpose
//
separation
between
two
bodies
for
energy
calculation
purpose
/∗ ∗
d, i , j ;
Reading
inPutFile
Opening
=
input
INPUTFILE
fscanf ( inPutFile
Reading
number
number
the
,
,
"r") ;
mode
//
"r"
&BODY_NB) ;
//
"
DIMENTIONS %i " ,
&DIMENTIONS) ;
//
dimensions
,
gravity
,
Reading
of
time
r e a d −o n l y
" BODY_NB %i " ,
fscanf ( inPutFile
run
∗ ∗/
bodies
of
fscanf ( inPutFile
Reading
in
of
fscanf ( inPutFile
Reading
file
f o p e n (INPUTFILE_NAME,
" G_CONST %l e " ,
&G_CONST) ;
//
constant
" RUN_TIME %l e " ,
the
simulation
52
&RUN_TIME) ;
//
Simulation n corps
24
fscanf ( inPutFile
Reading
25
the
,
Reading
the
,
27
the
,
use
28
29
30
31
32
the
/∗ ∗
for
33
( i
=
the
0;
{
//
36
37
for
&PRT_PRCT) ;
to
be
time
step
time
step
//
written
&USE_DYMC_DELTA_T) ;
//
boolean
" DYMC_DELTA_T_ACC %l e " ,
&DYMC_ACCURACY) ;
//
accuracy
initializing
=
of
(d =
array
∗ ∗/
(BODY) ) ;
//
i ++)
//
bodies
0;
Initializes
body
Bodies
< BODY_NB;
the
sizeof
the
c a l l o c (BODY_NB,
array
i
Initializes
34
35
,
and
∗ bodyArray
Creating
//
0.01;
Creating
BODY
points
dynamic
dynamic
∗=
PRT_PRCT
of
" USE_DYMC_DELTA_T %i " ,
of
fscanf ( inPutFile
Reading
&MAX_DELTA_T) ;
" PRT_PRCT %l e " ,
percentage
fscanf ( inPutFile
Reading
" DELTA_T %l e " ,
DELTA_T
fscanf ( inPutFile
26
d < DIMENTIONS ;
d++)
positions
{
fscanf ( inPutFile
//
38
39
40
Copies
read
,
"%l e
position
|
" ,
value
to
&b o d y A r r a y [ i ] . p o s [ d ] ) ;
body
}
//
41
42
for
(d =
0;
Initializes
d < DIMENTIONS ;
d++)
speed
{
fscanf ( inPutFile
//
43
44
Copies
read
,
speed
"%l e
|
value
" ,
to
&b o d y A r r a y [ i ] . s p d [ d ] ) ;
body
}
fscanf ( inPutFile
//
45
46
47
48
49
50
51
52
53
Initializes
,
"%l e
|
" ,
&b o d y A r r a y [ i ] . m ass ) ;
mass
}
/∗ ∗
Calculating
initial
THEORETICAL_ENERGY =
for
( i
= 0
;
total
energy
∗ ∗/
0;
i <BODY_NB
;
i ++)
{
for
spd2
=
0;
( d =0;
Calculating
54
55
56
57
58
59
d<DIMENTIONS ;
kinetic
d++)
//
energy
{
s p d 2 += pow ( b o d y A r r a y [ i ] . s p d [ d ] , 2 ) ;
}
THEORETICAL_ENERGY +=
for
( j=i +1;
Calculating
60
61
62
j <BODY_NB;
potential
∗
0.5
b o d y A r r a y [ i ] . mass
∗
spd2 ;
j ++)
//
energy
{
for
sep
Calculate
63
64
65
66
67
68
69
70
71
72
73
74
75
Thibault Wildi - 3M8
=
0;
( d =0;
d<DIMENTIONS ;
separation
d++)
//
distance
{
sep
+= pow ( b o d y A r r a y [ i ] . p o s [ d ]
−
bodyArray [ j ] . pos [ d ] , 2 ) ;
}
sep
=
s q r t ( sep ) ;
THEORETICAL_ENERGY
b o d y A r r a y [ j ] . mass
/
−=
G_CONST
∗
b o d y A r r a y [ i ] . mass
∗
sep ;
}
}
f c l o s e ( inPutFile ) ;
}
void
return
bodyArray ;
IO_printBodyData_TXT (
prt_time ,
bool
prt_pos ,
FILE ∗
bool
o u t P u t F i l e ,BODY∗
prt_spd ,
53
bool
char
bodyArray ,
prt_mass ,
bool
Simulation n corps
76
77
78
79
bodySeparator )
i ,d;
( prt_time
==
true )
//
Print
time
if
needed
followed
by
separator
{
f p r i n t f ( outPutFile , "
%.5 e %c%c " ,
TIME ,
dataSeparator ,
bodySeparator ) ;
}
for
( i
=
if
{
0;
i <BODY_NB;
( p r t _ p o s ==
for
{
(d =
0;
i ++)
//
true )
d<DIMENTIONS ;
For
every
body
:
//
Print
position
if
needed
d++)
{
f p r i n t f ( outPutFile , "
%.5 e %c " ,
bodyArray [ i ] . pos [ d ] ,
dataSeparator ) ;
91
92
93
94
95
96
97
}
if
}
( p r t _ s p d ==
for
{
(d =
0;
true )
//
d<DIMENTIONS ;
Print
speed
if
needed
d++)
{
f p r i n t f ( outPutFile , "
%.5 e %c " ,
bodyArray [ i ] . spd [ d ] ,
dataSeparator ) ;
98
99
100
101
102
}
if
}
( p r t _ m a s s ==
true )
//
Print
time
if
needed
{
f p r i n t f ( outPutFile , "
%.5 e %c " ,
b o d y A r r a y [ i ] . mass ,
dataSeparator ) ;
103
104
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
static int
if
body
82
83
84
85
86
87
88
89
90
111
112
113
char
dataSeparator ,
{
80
81
105
106
107
108
109
110
Thibault Wildi - 3M8
}
f p r i n t f ( o u t P u t F i l e , "%c " , b o d y S e p a r a t o r ) ;
separator
//
Print
body
char
}
f p r i n t f ( o u t P u t F i l e , " \n" ) ;
//
Print
NewLine
at
EOF
}
void
IO_printBodyData_CONSOLE (BODY∗
prt_pos ,
bool
prt_spd ,
bool
bodySeparator )
{
static int
if
bool
prt_time ,
dataSeparator ,
char
bool
i ,d;
( prt_time
body
char
bodyArray ,
prt_mass ,
==
true )
//
Print
time
if
needed
followed
by
separator
{
printf ("
%.5 e %c%c " ,
TIME ,
dataSeparator ,
bodySeparator ) ;
}
for
{
(
i
if
{
=
0;
i <BODY_NB;
( p r t _ p o s ==
for
(
d =
i ++)
//
true )
0;
d<DIMENTIONS ;
For
every
body
:
//
Print
position
if
needed
d++)
{
printf ("
%.5 e %c " ,
bodyArray [ i ] . pos [ d ] ,
dataSeparator ) ;
}
if
}
{
( p r t _ s p d ==
for
(
d =
true )
0;
//
d<DIMENTIONS ;
Print
speed
if
needed
d++)
{
printf ("
%.5 e %c " ,
bodyArray [ i ] . spd [ d ] ,
}
}
54
dataSeparator ) ;
Simulation n corps
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
if
( p r t _ m a s s ==
true )
//
Print
time
if
needed
{
printf ("
%.5 e %c " ,
b o d y A r r a y [ i ] . mass ,
dataSeparator ) ;
}
p r i n t f ( "%c " , b o d y S e p a r a t o r ) ;
//
Print
body
separator
char
}
p r i n t f ( " \n" ) ;
//
Print
NewLine
at
EOF
}
void
FILE ∗
IO_printBodyData_BIN (
prt_time ,
bool
prt_energy ,
o u t P u t F i l e ,BODY∗
bool
bodyArray ,
prt_pos ,
bool
prt_spd ,
//
time
if
bool
bool
prt_mass )
{
static int
if
i ;
( prt_time
==
true )
{
f w r i t e (&TIME ,
}
if
( prt_energy
sizeof double
==
(
Print
requested
) ,1 , outPutFile ) ;
true )
//
Print
system ' s
total
energy
if
requested
152
153
154
155
156
157
158
159
160
{
f w r i t e (&SYSTEM_ENERGY,
}
for
( i
= 0
if
{
;
i <BODY_NB
( p r t _ p o s ==
;
sizeof double
(
i ++)
//
true )
{
f w r i t e (& b o d y A r r a y [ i ] . p o s ,
outPutFile ) ;
161
162
163
164
165
166
167
168
169
170
171
Thibault Wildi - 3M8
if
) ,1 , outPutFile ) ;
For
every
body
//
Print
position
sizeof double
(
) ,
:
if
requested
DIMENTIONS ,
}
( p r t _ s p d ==
true )
//
{
f w r i t e (& b o d y A r r a y [ i ] . s p d ,
outPutFile ) ;
if
Print
speed
sizeof double
(
) ,
if
requested
DIMENTIONS ,
}
( p r t _ m a s s ==
true )
//
{
f w r i t e (& b o d y A r r a y [ i ] . mass ,
}
Print
time
sizeof double
(
) ,
if
1,
requested
outPutFile ) ;
}
}
Code 7.4 io_operations.c
7.2.5 iterator.h
1 #ifndef
2 #define
ITERATOR_H_INCLUDED
ITERATOR_H_INCLUDED
3
4 / ∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
5 ∗ NAME :
v o i d c a l c u l a t e N e x t S t e p (BODY∗ b o d y A r r a y )
6 ∗
7 ∗ DESCRIPTION :
C a l c u l a t e s the next p o s i t i o n
o f e v e r y body o f
bodyArray
8
9
10
11
∗
∗
∗
∗
12 ∗
13 ∗
14 ∗
calculates
INPUTS
with
interaction
system ' s
total
all
the
bodies
of
bodyArray
+
:
PARAMETERS
:
BODY∗
of
of
energy
pointers
OUTPUTS
on
the
bodyArray
Pointer
bodies
:
RETURN
:
none
55
on
the
array
Simulation n corps
Thibault Wildi - 3M8
15 ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
16
c a l c u l a t e N e x t S t e p (BODY∗ b o d y A r r a y ) ;
17
18
/ / ITERATOR_H_INCLUDED
void
#endif
Code 7.5 iterator.h
7.2.6 iterator.c
1 #include
2
3 #include
4
5 void
6
7
double
8
double
9
double
10
static double
11
static double
12
static double
13
static double
14
static int
15
16
if
<math . h>
//
Use
for
math
function
( like
" pow ( x , y ) " )
" c o n s t a n t s . h"
c a l c u l a t e N e x t S t e p (BODY∗
bodyArray )
{
a c c [ DIMENTIONS ] ;
( or
//
Will
contain
the
acceleration
f r c [ DIMENTIONS ] ;
//
Will
contain
the
forces
d i s [ DIMENTIONS ] ;
//
Will
contain
distances
//
Will
contain
the
distance
//
Will
contain
the
squared
force
between
per
unit
object
on
of
mass )
each
coordinate
sep ;
between
to
bodies
( separation )
spd2 ;
speed
of
object
for
system
energy
calculation
nextSystemEnregy ;
//
Will
hold
the
energy
of
the
energyDerivative ;
//
Will
hold
the
calculated
calculated
energy
derivative
i , j ,d;
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
( STEP ==
DELTA_T = MAX_DELTA_T;
}
/∗ ∗
for
Calculating
next
nextSystemEnregy
(
i =0;
every
=
position
i <BODY_NB;
i ++)
calculate
next
body
for
every
body
∗ ∗/
0;
//
For
position
{
for
spd2
frc
to
=
(
0;
d =0;
d<DIMENTIONS ;
d++)
//
Set
0
{
f r c [ d]=0;
s p d 2 += pow ( b o d y A r r a y [ i ] . s p d [ d ] , 2 ) ;
Calculating
total
speed
nextSystemEnregy
//
Calculating
for
every
{
//
(
j
= 0
body
if
Except
+=
kinetic
;
//
squared
}
0.5
∗
b o d y A r r a y [ i ] . mass
∗
spd2 ;
energy
j <BODY_NB
;
j ++)
//
For
o
( j
!=
body
i )
b
{
sep
//
38
39
40
41
42
0)
{
//
Reset
for
=
0;
separation
Calculate
(
d =0;
distance
between
d<DIMENTIONS ;
separation
b
and
dis [d]
=
to
0
distances
{
sep
o
d++)
bodyArray [ j ] . pos [ d ]
+= pow ( d i s [ d ] , 2 ) ;
}
56
−
bodyArray [ i ] . pos [ d ] ;
Simulation n corps
43
44
45
sep
//
59
60
61
62
63
64
65
66
67
68
69
70
for
For
every
(
s q r t ( sep ) ;
d =0;
frc [d]
∗
] . mass
dis [d]
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
calculate
d++)
force
that
body
o
applies
to
body
+= G_CONST
∗
b o d y A r r a y [ j ] . mass
∗
bodyArray [ i
/ pow ( s e p , 3 ) ;
}
if
//
(
j
>
Calculating
i
)
potential
energy
{
nextSystemEnregy
b o d y A r r a y [ i ] . mass
/
−=
∗
G_CONST
b o d y A r r a y [ j ] . mass
∗
sep ;
}
}
}
for
every
(
d =0;
d<DIMENTIONS ;
dimension
calculate
d++)
acceleration
object
//
For
//
For
b
{
acc [ d ]
=
frc [d]
/
b o d y A r r a y [ i ] . mass ;
}
for
every
(
d =0;
d<DIMENTIONS ;
dimension
calculate
d++)
next
speed
of
object
b
{
bodyArray [ i ] . next_spd [ d ]
=
bodyArray [ i ] . spd [ d ]
+ DELTA_T
∗
acc [ d ] ;
}
for
every
(
d =0;
d<DIMENTIONS ;
dimension
calculate
d++)
next
//
position
of
object
For
b
{
bodyArray [ i ] . next_pos [ d ]
bodyArray [ i ] . spd [ d ]
71
72
73
74
75
76
77
d<DIMENTIONS ;
dimension
{
51
52
53
54
55
56
57
58
=
b
46
47
48
49
50
Thibault Wildi - 3M8
spd
and
+
=
bodyArray [ i ] . pos [ d ]
bodyArray [ i ] . next_spd [ d ] ) /2
;
//
+ DELTA_T
∗
Averaging
next_spd
}
}
/∗ ∗
if
Calculating
new
time
( (USE_DYMC_DELTA_T ==
step
true )
if
dynamic
time
&&
( STEP >
0) )
step
enabled
∗ ∗/
{
//
Calculating
energy
variation
speed
( derivative )
step
energyDerivative
=
f a b s ( ( ( nextSystemEnregy
−
during
last
SYSTEM_ENERGY) /
DELTA_T) /THEORETICAL_ENERGY) ;
step
if
( energyDerivative
is
to
be
{
DELTA_T
else if
> DYMC_ACCURACY)
∗=
is
to
( energyDerivative
be
If
time
//
If
time
0.7;
}
step
//
reduced
<
(DYMC_ACCURACY
∗0.7) )
grown
{
DELTA_T
∗=
1.1;
}
big
if
(DELTA_T > MAX_DELTA_T)
//
If
time
step
too
//
If
time
step
too
{
DELTA_T = MAX_DELTA_T;
else if
}
(
DELTA_T <
(MAX_DELTA_T/ 5 0 0 0 0 ) )
small
57
(
Simulation n corps
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
Thibault Wildi - 3M8
{
DELTA_T = MAX_DELTA_T/ 5 0 0 0 0 ;
}
}
/∗ ∗
for
Flushing
the
(
i
= 0
for
{
(
;
d =0;
∗ ∗/
data
SYSTEM_ENERGY =
nextSystemEnregy ;
i <BODY_NB
;
i ++)
d<DIMENTIONS ;
d++)
{
bodyArray [ i ] . pos [ d ]
=
bodyArray [ i ] . next_pos [ d ] ;
bodyArray [ i ] . spd [ d ]
=
bodyArray [ i ] . next_spd [ d ] ;
}
}
TIME += DELTA_T ;
//
Flush
time
}
Code 7.6 iterator.c
7.2.7 display2d.h
1 #ifndef
2 #define
3
4 #include
5 #include
DISPLAY_H_INCLUDED
DISPLAY_H_INCLUDED
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<SDL/SDL . h>
//
Used
for
graphical
<SDL/ SDL_ttf . h>
//
Used
for
text
with
interface
SDL
/ ∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗
∗
∗
∗
∗
∗
∗
∗
∗
∗
∗
∗
NAME
:
display2D ( char ∗
void
DESCRIPTION
:
Displays
objects
dataFileName_BIN ) ;
trajectory
on
screen
( 2D
only )
:
INPUTS
PARAMETERS
file
to
OUTPUTS
read
:
char ∗
dataFileName
body
information ,
for
Contains
EXPECTS
. bin
name
of
FILES ! ! ! !
:
RETURN
:
None
NOTES
:
Expects
. bin
BDY_1_Y BDY_2_X BDY_2_Y
. . .
FILE ,
with
format :
TIME ENERGY BDY_1_X
TIME ENERGY BDY_1_X BDY_1_Y . . .
20 ∗
21 ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
22
display2D (
∗ dataFileName_BIN ) ;
23
24 / ∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
25 ∗ NAME :
v o i d p r i n t D a t a O n S c r e e n _ S t a t i c ( FILE ∗ d a t a F i l e _ B I N ,
double const s c a l e ,
d o u b l e c o n s t ∗ f o c u s C e n t e r , SDL_Surface ∗ s c r e e n
int
s c r e e n P r e c i s i o n , TTF_Font ∗ f o n t ) ;
S D L _ S u r f a c e ∗ bodyIMG ,
26 ∗
27 ∗ DESCRIPTION :
P r i n t s bodyIMG on s c r e e n a t e a c h p o s i t i o n r e d i n
void
28
29
30
31
∗
∗
∗
∗
32 ∗
33 ∗
char
,
datafile
INPUTS
:
PARAMETERS
:
FILE
∗ dataFile_BIN
DataFile ,
EXPECTS OPEN BIN
FILE ! ! ! ! ! !
double
scale
double
∗ focusCenter
meters
containing
center
of
screen
Printing
coordinates
58
double
( in
scale
array
meters )
of
in
pixel
size
2
per
Simulation n corps
Thibault Wildi - 3M8
34 ∗
SDL_Surface
positions
35 ∗
be
to
be
image
printed
position
of
index
only
1/5
of
the
used
on
N
SDL_surface
on
∗ bodyIMG
SDL_surface
containing
screenPrecision
∗
Will
screenPrecision
points
will
TTF_font
OUTPUTS
∗ screen
witch
the
the
printed
int
37 ∗
∗
∗
∗
∗
∗
to
SDL_Surface
body
36 ∗
38
39
40
41
42
are
be
( ex :
printed
be
printed
only
screenPrecision
= 5
−>
)
font
Font
pointer
that
will
be
writing
:
RETURN
:
None
NOTES
:
Expects
. . bin
BDY_1_Y BDY_2_X BDY_2_Y
. . .
FILE ,
with
format :
TIME ENERGY BDY_1_X
TIME ENERGY BDY_1_X BDY_1_Y . . .
43 ∗
44 ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
45
p r i n t D a t a O n S c r e e n _ S t a t i c ( FILE ∗ d a t a F i l e _ B I N ,
scale ,
∗ f o c u s C e n t e r , S D L _ S u r f a c e ∗ s c r e e n , S D L _ S u r f a c e ∗∗
bodyIMG ,
s c r e e n P r e c i s i o n , TTF_Font ∗ f o n t ) ;
46
47 / ∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
48 ∗ NAME :
v o i d p r i n t D a t a O n S c r e e n _ D y n a m i c ( FILE ∗ d a t a F i l e _ B I N ,
double const s c a l e ,
d o u b l e c o n s t ∗ f o c u s C e n t e r , SDL_Surface ∗ s c r e e n
S D L _ S u r f a c e ∗ bodyIMG , i n t
s c r e e n P r e c i s i o n , TTF_Font ∗ f o n t ) ;
49 ∗
P r i n t s bodyIMG an a n i m a t i o n o f t h e b o d i e s m o v i n g
50 ∗ DESCRIPTION :
51 ∗
52 ∗ INPUTS :
53 ∗
PARAMETERS :
54 ∗
FILE ∗ d a t a F i l e _ B I N
D a t a F i l e , EXPECTS OPEN BIN
void
double
scale
double
∗ focusCenter
meters
56 ∗
57 ∗
containing
center
canvas
text
of
screen
SDL_Surface
58 ∗
and
are
to
be
are
to
be
60 ∗
image
to
be
position
of
index
only
1/5
of
the
used
on
N
array
of
pixel
size
per
2
meters )
SDL_surface
on
witch
the
∗ canvas
SDL_surface
on
witch
the
∗ bodyIMG
SDL_surface
containing
the
∗
Will
screenPrecision
points
will
be
printed
( ex :
be
printed
only
screenPrecision
= 5
−>
)
font
Font
pointer
that
will
be
writing
bool
activated
OUTPUTS
∗ screen
screenPrecision
TTF_font
62 ∗
( in
in
printed
int
61 ∗
double
coordinates
scale
printed
SDL_Surface
body
Printing
printed
SDL_Surface
trajectories
59 ∗
∗
∗
∗
∗
∗
,
FILE ! ! ! ! ! !
55 ∗
63
64
65
66
67
double const
double const
int
or
printTrajectories
If
trajectories
display
is
not
:
RETURN
:
None
NOTES
:
Expects
. . bin
BDY_1_Y BDY_2_X BDY_2_Y
. . .
FILE ,
with
format :
TIME ENERGY BDY_1_X
TIME ENERGY BDY_1_X BDY_1_Y . . .
68 ∗
69 ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
70
p r i n t D a t a O n S c r e e n _ D y n a m i c ( FILE ∗ d a t a F i l e _ B I N ,
scale ,
∗ f o c u s C e n t e r , SDL_Surface ∗ s c r e e n , SDL_Surface ∗ c a n v a s
, S D L _ S u r f a c e ∗∗ bodyIMG ,
s c r e e n P r e c i s i o n , TTF_Font ∗ f o n t , b o o l
void
double const
printTrajectories ) ;
double const
int
71
72 / ∗ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
73 ∗ NAME :
v o i d p r i n t A x i s O n S c r e e n ( SDL_Surface ∗ s c r e e n ,
SDL_Surface ∗ a x i s X , SDL_Surface ∗ a x i s Y ) ;
74 ∗
75 ∗ DESCRIPTION :
Prints
a x i s on s c r e e n
76 ∗
59
Simulation n corps
77 ∗
78 ∗
79 ∗
INPUTS
:
SDL_Surface
axis
are
to
be
printed
axis
image
to
be
axis
image
to
be
axis
Scale
bars
axis
Scale
bars
SDL_Surface
81 ∗
printed
SDL_Surface
82 ∗
printed
SDL_Surface
83 ∗
to
be
to
be
85 ∗
on
on
∗ axisX
SDL_surface
containing
the
X
∗ axisY
SDL_surface
containing
the
Y
∗ scaleBarX
SDL_surface
containing
the
X
SDL_surface
containing
the
Y
witch
the
∗ scaleBarY
font
Font
pointer
that
will
be
writing
double
scale
double
∗ focusCenter
meters
86 ∗
SDL_surface
printed
TTF_font
used
∗ screen
printed
SDL_Surface
84 ∗
93
94
:
PARAMETERS
80 ∗
87
88
89
90
91
92
Thibault Wildi - 3M8
containing
center
of
screen
Printing
double
coordinates
( in
scale
array
in
of
pixel
size
per
2
meters )
∗ OUTPUTS :
∗
RETURN :
∗
None
∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ ∗ /
p r i n t A x i s O n S c r e e n ( SDL_Surface ∗ s c r e e n , SDL_Surface ∗ a x i s X ,
SDL_Surface ∗ a x i s Y ,
SDL_Surface ∗ s c a l e B a r X , SDL_Surface ∗ s c a l e B a r Y
, TTF_Font ∗ f o n t ,
scale ,
∗ focusCenter ) ;
void
#endif
double const
//
double const
DISPLAY_H_INCLUDED
Code 7.7 display2d.h
7.2.8 display2d.c
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 #include
8 #include
9
10 void
char ∗
< s t d i o . h>
//
Used
for
I /O
Operations
//
Used
for
mathematical
<SDL/SDL . h>
//
Used
for
graphical
< s t d b o o l . h>
//
Used
for
Boolean
<SDL/ SDL_ttf . h>
//
Used
for
text
( file
reading /
writing )
<math . h>
function
( absolute
function )
interface
operations
with
SDL
" c o n s t a n t s . h"
" d i s p l a y 2 d . h"
11
12
13
14
15
16
17
display2D (
{
/∗ ∗
enum
double
double
double
double
Setting
19
20
up
{STATIC ,
viewing
bodies
mode
bodies
on
∗ ∗/
variables
DYNAMIC}
viewingMode
= STATIC ;
true
position
in
Will
contain
//
Contains
//
Contains
meters
centerPosition [ 2 ] ;
of
the
focus
max_X =
0,
maximum
positions
point
min_X =
0,
in
the
max_Y =
middle
0,
of
min_Y =
meterToPixelRatio ;
to
//
type
bodyPosition [ 2 ] ;
coordinates
ratio
18
dataFileName_BIN )
convert
the
position
in
meters
to
the
the
screen
0;
//
Contains
//
Contains
position
in
the
the
pixels
screen
bool
pause
bool
print
bool
print
pause
=
value
false ;
for
printAxis
axis
=
dynamic
viewing
//
Contains
//
Contains
//
Contains
mode
true ;
value
printTrajectories
trajectories
for
=
false ;
dynamic
viewing
60
mode
the
Simulation n corps
21
int
screenPrecision ;
precision :
22
23
24
25
26
27
28
29
30
31
32
33
Will
(−>
precision
FILE ∗
window
SDL_Surface
grid
on
body
surface
SDL_Surface
axis
bar
SDL_Event
receive
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
only
every
1/10
step
= 10%
Will
of
pixel
= NULL ;
be
draw
our
bodies
on
dynamic
hold
N∗
index
is
printed )
//
Pointer
//
Will
be
our
//
Will
be
the
//
Will
be
our
//
Will
be
our
//
Will
be
our
//
Used
to
//
Used
for
mode
bodyImg [ 1 0 ] ;
for
the
∗ axisX
printing
the
∗ axisY
= NULL,
trajectories
= NULL ;
∗ scaleBarY
= NULL,
= NULL ;
event ;
or
TTF_Font
events
∗ font
= NULL ;
fonts
o;
/∗ ∗
Setting
SD L_I nit (
up
some
SDL
|
SDL_INIT_TIMER
Initializing
SDL
//
Initializing
SDL_ttf
Loading
= SDL_SetVideoMode (
Creating
//
canvas
axisX
0,
0,
0) ;
//
axisY
//
//
scaleBarX
SDL_FillRect ( canvas ,
SDL_FillRect ( axisX ,
1,
body
//
SDL_FillRect ( axisY ,
//
125) ) ;
125) ) ;
0;
o <
10
;
of
surface
of
1,
to
0,
0,
16 ,
0,
0,
40 ,
40 ,
16 ,
0,
0,
( 1 ; SCREEN_Y)
1,
size
16 ,
0,
0,
( 1 ; SCREEN_Y)
0,
0,
0) ) ;
black
to
gray
axisY
to
gray
125 ,
125 ,
125) )
125 ,
125 ,
125) )
SDL_MapRGB( s c r e e n −>f o r m a t ,
axisY
to
gray
axisY
to
gray
SDL_MapRGB( s c r e e n −>f o r m a t ,
Setting
16 ,
( 1 ; SCREEN_Y)
size
SDL_MapRGB( s c r e e n −>f o r m a t ,
NULL,
//
body
1,
(SCREEN_X ; 1 )
size
(SDL_HWSURFACE,
axisX
Setting
SDL_FillRect ( scaleBarY ,
surface
SCREEN_Y,
(1;1)
SCREEN_Y,
of
SDL_MapRGB( s c r e e n −>f o r m a t ,
NULL,
//
size
(SDL_HWSURFACE,
canvas
Setting
SDL_FillRect ( scaleBarX ,
surface
body
size
SDL_MapRGB( s c r e e n −>f o r m a t ,
Setting
NULL,
;
of
SCREEN_X,
(SDL_HWSURFACE,
Setting
NULL,
;
SCREEN_X,
surface
of
Creating
NULL,
//
) ;
Simulation " ) ;
surface
Creating
//
o =
body
= SDL_CreateRGBSurface
0 ,0) ;
body
(SDL_HWSURFACE,
Creating
//
SDL_HWSURFACE
Caption
(SDL_HWSURFACE,
= SDL_CreateRGBSurface
0 ,0) ;
scaleBarY
up
Creating
= SDL_CreateRGBSurface
0 ,0) ;
16 ,
screen
Creating
= SDL_CreateRGBSurface
0 ,0) ;
font
SCREEN_Y,
S i m u l a t i o n " , "N Body
Setting
= SDL_CreateRGBSurface
0,
" Consolas "
SCREEN_X,
SDL_WM_SetCaption ( "N Body
(
SDL_INIT_EVENTTHREAD) ;
= TTF_OpenFont ( " c o n s o l a . t t f " , 2 5 ) ;
//
for
|
//
//
16 ,
∗ ∗/
stuff
SDL_INIT_VIDEO
screen
42
10 ,
only
surfaces
36
41
∗ canvas
∗ scaleBarX
SDL_Surface
font
40
=
screen
surfaces
35
39
precision
= NULL ;
witch
TTF_Init ( ) ;
38
on
∗ screen
SDL_Surface ∗
int
if
//
printed
dataFile
SDL_Surface
axis
be
dataFile ;
toward
34
37
Thibault Wildi - 3M8
125 ,
125 ,
125 ,
125 ,
o++)
{
bodyImg [ o ]
0,
0) ;
= SDL_CreateRGBSurface (SDL_HWSURFACE,
//
Creating
body
surface
of
size
3,
3,
16 ,
0,
0,
(1;1)
}
S D L _ F i l l R e c t ( bodyImg [ 0 ] ,
255) ) ;
//
S D L _ F i l l R e c t ( bodyImg [ 1 ] ,
) ;
//
//
//
NULL,
NULL,
Green
S D L _ F i l l R e c t ( bodyImg [ 3 ] ,
) ;
Light
Red
S D L _ F i l l R e c t ( bodyImg [ 2 ] ,
) ;
NULL,
NULL,
SDL_MapRGB( s c r e e n −>f o r m a t ,
0,
255 ,
Blue
SDL_MapRGB( s c r e e n −>f o r m a t ,
255 ,
SDL_MapRGB( s c r e e n −>f o r m a t ,
SDL_MapRGB( s c r e e n −>f o r m a t ,
Blue
61
0,
0)
0,
255 ,
0)
0,
0,
255)
Simulation n corps
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
S D L _ F i l l R e c t ( bodyImg [ 4 ] ,
0) ) ;
0) ) ;
102
103
104
105
106
107
108
109
110
111
NULL,
Orange
//
NULL,
Yellow
S D L _ F i l l R e c t ( bodyImg [ 6 ] ,
0) ) ;
//
NULL,
Light
S D L _ F i l l R e c t ( bodyImg [ 7 ] ,
255) ) ;
255) ) ;
Starting
dataFile
in
bin
/∗ ∗
int
while
the
=
to
read
read
255 ,
255 ,
SDL_MapRGB( s c r e e n −>f o r m a t ,
128 ,
255 ,
128 ,
0,
Pink
SDL_MapRGB( s c r e e n −>f o r m a t ,
255 ,
0,
NULL,
SDL_MapRGB( s c r e e n −>f o r m a t ,
0,
//
dark
Pink
the
data
file
up
0;
=
(0
==
end
to
the
∗ ∗/
" rb " ) ;
//
scale ,
focus
center ,
and
screen
feof ( dataFile ) )
check
for
Opening
data
0;
(
o < BODY_NB;
precision
∗ ∗/
Read
until
file
o++
∗2 ,
)
SEEK_CUR) ;
)
//
Skip
//
for
body
{
f r e a d (& b o d y P o s i t i o n [ 0 ]
if
//
Set
up
the
maximum
( bodyPosition [0] >
,
sizeof double
(
and
minimum
) ,
2,
dataFile ) ;
values
max_X)
{
max_X =
if
bodyPosition [ 0 ] ;
}
( bodyPosition [0] <
min_X )
{
min_X =
if
bodyPosition [ 0 ] ;
}
( bodyPosition [1] >
max_Y)
{
max_Y =
if
bodyPosition [ 1 ] ;
}
( bodyPosition [1] <
min_Y )
{
min_Y =
bodyPosition [ 1 ] ;
}
}
s t e p s ++;
if
}
(
SCREEN_Y /
Checking
most
(max_Y
what
little
−
scale
min_Y ) <=
to
use
in
SCREEN_X /
function
meterToPixelRatio
Add
(max_X
of
screen
−
min_X ) )
ratio
( uses
scale )
{
//
a
10%
=
(SCREEN_Y /
(max_Y
−
min_Y ) )
∗
0.9;
(SCREEN_X /
(max_X
−
min_X ) )
∗
0.9;
margin
else
}
{
meterToPixelRatio
//
Add
a
10%
=
margin
}
/∗ ∗
Setting
file
coordinates
sizeof double
dataFile ,
energy
(o =
//
largest
{
fseek (
255 ,
mode
steps
for
SDL_MapRGB( s c r e e n −>f o r m a t ,
f o p e n ( dataFileName_BIN ,
Setting
and
128 ,
SDL_MapRGB( s c r e e n −>f o r m a t ,
NULL,
S D L _ F i l l R e c t ( bodyImg [ 9 ] ,
/∗ ∗
255 ,
Purple
//
128) ) ;
SDL_MapRGB( s c r e e n −>f o r m a t ,
Green
NULL,
//
S D L _ F i l l R e c t ( bodyImg [ 8 ] ,
//
100
101
//
S D L _ F i l l R e c t ( bodyImg [ 5 ] ,
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
Thibault Wildi - 3M8
center
point
on
screen
∗ ∗/
centerPosition [0]
=
(max_X + min_X ) / 2 ;
centerPosition [1]
=
(max_Y + min_Y ) / 2 ;
62
Time
every
Simulation n corps
112
113
114
115
116
117
118
119
120
/∗ ∗
if
Setting
Thibault Wildi - 3M8
percentage
screenPrecision
=
of
poins
∗
c e i l (( steps
( screenPrecision
==
to
125
126
127
128
0)
screenPrecision
=1;
/∗ ∗
Handling
∗ ∗/
events
SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY,
//
Enabling
key
board
while
( true )
{
SDL_FillRect ( s c r e e n ,
//
if
//
Setting
screen
NULL,
to
SDL_MapRGB( s c r e e n −>f o r m a t ,
137
138
139
140
0,
0,
( v i e w i n g M o d e == STATIC )
If
in
if
{
static
mode
( printAxis
//
Printing
:
==
true )
axis
{
p r i n t A x i s O n S c r e e n ( s c r e e n , axisX , axisY , scaleBarX , scaleBarY
, font , meterToPixelRatio , c e n t e r P o s i t i o n ) ;
}
printDataOnScreen_Static ( dataFile , meterToPixelRatio ,
Prints
trajectories
bodies
on
screenPrecision , font ) ;
//
screen
SDL_Flip ( s c r e e n ) ;
Update
screen
SDL_WaitEvent(& e v e n t ) ;
else if
}
//
If
if
{
( v i e w i n g M o d e == DYNAMIC)
in
dynamic
( pause
==
mode
:
false )
{
printDataOnScreen_Dynamic ( d a t a F i l e , m e t e r T o P i x e l R a t i o ,
c e n t e r P o s i t i o n , s c r e e n , c a n v a s , bodyImg , s c r e e n P r e c i s i o n , f o n t ,
141
if
printTrajectories ) ;
//
142
143
144
145
//
Print
( printAxis
Printing
==
body
position
on
screen
true )
axis
{
p r i n t A x i s O n S c r e e n ( s c r e e n , axisX , axisY , scaleBarX ,
scaleBarY , font , meterToPixelRatio , c e n t e r P o s i t i o n ) ;
}
SDL_Flip ( s c r e e n ) ;
//
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
0) ) ;
black
//
134
135
136
event
repetition
c e n t e r P o s i t i o n , s c r e e n , bodyImg ,
133
∗ ∗/
/ MAX_PT_ON_SCREEN) ;
}
129
130
131
132
printed
{
SDL_DEFAULT_REPEAT_INTERVAL) ;
121
122
123
124
be
BODY_NB)
Update
screen
}
SDL_PollEvent (& e v e n t ) ;
SDL_Delay ( 3 0 ) ;
}
switch
//
( event . type )
Checking
case
events
{
SDL_QUIT :
{
exit (0) ;
break
case
switch
}
;
SDL_KEYDOWN:
//
Handling
Keyboard
events
( e v e n t . k e y . keysym . sym )
{
63
Simulation n corps
case
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
Thibault Wildi - 3M8
/ ∗∗<
SDLK_KP_PLUS :
Case
of
numpad +
{
meterToPixelRatio
=
meterToPixelRatio
SDL_FillRect ( canvas ,
0,
NULL,
∗
,
∗/
Zoom
1.2;
SDL_MapRGB( c a n v a s −>f o r m a t ,
0,
0) ) ;
break
case
}
;
/ ∗∗<
SDLK_KP_MINUS :
Case
of
numpad
{
meterToPixelRatio
=
meterToPixelRatio
SDL_FillRect ( canvas ,
0,
NULL,
−
∗
un−Zoom ∗ /
0.8;
SDL_MapRGB( c a n v a s −>f o r m a t ,
0,
0) ) ;
break
case
}
;
/ ∗∗<
SDLK_UP :
Case
up
arrow ,
shift
upwards ∗/
{
centerPosition [1]
+=
SDL_FillRect ( canvas ,
0,
(SCREEN_Y /
NULL,
meterToPixelRatio ) /10;
SDL_MapRGB( c a n v a s −>f o r m a t ,
0,
0) ) ;
break
case
}
;
/ ∗∗<
SDLK_DOWN:
∗/
{
centerPosition [1]
−=
SDL_FillRect ( canvas ,
0,
Case
down
(SCREEN_Y /
NULL,
arrow , s h i f t
downwards
meterToPixelRatio ) /10;
SDL_MapRGB( c a n v a s −>f o r m a t ,
0,
0) ) ;
break
case
}
leftwards
∗/
;
/ ∗∗<
SDLK_LEFT :
{
centerPosition [0]
−=
SDL_FillRect ( canvas ,
0,
Case
left
(SCREEN_Y /
NULL,
arrow ,
shift
meterToPixelRatio ) /10;
SDL_MapRGB( c a n v a s −>f o r m a t ,
0,
0) ) ;
break
case
}
;
/ ∗∗<
SDLK_RIGHT :
rightwards
∗/
Case
right
arrow ,
shift
{
centerPosition [0]
+=
SDL_FillRect ( canvas ,
0,
(SCREEN_Y /
NULL,
meterToPixelRatio ) /10;
SDL_MapRGB( c a n v a s −>f o r m a t ,
0,
0) ) ;
break
case
}
printed
∗/
{
;
/ ∗∗<
SDLK_PERIOD :
if
( screenPrecision
>
Case
.
,
raise
Nb
Pts
1)
{
screenPrecision
of
=
floor ( screenPrecision
∗0.9)
;
}
break
case
}
printed
∗/
;
/ ∗∗<
SDLK_COMMA:
Case
,
diminish
{
screenPrecision
break
case
=
ceil ( screenPrecision
∗
Nb
of
Pts
1.1) ;
}
;
SDLK_s :
/ ∗∗<
Case
s
,
viewing
mode
static
Case
d
,
viewing
mode
dynamic
{
viewingMode
break
case
= STATIC ;
}
∗/
;
SDLK_d :
/ ∗∗<
{
64
∗/
Simulation n corps
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
Thibault Wildi - 3M8
viewingMode
= DYNAMIC ;
rewind ( d a t a F i l e ) ;
break
case
}
;
/ ∗∗<
SDLK_e :
Case
e
,
erase
∗/
trajectories
{
SDL_FillRect ( canvas ,
0,
NULL,
SDL_MapRGB( c a n v a s −>f o r m a t ,
0) ) ;
break
case
}
;
/ ∗∗<
SDLK_p :
dynamic
∗/
viewing
if
{
( pause
==
Case
p
,
toggle
pause
for
false )
{
pause
=
true ;
pause
=
false ;
else
}
{
while
}
prevents
key
( event . type
!= SDL_KEYUP)
//
This
loop
repetitions
{
SDL_WaitEvent(& e v e n t ) ;
}
break
case
if
}
;
/ ∗∗<
SDLK_a :
Case
a
,
toggle
axis
∗/
{
( printAxis
==
false )
{
printAxis
=
true ;
printAxis
=
false ;
else
}
{
while
}
prevents
key
( event . type
!= SDL_KEYUP)
//
This
loop
repetitions
{
SDL_WaitEvent(& e v e n t ) ;
}
break
case
if
}
;
SDLK_t :
/ ∗∗<
Case
==
false )
t
,
toggle
trajectory
//
loop
∗/
{
( printTrajectories
{
printTrajectories
=
true ;
printTrajectories
=
false ;
else
}
{
while
}
prevents
key
( event . type
!= SDL_KEYUP)
This
repetitions
{
SDL_WaitEvent(& e v e n t ) ;
}
break
case
}
Instant
;
SDLK_i :
Screen
Shot )
∗/
/ ∗∗<
Case
i
,
save
{
SDL_SaveBMP ( s c r e e n ,OUTPUTIMAGE_BMP) ;
65
actual
view
(
0,
Simulation n corps
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
break
case
}
310
311
312
313
314
315
316
317
;
/ ∗∗<
SDLK_r :
Case
rewind ( d a t a F i l e ) ;
SDL_FillRect ( canvas ,
0,
restart
∗/
dynamic
SDL_MapRGB( c a n v a s −>f o r m a t ,
NULL,
break
case
}
;
/ ∗∗<
SDLK_ESCAPE :
Case
ESC
,
quit
∗/
{
exit (0) ;
break
default
break
}
;
:
;
}
}
}
f c l o s e ( dataFile ) ;
TTF_CloseFont ( f o n t ) ;
TTF_Quit ( ) ;
SDL_Quit ( ) ;
}
void
double const ∗
int
static
static
static double
static double
p r i n t D a t a O n S c r e e n _ S t a t i c ( FILE
bodyIMG ,
{
focusCenter ,
screenPrecision ,
SDL_Rect
//
Will
hold
//
Will
hold
Will
Will
static
static
static
static
static
static
//
//
//
Will
double
int
char
Will
Will
hold
hold
in
pixels
txtPosError ;
position
on
number
position
maximum
scale
and
hold
Text
in
hold
total
our
still
on
screen
(
total
points
or
int
text
∗ txtPoints
number
of
∗ txtSurfError
,
points
colorWhite
=
;
texts
{255 ,
255 ,
255};
o;
up
some
stuff
up
=
screen
∗ ∗/
focusCenter [ 0 ]
boundaries
=
focusCenter [ 1 ]
screenBoundaryMin [ 0 ]
=
focusCenter [ 0 ]
screenBoundaryMin [ 1 ]
=
focusCenter [ 1 ]
322
323
324
325
rewind ( dataFile_BIN ) ;
loadedPtCount
//
showing
color
Setting
Setting
file
point
and
count
+ SCREEN_Y/ ( 2 ∗ s c a l e ) ;
−
−
SCREEN_X/ ( 2 ∗ s c a l e ) ;
SCREEN_Y/ ( 2 ∗ s c a l e ) ;
prints
to
0
points
∗ ∗/
f e o f ( dataFile_BIN ) )
until
the
end
{
fseek (
+ SCREEN_X/ ( 2 ∗ s c a l e ) ;
0;
file
0 ==
Read
=
loaded
Reading
(
screen
center )
on
loaded
screen
SDL_Color
Setting
while
on
meters
coordinates
focus
points
screenBoundaryMax [ 0 ]
/∗ ∗
points
loadedPercentage ;
loaded
SDL_Surface
//
//
of
text [ 3 0 ] ;
Will
//
∗∗
loadedPtCount ;
//
/∗ ∗
scale ,
SDL_Surface
screenBoundaryMax [ 2 ] , screenBoundaryMin [ 2 ] ;
the
on
,
bodyPosition [ 2 ] ;
body
hole
depending
position
txtPosPts ,
printing
hold
double const
bodyPrintPosition ;
body
SDL_Rect
//
∗ dataFile_BIN ,
∗ screen
TTF_Font ∗ f o n t )
SDL_Surface
screenBoundaryMax [ 1 ]
328
,
0) ) ;
318
319
320
321
326
327
r
{
//
309
Thibault Wildi - 3M8
dataFile_BIN ,
screenPrecision
− 1) +2) ,
to
check
for
sizeof double
(
SEEK_CUR) ;
66
)
largest
coordinates
∗ ( (BODY_NB∗ 2+2) ∗ (
//
Jump
to
next
position
0,
Simulation n corps
for
329
330
331
332
333
(o =
Thibault Wildi - 3M8
0;
o < BODY_NB;
o++
//
<
[1]
&&
is
334
335
if
[0]
in
,
bodyPosition [ 1 ]
the
<
body
(
( ( screenBoundaryMin [ 0 ]
screenBoundaryMax [ 0 ] )
every
sizeof double
{
f r e a d (& b o d y P o s i t i o n
)
for
&&
<
) ,
2,
dataFile_BIN ) ;
bodyPosition [ 0 ]
screenBoundaryMax [ 1 ] ) )
//
bodyPrintPosition . x =
printing
∗
scale )
bodyPrintPosition . y =
∗
round ( (
scale )
//
Setting
338
339
340
341
342
343
344
345
346
0,
screen ,
367
368
369
370
371
372
373
//
&
Printing
body
screen
l o a d e d P t C o u n t ++;
}
∗=
loadedPtCount
BODY_NB;
loadedPercentage
/∗ ∗
Prints
=
100
/
(
double
) screenPrecision ;
∗ ∗/
text
s p r i n t f ( t e x t , " Loaded
PTs :
%d / % . 2 f%%" ,
loadedPtCount , l o a d e d P e r c e n t a g e
) ;
txtPoints
= TTF_RenderText_Blended ( f o n t , t e x t , c o l o r W h i t e ) ;
s p r i n t f ( text , " Error :
%.6 f%%" , (THEORETICAL_ENERGY
THEORETICAL_ENERGY
100) ;
txtSurfError
∗
−
SYSTEM_ENERGY) /
= TTF_RenderText_Blended ( f o n t , t e x t , c o l o r W h i t e ) ;
txtPosPts . y =
10;
txtPosPts . x =
10;
txtPosError . y =
10;
−
t x t P o s E r r o r . x = SCREEN_X
t x t S u r f E r r o r −>w
−
10;
S D L _ B l i t S u r f a c e ( t x t P o i n t s , 0 , s c r e e n ,& t x t P o s P t s ) ;
S D L _ B l i t S u r f a c e ( t x t S u r f E r r o r , 0 , s c r e e n ,& t x t P o s E r r o r ) ;
}
void
double const
∗ focusCenter
S D L _ S u r f a c e ∗∗ bodyIMG ,
int
printTrajectories )
{
∗ dataFile_BIN ,
∗ screen
p r i n t D a t a O n S c r e e n _ D y n a m i c ( FILE
static
static
static double
static double
SDL_Rect
//
Will
hold
//
Will
hold
Will
hole
static double
static char
static
static
static int
depending
//
Will
on
hold
,
SDL_Surface
screenPrecision ,
,
double const
scale ,
∗ canvas
SDL_Surface
∗ font
TTF_Font
, bool
bodyPrintPosition ;
body
SDL_Rect
//
366
−
}
,
365
−
the
}
347
348
364
up
round (( −( b o d y P o s i t i o n [ 1 ]
S D L _ B l i t S u r f a c e ( bodyIMG [ o % 1 0 ] ,
on
point
+ SCREEN_Y/ 2 ;
bodyPrintPosition ) ;
362
363
the
( bodyPosition [ 0 ]
+ SCREEN_X/ 2 ;
position
focusCenter [ 1 ] ) )
337
361
bodyPosition
If
{
336
359
360
bodyPosition
<
screen
focusCenter [ 0 ] ) )
349
350
351
352
353
354
355
356
357
358
&&
( screenBoundaryMin [ 1 ]
position
in
txtPosTime ,
printing
pixels
txtPosEnergy ,
position
of
text
txtPosError ;
on
screen
bodyPosition [ 2 ] ;
screenBoundaryMax [ 2 ] , screenBoundaryMin [ 2 ] ;
the
maximum
scale
and
time ,
time
coordinates
focus
systemEnergy ,
and
still
showing
on
screen
(
center )
system ' s
systemError ;
total
energy
( at
time
" time ")
text [ 3 0 ] ;
//
Will
hold
our
screen
//
Will
hold
//
Text
text
SDL_Color
text
∗ txtSurfTime
SDL_Surface
,
∗ txtSurfEnergy
,
∗ txtSurfError
surfaces
colorWhite
=
{255 ,
255 ,
255};
color
o;
/∗ ∗
Setting
up
some
screenBoundaryMax [ 0 ]
//
Setting
up
stuff
=
screen
∗ ∗/
focusCenter [ 0 ]
boundaries
screenBoundaryMax [ 1 ]
=
focusCenter [ 1 ]
screenBoundaryMin [ 0 ]
=
focusCenter [ 0 ]
67
+ SCREEN_X/ ( 2 ∗ s c a l e ) ;
+ SCREEN_Y/ ( 2 ∗ s c a l e ) ;
−
SCREEN_X/ ( 2 ∗ s c a l e ) ;
;
Simulation n corps
374
375
376
377
378
379
Thibault Wildi - 3M8
screenBoundaryMin [ 1 ]
/∗ ∗
if
In
case
of
=
focusCenter [ 1 ]
trajectory
( printTrajectories
==
SDL_FillRect ( canvas ,
380
381
382
383
Setting
screen
∗ ∗/
mode
SDL_MapRGB( c a n v a s −>f o r m a t ,
NULL,
to
0,
0,
0) ) ;
black
}
/∗ ∗
Reading
fseek (
− 1) ,
384
385
386
387
and
prints
//
)
Jump
&t i m e ,
(
) ,
fread (
&s y s t e m E n e r g y ,
(
o =
0;
o < BODY_NB;
o++
//
every
for
f r e a d (& b o d y P o s i t i o n
if
&&
,
bodyPosition [ 1 ]
<
next
1,
dataFile_BIN ) ;
) ,
position
1,
&&
dataFile_BIN ) ;
)
body
(
( ( screenBoundaryMin [ 0 ]
screenBoundaryMax [ 0 ] )
(BODY_NB∗ 2+2) ∗ ( s c r e e n P r e c i s i o n
to
sizeof double
{
392
393
points
(
SEEK_CUR) ;
(
∗ ∗/
sizeof double ∗
sizeof double
sizeof double
file
dataFile_BIN ,
fread (
for
388
389
390
391
<
) ,
2,
dataFile_BIN ) ;
bodyPosition [ 0 ]
&&
( screenBoundaryMin [ 1 ]
<
bodyPosition [ 0 ]
screenBoundaryMax [ 1 ] ) )
scale )
round ( (
+ SCREEN_X/ 2 ;
//
scale )
up
the
−
focusCenter
printing
−
position
focusCenter
+ SCREEN_Y/ 2 ;
S D L _ B l i t S u r f a c e ( bodyIMG [ o % 1 0 ] ,
) ;
396
397
398
399
400
401
402
403
404
( bodyPosition [ 0 ]
Setting
round (( −( b o d y P o s i t i o n [ 1 ]
bodyPrintPosition . y =
∗
[1]) )
395
bodyPrintPosition . x =
∗
[0]) )
<
bodyPosition [ 1 ]
{
394
0,
//
canvas ,
&b o d y P r i n t P o s i t i o n
Printing
body
on
screen
}
}
/∗ ∗
if
(0
If
reaching
!=
end
of
∗ ∗/
file
f e o f ( dataFile_BIN ) )
{
rewind ( dataFile_BIN ) ;
SDL_Delay ( 1 0 0 0 ) ;
SDL_FillRect ( canvas ,
//
405
406
407
408
Setting
SDL_MapRGB( c a n v a s −>f o r m a t ,
NULL,
screen
to
0,
0,
0) ) ;
black
}
/∗ ∗
Print
canvas
on
//
/∗ ∗
Printing
Prints
text
systemError
=
body
on
screen ,
∗
0) ;
screen
∗ ∗/
s p r i n t f ( t e x t , " Time :
−
systemEnergy ) /
100;
%.2 f [ s ] " ,
time ) ;
= TTF_RenderText_Blended ( f o n t , t e x t , c o l o r W h i t e ) ;
s p r i n t f ( t e x t , " Energy :
txtSurfEnergy
%.10 e [ J ] " ,
systemEnergy ) ;
= TTF_RenderText_Blended ( f o n t , t e x t , c o l o r W h i t e ) ;
s p r i n t f ( text , " Error :
txtSurfError
0,
(THEORETICAL_ENERGY
THEORETICAL_ENERGY
txtSurfTime
∗ ∗/
screen
SDL_BlitSurface ( canvas ,
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
SCREEN_Y/ ( 2 ∗ s c a l e ) ;
false )
{
//
−
%.6 f%%" , s y s t e m E r r o r ) ;
= TTF_RenderText_Blended ( f o n t , t e x t , c o l o r W h i t e ) ;
txtPosTime . y =
10;
txtPosTime . x =
10;
txtPosEnergy . y =
10;
t x t P o s E n e r g y . x = SCREEN_X
−
t x t S u r f E n e r g y −>w
txtPosError . y =
txtPosEnergy . y +
txtPosError . x =
txtPosEnergy . x ;
−
10;
t x t S u r f E n e r g y −>h +
10;
S D L _ B l i t S u r f a c e ( t x t S u r f T i m e , 0 , s c r e e n ,& t x t P o s T i m e ) ;
S D L _ B l i t S u r f a c e ( t x t S u r f E n e r g y , 0 , s c r e e n ,& t x t P o s E n e r g y ) ;
S D L _ B l i t S u r f a c e ( t x t S u r f E r r o r , 0 , s c r e e n ,& t x t P o s E r r o r ) ;
}
void
p r i n t A x i s O n S c r e e n ( SDL_Surface
SDL_Surface
∗ axisY
,
∗ s c r e e n , SDL_Surface ∗ a x i s X ,
∗ s c a l e B a r X , SDL_Surface ∗ s c a l e B a r Y
SDL_Surface
68
Simulation n corps
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
,
{
Thibault Wildi - 3M8
∗ font
TTF_Font
static
static
static
static
static double
static
static char
static int
SDL_Rect
Will
hold
axis
Will
hold
Text
position
double const
,
axisXPrintPosition ,
positions
SDL_Rect
SDL_Rect
bar
for
color
Will
hold
//
positions
scaleBarYPosition ;
in
//
pixels
∗ txtScale
//
;
//
text
ScaleBarSpacing ;
between
SDL_Color
Text
axisYPrintPosition ;
txtScalePos ;
SDL_Surface
Separation
∗ focusCenter )
pixels
scaleBarXPosition ,
scales
SDL_Surface
in
double const
scale ,
scales
//
bars
colorWhite
=
{255 ,
255 ,
255};
//
text [ 3 0 ] ;
our
//
screen
text
i ;
/∗ ∗
Calculating
ScaleBarSpacing
scale
s p r i n t f ( text , " Scale :
ScaleBarSpacing
/∗ ∗
Setting
txtScale
up
bars
∗ ∗/
separation
= pow ( 1 0 , r o u n d ( l o g 1 0 ( (SCREEN_X /
=
scale ) ) ) ;
round ( S c a l e B a r S p a c i n g ∗ s c a l e ) ;
axis
∗ ∗/
positions
= TTF_RenderText_Blended ( f o n t , t e x t , c o l o r W h i t e ) ;
txtScalePos . x =
10;
t x t S c a l e P o s . y = SCREEN_Y
−
t x t S c a l e −>h
−
10;
axisXPrintPosition . x =
0;
axisXPrintPosition . y =
round ( f o c u s C e n t e r [ 1 ]
axisYPrintPosition . y =
0;
axisYPrintPosition . x =
r o u n d (−
axisXPrintPosition . y
scaleBarYPosition . x =
axisYPrintPosition . x
( axisXPrintPosition . y <
0)
scaleBarXPosition . y =
0;
∗
scale )
∗
focusCenter [ 0 ]
scaleBarXPosition . y =
if
10) /
%.0 e [m] " , S c a l e B a r S p a c i n g ) ;
−
−
+ SCREEN_Y/ 2 ;
scale )
+ SCREEN_X/ 2 ;
20;
20;
{
else if
}
( a x i s X P r i n t P o s i t i o n . y > SCREEN_Y)
{
−
s c a l e B a r X P o s i t i o n . y = SCREEN_Y
if
40;
}
( axisYPrintPosition . x <
0)
scaleBarYPosition . x =
0;
{
else if
}
( a x i s Y P r i n t P o s i t i o n . x > SCREEN_X)
{
−
s c a l e B a r Y P o s i t i o n . x = SCREEN_X
40;
}
/∗ ∗
Printing
Axis
and
scales
SDL_BlitSurface ( axisX ,
0,
SDL_BlitSurface ( axisY ,
0,
SDL_BlitSurface ( t x t S c a l e ,
for
( i =1
;
bars
on
Screen
∗ ∗/
screen ,
&a x i s X P r i n t P o s i t i o n ) ;
screen ,
&a x i s Y P r i n t P o s i t i o n ) ;
0,
screen ,
&t x t S c a l e P o s ) ;
s c a l e B a r X P o s i t i o n . x < SCREEN_X
;
i ++)
{
scaleBarXPosition . x =
axisYPrintPosition . x +
SDL_BlitSurface ( scaleBarX ,
for
0,
screen ,
i
∗ ScaleBarSpacing
;
&s c a l e B a r X P o s i t i o n ) ;
}
( i =1
;
scaleBarXPosition . x >
0
;
i ++)
{
scaleBarXPosition . x =
axisYPrintPosition . x
SDL_BlitSurface ( scaleBarX ,
0,
screen ,
−
}
for
( i =1
;
s c a l e B a r Y P o s i t i o n . y < SCREEN_Y
69
i
∗ ScaleBarSpacing
&s c a l e B a r X P o s i t i o n ) ;
;
i ++)
;
Simulation n corps
490
491
492
493
494
495
496
497
498
499
Thibault Wildi - 3M8
{
scaleBarYPosition . y =
axisXPrintPosition . y +
SDL_BlitSurface ( scaleBarY ,
for
0,
screen ,
i
∗ ScaleBarSpacing
;
&s c a l e B a r Y P o s i t i o n ) ;
}
( i =1
;
scaleBarYPosition . y >
0
;
i ++)
{
scaleBarYPosition . y =
axisXPrintPosition . y
SDL_BlitSurface ( scaleBarY ,
0,
screen ,
}
}
Code 7.8 display2d.c
70
−
i
∗ ScaleBarSpacing
&s c a l e B a r Y P o s i t i o n ) ;
;