Matemática Aplicada à Engenharia

Nelson Luís Dias Departamento de Engenharia Ambiental e Lemma — Laboratório de Estudos em Monitoramento e Modelagem Ambiental Universidade Federal do Paraná 30 de setembro de 2011

Sumário

2

Sumário
1 Ferramentas computacionais 1.1 Antes de começar a trabalhar, . . . . . . . . . . . . . . . 1.2 Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.1 Strings e Inteiros . . . . . . . . . . . . . . . . . . 1.2.2 Números de ponto flutuante “reais” e “complexos” 1.2.3 Obtenção de uma curva de permanência . . . . . 1.2.4 Arquivos texto e arquivos binários . . . . . . . . . 1.3 Gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.1 Ajuste de uma função . . . . . . . . . . . . . . . 1.4 Python de novo: projeto probabilístico . . . . . . . . . . 1.5 Maxima . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Um 2.1 2.2 2.3 11 11 13 13 15 16 19 22 24 26 30

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

pouco de polinômios, integrais, séries . . . 33 Integração numérica: motivação . . . . . . . . . . . . . . . . . . . . . 33 A regra do trapézio . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Aproximação de integrais com séries: a função erro . . . . . . . . . . 42 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 49 50 54 54 61 61 71 83

3 Solução numérica de equações diferenciais ordinárias 3.1 Solução numérica de equações diferenciais ordinárias . 3.1.1 Solução numérica; método de Euler . . . . . . . 3.1.2 Um método implícito, com tratamento analítico 3.1.3 Runge-Kutta . . . . . . . . . . . . . . . . . . .

4 Solução numérica de equações diferenciais parciais 4.1 Advecção pura: a onda cinemática . . . . . . . . . . . . . . . . . . . . 4.2 Difusão pura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 Difusão em 2 Dimensões: ADI, e equações elíticas . . . . . . . . . . .

A Dados de vazão média anual e vazão máxima anual, Rio dos Patos, 1931–1999 89

3

Sumário 4 .

. . . 16 Estimativas numéricas de I e seus erros relativos δ. . . .1 Vazões Máximas Anuais (m3 s−1 ) no Rio dos Patos. .Lista de Tabelas 1. . 38 5 . 1931–1999 . . PR. .1 2.

Sumário 6 .

. . . . . . 44 Função erf(x) calculada com série de Taylor. . . . . . . . . . . . . para ∆x = 0.2 1. . . . . . . . . . . 35 A regra do trapézio. . . . . . . . . . . . . . . . para ∆x = 0. . . . . . . . . . . . . . . . . . . . 55 Comparação da solução analítica da equação (3. . . . . .1) com a saída de sucesso. . . . . . . 500∆t e 750∆t. . . para t = 500∆t. . . . . . . .py.10 e t = 0. .3 4. . . . . . para ∆x = 0.py. . versus a erf pré-definida em Gnuplot. . . . . . . . . 71 Solução analítica da equação de difusão para t = 0. . . . . . . . Rio dos Patos . . . 25 Ajuste de uma FDA Weibull aos dados de vazão máxima anual do Rio dos Patos . . para ∆x = 0. . . . . . . . . . . . . . . . .5.5. . . . . . t = 0. . . . . . . . . . . . . . . . . . . . . . . . 1000∆t e 1500∆t. . . . . 56 Comparação da solução analítica da equação (3. . 59 Condição inicial da equação 4. . .1) com a saída de rungek4. .3 2. .1 2. . .05. . . .py. . . . . . . . . . . com n = 4 e n = 8 trapézios. . . . . 38 Função erf(x) calculada por integração numérica.1) com a saída de sucimp. . . . . . . . . para t = 500∆t. . . .15. . . . . . . 50 Comparação da solução analítica da equação (3.3. 53 Comparação da solução analítica da equação (3. . . . . . . . . . . .1) com a saída de sucesso. . . . .6 4. com erf_1. . . . 63 Solução numérica produzida por onda1d-lax. 1000∆t e 1500∆t. . . . . .2 3.py. . . . . . . 61 Solução numérica produzida por onda1d-ins. .py. . . . . . . . . . . . . . . . . . . . . . . . . . .5 Convenções do terminal postscript eps monochrome Times-Roman 18 . . .1 4. . . . . . . 27 Integração numérica de uma função . . . . . . . . . . . . . . . 53 Comparação da solução analítica da equação (3. . . . . . . . . . . . .4 4. . . 70 Solução numérica produzida pelo esquema upwind. . . . . . . . . .3 2. . . 74 7 . . . . . . . . . . . .01. . .4 3. . . . . . . . . . . .py. . . . . . . . . . . . . . .1 1. . . . . . . . . .2 4. . . . . . para ∆x = 0. . . . . . .2 2. . . .4 3. . .1). com trapepsilon e = 1 × 10−6 . . . . . . . .5 3. . . . . . . . . . .py. 24 FDA da vazão máxima anual. . . . . versus a erf pré-definida em Gnuplot. . . . . . . . . . . .5. . .1 3. . . . .Lista de Figuras 1. . . . 45 Solução da equação (3. . . . . . . . . .5. t = 0. .1) com a saída de euler2. .3 3. . . . . . . . para t = 250∆t. . . .

Sumário 4. . . . . . . . . . . . . . . .10 e t = 0. 87 . . . . . . . .10 e t = 0. . .10 Solução numérica da equação da difusão bidimensional com o esquema ADI. . . . . 83 . . . . . .1. . t = 0. . para facilitar a comparação com a solução analítica. t = 0. 80 . .1. . . . t = 0. . . . .39) (círculos) versus a solução analítica (linha cheia) da equação de difusão para t = 0. 8 . . . . . . . .05. 4. . . . . . . . para facilitar a comparação com a solução analítica. . . . . . .15. . .45)) (círculos) versus a solução analítica (linha cheia) da equação de difusão para t = 0. .8 Solução numérica com o método de Crank-Nicholson ( (4. . t = 0. para t = 0. 4.6 Solução numérica com o método explícito (4. para facilitar a comparação com a solução analítica. .2 e t = 0. t = 0. . . . t = 0. . Apenas 1 a cada 5 pontos da grade numérica são mostrados. . .2 e t = 0. . t = 0. . t = 0. t = 0. . t = 0. . . . . . . . .35) (círculos) versus a solução analítica (linha cheia) da equação de difusão para t = 0. . .15. . . . 77 . . t = 0. . 4. . . . . . . . . .05. . 4. . . para t = 0.10 e t = 0. . . 88 . .3 . . . . Apenas 1 a cada 5 pontos da grade numérica são mostrados. . .9 Solução analítica da equação da difusão bidimensional. . . . . . . . . .15. Apenas 1 a cada 5 pontos da grade numérica são mostrados. .3 .05. . t = 0.7 Solução numérica com o método implícito (4. .

. . . . . .py — exemplo de uso de float e complex. Cálculo de erf(x) com uma série de Taylor. . .2 1. .3 1. . vererf. . . . . .py — Integração numérica eficiente de f (x) com = 0. .py — Integração numérica ineficiente. .9 1. . . . . . . . . .3 2. . . . . . readarr. . . . . . (3. . . . .4 1. . . . .py — Escreve um arquivo binário contendo 3 “linhas”. .Lista de Listagens 1.py — Integração numérica ineficiente de f (x) com = 0. . . . . . . . . . . . .py — Cálculo da função erro por integração numérica . . . . fiqemp.8 2. . . . . . . . . . . passaquad. . . . . . . .max — Polinômio com propriedades definidas . e inteiros. .py — Integração numérica de f (x) com 8 trapézios . . . quadraver3. . . . . . writearr. Rio dos Patos fqiemp. . . . .000001 . . . . . . . . . . . . bintext. . . . . vererf1. . .1 1. . cada uma das quais com um array de 10 float’s. . . . . . ppbemp. fqiemp. . . . . . . . . . . . . . 9 13 15 17 18 19 20 21 22 23 25 28 29 31 34 34 36 37 39 39 40 40 41 41 43 43 46 46 . . . . . . .py — exemplo de strings. . .7 2.11 1.py — cálculo de uma FDA empírica . . . . patos-medmax. . . . . . . . . . .max — parábola h(x) = ax2 + bx + c passando por (1. . . . . . .py — Integração numérica eficiente. . . . . .10 1. . . . . .py — projeto probabilístico a partir da distribuição empírica mulambdak. .dat — vazões média e máxima anuais.2 2. regra do trapézio . numint. . . . . .5 2. . . . f (5)). . . . . . . . .dat — FDA empírica da vazão máxima anual no Rio dos Patos. . . . . . . . . . . . . . .7 1. .py — Escreve um arquivo binário contendo 3 “linhas”. . . . .9 2. . . . . . . interp. . . .12 2. . . . . . . . . .max . . . . . . . . . . . . . . . . . Saída de passaquad. . . .12 1. . . . . .plt — como ajustar uma FDA analítica (Weibull) aos dados da FDA empírica . . . . . . . . . . . . . . . . . . . . . . . quadraver2. . . . . . . . . floats. . .6 2. . . . . . . . . . . . . . . .11 2. . .max . . . . .plt — Plotagem da função erro por integração numérica versus a erf(x) pré-definida em Gnuplot . . . .py — Integração numérica. . . . . . cada uma das quais com um array de 10 float’s. . . . . . .5 1. . .10 2. .0001 . . vererf.1 2. . . . . . . . . com erro absoluto préestabelecido . . . . . . achapol. .13 2.max — cálculo da média da distribuição Weibull em em função de seus parâmetros λ e k . . . Saída de achapol. quadraver1. . . .plt — programa para plotar a FDA empírica do Rio dos Patos weibull. . . . . . . . .py — Exemplo de arquivo texto e arquivo binário . com erro absoluto préestabelecido . . numint. . . . . .13 2. f (1)). . . . . . . . . . . . . . . . . . . . . . . . . . .6 1.14 binint. . . . . . . . . . . . . . . . . . .4 2. . . . . . . .py — Cálculo da função erro com série de Taylor entre 0 e 3.py — módulo com função para calcular uma interpolação linear. .8 1. numint. . . . . . f (3)) e (5. .

. . . . . . .py — Seleciona alguns instantes de tempo da solução analítica para visualização . 10 47 48 49 51 51 52 55 57 58 63 64 68 69 73 74 76 77 80 81 84 89 . . . . . . . . . . . . . .py — Um programa com o método de Euler que não funciona 3.3 Saída de fracasso. . . . .py — Um programa com o método de Euler que funciona . . . . 4. . . . . . . . . . . . . . . . . . .py — Solução analítica da equação da difusão . . . . . . .py — Solução numérica da equação da difusão: esquema de Crank-Nicholson. . . . . . . . ordem 4 . . . . . .dat . . .py — Seleciona alguns intervalos de tempo da solução numérica para plotagem . . . .3 onda1d-lax. .16 erfs. . .py — Exporta uma rotina que resolve um sistema tridiagonal. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11 difusao1d-ckn. . . 4.7 rungek4 — Método de Runge-Kutta. . . . .py . . 2. . . . . . . . . . . . . . . . . . . . .py — Seleciona alguns instantes de tempo da solução analítica para visualização . . . . . . . . . . . . . . . . (1992) . . . . . . 4. . . . . . . . . . . . . . . . . 4.1 onda1d-ins. . . . . . .Sumário 2.py — Cálculo de erf(x) com série de Taylor. 4. . . . . . . . . . . . . .5 sucimp. . . . .py — Seleciona alguns intervalos de tempo da solução numérica para plotagem . . . . . . . . .py — Solução numérica da equação da difusão: método implícito. . . . . . 4. . . . . . . . . . . . . 4. .2 surf1d-ins. . . 4. . .15 vererf1. . .5 difusao1d-ana. 3. . . . .6 euler2 — Um método explícito de ordem 2 . . . . . 3. . . . . . . . . . 3. . .py — Método de Euler implícito . . . . . . . . . . . . . .plt — Plotagem da função erro calculada com série de Taylor versus a erf(x) pré-definida em Gnuplot . . . . . . . . . . . . . . . . . . . . . . . 3. . . . . . . . . . .7 difusao1d-exp. . . . . . 4. . . . . . . . . . . . . . . . . . . . . . . . . . . . patos–medmax. . . . . .py — Solução de uma onda 1D com um método explícito laxtável .8 divisao1d-exp. . . . . . . .6 divisao1d-ana. . 3. . .2 fracasso. . . . . limitado a no máximo 43 termos . . . . . . . . 4. . .4 surf1d-lax. . . . . . .9 alglin. . . . . . . . . . . . . . . . . . 4. .py — Solução numérica da equação da difusão: método explícito. . . . . . . . . . . . . . . . . . .1 resolve-eqdif — Solução de uma EDO com Maxima . . . . . . . . 3. . . . .4 sucesso. . . . . baseado em Press et al. . . . . . . . . . . .10 difusao1d-imp. .py — Solução de uma onda 1D com um método explícito instável . .

A escolha de Python deve-se ao fato de ela ser uma linguagem fácil de aprender.1 Neste momento. Nós vamos apenas calcular algumas integrais. Nós vamos gerar todos os nossos gráficos bidimensionais (gráficos “x × y”) com Gnuplot. e 3.1 – Antes de começar a trabalhar. e de existirem muitas bibliotecas de rotinas em Python que tornam muitas das tarefas de Matemática Aplicada fáceis de implementar em um computador. Eis os requisitos fundamentais: 11 . Da mesma maneira que nós faremos contas com Python.x.x quanto possível. Os usos que faremos de Maxima estarão longe de explorar todo o seu potencial.5 4. algumas séries de Taylor. Maxima é uma linguagem de processamento simbólico. nós faremos álgebra com Maxima.x. 1. e às vezes faz muita diferença. Ela é bastante popular.1 Ferramentas computacionais Neste capítulo nós fazemos uma introdução muito rápida a 3 ferramentas computacionais. Você precisará de algumas condições de “funcionamento”. Se você (já) estiver usando Python 3. a versão de um programa de computador faz diferença.21. existem duas linhagens de Python convivendo: 2. razoavelmente clássica. Python é uma linguagem de programação. O futuro é Python 3. e resolver algumas equações diferenciais ordinárias.6. Infelizmente.x. remova estes comandos do início de seus arquivos . que você encontrará diversas vezes ao longo do texto. fácil de usar.x.py. e da qual nós vamos explorar apenas uma parte chamada de programação procedural. entretanto.4 5. e muito flexível. a rapidez com que faremos isto justifica amplamente o seu uso. Gnuplot é uma linguagem para gerar gráficos. Isto é facilitado por comandos to tipo from __future__ import . e eu procurei usar uma sintaxe tão próxima de 3. As versões que eu utilizei para este texto foram: Python: Gnuplot: Maxima: 2.

ou bloco de notas nas versões em Português.html). 6) Certificar-se de que você tem Gnuplot instalado. ou “terminal”. mas não use acentos: em lugar de impossível. e não insere figuras. ou Maxima. voltar para 1). e que vamos utilizar seguidamente) instalado. ou maxima.Matemática Aplicada 1) Saber que sistema operacional você está usando. não cria tabelas. 12 2) Saber usar a linha de comando. onde você datilografa comandos que são em seguida executados. digite impossivel. sistemas operacionais. 2) Ir para a linha de comando. 5) Certificar-se de que você tem Numpy (um módulo de Python que deve ser instalado à parte. e reiniciar o processo. editores de texto simples são o gedit. Um editor de texto reproduz o texto que você datilografa. trabalhe normalmente. e o kate. Um editor de texto que “vem” com Windows chama-se notepad. Linux e MacOS. ou o emacs. 7) Certificar-se de que você tem Maxima instalada. eu vou partir do princípio de que todas estas condições estão cumpridas por você. Um editor de texto não produz letras de diferentes tamanhos. 3) Saber usar um editor de texto. e salvá-lo em codificação ISO-8859-1. Quando você estiver praticando o uso das ferramentas computacionais descritas neste texto. e bom trabalho! . Estes dois últimos possuem versões para os 3 sistemas operacionais mais comuns hoje em dia: Windows. em geral com um tipo de largura constante para que as colunas e espaços fiquem bem claros. mas não vou detalhá-las mais: em geral. usando o editor de texto. Se isto for impossível para você. 4) Certificar-se de que você tem Python instalado. suas tarefas invariavelmente serão: 1) Criar o arquivo com o programa em Python. editores de texto e ambientes de programação variam com o gosto do freguês: escolha os seus preferidos. e salvar seus arquivos com codificação ISO-8859-1. procure descobrir como você pode configurar o seu editor para salvar em ISO-8859-1. um excelente substituto chama-se notepad2 (http://www.flos-freeware. Atenção! Um editor de texto não é um processador de texto. Gnuplot. possivelmente precedido por python. Programadores mais experientes costumam preferir o vim.ch/notepad2. Em Linux. Se não for óbvio para você. 4) Verificar se o resultado está correto. gnuplot. 3) Executar o programa digitando o seu nome (e não clicando!). Neste texto. 5) Se houver erros.

1 – Strings e Inteiros Strings. Em Python.a : ) # separa a saída do primeiro for # p / cada c de a .1 Você já devia estar esperando por isto: o que é um sistema operacional? Qual é o sistema operacional que você usa? 1. c . Alguns comentários (sem intenção de trocadilho) adicionais. A listagem 1.py — exemplo de strings. c . Atenção: os números que aparecem à esquerda da listagem não fazem parte do arquivo.13 1. um comentário inicia-se com #.2 – Python Listagem 1. números inteiros. e mais ainda com o sistema operacional. ) = .x. ou cadeias de caracteres. 0.1 # i é o maior int s / sinal que cabe em 32 bits b = unicode ( i ) # converte i na string c orrespon dente b # imprime b na tela print ( b ) print ( --. A legenda de cada listagem se inicia sempre com o nome do arquivo correspondente (após um pouco de hesitação.coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n a = açafrão # a é uma string # imprime a na tela print ( a ) print ( len ( a )) # imprime o número de caracteres de a i = 2**32 . imprime seu valor unicode for c in a : print ( ord ( .x. e prossegue até o fim de linha. imprime seu valor unicode for c in b : print ( ord ( . 1. e 32767.2 – Python Python reconhece os seguintes tipos “básicos” de variáveis: strings. A listagem é um retrato fiel do arquivo. e números complexos. com duas exceções: as palavras reservadas de Python estão sublinhadas na listagem (mas não no arquivo). O tipo das strings que vamos usar chama-se unicode em Python 2. O tipo dos números inteiros chama-se int em Python. ) = . você precisará digitar os arquivos novamente: isto o (a) forçará a praticar programação). são criaturas do tipo abacaxi .1 mostra o conteúdo do arquivo binint. O caminho /usr/bin/python pode variar com a instalação.py está explicada nos próprios comentários.2 Como saber se Python está instalado? 1. e números inteiros são criaturas do tipo -1. eu decidi não disponibilizar estes arquivos. para testar os exemplos deste texto. e os espaços em branco dentro das strings estão enfatizados pelo símbolo . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # !/ usr / bin / python # -* . e inteiros.1: binint.2. números de ponto flutuante. A maior parte dos comandos de binint.py com alguns exemplos simples do uso de inteiros e strings. ord ( c )) print ( --. e str em Python 3.b : ) # separa a saída do segundo for # p / cada c de b . por linha: 1 Este comentário especial torna o arquivo executável em Linux. ord ( c )) print ( unichr (227)) # imprime o caractere unicode no 227 Exercícios Propostos 1. .

e recebe o valor 232 − 1. com a[0] == a . com caracteres estranhos. não se assuste (demais): o seu arquivo binint. O corpo do for tem que ser indentado. ord(c)) é executado 7 vezes. Vamos agora à saída do programa binint. a[1] == ç . Magia negra: print deixa de ser uma declaração.a : ord ( a ) = ord ( ç ) = ord ( a ) = ord ( f ) = ord ( r ) = ord ( ã ) = ord ( o ) = --. e na listagem a indentação é de 3 espaços. já que o maior inteiro que cabe em 32 bits é 11111111111111111111111111111111 (binário) = 1 × 231 + 1 × 230 + 1 × 229 + . no caso da linha 13. Este é o maior valor sem sinal que um inteiro pode assumir. A volta à indentação anterior na linha 14 define o fim do for.py e o terminal dentro do . A posição do caractere a na tabela Unicode é 97. 12–13 O comando for percorre em ordem um objeto iterável (no caso. não é óbvio? Magia negra: tudo que é escrito entre aspas passa a ser uma string to tipo unicode. o comando print( ord( . a posição do caractere 4 é 52. não esquente. ) = . Se você estiver vendo uma saída diferente da mostrada acima. o caractere Unicode de número 227 é o ã.Matemática Aplicada 2 3 4 8 14 Este comentário informa que o arquivo está codificado em iso-8859-1.). . Nesta linha. e passa a ser uma função. uma para cada caractere de a.py: açafrão 7 4294967295 --. a posição do caractere ç é 231. Desta forma. etc. a variável i torna-se um int. Finalmente. . O maior inteiro que cabe em 32 bits sem sinal é 4294967295 (como já vimos acima). a string açafrão é iterável. Se você não entendeu nada.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.c. + 1 × 22 + 1 × 21 + 1 × 20 = 4294967295 (decimal) . de alguma forma!). O operador ** significa exponenciação.

Deles.coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from math import pi .py. (linha 6). como FORTRAN.2 – Números de ponto flutuante “reais” e “complexos” Em primeiro lugar. que calcula o seno. com o mecanismo from .0) # neste programa . sin ( pi /2)) i = csqrt ( -1. existe uma função denominada sin. um esclarecimento: no computador. e seno # o seno de um número complexo vem com outro from cmath import sin as csin # nome . csin ( i )) # imprime sen ( i ) qual você está executando este programa certamente estão utilizando codificações diferentes (veja se o apêndice ?? pode ajudar). na listagem 1. para não confundir # imprime o valor de pi print ( pi = .2: floats. Em ambos. Note que Python usa a letra j para indicar um valor imaginário (e não i).17520119364 j Os comentários importantes seguem-se.15 1. e continuando com Python.. ALGOL e PASCAL.2. o seno de i é um número puramente imaginário. sen π/2 = 1. Na linha 13. import . e .. Linguagens de programação mais antigas. para variáveis “reais” e “complexas”.. i == sqrt ( -1) print ( sen ( i ) = . Nosso primeiro exemplo do uso de números de ponto flutuante (float) e “complexos” (complex) não podia ser mais simples. e substituído a linha 14 por print(’sen(i) = ’. no ato da importação do módulo.2 Eis a saída de floats. eu √ “forcei a barra”. Por outro lado.17520119364i.py: pi = 3. e criei a variável que. para não confundir from cmath import sqrt as csqrt # a raiz quadrada de um número complexo vem # com outro nome . Lembre-se de que na maioria dos casos você está vendo aproximações racionais de números reais.2 – Python Listagem 1. Mas eu também poderia ter simplesmente eliminado esta linha. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # !/ usr / bin / python # -* . mesmo assim chamavam estes tipos de REAL. e . em muitas linguagens passou-se a usar o nome mais adequado float.. A partir de C. importam-se variáveis e funções (e outras coisas) úteis.71828182846 sen ( pi /2) = 1..0 sen ( i ) = 1. Note que existem dois módulos. Como era de se esperar.. sin # pi . e que o computador não pode lidar com todos os números reais. eu rebatizei a função sin complexa de csin.py — exemplo de uso de float e complex. .14159265359 e = 2. math e cmath. 1.csin(1j)) . Para poder usar estas duas funções diferentes em meu programa floats. respectivamente. as . e você pode adicionar seus próprios módulos. pi ) print ( e = . e vale ≈ 1. mas apenas um subconjunto dos racionais Q.e ) # imprime o valor de e # imprime sen ( pi /2) print ( sen ( pi /2) = . Python vem com uma grande quantidade de módulos predefinidos. não é possível representar todos os números x ∈ R do conjunto dos reais. em notação matemática se escreveria i = −1.

00 206.20 399.00 Ano 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 Vaz Máx 188.00 Ano 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 Vaz Máx 266.00 251.python.40 165. 1931–1999 Ano 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 Vaz Máx 272.00 Exercícios Propostos 1.00 198.00 92.00 146. PR.00 486.00 275.00 272.00 75.50 451.00 255.00 660.00 196.40 299.00 134.00 133.00 311. PR.00 Ano 1991 1992 1993 1994 1995 1996 1997 1998 1999 Vaz Máx 131.10 131.2.00 172.1.3 – Obtenção de uma curva de permanência Uma função distribuição acumulada (FDA) de probabilidade é uma função que nos informa qual é a probabilidade de que uma variável aleatória Q assuma um valor menor ou igual que um certo nivel q. estação ANA (Agência Nacional de Águas do Brasil) 64620000.00 174.60 152.00 211.00 245.40 248.10 171. e que as observações são equiprováveis (em analogia com os 6 únicos resultados possíveis do lançamento de um dado não-viciado).00 257. se Q é a vazão máxima diária em um rio em um ano qualquer.1: Vazões Máximas Anuais (m3 s−1 ) no Rio dos Patos.60 169.00 192. 1.00 61. converta 7777 da base 10 para a base 2.00 226. teríamos que a probabilidade de ocorrência de qi é P {Q = qi } = 1 .00 146.40 135. e encontre a rotina pré-definida (built-in) que faz isto.50 152.00 208.00 333. Provavelmente.00 278.30 272.00 190.80 333. o valor observado de Q varia de ano para ano.50 156. Sugestão: estude a documentação em www.1) .60 178.75 125.org.00 68.40 146.00 176.00 133.00 223.Matemática Aplicada 16 Tabela 1.4 Como se faz para concatenar as strings “bom” e “demais”? 1. No caso da tabela 1.1 dá os valores da vazão máxima anual para o Rio dos Patos. entre 1931 e 1999.00 128.10 127.50 119.80 222.20 243. se qi é a vazão máxima do i-ésimo ano.00 56.00 252.00 135.40 380. Por exemplo.3 Usando Python.60 202.80 281.00 247. A tabela 1. 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.00 472. Os valores de Q variam de experimento para experimento. n (1.00 528.00 275.00 182.

onde (1.65 4. O programa fqiemp. e um novo operador // sempre produz divisão inteira. simplesmente. existem muitas outras posições de plotagem possíveis para a FDA empírica. ou FDA empírica. a string rt . é preciso considerar os valores iguais ou menores que o valor de corte q. 3/4 == 0.dat — vazões média e máxima anuais. para as vazões máximas anuais do Rio dos Patos. o ano.60 178.2 – Python Listagem 1. nós devemos primeiro ordenar os qi ’s.py. (1. que se trata de uma operação de leitura. de tal maneira que q0 ≤ q1 ≤ . Rio dos Patos 1931 1932 1933 1934 1935 21.dat. Em Hidrologia. O resultado (i + 1)/n é denominado uma posição de plotagem.3: patos-medmax.3) é chamada de distribuição acumulada empírica de probabilidade.0/4 == 0.76 11. que pode ser acessado linha a linha. Esta é.46 28. muitas vezes (1.py explicam muito do que está acontecendo. (1. uma tabela de duas colunas: a vazão observada (em ordem crescente). Como antes. As linhas são separadas por caracteres (invisíveis no editor de texto) de fim de linha. O segundo argumento de open. descrito acima e exemplificado na listagem 1. respectivamente.3) é denominada curva de permanência. Os dados da tabela 1. mostrado na listagem 1. de um arquivo que já existe: isto garante que patos-medmax.10 272.x. e o valor de (i + 1)/n.75.2) Para obtê-la.x. e a vazão máxima do ano.py.17 1.3) n n k=0 (1.00 61. que se trata de um arquivo texto. A listagem 1. o cálculo de F (qi ) é trivial: i 1 i+1 F (qi ) = = .dat (Apêndice A).00 onde n é o número de observações.1 estão digitados no arquivo patos-medmax. Mas há necessidade de explicações adicionais: 5 Faz a divisão funcionar como em Python 3.dat não será modificado por fqiemp.4. com t. Note que a ordenação não altera (1. os comentários em fqiemp. .00 278. Após a ordenação. A função pré-definida open abre o arquivo patos-medmax. Este arquivo contém 3 colunas contendo. calcula a curva de permanência.x. Em Python 3. Portanto. Em Python 2. ≤ qn−1 . A discussão detalhada de posições de plotagem deve ser feita em um curso de Probabilidade e Estatística. / sempre produz um resultado do tipo float (ou complex).3) serve (apenas) como um exemplo motivador. Um arquivo texto é um objeto iterável. Por diversos motivos.30 272. .1). e não aqui.3.57 25. 6 . sendo cada linha uma string. diz duas coisas: com r. a vazão média do ano. Um arquivo texto é um arquivo formado por linhas.3 mostra as 5 primeiras linhas do arquivo (que possui 69 linhas). Mas a FDA por definição é F (q) = P {Q ≤ q}. (read). que convencionalmente nós indicamos por \n. e 3. Uma muito popular é (i + 1)/(n + 1).

Este é o loop de leitura do programa.6 f \ n % ( qi . Uma lista a com n objetos vai de a[0] até a[n-1].76 . linha é uma string que contém em cada iteração uma das linhas de patos-medmax. Uma lista é uma sequência de objetos quaisquer. É preciso separar uma linha (veja a listagem 1. As 5 primeiras linhas que aparecem na tela devido ao comando print da linha 10 são: [ [ [ [ [ 1931 1932 1933 1934 1935 . Aqui o terceiro campo é convertido em um float e vai para a variável qi. O método1 split separa a string linha em 3 strings. 278. 272. Cada um dos campo’s agora é ele mesmo uma string. 272. append ( qi ) # fin .dat.4: fqiemp. seus elementos são a[0].57 . Fi )) # fou . campo[1].60 ] 11. . Finalmente. etc.coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from __future__ import division fin = open ( patos . 21.medmax . 178. fqiemp. dat . Agora o programa abre o arquivo de saída.30 28. write ( %8.py — cálculo de uma FDA empírica 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # !/ usr / bin / python # -* . e não float’s.65 . e as coloca em uma lista campo == [ campo[0].00 25. É bom estilo de programação fechar cada arquivo previamente aberto. wt ) # qmax .2 f %8. com os valores separados. w significa abertura para escrita (write). split () # # print ( campo ) qi = float ( campo [2]) # qmax .00 4. campo[2] ]. sort () # n = len ( qmax ) # # for i in range ( n ): qi = qmax [ i ] # Fi = ( i +1)/ n # fou . dat . .10 . um método é uma rotina que “pertence” a uma variável ou um tipo (a rigor. . close () # fou = open ( fqiemp .Matemática Aplicada 18 Listagem 1. a uma classe. a[1]. 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 vazão é o terceiro campo adiciona qi à lista qmax fecha o arquivo de entrada abre o arquivo de saída ordena a lista tamanho da lista loop nos elementos da lista ordenada vazão posição de plotagem imprime uma linha fim de papo 7 Nesta linha. usando os espaços em branco como separadores (que são eliminados). estes campos ainda são strings. Em Python. qmax é inicializado como uma lista vazia.3) em seus 3 campos.46 . Dada uma lista a. qi é incluída na lista qmax. rt ) # qmax = [] # # for linha in fin : campo = linha .dat. mas este não é um curso de programação) . . e t que o arquivo será texto..00 ] ] ] ] 8 9 10 11 12 13 14 1 No entato. 61.

40 75.2. utilizando o operador / para dividir dois int’s e gerar um resultado correto do tipo float (veja comentário sobre a linha 5). Exercícios Propostos 1. write sempre escreve seu único argumento. que é re-utilizada para este fim.dat são mostradas na listagem 1.057971 0.40 92.5 Dado um número inteiro p lido do terminal. As primeiras 5 linhas do arquivo de saída fqiemp. e imprimir o resultado. etc. A string resultante. Obtém o i-ésimo elemento de qmax. loop para impressão no arquivo de saída. O primeiro elemento será substituído no primeiro campo de formatação por uma string com 8 caracteres. 2 Em Python uma tupla é uma lista imutável . que precisa conter explicitamente o caractere de fim de linha \n.028986 0.2 – Python Listagem 1. à sua direita uma tupla 2 (qi.2f e %8. É para isto que serve o operador %: ele tem à sua esquerda uma string com os campos de formatação especiais %8.Fi) com tantos elementos quantos são os campos de formatação.19 1.5: fqiemp. Qualquer representação interna é primeiramente traduzida para uma string de caracteres antes de ser escrita em um arquivo texto. Arquivos binários em geral armazenam informação com a mesma representação interna utilizada pelo computador para fazer contas. 56.014493 0. Trata-se portanto do problema inverso do loop de leitura.dat — FDA empírica da vazão máxima anual no Rio dos Patos. escreva um programa Python para procurar o índice i de uma lista a de 10 números inteiros definida internamente no programa tal que a[i] == p. Calcula a posição de plotagem. write é um método do arquivo fou. será escrita no arquivo de saída. que transformava strings em float’s: agora precisamos transformar float’s em uma string.10 61.6f. O segundo elemento será substituído no segundo campo de formatação por uma string com 8 caracteres. que a ordena (por default em ordem crescente). colocado na variável qi.. len é uma função pré-definida que retorna o número de elementos da lista.5.60 68. sendo 6 deles para casas decimais.4 – Arquivos texto e arquivos binários Arquivos texto são legíveis por seres humanos.043478 0.75 0. que tem que ser uma string. sendo 2 deles para casas decimais. no arquivo. 1.072464 15 16 17 18 19 20 sort é um método pré-definido para qualquer lista.

O módulo struct provê a conversão de. byte strings. e para. temos o programa bintext. txt )) % getsize ( i . arquivos binários tendem a ser menores (para a mesma quantidade de informação).6.py. wb ) fob . Eis aqui a dissecação de bintext.py: 5 8 10 A função pré-definida bin produz a representação do objeto na base 2.6: bintext.i ) fob = open ( i . Cada um destes arquivos contém o número inteiro i == 673451.bin. A outra grande vantagem é que a leitura e a escritura de arquivos binários é muito mais rápida. wt ) fot . close () print ( type ( i )) print ( type ( b )) from os .py é 0 b10100100011010101011 < type int > < type str > tamanho do arquivo txt = 6 bytes tamanho do arquivo bin = 4 bytes Conte os 32 bits na primeira linha (após o prefixo 0b. porque não há necessidade de traduzir a informação de. 11 15–16 Verifica os tipos de i e b. e o arquivo binário i. 18–19 Mostra o tamanho de cada um dos arquivos gerados. usando um campo de 6 caracteres. txt . Finalmente. e para. close () from struct import pack b = pack ( i . o tamanho de b será de 4 bytes. A única maneira de ler ou escrever um arquivo binário em Python é por meio de byte strings: strings em que cada elemento é um byte (8 bits).txt. Repare que o arquivo binário é menor que o arquivo texto. Converte i em uma byte string. write ( %6 d % i ) fot . . bin )) Como sempre. que indica a representação na base 2): eles correspondem aos 4 bytes que custa ao programa para guardar o númreo inteiro 673451. path import getsize print ( tamanho do arquivo txt = % d bytes print ( tamanho do arquivo bin = % d bytes % getsize ( i .Matemática Aplicada 20 Listagem 1. Em geral. Na listagem 1. que é o tamanho necessário para escrever i na base 10. write ( b ) fob . strings. bin .txt. a saída de bintext. que produz dois arquivos: o arquivo texto i.py — Exemplo de arquivo texto e arquivo binário 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # !/ usr / bin / python # -* .coding : iso -8859 -1 -* from __future__ import print _functio n i = 673451 bdet = bin ( i ) print ( bdet ) fot = open ( i . Escreve a variável i no arquivo i. um exemplo vale por mil palavras. Como a representação interna de i é em 4 bytes.

2 – Python Listagem 1. Numpy também proporciona seus próprios métodos e funções para ler e escrever de e para arquivos binários. cada uma das quais com um array de 10 float’s.4833 0.py. Isto é feito com o programa readarray. e permite manipular com boa eficiência computacional vetores e matrizes em Python.9779 0. ler e escrever corretamente o arquivo. random import rand fob = open ( a . de modo que em cada iteração 80 bytes são escritos.1399 0.8427 0.1 nldias nldias 240 2011 -08 -28 14:08 a .21 1. A listagem 1.5809 0. Repare que tofile é um método do array a. bin -rw -r . writearr.py. O programa importa a rotina fromfile de Numpy. possui 240 bytes.py repete por 3 vezes a geração de a e a sua escritura no arquivo binário a.coding : iso -8859 -1 -* from numpy . que não vem com Python.2897 0. Prosseguimos agora para ler o arquivo binário gerado.4301 0.5942 0. Cada float custa 8 bytes. interpretar. 1 2 3 4 5 6 7 8 # !/ usr / bin / python # -* . Em cada uma das 3 iterações de writearr.0322 0. teremos algo do tipo > ls -l a .bin. bin O arquivo gerado. tudo ou quase tudo que funciona com listas também funciona com arrays. wb ) for k in range (3): a = rand (10) a . Primeiro. bin . ademais. No final. Cabe a você.0639 0. um programa para escrever um array.1799 0. No entanto.7713 0.8062 0. ele não precisa ser importado. Neste texto.2327 0.4387 0. arquivos binários estão invariavelmente associados ao uso de arrays.2892 0. para devolver um array com 10 números aleatórios entre 0 e 1.7 mostra o programa writearr. a.4299 0. apenas.4350 0.7: writearr.org . O módulo Numpy3 .. ele é.6117 0.0382 0. nós faremos a partir de agora amplo uso de Numpy e de seu tipo array. ele escreve 10 float’s no arquivo.scipy. se procurarmos no disco o arquivo gerado. Eis a sua saída: 0. Vamos então dar dois exemplos muito simples. Além de definir arrays.bin não possui estrutura: ele “não sabe” que dentro dele mora o array a. writearr roda silenciosamente: não há nenhuma saída na tela. pelo menos em Engenharia. e necessita ser instalado à parte. porém muito esclarecedores. são 240.0385 3 numpy.1473 0.0870 0.6567 0. podendo também ser comprada pela Internet. O programa usa uma rotina disponível em numpy.8. rand.bin e impressas com formato na tela.5785 0.0846 0.6097 0. a partir da qual 3 instâncias de a são lidas do arquivo a.2511 0.-r .py — Escreve um arquivo binário contendo 3 “linhas”.bin: a escritura utiliza o método tofile. programadora ou programador. proporciona um tipo chamado array. close () # # # # abre um loop em gera um escreve arq binário para escrita 3 " linhas " array com 10 números aleatórios uma " linha " Na prática. A referência completa de Numpy está disponível em domínio público (Oliphant.7737 0. O tipo permite na prática substituir listas (tipo list). É importante observar que o arquivo a. 2006).3156 0. tofile ( fob ) fob .py. uma “linguiça” de 240 bytes. mostrado na listagem 1. pois ele “já faz parte” da variável a a partir do momento em que ela é criada.

Via de regra. um arquivo a. no tamanho 18pt. no arquivo fqiemp. que colunas queremos utilizar. bem como espessuras ou tamanhos nós desejamos. agora. 1. float . é preciso explicar: 5 6 7 8 9 Gera um arquivo de saída no padrão Encapsulated Postscript. cada uma das quais com um array de 10 float’s. nós vamos sempre gerar pares de arquivos (quase idênticos) .emf está pronto para ser visualizado (com um clique). write ( %5. O nome do arquivo de saída. nós vamos plotá-la com o programa Gnuplot fiqemp.eps .pdf mediante o comando epstopdf a. isto é. um arquivo a. inserido em documentos. o arquivo de saída de um programa Gnuplot não é um arquivo texto.eps. que símbolos ou tipos de linhas. Gnuplot permite gerar arquivos de imagem em qualquer um destes formatos (e muitos outros!). e .10) # lê um array com 10 floats # imprime com formato na tela for e in a : stdout . plotá-la.Matemática Aplicada 22 Listagem 1. . rb ) # abre o arquivo binário for k in range (3): # loop em 3 " linhas " a = fromfile ( fib .1 O nome do arquivo de saída.py — Escreve um arquivo binário contendo 3 “linhas”. Em Linux. 1 2 3 4 5 6 7 8 9 10 11 12 # !/ usr / bin / python # -* . em preto-ebranco.png. mas um arquivo com uma descrição gráfica qualquer. close () O que vemos são os números aleatórios das 3 instâncias de a escritas pelo programa writearr. write ( \ n ) fib .emf.8: readarr.jpg. que usa a mesma convenção de Python (a bem da verdade. É para isto que serve Gnuplot. uma tela com o gráfico deverá se abrir para visualização interativa). Extensões comuns de nomes de arquivos que indicam imagens são .. Formato do eixo y. de C). etc. . Neste texto. bin .coding : iso -8859 -1 -* from __future__ import print _functio n from numpy import fromfile # para escrever na tela from sys import stdout fib = open ( a .dat. Gera um arquivo que mostra as convenções utilizadas neste “terminal”. e o nome do arquivo de saída (na falta de um nome para o arquivo de saída. em Windows. Este arquivo pode ser visto na figura 1.py. Um programa Gnuplot especifica o arquivo de onde vêm os dados. .4 f % e ) stdout . com tipo Times Roman. Nós já temos a FDA empírica da vazão máxima anual no Rio dos Patos.3 – Gnuplot Mas como é a “cara” da função distribuição acumulada empírica? Nós gostaríamos de “ver” a função.eps e .plt: Como sempre.emf (esta última em Windows).eps é facilmente conversível no arquivo a.

Uma última observação de cunho estético. e ??. dat using 1:2 notitle with points pt 7 # -----------------------------------------------------------------------------# agora no mundo de Windows # -----------------------------------------------------------------------------set terminal emf monochrome Times New Roman 18 set output test . usando o tipo Times New Roman. as figuras que são geradas por programas Gnuplot descritos explicitamente. no tamanho 18 pt. emf test set output fqiemp . gera o arquivo fqiemp. compare com as legendas). O mesmo que a linha 7. com símbolo 7 (veja a convenção na figura 1.emf. Mude o tipo de arquivo de saída para emf. a escolha de Times-Roman para . e cujas listagens . eps set format y %3. Utilizar um tipo de letra diferente nas figuras e no texto é ligeiramente inconsistente.plt são dadas no texto. Entretanto. Nome do eixo x.1 e 1. utilizam o tipo postscript Times-Roman. veja por exemplo as figuras 2. do ponto de vista tipográfico.1): gera o arquivo fqiemp.eps. Nome do arquivo de dados a ser utilizado.Roman 18 set output test . Neste texto. emf replot exit 10 11 12 13 17 18 19 20 21 Mostra o reticulado da escala.9: fiqemp. Plota novamente. Olhe bem para o tipo utilizado nas figuras 1. use pontos. na figura 1.plt — programa para plotar a FDA empírica do Rio dos Patos 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 set encoding iso_8859_1 # ------------------------------------------------------------------------------# no mundo de linux # ------------------------------------------------------------------------------set terminal postscript eps monochrome Times . usando todas as definições que não tiverem sido mudadas (só mudamos o “terminal” de saída).3 – Gnuplot Listagem 1. podemos ver a FDA empírica gerada por fqiemp.2: este não é o tipo utilizado no restante do texto (por exemplo.1. Finalmente. agora. O nome do arquivo de saída. Já as figuras geradas para fim ilustrativo utilizam o mesmo tipo que o texto. Nome do eixo y.23 1.plt.2. colunas para x e y.1 f set grid set xlabel Vazão máxima anual ( m3 / s ) set ylabel FDA empírica plot fqiemp . O nome do arquivo de saída. eps test set output fqiemp .

a Weibull é definida apenas para q ≥ 0.3) é muito limitada: é óbvio que nenhum destes 69 valores da tabela 1. Também é óbvio que valores maiores do que máximo de 660 m3 s−1 poderão ocorrer no futuro (em relação a 1999 . É praticamente impossível não existir o tipo Times-Roman em seu sistema operacional Linux. que é o que se espera de qualquer vazão em rios — nenhum rio tem vazão negativa. Na preparação de um texto mais bem-elaborado tipograficamente você deve.1 – Ajuste de uma função A definição da FDA empírica em (1. ). e a 1 em x → +∞). faça um trabalho no mínimo um pouco melhor do que a FDA empírica foi capaz de fazer para prever as probabilidades da vazão máxima anual no Rio dos Patos — mas espere para ver o resultado! Vamos tentar ajustar uma fórmula aos dados. é do gosto do freguês. Mas isto. .3. além de ser outra história. e isto é uma poderosa fonte de crítica à posição de plotagem ingênua que nós utilizamos em (1.Matemática Aplicada Terminal Test show ticscale −1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 9 22 23 24 24 (color) filled polygon: rotated ce+ntred text te d by +4 left justified centre+d text right justified test of character width: 12345678901234567890 ro ta linewidth lw 6 lw 5 lw 4 lw 3 lw 2 lw 1 pattern fill 3 4 5 6 5 ro ta te d by −4 5 de g de g 0 1 2 7 8 Figura 1. . F (q) = 1 − exp −(q/λ)k .1: Convenções do terminal postscript eps monochrome 18 Times-Roman a saída em postscript. uma fórmula. . foi feita em nome da simplicidade e da universalidade.4) Não existe absolutamente nenhum motivo transcedental para utilizar (1. A fórmula que escolheremos é a da distribuição de Weibull.3): ela prevê que a probabilidade de uma vazão máxima anual maior do que 660 m3 s−1 é nula! Em suma. 1. (1. é nossa esperança que uma relação analítica. utilizar o mesmo tipo nas figuras e no texto.1. ao contrário do que acontece no jogo de dados. jamais se repetirá. A rigor. nenhum rio corre do mar para suas cabeceiras. e praticamente impossível não existir o tipo Times New Roman em seu sistema operacional Windows.4): ela apenas atende aos requisitos fundamentais de uma FDA (tende a 0 em x → −∞. se possível. e de Times New Roman para a saída em EMF.

plt — como ajustar uma FDA analítica (Weibull) aos dados da FDA empírica 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 set encoding iso_8859_1 # ------------------------------------------------------------------------------# no mundo de linux # ------------------------------------------------------------------------------set terminal postscript eps monochrome Times . \ F ( x ) with lines notitle lt 1 lw 3 # -----------------------------------------------------------------------------# agora no mundo de Windows # -----------------------------------------------------------------------------set terminal emf monochrome Times New Roman 18 set output weibullfit .3 – Gnuplot 1.0 .1 f set grid set xlabel Vazão máxima anual ( m3 / s ) set ylabel FDA set xrange [0:1000] set yrange [0:1] set xtics 0 .1 set samples 10000 plot fqiemp .exp ( -(( x / lambda )** k )) fit F ( x ) fqiemp .Roman 18 # ------------------------------------------------------------------------------# ajusta lambda e k # ------------------------------------------------------------------------------lambda = 1000.8 0.9 0. eps set format y %3.0 0.0 0 100 200 300 400 500 Vazão máxima anual (m3/s) 600 700 Figura 1.1 0. dat using 1:2 notitle with points pt 7 .5 0. emf replot exit .0 F ( x ) = 1.0.4 0.6 0.2: FDA da vazão máxima anual.2 0.100 set ytics 0 .7 FDA empírica 0. dat using 1:2 via lambda .0 k = 1.25 1.10: weibull.3 0. Rio dos Patos Listagem 1. k set output weibullfit .

000 -0.10. os valores maiores de vazão máxima.0300336 : 0.6 Usando Gnuplot.05594 (0. plote em tons de cinza a área debaixo da curva y = x para x = 2. ou seja.283 +/ .000 donde λ = 233.486.346 1.plt.1.Matemática Aplicada 26 No programa weibullfit.135%) correlation matrix of the fit parameters : lambda k lambda k 1.486 = 2.1.000902019 Asymptotic Standard Error ========================== +/ .62023. quando a aparência das mesmas for “quebrada”. comentários adicionais são: 9–10 Os valores iniciais de lambda e k influenciam nos valores finais encontrados — ou não.10. um projeto probabilístico é a definição de um valor de corte q cuja probabilidade de excedência seja menor que um certo risco predeterminado α. para o Rio dos Patos. final sum of squares of residuals : 0. change during last iteration : -6. muitas vezes você precisará fazer várias tentativas com os valores iniciais até ter sucesso.0604353 rel . É possível aumentar a espessura das curvas. k = 2. Gnuplot produz informações na tela sobre o ajuste requisitado pelo comando fit.0 .5495%) (2. o comando fit da linha 12 não consegue ajustar a curva F (x).3 mostra o gráfico gerado: note como a cauda da direita.0. 11 22 23 É possível definir funções que serão depois plotadas. Suponha que. nós desejemos calcular o valor q da vazão máxima anual .4 – Python de novo: projeto probabilístico De fato. Quanto vale esta área? 1. veja como Gnuplot lida facilmente com o ajuste dos valores de λ e de k aos dados de que dispomos. Por exemplo. com lw (line width): o número a seguir especifica a espessura desejada: veja a figura 1. É possível aumentar o número de pontos utilizados para traçar curvas. Na listagem 1. mostrado na listagem 1.18025 e -06 degrees of freedom ( FIT_NDF ) rms of residuals ( FIT_STDFIT ) = sqrt ( WSSR / ndf ) variance of residuals ( reduced chisquare ) = WSSR / ndf Final set of parameters ======================= lambda k = 233. uma vez que as maiores cheias seriam subestimadas! Exercícios Propostos 1.62023 : 67 : 0. as últimas linhas da saída em tela são After 11 iterations the fit converged . são mal ajustados: F (q) subestima o valor de q para probabilidades altas (próximas de 1): o uso da Weibull para este conjunto de dados seria desastroso. A figura 1. se mudarmos a linha 9 para lambda = 1.

3 0.2 0. mas sim uma tabela na qual devemos interpolar o valor desejado de q. . il é para “lower”: são os índices do intervalo que contém xc.4 0. e em seguida calcule o yc correspondente interpolando linearmente entre os valores da coluna y para o mesmo intervalo. F (q) = 1 − α.05 (5%). uma função é definida com a palavra reservada def. mostrado na listagem 1. A dissecação do módulo e da função interp é 6 9 Em Python.7 0.8 0. Quando a F (q) é a FDA empírica.11. procure o intervalo em que ele se encontra na coluna x da tabela. dado um valor xc.py. 1 − F (q) = α. == é um operador lógico que retorna True se os operandos forem iguais. Primeiramente nós precisamos escrever uma função que. O intervalo se inicia igual ao intervalo da tabela toda.4 – Python de novo: projeto probabilístico 400 500 600 700 Vazão máxima anual (m3/s) 800 900 1000 Figura 1. Isto significa que precisamos resolver a equação P {Q > q} = 1 − P {Q ≤ q} = α. O módulo interp.1 0. assert significa “assegure-se de que”. arquivo interp.5) para q.0 0. 17–18 iu é para “upper”.5 0. (1. Esta rotina estará disponível para qualquer programa Python por meio de uma declaração do tipo from interp import interp .3: Ajuste de uma FDA Weibull aos dados de vazão máxima anual do Rio dos Patos cuja probabilidade de excedência em um ano qualquer seja α = 0. faz isto.9 0.0 0 100 200 300 1.27 1.6 FDA 0. não existe uma equação para se resolver. interp não é um programa: ele é um módulo que contém uma única função (que possui também o nome interp).

basta resolver (1.x [ il ])) # y interpolado 19–24 Este é um algoritmo de busca binária: o índice iu vai diminuindo. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # !/ usr / bin / python # -* .55m3 s−1 . y ): nx = len ( x ) ny = len ( y ) assert nx == ny # x e y devem ser listas com tamanhos iguais # deve haver pelo menos 2 pontos if nx < 2: exit ( " interp : n = % d deve ser >= 2\ n " % nx ) if ( xc < x [0]) or ( xc > x [ nx -1]): # xc deve estar no intervalo da lista x exit ( " xc = % lf fora de alcance : % f % f \ n " % ( xc . da Weibull com os valores de k e de λ encontrados anteriormente).11: interp. O programa é muito óbvio. Para projetar a partir da F (x) analítica (isto é. x [0] . até que a diferença entre os dois seja igual a 1.12. é comum em Hidrologia (e em outras disciplinas em que se utiliza critérios de risco) dizer que q20 é a “vazão de 20 anos de tempo de recorrência”. e interpola um valor qproj nesta tabela. e não necessita de maiores explicações. Lembre-se da equação da reta em Geometria Analítica. 28–31 Uma interpolação linear padrão. Estude-o. está no arquivo fqiemp. x [ nx -1])) # -----------------------------------------------------------------------------# inicia uma busca binária # -----------------------------------------------------------------------------iu = nx . A vazão com risco de 5% de excedência calculada é q20 = 462. como sabemos. x . ou o índice il vai aumentando. Este programa. Como 5% = 1/20. podemos escrever um programa que a utilize. ppbemp.coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from __future__ import division def interp ( xc .Matemática Aplicada 28 Listagem 1.il > 1): im = ( iu + il )//2 if ( xc <= x [ im ] ): iu = im else : il = im # -----------------------------------------------------------------------------# interpola linearmente . e retorna # -----------------------------------------------------------------------------dx = ( x [ iu ] .x [ il ]) # delta x dy = ( y [ iu ] . Agora que temos uma função de interpolação linear.py (“projeto probabilístico a partir da distribuição empírica”) mostrado na listagem 1.py — módulo com função para calcular uma interpolação linear.y [ il ]) # delta y m = dy / dx # coeficiente angular return ( y [ il ] + m * ( xc .dat). e compreenda-o.5) analiticamente: .1 il = 0 while ( iu . simplesmente lê a tabela com a FDA empírica (que.

99573.12: ppbemp. qq ) # projeto para risco de exc .62023 = −2.7 Usando Gnuplot (é claro).95 . close () # fecha o arquivo de entrada # importa interp from interp import interp qproj = interp (0.486 = 2. rt ) # abre o arquivo de dados ( entrada ) qq = [] # tabela inicialmente vazia FF = [] # tabela inicialmente vazia # loop nas linhas do arquivo for linha in fin : campo = linha . o método que utilizamos para ajustar a FDA da Weibull. exp −(q20 /λ)k = 0. dat . append ( Fi ) fin . float ( campo [1])) qq .2 f \ n " % qproj ) # fim de papo F (q20 ) = 0. e plote novamente.8 Com Gnuplot. O uso de outros métodos de ajuste. q20 /233.908 Observe que este é um valor consideravelmente menor que o da própria distribuição empírica! Como já havíamos comentado baseados na análise visual da figura 1. Você acha que a vazão média do Rio dos Patos está mudando com o tempo? . 1 − exp −(q20 /λ)k = 0. Fi ) = ( float ( campo [0]) .29 1. 1. q20 = 354.4 – Python de novo: projeto probabilístico Listagem 1. e não deve ser utilizada para projetos probabilísticos: às vezes uma tabela de dados usada corretamente é melhor que um modelo matemático ajustado com ferramentas computacionais sofisticadas! Além disso. notadamente o método dos momentos e o método da máxima verossimilhança. Exercícios Propostos 1. FF . provavelmente produziria resultados muito melhores. usando o comando fit de Gnuplot. existem outros métodos para o ajuste de distribuições de probabilidade. e de outras distribuições de probabilidade. plote a vazão média anual do Rio dos Patos em função do tempo.py — projeto probabilístico a partir da distribuição empírica 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # !/ usr / bin / python # -* . ajuste uma reta às vazões médias em função do tempo no Rio dos Patos.95. split () # separa os campos ( qi .995731/2. append ( qi ) FF . a distribuição ajustada subestima as vazões com tempos de recorrência altos.coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from __future__ import division fin = open ( fqiemp . é incomum: em Probabilidade e Estatística.3.52004.05.95.62023 = 1. de 5% print ( " qproj = %8.486)2. −(q20 /233.

derivar. resolver equações diferenciais. MACSYMA. net using Lisp GNU Common Lisp ( GCL ) GCL 2. (1.6. Por exemplo: você sabe quanto é (a + b)4 ? Não? Digitando maxima na linha de comando você obterá Maxima 5. integrar. See the file COPYING .5 – Maxima Maxima é a linguagem de processamento simbólico mais antiga que existe: ela se chamava.7 ( a . As explicações se seguem: 1–2 Declara que k e lam são variáveis reais. a média de uma distribuição cuja FDA é F (x) é dF dx. GCL ) Distributed under the GNU Public License . você encontrará: (% i1 ) ( a + b )^4 . The function bug_report () provides bug reporting information . donde ∞ d x µ= 1 − exp −(x/λ)k dx. k . em função de λ e de k. Dedicated to the memory of William Schelter . analiticamente. nem à integral. A mudança de nome ocorreu quando o código se tornou livre. (1.1 http :// maxima . Maxima vai parar e perguntar se k é integer — apesar da linha 1! 3–4 5 .21. (% o2 ) (% i3 ) quit ().’. No caso da Weibull.6) µ= x dx x∈D onde D é o domínio de validade da variável aleatória. A listagem 1. b (b + a) 4 + 4 a b 3 + 6 a 2 b 4 2 3 4 + 4 a b + a O comando quit().Matemática Aplicada 30 1. (% i1 ) Continuando a digitar. Vamos fazer algo um pouco mais sofisticado: suponha que você deseje calcular a média de população da distribuição Weibull. quando foi criada.7) dx 0 A derivada ficou intencionalmente indicada: estou supondo que nós somos preguiçosos. O símbolo $ no fim de cada linha omite a “resposta” de Maxima. que nós encontramos na seção anterior. a . etc. com Maxima. calcular transformadas de Laplace. o normal é encerrar cada comando com ‘. Maxima é capaz de fazer álgebra. Por definição.max. x ≥ 0. em função de seus dois parâmetros λ e k. isto é útil quando executamos uma série de comandos de Maxima em “batch” (em série) a partir de um arquivo . e não estamos interessados em ver o resultado de cada um deles. sourceforge .13 mostra uma maneira de calcular µ.. (% o1 ) (% i2 ) expand (%). o devolverá para a linha de comando. Maxima suporá que k e lam são positivos em seus cálculos. Em seções interativas. e não queremos calculá-la manualmente. Sem a linha 5.

13: mulambdak.1 http :// maxima .. k+1 . que em probabilidade se chama função densidade de probabilidade. max ) read and interpret file : # p / home / nldias / work / graduacao / matap / aulas / mulambdak . 6 Define F (F (x)): note que não é F(x)! Note também que a atribuição. Calcula a integral definidora da média..8) . noninteger ) $ F : 1 .( . sourceforge . The function bug_report () provides bug reporting information . real ) $ assume ( k > 0) $ assume ( lam > 0) $ declare ( [ k ] . noninteger ) x k (% i7 ) F : 1 . See the file COPYING . real ) (% i4 ) assume ( k > 0) (% i5 ) assume ( lam > 0) (% i6 ) declare ([ k ] . x ) (% i9 ) mu : integrate ( x fdp . inf ) k + 1 (% o9 ) gamma ( . max (% i2 ) declare ([ k ] . real ) (% i3 ) declare ([ lam ] . na variável fdp. x .31 1.5 – Maxima Listagem 1.max 7 8 é Maxima 5. mas sim com ‘:’. GCL ) Distributed under the GNU Public License .21. real ) $ declare ( [ lam ] .0 . calcule a derivada de f (x) = ln(sen(ex )). que nós vamos encontrar muitas vezes neste curso. (% i1 ) batch ( mulambdak . inf ) .exp ( . ‘=’ fica reservado para igualdade.9 Com Maxima.max.max — cálculo da média da distribuição Weibull em em função de seus parâmetros λ e k 1 2 3 4 5 6 7 8 declare ( [ k ] .-) lam k (% o9 ) mulambdak . a . mas que não vem ao caso detalhar agora. armazena a derivada de F (x).6.x . em Maxima..-) ) lam (% i8 ) fdp : diff (F . O resultado analítico que nós obtivemos com Maxima é µ = λΓ Exercícios Propostos 1. O resultado de “rodar” mulambdak. net using Lisp GNU Common Lisp ( GCL ) GCL 2. não é feita com ‘=’ (como em Python ou Gnuplot).. com o comando maxima -b mulambdak. k . 0 . x ) $ mu : integrate ( x * fdp . gamma significa a função gama Γ(x).7 ( a .exp ( -( x / lam )^ k ) $ fdp : diff (F . Dedicated to the memory of William Schelter . max Na linha (%o9). k (1.

2 2 .Matemática Aplicada 1. calcule 1 32 ∞ 1 x3/2 dx. 1.10 Com Maxima.11 Com Maxima. obtenha as raízes de 3 29 x3 + x2 − x + 15 = 0.

2 Um pouco de polinômios. 48 48 12 3 33 (2. 1 13 17 11 f (x) = − x4 + x3 − x2 + x. e. Agora. e com Maxima. mas uma candidata natural é um polinômio de grau 5. • possuir derivada igual a 0 em x = 4. 5/2). A dissecação de achapol. Resolve um sistema linear 5 × 5 em a. Existem muitas curvas com estas propriedades. f (2) = 7/2. podemos obter facilmente a.1) . A saída de achapol. d. 0). integrais. e o valor de g(x) em x = 4. d.max é mostrada na listagem 2. Define o valor de f (x) em x = 0. em função de a. séries . Portanto. c. f (x) = ax4 + bx3 + cx2 + dx + e. 2. e. 1. 7/2) e (4. .1 – Integração numérica: motivação Suponha que você deseje traçar uma curva com as seguintes propriedades: • passar pelos pontos (0. d. g(4) = 0. g(x) = dx f (0) = 0. 4. f (1) = 5/2. df . b. (2. b. uma vez que existem 5 propriedades — ou graus de liberdade — na lista acima. 4).max é a seguinte: 1–2 3–7 8 Define f (x) e g(x).max da listagem 2.2 Portanto. b. . c. com o programa achapol. (1.1. 2. f (4) = 4. c.

x =2 .d . a . [a . e ]) . eq2 = -.--. eq3 : f .Matemática Aplicada 34 Listagem 2. net using Lisp GNU Common Lisp ( GCL ) GCL 2. c . eq4 = 4 .. eq4 = 4 .-. x = 0) (% o4 ) e (% i5 ) ev ( eq2 : f .1 . x = 4) (% o7 ) e + 4 d + 16 c + 64 b + 256 a (% i8 ) ev ( eq5 : g . GCL ) Distributed under the GNU Public License . k . É claro que esta integral pode ser calculada analiticamente com Maxima: (% i1 ) [ a : -1/48 . eq5 = 0] . 1 13 17 11 (% o1 ) [ . x = 4) (% o8 ) d + 8 c + 48 b + 256 a 5 7 (% i9 ) solve ([ eq1 = 0 . 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 .max — Polinômio com propriedades definidas 1 2 3 4 5 6 7 8 f : a * x ^4 + b * x ^3 + c * x ^2 + d * x + e .b .1 http :// maxima .7 ( a . c : -17/12 . x ) 3 2 (% o3 ) 4 a x + 3 b x + 2 c x + d (% i4 ) ev ( eq1 : f . (% i1 ) batch ( achapol . d . sourceforge . b .6.c . The function bug_report () provides bug reporting information .1: achapol. [a . 4 3 2 x 13 x 17 x 11 x (% o2 ) . x =0 . x =1 . eq2 = 5/2 . d : 11/3] .----. eq5 = 0] . c = . g : diff (f .--.21. e ]) 2 2 1 13 17 11 (% o9 ) [[ a = .+ ---48 48 12 3 (% i3 ) integrate (f . b : 13/48 .2: Saída de achapol. x ). x = 2) (% o6 ) e + 2 d + 4 c + 8 b + 16 a (% i7 ) ev ( eq4 : f .x .-] 48 48 12 3 (% i2 ) f : a * x ^4 + b * x ^3 + c * x ^2 + d * x . d = --. solve ([ eq1 = 0 .+ ----. b = --. 1321 (% o3 ) ---90 . eq5 : g . x =4 . eq4 : f . Dedicated to the memory of William Schelter . x =4 . See the file COPYING . e = 0]] 48 48 12 3 (% o9 ) achapol . x = 1) (% o5 ) e + d + c + b + a (% i6 ) ev ( eq3 : f . max Suponha agora que você deseje calcular I= 5 1 f (x) dx.max Maxima 5. .--. eq2 : f . --. eq3 = -.5) . eq3 = 7/2 . . eq1 : f . Listagem 2.

Suponha portanto que você não soubesse que I = 1321/90.. etc. com o uso de dois trapézios. f (1)) e (5. e você pode querer ter uma idéia inicial do valor da integral. mas não por uma fórmula.35 f (x) 2. 2 2 Note que estamos muito próximos do valor verdadeiro — com apenas 2 trapézios.50. 4 6 7 7 7 7 7 7 7 7 7 7 7 7 8 b1 Logo. Para isto. (% o4 ) 1 .1: Integração numérica de uma função (% i4 ) bfloat (%). • a função pode ser difícil de integrar analiticamente. Mas existe uma alternativa analítica mais inteligente do que trapézios: como temos 3 pontos. nem todas as integrais podem ser calculadas assim. considerando o valor verdadeiro 14. nós podemos aproximar a curva por uma parábola do 2 o grau passando .6778 (atenção para o arredondamento). Entretanto. por uma série de motivos: • a função pode não possuir uma integral em forma fechada.1 – Integração numérica: motivação 4 f (x) 3 2 h(x) 1 0 0 1 2 3 4 5 x Figura 2. f (5)).1: uma das aproximações mais óbvias — mas também mais grosseiras — é substituir a função por uma reta ligando os pontos (1. I = 1321/90 ≈ 14. A área do trapézio é a nossa primeira aproximação para a integral: I0 = f (1) + f (5) × 4 = 12.6778! Mas pode ser melhorada. basta calcular f (3) e somar as áreas dos dois trapézios resultantes: I1 = f (1) + f (3) f (3) + f (5) ×2+ × 2 = 14. mas fosse capaz de calcular em princípio tantos pontos de f (x) quantos fossem necessários: qual a sua aposta para o valor de I? Considere a figura 2.000. 2 Nada mal. • a função pode ser definida por pontos.

max redefine h(x) com os coeficientes encontrados.3: passaquad. eq3 : ev (h .1 . mostrado na listagem 2. f (5)). você não está muito contente com o resultado do Problema 2. (3. f (1)). I (2.max é mostrada na listagem 2. e já calcula a integral de h(x) entre 1 e 5.4.5). x =3) = y3 . x =3 $ y5 : f . Um caminho geral para a integração numérica está aberto: aumentar o número de “elementos” de integração (no nosso caso foram trapézios) e/ou aumentar a ordem do polinômio aproximador da função por um certo número de pontos. f (5)).1 Se f (x) = sen x. h : h .b . 2 3 2 23 5 x + x+ dx 16 16 4 Até agora nós avaliamos 3 alternativas de integração numérica de f (x): com um trapézio. eq2 : ev (h .1.max — parábola h(x) = ax2 +bx+c passando por (1. e acha os coeficientes a.max. No embalo.(17/12)* x ^2 + (11/3)* x . faz este trabalho. f (3)) e (5. eq3 ] . O erro relativo de cada estimativa é δ= Ik − I . b. A saída de passaquad. f (3)) e (5. abc . abc : % .3. x =5) = y5 .5000. A parábola h também é mostrada na figura 2. com dois trapézios. Exercícios Propostos 2.2) Uma única parábola foi capaz de estimar I com um erro relativo ligeiramente superior a 1%. integrate (h . f (1)). (3. c ]) . O programa passaquad. 1 2 3 4 5 6 7 8 9 10 11 12 f : ( -1/48)* x ^4 + (13/48)* x ^3 . c da parábola h(x) = ax2 + bx + c que passa por (1. y1 : f . Com os coeficientes a. A tabela 2. e com uma parábola. solve ( [ eq1 . b. qual é a estimativa de I = π 0 f (x) dx = 2 com um trapézio ? 2.Matemática Aplicada 36 por estes 3 pontos.1 dá um resumo dos resultados alcançados. x =1 $ y3 : f . nós podemos calcular — analiticamente — nossa próxima aproximação: I2 = = 2 1 1 h(x) dx 2 − 29 = = 14.[a . eq2 .x .2 Provavelmente. . x =1) = y1 . c de h(x). Listagem 2. Este é o conteúdo da próxima seção. passaquad.1. x =5 $ h : a * x ^2 + b * x + c$ eq1 : ev (h .

x = 1) (% i4 ) ev ( y3 : f . c = -]] 16 16 4 (% i11 ) abc : % 3 23 5 (% o11 ) [[ a = . 1) e (π. abc ) 2 3 x 23 x 5 (% o12 ) .37 2.----..--. 2. 0). denominado “Regra do Trapézio”.1 com dois trapézios. b = --.2 – A regra do trapézio Listagem 2.. c) Aproxime a integral de f (x) pela integral da parábola cúbica h(x) = ax3 + bx2 + cx + d passando pelos mesmos pontos acima. 0).2.+ ---. x = 3) (% i5 ) ev ( y5 : f . b . [a .+ 16 16 4 (% i13 ) integrate (h . 1 .. x = 1) = y1 5 (% o7 ) c + b + a = 2 (% i8 ) eq2 : ev (h . de aumentar o número de trapézios. Isto nos levará ao método talvez mais simples de integração numérica que vale a pena mencionar. 5) 29 (% o13 ) -2 (% o13 ) passaquad .--. max 2 3 4 11 x 17 x 13 x ( .4: Saída de passaquad.3 12 48 48 4 3 2 x 13 x 17 x 11 x (% o2 ) . e com h (π/2) = 0. (π/2.+ .+ ----. x = 5) = y5 15 (% o9 ) c + 5 b + 25 a = -4 (% i10 ) solve ([ eq1 . x = 3) = y3 31 (% o8 ) c + 3 b + 9 a = -8 (% i9 ) eq3 : ev (h . plote f (x) = sen x e a aproximação g(x) obtida no Problema 2. b = --. c = -]] 16 16 4 (% i12 ) ev ( h : h . x = 5) 2 (% i6 ) h : c + b x + a x (% i7 ) eq1 : ev (h ..+ ----...1) x (% i2 ) f : ---. eq2 .3 Com Gnuplot. eq3 ] . e entre x = pi/2 e π. b) Aproxime a integral pela integral da parábola quadrática g(x) = ax2 + bx + c passando pelos pontos (0.2 – A regra do trapézio Vamos começar a melhorar nossas estimativas de I pelo método de “força bruta”.----. 2. . x . max a) Aproxime a integral I do Problema 2.-.---.max batching / home / nldias / work / graduacao / matap / aulas / passaquad .. c ]) 3 23 5 (% o10 ) [[ a = .+ ---48 48 12 3 (% i3 ) ev ( y1 : f . entre x = 0 e π/2..

.2: A regra do trapézio.3) pode ser re-escrita: I3 = f (x0 ) + f (x1 ) f (x1 ) + f (x2 ) f (xn−1 ) + f (xn ) + + .2 mostra a mesma função f (x) da seção anterior. entretanto.1483 14. n Prosseguindo.5000 0. É evidente que a área sob f (x) está agora muito bem aproximada com n = 8 trapézios. A figura 2. com n = 4 e n = 8 trapézios.7) .1: Estimativas numéricas de I e seus erros relativos δ.0000 0..4) (2. Integral Exato Um trapézio Dois trapézios Uma parábola f (x) 38 Valor δ 14.5000 0. xn = 5. . nós desenhamos 4 e 8 trapézios sob a curva f (x).0461 14. agora..6778 0 12. 2 (2. xn − x0 ∆x = . + ∆x 2 2 2 ∆x = f (x0 ) + 2 f (x1 ) + f (x2 ) + . O seu valor pode ser estimado por I3 = com x0 = 1.6) f (xi−1 ) + f (xi ) ∆x.3) (2.Matemática Aplicada Tabela 2. 2 i=1 n (2.0121 f (x) x0 x1 x2 x3 x4 x5 x6 x7 x8 x Figura 2. (2.5) (2. + f (xn−1 ) + f (xn ) 2 ∆x = (Se + 2Si ) .

Esta seção vale um módulo de Python.py. Uma implementação razoavelmente eficiente da regra do trapézio é mostrada nas primeiras 21 linhas de numint.a .5 .0 for k in range (1 . f ): trapezio (n . de forma muito ineficiente.8) (2. Isto é implementado.py é I3 ≈ 14. O erro está agora na 2a casa decimal. f ): integra f entre a e b com n trapézios deltax = (b .2 – A regra do trapézio (2.trapezio é que nós não temos uma idéia do erro que estamos cometendo.coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from __future__ import division def trapezio (n . é porque não conhecemos o valor exato de I! Um primeiro remédio para este problema é ficar recalculando a regra do trapézio com um número dobrado de trapézios. porque. f ) print ( I3 = %8.5: numint.1 .b .0031. até que a diferença absoluta entre duas estimativas sucessivas fique abaixo de um valor estipulado. Si = n−1 i=1 2.b .3%.4 f \ n % I3 ) A saída de quadraver1. na listagen 2.a . e o erro relativo é δ = 0.5 Listagem 2.a )/ n Se = f ( a ) + f ( b ) Si = 0.py — Integração numérica de f (x) com 8 trapézios 1 2 3 4 5 6 7 8 9 10 # !/ usr / bin / python # -* . Listagem 2. n ): xk = a + k * deltax Si += f ( xk ) I = Se + 2* Si I *= deltax I /= 2 return I # define Se # inicializa Si # calcula Si # cálculo de I O programa quadraver1.py — Integração numérica.6: quadraver1. na próxima rotina .6). ou 0. regra do trapézio 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # !/ usr / bin / python # -* .coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from __future__ import division 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 .9) f (xi ).6328.39 com Se = f (x0 ) + f (xn ). que nós vamos denominar numint. se estamos utilizando integração numérica. O “problema” com numint.py calcula a integral de f (x) com 8 trapézios (listagem 2.

67777.Matemática Aplicada 40 do módulo numint (listagem 2.b .0001. e depois basta aplicar (2.a .b .py calcula a integral de f (x) com erro absoluto estipulado menor que 0.a .b . denominada trapepsilon. a rotina trapepsilon em numint. recalculada do zero calcula o erro absoluto atualiza a estimativa " velha " O programa quadraver2. reaproveitando todos os cálculos. f ): t r a p e p s i l o n l en t o ( epsilon .a . O que nós precisamos fazer agora é somar f (x1 ) + f (x3 ) + f (x5 ) + f (x7 ) ao Si que já tínhamos. f ): calcula a integral de f entre a e b com erro absoluto epsilon .5 .py). " velha " loop dobra o número de trapézios estimativa " nova " .7.7: note a continuação da numeração de linhas dentro do mesmo arquivo numint.coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from __future__ import division from numint import t r a p e p s i l o n l en t o def f ( x ): return (( -1/48)* x **4 + (13/48)* x **3 + ( -17/12)* x **2 + (11/3)* x ) ( I4 . eps )) II = 1 4 .a . denominada trapepsilonlento.b . para n = 4. eps ) = t r a p e ps i l o n l e n t o (0.py — Integração numérica ineficiente. Nosso último esforço. Com 4 casas decimais.1 .0001 1 2 3 4 5 6 7 8 9 10 11 12 13 # !/ usr / bin / python # -* . nós vemos a integração numérica de f (x) com n = 4 e depois com n = 8 trapézios.9.py — Integração numérica ineficiente de f (x) com 0. f ) print ( I4 = %8. e não precisa ser recalculada. Repare que Si para n = 4 é parte do valor de Si para n = 8. na listagem 2.5 f % ( I4 .7). 6 7 7 7 7 7 7 7 7 7 7 7 7 7 7 delta = ( I4 .5 f eps = %8. δ = 0. eps ) # # # # # # # # estabelece um erro inicial grande um único trapézio primeira estimativa .7: numint. f ) while eps > epsilon : n *= 2 In = trapezio (n . de forma ineficiente eps = 2* epsilon n = 1 Iv = trapezio (1 .00000075. e imprime a estimativa da integral. f ) eps = abs ( In .2: nela.Iv ) Iv = In return ( In . Isto é feito na última rotina de numint.py.II )/ II print ( delta = %10. Se permanece o mesmo. com erro absoluto préestabelecido 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 def t r a p e p s i l o n l e nt o ( epsilon . e mostrada na listagem 2. corrige este problema. o erro absoluto e o erro relativo (em relação ao valor exato conhecido) encontrados: I4 = 14. Volte um pouco à figura 2. = 0.0001 . Esta soma já foi calculada na integral com 4 trapézios. .8 f % delta ) = O problema com trapepsilonlento é que todos os pontos que já haviam sido calculados por trapezio são recalculados em cada iteração (verifique). Listagem 2. este é um resultado exato! Listagem 2. Si = f (x2 ) + f (x4 ) + f (x6 ) (note que os índices já estão definidos para o caso n = 8).8: quadraver2.00003. De fato.

f ) print ( I5 = %12.trapezio. δ = 0.II )/ II print ( delta = %12.. o erro absoluto e o erro relativo (em relação ao valor exato conhecido) encontrados: I5 = 14. π 0 sen(x) dx pela regra do trapézio π 0 2. sen(x) dx pela regra do .5 .py — Integração numérica eficiente de f (x) com 0. de forma eficiente eps = 2* epsilon n = 1 Se = f ( a ) + f ( b ) deltax = (b .trapepsilon. f ): calcula a integral de f entre a e b com erro absoluto epsilon .py — Integração numérica eficiente.9: numint.000001 . = 0. 6 7 7 7 7 7 7 7 7 7 7 7 7 7 7 delta = ( I5 . Listagem 2. n . aproxime I = com 10 trapézios.10: quadraver3.1 . eps ) # # # # # # # # # # # # # # # # # # # # estabelece um erro inicial grande n é o número de trapézios Se não muda primeiro deltax primeiro deltax /2 Si " velho " I " velho " executa o loop pelo menos uma vez Si " novo " dobra o número de trapézios divide deltax por dois idem para dx2 apenas os ímpares ..b .0 n *= 2 deltax /= 2 dx2 = deltax /2 for i in range (1 . eps ) = trapepsilon (0.Iv ) Siv = Sin Iv = In return ( In .a . f ): trapepsilon ( epsilon . e imprime a estimativa da integral.6777776.a )/ n dx2 = deltax /2 Siv = 0.b .7 f eps = %12.2 – A regra do trapézio Listagem 2. conforme estipulado.coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from __future__ import division from numint import trapepsilon def f ( x ): return (( -1/48)* x **4 + (13/48)* x **3 + ( -17/12)* x **2 + (11/3)* x ) ( I5 .41 2.2): xi = a + i * deltax Sin += f ( xi ) Sin = Sin + Siv In = ( Se + 2* Sin )* dx2 eps = abs ( In .00000001.0000005.5 Usando Python e numint. com erro absoluto préestabelecido 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 .000001 1 2 3 4 5 6 7 8 9 10 11 12 13 # !/ usr / bin / python # -* . Note que I5 é exato até a 6a casa decimal.8 f % delta ) = Exercícios Propostos 2.10) calcula a integral de f (x) com erro absoluto estipulado menor que 0.7 f % ( I5 . eps )) II = 1 4 .0 Iv = Se * dx2 while eps > epsilon : Sin = 0. pula os ptos já calculados ! soma sobre os novos ptos internos aproveita todos os ptos já calculados I " novo " calcula o erro absoluto atualiza Siv atualiza Iv O programa quadraver3. aproxime I = trapézio com precisão absoluta menor ou igual a 1 × 10−5 .py (listagem 2.a .4 Usando Python e numint.000001.

xn = x0 + nh.10) erf(x) ≡ √ π u=0 A função erro está definida em Gnuplot e em Maxima. (% o1 )/ T / 1 . f0 ). x0 + 2h]. (x1 .8 Estenda numint com uma rotina simpson para calcular a regra de Simpson com 2n intervalos.1. 10−6 ). 3 com fn = f (xn ). mostrado na figura 2.py. Como obtê-la? Uma maneira “força bruta” é utilizar trapepsilon com uma precisão razoável (digamos.Matemática Aplicada 2. Existe uma maneira mais inteligente de calcular erf(x): ela se baseia em integrar 2 a série de Taylor do integrando. 3 2. etc.--. Considere agora o cálculo de uma integral particularmente importante. obtenha a regra de Simpson para 5 pontos. Algumas vezes.3.plt (listagem 2.7 Dobrando o número de pontos de 2 para 4. que foi capaz de baixar o erro relativo para pouco mais de 1%. u .2 podem ser muito “custosas” em termos do número de operações de ponto flutuante necessárias. e−u .dat.. 2 6 24 120 1 Sim! existem parábolas cúbicas. gerar um arquivo.11) calcula a função em um grande número de pontos.+ . . deduza a regra de Simpson: x0 +2h 42 f (x) dx ≈ x0 h [f0 + 4f1 + f2 ] .. gera um arquivo de dados vererf.plt utiliza a função erf pré-definida em Gnuplot e plota uma comparação: a linha contínua é a erf de Gnuplot.12) plota o resultado. + 2f2n−2 + 4f2n−1 + f2n ] . f1 ) e (x2 .10) .6 Dada f (x) definida no intervalo [x0 . é possível ser mais inteligente. a função erro.+ -. e plotar o resultado para “ver a cara” da erf(x). . . O programa vererf. .3 – Aproximação de integrais com séries: a função erro Integrações numéricas tais como as mostradas na seção 2. 2. quárticas. interpolando a função g(x) = ax2 + bx + c através dos pontos (x0 .u ^2) .0 . Observe que vererf.u 2 4 6 8 10 u u u u + -. (2. mas não em Python < 2.py (listagem 2. e os pontos são os valores obtidos por vererf. f2 ) e calculando sua integral. . e uma rotina simpepsilon para calcular uma integral numérica pela regra de Simpson com precisão estipulada.. 2.7. x0 +4h f (x) dx ≈ x0 h [f0 + 4f1 + 2f2 + 4f3 + f4 ] . definida por x 2 2 e−u du. Baseie-se em trapezio e trapepsilon.-. Maxima permite calcular os primeiros termos: (% i1 ) taylor ( exp ( . 3 generalize: b≡x0 +2nh f (x) dx ≈ a≡x0 h [f0 + 4f1 + 2f2 + . Um exemplo disto foi o cálculo de I2 com uma única parábola quadrática1 no fim da seção 2. e então o programa vererf.

xmin )/ nx erf = 0.0. eps set format y %3.6 f \ n % ( xl . dat .coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from __future__ import division from math import exp .\ erf ( x ) title Gnuplot with lines lt 1 lw 2 # -----------------------------------------------------------------------------# agora no mundo de Windows # -----------------------------------------------------------------------------set terminal emf monochrome Times New Roman 18 set output vererf . close () # # # # # # # # # # # # # # # de 0 a 3 em 100 passos de dx erf (0) = 0 arquivo de saída 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 saída Listagem 2.0 e -6 . emf replot exit . xu . eps ) = trapepsilon (1. wt ) xl = xmin fou .py — Cálculo da função erro por integração numérica 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 # -* .0 fou = open ( vererf .x * x ) xmin = 0.43 2. erf )) for k in range ( nx ): xu = xl + dx (I . write ( %8.5 set ytics 0 .1 f set grid set xlabel x set ylabel erf ( x ) set xrange [0:3] set yrange [0:1] set xtics 0 .1 plot vererf . write ( %8.75 .6 f %8.plt — Plotagem da função erro por integração numérica versus a erf(x) pré-definida em Gnuplot 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 set encoding iso_8859_1 # ------------------------------------------------------------------------------# no mundo de linux # ------------------------------------------------------------------------------set terminal postscript eps monochrome Times .11: vererf.0 nx = 100 dx = ( xmax .0. f ) erf = erf + (2. erf )) xl = xu fou . pi from numint import trapepsilon def f ( x ): return exp ( .12: vererf. sqrt .6 f \ n % ( xu .0 xmax = 3. dat using 1:2 title trapepsilon with points pt 7 ps 0.0/ sqrt ( pi ))* I fou .Roman 18 set output vererf .6 f %8.3 – Aproximação de integrais com séries: a função erro Listagem 2. xl .

4 0.Matemática Aplicada 1.6 erf(x) 0.0 0 0.5 0.2 0.11) Portanto. 2. com trapepsilon e = 1 × 10−6 . Admitindo que está tudo bem. n! (2. Não é muito difícil reconhecer nos denominadores os fatoriais de 0. nós conseguimos a série de Taylor de erf(x)! .5 3 trapepsilon Gnuplot 44 Figura 2.0 0. 4 e 5. Em geral. 3.5 1 1. 1.1 0. e as potências dos dobros destes valores nos expoentes de u.12) Cuidado: não é toda série que permite a troca impune da ordem de integração e da soma (infinita) da série.8 0. devemos procurar os teoremas relevantes que nos permitem esta troca de ordem. entretanto.3: Função erf(x) calculada por integração numérica. x 0 e−u du = = = = 2 x ∞ (−1)n n! n=0 ∞ 0 n=0 ∞ (−1)n 0 u2n du n! u2n du x (−1)n x2n+1 n! 2n + 1 n=0 ∞ (−1)n n=0 x2n+1 .5 x 2 2. (2n + 1)n! (2. versus a erf pré-definida em Gnuplot. e−u = 2 ∞ (−1)n n=0 u2n .3 0. Em princípio. e é feita até o 10o termo.7 0.9 0. A expansão é em torno de u = 0.

versus a erf pré-definida em Gnuplot. do arquivo erfs.6 erf(x) 0. com erf_1.7 0.0 0. Bn = 2n + 1 = Bn−1 + 2.14).3 0. Mais uma coisa: a série de erf(x) só contém potências ímpares: portanto.dat e plotar com o programa vererf1. gerar um arquivo de saída vererf1. e vale a relação erf(−x) = − erf(x). erf(x) é uma função ímpar.2 0.5 1 1.13) Em outras palavras.plt (listagem 2.15).4 0. Com isto. Cn = n! = Cn−1 × n. ele é formado pelo produto Bn Cn . . O denominador é mais complicado. o numerador An de cada novo termo da série é o anterior vezes −x2 .4: Função erf(x) calculada com série de Taylor. temos uma rotina em Python para calcular erf(x). podemos escrever vererf1.9 0. no módulo erfs.8 0. chamada erf_1(x).1 0.13 Agora.5 3 Figura 2. Ainda falta encontrar uma maneira computacionalmente eficiente de passar do termo n − 1 para o termo n.py. Os resultados continuam idênticos à erf(x) de Gnuplot. Vamos a isto: x2n+1 An ≡ (2n + 1)n! Bn Cn = = = (−1)n x2(n−1+1)+1 2(n − 1 + 1) + 1) n(n − 1)! (−1)n−1 x2(n−1)+1 × [−x2 ] 2(n − 1) + 1) + [2] [n](n − 1)! An−1 × (−x2 ) (Bn−1 + 2)(Cn−1 × n) (2.5 x 2 2.5 0.0 0 2. As linhas correspondentes a erf_1(x) são mostradas na listagem 2.3 – Aproximação de integrais com séries: a função erro erf_1 Gnuplot 0. e as relações completas de recursão são An = x2n+1 = An−1 × (−x2 ).py (listagem 2.45 1.

n ) = erf_1 ( xu ) fou .6 f %8. close () # # # # # # # # # de 0 a 3 em 100 passos de dx arquivo de saída limite inferior a partir de xmin erf (0) = 0 loop novo limite superior # imprime até aqui # atualiza limite inferior # fecha o arquivo de saída . n ) # # # # # # # # # # # # # # # # mesma precisão garante entrada no while primeiro A primeiro B primeiro C primeiro n primeiro termo da série primeira soma da série loop incrementa n novo A novo B novo C novo termo seu valor absoluto soma na série Listagem 2.0 xmax = 3. erf )) xl = xu fou . write ( %8. dat . wt ) xl = xmin fou .0.Matemática Aplicada 46 Listagem 2. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # !/ usr / bin / python # -* .13: Cálculo de erf(x) com uma série de Taylor. pi def erf_1 ( x ): epsilon_erf = 1.coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from __future__ import division from math import sqrt . write ( %8.py — Cálculo da função erro com série de Taylor entre 0 e 3.coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n from __future__ import division from math import exp . sqrt .6 f \ n % ( xl .14: vererf1. pi from erfs import erf_1 xmin = 0.6 f %8.0 e -6 eps_erf = 2* epsilon_erf A = x B = 1 C = 1 n = 0 termo = A /( B * C ) s = termo while eps_erf > epsilon_erf : n += 1 A *= ( .6 f \ n % ( xu .x * x ) B += 2 C *= n termo = A /( B * C ) eps_erf = abs ( termo ) s += termo return (2/ sqrt ( pi ) * s .xmin )/ nx fou = open ( vererf1 .0 nx = 100 dx = ( xmax .0)) for k in range ( nx ): xu = xl + dx ( erf . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # !/ usr / bin / python # -* .

usa este fato para impedir que o número de termos continue crescendo. É preciso enfatizar que erf em erfs.15: vererf1. É possível obter fórmulas que aproximam erf(x) com menos termos. Para calcular erf(3.py ainda não é uma rotina “profissional”. e este é o motivo de erf_1 devolver também n. no intervalo (digamos) de 0 a 3.py.\ erf ( x ) title Gnuplot with lines lt 1 lw 2 # -----------------------------------------------------------------------------# agora no mundo de Windows # -----------------------------------------------------------------------------set terminal emf monochrome Times New Roman 18 set output vererf1 . que ainda está acima da precisão especificada de 0. a rotina erf_1 fica mais lenta à medida em que |x| cresce. nos dá erf_1(3) = 0.4.1 f set grid set xlabel x set ylabel erf ( x ) set xrange [0:3] set yrange [0:1] set xtics 0 .Roman 18 set output vererf1 .dat. erf é uma opção vantajosa em relação à integração numérica.75 . . você mesmo(a). B e C. consequentemente. mas que erf_1(100) dá um erro de ponto flutuante.plt — Plotagem da função erro calculada com série de Taylor versus a erf(x) pré-definida em Gnuplot 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 set encoding iso_8859_1 # ------------------------------------------------------------------------------# no mundo de linux # ------------------------------------------------------------------------------set terminal postscript eps monochrome Times . Precisamos descobrir o valor de x para o qual erf_1 produz 0. A rotina erf na listagem 2. Abramowitz e Stegun (1972).0. Mesmo assim.16.0. é possível obter uma mistura de métodos analíticos e numéricos que costuma ser amplamente superior ao uso de um método numérico “puro” (por exemplo a regra do trapézio) para a obtenção de resultados semelhantes. nós precisamos de n = 43 termos.1 plot vererf1 .6) com erf_1. eps set format y %3. Por tentativa e erro.999978 . emf replot exit Embora formalmente correta. Precisamos também saber com quantos termos este cálculo foi feito. uma olhada em vererf1. dat using 1:2 title erf_1 with points pt 7 ps 0. com esforço analítico adicional. por exemplo.000001. Porém.999999. há muitas operações de ponto flutuante envolvendo A. também no arquivo erfs. e muitos testes dentro do while. que erf(100) retorna 1.3 e 2.99999952358847277 . Como já vimos nas figuras 2. que é igual a 1. O número de termos usado ainda é potencialmente muito grande.6: veja.0.5 set ytics 0 . A lição desta seção é a seguinte: em geral. erf(x) ≈ 1 para |x| 3. encontramos erf_1(3. Verifique.3 – Aproximação de integrais com séries: a função erro Listagem 2. uniformemente.0 para 6 casas decimais. Exemplos deste fato vão reaparecer nos capítulos seguintes.6) = 0.47 2.

Matemática Aplicada 48 Listagem 2. .x * x ) B += 2 C *= n termo = A /( B * C ) eps_erf = abs ( termo ) s += termo return 2/ sqrt ( pi ) * s # limita o número de termos a 43 # # # # # # # # # # # # # # # # mesma precisão garante entrada no while primeiro A primeiro B primeiro C primeiro n primeiro termo da série primeira soma da série loop incrementa n novo A novo B novo C novo termo seu valor absoluto soma na série Exercícios Propostos 2.6: return -1. limitado a no máximo 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. compare o resultado obtido com integração numérica. seção 6. Exemplo 2) Obtenha uma série para x F (x) ≡ 0 t−1/2 e−t dt.9 (Bender e Orszag (1978).0 e -6 eps_erf = 2* epsilon_erf A = x B = 1 C = 1 n = 0 termo = A /( B * C ) s = termo while eps_erf > epsilon_erf : n += 1 A *= ( .py — Cálculo de erf(x) com série de Taylor.6: return 1.0 elif x < -3.2.16: erfs.0 epsilon_erf = 1.

nem a equação diferencial nem sua solução "existem"em x = 0. forçada eternamente por um seno: dy y + = sen x.= sin ( x ) dx x ode2 (% .1: resolve-eqdif — Solução de uma EDO com Maxima 1 2 3 4 5 6 7 8 9 10 (% i2 ) (% o2 ) (% i3 ) (% o3 ) y dy . em geral. Considere uma equação diferencial de 1a ordem simples.= sin ( x ) x dx dy y -. nós resolvemos esta equação com Maxima.1) Maxima nos informa de que a solução geral é da forma y(x) = sen x − x cos x + c . para c = 0. sen x = 1. sen x y(x) = − cos x. x É evidente que.+ . x 49 . x ) sin ( x ) . Entretanto. dx x Na listagem 3. x de modo que existe uma solução para a equação partindo de x = 0 se nós impusermos a condição incial y(0) = 0.1. De fato: x→0 lim x→0 lim sen x − cos x = 1 − 1 = 0. x Agora.1 – Solução numérica de equações diferenciais ordinárias Solução analítica de uma EDO com Maxima. Listagem 3.3 Solução numérica de equações diferenciais ordinárias 3.x cos ( x ) + % c y = ---------------------x (3. y .+ -.

Matemática Aplicada
1.5

50

1.0

0.5

y(x)

0.0

−0.5

−1.0

−1.5

0

10

20
x

30

40

50

Figura 3.1: Solução da equação (3.1). O resultado está mostrado na figura 3.1. Claramente, existe uma parte “transiente” da solução, dada por sen x/x, que “morre” à medida que x cresce, e existe uma parte periódica (mas não permanente!) da solução, dada por cos x, que “domina” y(x) quando x se torna grande. Nós dizemos que cos x é parte estacionária da solução. 3.1.1 – Solução numérica; método de Euler A coisa mais simples que pode ser pensada para resolver a equação diferencial em questão é transformar a derivada em uma diferença finita: ∆y y + = sen x ∆x x Isto é um começo, mas não é suficiente. Na verdade, o que desejamos é que o computador gere uma lista de x’s (uniformemente espaçados por ∆x), e uma lista de y’s correspondentes. Obviamente, como os y’s devem aproximar a função, não podemos esperar deles que sejam igualmente espaçados! Desejamos então: x0 , x1 , . . . , xn onde com os correspondentes y0 , y1 , . . . , yn . Como ∆x será fixo, podemos escrever nossa equação de diferenças 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 também a mais instável, é usar i: yi+1 − yi yi + = sen(xi ). ∆x xi xi = i∆x,

51

3.1 – Solução numérica de equações diferenciais ordinárias

Listagem 3.2: fracasso.py — Um programa com o método de Euler que não funciona
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # !/ usr / bin / python # -* - coding : iso -8859 -1 -* from __future__ import u n i c o d e _ l i t e ra l s from __future__ import print _functio n # ---------------------------------------------------------# cria listas com condições iniciais # ---------------------------------------------------------x = [0.0] y = [0.0] dx = 0.01 n = int (50/0.01) from math import sin for i in range (0 , n ): # de 0 até ... n -1 !!!! xn = ( i +1)* dx yn = y [ i ] + ( sin ( x [ i ]) - y [ i ]/ x [ i ])* dx x . append ( xn ) y . append ( yn ) fou = open ( fracasso . out , wt ) for i in range ( n ): fou . write ( %12.6 f %12.6 f \ n % ( x [ i ] , y [ i ])) fou . close ()

Note que é agora possível explicitar yi+1 em função de todos os outros valores em i: yi+1 = yi + sen(xi ) − yi ∆x. xi

Este é um exemplo de um método explícito: o novo valor da função em xi+1 (yi+1 ) só depende de valores calculados no valor anterior, xi . Um olhar um pouco mais cuidadoso será capaz de prever o desastre: na fórmula acima, se partirmos de x0 = 0, teremos uma divisão por zero já no primeiro passo! Muitos não veriam isto, entretanto, e nosso primeiro programa para tentar resolver a equação diferencial numericamente se chamará fracasso.py, e está mostrado na listagem 3.2 O resultado, mostrado na listagem 3.3 é o seguinte fracasso: Listagem 3.3: Saída de fracasso.py
Traceback ( most recent call last ): File "./ fracasso . py " , line 15 , in < module > yn = y [ i ] + ( sin ( x [ i ]) - y [ i ]/ x [ i ])* dx Z e r o D i v i s i o n E r r o r : float division by zero

Isto já era previsível: quando i == 0 no loop, x[0] == 0 no denominador, e o programa para com uma divisão por zero. Para conseguir fazer o método numérico funcionar, nós vamos precisar de mais análise! De volta à equação diferencial, note que para que exista uma solução na vizinhança de x = 0 é necessário que o limite limx→0 y(x)/x exista; nós devemos ter y(x) = L, x→0 x lim onde L é uma constante finita a determinar. Mas, de nossa condição inicial,
x→0

lim y(x) = 0 ⇒ L = 0.

Matemática Aplicada

52

Listagem 3.4: sucesso.py — Um programa com o método 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 equação diferencial # dy / dx + y / x = sen ( x ) # pelo método de Euler . Uso : # # ./ sucesso . py <dx > < arquivo de saída > # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division from sys import argv dx = float ( argv [1]) # tamanho do passo x = [0.0 , dx ] # condições inciais em x y = [0.0 , 0.0] # condições iniciais em y n = int (50/ dx ) from math import sin , cos # solução numérica 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 médio 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 médio = , %10.5 f % erro ) fou = open ( argv [2] , wt ) for i in range (0 , n +1): # imprime o arquivo de saída fou . write ( %12.6 f %12.6 f \ n % ( x [ i ] , y [ i ]) ) fou . close ()

Vamos então reescrever a equação de diferenças usando o limite: y1 = y0 + sen(x0 ) − y0 ∆x = 0. x0

=0, lim x0 →0

Na prática, isto significa que nós podemos começar o programa do ponto x1 = ∆x, y1 = 0! Vamos então reescrever o código, que nós agora vamos chamar, é claro, de sucesso.py, que pode ser visto na listagem 3.4 A saída de sucesso.py gera o arquivo sucesso.out, que nós utilizamos para plotar uma comparação entre a solução analítica e a solução numérica, mostrada na figura 3.2 Na verdade, o sucesso é estrondoso: com ∆x = 0,01, nós conseguimos produzir uma solução numérica que é visualmente indistinguível da solução analítica. Uma das coisas que o programa ‘sucesso.py‘ calculou foi o erro relativo médio
n


i=1

yi − y(xi ) y(xi )

(onde yi é a solução numérica, e y(xi ) é a solução exata no mesmo ponto xi ). Para ∆x = 0,01, = 0,02619, ou seja: menos de 3%. O preço, entretanto, foi “alto”: nós precisamos de um ∆x bem pequeno, e de 50/0,01 = 5000 pontos para gerar a solução. Será possível gerar uma solução tão boa com, digamos, 100 pontos?

5 solução numérica solução analítica 1.5 0 10 20 x 30 40 50 Figura 3.0 0.py.5 -1.5 0 10 20 x 30 40 50 Figura 3.5 ∆x = 0.0 -1.5 y(x) 0.1) com a saída de sucesso.5 ∆x = 0. para ∆x = 0.2: Comparação da solução analítica da equação (3.5 -1.5.5 y(x) 0.53 3. para ∆x = 0. 1.3: Comparação da solução analítica da equação (3.0 -0.0 -0. .01.1 – Solução numérica de equações diferenciais ordinárias 1.0 0.01 solução numérica solução analítica 1.1) com a saída de sucesso.0 -1.py.

Matemática Aplicada

54

A figura 3.3 mostra o resultado de rodar sucesso.py com ∆x = 0,5, muito maior do que antes. O erro médio relativo agora pulou para = 1,11774, nada menos do que 111%, e muito pior do que a figura acima faz parecer à primeira vista! 3.1.2 – Um método implícito, com tratamento analítico Nosso desafio é desenvolver um método numérico que melhore consideravelmente a solução mesmo com um ∆x grosseiro, da ordem de 0,5. Nossa abordagem será propor um método implícito: xi + xi+1 yi+1 − yi yi + yi+1 + = sen . ∆x xi + xi+1 2 Note que tanto o termo y/x quando sen x estão sendo agora avaliados no ponto médio entre xi e xi+1 . Lembrando que ∆x = xi+1 − xi , yi+1 : xi + xi+1 yi + yi+1 yi+1 − yi = sen + , ∆x xi + xi+1 2 1 1 1 1 xi + xi+1 + + yi − + = sen , ∆x xi + xi+1 ∆x xi + xi+1 2 2xi+1 2xi xi + xi+1 yi+1 − yi = sen . ∆x(xi+1 + xi ) ∆x(xi+1 + xi ) 2

yi+1

Uma rápida rearrumação produz yi+1 xi+1 − yi xi = yi+1 ∆x(xi+1 + xi ) xi + xi+1 sen , 2 2 xi ∆x(xi+1 + xi ) xi + xi+1 = yi + sen . xi+1 2xi+1 2

(3.2)

Repare que a condição inicial y(0) = 0 não produz nenhuma singularidade em (3.2) para i = 0 ⇒ x0 = 0, y0 = 0. O programa que implementa este esquema é o sucimp.py, mostrado na listagem 3.5. O resultado é um sucesso mais estrondoso ainda, e pode ser visto na figura 3.4. Agora, o erro médio relativo baixou para = 0,02072, que é ainda menor do que o do método de Euler com ∆x = 0,01, ou seja: com um ∆x 50 vezes menor! 3.1.3 – Runge-Kutta O preço que nós pagamos pelo método extremamente acurado implementado em sucimp.py foi trabalhar analiticamente a equação diferencial, até chegar à versão “dedicada” (3.2). Isto é bom! Porém, às vezes não há tempo ou não é possível melhorar o método por meio de um “pré-tratamento” analítico. Nossa discussão agora nos levará a um método excepcionalmente popular, denominado método de Runge-Kutta. Dada a equação dy = f (x, y) dx nós podemos tentar estimar a derivada “no meio” do intervalo h (estamos mudando a notação: até agora, usávamos ∆x, mas h é uma forma usual de explicitar o passo

55

3.1 – Solução numérica de equações diferenciais ordinárias

Listagem 3.5: sucimp.py — Método de Euler implícito
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 # !/ usr / bin / python # -* - coding : iso -8859 -1 -* # ---------------------------------------------------------# sucimp : resolve a equação diferencial # dy / dx + y / x = sen ( x ) # usando um método implícito sob medida # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division dx = 0.5 # passo em x x = [0.0] # x inicial y = [0.0] # y inicial n = int (50/ dx ) # número de passos from math import sin , cos # loop na soluão numérica for i in range (0 , n ): xn = ( i +1)* dx xm = x [ i ] + dx /2.0 yn = y [ i ]* x [ i ]/ xn + ( dx * xm / xn )* sin (( x [ i ]+ xn )/2) x . append ( xn ) y . append ( yn ) erro = 0.0 for i in range (1 , n +1): # calcula o erro relativo médio yana = sin ( x [ i ])/ x [ i ] - cos ( x [ i ]) erro += abs ( ( y [ i ] - yana )/ yana ) erro /= n ; print ( erro relativo médio = , %10.5 f % erro ) fou = open ( sucimp . out , wt ) for i in range (0 , n +1): # imprime o arquivo de saída fou . write ( %12.6 f %12.6 f \ n % ( x [ i ] , y [ i ]) ) fou . close ()

1.5

∆x = 0,5
solução numérica solução analítica

1.0

0.5

y(x)

0.0

-0.5

-1.0

-1.5 0 10 20 30 40 50

x

Figura 3.4: Comparação da solução analítica da equação (3.1) com a saída de sucimp.py, para ∆x = 0,5.

Matemática Aplicada
1.5 ∆x = 0,5 solução numérica solução analítica

56

1.0

0.5

y(x)

0.0

-0.5

-1.0

-1.5

0

10

20 x

30

40

50

Figura 3.5: Comparação da solução analítica da equação (3.1) com a saída de euler2.py, para ∆x = 0,5. quando se trata do método de Runge-Kutta, ou métodos similares): dy dx = f (x + h/2, y(x + h/2))
x+h/2

O problema é que nós não conhecemos y em x + h/2! Isto pode ser contornado, entretanto, usando o método de Euler de 1a ordem para primeiro estimar y(x+h/2): yn+1/2 ≈ yn + hf (xn , yn )/2. Um método mais acurado será portanto k1 = hf (xn , yn ), k2 = hf (xn + h/2, yn + k1 /2), yn+1 = yn + k2 Vamos tentar este método e ver como ele se compara com nossos esforços anteriores. Vamos manter h = 0,5 como nos casos anteriores. No entanto, nós ainda sofremos do cálculo da derivada em x = 0; por isto, nós vamos mudar o cálculo da derivada, colocando um if na função ff que a calcula. Note que, do ponto de vista de eficiência computacional, isto é péssimo, porque o if será verificado em todos os passos, quando na verdade ele só é necessário no passo zero. No entanto, o programa resultante, euler2.py (listagem 3.6), fica mais simples e fácil de entender, e esta é nossa prioridade aqui. O resultado é mostrado na figura 3.5. O resultado é muito bom, com um erro absoluto médio = 0,02529. Mas nós podemos fazer melhor, com o método de Runge-Kutta de 4a ordem! Não vamos deduzir as equações, mas elas seguem uma lógica parecida com a do método de

6 f %12. %10.5 f % erro ) fou = open ( euler2 . n +1): yana = sin ( x [ i ])/ x [ i ] .6 f \ n % ( x [ i ] .0 else : return sin ( x ) . wt ) for i in range (0 .0 # calcula o erro relativo médio for i in range (1 . y + k1 /2) yn = y + k2 return yn for i in range (0 .6: euler2 — Um método explícito de ordem 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 # !/ usr / bin / python # -* . y ) k2 = h * ff ( x + h /2 .y / x def eul2 (x . append ( yn ) erro = 0. n ): # loop da solução numérica xn = ( i +1)* h yn = eul2 ( x [ i ] . close () .0: # implementa a condição inicial return 0. n +1): # imprime o arquivo de saída fou .5 # passo em x x = [0. cos def ff (x .0] # y inicial n = int (50/ h ) # número de passos from math import sin . y [ i ] .coding : iso -8859 -1 -* # ---------------------------------------------------------# euler2 : resolve a equação diferencial # dy / dx + y / x = sen ( x ) # usando um método explítico de ordem 2 ( Euler ) # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division h = 0. write ( %12. y ): if x == 0.y .yana )/ yana ) erro /= n .h .0] # x inicial y = [0.57 3.cos ( x [ i ]) erro += abs ( ( y [ i ] . ff ) x . out .1 – Solução numérica de equações diferenciais ordinárias Listagem 3. print ( erro relativo médio = . append ( xn ) y . ff ): k1 = h * ff (x . y [ i ]) ) fou .h .

Desta vez.00007: o campeão de todos os métodos tentados até agora. yn + k3 ).5 f % erro ) fou = open ( rungek4 . y + k2 /2) k4 = h * ff ( x +h . wt ) for i in range (0 . .5 # passo em x x = [0. out . h k1 k2 = hf (xn + . yn + ).h . n +1): # imprime o arquivo de saÃŋda fou .h . %10.7. n ): # loop da soluÃğÃčo numÃľrica xn = ( i +1)* h yn = rk4 ( x [ i ] . O resultado é mostrado na figura 3.6 f %12.y / x def rk4 (x .7: rungek4 — Método de Runge-Kutta. print ( erro relativo mÃľdio = . append ( xn ) y . append ( yn ) erro = 0. y [ i ] . y [ i ]) ) fou .Kutta de ordem 4 k1 = h * ff (x . 6 3 3 6 Para o nosso bem conhecido problema. y ) k2 = h * ff ( x + h /2 . y ): estou integrando dy / dx = sen ( x ) . na listagem 3. yn ).0 # calcula o erro relativo mÃľdio for i in range (1 . y + k1 /2) k3 = h * ff ( x + h /2 .0] # x inicial y = [0. o método é implementado no programa rungek4.y / x if x == 0. k1 k2 k3 k4 yn+1 = yn + + + + .y .0 + k3 /3.6.Kutta de ordem 4 # ---------------------------------------------------------from __future__ import print _functio n h = 0.6 f \ n % ( x [ i ] . 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 # -* .0 + k2 /3. ff ): rk4 implementa um passo do mÃľtodo de Runge . write ( %12. yn + k2 /2). y + k3 ) yn = y + k1 /6. 2 2 k3 = hf (xn + h/2.0] # y inicial n = int (50/ h ) # nÞmero de passos from math import sin . n +1): yana = sin ( x [ i ])/ x [ i ] .0: return 0. e uma clara evidência da eficácia do método de Runge-Kutta.0 else : return sin ( x ) .0 + k4 /6. o erro absoluto médio foi = 0. close () ordem 2: k1 = hf (xn .cos ( x [ i ]) erro += abs ( ( y [ i ] . ff ) x . k4 = hf (xn + h.Matemática Aplicada 58 Listagem 3.coding : utf -8 -* # ---------------------------------------------------------# rungek4 : resolve a equaÃğÃčo diferencial # dy / dx + y / x = sen ( x ) # usando o mÃľtodo de Runge . cos def ff (x .yana )/ yana ) erro /= n .0 return yn for i in range (0 .

1) com a saída de rungek4. dx 3.1 Resolva.59 1.5 -1. ao valor L. necessário para produzir y(0) = 0. dx x x 3.py.5 0 10 20 30 40 50 x Figura 3. dx y(0) = 0.6: Comparação da solução analítica da equação (3.001.1 – Solução numérica de equações diferenciais ordinárias ∆x = 0. 3. resolva dy y ex + = . .0 -1.0 -0. dx x L estude a sensibilidade do h.3 Na equação dy y 2πx + = sen . e compare com a solução analítica: dy + y = x2 exp(−x).01 solução numérica solução analítica 1. para ∆x = 0. usando o método de Euler e o Método de Runge-Kutta de ordem 4: dy + xy = sen(x).5 3. Exercícios Propostos 3. y(0) = 1.5 y(x) 0. usando o método de Euler de ordem 2. y(x) = 0. utilizando Runge-Kutta: dy + y = sen(x).4 Utilizando um método implícito semi-analítico.5. = 0. 3.5 Resolva.0 0. dx y(0) = 1.2 Resolva.

Matemática Aplicada 60 .

(4.1) A sua solução pode ser obtida pelo método das características. (4.4) (4. u(x. 0) = 2x(1 − x).3) (4.50 1 0. 3) estão mostrados na figura 4. t) . ∂t ∂x u(x.1: Condição inicial da equação 4. ∂t ∂x u(x.2) A condição inicial. 4 3 2 0. 61 tempo u(x.3. Seja então o problema ∂u ∂u +2 = 0.1 – Advecção pura: a onda cinemática Considere a equação ∂u ∂u +c = 0.00 0 2 4 x 6 8 10 0 Figura 4.4 Solução numérica de equações diferenciais parciais 4. Observe que a solução da equação é uma simples onda cinemática.1. t) = g(x − ct). 2) e u(x. e é u(x. 1). juntamente com u(x. 0) = g(x).

mostrado na listagem 4.py 3 250 . T são os tamanhos de grade no espaço e no tempo. Claramente.n i.11) i. ∆t = T /Nt 62 (4. o esquema explícito que nós programamos jamais nos levará a uma solução numérica satisfatória para tempos da ordem de t = 1! . ∆x (4. Ela vai servir para desenferrujar nossas habilidades de programação de métodos de diferenças finitas. que por sua vez é lindo pelo próximo programa na sequência. ainda está bastante distante dos tempos mostrados na solução analítica da figura 4. e ∆t = 0. em t = 750∆t = 0.Matemática Aplicada Vamos adotar a notação un ≡ u(xi . com ∆x = L/Nx . surf1d-ins.py. ∆t 2∆x c∆t n un+1 = un − (u − un ). Por motivos que ficarão mais claros na sequência. O programa que implementa o esquema instável é o onda1d-ins. O resultado dos primeiros 750 intervalos de tempo de simulação é mostrado na figura 4. Repare como a solução se torna rapidamente instável. tn ).10) (4. obtemos o esquema de diferenças finitas explícito: un − un un+1 − un i i−1 i = −c i+1 .2. o que significa selecionar 3 saídas (além da condição inicial). Observe que para isto nós utilizamos uma lista (v).2.n Substituindo na equação (4. já conformados com o fracasso antecipado.12) (com c = 2 no nosso caso). Uma maneira simples de transformar as derivadas parciais em diferenças finitas na equação (4. Repare também como a solução numérica.7) (4.0005. tn = n∆t. mostrado na listagem 4. Este é um esquema incondicionalmente instável.py. nós o rodamos com o comando onda1d-ins.9) onde L.1.8) (4. i i i−1 2∆x i+1 (4.01. Nt são os números de divisões no espaço e no tempo. no caso. e vai fracassar. O programa gera um arquivo de saída binário. respectivamente. O único trabalho deste programa é selecionar algumas “linhas” da saída de onda1d-ins.py.3). ∆t un − un i−1 = i+1 + O(∆x2 ). i xi = i∆x.3) é fazer ∂u ∂t ∂u ∂x un+1 − un i = i + O(∆t).375.5) (4. Vamos fazer uma primeira tentativa. nós escolhemos ∆x = 0.1 (que vão até t = 4). cujos elementos são arrays. e Nx . de 250 em 250 intervalos de tempo ∆t.6) (4.

coding : iso -8859 -1 -* # ---------------------------------------------------------# onda1d . new ) = ( new .250 0.4 f % dx ) print ( # dy = %9. para t = 250∆t.py — Solução de uma onda 1D com um método explícito instável 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 # -* .125 0.2: Solução numérica produzida por onda1d-ins. float ) # apenas 2 posições no tempo # são necessárias ! def CI ( x ): # define a condição inicial if 0 <= x <= 1.0 u [ new .py.63 4.50 0.ins . i +1] . 500∆t e 750∆t.couhalf *( u [ old .0/ dt ) # número de pontos em t print ( # nx = %9 d % nx ) print ( # nt = %9 d % nt ) u = zeros ((2 .4 f % dt ) from numpy import zeros nx = int (10.000 10 Figura 4. nx ] = 0.ins .0005 print ( # dx = %9.0* dx ) # metade do número de Courant for n in range ( nt ): # loop no tempo # loop no espaço for i in range (1 . nx +1) . nx ): u [ new ./ onda1d .1 – Advecção pura: a onda cinemática Listagem 4.x ) else : return 0. t) 0. dat . i ] = u [ old . tofile ( fou ) # imprime a condição inicial old = False new = True c = 2. wb ) dx = 0. .01 dt = 0. close () 0.0* x *(1.375 tempo de simulação u(x. i ] . i ] = CI ( xi ) u [0].1: onda1d-ins.0/ dx ) # número de pontos em x nt = int (1.500 0.i -1]) u [ new .u [ old . py # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division fou = open ( onda1d .0 # celeridade da onda couhalf = c * dt /(2.0: return 2.00 0 2 4 x 6 8 0.ins resolve uma equação de onda com um método # explícito # # uso : .0 for i in range ( nx +1): # monta a condição inicial xi = i * dx u [0 .0 . tofile ( fou ) # imprime uma linha com os novos dados ( old . old ) # troca os índices fou .0 u [ new ].0] = 0.

write ( \ n ) fou .01 dt = 0.Matemática Aplicada 64 Listagem 4. dat . float .0005 print ( # dx = %9. close () . append ( u ) # guarda a última founam = surf1d .6 f % ( i * dx )) # escreve o " x " fou . py <m > <n > # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division from sys import argv dx = 0. py : imprime em <arq > <m >+1 saídas de # onda1d . rb ) # abre o arquivo com os dados from numpy import fromfile u = fromfile ( fin .0/ dx ) # número de pontos em x print ( # nx = %9 d % nx ) m = int ( argv [1]) # m saídas n = int ( argv [2]) # a cada n intervalos de tempo print ( # m = %9 d % m ) print ( # n = %9 d % n ) fin = open ( onda1d ./ surf1d .ésimo fou .2: surf1d-ins.ins . write ( %10. nx +1) v . nx +1) # lê a condição inicial v = [u] # inicializa a lista da " transposta " # para <m > instantes : for it in range ( m ): for ir in range ( n ): # lê <ir > vezes .4 f % dx ) print ( # dy = %9. wt ) # abre o arquivo de saída for i in range ( nx +1): fou . só guarda a última u = fromfile ( fin . dat print ( founam ) fou = open ( founam .ins .py — Seleciona alguns intervalos de tempo da solução numérica 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 # -* . write ( %10.ins .coding : iso -8859 -1 -* # ---------------------------------------------------------# surf1d .4 f % dt ) nx = int (10. float . write ( %10.ins .ins a cada <n > intervalos de tempo # # uso : .6 f % v [0][ i ]) # escreve a cond inicial for k in range (1 .6 f % v [ k ][ i ]) # escreve o k . m +1): fou .

mostre que isto funciona.14).15) ∆x é o número de Courant. de maneira que o lado esquerdo também tem que ser! Como conciliá-los? Fazendo a = α + i β.16).12) fracassa? Uma forma de obter a resposta é fazer uma análise de estabilidade de von Neumann. Mesmo para equações não-lineares. e substituindo: e(α−i β)∆t = 1 − i Co sen kl ∆x.16). onde ela importa.12) jamais será calculada com precisão infinita. .1 – Advecção pura: a onda cinemática Por que o esquema utilizado em (4. O erro ˜ de truncamento é n n ˜n (4. entretanto. e α∆t (4. nós estamos supondo que o erro cresce exponencialmente.12) se aplica tanto para u quanto para u. Por enquanto.13) i ≡ ui − ui . (4.20) sen(β∆t) = Co sen(kl ∆x). Note que (4. ea∆t = 1 − Co +i kl ∆x e − e−i kl ∆x 2 = 1 − i Co sen kl ∆x. N/2 n i No capítulo sobre atn i kl xi = l=1 ξl e e .12) é uma equação linear em u. (4. aqui. i = −1. donde ξl ea(tn +∆t) ei kl i∆x = ξl eatn ei kl i∆x − Co ξl eatn ei kl (i+1)∆x − ξl eatn ei kl (i−1)∆x .18) O lado direito é um número complexo. xi = i∆x. (4.16) séries de Fourier. 2 (4. Argumentando novamente com a linearidade. sempre será possível fazer pelo menos uma análise local de estabilidade. eα∆t [cos(β∆t) − i sen(β∆t)] = 1 − i Co sen kl ∆x. na forma i Co ≡ tn = n∆t. desta vez de (4. A análise de estabilidade de von Neumann consiste primeiramente em observar que. (4.65 4. em um computador real. O próximo passo da análise de estabilidade de von Neumman é escrever uma série de Fourier para n . nós só ˜i vamos fazer esta distinção de notação. ⇒ eα∆t cos(β∆t) = 1. entre u e u. e L é o tamanho do domínio em x.19) (4.14) onde c∆t (4. Isto só foi possível porque (4. N = L/∆x é o número de pontos da discretização em x. obtém-se a mesma equação para a evolução de n : ˜ i n+1 i = n i − Co ( 2 n i+1 − n i−1 ). e discuta o N/2 √ onde e é a base dos logaritmos naturais. O que o computador realmente calcula é um valor truncado un .Em (4. subtraindo as equações resul˜ n+1 n+1 tantes para ui e ui . ela vale para cada modo l de (4.17) eliminando o fator comum ξl eatn +i kl i∆x .

comparando-a com (4.12) (nosso esquema instável inicialmente empregado).21) é que ela introduz um pouco de difusão numérica. podemos reescrevê-la na forma un − un un − 2un + un un+1 − un i i−1 i i−1 i = −c i+1 + i+1 ∆t 2∆x 2∆t un − un ∆x2 un − 2un + un i+1 i−1 i+1 i i−1 = −c + .24) Não custa repetir: (4. Vamos a isto: utilizando novamente (4. Desejamos. 2 2∆x 2∆t ∆x (4. dx i 2 dx2 i du 1 d2 u ∆x + + O(∆x2 ). temos ξl ea(tn +∆t) ei kl i∆x = 1 ξl eatn ei kl (i+1)∆x + ξl eatn ei kl (i−1)∆x 2 − Co ξl eatn ei kl (i+1)∆x − ξl eatn ei kl (i−1)∆x . (4.24) é idêntica a (4. nós vemos que ela também é equivalente a esta última. O método de Lax Uma alternativa que produz um esquema estável é o método de Lax (estamos seguindo os passos de Numerical Recipes): un+1 = i 1 (un + un ) − Co(un − un ) . mas há um caminho mais rápido: o truque é perceber que se o fator de amplificação ea∆t for um número complexo com módulo maior que 1. de fato. (4. portanto.21) numericamente. donde eα∆t > 1.16) e substituindo em (4. o que só é possível se Co ≤ 1. o esquema será instável. devemos fazer uma análise de estabilidade antes de tentar implementar (4. 1 e+i kl ∆x + e−i kl ∆x − Co e+i kl ∆x − e−i kl ∆x ea∆t = 2 ea∆t = cos(kl ∆x) − i Co sen(kl ∆x) . i+1 i i−1 O que este termo adicional significa? A resposta é uma derivada numérica de ordem 2.Matemática Aplicada 66 As duas últimas equações formam um sistema não-linear nas incógnitas α β. é claro. O sistema pode ser resolvido: tg(β∆t) = Co sen(kl ∆x) ⇒ β∆t = arctg (Co sen(kl ∆x)) . fazer a = α − i β. A “mágica” de (4. i+1 i−1 i+1 i−1 2 (4.22) Nós podemos. com o termo adicional (∆x2 /2∆t) (un − 2un + un )/∆x2 . Note que β = 0. 2 dx i 2 dx i . que |ea∆t ≤ 1|.23) que é o critério de estabilidade de Courant-Friedrichs-Lewy. Porém.21). De fato.21). e o esquema de diferenças finitas é incondicionalmente instável. considere as expansões em série de Taylor ui+1 = ui + ui−1 = ui − du 1 d2 u ∆x + + O(∆x2 ).21) Agora que nós já sabemos que esquemas numéricos podem ser instáveis.

4. mostrado na listagem 4. isto significa que. devemos portanto verificar se D∂ u ∂x2 1. 2 dx i ∆x2 d2 u = 2ui + 2 ∆x2 + O(∆x2 ). surf1d-lax. ou seja. ou o esquema é estável com muita difusão numérica. O único trabalho deste programa é selecionar algumas “linhas” da saída de onda1d-lax. 2∆t Note que D tem dimensões de difusividade: D = L2 T−1 . a equação (4. “real”) que estamos simulando é c. que por sua vez é lindo pelo próximo programa na sequência. Mesmo assim.01. desde que o efeito da difusão seja muito menor que o da advecção que estamos tentando simular. O quanto isto nos prejudica? Não muito. u c ∆x D c. ou ele é instável. nós descobrimos que o critério para que o esquema seja acurado do ponto de vista físico é conflitante com o critério de estabilidade: enquanto que estabilidade demandava Co < 1. ∆x ∆x2 c. .21) — pode ser interpretada também como uma solução aproximada da equação de advecção-difusão ∂u ∂ 2u ∂u +c = D 2.25) Portanto. O programa gera um arquivo de saída binário.1 – Advecção pura: a onda cinemática d2 u ui+1 − 2ui + ui−1 = + O(∆x2 ).py. dx i (4. Isto praticamente elimina a possibilidade de qualquer uso sério de (4. Na prática. ∂u c ∂x u D ∆x2 1. o critério de que a solução seja também fisicamente acurada demanda que Co 1/2. vamos programá-lo! O programa onda1d-lax.0005 e ∆x = 0.py está mostrado na listagem 4. Co = 0.67 e some: ui+1 + ui−1 4.10. ∂t ∂c ∂x com D= ∆x2 . Como a velocidade de advecção (“física”. para c = 2.21). sim: estamos introduzindo um pouco de difusão na equação para amortecer as oscilações que aparecerão em decorrência da amplificação dos erros de truncamento. precisamos comparar isto com (por exemplo) a magnitude das velocidades introduzidas pela difusão numérica.3.24) — ou seja: o esquema de Lax (4. No entanto: não estamos então resolvendo a equação errada? De certa forma. 2∆t∆x c∆t = Co ∆x 2 1 2 Em outras palavras.py. Ele usa os mesmos valores ∆t = 0.

0/ dt ) # número de pontos em t print ( # nx = %9 d % nx ) print ( # nt = %9 d % nt ) u = zeros ((2 .py — Solução de uma onda 1D com um método explícito laxtável 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 # -* .6 f " % cou ) for n in range ( nt ): # loop no tempo for i in range (1 .lax . old ) # troca os índices fou .4 f % dt ) from numpy import zeros nx = int (10. nx ): # loop no espaço u [ new . dat . nx +1) .u [ old .x ) else : return 0. i +1] .0 .0 # monta a condição inicial for i in range ( nx +1): xi = i * dx u [0 . tofile ( fou ) # imprime a condição inicial old = False new = True c = 2.0* x *(1.Matemática Aplicada 68 Listagem 4.lax resolve uma equação de onda com um método # explícito # # uso : ./ onda1d .coding : iso -8859 -1 -* # ---------------------------------------------------------# onda1d .0: return 2.ins . i +1] + u [ old .4 f % dx ) print ( # dy = %9.0 # celeridade da onda cou = c * dt /( dx ) # número de Courant print ( " Co = %10. new ) = ( new . py # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division fou = open ( onda1d . float ) # apenas 2 posições no tempo # são necessárias ! def CI ( x ): # define a condição inicial if 0 <= x <= 1.0 u [ new . i ] = CI ( xi ) u [0]. close () .0/ dx ) # número de pontos em x nt = int (1.0] = 0.01 dt = 0.0005 print ( # dx = %9. tofile ( fou ) # imprime uma linha com os novos dados ( old .0 u [ new ].i -1]) cou *( u [ old .3: onda1d-lax.i -1]) ) u [ new . wb ) dx = 0.5*( ( u [ old . nx ] = 0. i ] = 0.

ésimo fou . Com isto. write ( %10. write ( \ n ) fou . “corrente acima” — na de língua inglesa.4 f % dx ) print ( # dy = %9. float . close () no caso.75 da simulação. o que significa selecionar 3 saídas (além da condição inicial). a solução está agora “amortecida” pela difusão numérica! Upwind melhor o esquema.4 f % dt ) nx = int (10. dat print ( founam ) fou = open ( founam . write ( %10. py : imprime em <arq > <m >+1 saídas de # onda1d . ∆t ∆x un+1 = un − Co un − un . nx +1) v . nós conseguimos chegar até o instante 0. neste chamado de esquema upwind — literalmente.6 f % v [ k ][ i ]) # escreve o k .3.lax . rb ) # abre o arquivo com os dados from numpy import fromfile u = fromfile ( fin . m +1): fou . só guarda a última u = fromfile ( fin .69 4. No entanto.6 f % v [0][ i ]) # escreve a cond inicial for k in range (1 .lax .26) .0/ dx ) # número de pontos em x print ( # nx = %9 d % nx ) m = int ( argv [1]) # m saídas n = int ( argv [2]) # a cada n intervalos de tempo print ( # m = %9 d % m ) print ( # n = %9 d % n ) fin = open ( onda1d . de 500 em 500 intervalos de tempo ∆t./ surf1d . nx +1) # lê a condição inicial v = [u] # inicializa a lista da " transposta " for it in range ( m ): # para <m > instantes : for ir in range ( n ): # lê <ir > vezes . O resultado dos primeiros 1500 intervalos de tempo de simulação é mostrado na figura 4.py 3 500 . append ( u ) # guarda a última founam = surf1d .py — Seleciona alguns intervalos de tempo da solução numérica 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 # -* . Observe que agora não há oscilações espúrias: o esquema é estável no tempo. py <m > <n > # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division from sys import argv dx = 0. dat . nós o rodamos com o comando onda1d-lax. a discretização utilizada é un − un un+1 − un i i−1 i = −c i .lax a cada <n > intervalos de tempo # # uso : .0005 print ( # dx = %9.1 – Advecção pura: a onda cinemática Listagem 4.4: surf1d-lax.lax .coding : iso -8859 -1 -* # ---------------------------------------------------------# surf1d . literatura Um esquema que é conhecido na literatura como indicado por representar termo advectivo em (4.6 f % ( i * dx )) # escreve o " x " fou . wt ) # abre o arquivo de saída for i in range ( nx +1): fou . float .lax . write ( %10. i i i i−1 (4.01 dt = 0.1) é o esquema de diferenças regressivas.

Claramente. . o resultado pode ser melhor para tratar a advecção.00 0 2 4 x 6 8 0. Antes de “colocarmos as mãos na massa”. Sk ≡ sen(kl ∆x). (4.000 10 Figura 4. Então. sabemos que devemos analisar analiticamente a estabilidade do esquema.500 0. Ele é um esquema menos acurado que os usados anteriormente. Vamos a isto: ξl ea(tn +∆t) ei kl i∆x = ξl eatn ei kl i∆x − Co ξl eatn ei kl i∆x − ξl eatn ei kl (i−1)∆x ea∆t ei kl i∆x = ei kl i∆x − Co ei kl i∆x − ei kl (i−1)∆x ea∆t = 1 − Co 1 − e−i kl ∆x ea∆t = 1 − Co + Co cos(kl ∆x) − i Co sen(kl ∆x).000 70 0.750 tempo de simulação u(x.27) Desejamos que o módulo do fator de amplificação ea∆t seja menor que 1. para t = 500∆t.3: Solução numérica produzida por onda1d-lax.250 0. 1000∆t e 1500∆t.py. O módulo (ao quadrado) é |ea∆t |2 = (1 − Co + Co cos(kl ∆x))2 + (Co sen(kl ∆x))2 . |ea∆t |2 = (CoSk )2 + (CoCk − Co + 1)2 2 2 = Co2 Sk + (Co2 Ck + Co2 + 1) + 2(−Co2 Ck + CoCk − Co) 2 2 = Co2 (Sk + Ck + 1 − 2Ck ) + 2Co(Ck − 1) + 1 = 2Co2 (1 − Ck ) + 2Co(Ck − 1) + 1. estamos utilizando um esquema de O(∆x) para a derivada espacial.Matemática Aplicada 1.50 0. mas se ele ao mesmo tempo for condicionalmente estável e não introduzir difusão numérica. Para aliviar a notação. façamos Ck ≡ cos(kl ∆x). t) 0.

mas em um outro esquema de diferenças finitas. ∂ 2u ∂u = D 2. embora em grau muito menor.750 tempo de simulação u(x.00 0 2 4 x 6 8 0. 4. 1000∆t e 1500∆t. que implementam o esquema upwind.2 Calcule a difusividade numérica introduzida pelo esquema upwind.500 0.4. 2Co [Co(1 − Ck ) + (Ck − 1)] ≤ 0. é condicionalmente estável. 4. e tudo indica que podemos agora implementá-lo computacionalmente. e são deixadas a cargo do(a) leitor(a). (1 − cos(kl ∆x)) [Co − 1] ≤ 0. portanto. Exercícios Propostos 4.23) vale sempre.000 10 Figura 4. portanto. a condição (4.23). e ver no que ele vai dar. 2Co2 (1 − Ck ) + 2Co(Ck − 1) + 1 ≤ 1.250 0.50 0. a figura sugere que algum amortecimento (difusão numérica?) também está ocorrendo. Co ≤ 1 Reencontramos. então. ∂t ∂x (4. No entanto. é a análise de estabilidade que deve refeita para cada novo esquema de diferenças finitas! O esquema upwind. Note que ele é muito melhor (para esta equação diferencial) que o esquema de Lax. Nós utilizamos os mesmos valores de ∆t e de ∆x de antes.2 – Difusão pura Considere agora a equação da difusão.000 4.1 Escreva o programa onda1d-upw e surfa1d-upw. As mudanças necessárias nos códigos computacionais são óbvias.4 mostra o resultado do esquema upwind. t) 0. A condição para que o esquema de diferenças finitas seja estável é.71 1.2 – Difusão pura 0. Reproduza a figura 4.28) . A lição não deve ser mal interpretada: longe de supor que (4. para t = 500∆t. A figura 4.4: Solução numérica produzida pelo esquema upwind.

(4. enquanto que a derivada segunda parcial em relação ao espaço é. com a solução analítica tendendo rapidamente para zero. implementa a solução analítica para ∆t = 0.py. t) = n=1 A n e− L 0 n2 π 2 α2 t L2 sen nπx .34) 2 ∆t ∆x A derivada parcial em relação ao tempo é de O(∆t).34) é estável? Explicitamos un+1 em (4. o programa divisao1d-ana. f (x) = 2x(1 − x).15. Este é praticamente o “fim” do processo difusivo. como você já sabe.py. Da mesma maneira que os programas surf1d*. L 2x(1 − x) sen(nπx) dx = π 3 n3 8 [1 − (−1)n ] . 0) = f (x) u(0. t) = 0. mostrado na listagem 4.34): i un+1 = un + Fo un − 2un + un . L = 1.35) (4. An = 2 1 0 2 L f (x) sen nπx dx.29) (4.0005 e ∆x = 0. A figura 4. t = 0. é outra: o esquema (4. L (4.33) O programa difusao1d-ana.25). mostrado na listagem 4. Esta solução foi vista no capítulo ??: ∞ 72 (4. de O(∆x2 ). t = 0.30) u(x. com a acurácia do esquema numérico.Matemática Aplicada com condições iniciais e de contorno u(x.31) (4. Nossa primeira preocupação. se D = 2. Todos os An ’s pares se anulam.28) seja un − 2un + un un+1 − un i i i−1 i = D i+1 .py.5 mostra o resultado da solução numérica para t = 0.05. como vimos em (4.001.36) . t) = u(L. + 1)3 ∞ 16 2 2 u(x. ainda.6. Esquema explícito Talvez o esquema explícito mais óbvio para discretizar (4.10 e t = 0. i−1 i i i+1 i onde Fo = D∆t ∆x2 (4. Mas não nos preocupemos muito.5. Fique então apenas com os ímpares: 16 . t) = e−(2(2n+1) π )t sen ((2n + 1)πx) 3 3 n=0 π (2n + 1) A2n+1 = π 3 (2n (4. seleciona alguns instantes de tempo da solução analítica para visualização.32) An = Em particular.

ana : solução analítica de # # du / dt = D du ^2/ dx ^2 # # u (x . exp epsilon = 1.001 dt = 0.0/ dx ) # número de pontos em x nt = int (1.x ) # u (0 .0 ds = epsilon n = 0 while abs ( ds ) >= epsilon : dnm1 = 2* n + 1 # (2 n +1) dnm1q = dnm1 * dnm1 # (2 n +1)^2 dnm1c = dnm1q * dnm1 # (2 n +1)^3 ds = exp ( . wb ) dx = 0.0/ dt ) # número de pontos em t print ( # nx = %9 d % nx ) print ( # nt = %9 d % nt ) from math import pi . float ) # um array para conter a solução for n in range ( nt +1): # loop no tempo t = n * dt print ( t ) for i in range ( nx +1): # loop no espaço xi = i * dx u [ i ] = ana ( xi .2 – Difusão pura Listagem 4.73 4. t ) = 0 # # uso : .0005 print ( # dx = %9.0) = 2 x (1 ./ difusao1d .ana .4 f % dt ) nx = int (1.coding : iso -8859 -1 -* # ---------------------------------------------------------# difusao1d .4 f % dx ) print ( # dy = %9. close () .py — Solução analítica da equação da difusão 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 # -* .ana .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 . tofile ( fou ) # imprime uma linha com os novos dados fou . py # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division fou = open ( difusao1d .0 e -6 # precisão da solução analítica dpiq = 2* pi * pi # 2 pi ^2 dzpic = 16/( pi * pi * pi ) # 16/ pi ^3 def ana (x . t ) = 0 # u (1 . t ) u . dat .5: difusao1d-ana. t ): s = 0. sin .

6: divisao1d-ana. nx +1) v .6 0. close () 0.10 e t = 0.4 f % dt ) nx = int (1.4 f % dx ) print ( # dt = %9. write ( %10. write ( %10. nx +1) # lê a condição inicial v = [u] # inicializa a lista da " transposta " for it in range ( m ): # para <m > instantes : for ir in range ( n ): # lê <ir > vezes .15 0. m +1): fou .0005 print ( # dx = %9.2 0. t) 0.3 u(x.05 0. float .ana .py — Seleciona alguns instantes de tempo da solução analítica para visualização 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 # -* . dat print ( founam ) fou = open ( founam .4 t = 0.1 t = 0.15. . py <m > <n > # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division from sys import argv dx = 0.6 f % v [0][ i ]) # escreve a cond inicial for k in range (1 .Matemática Aplicada 74 Listagem 4.00 0.4 x 0.5: Solução analítica da equação de difusão para t = 0.ana ./ divisao1d .001 dt = 0.ana .ésimo fou .8 1 Figura 4.ana .6 f % ( i * dx )) # escreve o " x " fou .coding : iso -8859 -1 -* # ---------------------------------------------------------# divisao1d . dat .10 t = 0.ana a cada <n > intervalos de tempo # # uso : . rb ) # abre o arquivo com os dados from numpy import fromfile u = fromfile ( fin . só guarda a última u = fromfile ( fin .6 f % v [ k ][ i ]) # escreve o k .2 t = 0. append ( u ) # guarda a última founam = divisao1d .0/ dx ) # número de pontos em x print ( # nx = %9 d % nx ) m = int ( argv [1]) # m saídas n = int ( argv [2]) # a cada n intervalos de tempo print ( # m = %9 d % m ) print ( # n = %9 d % n ) fin = open ( difusao1d . t = 0.5 0.0 0 0.05. py : imprime em <arq > <m >+1 saídas de # difusao1d . write ( \ n ) fou . float . wt ) # abre o arquivo de saída for i in range ( nx +1): fou . t = 0. write ( %10.

6: ele é impressionantemente bom.001 levaria a um esquema instável. mostrado na listagem 4. 2 Podemos agora calcular o número de Fourier que utilizamos para plotar a solução analítica (verifique nas listagens 4.py.01. < 0.75 4.7. seleciona alguns instantes de tempo da solução analítica para visualização. .5 (0.0005 e ∆x = 0.6): Fo = 2 × 0.01)2 (OK).38) foi fundamental para a obtenção de um bom resultado “de primeira”. O resultado da solução numérica com o método explícito está mostrado na figura 4. A análise de estabiliade de von Neumann agora produz ξl ea(tn +∆t) ei kl i∆x = ξl eatn ei kl i∆x + Fo ξl eatn ei kl (i+1)∆x − 2ξl eatn ei kl i∆x + ξl eatn ei kl (i−1)∆x . A escolha judiciosa de ∆t e ∆x para obeder ao critério (4. O programa que implementa o esquema é o difusao1d-exp. mostrado na listagem 4. (4. Precisamos diminuir ∆t e/ou aumentar ∆x. Fo = 2 × 0. Repare que Fo < 1/2 é um critério de estabilidade muito mais exigente do que Co < 1/2 (para D = 2).0005 = 1000. Com ∆t = 0.38) kl ∆x kl ∆x + 16Fo2 sen4 2 2 <1 1 Fo < . O programa divisao1d-exp. (0.py.5 e 4. Mas vamos implementá-lo.001)2 Utilizar os valores ∆x = 0. 1993).2 < 0.00001 = 0. sem a necessidade dolorosa de ficar tentando diversas combinações até que o esquema se estabilize e produza bons resultados.8.00001 e ∆x = 0. Nós esperamos que nosso esquema explícito agora rode muito lentamente. embora seja computacionalmente muito caro. ea∆t = 1 + Fo e+i kl ∆x − 2 + e−i kl ∆x = 1 + 2Fo [cos(kl ∆x) − 1] = 1 − 4Fo sen2 kl ∆x 2 (4.37) A análise de estabilidade requer que |ea∆t | < 1: |ea∆t |2 = 1 − 8Fo sen2 ou −8Fo sen2 8Fo sen2 kl ∆x kl ∆x + 16Fo2 sen4 2 2 kl ∆x kl ∆x −1 + 2Fo sen2 2 2 < 0.2 – Difusão pura é o número de Fourier de grade (El-Kadi e Ling.

00001 print ( # dx = %9. i ] = u [ old . i ] = CI ( xi ) u [0]. i ] + u [ old .i -1]) u [ new .0 # condição de contorno . close () .py — Solução numérica da equação da difusão: método explícito.0 # monta a condição inicial for i in range ( nx +1): xi = i * dx u [0 .exp resolve uma equação de difusão com um método # explícito # # uso : . nx ): # loop no espaço u [ new .01 dt = 0. nx +1) . float ) # apenas 2 posições no tempo # são necessárias ! def CI ( x ): # define a condição inicial if 0 <= x <= 1.6 f " % Fon ) for n in range ( nt ): # loop no tempo print ( n ) for i in range (1 .0)) # número de pontos em x nt = int ( round (1. nx ] = 0. old ) # troca os índices fou .4 f % dt ) from numpy import zeros nx = int ( round (1. i ] + Fon *( u [ old .0] = 0.0/ dt .2* u [ old . new ) = ( new .0/ dx . tofile ( fou ) # imprime a condição inicial old = False new = True D = 2. dat . x = 1 u [ new ]. py # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division fou = open ( difusao1d .Matemática Aplicada 76 Listagem 4. i +1] .coding : iso -8859 -1 -* # ---------------------------------------------------------# difusao1d .0: return 2.x ) else : return 0.0* x *(1.4 f % dx ) print ( # dy = %9./ difusao1d . x = 0 u [ new .0 .exp .0 # celeridade da onda Fon = D * dt /(( dx )**2) # número de Fourier print ( " Fo = %10.0)) # número de pontos em t print ( # nx = %9 d % nx ) print ( # nt = %9 d % nt ) u = zeros ((2 .exp . 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 # -* .7: difusao1d-exp. wb ) dx = 0. tofile ( fou ) # imprime uma linha com os novos dados ( old .0 # condição de contorno .

rb ) # abre o arquivo com os dados from numpy import fromfile u = fromfile ( fin .2 t = 0. t = 0.4 f % dx ) print ( # dt = %9.15.exp . close () 0.4 t = 0.6 0.8: divisao1d-exp.5 0.0/ dt . m +1): fou . t = 0. . para facilitar a comparação com a solução analítica.6 f % v [ k ][ i ]) # escreve o k .4 x 0.exp . dat fou = open ( founam .py — Seleciona alguns instantes de tempo da solução analítica para visualização 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 # -* . Apenas 1 a cada 5 pontos da grade numérica são mostrados. nx +1) v .00001 print ( # dx = %9. py <m > <n > # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division from sys import argv dx = 0. write ( %10.exp . append ( u ) # guarda a última founam = divisao1d .ésimo fou .01 dt = 0.05 0.3 u(x. write ( %10.10 t = 0. float .2 – Difusão pura Listagem 4.coding : iso -8859 -1 -* # ---------------------------------------------------------# divisao1d .77 4.exp a cada <n > intervalos de tempo # # uso : . write ( \ n ) fou . float . write ( %10.1 t = 0.0/ dx .6: Solução numérica com o método explícito (4. nx +1) # lê a condição inicial v = [u] # inicializa a lista da " transposta " for it in range ( m ): # para <m > instantes : for ir in range ( n ): # lê <ir > vezes .2 0.4 f % dt ) nx = int ( round (1.0)) # número de pontos em t print ( # nx = %9 d % nx ) m = int ( argv [1]) # m saídas n = int ( argv [2]) # a cada n intervalos de tempo print ( # m = %9 d % m ) print ( # n = %9 d % n ) fin = open ( difusao1d .05. só guarda a última u = fromfile ( fin .10 e t = 0.8 1 Figura 4. py : imprime em <arq > <m >+1 saídas de # difusao1d .0 0 0.exp .6 f % v [0][ i ]) # escreve a cond inicial for k in range (1 .15 0. wt ) # abre o arquivo de saída for i in range ( nx +1): fou .35) (círculos) versus a solução analítica (linha cheia) da equação de difusão para t = 0. dat .00 0.0)) # número de pontos em x nt = int ( round (1./ divisao1d .6 f % ( i * dx )) # escreve o " x " fou . t) 0.

un+1 .41) Em resumo.  . i i i+1 i i−1 n+1 n+1 n+1 n −Foui−1 + (1 + 2Fo)ui − Foui+1 = ui (4.9): para i = 1.Matemática Aplicada 78 Esquemas implícitos Embora o esquema explícito que nós utilizamos acima seja acurado. 0 0 . nosso argumento é didático: com uma linguagem mais simples. .py. .39) precisa ser modificada. .. .. e i = Nx + 1.. e quando i = Nx .39) acopla 3 valores das incógnitas un+1 no instante n + 1. nós já estamos utilizando muito mal nossos recursos. nossas incógnitas são un+1 . 0 0 . Nx − 1. no entanto. todos os ganhos relativos que obtivermos se manterão em qualquer outra linguagem) Vamos portanto fazer uma mudança fundamental nos nossos esquemas de diferenças finitas: vamos calcular a derivada espacial no instante n + 1: un+1 − 2un+1 + un+1 un+1 − un i i−1 i i = D i+1 . ao utilizarmos uma linguagem interpretada — Python — para programar. ..  (4. porque não existem os índices i = −1.  . para a introdução das condições de contorno: como un = 0 e un x = 0 para qualquer n. 1 2 1 n+1 n+1 −FouNx −2 + (1 + 2Fo)uNx −1 = un x −1 .. ..40) (4.            un+1    Nx −2  = un+1 Nx −1             un   Nx −2  un 1 un 2 . 0 −Fo 1 + 2Fo 0 0 . . . un+1 (Nx − 1 incógnitas). ele é lento — se você programou e rodou difusao1d-exp. isto não é desculpa para utilizar mal nossos recursos computacionais (é claro que.39). (4. 0 0 −Fo 1 + 2Fo −Fo .. . un+1  1   un+1  2  . Além disto.     . deve ter notado alguma demora para o programa rodar. .. não podemos utilizar (4. . . N (4. teremos N 0 (1 + 2Fo)un+1 − Foun+1 = un . e seu 1 2 Nx −1 cálculo envolve a solução do sistema de equações 1 + 2Fo −Fo 0   −Fo 1 + 2Fo Fo   .39) Reveja a discretização (4. podemos aprender mais rápido e errar menos.42) un x −1 N . Embora nossos computadores estejam ficando a cada dia mais rápidos. (4. Quando i = 0. ∆t ∆x2 un+1 − un = Fo(un+1 − 2un+1 + un+1 ). . Quando i = 1 e i = Nx − 1.5)–(4.

que resolve um sistema tridiagonal.py. Existe um programa divisao1d-imp. ea∆t = 1 + ea∆t Fo ei kl ∆x − 2 + e−i kl ∆x .79 4. Em Python e Numpy. no esquema implícito (4. . por envolver a solução de um sistema de equações acopladas.nx-1] recebem o valor -Fon. na linha 43. por sua vez. Ele está mostrado na listagem 4.42).9. Em seguida. . ea∆t = 1 + ea∆t 2Fo (cos(kl ∆x) − 1) . ea∆t = 1 − ea∆t 4Fo sin2 ea∆t 1 + 4Fo sin2 kl ∆x 2 = 1.43) Portanto. é um pouco mais custosa. 1992.001. que torna a programação mais compacta e clara. sistemas lineares com este tipo de matriz são particularmente simples de resolver.py. e ∆x = 0. mas ele não precisa ser mostrado aqui. Para ∆t = 0. o programa difusao1d-imp. com um dispositivo denominado slicing.39) é incondicionalmente estável. A derivada temporal.39). o resultado do método implícito está mostrado na figura 4.7 Nada mal. é possível especificar sub-listas. para uma economia de 100 vezes (em relação ao método explícito) em passos de tempo! (Note entretanto que a solução. ainda que tridiagonal. 1 1 + 4Fo sin2 kl ∆x 2 kl ∆x . e estão disponíveis na literatura (por exemplo: Press et al.2 – Difusão pura A análise de estabilidade de von Neumann procede agora da maneira usual: n+1 i a(tn +∆t) i kl i∆x = n i + Fo( ξl e e = ξl eatn e n+1 i+1 i kl i∆x −2 n+1 i + n+1 i−1 ) + Fo ξl ea(tn +∆t) ei kl (i+1)∆x − 2ξl ea (tn + ∆t)ei kl i∆x +ξl ea(tn +∆t) ei kl (i−1)∆x . A[0. subrotina tridag).10. a matriz do sistema é uma matriz banda tridiagonal. Em segundo lugar. todos os elementos A[0. em cada passo de tempo. são demasiadamente triviais para justificarem o gasto adicional de papel. (4. porque as modificações. convenientemente denominado alglin.py. Por exemplo. mostrado na listagem 4..py resolve o problema com o método implícito. por exemplo a partir de divisao1d-exp. seção 2. então.01.4.1]. Existem várias coisas atraentes para um programador em (4. que exporta a função tridag. e depois novamente na linha 56.) Crank Nicholson A derivada espacial em (4. é . o esquema implícito (4. 2 |ea∆t | = ≤1 sempre. Nós vamos começar.28) é aproximada. A principal novidade está nas linhas 42–46. e temos confiança de que o programa correspondente não se instabilizará. por um esquema de O(∆x2 ). a matriz do sistema é constante: ela só precisa ser montada uma vez no programa. o que torna a solução numérica potencialmente muito rápida. construindo um pequeno módulo. e sub-arrays. Em primeiro lugar.

py — Exporta uma rotina que resolve um sistema tridiagonal.4 t = 0. shape [1] # matriz tridiagonal assert ( m == 3) # garante que todos os tamanhos estão OK o = y .6 0. t = 0.1 t = 0. shape [0] # garante que A representa uma n = A . . -1): x [ j ] -= gam [ j +1]* x [ j +1] return x 0. y ): # A .A [0 . j ] .coding : iso -8859 -1 -* # -----------------------------------------------------------------------------# alglin . y têm que ser arrays ! m = A .3 u(x.0): exit ( " Erro 2 em tridag " ) x [ j ] = ( y [ j ] . para facilitar a comparação com a solução analítica.A [0 .j -1]/ bet bet = A [1 . t = 0. j ]* x [j -1])/ bet for j in range (n -2 . t) 0.0 0 0.0] x [0] = y [0]/ bet for j in range (1 .10 t = 0. baseado em Press et al.2 t = 0.39) (círculos) versus a solução analítica (linha cheia) da equação de difusão para t = 0. -1 .9: alglin. float ) # vetor de trabalho : vai retornar a solução gam = zeros (n .15. (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 # -* .4 x 0.05 0.2 0. py implementa uma solução de um sistema linear com matriz tridiagonal # -----------------------------------------------------------------------------from numpy import zeros def tridag (A .7: Solução numérica com o método implícito (4.0 : exit ( " Erro 1 em tridag " ) bet = A [1 .8 1 Figura 4. float ) # vetor de trabalho : vai ficar por aqui if A [1 . n ): gam [ j ] = A [2 . shape [0] assert ( n == o ) x = zeros (n . j ]* gam [ j ] if ( bet == 0.Matemática Aplicada 80 Listagem 4. Apenas 1 a cada 5 pontos da grade numérica são mostrados.5 0.00 0.05.10 e t = 0.15 0.0] == 0.

wb ) dx = 0.0)) # número de pontos em t print ( # nx = %9 d % nx ) print ( # nt = %9 d % nt ) from numpy import zeros u = zeros ((2 .0)) # número de pontos em x nt = int ( round (1. u [ old . old ) # troca os índices fou . nx ] = 0.0] = 0.imp resolve uma equação de difusão com um método # implícito # # uso : .6 f " % Fon ) A = zeros ((3 .0 . float ) # cria a matriz do sistema # -----------------------------------------------------------------------------# cuidado . i ] = CI ( xi ) u [0].1: nx ] = tridag (A .0 # zera A [0 .0 # condição de contorno . " linha " e " coluna " abaixo não significam as reais linhas e colunas # do sistema de equações .Fon # preenche o fim da 1 a linha A [1 . dat .1: nx -1] = .py — Solução numérica da equação da difusão: método implícito.0 + 2* Fon # preenche a segunda linha A [2 .0 # zera A [2 .0 # condição de contorno . x = 1 u [ new ]. tofile ( fou ) # imprime a condição inicial old = False new = True D = 2. nx +1) . nx -2] = 0. float ) # apenas 2 posições no tempo # são necessárias ! def CI ( x ): # define a condição inicial if 0 <= x <= 1.0 for i in range ( nx +1): # monta a condição inicial xi = i * dx u [0 .0: nx -2] = .coding : iso -8859 -1 -* # ---------------------------------------------------------# difusao1d . .0: nx -1] = 1. nx -2] # -----------------------------------------------------------------------------# importa uma tradução de tridag de Numerical Recipes para Python # -----------------------------------------------------------------------------from alglin import tridag for n in range ( nt ): # loop no tempo print ( n ) # -----------------------------------------------------------------------------# atenção : calcula apenas os pontos internos de u ! # -----------------------------------------------------------------------------u [ new . tofile ( fou ) # imprime uma linha com os novos dados ( old .0 # difusividade Fon = D * dt /(( dx )**2) # número de Fourier print ( " Fo = %10. mas sim a forma de armazenar uma matriz tridiagonal # -----------------------------------------------------------------------------A [0 . nx -1) . 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 # -* .2 – Difusão pura Listagem 4.4 f % dx ) print ( # dy = %9.imp .81 4.0/ dx . x = 0 u [ new .01 # define a discretização em x dt = 0.0] = 0.10: difusao1d-imp. close () # fecha o arquivo de saída . new ) = ( new .imp .0] A [0 .001 # define a discretização em t print ( # dx = %9.x ) else : return 0.1: nx ]) u [ new . py # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division fou = open ( difusao1d .0: return 2.Fon # preenche o início da 2 a linha A [2 ./ difusao1d . e fim .0/ dt .4 f % dt ) nx = int ( round (1.0* x *(1.

1 2 2 2 F ou n+1 Fo n − uNx −2 + (1 + Fo)un+1 = u + (1 − Fo)un x −1 Nx −1 N 2 2 Nx −2 (1 + Fo)un+1 − 1 (4. Com isto.Matemática Aplicada apenas de O(∆t). a derivada espacial agora é uma média das derivadas em n e n + 1.46) (4.44) Com esta mudança simples. e substituímos um modo de Fourier: ξl ea(tn +∆t) ei kl i∆x − Fo i kl (i+1)∆x e − 2ei kl i∆x + ei kl (i−1)∆x = 2 Fo i kl (i+1)∆x e − 2ei kl i∆x + ei kl (i−1)∆x ξl eatn ei kl i∆x + 2 Fo i kl ∆x e − 2 + e−i kl ∆x 2 kl ∆x 2 kl ∆x 2 kl ∆x 2 ea∆t 1 − Fo i kl ∆x e − 2 + e−i kl ∆x 2 kl ∆x 2 e a∆t = 1+ ea∆t [1 − Fo (cos(kl ∆x) − 1)] = [1 + Fo (cos(kl ∆x) − 1)] ea∆t 1 + 2Fo sin2 = 1 − 2Fo sin2 = 1 − 2Fo sin2 1 + 2Fo sin2 . nosso trabalho agora é verificar a estabilidade do esquema numérico. fazemos n+1 i − Fo 2 n+1 i+1 −2 n+1 i + n+1 i−1 = n i + Fo 2 n i+1 −2 n i + n i−1 . ou seja: ela está centrada em n + 1/2.30).45) Para as condições de contorno de (4. O código do programa que implementa o esquema numérico de Crank-Nicholson.39): − Fo n+1 Fo Fo n Fo ui−1 + (1 + Fo)un+1 − un+1 = ui−1 + (1 − Fo)un + un i i i+1 2 2 2 2 i+1 (4. na prática.py são relativamente fáceis de se identificar.11. e o esquema numérico de Crank-Nicholson é incondicionalmente estável. as linhas correspondentes a i = 1 e i = Nx − 1 são Fo n+1 Fo u2 = (1 − 2Fo)un + un . + i+1 ∆t 2 ∆x2 ∆x2 Fo n un+1 = un + ui+1 − 2un + un + un+1 − 2un+1 + un+1 . É fácil notar que |ea∆t | < 1. é mostrado na listagem 4. Mas é possível consertar isto! A idéia é substituir (4. difusao1d-ckn. Para isto.39) por un+1 − un D un − 2un + un un+1 − 2un+1 + un+1 i i i−1 i−1 i i+1 i = . O esquema numérico de Crank-Nicholson é similar a (4.py. i−1 i i+1 i i−1 i i 2 82 (4. um esquema de ordem 2 centrado em n + 1/2! Como sempre. a derivada temporal do lado esquerdo torna-se. .47) As mudanças no código de difusao-imp.

A grande novidade computacional de difusao1d-ckn.4 x 0. portanto ele deve ser capaz de dar passos ainda mais largos no tempo que o método implícito (4.05 0. O método de Crank-Nicholson possui acurácia O(∆t)2 . t) 0. e é mostrado na figura 4.3 – Difusão em 2 Dimensões: ADI. O resultado é uma solução cerca de 5 vezes mais rápida (embora. O mesmo tipo de facilidade está disponível em FORTRAN90.3 u(x.8 1 Figura 4.48) Como sempre.10 t = 0. no programa difusao1d-ckn. Considere então a condição inicial u(x.05. t = 0. y.2 0.0 0 0.1 t = 0. ∂t ∂x2 ∂y 2 (4.15. etc. ∂ 2u ∂ 2u ∂u =D + .2 t = 0.45)) (círculos) versus a solução analítica (linha cheia) da equação de difusão para t = 0.py.39).. haja mais contas agora para calcular o vetor de carga b).4 t = 0.3 – Difusão em 2 Dimensões: ADI. y.6 0. FORTRAN95. nós especificamos um passo de tempo 5 vezes maior do que em difusao1d-imp. e equações elíticas Considere a equação da difusão em 2 dimensões.00 0.10 e t = 0. para facilitar a comparação com a solução analítica.py. e equações elíticas 0.49) . L2 (4. é possível escrever (4.8 4. 1 + 4tD/L2 L + 4Dt (4. Apenas 1 a cada 5 pontos da grade numérica são mostrados.15 0.5 4. a implementação computacional dos cálculos gerada por Numpy (ou pelo compilador FORTRAN) também é potencialmente mais eficiente. 0) = u0 exp − a solução analítica é u(x.py é a linha 56: com os arrays proporcionados por Numpy.45) vetorialmente: note que não há necessidade de fazer um loop em x para calcular cada elemento b[i] individualmente.83 0. nós queremos ser muito concretos. Com isto. t = 0. t) = (x2 + y 2 ) u0 exp − 2 . novamente.50) (x2 + y 2 ) .8: Solução numérica com o método de Crank-Nicholson ( (4. e trabalhar com um problema que possua solução analítica.

dat .1: nx ] + ( Fon /2)* u [ old .0: nx -2] = .2: nx +1] # -----------------------------------------------------------------------------# atenção : calcula apenas os pontos internos de u ! # -----------------------------------------------------------------------------u [ new .0 # difusividade Fon = D * dt /(( dx )**2) # número de Fourier print ( " Fo = %10. x = 1 u [ new ].0 # condição de contorno .Fon /2. float ) # apenas 2 posições no tempo # são necessárias ! def CI ( x ): # define a condição inicial if 0 <= x <= 1.0: return 2. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 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 # -* .Fon /2.0/ dx . new ) = ( new . i ] = CI ( xi ) u [0].005 # define a discretização em t print ( # dx = %9.0)) # número de pontos em x nt = int ( round (1.1: nx -1] = .coding : iso -8859 -1 -* # ---------------------------------------------------------# difusao1d . mas sim a forma de armazenar uma matriz tridiagonal # -----------------------------------------------------------------------------A [0 .py — Solução numérica da equação da difusão: esquema de Crank-Nicholson. b ) u [ new .Nicholson # # uso : .0 # preenche o início da 2 a linha A [2 . old ) # troca os índices fou .11: difusao1d-ckn.4 f % dx ) print ( # dt = %9.0 # zera A [0 .Fon )* u [ old .6 f " % Fon ) A = zeros ((3 .0 # zera A [2 .ckn . nx -2] # -----------------------------------------------------------------------------# importa uma tradução de tridag de Numerical Recipes para Python # -----------------------------------------------------------------------------from alglin import tridag for n in range ( nt ): # loop no tempo print ( n ) # -----------------------------------------------------------------------------# recalcula o vetor de carga vetorialmente # -----------------------------------------------------------------------------b = ( Fon /2)* u [ old .0 # preenche o fim da 1 a linha A [1 . wb ) dx = 0. nx -1) .4 f % dt ) nx = int ( round (1./ difusao1d .0] = 0.0 # monta a condição inicial for i in range ( nx +1): xi = i * dx u [0 .0/ dt .0* x *(1. py # ---------------------------------------------------------from __future__ import print _functio n from __future__ import division fou = open ( difusao1d . tofile ( fou ) # imprime uma linha com os novos dados ( old .Matemática Aplicada 84 Listagem 4. nx -2] = 0. e fim .0] = 0. tofile ( fou ) # imprime a condição inicial old = False new = True D = 2. close () # fecha o arquivo de saída .0: nx -1] = 1.0 + Fon # preenche a segunda linha A [2 .1: nx ] = tridag (A . .0)) # número de pontos em t print ( # nx = %9 d % nx ) print ( # nt = %9 d % nt ) from numpy import zeros u = zeros ((2 .0] A [0 . " linha " e " coluna " abaixo não significam as reais linhas e colunas # do sistema de equações .01 # define a discretização em x dt = 0. float ) # cria a matriz do sistema # -----------------------------------------------------------------------------# cuidado .0 . x = 0 u [ new .ckn resolve uma equação de difusão com o método # de Crank .0 # condição de contorno .0: nx -1] + (1 . nx ] = 0.x ) else : return 0.ckn . nx +1) .

Além disto.j n n − Foun+1 + (1 + 2Fo)un+1 − Foun+1 = Foun i−1.j i+1. t) = (L2 + y 2 ) L2 + 4Dt (L2 + y 2 ) exp − 2 L + 4Dt (x2 + L2 ) exp − 2 L + 4Dt (x2 + L2 ) exp − 2 L + 4Dt exp − .53) (4. para x: n n un+1 − un = Fo un+1 − 2un+1 + un+1 + un i−1.j i.j i.j i+1. de maneira que só haverá um número de Fourier de grade no problema. . i. por exemplo. t) = 1 + 4tD/L2 u0 u(x. Nossa escolha recairá sobre um método simples. t) = 1 + 4tD/L2 u(−L. Portanto.j i.56): na primeira. −L.j + Foui. denominado ADI (alternating-direction implicit).j i+1. para resolver o problema! Ei-los − 2un + un un un+1 − un un+1 − 2un+1 + un+1 i. e o esquema é implícito em y.j =D + i.56) Examine cuidadosamente (4.85 4.57) .j i.j+1 ∆t ∆x2 ∆y 2 (4. y.j i.j n n un+1 − Fo un+1 − 2un+1 + un+1 = un + Fo un i−1.52) (4. É claro que nós vamos precisar de duas análises de estabilidade de von Neumann.j i.51) (4.j i+1.55) e (4. ∆2 (4. vou supor que os dois esquemas são incondicionalmente estáveis. mantendo a outra dimensão “explícita”.j+1 (4.55) (4.j i.j+1 . e de O(∆t)2 . y. L. e equações elíticas Na verdade esta solução se “espalha” por todo o plano xy.3 – Difusão em 2 Dimensões: ADI. que nós vamos traduzir como “separação de operadores” Esta técnica consiste em marchar implicitamente em uma dimensão espacial de cada vez. .j i+1. e impondo condições de contorno que se ajustem exatamente à solução analítica: u0 1 + 4tD/L2 u0 u(L.j i−1. 2011-09-24T17:07:04 Por enquanto.j i. uma para cada equação. nós vamos fazer D = 2 (como antes) e L = 1.j i.j−1 − 2ui.j+1 ∆t ∆x2 ∆y 2 un+1 − 2un+1 + un+1 un+2 − un+1 un+2 − 2un+2 + un+2 i−1.j−1 + (1 − 2Fo)ui.j+1 . Fo = e então teremos.54) Agora. e resolver o problema numericamente.j−1 i. mas nós podemos trabalhar com um problema finito em x e y. e mandar ver. −L ≤ y ≤ L.j i. nós vamos utilizar dois esquemas diferentes de diferenças finitas (na prática). .j i.j + ui.58) D∆t . i. t) = 1 + 4tD/L2 u0 u(x. Este método nos proporcionará um exemplo de uma técnica denominada operator splitting ou time splitting.j i. note que o esquema é implícito em x.j i.j−1 i. fazendo −L ≤ x ≤ L. por simplicidade vamos fazer ∆x = ∆y = ∆.j i. a situação se reverte. (4.j =D + i. na segunda.j + ui.j−1 − 2ui.j i.

programar a solução analítica.j−1 i.59) é que em vez de resolver a cada passo (digamos) 2∆t um sistema de (N − 1)2 incógnitas.. A solução analítica do problema para os instantes de tempo t = 0.3 está mostrada na figura 4.j i. .j+1 i−1. . t = 0.j+1 un+2 − Fo un+2 − 2un+2 + un+2 = un+1 + Fo un+1 − 2un+1 + un+1 . . em vez de usar um esquema totalmente implícito. yj = −L + j∆.58) e (4..62) e portanto −L ≤ xi ≤ L e −L ≤ yj ≤ L. alternadamente para u1. ∆ xi = −L + i∆. portanto. ui. .j i.1. N.j i+1.2 e t = 0. inicialmente. usar Crank-Nicholson em cada avanço ∆t.j i. (4. .j+1 i..10 . j = 0. assim como está o método ADI já é suficientemente sofisticado para nosso primeiro encontro com este tipo de problema.60) i = 0.59) Se nós utilizarmos (novamente por simplicidade) o mesmo número de pontos N + 1 em x e em y..N1 . É claro que o céu é o limite: poderíamos. programá-lo.j 86 − Foun+2 + (1 + 2Fo)un+2 − Foun+2 = Foun+1 + (1 − 2Fo)un+1 + Foun+1 i.1.. nós agora podemos resolver a cada passo ∆t N − 1 sistemas de (N − 1) incógnitas. un+2 − un+1 = Fo un+1 − 2un+1 + un+1 + un+2 − 2un+2 + un+2 .61) (4. Devemos. (4.j i. Vamos.j i+1. por exemplo. A beleza de (4.j e ui. uN.j .j i. t = 0.0 e ui.N estão especificados. . Lembrando que os valores de u0.N −1. isto nos daria imediatamente um esquema com acurácia de ordem ∆t2 .Matemática Aplicada Na dimensão y. N. .. . No entanto.j .. i.j i+1.j i. i.j i. teremos o seguinte mapeamento para a nossa grade: N= 2L .j i−1.j i.j−1 i.. há (N − 1)2 incógnitas para serem calculadas.j i−1.j (4.j i.j−1 i.

9: Solução analítica da equação da difusão bidimensional. t = 0.3 .1.3 – Difusão em 2 Dimensões: ADI. t = 0.87 4. para t = 0.2 e t = 0. t = 0. e equações elíticas Figura 4.

t = 0.Matemática Aplicada 88 Figura 4. t = 0. t = 0.10: Solução numérica da equação da difusão bidimensional com o esquema ADI.2 e t = 0.3 . para t = 0.1.

00 133.57 25.80 21.00 133.10 171.00 192.00 278.60 13.00 206.40 135.33 28.57 26.75 125.00 208.97 272.00 211.00 56.60 169.10 14.40 380.00 135.20 243.75 21.63 13.00 198.00 89 . 1931–1999 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.00 251.49 19.33 17.25 16.95 32.70 20.50 22.26 26.82 34.62 16.40 146.60 152.50 152.A Dados de vazão média anual e vazão máxima anual.00 92.61 30.60 178.30 22.94 25.09 24. Rio dos Patos.04 14.00 252.80 222.00 68.25 9.72 14.31 27.05 22.40 299.64 41.40 248.00 272.00 188.10 131.68 8.00 223.80 281.50 156.20 399.60 202.00 146.13 30.09 22.82 15.00 266.62 24.00 176.00 311.49 24.59 15.00 172.29 7.65 4.40 165.23 36.00 61.00 174.36 21.46 28.50 13.30 272.10 127.23 15.76 11.00 257.11 15.81 26.88 20.22 22.00 75.77 32.50 119.48 27.

00 247.02 51.60 27.73 31.55 24.30 20.00 660.74 31.80 333.24 34.64 15.00 226.68 57.00 245.00 131.92 35.92 14.00 528.13 12.00 486.78 35.20 43.00 472.48 11.22 31.00 275.Matemática Aplicada 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 26.00 255.00 275.00 333.00 190.00 134.00 146.49 182.44 41.00 128.74 26.00 196.55 16.50 451.00 90 .

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

Sign up to vote on this title
UsefulNot useful