Come migliorare le prestazioni di un codice di dinamica molecolare
Ogni volta che facciamo la lista dei vicini …. do i=1,N do j=1,N ….. end do CICLO DOPPIO SUL NUMERO DI ATOMI. SCALA CON N 2 (anche se lo implemento come do i=1,N do j=i+1,N …. end do end do)
I cicli per calcolare forze/energia potenziale sono del tipo … do i=1,N do j=1,nvicini(i) ….. end do ovvero scalano in modo lineare con N. Pensarci: parto da una cella di N atomi. Diciamo che ogni atomo ha M vicini, allora il ciclo porta a NxM operazioni. Ora raddoppio la cella. Il numero di vicini è sempre lo stesso, quindi le operazioni sono 2NxM -> scaling lineare. Ma lo scaling complessivo del codice è determinato dalla chiamata ai vicini che, se raddoppio la cella, richiede 2Nx2N operazioni, e quindi scala col quadrato. DOMANDA: MA PERCHE’ ALLORA MI COMPLICO LA VITA FACENDO I VICINI QUANDO A PARITA’ DI SCALING POTREI FARE ….
Calcolo energia potenziale (stesso per le forze) senza passare per i vicini … do i=1,N do j=1,N calcolo distanza tra i e j, se è minore di rc, allora E=E+… end do il codice continuerebbe a scalare con il quadrato degli atomi ed eviterei i problemi connessi a costruire nvicini(i), e ivicini(i,j). Il punto chiave è che nessun codice di dinamica molecolare veramente utile (ovvero tale da permettere simulazioni con oltre 1 milione di atomi) scala con N 2. L’utilizzo del concetto di “vicino” (possibile solo se posso introdurre un raggio di cutoff per il potenziale) permette di implementare dei trucchi piuttosto semplici che pur lasciando del tutto invariata la dinamica migliorano le prestazioni del codice.
Le gabbie di Verlet Fissiamo l’attenzione su un atomo (blu) del nostro sistema: sappiamo che solo gli atomi con distanza minore di rc da lui sono rilevanti (in rosso). Gli altri (verdi) non influenzano la sua energetica/dinamica. rc
Le gabbie di Verlet Durante la dinamica l’atomo di riferimento si sposta portandosi appresso la sua sfera, e parimenti si spostano gli altri atomi. Per semplicità mettiamoci in un sistema di riferimento solidale con l’atomo di riferimento. Immaginiamo di essere al passo zero, di calcolare la lista dei vicini e poi di evolvere il sistema senza aggiornarla più. rc
Le gabbie di Verlet Se le distanze cambiano, nelle routines delle forze e dell’energia potenziale me ne accorgo perché le ricalcolo ogni volta. Finche’ la lista dei vicini è invariata la dinamica è esatta, e il costo computazionale è inferiore. rc
Le gabbie di Verlet Se le distanze cambiano, nelle routines delle forze e dell’energia potenziale me ne accorgo perché le ricalcolo ogni volta. Finche’ la lista dei vicini è invariata la dinamica è esatta, e il costo computazionale è inferiore. rc
Le gabbie di Verlet Se un atomo esce dalla sfera non è un problema dato che nel calcolo delle forze/dell’energia mi accorgo che la sua distanza è superiore a rc e pongo uguale a zero il suo contributo rc
Le gabbie di Verlet Se un atomo entra nella sfera è invece un disastro dato che se non aggiorno la lista dei vicini non mi accorgo della sua presenza. rc
Le gabbie di Verlet Posso limitare il numero delle chiamate ai vicini senza commettere un simile errore? Vediamo lo schema seguente. Introduco un secondo raggio, fittizo, rv>rc e calcolo la lista dei vicini nella sfera grande. Gli atomi tra le due sfere sono vicini ma non contribuiscono a forza/energia. rc
Le gabbie di Verlet Se un atomo passa dalla crosta sferica alla vera sfera di cutoff, non c’e’ alcun problema. Dato che è in lista, mi accorgo che la sua distanza è diventata inferiore a rc, e calcolo il suo contributo. rc
Le gabbie di Verlet Se un atomo passa dalla crosta sferica alla regione esterna non c’e’ alcun problema. Il suo contributo a forza/energia nullo era e nullo rimane. rc
Le gabbie di Verlet Se un atomo passa dalla sfera interna alla crosta sferica, non c’e’ alcun problema. Mi accorgo che la sua distanza è ora maggiore di rc e non calcolo il suo contributo. rc
Le gabbie di Verlet Se un atomo passa dalla sfera interna alla regione esterna non c’e’ alcun problema. Mi accorgo che la sua distanza è ora maggiore di rc e non calcolo il suo contributo. rc
Le gabbie di Verlet Se un atomo passa dalla regione esterna alla sfera interna allora ho problemi: non mi accorgo di avere un nuovo vicino. Come evitarlo? rc
Le gabbie di Verlet Al passo zero, quando calcolo la lista dei vicini per la prima volta, salvo le posizioni. Ad ogni passo successivo calcolo la distanza massima di cui si è mosso un atomo dalla configurazione salvata. Dato che sono preoccupato che un atomo possa passare dalla regione esterna alla sfera interna, controllo che rc (il fattore ½ tiene conto del fatto che anche l’atomo di cui sto calcolando i vicini si può muovere) Se la diseguaglianza è soddisfatta vado avanti con la dinamica, se no riaggiorno la lista dei vicini, e aggiorno la configurazione da usare come riferimento.
Implementazione call vicini(rv,….) do i=1,natoms xsave(i)=x(i)!stesso per y e z end do dmax=0.d0 do imd=1,nmd!passi di dinamica molecolare do i=1,natoms x(i)=x(i)+… algoritmo di Verlet ddx=x(i)-xsave(i) + aggiungi PBC e ripeti su y e z dd=sqrt(ddx*ddx+ddy*ddy+ddz*ddz) if(dd.ge.dmax)dmax=dd end do if(dd.ge.0.4*(rv-rc))then!uso 0.4 per essere tranquillo, basterebbe 0.5 … call vicini(rv,…) ncall=ncall+1!voglio sapere quante volte chiama i vicini..,. dmax=0.d0 do i=1,natoms xsave(i)=x(i)… end do end do!chiude la dinamica molecolare
Scelte infelici: rv=rc + epsilon (epsilon -> 0) - ricalcolo sempre i vicini rv molto grande (non ricalcolo mai i vicini ma calcolo forza ed energia sull’intero sistema). Consiglio: rv=rc+( ) Angstrom dovrebbe abbattere i costi computazionali di un fattore in tipici range di temperatura. P.S. Il metodo delle gabbie di Verlet puo’ ovviamente essere implementato anche nello steepest descent. Aspettatevi pochissime chiamate ai vicini!!!
OK, il nostro codice ora va molto piu’ veloce. Posso usarlo per studiare atomi? NO!!! Purtroppo la lista dei vicini la devo pur sempre calcolare almeno una volta. La sua determinazione per 10 8 atomi è semplicemente impossibile nei nostri computers! E allora? Si combinano le gabbie di Verlet con un secondo trucco LINKED CELLS. Non lo facciamo. Solo l’idea …
Linked cells (sketch). 1) Considera l’intera cella di simulazione
Linked cells (sketch). 2) Dividi la cella di simulazione in sottocelle di lato superiore al raggio di cutoff …
Linked cells (sketch). 3) Assegna ad ogni atomo la propria cella
Linked cells (sketch). 4) Cerca i sui vicini solo all’interno della sua cella e nelle celle vicine. Gabbie di Verlet + Linked cells = codice che scala linearmente con N
Attenzione! I trucchi per “linearizzare” la dipendenza di un codice da N richiedono sempre un certo “overhead”. Risultato: N Velocità del codice Se uno è solo interessato a sistemi molto piccoli può essere addirittura svantaggioso introdurre tecniche per cambiare lo scaling col numero di atomi! Lo scaling lineare è invece del tutto essenziale per studiare sistemi con oltre un milione di particelle.