Grupo2 - Ondas1: mudanças entre as edições
Linha 259: | Linha 259: | ||
Cálculo da onda em um tempo <math>t=t_f</math>: | Cálculo da onda em um tempo <math>t=t_f</math>: | ||
Lax-Friedrichs: | |||
<source lang="c"> | |||
#include<stdio.h> | |||
#include<math.h> | |||
#include<string.h> | |||
#include<stdlib.h> | |||
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k); | |||
void main() | |||
{ | |||
FILE *arq; | |||
arq = fopen("lax.txt", "w+"); | |||
int tmax, i, j, jmax; | |||
//tamanho da corda: jmax-1 | |||
jmax = 50; | |||
//u: posicao da corda | |||
/* u_old em t-1 */ | |||
/* u_now em t */ | |||
/* u_new em t+1 */ | |||
//k = dt/dx | |||
double u_new[jmax], t, u_old[jmax], u_now[jmax], k, erro; | |||
//tmax: tempo final | |||
tmax = 100; | |||
k = 0.2; | |||
//condicao inicial | |||
for (j = 0 ; j < jmax ; j++) | |||
{ | |||
u_now[j] = sin(M_PI*j/(jmax - 1)); | |||
} | |||
//condicao de contorno | |||
u_old[0]=0; | |||
u_old[jmax-1]=0; | |||
u_new[0] = 0; | |||
u_new[jmax-1] = 0; | |||
//calculo de u para t=-dt, utilizando o metodo de leapfrog - aqui usamos que du/dt = 0 em t=0 | |||
for (j = 1; j< jmax-1 ; j++) | |||
{ | |||
u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]); | |||
} | |||
//atualizacao da onda | |||
for(t = 0 ; t < tmax ; t+=k) | |||
{ | |||
atualizar_onda(u_new,u_now,u_old,jmax,k); | |||
memcpy(u_old,u_now, sizeof(double)*jmax); | |||
memcpy(u_now,u_new, sizeof(double)*jmax); | |||
} | |||
//onda no tempo t=tmax | |||
for(j=0; j<jmax; j++) | |||
{ | |||
fprintf(arq,"%d %lf\n", j, u_new[j]); | |||
} | |||
fclose(arq); | |||
} | |||
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k) | |||
{ | |||
int j; | |||
//para j=1 e j=jmax-2 (penultimas posições), necessitamos de u em x=-1 e x=jmax, respectivamente, sendo que essas posicoes ficam fora do vetor (vai de 0 a jmax-1). Aqui, foi feito u(x=-1)=-u(x=1) e u(x=jmax)=-u(x=jmax-2) | |||
j=1; | |||
u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (u_old_[j+2] - 2 * u_old_[j] - u_old_[j]); | |||
for(j = 2 ; j < jmax-2 ; j++) | |||
{ | |||
u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (u_old_[j+2] - 2 * u_old_[j] + u_old_[j-2]); | |||
} | |||
j=jmax-2; | |||
u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (-u_old_[j] - 2 * u_old_[j] + u_old_[j-2]); | |||
} | |||
<source> | |||
Lax-Wendroff: | |||
<source lang="c"> | |||
#include<stdio.h> | |||
#include<math.h> | |||
#include<string.h> | |||
#include<stdlib.h> | |||
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k); | |||
void main() | |||
{ | |||
FILE *arq; | |||
arq = fopen("laxw.txt", "w+"); | |||
int tmax,i,j,jmax; | |||
//tamanho da corda: jmax-1 | |||
jmax = 50; | |||
//u: posicao da corda | |||
/* u_old em t-1 */ | |||
/* u_now em t */ | |||
/* u_new em t+1 */ | |||
//k = dt/dx | |||
double u_new[jmax],t,u_old[jmax],u_now[jmax],k,erro; | |||
//tmax: tempo final | |||
tmax = 100; | |||
k = 0.2; | |||
//condição inicial | |||
for (j = 0 ; j < jmax ; j++) | |||
{ | |||
u_now[j] = sin(M_PI*j/(jmax - 1)); | |||
} | |||
//condição de contorno | |||
u_old[0] = 0; | |||
u_old[jmax-1] = 0; | |||
u_new[0] = 0; | |||
u_new[jmax-1] = 0; | |||
//cálculo de u para t=-dt, utilizando o método de leapfrog - aqui usamos que du/dt = 0 em t=0 | |||
for (j = 1; j< jmax-1 ; j++) | |||
{ | |||
u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]); | |||
} | |||
//atualização da onda | |||
for(t = 0 ; t < tmax ; t+=k) | |||
{ | |||
atualizar_onda(u_new,u_now,u_old,jmax,k); | |||
memcpy(u_old,u_now, sizeof(double)*jmax); | |||
memcpy(u_now,u_new, sizeof(double)*jmax); | |||
} | |||
//onda no tempo t=tmax | |||
for(j=0; j<jmax; j++) | |||
{ | |||
fprintf(arq,"%d %lf\n", j, u_new[j]); | |||
} | |||
fclose(arq); | |||
} | |||
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k) | |||
{ | |||
int j; | |||
//para j=1 e j=jmax-2 (penúltimas posições), necessitamos de u em x=-1 e x=jmax, respectivamente, sendo que essas posições ficam fora do vetor (vai de 0 a jmax-1). Aqui, foi feito u(x=-1)=-u(x=1) e u(x=jmax)=-u(x=jmax-2) | |||
j=1; | |||
u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (0.5 * u_old_[j+2] - u_old_[j+1] + u_old_[j] - u_old_[j-1] - 0.5 * u_old_[j] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]); | |||
for(j = 2 ; j < jmax-2 ; j++) | |||
{ | |||
u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (0.5 * u_old_[j+2] - u_old_[j+1] + u_old_[j] - u_old_[j-1] + 0.5 * u_old_[j-2] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]); | |||
} | |||
j=jmax-2; | |||
u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (-0.5 * u_old_[j] - u_old_[j+1] + u_old_[j] - u_old_[j-1] + 0.5 * u_old_[j-2] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]); | |||
} | |||
<source> | |||
Leapfrog: | |||
<source lang="c"> | |||
#include<stdio.h> | |||
#include<math.h> | |||
#include<string.h> | |||
#include<stdlib.h> | |||
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k); | |||
void main() | |||
{ | |||
FILE *arq; | |||
arq = fopen("leapfrog.txt", "w+"); | |||
int i, j, jmax; | |||
//tamanho da corda: jmax-1 | |||
jmax = 50; | |||
//u: posicao da corda | |||
/* u_old em t-1 */ | |||
/* u_now em t */ | |||
/* u_new em t+1 */ | |||
//k = dt/dx | |||
double u_new[jmax], t, u_old[jmax], u_now[jmax], k, erro, tmax; | |||
//tmax: tempo final | |||
tmax = 100; | |||
k = 0.2; | |||
//condicao inicial | |||
for (j = 0 ; j < jmax ; j++) | |||
{ | |||
u_now[j] = sin(M_PI*j/(jmax - 1)); | |||
} | |||
//condicao de contorno | |||
u_new[0] = 0; | |||
u_new[jmax-1] = 0; | |||
u_old[0] = 0; | |||
u_old[jmax-1] = 0; | |||
//calculo de u para t=-dt, utilizando o metodo de leapfrog - aqui usamos que du/dt = 0 em t=0 | |||
for (j = 1; j< jmax-1 ; j++) | |||
{ | |||
u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]); | |||
} | |||
//atualizacao da onda | |||
for(t = 0 ; t < tmax ; t+=k) | |||
{ | |||
atualizar_onda(u_new,u_now,u_old,jmax,k); | |||
memcpy(u_old,u_now, sizeof(double)*jmax); | |||
memcpy(u_now,u_new, sizeof(double)*jmax); | |||
} | |||
for(j=0; j<jmax; j++) | |||
{ | |||
fprintf(arq,"%d %lf\n", j, u_new[j]); | |||
} | |||
fclose(arq); | |||
} | |||
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k) | |||
{ | |||
int j; | |||
for(j = 1 ; j < jmax-1 ; j++) | |||
{ | |||
u_new_[j] = 2 * u_now_[j] - u_old_[j] + pow(k,2) *( u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1] ); | |||
} | |||
} | |||
<source> | |||
Cálculo do erro: | Cálculo do erro: | ||
Lax-Friedrichs: | |||
<source lang="c"> | |||
#include<stdio.h> | |||
#include<math.h> | |||
#include<string.h> | |||
#include<stdlib.h> | |||
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k); | |||
void main() | |||
{ | |||
FILE *arq; | |||
arq = fopen("erro_lax.dat", "w"); | |||
int tmax, i, j, jmax; | |||
//tamanho da corda: jmax-1 | |||
jmax = 50; | |||
//u: posicao da corda | |||
/* u_old em t-1 */ | |||
/* u_now em t */ | |||
/* u_new em t+1 */ | |||
//k = dt/dx (aqui, dx = 1, k=dt) | |||
double u_new[jmax], t, u_old[jmax], u_now[jmax], k, erro; | |||
//tmax: tempo final | |||
tmax = 100; | |||
//variamos o dt para fazer um grafico do erro em função de dt | |||
int n=1; | |||
while( n < 1200) | |||
{ | |||
k = 0.001*n; | |||
//condicao inicial | |||
for (j = 0 ; j < jmax ; j++) | |||
{ | |||
u_now[j] = sin(M_PI*j/(jmax - 1)); | |||
} | |||
//condicao de contorno | |||
u_old[0]=0; | |||
u_old[jmax-1]=0; | |||
u_new[0] = 0; | |||
u_new[jmax-1] = 0; | |||
//calculo de u para t=-dt, utilizando o metodo de leapfrog - aqui usamos que du/dt = 0 em t=0 | |||
for (j = 1; j< jmax-1 ; j++) | |||
{ | |||
u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]); | |||
} | |||
//atualizacao da onda | |||
for(t = 0 ; t < tmax ; t+=k) | |||
{ | |||
//para que o ultimo tempo em que se calcula a posicao seja tmax, independentemente do valor de dt | |||
if(t+k >tmax) | |||
{ | |||
k = tmax -t; | |||
} | |||
atualizar_onda(u_new,u_now,u_old,jmax,k); | |||
memcpy(u_old,u_now, sizeof(double)*jmax); | |||
memcpy(u_now,u_new, sizeof(double)*jmax); | |||
} | |||
//calculo do erro | |||
erro = 0; | |||
for(j = 0 ; j < jmax ; j++) | |||
{ | |||
double analitica = cos((M_PI*t)/(jmax - 1))*sin((M_PI*j)/(jmax - 1)); | |||
erro += fabs(analitica - u_now[j]); | |||
} | |||
erro = erro/jmax; | |||
fprintf(arq,"%.12lf %.12lf\n", n*0.001, erro); | |||
n++; | |||
} | |||
fclose(arq); | |||
} | |||
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k) | |||
{ | |||
int j; | |||
//para j=1 e j=jmax-2 (penultimas posições), necessitamos de u em x=-1 e x=jmax, respectivamente, sendo que essas posicoes ficam fora do vetor (vai de 0 a jmax-1). Aqui, foi feito u(x=-1)=-u(x=1) e u(x=jmax)=-u(x=jmax-2) | |||
j=1; | |||
u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (u_old_[j+2] - 2 * u_old_[j] - u_old_[j]); | |||
for(j = 2 ; j < jmax-2 ; j++) | |||
{ | |||
u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (u_old_[j+2] - 2 * u_old_[j] + u_old_[j-2]); | |||
} | |||
j=jmax-2; | |||
u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (-u_old_[j] - 2 * u_old_[j] + u_old_[j-2]); | |||
} | |||
<source> | |||
Lax-Wendroff: | |||
<source lang="c"> | |||
#include<stdio.h> | |||
#include<math.h> | |||
#include<string.h> | |||
#include<stdlib.h> | |||
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k); | |||
void main() | |||
{ | |||
FILE *arq; | |||
arq = fopen("erro_laxw.dat", "w"); | |||
int tmax,i,j,jmax; | |||
//tamanho da corda: jmax-1 | |||
jmax = 50; | |||
//u: posição da corda | |||
/* u_old em t-1 */ | |||
/* u_now em t */ | |||
/* u_new em t+1 */ | |||
//k = dt/dx (aqui, dx = 1, k=dt) | |||
double u_new[jmax],t,u_old[jmax],u_now[jmax],k,erro; | |||
//tmax: tempo final | |||
tmax = 100; | |||
//variamos o dt para fazer um gráfico do erro em função de dt | |||
int n=1; | |||
while( n < 1200) | |||
{ | |||
k = 0.001*n; | |||
//condição inicial | |||
for (j = 0 ; j < jmax ; j++) | |||
{ | |||
u_now[j] = sin(M_PI*j/(jmax - 1)); | |||
} | |||
//condição de contorno | |||
u_old[0] = 0; | |||
u_old[jmax-1] = 0; | |||
u_new[0] = 0; | |||
u_new[jmax-1] = 0; | |||
//cálculo de u para t=-dt, utilizando o método de leapfrog - aqui usamos que du/dt = 0 em t=0 | |||
for (j = 1; j< jmax-1 ; j++) | |||
{ | |||
u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]); | |||
} | |||
//atualização da onda | |||
for(t = 0 ; t < tmax ; t+=k) | |||
{ | |||
//para que o último tempo em que se calcula a posição seja tmax, independentemente do valor de dt | |||
if(t+k >tmax) | |||
{ | |||
k = tmax -t; | |||
} | |||
atualizar_onda(u_new,u_now,u_old,jmax,k); | |||
memcpy(u_old,u_now, sizeof(double)*jmax); | |||
memcpy(u_now,u_new, sizeof(double)*jmax); | |||
} | |||
//cálculo do erro | |||
erro = 0; | |||
for(j = 0 ; j < jmax ; j++) | |||
{ | |||
double analitica = cos((M_PI*t)/(jmax - 1))*sin((M_PI*j)/(jmax - 1)); | |||
erro += fabs(analitica - u_now[j]); | |||
} | |||
erro = erro/jmax; | |||
fprintf(arq,"%.12lf %.12lf\n", n*0.001, erro); | |||
n++; | |||
} | |||
fclose(arq); | |||
} | |||
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k) | |||
{ | |||
int j; | |||
//para j=1 e j=jmax-2 (penúltimas posições), necessitamos de u em x=-1 e x=jmax, respectivamente, sendo que essas posições ficam fora do vetor (vai de 0 a jmax-1). Aqui, foi feito u(x=-1)=-u(x=1) e u(x=jmax)=-u(x=jmax-2) | |||
j=1; | |||
u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (0.5 * u_old_[j+2] - u_old_[j+1] + u_old_[j] - u_old_[j-1] - 0.5 * u_old_[j] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]); | |||
for(j = 2 ; j < jmax-2 ; j++) | |||
{ | |||
u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (0.5 * u_old_[j+2] - u_old_[j+1] + u_old_[j] - u_old_[j-1] + 0.5 * u_old_[j-2] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]); | |||
} | |||
j=jmax-2; | |||
u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (-0.5 * u_old_[j] - u_old_[j+1] + u_old_[j] - u_old_[j-1] + 0.5 * u_old_[j-2] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]); | |||
} | |||
<source> | |||
Leapfrog: | |||
<source lang="c"> | |||
#include<stdio.h> | |||
#include<math.h> | |||
#include<string.h> | |||
#include<stdlib.h> | |||
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k); | |||
void main() | |||
{ | |||
FILE *arq; | |||
arq = fopen("erro_leapfrog.dat", "w"); | |||
int i, j, jmax; | |||
//tamanho da corda: jmax-1 | |||
jmax = 50; | |||
//u: posicao da corda | |||
/* u_old em t-1 */ | |||
/* u_now em t */ | |||
/* u_new em t+1 */ | |||
//k = dt/dx (aqui, dx = 1, k=dt) | |||
double u_new[jmax], t, u_old[jmax], u_now[jmax], k, erro, tmax; | |||
//tmax: tempo final | |||
tmax = 100; | |||
//variamos o dt para fazer um grafico do erro em função de dt | |||
int n=1; | |||
while( n < 1200) | |||
{ | |||
k = 0.001*n; | |||
//condicao inicial | |||
for (j = 0 ; j < jmax ; j++) | |||
{ | |||
u_now[j] = sin(M_PI*j/(jmax - 1)); | |||
} | |||
//condicao de contorno | |||
u_new[0] = 0; | |||
u_new[jmax-1] = 0; | |||
u_old[0] = 0; | |||
u_old[jmax-1] = 0; | |||
//calculo de u para t=-dt, utilizando o metodo de leapfrog - aqui usamos que du/dt = 0 em t=0 | |||
for (j = 1; j< jmax-1 ; j++) | |||
{ | |||
u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]); | |||
} | |||
//atualizacao da onda | |||
for(t = 0 ; t < tmax ; t+=k) | |||
{ | |||
//para que o ultimo tempo em que se calcula a posicao seja tmax, independentemente do valor de dt | |||
if(t+k >tmax) | |||
{ | |||
k = tmax - t; | |||
} | |||
atualizar_onda(u_new,u_now,u_old,jmax,k); | |||
memcpy(u_old,u_now, sizeof(double)*jmax); | |||
memcpy(u_now,u_new, sizeof(double)*jmax); | |||
} | |||
//calculo do erro | |||
erro = 0; | |||
for(j = 0 ; j < jmax ; j++) | |||
{ | |||
double analitica = cos((M_PI*t)/(jmax - 1))*sin((M_PI*j)/(jmax - 1)); | |||
erro += fabs(analitica - u_now[j]); | |||
} | |||
erro = erro/jmax; | |||
fprintf(arq,"%.12lf %.12lf\n", n*0.001,erro); | |||
n++; | |||
} | |||
fclose(arq); | |||
} | |||
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k) | |||
{ | |||
int j; | |||
for(j = 1 ; j < jmax-1 ; j++) | |||
{ | |||
u_new_[j] = 2 * u_now_[j] - u_old_[j] + pow(k,2) *( u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1] ); | |||
} | |||
} | |||
<source> | |||
'''Equação da onda em duas dimensões:''' | '''Equação da onda em duas dimensões:''' | ||
<source lang="c"> | |||
#include<stdio.h> | |||
#include<math.h> | |||
#include<string.h> | |||
#include<stdlib.h> | |||
#define nx_ 71 | |||
#define ny_ 71 | |||
double gauss( int x, int y, int tam); | |||
double H( int x, int y, int tam); | |||
void atualizar_onda(double u_new[][ny_], double u_now[][ny_], double u_old[][ny_], double lambda[][ny_], double a, double b, double c, int nx, int ny, double rx, double ry); | |||
double delta_u( double rx, double ry, double lambda[][ny_], double u_now[][ny_], int i, int j, int im1, int ip1, int jm1, int jp1); | |||
/* META DADOS */ | |||
// | |||
/* nx_ e ny_ , definidos acima por praticidade, */ | |||
/* setam o tamanho dos vetores. */ | |||
/* */ | |||
/* tmax , tempo total da simulacao */ | |||
/* rx e ry, dt/dx e dy/dt respectivamente */ | |||
/* lambda , mapa do solo (profundidade em (x,y)) */ | |||
// | |||
// | |||
/* u representa a altura do mar em (x,y), sendo: */ | |||
// | |||
/* u_old[x][y] em t = t-1 */ | |||
/* u_now[x][y] em t = t */ | |||
/* u_new[x][y] em t = t+1 */ | |||
// | |||
void main() | |||
{ | |||
FILE *arq; | |||
arq = fopen("onda.txt", "w+"); | |||
int tmax, i, j, t, nx, ny; | |||
nx = nx_; | |||
ny = ny_; | |||
tmax = 300; | |||
double u_new[nx][ny], u_old[nx][ny], u_now[nx][ny], lambda[nx][ny], rx, ry; | |||
rx = 0.25; | |||
ry = 0.25; | |||
// incio loop da condição inicial, | |||
// laco duplo e usado para percorrer matriz nx*ny | |||
for(j = 0 ; j < ny ; j++) | |||
{ | |||
for(i = 0 ; i < nx ; i++) | |||
{ | |||
/* u_now inicial em forma de sino */ | |||
u_now[i][j] = gauss(i,j,nx); | |||
/* lambda inicial em forma de H() */ | |||
lambda[i][j] = H(i,j,nx); | |||
} | |||
} | |||
// fim loop da condição inicial | |||
/* calculo "sintetico" de u_old, pois a atualizacao nao e auto-iniciavel */ | |||
atualizar_onda(u_old, u_now, u_old, lambda, 0.5, 0, 0.5, nx, ny, rx, ry); | |||
//inicio do laço temporal | |||
for(t = 0 ; t < tmax ; t++) | |||
{ | |||
//imprimindo no arquivo com laco duplo | |||
/* calculam-se novos valores */ | |||
atualizar_onda( u_new, u_now, u_old, lambda, 1, 1, 1, nx, ny, rx, ry); | |||
/* matrizes antes novas se tornam antigas */ | |||
/* u_old = u_now, u_now = u_new */ | |||
memcpy(u_old,u_now, sizeof(double)*nx*ny); | |||
memcpy(u_now,u_new, sizeof(double)*nx*ny); | |||
/* OBS: Double tem o valor de 8 bytes na memoria. Como temos uma matriz de nx*ny, pegamos o tamanho*/ | |||
/* de um double e multiplicamos pela dimensao da matriz */ | |||
/* sintaxe memcpy(matriz a ser atualizada, matriz que passa o valor, tamanho em bytes da matriz) */ | |||
} | |||
for(j = 0 ; j < ny ; j++) | |||
{ | |||
for(i = 0 ; i < nx ; i++) | |||
{ | |||
if(i == j){ | |||
fprintf(arq, "%d %d %lf\n", i, j, u_now[i][j]); | |||
} | |||
} | |||
} | |||
/* Linhas em branco ao final de cada tempo para index do gnuplot */ | |||
fprintf(arq,"\n\n"); | |||
fclose(arq); | |||
} | |||
double gauss(int x, int y,int tam) | |||
{ | |||
/* curva inicial em forma de sino*/ | |||
double A, xc, yc, gauss, sigmax, sigmay; | |||
//xc = (tam-1) / 2.; | |||
//yc = (tam-1) / 2.; | |||
xc = 0; | |||
yc = 0; | |||
A = 1; | |||
sigmax = 1; | |||
sigmay = 1; | |||
gauss = A * exp(-0.5*pow(((x-xc)/sigmax),2) -0.5*pow(((y-yc)/sigmay),2)); | |||
return gauss; | |||
} | |||
/* a funcao H corresponde ao formato do terreno, retorna a profundidade em relação a aguas calmas */ | |||
double H(int x, int y,int tam) | |||
{ | |||
/* curva para o formato do terreno em forma de sino virado*/ | |||
double A,xc,yc,h,sigmax,sigmay; | |||
//xc = (tam-1) / 2.; | |||
//yc = (tam-1) / 2.; | |||
A = 1; | |||
sigmax = 1; | |||
sigmay = 1; | |||
xc = 0; | |||
yc = 0; | |||
h = 1 - A * exp(-0.5*pow(((x-xc)/sigmax),2) -0.5*pow(((y-yc)/sigmay),2)); | |||
return h; | |||
} | |||
void atualizar_onda(double u_new[][ny_], double u_now[][ny_], double u_old[][ny_], double lambda[][ny_], double a, double b, double c, int nx, int ny, double rx, double ry) | |||
{ | |||
// DOUBLE U_NEW[][NY_)] SINALIZA PARA O C QUE A FUNÇÃO RECEBERA UMA MATRIZ( TECNICAMENTE RECEBERA O ENDEREÇO NA MEMORIA DA MATRIZ) POR ISSO NÃO É NECESSARIO RETORNAR NENHUM VALOR | |||
// ESTA "TECNICA" É POSSIVEL POIS O NOME DA MATRIZ, NO CASO U_NEW, É NA VERDADE O ENDEREÇO DESSA MATRIZ NA MEMORIA. COMO ESTAMOS PASSANDO O ENDEREÇO NA MEMORIA, A FUNÇÃO CONSEGUE ALTERAR OS VALORES SEM NECESSIDADE DE RETORNO | |||
// PRECISAMOS DECLARAR O [NY_] NA FUNÇÃO POR QUESTÕES TECNICAS. MAS PENSEM NESSA SINTAXE COMO: PASSANDO O ENDEREÇO DA MATRIX PARA A FUNÇÃO, SEM NECESSIDADE DE RETORNO. A FUNÇÃO É LIVRE PARA EDITAR A PROPRIA MATRIZ | |||
int i,j; | |||
// LOOP DUPLO PARA ATUALIZAR AS PARTES INTERNAS DA MATRIZ | |||
for(j = 1 ; j < ny - 1 ; j++) | |||
{ | |||
for(i = 1 ; i < nx - 1 ; i++) | |||
// SEPAREI PARTE DA EQUAÇAO EM OUTRA FUNÇÃO PARA SIMPLIFICAR A VIDA. DELTA_U É SIMPLESMENTE UMA PARTE DA EQUAÇÃO ORIGINAL | |||
u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i+1,j-1,j+1); | |||
} | |||
//PRECISAMOS AGORA ATUALIZAR AS LINHAS E COLUNAS EXTERNAS DA MATRIZ, POIS ESTAS NÃO FORAM INCLUIDAS NO LOOP ANTERIOR. ESTA AÇÃO NÃO ATUALIZA AS PONTAS, OU QUINAS, DA MATRIZ | |||
i = 0; // ATUALiZANDO A PRIMEIRA COLUNA DA MATRIZ | |||
for( j = 1; j < ny - 1 ; j++) | |||
{ | |||
u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i+1,i+1,j-1,j+1); | |||
} | |||
i = nx - 1;// ATUALZANDO A ULTIMA COLUNA DA MATRIZ | |||
for( j = 1; j < ny - 1 ; j++) | |||
{ | |||
u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i-1,j-1,j+1); | |||
} | |||
// ---------------------- // | |||
j = 0; // ATUALZANDO A PRIMEIRA LINHA DA MATRIZ | |||
for( i = 1; i < nx - 1 ; i++) | |||
{ | |||
u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i+1,j+1,j+1); | |||
} | |||
j = ny - 1; // ATUALZANDO A ULTIMA LINHA DA MATRIZ | |||
for( i = 1; i < nx - 1 ; i++) | |||
{ | |||
u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i+1,j-1,j-1); | |||
} | |||
// AGORA VAMOS ATUALIZAR as PONTAS DA MATRIZ. OU CANTOS, SE PREFERIR CHAMAR ASSIM | |||
// PONTA [0][0] | |||
i = 0; | |||
j = 0; | |||
u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i+1,i+1,j+1,j+1); | |||
// PONTA [nx - 1][0] | |||
i= nx - 1; | |||
j= 0; | |||
u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i-1,j+1,j+1); | |||
// PONTA [0][ny -1] | |||
i= 0; | |||
j= ny - 1; | |||
u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i+1,i+1,j-1,j-1); | |||
// PONTA [NX-1][ny -1] | |||
i= nx - 1; | |||
j= ny - 1; | |||
u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i-1,j-1,j-1); | |||
} | |||
double delta_u( double rx, double ry, double lambda[][ny_], double u_now[][ny_], int i, int j, int im1, int ip1, int jm1, int jp1) | |||
{ | |||
//CALCULAMOS AQUI SEPARADO UMA PARTE DA EQUAÇÃO, POIS ELA MUDA DEPENDENDO DO QUE ESTAMOS CALCULANDO. SEJA UMA COLUNA INICIAL OU FINAL OU UM CANTO DA MATRIZ | |||
//PARA ISSO COLOQUEI VALORES AUXILIARES DE IM1, IP1, JM1, JP1 . P DE PLUS E M DE MINUS.POIS ESTES VALORES SAO TROCADOS EM VARIAS PARTES | |||
return ( | |||
pow(rx,2) * ( ((0.5 * (lambda[ip1][j] + lambda[i][j])) * (u_now[ip1][j] - u_now[i][j])) | |||
- ((0.5 * (lambda[i][j] + lambda[im1][j])) * (u_now[i][j] - u_now[im1][j]))) | |||
+ pow(ry,2) * ( ((0.5 * (lambda[i][jp1] + lambda[i][j])) * (u_now[i][jp1] - u_now[i][j])) | |||
- ((0.5 * (lambda[i][j] + lambda[i][jm1])) * (u_now[i][j] - u_now[i][jm1])))); | |||
} | |||
<source> | |||
==Bibliografia== | ==Bibliografia== | ||
<references/> | <references/> |
Edição das 21h00min de 26 de novembro de 2017
Integrantes do grupo: Rodrigo Zamin Ferreira (262692), Leonardo Xavier Rodrigues (262696), Maurício Gomes de Queiroz (264889) e Rodrigo Lopes de Sousa Silva (262705)
Introdução
A modelagem numérica vem se tornando cada vez mais uma ferramenta indispensável para um engenheiro. Tal modelagem pode trazer informações importantes para entender como melhor abordar o desenvolvimento de um projeto, neste caso, um que envolva ondas. Nós, como futuros engenheiros físicos, pensamos em trazer um problema mais "concreto", de engenharia costeira e portuária, que pode ou não surgir em nossas vidas profissionais mas cujo método de solução certamente estará presente. Aqui será apresentado um modelo baseado em uma condição inicial e um perfil topográfico do local estudado que descreve a evolução temporal de uma onda.
Inicialmente, para testarmos os diferentes métodos, utilizaremos a equação da onda em uma dimensão, que é uma equação diferencial parcial de segunda ordem, para modelarmos uma corda:
em que é o deslocamento vertical da corda, é a velocidade de propagação da onda e , com o comprimento da corda.
Podemos reescrever a equação da seguinte forma:
.
Uma vez que os métodos citados abaixo são para equações de primeira ordem, é necessário separarmos a equação em um sistema de equações, fazendo a substituição e , de forma que:
Aqui usaremos , sem perda de generalidade. As condições de contorno utilizadas aqui são (pontas fixas), e as condições iniciais são e
Algoritmos
Apresentaremos aqui três abordagens diferentes para a solução da equação diferencial parcial apresentada, e após, seus respectivos erros associados. A respeito das discretizações, corresponde à posição, e representa o tempo.
Método de Lax-Friedrichs
Esse método de ordem [1] consiste em inicialmente discretizar as equações no esquema FTCS (Forward Time Centered Space), ou seja, discretizando a derivada temporal utilizando os tempos e e a derivada espacial através das posições e :
,
.
Resultando em
,
.
Entretanto, ao se realizar uma análise de estabilidade de Von Neumann, conclui-se que esse método é instável[1] . Para torná-lo estável, é necessário trocarmos os termos e por suas médias espaciais, chegando, assim, na expressão do esquema de Lax-Friedrichs:
,
.
Para obtermos o valor de , que é o nosso objetivo, discretizamos a equação
,
Embora as médias espaciais sejam necessárias para a estabilidade do método, elas introduzem um problema: surge um efeito chamado de dissipação numérica, ou seja, a amplitude da solução diminui com o tempo. Isso pode ser observado através da análise de Von Neumann ou de uma investigação da equação do esquema Lax-Friedrichs [1] . Por este método, observa-se que ao inserirmos as médias, mudamos a equação original do problema, pois agora há também um termo do tipo difusivo (uma derivada segunda), com constante de difusão [1].
Agora vamos unir todas as equações, utilizando, além da equação para obtida acima, as discretizações de e
,
.
Assim, obtemos
.
Método de Leapfrog
Neste método , de ordem [1], utilizamos os pontos intermediários na discretização das equações.
Para temos
,
Para temos
,
Para temos
,
Utilizando o fato de que
,
,
chegamos na equação para
,
o que é equivalente a discretizarmos a equação da onda diretamente, utilizando que, para uma função ,
,
sendo a discretização em .
Método de Lax-Wendroff de Dois Passos
Para este método, de ordem , o primeiro passo consiste em calcular o valor de e utilizando o método de Lax-Friedrichs, para posterior cálculo de e :
,
,
,
,
Agora, no tempo :
,
,
Agrupando as equações,
,
,
E finalmente temos a equação unificada em u, utilizando a expressão para e as discretizações de e , como obtidas na seção sobre o Método de Lax-Friedrichs:
,
Implementação
Ao implementarmos o método, surgem dois problemas: o problema não é auto-inicializável, pois para calcularmos o valor de , necessitamos de (além de ). Entretanto, isto é rapidamente solucionado quando discretizamos a condição inicial de que :
,
ou seja, para o cálculo de , utilizamos que . Através do método de Leapfrog, dessa forma conseguimos isolar :
,
.
Porém, isso não ocorre com os outros dois métodos, pois surgem termos em diferentes posições para o tempo (de , , até ), sendo necessário resolvermos o sistema como um todo simultaneamente, ou seja, teríamos que inverter uma matriz. Por isso, foi utilizado o método de Leapfrog para o cálculo de em todos os métodos, devido a sua simplicidade.
Além disso, são necessários valores de e de , com correspondendo a , para calcularmos e , para qualquer tempo, utilizando os métodos de Lax-Wendroff de dois passos e Lax-Friedrichs. A solução a este problema foi utilizarmos
.
Pensando na condição inicial , e estendendo para além da corda (pensando no seno de ), observamos que ela respeita as equações acima.
Solução e Análise de erros
Primeiramente, apresentamos abaixo as soluções geradas pelos programas, em comparação com a solução analítica.
Aqui já podemos observar o que foi comentado na seção sobre o método de Lax-Friedrichs: devido à dissipação numérica inerente ao método, há uma diminuição da amplitude da onda ao longo do tempo, embora ela mantenha sua forma. Isso interferirá na análise do erro deste método, o que será apresentado na sequência.
A partir do cálulo da solução analítica da equação da onda, podemos calcular quanto o valor obtido pelos métodos difere da solução real, o que leva a uma visualização do erro corrente em cada método de integração.
Nesse caso, a solução é [2].A análise de erros se torna mais evidente durante a escolha do parâmetro , onde . Valores grandes trazem pouca acurácia, e valores pequenos necessitam de muito poder de computação (tempo e dinheiro).
O erro foi obtido efetuando uma média espacial, ou seja, o programa foi evoluindo até um tempo final , e, em , foi feita uma média sobre o valor absoluto da diferença entre a solução analítica e a numérica. Aqui variamos o valor de , fixando , de forma que .
Podemos observar que os erros crescem à medida que o parâmetro k se torna maior, como seria de se esperar.
Além disso, sabendo a ordem do erro dos métodos, podemos determinar a inclinação da reta que melhor se ajusta aos pontos. Se um método tem erro de ordem ,
em que é o erro local, ou seja, o erro de um passo do método, e é uma constante. Assim, o erro global , ou seja, o erro após N passos, é dado por
Como , . Logo, se o erro local é de ordem , o erro global (que é o que calculamos aqui) é de ordem . Além disso, como utilizamos escala logarítmica para representar os resultados, a função do erro global se torna
Ou seja, a inclinação do gráfico do erro global é .
Observamos que se determinarmos a reta que melhor se ajusta às curvas dos métodos de Leapfrog e Lax-Wendroff, ela tem inclinação aproximada de 1, já que os métodos são de ordem . Com relação ao gráfico do erro do método de Lax-Friedrichs, é mais complicado de fazer sua análise, uma vez que há o efeito de dissipação numérica, que se intensifica para valores menores de . Podemos observar nos dados que o ponto de máximo na parte esquerda do gráfico corresponde a um erro de aproximadamente , que é a média da solução analítica no tempo (conforme solução analítica, a amplitude no tempo é , e a média de vale ). Isso significa que, devido à dissipação, a solução numérica é praticamente 0 frente à solução analítica na parte esquerda do gráfico.
Simulação de Propagação de Onda 2D no Mar Dependente de Topografia
O modelo mais simples para a propagação de onda dependente da topografia parte da equação da onda [3] [4], incluindo uma velocidade dependente da posição, da forma .
,
Sendo uma representação da profundidade em águas calmas, a aceleração da gravidade e a elevação da água em relação ao nível de águas calmas. Em uma situação real, pode-se obtê-la por mapeamento eletrônico do terreno por sistema de sonar. A dependência em de permite um modelo no qual o terreno se modifica com o tempo. Isto é, pode-se observar o efeito que o deslocamento de placas tectônicas, deslizamentos, e até explosões provocam no comportamento das ondas na costa de um país e o reconhecimento de áreas críticas. Entretanto, utilizaremos aqui , sem dependência no tempo, e mudaremos as condições iniciais para a modelagem do problema, além de usarmos , para simplificarmos as expressões.
Como primeira abordagem visando uma análise em 2D, a integração da equação em 1D (mesmo sendo uma situação muito idealizada) já traz resultados interessantes. Pode ser mostrado que a velocidade da onda pode ser dada por , para o caso em que , o que é razoável para um tsunami, que tem um comprimento de onda da ordem de até centenas de quilômetros, com uma profundidade da ordem de quilômetros[6]. Como o período da onde não se altera [6], quanto menor a profundidade, menor a velocidade, e menor o seu comprimento de onda. Além disso, devido à conservação de energia, e supondo que a extensão da frente de onda não seja alterada, é obtida a chamada Lei de Green[6]:
em que é a amplitude da onda, e os índices representando dois meios. Logo, quanto menos profundo, maior a amplitude da onda. Esta informação por si só ajuda na construção de proteção contra quebra de ondas, pois é obtido o tamanho que as mesmas atingem. Nos gráficos abaixo podemos observar esses efeitos.
E no caso em que simulamos uma fina camada de líquido, podemos ver a diminuição de velocidade da onda e o aumento de sua amplitude, especialmente no trecho mais à esquerda:
É importante notar o quão poderosa é a integração de equações parciais na vida de um engenheiro.
Estendendo o algoritmo de Leapfrog à situação 2D, obtemos, para uma condição inicial de uma gaussiana com média 0 e desvio padrão 1, tanto em quanto em , e :
Podemos então, analisar como a mesma condição inicial se porta quando , simulando uma elevação de terra:
Perfil da onda em sua diagonal:
Programas
Equação da onda em uma dimensão:
Cálculo da onda em um tempo : Lax-Friedrichs: <source lang="c">
- include<stdio.h>
- include<math.h>
- include<string.h>
- include<stdlib.h>
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k);
void main() {
FILE *arq; arq = fopen("lax.txt", "w+");
int tmax, i, j, jmax;
//tamanho da corda: jmax-1
jmax = 50;
//u: posicao da corda /* u_old em t-1 */ /* u_now em t */ /* u_new em t+1 */
//k = dt/dx double u_new[jmax], t, u_old[jmax], u_now[jmax], k, erro;
//tmax: tempo final
tmax = 100; k = 0.2;
//condicao inicial for (j = 0 ; j < jmax ; j++) { u_now[j] = sin(M_PI*j/(jmax - 1)); }
//condicao de contorno u_old[0]=0; u_old[jmax-1]=0;
u_new[0] = 0; u_new[jmax-1] = 0;
//calculo de u para t=-dt, utilizando o metodo de leapfrog - aqui usamos que du/dt = 0 em t=0
for (j = 1; j< jmax-1 ; j++) { u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]); }
//atualizacao da onda
for(t = 0 ; t < tmax ; t+=k) {
atualizar_onda(u_new,u_now,u_old,jmax,k);
memcpy(u_old,u_now, sizeof(double)*jmax); memcpy(u_now,u_new, sizeof(double)*jmax); }
//onda no tempo t=tmax
for(j=0; j<jmax; j++) { fprintf(arq,"%d %lf\n", j, u_new[j]); }
fclose(arq);
}
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k)
{
int j;
//para j=1 e j=jmax-2 (penultimas posições), necessitamos de u em x=-1 e x=jmax, respectivamente, sendo que essas posicoes ficam fora do vetor (vai de 0 a jmax-1). Aqui, foi feito u(x=-1)=-u(x=1) e u(x=jmax)=-u(x=jmax-2) j=1; u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (u_old_[j+2] - 2 * u_old_[j] - u_old_[j]);
for(j = 2 ; j < jmax-2 ; j++) { u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (u_old_[j+2] - 2 * u_old_[j] + u_old_[j-2]); }
j=jmax-2; u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (-u_old_[j] - 2 * u_old_[j] + u_old_[j-2]);
}
<source>
Lax-Wendroff: <source lang="c">
- include<stdio.h>
- include<math.h>
- include<string.h>
- include<stdlib.h>
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k);
void main() {
FILE *arq; arq = fopen("laxw.txt", "w+");
int tmax,i,j,jmax;
//tamanho da corda: jmax-1
jmax = 50;
//u: posicao da corda /* u_old em t-1 */ /* u_now em t */ /* u_new em t+1 */
//k = dt/dx double u_new[jmax],t,u_old[jmax],u_now[jmax],k,erro;
//tmax: tempo final
tmax = 100; k = 0.2;
//condição inicial for (j = 0 ; j < jmax ; j++) { u_now[j] = sin(M_PI*j/(jmax - 1)); }
//condição de contorno u_old[0] = 0; u_old[jmax-1] = 0;
u_new[0] = 0; u_new[jmax-1] = 0;
//cálculo de u para t=-dt, utilizando o método de leapfrog - aqui usamos que du/dt = 0 em t=0
for (j = 1; j< jmax-1 ; j++) { u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]);
}
//atualização da onda
for(t = 0 ; t < tmax ; t+=k) {
atualizar_onda(u_new,u_now,u_old,jmax,k);
memcpy(u_old,u_now, sizeof(double)*jmax); memcpy(u_now,u_new, sizeof(double)*jmax); }
//onda no tempo t=tmax
for(j=0; j<jmax; j++) { fprintf(arq,"%d %lf\n", j, u_new[j]); }
fclose(arq);
}
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k)
{
int j;
//para j=1 e j=jmax-2 (penúltimas posições), necessitamos de u em x=-1 e x=jmax, respectivamente, sendo que essas posições ficam fora do vetor (vai de 0 a jmax-1). Aqui, foi feito u(x=-1)=-u(x=1) e u(x=jmax)=-u(x=jmax-2) j=1;
u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (0.5 * u_old_[j+2] - u_old_[j+1] + u_old_[j] - u_old_[j-1] - 0.5 * u_old_[j] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]);
for(j = 2 ; j < jmax-2 ; j++) { u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (0.5 * u_old_[j+2] - u_old_[j+1] + u_old_[j] - u_old_[j-1] + 0.5 * u_old_[j-2] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]); }
j=jmax-2; u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (-0.5 * u_old_[j] - u_old_[j+1] + u_old_[j] - u_old_[j-1] + 0.5 * u_old_[j-2] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]);
}
<source>
Leapfrog: <source lang="c">
- include<stdio.h>
- include<math.h>
- include<string.h>
- include<stdlib.h>
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k);
void main() {
FILE *arq; arq = fopen("leapfrog.txt", "w+");
int i, j, jmax;
//tamanho da corda: jmax-1 jmax = 50;
//u: posicao da corda
/* u_old em t-1 */ /* u_now em t */ /* u_new em t+1 */
//k = dt/dx double u_new[jmax], t, u_old[jmax], u_now[jmax], k, erro, tmax;
//tmax: tempo final tmax = 100; k = 0.2;
//condicao inicial for (j = 0 ; j < jmax ; j++) { u_now[j] = sin(M_PI*j/(jmax - 1)); }
//condicao de contorno u_new[0] = 0; u_new[jmax-1] = 0;
u_old[0] = 0; u_old[jmax-1] = 0;
//calculo de u para t=-dt, utilizando o metodo de leapfrog - aqui usamos que du/dt = 0 em t=0 for (j = 1; j< jmax-1 ; j++) { u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]); }
//atualizacao da onda for(t = 0 ; t < tmax ; t+=k) {
atualizar_onda(u_new,u_now,u_old,jmax,k);
memcpy(u_old,u_now, sizeof(double)*jmax); memcpy(u_now,u_new, sizeof(double)*jmax); }
for(j=0; j<jmax; j++) { fprintf(arq,"%d %lf\n", j, u_new[j]); }
fclose(arq);
}
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k)
{
int j;
for(j = 1 ; j < jmax-1 ; j++) { u_new_[j] = 2 * u_now_[j] - u_old_[j] + pow(k,2) *( u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1] ); }
}
<source>
Cálculo do erro:
Lax-Friedrichs: <source lang="c">
- include<stdio.h>
- include<math.h>
- include<string.h>
- include<stdlib.h>
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k);
void main() {
FILE *arq; arq = fopen("erro_lax.dat", "w");
int tmax, i, j, jmax; //tamanho da corda: jmax-1 jmax = 50; //u: posicao da corda
/* u_old em t-1 */ /* u_now em t */ /* u_new em t+1 */
//k = dt/dx (aqui, dx = 1, k=dt) double u_new[jmax], t, u_old[jmax], u_now[jmax], k, erro; //tmax: tempo final tmax = 100;
//variamos o dt para fazer um grafico do erro em função de dt
int n=1; while( n < 1200) { k = 0.001*n;
//condicao inicial
for (j = 0 ; j < jmax ; j++) { u_now[j] = sin(M_PI*j/(jmax - 1)); } //condicao de contorno u_old[0]=0; u_old[jmax-1]=0; u_new[0] = 0;
u_new[jmax-1] = 0;
//calculo de u para t=-dt, utilizando o metodo de leapfrog - aqui usamos que du/dt = 0 em t=0
for (j = 1; j< jmax-1 ; j++) { u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]); }
//atualizacao da onda
for(t = 0 ; t < tmax ; t+=k) { //para que o ultimo tempo em que se calcula a posicao seja tmax, independentemente do valor de dt if(t+k >tmax) { k = tmax -t; }
atualizar_onda(u_new,u_now,u_old,jmax,k);
memcpy(u_old,u_now, sizeof(double)*jmax); memcpy(u_now,u_new, sizeof(double)*jmax); }
//calculo do erro
erro = 0; for(j = 0 ; j < jmax ; j++) { double analitica = cos((M_PI*t)/(jmax - 1))*sin((M_PI*j)/(jmax - 1)); erro += fabs(analitica - u_now[j]); } erro = erro/jmax; fprintf(arq,"%.12lf %.12lf\n", n*0.001, erro);
n++;
}
fclose(arq);
}
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k) {
int j;
//para j=1 e j=jmax-2 (penultimas posições), necessitamos de u em x=-1 e x=jmax, respectivamente, sendo que essas posicoes ficam fora do vetor (vai de 0 a jmax-1). Aqui, foi feito u(x=-1)=-u(x=1) e u(x=jmax)=-u(x=jmax-2) j=1; u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (u_old_[j+2] - 2 * u_old_[j] - u_old_[j]);
for(j = 2 ; j < jmax-2 ; j++) { u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (u_old_[j+2] - 2 * u_old_[j] + u_old_[j-2]); } j=jmax-2; u_new_[j] = u_now_[j] + 0.5 * (u_now_[j-1] + u_now_[j+1]) - 0.5 * (u_old_[j-1] + u_old_[j+1]) + 0.25 * pow(k,2) * (-u_old_[j] - 2 * u_old_[j] + u_old_[j-2]);
}
<source>
Lax-Wendroff: <source lang="c">
- include<stdio.h>
- include<math.h>
- include<string.h>
- include<stdlib.h>
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k);
void main() {
FILE *arq; arq = fopen("erro_laxw.dat", "w");
int tmax,i,j,jmax; //tamanho da corda: jmax-1 jmax = 50; //u: posição da corda
/* u_old em t-1 */ /* u_now em t */ /* u_new em t+1 */
//k = dt/dx (aqui, dx = 1, k=dt) double u_new[jmax],t,u_old[jmax],u_now[jmax],k,erro;
//tmax: tempo final
tmax = 100;
//variamos o dt para fazer um gráfico do erro em função de dt
int n=1; while( n < 1200) { k = 0.001*n;
//condição inicial
for (j = 0 ; j < jmax ; j++) { u_now[j] = sin(M_PI*j/(jmax - 1)); }
//condição de contorno u_old[0] = 0; u_old[jmax-1] = 0;
u_new[0] = 0; u_new[jmax-1] = 0;
//cálculo de u para t=-dt, utilizando o método de leapfrog - aqui usamos que du/dt = 0 em t=0
for (j = 1; j< jmax-1 ; j++) {
u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]);
}
//atualização da onda
for(t = 0 ; t < tmax ; t+=k) { //para que o último tempo em que se calcula a posição seja tmax, independentemente do valor de dt if(t+k >tmax) { k = tmax -t; }
atualizar_onda(u_new,u_now,u_old,jmax,k);
memcpy(u_old,u_now, sizeof(double)*jmax); memcpy(u_now,u_new, sizeof(double)*jmax); }
//cálculo do erro
erro = 0; for(j = 0 ; j < jmax ; j++) { double analitica = cos((M_PI*t)/(jmax - 1))*sin((M_PI*j)/(jmax - 1)); erro += fabs(analitica - u_now[j]); } erro = erro/jmax; fprintf(arq,"%.12lf %.12lf\n", n*0.001, erro);
n++;
}
fclose(arq);
}
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k)
{
int j;
//para j=1 e j=jmax-2 (penúltimas posições), necessitamos de u em x=-1 e x=jmax, respectivamente, sendo que essas posições ficam fora do vetor (vai de 0 a jmax-1). Aqui, foi feito u(x=-1)=-u(x=1) e u(x=jmax)=-u(x=jmax-2) j=1;
u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (0.5 * u_old_[j+2] - u_old_[j+1] + u_old_[j] - u_old_[j-1] - 0.5 * u_old_[j] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]);
for(j = 2 ; j < jmax-2 ; j++) { u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (0.5 * u_old_[j+2] - u_old_[j+1] + u_old_[j] - u_old_[j-1] + 0.5 * u_old_[j-2] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]); } j=jmax-2; u_new_[j] = 2 * u_now_[j] - u_old_[j] + 0.5 * pow(k,2) * (-0.5 * u_old_[j] - u_old_[j+1] + u_old_[j] - u_old_[j-1] + 0.5 * u_old_[j-2] + u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1]);
}
<source>
Leapfrog: <source lang="c">
- include<stdio.h>
- include<math.h>
- include<string.h>
- include<stdlib.h>
void atualizar_onda(double u_new[],double u_now[],double u_old[],int jmax,double k);
void main() {
FILE *arq; arq = fopen("erro_leapfrog.dat", "w");
int i, j, jmax; //tamanho da corda: jmax-1 jmax = 50; //u: posicao da corda
/* u_old em t-1 */ /* u_now em t */ /* u_new em t+1 */
//k = dt/dx (aqui, dx = 1, k=dt) double u_new[jmax], t, u_old[jmax], u_now[jmax], k, erro, tmax;
//tmax: tempo final
tmax = 100;
//variamos o dt para fazer um grafico do erro em função de dt
int n=1; while( n < 1200) { k = 0.001*n;
//condicao inicial
for (j = 0 ; j < jmax ; j++) { u_now[j] = sin(M_PI*j/(jmax - 1)); }
//condicao de contorno u_new[0] = 0; u_new[jmax-1] = 0;
u_old[0] = 0; u_old[jmax-1] = 0;
//calculo de u para t=-dt, utilizando o metodo de leapfrog - aqui usamos que du/dt = 0 em t=0
for (j = 1; j< jmax-1 ; j++) { u_old[j] = u_now[j] + 0.5 * pow(k,2) * (u_now[j+1] - 2 * u_now[j] + u_now[j-1]); }
//atualizacao da onda
for(t = 0 ; t < tmax ; t+=k) { //para que o ultimo tempo em que se calcula a posicao seja tmax, independentemente do valor de dt if(t+k >tmax) { k = tmax - t; } atualizar_onda(u_new,u_now,u_old,jmax,k);
memcpy(u_old,u_now, sizeof(double)*jmax); memcpy(u_now,u_new, sizeof(double)*jmax); }
//calculo do erro
erro = 0; for(j = 0 ; j < jmax ; j++) { double analitica = cos((M_PI*t)/(jmax - 1))*sin((M_PI*j)/(jmax - 1)); erro += fabs(analitica - u_now[j]); } erro = erro/jmax; fprintf(arq,"%.12lf %.12lf\n", n*0.001,erro);
n++;
}
fclose(arq);
}
void atualizar_onda(double u_new_[],double u_now_[],double u_old_[],int jmax,double k)
{
int j;
for(j = 1 ; j < jmax-1 ; j++) { u_new_[j] = 2 * u_now_[j] - u_old_[j] + pow(k,2) *( u_now_[j+1] - 2 * u_now_[j] + u_now_[j-1] ); }
}
<source>
Equação da onda em duas dimensões: <source lang="c">
- include<stdio.h>
- include<math.h>
- include<string.h>
- include<stdlib.h>
- define nx_ 71
- define ny_ 71
double gauss( int x, int y, int tam);
double H( int x, int y, int tam);
void atualizar_onda(double u_new[][ny_], double u_now[][ny_], double u_old[][ny_], double lambda[][ny_], double a, double b, double c, int nx, int ny, double rx, double ry);
double delta_u( double rx, double ry, double lambda[][ny_], double u_now[][ny_], int i, int j, int im1, int ip1, int jm1, int jp1);
/* META DADOS */ // /* nx_ e ny_ , definidos acima por praticidade, */ /* setam o tamanho dos vetores. */ /* */ /* tmax , tempo total da simulacao */ /* rx e ry, dt/dx e dy/dt respectivamente */ /* lambda , mapa do solo (profundidade em (x,y)) */ // // /* u representa a altura do mar em (x,y), sendo: */ // /* u_old[x][y] em t = t-1 */ /* u_now[x][y] em t = t */ /* u_new[x][y] em t = t+1 */ //
void main() {
FILE *arq; arq = fopen("onda.txt", "w+");
int tmax, i, j, t, nx, ny;
nx = nx_; ny = ny_; tmax = 300;
double u_new[nx][ny], u_old[nx][ny], u_now[nx][ny], lambda[nx][ny], rx, ry;
rx = 0.25; ry = 0.25;
// incio loop da condição inicial, // laco duplo e usado para percorrer matriz nx*ny
for(j = 0 ; j < ny ; j++) { for(i = 0 ; i < nx ; i++) { /* u_now inicial em forma de sino */ u_now[i][j] = gauss(i,j,nx); /* lambda inicial em forma de H() */ lambda[i][j] = H(i,j,nx);
} }
// fim loop da condição inicial
/* calculo "sintetico" de u_old, pois a atualizacao nao e auto-iniciavel */
atualizar_onda(u_old, u_now, u_old, lambda, 0.5, 0, 0.5, nx, ny, rx, ry);
//inicio do laço temporal
for(t = 0 ; t < tmax ; t++) {
//imprimindo no arquivo com laco duplo
/* calculam-se novos valores */
atualizar_onda( u_new, u_now, u_old, lambda, 1, 1, 1, nx, ny, rx, ry);
/* matrizes antes novas se tornam antigas */ /* u_old = u_now, u_now = u_new */
memcpy(u_old,u_now, sizeof(double)*nx*ny); memcpy(u_now,u_new, sizeof(double)*nx*ny);
/* OBS: Double tem o valor de 8 bytes na memoria. Como temos uma matriz de nx*ny, pegamos o tamanho*/ /* de um double e multiplicamos pela dimensao da matriz */ /* sintaxe memcpy(matriz a ser atualizada, matriz que passa o valor, tamanho em bytes da matriz) */
}
for(j = 0 ; j < ny ; j++) { for(i = 0 ; i < nx ; i++) { if(i == j){ fprintf(arq, "%d %d %lf\n", i, j, u_now[i][j]); } } }
/* Linhas em branco ao final de cada tempo para index do gnuplot */ fprintf(arq,"\n\n");
fclose(arq);
}
double gauss(int x, int y,int tam)
{
/* curva inicial em forma de sino*/
double A, xc, yc, gauss, sigmax, sigmay; //xc = (tam-1) / 2.; //yc = (tam-1) / 2.; xc = 0; yc = 0;
A = 1; sigmax = 1; sigmay = 1;
gauss = A * exp(-0.5*pow(((x-xc)/sigmax),2) -0.5*pow(((y-yc)/sigmay),2));
return gauss;
}
/* a funcao H corresponde ao formato do terreno, retorna a profundidade em relação a aguas calmas */
double H(int x, int y,int tam) {
/* curva para o formato do terreno em forma de sino virado*/ double A,xc,yc,h,sigmax,sigmay; //xc = (tam-1) / 2.; //yc = (tam-1) / 2.;
A = 1; sigmax = 1; sigmay = 1; xc = 0; yc = 0;
h = 1 - A * exp(-0.5*pow(((x-xc)/sigmax),2) -0.5*pow(((y-yc)/sigmay),2));
return h;
}
void atualizar_onda(double u_new[][ny_], double u_now[][ny_], double u_old[][ny_], double lambda[][ny_], double a, double b, double c, int nx, int ny, double rx, double ry) { // DOUBLE U_NEW[][NY_)] SINALIZA PARA O C QUE A FUNÇÃO RECEBERA UMA MATRIZ( TECNICAMENTE RECEBERA O ENDEREÇO NA MEMORIA DA MATRIZ) POR ISSO NÃO É NECESSARIO RETORNAR NENHUM VALOR // ESTA "TECNICA" É POSSIVEL POIS O NOME DA MATRIZ, NO CASO U_NEW, É NA VERDADE O ENDEREÇO DESSA MATRIZ NA MEMORIA. COMO ESTAMOS PASSANDO O ENDEREÇO NA MEMORIA, A FUNÇÃO CONSEGUE ALTERAR OS VALORES SEM NECESSIDADE DE RETORNO // PRECISAMOS DECLARAR O [NY_] NA FUNÇÃO POR QUESTÕES TECNICAS. MAS PENSEM NESSA SINTAXE COMO: PASSANDO O ENDEREÇO DA MATRIX PARA A FUNÇÃO, SEM NECESSIDADE DE RETORNO. A FUNÇÃO É LIVRE PARA EDITAR A PROPRIA MATRIZ
int i,j;
// LOOP DUPLO PARA ATUALIZAR AS PARTES INTERNAS DA MATRIZ for(j = 1 ; j < ny - 1 ; j++) { for(i = 1 ; i < nx - 1 ; i++)
// SEPAREI PARTE DA EQUAÇAO EM OUTRA FUNÇÃO PARA SIMPLIFICAR A VIDA. DELTA_U É SIMPLESMENTE UMA PARTE DA EQUAÇÃO ORIGINAL
u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i+1,j-1,j+1); }
//PRECISAMOS AGORA ATUALIZAR AS LINHAS E COLUNAS EXTERNAS DA MATRIZ, POIS ESTAS NÃO FORAM INCLUIDAS NO LOOP ANTERIOR. ESTA AÇÃO NÃO ATUALIZA AS PONTAS, OU QUINAS, DA MATRIZ
i = 0; // ATUALiZANDO A PRIMEIRA COLUNA DA MATRIZ for( j = 1; j < ny - 1 ; j++) { u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i+1,i+1,j-1,j+1); }
i = nx - 1;// ATUALZANDO A ULTIMA COLUNA DA MATRIZ for( j = 1; j < ny - 1 ; j++) { u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i-1,j-1,j+1); }
// ---------------------- //
j = 0; // ATUALZANDO A PRIMEIRA LINHA DA MATRIZ for( i = 1; i < nx - 1 ; i++) { u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i+1,j+1,j+1);
}
j = ny - 1; // ATUALZANDO A ULTIMA LINHA DA MATRIZ for( i = 1; i < nx - 1 ; i++) { u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i+1,j-1,j-1);
}
// AGORA VAMOS ATUALIZAR as PONTAS DA MATRIZ. OU CANTOS, SE PREFERIR CHAMAR ASSIM
// PONTA [0][0] i = 0; j = 0; u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i+1,i+1,j+1,j+1);
// PONTA [nx - 1][0] i= nx - 1; j= 0; u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i-1,j+1,j+1);
// PONTA [0][ny -1] i= 0; j= ny - 1; u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i+1,i+1,j-1,j-1);
// PONTA [NX-1][ny -1] i= nx - 1; j= ny - 1; u_new[i][j] = a * 2 * u_now[i][j] - b * u_old[i][j] + c * delta_u(rx,ry,lambda,u_now,i,j,i-1,i-1,j-1,j-1);
}
double delta_u( double rx, double ry, double lambda[][ny_], double u_now[][ny_], int i, int j, int im1, int ip1, int jm1, int jp1) {
//CALCULAMOS AQUI SEPARADO UMA PARTE DA EQUAÇÃO, POIS ELA MUDA DEPENDENDO DO QUE ESTAMOS CALCULANDO. SEJA UMA COLUNA INICIAL OU FINAL OU UM CANTO DA MATRIZ //PARA ISSO COLOQUEI VALORES AUXILIARES DE IM1, IP1, JM1, JP1 . P DE PLUS E M DE MINUS.POIS ESTES VALORES SAO TROCADOS EM VARIAS PARTES
return ( pow(rx,2) * ( ((0.5 * (lambda[ip1][j] + lambda[i][j])) * (u_now[ip1][j] - u_now[i][j])) - ((0.5 * (lambda[i][j] + lambda[im1][j])) * (u_now[i][j] - u_now[im1][j])))
+ pow(ry,2) * ( ((0.5 * (lambda[i][jp1] + lambda[i][j])) * (u_now[i][jp1] - u_now[i][j])) - ((0.5 * (lambda[i][j] + lambda[i][jm1])) * (u_now[i][j] - u_now[i][jm1]))));
}
<source>
Bibliografia
- ↑ 1,0 1,1 1,2 1,3 1,4 Press, William H.; Teukolsky, Saul A.; Vetterling, William T.; Flannery, Brian P. (2007). "Numerical Recipes: The Art of Scientific Computing" (3rd ed.). New York: Cambridge University Press. ISBN 978-0-521-88068-8.
- ↑ Weisstein, Eric W. "Wave Equation--1-Dimensional." From MathWorld--A Wolfram Web Resource; disponível em: [1]; último acesso em 26/11/2017
- ↑ Lie, Knut-Andreas. "The Wave Equation in 1D and 2D". Dept. of Informatics, University of Oslo; disponível em: [2]; último acesso em 23/10/2017.
- ↑ Hjorth-Jensen, Morten. Computational Physics, University of Oslo, 2009.
- ↑ Wadhams, M. J. Doble. "Digital terrain mapping of the underside of sea ice from a small AUV"; disponível em: DOI: 10.1029/2007GL031921 ; último acesso em 23/10/2017.
- ↑ 6,0 6,1 6,2 Silveira, F. L.; Varriale, M. C. "Propagação das ondas marítimas e dos tsunami". Caderno Brasileiro de Ensino de Física, V. 22, N. 2: P. 190-215, 2005.