Medidas dinâmicas: mudanças entre as edições

De Física Computacional
Ir para navegação Ir para pesquisar
Sem resumo de edição
Sem resumo de edição
Linha 22: Linha 22:
A equação acima é válida para simulações em duas dimensões. Assim, este é um método amplamente usado para quantificar a difusão do sistema. Qualitativamente, classifica-se os sistemas enquanto ao MSD da seguinte forma:
A equação acima é válida para simulações em duas dimensões. Assim, este é um método amplamente usado para quantificar a difusão do sistema. Qualitativamente, classifica-se os sistemas enquanto ao MSD da seguinte forma:


:<math> \lim_{t \to \inf} \langle (\vec{r}-\vec{r_0})^2 \rangle = <r^{2}_c> </math>: Regime confinado  
:<math> \lim_{t \to \inf} \langle (\vec{r}-\vec{r_0})^2 \rangle = \langle r^{2}_c \rangle </math>: Regime confinado  


:<math> \langle (\vec{r}-\vec{r_0})^2 \rangle \propto t^{\alpha}, 0<\alpha<1</math>: Regime subdifusivo
:<math> \langle (\vec{r}-\vec{r_0})^2 \rangle \propto t^{\alpha}, 0<\alpha<1</math>: Regime subdifusivo
Linha 44: Linha 44:
</pre>
</pre>


Alocaremos dinamicamente na memória um vetor double com o tamanho de passos máximo. Também será necessário vetores para armazenarmos as posições de referência de cada partícula (NP = Número de partículas).
Alocaremos dinamicamente na memória um vetor ''double'' com o tamanho de passos máximo. Também será necessário vetores para armazenarmos as posições de referência de cada partícula (''NP'' = Número de partículas).


<pre>
<pre>
double *x_zero  = (double *) malloc( NP * sizeof(double) ); //Valores de posição x de referência
double *x_zero  = (double *) malloc( NP * sizeof(double) ); //Valores de x de referência
double *y_zero  = (double *) malloc( NP * sizeof(double) ); //Valores de posição y de referência
double *y_zero  = (double *) malloc( NP * sizeof(double) ); //Valores de y de referência
double *msd = (double *) malloc( numMSD * sizeof(double) ); //Armazenaremos os valores de MSD(t) aqui
double *msd = (double *) malloc( numMSD * sizeof(double) ); //Valores de deslocamento MSD(t)
</pre>
</pre>


Declararemos também uma assinatura da função ''meansquaredisplacement''.  Para ela, será necessário enviar as posições atuais, as posições de referência, o vetor onde armazenamos os valores de deslocamento e também a quantidade de passos a frente da posição de referencia estamos.
Declararemos também uma assinatura da função ''MSDf''.  Para ela, será necessário enviar as posições atuais, as posições de referência, o vetor onde armazenamos os valores de deslocamento e também a quantidade de passos a frente da posição de referencia estamos.


<pre>
<pre>
void meansquaredisplacement (double *x, double *y, double *x_zero, double *y_zero, double *msd, int ref);
void MSDf (double *x, double *y, double *x_zero, double *y_zero, double *msd, int ref);
</pre>
</pre>


No corpo principal do programa, chamaremos a função ''meansquaredisplacement''. Tomaremos o cuidado de garantir que calcularemos o MSD após atingirmos um ponto de equilíbrio do sistema (assim, ignoraremos os primeiros ''numMSD'' passos com um ''if'' ).
No corpo principal do programa, chamaremos a função ''MSDf''. Tomaremos o cuidado de garantir que calcularemos o MSD após atingirmos um ponto de equilíbrio do sistema (assim, ignoraremos os primeiros ''numMSD'' passos com um ''if'' ).


Manteremos também um ''counter'', para sabermos quantas vezes passamos por esta função e acumulamos dados no vetor msd. Consideramos que o counter é igual para todos os valores de <math>\Delta t</math>. Caso isso não seja verdade, é necessário um vetor que contabiliza quantos vezes calculou-se o MSD para cada intervalo.
Manteremos também um ''counter'', para sabermos quantas vezes passamos por esta função e acumulamos dados no vetor msd. Consideramos que o counter é igual para todos os valores de <math>\Delta t</math>. Caso isso não seja verdade, é necessário um vetor que contabiliza quantos vezes calculou-se o MSD para cada intervalo.
Linha 65: Linha 65:


if(passo >= numMSD){
if(passo >= numMSD){
  meansquaredisplacement(x, y, x_zero, y_zero, msd, passo % numMSD);
  MSDf(x, y, x_zero, y_zero, msd, passo % numMSD);
counter++;
counter++;
}
}
Linha 73: Linha 73:
Note que o valor de ''passo%numMSD'' varia de 0, quanto tomaremos nossos valores de referência, até  ''numMSD-1'' que será o nosso maior intervalo de passos. No caso deste programa calculamos o MSD para cada <math>\Delta t</math>. Geralmente programas que não apresentam essa necessidade, o que pode ser facilmente ajustado.
Note que o valor de ''passo%numMSD'' varia de 0, quanto tomaremos nossos valores de referência, até  ''numMSD-1'' que será o nosso maior intervalo de passos. No caso deste programa calculamos o MSD para cada <math>\Delta t</math>. Geralmente programas que não apresentam essa necessidade, o que pode ser facilmente ajustado.


Então, teremos o corpo da função ''meansquaredisplacement'', que, caso o parâmetro ''ref'' é zero, toma as posições atuais como referência. Ademais, calcula a diferença entre a posição atual e a posição de referência, fazendo a média sobre essa informação das partículas e salvando no vetor MSD.
Então, teremos o corpo da função ''MSDf'', que, caso o parâmetro ''ref'' é zero, toma as posições atuais como referência. Se não, calcula a diferença entre a posição atual e a posição de referência, fazendo a média sobre essa informação das partículas e salvando no vetor ''msd''.


<pre>
<pre>
void meansquaredisplacement (double *x, double *y, double *x_zero, double *y_zero, double *msd, int ref){
void MSDf (double *x, double *y, double *x_zero, double *y_zero, double *msd, int ref){


int i;
int i;


if(ref == 0) //Se estamos no tempo de referência, salvamos a posição atual
if(ref == 0){ //Se estamos no tempo de referência, salvamos a posição atual
   for(i=0; i<NP; i++){
   for(i=0; i<NP; i++){
     x_zero[i]=x[i];
     x_zero[i]=x[i];
     y_zero[i]=y[i];
     y_zero[i]=y[i];
}
}
 
}else{
double aux=0; // Essa variável irá acumular a soma dos deslocamentos quadráticos
double aux=0; // Essa variável irá acumular a soma dos deslocamentos quadráticos


Linha 93: Linha 93:
msd[ ref ] += aux/NP; // Então acumularemos o deslocamento quadrático médio
msd[ ref ] += aux/NP; // Então acumularemos o deslocamento quadrático médio
                       // por partícula para um intervalo ref de passos no vetor msd.
                       // por partícula para um intervalo ref de passos no vetor msd.
}


}
}
Linha 103: Linha 104:
                           //valor de intervalo de passos ref.
                           //valor de intervalo de passos ref.


for(i=0; i<numMSD; i++){
for(i=1; i<numMSD; i++){
fprintf(arquivo, "%lf\t%lf\n", i*dt, (double)msd[i]/counter); //Impressão
fprintf(arq, "%lf\t%lf\n", i*dt, (double)msd[i]/counter); //Impressão


</pre>
</pre>
No arquivo apontado por ''arq'', constará ao final do programa:
<pre>
0.010000 0.000145
0.020000 0.000580
0.030000 0.001303
0.040000 0.002314
...            ...
</pre>
Onde a primeira coluna é a diferença entre o tempo da medição e o tempo de referência. A segunda coluna é o valor de <math>\langler^{2}\rangle</math> para este intervalo de tempo.


== Análise de resultados e exemplos ==
== Análise de resultados e exemplos ==

Edição das 13h50min de 6 de maio de 2016

[Página em construção]

Em Dinâmica Molecular são chamadas de Medidas (ou Propriedades) Dinâmicas aquelas características do sistema que variam no tempo. Aqui, apresentaremos duas medidas dinâmicas de interessante importância: o deslocamento quadrático médio e a correlação entre velocidades.

Deslocamento quadrático médio

Uma introdução teórica

O Deslocamento quadrático médio, do inglês Mean square displacement (MSD), é uma medida da capacidade de dispersão (difusão) das partículas do sistema. Ela representa a média dos quadrados dos deslocamentos em relação à uma posição anterior de referência de cada partícula (Note que a média dos deslocamentos das partículas é nula, pois o centro de massa não se move, por isso a necessidade de tomarmos os quadrados). Matematicamente, podemos expressar:

Perceba que o MSD é uma função do tempo (na verdade, do intervalo de tempo) e portanto estamos interessados em estudar como esta função varia no tempo.

Em dinâmicas com fases líquidas e gasosas, teremos então o fenômeno da dispersão. As partículas irão "caminhar" por todo o espaço permitido em um movimento aleatório. Este movimento é conhecido como movimento Browniano e fui estudando por grandes cientistas, como Albert Einstein. Einstein consegiu modelar o deslocamento quadrático médio como uma função linear do tempo, e determinou uma constante chamada de constante de difusão (D):

A equação acima é válida para simulações em duas dimensões. Assim, este é um método amplamente usado para quantificar a difusão do sistema. Qualitativamente, classifica-se os sistemas enquanto ao MSD da seguinte forma:

: Regime confinado
: Regime subdifusivo
: Regime normalmente difusivo
: Regime superdifusivo

Em uma dinâmica com um estado sólido, esperamos que as partículas apenas vibrem, e não se deslocam grandes distâncias. Portanto, o MSD terá um limite e diremos que o regime é confinado, pois as partículas não têm espaço para se difundirem.

A imagem ao lado mostra o MSD em função do tempo para cada um destes casos.

Implementação computacional

Primeiro é importante ressaltar que precisamos comprar a posição da partícula com a posição da mesma partícula em um tempo anteior de referência, sem levar em consideração o condições de contorno periódicas. Nos trechos de códigos apresentados a seguir, consideraremos que as posições não são corrigidas quanto à este aspecto.

Difiniremos primeiro um período de passos em que analisaremos o MSD.

#define numMSD 1000 // Período do MSD

Alocaremos dinamicamente na memória um vetor double com o tamanho de passos máximo. Também será necessário vetores para armazenarmos as posições de referência de cada partícula (NP = Número de partículas).

double *x_zero  = (double *) malloc( NP * sizeof(double) ); //Valores de x de referência
double *y_zero  = (double *) malloc( NP * sizeof(double) ); //Valores de y de referência
double *msd = (double *) malloc( numMSD * sizeof(double) ); //Valores de deslocamento MSD(t)

Declararemos também uma assinatura da função MSDf. Para ela, será necessário enviar as posições atuais, as posições de referência, o vetor onde armazenamos os valores de deslocamento e também a quantidade de passos a frente da posição de referencia estamos.

void MSDf (double *x, double *y, double *x_zero, double *y_zero, double *msd, int ref);

No corpo principal do programa, chamaremos a função MSDf. Tomaremos o cuidado de garantir que calcularemos o MSD após atingirmos um ponto de equilíbrio do sistema (assim, ignoraremos os primeiros numMSD passos com um if ).

Manteremos também um counter, para sabermos quantas vezes passamos por esta função e acumulamos dados no vetor msd. Consideramos que o counter é igual para todos os valores de . Caso isso não seja verdade, é necessário um vetor que contabiliza quantos vezes calculou-se o MSD para cada intervalo.


if(passo >= numMSD){
 		MSDf(x, y, x_zero, y_zero, msd, passo % numMSD);
		counter++;
	}

Note que o valor de passo%numMSD varia de 0, quanto tomaremos nossos valores de referência, até numMSD-1 que será o nosso maior intervalo de passos. No caso deste programa calculamos o MSD para cada . Geralmente programas que não apresentam essa necessidade, o que pode ser facilmente ajustado.

Então, teremos o corpo da função MSDf, que, caso o parâmetro ref é zero, toma as posições atuais como referência. Se não, calcula a diferença entre a posição atual e a posição de referência, fazendo a média sobre essa informação das partículas e salvando no vetor msd.

void MSDf (double *x, double *y, double *x_zero, double *y_zero, double *msd, int ref){

int i;

if(ref == 0){ //Se estamos no tempo de referência, salvamos a posição atual
  for(i=0; i<NP; i++){
    x_zero[i]=x[i];
    y_zero[i]=y[i];
	}
}else{
double aux=0; // Essa variável irá acumular a soma dos deslocamentos quadráticos

for(i=0; i<NP; i++)
	aux += (x[i]-x_zero[i])*(x[i]-x_zero[i]) + (y[i]-y_zero[i])*(y[i]-y_zero[i]);

msd[ ref ] += aux/NP; // Então acumularemos o deslocamento quadrático médio
                      // por partícula para um intervalo ref de passos no vetor msd.
}

}

Por fim, depois do laço temporal, dividiremos o valor de counter por numMSD, dando assim o valor de vezes em que se acumulou o valor do MSD por intervalo de passos. Para imprimirmos, usaremos o intervalo de passo em intervalo de tempo reduzido, multiplicando o número de passos pelo tamanho de cada passo.

counter = counter/numMSD; //Counter marcará quantas vezes se passou pela função para cada 
                          //valor de intervalo de passos ref.

for(i=1; i<numMSD; i++){
	fprintf(arq, "%lf\t%lf\n", i*dt, (double)msd[i]/counter); //Impressão

No arquivo apontado por arq, constará ao final do programa:

0.010000	0.000145
0.020000	0.000580
0.030000	0.001303
0.040000	0.002314
...             ...

Onde a primeira coluna é a diferença entre o tempo da medição e o tempo de referência. A segunda coluna é o valor de Falhou ao verificar gramática (função desconhecida '\langler'): {\displaystyle \langler^{2}\rangle} para este intervalo de tempo.

Análise de resultados e exemplos

Correlação de velocidades

A Correlação de velocidades é uma medida da variação das velocidades das partículas em um sistema.


Referências

  • Frenkel, Daan and Smit, Berend (2001). Understanding Molecular Simulation. Academic Press.