Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Scienze Matematiche
Fisiche e Naturali
Ottimizzazione della
Velocità di Esecuzione
in Simulazioni di
Dinamica Molecolare 2D
Docente: Studente:
Franco Bagnoli Pier Paolo Bonaccini
1 Introduzione 1
3 Algoritmi e implementazioni 8
3.1 Integrazione temporale . . . . . . . . . . . . . . . . . . . . . . . . 8
3.1.1 Velocity Verlet . . . . . . . . . . . . . . . . . . . . . . . . 9
3.2 Implementazione del programma base . . . . . . . . . . . . . . . 10
3.3 Un programma più veloce . . . . . . . . . . . . . . . . . . . . . . 13
3.4 Un programma ancora più veloce . . . . . . . . . . . . . . . . . . 13
3.4.1 La funzione pp_sort . . . . . . . . . . . . . . . . . . . . . 19
3.5 Compilazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4 Simulazioni e risultati 23
4.1 Spostamento quadratico medio . . . . . . . . . . . . . . . . . . . 23
4.2 Misure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.2.1 L = 20 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.2.2 L = 100 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5 Conclusioni 35
A 001base.c 36
B 002trunc.c 41
C 003fast.c 46
D box.c 57
E measure.c 78
Bibliografia 79
CAPITOLO 1. INTRODUZIONE 1
Capitolo 1
Introduzione
Capitolo 2
ε/2
0
φLJ (r)
−ε/2
−ε
0 σ 2σ 3σ 4σ 5σ
r
dove l, m, n sono numeri interi e ~a, ~b, ~c sono i vettori corrispondenti agli spigoli
della scatola. Tutte queste particelle “immagine” si muovono insieme, e infatti
soltanto una di queste è rappresentata nel computer dal programma. Il punto
chiave è che adesso possiamo pensare ogni particella i all’interno della scatola
interagente non solo con le altre particelle j nella scatola, ma anche con le loro
immagini che si trovano nelle scatole vicine. Cioè, le interazioni possono “andare
oltre” le pareti della scatola.
Apparentemente, il numero di coppie interagenti cresce enormemente come
effetto delle PBC. Nella pratica, grazie alla convenzione della minima immagine,
le PBC impongono un cutoff naturale al raggio d’azione del potenziale.
CAPITOLO 2. MODELLIZZAZIONE DEL SISTEMA FISICO 6
Alcuni ricercatori alterano la forma del potenziale vicino a Rc così da ottenere un raccordo
più liscio, ma non c’è un metodo standard per farlo.
CAPITOLO 2. MODELLIZZAZIONE DEL SISTEMA FISICO 7
Capitolo 3
Algoritmi e implementazioni
~ (~r(t))
∇V
~a(t) = − (3.5)
m
Quindi, utilizzando l’equazione (3.2) nell’equazione (3.1) e l’equazione (3.5)
nell’equazione (3.3), lo schema dell’algoritmo velocity Verlet diventa:
∆t2
~r(t + ∆t) = ~r(t) + ~v (t)∆t + ~a(t) (3.6)
2
∆t ∆t
~v (t + ) = ~v (t) + ~a(t) (3.7)
2 2
~ (~r(t + ∆t)
∇V
~a(t + ∆t) = − (3.8)
m
∆t ∆t
~v (t + ∆t) = ~v (t + ) + ~a(t + ∆t) (3.9)
2 2
È interessante notare la necessità di 9N locazioni di memoria per salvare le
3N posizioni, velocità e accelerazioni3 , senza però il bisogno di memorizza-
re contemporaneamente i valori di nessuna di questa quantità per due tempi
differenti.
Questo algoritmo è al tempo stesso semplice da implementare, preciso e
stabile, il che spiega il suo largo utilizzo nelle simulazioni di MD.
2 Un altro algoritmo simplettico molto utilizzato è il leap frog.
3 Questo nel caso 3D, in 2D le allocazioni di memoria sono 6N .
CAPITOLO 3. ALGORITMI E IMPLEMENTAZIONI 10
avere tutte masse diverse. Come opzione, non utilizzata però, è stato aggiunto il campo m0,
in modo da poter impostare una massa diversa per la sola particella 0.
CAPITOLO 3. ALGORITMI E IMPLEMENTAZIONI 11
Seguendo lo schema del velocity Verlet (capitolo 3.1.1), prima viene calcolata
la nuova posizione ~r(t + ∆t) della particella:
p[0].v[0] += p[0].f[0]/opt.m0*0.5*opt.dt;
p[0].v[1] += p[0].f[1]/opt.m0*0.5*opt.dt;
p[0].f[0] = p[0].f[1] = 0;
Questi passaggi vengono ripetuti per tutte le altre particelle all’interno di un
ciclo for.
A questo punto si calcola la forza F~ (t + ∆t). Il ciclo è strutturato in modo
da considerare tutte le coppie che è possibile formare con le N particelle del
sistema:
for(a = 0; a < opt.N-1; a++){
for(b = a+1; b < opt.N; b++){
[. . .]
}
}
La sua complessità si trova calcolando C(N ; 2):
N N!
C(N ; 2) = =
2 2! (N − 2)!
(3.10)
N
= (N − 1) ∈ O(N 2 )
2
CAPITOLO 3. ALGORITMI E IMPLEMENTAZIONI 12
Nel caso 2D, avendo posto kB = 1, l’energia cinetica per particella coincide con
la temperatura. Infatti, per il teorema di equipartizione dell’energia:
D
K= N kB T (3.11)
2
Dove D è il numero di gradi di libertà di ogni particella. Quindi:
2 K(t) D=2 K(t)
T (t) = −−−−→ T (t) = (3.12)
D N kB kB =1 N
Il calcolo dell’energia totale e della temperatura permette di verificare che il
sistema sia in equilibrio termodinamico durante la misura.
Il programma completo 001base.c si trova in appendice A.
3 0 1 2 3 0
2
0 9
2
0
15 12 13 14 15 12
7
5 1
7
5
4
11 8 9 10 11 8 3
6
7 4 5 6 7 4 8
3 0 1 2 3 0
2
0 9
2
0
15 12 13 14 15 12
7
5 1
7
5
Quindi, riprendo l’esempio della figura 3.1, il vettore cum risulta essere:
i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
cum[i] 0 1 1 0 1 0 0 1 0 0 0 3 0 1 1 0 1
i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
cum[i] 0 1 2 2 3 3 3 4 4 4 4 7 7 8 9 9 10
i 0 1 2 3 4 5 6 7 8 9
pp[i]
p[i].nc 0 13 3 10 10 12 10 15 6 1
i 0 1 2 3 4 5 6 7 8 9
j=3 4 5 6
j=2
j=1 1 2 3
j=0
Si comincia con un ciclo for che va dalla prima riga di celle fino alla
penultima.
//i = 0;
l = j*opt.c;
for(a = cum[l]; a < cum[l+1]; a++){
cnt++;
[. . .]
}//chiude ciclo a
La variabile cnt tiene il conto delle particelle in esame, cosicché, finito il
ciclo delle forze, si possa verificare che tutte le particelle nella scatola siano
state prese in considerazione.
Quindi, seguendo lo schema della figura 3.2, si calcolano prima le forze tra
una particella e quelle all’interno della stessa cella (se ce ne sono):
if(a < cum[l+1]-1){
for(b = a+1; b < cum[l+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
La macro 5 forces è utilizzata per snellire la scrittura e la lettura del file
sorgente. Al suo interno vengono calcolate le forze e l’energia potenziale:
#define forces(a,b) \
r2 = r[0]*r[0] + r[1]*r[1]; \
if(r2 < opt.R2){ \
r_2 = 1./r2; \
r_6 = r_2*r_2*r_2; \
ff = -24*r_6*(2*r_6-1)*r_2; \
pp[a]->f[0] += ff*r[0]; \
pp[a]->f[1] += ff*r[1]; \
pp[b]->f[0] -= ff*r[0]; \
pp[b]->f[1] -= ff*r[1]; \
E[1] += (4*r_6*(r_6-1) - opt.Vt); \
}
Si calcolano, poi, le forze tra la particella e quelle contenute nella cella
accanto a destra:
for(b = cum[l+1]; b < cum[l+2]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
Si passa quindi a considerare le interazioni con le particelle nelle celle poste
sopra. Si parte da quella in alto a sinistra che, per le PBC, è la cella situata sul
bordo destro della scatola:
5 Una macro è un frammento di codice al quale viene dato un nome. Quando il preprocessore
incontra il nome di una macro all’interno del codice sorgente, lo sostituisce con il suo contenuto.
CAPITOLO 3. ALGORITMI E IMPLEMENTAZIONI 18
Con qualche piccola variazione a causa delle PBC, il codice è lo stesso anche
per gli altri blocchi. Il programma completo 003fast.c si trova in appendice C.
Il blocco 2 è il più grande e comprende le celle al centro della scatola (in
giallo nella figura 3.3). Il loro numero è pari a (c − 2) · (c − 1) = c2 − 3c + 2, dove
c indica sempre il numero di celle per lato. Queste sono tutte celle “standard”
per le quali non dobbiamo preoccuparci delle PBC.
Passiamo al blocco 3, cioè quello che comprende le celle sul bordo destro
della scatola, evidenziato in verde nella figura 3.3. Il numero di celle in questo
blocco è lo stesso del blocco 1, cioè (c − 1).
Lo schema è sempre lo stesso (quello della figura 3.2), con l’accortezza di
considerare le PBC per la cella accanto a destra e per la cella in alto a destra.
Quest’ultime vengono quindi a trovarsi sul bordo sinistro della scatola.
Si passa all’ultima riga di celle, che comprende i blocchi 4, 5 e 6:
//j = opt.c-1;
Il blocco 4 è formato da un’unica cella, quella in alto a sinistra e colorata di
blu in figura 3.2.
Qui le PBC vanno applicate alle tre celle che si trovano sopra. La cella in
alto a sinistra, allora, risulta essere quella nell’angolo in basso a destra della
scatola; le altre due, invece, diventano le prime due celle sul fondo.
Il blocco 5 (colorato di arancione in figura 3.2) comprende la parte centrale
delle celle sul bordo superiore della scatola. Il loro numero è pari a (c − 2).
L’ultimo blocco è il 6 e, proprio come il 4, è formato da un’unica cella, quella
in alto a destra di colore grigio nella figura 3.3.
Qui le PBC vanno applicate a tutte le celle dello schema di interazione in
figura 3.2. La cella accanto a destra risulta essere la cella del blocco 4, quelle
sopra diventano rispettivamente le ultime due celle del bordo inferiore della
scatola e la prima cella del bordo inferiore.
Scritto in questo modo il ciclo delle forze è chiaramente più lungo e com-
plicato rispetto a quello base. Evita però di calcolare inutilmente distanze tra
particelle che sicuramente non interagiscono.
Il “collo di bottiglia” diventa così un problema di ordinamento: se ordinare
il vettore pp in funzione della cella occupata dalle particelle richiedesse più
tempo del calcolare tutte le distanze tra particelle e confrontarle con il raggio di
CAPITOLO 3. ALGORITMI E IMPLEMENTAZIONI 19
cutoff del potenziale troncato, avremmo solo complicato il codice senza alcun
guadagno.
A tal proposito la funzione pp_sort risulta fondamentale.
La macro swap scambia gli elementi del vettore pp servendosi della variabile
temporanea tmp:
#define swap(a,b,c) (c = (*(a)), (*(a)) = (*(b)), (*(b)) = c)
Quando i vettori sono più grandi è invece fondamentale la scelta del pivot.
Quando n = 7 viene scelto l’elemento centrale del vettore. Quando il vettore è
di medie dimensioni (fino a n = 40) come pivot viene scelto il mediano tra il
primo elemento, quello centrale e l’ultimo. Quando n > 40 come pivot viene
scelto il ninther, cioè il mediano dei mediani di tre campioni composti da tre
elementi ciascuno.
CAPITOLO 3. ALGORITMI E IMPLEMENTAZIONI 20
pm=pp+(n/2);
if(n>7){
pl=pp;
pn=pp+(n-1);
if(n>40){
s=(n/8);
pl=med3(pl,pl+s,pl+2*s);
pm=med3(pm-s,pm,pm+s);
pn=med3(pn-2*s,pn-s,pn);
}
pm=med3(pl,pm,pn);
}
Il mediano di tre elementi si trova grazie alla macro med3:
#define med3(a,b,c) \
cmp_nc(a,b) < 0 ? \
(cmp_nc(b,c) < 0 ? b : cmp_nc(a,c) < 0 ? c : a) : \
(cmp_nc(b,c) > 0 ? b : cmp_nc(a,c) > 0 ? c : a)
Il disordine indotto scambiando il pivot con il primo elemento risulta esse-
re molto costoso quando il vettore è ordinato, o quasi ordinato, al contrario.
Quindi, invece di eseguire lo scambio, come viene fatto tipicamente, il valore del
pivot viene copiato nella variabile ausiliaria pv:
pv=&v;
v=*pm;
Si passa poi alla tripartizione del vettore. Tripartizione perché oltre a sposta-
re gli elementi minori del pivot a sinistra e quelli maggiori a destra, gli elementi
con lo stesso valore del pivot vengono a trovarsi ai due estremi del vettore.
pa=pb=pp;
pc=pd=pp+(n-1);
for(;;){
while(pb<=pc && (r=cmp_nc(pb,pv))<=0){
if(r==0){
swap(pa,pb,tmp);
pa++;
}
pb++;
}
while(pc>=pb && (r=cmp_nc(pc,pv))>=0){
if(r==0){
swap(pc,pd,tmp);
pd--;
}
pc--;
}
if(pb>pc)
break;
swap(pb,pc,tmp);
CAPITOLO 3. ALGORITMI E IMPLEMENTAZIONI 21
pb++;
pc--;
}
La situazione del vettore dopo la tripartizione risulta:
= < > =
Vengono allora riportati al centro del vettore gli elementi uguali al pivot:
pn=pp+n;
s=min(pa-pp,pb-pa);
pv=pp;
while(s>0){
swap(pv,pb-s,tmp);
pv++;
s--;
}
s=min(pd-pc,pn-pd-1);
while(s>0){
swap(pb,pn-s,tmp);
pb++;
s--;
}
La macro min ci assicura di effettuare il minor numero di scambi in questa
operazione:
#define min(a,b) \
(a)-(b) < 0 ? (a) : (b)
La tripartizione del vettore risulta allora evidente:
< = >
3.5 Compilazione
I tre file sorgente sono stati compilati utilizzando il programma GNU Compiler
Collection version 5.4.0 (GCC 5.4.0). GCC è il compilatore ufficiale dei sistemi
GNU/Linux6 .
6 gcc.gnu.org
CAPITOLO 3. ALGORITMI E IMPLEMENTAZIONI 22
Capitolo 4
Simulazioni e risultati
La porzione di codice che si occupa del calcolo del MSD è uguale per tutti e
tre i programmi e si trova subito dopo la funzione evolve:
MSD = 0;
for(i=0;i<opt.N;i++){
z[0] = opt.L*p[i].l[0] + p[i].x[0] - x0[i][0];
z[1] = opt.L*p[i].l[1] + p[i].x[1] - x0[i][1];
MSD += z[0]*z[0] + z[1]*z[1];
}
MSD = MSD/opt.N;
Ad ogni intervallo temporale, i valori di tempo, MSD, energia totale, cinetica
e potenziale vengono trascritti su file utilizzando la funzione fwrite:
fwrite(&t,sizeof(double),1,fp);
fwrite(&MSD,sizeof(double),1,fp);
fwrite(E,sizeof(double),3,fp);
In questo modo il computer non deve effettuare la conversione dei dati da
binario ad ASCII, risultando notevolmente più veloce nel processo di salvataggio.
Il MSD contiene informazioni sulla diffusività atomica. Se il sistema è so-
lido, il MSD satura ad un valore finito. Se il sistema è liquido, il MSD cresce
linearmente nel tempo.
CAPITOLO 4. SIMULAZIONI E RISULTATI 24
4.2 Misure
La macchina su cui sono stati fatti girare i programmi è dotata di un processore
Intel Core i5-4210U CPU @ 1.70 GHz × 4 e di una RAM da 5.7 GiB.
Le condizioni iniziali dei sistemi atomici studiati nelle simulazioni vengono
generate con l’utilizzo del programma box.c (appendice D). Questo è dotato
di un’interfaccia grafica che permette di osservare l’evoluzione del sistema di-
rettamente sullo schermo e di controllarne la temperatura. Una volta raggiunto
l’equilibrio termodinamico alla temperatura desiderata, le posizioni, le velocità
e tutti gli altri dati relativi agli atomi e al sistema vengono salvati in un file dal
quale caricheremo le condizioni iniziali per le nostre simulazioni.
Come unità di misura delle lunghezze si utilizza σ = 1. Invece, per mante-
nere la generalità delle simulazioni, le energie, la temperatura e la massa sono
adimensionali.
Per la scatola sono state scelte due grandezze, L = 20 e L = 100. In tutte le
simulazioni, la massa degli atomi è uguale a mi = 1 e il raggio di cutoff Rc = 4.
L’intervallo temporale di integrazione è uguale a ∆t = 0.01 s.
La durata delle simulazioni è stata misurata grazie al comando time di Unix,
evocato dalla funzione di sistema system all’interno del programma measure.c
(in appendice E la versione per L = 20).
4.2.1 L = 20
Sono stati simulati, per TMAX = 100000 s (∼ 28 ore), sistemi con densità nume-
rica1 pari a ρ = {0.25, 0.50, 0.75, 1.00}. Per ognuna di esse sono stati misurati
i MSD alle temperature T = {0.1, 0.2, 0.5, 1.0, 2.0}.
Come si vede nelle figure 4.1, 4.2, 4.3 e 4.4, per tutte le simulazioni a T = 2.0,
la temperatura non rimane costante. Questo è dovuto alla scelta di un intervallo
temporale di integrazione troppo grande che non permette un campionamento
adeguato dell’evoluzione del sistema. Gli atomi a quella temperatura sono ab-
bastanza veloci da percorrere, in un intervallo temporale ∆t = 0.01 s, spazi
sufficienti a oltrepassare la barriera del potenziale, trovandosi sottoposti a for-
ze di repulsione elevatissime. Di conseguenza, hanno accelerazioni elevatissime
che portano a velocità altrettanto elevate. Le variabili double non sono più
sufficienti a rappresentare valori numerici così grandi. Si innesca, quindi, un
effetto valanga che fa esplodere la temperatura del sistema. Per questa ragione
la misura del MSD per T = 2.0 è stata esclusa dal confronto.
1 Siamo N
nel caso 2D, quindi ρ = .
σ2
CAPITOLO 4. SIMULAZIONI E RISULTATI 25
2 2 2
1 1 1
2 2 2
1 1 1
2 2 2
1 1 1
2 2 2
1 1 1
T = 0.1 T = 0.2
7.0 10+3 1.0 10+4
base 6.0 10+3
base 9.0 10+3
trunc trunc 8.0 10+3
5.0 10+3 7.0 10+3
fast 4.0 10+3
fast 6.0 10+3
5.0 10+3
3.0 10+3 4.0 10+3
2.0 10+3 3.0 10+3
1.0 10+3 2.0 10+3
1.0 10+3
0.0 10+0 0.0 10+0
0 105 0 105
t (s) t (s)
T = 0.5 T = 1.0
2.5 10+5 6.0 10+5
base base
trunc 2.0 10+5 trunc 5.0 10+5
fast fast 4.0 10+5
1.5 10+5
3.0 10+5
1.0 10+5
2.0 10+5
5.0 10+4 1.0 10+5
0.0 10+0 0.0 10+0
0 105 0 105
t (s) t (s)
T = 0.1 T = 0.2
4.5 10+2 4.5 10+1
base 4.0 10+2 base 4.0 10+1
trunc 3.5 10+2 trunc 3.5 10+1
fast 3.0 10+2 fast 3.0 10+1
2.5 10+2 2.5 10+1
2.0 10+2 2.0 10+1
1.5 10+2 1.5 10+1
1.0 10+2 1.0 10+1
5.0 10+1 5.0 10+0
0.0 10+0 0.0 10+0
0 105 0 105
t (s) t (s)
T = 0.5 T = 1.0
8.0 10+4 1.6 10+5
base 7.0 10+4 base 1.4 10+5
trunc 6.0 10+4 trunc 1.2 10+5
fast 5.0 10+4 fast 1.0 10+5
4.0 10+4 8.0 10+4
3.0 10+4 6.0 10+4
2.0 10+4 4.0 10+4
1.0 10+4 2.0 10+4
0.0 10+0 0.0 10+0
0 105 0 105
t (s) t (s)
T = 0.1 T = 0.2
1.8 10+0 3.0 10+1
base 1.6 10+0 base
trunc 1.4 10+0 trunc 2.5 10+1
fast 1.2 10+0 fast 2.0 10+1
1.0 10+0 1.5 10+1
8.0 10−1
6.0 10−1 1.0 10+1
4.0 10−1 5.0 10+0
2.0 10−1
0.0 10+0 0.0 10+0
0 105 0 105
t (s) t (s)
T = 0.5 T = 1.0
2.5 10+4 5.0 10+4
base base 4.5 10+4
trunc 2.0 10+4 trunc 4.0 10+4
fast fast 3.5 10+4
1.5 10+4 3.0 10+4
2.5 10+4
1.0 10+4 2.0 10+4
1.5 10+4
5.0 10+3 1.0 10+4
5.0 10+3
0.0 10+0 0.0 10+0
0 105 0 105
t (s) t (s)
T = 0.1 T = 0.2
6.0 10+0 2.0 10−1
base base 1.8 10−1
trunc 5.0 10+0 trunc 1.6 10−1
fast 4.0 10+0 fast 1.4 10−1
1.2 10−1
3.0 10+0 1.0 10−1
8.0 10−2
2.0 10+0 6.0 10−2
1.0 10+0 4.0 10−2
2.0 10−2
0.0 10+0 0.0 10+0
0 105 0 105
t (s) t (s)
T = 0.5 T = 1.0
1.2 10+2 7.0 10+1
base base 6.0 10+1
trunc 1.0 10+2 trunc
8.0 10+1 5.0 10+1
fast fast 4.0 10+1
6.0 10+1
3.0 10+1
4.0 10+1 2.0 10+1
2.0 10+1 1.0 10+1
0.0 10+0 0.0 10+0
0 105 0 105
t (s) t (s)
Gli altri MSD sono mostrati nelle figure 4.5, 4.6, 4.7 e 4.8. Come si vede,
gli andamenti sono piuttosto consistenti tra loro. Per i programmi trunc.c
e fast.c ci aspetteremmo però andamenti identici, dopotutto hanno lo stesso
valore di Rc . Le discrepanze tra i due MSD sono dovute all’aritmetica in virgola
mobile che, a differenza dell’aritmetica reale, non gode delle proprietà associativa
e distributiva: l’ordine con cui vengono eseguite le operazioni algebriche influisce
sul risultato finale.
La tabella 4.1 mostra i tempi che impiegano i tre programmi a far evolvere
i diversi sistemi per la durata di simulazione TMAX = 100000 s.
Come si vede, il programma fast.c ha sempre prestazioni superiori agli altri
due e, all’aumentare del numero N degli atomi, il divario aumenta.
4.2.2 L = 100
Per TMAX = 1000 s (∼ 17 minuti), vengono simulati sistemi con densità numerica
pari a ρ = {0.25, 0.50, 0.75}. Per ognuna di esse sono stati misurati i MSD alle
temperature T = {0.1, 0.2, 0.5, 1.0, 2.0}.
Come si vede nelle figure 4.9, 4.10 e 4.11, la temperatura rimane costante
per tutti i valori di T .
I MSD sono mostrati nelle figure 4.12, 4.13 e 4.14. Anche in questo caso,
gli andamenti sono piuttosto consistenti tra loro. Le discrepanze sono proba-
bilmente dovute, oltre ai motivi discussi per L = 20, anche ad una durata delle
simulazione più piccola di 2 ordini di grandezza.
CAPITOLO 4. SIMULAZIONI E RISULTATI 30
1 1 1
1 1 1
1 1 1
T = 0.1 T = 0.2
7.0 10+0 6.0 10+1
Basic Basic
Trunc 6.0 10+0 Trunc 5.0 10+1
Fast Fast
5.0 10+0
4.0 10+1
4.0 10+0
3.0 10+1
3.0 10+0
2.0 10+1
2.0 10+0
1.0 10+0 1.0 10+1
T = 0.5 T = 1.0
3.0 10+3 5.0 10+3
Basic Basic
Trunc Trunc 4.5 10+3
2.5 10+3 4.0 10+3
Fast Fast
2.0 10+3 3.5 10+3
3.0 10+3
1.5 10+3 2.5 10+3
2.0 10+3
1.0 10+3 1.5 10+3
5.0 10+2 1.0 10+3
5.0 10+2
0.0 10+0 0.0 10+0
0 103 0 103
t (s) t (s)
T = 2.0
7.0 10+3
Basic
Trunc 6.0 10+3
Fast
5.0 10+3
4.0 10+3
3.0 10+3
2.0 10+3
1.0 10+3
0.0 10+0
0 103
t (s)
T = 0.1 T = 0.2
2.0 10−1 2.5 10+0
Basic Basic
Trunc 1.8 10−1 Trunc
Fast 1.6 10−1 Fast 2.0 10+0
1.4 10−1
1.2 10−1 1.5 10+0
1.0 10−1
8.0 10−2 1.0 10+0
6.0 10−2
4.0 10−2 5.0 10−1
2.0 10−2
0.0 10+0 0.0 10+0
0 103 0 103
t (s) t (s)
T = 0.5 T = 1.0
1.2 10+3 2.0 10+3
Basic Basic
Trunc Trunc 1.8 10+3
1.0 10+3 1.6 10+3
Fast Fast
8.0 10+2 1.4 10+3
1.2 10+3
6.0 10+2 1.0 10+3
8.0 10+2
4.0 10+2 6.0 10+2
2.0 10+2 4.0 10+2
2.0 10+2
0.0 10+0 0.0 10+0
0 103 0 103
t (s) t (s)
T = 2.0
3.5 10+3
Basic
Trunc 3.0 10+3
Fast
2.5 10+3
2.0 10+3
1.5 10+3
1.0 10+3
5.0 10+2
0.0 10+0
0 103
t (s)
T = 0.1 T = 0.2
3.5 10−2 2.0 10−1
Basic Basic
Trunc Trunc 1.8 10−1
3.0 10−2
Fast Fast 1.6 10−1
2.5 10−2 1.4 10−1
2.0 10−2 1.2 10−1
1.0 10−1
1.5 10−2 8.0 10−2
1.0 10−2 6.0 10−2
4.0 10−2
5.0 10−3
2.0 10−2
0.0 10+0 0.0 10+0
0 103 0 103
t (s) t (s)
T = 0.5 T = 1.0
3.5 10+2 7.0 10+2
Basic Basic
Trunc 3.0 10+2 Trunc 6.0 10+2
Fast Fast
2.5 10+2 5.0 10+2
2.0 10+2 4.0 10+2
1.5 10+2 3.0 10+2
1.0 10+2 2.0 10+2
5.0 10+1 1.0 10+2
0.0 10+0 0.0 10+0
0 103 0 103
t (s) t (s)
T = 2.0
1.4 10+3
Basic
Trunc 1.2 10+3
Fast
1.0 10+3
8.0 10+2
6.0 10+2
4.0 10+2
2.0 10+2
0.0 10+0
0 103
t (s)
La tabella 4.2 mostra i tempi che impiegano i tre programmi a far evolvere
i diversi sistemi per la durata di simulazione TMAX = 1000 s.
La superiorità del programma fast.c qui è ancora più evidente che nel caso
di L = 20. Il diavario tra le prestazioni dei tre programmi all’aumentare del
numero N degli atomi è impressionante.
Da questo si intuisce quanto sarebbe stato proibitivo, per L = 100, studiare
il comportamento del sistema con ρ = 1.00 (N = 10000) con i programmmi
base.c e trunc.c, ed anche impostare TMAX = 100000 s.
CAPITOLO 5. CONCLUSIONI 35
Capitolo 5
Conclusioni
Appendice A
001base.c
#include <stdio.h>
#include <stdlib.h>
x0 = calloc(opt.N,sizeof(double*));
for(i=0;i<opt.N;i++){
x0[i] = calloc(2,sizeof(double));
x0[i][0] = p[i].x[0];
x0[i][1] = p[i].x[1];
}
it = 0;// indice conteggio step temporali
t = 0;// variabile tempo
//fprintf(fp,"%f %f %f %f %f\n",t,MSD,E[0],E[1],E[2]);
//printf("%f\n",t);
fwrite(&t,sizeof(double),1,fp);
fwrite(&MSD,sizeof(double),1,fp);
fwrite(E,sizeof(double),3,fp);
while(t < tmax){
it++;
if(it%100 == 0)
t = it * opt.dt;
else
t += opt.dt;
evolve(p,opt,E);
MSD = 0;
for(i=0;i<opt.N;i++){
z[0] = opt.L*p[i].l[0] + p[i].x[0] - x0[i][0];
z[1] = opt.L*p[i].l[1] + p[i].x[1] - x0[i][1];
MSD += z[0]*z[0] + z[1]*z[1];
}
MSD = MSD/opt.N;
fwrite(&t,sizeof(double),1,fp);
fwrite(&MSD,sizeof(double),1,fp);
fwrite(E,sizeof(double),3,fp);
}
APPENDICE A. 001BASE.C 38
fclose(fp);
return 0;
}
E[0]=E[1]=E[2]=0;
//reticolo periodico
if(p[0].x[0] < 0){
p[0].l[0]--;
p[0].x[0] += opt.L;
}
else if(p[0].x[0] > opt.L){
p[0].l[0]++;
p[0].x[0] -= opt.L;
}
if(p[0].x[1] < 0){
p[0].l[1]--;
p[0].x[1] += opt.L;
}
else if(p[0].x[1] > opt.L){
p[0].l[1]++;
p[0].x[1] -= opt.L;
}
//reticolo periodico
if(p[i].x[0] < 0){
APPENDICE A. 001BASE.C 39
p[i].l[0]--;
p[i].x[0] += opt.L;
}
else if(p[i].x[0] > opt.L){
p[i].l[0]++;
p[i].x[0] -= opt.L;
}
if(p[i].x[1] < 0){
p[i].l[1]--;
p[i].x[1] += opt.L;
}
else if(p[i].x[1] > opt.L){
p[i].l[1]++;
p[i].x[1] -= opt.L;
}
//////////////////////////////
// calcolo di F(t+dt)
for(a = 0; a < opt.N-1; a++){
for(b = a+1; b < opt.N; b++){
r[0] = p[b].x[0] - p[a].x[0];
if(r[0] > opt.L/2.)
r[0] = r[0] - opt.L;
else if(r[0] < -opt.L/2.)
r[0] = r[0] + opt.L;
r[1] = p[b].x[1] - p[a].x[1];
if(r[1] > opt.L/2.)
r[1] = r[1] - opt.L;
else if(r[1] < -opt.L/2.)
r[1] = r[1] + opt.L;
r2 = r[0]*r[0] + r[1]*r[1];
if(r2 < opt.R2){
r_2 = 1./r2;
r_6 = r_2*r_2*r_2;
ff = -24*r_6*(2*r_6-1)*r_2;
p[a].f[0] += ff*r[0];
p[a].f[1] += ff*r[1];
p[b].f[0] -= ff*r[0];
p[b].f[1] -= ff*r[1];
E[1] += (4*r_6*(r_6-1) - opt.Vt);
}
}
}
APPENDICE A. 001BASE.C 40
for(i=0;i<popt->N;i++)
p[i].l[0] = p[i].l[1] = 0;
dm2 = 1./popt->R2;
dm6 = dm2 * dm2 * dm2;
popt->Vt = 4*dm6*(dm6-1);
fclose(sp);
return p;
}
APPENDICE B. 002TRUNC.C 41
Appendice B
002trunc.c
#include <stdio.h>
#include <stdlib.h>
x0 = calloc(opt.N,sizeof(double*));
for(i=0;i<opt.N;i++){
x0[i] = calloc(2,sizeof(double));
x0[i][0] = p[i].x[0];
x0[i][1] = p[i].x[1];
}
it = 0;// indice conteggio step temporali
t = 0;// variabile tempo
fwrite(&t,sizeof(double),1,fp);
fwrite(&MSD,sizeof(double),1,fp);
fwrite(E,sizeof(double),3,fp);
while(t < tmax){
it++;
if(it%100 == 0)
t = it * opt.dt;
else
t += opt.dt;
evolve(p,opt,E);
MSD = 0;
for(i=0;i<opt.N;i++){
z[0] = opt.L*p[i].l[0] + p[i].x[0] - x0[i][0];
z[1] = opt.L*p[i].l[1] + p[i].x[1] - x0[i][1];
MSD += z[0]*z[0] + z[1]*z[1];
}
MSD = MSD/opt.N;
fwrite(&t,sizeof(double),1,fp);
fwrite(&MSD,sizeof(double),1,fp);
fwrite(E,sizeof(double),3,fp);
}
fclose(fp);
APPENDICE B. 002TRUNC.C 43
return 0;
}
E[0]=E[1]=E[2]=0;
//reticolo periodico
if(p[0].x[0] < 0){
p[0].l[0]--;
p[0].x[0] += opt.L;
}
else if(p[0].x[0] > opt.L){
p[0].l[0]++;
p[0].x[0] -= opt.L;
}
if(p[0].x[1] < 0){
p[0].l[1]--;
p[0].x[1] += opt.L;
}
else if(p[0].x[1] > opt.L){
p[0].l[1]++;
p[0].x[1] -= opt.L;
}
//reticolo periodico
if(p[i].x[0] < 0){
p[i].l[0]--;
APPENDICE B. 002TRUNC.C 44
p[i].x[0] += opt.L;
}
else if(p[i].x[0] > opt.L){
p[i].l[0]++;
p[i].x[0] -= opt.L;
}
if(p[i].x[1] < 0){
p[i].l[1]--;
p[i].x[1] += opt.L;
}
else if(p[i].x[1] > opt.L){
p[i].l[1]++;
p[i].x[1] -= opt.L;
}
//////////////////////////////
// calcolo di F(t+dt)
for(a = 0; a < opt.N-1; a++){
for(b = a+1; b < opt.N; b++){
r[0] = p[b].x[0] - p[a].x[0];
if(r[0] > opt.L/2.)
r[0] = r[0] - opt.L;
else if(r[0] < -opt.L/2.)
r[0] = r[0] + opt.L;
r[1] = p[b].x[1] - p[a].x[1];
if(r[1] > opt.L/2.)
r[1] = r[1] - opt.L;
else if(r[1] < -opt.L/2.)
r[1] = r[1] + opt.L;
r2 = r[0]*r[0] + r[1]*r[1];
if(r2 < opt.R2){r_2 = 1./r2;
r_6 = r_2*r_2*r_2;
ff = -24*r_6*(2*r_6-1)*r_2;
p[a].f[0] += ff*r[0];
p[a].f[1] += ff*r[1];
p[b].f[0] -= ff*r[0];
p[b].f[1] -= ff*r[1];
E[1] += (4*r_6*(r_6-1) - opt.Vt);
}
}
}
p[0].v[0] += p[0].f[0]/opt.m0*0.5*opt.dt;
p[0].v[1] += p[0].f[1]/opt.m0*0.5*opt.dt;
E[2] += opt.m0*(p[0].v[0]*p[0].v[0] + p[0].v[1]*p[0].v[1])/2;
}
E[0] = E[1] + E[2];
E[0] = E[0]/opt.N;
E[1] = E[1]/opt.N;
E[2] = E[2]/opt.N;
}
for(i=0;i<popt->N;i++)
p[i].l[0] = p[i].l[1] = 0;
fclose(sp);
return p;
}
APPENDICE C. 003FAST.C 46
Appendice C
003fast.c
#include <stdio.h>
#include <stdlib.h>
#define forces(a,b) \
r2 = r[0]*r[0] + r[1]*r[1]; \
if(r2 < opt.R2){ \
r_2 = 1./r2; \
r_6 = r_2*r_2*r_2; \
ff = -24*r_6*(2*r_6-1)*r_2; \
pp[a]->f[0] += ff*r[0]; \
pp[a]->f[1] += ff*r[1]; \
pp[b]->f[0] -= ff*r[0]; \
pp[b]->f[1] -= ff*r[1]; \
E[1] += (4*r_6*(r_6-1) - opt.Vt); \
}
double t;
int it;
p = load(argv[1],&opt);
pp = calloc(opt.N,sizeof(struct _particle *));
for(i = 0; i < opt.N; i++){
pp[i] = p+i;
}
cum = calloc(opt.C+1,sizeof(int));
fp = fopen(argv[2],"w");
x0 = calloc(opt.N,sizeof(double*));
for(i=0;i<opt.N;i++){
x0[i] = calloc(2,sizeof(double));
x0[i][0] = p[i].x[0];
x0[i][1] = p[i].x[1];
}
it = 0;// indice conteggio step temporali
t = 0;// variabile tempo
fwrite(&t,sizeof(double),1,fp);
fwrite(&MSD,sizeof(double),1,fp);
fwrite(E,sizeof(double),3,fp);
while(t < tmax){
it++;
if(it%100 == 0)
t = it * opt.dt;
else
t += opt.dt;
evolve(p,pp,opt,cum,E);
MSD = 0;
for(i=0;i<opt.N;i++){
z[0] = opt.L*p[i].l[0] + p[i].x[0] - x0[i][0];
z[1] = opt.L*p[i].l[1] + p[i].x[1] - x0[i][1];
MSD += z[0]*z[0] + z[1]*z[1];
}
MSD = MSD/opt.N;
fwrite(&t,sizeof(double),1,fp);
fwrite(&MSD,sizeof(double),1,fp);
fwrite(E,sizeof(double),3,fp);
}
fclose(fp);
return 0;
}
double r2,r_2,r_6,ff;
E[0]=E[1]=E[2]=0;
// azzeramento celle
for(i = 1; i <= opt.C; i++){
cum[i] = 0;
}
// calcolo di x(t + dt) = x(t) + v(t + dt/2) * dt
// con v(t + dt/2) = v(t) + F(t)/m * dt/2
// sì da considerare correttamente gli urti con le pareti della scatola
p[0].x[0] += (p[0].v[0] + p[0].f[0]/opt.m0*0.5*opt.dt)*opt.dt;
p[0].x[1] += (p[0].v[1] + p[0].f[1]/opt.m0*0.5*opt.dt)*opt.dt;
//reticolo periodico
if(p[0].x[0] < 0){
p[0].l[0]--;
p[0].x[0] += opt.L;
}
else if(p[0].x[0] > opt.L){
p[0].l[0]++;
p[0].x[0] -= opt.L;
}
if(p[0].x[1] < 0){
p[0].l[1]--;
p[0].x[1] += opt.L;
}
else if(p[0].x[1] > opt.L){
p[0].l[1]++;
p[0].x[1] -= opt.L;
}
p[0].nc = (int)(p[0].x[0]/opt.R) + \
(int)(p[0].x[1]/opt.R)*opt.c;
cum[p[0].nc+1]++;
//reticolo periodico
if(p[i].x[0] < 0){
APPENDICE C. 003FAST.C 50
p[i].l[0]--;
p[i].x[0] += opt.L;
}
else if(p[i].x[0] > opt.L){
p[i].l[0]++;
p[i].x[0] -= opt.L;
}
if(p[i].x[1] < 0){
p[i].l[1]--;
p[i].x[1] += opt.L;
}
else if(p[i].x[1] > opt.L){
p[i].l[1]++;
p[i].x[1] -= opt.L;
}
p[i].nc = (int)(p[i].x[0]/opt.R) + \
(int)(p[i].x[1]/opt.R)*opt.c;
cum[p[i].nc+1]++;
// cumulata
for(i = 1; i < opt.C + 1; i++){
cum[i] += cum[i-1];
}
/*ordinamento del vettore pp in funzione
della cella occupata dalla particella*/
pp_sort(pp,opt.N);
//////////////////////////////
// calcolo di F(t+dt)
for(j = 0; j < opt.c-1; j++){
//i = 0;
l = j*opt.c;
for(a = cum[l]; a < cum[l+1]; a++){
cnt++;
if(a < cum[l+1]-1){
for(b = a+1; b < cum[l+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
for(b = cum[l+1]; b < cum[l+2]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
APPENDICE C. 003FAST.C 51
}
}
for(b = cum[l-opt.c+1]; b < cum[l-opt.c+2]; b++){
r[0] = (pp[b]->x[0] + opt.L) - pp[a]->x[0];//special
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
for(k = -1; k < 1; k++){
for(b = cum[l+opt.c+k]; b < cum[l+opt.c+k+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
for(b = cum[l+1]; b < cum[l+2]; b++){
r[0] = (pp[b]->x[0] + opt.L) - pp[a]->x[0];//special
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}//chiude cicla a
}//chiude ciclo j
//j = opt.c-1;
//i = 0;
l = j*opt.c;
for(a = cum[l]; a < cum[l+1]; a++){
cnt++;
if(a < cum[l+1]-1){
for(b = a+1; b < cum[l+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
for(b = cum[l+1]; b < cum[l+2]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
for(b = cum[opt.c-1]; b < cum[opt.c]; b++){
r[0] = (pp[b]->x[0] - opt.L) - pp[a]->x[0];//special
r[1] = (pp[b]->x[1] + opt.L) - pp[a]->x[1];//special
forces(a,b);
}
for(k = 0; k < 2; k++){
for(b = cum[k]; b < cum[k+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = (pp[b]->x[1] + opt.L) - pp[a]->x[1];//special
forces(a,b);
}
}
APPENDICE C. 003FAST.C 53
}//chiude ciclo a
for(i = 1; i < opt.c-1; i++){
l = j*opt.c + i;
for(a = cum[l]; a < cum[l+1]; a++){
cnt++;
if(a < cum[l+1]-1){
for(b = a+1; b < cum[l+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
for(b = cum[l+1]; b < cum[l+2]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
for(k = -1; k < 2; k++){
for(b = cum[i+k]; b < cum[i+k+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = (pp[b]->x[1] + opt.L) - pp[a]->x[1];//special
forces(a,b);
}
}
}//chiude ciclo a
}//chiude ciclo i
//i = opt.c-1;
l = j*opt.c + i;
for(a = cum[l]; a < cum[l+1]; a++){
cnt++;
if(a < cum[l+1]-1){
for(b = a+1; b < cum[l+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
for(b = cum[l-opt.c+1]; b < cum[l-opt.c+2]; b++){
r[0] = (pp[b]->x[0] + opt.L) - pp[a]->x[0];//special
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
for(k = -1; k < 1; k++){
for(b = cum[opt.c-1+k]; b < cum[opt.c+k]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = (pp[b]->x[1] + opt.L) - pp[a]->x[1];//special
forces(a,b);
}
}
for(b = cum[0]; b < cum[1]; b++){
APPENDICE C. 003FAST.C 54
if(cnt != opt.N){
fprintf(stdout,"cnt = %3d\n",cnt);
exit(-1);
}
}
E[0] = E[1] + E[2];
E[0] = E[0]/opt.N;
E[1] = E[1]/opt.N;
E[2] = E[2]/opt.N;
}
for(i=0;i<popt->N;i++)
p[i].l[0] = p[i].l[1] = 0;
fclose(sp);
return p;
}
APPENDICE C. 003FAST.C 55
s=min(pa-pp,pb-pa);
pv=pp;
while(s>0){
swap(pv,pb-s,tmp);
pv++;
s--;
}
s=min(pd-pc,pn-pd-1);
while(s>0){
swap(pb,pn-s,tmp);
pb++;
s--;
}
if((s=pb-pa) > 1)
pp_sort(pp,s);
if((s=pd-pc) > 1)
pp_sort(pn-s,s);
}
Appendice D
box.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <math.h>//-----to compile -lm
#include <ncurses.h>//--to compile -lncurses
#define forces(a,b) \
r2 = r[0]*r[0] + r[1]*r[1]; \
if(r2 < opt.R2){ \
r_2 = 1./r2; \
r_6 = r_2*r_2*r_2; \
ff = -24*r_6*(2*r_6-1)*r_2; \
pp[a]->f[0] += ff*r[0]; \
pp[a]->f[1] += ff*r[1]; \
pp[b]->f[0] -= ff*r[0]; \
pp[b]->f[1] -= ff*r[1]; \
E[1] += (4*r_6*(r_6-1) - opt.Vt); \
}
int kbhit(void);//-----------------detect keyboard hit
57
APPENDICE D. BOX.C 58
/////////////////////////////////////////////////////////////////////
opt = opt_manager(argc,argv);
int Ndata = (int)(tmax/opt.dt);
data = calloc(Ndata+1,sizeof(double *));
for(i=0;i<Ndata+1;i++){
data[i] = calloc(2,sizeof(double));
}
/////////////////////////////
// ncurses //
/////////////////////////////
int cc;
int bath = 0;
initscr();
cbreak();
noecho();
nodelay(stdscr,TRUE);
/////////////////////////////
if((argc-optind) == 0){
p = calloc(opt.N,sizeof(struct _particle));
pp = calloc(opt.N,sizeof(struct _particle *));
for(i = 0; i < opt.N; i++){
pp[i] = p+i;
}
cum = calloc(opt.C+1,sizeof(int));
APPENDICE D. BOX.C 60
init(p,opt);
}
else
if((argc-optind) == 1){
char string[2];
p = load(argv[optind],&opt);
pp = calloc(opt.N,sizeof(struct _particle *));
for(i = 0; i < opt.N; i++){
pp[i] = p+i;
}
cum = calloc(opt.C+1,sizeof(int));
nodelay(stdscr,FALSE);
refresh();
printw("evolution function: ");
echo();
getstr(string);
opt.func = atoi(string);
move(0,0);
noecho();
nodelay(stdscr,TRUE);
refresh();
}
else{
fprintf(stderr,"\nwrong command line\nto load file use: \
%s file_name\nto look at the options: %s -h\n",argv[0],argv[0]);
return -1;
}
printw("R = %.2f; L = %.2f; N = %d; rho = %.2f; \
",opt.R,opt.L,opt.N,opt.N/(opt.L*opt.L));
if(opt.func == 1)
printw("truncated %d\n",opt.func);
else if(opt.func == 2)
printw("basic %d\n",opt.func);
else
printw("fast_truncated %d\n",opt.func);
refresh();
sz0 = sqrt(opt.m0);
szi = sqrt(opt.mi);
fp = popen("gnuplot","w");
fprintf(fp,"set term x11 persist; unset key\n");
fprintf(fp,"set xrange[0:100]; set yrange[0:3]\n");
fprintf(fp,"set title ’Temperature’\n");
gp = popen("gnuplot","w");
fprintf(gp,"set term x11 persist; unset key; set size square\n");
fprintf(gp,"set xrange[0:%f]; set yrange[0:%f]\n",opt.L,opt.L);
//fprintf(gp,"set xtics 20\n");
//fprintf(gp,"set ytics 20\n");
//fprintf(gp,"set mxtics 5\n");
//fprintf(gp,"set mytics 5\n");
APPENDICE D. BOX.C 61
evolve = basic_evolve;
if(opt.func == 2){
opt.R = opt.L/2.;
opt.R2 = opt.R * opt.R;
opt.Vt = 4*dm6*(dm6-1);
}
else if(opt.func == 0)
evolve = fast_trunc_evolve;
data[it][0] = t;
data[it][1] = E[2];
APPENDICE D. BOX.C 62
if(it%fr == 0){
fprintf(fp,\
"plot ’-’ binary record=%d format=’%%double’ w l\n",(it/fr)+1);
for(i = 0; i < it+1; i++){
if(i%fr == 0)
fwrite(data[i],sizeof(double),2,fp);
}
fprintf(gp,"set title ’e = %-8.4f; t = %-8.2f; u = %-8.4f; \
T = %-8.4f’\n",E[0],t,E[1],E[2]);
fprintf(gp,"plot ’-’ binary record=1 format=’%%double’ w p \
ls 6 lc ’blue’ ps %f, ’-’ binary record=%d format=’%%double’ w p \
ls 6 lc ’red’ ps %f\n",sz0,opt.N-1,szi);
fwrite(p[0].x,sizeof(double),2,gp);
for(i = 1; i < opt.N; i++){
fwrite(p[i].x,sizeof(double),2,gp);
}
fflush(gp);
fflush(fp);
}
/*-- cooling/heating block --*/
if(bath != 0){
A = sqrt(opt.T/E[2]);
}
/*-- end cooling/heating block --*/
/*-- keyboard commands block --*/
cc=kbhit();
switch(cc){
int chr;
char string[100];
case 0:
break;
case ’p’:
move(2,0);
nodelay(stdscr,FALSE);
refresh();
chr = getchar();
switch(chr){
case ’g’:
move(3,0);
printw("gnuplot command: ");
echo();
getstr(string);
fprintf(fp,"%s\n",string);
fflush(fp);
break;
case ’f’:
move(3,0);
printw("frames: ");
echo();
getstr(string);
APPENDICE D. BOX.C 63
fr = atoi(string);
break;
case ’s’:
move(3,0);
printw("save as: ");
echo();
getstr(string);
save(p,opt,string);
break;
default:
break;
}
nodelay(stdscr,TRUE);
noecho();
move(2,0);
clrtobot();
move(2,0);
break;
case ’t’://-- termalization
if(bath==0){
bath=1;
move(2,0);
nodelay(stdscr,FALSE);
refresh();
move(3,0);
printw("temperature: ");
echo();
getstr(string);
opt.T = atof(string);
nodelay(stdscr,TRUE);
noecho();
move(1,0);
clrtobot();
move(1,0);
printw("termalization T = %.2f\n",opt.T);
}
else {
double vx,vy;
bath = 0;
A=1;
move(1,0);
clrtobot();
move(1,0);
for(i=0;i<opt.N;i++){
vx += p[i].v[0];
vy += p[i].v[1];
}
vx /= opt.N;
vy /= opt.N;
for(i=0;i<opt.N;i++){
APPENDICE D. BOX.C 64
p[i].v[0] -= vx;
p[i].v[1] -= vy;
p[i].l[0] = p[i].l[1] = 0;
}
}
break;
default:
move(1,0);
clrtoeol();
move(1,0);
break;
}
/*-- end keyboard commands block --*/
}
endwin();
return 0;
}
int kbhit(void){
int c;
c=getch();
if(c != ERR)
return c;
else
return 0;
}
/////////////////////////////////////////////////////////////////////
opt.N = 200;
opt.R = 4;
opt.L = 100;
opt.m0 = 1;
opt.mi = 1;
opt.dt = 0.01;
opt.T = 1;
opt.func = 0;
while((c=getopt(argc,argv,option)) != -1){
switch(c){
case ’t’://intervallo di integrazione
APPENDICE D. BOX.C 65
opt.dt = atof(optarg);
break;
case ’L’://dimensioni scatola
opt.L = atof(optarg);
break;
case ’R’://raggio potenziale troncato
opt.R = atof(optarg);
break;
case ’f’://funzione di evoluzione
opt.func = atoi(optarg);
break;
case ’T’://temperatura iniziale
opt.T = atof(optarg);
break;
case ’N’://numero particelle
opt.N = atoi(optarg);
break;
case ’M’://massa particella 0
opt.m0 = atof(optarg);
break;
case ’m’://massa particelle
opt.mi = atof(optarg);
break;
default:
fprintf(stdout,"to look at the options: %s -h\n",argv[0]);
exit(-1);
}
}
opt.c = (int)(opt.L/opt.R);
if((opt.L - opt.c*opt.R) > opt.R)
opt.c++;
opt.C = opt.c * opt.c;
opt.L = opt.R * opt.c;
if(opt.func == 2)
opt.R = opt.L/2.;
opt.R2 = opt.R * opt.R;
dm2 = 1./opt.R2;
dm6 = dm2 * dm2 * dm2;
opt.Vt = 4*dm6*(dm6-1);
return opt;
}
double d[2];
//double theta;
int m;
double vx,vy,rsq,vf;
srand48(time(NULL));
a[0] = sqrt(opt.N);
a[1] = opt.N/a[0];
b = opt.N%a[0];
d[0] = opt.L/(a[0]);
if(b)// se b=0 => if falso => else
d[1] = opt.L/(a[1]+1);
else
d[1] = opt.L/a[1];
n = 0;
for(i = 0; i < a[0] ; i++){
for(j = 0; j < a[1]; j++){
//theta = 2*M_PI*drand48();
p[n].x[0] = (0.5 + i /* + 0.25*cos(theta) */)*d[0];
p[n].x[1] = (0.5 + j /* + 0.25*sin(theta) */)*d[1];
n++;
}
}
if(b){// se b=0 => if falso => non fa nulla
d[0] = opt.L / b;
for(i = 0 ; i < b; i++){
//theta = 2*M_PI*drand48();
p[n].x[0] = (0.5 + i /* + 0.25*cos(theta) */)*d[0];
p[n].x[1] = (0.5 + a[1] /* + 0.25*sin(theta) */)*d[1];
n++;
}
}
// distribuzione di Maxwell-Boltzman delle velocità
// v[i,j] = sqrt(kB*T/m[i])*G(0,1), j = {x, y}
// G(0,1) distribuzione gaussiana centrata in 0 con varianza 1
m = opt.N - opt.N%2;
for(j=0;j<2;j++){
for(i=0;i<m;i+=2){
do{
vx=2*drand48()-1;
vy=2*drand48()-1;
rsq=vx*vx+vy*vy;
}while(rsq>=1 || rsq==0);
vf=sqrt(-opt.T/opt.mi*2*log(rsq)/rsq);// kB == 1
p[i].v[j]=vx*vf;
p[i+1].v[j]=vy*vf;
}// qui i = opt.N -1
if(m < opt.N){
do{
vx=2*drand48()-1;
APPENDICE D. BOX.C 67
vy=2*drand48()-1;
rsq=vx*vx+vy*vy;
}while(rsq>=1 || rsq==0);
vf=sqrt(-opt.T/opt.mi*2*log(rsq)/rsq);
p[i].v[j]=vx*vf;
}
}
p[0].v[0] = p[0].v[1] = vx = vy = 0;// p[0] è speciale
for(i=0;i<opt.N;i++){
vx += p[i].v[0];
vy += p[i].v[1];
}
vx /= opt.N;
vy /= opt.N;
/* fprintf(stderr,"vmx = %f\nvmy = %f\n",vx,vy); */
for(i=0;i<opt.N;i++){
p[i].v[0] -= vx;
p[i].v[1] -= vy;
p[i].l[0] = p[i].l[1] = 0;
}
}
}
fclose(sp);
return p;
}
E[0]=E[1]=E[2]=0;
//reticolo periodico
if(p[0].x[0] < 0){
p[0].l[0]--;
p[0].x[0] += opt.L;
}
else if(p[0].x[0] > opt.L){
p[0].l[0]++;
p[0].x[0] -= opt.L;
}
if(p[0].x[1] < 0){
p[0].l[1]--;
p[0].x[1] += opt.L;
}
else if(p[0].x[1] > opt.L){
p[0].l[1]++;
p[0].x[1] -= opt.L;
}
//reticolo periodico
if(p[i].x[0] < 0){
p[i].l[0]--;
p[i].x[0] += opt.L;
}
else if(p[i].x[0] > opt.L){
p[i].l[0]++;
p[i].x[0] -= opt.L;
}
if(p[i].x[1] < 0){
p[i].l[1]--;
p[i].x[1] += opt.L;
}
else if(p[i].x[1] > opt.L){
p[i].l[1]++;
p[i].x[1] -= opt.L;
}
//////////////////////////////
// calcolo di F(t+dt)
for(a = 0; a < opt.N-1; a++){
for(b = a+1; b < opt.N; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
if(r[0] > opt.L/2.)
r[0] = r[0] - opt.L;
else if(r[0] < -opt.L/2.)
r[0] = r[0] + opt.L;
r[1] = pp[b]->x[1] - pp[a]->x[1];
if(r[1] > opt.L/2.)
r[1] = r[1] - opt.L;
else if(r[1] < -opt.L/2.)
r[1] = r[1] + opt.L;
r2 = r[0]*r[0] + r[1]*r[1];
if(r2 < opt.R2){
r_2 = 1./r2;
r_6 = r_2*r_2*r_2;
ff = -24*r_6*(2*r_6-1)*r_2;
pp[a]->f[0] += ff*r[0];
pp[a]->f[1] += ff*r[1];
pp[b]->f[0] -= ff*r[0];
pp[b]->f[1] -= ff*r[1];
E[1] += (4*r_6*(r_6-1) - opt.Vt);
}
APPENDICE D. BOX.C 70
}
}
}
E[0] = E[1] + E[2];
E[0] = E[0]/opt.N;
E[1] = E[1]/opt.N;
E[2] = E[2]/opt.N;
return E;
}
E[0]=E[1]=E[2]=0;
// azzeramento celle
for(i = 1; i <= opt.C; i++){
cum[i] = 0;
}
// calcolo di x(t + dt) = x(t) + v(t + dt/2) * dt
// con v(t + dt/2) = v(t) + F(t)/m * dt/2
// sì da considerare correttamente gli urti con le pareti della scatola
p[0].x[0] += (p[0].v[0] + p[0].f[0]/opt.m0*0.5*opt.dt)*opt.dt;
p[0].x[1] += (p[0].v[1] + p[0].f[1]/opt.m0*0.5*opt.dt)*opt.dt;
//reticolo periodico
if(p[0].x[0] < 0){
p[0].l[0]--;
p[0].x[0] += opt.L;
}
else if(p[0].x[0] > opt.L){
p[0].l[0]++;
p[0].x[0] -= opt.L;
}
APPENDICE D. BOX.C 71
p[0].nc = (int)(p[0].x[0]/opt.R) + \
(int)(p[0].x[1]/opt.R)*opt.c;
cum[p[0].nc+1]++;
//reticolo periodico
if(p[i].x[0] < 0){
p[i].l[0]--;
p[i].x[0] += opt.L;
}
else if(p[i].x[0] > opt.L){
p[i].l[0]++;
p[i].x[0] -= opt.L;
}
if(p[i].x[1] < 0){
p[i].l[1]--;
p[i].x[1] += opt.L;
}
else if(p[i].x[1] > opt.L){
p[i].l[1]++;
p[i].x[1] -= opt.L;
}
p[i].nc = (int)(p[i].x[0]/opt.R) + \
(int)(p[i].x[1]/opt.R)*opt.c;
cum[p[i].nc+1]++;
p[i].f[0] = p[i].f[1] = 0;
}
// cumulata
for(i = 1; i < opt.C + 1; i++){
cum[i] += cum[i-1];
}
//ordinamento del vettore pp in funzione della cella occupata dalla particella
pp_sort(pp,opt.N);
//////////////////////////////
// calcolo di F(t+dt)
for(j = 0; j < opt.c-1; j++){
//i = 0;
l = j*opt.c;
for(a = cum[l]; a < cum[l+1]; a++){
cnt++;
if(a < cum[l+1]-1){
for(b = a+1; b < cum[l+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
for(b = cum[l+1]; b < cum[l+2]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
for(b = cum[l+2*opt.c-1]; b < cum[l+2*opt.c]; b++){
r[0] = (pp[b]->x[0] - opt.L) - pp[a]->x[0];//special
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
for(k = 0; k < 2; k++){
for(b = cum[l+opt.c+k]; b < cum[l+opt.c+k+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
}//chiude ciclo a
for(i = 1; i < opt.c-1; i++){
l = j*opt.c + i;
for(a = cum[l]; a < cum[l+1]; a++){
cnt++;
if(a < cum[l+1]-1){
for(b = a+1; b < cum[l+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
APPENDICE D. BOX.C 73
forces(a,b);
}
}
for(b = cum[l+1]; b < cum[l+2]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
for(k = -1; k < 2; k++){
for(b = cum[l+opt.c+k]; b < cum[l+opt.c+k+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
}//chiude ciclo a
}//chiude ciclo i
//i = opt.c-1;
l = j*opt.c + i;
for(a = cum[l]; a < cum[l+1]; a++){
cnt++;
if(a < cum[l+1]-1){
for(b = a+1; b < cum[l+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
for(b = cum[l-opt.c+1]; b < cum[l-opt.c+2]; b++){
r[0] = (pp[b]->x[0] + opt.L) - pp[a]->x[0];//special
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
for(k = -1; k < 1; k++){
for(b = cum[l+opt.c+k]; b < cum[l+opt.c+k+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
for(b = cum[l+1]; b < cum[l+2]; b++){
r[0] = (pp[b]->x[0] + opt.L) - pp[a]->x[0];//special
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}//chiude cicla a
}//chiude ciclo j
//j = opt.c-1;
//i = 0;
l = j*opt.c;
APPENDICE D. BOX.C 74
}//chiude ciclo a
}//chiude ciclo i
//i = opt.c-1;
l = j*opt.c + i;
for(a = cum[l]; a < cum[l+1]; a++){
cnt++;
if(a < cum[l+1]-1){
for(b = a+1; b < cum[l+1]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
}
for(b = cum[l-opt.c+1]; b < cum[l-opt.c+2]; b++){
r[0] = (pp[b]->x[0] + opt.L) - pp[a]->x[0];//special
r[1] = pp[b]->x[1] - pp[a]->x[1];
forces(a,b);
}
for(k = -1; k < 1; k++){
for(b = cum[opt.c-1+k]; b < cum[opt.c+k]; b++){
r[0] = pp[b]->x[0] - pp[a]->x[0];
r[1] = (pp[b]->x[1] + opt.L) - pp[a]->x[1];//special
forces(a,b);
}
}
for(b = cum[0]; b < cum[1]; b++){
r[0] = (pp[b]->x[0] + opt.L) - pp[a]->x[0];//special
r[1] = (pp[b]->x[1] + opt.L) - pp[a]->x[1];//special
forces(a,b);
}
}//chiude ciclo a
if(cnt != opt.N){
fprintf(stderr,"cnt = %3d\n",cnt);
endwin();
exit(-1);
}
}
E[0] = E[1] + E[2];
APPENDICE D. BOX.C 76
E[0] = E[0]/opt.N;
E[1] = E[1]/opt.N;
E[2] = E[2]/opt.N;
return E;
}
break;
swap(pb,pc,tmp);
pb++;
pc--;
}
pn=pp+n;
s=min(pa-pp,pb-pa);
pv=pp;
while(s>0){
swap(pv,pb-s,tmp);
pv++;
s--;
}
s=min(pd-pc,pn-pd-1);
while(s>0){
swap(pb,pn-s,tmp);
pb++;
s--;
}
if((s=pb-pa) > 1)
pp_sort(pp,s);
if((s=pd-pc) > 1)
pp_sort(pn-s,s);
}
Appendice E
measure.c
#include <stdio.h>
#include <stdlib.h>
78
BIBLIOGRAFIA 79
Bibliografia