Você está na página 1de 91

Matemtica Aplicada Engenharia

Nelson Lus Dias


Departamento de Engenharia Ambiental e
Lemma Laboratrio de Estudos em Monitoramento e
Modelagem Ambiental
Universidade Federal do Paran
30 de setembro de 2011

Sumrio

Sumrio
1 Ferramentas computacionais
1.1 Antes de comear a trabalhar, . . . . . . . . . . . . . . .
1.2 Python . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.1 Strings e Inteiros . . . . . . . . . . . . . . . . . .
1.2.2 Nmeros de ponto flutuante reais e complexos
1.2.3 Obteno de uma curva de permanncia . . . . .
1.2.4 Arquivos texto e arquivos binrios . . . . . . . . .
1.3 Gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3.1 Ajuste de uma funo . . . . . . . . . . . . . . .
1.4 Python de novo: projeto probabilstico . . . . . . . . . .
1.5 Maxima . . . . . . . . . . . . . . . . . . . . . . . . . . .
2 Um
2.1
2.2
2.3

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

11
11
13
13
15
16
19
22
24
26
30

pouco de polinmios, integrais, sries . . .


33
Integrao numrica: motivao . . . . . . . . . . . . . . . . . . . . . 33
A regra do trapzio . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Aproximao de integrais com sries: a funo erro . . . . . . . . . . 42

3 Soluo numrica de equaes diferenciais ordinrias


3.1 Soluo numrica de equaes diferenciais ordinrias .
3.1.1 Soluo numrica; mtodo de Euler . . . . . . .
3.1.2 Um mtodo implcito, com tratamento analtico
3.1.3 Runge-Kutta . . . . . . . . . . . . . . . . . . .

.
.
.
.

49
49
50
54
54

4 Soluo numrica de equaes diferenciais parciais


4.1 Adveco pura: a onda cinemtica . . . . . . . . . . . . . . . . . . . .
4.2 Difuso pura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3 Difuso em 2 Dimenses: ADI, e equaes elticas . . . . . . . . . . .

61
61
71
83

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

A Dados de vazo mdia anual e vazo mxima anual, Rio dos Patos,
19311999
89

Sumrio

Lista de Tabelas
1.1

Vazes Mximas Anuais (m3 s1 ) no Rio dos Patos, PR, 19311999 . 16

2.1

Estimativas numricas de I e seus erros relativos . . . . . . . . . . . 38

Sumrio

Lista de Figuras
1.1

Convenes do terminal postscript eps monochrome 'Times-Roman'


18 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

1.2

FDA da vazo mxima anual, Rio dos Patos . . . . . . . . . . . . . . 25

1.3

Ajuste de uma FDA Weibull aos dados de vazo mxima anual do


Rio dos Patos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

2.1

Integrao numrica de uma funo . . . . . . . . . . . . . . . . . . . 35

2.2

A regra do trapzio, com n = 4 e n = 8 trapzios. . . . . . . . . . . . 38

2.3

Funo erf(x) calculada por integrao numrica, com trapepsilon


e  = 1 106 , versus a erf pr-definida em Gnuplot. . . . . . . . . . 44

2.4

Funo erf(x) calculada com srie de Taylor, com erf_1, versus a erf
pr-definida em Gnuplot. . . . . . . . . . . . . . . . . . . . . . . . . . 45

3.1

Soluo da equao (3.1).

3.2

Comparao da soluo analtica da equao (3.1) com a sada de


sucesso.py, para x = 0,01. . . . . . . . . . . . . . . . . . . . . . . 53

3.3

Comparao da soluo analtica da equao (3.1) com a sada de


sucesso.py, para x = 0,5. . . . . . . . . . . . . . . . . . . . . . . . 53

3.4

Comparao da soluo analtica da equao (3.1) com a sada de


sucimp.py, para x = 0,5. . . . . . . . . . . . . . . . . . . . . . . . . 55

3.5

Comparao da soluo analtica da equao (3.1) com a sada de


euler2.py, para x = 0,5. . . . . . . . . . . . . . . . . . . . . . . . . 56

3.6

Comparao da soluo analtica da equao (3.1) com a sada de


rungek4.py, para x = 0,5. . . . . . . . . . . . . . . . . . . . . . . . 59

4.1

Condio inicial da equao 4.3. . . . . . . . . . . . . . . . . . . . . . 61

4.2

Soluo numrica produzida por onda1d-ins.py, para t = 250t,


500t e 750t. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

4.3

Soluo numrica produzida por onda1d-lax.py, para t = 500t,


1000t e 1500t. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

4.4

Soluo numrica produzida pelo esquema upwind, para t = 500t,


1000t e 1500t. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

4.5

Soluo analtica da equao de difuso para t = 0, t = 0,05, t = 0,10


e t = 0,15. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

. . . . . . . . . . . . . . . . . . . . . . . . 50

Sumrio
Soluo numrica com o mtodo explcito (4.35) (crculos) versus a
soluo analtica (linha cheia) da equao de difuso para t = 0,
t = 0,05, t = 0,10 e t = 0,15. Apenas 1 a cada 5 pontos da grade
numrica so mostrados, para facilitar a comparao com a soluo
analtica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.7 Soluo numrica com o mtodo implcito (4.39) (crculos) versus a
soluo analtica (linha cheia) da equao de difuso para t = 0,
t = 0,05, t = 0,10 e t = 0,15. Apenas 1 a cada 5 pontos da grade
numrica so mostrados, para facilitar a comparao com a soluo
analtica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.8 Soluo numrica com o mtodo de Crank-Nicholson ( (4.45)) (crculos) versus a soluo analtica (linha cheia) da equao de difuso
para t = 0, t = 0,05, t = 0,10 e t = 0,15. Apenas 1 a cada 5 pontos
da grade numrica so mostrados, para facilitar a comparao com a
soluo analtica. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.9 Soluo analtica da equao da difuso bidimensional, para t = 0,
t = 0, t = 0,1, t = 0,2 e t = 0,3 . . . . . . . . . . . . . . . . . . . . .
4.10 Soluo numrica da equao da difuso bidimensional com o esquema
ADI, para t = 0, t = 0, t = 0,1, t = 0,2 e t = 0,3 . . . . . . . . . . .

4.6

. 77

. 80

. 83
. 87
. 88

Lista de Listagens
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
1.10
1.11
1.12
1.13
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
2.10
2.11
2.12
2.13
2.14

binint.py exemplo de strings, e inteiros. . . . . . . . . . . . . . .


floats.py exemplo de uso de float e complex. . . . . . . . . . .
patos-medmax.dat vazes mdia e mxima anuais, Rio dos Patos
fqiemp.py clculo de uma FDA emprica . . . . . . . . . . . . . .
fqiemp.dat FDA emprica da vazo mxima anual no Rio dos Patos.
bintext.py Exemplo de arquivo texto e arquivo binrio . . . . . .
writearr.py Escreve um arquivo binrio contendo 3 linhas,
cada uma das quais com um array de 10 floats. . . . . . . . . . . .
readarr.py Escreve um arquivo binrio contendo 3 linhas, cada
uma das quais com um array de 10 floats. . . . . . . . . . . . . . .
fiqemp.plt programa para plotar a FDA emprica do Rio dos Patos
weibull.plt como ajustar uma FDA analtica (Weibull) aos dados
da FDA emprica . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
interp.py mdulo com funo para calcular uma interpolao
linear. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ppbemp.py projeto probabilstico a partir da distribuio emprica
mulambdak.max clculo da mdia da distribuio Weibull em em
funo de seus parmetros e k . . . . . . . . . . . . . . . . . . . . .
achapol.max Polinmio com propriedades definidas . . . . . . . .
Sada de achapol.max . . . . . . . . . . . . . . . . . . . . . . . . . .
passaquad.max parbola h(x) = ax2 + bx + c passando por
(1, f (1)), (3, f (3)) e (5, f (5)). . . . . . . . . . . . . . . . . . . . . . .
Sada de passaquad.max . . . . . . . . . . . . . . . . . . . . . . . . .
numint.py Integrao numrica, regra do trapzio . . . . . . . . .
quadraver1.py Integrao numrica de f (x) com 8 trapzios . . .
numint.py Integrao numrica ineficiente, com erro absoluto prestabelecido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
quadraver2.py Integrao numrica ineficiente de f (x) com  =
0,0001 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
numint.py Integrao numrica eficiente, com erro absoluto prestabelecido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
quadraver3.py Integrao numrica eficiente de f (x) com  =
0,000001 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
vererf.py Clculo da funo erro por integrao numrica . . . .
vererf.plt Plotagem da funo erro por integrao numrica versus a erf(x) pr-definida em Gnuplot . . . . . . . . . . . . . . . . . .
Clculo de erf(x) com uma srie de Taylor. . . . . . . . . . . . . . . .
vererf1.py Clculo da funo erro com srie de Taylor entre 0 e 3.
9

13
15
17
18
19
20
21
22
23
25
28
29
31
34
34
36
37
39
39
40
40
41
41
43
43
46
46

Sumrio
2.15 vererf1.plt Plotagem da funo erro calculada com srie de Taylor versus a erf(x) pr-definida em Gnuplot . . . . . . . . . . . . . . .
2.16 erfs.py Clculo de erf(x) com srie de Taylor, limitado a no
mximo 43 termos . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1 resolve-eqdif Soluo de uma EDO com Maxima . . . . . . . .
3.2 fracasso.py Um programa com o mtodo de Euler que no funciona
3.3 Sada de fracasso.py . . . . . . . . . . . . . . . . . . . . . . . . . .
3.4 sucesso.py Um programa com o mtodo de Euler que funciona .
3.5 sucimp.py Mtodo de Euler implcito . . . . . . . . . . . . . . . .
3.6 euler2 Um mtodo explcito de ordem 2 . . . . . . . . . . . . . .
3.7 rungek4 Mtodo de Runge-Kutta, ordem 4 . . . . . . . . . . . . .
4.1 onda1d-ins.py Soluo de uma onda 1D com um mtodo explcito
instvel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 surf1d-ins.py Seleciona alguns intervalos de tempo da soluo
numrica para plotagem . . . . . . . . . . . . . . . . . . . . . . . . .
4.3 onda1d-lax.py Soluo de uma onda 1D com um mtodo explcito
laxtvel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.4 surf1d-lax.py Seleciona alguns intervalos de tempo da soluo
numrica para plotagem . . . . . . . . . . . . . . . . . . . . . . . . .
4.5 difusao1d-ana.py Soluo analtica da equao da difuso . . . .
4.6 divisao1d-ana.py Seleciona alguns instantes de tempo da soluo
analtica para visualizao . . . . . . . . . . . . . . . . . . . . . . . .
4.7 difusao1d-exp.py Soluo numrica da equao da difuso: mtodo explcito. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.8 divisao1d-exp.py Seleciona alguns instantes de tempo da soluo
analtica para visualizao . . . . . . . . . . . . . . . . . . . . . . . .
4.9 alglin.py Exporta uma rotina que resolve um sistema tridiagonal,
baseado em Press et al. (1992) . . . . . . . . . . . . . . . . . . . . . .
4.10 difusao1d-imp.py Soluo numrica da equao da difuso: mtodo implcito. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.11 difusao1d-ckn.py Soluo numrica da equao da difuso: esquema de Crank-Nicholson. . . . . . . . . . . . . . . . . . . . . . . .
patosmedmax.dat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

47
48
49
51
51
52
55
57
58
63
64
68
69
73
74
76
77
80
81
84
89

1
Ferramentas computacionais
Neste captulo ns fazemos uma introduo muito rpida a 3 ferramentas computacionais.
Python uma linguagem de programao, razoavelmente clssica, e da qual ns
vamos explorar apenas uma parte chamada de programao procedural. A escolha
de Python deve-se ao fato de ela ser uma linguagem fcil de aprender, e de existirem muitas bibliotecas de rotinas em Python que tornam muitas das tarefas de
Matemtica Aplicada fceis de implementar em um computador.
Gnuplot uma linguagem para gerar grficos. Ela bastante popular, fcil de
usar, e muito flexvel. Ns vamos gerar todos os nossos grficos bidimensionais
(grficos x y) com Gnuplot.
Maxima uma linguagem de processamento simblico. Da mesma maneira que
ns faremos contas com Python, ns faremos lgebra com Maxima. Os usos que
faremos de Maxima estaro longe de explorar todo o seu potencial. Ns vamos
apenas calcular algumas integrais, algumas sries de Taylor, e resolver algumas
equaes diferenciais ordinrias; entretanto, a rapidez com que faremos isto justifica
amplamente o seu uso.
Infelizmente, a verso de um programa de computador faz diferena, e s vezes
faz muita diferena. As verses que eu utilizei para este texto foram:
Python:

2.6.5

Gnuplot:

4.4

Maxima:

5.21.1

Neste momento, existem duas linhagens de Python convivendo: 2.x, e 3.x. O


futuro Python 3.x, e eu procurei usar uma sintaxe to prxima de 3.x quanto
possvel. Isto facilitado por comandos to tipo
h

from __future__ import ,

que voc encontrar diversas vezes ao longo do texto. Se voc (j) estiver usando
Python 3.x, remova estes comandos do incio de seus arquivos .py.

1.1 Antes de comear a trabalhar,


Voc precisar de algumas condies de funcionamento. Eis os requisitos fundamentais:
11

Matemtica Aplicada

12

1) Saber que sistema operacional voc est usando.


2) Saber usar a linha de comando, ou terminal, onde voc datilografa comandos
que so em seguida executados.
3) Saber usar um editor de texto, e salvar seus arquivos com codificao ISO-8859-1.
4) Certificar-se de que voc tem Python instalado.
5) Certificar-se de que voc tem Numpy (um mdulo de Python que deve ser instalado parte, e que vamos utilizar seguidamente) instalado.
6) Certificar-se de que voc tem Gnuplot instalado.
7) Certificar-se de que voc tem Maxima instalada.
Ateno! Um editor de texto no um processador de texto. Um editor
de texto no produz letras de diferentes tamanhos, no cria tabelas, e no insere figuras. Um editor de texto reproduz o texto que voc datilografa, em geral com um tipo de largura constante para que as colunas e espaos fiquem bem
claros. Um editor de texto que vem com Windows chama-se notepad, ou bloco
de notas nas verses em Portugus; um excelente substituto chama-se notepad2
(http://www.flos-freeware.ch/notepad2.html). Em Linux, editores de texto
simples so o gedit, e o kate. Programadores mais experientes costumam preferir o
vim, ou o emacs. Estes dois ltimos possuem verses para os 3 sistemas operacionais
mais comuns hoje em dia: Windows, Linux e MacOS.
Quando voc estiver praticando o uso das ferramentas computacionais descritas
neste texto, suas tarefas invariavelmente sero:
1) Criar o arquivo com o programa em Python, Gnuplot, ou Maxima, usando o
editor de texto, e salv-lo em codificao ISO-8859-1.
Se no for bvio para voc, procure descobrir como voc pode configurar o seu editor para salvar em ISO-8859-1. Se isto for impossvel
para voc, trabalhe normalmente, mas no use acentos: em lugar de
impossvel, digite impossivel.
2) Ir para a linha de comando.
3) Executar o programa digitando o seu nome (e no clicando!), possivelmente
precedido por python, gnuplot, ou maxima.
4) Verificar se o resultado est correto.
5) Se houver erros, voltar para 1), e reiniciar o processo.
Neste texto, eu vou partir do princpio de que todas estas condies esto cumpridas por voc, mas no vou detalh-las mais: em geral, sistemas operacionais,
editores de texto e ambientes de programao variam com o gosto do fregus: escolha os seus preferidos, e bom trabalho!

13

1.2 Python
Listagem 1.1: binint.py exemplo de strings, e inteiros.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
a = ' aafro '
# a uma string
# imprime a na tela
print ( a )
print ( len ( a ))
# imprime o nmero de caracteres de a
i = 2**32 - 1
# i o maior int s / sinal que cabe em 32 bits
b = unicode ( i )
# converte i na string c orrespon dente b
# imprime b na tela
print ( b )
print ( ' --- a : ')
# separa a sada do primeiro for
# p / cada c de a , imprime seu valor unicode
for c in a :
print ( ' ord ( ' , c , ') = ' , ord ( c ))
print ( ' --- b : ')
# separa a sada do segundo for
# p / cada c de b , imprime seu valor unicode
for c in b :
print ( ' ord ( ' , c , ') = ' , ord ( c ))
print ( unichr (227))
# imprime o caractere unicode no 227

Exerccios Propostos
1.1 Voc j devia estar esperando por isto: o que um sistema operacional? Qual o
sistema operacional que voc usa?
1.2 Como saber se Python est instalado?

1.2 Python
Python reconhece os seguintes tipos bsicos de variveis: strings, nmeros
inteiros, nmeros de ponto flutuante, e nmeros complexos.
1.2.1 Strings e Inteiros
Strings, ou cadeias de caracteres, so criaturas do tipo 'abacaxi', e nmeros
inteiros so criaturas do tipo -1, 0, e 32767. O tipo das strings que vamos usar
chama-se unicode em Python 2.x, e str em Python 3.x. O tipo dos nmeros
inteiros chama-se int em Python.
A listagem 1.1 mostra o contedo do arquivo binint.py com alguns exemplos
simples do uso de inteiros e strings. A legenda de cada listagem se inicia sempre
com o nome do arquivo correspondente (aps um pouco de hesitao, eu decidi no
disponibilizar estes arquivos; para testar os exemplos deste texto, voc precisar
digitar os arquivos novamente: isto o (a) forar a praticar programao). A listagem
um retrato fiel do arquivo, com duas excees: as palavras reservadas de Python
esto sublinhadas na listagem (mas no no arquivo), e os espaos em branco dentro
das strings esto enfatizados pelo smbolo .
Ateno: os nmeros que aparecem esquerda da listagem no fazem parte do
arquivo. Em Python, um comentrio inicia-se com #, e prossegue at o fim de linha.
A maior parte dos comandos de binint.py est explicada nos prprios comentrios.
Alguns comentrios (sem inteno de trocadilho) adicionais, por linha:
1

Este comentrio especial torna o arquivo executvel em Linux. O caminho


/usr/bin/python pode variar com a instalao, e mais ainda com o sistema
operacional.

14

Matemtica Aplicada
2

Este comentrio informa que o arquivo est codificado em iso-8859-1, no


bvio?

Magia negra: tudo que escrito entre aspas passa a ser uma string to tipo
unicode.

Magia negra: print deixa de ser uma declarao, e passa a ser uma funo.
Se voc no entendeu nada, no esquente.

O operador ** significa exponenciao. Nesta linha, a varivel i torna-se um


int, e recebe o valor 232 1. Este o maior valor sem sinal que um inteiro
pode assumir, j que o maior inteiro que cabe em 32 bits
11111111111111111111111111111111 (binrio) =
1 231 + 1 230 + 1 229 + . . . + 1 22 + 1 21 + 1 20 =
4294967295 (decimal) .

1213 O comando for percorre em ordem um objeto itervel (no caso, a string
'aafro' itervel, com a[0] == 'a', a[1] == '', etc.). O corpo do
for tem que ser indentado, e na listagem a indentao de 3 espaos. Desta
forma, no caso da linha 13, o comando
h

print('ord(',c,') = ', ord(c))

executado 7 vezes, uma para cada caractere de a. A volta indentao


anterior na linha 14 define o fim do for.
Vamos agora sada do programa binint.py:
aafro
7
4294967295
--- a :
ord ( a ) =
ord ( ) =
ord ( a ) =
ord ( f ) =
ord ( r ) =
ord ( ) =
ord ( o ) =
--- b :
ord ( 4 ) =
ord ( 2 ) =
ord ( 9 ) =
ord ( 4 ) =
ord ( 9 ) =
ord ( 6 ) =
ord ( 7 ) =
ord ( 2 ) =
ord ( 9 ) =
ord ( 5 ) =

97
231
97
102
114
227
111
52
50
57
52
57
54
55
50
57
53

print imprime com o formato apropriado inteiros e strings (e muito mais: quase
tudo, de alguma forma!). O maior inteiro que cabe em 32 bits sem sinal 4294967295
(como j vimos acima). A posio do caractere a na tabela Unicode 97; a posio
do caractere 231; a posio do caractere 4 52. Finalmente, o caractere Unicode
de nmero 227 o .
Se voc estiver vendo uma sada diferente da mostrada acima, com caracteres
estranhos, no se assuste (demais): o seu arquivo binint.py e o terminal dentro do

15

1.2 Python
Listagem 1.2: floats.py exemplo de uso de float e complex.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from math import pi , e , sin
# pi , e , e seno
# o seno de um nmero complexo vem com outro
from cmath import sin as csin
# nome , para no confundir
from cmath import sqrt as csqrt
# a raiz quadrada de um nmero complexo vem
# com outro nome , para no confundir
# imprime o valor de pi
print ( ' pi = ' , pi )
print ( 'e = ' ,e )
# imprime o valor de e
# imprime sen ( pi /2)
print ( ' sen ( pi /2) = ' , sin ( pi /2))
i = csqrt ( -1.0)
# neste programa , i == sqrt ( -1)
print ( ' sen ( i ) = ' , csin ( i ))
# imprime sen ( i )

qual voc est executando este programa certamente esto utilizando codificaes
diferentes (veja se o apndice ?? pode ajudar).
1.2.2 Nmeros de ponto flutuante reais e complexos
Em primeiro lugar, um esclarecimento: no computador, no possvel representar todos os nmeros x R do conjunto dos reais, mas apenas um subconjunto dos
racionais Q. Linguagens de programao mais antigas, como FORTRAN, ALGOL e
PASCAL, mesmo assim chamavam estes tipos de REAL. A partir de C, e continuando
com Python, em muitas linguagens passou-se a usar o nome mais adequado float.
Python vem com uma grande quantidade de mdulos predefinidos, e voc pode
adicionar seus prprios mdulos. Deles, importam-se variveis e funes (e outras
coisas) teis. Nosso primeiro exemplo do uso de nmeros de ponto flutuante (float)
e complexos (complex) no podia ser mais simples, na listagem 1.2
Eis a sada de floats.py:
pi = 3.14159265359
e = 2.71828182846
sen ( pi /2) = 1.0
sen ( i )
= 1.17520119364 j

Os comentrios importantes seguem-se. Lembre-se de que na maioria dos casos


voc est vendo aproximaes racionais de nmeros reais, e que o computador no
pode lidar com todos os nmeros reais.
Como era de se esperar, sen /2 = 1. Por outro lado, o seno de i um nmero
puramente imaginrio, e vale 1,17520119364i. Note que Python usa a letra j
para indicar um valor imaginrio (e no i). Na linha 13, eu
forcei a barra, e criei
a varivel que, em notao matemtica se escreveria i = 1. Mas eu tambm
poderia ter simplesmente eliminado esta linha, e substitudo a linha 14 por
h

print(sen(i) = ,csin(1j)) .

Note que existem dois mdulos, math e cmath, para variveis reais e complexas,
respectivamente. Em ambos, existe uma funo denominada sin, que calcula o
seno. Para poder usar estas duas funes diferentes em meu programa floats.py,
eu rebatizei a funo sin complexa de csin, no ato da importao do mdulo, com
o mecanismo from ... import ... as ... (linha 6).

16

Matemtica Aplicada

Tabela 1.1: Vazes Mximas Anuais (m3 s1 ) no Rio dos Patos, PR, 19311999
Ano

Vaz Mx

Ano

Vaz Mx

Ano

Vaz Mx

Ano

Vaz Mx

1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950

272.00
278.00
61.60
178.30
272.00
133.40
380.00
272.00
251.00
56.10
171.60
169.40
135.00
146.40
299.00
206.20
243.00
223.00
68.40
165.00

1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970

266.00
192.10
131.80
281.00
311.50
156.20
399.50
152.10
127.00
176.00
257.00
133.40
248.00
211.00
208.60
152.00
92.75
125.00
135.60
202.00

1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990

188.00
198.00
252.50
119.00
172.00
174.00
75.40
146.80
222.00
182.00
134.00
275.00
528.00
190.00
245.00
146.80
333.00
255.00
226.00
275.00

1991
1992
1993
1994
1995
1996
1997
1998
1999

131.00
660.00
333.00
128.00
472.00
196.00
247.50
451.00
486.00

Exerccios Propostos
1.3 Usando Python, converta 7777 da base 10 para a base 2. Sugesto: estude a documentao em www.python.org, e encontre a rotina pr-definida (built-in) que faz isto.
1.4 Como se faz para concatenar as strings bom e demais?

1.2.3 Obteno de uma curva de permanncia


Uma funo distribuio acumulada (FDA) de probabilidade uma funo que
nos informa qual a probabilidade de que uma varivel aleatria Q assuma um valor
menor ou igual que um certo nivel q. Os valores de Q variam de experimento para
experimento. Por exemplo, se Q a vazo mxima diria em um rio em um ano
qualquer, o valor observado de Q varia de ano para ano.
A tabela 1.1 d os valores da vazo mxima anual para o Rio dos Patos, PR,
estao ANA (Agncia Nacional de guas do Brasil) 64620000, entre 1931 e 1999.
Provavelmente, a maneira mais simples de se estimar uma FDA a partir de um
conjunto de dados supor que os dados representam a totalidade das possibilidades,
e que as observaes so equiprovveis (em analogia com os 6 nicos resultados
possveis do lanamento de um dado no-viciado). No caso da tabela 1.1, se qi a
vazo mxima do i-simo ano, teramos que a probabilidade de ocorrncia de qi
P {Q = qi } =

1
,
n

(1.1)

17

1.2 Python

Listagem 1.3: patos-medmax.dat vazes mdia e mxima anuais, Rio dos Patos
1931
1932
1933
1934
1935

21.57
25.65
4.76
11.46
28.10

272.00
278.00
61.60
178.30
272.00

onde n o nmero de observaes. Mas a FDA por definio


F (q) = P {Q q}.

(1.2)

Para obt-la, preciso considerar os valores iguais ou menores que o valor de corte
q. Portanto, ns devemos primeiro ordenar os qi s, de tal maneira que
q0 q1 . . . qn1 .
Note que a ordenao no altera (1.1). Aps a ordenao, o clculo de F (qi )
trivial:
i
X
1
i+1
F (qi ) =
=
.
(1.3)
n
n
k=0
(1.3) chamada de distribuio acumulada emprica de probabilidade. Em Hidrologia, muitas vezes (1.3) denominada curva de permanncia. O resultado (i + 1)/n
denominado uma posio de plotagem. Por diversos motivos, existem muitas outras posies de plotagem possveis para a FDA emprica. Uma muito popular
(i + 1)/(n + 1). A discusso detalhada de posies de plotagem deve ser feita em
um curso de Probabilidade e Estatstica, e no aqui, onde (1.3) serve (apenas) como
um exemplo motivador.
Os dados da tabela 1.1 esto digitados no arquivo patos-medmax.dat (Apndice
A). Este arquivo contm 3 colunas contendo, respectivamente, o ano, a vazo mdia
do ano, e a vazo mxima do ano. A listagem 1.3 mostra as 5 primeiras linhas do
arquivo (que possui 69 linhas).
O programa fqiemp.py, mostrado na listagem 1.4, calcula a curva de permanncia, ou FDA emprica, para as vazes mximas anuais do Rio dos Patos. Esta ,
simplesmente, uma tabela de duas colunas: a vazo observada (em ordem crescente),
e o valor de (i + 1)/n.
Como antes, os comentrios em fqiemp.py explicam muito do que est acontecendo. Mas h necessidade de explicaes adicionais:
5

Faz a diviso funcionar como em Python 3.x. Em Python 2.x, 3/4 == 0,


e 3.0/4 == 0.75. Em Python 3.x, / sempre produz um resultado do tipo
float (ou complex); e um novo operador // sempre produz diviso inteira.

A funo pr-definida open abre o arquivo patos-medmax.dat, descrito acima


e exemplificado na listagem 1.3. O segundo argumento de open, a string
'rt', diz duas coisas: com r, que se trata de uma operao de leitura, (read),
de um arquivo que j existe: isto garante que patos-medmax.dat no ser
modificado por fqiemp.py; com t, que se trata de um arquivo texto. Um
arquivo texto um arquivo formado por linhas, sendo cada linha uma string.
As linhas so separadas por caracteres (invisveis no editor de texto) de fim
de linha, que convencionalmente ns indicamos por \n. Um arquivo texto
um objeto itervel, que pode ser acessado linha a linha.

18

Matemtica Aplicada

Listagem 1.4: fqiemp.py clculo de uma FDA emprica


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from __future__ import division
fin = open ( ' patos - medmax . dat ' , ' rt ')
#
qmax = []
#
#
for linha in fin :
campo = linha . split ()
#
#
print ( campo )
qi = float ( campo [2])
#
qmax . append ( qi )
#
fin . close ()
#
fou = open ( ' fqiemp . dat ' , ' wt ')
#
qmax . sort ()
#
n = len ( qmax )
#
#
for i in range ( n ):
qi = qmax [ i ]
#
Fi = ( i +1)/ n
#
fou . write ( ' %8.2 f %8.6 f \ n ' % ( qi , Fi )) #
fou . close ()
#

abre o arquivo de dados ( entrada )


uma lista vazia
loop nas linhas do arquivo
separa os campos
para ver campo a campo na tela
a vazo o terceiro campo
adiciona qi lista qmax
fecha o arquivo de entrada
abre o arquivo de sada
ordena a lista
tamanho da lista
loop nos elementos da lista ordenada
vazo
posio de plotagem
imprime uma linha
fim de papo

Nesta linha, qmax inicializado como uma lista vazia. Uma lista uma
sequncia de objetos quaisquer. Dada uma lista a, seus elementos so a[0],
a[1], etc.. Uma lista a com n objetos vai de a[0] at a[n-1].

Este o loop de leitura do programa. linha uma string que contm em


cada iterao uma das linhas de patos-medmax.dat.

preciso separar uma linha (veja a listagem 1.3) em seus 3 campos. O


mtodo1 split separa a string linha em 3 strings, e as coloca em uma
lista campo == [ campo[0], campo[1], campo[2] ], usando os espaos em
branco como separadores (que so eliminados).

10

Cada um dos campos agora ele mesmo uma string, com os valores separados.
As 5 primeiras linhas que aparecem na tela devido ao comando print da linha
10 so:
[ '1931 ' ,
[ '1932 ' ,
[ '1933 ' ,
[ '1934 ' ,
[ '1935 ' ,

'21.57 ' , '272.00 ']


'25.65 ' , '278.00 ']
'4.76 ' , '61.60 ']
'11.46 ' , '178.30 ']
'28.10 ' , '272.00 ']

11

No entato, estes campos ainda so strings, e no floats. Aqui o terceiro


campo convertido em um float e vai para a varivel qi.

12

Finalmente, qi includa na lista qmax.

13

bom estilo de programao fechar cada arquivo previamente aberto.

14

Agora o programa abre o arquivo de sada, fqiemp.dat. w significa abertura


para escrita (write); e t que o arquivo ser texto.
1

Em Python, um mtodo uma rotina que pertence a uma varivel ou um tipo (a rigor, a
uma classe, mas este no um curso de programao)

19

1.2 Python

Listagem 1.5: fqiemp.dat FDA emprica da vazo mxima anual no Rio dos
Patos.
56.10
61.60
68.40
75.40
92.75

0.014493
0.028986
0.043478
0.057971
0.072464

15

sort um mtodo pr-definido para qualquer lista, que a ordena (por default
em ordem crescente).

16

len uma funo pr-definida que retorna o nmero de elementos da lista.

17

loop para impresso no arquivo de sada.

18

Obtm o i-simo elemento de qmax, colocado na varivel qi, que re-utilizada


para este fim.

19

Calcula a posio de plotagem, utilizando o operador / para dividir dois ints


e gerar um resultado correto do tipo float (veja comentrio sobre a linha 5).

20

write um mtodo do arquivo fou. write sempre escreve seu nico argumento, que tem que ser uma string, no arquivo. Trata-se portanto do
problema inverso do loop de leitura, que transformava strings em floats:
agora precisamos transformar floats em uma string. para isto que serve
o operador %: ele tem sua esquerda uma string com os campos de formatao especiais %8.2f e %8.6f; sua direita uma tupla 2 (qi,Fi) com tantos
elementos quantos so os campos de formatao. O primeiro elemento ser
substitudo no primeiro campo de formatao por uma string com 8 caracteres, sendo 2 deles para casas decimais. O segundo elemento ser substitudo
no segundo campo de formatao por uma string com 8 caracteres, sendo 6
deles para casas decimais. A string resultante, que precisa conter explicitamente o caractere de fim de linha \n, ser escrita no arquivo de sada.

As primeiras 5 linhas do arquivo de sada fqiemp.dat so mostradas na listagem


1.5.
Exerccios Propostos
1.5 Dado um nmero inteiro p lido do terminal, escreva um programa Python para procurar o ndice i de uma lista a de 10 nmeros inteiros definida internamente no programa
tal que a[i] == p, e imprimir o resultado.

1.2.4 Arquivos texto e arquivos binrios


Arquivos texto so legveis por seres humanos. Qualquer representao interna
primeiramente traduzida para uma string de caracteres antes de ser escrita em
um arquivo texto. Arquivos binrios em geral armazenam informao com a mesma
representao interna utilizada pelo computador para fazer contas, etc..
2

Em Python uma tupla uma lista imutvel

Matemtica Aplicada

20

Listagem 1.6: bintext.py Exemplo de arquivo texto e arquivo binrio


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import print _functio n
i = 673451
bdet = bin ( i )
print ( bdet )
fot = open ( 'i . txt ' , ' wt ')
fot . write ( ' %6 d ' % i )
fot . close ()
from struct import pack
b = pack ( 'i ' ,i )
fob = open ( 'i . bin ' , ' wb ')
fob . write ( b )
fob . close ()
print ( type ( i ))
print ( type ( b ))
from os . path import getsize
print ( ' tamanho do arquivo txt = % d bytes ' % getsize ( 'i . txt ' ))
print ( ' tamanho do arquivo bin = % d bytes ' % getsize ( 'i . bin ' ))

Como sempre, um exemplo vale por mil palavras. Na listagem 1.6, temos o
programa bintext.py, que produz dois arquivos: o arquivo texto i.txt, e o arquivo
binrio i.bin. Cada um destes arquivos contm o nmero inteiro i == 673451.
Eis aqui a dissecao de bintext.py:
5

A funo pr-definida bin produz a representao do objeto na base 2.

Escreve a varivel i no arquivo i.txt, usando um campo de 6 caracteres, que


o tamanho necessrio para escrever i na base 10.

10

A nica maneira de ler ou escrever um arquivo binrio em Python por meio


de byte strings: strings em que cada elemento um byte (8 bits). O mdulo
struct prov a converso de, e para, byte strings.

11

Converte i em uma byte string. Como a representao interna de i em 4


bytes, o tamanho de b ser de 4 bytes.

1516 Verifica os tipos de i e b.


1819 Mostra o tamanho de cada um dos arquivos gerados.
Finalmente, a sada de bintext.py
0 b10100100011010101011
< type 'int ' >
< type 'str ' >
tamanho do arquivo txt = 6 bytes
tamanho do arquivo bin = 4 bytes

Conte os 32 bits na primeira linha (aps o prefixo 0b, que indica a representao
na base 2): eles correspondem aos 4 bytes que custa ao programa para guardar o
nmreo inteiro 673451. Repare que o arquivo binrio menor que o arquivo texto.
Em geral, arquivos binrios tendem a ser menores (para a mesma quantidade de
informao). A outra grande vantagem que a leitura e a escritura de arquivos
binrios muito mais rpida, porque no h necessidade de traduzir a informao
de, e para, strings.

21

1.2 Python

Listagem 1.7: writearr.py Escreve um arquivo binrio contendo 3 linhas,


cada uma das quais com um array de 10 floats.
1
2
3
4
5
6
7
8

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from numpy . random import rand
fob = open ( 'a . bin ' , ' wb ')
for k in range (3):
a = rand (10)
a . tofile ( fob )
fob . close ()

#
#
#
#

abre um
loop em
gera um
escreve

arq binrio para escrita


3 " linhas "
array com 10 nmeros aleatrios
uma " linha "

Na prtica, arquivos binrios esto invariavelmente associados ao uso de arrays,


pelo menos em Engenharia. O mdulo Numpy3 , que no vem com Python, e necessita ser instalado parte, proporciona um tipo chamado array, e permite manipular
com boa eficincia computacional vetores e matrizes em Python. O tipo permite
na prtica substituir listas (tipo list); ademais, tudo ou quase tudo que funciona
com listas tambm funciona com arrays. Neste texto, ns faremos a partir de agora
amplo uso de Numpy e de seu tipo array. A referncia completa de Numpy est
disponvel em domnio pblico (Oliphant, 2006), podendo tambm ser comprada
pela Internet.
Alm de definir arrays, Numpy tambm proporciona seus prprios mtodos e funes para ler e escrever de e para arquivos binrios. Vamos ento dar dois exemplos
muito simples, porm muito esclarecedores.
Primeiro, um programa para escrever um array. A listagem 1.7 mostra o programa writearr.py. O programa usa uma rotina disponvel em numpy, rand, para
devolver um array com 10 nmeros aleatrios entre 0 e 1. writearr.py repete por
3 vezes a gerao de a e a sua escritura no arquivo binrio a.bin: a escritura utiliza
o mtodo tofile. Repare que tofile um mtodo do array a; ele no precisa ser
importado, pois ele j faz parte da varivel a a partir do momento em que ela
criada. writearr roda silenciosamente: no h nenhuma sada na tela. No entanto,
se procurarmos no disco o arquivo gerado, teremos algo do tipo
> ls -l a . bin
-rw -r - -r - - 1 nldias nldias 240 2011 -08 -28 14:08 a . bin

O arquivo gerado, a.bin, possui 240 bytes. Em cada uma das 3 iteraes de
writearr.py, ele escreve 10 floats no arquivo. Cada float custa 8 bytes, de
modo que em cada iterao 80 bytes so escritos. No final, so 240.
importante observar que o arquivo a.bin no possui estrutura: ele no sabe
que dentro dele mora o array a; ele , apenas, uma linguia de 240 bytes. Cabe
a voc, programadora ou programador, interpretar, ler e escrever corretamente o
arquivo.
Prosseguimos agora para ler o arquivo binrio gerado. Isto feito com o programa
readarray.py, mostrado na listagem 1.8.
O programa importa a rotina fromfile de Numpy, a partir da qual 3 instncias
de a so lidas do arquivo a.bin e impressas com formato na tela. Eis a sua sada:
0.2327 0.6117 0.7713 0.5942 0.1799 0.3156 0.1473 0.4299 0.0870 0.0846
0.4301 0.9779 0.0322 0.4833 0.6097 0.4387 0.0639 0.1399 0.4350 0.7737
0.5809 0.0382 0.6567 0.8062 0.8427 0.2511 0.2897 0.5785 0.2892 0.0385
3

numpy.scipy.org

Matemtica Aplicada

22

Listagem 1.8: readarr.py Escreve um arquivo binrio contendo 3 linhas, cada


uma das quais com um array de 10 floats.
1
2
3
4
5
6
7
8
9
10
11
12

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import print _functio n
from numpy import fromfile
# para escrever na tela
from sys import stdout
fib = open ( 'a . bin ' , ' rb ')
# abre o arquivo binrio
for k in range (3):
# loop em 3 " linhas "
a = fromfile ( fib , float ,10)
# l um array com 10 floats
# imprime com formato na tela
for e in a :
stdout . write ( ' %5.4 f ' % e )
stdout . write ( '\ n ')
fib . close ()

O que vemos so os nmeros aleatrios das 3 instncias de a escritas pelo programa writearr.py.

1.3 Gnuplot
Mas como a cara da funo distribuio acumulada emprica? Ns gostaramos de ver a funo, isto , plot-la. para isto que serve Gnuplot. Um
programa Gnuplot especifica o arquivo de onde vm os dados; que colunas queremos
utilizar; que smbolos ou tipos de linhas, bem como espessuras ou tamanhos ns
desejamos, e o nome do arquivo de sada (na falta de um nome para o arquivo de
sada, uma tela com o grfico dever se abrir para visualizao interativa). Via de
regra, o arquivo de sada de um programa Gnuplot no um arquivo texto, mas
um arquivo com uma descrio grfica qualquer. Extenses comuns de nomes de
arquivos que indicam imagens so .jpg, .png, .eps, e .emf (esta ltima em Windows). Gnuplot permite gerar arquivos de imagem em qualquer um destes formatos
(e muitos outros!). Neste texto, ns vamos sempre gerar pares de arquivos (quase
idnticos) .eps e .emf. Em Linux, um arquivo a.eps facilmente conversvel no
arquivo a.pdf mediante o comando
h

epstopdf a.eps ;

em Windows, um arquivo a.emf est pronto para ser visualizado (com um clique),
inserido em documentos, etc..
Ns j temos a FDA emprica da vazo mxima anual no Rio dos Patos, no arquivo fqiemp.dat; agora, ns vamos plot-la com o programa Gnuplot fiqemp.plt:
Como sempre, preciso explicar:
5

Gera um arquivo de sada no padro Encapsulated Postscript, em preto-ebranco, com tipo Times Roman, no tamanho 18pt.

O nome do arquivo de sada.

Gera um arquivo que mostra as convenes utilizadas neste terminal. Este


arquivo pode ser visto na figura 1.1

O nome do arquivo de sada.

Formato do eixo y, que usa a mesma conveno de Python (a bem da verdade,


de C).

23

1.3 Gnuplot

Listagem 1.9: fiqemp.plt programa para plotar a FDA emprica do Rio dos
Patos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

set encoding iso_8859_1


# ------------------------------------------------------------------------------# no mundo de linux
# ------------------------------------------------------------------------------set terminal postscript eps monochrome ' Times - Roman ' 18
set output ' test . eps '
test
set output ' fqiemp . eps '
set format y ' %3.1 f '
set grid
set xlabel ' Vazo mxima anual ( m3 / s ) '
set ylabel ' FDA emprica '
plot ' fqiemp . dat ' using 1:2 notitle with points pt 7
# -----------------------------------------------------------------------------# agora no mundo de Windows
# -----------------------------------------------------------------------------set terminal emf monochrome ' Times New Roman ' 18
set output ' test . emf '
test
set output ' fqiemp . emf '
replot
exit

10

Mostra o reticulado da escala.

11

Nome do eixo x.

12

Nome do eixo y.

13

Nome do arquivo de dados a ser utilizado; colunas para x e y; use pontos,


com smbolo 7 (veja a conveno na figura 1.1): gera o arquivo fqiemp.eps.

17

Mude o tipo de arquivo de sada para emf, usando o tipo Times New Roman,
no tamanho 18 pt.

18

O nome do arquivo de sada.

19

O mesmo que a linha 7.

20

O nome do arquivo de sada.

21

Plota novamente, usando todas as definies que no tiverem sido mudadas


(s mudamos o terminal de sada); agora, gera o arquivo fqiemp.emf.

Finalmente, podemos ver a FDA emprica gerada por fqiemp.plt, na figura 1.2.
Uma ltima observao de cunho esttico. Neste texto, as figuras que so geradas
por programas Gnuplot descritos explicitamente, e cujas listagens .plt so dadas
no texto, utilizam o tipo postscript Times-Roman. Olhe bem para o tipo utilizado
nas figuras 1.1 e 1.2: este no o tipo utilizado no restante do texto (por exemplo,
compare com as legendas).
J as figuras geradas para fim ilustrativo utilizam o mesmo tipo que o texto; veja
por exemplo as figuras 2.1, e ??.
Utilizar um tipo de letra diferente nas figuras e no texto ligeiramente inconsistente, do ponto de vista tipogrfico. Entretanto, a escolha de Times-Roman para

24

Matemtica Aplicada
show ticscale

Terminal Test

te
d

by

+4

de
g

left justified
centre+d text
right justified

ro

ta

test of character width:


12345678901234567890

ro
d

te

ta
by
4

rotated ce+ntred text

1
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
9 22
23
24

(color) filled polygon:

5
g

de
linewidth
lw 6
lw 5
lw 4
lw 3
lw 2
lw 1

pattern fill
3 4 5 6

Figura 1.1: Convenes do terminal postscript eps monochrome 'Times-Roman'


18
a sada em postscript, e de Times New Roman para a sada em EMF, foi feita em
nome da simplicidade e da universalidade. praticamente impossvel no existir
o tipo Times-Roman em seu sistema operacional Linux, e praticamente impossvel
no existir o tipo Times New Roman em seu sistema operacional Windows. Na preparao de um texto mais bem-elaborado tipograficamente voc deve, se possvel,
utilizar o mesmo tipo nas figuras e no texto. Mas isto, alm de ser outra histria,
do gosto do fregus.
1.3.1 Ajuste de uma funo
A definio da FDA emprica em (1.3) muito limitada: bvio que nenhum
destes 69 valores da tabela 1.1, ao contrrio do que acontece no jogo de dados, jamais
se repetir. Tambm bvio que valores maiores do que mximo de 660 m3 s1
podero ocorrer no futuro (em relao a 1999 . . . ), e isto uma poderosa fonte de
crtica posio de plotagem ingnua que ns utilizamos em (1.3): ela prev que a
probabilidade de uma vazo mxima anual maior do que 660 m3 s1 nula!
Em suma, nossa esperana que uma relao analtica, uma frmula, faa um
trabalho no mnimo um pouco melhor do que a FDA emprica foi capaz de fazer para
prever as probabilidades da vazo mxima anual no Rio dos Patos mas espere
para ver o resultado!
Vamos tentar ajustar uma frmula aos dados. A frmula que escolheremos a
da distribuio de Weibull,


F (q) = 1 exp (q/)k .

(1.4)

No existe absolutamente nenhum motivo transcedental para utilizar (1.4): ela apenas atende aos requisitos fundamentais de uma FDA (tende a 0 em x ; e a
1 em x +). A rigor, a Weibull definida apenas para q 0, que o que se
espera de qualquer vazo em rios nenhum rio tem vazo negativa; nenhum rio
corre do mar para suas cabeceiras.

25

1.3 Gnuplot

1.0
0.9
0.8

FDA emprica

0.7
0.6
0.5
0.4
0.3
0.2
0.1
0.0
0

100

200

300
400
500
Vazo mxima anual (m3/s)

600

700

Figura 1.2: FDA da vazo mxima anual, Rio dos Patos

Listagem 1.10: weibull.plt como ajustar uma FDA analtica (Weibull) aos
dados da FDA emprica
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

set encoding iso_8859_1


# ------------------------------------------------------------------------------# no mundo de linux
# ------------------------------------------------------------------------------set terminal postscript eps monochrome ' Times - Roman ' 18
# ------------------------------------------------------------------------------# ajusta lambda e k
# ------------------------------------------------------------------------------lambda = 1000.0
k = 1.0
F ( x ) = 1.0 - exp ( -(( x / lambda )** k ))
fit F ( x ) ' fqiemp . dat ' using 1:2 via lambda , k
set output ' weibullfit . eps '
set format y ' %3.1 f '
set grid
set xlabel ' Vazo mxima anual ( m3 / s ) '
set ylabel ' FDA '
set xrange [0:1000]
set yrange [0:1]
set xtics 0 ,100
set ytics 0 ,0.1
set samples 10000
plot ' fqiemp . dat ' using 1:2 notitle with points pt 7 , \
F ( x ) with lines notitle lt 1 lw 3
# -----------------------------------------------------------------------------# agora no mundo de Windows
# -----------------------------------------------------------------------------set terminal emf monochrome ' Times New Roman ' 18
set output ' weibullfit . emf '
replot
exit

26

Matemtica Aplicada

No programa weibullfit.plt, mostrado na listagem 1.10, veja como Gnuplot


lida facilmente com o ajuste dos valores de e de k aos dados de que dispomos.
Gnuplot produz informaes na tela sobre o ajuste requisitado pelo comando fit;
as ltimas linhas da sada em tela so
After 11 iterations the fit converged .
final sum of squares of residuals : 0.0604353
rel . change during last iteration : -6.18025 e -06
degrees of freedom
( FIT_NDF )
rms of residuals
( FIT_STDFIT ) = sqrt ( WSSR / ndf )
variance of residuals ( reduced chisquare ) = WSSR / ndf

: 67
: 0.0300336
: 0.000902019

Final set of parameters


=======================

Asymptotic Standard Error


==========================

lambda
k

+/ - 1.283
+/ - 0.05594

= 233.486
= 2.62023

(0.5495%)
(2.135%)

correlation matrix of the fit parameters :


lambda k
1.000
-0.346 1.000

lambda
k

donde = 233,486, k = 2,62023. Na listagem 1.10, comentrios adicionais so:


910 Os valores iniciais de lambda e k influenciam nos valores finais encontrados
ou no. Por exemplo, se mudarmos a linha 9 para
h

lambda = 1.0 ,

o comando fit da linha 12 no consegue ajustar a curva F (x); muitas vezes


voc precisar fazer vrias tentativas com os valores iniciais at ter sucesso.
11

possvel definir funes que sero depois plotadas.

22

possvel aumentar o nmero de pontos utilizados para traar curvas, quando


a aparncia das mesmas for quebrada.

23

possvel aumentar a espessura das curvas, com lw (line width): o nmero


a seguir especifica a espessura desejada: veja a figura 1.1.

A figura 1.3 mostra o grfico gerado: note como a cauda da direita, ou seja, os
valores maiores de vazo mxima, so mal ajustados: F (q) subestima o valor de q
para probabilidades altas (prximas de 1): o uso da Weibull para este conjunto de
dados seria desastroso, uma vez que as maiores cheias seriam subestimadas!
Exerccios Propostos
1.6 Usando Gnuplot, plote em tons de cinza a rea debaixo da curva y = x para x = 2.
Quanto vale esta rea?

1.4 Python de novo: projeto probabilstico


De fato, um projeto probabilstico a definio de um valor de corte q cuja probabilidade de excedncia seja menor que um certo risco predeterminado . Suponha
que, para o Rio dos Patos, ns desejemos calcular o valor q da vazo mxima anual

27

1.4 Python de novo: projeto probabilstico


1.0
0.9
0.8
0.7

FDA

0.6
0.5
0.4
0.3
0.2
0.1
0.0
0

100

200

300

400
500
600
700
Vazo mxima anual (m3/s)

800

900

1000

Figura 1.3: Ajuste de uma FDA Weibull aos dados de vazo mxima anual do Rio
dos Patos
cuja probabilidade de excedncia em um ano qualquer seja = 0.05 (5%). Isto
significa que precisamos resolver a equao
P {Q > q} = 1 P {Q q} = ,
1 F (q) = ,
F (q) = 1 ,

(1.5)

para q.
Quando a F (q) a FDA emprica, no existe uma equao para se resolver, mas
sim uma tabela na qual devemos interpolar o valor desejado de q. Primeiramente
ns precisamos escrever uma funo que, dado um valor xc, procure o intervalo em
que ele se encontra na coluna x da tabela, e em seguida calcule o yc correspondente
interpolando linearmente entre os valores da coluna y para o mesmo intervalo. O
mdulo interp, arquivo interp.py, mostrado na listagem 1.11, faz isto.
interp no um programa: ele um mdulo que contm uma nica funo
(que possui tambm o nome interp). Esta rotina estar disponvel para qualquer
programa Python por meio de uma declarao do tipo
h

from interp import interp .

A dissecao do mdulo e da funo interp


6

Em Python, uma funo definida com a palavra reservada def.

assert significa assegure-se de que; == um operador lgico que retorna


True se os operandos forem iguais.

1718 iu para upper, il para lower: so os ndices do intervalo que contm


xc. O intervalo se inicia igual ao intervalo da tabela toda.

Matemtica Aplicada

28

Listagem 1.11: interp.py mdulo com funo para calcular uma interpolao
linear.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from __future__ import division
def interp ( xc , x , y ):
nx = len ( x )
ny = len ( y )
assert nx == ny
# x e y devem ser listas com tamanhos iguais
# deve haver pelo menos 2 pontos
if nx < 2:
exit ( " interp : n = % d deve ser >= 2\ n " % nx )
if ( xc < x [0]) or ( xc > x [ nx -1]):
# xc deve estar no intervalo da lista x
exit ( " xc = % lf fora de alcance : % f % f \ n " % ( xc , x [0] , x [ nx -1]))
# -----------------------------------------------------------------------------# inicia uma busca binria
# -----------------------------------------------------------------------------iu = nx - 1
il = 0
while ( iu - il > 1):
im = ( iu + il )//2
if ( xc <= x [ im ] ):
iu = im
else :
il = im
# -----------------------------------------------------------------------------# interpola linearmente , e retorna
# -----------------------------------------------------------------------------dx = ( x [ iu ] - x [ il ])
# delta x
dy = ( y [ iu ] - y [ il ])
# delta y
m = dy / dx
# coeficiente angular
return ( y [ il ] + m * ( xc - x [ il ]))
# y interpolado

1924 Este um algoritmo de busca binria: o ndice iu vai diminuindo, ou o ndice


il vai aumentando, at que a diferena entre os dois seja igual a 1. Estude-o,
e compreenda-o.

2831 Uma interpolao linear padro. Lembre-se da equao da reta em Geometria


Analtica.

Agora que temos uma funo de interpolao linear, podemos escrever um programa que a utilize. Este programa, ppbemp.py (projeto probabilstico a partir da
distribuio emprica) mostrado na listagem 1.12, simplesmente l a tabela com a
FDA emprica (que, como sabemos, est no arquivo fqiemp.dat), e interpola um
valor qproj nesta tabela. O programa muito bvio, e no necessita de maiores
explicaes.
A vazo com risco de 5% de excedncia calculada q20 = 462,55m3 s1 . Como
5% = 1/20, comum em Hidrologia (e em outras disciplinas em que se utiliza
critrios de risco) dizer que q20 a vazo de 20 anos de tempo de recorrncia.
Para projetar a partir da F (x) analtica (isto , da Weibull com os valores de k
e de encontrados anteriormente), basta resolver (1.5) analiticamente:

29

1.4 Python de novo: projeto probabilstico

Listagem 1.12: ppbemp.py projeto probabilstico a partir da distribuio emprica


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from __future__ import division
fin = open ( ' fqiemp . dat ' , ' rt ')
# abre o arquivo de dados ( entrada )
qq = []
# tabela inicialmente vazia
FF = []
# tabela inicialmente vazia
# loop nas linhas do arquivo
for linha in fin :
campo = linha . split ()
# separa os campos
( qi , Fi ) = ( float ( campo [0]) , float ( campo [1]))
qq . append ( qi )
FF . append ( Fi )
fin . close ()
# fecha o arquivo de entrada
# importa interp
from interp import interp
qproj = interp (0.95 , FF , qq )
# projeto para risco de exc . de 5%
print ( " qproj = %8.2 f \ n " % qproj )
# fim de papo

F (q20 ) = 0,95,


1 exp (q20 /)k = 0,95,


exp (q20 /)k = 0,05,
(q20 /233,486)2,62023 = 2.99573,
q20 /233,486 = 2.995731/2,62023 = 1.52004,
q20 = 354.908
Observe que este um valor consideravelmente menor que o da prpria distribuio emprica! Como j havamos comentado baseados na anlise visual da figura
1.3, a distribuio ajustada subestima as vazes com tempos de recorrncia altos, e
no deve ser utilizada para projetos probabilsticos: s vezes uma tabela de dados
usada corretamente melhor que um modelo matemtico ajustado com ferramentas
computacionais sofisticadas!
Alm disso, o mtodo que utilizamos para ajustar a FDA da Weibull, usando o
comando fit de Gnuplot, incomum: em Probabilidade e Estatstica, existem outros mtodos para o ajuste de distribuies de probabilidade, notadamente o mtodo
dos momentos e o mtodo da mxima verossimilhana. O uso de outros mtodos de
ajuste, e de outras distribuies de probabilidade, provavelmente produziria resultados muito melhores.
Exerccios Propostos
1.7 Usando Gnuplot ( claro), plote a vazo mdia anual do Rio dos Patos em funo do
tempo.
1.8 Com Gnuplot, ajuste uma reta s vazes mdias em funo do tempo no Rio dos
Patos, e plote novamente. Voc acha que a vazo mdia do Rio dos Patos est mudando
com o tempo?

30

Matemtica Aplicada

1.5 Maxima
Maxima a linguagem de processamento simblico mais antiga que existe: ela
se chamava, quando foi criada, MACSYMA. A mudana de nome ocorreu quando o
cdigo se tornou livre. Maxima capaz de fazer lgebra, derivar, integrar, resolver
equaes diferenciais, calcular transformadas de Laplace, etc., analiticamente. Por
exemplo: voc sabe quanto (a + b)4 ? No? Digitando maxima na linha de comando
voc obter
Maxima 5.21.1 http :// maxima . sourceforge . net
using Lisp GNU Common Lisp ( GCL ) GCL 2.6.7 ( a . k . a . GCL )
Distributed under the GNU Public License . See the file COPYING .
Dedicated to the memory of William Schelter .
The function bug_report () provides bug reporting information .
(% i1 )

Continuando a digitar, voc encontrar:


(% i1 ) ( a + b )^4 ;
(% o1 )
(% i2 ) expand (%);
(% o2 )
(% i3 ) quit ();

(b + a)
b

+ 4 a b

+ 6 a

4
2

+ 4 a

b + a

O comando
h

quit();

o devolver para a linha de comando.


Vamos fazer algo um pouco mais sofisticado: suponha que voc deseje calcular a
mdia de populao da distribuio Weibull, que ns encontramos na seo anterior,
em funo de seus dois parmetros e k. Por definio, a mdia de uma distribuio
cuja FDA F (x)
Z
dF
dx,
(1.6)
=
x
dx
xD
onde D o domnio de validade da varivel aleatria. No caso da Weibull, x 0,
donde
Z

i
d h
x
=
1 exp (x/)k dx.
(1.7)
dx
0
A derivada ficou intencionalmente indicada: estou supondo que ns somos preguiosos, e no queremos calcul-la manualmente, nem integral. A listagem 1.13 mostra
uma maneira de calcular , em funo de e de k, com Maxima.
As explicaes se seguem:
12

Declara que k e lam so variveis reais. O smbolo $ no fim de cada linha


omite a resposta de Maxima; isto til quando executamos uma srie de
comandos de Maxima em batch (em srie) a partir de um arquivo .max, e
no estamos interessados em ver o resultado de cada um deles. Em sees
interativas, o normal encerrar cada comando com ;.

34

Maxima supor que k e lam so positivos em seus clculos.

Sem a linha 5, Maxima vai parar e perguntar se k integer apesar da


linha 1!

31

1.5 Maxima

Listagem 1.13: mulambdak.max clculo da mdia da distribuio Weibull em em


funo de seus parmetros e k
1
2
3
4
5
6
7
8

declare ( [ k ] , real ) $
declare ( [ lam ] , real ) $
assume ( k > 0) $
assume ( lam > 0) $
declare ( [ k ] , noninteger ) $
F : 1 - exp ( -( x / lam )^ k ) $
fdp : diff (F , x ) $
mu : integrate ( x * fdp ,x ,0 , inf ) ;

Define F (F (x)): note que no F(x)! Note tambm que a atribuio, em


Maxima, no feita com = (como em Python ou Gnuplot), mas sim com
:; = fica reservado para igualdade.

armazena a derivada de F (x), que em probabilidade se chama funo densidade de probabilidade, na varivel fdp.

Calcula a integral definidora da mdia.


O resultado de rodar mulambdak.max, com o comando

maxima -b mulambdak.max

Maxima 5.21.1 http :// maxima . sourceforge . net


using Lisp GNU Common Lisp ( GCL ) GCL 2.6.7 ( a . k . a . GCL )
Distributed under the GNU Public License . See the file COPYING .
Dedicated to the memory of William Schelter .
The function bug_report () provides bug reporting information .
(% i1 )
batch ( mulambdak . max )
read and interpret file : # p / home / nldias / work / graduacao / matap / aulas / mulambdak . max
(% i2 )
declare ([ k ] , real )
(% i3 )
declare ([ lam ] , real )
(% i4 )
assume ( k > 0)
(% i5 )
assume ( lam > 0)
(% i6 )
declare ([ k ] , noninteger )
x k
(% i7 )
F : 1 - exp ( - ( - - -) )
lam
(% i8 )
fdp : diff (F , x )
(% i9 )
mu : integrate ( x fdp , x , 0 , inf )
k + 1
(% o9 )
gamma ( - - - - -) lam
k
(% o9 )
mulambdak . max

Na linha (%o9), gamma significa a funo gama (x), que ns vamos encontrar
muitas vezes neste curso, mas que no vem ao caso detalhar agora. O resultado
analtico que ns obtivemos com Maxima
k+1
=
.
k
!

Exerccios Propostos
1.9 Com Maxima, calcule a derivada de
f (x) = ln(sen(ex )).

(1.8)

32

Matemtica Aplicada
1.10 Com Maxima, calcule

x3/2

dx.

1.11 Com Maxima, obtenha as razes de


3
29
x3 + x2 x + 15 = 0.
2
2

2
Um pouco de polinmios, integrais,
sries . . .
2.1 Integrao numrica: motivao
Suponha que voc deseje traar uma curva com as seguintes propriedades:
passar pelos pontos (0, 0), (1, 5/2), (2, 7/2) e (4, 4);
possuir derivada igual a 0 em x = 4.
Existem muitas curvas com estas propriedades, mas uma candidata natural um
polinmio de grau 5, uma vez que existem 5 propriedades ou graus de liberdade
na lista acima. Portanto,
f (x) = ax4 + bx3 + cx2 + dx + e,
df
,
g(x) =
dx
f (0) = 0,
f (1) = 5/2,
f (2) = 7/2,
f (4) = 4,
g(4) = 0.
Agora, podemos obter facilmente a, b, c, d, e com Maxima, com o programa
achapol.max da listagem 2.1.
A dissecao de achapol.max a seguinte:
12

Define f (x) e g(x).

37

Define o valor de f (x) em x = 0, 1, 2, 4, e o valor de g(x) em x = 4, em funo


de a, b, c, d, e.

Resolve um sistema linear 5 5 em a, b, c, d, e.


A sada de achapol.max mostrada na listagem 2.2
Portanto,
1
13
17
11
f (x) = x4 + x3 x2 + x.
48
48
12
3
33

(2.1)

34

Matemtica Aplicada

Listagem 2.1: achapol.max Polinmio com propriedades definidas


1
2
3
4
5
6
7
8

f : a * x ^4 + b * x ^3 + c * x ^2 + d * x + e ;
g : diff (f , x );
eq1 : f , x =0 ;
eq2 : f , x =1 ;
eq3 : f , x =2 ;
eq4 : f , x =4 ;
eq5 : g , x =4 ;
solve ([ eq1 = 0 , eq2 = 5/2 , eq3 = 7/2 , eq4 = 4 , eq5 = 0] , [a ,b ,c ,d , e ]) ;

Listagem 2.2: Sada de achapol.max


Maxima 5.21.1 http :// maxima . sourceforge . net
using Lisp GNU Common Lisp ( GCL ) GCL 2.6.7 ( a . k . a . GCL )
Distributed under the GNU Public License . See the file COPYING .
Dedicated to the memory of William Schelter .
The function bug_report () provides bug reporting information .
(% i1 )
batch ( achapol . max )
read and interpret file : # p / home / nldias / work / graduacao / matap / aulas / achapol . max
2
3
4
(% i2 )
f : e + d x + c x + b x + a x
4
3
2
(% o2 )
a x + b x + c x + d x + e
(% i3 )
g : diff (f , x )
3
2
(% o3 )
4 a x + 3 b x + 2 c x + d
(% i4 )
ev ( eq1 : f , x = 0)
(% o4 )
e
(% i5 )
ev ( eq2 : f , x = 1)
(% o5 )
e + d + c + b + a
(% i6 )
ev ( eq3 : f , x = 2)
(% o6 )
e + 2 d + 4 c + 8 b + 16 a
(% i7 )
ev ( eq4 : f , x = 4)
(% o7 )
e + 4 d + 16 c + 64 b + 256 a
(% i8 )
ev ( eq5 : g , x = 4)
(% o8 )
d + 8 c + 48 b + 256 a
5
7
(% i9 ) solve ([ eq1 = 0 , eq2 = -, eq3 = -, eq4 = 4 , eq5 = 0] , [a , b , c , d , e ])
2
2
1
13
17
11
(% o9 )
[[ a = - --, b = --, c = - --, d = --, e = 0]]
48
48
12
3
(% o9 )
achapol . max

Suponha agora que voc deseje calcular


I=

Z 5
1

f (x) dx.

claro que esta integral pode ser calculada analiticamente com Maxima:
(% i1 ) [ a : -1/48 , b : 13/48 , c : -17/12 , d : 11/3] ;
1
13
17 11
(% o1 )
[ - --, --, - --, - -]
48 48
12 3
(% i2 ) f : a * x ^4 + b * x ^3 + c * x ^2 + d * x ;
4
3
2
x
13 x
17 x
11 x
(% o2 )
- -- + ----- - ----- + ---48
48
12
3
(% i3 ) integrate (f ,x ,1 ,5) ;
1321
(% o3 )
---90

35

2.1 Integrao numrica: motivao


f (x)

4
f (x)

h(x)

Figura 2.1: Integrao numrica de uma funo


(% i4 ) bfloat (%);
(% o4 )

1 . 4 6 7 7 7 7 7 7 7 7 7 7 7 7 8 b1

Logo, I = 1321/90 14,6778 (ateno para o arredondamento). Entretanto,


nem todas as integrais podem ser calculadas assim, por uma srie de motivos:
a funo pode no possuir uma integral em forma fechada,
a funo pode ser definida por pontos, mas no por uma frmula,
a funo pode ser difcil de integrar analiticamente, e voc pode querer ter
uma idia inicial do valor da integral,
etc..
Suponha portanto que voc no soubesse que I = 1321/90, mas fosse capaz de
calcular em princpio tantos pontos de f (x) quantos fossem necessrios: qual a sua
aposta para o valor de I?
Considere a figura 2.1: uma das aproximaes mais bvias mas tambm mais
grosseiras substituir a funo por uma reta ligando os pontos (1, f (1)) e (5, f (5)).
A rea do trapzio a nossa primeira aproximao para a integral:
I0 =

f (1) + f (5)
4 = 12,50.
2

Nada mal, considerando o valor verdadeiro 14,6778! Mas pode ser melhorada, com
o uso de dois trapzios. Para isto, basta calcular f (3) e somar as reas dos dois
trapzios resultantes:
I1 =

f (1) + f (3)
f (3) + f (5)
2+
2 = 14,000.
2
2

Note que estamos muito prximos do valor verdadeiro com apenas 2 trapzios.
Mas existe uma alternativa analtica mais inteligente do que trapzios: como temos
3 pontos, ns podemos aproximar a curva por uma parbola do 2 o grau passando

36

Matemtica Aplicada

por estes 3 pontos. O programa passaquad.max, mostrado na listagem 2.3, faz este
trabalho, e acha os coeficientes a, b, c da parbola
h(x) = ax2 + bx + c
que passa por (1, f (1)), (3, f (3)) e (5, f (5)). No embalo, passaquad.max redefine
h(x) com os coeficientes encontrados, e j calcula a integral de h(x) entre 1 e 5. A
parbola h tambm mostrada na figura 2.1.
Listagem 2.3: passaquad.max parbola h(x) = ax2 +bx+c passando por (1, f (1)),
(3, f (3)) e (5, f (5)).
1
2
3
4
5
6
7
8
9
10
11
12

f : ( -1/48)* x ^4 + (13/48)* x ^3 - (17/12)* x ^2 + (11/3)* x ;


y1 : f , x =1 $
y3 : f , x =3 $
y5 : f , x =5 $
h : a * x ^2 + b * x + c$
eq1 : ev (h , x =1) = y1 ;
eq2 : ev (h , x =3) = y3 ;
eq3 : ev (h , x =5) = y5 ;
solve ( [ eq1 , eq2 , eq3 ] ,[a ,b , c ]) ;
abc : % ;
h : h , abc ;
integrate (h ,x ,1 ,5);

A sada de passaquad.max mostrada na listagem 2.4.


Com os coeficientes a, b, c de h(x), ns podemos calcular analiticamente
nossa prxima aproximao:
I2 =
=

Z 2
1

h(x) dx

Z 2
1

3
23
5
x2 + x +
dx
16
16
4


29
=
= 14,5000.
2

At agora ns avaliamos 3 alternativas de integrao numrica de f (x): com um


trapzio, com dois trapzios, e com uma parbola. A tabela 2.1 d um resumo dos
resultados alcanados. O erro relativo de cada estimativa
=

Ik I
.
I

(2.2)

Uma nica parbola foi capaz de estimar I com um erro relativo ligeiramente
superior a 1%. Um caminho geral para a integrao numrica est aberto: aumentar o nmero de elementos de integrao (no nosso caso foram trapzios) e/ou
aumentar a ordem do polinmio aproximador da funo por um certo nmero de
pontos. Este o contedo da prxima seo.
Exerccios Propostos
2.1 Se f (x) = sen x, qual a estimativa de I =

R
0

f (x) dx = 2 com um trapzio ?

2.2 Provavelmente, voc no est muito contente com o resultado do Problema 2.1.

37

2.2 A regra do trapzio


Listagem 2.4: Sada de passaquad.max

batching / home / nldias / work / graduacao / matap / aulas / passaquad . max


2
3
4
11 x
17 x
13 x
( - 1) x
(% i2 )
f : ---- - ----- + ----- + - - - - - - - 3
12
48
48
4
3
2
x
13 x
17 x
11 x
(% o2 )
- -- + ----- - ----- + ---48
48
12
3
(% i3 )
ev ( y1 : f , x = 1)
(% i4 )
ev ( y3 : f , x = 3)
(% i5 )
ev ( y5 : f , x = 5)
2
(% i6 )
h : c + b x + a x
(% i7 )
eq1 : ev (h , x = 1) = y1
5
(% o7 )
c + b + a = 2
(% i8 )
eq2 : ev (h , x = 3) = y3
31
(% o8 )
c + 3 b + 9 a = -8
(% i9 )
eq3 : ev (h , x = 5) = y5
15
(% o9 )
c + 5 b + 25 a = -4
(% i10 )
solve ([ eq1 , eq2 , eq3 ] , [a , b , c ])
3
23
5
(% o10 )
[[ a = - --, b = --, c = -]]
16
16
4
(% i11 )
abc : %
3
23
5
(% o11 )
[[ a = - --, b = --, c = -]]
16
16
4
(% i12 )
ev ( h : h , abc )
2
3 x
23 x
5
(% o12 )
- ---- + ---- + 16
16
4
(% i13 )
integrate (h , x , 1 , 5)
29
(% o13 )
-2
(% o13 )
passaquad . max

a) Aproxime a integral I do Problema 2.1 com dois trapzios, entre x = 0 e /2, e entre
x = pi/2 e .
b) Aproxime a integral pela integral da parbola quadrtica g(x) = ax2 + bx + c passando
pelos pontos (0, 0), (/2, 1) e (, 0).
c) Aproxime a integral de f (x) pela integral da parbola cbica h(x) = ax3 + bx2 + cx + d
passando pelos mesmos pontos acima, e com h0 (/2) = 0.
2.3 Com Gnuplot, plote f (x) = sen x e a aproximao g(x) obtida no Problema 2.2.

2.2 A regra do trapzio


Vamos comear a melhorar nossas estimativas de I pelo mtodo de fora bruta,
de aumentar o nmero de trapzios. Isto nos levar ao mtodo talvez mais simples de
integrao numrica que vale a pena mencionar, denominado Regra do Trapzio.

38

Matemtica Aplicada
Tabela 2.1: Estimativas numricas de I e seus erros relativos .
Integral

Valor

Exato
Um trapzio
Dois trapzios
Uma parbola

14,6778
0
12,5000 0,1483
14,0000 0,0461
14,5000 0,0121

f (x)

f (x)

x0

x1

x2

x3

x4

x5

x6

x7

x8

Figura 2.2: A regra do trapzio, com n = 4 e n = 8 trapzios.


A figura 2.2 mostra a mesma funo f (x) da seo anterior; agora, entretanto, ns
desenhamos 4 e 8 trapzios sob a curva f (x).
evidente que a rea sob f (x) est agora muito bem aproximada com n = 8
trapzios. O seu valor pode ser estimado por
I3 =

f (xi1 ) + f (xi )
x,
2
i=1

n
X

(2.3)

com
x0 = 1,
xn = 5,
xn x0
x =
.
n

(2.4)
(2.5)
(2.6)

Prosseguindo, (2.3) pode ser re-escrita:


f (x0 ) + f (x1 ) f (x1 ) + f (x2 )
f (xn1 ) + f (xn )
+
+ ... +
x
I3 =
2
2
2
h


i x
= f (x0 ) + 2 f (x1 ) + f (x2 ) + . . . + f (xn1 ) + f (xn )
2
x
= (Se + 2Si )
,
2
"

(2.7)

39

2.2 A regra do trapzio

com
Se = f (x0 ) + f (xn ),
Si =

n1
X

f (xi ).

(2.8)
(2.9)

i=1

Esta seo vale um mdulo de Python, que ns vamos denominar numint. Uma
implementao razoavelmente eficiente da regra do trapzio mostrada nas primeiras
21 linhas de numint.py, na listagen 2.5
Listagem 2.5: numint.py Integrao numrica, regra do trapzio
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from __future__ import division
def trapezio (n ,a ,b , f ):
'''
trapezio (n ,a ,b , f ): integra f entre a e b com n trapzios
'''
deltax = (b - a )/ n
Se = f ( a ) + f ( b )
# define Se
Si = 0.0
# inicializa Si
for k in range (1 , n ):
# calcula Si
xk = a + k * deltax
Si += f ( xk )
I = Se + 2* Si
# clculo de I
I *= deltax
I /= 2
return I

O programa quadraver1.py calcula a integral de f (x) com 8 trapzios (listagem


2.6).
Listagem 2.6: quadraver1.py Integrao numrica de f (x) com 8 trapzios
1
2
3
4
5
6
7
8
9
10

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from __future__ import division
from numint import trapezio
def f ( x ):
return (( -1/48)* x **4 + (13/48)* x **3 + ( -17/12)* x **2 + (11/3)* x )
I3 = trapezio (8 ,1 ,5 , f )
print ( ' I3 = %8.4 f \ n ' % I3 )

A sada de quadraver1.py I3 14,6328. O erro est agora na 2a casa decimal,


e o erro relativo = 0,0031, ou 0,3%.
O problema com numint.trapezio que ns no temos uma idia do erro
que estamos cometendo, porque, se estamos utilizando integrao numrica, porque no conhecemos o valor exato de I! Um primeiro remdio para este problema
ficar recalculando a regra do trapzio com um nmero dobrado de trapzios, at
que a diferena absoluta entre duas estimativas sucessivas fique abaixo de um valor estipulado. Isto implementado, de forma muito ineficiente, na prxima rotina

40

Matemtica Aplicada

do mdulo numint (listagem 2.7: note a continuao da numerao de linhas dentro do mesmo arquivo numint.py), denominada trapepsilonlento, e mostrada na
listagem 2.7.
Listagem 2.7: numint.py Integrao numrica ineficiente, com erro absoluto prestabelecido
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

def t r a p e p s i l o n l e nt o ( epsilon ,a ,b , f ):
'''
t r a p e p s i l o n l en t o ( epsilon ,a ,b , f ): calcula a integral de f entre a e b com
erro absoluto epsilon , de forma ineficiente
'''
eps = 2* epsilon
n = 1
Iv = trapezio (1 ,a ,b , f )
while eps > epsilon :
n *= 2
In = trapezio (n ,a ,b , f )
eps = abs ( In - Iv )
Iv = In
return ( In , eps )

#
#
#
#
#
#
#
#

estabelece um erro inicial grande


um nico trapzio
primeira estimativa , " velha "
loop
dobra o nmero de trapzios
estimativa " nova " , recalculada do zero
calcula o erro absoluto
atualiza a estimativa " velha "

O programa quadraver2.py calcula a integral de f (x) com erro absoluto estipulado menor que 0,0001, e imprime a estimativa da integral, o erro absoluto e
o erro relativo (em relao ao valor exato conhecido) encontrados: I4 = 14,67777,
 = 0,00003, = 0,00000075. Com 4 casas decimais, este um resultado exato!
Listagem 2.8: quadraver2.py Integrao numrica ineficiente de f (x) com  =
0,0001
1
2
3
4
5
6
7
8
9
10
11
12
13

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from __future__ import division
from numint import t r a p e p s i l o n l en t o
def f ( x ):
return (( -1/48)* x **4 + (13/48)* x **3 + ( -17/12)* x **2 + (11/3)* x )
( I4 , eps ) = t r a p e ps i l o n l e n t o (0.0001 ,1 ,5 , f )
print ( ' I4 = %8.5 f eps = %8.5 f ' % ( I4 , eps ))
II = 1 4 . 6 7 7 7 7 7 7 7 7 7 7 7 7 7 7
delta = ( I4 - II )/ II
print ( ' delta = %10.8 f ' % delta )

O problema com trapepsilonlento que todos os pontos que j haviam sido


calculados por trapezio so recalculados em cada iterao (verifique). Nosso ltimo
esforo, a rotina trapepsilon em numint.py, corrige este problema, reaproveitando
todos os clculos. Volte um pouco figura 2.2: nela, ns vemos a integrao numrica de f (x) com n = 4 e depois com n = 8 trapzios. Repare que Si para n = 4
parte do valor de Si para n = 8. De fato, para n = 4, Si = f (x2 ) + f (x4 ) + f (x6 )
(note que os ndices j esto definidos para o caso n = 8). Esta soma j foi calculada
na integral com 4 trapzios, e no precisa ser recalculada. O que ns precisamos
fazer agora somar f (x1 ) + f (x3 ) + f (x5 ) + f (x7 ) ao Si que j tnhamos. Se permanece o mesmo, e depois basta aplicar (2.7). Isto feito na ltima rotina de numint,
denominada trapepsilon, na listagem 2.9.

41

2.2 A regra do trapzio

Listagem 2.9: numint.py Integrao numrica eficiente, com erro absoluto prestabelecido
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

def trapepsilon ( epsilon ,a ,b , f ):


'''
trapepsilon ( epsilon ,a ,b , f ): calcula a integral de f entre a e b com
erro absoluto epsilon , de forma eficiente
'''
eps = 2* epsilon
# estabelece um erro inicial grande
n = 1
# n o nmero de trapzios
Se = f ( a ) + f ( b )
# Se no muda
deltax = (b - a )/ n
# primeiro deltax
dx2 = deltax /2
# primeiro deltax /2
Siv = 0.0
# Si " velho "
Iv = Se * dx2
# I " velho "
# executa o loop pelo menos uma vez
while eps > epsilon :
Sin = 0.0
# Si " novo "
n *= 2
# dobra o nmero de trapzios
deltax /= 2
# divide deltax por dois
dx2 = deltax /2
# idem para dx2
# apenas os mpares ...
for i in range (1 , n ,2):
xi = a + i * deltax
# pula os ptos j calculados !
Sin += f ( xi )
# soma sobre os novos ptos internos
Sin = Sin + Siv
# aproveita todos os ptos j calculados
In = ( Se + 2* Sin )* dx2
# I " novo "
eps = abs ( In - Iv )
# calcula o erro absoluto
Siv = Sin
# atualiza Siv
Iv = In
# atualiza Iv
return ( In , eps )

O programa quadraver3.py (listagem 2.10) calcula a integral de f (x) com erro


absoluto estipulado menor que 0,000001, e imprime a estimativa da integral, o erro
absoluto e o erro relativo (em relao ao valor exato conhecido) encontrados: I5 =
14.6777776,  = 0.0000005, = 0.00000001. Note que I5 exato at a 6a casa
decimal, conforme estipulado.
Listagem 2.10: quadraver3.py Integrao numrica eficiente de f (x) com  =
0,000001
1
2
3
4
5
6
7
8
9
10
11
12
13

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from __future__ import division
from numint import trapepsilon
def f ( x ):
return (( -1/48)* x **4 + (13/48)* x **3 + ( -17/12)* x **2 + (11/3)* x )
( I5 , eps ) = trapepsilon (0.000001 ,1 ,5 , f )
print ( ' I5 = %12.7 f eps = %12.7 f ' % ( I5 , eps ))
II = 1 4 . 6 7 7 7 7 7 7 7 7 7 7 7 7 7 7
delta = ( I5 - II )/ II
print ( ' delta = %12.8 f ' % delta )

Exerccios Propostos
2.4 Usando Python e numint.trapezio, aproxime I =
com 10 trapzios.

R
0

sen(x) dx pela regra do trapzio

2.5 Usando Python e numint.trapepsilon, aproxime I =


trapzio com preciso absoluta menor ou igual a 1 105 .

R
0

sen(x) dx pela regra do

42

Matemtica Aplicada
2.6 Dada f (x) definida no intervalo [x0 , x0 + 2h], deduza a regra de Simpson:
Z x0 +2h

f (x) dx

x0

h
[f0 + 4f1 + f2 ] ,
3

com fn = f (xn ), xn = x0 + nh, interpolando a funo g(x) = ax2 + bx + c atravs dos


pontos (x0 , f0 ), (x1 , f1 ) e (x2 , f2 ) e calculando sua integral.
2.7 Dobrando o nmero de pontos de 2 para 4, obtenha a regra de Simpson para 5 pontos,
Z x0 +4h

f (x) dx

x0

h
[f0 + 4f1 + 2f2 + 4f3 + f4 ] ;
3

generalize:
Z bx0 +2nh

f (x) dx

ax0

h
[f0 + 4f1 + 2f2 + . . . + 2f2n2 + 4f2n1 + f2n ] .
3

2.8 Estenda numint com uma rotina simpson para calcular a regra de Simpson com 2n
intervalos, e uma rotina simpepsilon para calcular uma integral numrica pela regra de
Simpson com preciso estipulada. Baseie-se em trapezio e trapepsilon.

2.3 Aproximao de integrais com sries: a funo erro


Integraes numricas tais como as mostradas na seo 2.2 podem ser muito
custosas em termos do nmero de operaes de ponto flutuante necessrias. Algumas vezes, possvel ser mais inteligente. Um exemplo disto foi o clculo de I2
com uma nica parbola quadrtica1 no fim da seo 2.1, que foi capaz de baixar o
erro relativo para pouco mais de 1%.
Considere agora o clculo de uma integral particularmente importante, a funo
erro, definida por
2 Z x u2

e
du.
(2.10)
erf(x)
u=0
A funo erro est definida em Gnuplot e em Maxima, mas no em Python < 2.7.
Como obt-la? Uma maneira fora bruta utilizar trapepsilon com uma preciso
razovel (digamos, 106 ), gerar um arquivo, e plotar o resultado para ver a cara
da erf(x). O programa vererf.py (listagem 2.11) calcula a funo em um grande
nmero de pontos; gera um arquivo de dados vererf.dat, e ento o programa
vererf.plt (listagem 2.12) plota o resultado, mostrado na figura 2.3.
Observe que vererf.plt utiliza a funo erf pr-definida em Gnuplot e plota
uma comparao: a linha contnua a erf de Gnuplot, e os pontos so os valores
obtidos por vererf.py.
Existe uma maneira mais inteligente de calcular erf(x): ela se baseia em integrar
2
a srie de Taylor do integrando, eu . Maxima permite calcular os primeiros termos:
(% i1 ) taylor ( exp ( - u ^2) , u ,0 ,10) ;
(% o1 )/ T /

1 - u

4
6
8
10
u
u
u
u
+ -- - -- + -- - --- + . . .
2
6
24
120

Sim! existem parbolas cbicas, qurticas, etc..

43

2.3 Aproximao de integrais com sries: a funo erro

Listagem 2.11: vererf.py Clculo da funo erro por integrao numrica


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from __future__ import division
from math import exp , sqrt , pi
from numint import trapepsilon
def f ( x ):
return exp ( - x * x )
xmin = 0.0
xmax = 3.0
nx = 100
dx = ( xmax - xmin )/ nx
erf = 0.0
fou = open ( ' vererf . dat ' , ' wt ')
xl = xmin
fou . write ( ' %8.6 f %8.6 f \ n ' % ( xl , erf ))
for k in range ( nx ):
xu = xl + dx
(I , eps ) = trapepsilon (1.0 e -6 , xl , xu , f )
erf = erf + (2.0/ sqrt ( pi ))* I
fou . write ( ' %8.6 f %8.6 f \ n ' % ( xu , erf ))
xl = xu
fou . close ()

#
#
#
#
#
#
#
#
#
#
#
#
#
#
#

de 0
a 3
em 100 passos
de dx
erf (0) = 0
arquivo de sada
limite inferior a partir de xmin
erf (0) = 0
loop
novo limite superior
integra mais uma fatia
acumula erf
imprime at aqui
atualiza limite inferior
fecha o arquivo de sada

Listagem 2.12: vererf.plt Plotagem da funo erro por integrao numrica


versus a erf(x) pr-definida em Gnuplot
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

set encoding iso_8859_1


# ------------------------------------------------------------------------------# no mundo de linux
# ------------------------------------------------------------------------------set terminal postscript eps monochrome ' Times - Roman ' 18
set output ' vererf . eps '
set format y ' %3.1 f '
set grid
set xlabel 'x '
set ylabel ' erf ( x ) '
set xrange [0:3]
set yrange [0:1]
set xtics 0 ,0.5
set ytics 0 ,0.1
plot ' vererf . dat ' using 1:2 title ' trapepsilon ' with points pt 7 ps 0.75 ,\
erf ( x ) title ' Gnuplot ' with lines lt 1 lw 2
# -----------------------------------------------------------------------------# agora no mundo de Windows
# -----------------------------------------------------------------------------set terminal emf monochrome ' Times New Roman ' 18
set output ' vererf . emf '
replot
exit

44

Matemtica Aplicada
1.0

trapepsilon
Gnuplot

0.9
0.8
0.7

erf(x)

0.6
0.5
0.4
0.3
0.2
0.1
0.0
0

0.5

1.5
x

2.5

Figura 2.3: Funo erf(x) calculada por integrao numrica, com trapepsilon e
 = 1 106 , versus a erf pr-definida em Gnuplot.

A expanso em torno de u = 0, e feita at o 10o termo. No muito difcil


reconhecer nos denominadores os fatoriais de 0, 1, 2, 3, 4 e 5, e as potncias dos
dobros destes valores nos expoentes de u. Em geral,

eu =

(1)n

n=0

u2n
.
n!

(2.11)

Portanto,

Z x
0

eu du =

Z xX

(1)n

0 n=0

u2n
du
n!

(1)n Z x 2n
=
u du
n!
0
n=0
=
=

(1)n x2n+1
n! 2n + 1
n=0

(1)n

n=0

x2n+1
.
(2n + 1)n!

(2.12)

Cuidado: no toda srie que permite a troca impune da ordem de integrao e


da soma (infinita) da srie. Em princpio, devemos procurar os teoremas relevantes
que nos permitem esta troca de ordem. Admitindo que est tudo bem, entretanto,
ns conseguimos a srie de Taylor de erf(x)!

45

2.3 Aproximao de integrais com sries: a funo erro


1.0

erf_1
Gnuplot

0.9
0.8
0.7

erf(x)

0.6
0.5
0.4
0.3
0.2
0.1
0.0
0

0.5

1.5
x

2.5

Figura 2.4: Funo erf(x) calculada com srie de Taylor, com erf_1, versus a erf
pr-definida em Gnuplot.
Ainda falta encontrar uma maneira computacionalmente eficiente de passar do
termo n 1 para o termo n. Vamos a isto:
x2n+1
An

(2n + 1)n!
Bn Cn
=

=
=

(1)n x2(n1+1)+1


2(n 1 + 1) + 1) n(n 1)!


(1)n1 x2(n1)+1 [x2 ]


2(n 1) + 1) + [2] [n](n 1)!

An1 (x2 )
(Bn1 + 2)(Cn1 n)

(2.13)

Em outras palavras, o numerador An de cada novo termo da srie o anterior vezes


x2 . O denominador mais complicado; ele formado pelo produto Bn Cn , e as
relaes completas de recurso so
An = x2n+1 = An1 (x2 ),
Bn = 2n + 1 = Bn1 + 2,
Cn = n! = Cn1 n.
Mais uma coisa: a srie de erf(x) s contm potncias mpares: portanto, erf(x)
uma funo mpar, e vale a relao
erf(x) = erf(x).
Com isto, temos uma rotina em Python para calcular erf(x), chamada erf_1(x),
no mdulo erfs, do arquivo erfs.py. As linhas correspondentes a erf_1(x) so
mostradas na listagem 2.13
Agora, podemos escrever vererf1.py (listagem 2.14), gerar um arquivo de sada
vererf1.dat e plotar com o programa vererf1.plt (listagem 2.15). Os resultados
continuam idnticos erf(x) de Gnuplot.

46

Matemtica Aplicada

Listagem 2.13: Clculo de erf(x) com uma srie de Taylor.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from __future__ import division
from math import sqrt , pi
def erf_1 ( x ):
epsilon_erf = 1.0 e -6
eps_erf = 2* epsilon_erf
A = x
B = 1
C = 1
n = 0
termo = A /( B * C )
s = termo
while eps_erf > epsilon_erf :
n += 1
A *= ( - x * x )
B += 2
C *= n
termo = A /( B * C )
eps_erf = abs ( termo )
s += termo
return (2/ sqrt ( pi ) * s , n )

#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#

mesma preciso
garante entrada no while
primeiro A
primeiro B
primeiro C
primeiro n
primeiro termo da srie
primeira soma da srie
loop
incrementa n
novo A
novo B
novo C
novo termo
seu valor absoluto
soma na srie

Listagem 2.14: vererf1.py Clculo da funo erro com srie de Taylor entre 0 e
3.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
from __future__ import division
from math import exp , sqrt , pi
from erfs import erf_1
xmin = 0.0
xmax = 3.0
nx = 100
dx = ( xmax - xmin )/ nx
fou = open ( ' vererf1 . dat ' , ' wt ')
xl = xmin
fou . write ( ' %8.6 f %8.6 f \ n ' % ( xl ,0.0))
for k in range ( nx ):
xu = xl + dx
( erf , n ) = erf_1 ( xu )
fou . write ( ' %8.6 f %8.6 f \ n ' % ( xu , erf ))
xl = xu
fou . close ()

#
#
#
#
#
#
#
#
#

de 0
a 3
em 100 passos
de dx
arquivo de sada
limite inferior a partir de xmin
erf (0) = 0
loop
novo limite superior

# imprime at aqui
# atualiza limite inferior
# fecha o arquivo de sada

47

2.3 Aproximao de integrais com sries: a funo erro

Listagem 2.15: vererf1.plt Plotagem da funo erro calculada com srie de


Taylor versus a erf(x) pr-definida em Gnuplot
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

set encoding iso_8859_1


# ------------------------------------------------------------------------------# no mundo de linux
# ------------------------------------------------------------------------------set terminal postscript eps monochrome ' Times - Roman ' 18
set output ' vererf1 . eps '
set format y ' %3.1 f '
set grid
set xlabel 'x '
set ylabel ' erf ( x ) '
set xrange [0:3]
set yrange [0:1]
set xtics 0 ,0.5
set ytics 0 ,0.1
plot ' vererf1 . dat ' using 1:2 title ' erf_1 ' with points pt 7 ps 0.75 ,\
erf ( x ) title ' Gnuplot ' with lines lt 1 lw 2
# -----------------------------------------------------------------------------# agora no mundo de Windows
# -----------------------------------------------------------------------------set terminal emf monochrome ' Times New Roman ' 18
set output ' vererf1 . emf '
replot
exit

Embora formalmente correta, a rotina erf_1 fica mais lenta medida em que
|x| cresce. Como j vimos nas figuras 2.3 e 2.4, erf(x) 1 para |x| & 3. Porm,
uma olhada em vererf1.dat, nos d
h

erf_1(3) = 0.999978 ,

que ainda est acima da preciso especificada de 0,000001. Precisamos descobrir o


valor de x para o qual erf_1 produz 0,999999. Por tentativa e erro, encontramos
h

erf_1(3.6) = 0.99999952358847277 ,

que igual a 1,0 para 6 casas decimais. Precisamos tambm saber com quantos
termos este clculo foi feito, e este o motivo de erf_1 devolver tambm n. Para
calcular erf(3,6) com erf_1, ns precisamos de n = 43 termos. A rotina erf na
listagem 2.16, tambm no arquivo erfs.py, usa este fato para impedir que o nmero
de termos continue crescendo. Verifique, voc mesmo(a), que erf(100) retorna 1.0,
mas que erf_1(100) d um erro de ponto flutuante.
preciso enfatizar que erf em erfs.py ainda no uma rotina profissional.
O nmero de termos usado ainda potencialmente muito grande; consequentemente,
h muitas operaes de ponto flutuante envolvendo A, B e C, e muitos testes dentro
do while.
possvel obter frmulas que aproximam erf(x) com menos termos, uniformemente, no intervalo (digamos) de 0 a 3,6: veja, por exemplo, Abramowitz e Stegun
(1972). Mesmo assim, erf uma opo vantajosa em relao integrao numrica.
A lio desta seo a seguinte: em geral, com esforo analtico adicional,
possvel obter uma mistura de mtodos analticos e numricos que costuma ser
amplamente superior ao uso de um mtodo numrico puro (por exemplo a regra
do trapzio) para a obteno de resultados semelhantes. Exemplos deste fato vo
reaparecer nos captulos seguintes.

48

Matemtica Aplicada

Listagem 2.16: erfs.py Clculo de erf(x) com srie de Taylor, limitado a no


mximo 43 termos
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

def erf ( x ):
if x > 3.6:
return 1.0
elif x < -3.6:
return -1.0
epsilon_erf = 1.0 e -6
eps_erf = 2* epsilon_erf
A = x
B = 1
C = 1
n = 0
termo = A /( B * C )
s = termo
while eps_erf > epsilon_erf :
n += 1
A *= ( - x * x )
B += 2
C *= n
termo = A /( B * C )
eps_erf = abs ( termo )
s += termo
return 2/ sqrt ( pi ) * s

# limita o nmero de termos a 43

#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#

mesma preciso
garante entrada no while
primeiro A
primeiro B
primeiro C
primeiro n
primeiro termo da srie
primeira soma da srie
loop
incrementa n
novo A
novo B
novo C
novo termo
seu valor absoluto
soma na srie

Exerccios Propostos
2.9 (Bender e Orszag (1978), seo 6.2, Exemplo 2) Obtenha uma srie para
F (x)

Z x
0

t1/2 et dt;

compare o resultado obtido com integrao numrica.

3
Soluo numrica de equaes
diferenciais ordinrias
3.1 Soluo numrica de equaes diferenciais ordinrias
Soluo analtica de uma EDO com Maxima. Considere uma equao diferencial
de 1a ordem simples, forada eternamente por um seno:
dy y
+ = sen x.
dx x
Na listagem 3.1, ns resolvemos esta equao com Maxima.

(3.1)

Listagem 3.1: resolve-eqdif Soluo de uma EDO com Maxima


1
2
3
4
5
6
7
8
9
10

(% i2 )
(% o2 )
(% i3 )
(% o3 )

y
dy
- + -- = sin ( x )
x
dx
dy
y
-- + - = sin ( x )
dx
x
ode2 (% , y , x )
sin ( x ) - x cos ( x ) + % c
y = ---------------------x

Maxima nos informa de que a soluo geral da forma


y(x) =

sen x x cos x + c
.
x

evidente que, em geral, nem a equao diferencial nem sua soluo "existem"em
x = 0. Entretanto, para c = 0,
sen x
y(x) =
cos x.
x
Agora,

sen x
= 1,
x
de modo que existe uma soluo para a equao partindo de x = 0 se ns impusermos
a condio incial y(0) = 0. De fato:
lim

x0

sen x
lim
cos x = 1 1 = 0.
x0
x


49

50

Matemtica Aplicada
1.5

1.0

y(x)

0.5

0.0

0.5

1.0

1.5

10

20

30

40

50

Figura 3.1: Soluo da equao (3.1).


O resultado est mostrado na figura 3.1.
Claramente, existe uma parte transiente da soluo, dada por sen x/x, que
morre medida que x cresce, e existe uma parte peridica (mas no permanente!)
da soluo, dada por cos x, que domina y(x) quando x se torna grande. Ns
dizemos que cos x parte estacionria da soluo.
3.1.1 Soluo numrica; mtodo de Euler
A coisa mais simples que pode ser pensada para resolver a equao diferencial
em questo transformar a derivada em uma diferena finita:
y y
+ = sen x
x x
Isto um comeo, mas no suficiente. Na verdade, o que desejamos que o
computador gere uma lista de xs (uniformemente espaados por x), e uma lista
de ys correspondentes. Obviamente, como os ys devem aproximar a funo, no
podemos esperar deles que sejam igualmente espaados!
Desejamos ento:
x0 , x1 , . . . , xn
onde

xi = ix,

com os correspondentes
y0 , y1 , . . . , yn .
Como x ser fixo, podemos escrever nossa equao de diferenas finitas da seguinte
forma:
yi+1 yi y
+ = sen(x),
x
x
onde eu deixei, propositadamente,
x
. . . = sen(x)
y
ainda sem ndices. De fato: qual xi e qual yi usar aqui? A coisa mais simples, mas
tambm a mais instvel, usar i:
yi+1 yi yi
+
= sen(xi ).
x
xi

51

3.1 Soluo numrica de equaes diferenciais ordinrias

Listagem 3.2: fracasso.py Um programa com o mtodo de Euler que no funciona


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s
from __future__ import print _functio n
# ---------------------------------------------------------# cria listas com condies iniciais
# ---------------------------------------------------------x = [0.0]
y = [0.0]
dx = 0.01
n = int (50/0.01)
from math import sin
for i in range (0 , n ): # de 0 at ... n -1 !!!!
xn = ( i +1)* dx
yn = y [ i ] + ( sin ( x [ i ]) - y [ i ]/ x [ i ])* dx
x . append ( xn )
y . append ( yn )
fou = open ( ' fracasso . out ' , ' wt ')
for i in range ( n ):
fou . write ( ' %12.6 f %12.6 f \ n ' % ( x [ i ] , y [ i ]))
fou . close ()

Note que agora possvel explicitar yi+1 em funo de todos os outros valores em i:


yi+1 = yi + sen(xi )

yi
x.
xi


Este um exemplo de um mtodo explcito: o novo valor da funo em xi+1 (yi+1 )


s depende de valores calculados no valor anterior, xi . Um olhar um pouco mais
cuidadoso ser capaz de prever o desastre: na frmula acima, se partirmos de x0 = 0,
teremos uma diviso por zero j no primeiro passo!
Muitos no veriam isto, entretanto, e nosso primeiro programa para tentar resolver a equao diferencial numericamente se chamar fracasso.py, e est mostrado
na listagem 3.2
O resultado, mostrado na listagem 3.3 o seguinte fracasso:
Listagem 3.3: Sada de fracasso.py
Traceback ( most recent call last ):
File "./ fracasso . py " , line 15 , in < module >
yn = y [ i ] + ( sin ( x [ i ]) - y [ i ]/ x [ i ])* dx
Z e r o D i v i s i o n E r r o r : float division by zero

Isto j era previsvel: quando i == 0 no loop, x[0] == 0 no denominador, e o


programa para com uma diviso por zero. Para conseguir fazer o mtodo numrico
funcionar, ns vamos precisar de mais anlise! De volta equao diferencial, note
que para que exista uma soluo na vizinhana de x = 0 necessrio que o limite
limx0 y(x)/x exista; ns devemos ter
y(x)
= L,
x0 x
lim

onde L uma constante finita a determinar. Mas, de nossa condio inicial,


lim y(x) = 0 L = 0.

x0

52

Matemtica Aplicada

Listagem 3.4: sucesso.py Um programa com o mtodo de Euler que funciona


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# sucesso : resolve a equao diferencial
# dy / dx + y / x = sen ( x )
# pelo mtodo de Euler . Uso :
#
# ./ sucesso . py <dx > < arquivo de sada >
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
from sys import argv
dx = float ( argv [1])
# tamanho do passo
x = [0.0 , dx ]
# condies inciais em x
y = [0.0 , 0.0]
# condies iniciais em y
n = int (50/ dx )
from math import sin , cos
# soluo numrica
for i in range (1 , n ):
xn = ( i +1)* dx
yn = y [ i ] + ( sin ( x [ i ]) - y [ i ]/ x [ i ])* dx
x . append ( xn )
y . append ( yn )
erro = 0.0
# calcula o erro relativo mdio
for i in range (1 , n +1):
yana = sin ( x [ i ])/ x [ i ] - cos ( x [ i ])
erro += abs ( ( y [ i ] - yana )/ yana )
erro /= n ;
print ( ' erro relativo mdio = ' , ' %10.5 f ' % erro )
fou = open ( argv [2] , ' wt ')
for i in range (0 , n +1):
# imprime o arquivo de sada
fou . write ( ' %12.6 f %12.6 f \ n ' % ( x [ i ] , y [ i ]) )
fou . close ()

Vamos ento reescrever a equao de diferenas usando o limite:


y0
x = 0.
y1 = y0 + sen(x0 )
x0


{z

=0, lim x0 0

Na prtica, isto significa que ns podemos comear o programa do ponto x1 =


x, y1 = 0! Vamos ento reescrever o cdigo, que ns agora vamos chamar, claro,
de sucesso.py, que pode ser visto na listagem 3.4
A sada de sucesso.py gera o arquivo sucesso.out, que ns utilizamos para
plotar uma comparao entre a soluo analtica e a soluo numrica, mostrada na
figura 3.2
Na verdade, o sucesso estrondoso: com x = 0,01, ns conseguimos produzir
uma soluo numrica que visualmente indistinguvel da soluo analtica. Uma
das coisas que o programa sucesso.py calculou foi o erro relativo mdio



n
X
yi


i=1

y(xi )

y(xi )

(onde yi a soluo numrica, e y(xi ) a soluo exata no mesmo ponto xi ). Para


x = 0,01,  = 0,02619, ou seja: menos de 3%.
O preo, entretanto, foi alto: ns precisamos de um x bem pequeno, e de
50/0,01 = 5000 pontos para gerar a soluo. Ser possvel gerar uma soluo to
boa com, digamos, 100 pontos?

53

3.1 Soluo numrica de equaes diferenciais ordinrias

1.5

x = 0,01
soluo numrica
soluo analtica

1.0

y(x)

0.5

0.0

-0.5

-1.0

-1.5

10

20

30

40

50

Figura 3.2: Comparao da soluo analtica da equao (3.1) com a sada de


sucesso.py, para x = 0,01.

1.5

x = 0,5
soluo numrica
soluo analtica

1.0

y(x)

0.5

0.0

-0.5

-1.0

-1.5

10

20

30

40

50

Figura 3.3: Comparao da soluo analtica da equao (3.1) com a sada de


sucesso.py, para x = 0,5.

54

Matemtica Aplicada

A figura 3.3 mostra o resultado de rodar sucesso.py com x = 0,5, muito maior
do que antes.
O erro mdio relativo agora pulou para  = 1,11774, nada menos do que 111%,
e muito pior do que a figura acima faz parecer primeira vista!
3.1.2 Um mtodo implcito, com tratamento analtico
Nosso desafio desenvolver um mtodo numrico que melhore consideravelmente
a soluo mesmo com um x grosseiro, da ordem de 0,5. Nossa abordagem ser
propor um mtodo implcito:
xi + xi+1
yi+1 yi
yi + yi+1
+
= sen
.
x
xi + xi+1
2


Note que tanto o termo y/x quando sen x esto sendo agora avaliados no ponto
mdio entre xi e xi+1 .
Lembrando que x = xi+1 xi , yi+1 :
xi + xi+1
yi + yi+1
yi+1 yi
= sen
+
,
x
xi + xi+1
2
"
#
#
"


1
1
1
1
xi + xi+1
yi+1
+
+ yi
+
= sen
,
x xi + xi+1
x xi + xi+1
2
#
#
"
"


2xi+1
2xi
xi + xi+1
yi+1
yi
= sen
.
x(xi+1 + xi )
x(xi+1 + xi )
2


Uma rpida rearrumao produz


x(xi+1 + xi )
xi + xi+1
yi+1 xi+1 yi xi =
sen
,
2
2


xi
x(xi+1 + xi )
xi + xi+1
yi+1 = yi
+
sen
.
xi+1
2xi+1
2


(3.2)

Repare que a condio inicial y(0) = 0 no produz nenhuma singularidade em


(3.2) para i = 0 x0 = 0, y0 = 0. O programa que implementa este esquema o
sucimp.py, mostrado na listagem 3.5.
O resultado um sucesso mais estrondoso ainda, e pode ser visto na figura 3.4.
Agora, o erro mdio relativo baixou para  = 0,02072, que ainda menor do que
o do mtodo de Euler com x = 0,01, ou seja: com um x 50 vezes menor!
3.1.3 Runge-Kutta
O preo que ns pagamos pelo mtodo extremamente acurado implementado em
sucimp.py foi trabalhar analiticamente a equao diferencial, at chegar verso
dedicada (3.2). Isto bom! Porm, s vezes no h tempo ou no possvel
melhorar o mtodo por meio de um pr-tratamento analtico. Nossa discusso
agora nos levar a um mtodo excepcionalmente popular, denominado mtodo de
Runge-Kutta.
Dada a equao
dy
= f (x, y)
dx
ns podemos tentar estimar a derivada no meio do intervalo h (estamos mudando
a notao: at agora, usvamos x, mas h uma forma usual de explicitar o passo

55

3.1 Soluo numrica de equaes diferenciais ordinrias

Listagem 3.5: sucimp.py Mtodo de Euler implcito


# !/ usr / bin / python
# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# sucimp : resolve a equao diferencial
# dy / dx + y / x = sen ( x )
# usando um mtodo implcito sob medida
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
dx = 0.5
# passo em x
x = [0.0]
# x inicial
y = [0.0]
# y inicial
n = int (50/ dx )
# nmero de passos
from math import sin , cos
# loop na soluo numrica
for i in range (0 , n ):
xn = ( i +1)* dx
xm = x [ i ] + dx /2.0
yn = y [ i ]* x [ i ]/ xn + ( dx * xm / xn )* sin (( x [ i ]+ xn )/2)
x . append ( xn )
y . append ( yn )
erro = 0.0
for i in range (1 , n +1):
# calcula o erro relativo mdio
yana = sin ( x [ i ])/ x [ i ] - cos ( x [ i ])
erro += abs ( ( y [ i ] - yana )/ yana )
erro /= n ;
print ( ' erro relativo mdio = ' , ' %10.5 f ' % erro )
fou = open ( ' sucimp . out ' , ' wt ')
for i in range (0 , n +1):
# imprime o arquivo de sada
fou . write ( ' %12.6 f %12.6 f \ n ' % ( x [ i ] , y [ i ]) )
fou . close ()

1.5

x = 0,5
soluo numrica
soluo analtica

1.0

0.5

y(x)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

0.0

-0.5

-1.0

-1.5
0

10

20

30

40

50

Figura 3.4: Comparao da soluo analtica da equao (3.1) com a sada de


sucimp.py, para x = 0,5.

56

Matemtica Aplicada
1.5

x = 0,5
soluo numrica
soluo analtica

1.0

y(x)

0.5

0.0

-0.5

-1.0

-1.5

10

20

30

40

50

Figura 3.5: Comparao da soluo analtica da equao (3.1) com a sada de


euler2.py, para x = 0,5.
quando se trata do mtodo de Runge-Kutta, ou mtodos similares):

dy
dx

= f (x + h/2, y(x + h/2))


x+h/2

O problema que ns no conhecemos y em x + h/2! Isto pode ser contornado,


entretanto, usando o mtodo de Euler de 1a ordem para primeiro estimar y(x+h/2):
yn+1/2 yn + hf (xn , yn )/2.
Um mtodo mais acurado ser portanto
k1 = hf (xn , yn ),
k2 = hf (xn + h/2, yn + k1 /2),
yn+1 = yn + k2
Vamos tentar este mtodo e ver como ele se compara com nossos esforos anteriores.
Vamos manter h = 0,5 como nos casos anteriores. No entanto, ns ainda sofremos
do clculo da derivada em x = 0; por isto, ns vamos mudar o clculo da derivada,
colocando um if na funo ff que a calcula. Note que, do ponto de vista de
eficincia computacional, isto pssimo, porque o if ser verificado em todos os
passos, quando na verdade ele s necessrio no passo zero. No entanto, o programa
resultante, euler2.py (listagem 3.6), fica mais simples e fcil de entender, e esta
nossa prioridade aqui.
O resultado mostrado na figura 3.5.
O resultado muito bom, com um erro absoluto mdio  = 0,02529. Mas ns
podemos fazer melhor, com o mtodo de Runge-Kutta de 4a ordem! No vamos
deduzir as equaes, mas elas seguem uma lgica parecida com a do mtodo de

57

3.1 Soluo numrica de equaes diferenciais ordinrias

Listagem 3.6: euler2 Um mtodo explcito de ordem 2


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# euler2 : resolve a equao diferencial
# dy / dx + y / x = sen ( x )
# usando um mtodo expltico de ordem 2 ( Euler )
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
h = 0.5
# passo em x
x = [0.0]
# x inicial
y = [0.0]
# y inicial
n = int (50/ h )
# nmero de passos
from math import sin , cos
def ff (x , y ):
if x == 0.0:
# implementa a condio inicial
return 0.0
else :
return sin ( x ) - y / x
def eul2 (x ,y ,h , ff ):
k1 = h * ff (x , y )
k2 = h * ff ( x + h /2 , y + k1 /2)
yn = y + k2
return yn
for i in range (0 , n ):
# loop da soluo numrica
xn = ( i +1)* h
yn = eul2 ( x [ i ] , y [ i ] ,h , ff )
x . append ( xn )
y . append ( yn )
erro = 0.0
# calcula o erro relativo mdio
for i in range (1 , n +1):
yana = sin ( x [ i ])/ x [ i ] - cos ( x [ i ])
erro += abs ( ( y [ i ] - yana )/ yana )
erro /= n ;
print ( ' erro relativo mdio = ' , ' %10.5 f ' % erro )
fou = open ( ' euler2 . out ' , ' wt ')
for i in range (0 , n +1):
# imprime o arquivo de sada
fou . write ( ' %12.6 f %12.6 f \ n ' % ( x [ i ] , y [ i ]) )
fou . close ()

Matemtica Aplicada

58

Listagem 3.7: rungek4 Mtodo de Runge-Kutta, ordem 4


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# !/ usr / bin / python


# -* - coding : utf -8 -* # ---------------------------------------------------------# rungek4 : resolve a equao diferencial
# dy / dx + y / x = sen ( x )
# usando o mtodo de Runge - Kutta de ordem 4
# ---------------------------------------------------------from __future__ import print _functio n
h = 0.5
# passo em x
x = [0.0]
# x inicial
y = [0.0]
# y inicial
n = int (50/ h )
# nmero de passos
from math import sin , cos
def ff (x , y ):
'''
estou integrando dy / dx = sen ( x ) - y / x
'''
if x == 0.0:
return 0.0
else :
return sin ( x ) - y / x
def rk4 (x ,y ,h , ff ):
'''
rk4 implementa um passo do mtodo de Runge - Kutta de ordem 4
'''
k1 = h * ff (x , y )
k2 = h * ff ( x + h /2 , y + k1 /2)
k3 = h * ff ( x + h /2 , y + k2 /2)
k4 = h * ff ( x +h , y + k3 )
yn = y + k1 /6.0 + k2 /3.0 + k3 /3.0 + k4 /6.0
return yn
for i in range (0 , n ):
# loop da soluo numrica
xn = ( i +1)* h
yn = rk4 ( x [ i ] , y [ i ] ,h , ff )
x . append ( xn )
y . append ( yn )
erro = 0.0
# calcula o erro relativo mdio
for i in range (1 , n +1):
yana = sin ( x [ i ])/ x [ i ] - cos ( x [ i ])
erro += abs ( ( y [ i ] - yana )/ yana )
erro /= n ;
print ( ' erro relativo mdio = ' , ' %10.5 f ' % erro )
fou = open ( ' rungek4 . out ' , ' wt ')
for i in range (0 , n +1):
# imprime o arquivo de sada
fou . write ( ' %12.6 f %12.6 f \ n ' % ( x [ i ] , y [ i ]) )
fou . close ()

ordem 2:
k1 = hf (xn , yn ),
h
k1
k2 = hf (xn + , yn + ),
2
2
k3 = hf (xn + h/2, yn + k2 /2),
k4 = hf (xn + h, yn + k3 ),
k1 k2 k3 k4
yn+1 = yn +
+
+
+ .
6
3
3
6
Para o nosso bem conhecido problema, o mtodo implementado no programa
rungek4, na listagem 3.7.
O resultado mostrado na figura 3.6.
Desta vez, o erro absoluto mdio foi  = 0,00007: o campeo de todos os mtodos
tentados at agora, e uma clara evidncia da eficcia do mtodo de Runge-Kutta.

59

3.1 Soluo numrica de equaes diferenciais ordinrias


1.5

x = 0,01
soluo numrica
soluo analtica

1.0

y(x)

0.5

0.0

-0.5

-1.0

-1.5
0

10

20

30

40

50

Figura 3.6: Comparao da soluo analtica da equao (3.1) com a sada de


rungek4.py, para x = 0,5.
Exerccios Propostos
3.1 Resolva, usando o mtodo de Euler e o Mtodo de Runge-Kutta de ordem 4:
dy
+ xy = sen(x),
dx

y(0) = 0.

3.2 Resolva, usando o mtodo de Euler de ordem 2, e compare com a soluo analtica:
dy
+ y = x2 exp(x),
dx

y(0) = 1.

dy
y
2x
+ = sen
,
dx x
L

y(0) = 0,

3.3 Na equao


estude a sensibilidade do h, necessrio para produzir  = 0,001, ao valor L.


3.4 Utilizando um mtodo implcito semi-analtico, resolva
dy
y
ex
+ = ,
dx x
x

y(x) = 0.

3.5 Resolva, utilizando Runge-Kutta:


dy
+ y = sen(x),
dx

y(0) = 1.

Matemtica Aplicada

60

4
Soluo numrica de equaes
diferenciais parciais
4.1 Adveco pura: a onda cinemtica
Considere a equao
u
u
+c
= 0,
t
x

u(x, 0) = g(x).

(4.1)

A sua soluo pode ser obtida pelo mtodo das caractersticas, e


u(x, t) = g(x ct).

(4.2)

u
u
+2
= 0,
t
x
u(x, 0) = 2x(1 x).

(4.3)

Seja ento o problema

(4.4)

A condio inicial, juntamente com u(x, 1), u(x, 2) e u(x, 3) esto mostrados na
figura 4.1. Observe que a soluo da equao uma simples onda cinemtica.
4

0.50

0.00

tempo

u(x, t)

10

Figura 4.1: Condio inicial da equao 4.3.


61

62

Matemtica Aplicada
Vamos adotar a notao
uni u(xi , tn ),
xi = ix,
tn = nt,

(4.5)
(4.6)
(4.7)

com
x = L/Nx ,
t = T /Nt

(4.8)
(4.9)

onde L, T so os tamanhos de grade no espao e no tempo, respectivamente, e Nx , Nt


so os nmeros de divises no espao e no tempo.
Uma maneira simples de transformar as derivadas parciais em diferenas finitas
na equao (4.3) fazer
un+1
uni
u
i
=
+ O(t),
t i,n
t

(4.10)

uni+1 uni1
u
=
+ O(x2 ).

x i,n
x

(4.11)

Substituindo na equao (4.3), obtemos o esquema de diferenas finitas explcito:


un uni1
un+1
uni
i
= c i+1
,
t
2x
ct n
un+1
= uni
(u uni1 ),
i
2x i+1


(4.12)

(com c = 2 no nosso caso). Este um esquema incondicionalmente instvel, e


vai fracassar. Vamos fazer uma primeira tentativa, j conformados com o fracasso
antecipado. Ela vai servir para desenferrujar nossas habilidades de programao de
mtodos de diferenas finitas.
O programa que implementa o esquema instvel o onda1d-ins.py, mostrado
na listagem 4.1. Por motivos que ficaro mais claros na sequncia, ns escolhemos
x = 0,01, e t = 0,0005.
O programa gera um arquivo de sada binrio, que por sua vez lindo pelo
prximo programa na sequncia, surf1d-ins.py, mostrado na listagem 4.2. O nico
trabalho deste programa selecionar algumas linhas da sada de onda1d-ins.py;
no caso, ns o rodamos com o comando
h

onda1d-ins.py 3 250 ,

o que significa selecionar 3 sadas (alm da condio inicial), de 250 em 250 intervalos
de tempo t. Observe que para isto ns utilizamos uma lista (v), cujos elementos
so arrays.
O resultado dos primeiros 750 intervalos de tempo de simulao mostrado na
figura 4.2. Repare como a soluo se torna rapidamente instvel. Repare tambm
como a soluo numrica, em t = 750t = 0,375, ainda est bastante distante dos
tempos mostrados na soluo analtica da figura 4.1 (que vo at t = 4). Claramente,
o esquema explcito que ns programamos jamais nos levar a uma soluo numrica
satisfatria para tempos da ordem de t = 1!

63

4.1 Adveco pura: a onda cinemtica

Listagem 4.1: onda1d-ins.py Soluo de uma onda 1D com um mtodo explcito


instvel
# !/ usr / bin / python
# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# onda1d - ins resolve uma equao de onda com um mtodo
# explcito
#
# uso : ./ onda1d - ins . py
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
fou = open ( ' onda1d - ins . dat ' , ' wb ')
dx = 0.01
dt = 0.0005
print ( '# dx = %9.4 f ' % dx )
print ( '# dy = %9.4 f ' % dt )
from numpy import zeros
nx = int (10.0/ dx )
# nmero de pontos em x
nt = int (1.0/ dt )
# nmero de pontos em t
print ( '# nx = %9 d ' % nx )
print ( '# nt = %9 d ' % nt )
u = zeros ((2 , nx +1) , float )
# apenas 2 posies no tempo
# so necessrias !
def CI ( x ):
# define a condio inicial
if 0 <= x <= 1.0:
return 2.0* x *(1.0 - x )
else :
return 0.0
for i in range ( nx +1):
# monta a condio inicial
xi = i * dx
u [0 , i ] = CI ( xi )
u [0]. tofile ( fou )
# imprime a condio inicial
old = False
new = True
c = 2.0
# celeridade da onda
couhalf = c * dt /(2.0* dx )
# metade do nmero de Courant
for n in range ( nt ):
# loop no tempo
# loop no espao
for i in range (1 , nx ):
u [ new , i ] = u [ old , i ] - couhalf *( u [ old , i +1] - u [ old ,i -1])
u [ new ,0] = 0.0
u [ new , nx ] = 0.0
u [ new ]. tofile ( fou )
# imprime uma linha com os novos dados
( old , new ) = ( new , old )
# troca os ndices
fou . close ()

0.500

0.250

0.50

0.00

tempo de simulao

0.375

u(x, t)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

0.125

0.000
10

Figura 4.2: Soluo numrica produzida por onda1d-ins.py, para t = 250t, 500t
e 750t.

Matemtica Aplicada

64

Listagem 4.2: surf1d-ins.py Seleciona alguns intervalos de tempo da soluo


numrica para plotagem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# surf1d - ins . py : imprime em <arq > <m >+1 sadas de
# onda1d - ins a cada <n > intervalos de tempo
#
# uso : ./ surf1d - ins . py <m > <n >
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
from sys import argv
dx = 0.01
dt = 0.0005
print ( '# dx = %9.4 f ' % dx )
print ( '# dy = %9.4 f ' % dt )
nx = int (10.0/ dx )
# nmero de pontos em x
print ( '# nx = %9 d ' % nx )
m = int ( argv [1])
# m sadas
n = int ( argv [2])
# a cada n intervalos de tempo
print ( '# m = %9 d ' % m )
print ( '# n = %9 d ' % n )
fin = open ( ' onda1d - ins . dat ' ,
' rb ')
# abre o arquivo com os dados
from numpy import fromfile
u = fromfile ( fin , float , nx +1) # l a condio inicial
v = [u]
# inicializa a lista da " transposta "
# para <m > instantes :
for it in range ( m ):
for ir in range ( n ):
# l <ir > vezes , s guarda a ltima
u = fromfile ( fin , float , nx +1)
v . append ( u )
# guarda a ltima
founam = ' surf1d - ins . dat '
print ( founam )
fou = open ( founam , ' wt ')
# abre o arquivo de sada
for i in range ( nx +1):
fou . write ( ' %10.6 f ' % ( i * dx ))
# escreve o " x "
fou . write ( ' %10.6 f ' % v [0][ i ])
# escreve a cond inicial
for k in range (1 , m +1):
fou . write ( ' %10.6 f ' % v [ k ][ i ]) # escreve o k - simo
fou . write ( '\ n ')
fou . close ()

65

4.1 Adveco pura: a onda cinemtica

Por que o esquema utilizado em (4.12) fracassa? Uma forma de obter a resposta
fazer uma anlise de estabilidade de von Neumann.
A anlise de estabilidade de von Neumann consiste primeiramente em observar
que, em um computador real, (4.12) jamais ser calculada com preciso infinita. O
que o computador realmente calcula um valor truncado uni . Por enquanto, ns s
vamos fazer esta distino de notao, entre u e u, aqui, onde ela importa. O erro
de truncamento
ni uni uni .
(4.13)
Note que (4.12) se aplica tanto para u quanto para u; subtraindo as equaes resultantes para un+1
e un+1
, obtm-se a mesma equao para a evoluo de ni :
i
i
n+1
= ni
i

Co n
( ni1 ),
2 i+1

(4.14)

onde

ct
(4.15)
x
o nmero de Courant. Isto s foi possvel porque (4.12) uma equao linear em
u. Mesmo para equaes no-lineares, entretanto, sempre ser possvel fazer pelo
menos uma anlise local de estabilidade.
O prximo passo da anlise de estabilidade de von Neumman escrever uma
srie de Fourier para ni , na forma
Co

tn = nt,
xi = ix,

No captulo sobre

N/2

ni

l e

atn i kl xi

(4.16)

l=1

onde e a base dos logaritmos naturais, i = 1, N = L/x o nmero de pontos


da discretizao em x, e L o tamanho do domnio em x.Em (4.16), ns estamos
supondo que o erro cresce exponencialmente.
Argumentando novamente com a linearidade, desta vez de (4.14), ela vale para
cada modo l de (4.16), donde
l ea(tn +t) ei kl ix = l eatn ei kl ix


Co  atn i kl (i+1)x
l e e
l eatn ei kl (i1)x ;
2

(4.17)

eliminando o fator comum l eatn +i kl ix ,



Co  +i kl x
e
ei kl x
2
= 1 i Co sen kl x.

eat = 1

(4.18)

O lado direito um nmero complexo, de maneira que o lado esquerdo tambm tem
que ser! Como concili-los? Fazendo a = + i , e substituindo:
e(i )t = 1 i Co sen kl x;
et [cos(t) i sen(t)] = 1 i Co sen kl x;
et cos(t) = 1,
t

sen(t) = Co sen(kl x).

(4.19)
(4.20)

sries de Fourier,
mostre que isto
funciona, e discuta
o N/2

66

Matemtica Aplicada

As duas ltimas equaes formam um sistema no-linear nas incgnitas . O


sistema pode ser resolvido:
tg(t) = Co sen(kl x) t = arctg (Co sen(kl x)) .
Note que 6= 0, donde et > 1, e o esquema de diferenas finitas incondicionalmente instvel.
O mtodo de Lax Uma alternativa que produz um esquema estvel o mtodo
de Lax (estamos seguindo os passos de Numerical Recipes):
=
un+1
i

i
1h n
(ui+1 + uni1 ) Co(uni+1 uni1 ) .
2

(4.21)

Agora que ns j sabemos que esquemas numricos podem ser instveis, devemos
fazer uma anlise de estabilidade antes de tentar implementar (4.21) numericamente.
Vamos a isto: utilizando novamente (4.16) e substituindo em (4.21), temos

1 h atn i kl (i+1)x
l e e
+ l eatn ei kl (i1)x
2 
i
Co l eatn ei kl (i+1)x l eatn ei kl (i1)x ;


i
1 h +i kl x
e
+ ei kl x Co e+i kl x ei kl x ;
eat =
2
at
e
= cos(kl x) i Co sen(kl x)
(4.22)

l ea(tn +t) ei kl ix =

Ns podemos, claro, fazer a = i , mas h um caminho mais rpido: o truque


perceber que se o fator de amplificao eat for um nmero complexo com mdulo
maior que 1, o esquema ser instvel. Desejamos, portanto, que |eat 1|, o que s
possvel se
Co 1,
(4.23)
que o critrio de estabilidade de Courant-Friedrichs-Lewy.
A mgica de (4.21) que ela introduz um pouco de difuso numrica; de fato,
podemos reescrev-la na forma
un uni1 uni+1 2uni + uni1
uni
un+1
i
= c i+1
+
t
2x
!2t
n
n
2
ui+1 ui1
x uni+1 2uni + uni1
= c
+
.
2x
2t
x2

(4.24)

No custa repetir: (4.24) idntica a (4.21). Porm, comparando-a com (4.12)


(nosso esquema instvel inicialmente empregado), ns vemos que ela tambm equivalente a esta ltima, com o termo adicional (x2 /2t) (uni+1 2uni + uni1 )/x2 .
O que este termo adicional significa? A resposta uma derivada numrica de ordem
2. De fato, considere as expanses em srie de Taylor
du
1 d2 u
= ui + x +
+ O(x2 ),
dx i
2 dx2 i

ui+1

du
1 d2 u
+ O(x2 ),
= ui x +
2
dx i
2 dx i

ui1

67

4.1 Adveco pura: a onda cinemtica

e some:
d2 u
= 2ui + 2 x2 + O(x2 ),
dx i

ui+1 + ui1

d2 u
ui+1 2ui + ui1
=
+ O(x2 ).
2
dx i
x2

(4.25)

Portanto, a equao (4.24) ou seja: o esquema de Lax (4.21) pode ser interpretada tambm como uma soluo aproximada da equao de adveco-difuso
u
2u
u
+c
= D 2,
t
c
x
com

x2
.
2t
!

D=

Note que D tem dimenses de difusividade: JDK = L2 T1 . No entanto: no estamos


ento resolvendo a equao errada? De certa forma, sim: estamos introduzindo
um pouco de difuso na equao para amortecer as oscilaes que aparecero em
decorrncia da amplificao dos erros de truncamento.
O quanto isto nos prejudica? No muito, desde que o efeito da difuso seja
muito menor que o da adveco que estamos tentando simular. Como a velocidade
de adveco (fsica; real) que estamos simulando c, precisamos comparar isto
com (por exemplo) a magnitude das velocidades introduzidas pela difuso numrica;
devemos portanto verificar se
2

D xu2
c u
x
u
D x
2
u
c x
D
x
x2
2tx
ct
x

 1,
 1,
 c,
 c,
= Co 

1
2

Em outras palavras, ns descobrimos que o critrio para que o esquema seja acurado
do ponto de vista fsico conflitante com o critrio de estabilidade: enquanto que
estabilidade demandava Co < 1, o critrio de que a soluo seja tambm fisicamente
acurada demanda que Co  1/2. Na prtica, isto significa que, para c = 2, ou o
esquema estvel com muita difuso numrica, ou ele instvel. Isto praticamente
elimina a possibilidade de qualquer uso srio de (4.21).
Mesmo assim, vamos program-lo! O programa onda1d-lax.py est mostrado
na listagem 4.3. Ele usa os mesmos valores t = 0,0005 e x = 0,01, ou seja,
Co = 0,10.
O programa gera um arquivo de sada binrio, que por sua vez lindo pelo
prximo programa na sequncia, surf1d-lax.py, mostrado na listagem 4.4. O nico
trabalho deste programa selecionar algumas linhas da sada de onda1d-lax.py;

Matemtica Aplicada

68

Listagem 4.3: onda1d-lax.py Soluo de uma onda 1D com um mtodo explcito


laxtvel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# onda1d - lax resolve uma equao de onda com um mtodo
# explcito
#
# uso : ./ onda1d - ins . py
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
fou = open ( ' onda1d - lax . dat ' , ' wb ')
dx = 0.01
dt = 0.0005
print ( '# dx = %9.4 f ' % dx )
print ( '# dy = %9.4 f ' % dt )
from numpy import zeros
nx = int (10.0/ dx )
# nmero de pontos em x
nt = int (1.0/ dt )
# nmero de pontos em t
print ( '# nx = %9 d ' % nx )
print ( '# nt = %9 d ' % nt )
u = zeros ((2 , nx +1) , float )
# apenas 2 posies no tempo
# so necessrias !
def CI ( x ):
# define a condio inicial
if 0 <= x <= 1.0:
return 2.0* x *(1.0 - x )
else :
return 0.0
# monta a condio inicial
for i in range ( nx +1):
xi = i * dx
u [0 , i ] = CI ( xi )
u [0]. tofile ( fou )
# imprime a condio inicial
old = False
new = True
c = 2.0
# celeridade da onda
cou = c * dt /( dx )
# nmero de Courant
print ( " Co = %10.6 f " % cou )
for n in range ( nt ):
# loop no tempo
for i in range (1 , nx ):
# loop no espao
u [ new , i ] = 0.5*(
( u [ old , i +1] + u [ old ,i -1]) cou *( u [ old , i +1] - u [ old ,i -1])
)
u [ new ,0] = 0.0
u [ new , nx ] = 0.0
u [ new ]. tofile ( fou )
# imprime uma linha com os novos dados
( old , new ) = ( new , old )
# troca os ndices
fou . close ()

69

4.1 Adveco pura: a onda cinemtica

Listagem 4.4: surf1d-lax.py Seleciona alguns intervalos de tempo da soluo


numrica para plotagem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# surf1d - lax . py : imprime em <arq > <m >+1 sadas de
# onda1d - lax a cada <n > intervalos de tempo
#
# uso : ./ surf1d - lax . py <m > <n >
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
from sys import argv
dx = 0.01
dt = 0.0005
print ( '# dx = %9.4 f ' % dx )
print ( '# dy = %9.4 f ' % dt )
nx = int (10.0/ dx )
# nmero de pontos em x
print ( '# nx = %9 d ' % nx )
m = int ( argv [1])
# m sadas
n = int ( argv [2])
# a cada n intervalos de tempo
print ( '# m = %9 d ' % m )
print ( '# n = %9 d ' % n )
fin = open ( ' onda1d - lax . dat ' ,
' rb ')
# abre o arquivo com os dados
from numpy import fromfile
u = fromfile ( fin , float , nx +1) # l a condio inicial
v = [u]
# inicializa a lista da " transposta "
for it in range ( m ):
# para <m > instantes :
for ir in range ( n ):
# l <ir > vezes , s guarda a ltima
u = fromfile ( fin , float , nx +1)
v . append ( u )
# guarda a ltima
founam = ' surf1d - lax . dat '
print ( founam )
fou = open ( founam , ' wt ')
# abre o arquivo de sada
for i in range ( nx +1):
fou . write ( ' %10.6 f ' % ( i * dx ))
# escreve o " x "
fou . write ( ' %10.6 f ' % v [0][ i ])
# escreve a cond inicial
for k in range (1 , m +1):
fou . write ( ' %10.6 f ' % v [ k ][ i ]) # escreve o k - simo
fou . write ( '\ n ')
fou . close ()

no caso, ns o rodamos com o comando


h

onda1d-lax.py 3 500 ,

o que significa selecionar 3 sadas (alm da condio inicial), de 500 em 500 intervalos
de tempo t. Com isto, ns conseguimos chegar at o instante 0,75 da simulao.
O resultado dos primeiros 1500 intervalos de tempo de simulao mostrado na
figura 4.3. Observe que agora no h oscilaes esprias: o esquema estvel no
tempo. No entanto, a soluo est agora amortecida pela difuso numrica!
Upwind
melhor o
esquema,
literatura

Um esquema que conhecido na literatura como indicado por representar


termo advectivo em (4.1) o esquema de diferenas regressivas; neste
chamado de esquema upwind literalmente, corrente acima na
de lngua inglesa, a discretizao utilizada
un uni1
un+1
uni
i
= c i
,
t
xh
i
n
n
n
=
u

Co
u

u
un+1
i
i
i
i1 .

(4.26)

70

Matemtica Aplicada
1.000

0.500

0.50

0.00

tempo de simulao

u(x, t)

0.750

0.250

0.000
10

Figura 4.3: Soluo numrica produzida por onda1d-lax.py, para t = 500t,


1000t e 1500t.
Claramente, estamos utilizando um esquema de O(x) para a derivada espacial. Ele
um esquema menos acurado que os usados anteriormente, mas se ele ao mesmo
tempo for condicionalmente estvel e no introduzir difuso numrica, o resultado
pode ser melhor para tratar a adveco.
Antes de colocarmos as mos na massa, sabemos que devemos analisar analiticamente a estabilidade do esquema. Vamos a isto:
l ea(tn +t) ei kl ix = l eatn ei kl ix Co l eatn ei kl ix l eatn ei kl (i1)x
h

eat ei kl ix = ei kl ix Co ei kl ix ei kl (i1)x
h

eat = 1 Co 1 ei kl x
h

eat = 1 Co + Co cos(kl x) i Co sen(kl x).

(4.27)

Desejamos que o mdulo do fator de amplificao eat seja menor que 1. O


mdulo (ao quadrado)
|eat |2 = (1 Co + Co cos(kl x))2 + (Co sen(kl x))2 .
Para aliviar a notao, faamos
Ck cos(kl x),
Sk sen(kl x).
Ento,
|eat |2 = (CoSk )2 + (CoCk Co + 1)2
= Co2 Sk2 + (Co2 Ck2 + Co2 + 1) + 2(Co2 Ck + CoCk Co)
= Co2 (Sk2 + Ck2 + 1 2Ck ) + 2Co(Ck 1) + 1

= 2Co2 (1 Ck ) + 2Co(Ck 1) + 1.

71

4.2 Difuso pura


1.000

0.500

0.50

0.00

tempo de simulao

u(x, t)

0.750

0.250

0.000
10

Figura 4.4: Soluo numrica produzida pelo esquema upwind, para t = 500t,
1000t e 1500t.
A condio para que o esquema de diferenas finitas seja estvel , ento,
2Co2 (1 Ck ) + 2Co(Ck 1) + 1 1,
2Co [Co(1 Ck ) + (Ck 1)] 0,
(1 cos(kl x)) [Co 1] 0,
Co 1
Reencontramos, portanto, a condio (4.23), mas em um outro esquema de diferenas finitas. A lio no deve ser mal interpretada: longe de supor que (4.23)
vale sempre, a anlise de estabilidade que deve refeita para cada novo esquema de
diferenas finitas!
O esquema upwind, portanto, condicionalmente estvel, e tudo indica que podemos agora implement-lo computacionalmente, e ver no que ele vai dar. Ns
utilizamos os mesmos valores de t e de x de antes. As mudanas necessrias nos
cdigos computacionais so bvias, e so deixadas a cargo do(a) leitor(a).
A figura 4.4 mostra o resultado do esquema upwind. Note que ele muito melhor
(para esta equao diferencial) que o esquema de Lax. No entanto, a figura sugere
que algum amortecimento (difuso numrica?) tambm est ocorrendo, embora em
grau muito menor.
Exerccios Propostos
4.1 Escreva o programa onda1d-upw e surfa1d-upw, que implementam o esquema
upwind. Reproduza a figura 4.4.
4.2 Calcule a difusividade numrica introduzida pelo esquema upwind.

4.2 Difuso pura


Considere agora a equao da difuso,
2u
u
= D 2,
t
x

(4.28)

72

Matemtica Aplicada
com condies iniciais e de contorno
u(x, 0) = f (x)
u(0, t) = u(L, t) = 0.

(4.29)
(4.30)

Esta soluo foi vista no captulo ??:


u(x, t) =

A n e

n2 2 2
t
L2

sen

n=1

nx
,
L

2ZL
nx
An =
f (x) sen
dx.
L 0
L

(4.31)
(4.32)

Em particular, se
D = 2,
L = 1,
f (x) = 2x(1 x),
An = 2

Z 1
0

2x(1 x) sen(nx) dx =

3 n3

[1 (1)n ] .

Todos os An s pares se anulam. Fique ento apenas com os mpares:


16
,
+ 1)3

X
16
(2(2n+1)2 2 )t
u(x, t) =
e
sen ((2n + 1)x)
3
3
n=0 (2n + 1)
A2n+1 =

3 (2n

(4.33)

O programa difusao1d-ana.py, mostrado na listagem 4.5, implementa a soluo


analtica para t = 0,0005 e x = 0,001.
Da mesma maneira que os programas surf1d*.py, o programa divisao1d-ana.py,
mostrado na listagem 4.6, seleciona alguns instantes de tempo da soluo analtica
para visualizao.
A figura 4.5 mostra o resultado da soluo numrica para t = 0, t = 0,05, t = 0,10
e t = 0,15. Este praticamente o fim do processo difusivo, com a soluo analtica
tendendo rapidamente para zero.
Esquema explcito Talvez o esquema explcito mais bvio para discretizar (4.28)
seja
uni+1 2uni + uni1
un+1
uni
i
=D
.
(4.34)
t
x2
A derivada parcial em relao ao tempo de O(t), enquanto que a derivada segunda
parcial em relao ao espao , como vimos em (4.25), de O(x2 ). Mas no nos
preocupemos muito, ainda, com a acurcia do esquema numrico. Nossa primeira
preocupao, como voc j sabe, outra: o esquema (4.34) estvel?
Explicitamos un+1
em (4.34):
i
h

un+1
= uni + Fo uni+1 2uni + uni1 ,
i
onde
Fo =

Dt
x2

(4.35)
(4.36)

73

4.2 Difuso pura

Listagem 4.5: difusao1d-ana.py Soluo analtica da equao da difuso


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# difusao1d - ana : soluo analtica de
#
# du / dt = D du ^2/ dx ^2
#
# u (x ,0) = 2 x (1 - x )
# u (0 , t ) = 0
# u (1 , t ) = 0
#
# uso : ./ difusao1d - ana . py
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
fou = open ( ' difusao1d - ana . dat ' , ' wb ')
dx = 0.001
dt = 0.0005
print ( '# dx = %9.4 f ' % dx )
print ( '# dy = %9.4 f ' % dt )
nx = int (1.0/ dx )
# nmero de pontos em x
nt = int (1.0/ dt )
# nmero de pontos em t
print ( '# nx = %9 d ' % nx )
print ( '# nt = %9 d ' % nt )
from math import pi , sin , exp
epsilon = 1.0 e -6
# preciso da soluo analtica
dpiq = 2* pi * pi
# 2 pi ^2
dzpic = 16/( pi * pi * pi )
# 16/ pi ^3
def ana (x , t ):
s = 0.0
ds = epsilon
n = 0
while abs ( ds ) >= epsilon :
dnm1 = 2* n + 1
# (2 n +1)
dnm1q = dnm1 * dnm1
# (2 n +1)^2
dnm1c = dnm1q * dnm1
# (2 n +1)^3
ds = exp ( - dnm1q * dpiq * t )
ds *= sin ( dnm1 * pi * x )
ds /= dnm1c
s += ds
n += 1
return s * dzpic
from numpy import zeros
u = zeros ( nx +1 , float )
# um array para conter a soluo
for n in range ( nt +1):
# loop no tempo
t = n * dt
print ( t )
for i in range ( nx +1):
# loop no espao
xi = i * dx
u [ i ] = ana ( xi , t )
u . tofile ( fou )
# imprime uma linha com os novos dados
fou . close ()

74

Matemtica Aplicada

Listagem 4.6: divisao1d-ana.py Seleciona alguns instantes de tempo da soluo


analtica para visualizao
# !/ usr / bin / python
# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# divisao1d - ana . py : imprime em <arq > <m >+1 sadas de
# difusao1d - ana a cada <n > intervalos de tempo
#
# uso : ./ divisao1d - ana . py <m > <n >
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
from sys import argv
dx = 0.001
dt = 0.0005
print ( '# dx = %9.4 f ' % dx )
print ( '# dt = %9.4 f ' % dt )
nx = int (1.0/ dx )
# nmero de pontos em x
print ( '# nx = %9 d ' % nx )
m = int ( argv [1])
# m sadas
n = int ( argv [2])
# a cada n intervalos de tempo
print ( '# m = %9 d ' % m )
print ( '# n = %9 d ' % n )
fin = open ( ' difusao1d - ana . dat ' ,
' rb ')
# abre o arquivo com os dados
from numpy import fromfile
u = fromfile ( fin , float , nx +1) # l a condio inicial
v = [u]
# inicializa a lista da " transposta "
for it in range ( m ):
# para <m > instantes :
for ir in range ( n ):
# l <ir > vezes , s guarda a ltima
u = fromfile ( fin , float , nx +1)
v . append ( u )
# guarda a ltima
founam = ' divisao1d - ana . dat '
print ( founam )
fou = open ( founam , ' wt ')
# abre o arquivo de sada
for i in range ( nx +1):
fou . write ( ' %10.6 f ' % ( i * dx ))
# escreve o " x "
fou . write ( ' %10.6 f ' % v [0][ i ])
# escreve a cond inicial
for k in range (1 , m +1):
fou . write ( ' %10.6 f ' % v [ k ][ i ]) # escreve o k - simo
fou . write ( '\ n ')
fou . close ()

0.5

t = 0,00

0.4

0.3
u(x, t)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

0.2
t = 0,05
0.1
t = 0,10
t = 0,15
0.0

0.2

0.4

0.6

0.8

Figura 4.5: Soluo analtica da equao de difuso para t = 0, t = 0,05, t = 0,10 e


t = 0,15.

75

4.2 Difuso pura

o nmero de Fourier de grade (El-Kadi e Ling, 1993). A anlise de estabiliade de


von Neumann agora produz
l ea(tn +t) ei kl ix = l eatn ei kl ix +
Fo l eatn ei kl (i+1)x 2l eatn ei kl ix + l eatn ei kl (i1)x ,
h

eat = 1 + Fo e+i kl x 2 + ei kl x
h

= 1 + 2Fo [cos(kl x) 1]
= 1 4Fo sen

kl x
2

(4.37)

A anlise de estabilidade requer que |eat | < 1:


|e

at 2

| = 1 8Fo sen

kl x
kl x
+ 16Fo2 sen4
2
2
!

<1

ou
kl x
kl x
8Fo sen
+ 16Fo2 sen4
< 0,
2
2
!"
!#
2 kl x
2 kl x
1 + 2Fo sen
< 0,
8Fo sen
2
2
1
Fo < .
2
!

(4.38)

Podemos agora calcular o nmero de Fourier que utilizamos para plotar a soluo
analtica (verifique nas listagens 4.5 e 4.6):
Fo =

2 0,0005
= 1000.
(0,001)2

Utilizar os valores x = 0,0005 e x = 0,001 levaria a um esquema instvel.


Precisamos diminuir t e/ou aumentar x. Com t = 0,00001 e x = 0,01,
Fo =

2 0,00001
= 0,2 < 0,5
(0,01)2

(OK).

Repare que Fo < 1/2 um critrio de estabilidade muito mais exigente do


que Co < 1/2 (para D = 2). Ns esperamos que nosso esquema explcito agora
rode muito lentamente. Mas vamos implement-lo. O programa que implementa o
esquema o difusao1d-exp.py, mostrado na listagem 4.7.
O programa divisao1d-exp.py, mostrado na listagem 4.8, seleciona alguns instantes de tempo da soluo analtica para visualizao.
O resultado da soluo numrica com o mtodo explcito est mostrado na figura
4.6: ele impressionantemente bom, embora seja computacionalmente muito caro.
A escolha judiciosa de t e x para obeder ao critrio (4.38) foi fundamental para
a obteno de um bom resultado de primeira, sem a necessidade dolorosa de
ficar tentando diversas combinaes at que o esquema se estabilize e produza bons
resultados.

Matemtica Aplicada

76

Listagem 4.7: difusao1d-exp.py Soluo numrica da equao da difuso: mtodo explcito.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# difusao1d - exp resolve uma equao de difuso com um mtodo
# explcito
#
# uso : ./ difusao1d - exp . py
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
fou = open ( ' difusao1d - exp . dat ' , ' wb ')
dx = 0.01
dt = 0.00001
print ( '# dx = %9.4 f ' % dx )
print ( '# dy = %9.4 f ' % dt )
from numpy import zeros
nx = int ( round (1.0/ dx ,0))
# nmero de pontos em x
nt = int ( round (1.0/ dt ,0))
# nmero de pontos em t
print ( '# nx = %9 d ' % nx )
print ( '# nt = %9 d ' % nt )
u = zeros ((2 , nx +1) , float )
# apenas 2 posies no tempo
# so necessrias !
def CI ( x ):
# define a condio inicial
if 0 <= x <= 1.0:
return 2.0* x *(1.0 - x )
else :
return 0.0
# monta a condio inicial
for i in range ( nx +1):
xi = i * dx
u [0 , i ] = CI ( xi )
u [0]. tofile ( fou )
# imprime a condio inicial
old = False
new = True
D = 2.0
# celeridade da onda
Fon = D * dt /(( dx )**2)
# nmero de Fourier
print ( " Fo = %10.6 f " % Fon )
for n in range ( nt ):
# loop no tempo
print ( n )
for i in range (1 , nx ):
# loop no espao
u [ new , i ] = u [ old , i ] + Fon *( u [ old , i +1] - 2* u [ old , i ] + u [ old ,i -1])
u [ new ,0] = 0.0
# condio de contorno , x = 0
u [ new , nx ] = 0.0
# condio de contorno , x = 1
u [ new ]. tofile ( fou )
# imprime uma linha com os novos dados
( old , new ) = ( new , old )
# troca os ndices
fou . close ()

77

4.2 Difuso pura

Listagem 4.8: divisao1d-exp.py Seleciona alguns instantes de tempo da soluo


analtica para visualizao
# !/ usr / bin / python
# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# divisao1d - exp . py : imprime em <arq > <m >+1 sadas de
# difusao1d - exp a cada <n > intervalos de tempo
#
# uso : ./ divisao1d - exp . py <m > <n >
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
from sys import argv
dx = 0.01
dt = 0.00001
print ( '# dx = %9.4 f ' % dx )
print ( '# dt = %9.4 f ' % dt )
nx = int ( round (1.0/ dx ,0))
# nmero de pontos em x
nt = int ( round (1.0/ dt ,0))
# nmero de pontos em t
print ( '# nx = %9 d ' % nx )
m = int ( argv [1])
# m sadas
n = int ( argv [2])
# a cada n intervalos de tempo
print ( '# m = %9 d ' % m )
print ( '# n = %9 d ' % n )
fin = open ( ' difusao1d - exp . dat ' ,
' rb ')
# abre o arquivo com os dados
from numpy import fromfile
u = fromfile ( fin , float , nx +1) # l a condio inicial
v = [u]
# inicializa a lista da " transposta "
for it in range ( m ):
# para <m > instantes :
for ir in range ( n ):
# l <ir > vezes , s guarda a ltima
u = fromfile ( fin , float , nx +1)
v . append ( u )
# guarda a ltima
founam = ' divisao1d - exp . dat '
fou = open ( founam , ' wt ')
# abre o arquivo de sada
for i in range ( nx +1):
fou . write ( ' %10.6 f ' % ( i * dx ))
# escreve o " x "
fou . write ( ' %10.6 f ' % v [0][ i ])
# escreve a cond inicial
for k in range (1 , m +1):
fou . write ( ' %10.6 f ' % v [ k ][ i ]) # escreve o k - simo
fou . write ( '\ n ')
fou . close ()

0.5

t = 0,00

0.4

0.3
u(x, t)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

0.2
t = 0,05
0.1
t = 0,10
t = 0,15
0.0

0.2

0.4

0.6

0.8

Figura 4.6: Soluo numrica com o mtodo explcito (4.35) (crculos) versus a
soluo analtica (linha cheia) da equao de difuso para t = 0, t = 0,05, t = 0,10 e
t = 0,15. Apenas 1 a cada 5 pontos da grade numrica so mostrados, para facilitar
a comparao com a soluo analtica.

78

Matemtica Aplicada

Esquemas implcitos Embora o esquema explcito que ns utilizamos acima seja


acurado, ele lento se voc programou e rodou difusao1d-exp.py, deve ter notado alguma demora para o programa rodar. Embora nossos computadores estejam
ficando a cada dia mais rpidos, isto no desculpa para utilizar mal nossos recursos
computacionais ( claro que, ao utilizarmos uma linguagem interpretada Python
para programar, ns j estamos utilizando muito mal nossos recursos; no entanto,
nosso argumento didtico: com uma linguagem mais simples, podemos aprender
mais rpido e errar menos. Alm disto, todos os ganhos relativos que obtivermos se
mantero em qualquer outra linguagem)
Vamos portanto fazer uma mudana fundamental nos nossos esquemas de diferenas finitas: vamos calcular a derivada espacial no instante n + 1:

un+1 2un+1
+ un+1
un+1
uni
i
i1
i
= D i+1
,
t
x2
n+1
un+1
uni = Fo(un+1
+ un+1
i
i+1 2ui
i1 ),
n+1
n
Foun+1
Foun+1
i1 + (1 + 2Fo)ui
i+1 = ui

(4.39)

Reveja a discretizao (4.5)(4.9): para i = 1, . . . , Nx 1, (4.39) acopla 3 valores


das incgnitas un+1 no instante n + 1. Quando i = 0, e quando i = Nx , no podemos
utilizar (4.39), porque no existem os ndices i = 1, e i = Nx + 1. Quando i = 1
e i = Nx 1, (4.39) precisa ser modificada, para a introduo das condies de
contorno: como un0 = 0 e unNx = 0 para qualquer n, teremos

(1 + 2Fo)un+1
Foun+1
= un1 ,
1
2
n+1
n
Foun+1
Nx 2 + (1 + 2Fo)uNx 1 = uNx 1 .

(4.40)
(4.41)

Em resumo, nossas incgnitas so un+1


, un+1
, . . . un+1
1
2
Nx 1 (Nx 1 incgnitas), e seu
clculo envolve a soluo do sistema de equaes

1 + 2Fo
Fo
0

Fo
1 + 2Fo Fo

.
..

0
0

...
0

...
0

0
...

0
0
..
.

0 Fo 1 + 2Fo
Fo
...
0
Fo
1 + 2Fo

un+1
1n+1
u2

..
.

un+1
Nx 2

un+1
Nx 1

un1
un2
..
.

un

Nx 2

unNx 1

(4.42)

79

4.2 Difuso pura


A anlise de estabilidade de von Neumann procede agora da maneira usual:
n+1
n+1
= ni + Fo(n+1
+ n+1
i
i+1 2i
i1 )

l ea(tn +t) ei kl ix = l eatn ei kl ix


+ Fo l ea(tn +t) ei kl (i+1)x 2l ea (tn + t)ei kl ix


+l ea(tn +t) ei kl (i1)x ,




eat = 1 + eat Fo ei kl x 2 + ei kl x ,


eat = 1 + eat 2Fo (cos(kl x) 1) ,


e
"

eat 1 + 4Fo sin2

at

kl x
2

=1e

at

4Fo sin

kl x
,
2
!

!#

= 1,

|eat | =

1
1 + 4Fo sin2

kl x
2

sempre.

(4.43)

Portanto, o esquema implcito (4.39) incondicionalmente estvel, e temos confiana de que o programa correspondente no se instabilizar.
Existem vrias coisas atraentes para um programador em (4.42). Em primeiro
lugar, a matriz do sistema uma matriz banda tridiagonal; sistemas lineares com
este tipo de matriz so particularmente simples de resolver, e esto disponveis
na literatura (por exemplo: Press et al., 1992, seo 2.4, subrotina tridag). Em
segundo lugar, a matriz do sistema constante: ela s precisa ser montada uma vez
no programa, o que torna a soluo numrica potencialmente muito rpida.
Ns vamos comear, ento, construindo um pequeno mdulo, convenientemente
denominado alglin.py, que exporta a funo tridag, que resolve um sistema tridiagonal, mostrado na listagem 4.9.
Em seguida, o programa difusao1d-imp.py resolve o problema com o mtodo
implcito. Ele est mostrado na listagem 4.10. A principal novidade est nas linhas
4246, e depois novamente na linha 56. Em Python e Numpy, possvel especificar sub-listas, e sub-arrays, com um dispositivo denominado slicing, que torna a
programao mais compacta e clara. Por exemplo, na linha 43, todos os elementos
A[0,1]. . . A[0,nx-1] recebem o valor -Fon.
Existe um programa divisao1d-imp.py, mas ele no precisa ser mostrado aqui,
porque as modificaes, por exemplo a partir de divisao1d-exp.py, so demasiadamente triviais para justificarem o gasto adicional de papel. Para t = 0,001, e
x = 0,01, o resultado do mtodo implcito est mostrado na figura 4.7
Nada mal, para uma economia de 100 vezes (em relao ao mtodo explcito) em
passos de tempo! (Note entretanto que a soluo, em cada passo de tempo, um
pouco mais custosa, por envolver a soluo de um sistema de equaes acopladas,
ainda que tridiagonal.)
Crank Nicholson A derivada espacial em (4.28) aproximada, no esquema implcito (4.39), por um esquema de O(x2 ). A derivada temporal, por sua vez,

80

Matemtica Aplicada

Listagem 4.9: alglin.py Exporta uma rotina que resolve um sistema tridiagonal,
baseado em Press et al. (1992)
# -* - coding : iso -8859 -1 -* # -----------------------------------------------------------------------------# alglin . py implementa uma soluo de um sistema linear com matriz tridiagonal
# -----------------------------------------------------------------------------from numpy import zeros
def tridag (A , y ):
# A , y tm que ser arrays !
m = A . shape [0]
# garante que A representa uma
n = A . shape [1]
# matriz tridiagonal
assert ( m == 3)
# garante que todos os tamanhos esto OK
o = y . shape [0]
assert ( n == o )
x = zeros (n , float )
# vetor de trabalho : vai retornar a soluo
gam = zeros (n , float )
# vetor de trabalho : vai ficar por aqui
if A [1 ,0] == 0.0 :
exit ( " Erro 1 em tridag " )
bet = A [1 ,0]
x [0] = y [0]/ bet
for j in range (1 , n ):
gam [ j ] = A [2 ,j -1]/ bet
bet = A [1 , j ] - A [0 , j ]* gam [ j ]
if ( bet == 0.0):
exit ( " Erro 2 em tridag " )
x [ j ] = ( y [ j ] - A [0 , j ]* x [j -1])/ bet
for j in range (n -2 , -1 , -1):
x [ j ] -= gam [ j +1]* x [ j +1]
return x

0.5

t = 0,00

0.4

0.3
u(x, t)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

0.2
t = 0,05
0.1
t = 0,10
t = 0,15
0.0

0.2

0.4

0.6

0.8

Figura 4.7: Soluo numrica com o mtodo implcito (4.39) (crculos) versus a
soluo analtica (linha cheia) da equao de difuso para t = 0, t = 0,05, t = 0,10 e
t = 0,15. Apenas 1 a cada 5 pontos da grade numrica so mostrados, para facilitar
a comparao com a soluo analtica.

81

4.2 Difuso pura

Listagem 4.10: difusao1d-imp.py Soluo numrica da equao da difuso:


mtodo implcito.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# difusao1d - imp resolve uma equao de difuso com um mtodo
# implcito
#
# uso : ./ difusao1d - imp . py
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
fou = open ( ' difusao1d - imp . dat ' , ' wb ')
dx = 0.01
# define a discretizao em x
dt = 0.001
# define a discretizao em t
print ( '# dx = %9.4 f ' % dx )
print ( '# dy = %9.4 f ' % dt )
nx = int ( round (1.0/ dx ,0))
# nmero de pontos em x
nt = int ( round (1.0/ dt ,0))
# nmero de pontos em t
print ( '# nx = %9 d ' % nx )
print ( '# nt = %9 d ' % nt )
from numpy import zeros
u = zeros ((2 , nx +1) , float )
# apenas 2 posies no tempo
# so necessrias !
def CI ( x ):
# define a condio inicial
if 0 <= x <= 1.0:
return 2.0* x *(1.0 - x )
else :
return 0.0
for i in range ( nx +1):
# monta a condio inicial
xi = i * dx
u [0 , i ] = CI ( xi )
u [0]. tofile ( fou )
# imprime a condio inicial
old = False
new = True
D = 2.0
# difusividade
Fon = D * dt /(( dx )**2)
# nmero de Fourier
print ( " Fo = %10.6 f " % Fon )
A = zeros ((3 , nx -1) , float )
# cria a matriz do sistema
# -----------------------------------------------------------------------------# cuidado , " linha " e " coluna " abaixo no significam as reais linhas e colunas
# do sistema de equaes , mas sim a forma de armazenar uma matriz tridiagonal
# -----------------------------------------------------------------------------A [0 ,0] = 0.0
# zera A [0 ,0]
A [0 ,1: nx -1] = - Fon
# preenche o fim da 1 a linha
A [1 ,0: nx -1] = 1.0 + 2* Fon
# preenche a segunda linha
A [2 ,0: nx -2] = - Fon
# preenche o incio da 2 a linha
A [2 , nx -2] = 0.0
# zera A [2 , nx -2]
# -----------------------------------------------------------------------------# importa uma traduo de tridag de Numerical Recipes para Python
# -----------------------------------------------------------------------------from alglin import tridag
for n in range ( nt ):
# loop no tempo
print ( n )
# -----------------------------------------------------------------------------# ateno : calcula apenas os pontos internos de u !
# -----------------------------------------------------------------------------u [ new ,1: nx ] = tridag (A , u [ old ,1: nx ])
u [ new ,0] = 0.0
# condio de contorno , x = 0
u [ new , nx ] = 0.0
# condio de contorno , x = 1
u [ new ]. tofile ( fou )
# imprime uma linha com os novos dados
( old , new ) = ( new , old )
# troca os ndices
fou . close ()
# fecha o arquivo de sada , e fim .

82

Matemtica Aplicada
apenas de O(t). Mas possvel consertar isto! A idia substituir (4.39) por
n+1
un+1
uni
D uni+1 2uni + uni1 un+1
+ un+1
i
i+1 2ui
i1
=
,
+
t
2
x2
x2
i
Fo h n
n+1
+ un+1
= uni +
un+1
ui+1 2uni + uni1 + un+1
i1 .
i+1 2ui
i
2

"

(4.44)

Com esta mudana simples, a derivada espacial agora uma mdia das derivadas
em n e n + 1, ou seja: ela est centrada em n + 1/2. Com isto, a derivada temporal
do lado esquerdo torna-se, na prtica, um esquema de ordem 2 centrado em n + 1/2!
Como sempre, nosso trabalho agora verificar a estabilidade do esquema numrico. Para isto, fazemos
n+1

i
i
Fo h n+1
Fo h n
n
i+1 2n+1
+ n+1
i+1 2ni + ni1 ,
i
i1 = i +
2
2

e substitumos um modo de Fourier:


a(tn +t)

l e

"

eat

"


Fo  i kl (i+1)x

e
2ei kl ix + ei kl (i1)x =
2
#
"

Fo  i kl (i+1)x
i kl ix
i kl (i1)x
atn
i kl ix
e
2e
+e
l e
e
+
2
#

i kl ix



Fo  i kl x
Fo  i kl x
1
e
2 + ei kl x = 1 +
e
2 + ei kl x
2
2
#

"

eat [1 Fo (cos(kl x) 1)] = [1 + Fo (cos(kl x) 1)]


"

at

1 + 2Fo sin

kl x
2

!#

"

= 1 2Fo sin

eat =

kl x
2

!#

kl x
2

.
2 kl x
2Fo sin
2

1 2Fo sin2
1+

fcil notar que |eat | < 1, e o esquema numrico de Crank-Nicholson incondicionalmente estvel. O esquema numrico de Crank-Nicholson similar a (4.39):

Fo n+1
Fo
Fo n
Fo
ui1 + (1 + Fo)un+1
un+1
ui1 + (1 Fo)uni + uni+1
i
i+1 =
2
2
2
2

(4.45)

Para as condies de contorno de (4.30), as linhas correspondentes a i = 1 e i =


Nx 1 so
Fo n+1
Fo
u2 = (1 2Fo)un1 + un2 ,
2
2
F ou n+1
Fo

u
+ (1 + Fo)un+1
un
+ (1 Fo)unNx 1
Nx 1 =
2 Nx 2
2 Nx 2

(1 + Fo)un+1
1

(4.46)
(4.47)

As mudanas no cdigo de difusao-imp.py so relativamente fceis de se identificar.


O cdigo do programa que implementa o esquema numrico de Crank-Nicholson,
difusao1d-ckn.py, mostrado na listagem 4.11.

83

4.3 Difuso em 2 Dimenses: ADI, e equaes elticas


0.5

t = 0,00

0.4

u(x, t)

0.3

0.2
t = 0,05
0.1
t = 0,10
t = 0,15
0.0

0.2

0.4

0.6

0.8

Figura 4.8: Soluo numrica com o mtodo de Crank-Nicholson ( (4.45)) (crculos)


versus a soluo analtica (linha cheia) da equao de difuso para t = 0, t = 0,05,
t = 0,10 e t = 0,15. Apenas 1 a cada 5 pontos da grade numrica so mostrados,
para facilitar a comparao com a soluo analtica.
A grande novidade computacional de difusao1d-ckn.py a linha 56: com os
arrays proporcionados por Numpy, possvel escrever (4.45) vetorialmente: note
que no h necessidade de fazer um loop em x para calcular cada elemento b[i]
individualmente. O mesmo tipo de facilidade est disponvel em FORTRAN90,
FORTRAN95, etc.. Com isto, a implementao computacional dos clculos gerada
por Numpy (ou pelo compilador FORTRAN) tambm potencialmente mais eficiente.
O mtodo de Crank-Nicholson possui acurcia O(t)2 , portanto ele deve ser
capaz de dar passos ainda mais largos no tempo que o mtodo implcito (4.39); no
programa difusao1d-ckn.py, ns especificamos um passo de tempo 5 vezes maior
do que em difusao1d-imp.py.
O resultado uma soluo cerca de 5 vezes mais rpida (embora, novamente,
haja mais contas agora para calcular o vetor de carga b), e mostrado na figura 4.8

4.3 Difuso em 2 Dimenses: ADI, e equaes elticas


Considere a equao da difuso em 2 dimenses,
2u 2u
u
=D
+
.
t
x2 y 2
!

(4.48)

Como sempre, ns queremos ser muito concretos, e trabalhar com um problema


que possua soluo analtica. Considere ento a condio inicial
(x2 + y 2 )
u(x, y, 0) = u0 exp
;
L2
!

(4.49)

a soluo analtica
(x2 + y 2 )
u0
exp
u(x, y, t) =

.
1 + 4tD/L2
L2 + 4Dt
!

(4.50)

Matemtica Aplicada

84

Listagem 4.11: difusao1d-ckn.py Soluo numrica da equao da difuso:


esquema de Crank-Nicholson.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

# !/ usr / bin / python


# -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# difusao1d - ckn resolve uma equao de difuso com o mtodo
# de Crank - Nicholson
#
# uso : ./ difusao1d - ckn . py
# ---------------------------------------------------------from __future__ import print _functio n
from __future__ import division
fou = open ( ' difusao1d - ckn . dat ' , ' wb ')
dx = 0.01
# define a discretizao em x
dt = 0.005
# define a discretizao em t
print ( '# dx = %9.4 f ' % dx )
print ( '# dt = %9.4 f ' % dt )
nx = int ( round (1.0/ dx ,0))
# nmero de pontos em x
nt = int ( round (1.0/ dt ,0))
# nmero de pontos em t
print ( '# nx = %9 d ' % nx )
print ( '# nt = %9 d ' % nt )
from numpy import zeros
u = zeros ((2 , nx +1) , float )
# apenas 2 posies no tempo
# so necessrias !
def CI ( x ):
# define a condio inicial
if 0 <= x <= 1.0:
return 2.0* x *(1.0 - x )
else :
return 0.0
# monta a condio inicial
for i in range ( nx +1):
xi = i * dx
u [0 , i ] = CI ( xi )
u [0]. tofile ( fou )
# imprime a condio inicial
old = False
new = True
D = 2.0
# difusividade
Fon = D * dt /(( dx )**2)
# nmero de Fourier
print ( " Fo = %10.6 f " % Fon )
A = zeros ((3 , nx -1) , float )
# cria a matriz do sistema
# -----------------------------------------------------------------------------# cuidado , " linha " e " coluna " abaixo no significam as reais linhas e colunas
# do sistema de equaes , mas sim a forma de armazenar uma matriz tridiagonal
# -----------------------------------------------------------------------------A [0 ,0] = 0.0
# zera A [0 ,0]
A [0 ,1: nx -1] = - Fon /2.0
# preenche o fim da 1 a linha
A [1 ,0: nx -1] = 1.0 + Fon
# preenche a segunda linha
A [2 ,0: nx -2] = - Fon /2.0
# preenche o incio da 2 a linha
A [2 , nx -2] = 0.0
# zera A [2 , nx -2]
# -----------------------------------------------------------------------------# importa uma traduo de tridag de Numerical Recipes para Python
# -----------------------------------------------------------------------------from alglin import tridag
for n in range ( nt ):
# loop no tempo
print ( n )
# -----------------------------------------------------------------------------# recalcula o vetor de carga vetorialmente
# -----------------------------------------------------------------------------b = ( Fon /2)* u [ old ,0: nx -1] + (1 - Fon )* u [ old ,1: nx ] + ( Fon /2)* u [ old ,2: nx +1]
# -----------------------------------------------------------------------------# ateno : calcula apenas os pontos internos de u !
# -----------------------------------------------------------------------------u [ new ,1: nx ] = tridag (A , b )
u [ new ,0] = 0.0
# condio de contorno , x = 0
u [ new , nx ] = 0.0
# condio de contorno , x = 1
u [ new ]. tofile ( fou )
# imprime uma linha com os novos dados
( old , new ) = ( new , old )
# troca os ndices
fou . close ()
# fecha o arquivo de sada , e fim .

85

4.3 Difuso em 2 Dimenses: ADI, e equaes elticas

Na verdade esta soluo se espalha por todo o plano xy, mas ns podemos trabalhar com um problema finito em x e y, por exemplo, fazendo L x L,
L y L, e impondo condies de contorno que se ajustem exatamente soluo analtica:
u(L, y, t) =
u(L, y, t) =
u(x, L, t) =
u(x, L, t) =

u0
1 + 4tD/L2
u0
1 + 4tD/L2
u0
1 + 4tD/L2
u0
1 + 4tD/L2

(L2 + y 2 )
,
2
L + 4Dt
!
(L2 + y 2 )
,
2
L + 4Dt
!
(x2 + L2 )
,
2
L + 4Dt
!
(x2 + L2 )
.
2
L + 4Dt
!

exp
exp
exp
exp

(4.51)
(4.52)
(4.53)
(4.54)

Agora, ns vamos fazer D = 2 (como antes) e L = 1, e resolver o problema


numericamente. Nossa escolha recair sobre um mtodo simples, e de O(t)2 , denominado ADI (alternating-direction implicit). Este mtodo nos proporcionar um
exemplo de uma tcnica denominada operator splitting ou time splitting, que ns
vamos traduzir como separao de operadores Esta tcnica consiste em marchar
implicitamente em uma dimenso espacial de cada vez, mantendo a outra dimenso explcita. Portanto, ns vamos utilizar dois esquemas diferentes de diferenas
finitas (na prtica), para resolver o problema! Ei-los
n+1
n+1
n
uni,j+1 2uni,j + uni,j1
un+1
un+1
i,j ui,j
i+1,j 2ui,j + ui1,j
=D
+
t
x2
y 2
n+1
n+1
n+2 !
n+1
n+2
un+1
un+2
un+2
i+1,j 2ui,j + ui1,j
i,j ui,j
i,j+1 2ui,j + ui,j1
=D
+
t
x2
y 2

(4.55)
(4.56)

Examine cuidadosamente (4.55) e (4.56): na primeira, note que o esquema implcito em x; na segunda, a situao se reverte, e o esquema implcito em y. claro
que ns vamos precisar de duas anlises de estabilidade de von Neumann, uma para
cada equao.
2011-09-24T17:07:04 Por enquanto, vou supor que os dois esquemas so incondicionalmente estveis, e mandar ver.
Alm disto, por simplicidade vamos fazer x = y = , de maneira que s
haver um nmero de Fourier de grade no problema,
Fo =

Dt
,
2

(4.57)

e ento teremos, para x:




n
n
n
n+1
n+1
n+1
n
un+1
i,j ui,j = Fo ui1,j 2ui,j + ui+1,j + ui,j1 2ui,j + ui,j+1 ,

n
n
n
n+1
n+1
n+1
n
un+1
i,j Fo ui1,j 2ui,j + ui+1,j = ui,j + Fo ui,j1 2ui,j + ui,j+1 ,
n+1
n+1
n
n
n
Foun+1
i1,j + (1 + 2Fo)ui,j Foui+1,j = Foui,j1 + (1 2Fo)ui,j + Foui,j+1 (4.58)

86

Matemtica Aplicada
Na dimenso y,


n+1
n+1
n+1
n+1
n+2
n+2
n+2
un+2
i,j ui,j = Fo ui1,j 2ui,j + ui+1,j + ui,j1 2ui,j + ui,j+1 ,

n+2
n+2
n+2
n+1
n+1
n+1
n+1
un+2
i,j Fo ui,j1 2ui,j + ui,j+1 = ui,j + Fo ui1,j 2ui,j + ui+1,j ,
n+2
n+2
n+1
n+1
n+1
Foun+2
i,j1 + (1 + 2Fo)ui,j Foui,j+1 = Foui1,j + (1 2Fo)ui,j + Foui+1,j
(4.59)

Se ns utilizarmos (novamente por simplicidade) o mesmo nmero de pontos


N + 1 em x e em y, teremos o seguinte mapeamento para a nossa grade:
2L
;

xi = L + i,
yj = L + j,

(4.60)

N=

i = 0, . . . , N,
j = 0, . . . , N,

(4.61)
(4.62)

e portanto L xi L e L yj L. Lembrando que os valores de u0,j , uN,j , ui,0


e ui,N esto especificados, h (N 1)2 incgnitas para serem calculadas. A beleza
de (4.58) e (4.59) que em vez de resolver a cada passo (digamos) 2t um sistema
de (N 1)2 incgnitas, ns agora podemos resolver a cada passo t N 1 sistemas
de (N 1) incgnitas, alternadamente para u1,...,N 1;j e ui;1,...,N1 .
claro que o cu o limite: poderamos, por exemplo, em vez de usar um esquema totalmente implcito, usar Crank-Nicholson em cada avano t; isto nos daria
imediatamente um esquema com acurcia de ordem t2 . No entanto, assim como
est o mtodo ADI j suficientemente sofisticado para nosso primeiro encontro
com este tipo de problema. Devemos, portanto, program-lo. Vamos, inicialmente,
programar a soluo analtica.
A soluo analtica do problema para os instantes de tempo t = 0, t = 0,1,
t = 0,2 e t = 0,3 est mostrada na figura 4.10

87

4.3 Difuso em 2 Dimenses: ADI, e equaes elticas

Figura 4.9: Soluo analtica da equao da difuso bidimensional, para t = 0, t = 0,


t = 0,1, t = 0,2 e t = 0,3

Matemtica Aplicada

88

Figura 4.10: Soluo numrica da equao da difuso bidimensional com o esquema


ADI, para t = 0, t = 0, t = 0,1, t = 0,2 e t = 0,3

A
Dados de vazo mdia anual e vazo
mxima anual, Rio dos Patos,
19311999
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979

21.57
25.65
4.76
11.46
28.10
14.30
22.09
24.09
22.29
7.48
27.49
19.11
15.62
16.25
16.57
26.75
21.88
20.68
8.36
21.62
24.72
14.59
15.31
27.33
28.23
15.64
41.70
20.04
14.50
22.61
30.82
15.22
22.49
24.23
36.80
21.60
13.25
9.05
22.94
25.95
32.82
34.13
30.33
17.81
26.77
32.50
13.63
13.26
26.97

272.00
278.00
61.60
178.30
272.00
133.40
380.00
272.00
251.00
56.10
171.60
169.40
135.00
146.40
299.00
206.20
243.00
223.00
68.40
165.00
266.00
192.10
131.80
281.00
311.50
156.20
399.50
152.10
127.00
176.00
257.00
133.40
248.00
211.00
208.60
152.00
92.75
125.00
135.60
202.00
188.00
198.00
252.50
119.00
172.00
174.00
75.40
146.80
222.00

89

Matemtica Aplicada
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999

26.92
14.73
31.68
57.60
27.13
12.55
16.74
26.64
15.22
31.20
43.48
11.92
35.24
34.30
20.74
31.78
35.44
41.02
51.55
24.49

182.00
134.00
275.00
528.00
190.00
245.00
146.80
333.00
255.00
226.00
275.00
131.00
660.00
333.00
128.00
472.00
196.00
247.50
451.00
486.00

90

Referncias Bibliogrficas
Abramowitz, M. e Stegun, I. A., editores (1972). Handbook of mathematical functions. Dover Publications, Inc., New York.
Bender, C. M. e Orszag, S. A. (1978). Advanced Mathematical Methods for Scientists
and Engineers. McGraw-Hill.
El-Kadi, A. I. e Ling, G. (1993). The Courant and Peclet Number Criteria for the
Numerical Solution of the Richards Equation. Water Resour Res, 29:34853494.
Oliphant, T. E. (2006). Guide to Numpy. Trelgol Publishing.
Press, W. H., Teukolsky, S. A., Vetterling, W. T., e Flannery, B. P. (1992). Numerical
Recipes in C. Cambridge University Press, Cambridge, UK. 1020 pp.

91

Você também pode gostar