13.2 Problema de transporte
Exemplo 13.2.1. Resolva o problema dado pela equação estacionária do
transporte unidimensional com espalhamento isotrópico:
Nesse modelo,
é uma intensidade radiativa,
é o fluxo escalar, é o
coeficiente de absorção, é
o coeficiente de espalhamento,
é uma fonte, e
são os fluxos de
entrada na fronteira, é
a variável espacial e
é o cosseno do ângulo entre o raio e o eixo
.
Começamos discretizando à variável angular
com um método chamado de Ordenadas Discretas. Escolhemos a
quadratura numérica de Gauss-Legendre com um número par de abscissas
e
pesos
e discretizamos a equação de forma a transformar a integral em um somatório.
Este procedimento transforma o problema em um sistema de EDO’s na variável
:
onde .
Agora, separaramos o sistema de EDO’s em dois: um para
e outro
para .
Portanto,
e
Agora, vamos discretizar à variável espacial
. Dividimos o
intervalo em
subintervalos
de tamanho , e
construímos a malha ,
. Suponhamos que em
um intervalo da malha
o lado direito das equações seja constante e conhecido. Vamos
denotar a aproximação para o lado direito da equação de
.
Logo, neste intervalo temos:
As duas equações podem ser resolvidas pelo método do fator integrante:
As condições de contorno nos dão:
Logo, podemos obter
e de
maneira recursiva, ou seja,
Damos um chute inicial para a solução e calculamos
com
as seguintes médias:
A solução aproximada é obtida quando houver convergência do processo iterativo:
Calculamos ,
depois ,
,
,
,
e
,,
,
. Depois
recalculamos
e .
Para implementar esse algoritmo, fazemos algumas considerações:
- É necessário entender o algoritmo antes de começar a programar.
Embora seja uma questão óbvia, a ansiedade pode nos trair.
- É importante pensar na estrutura do código antes de programar:
tipo das principais variáveis, formas de armazenamento (ponteiros,
matrizes), variáveis globais, estruturas, funções, pacotes, etc.
- Não é indicado programar tudo de uma só vez. Faça por pedaços
e valide cada função independentemente.
- Compile o código seguidamente para não acumular erros de
compilação.
Começamos implemetando uma função que calcula pesos e abscissas para
a quadratura de Gauss-Legendre:
#include <stdio.h>
#include <math.h>
#include <gsl/gsl_integration.h>
#define M 10
double *x,*w;
double GL()
{
size_t i,flag;
gsl_integration_glfixed_table * table;
table = gsl_integration_glfixed_table_alloc (M);
for (i=0; i<M;i++)
{
flag = gsl_integration_glfixed_point (-1, 1, i, &x[i], &w[i], table);
//printf("flag=%zu, %zu %f %f\n",flag, i, x[i], w[i]);
}
gsl_integration_glfixed_table_free(table);
}
double teste(double x)
{
return x*x;
}
void main()
{
int i;
if (((x=malloc(sizeof(double)*M))==NULL)||((w=malloc(sizeof(double)*M))==NULL))
{
printf("Erro ao alocar memória");
return;
}
GL(x,w);
double result=0;
for (i=0; i<M;i++) result+=w[i]*teste(x[i]);
printf("O valor da integral é %f\n",result);
}
Depois de testar essa rotina integrando várias funções, vamos um passo
adiante. Definimos duas variáveis globais para salvar pesos e abscissas e
alocamos espaço para salvar a solução numa variável tipo ponteiro para
ponteiro.
#include <stdio.h>
#include <math.h>
#include <gsl/gsl_integration.h>
#define M 10
#define N 10
double *x,*w;
double GL()
{
size_t i,flag;
gsl_integration_glfixed_table * table;
table = gsl_integration_glfixed_table_alloc (2*M);
for (i=0; i<2*M;i++)
{
flag = gsl_integration_glfixed_point (-1, 1, i, &x[i], &w[i], table);
//printf("flag=%zu, %zu %f %f\n",flag, i, x[i], w[i]);
}
gsl_integration_glfixed_table_free(table);
}
void main()
{
int i;
double **I;
if (((x=malloc(sizeof(double)*2*M))==NULL)||((w=malloc(sizeof(double)*2*M))==NULL))
{
printf("Erro ao alocar memória");
return;
}
if ((I = calloc(N+1,sizeof(double)))==NULL)
{
printf("Erro ao alocar memória");
return;
}
for (i=0;i<N+1;i++) if ((I[i] = calloc(2*M,sizeof(double)))==NULL)
{
printf("Erro ao alocar memória");
return;
}
GL(x,w);
}
Agora, implementamos a primeira versão do código que resolve o problema:
#include <stdio.h>
#include <math.h>
#include <gsl/gsl_integration.h>
#define M 1000
#define N 2000
const double L=1;
const double B0=1;
const double BL=1;
const double sigma=1;
const double lambda=1.0;
double *mu,*w,*y;
double GL()
{
size_t i,flag;
gsl_integration_glfixed_table * table;
table = gsl_integration_glfixed_table_alloc (2*M);
for (i=M; i<2*M;i++)
{
flag = gsl_integration_glfixed_point (-1, 1, i, &mu[i-M], &w[i-M], table);
//printf("flag=%zu, %zu %f %f\n",flag, i, mu[i], w[i]);
}
gsl_integration_glfixed_table_free(table);
}
double Q(double x)
{
return exp(-x);
}
void main(void)
{
int i,k,n;
double **I,*II;
if (((mu=malloc(sizeof(double)*M))==NULL)||((w=malloc(sizeof(double)*M))==NULL))
{
printf("Erro ao alocar memória");
return;
}
GL();
if ((y=malloc(sizeof(double)*(N+1)))==NULL)
{
printf("Erro ao alocar memória");
return;
}
if ((II=malloc(sizeof(double)*(N+1)))==NULL)
{
printf("Erro ao alocar memória");
return;
}
if ((I = calloc(N+1,sizeof(double)))==NULL)
{
printf("Erro ao alocar memória");
return;
}
for (i=0;i<N+1;i++) if ((I[i] = calloc(2*M,sizeof(double)))==NULL)
{
printf("Erro ao alocar memória");
return;
}
//malha espacial
double h = L/N;
for (i=0;i<N+1;i++) y[i] = i*h;
//Contorno
for (i=0;i<M;i++)
{
I[0][i] = B0;
I[N][M+i] =BL;
}
//iteracao
double Exp,S=0;
for (n=0;n<200;n++)
{
//Fluxo Escalar
for(k=0;k<N+1;k++)
{
II[k]=0;
for(i=0;i<M;i++)
{
II[k] += w[i]*(I[k][i]+I[k][M+i]);
}
if (k%200==0) printf("II(%d)=%f\n",k,II[k]);
}
//Recorrência
for (i=0;i<M;i++)
{
for(k=0;k<N;k++)
{
S = 1/2.0*(sigma/2.0*(II[k]+II[k+1])+Q(y[k])+Q(y[k+1]));
Exp = exp(lambda/mu[i]*(y[k]-y[k+1]));
I[k+1][i] = S/lambda*(1-Exp)+I[k][i]*Exp;
}
for(k=N-1;k>-1;k--)
{
S = 1/2.0*(sigma/2.0*(II[k]+II[k+1])+Q(y[k])+Q(y[k+1]));
Exp = exp(lambda/mu[i]*(y[k]-y[k+1]));
I[k][M+i] = S/lambda*(1-Exp)+I[k+1][M+i]*Exp;
}
}
}
}
Para validar usamos resultados de artigos científicos, que fornecem dados tais
como dessa tabela:
Tabela 13.1: Valores calculados para
quando ,
e ,
com .
|
|
|
|
|
|
|
| y | 0.0 | 0.2 | 0.4 | 0.6 | 0.8 | 1.0 |
|
|
|
|
|
|
|
| | 3.514742 | 4.193467 | 4.307001 | 4.162773 | 3.820960 | 3.196349 |
|
|
|
|
|
|
|
| DD & Gauss-Legendre | 3.514748 | 4.193470 | 4.307004 | 4.162776 | 3.820963 | 3.196353 |
|
|
|
|
|
|
|
| DD & Clenshaw-Curtis | 3.514748 | 4.193471 | 4.307005 | 4.162777 | 3.820963 | 3.196354 |
|
|
|
|
|
|
|
| |
Naturalmente, o código pode ser melhorado. Por exemplo, podemos
estabelecer um critério de convergência para o processo iterativo.