Você está na página 1de 115

Mtodos Numricos em Matemtica Aplicada

Engenharia
Nelson Lus Dias
Departamento de Engenharia Ambiental e
Lemma Laboratrio de Estudos em Monitoramento e
Modelagem Ambiental
Universidade Federal do Paran
18 de setembro de 2013

2013 Nelson Lus da Costa Dias. Todos os direitos deste documento esto reservados. Este documento no est em domnio pblico. Cpias para uso acadmico podem
ser feitas e usadas livremente, e podem ser obtidas em http://www.lemma.ufpr.br/
wiki/index.php/Prof._Nelson_Lus_Dias Recursos de Internet. Este documento distribudo sem nenhuma garantia, de qualquer espcie, contra eventuais erros
aqui contidos.

Sumrio
0 Formalismos matemticos

13

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

.
.
.
.
.
.
.

15
15
17
17
18
20
24
26

.
.
.
.
.
.
.
.
.
.

31
31
36
40
46
46
50
51
61
65
67

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

2 Um pouco de polinmios, integrais, sries e equaes diferenciais


2.1 Integrao numrica: motivao . . . . . . . . . . . . . . . . . . . .
2.2 A regra do trapzio . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3 Aproximao de integrais com sries: a funo erro . . . . . . . . .
2.4 Soluo numrica de equaes diferenciais ordinrias . . . . . . . .
2.5 Soluo numrica; mtodo de Euler . . . . . . . . . . . . . . . . . .
2.6 Um mtodo implcito, com tratamento analtico . . . . . . . . . . .
2.7 Runge-Kutta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.8 O mtodo de Runge-Kutta multidimensional . . . . . . . . . . . . .
2.9 Soluo numrica de um problema no-linear . . . . . . . . . . . .
2.10 Poluio orgnica em rios . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

3 Soluo numrica de equaes diferenciais parciais


73
3.1 Adveco pura: a onda cinemtica . . . . . . . . . . . . . . . . . . . . . . 73
3.2 Difuso pura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.3 Difuso em 2 Dimenses: ADI, e equaes elticas . . . . . . . . . . . . . 103
A Para as coisas funcionarem em Windows

111

B Dados de vazo mdia anual e vazo mxima anual, Rio dos Patos, 1931
1999
113

Sumrio

Lista de Tabelas
1.1

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

20

2.1

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

36

Sumrio

Lista de Figuras
1.1
1.2

FDA emprica da vazo mxima anual no Rio dos Patos. . . . . . . . . . .


A funo f (x) = x/(1 + x 7/3 ) . . . . . . . . . . . . . . . . . . . . . . . . .

23
27

2.1
2.2
2.3

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


A regra do trapzio, com n = 4 e n = 8 trapzios. . . . . . . . . . . . . .
Funo erf(x) calculada por integrao numrica, com trapepsilon e
= 1 106 , versus a erf pr-definida no programa de plotagem. . . .
Funo erf(x) calculada com srie de Taylor, com erf_1, versus a erf
pr-definida no programa de plotagem. . . . . . . . . . . . . . . . . . .
Soluo da equao (2.14). . . . . . . . . . . . . . . . . . . . . . . . . .
Comparao da soluo analtica da equao (2.14) com a sada de
sucesso.py, para x = 0,01. . . . . . . . . . . . . . . . . . . . . . . .
Comparao da soluo analtica da equao (2.14) com a sada de
sucesso.py, para x = 0,5. . . . . . . . . . . . . . . . . . . . . . . . .
Comparao da soluo analtica da equao (2.14) com a sada de
sucimp.py, para x = 0,5. . . . . . . . . . . . . . . . . . . . . . . . . .
Comparao da soluo analtica da equao (2.14) com a sada de
euler2.py, para x = 0,5. . . . . . . . . . . . . . . . . . . . . . . . . .
Comparao da soluo analtica da equao (2.14) com a sada de
rungek4.py, para x = 0,5. . . . . . . . . . . . . . . . . . . . . . . . .
O integrando (x , t) para x = 1, . . . , 5. . . . . . . . . . . . . . . . . . . .
Clculo de (x) com o mtodo de Runge-Kutta: sada de intgam1 comparada com a funo (x) do programa de plotagem (Gnuplot) . . . . .
Soluo numrica pelo Mtodo de Runge-Kutta de um sistema de 2 equaes diferenciais ordinrias . . . . . . . . . . . . . . . . . . . . . . . . .
Drenagem de um macio poroso semi-infinito inicialmente totalmente
saturado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Resultado da integrao numrica do problema de Boussinesq para um
aqufero semi-infinito . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Soluo numrica do modelo de Streeter-Phelps com o mtodo de
Runge-Kutta. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

.
.

33
36

41

.
.

44
47

49

51

52

54

.
.

56
57

60

63

64

68

70

Condio inicial da equao 3.3. . . . . . . . . . . . . . . . . . . . . . . .


Soluo numrica produzida por onda1d-ins.py, para t = 250t, 500t
e 750t. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Soluo numrica produzida por onda1d-lax.py, para t = 500t,
1000t e 1500t. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73

2.4
2.5
2.6
2.7
2.8
2.9
2.10
2.11
2.12
2.13
2.14
2.15
2.16
3.1
3.2
3.3

77
83

Sumrio
Soluo numrica produzida pelo esquema upwind, para t = 500t,
1000t e 1500t. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.5 Soluo analtica da equao de difuso para t = 0, t = 0,05, t = 0,10 e
t = 0,15. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.6 Soluo numrica com o mtodo explcito (3.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. . . . .
3.7 Soluo numrica com o mtodo implcito (3.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. . . . .
3.8 Soluo numrica com o mtodo de Crank-Nicholson ( (3.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. . .
3.9 Comparao entre as solues analtica (linhas) e numrica com um esquema implcito (pontos) da equao da difuso-adveco com termo de
decaimento, para t = 0,333, t = 0,666 e t = 0,999. . . . . . . . . . . . . .
3.10 Soluo analtica da equao da difuso bidimensional, para t = 0, t = 0,
t = 0,1, t = 0,2 e t = 0,3 . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.11 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 . . . . . . . . . . . . . .

3.4

84

88

91

95

98

. 101
. 106
. 109

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
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
2.15
2.16
2.17
2.18

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 L um arquivo binrio contendo 3 linhas, cada uma das
quais com um array de 10 floats. . . . . . . . . . . . . . . . . . . . . .
Obteno do ponto de mximo de uma funo com Maxima . . . . . . .
mulambdak.max clculo da mdia da distribuio Weibull em em funo de seus parmetros e k . . . . . . . . . . . . . . . . . . . . . . . . .
Sada do programa mulambdak.max . . . . . . . . . . . . . . . . . . . . .
achapol.max Polinmio com propriedades definidas . . . . . . . . . .
Sada de achapol.max . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Clculo da integral de um polinmio analiticamente, com Maxima . . . .
passaquad.max parbola h(x) = ax 2 + 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 . . . . . .
Clculo de erf(x) com uma srie de Taylor. . . . . . . . . . . . . . . . . .
vererf1.py Clculo da funo erro com srie de Taylor entre 0 e 3. .
erfs.py Clculo de erf(x) com srie de Taylor, limitado a no mximo
43 termos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
resolve-eqdif Soluo de uma EDO com Maxima . . . . . . . . . .
fracasso.py Um programa com o mtodo de Euler que no funciona
sucesso.py Um programa com o mtodo de Euler que funciona . . .
9

17
19
21
21
23
24
25
26
28
29
29
32
32
33
34
35
37
37
38
38
39
39
41
43
44
45
46
48
50

Sumrio
2.19
2.20
2.21
2.22
2.23
2.24
2.25
2.26
2.27

sucimp.py Mtodo de Euler implcito . . . . . . . . . . . . . . . . .


euler2 Um mtodo explcito de ordem 2 . . . . . . . . . . . . . . . .
rungek4 Mtodo de Runge-Kutta, ordem 4 . . . . . . . . . . . . . . .
Primeiro prottipo para o clculo de (x) . . . . . . . . . . . . . . . . .
Programa definitivo para o clculo de (x) . . . . . . . . . . . . . . . .
Listas em Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
tentaarray.py: arrays com Numpy . . . . . . . . . . . . . . . . . . .
rungek4v.py: o mtodo de Runge-Kutta multidimensional . . . . . . .
Soluo numrica do modelo de Streeter-Phelps com o mtodo de
Runge-Kutta. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1 onda1d-ins.py Soluo de uma onda 1D com um mtodo explcito
instvel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 surf1d-ins.py Seleciona alguns intervalos de tempo da soluo numrica para plotagem . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3 onda1d-lax.py Soluo de uma onda 1D com um mtodo explcito
laxtvel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.4 surf1d-lax.py Seleciona alguns intervalos de tempo da soluo numrica para plotagem . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.5 difusao1d-ana.py Soluo analtica da equao da difuso . . . .
3.6 divisao1d-ana.py Seleciona alguns instantes de tempo da soluo
analtica para visualizao . . . . . . . . . . . . . . . . . . . . . . . . .
3.7 difusao1d-exp.py Soluo numrica da equao da difuso: mtodo explcito. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.8 divisao1d-exp.py Seleciona alguns instantes de tempo da soluo
analtica para visualizao . . . . . . . . . . . . . . . . . . . . . . . . .
3.9 alglin.py Exporta uma rotina que resolve um sistema tridiagonal,
baseada em Press et al. (1992) . . . . . . . . . . . . . . . . . . . . . . . .
3.10 difusao1d-imp.py Soluo numrica da equao da difuso: mtodo implcito. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.11 difusao1d-ckn.py Soluo numrica da equao da difuso: esquema de Crank-Nicholson. . . . . . . . . . . . . . . . . . . . . . . . .
sana.max . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.12 Implementao de um esquema numrico implcito para a equao da
difuso-adveco. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.13 difusao2d-ana.py Soluo analtica da equao da difuso bidimensional. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.14 difusao2d-adi.py Soluo numrica da equao da difuso bidimensional, esquema ADI. . . . . . . . . . . . . . . . . . . . . . . . . . .
patosmedmax.dat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10
.
.
.
.
.
.
.
.

52
54
55
58
59
62
62
64

71

75

76

81

.
.

82
86

87

89

90

93

94

. 97
. 100
. 102
. 105
. 107
. 113

Prefcio
Este texto parte de um projeto maior, em preparao, que ambiciona cobrir o contedo
de duas disciplinas que o autor leciona na graduao da UFPR. No seria justo fazer
meus alunos esperarem demais pelas partes que j esto razoavelmente prontas. O
leitor, ou a leitora, deve entretanto cuidar para o fato de que se trata de um excerto de
um projeto maior, e que consequentemente pode haver falhas. Mesmo assim, creio que
a hora de divulgar o contedo relacionado a um assunto absolutamente fascinante, que
so os mtodos numricos. Note, leitor ou leitora, que se trata de uma introduo, e que
no h nenhuma ambio de completude da parte do autor; mesmo assim. . . Divirta-se!

11

Sumrio

12

0
Formalismos matemticos
Este um livro sobre formalismos matemticos, e como eles podem ajudar voc, estudante, a resolver problemas mais rapidamente, e mais facilmente. O uso de matemtica
para resolver problemas cada vez mais sofisticados e realistas relacionados ao meio fsico, qumico e biolgico que nos cerca um fato: o caminho do futuro com certeza um
caminho em que o contedo matemtico ser cada vez maior na soluo de problemas
de Engenharia.
Novos formalismos permitem resolver mais rapidamente problemas mais difceis,
mas muitos estudantes tm dificuldade de ver as vantagens. No curto prazo, o aprendizado penoso, difcil, e cansativo. mesmo, e no minha inteno encobrir o grande
esforo envolvido. O ponto fundamental, entretanto, estar disposta(o) a entender que
o formalismo novo, e que ele precisa ser aprendido antes que o retorno medido na
soluo de problemas de seu interesse possa vir. Pense nisso como um investimento.
Como qualquer aluno que completou o ensino mdio antes de ingressar em um curso
superior, isso j aconteceu na sua vida. Um dia, voc aprendeu um novo formalismo
matemtico, muito difcil de entender (naquela ocasio), mas que lhe deu um gigantesco
poder de resolver novos problemas. O poder to grande, que voc quase certamente
esqueceu a forma antiga.
Exemplo 0.1 Maria possui o dobro das mas de Joo, e duas mas a mais que Jos. O nmero
total de mas que os trs possuem 18. Quantas mas Maria possui? Resolva esse problema
sem usar lgebra
SOLUO
Sem lgebra significa com Aritmtica apenas. A nica forma possvel por enumerao. Na
tabela abaixo, ns vamos aumentando o nmero de mas de Jos, e calculando as mas que
Maria e que Joo tm, at que a soma produza o valor do enunciado. Observao: o nmero de
mas de Maria par; logo, o nmero de mas de Jos tambm . Variamos portanto o nmero
de mas de Jos de 2 em 2.
Jos

Maria

Joo

Total

0
2
4
6

2
4
6
8

1
2
3
4

3
8
13
18

Portanto, Maria tem 8 mas. Era assim que voc fazia at aprender lgebra. Tambm era
assim que o mundo inteiro fazia, at a lgebra ser inventada. Hoje, ela to corriqueira, que

13

14

Matemtica Aplicada

ningum mais se lembra de que, um dia, ser matemtico era ser aritmtico e gemetra, mas ainda
no era ser algebrista.

claro que existe uma outra forma. Se x o nmero de mas de Maria, y o de Joo,
e z o de Jos,
x = 2y,
x = z + 2,
x + y + z = 18.
Ou:
x + x/2 + (x 2) = 18,
2x + x + 2x 4 = 36,
5x = 40,
x =8
A superioridade da abordagem algbrica to gritante que a maioria de ns se esquece da soluo aritmtica que aprendemos. A lgebra um formalismo novo, que nos
d tanto poder que vale a pena aprend-la ainda bem cedo, e utiliz-la para resolver
quase tudo que aparece at o fim do ensino mdio. Nesse ponto, entretanto, o poder da
lgebra d sinais de cansao. Novos formalismos so necessrios. Esses formalismos so
o Clculo, e a lgebra Linear. Este livro trata do seu uso sistemtico, e intensivo, para
resolver todo tipo de problema. Mas eles so formalismos novos. Suas regras so diferentes das regras da lgebra elementar. Esse fato precisa ser aceito, para que o contedo
do livro seja proveitosamente aprendido.
Exerccios Propostos
0.1 Resolva o mesmo problema, substituindo 18 por 33599999998.

1
Ferramentas computacionais
Neste captulo ns fazemos uma introduo muito rpida a duas 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.
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 isso 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.7.2

Maxima:

5.24.0

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. Isso
facilitado por comandos do tipo


from __future__ import ,
que voc encontrar diversas vezes ao longo do texto. Se voc (j) estiver usando Python
3.x, remova esses comandos do incio de seus arquivos .py. Note que os colchetes acima
no fazem parte do comando; eles apenas o delimitam, como se fossem aspas.

1.1 Antes de comear a trabalhar,


Voc precisar de algumas condies de funcionamento. Eis os requisitos fundamentais:
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.
15

Matemtica Aplicada

16

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 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 (http://projects.gnome.
org/gedit/) que tambm funciona muito bem em Windows, e o kate. Programadores mais experientes costumam preferir o vim, ou o emacs. Esses dois ltimos possuem
verses para os 3 sistemas operacionais mais comuns hoje em dia: Windows, Linux e
Mac OS X.
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, 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 isso 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 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!
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?

17

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 unicode_literals
from __future__ import print_function
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 correspondente 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

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.

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 se preocupe.

Matemtica Aplicada
8

18

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


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 qual
voc est executando este programa certamente esto utilizando codificaes diferentes
(veja se o apndice A 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,

19

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 unicode_literals
from __future__ import print_function
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)

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 (Ns adotamos a conveno de
escrever i = 1 em tipo romano, e no i = 1 em tipo itlico; desta forma, ns
enfatizamos, dentro das equaes, o nmero imaginrio i; o problema, como voc pode
notar, que no texto ele fica confundido com a vogal i; da mesma forma, ns adotaremos
para a base dos logaritmos naturais o smbolo e em tipo romano, em lugar de e
em tipo itlico, com o mesmo problema). Mas eu tambm poderia ter simplesmente
eliminado essa linha, e substitudo a linha 14 por


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

20

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

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
1
,
n
onde n o nmero de observaes. Mas a FDA por definio
P {Q = qi } =

F (q) = P {Q q }.

(1.1)

(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
q 0 q 1 . . . qn1 .

21

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

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 unicode_literals
from __future__ import print_function
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.2f %8.6f\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

Note que a ordenao no altera (1.1). Aps a ordenao, o clculo de F (qi ) trivial:
F (qi ) =

i
X
1
k=0

i+1
.
n

(1.3)

(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 B).
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. Essa , 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.

Matemtica Aplicada

22

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.

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.

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

23

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

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

600

700

Vazo mxima anual (m3 s 1 )

Figura 1.1: FDA emprica da vazo mxima anual no Rio dos Patos.
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 tupla2 (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; o seu grfico, plotado a partir de fqiemp.dat, mostrado na figura 1.1
2 Em

Python uma tupla uma lista imutvel

Matemtica Aplicada

24

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_function
i = 673451
bdet = bin(i)
print(bdet)
fot = open('i.txt ','wt')
fot. write ('%6d' % 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 '))

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

25

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 "

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 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 (apenas 20 bits so mostrados; os 12 bits esquerda desses so iguais a
zero). 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 escrita de arquivos binrios muito mais rpida,
porque no h necessidade de traduzir a informao de, e para, strings.
Na prtica, arquivos binrios esto invariavelmente associados ao uso de arrays, pelo
menos em Engenharia. O mdulo Numpy (http://numpy.scipy.org), 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.

26

Matemtica Aplicada

Listagem 1.8: readarr.py L 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_function
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.4f' % e)
stdout . write ('\n')
fib. close ()

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

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


writearr.py.

1.3 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 ;
4
(% o1)
(% i2) expand (%);

(b + a)
4

(% o2)
(% i3) quit ();

3
+ 4 a b

2
+ 6 a

O comando

quit();

o devolver para a linha de comando.

2
b

3
+ 4 a

4
b + a

27

1.3 Maxima
0.6

0.5

f (x)

0.4

0.3

0.2

0.1

0.0
0.01

0.1

10

100

Figura 1.2: A funo f (x) = x/(1 + x 7/3 )


Vamos fazer algo um pouco mais sofisticado: quais so as razes de
P (x) = x 4 10x 3 + 35x 2 50x + 24?
Faa
(% i1) P : x^4 - 10*x^3 + 35*x^2 - 50*x + 24 ;
4
3
2
(% o1)
x - 10 x + 35 x - 50 x + 24
(% i2) solve (P,x);
(% o2)
[x = 3, x = 4, x = 1, x = 2]

Uma outra maneira de obter o mesmo efeito teria sido


(% i1) P : x^4 - 10*x^3 + 35*x^2 - 50*x + 24 ;
4
3
2
(% o1)
x - 10 x + 35 x - 50 x + 24
(% i2) factor (P);
(% o2)
(x - 4) (x - 3) (x - 2) (x - 1)

Maxima capaz de resolver muitas equaes quando a soluo algbrica existe. Por
exemplo, considere o problema de encontrar o mximo da funo
f (x) =

x
,
1 + x 7/3

mostrada na figura 1.2: note que se trata de uma funo muito apertada em torno de
x = 0; para vermos melhor a funo nas proximidades de zero, ns plotamos o eixo
dos x em escala logaritmica. evidente que s existe um mximo para a funo. Para
encontr-lo, ns derivamos f (x), igualamos a derivada a zero, e encontramos a raiz de
f 0(x) = 0. Com Maxima, isto fica mostrado na listagem 1.9.
Note que existem 7 razes para f 0(x ) = 0, mas 6 delas so complexas! Por exemplo, a
primeira raiz encontrada por Maxima foi
x=

  3/7 6i   3/7 

3
3
6i
6i
e7 =
cos
+ i sen
;
4
4
7
7

28

Matemtica Aplicada
Listagem 1.9: Obteno do ponto de mximo de uma funo com Maxima
(% i1) f : x/(1 + x ^(7/3)) ;
x
-------7/3
x
+ 1

(% o1)

(% i2) diff(f,x);
7/3
1
7 x
-------- - ------------7/3
7/3
2
x
+ 1
3 (x
+ 1)

(% o2)

(% i3) solve (%,x);


6 %i %pi
-------7

2 %i %pi
- -------7

4 %i %pi
-------7

3/7
3/7
3/7
3
%e
3
%e
3
%e
(% o3) [x = ---------------, x = -----------------, x = ---------------,
3/7
3/7
3/7
4
4
4
4 %i %pi
2 %i %pi
6 %i %pi
- --------------- -------3/7
7
3/7
7
3/7
7
3/7
3
%e
3
%e
3
%e
3
x = -----------------, x = ---------------, x = -----------------, x = ----]
3/7
3/7
3/7
3/7
4
4
4
4

observe que Maxima usa os smbolos %e para o nmero e, %i para o nmero i =


%pi para o nmero . Alm disto, na linha (%i3), o comando


solve(%,x)

1, e

significa: resolva a expresso da linha anterior ((%o2)) em relao a x. A nica raiz


real, portanto, (3/4)3/7 0.884005215243613, como pode ser confirmado visualmente
na figura 1.2.
Suponha agora que voc deseje calcular a integral

=

x
0

dF
dx .
dx

onde


F (x) = 1 exp (x/)k .
A derivada dentro da integral ficou intencionalmente indicada: estou supondo que ns
somos preguiosos, e no queremos calcul-la manualmente, nem integral. A listagem
1.10 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!

29

1.3 Maxima

Listagem 1.10: 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) ;

Listagem 1.11: Sada do programa 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

Define F (F (x)): note que no F(x)! Note tambm que a atribuio, em Maxima,
no feita com = (como em Python), mas sim com :; = fica reservado para
igualdade.

Armazena a derivada de F (x ).

Calcula a integral.

O resultado de rodar mulambdak.max, com o comando



maxima -b mulambdak.max

mostrado na listagem 1.11


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
=
.
(1.4)
k
Exerccios Propostos
1.6 Com Maxima, calcule a derivada de
f (x ) = ln(sen(ex )).

30

Matemtica Aplicada
1.7 Com Maxima, calcule


1

1
x 3/2

dx .

1.8 Com Maxima, obtenha as razes de


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

2
Um pouco de polinmios, integrais,
sries e equaes diferenciais
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) = ax 4 + bx 3 + cx 2 + dx + e,
df
,
(x) =
dx
f (0) = 0,
f (1) = 5/2,
f (2) = 7/2,
f (4) = 4,
(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 (x ).

37

Define o valor de f (x) em x = 0, 1, 2, 4, e o valor de (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) = x 4 + x 3 x 2 + x .
48
48
12
3
31

(2.1)

32

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


 5
I =
f (x) dx .
1

claro que esta integral pode ser calculada analiticamente com Maxima, conforme podemos ver na listagem 2.3. 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..

33

2.1 Integrao numrica: motivao


Listagem 2.3: Clculo da integral de um polinmio 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
(% i4) bfloat (%);
(% o4)
1.467777777777778 b1

y
5
4

f (x )

3
h(x )
2
1
0
b

Figura 2.1: Integrao numrica de uma funo


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:
f (1) + f (3)
f (3) + f (5)
I1 =
2+
2 = 14,000.
2
2

34

Matemtica Aplicada

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 2o grau passando por estes
3 pontos. O programa passaquad.max, mostrado na listagem 2.4, faz este trabalho, e
acha os coeficientes a, b, c da parbola
h(x) = ax 2 + 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.4: passaquad.max parbola h(x) = ax 2 + 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.5.


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

I2 =


=

h(x) dx



3 2 23
5
x + 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.

35

2.1 Integrao numrica: motivao


Listagem 2.5: 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

Exerccios Propostos
2.1 Se f (x ) = sen x, qual a estimativa de I =


0

f (x ) dx = 2 com um trapzio ?

2.2 Provavelmente, voc no est muito contente com o resultado do Problema 2.1.
a) Aproxime a integral I do Problema 2.1 com dois trapzios, entre x = 0 e /2, e entre x = /2
e .
b) Aproxime a integral pela integral da parbola quadrtica (x ) = ax 2 + 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) = ax 3 +bx 2 +cx +d passando
pelos mesmos pontos acima, e com h 0 ( /2) = 0.

36

Matemtica Aplicada
Tabela 2.1: Estimativas numricas de I e seus erros relativos .
Integral
Exato
Um trapzio
Dois trapzios
Uma parbola

Valor

14,6778
12,5000
14,0000
14,5000

0
0,1483
0,0461
0,0121
b

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.

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. 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
n
X
f (xi1 ) + f (xi )
x ,
I3 =
2
i=1

(2.3)

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

(2.4)
(2.5)
(2.6)

37

2.2 A regra do trapzio

Prosseguindo, (2.3) pode ser re-escrita:


"
#
f (x 0 ) + f (x 1 ) f (x 1 ) + f (x 2 )
f (xn1 ) + f (xn )
I3 =
+
+...+
x
2
2
2


 x
= f (x 0 ) + 2 f (x 1 ) + f (x 2 ) + . . . + f (xn1 ) + f (xn )
2
x
= (Se + 2Si )
,
2
com
Se = f (x 0 ) + f (xn ),
n1
X
Si =
f (xi ).

(2.7)

(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.6
Listagem 2.6: 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 unicode_literals
from __future__ import print_function
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.7).
Listagem 2.7: 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 unicode_literals
from __future__ import print_function
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.4f\n' % I3)

A sada de quadraver1.py I 3 14,6328. O erro est agora na 2a casa decimal, e o


erro relativo = 0,0031, ou 0,3%.

38

Matemtica Aplicada

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 do mdulo numint (listagem
2.8: note a continuao da numerao de linhas dentro do mesmo arquivo numint.py),
denominada trapepsilonlento, e mostrada na listagem 2.8.
Listagem 2.8: 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 trapepsilonlento (epsilon ,a,b,f):


'''
trapepsilonlento (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: I 4 = 14,67777, = 0,00003, =
0,00000075. Com 4 casas decimais, este um resultado exato!
Listagem 2.9: 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 unicode_literals
from __future__ import print_function
from __future__ import division
from numint import trapepsilonlento
def f(x):
return (( -1/48)*x**4 + (13/48)* x**3 + ( -17/12)*x**2 + (11/3)* x)
(I4 ,eps) = trapepsilonlento (0.0001 ,1 ,5 ,f)
print('I4 = %8.5f eps = %8.5f' % (I4 ,eps ))
II = 14.677777777777777
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 (x 2 ) + f (x 4 ) + f (x 6 ) (note que os
ndices j esto definidos para o caso n = 8). Esta soma j foi calculada na integral com

39

2.2 A regra do trapzio

4 trapzios, e no precisa ser recalculada. O que ns precisamos fazer agora somar


f (x 1 ) + f (x 3 ) + f (x 5 ) + f (x 7 ) 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.10.

Listagem 2.10: 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
for i in range (1,n ,2):
# apenas os mpares ...
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.11) 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: I 5 =
14.6777776, = 0.0000005, = 0.00000001. Note que I 5 exato at a 6a casa decimal, conforme estipulado.

Listagem 2.11: 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 unicode_literals
from __future__ import print_function
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 = 14.677777777777777
delta = (I5 - II )/ II
print('delta = %12.8 f' % delta )

40

Matemtica Aplicada
Exerccios Propostos
2.3 Usando Python e numint.trapezio, aproxime I =
10 trapzios.


0

sen(x ) dx pela regra do trapzio com

2.4 Usando Python e numint.trapepsilon, aproxime I =


com preciso absoluta menor ou igual a 1 10 5 .


0

sen(x ) dx pela regra do trapzio

2.5 Dada f (x ) definida no intervalo [x 0 , x 0 + 2h], deduza a regra de Simpson:


 x 0 +2h
h
f (x) dx [f 0 + 4f 1 + f 2 ] ,
3
x0
com fn = f (xn ), xn = x 0 + nh, interpolando a funo (x ) = ax 2 + bx + c atravs dos pontos
(x 0 , f 0 ), (x 1 , f 1 ) e (x 2 , f 2 ) e calculando sua integral.
2.6 Dobrando o nmero de pontos de 2 para 4, obtenha a regra de Simpson para 5 pontos,
 x 0 +4h
h
f (x ) dx [f 0 + 4f 1 + 2f 2 + 4f 3 + f 4 ] ;
3
x0
generalize:


b x 0 +2nh

ax 0

f (x ) dx

h
[f 0 + 4f 1 + 2f 2 + . . . + 2f 2n 2 + 4f 2n 1 + f 2n ] .
3

2.7 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 I 2 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
 x
2
2
eu du.
(2.10)
erf(x)
u=0
A funo erro est definida em Maxima e 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.12) calcula a funo em um grande nmero de pontos; gera um arquivo de
dados vererf.dat. O resultado mostrado com pontos na figura 2.3 em comparao
com uma implementao padro (mostrada em linha contnua) de erf(x) do programa
de plotagem.
Existe uma maneira mais inteligente de calcular erf(x): ela se baseia em integrar a
2
srie de Taylor do integrando, eu . Maxima permite calcular os primeiros termos:
1 Sim!

existem parbolas cbicas, qurticas, etc..

41

2.3 Aproximao de integrais com sries: a funo erro

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


#!/ usr/bin/ python
# -*- coding : iso -8859 -1 -*from __future__ import unicode_literals
from __future__ import print_function
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.6f %8.6f\n' % (xl ,erf ))
for k in range (nx ):
xu = xl + dx
(I,eps) = trapepsilon (1.0e-6,xl ,xu ,f)
erf = erf + (2.0/ sqrt(pi ))*I
fou. write ('%8.6f %8.6f\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

1.0
trapepsilon
pr-definida

0.9
0.8
0.7
0.6
erf(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

0.5
0.4
0.3
0.2
0.1
0.0
0

0.5

1.5

2.5

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

42

Matemtica Aplicada

(% i1) taylor (exp(-u^2) ,u ,0 ,10) ;


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

2
(% o1 )/T/

1 - u

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,
e

u 2

(1)n

n=0

u 2n
.
n!

(2.11)

Portanto,

0

u 2


du =
=

xX

X
n=0

(1)n

n=0

(1)n
n!


0

u 2n
du
n!

u 2n du

X
(1)n x 2n+1
=
n! 2n + 1
n=0

X
n=0

(1)n

x 2n+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)!
Ainda falta encontrar uma maneira computacionalmente eficiente de passar do
termo n 1 para o termo n. Vamos a isto:
An
x 2n+1

(2n + 1)n! BnCn


=

(1)n x 2(n1+1)+1


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

(1)n1x 2(n1)+1 [x 2 ]


2(n 1) + 1) + [2] [n](n 1)!
An1 (x 2 )
=
.
(Bn1 + 2)(Cn1 n)
=

(2.13)

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


x 2 . O denominador mais complicado; ele formado pelo produto BnCn , e as relaes
completas de recurso so
An = x 2n+1 = An1 (x 2 ),
Bn = 2n + 1 = Bn1 + 2,
Cn = n! = Cn1 n.

43

2.3 Aproximao de integrais com sries: a funo erro

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 unicode_literals
from __future__ import print_function
from __future__ import division
from math import sqrt , pi
def erf_1 (x):
epsilon_erf = 1.0e -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

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 a sada, mostrada na figura 2.4.
Embora formalmente correta, a rotina erf_1 fica mais lenta medida 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


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


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.15, 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.

44

Matemtica Aplicada

Listagem 2.14: vererf1.py Clculo da funo erro com srie de Taylor entre 0 e 3.
#!/ usr/bin/ python
# -*- coding : iso -8859 -1 -*from __future__ import unicode_literals
from __future__ import print_function
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.6f %8.6f\n' % (xl ,0.0))
for k in range (nx ):
xu = xl + dx
(erf ,n) = erf_1 (xu)
fou. write ('%8.6f %8.6f\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

1.0
erf_1
pr-definida

0.9
0.8
0.7
0.6
erf(x)

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

0.5
0.4
0.3
0.2
0.1
0.0
0

0.5

1.5

2.5

Figura 2.4: Funo erf(x) calculada com srie de Taylor, com erf_1, versus a erf prdefinida no programa de plotagem.

45

2.3 Aproximao de integrais com sries: a funo erro

Listagem 2.15: 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.0e -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

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, a nossa erf j 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.
Exerccios Propostos
2.8 (Bender e Orszag (1978), seo 6.2, Exemplo 2) Obtenha uma srie para
 x
F (x )
t 1/2 e t dt;
0

compare o resultado obtido com integrao numrica.


2.9 Considere a funo F (x ) definida pela integral
 x t
e 1
dt ,
F (x)
t
0

x 0.

Obtenha uma srie para o clculo de F (x ). Sugesto: expanda et em srie de Taylor em torno de
t = 0, etc., e em seguida integre termo a termo.
2.10 Escreva um programa em Python para calcular a srie de Taylor de f (x ) = x sen(x) em
torno de x = 0. Utilize Maxima para obter os primeiros termos da srie, e desta forma, reconhecendo o padro, encontrar o termo geral.

46

Matemtica Aplicada

2.4 Soluo numrica de equaes diferenciais ordinrias


Considere uma equao diferencial de 1a ordem simples, forada eternamente por
um seno:
dy y
+ = sen x .
(2.14)
dx x
Na listagem 2.16, ns resolvemos esta equao com Maxima. Maxima nos informa
de que a soluo geral da forma
y(x ) =

sen x x cos x + c
.
x

(2.15)

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

sen x
cos x .
x

(2.16)

Agora,

sen x
= 1,
x0 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:


sen x
cos x = 1 1 = 0.
(2.17)
lim
x0
x
lim

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


(% i1) 'diff(y,x) + y/x = sin(x) ;
dy
y
(% o1)
-- + - = sin(x)
dx
x
(% i2) ode2 (%,y,x);
sin(x) - x cos(x) + %c
(% o2)
y = ---------------------x

O resultado est mostrado na figura 2.5.


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.

2.5 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
Isso 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

47

2.5 Soluo numrica; mtodo de Euler


1.5

1.0

y(x )

0.5

0.0

0.5

1.0

1.5
0

10

20

30

40

50

Figura 2.5: Soluo da equao (2.14).


correspondentes. Obviamente, como os ys devem aproximar a funo, no podemos
esperar deles que sejam igualmente espaados!
Desejamos ento:
x 0 , x 1 , . . . , 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
Note que agora possvel explicitar yi+1 em funo de todos os outros valores em i:
"
#
yi
yi+1 = yi + sen(xi )
x .
(2.18)
xi
Esse 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

48

Matemtica Aplicada

Listagem 2.17: 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 unicode_literals
from __future__ import print_function
# ---------------------------------------------------------# 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 ()

ser capaz de prever o desastre: na frmula acima, se partirmos de x 0 = 0, teremos uma


diviso por zero j no primeiro passo!
Muitos no veriam isso, entretanto, e nosso primeiro programa para tentar resolver
a equao diferencial numericamente se chamar fracasso.py, e est mostrado na
listagem 2.17
O resultado o seguinte fracasso:
Traceback (most recent call last ):
File "./ fracasso .py", line 15, in <module >
yn = y[i] + (sin(x[i]) - y[i]/x[i])* dx
ZeroDivisionError : float division by zero

Isso 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, na verdade possvel conhecer uma boa parte do
comportamento prximo da origem de y(x ), a soluo de (2.14) (para a condio inicial
y(0) = 0) sem resolv-la! Para tanto, expanda tanto y(x) quanto sen(x) em srie de
Taylor em torno de x = 0:
y = a + bx + cx 2 + . . . ,
dy
= b + 2cx + . . . ,
dx
sen(x) = x + . . .
Substituindo na equao diferencial,
b + 2cx +

a
+ b + cx + . . . = x + . . .
x

Note que a srie de Taylor de sen(x) foi truncada corretamente, porque o maior expoente
de x em ambos os lados da equao acima 1. Simplificando,
a
+ 2b + 3cx + . . . = x + . . .
x

49

2.5 Soluo numrica; mtodo de Euler


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 2.6: Comparao da soluo analtica da equao (2.14) com a sada de


sucesso.py, para x = 0,01.
A igualdade acima s possvel se a = 0 e b = 0; nesse caso, c = 1/3. Esse o valor
correto! De fato, a expanso em srie de Taylor da soluo analtica em torno de x = 0
d
x2 x4 x6
sen(x)/x cos(x) =

+
...
3
30 840
Esse resultado nos informa que, prximo da origem, y(x) se comporta como x 2 /3. Ns
vamos utilizar a notao
x 0 y x 2 /3
(2.19)
para indicar esse fato.
Na verdade, (2.19), obtida sem recurso soluo analtica, suficiente para tratar
numericamente o problema da singularidade na origem. Note que
y(x)
1 x2
= lim
= x/3 = 0;
x0 x
x0 3 x
lim

Vamos ento reescrever a equao de diferenas (2.18) usando o limite:


"
#
y0
y1 = y0 + sen(x 0 )
x = 0.
x0
|
{z
}
=0, lim x 0 0

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


y1 = 0! Vamos ento reescrever o cdigo, que ns agora vamos chamar, claro, de
sucesso.py, que pode ser visto na listagem 2.18
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 2.6
Na verdade, o sucesso estrondoso: com x = 0,01, ns conseguimos produzir uma
soluo numrica que visualmente indistinguvel da soluo analtica. Uma das coisas

Matemtica Aplicada

50

Listagem 2.18: 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_function
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 ()

que o programa sucesso.py calculou foi o erro absoluto relativo mdio



n
X
yi y(xi )



y(xi )
i=1
(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?
A figura 2.7 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!

2.6 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:


yi+1 yi yi + yi+1
xi + xi+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 .

51

2.7 Runge-Kutta
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 2.7: Comparao da soluo analtica da equao (2.14) com a sada de


sucesso.py, para x = 0,5.
Lembrando que x = xi+1 xi ,


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


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


xi + xi+1
2xi+1
2xi
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+1xi+1 yi xi =
sen
,
2
2


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

(2.20)

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


para i = 0 x 0 = 0, y0 = 0, pois os denominadores em (2.20) no contm xi . O
programa que implementa este esquema o sucimp.py, mostrado na listagem 2.19.
O resultado um sucesso mais estrondoso ainda, e pode ser visto na figura 2.8.
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!

2.7 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 (2.20). 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.

52

Matemtica Aplicada

Listagem 2.19: 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_function
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
for i in range (0,n):
# loop na soluo numrica
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
# 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('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

10

20

30

40

50

Figura 2.8: Comparao da soluo analtica da equao (2.14) com a sada de


sucimp.py, para x = 0,5.

53

2.7 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 quando
se trata do mtodo de Runge-Kutta, ou mtodos similares):

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

dx
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
k 1 = hf (xn , yn ),
k 2 = hf (xn + h/2, yn + k 1 /2),
yn+1 = yn + k 2 .
Vamos tentar este mtodo e ver como ele se compara com nossos esforos anteriores.
Vamos manter h = 0,5 como antes. 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
2.20), fica mais simples e fcil de entender, e esta nossa prioridade aqui.
O resultado mostrado na figura 2.9.
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 ordem 2:
k 1 = hf (xn , yn ),
h
k1
k 2 = hf (xn + , yn + ),
2
2
k 3 = hf (xn + h/2, yn + k 2 /2),
k 4 = hf (xn + h, yn + k 3 ),
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 2.21.
O resultado mostrado na figura 2.10.
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.

54

Matemtica Aplicada

Listagem 2.20: euler2 Um mtodo explcito de ordem 2


#!/ 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_function
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 ()

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
31
32
33
34
35
36
37
38
39

0.0

0.5

1.0

1.5

10

20

30

40

50

Figura 2.9: Comparao da soluo analtica da equao (2.14) com a sada de


euler2.py, para x = 0,5.

55

2.7 Runge-Kutta

Listagem 2.21: 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 : iso -8859 -1 -*# ---------------------------------------------------------# rungek4 : resolve a equao diferencial
# dy/dx + y/x = sen(x)
# usando o mtodo de Runge - Kutta de ordem 4
# ---------------------------------------------------------from __future__ import print_function
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')
# imprime o arquivo de sada
for i in range (0,n+1):
fou. write ( '%12.6 f %12.6 f\n' % (x[i],y[i]) )
fou. close ()

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 2.10: Comparao da soluo analtica da equao (2.14) com a sada de


rungek4.py, para x = 0,5.

Exemplo 2.1 Utilizando o mtodo de Runge-Kutta (!), calcule a funo gama



(x )
t x 1 e t dt
0

numericamente para o intervalo x [1, 5].


SOLUO
A varivel independente x entra com um parmetro, no como um dos limites de integrao.
Isto torna as coisas um pouco mais complicadas. Para obter a soluo, vamos primeiro definir a
funo gama incompleta inferior (Abramowitz e Stegun, 1972):
 y
(x , y)
t x 1 e t dt.
(2.21)
0

Toda integrao numrica pode ser convertida na soluo numrica de uma EDO (Press et al.,
1992, p. 129). Por exemplo, no caso acima, a integrao numrica equivalente a
d (x , t)
= t x 1e t ;
dt

(x , 0) = 0.

Se resolvermos a equao diferencial acima, ento teremos, simplesmente,


(x ) = (x , ).
Numericamente, ns vamos substituir por um valor finito porm suficientemente grande.
Para termos uma boa idia do que signfica um valor suficientemente grande, vamos plotar o
integrando t x 1e t para os valores x = 1, x = 2, x = 3, x = 4 e x = 5. Isto mostrado na figura
2.11.
Note que o limite prtico de integrao varia com x . No entanto, por simplicidade, podemos
adotar t = 20 para todos os casos (com um pouco de exagero). Em outras palavras, ns esperamos
que (numericamente) (x ) (x , 20) para 1 x 5.

57

2.7 Runge-Kutta
5

x
x
x
x
x

d (x , t)/dt

=1
=2
=3
=4
=5

0
0

10

12

14

16

18

20

Figura 2.11: O integrando (x , t) para x = 1, . . . , 5.


Um outro ponto importante que relativamente simples provar que
(x ) = (x 1)!

(2.22)

para x N. Portanto, imediato que (1) = 1, (2) = 1, (3) = 2, (4) = 6 e (5) = 24. Isto
significa que possvel testar a soluo numrica para estes valores particulares de x .
Nosso primeiro esforo, portanto, escrever um prottipo para testar alguns ou todos entre
estes valores particulares. Lembremo-nos de que isto feito simplesmente integrando a equao
diferencial (2.1) at 20, com um passo que precisa ser verificado por tentativa e erro.
Nosso primeiro prottipo, muito simples, e denominado intgam0.py, mostrado na listagem 2.22. Note que ns reaproveitamos a rotina rk4 que foi introduzida na listagem 2.21.
Ns observamos, por tentativa e erro, que h = 10 4 um passo suficientemente preciso
para o mtodo de Runge-Kutta, mas que o infinito melhor representado numericamente por
30, e no por 20. Observe tambm na listagem 2.22 que o valor de x definido na fora bruta,
de maneira um pouco deselegante, por meio de uma varivel global dentro do prprio programa.
Para testar x = 1, . . . , 5, ns simplesmente editamos o programa e modificamos o valor de x
com um editor de texto.
O programa definitivo chama-se intgam1.py. Ele mostrado na listagem 2.23. A principal
diferena em relao a intgam0 consiste em um loop externo, implementado por meio de um
while, em que o valor de x , que antes era fixo, incrementado de 0,01 em 0,01. Alm disto, os
valores para cada x so impressos em um arquivo de sada.
O resultado de intgam1.py mostrado na figura 2.12. Na figura, note que a concordncia
(visualmente) perfeita. Algumas observaes importantes so as seguintes:
As figuras deste trabalho foram geradas com o programa de plotagem Gnuplot (www.
gnuplot.info). Como Gnuplot possui uma funo gamma(x) embutida, ela foi utilizada para comparao com os pontos calculados por intgam1.py na figura 2.12.
Apenas 1 a cada 5 pontos gerados est plotado na figura 2.12 para no sobrecarregar a
figura.

Matemtica Aplicada

Listagem 2.22: Primeiro prottipo para o clculo de (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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

#!/ usr/bin/ python


# -*- coding : iso -8859 -1 -*# ---------------------------------------------------------# intgam0 : resolve a integral
#
# \ int_0 ^ infty t^{x -1}e^{-t}\,dt
#
# usando o mtodo de Runge - Kutta de ordem 4
#
# 2012 -02 -14 T20 :45:29
# 2012 -02 -14 T20 :45:40
#
# uso: ./ intgam0 .py
# ---------------------------------------------------------from __future__ import print_function
from __future__ import division
from math import exp
h = 1.0e -4
# passo de integrao
to = 0.0
# t inicial
go = 0.0
# gamma inicial
n = int (30.0/ h)
# nmero de passos at o " infinito "
# ---------------------------------------------------------# define a funo a ser integrada
# ---------------------------------------------------------x = 4.0
def ff(t,g):
return t**(x -1.0)* exp(-t)
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
tn = (i+1)*h
# novo t
gn = rk4(to ,go ,h,ff)
# novo gamma (x,t)
(to ,go) = (tn ,gn)
# o antigo passa a ser o novo
# ---------------------------------------------------------# imprime o resultado final
# ---------------------------------------------------------print ( '%10.6 f %10.6 f' % (tn ,gn) )

58

59

2.7 Runge-Kutta

Listagem 2.23: Programa definitivo para o clculo de (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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

#!/ usr/bin/ python


# -*- coding : iso -8859 -1 -*# ---------------------------------------------------------# intgam1 : resolve a integral
#
# \ int_0 ^ infty t^{x -1}e^{-t}\,dt
#
# usando o mtodo de Runge - Kutta de ordem 4
#
# para x=1 ,1+dx ,... ,5 com dx = 0.01
#
# 2012 -02 -14 T21 :16:09
# 2012 -02 -14 T21 :16:14
#
# uso: ./ intgam1 .py
# ---------------------------------------------------------from __future__ import print_function
from __future__ import division
from math import exp
h = 1.0e -4
# passo de integrao de rk4
dx = 0.01
# passo de variao de x
n = int (30.0/ h)
# nmero de passos at o " infinito "
# ---------------------------------------------------------# define a funo a ser integrada
# ---------------------------------------------------------def ff(t,g):
return t**(x -1.0)* exp(-t)
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
fou = open('intgam1 .dat ','wt')
# abre o arquivo de sada
x = 1.0
while (x <= 5.0) :
to = 0.0
# t inicial
go = 0.0
# gamma inicial
for i in range (0,n):
# loop da soluo numrica
tn = (i+1)*h
# novo t
gn = rk4(to ,go ,h,ff)
# novo gamma (x,t)
(to ,go) = (tn ,gn)
# o antigo passa a ser o novo
# ---------------------------------------------------------# imprime o resultado no arquivo de sada
# ---------------------------------------------------------print(x,go)
# imprime x na tela
fou. write ( '%10.6 f %10.6 f\n' % (x,gn) )
x += dx
fou. close ()

60

Matemtica Aplicada
25

(x) intgama1.py
(x ) Gnuplot

20

(x )

15

10

Figura 2.12: Clculo de (x) com o mtodo de Runge-Kutta: sada de intgam1 comparada com a funo (x ) do programa de plotagem (Gnuplot)
Exerccios Propostos
2.11 Resolva, usando o mtodo de Euler e o Mtodo de Runge-Kutta de ordem 4:
dy
+ xy = sen(x),
dx

y(0) = 0.

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

y(0) = 1.



dy y
2x
+ = sen
,
dx x
L

y(0) = 0,

2.13 Na equao

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


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

y(x ) = 0.

2.15 Resolva, utilizando Runge-Kutta:


dy
+ y = sen(x ),
dx

y(0) = 1.

61

2.8 O mtodo de Runge-Kutta multidimensional

2.8 O mtodo de Runge-Kutta multidimensional


Vamos, na sequncia, generalizar o mtodo de Runge-Kutta para que ele seja capaz
de resolver sistemas de equaes diferenciais ordinrias do tipo
dy
= f (x , y).
dx
Note que y e f so vetores, enquanto que x permanece sendo um escalar.
A base para a soluo de sistemas de equaes diferenciais ordinrias com o mtodo
de Runge-Kutta muito simples: basta reconhecer que as equaes tambm funcionam vetorialmente! De fato, podemos escrever
k 1 = f (xn , y n ),
1
h
k 2 = h f (xn + , y n + k 1 ),
2
2
h
1
k 3 = h f (xn + , y n + k 2 ),
2
2
k 4 = h f (xn + h, y n + k 3 ),
1
1
1
1
y n+1 = y n + k 1 + k 2 + k 3 + k 4 .
6
3
3
6
As questes fundamentais que ns teremos aqui do ponto de vista de implementao
computacional do mtodo de Runge-Kutta multidimensional so como:
Representar um vetor computacionalmente.
Multiplicar um vetor por um escalar.
Somar dois vetores.
A primeira idia que vem cabea representar um vetor em Python por uma lista;
assim, por exemplo, o vetor (1, 1) seria representado pela lista [1,-1]. preciso
lidar com o fato de que em geral ns escrevemos para as componentes de um vetor em
matemtica:
u = (u 1 , u 2 , u 3 )
(os subscritos comeam em 1), enquanto que os elementos de uma lista u em Python so
u[0], u[1], e u[2].
Vamos tentar ento utilizar listas, no programa tentalista.py, mostrado na listagem 2.24.
O resultado de rodar tentalista.py
ww =
kk =

[1, 2, 3, 4]
[1, 2, 1, 2, 1, 2]

Que no o que espervamos! O operador + aplicado a listas no soma componente a componente, mas sim concatena as duas listas; e o produto por 3 no multiplica
componente a componente, mas sim repete a lista 3 vezes.
Felizmente, existe uma maneira de se obter o comportamento esperado mas no
com listas. Um mdulo extra-Python (que tem que ser instalado separadamente), denominado numpy, faz a mgica. A principal contribuio de numpy que ele prov um
novo tipo chamado array, que se comporta como um vetor. Vamos v-lo em ao no
prximo programa, tentaarray.py mostrado na listagem 2.25, cujo resultado

62

Matemtica Aplicada

Listagem 2.24: Listas em Python


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

#!/ usr/bin/ python


# -*- coding : iso -8859 -1 -*# ---------------------------------------------------------# tentalista : tenta manipular uma lista como se ela fosse
# um vetor matemtico .
# ---------------------------------------------------------from __future__ import print_function
uu = [1 ,2]
# lista com dois elementos
vv = [3 ,4]
# outra lista com dois elementos
ww = uu + vv
# soma para ver no que d
kk = 3* uu
# multiplica pelo escalar 3 para ver no
# que d
print('ww = ', ww) ;
print('kk = ',kk) ;

Listagem 2.25: tentaarray.py: arrays com Numpy


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

#!/ usr/bin/ python


# -*- coding : iso -8859 -1 -*# ---------------------------------------------------------# tentaarray : usa arrays , em vez de listas
# ---------------------------------------------------------from __future__ import print_function
from numpy import array
uu = array ([1 ,2])
# lista com dois elementos
vv = array ([3 ,4])
# outra lista com dois elementos
ww = uu + vv
# soma para ver no que d
kk = 3* uu
# multiplica pelo escalar 3 para ver no
# que d
print('ww = ', ww) ;
print('kk = ',kk) ;

63

2.8 O mtodo de Runge-Kutta multidimensional


30.0

delta x = 0.5
u1(x) (num)
u1(x) (ana)
u2(x) (num)
u2(x) (ana)

25.0

u(x )

20.0

15.0

10.0

5.0

0.0
0.0

0.5

1.0

1.5

2.0

2.5

3.0

3.5

4.0

Figura 2.13: Soluo numrica pelo Mtodo de Runge-Kutta de um sistema de 2 equaes


diferenciais ordinrias

ww =
kk =

[4 6]
[3 6]

Como podemos ver, agora as coisas funcionam.


Para usar numpy, claro, voc tem que baixar o pacote, e ler o manual: procure em
http://numpy.scipy.org.
Vamos agora resolver um caso para o qual possumos soluo analtica. Dado o
sistema
du 1
= u2 ,
dx
du 2
= u1 ,
dx
a sua soluo
u 1 (x) = k 1 ex + k 2 ex ,
u 2 (x) = k 1 ex + k 2 ex .
O programa que resolve este sistema o rungek4v.py mostrado na listagem 2.26; o
mais interessante, e um dos pontos fortes de Python, que a rotina rk4 segue inalterada:
observe que ela capaz de receber como entrada um array (y), assim como uma funo
que agora devolve arrays (ff), e que ela prpria agora devolve um array.
Com um h = 0.1, os erros relativos mdios de u 1 e u 2 so extremamente pequenos:
= 0.000004 em ambos os casos. Graficamente, temos a resultado mostrado na figura
2.13. Note que cosh x sinh x para x & 2,5.

64

Matemtica Aplicada

Listagem 2.26: rungek4v.py: o mtodo de Runge-Kutta multidimensional


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

#!/ usr/bin/ python


# -*- coding : iso -8859 -1 -*# ---------------------------------------------------------# rungek4v : resolve as equaes diferenciais
#
# du1/dx = u2 ,
# du2/dx = u1 ,
#
# usando o mtodo de Runge - Kutta de ordem 4
# ---------------------------------------------------------from __future__ import print_function
from numpy import array
h = 0.1
# passo em x
x = [0.0]
# x inicial
y = [ array ([1.0 ,0.0])]
# y inicial
n = int (10/h)
# nmero de passos
from math import sinh , cosh
def ff(x,y):
return array ([y[1] ,y [0]])
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)
erro0 = 0.0
# calcula o erro relativo mdio
erro1 = 0.0
for i in range (1,n+1):
yana0 = cosh(x[i])
yana1 = sinh(x[i])
erro0 += abs( (y[i][0] - yana0 )/ yana0 )
erro1 += abs( (y[i][1] - yana1 )/ yana1 )
erro0 /= n
erro1 /= n
print ( 'erro relativo mdio = ', '%10.6 f %10.6 f' % (erro0 , erro1 ) )
fou = open('rungek4v .out ','wt')
for i in range (0,n+1):
# imprime o arquivo de sada
fou. write ( '%12.6 f %12.6 f %12.6 f\n' % (x[i],y[i][0] ,y[i ][1]) )
fou. close ()

h(x , t)
x

Figura 2.14: Drenagem de um macio poroso semi-infinito inicialmente totalmente saturado.

65

2.9 Soluo numrica de um problema no-linear

2.9 Soluo numrica de um problema no-linear


Considere a soluo da equao diferencial parcial no-linear de Boussinesq
"
#
h
h ks
=
h
(2.23)
t
f x x
em um aqufero semi-infinito mostrado na figura 2.14, 0 x < e para t 0, com
condies inicial e de contorno
h(x , 0) = h 0 ,
h(0, t) = 0,
h(, t) = h 0 .

(2.24)
(2.25)
(2.26)

Em (2.23), ks a condutividade hidrulica saturada, e f a porosidade drenvel (Brutsaert, 2005).


O problema consiste em obter a evoluo da superfcie fretica h(x , t) a partir da
condio inicial (2.24); a condio de contorno (2.25) estabelece que existe um canal
drenando o macio poroso cujo nvel o mesmo da camada impermevel em z = 0, e a
condio de contorno (2.26) simplesmente estabelece que as dimenses do aqufero em
x so infinitas.
Primeiramente, procuramos adimensionalizar a equao. As grandezas disponveis
so h 0 , ks e f , sendo esta ltima adimensional. Comeamos com
h(x , t) (x , t)h 0 ,

(2.27)

onde ~ = 1; ento, (2.23) torna-se


"
#
h 0
ks
=
h0
,
h0
t
f x
x
"
#
ks h 0

,
t
f x
x
"
#

=D

,
t
x
x
onde
D=

ks h 0
f

(2.28)

(2.29)

uma difusividade (L2 T1 ) hidrulica. As condies inicial e de contorno em (x , t)


agora so
(x , 0) = 1,
(0, t) = 0,
(, t) = 1.

(2.30)
(2.31)
(2.32)

A existncia de duas condies idnticas a marca registrada do mtodo de similaridade


denominado mtodo da transformao de Boltzmann. Neste mtodo, ns fazemos
(x , t) = ( ),

(2.33)

66

Matemtica Aplicada
onde

x
=
.
(2.34)
4Dt
O fator 4 apenas para tornar a soluo um pouco mais elegante algebricamente, e
no deve preocupar. Substituindo (2.33) em (2.28), ns inicialmente calculamos todas as
derivadas parciais separadamente:
!#
"
x

=

t
t
4Dt
d
=
d t
x D d
;
=
4(Dt)3/2 d
d
1 d
=
=
;
x
d x
4Dt d
d
1
d
=
=

;
x
d x
4Dt d
"
#
"
#
d

1 d

,
x
x
d x
4Dt d
"
#
d
1 d
=

.
4Dt d
d
Em seguida, substituindo as derivadas parciais em (2.28), ns obtemos
"
#
d
x D d
D d

=
4Dt d
d
4(Dt)3/2 d
"
#
d
D
D d
2x d

4Dt (4Dt)1/2 d
4Dt d
d
"
#
d
D
2x d
D d

4Dt (4Dt)1/2 d
4Dt d
d
"
#
d
d
d

+ 2
= 0.
d
d
d

(2.35)

(2.35) uma EDO no-linear de ordem 2, de coeficientes no-constantes. A sua soluo


demanda 2 condies de contorno em ou em sua derivada. As condies (2.30)(2.32)
traduzem-se, por meio de (2.34), em
(x , 0) = 1
(0, t) = 0
(, t) = 1

() = 1,
(0) = 0,
() = 1.

(2.36)
(2.37)
(2.38)

Portanto, existem apenas duas condies de contorno independentes, (2.37) e (2.38).


Podemos agora transformar (2.35) em um sistema de EDOs de ordem 1:
d

,
d
d
= ,
(2.39)
d

= 2
(2.40)
d

67

2.10 Poluio orgnica em rios

com condies iniciais


(0) = 0,
(0) = 0 ,

(2.41)
(2.42)

onde o valor de 0 tem que ser encontrado por tentativa e erro de tal modo que () = 1.
O problema que o sistema (2.39)(2.40) no pode ser implementado diretamente no
esquema de Runge-Kutta de 4a ordem, porque a condio inicial (2.41) produz uma singularidade (tente!). Em vez disto, ns precisamos pular sobre a singularidade. Como
vimos na seo 2.6, mtodos implcitos podem resolver o problema de singularidades na
condio inicial ao calcular a funo e suas derivadas utilizando os pontos em i e i + 1.
Para o primeiro passo entre = 0 e = , portanto, ns discretizamos (2.39)(2.40)
como
1 0 1 + 0
=
,

1 + 0
1 0
1 + 0
= 2
.

2 1 + 0

(2.43)
(2.44)

Note que o valor de foi tomado em (0 + 1 )/2 = /2. Substituindo 0 = 0 e simplificando, obtemos o sistema de equaes
1 + 2
1 = 0
,
1 2
p
1 = (1 + 0 ) ,

(2.45)
(2.46)

que pode ser resolvido iterativamente a partir de uma estimativa inicial trivial 1 = 0 .
A partir do valor correto de 0 , obtido por tentativa p
e erro para que () = 1, o sistema
converge muito rapidamente para um erro global (1 0 )2 + (1 0 )2 < : para
= 1.0 1014 , bastam 3 iteraes. Os novos valores iniciais 1 e 1 podem ento ser
utilizados para marchar com passo em um esquema de Runge-Kutta. O resultado da
integrao numrica est mostrado na figura 2.15

2.10 Poluio orgnica em rios


Uma equao muito mal usada, e pessimamente compreendida,
Q =UA

(2.47)

onde Q a vazo, U a velocidade mdia, e A a seo transversal de um rio. Outra equao muito mal compreendida a equao de transporte de um poluente cuja
concentrao C em um rio:
C
C
2C
+U
= E 2 kC
t
x
x

(2.48)

De qualquer forma, vamos us-las! E o coeficiente de disperso longitudinal do rio; e k


um coeficiente de decaimento de 1a ordem.
A degradao geral de matria orgnica na gua tem a forma geral (Schnoor, 1996)
bactrias

CH2 O + O2 CO2 + H2 O.

68

Matemtica Aplicada
1.2

()
()

1.0

0.8
0.6
0.4
0.2
0.0
0

Figura 2.15: Resultado da integrao numrica do problema de Boussinesq para um


aqufero semi-infinito
Em Schnoor (1996), ns encontramos as concentraes consideradas aceitveis de O2 na
gua: pelo menos 4 mg L1 , e 5 mg L1 na maior parte do tempo o que quer que isto
signifique!
A equao de Streeter-Phelps , na verdade, a soluo de um problema acoplado. A
primeira hiptese a de um problema permanente: /t = 0 para todos os participantes.
Os participantes, por sua vez, so o oxignio dissolvido na gua, com concentrao
C, e a demanda bioqumica de oxignio (DBO) L, ambos expresssos em concentrao
volumtrica, em geral mg L1 . Alm disto, o modelo de Streeter-Phelps desconsidera os
efeitos de disperso longitudinal: E = 0. Para a DBO,
U

dL
= kd L,
dx

(2.49)

onde kd a taxa de decaimento de oxignio de 1a ordem. Para a concentrao de oxignio dissolvido,


dC
U
= kd L + ka (Cs C),
(2.50)
dx
onde Cs a concentrao de saturao do oxignio, e ka a constante de reaerao de
ordem 1.
Juntas, as equaes (2.49) e (2.50) formam um sistema de 2 equaes diferenciais de
ordem 1. Tradicionalmente, conveniente introduzir o deficit de oxignio dissolvido
D = Cs C

(2.51)

dD
dC
= ,
dx
dx

(2.52)

donde, para Cs = cte,

69

2.10 Poluio orgnica em rios

e (2.50) pode ser traduzida para


dD
= kd L + ka D
dx
dD
U
= kd L ka D.
dx
Na prtica, possvel desacoplar o sistema; de fato, (2.49) no depende de D, e tem
soluo (para L(x = 0) = L 0 )
U

kd

L = L 0 e U x .

(2.53)

A equao para o deficit de oxignio dissolvido transformou-se agora em uma equao diferencial de ordem 1, no-homognea:
dD ka
kd L 0 k d x
+ D=
e U ,
(2.54)
dx U
U
cuja condio inicial D(x = 0) = D 0 . Para resolver com Maxima, conveniente fazer
ka
,
U
kd L 0
B=
,
U
kd
C= .
U
A=

Ento,
(% i1) 'diff(D,x) + A*D = B*exp(-C*x) ;
dD
- x C
(% o1)
-- + A D = B %e
dx
(% i2) ode2 (%o1 ,D,x) ;
x A - x C
- x A B %e
(% o2)
D = %e
(------------- + %c)
A - C

Ou seja:
D =e

kUa x

k L ka kd

d 0 e U x

U
+ c ,
ka kd
U

D =e

kUa x

!
kd L 0 ka kd x
U
e
+c .
k a kd

Devemos escolher c para que D = D 0 em x = 0:


!
kd L 0
D0 =
+c ,
k a kd
kd L 0
c = D0
.
k a kd
Ento,
kd L 0 ka kd x
kd L 0
D =e
e U
+ D0
k a kd
k a kd


kd
ka
ka
kd L 0
= D 0e U x +
e U x e U x
k a kd
kUa x

70

Matemtica Aplicada
10.0

L(x)
D(x)

L, D (mg L 1 )

8.0

6.0

4.0

2.0

0.0
0

100000

200000

300000

400000

500000

x(m)

Figura 2.16: Soluo numrica do modelo de Streeter-Phelps com o mtodo de RungeKutta.


Agora, possvel encontrar o ponto xc em que o deficit mnimo:
"
!#
k a kd D 0
U
ka
1
xc =
ln
.
k a kd
kd
kd L 0

(2.55)

A conta um pouco longa; faa-a!


Considere agora o exemplo, razoavelmente realista:
ka = 1,5 dia1 = 1,5 (86400 s)1 = 1,736 105 s1 ;
kd = 0,5 dia1 = 5,787 106 s1 ,
U = 1 m s1 ,
L 0 = 10 mg L1 ,
D 0 = 0 mg L1 .
Com este exemplo, ns podemos resolver Streeter-Phelps numericamente, com RungeKutta, utilizando o programa street.py mostrado na listagem 2.27. O resultado
mostrado na figura 2.16. Se voc est achando algo estranho, no ache! O modelo
de Streeter-Phelps prev que demora quase 100 km para que a DBO caia de 10 para
6 mg L1 , e que o deficit de OD chega a quase 2 mg L1 neste ponto.

71

2.10 Poluio orgnica em rios

Listagem 2.27: Soluo numrica do modelo de Streeter-Phelps com o mtodo de RungeKutta.


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

#!/ usr/bin/ python


# -*- coding : iso -8859 -1 -*# ---------------------------------------------------------# street .py: soluo numrica do problema de Streeter - Phelps
#
# usando o mtodo de Runge - Kutta de ordem 4
# ---------------------------------------------------------from __future__ import print_function
from numpy import array
# ---------------------------------------------------------# parmetros do problema
# ---------------------------------------------------------h = 1000
# passo em x (100 m)
x = [0.0]
# x inicial
y = [ array ([10.0 ,0.0])]
# L0 = 10 mg/L, D0 = 0 mg/L
n = int (500000/ h)
# nmero de passos (50 km)
# ---------------------------------------------------------# dados do rio:
# ---------------------------------------------------------U = 1.0
ka = 1.736e -5
kd = 5.787e -6
L0 = 10.0
D0 = 0.0
def ff(x,y):
dLdx = -(kd/U)*y[0]
dDdx = (kd/U)*y[0] - (ka/U)*y[1]
return array ([ dLdx ,dDdx ])
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)
fou = open('street .out ','wt')
for i in range (0,n+1):
# imprime o arquivo de sada
fou. write ( '%12.6 f %12.6 f %12.6 f\n' % (x[i],y[i][0] ,y[i ][1]) )
fou. close ()

Matemtica Aplicada

72

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

u(x , 0) = (x).

(3.1)

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


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

(3.2)

Seja ento o problema


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

(3.3)
(3.4)

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

0.50

0.00

0
0

10

Figura 3.1: Condio inicial da equao 3.3.


73

tempo

u(x, t)

74

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

(3.5)
(3.6)
(3.7)

x = L/Nx ,
t = T /Nt

(3.8)
(3.9)

com

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 (3.3) fazer

uin+1 uin
u
=
+ O(t),
t i,n
t

n
un ui1
u
= i+1
+ O(x 2 ).
x i,n
2x

(3.10)
(3.11)

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


n un !
uin+1 uin
ui+1
i1
= c
,
t
2x
ct n
n
uin+1 = uin
(ui+1 ui1
),
(3.12)
2x
(com c = 2 no nosso caso). Esse 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 3.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 3.2. O nico trabalho
deste programa selecionar algumas linhas da sada de onda1d-ins.py; no caso, ns
o rodamos com o comando


surf1d-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 3.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 3.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!

75

3.1 Adveco pura: a onda cinemtica

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


instvel
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

#!/ 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_function
from __future__ import division
fou = open('onda1d -ins.dat ','wb')
dx = 0.01
dt = 0.0005
print('# dx = %9.4f' % dx)
print('# dy = %9.4f' % 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 = %9d' % nx)
print('# nt = %9d' % 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
for i in range (1,nx ):
# loop no espao
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 ()

Matemtica Aplicada

76

Listagem 3.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_function
from __future__ import division
from sys import argv
dx = 0.01
dt = 0.0005
print('# dx = %9.4f' % dx)
print('# dy = %9.4f' % dt)
nx = int (10.0/ dx)
# nmero de pontos em x
print('# nx = %9d' % nx)
m = int(argv [1])
# m sadas
n = int(argv [2])
# a cada n intervalos de tempo
print('# m = %9d' % m)
print('# n = %9d' % 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 ()

77

3.1 Adveco pura: a onda cinemtica


0.500

0.250

0.50

tempo de simulao

u(x , t)

0.375

0.125

0.00

0.000
0

10

Figura 3.2: Soluo numrica produzida por onda1d-ins.py, para t = 250t, 500t e
750t.
Por que o esquema utilizado em (3.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, (3.12) jamais ser calculada com preciso infinita. O que o
computador realmente calcula um valor truncado uin . Por enquanto, ns s vamos fazer
essa distino de notao, entre u e u, aqui, onde ela importa. O erro de truncamento
in uin uin .

(3.13)

Note que (3.12) se aplica tanto para u quanto para u;


subtraindo as equaes resultantes
n+1
n+1
para ui e ui , obtm-se a mesma equao para a evoluo de in :
in+1 = in

Co n
n
( i1
),
2 i+1

(3.14)

onde

ct
(3.15)
x
o nmero de Courant. Isso s foi possvel porque (3.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 in , na forma
Co

tn = nt ,
xi = ix ,
in

N /2
X
l=1

l eatn eikl xi ,

(3.16)

78

Matemtica Aplicada

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.
Argumentando novamente com a linearidade, desta vez de (3.14), ela vale para cada
modo l de (3.16), donde
l ea(tn +t) eikl ix = l eatn eikl ix


Co  atn ikl (i+1)x
l e e
l eatn eikl (i1)x ;
2

(3.17)

eliminando o fator comum l eatn +ikl ix ,



Co  +ikl x
e
eikl x
2
= 1 iCo sen kl x .

eat = 1

(3.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 iCo sen kl x;
et [cos(t) i sen(t)] = 1 iCo sen kl x;
e t cos(t) = 1,

(3.19)

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

(3.20)

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 , 0, donde e t > 1 via (3.19), e o esquema de diferenas finitas incondicionalmente instvel.
O mtodo de Lax Uma alternativa que produz um esquema estvel o mtodo de
Lax:
1 n
n
n
n 
uin+1 =
(ui+1 + ui1
) Co(ui+1
ui1
) .
(3.21)
2
Agora que ns j sabemos que esquemas numricos podem ser instveis, devemos
fazer uma anlise de estabilidade antes de tentar implementar (3.21) numericamente.
Vamos a isto: utilizando novamente (3.16) e substituindo em (3.21), temos

1 h atn ikl (i+1)x
l e e
+ l eatn eikl (i1)x
2 
i
Co l eatn eikl (i+1)x l eatn eikl (i1)x ;


i
1 h +ikl x
=
e
+ eikl x Co e+ikl x eikl x ;
2
= cos(kl x) iCo sen(kl x )

l ea(tn +t) eikl ix =

eat
eat

(3.22)

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,
(3.23)

79

3.1 Adveco pura: a onda cinemtica

que o critrio de estabilidade de Courant-Friedrichs-Lewy.


A mgica de (3.21) que ela introduz um pouco de difuso numrica; de fato,
podemos reescrev-la na forma
n
n
un ui1
un 2uin + ui1
uin+1 uin
= c i+1
+ i+1
t
2x
! 2t
n un
n 2un + un
2
ui+1
x ui+1
i1
i1
i
= c
+
.
2
2x
2t
x

(3.24)

No custa repetir: (3.24) idntica a (3.21). Porm, comparando-a com (3.12) (nosso
esquema instvel inicialmente empregado),
ns

 vemos que ela tambm equivalente a
2
n 2un + un )/x 2 . O que este termo
esta ltima, com o termo adicional x /2t (ui+1
i1
i
adicional significa? A resposta uma derivada numrica de ordem 2. De fato, considere
as expanses em srie de Taylor

ui+1
ui1



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


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

e some:
ui+1 + ui1

d 2u

dx 2 i


d 2u 2
= 2ui + 2 x + O(x 2 ),
dx i
ui+1 2ui + ui1
+ O(x 2 ).
=
x 2

(3.25)

Portanto, a equao (3.24) ou seja: o esquema de Lax (3.21) pode ser interpretada
tambm como uma soluo aproximada da equao de adveco-difuso
u
2u
u
+c
= D 2,
t
c
x
com
!
x 2
D=
.
2t
Note que D tem dimenses de difusividade: ~D = 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

80

Matemtica Aplicada
verificar se
2

u
D x
2
u
c x
D xu 2

 1,

u  1,
c x
D
 c,
x
x 2
 c,
2tx
ct
1
= Co 
x
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 (3.21).
Mesmo assim, vamos program-lo! O programa onda1d-lax.py est mostrado na
listagem 3.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 lido pelo prximo
programa na sequncia, surf1d-lax.py, mostrado na listagem 3.4. O nico trabalho
deste programa selecionar algumas linhas da sada de onda1d-lax.py; no caso, ns
o rodamos com o comando


surf1d-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 3.3. Observe que agora no h oscilaes esprias: o esquema estvel no tempo.
No entanto, a soluo est agora amortecida pela difuso numrica!
Upwind Um esquema que conhecido na literatura como indicado por representar
melhor o termo advectivo em (3.1) o esquema de diferenas regressivas; neste esquema,
chamado de esquema upwind literalmente, corrente acima na literatura de lngua
inglesa, a discretizao utilizada
n
uin ui1
uin+1 uin
= c
,
t
x

n 
uin+1 = uin Co uin ui1
.

(3.26)

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:

81

3.1 Adveco pura: a onda cinemtica

Listagem 3.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_function
from __future__ import division
fou = open('onda1d -lax.dat ','wb')
dx = 0.01
dt = 0.0005
print('# dx = %9.4f' % dx)
print('# dy = %9.4f' % 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 = %9d' % nx)
print('# nt = %9d' % 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 ()

Matemtica Aplicada

82

Listagem 3.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_function
from __future__ import division
from sys import argv
dx = 0.01
dt = 0.0005
print('# dx = %9.4f' % dx)
print('# dy = %9.4f' % dt)
nx = int (10.0/ dx)
# nmero de pontos em x
print('# nx = %9d' % nx)
m = int(argv [1])
# m sadas
n = int(argv [2])
# a cada n intervalos de tempo
print('# m = %9d' % m)
print('# n = %9d' % 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 "
# 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 -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 ()

83

3.1 Adveco pura: a onda cinemtica


1.000

0.500

0.50

tempo de simulao

u(x , t)

0.750

0.250

0.00

0.000
0

10

Figura 3.3: Soluo numrica produzida por onda1d-lax.py, para t = 500t, 1000t e
1500t.

h
i
l ea(tn +t) eikl ix = l eatn eikl ix Co l eatn eikl ix l eatn eikl (i1)x
h
i
eat eikl ix = eikl ix Co eikl ix eikl (i1)x
h
i
eat = 1 Co 1 eikl x
eat = 1 Co + Co cos(kl x) iCo sen(kl x).

(3.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 + (Co2Ck2 + Co2 + 1) + 2(Co2Ck + CoCk Co)
= Co2 (Sk2 + Ck2 + 1 2Ck ) + 2Co(Ck 1) + 1
= 2Co2 (1 Ck ) + 2Co(Ck 1) + 1.
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

84

Matemtica Aplicada
1.000

0.500

0.50

tempo de simulao

u(x , t)

0.750

0.250

0.00

0.000
0

10

Figura 3.4: Soluo numrica produzida pelo esquema upwind, para t = 500t, 1000t e
1500t.
Reencontramos, portanto, a condio (3.23), mas em um outro esquema de diferenas
finitas. A lio no deve ser mal interpretada: longe de supor que (3.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 3.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 tambm est ocorrendo, embora em grau muito menor.
Exerccios Propostos
3.1 Escreva o programa onda1d-upw e surfa1d-upw, que implementam o esquema upwind.
Reproduza a figura 3.4.
3.2 Calcule a difusividade numrica introduzida pelo esquema upwind.

3.2 Difuso pura


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

(3.28)

u(x , 0) = f (x)
u(0, t) = u(L, t) = 0.

(3.29)
(3.30)

com condies iniciais e de contorno

85

3.2 Difuso pura

Esta soluo
u(x , t) =

An e

n2 2 2
t
L2

sen

n=1

2
An =
L


0

f (x) sen

nx
,
L

nx
dx .
L

(3.31)
(3.32)

Em particular, se
D = 2,
L = 1,
f (x) = 2x(1 x),
 1
An = 2
2x(1 x) sen(nx) dx =
0

8
3n 3

[1 (1)n ] .

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


A 2n+1 =
u(x , t) =

16
,
+ 1)3

3 (2n

X
n=0

2 2
16
e(2(2n+1) )t sen ((2n + 1)x)
3
+ 1)

3 (2n

(3.33)

O programa difusao1d-ana.py, mostrado na listagem 3.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 3.6, seleciona alguns instantes de tempo da soluo analtica para
visualizao:


divisao1d-ana.py 3 100 .
A figura 3.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 (3.28) seja
n
un 2uin + ui1
uin+1 uin
= D i+1
.
t
x 2

(3.34)

A derivada parcial em relao ao tempo de O(t), enquanto que a derivada segunda


parcial em relao ao espao , como vimos em (3.25), de O(x 2 ). Mas no nos preocupemos muito, ainda, com a acurcia do esquema numrico. Nossa primeira preocupao,
como voc j sabe, outra: o esquema (3.34) estvel?
Explicitamos uin+1 em (3.34):
 n
n 
uin+1 = uin + Fo ui+1
2uin + ui1
,
onde
Fo =

Dt
x 2

(3.35)
(3.36)

Matemtica Aplicada

Listagem 3.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) = 2x(1-x)
# u(0,t) = 0
# u(1,t) = 0
#
# uso: ./ difusao1d -ana.py
# ---------------------------------------------------------from __future__ import print_function
from __future__ import division
fou = open('difusao1d -ana.dat ','wb')
dx = 0.001
dt = 0.0005
print('# dx = %9.4f' % dx)
print('# dy = %9.4f' % dt)
nx = int (1.0/ dx)
# nmero de pontos em x
nt = int (1.0/ dt)
# nmero de pontos em t
print('# nx = %9d' % nx)
print('# nt = %9d' % nt)
from math import pi , sin , exp
epsilon = 1.0e -6
# preciso da soluo analtica
dpiq = 2* pi*pi
# 2pi ^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
# (2n+1)
dnm1q = dnm1*dnm1
# (2n +1)^2
dnm1c = dnm1q *dnm1
# (2n +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 ()

86

87

3.2 Difuso pura

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


analtica para visualizao
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 -*# ---------------------------------------------------------# 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_function
from __future__ import division
from sys import argv
dx = 0.001
dt = 0.0005
print('# dx = %9.4f' % dx)
print('# dt = %9.4f' % dt)
nx = int (1.0/ dx)
# nmero de pontos em x
print('# nx = %9d' % nx)
m = int(argv [1])
# m sadas
n = int(argv [2])
# a cada n intervalos de tempo
print('# m = %9d' % m)
print('# n = %9d' % 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 "
# 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 = '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 ()

88

Matemtica Aplicada
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

0.2

0.4

0.6

0.8

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


t = 0,15.
o nmero de Fourier de grade (El-Kadi e Ling, 1993). A anlise de estabiliade de von
Neumann agora produz
l ea(tn +t) eikl ix = l eatn eikl ix +
h
i
Fo l eatn eikl (i+1)x 2l eatn eikl ix + l eatn eikl (i1)x ,
h
i
eat = 1 + Fo e+ikl x 2 + eikl x
= 1 + 2Fo [cos(kl x) 1]
!
2 kl x
= 1 4Fo sen
2

(3.37)

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


!
!
at 2
2 kl x
2
4 kl x
|e | = 1 8Fo sen
+ 16Fo sen
<1
2
2
ou
!
!
kl x
2
4 kl x
8Fo sen
+ 16Fo sen
< 0,
2
2
!"
!#
2 kl x
2 kl x
8Fo sen
1 + 2Fo sen
< 0,
2
2
1
Fo < .
2
2

(3.38)

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

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

89

3.2 Difuso pura

Listagem 3.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_function
from __future__ import division
fou = open('difusao1d -exp.dat ','wb')
dx = 0.01
dt = 0.00001
print('# dx = %9.4f' % dx)
print('# dy = %9.4f' % 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 = %9d' % nx)
print('# nt = %9d' % nt)
u = zeros ((2 , nx +1) , float )
# apenas 2 posies no tempo
# so necessrias !
# define a condio inicial
def CI(x):
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
# 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 ()

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 3.7.
O programa divisao1d-exp.py, mostrado na listagem 3.8, seleciona alguns
instantes de tempo da soluo analtica para visualizao:


divisao1d-exp 3 5000 .

Matemtica Aplicada

90

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


analtica para visualizao
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 -*# ---------------------------------------------------------# 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_function
from __future__ import division
from sys import argv
dx = 0.01
dt = 0.00001
print('# dx = %9.4f' % dx)
print('# dt = %9.4f' % 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 = %9d' % nx)
m = int(argv [1])
# m sadas
n = int(argv [2])
# a cada n intervalos de tempo
print('# m = %9d' % m)
print('# n = %9d' % 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 ()

91

3.2 Difuso pura


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

0.2

0.4

0.6

0.8

Figura 3.6: Soluo numrica com o mtodo explcito (3.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.
O resultado da soluo numrica com o mtodo explcito est mostrado na figura
3.6: ele impressionantemente bom, embora seja computacionalmente muito caro. A
escolha judiciosa de t e x para obeder ao critrio (3.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.
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, isso 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 disso, 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:
n+1 2un+1 + un+1
ui+1
uin+1 uin
i
i1
=D
,
t
x 2
n+1
n+1
),
2uin+1 + ui1
uin+1 uin = Fo(ui+1
n+1
n+1
Foui1
+ (1 + 2Fo)uin+1 Foui+1
= uin .

(3.39)

Reveja a discretizao (3.5)(3.9): para i = 1, . . . , Nx 1, (3.39) acopla 3 valores das


incgnitas un+1 no instante n + 1. Quando i = 0, e quando i = Nx , no podemos utilizar
(3.39), porque no existem os ndices i = 1, e i = Nx + 1. Quando i = 1 e i = Nx 1,

92

Matemtica Aplicada

(3.39) precisa ser modificada, para a introduo das condies de contorno: como un0 = 0
e unNx = 0 para qualquer n, teremos
n+1
(1 + 2Fo)un+1
= un1 ,
1 Fou 2

Foun+1
N x 2

+ (1 +

2Fo)un+1
N x 1

= unNx 1 .

(3.40)
(3.41)

n+1
n+1
Em resumo, nossas incgnitas so un+1
1 , u 2 , . . . u N x 1 (Nx 1 incgnitas), e seu clculo
envolve a soluo do sistema de equaes

0 ...
0
0
1 + 2Fo Fo

Fo 1 + 2Fo Fo
0
...
0

..
...
.

0
...
0 Fo 1 + 2Fo Fo

0
0
... 0
Fo 1 + 2Fo

n+1 n
u 1 u 1
un+1 un
2 2
.. = ..
. .
un+1 un
N x 2
n+1
nNx 2
u Nx 1
u Nx 1

(3.42)

A anlise de estabilidade de von Neumann procede agora da maneira usual:


n+1
n+1
in+1 = in + Fo(i+1
2in+1 + i1
)

l ea(tn +t) eikl ix = l eatn eikl ix



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

+l ea(tn +t) eikl (i1)x ,


eat = 1 + eat Fo eikl x 2 + eikl x ,

"
e

at

1 + 4Fo sin2

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


!
at
at
2 kl x
e = 1 e 4Fo sin
,
2
!#
kl x
= 1,
2
1

 1
|eat | =
sempre.
1 + 4Fo sin2 kl 2x

(3.43)

Portanto, o esquema implcito (3.39) incondicionalmente estvel, e temos confiana


de que o programa correspondente no se instabilizar.
Existem vrias coisas atraentes para um programador em (3.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 tridiag, adaptada para Python da tridag
de Press et al. (1992), que resolve um sistema tridiagonal, mostrado na listagem 3.9.
Em seguida, o programa difusao1d-imp.py resolve o problema com o mtodo implcito. Ele est mostrado na listagem 3.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

93

3.2 Difuso pura

Listagem 3.9: alglin.py Exporta uma rotina que resolve um sistema tridiagonal,
baseada em Press et al. (1992)
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

# -*- coding : iso -8859 -1 -*# -----------------------------------------------------------------------------# alglin .py implementa uma soluo de um sistema linear com matriz tridiagonal
# -----------------------------------------------------------------------------from numpy import zeros
from sys import exit
def tridiag (A,y):
# A,y tm que ser arrays de Numpy !
m = A.shape [0]
# garante que A representa uma
n = A.shape [1]
# matriz tridiagonal
if ( m != 3 ) :
# garante que todos os tamanhos esto OK
exit("Erro na forma de A")
pass
o = y. shape [0]
if ( n != 0 ) :
exit("A e y no so compatveis ")
pass
x = zeros (n, float )
# vetor de trabalho : vai retornar a soluo
c = zeros (n, float )
# vetor de trabalho : vai ficar por aqui
if A[1 ,0] == 0.0 :
exit("zero na diagonal de A")
pass
bb = A[1 ,0]
x[0] = y[0]/ bb
for j in range (1,n):
c[j] = A[2,j -1]/ bb
bb = A[1,j] - A[0,j]*c[j]
if (bb == 0.0):
exit("A singular ")
pass
x[j] = (y[j] - A[0,j]*x[j -1])/ bb
pass
for j in range (n -2 , -1 , -1):
x[j] -= c[j+1]*x[j+1]
pass
return x
pass

Matemtica Aplicada

94

Listagem 3.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_function
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.4f' % dx)
print('# dy = %9.4f' % 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 = %9d' % nx)
print('# nt = %9d' % 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 1a linha
A[1 ,0:nx -1] = 1.0 + 2* Fon
# preenche a segunda linha
A[2 ,0:nx -2] = -Fon
# preenche o incio da 2a linha
A[2,nx -2] = 0.0
# zera A[2,nx -2]
# -----------------------------------------------------------------------------# importa uma adaptao de tridag de Numerical Recipes para Python
# -----------------------------------------------------------------------------from alglin import tridiag
for n in range (nt ):
# loop no tempo
print(n)
# -----------------------------------------------------------------------------# ateno : calcula apenas os pontos internos de u!
# -----------------------------------------------------------------------------u[new ,1: nx] = tridiag (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.

95

3.2 Difuso pura


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

0.2

0.4

0.6

0.8

Figura 3.7: Soluo numrica com o mtodo implcito (3.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.
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 3.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 (3.28) aproximada, no esquema implcito
(3.39), por um esquema de O(x 2 ). A derivada temporal, por sua vez, apenas de O(t).
Mas possvel consertar isso! A idia substituir (3.39) por
" n
n
n+1 2un+1 + un+1 #
2uin + ui1
ui+1
uin+1 uin D ui+1
i
i1
+
,
=
2
2
t
2
x
x
i
Fo h n
n
n+1
n+1
uin+1 = uin +
ui+1 2uin + ui1
+ ui+1
2uin+1 + ui1
.
(3.44)
2
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
i
Fo  n
Fo h n+1
n+1
n 
i+1 2in+1 + i1
= in +
i+1 2in + i1
,
in+1
2
2

96

Matemtica Aplicada

e substitumos um modo de Fourier:




Fo  ikl (i+1)x
a(tn +t) ikl ix
ikl ix
ikl (i1)x
=
l e
e

e
2e
+e
2


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

 

Fo  ikl x
Fo  ikl x
eat 1
e
2 + eikl x = 1 +
e
2 + eikl x
2
2
at
e [1 Fo (cos(kl x) 1)] = [1 + Fo (cos(kl x ) 1)]
"
!# "
!#
at
2 kl x
2 kl x
e
1 + 2Fo sin
= 1 2Fo sin
2
2


2 kl x
1 2Fo sin
2

.
eat =
1 + 2Fo sin2 kl 2x
fcil notar que |eat | < 1, e o esquema numrico de Crank-Nicholson incondicionalmente estvel. O esquema numrico de Crank-Nicholson similar a (3.39):

Fo n+1
Fo n+1 Fo n
Fo n
ui1 + (1 + Fo)uin+1 ui+1
= ui1 + (1 Fo)uin + ui+1
2
2
2
2

(3.45)

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


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

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

(3.46)
(3.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 3.11.
A grande novidade computacional de difusao1d-ckn.py a linha 56: com os
arrays proporcionados por Numpy, possvel escrever (3.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 isso, 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 (3.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 3.8.
Exemplo 3.1 Dada a equao da difuso unidimensional
u
2u
= D 2,
t
x

0 x L,

97

3.2 Difuso pura

Listagem 3.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_function
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.4f' % dx)
print('# dt = %9.4f' % 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 = %9d' % nx)
print('# nt = %9d' % 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 1a 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 2a linha
A[2,nx -2] = 0.0
# zera A[2,nx -2]
# -----------------------------------------------------------------------------# importa uma adaptao de tridag de Numerical Recipes para Python
# -----------------------------------------------------------------------------from alglin import tridiag
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] = tridiag (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.

98

Matemtica Aplicada
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

0.2

0.4

0.6

0.8

Figura 3.8: Soluo numrica com o mtodo de Crank-Nicholson ( (3.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.

e o esquema de discretizao

x = L/N x ,
xi = ix ,

i = 0, . . . , N x ,

tn = tt ,
uin = u(xi , tn ),
i
uin+1 2uin + uin1
1 h n+1
n
(ui +1 uin+1 ) + (uin+1

u
)
=
D
,
1
i 1
2t
x 2

obtenha o critrio de estabilidade por meio de uma anlise de estabilidade de von Neumann.
SOLUO
Suponha que a equao diferencial se aplique ao erro:

in =

X
l

l eatn eik l i x

99

3.2 Difuso pura

Ento
i
1 h a(tn +t ) ik l (i +1)x
(l e
e
l eatn eik l (i +1)x ) + (l ea(tn +t ) eik l (i 1)x l eatn eik l (i 1)x =
2t
l eatn eik l (i +1)x 2l eatn eik l i x + l eatn eik l (i 1)x
;
D
x 2
i
1 h at ik l (i +1)x
(l e e
l eik l (i +1)x ) + (l eat eik l (i 1)x l eik l (i 1)x =
2t
l eik l (i +1)x 2l eik l i x + l eik l (i 1)x
D
;
x 2
i
1 h at ik l (i +1)x
(e e
eik l (i +1)x ) + ( eat eik l (i 1)x eik l (i 1)x =
2t
eik l (i +1)x 2 eik l i x + eik l (i 1)x
D
;
x 2
h
i
( eat eik l (i +1)x eik l (i +1)x ) + ( eat eik l (i 1)x eik l (i 1)x =
i
2Dt h ik l (i +1)x
ik l i x
ik l (i 1)x
e

2
e
+
e
.
x 2
Segue-se que
h
i
h
i
eat eik l (i +1)x + eik l (i 1)x = eik l (i +1)x + eik l (i 1)x + 2Fo eik l (i +1)x 2 eik l i x + eik l (i 1)x
h
i
h
i
eat eik l x + e ik l x = eik l x + e ik l x + 2Fo eik l x 2 + e ik l x
2 cos(kl x ) 2
2 cos(kl x )
cos(kl x) 1
= 1 + 2Fo
cos(kl x)
sen2 (kl x/2)
= 1 4Fo
.
cos(kl x )

eat = 1 + 2Fo

A funo

sen2 (x/2)
cos(x )
possui singularidades em /2+k , e muda de sinal em torno destas singularidades: no possvel
garantir que |e at | < 1 uniformemente, e o esquema incondicionalmente instvel.
f (x ) =

Exemplo 3.2 Considere a equao de adveco-difuso unidimensional

2u
+U
= D 2 K,
t
x
x
com condies iniciais e de contorno

0 x ,

t > 0,

(3.48)

(x , 0) = 0,
(0, t) = M ,
(, t) = 0.
A soluo analtica (OLoughlin e Bowmer, 1975)
"
!


M
Ux
x + Ut(1 + 2H )1/2
1/2
(x , t) =
exp
(1 + (1 + 2H ) ) erfc
+

2
2D
4Dt
!#


Ux
x Ut(1 + 2H )1/2
1/2
exp
(1 (1 + 2H ) ) erfc

2D
4Dt

(3.49)

100

Matemtica Aplicada
onde

H = 2K D/U 2 .

(3.50)

a) [20] Mostre que (3.49) atende equao diferencial. Voc pode fazer tudo analiticamente
com lpis e papel, ou usar Maxima; em ambos os casos sua resposta deve ser passada para
o arquivo difadv-xxxx.pdf.
b) [20] Discretize (3.48) usando um esquema upwind implcito para
mente implcito no lado direito. Faa

e um esquema total-

x = 0,01 = L/N ,

(3.51)

xi = ix .

(3.52)

c) [60] Resolva (3.48) numericamente com o esquema obtido acima para U = 1, D = 2,


K = 1 e M = 1 e compare graficamente com a soluo analtica em t = 0,333, t = 0,666
e t = 0,999. Por tentativa e erro, escolha L suficientemente grande para representar
numericamente o infinito.
SOLUO
a)
1
2
3
4
5
6
7
8
9

a : U*x/(2*D) ;
h : 2*K*D/U^2 ;
s : (1 + 2*h )**(1/2) ;
e1 : (x + U*t*s)/( sqrt (4*D*t)) ;
e2 : (x - U*t*s)/( sqrt (4*D*t)) ;
fi : (1/2)*( exp(a*(1 + s))* erfc(e1) + exp(a*(1 -s))* erfc(e2 )) ;
diff(fi ,t) + U*diff(fi ,x) - D*diff(fi ,x ,2) + K*fi ;
expand (%) ;
ratsimp (%) ;

b)
n+1 + n+1
in+1 in
in+1 in+1
in+1
+1 2i
1
i 1
+U
=D
Kin+1
t
x
x 2
Dt n+1
U t n+1
n+1
2in+1 + in+1
in+1 in +
(i in+1
(
1 ) =
1 ) (K t)i
x
x 2 i +1
n+1
n+1
n+1
in+1 in + Co(in+1 in+1
+ in+1
1 ) = Fo(i +1 2i
1 ) Kai

Passando todos os termos em (n + 1) para o lado esquerdo, e todos os termos em n para o lado
direito, tem-se
n+1
n
Foin+1
(Fo + Co)in+1
1 + (1 + 2Fo + Co + Ka)i
+1 = i ,

onde
U t
,
x
Dt
Fo =
,
x 2
Ka = K t.

Co =

Como sempre, as condies de contorno produzem linhas especiais: para i = 1 e i = N x teremos,


respectivamente,
0n+1 = M
+(1 + 2Fo + Co +
(Fo +

Co) n+1
N 2

Ka)1n+1

+ (1 + 2Fo + Co +

Fo2n+1

N
n+1
Ka) N 1

1n

=0
=

in

+ (Fo + Co) M ;

101

3.2 Difuso pura


1.0
0.9
0.8
0.7
(x , t)

0.6
0.5
0.4
0.3
t = 0,9999

0.2

t = 0,6666
t = 0,3333

0.1
0.0
0

10

Figura 3.9: Comparao entre as solues analtica (linhas) e numrica com um esquema
implcito (pontos) da equao da difuso-adveco com termo de decaimento, para t =
0,333, t = 0,666 e t = 0,999.
A listagem 3.12 mostra a implementao do esquema numrico acima com as condies de
contorno.
A comparao entre a soluo numrica (pontos) e a soluo analtica (linhas contnuas)
para os 3 instantes especificados est mostrada na figura 3.9
Exerccios Propostos
3.3 Considere a equao diferencial parcial
u
2u
= D 2,
t
x

0 x L,

com condies iniciais e de contorno


u(x , 0) = 0,

u(0, t) = c,

u
(L, t) = 0,
x

onde c uma constante. Dado o esquema de discretizao implcito clssico,


uin+1 uin
un+1 2uin+1 + uin+1
1
= D i +1
2
t
x
para N x = 8, obtenha o sistema de equaes lineares
[A][u]n+1 = [b]
onde os Ai , j s dependem do nmero de grade de Fourier, e os bi s dependem dos uin s. Em
outras palavras, escreva explicitamente a matriz quadrada [A] e a matriz-coluna [b] para
N x = 8.
3.4 Dada a equao diferencial no-linear de Boussinesq,
"
#
h

h
=
h
,
t
x x
h(x , 0) = H ,
h(0, t) = H 0 ,

h

= 0,
x x =1

Matemtica Aplicada

102

Listagem 3.12: Implementao de um esquema numrico implcito para a equao da


difuso-adveco.
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

#!/ usr/bin/ python


# -*- coding : iso -8859 -1 -*# -------------------------------------------------------------------# difadv -imp resolve uma equao de difuso com um mtodo
# implcito
#
# uso: ./ difadv -imp.py
# -------------------------------------------------------------------from __future__ import print_function
from __future__ import division
fou = open('difadv -imp.dat ','wb')
dx = 0.01
# define a discretizao em x
dt = 0.001
# define a discretizao em t
print('# dx = %9.4f' % dx)
print('# dy = %9.4f' % dt)
nx = int( round (10.0/ dx ,0))
# nmero de pontos em x
nt = int( round (1.0/ dt ,0))
# nmero de pontos em t
print('# nx = %9d' % nx)
print('# nt = %9d' % nt)
from numpy import zeros
u = zeros ((2 , nx +1) , float )
# apenas 2 posies no tempo
# so necessrias !
u[0 ,0: nx +1] = 0.0
# monta a condio inicial
u[0]. tofile (fou)
# imprime a condio inicial
old = False
new = True
U = 1.0
# adveco
D = 2.0
# difusividade
K = 1.0
# coeficiente de decaimento
FIM = 1.0
# CC
Cou = U*dt/dx
# nmero de Courant
Fon = D*dt /(( dx )**2)
# nmero de Fourier
Kai = K*dt
# nmero de decaimento
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] -> diagonal inferior
# A[1] -> diagonal principal
# A[2] -> diagonal superior
# -----------------------------------------------------------------------------A[0 ,0] = 0.0
# zera A[0 ,0]
A[0 ,1:nx -1] = -(Fon+Cou)
# preenche o fim da 1a linha
A[1 ,0:nx -1] = 1.0 + 2* Fon + Cou + Kai
# preenche a segunda linha
A[2 ,0:nx -2] = -Fon
# preenche o incio da 2a linha
A[2,nx -2] = 0.0
# zera A[2,nx -2]
# -----------------------------------------------------------------------------# importa uma adaptao de tridag de Numerical Recipes para Python
# -----------------------------------------------------------------------------from alglin import tridiag
b = zeros(nx -1, float )
# aloca b com o tamanho certo
for n in range (nt ):
# loop no tempo
print(n)
# -----------------------------------------------------------------------------# ateno : calcula apenas os pontos internos de u!
# -----------------------------------------------------------------------------b[0]
= u[old ,1] + (Fon + Cou )* FIM
b[1:nx -1] = u[old ,2: nx]
u[new ,1: nx] = tridiag (A,b)
u[new ,0] = FIM
# condio de contorno , x = 0
u[new ,nx] = 0.0
# condio de contorno , x = 10
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.

103

3.3 Difuso em 2 Dimenses: ADI, e equaes elticas

obtenha uma discretizao linearizada da mesma em diferenas finitas do tipo


h(xi , tn ) = h(ix , nt) = hin
da seguinte forma:
discretize a derivada parcial em relao ao tempo com um esquema progressivo no tempo
entre n e n + 1;
aproxime h dentro do colchete por hin (este o truque que lineariza o esquema de diferenas finitas) e mantenha-o assim;
utilize esquemas de diferenas finitas implcitos centrados no espao para as derivadas
parciais em relao a x , exceto no termo hin do item anterior.
NO MEXA COM AS CONDIES DE CONTORNO.

3.3 Difuso em 2 Dimenses: ADI, e equaes elticas


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

(3.53)

Como sempre, ns queremos ser muito concretos, e trabalhar com um problema que
possua soluo analtica. Considere ento a condio inicial
!
(x 2 + y 2 )
;
(3.54)
u(x , y, 0) = u 0 exp
L2
a soluo analtica
!
(x 2 + y 2 )
u0
u(x , y, t) =
exp 2
.
1 + 4tD/L 2
L + 4Dt

(3.55)

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:
!
(L 2 + y 2 )
u0
exp 2
u(L, y, t) =
,
(3.56)
1 + 4tD/L 2
L + 4Dt
!
(L 2 + y 2 )
u0
u(L, y, t) =
exp 2
,
(3.57)
1 + 4tD/L 2
L + 4Dt
!
u0
(x 2 + L 2 )
u(x , L, t) =
exp 2
,
(3.58)
1 + 4tD/L 2
L + 4Dt
!
(x 2 + L 2 )
u0
u(x , L, t) =
exp 2
.
(3.59)
1 + 4tD/L 2
L + 4Dt
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

104

Matemtica Aplicada

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 + un+1
n + un
n+1 un
n
ui+1,j 2ui,j
2ui,j
ui,j
ui,j+1

i1,j
i,j1
i,j
(3.60)
= D
+

2
2
t
x
y
n+1
n+1 + un+1
n+2 un+1
n+2 2un+2 + un+2
ui+1,j 2ui,j
ui,j
ui,j+1

i1,j
i,j1
i,j
i,j
(3.61)
= D
+

2
2
t
x
y
Examine cuidadosamente (3.60) e (3.61): 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

(3.62)

e ento teremos, para x:




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




n+1
n+1
n+1
n+1
n
n
n
n
,
+ ui,j+1
2ui,j
+ Fo ui,j1
ui,j
Fo ui1,j
2ui,j
+ ui+1,j
= ui,j
n+1
n+1
n+1
n
n
n
Foui1,j
+ (1 + 2Fo)ui,j
Foui+1,j
= Foui,j1
+ (1 2Fo)ui,j
+ Foui,j+1
(3.63)

Na dimenso y,


n+2
n+1
n+1
n+1
n+1
n+2
n+2
n+2
ui,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+2
n+1
n+1
n+1
n+1
ui,j
Fo ui,j1
2ui,j
+ ui,j+1
= ui,j
+ Fo ui1,j
2ui,j
+ ui+1,j
,
n+2
n+2
n+2
n+1
n+1
n+1
Foui,j1
+ (1 + 2Fo)ui,j
Foui,j+1
= Foui1,j
+ (1 2Fo)ui,j
+ Foui+1,j
(3.64)

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,
y j = L + j,
N =

(3.65)
i = 0, . . . , N ,
j = 0, . . . , N ,

(3.66)
(3.67)

e portanto L xi L e L y j L. Lembrando que os valores de u 0,j , u N ,j , ui,0 e


ui,N esto especificados, h (N 1)2 incgnitas para serem calculadas. A beleza de (3.63)
e (3.64) 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 u 1,...,N 1;j e ui;1,...,N1 .

105

3.3 Difuso em 2 Dimenses: ADI, e equaes elticas

Listagem 3.13: difusao2d-ana.py Soluo analtica da equao da difuso bidimensional.


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 -*# ---------------------------------------------------------# difusao2d -ana: soluo analtica de
#
# du/dt = D (du ^2/ dx ^2 + du ^2/ dy ^2)
#
# u(x ,0) = T0 exp (-(x^2 + y^2)/L^2)
#
# com T0 = 1, D = 2, L = 1, em um domnio (-L,-L) at (L,L)
#
# uso: ./ difusao2d -ana.py
# ---------------------------------------------------------from __future__ import print_function
from __future__ import division
fou = open('difusao2d -ana.dat ','wb')
dd = 0.01
dt = 0.001
print('# dd = %9.4f' % dd)
print('# dt = %9.4f' % dt)
nn = int (2.0/ dd)
# nmero de pontos em x e em y
nt = int (1.0/ dt)
# nmero de pontos em t
print('# nn = %9d' % nn)
print('# nt = %9d' % nt)
from math import exp
def ana(x,y,t):
return (1.0/(1.0 + 8*t))* exp (-(x**2 + y **2))
from numpy import zeros
u = zeros (( nn+1,nn +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 (nn +1):
# loop no espao
xi = -1 + i*dd
for j in range (nn +1):
yj = -1 + j*dd
u[i,j] = ana(xi ,yj ,t)
u. tofile (fou)
# imprime uma matriz com os dados
fou. close ()

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 t 2 . 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, na listagem 3.13.
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 3.10

Matemtica Aplicada

106

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


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

107

3.3 Difuso em 2 Dimenses: ADI, e equaes elticas

Em seguida, o esquema numrico ADI est implementado na listagem 3.14. O resultado mostrado na figura 3.11.
Listagem 3.14: difusao2d-adi.py Soluo numrica da equao da difuso bidimensional, esquema ADI.
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
66

#!/ usr/bin/ python


# -*- coding : iso -8859 -1 -*# -----------------------------------------------------------------------------# difusao2d -adi resolve uma equao de difuso com um mtodo implcito
#
# uso: ./ difusao2d -adi.py
# -----------------------------------------------------------------------------from __future__ import print_function
from __future__ import division
fou = open('difusao2d -adi.dat ','wb')
dd = 0.02
# define a discretizao em x,y
dt = 0.001
# define a discretizao em t
print('# dd = %9.4f' % dd)
print('# dt = %9.4f' % dt)
nn = int( round (2.0/ dd ,0))
# nmero de pontos em x,y
nt = int( round (1.0/ dt ,0))
# nmero de pontos em t
print('# nn = %9d' % nn)
print('# nt = %9d' % nt)
from numpy import zeros
u = zeros ((2 , nn+1,nn +1) , float )
# apenas 2 posies no tempo
# so necessrias !
from math import exp
def CCy(y):
return (1.0/ aux )* exp( - (1.0 + y*y)/ aux)
def CCx(x):
return (1.0/ aux )* exp( - (1.0 + x*x)/ aux)
def CI(x, y):
return exp (-(x*x + y*y))
for i in range (nn +1):
# monta a condio inicial
xi = -1.0 + i*dd
# inteira , at as fronteiras
for j in range (nn +1):
# inclusive
yj = -1.0 + j*dd
u[0,i,j] = CI(xi ,yj)
u[0]. tofile (fou)
# imprime a condio inicial
D = 2.0
# difusividade
Fon = D*dt /(( dd )**2)
# nmero de Fourier
print("Fo = %10.6 f" % Fon)
A = zeros ((3 ,nn -1) , float )
# cria a matriz do sistema
# -----------------------------------------------------------------------------# monta a matriz do sistema
# -----------------------------------------------------------------------------A[0 ,0]
= 0.0
# zera A[0 ,0]
A[0 ,1:nn -1] = -Fon
# preenche o fim da 1a linha
A[1 ,0:nn -1] = 1.0 + 2* Fon
# preenche a segunda linha
A[2 ,0:nn -2] = -Fon
# preenche o incio da 2a linha
A[2,nn -2]
= 0.0
# zera A[2,nn -2]
# -----------------------------------------------------------------------------# importa uma traduo de tridag de Numerical Recipes para Python
# -----------------------------------------------------------------------------from alglin import tridag
old = False
# o velho truque !
new = True
n = 0
b = zeros (nn -1, float )
while (n < nt +1):
# loop no tempo
n += 1
print(n)
# -----------------------------------------------------------------------------# varre na direo x
# -----------------------------------------------------------------------------t = n*dt
aux = 1.0 + 8.0*t
for j in range (nn +1):
# CC ao longo de x
yj = -1.0 + j*dd
u[new ,0,j] = CCy(yj)
u[new ,nn ,j] = CCy(yj)

108

Matemtica Aplicada
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

for j in range (1,nn ):


# nn -1 varreduras em x (logo , loop em y)
yj = -1.0 + j*dd
b[1:nn -2] = Fon*u[old ,2:nn -1,j -1] \
+ (1.0 - 2* Fon )*u[old ,2:nn -1,j] \
+ Fon*u[old ,2:nn -1,j+1]
b[0] = Fon*u[old ,1,j -1] + (1.0 - 2* Fon )*u[old ,1,j] \
+ Fon*u[old ,1,j+1] \
+ Fon*u[new ,0,j]
b[nn -2] = Fon*u[old ,nn -1,j -1] + (1.0 - 2* Fon )*u[old ,nn -1,j] \
+ Fon*u[old ,nn -1,j+1] \
+ Fon*u[new ,nn ,j]
u[new ,1:nn ,j] = tridag (A,b)
u[new ]. tofile (fou)
# -----------------------------------------------------------------------------# varre na direo y
# -----------------------------------------------------------------------------(new ,old) = (old ,new)
n += 1
print(n)
t = n*dt
aux = 1.0 + 8.0*t
# CC ao longo de y
for i in range (nn +1):
xi = -1.0 + i*dd
u[new ,i ,0] = CCx(xi)
u[new ,i,nn] = CCx(xi)
# nn -1 varreduras em y (logo , loop em x)
for i in range (1,nn ):
xi = -1.0 + i*dd
b[1:nn -2] = Fon*u[old ,i -1 ,2:nn -1] \
+ (1.0 - 2* Fon )*u[old ,i ,2:nn -1] \
+ Fon*u[old ,i+1 ,2:nn -1]
b[0] = Fon*u[old ,i -1 ,1] + (1.0 - 2* Fon )*u[old ,i ,1] \
+ Fon*u[old ,i+1 ,1] \
+ Fon*u[new ,i ,0]
b[nn -2] = Fon*u[old ,i-1,nn -1] + (1.0 - 2* Fon )*u[old ,i,nn -1] \
+ Fon*u[old ,i+1,nn -1] \
+ Fon*u[new ,i,nn]
u[new ,i ,1: nn] = tridag (A,b)
u[new ]. tofile (fou)
(new ,old) = (old ,new)
fou. close ()
# fecha o arquivo de sada , e fim.

Exemplo 3.3 Utilizando a anlise de estabilidade de von Newmann, mostre que o esquema
numrico correspondente primeira das equaes acima incondicionalmente estvel. Suponha
x = y = s.
SOLUO
Inicialmente, rearranjamos o esquema de discretizao, multiplicando por t e dividindo por
x 2 :
i
h
n
n+1
n+1
n+1
n
n
n
uin+1
, j ui , j = Fo ui +1, j 2ui , j + ui 1, j + ui , j +1 2ui , j + ui , j 1 ,
onde
Fo =

Dt
.
s 2

Faa agora
tn = nt ,
xi = is,
y j = js,
X
in =
l ,m eatn eik l xi eikm y j ,
l ,m

109

3.3 Difuso em 2 Dimenses: ADI, e equaes elticas

Figura 3.11: 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

110

Matemtica Aplicada
e substitua o modo (l , m) no esquema de discretizao:

l ,m ea(tn +t ) eik l i s eikm j s l ,m eatn eik l i s eikm j s =


h
Fo l ,m ea(tn +t ) eik l (i +1)s eikm j s 2l ,m ea(tn +t ) eik l i s eikm j s + l ,m ea(tn +t ) eik l (i 1)s eikm j s
i
l ,m eatn eik l i s eikm (j +1)s 2l ,m eatn eik l i s eikm j s + l ,m eatn eik l i s eikm (j 1)s .
Ns imediatamente reconhecemos o fator comum
l ,m eatn eik l i s eikm j s ,
e simplificamos:

h
eat 1 Fo(e+ik l s

h
i
eat 1 = Fo eat e+ik l s 2eat + eat e ik l s + e+ikm s 2 + e ikm s ,
i
h
i
2 + e ik l s ) = 1 + Fo e+ikm s 2 + e ikm s

eat [1 2Fo(cos(kl s) 1)] = 1 + 2Fo(cos(km s) 1)


at 1 + 2Fo(cos(km s) 1)
.
e =
1 2Fo(cos(kl s) 1)



at 1 4Fo sen2 km2s
e =

 1
1 + 4Fo sen2 k l s
2

A
Para as coisas funcionarem em
Windows
1. Utilize um editor capaz de definir explicitamente que a codificao de todos os
arquivos texto utilizados iso-8859-1.
2. No Painel de Controle, escolha Data, hora, idioma e opes regionais; em seguida, Opes regionais e de idioma; em seguida, Avanado; e escolha Portugs (Brasil).
3. No prompt de comando, digite chcp e verifique se o cdigo de pgina 850
antes de comear a trabalhar; se no for, digite chcp 850, ou (melhor ainda) chcp
1252.
4. Na barra superior do prompt de comando clique e escolha tanto em Padres,
quando em Propriedades: Fonte, Lucida Console.

111

Matemtica Aplicada

112

B
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

113

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

114

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.
Brutsaert, W. (2005). Hydrology. An introduction. Cambridge University Press, Cambridge, UK.
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.
OLoughlin, E. M. e Bowmer, K. H. (1975). Dilution and decay of aquatic herbicides in
flowing channels. J of Hydrology, 26:217235.
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.
Schnoor, J. L. (1996). Environmental Modeling. Wiley-Interscience.

115