Use o botão abaixo para reportar erros ou dar sugestões.

Computação Científica - Um Livro Colaborativo

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: μ∂I ∂y + λI = σ 2 ∫ −11I(y,μ)dμ + Q(y,μ), y ∈ (0,L),μ ∈ [−1,1], I(0,μ) = B0, μ > 0, I(L,μ) = BL, μ < 0.

Nesse modelo, I(y,μ) é uma intensidade radiativa, I(y) = 1 2 ∫ −11I(y,μ)dμ

é o fluxo escalar, λ é o coeficiente de absorção, σ é o coeficiente de espalhamento, Q(y,μ) é uma fonte, B0 e BL são os fluxos de entrada na fronteira, y ∈ [0,L] é a variável espacial e μ ∈ [−1,1] é o cosseno do ângulo entre o raio e o eixo y.

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 μi e pesos ωi 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 y: μidIi dy + λIi = σ 2 ∑ j=−MMω jIj(y) + Qi, y ∈ (0,L), Ii(0) = B0, μi > 0, Ii(L) = BL, μi < 0,

onde i = −M,...,M. Agora, separaramos o sistema de EDO’s em dois: um para μi < 0 e outro para μi > 0. Portanto, − μidI−i dy + λI−i = σ 2 ∑ j=1Mω j(I−j + Ij) + Q−i, i = 1,2,...,M, I−i(L) = BL, i = 1,2,...,M,

e μidIi dy + λIi = σ 2 ∑ j=1Mω j(I−j + Ij) + Qi, i = 1,2,...,M, Ii(0) = B0, i = 1,2,...,M.

Agora, vamos discretizar à variável espacial y. Dividimos o intervalo [0,L] em N subintervalos de tamanho h = L N, e construímos a malha yk = (k − 1)h, k = 1,2,...,N + 1. Suponhamos que em um intervalo da malha [yk,yk+1] o lado direito das equações seja constante e conhecido. Vamos denotar a aproximação para o lado direito da equação de Sik+1∕2. Logo, neste intervalo temos: dI−i dy − λ μiI−i = −1 μiS−ik+1∕2, i = 1,2,...,M, y k ≤ y ≤ yk+1, dIi dy + λ μiIi = 1 μiSik+1∕2, i = 1,2,...,M, y k ≤ y ≤ yk+1.

As duas equações podem ser resolvidas pelo método do fator integrante: e− λ μiyk+1 I−ik+1 − e− λ μiyk I−ik = S−ik+1∕2 λ e− λ μiyk+1 − e− λ μiyk ,i = 1,2,...,M,k = 1,2,...,N, e λ μiyk+1 Iik+1 − e λ μiyk Iik = Sik+1∕2 λ e λ μiyk+1 − e λ μiyk , i = 1,2,...,M,k = 1,2,...,N.

As condições de contorno nos dão: I−iN+1 = B L, i = 1,2,...,M, Ii1 = B 0, i = 1,2,...,M.

Logo, podemos obter I−ik e Iik+1 de maneira recursiva, ou seja, I−ik = e λ μi(yk−yk+1) I−ik+1 + S−ik+1∕2 λ 1 − e λ μi(yk−yk+1) ,i = 1,2,...,M,k = N,N − 1,...,1, Iik+1 = e λ μi(yk−yk+1) Iik + Sik+1∕2 λ 1 − e λ μi(yk−yk+1) , i = 1,2,...,M,k = 1,2,...,N.

Damos um chute inicial para a solução e calculamos Sik+1∕2 com as seguintes médias: S±ik+1∕2 = 1 2 σ 2 ∑ j=1Mω j(I−jk + I jk) + Q ±ik + σ 2 ∑ j=1Mω j(I−jk+1 + I jk+1) + Q ±ik+1 .

A solução aproximada é obtida quando houver convergência do processo iterativo: Calculamos S±ik+1∕2 = 0, depois I−iN+1, I−iN, I−iN−1, ⋯, I−i1 e Ii1,I i2, ⋯, IiN+1. Depois recalculamos S±ik+1∕2 e I±ik.

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 ∫ −11I(y,μ)dμ quando Q y = e−y, λ′ = σ′ = 1 e B0 = BL = 1, com L = 1.







y 0.0 0.2 0.4 0.6 0.8 1.0







GFD800 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.

Creative Commons License Este texto é disponibilizado nos termos da licença Creative Commons Atribuição-CompartilhaIgual 3.0 Não Adaptada (CC-BY-SA 3.0). Página gerada em 19/8/2020 às 17:33:16.

Informe erros ou edite você mesmo!