Você está na página 1de 62

Morais & Nogueira – Física Computacional com Python

Capítulo Dois: Operações Básicas

Antes de entrar nos métodos computacionais da Física Computacional, vamos nos


deter a realizar exemplos com operações matemáticas básicas como plotar gráficos, obter
raízes de funções, integração simples e procura de máximos e mínimos.
Raízes
Seja uma função 𝑓(𝑥) de qualquer grau, definimos suas raízes como os valores de
𝑥 = 𝑥𝑗 em que 𝑓(𝑥𝑗 ) = 0. Em outras palavras, são os pontos em que a curva toca o eixo 𝑋.
Se a função 𝑓(𝑥) não possuir descontinuidades no intervalo estudado, podemos fazer uso do
seguinte método de encontrar raízes de 𝑓(𝑥). Primeiro, precisamos definir o intervalo
estudado, isto é, entre quais valores de 𝑥 estamos tentando encontrar a raiz em questão. Seja o
intervalo então definido entre 𝑥𝑚í𝑛 e 𝑥𝑚á𝑥 ([𝑥𝑚í𝑛 ; 𝑥𝑚á𝑥 ]). Considere o valor inicial 𝑥1 =
𝑥𝑚í𝑛 para um “chute” (tentativa) e substitua na função, resultando em 𝑓(𝑥1 ). A partir daí,
faremos uma variação no valor no valor de 𝑥 incrementando até metade do intervalo
estudado; digamos que o novo valor agora é 𝑥2 = 𝑥1 + 𝛿𝑥1 , onde 𝛿𝑥1 é um incremento
pequeno: 𝛿𝑥1 = (𝑥𝑚á𝑥 − 𝑥𝑚í𝑛 )/2, resultando em 𝑓(𝑥2 ). Faremos isso repetidas vezes até
que o sinal da função mude quando o valor de 𝑥𝑗 passar o valor da raiz 𝑥0 . Neste ponto 𝑥𝑗 >
𝑥0 , faremos então o incremento negativo e diminuiremos o incremento pela metade: 𝛿𝑥𝑗 =
−𝛿𝑥𝑗−1 /2. Realizaremos o mesmo procedimento de mudar o sinal do incremento, caso o
módulo da função venha a aumentar, pois sabemos que ele deve diminuir à medida que nos
aproximamos da raiz 𝑥0 . Podemos ter a sorte de achar o valor exato em algum incremento,
todavia é mais provável que não cheguemos nesse valor. Neste caso, definimos um valor de
tolerância 𝛼 muito próximo de zero, tal que nos satisfaremos se |𝛿𝑥𝑗 | for tão pequeno, que se
aproxime de zero. Comparamos então o valor de 𝑓(𝑥𝑗 ) com a tolerância: se |𝛿𝑥𝑗 | < 𝛼,
chegamos à solução aceitável.
Este algoritmo para achar o valor de uma raiz da função 𝑓(𝑥) = 𝑥 3 − 3,77𝑥 2 no
intervalo [1; 5] pode ser escrito em Python do seguinte modo:
x_min = 3
x_max = 4
itera = 0
dx = (x_max-x_min)/2.
tolera = 0.00001
# Definimos a função funcao(x) igual a equação que desejamos encontrar a
raiz
def funcao(x):
return (x**3) - 3.77*(x**2)
# Escolhemos o chute inicial de x
x = x_min
# Definimos duas variáveis contendo o valor da função na iteração atual
(f_velha) e na seguinte (f_nova)
f_velha = funcao(x)
f_nova = f_velha
# A variável Booleana “achou” que determina se a solução exata foi
encontrada
achou = False
# A variável Booleana “primeiro” determina se o valor de x na iteração
passou da raiz pela primeira vez
primeiro = False
while achou == False:

6
Morais & Nogueira – Física Computacional com Python

# A variável Booleana “passou” determina se o valor de x na iteração passou


da raiz
passou = False
if abs(dx)<tolera:
break
while passou == False:
itera += 1
x=x+dx
f_velha = f_nova
f_nova=funcao(x)
print("A raiz aproximada é "+str(x)+" cujo resíduo foi "+ str(dx))
# Se o sinal da função muda na iteração, mudamos o sinal do incremento e
diminuimos pela metade
if f_nova*f_velha < 0:
dx=-dx/2
passou = True
primeiro = True
# Se o valor absoluto da função é maior que seu valor na iteração passada,
mudamos o sinal do incremento dx
if abs(f_nova)>abs(f_velha) and primeiro==True:
dx=-dx
# Se a solução exata foi encontrada, terminamos o algoritmo
if f_nova == 0:
achou=True
break
# Imprimindo na tela o valor encontrado
print("A raiz encontrada foi "+str(x)+" com tolerância de "+ str(tolera))

Figura 3 - Saída do programa acima que utiliza o método de busca da raiz.

7
Morais & Nogueira – Física Computacional com Python

Métodos Newton-Raphson
O método de Newton-Raphson é uma maneira para encontrar as raízes de equações não
lineares e é um dos algoritmos mais comuns para encontrar raízes devido à sua relativa
simplicidade e velocidade. O método usa a derivada da função 𝑓 ′ (𝑥) e a função original
𝑓(𝑥).
Iteração Newton-Raphson
O chute inicial da raiz é denotado por 𝑥1 . A raiz verdadeira é 𝑥0 e pode ser expressa como
𝑥0 = 𝑥1 + ℎ, onde ℎ é a distância entre a estimativa e o valor verdadeiro da raiz. Como ℎ será
pequeno, uma linha tangente linear é usada para aproximar a localização da raiz e pode ser
escrita como:
𝑓(𝑥0 ) = 0 = 𝑓(𝑥1 + ℎ) ≅ 𝑓(𝑥1 ) + ℎ𝑓 ′ (𝑥1 ) + ⋯
1

Assim, ℎ ≈ −𝑓(𝑥1 )/𝑓 ′ (𝑥1 ), desde que 𝑓 ′ (𝑥1 ) ≠ 0. Podemos então escrever
𝑓(𝑥1 )
𝑥0 = 𝑥1 + ℎ ≈ 𝑥1 −
𝑓 ′ (𝑥1 )
Todavia, podemos iterar mais uma vez e estimar
𝑓(𝑥1 )
𝑥2 ≈ 𝑥1 −
𝑓 ′ (𝑥1 )
𝑓(𝑥2 )
𝑥3 ≈ 𝑥2 −
𝑓 ′ (𝑥2 )

𝑓(𝑥𝑛 )
𝑥𝑛+1 ≈ 𝑥𝑛 −
𝑓 ′ (𝑥𝑛 )
2

O método de Newton-Raphson só é confiável no caso de 𝒇′ (𝒙𝒏 ) não ser próximo


de zero!
Vamos testar o método com a mesma função 𝑓(𝑥) = 𝑥 3 − 3,77𝑥 2 , tal que 𝑓′(𝑥) =
2
3𝑥 − 7,54𝑥.
# Definimos a tolerância para o problema
tolera = 0.00001
# Definimos a função funcao(x) igual a equação que desejamos encontrar a
raiz
def funcao(x):
return (x**3) - 3.77*(x**2)
# Definimos a derivada da função obtida analiticamente
def deriva(x):
return 3.*(x**2)-7.54*x
# Definimos o incremento do método de Newton-Raphson h = f(x)/f'(x)
def h(x):
return funcao(x)/deriva(x)
# O valor do chute inicial é
x = 3

8
Morais & Nogueira – Física Computacional com Python

# o valor do resíduo é igual ao módulo de h e seu valor inicial é maior que


a tolerância
residuo = 2.*tolera
# A solução é procurada até que o critério de convergência seja satisfeito
while tolera < residuo:
x=x-(funcao(x)/deriva(x))
residuo = abs(h(x))
print("A raiz aproximada é "+str(x)+" cujo resíduo foi "+ str(residuo))
# Imprimindo na tela o valor encontrado
print("A raiz encontrada foi "+str(x)+" com tolerância de "+ str(tolera))

Figura 4- Saída do programa acima que utiliza o método de Newton-Raphson.

Compare a rapidez desse método com o método proposto no início da sessão. Essa
velocidade é o que torna o Método de Newton-Raphson amplamente difundido e utilizado.
Métodos da Secante
Um método semelhante, é o método da secante. Ele consiste em aproximar a derivada
encontrada no Método de Newton-Raphson por uma equação de diferença. Sejam os valores
iniciais 𝑥0 e 𝑥1 , é possível construir uma linha passando pelos pontos [𝑥0 , 𝑓(𝑥0 )] e
[𝑥1 , 𝑓(𝑥1 )]. A equação da reta que passa por esses dois pontos é
𝑓(𝑥1 ) − 𝑓(𝑥0 )
𝑦= (𝑥 − 𝑥1 ) + 𝑓(𝑥1 )
𝑥1 − 𝑥0
3

A raiz desta equação linear é


𝑓(𝑥1 )
𝑥 = 𝑥1 − (𝑥 − 𝑥0 )
𝑓(𝑥1 ) − 𝑓(𝑥0 ) 1
Seja um valor 𝑥2 feito ser 𝑥2 = 𝑥, temos uma nova reta passando pelos pontos [𝑥1 , 𝑓(𝑥1 )] e
[𝑥2 , 𝑓(𝑥2 )], cuja raiz é
𝑓(𝑥2 )
𝑥3 = 𝑥2 − (𝑥 − 𝑥1 )
𝑓(𝑥2 ) − 𝑓(𝑥1 ) 2
Podemos fazer isso sucessivamente e encontrar uma relação de recorrência, tal que
𝑓(𝑥𝑛 )
𝑥𝑛+1 = 𝑥𝑛 − (𝑥 − 𝑥𝑛−1 )
𝑓(𝑥𝑛 ) − 𝑓(𝑥𝑛−1 ) 𝑛
4

Podemos proceder a iteração até o resíduo 𝑥𝑛+1 − 𝑥𝑛 atingir o limite de convergência


desejado.
# Definimos a tolerância para o problema
tolera = 0.00001

9
Morais & Nogueira – Física Computacional com Python

# Definimos a função funcao(x) igual a equação que desejamos encontrar a


raiz
def funcao(x):
return (x**3) - 3.77*(x**2)
# Definimos a derivada da função obtida analiticamente
# O valor do chute inicial para x1 é
x = 3
# Valor inicial de x0 é
x_menos_um = 4
# Seja o valor do resíduo igual ao valor absoluto da função f(x)
residuo = abs(funcao(x))
# A solução é procurada até que o critério de convergência seja satisfeito
while tolera < residuo:
while funcao(x) == funcao(x_menos_um):
print('Deu m! Dividimos por zero')
break
x=x-(x-x_menos_um)*funcao(x)/((funcao(x)-funcao(x_menos_um)))
residuo = abs(funcao(x))
print("A raiz aproximada é"+str(x)+" cujo resíduo foi "+ str(residuo))
# Imprimindo na tela o valor encontrado
print("A raiz encontrada foi "+str(x)+" com tolerância de "+ str(tolera))

Figura 5- Saída do programa acima que utiliza o método da secante.

Utilizando Gráficos
Uma das grandes vantagens de se escrever os códigos em Python em comparação com
linguagens mais robustas como C, C++, Fortran e Assembler é a fácil visualização das
simulações. Uma das bibliotecas mais utilizadas é a matplotlib.pyplot. É possível representar
graficamente funções com certa facilidade. Vamos tentar...

O potencial de Lennard-Jones é um modelo simplificado da energia de interação entre


moléculas simples. O valor da energia potencial de interação entre duas moléculas separadas
por uma distância 𝑟 é escrito como
𝜎 12 𝜎 6
𝑉(𝑟) = 4𝜖 [( ) − ( ) ],
𝑟 𝑟
5

onde 𝜎 é a separação mínima entre duas moléculas de “caroço duro”1 (hard core) e 𝜖 é o
valor mínimo do potencial chamado de profundidade do poço expresso em kJ/mol. Sejam
𝜖 = 1,77kJ/mol e 𝜎 = 4,1 × 10−10 m no potencial de Lennard-Jones (equação Erro! Fonte d
e referência não encontrada.) para um átomo de xenônio, vamos escrever um programa

1
Chamamos de caroço duro as moléculas que preservam sua forma sem que haja a sobreposição de
duas partículas caroço duro, quando pressionadas uma contra a outra, i.e., se comportam como um corpo rígido.

10
Morais & Nogueira – Física Computacional com Python

para representar graficamente este potencial começando do valor de 𝑟1 = 4 × 10−10 m com


100 pontos até o ponto 𝑟2 = 10−9 m.

Exercício. Por simplicidade, vamos supor que o movimento ocorra somente na direção 𝑋, tal
que a forma do potencial de Lennard-Jones é
𝜎 12 𝜎 6
𝑉(𝑥) = 4𝜖 [( ) − ( ) ]
𝑥 𝑥
1
e a energia total é 𝐸 = 2 𝑚𝑣𝑥2 + 𝑉(𝑥). A partícula estará confinada se 𝐸 < 0 entre os pontos
𝑥𝑚í𝑛 e 𝑥𝑚á𝑥 .
Faça um programa para encontrar os pontos 𝑥𝑚í𝑛 e 𝑥𝑚á𝑥 da órbita de uma partícula com
energia total 𝐸 = −4 × 10−12 J se o potencial tem os seguintes parâmetros 𝜎 = 2 × 10−9 m e
𝜖 = 5 × 10−12 J.

Máximos e Mínimos
É extremamente comum em Física a busca pelo valor de extremos de uma função. Ela
surge em muitas situações como a procura dos pontos de equilíbrio em funções de energia
potencial na Mecânica Clássica e na Mecânica Quântica, do equilíbrio dos potenciais
termodinâmicos e do melhor caminho óptico. Muitas linguagens, incluindo o Python,
apresentam funções implícitas e módulos para obtenção de máximos e mínimos em conjunto
de dados, mas vamos pelo caminho mais lógico antes de utilizar este atalho.
Seja a função 𝑓(𝑥), tal que esta função apresenta um máximo local na região de
interesse estudado [𝑥1 ; 𝑥2 ]. A busca por esse máximo consiste em varrer a região de interesse
e guardar o ponto em que a função 𝑓(𝑥) tem o maior valor.
import matplotlib.pyplot as plt
x_1 = 1.
x_2 = 5.
itera = 0
h = (x_2-x_1)/10
tolera = 0.000000001
# Definimos a função funcao(x) igual a equação que desejamos encontrar a
raiz
def funcao(x):
return 5-((x-3.77)**2)
# Escolhemos o chute inicial de x
x = x_1
# A variável Booleana achou que determina se a solução exata foi encontrada
achou = False
# A variável Booleana primeiro determina se o valor de x na iteração passou
da raiz pela primeira vez
primeiro = False
passou = False
fmax = funcao(x)
xmax=x

11
Morais & Nogueira – Física Computacional com Python

while abs(h)>tolera:
passou = False
if x<x_1 and x>x_2:
break
while passou == False:
itera += 1
x=x+h
# plotando os pontos em cada iteração
plt.scatter(x, funcao(x),)
if(funcao(x)>fmax):
xmax=x
fmax=funcao(x)
else:
passou = True
primeiro = True
x=x-h
h=-h*2./3.
# Plotando a função(x)
h=(x_2-x_1)/100.
x=x_1
xpontos=([x])
ypontos=([funcao(x)])
while x<x_2:
x=x+h
xpontos=xpontos+[x]
ypontos=ypontos+[funcao(x)]
plt.xlabel('x')
plt.ylabel('função (x)')
plt.plot(xpontos, ypontos)
xpontos2 = ([xmax,xmax])
ypontos2 = ([-3,6])
plt.plot(xpontos2,ypontos2)
plt.show()

Figura 6- Saída gráfica do


programa acima que utiliza o método de
busca de máximo. As bolinhas coloridas se
referem a cada iteração na busca do ponto
de máximo da função 𝑓(𝑥) = 5 −
(𝑥 − 3,77)2, cuja solução analítica é
𝑥𝑚á𝑥 = 3,77.

Interferência de ondas
Uma onda é uma perturbação de propagação de uma ou mais quantidades. As ondas
ocorrem em vários sistemas físicos, desde a perturbação que se propaga em um lago quando
se joga uma pedra, passando por vibrações estacionárias nas cordas de um violão e chegando
às ondas eletromagnéticas. Veremos mais a frente como as propriedades dos sistemas físicos
resultam na geração e propagação das ondas específicas nestes meios. Por hora, vamos nos
ater a solução mais simples da equação de onda clássica: a onda harmônica simples. Nela, a

12
Morais & Nogueira – Física Computacional com Python

amplitude 𝐴 , que é o valor do campo oscilante medido, é constante. Por exemplo, em uma
onda no lago, a amplitude é a altura máxima da água na onda em relação a água não-
perturbada no resto do lago. Matematicamente, a onda pode ser escrita na forma
𝜙 = 𝐴 sin(𝑘𝑥 ± 𝜔𝑡 + 𝛿)  
Aqui, 𝑘 é o número de onda, 𝜔 é a frequência angular de oscilação da onda e 𝛿 é uma
constante de fase. Note que a unidade de medida para 𝑘 é o radiano por metro (rad/m) e a
unidade de 𝜔 é o radiano por segundo (rad/s), assim restando a unidade de 𝛿 como radiano. É
comum expressar o número de onda em termos do comprimento de onda 𝜆 através da
2𝜋
relação𝑘 = 𝜆 . A frequência angular pode ser expressa como 𝜔 = 2𝜋𝑓 , onde 𝑓 é a
frequência da onda. 𝑓 e 𝜔 estão relacionados com a velocidade de fase da onda 𝑣 por 𝑣 =
𝜆𝑓 . A forma da onda pode ser escrita como
2𝜋𝑥
𝜙 = 𝐴 sen ( ± 2𝜋𝑓𝑡 + 𝛿)
𝜆
Suponha então duas ondas distintas cujas formas são
𝜙1 = 𝐴1 sen(𝑘1  𝑥 ± 𝜔1 𝑡)
𝜙2 = 𝐴2 sen(𝑘2  𝑥 ± 𝜔2 𝑡 + 𝛿2 )
A onda resultante da superposição destas ondas é a soma algébrica de suas formas
𝜙𝑅 = 𝜙1 + 𝜙2
𝐴+𝐵 𝐴−𝐵
Usando a relação trigonométrica para a soma dos senos sen 𝐴 + sen 𝐵 = 2 sen cos ,
2 2
temos
𝜙𝑅
𝐴1 − 𝐴2
= 𝜙1
𝐴1
(𝑘1  + 𝑘2 )𝑥 ± (𝜔1 + 𝜔2 )𝑡 + 𝛿2 (𝑘1  − 𝑘2 )𝑥 ± (𝜔1 − 𝜔2 )𝑡 − 𝛿2
+ 2𝐴2 sen cos
2 2
No caso em que as amplitudes são iguais, 𝐴1 = 𝐴2 = 𝐴, temos
(𝑘1  + 𝑘2 )𝑥 ± (𝜔1 + 𝜔2 )𝑡 + 𝛿2 (𝑘1  − 𝑘2 )𝑥 ± (𝜔1 − 𝜔2 )𝑡 − 𝛿2
𝜙𝑅 = 2𝐴 sen cos
2 2
Para o caso das duas ondas se propagarem no mesmo meio (longe da interface entre meios) e
supondo que as ondas tenham a mesma frequência, temos
𝛿2 𝛿2
𝜙𝑅 = 2𝐴 sen (𝑘𝑥 ± 𝜔𝑡 + ) cos
2 2

Batimento de ondas
Um fenômeno adjacente a qualquer interação de ondas é o chamado batimento. Ele
ocorre quando duas ondas sonoras com frequências próximas atingem o receptor. Neste caso,
vamos considerar 𝑥 = 0 e as ondas em fase, 𝛿2 = 0, tal que

13
Morais & Nogueira – Física Computacional com Python

(𝜔1 + 𝜔2 ) (𝜔1 − 𝜔2 )
𝜙𝑅 = (𝐴1 − 𝐴2 ) sen(𝜔1 𝑡) + 2𝐴2 sen 𝑡 cos 𝑡
2 2
No caso de as frequências serem próximas, podemos escrever a frequência da onda 2
como 𝜔1 = 𝜔2 + Δ𝜔, com Δ𝜔 → 0. Podemos aproximar a onda resultante por
Δ𝜔
𝜙𝑅 ≅ {𝐴1 + 𝐴2 [2 cos ( 𝑡) − 1]} sen(𝜔1 𝑡)
2
E no caso em que as amplitudes são iguais 𝐴1 = 𝐴2 = 𝐴, temos
Δ𝜔
𝜙𝑅 ≅ 2𝐴 cos ( 𝑡) sen(𝜔1 𝑡)
2
import math as m
import matplotlib.pyplot as plt
import numpy as np
# Seja Tamanho o comprimento que se deseja observar da interferência
Tamanho = 2.*m.pi
# O incremento é o tamanho dividio pelo número de pontos
N = 1000
h = Tamanho/N
# Definindo os valores da onda 1
a1 = 1
k1 = 8*m.pi
fi1 = 0.
# Definindo os valores da onda 2
a2 = 1
k2 = 8.5*m.pi
fi2 = 0
def onda(a,k,x,fi):
return a*m.sin(k*x+fi)
x=([0.])
S1 = ([onda(a1,k1,x[-1],fi1)])
S2 = ([onda(a2,k2,x[-1],fi2)])
# A onda resultante é a soma das duas ondas
resultante = ([onda(a1,k1,x[-1],fi1)+onda(a2,k2,x[-1],fi2)])
itera=0
while x[-1]<Tamanho:
itera += 1
x = x+[itera*h]
S1 = S1+[onda(a1,k1,x[-1],fi1)]
S2 = S2+[onda(a2,k2,x[-1],fi2)]
resultante = resultante+ [onda(a1,k1,x[-1],fi1)+onda(a2,k2,x[-1],fi2)]
# Gráficos
plt.plot(x, S1,label="Onda 1")
plt.plot(x, S2,label="Onda 2")
plt.plot(x, resultante,label="Resultante")
# Caso a intensidade seja de interesse, descomente as três linhas abaixo
#Intensidade = np.array(resultante)
#Intensidade = Intensidade**2
#plt.plot(x, Intensidade,label="Intensidade")
plt.xlabel("Espaço (m)")
plt.ylabel("Valores das Funções")
plt.legend()
plt.show()

14
Morais & Nogueira – Física Computacional com Python

Figura 7- Saída gráfica do programa para interação de ondas. Os valores do batimento mostrado referem-se às
ondas …

Polarização da Luz
A polarização é uma propriedade das ondas transversais a qual especifica a orientação
geométrica da direção de oscilação da onda. Em uma onda transversal, a direção da oscilação
é sempre perpendicular à direção do movimento da onda, como as vibrações que viajam ao
longo de uma corda esticada. Dependendo de como a corda é acionada, as vibrações podem
ser na direção vertical, horizontal ou em qualquer ângulo perpendicular à corda. Em
contraste, em ondas longitudinais, como ondas sonoras em um líquido ou gás, o
deslocamento das partículas na oscilação é sempre na direção de propagação, de modo que
essas ondas não apresentam polarização. Ondas transversais que exibem polarização incluem
ondas eletromagnéticas, como ondas de luz e rádio, ondas gravitacionais e ondas sonoras
transversais (ondas de cisalhamento) em sólidos.
As ondas eletromagnéticas

# Programa de polarização da luz


import matplotlib.pyplot as plt
import numpy as np
import math as m
# ni é o índice de refração do meio de onde vem a luz (incidente)
ni = 1.
# nt é o índice de refração do meio para onda e luz é transmitida
nt = 1.5
#vamos definir o cosseno do ângulo de transmissão através da lei de Snell
def costt(ni,nt,tetai):
return m.sqrt(1.-(ni/nt)*m.sin(tetai))
# definindo o coeficiente de reflexão através das equações de Fresnel para
os modos s e p
def CRs(nt,ni,tetai,cost):
return (nt*m.cos(tetai)-ni*cost)/(nt*m.cos(tetai)+ni*cost)
def CRp(nt,ni,tetai,cost):
return (ni*m.cos(tetai)-nt*cost)/(ni*m.cos(tetai)+nt*cost)

15
Morais & Nogueira – Física Computacional com Python

# definindo o passo como h igual a 90º/100


itera = 0
h = m.pi/200.
# definindo o ângulo incidente inicial tetai = 0
tetai = 0.
# definindo o valor as funções no angulo 0
# Note que guardamos a Refletividade = c_R**2
tt = costt(ni,nt,tetai)
Rs = (CRs(nt,ni,tetai,tt))**2
Rp = (CRp(nt,ni,tetai,tt))**2
# Guardamos a transmissividade T+R=1
Ts = 1.-Rs
Tp = 1.-Rp
# Criamos o array tetaipontos para armazenar os pontos do ângulo de entrada
tetaipontos = ([tetai])
# Criamos os arrays Tspontos e Tpppontos para armazenar os pontos da
transmissividade nos modos s e p
Tspontos = ([Ts])
Tppontos = ([Tp])
Rspontos = ([Rs])
Rppontos = ([Rp])
# Criando o y para guardar o menor valor da Reflectividade S
Brewster = 1.
# O laço é feito até que o ângulo de incidência seja igual a 90º
while tetai < m.pi/2:
itera += 1
tetai = itera*h
tt = costt(ni,nt,tetai)
Rs = (CRs(nt,ni,tetai,tt))**2
Rp = (CRp(nt,ni,tetai,tt))**2
Ts = 1.-Rs
Tp = 1.-Rp
tetaipontos = tetaipontos + [tetai]
Rspontos = Rspontos + [Rs]
Rppontos = Rppontos + [Rp]
Tspontos = Tspontos + [Ts]
Tppontos = Tppontos + [Tp]
if Brewster > Rs:
Brewster = Rs
TetaB = tetai
# Fazendo o gráfico com os pontos do tempo contra a posição
tetapontosgraus = np.array(tetaipontos)*180./m.pi
Tcruzada = (np.array(Tspontos)+np.array(Tppontos))/2.
# Definimos os eixos dos gráficos
plt.xlim([0, 90])
plt.ylim([0, 1])
# Definindo os nomes dos eixos
plt.xlabel("Ângulo")
plt.ylabel("Função de resposta")
# Definindo as legendas e plotando as Transmissividades em função do ângulo
de incidência
plt.plot(tetapontosgraus,Rspontos,label="R Polarização-S")
plt.plot(tetapontosgraus,Rppontos,label="R Polarização-P")
plt.plot(tetapontosgraus,Tspontos,label="T Polarização-S")
plt.plot(tetapontosgraus,Tppontos,label="T Polarização-P")
#plt.plot(tetapontosgraus,Tcruzada,label="Polarização Circular")
# Escrendo a reta do ângulo de Teta
TetaB = TetaB*180./m.pi
x = [TetaB,TetaB]
y = [0,1]
plt.plot(x, y)

16
Morais & Nogueira – Física Computacional com Python

TetaB = TetaB-4
# round(Numero, casas decimais)
Texto = 'Ângulo de Brewster = ' + str(round(TetaB+4,3))
plt.text(TetaB, 0.1, Texto, rotation=90)
plt.legend()
plt.show()

Figura 8- Saída gráfica do programa das Equações de Fresnel e algoritmo de busca do máximo para encontrar o
ângulo de polarização de Brewster.

17
Morais & Nogueira – Física Computacional com Python

PARTE II: Insira o Título da parte


Use trechos subsequentes para abordar as áreas mais detalhadas ou complexas do
tópico do livro. Como a Parte I definiu o tópico/problema, considere usar esta seção para
fornecer soluções. Nesse caso, um título de exemplo adequado seria "Como Identificar as
Estratégias Corretas para a Criação de Filhos" ou "Como Tornar a Mentalidade de seu Filho à
Prova de Balas." Não se esqueça de que os capítulos desta parte do livro devem se alinhar
ao título da parte que você escolheu.

18
Morais & Nogueira – Física Computacional com Python

Capítulo Três: Equações Diferenciais Ordinárias


Inicie um novo capítulo aqui...
Método de Euler
O método mais simples para solucionar numericamente EDOs de primeira ordem é o
Método de Euler. Este método consiste em aproximar a derivada 𝑓 ′(𝑥) = 𝑔(𝑥) através da
definição via limite:
𝑓(𝑥 + ℎ) − 𝑓(𝑥) 𝑓(𝑥 + ℎ) − 𝑓(𝑥)
𝑔(𝑥) = lim ≈
ℎ→0 ℎ ℎ
onde ℎ é o incremento. Retornando, temos
𝑓(𝑥 + ℎ) = 𝑓(𝑥) + ℎ𝑔(𝑥)
Seja o valor inicial da função 𝑓0 = 𝑓(𝑥0 ) no ponto 𝑥0 e 𝑓1 = 𝑓(𝑥1 ) = 𝑓(𝑥0 + ℎ), podemos
encontrar o valor de 𝑓1 por
𝑓1 = 𝑓0 + ℎ𝑔0
A iteração deste método é então
𝑥𝑛+1 = 𝑥𝑛 + ℎ
𝑓𝑛+1 = 𝑓𝑛 + ℎ𝑔𝑛

Velocidade Terminal
Uma esfera sólida, que tem um movimento relativo a um fluido, experimenta uma
força de arrasto de modo a resistir o movimento. A força de arrasto é proporcional à
velocidade para escoamentos lentos e ao quadrado da velocidade para escoamentos de alta
velocidade. A quantificação do que é lento ou rápido requer a definição de um parâmetro,
chamado de Número de Reynolds, o qual definiremos no capítulo X. Por hora, vamos
apenas utilizar o resultado obtido por George Stokes, em 1851, da força de arrasto de uma
esfera passando lentamente por um fluido viscoso. Essa força é conhecida como Lei de
Stokes e sua forma para uma esfera de raio 𝑅 viajando a uma velocidade relativa 𝑣⃗ em
relação a um fluido cuja viscosidade é 𝜇 é

𝐹⃗ = −6𝜋𝜇𝑅𝑣⃗
Note que a viscosidade tem unidades de newton-segundo por metro quadrado ou
pascal vezes segundo, no SI.

19
Morais & Nogueira – Física Computacional com Python

Em 1883, Osborne Reynolds descreveu a transição do escoamento laminar2 para


turbulento3 em um experimento clássico no qual estudou o comportamento do escoamento de
água sob diferentes velocidades usando um pequeno escoamento de água tingida introduzido
no centro do escoamento de água clara em um tubo maior de vidro. Quando a velocidade era
baixa, a camada tingida permanecia marcada em todo o comprimento do tubo grande.
Quando a velocidade foi aumentada, a camada se rompeu em um determinado ponto e se
difundiu por toda a seção transversal do fluido. Este é o ponto que marca a transição do
escoamento laminar para o turbulento. O Número de Reynolds é a razão entre as forças
inerciais e as forças viscosas dentro de um fluido que está sujeito a movimento interno
relativo devido a diferentes velocidades do fluido. Mesmo que a causa final de um arrasto
seja o atrito viscoso, o arrasto turbulento é independente da viscosidade.
Considere o exemplo em que se deseja encontrar a velocidade de uma esfera caindo
em fluido lentamente sujeita à força de Stokes e seu próprio peso. As forças atuando na esfera
são seu peso 𝑚𝑔 e a força de arrasto 𝑏𝑣, com 𝑏 = 6𝜋𝜇𝑅. A velocidade terminal é alcançada
quando estas forças se igualam, resultando em
𝑚𝑔
𝑣∞ =
𝑏
Vamos então fazer um algoritmo de Euler para encontrar a velocidade da esfera
partindo do repouso com massa 𝑚 = 80 kg e 𝑏 = 10 N.s/m.

import math as mt
import matplotlib.pyplot as plt

m = 80
grav = 9.8
b = 10
v = 0.
t = 0.
h = 0.01
# Vamos definir a função de dv/dt
def g(grav,b,m,v):
return grav-(b*v/m)

vterm = m*grav/b
print('A velocidade terminal para o problema é ', vterm, 'm/s')

tpontos = [t]
vpontos = [v]
while v<.999*vterm:
t += h
v += h*g(grav,b,m,v)
tpontos += [t]
vpontos += [v]

2
No escoamento laminar as partículas de fluido seguem caminhos suaves em lâminas, com cada
lâmina movendo-se suavemente pelas lâminas vizinhas com pouca ou nenhuma mistura. Em baixas velocidades,
o fluido tende a fluir sem mistura lateral, e camadas adjacentes deslizam umas sobre as outras.
3
O escoamento turbulento é o movimento do fluido caracterizado por mudanças caóticas na pressão e
na velocidade do escoamento.

20
Morais & Nogueira – Física Computacional com Python

# Gráficos
# Definindo os rótulos x e y
plt.xlabel('Tempo (s)')
plt.ylabel('Velocidade (m/s)')
# Definindo os limites do gráfico
plt.xlim(0, t)
plt.ylim(0, 1.1*v)
# Plotando os pontos da velocidade
plt.plot(tpontos,vpontos,label='v(t)')
# Plotando os pontos da linha auxiliar
linhaauxiliart = [0]
linhaauxiliarv = [vterm]
linhaauxiliart += [t]
linhaauxiliarv += [vterm]
plt.plot(linhaauxiliart,linhaauxiliarv,':',label='Velocidade Terminal')
plt.legend()
plt.show()

Estabilidade e Erro do Método do Euler


O erro de truncamento local do método de Euler é o erro cometido em uma única
iteração. É a diferença entre a solução numérica após uma etapa, 𝑓𝑛+1 , e a solução exata na
posição 𝑥𝑛+1. A aproximação é que
𝑓𝑛+1 = 𝑓𝑛 + ℎ𝑔𝑛
Qualquer função 𝑓(𝑥) que na região de interesse tenha valor único com um número
infinito de derivadas contínuas pode ser expressa com uma série de Taylor. Assim sendo,
vamos fazer a expansão em séries de Taylor de 𝑓(𝑥) em torno de ℎ :

𝑑𝑖 𝑓 ℎ𝑖
𝑓(𝑥 + ℎ) = ∑ (𝑥)  
𝑑𝑥 𝑖 𝑖!
𝑖=0

Esta é a solução extada função, seja ela qual for. Subtraindo da equação acima, a
aproximação de Euler, temos

21
Morais & Nogueira – Física Computacional com Python


𝑑𝑖 𝑓 ℎ𝑖
𝑓(𝑥 + ℎ) − 𝑓𝑛+1 = ∑ (𝑥)  
𝑑𝑥 𝑖 𝑖!
𝑖=2

Assim, o erro de truncamento é da ordem de ℎ2 , enquanto o erro local é da ordem de


ℎ.

Método de Taylor
Como vimos, a propagação de erro no Método de Euler em equações não-lineares
impossibilita sua utilização devido ao custo computacional, desde que o erro não é
amortizado. Ao invés de utilizarmos a definição da derivada para aproximar a primeira
derivada, podemos utilizar uma expansão em séries de Taylor da função 𝑓(𝑥) em torno de ℎ :
𝑑𝑓 ℎ2 𝑑 2 𝑓
𝑓(𝑥 + ℎ) ≈ 𝑓(𝑥) + ℎ (𝑥) + (𝑥) + ⋯
𝑑𝑥 2 𝑑𝑥 2
𝑑𝑓
Note que 𝑔 = 𝑑𝑥 , que é uma derivada total. Logo

𝑑𝑔 𝜕𝑔 𝑑𝑥 𝜕𝑔  𝑑𝑓 𝜕𝑔 𝜕𝑔
= + = + 𝑔
𝑑𝑥  𝜕𝑥 𝑑𝑥 𝜕𝑓 𝑑𝑥  𝜕𝑥 𝜕𝑓
Introduzindo a equação X na equação acima, temos
ℎ2 𝜕𝑔 𝜕𝑔
𝑓(𝑥 + ℎ) ≈ 𝑓(𝑥) + ℎ𝑔(𝑥) + [ (𝑥) + (𝑥)𝑔(𝑥)] + ⋯
2 𝜕𝑥 𝜕𝑓
Na nossa notação de equação de diferença, fica
ℎ2 𝜕𝑔 𝜕𝑔
𝑓𝑛+1 ≈ 𝑓𝑛 + ℎ𝑔𝑛 + ( + 𝑔) + ⋯
2 𝜕𝑥 𝜕𝑓 𝑛
Claramente, as derivadas de 𝑔 são calculadas em 𝑥𝑛 . Note que o erro local é na
segunda ordem e o de truncamento é da ordem de ℎ3 .
Exemplo: Vamos encontrar a solução da seguinte equação diferencial de primeira
ordem
𝑑𝑦
= −𝑥 2 𝑦
𝑑𝑥
Equação 6

com condição de contorno 𝑦(0) = 1 pelos métodos de Euler e Taylor. Vamos chamar
𝜕𝑓 𝜕𝑓
𝑓(𝑥) = −𝑥 2 𝑦. Assim, as derivadas aparecendo no Método de Taylor são 𝜕𝑥 = −2𝑥𝑦 e 𝜕𝑦 =
−𝑥 2 .
A solução analítica desta equação pode ser obtida diretamente da integração simples,
𝑥3
resultando em 𝑦(𝑥) = 𝑒 − 3 .
Código Usando o Método de Euler
import math as mt
import matplotlib.pyplot as plt

22
Morais & Nogueira – Física Computacional com Python

# Definindo a função a ser encontrada


def funcao(x,y):
return -y*x*x
# Definindo o valor exato desta função com a condição de contorno desejada
def exato(x):
return mt.exp(-(x**3)/3.)
# Definindo as condições de operação do programa
x0 = 0
y0 = 1
xfinal = 2
N_passos = 20
h = (xfinal-x0)/N_passos
contador = 0
# Definindo a condição de contorno
x=x0
y=y0
xpontos=([x0])
ypontos=([y0])
yexato =([y0])
Erro =([0.])

while contador < N_passos:


contador += 1
x = x+h
xpontos=xpontos+[x]
derivada = h*funcao(x,y)
y=y+derivada
ypontos=ypontos+[y]
yexato=yexato+[exato(x)]
Erro = Erro +[1.-y/exato(x)]

# Gráficos: vamos utilizar o módulo subplot para gerar dois gráficos


agrupados verticalmente com plt.subplot(2)
plt.figure()
plt.subplot(211)
plt.plot(xpontos, ypontos, label=("Euler h="+str(h)), color='tab:blue')
plt.plot(xpontos, yexato, label="Analítico", color='black')
plt.ylabel("y")
plt.legend()
plt.subplot(212)
plt.plot(xpontos, Erro, label="(Exato - Calculado)/Exato",
color='tab:orange', linestyle='--')
plt.xlabel("x")
plt.ylabel("Erro")
plt.legend()
plt.show()

A saída em tela do programa é

23
Morais & Nogueira – Física Computacional com Python

Figura 9 - Saída do programa para solução de 𝑦(𝑥) = −𝑥 2 𝑦 pelo método de Euler. A figura de baixa mostra a
propagação do erro fracional.

Figura 10- Saída do programa para solução de 𝑦(𝑥) = −𝑥 2 𝑦 pelo método de Taylor. A figura de baixa mostra a
propagação do erro fracional

Código utilizando o método de Taylor


import math as mt
import matplotlib.pyplot as plt
def funcao(x,y):
return -y*x*x
def exato(x):
return mt.exp(-(x**3)/3.)
# Para usar o método de Taylor, devemos agora definir as funções df/dx e
df/dy
def dfdx(x,y):
return -2*y*x
def dfdy(x,y):
return -x*x
# Definindo as condições de operação do programa
x0 = 0
y0 = 1
xfinal = 2
N_passos = 20
h = (xfinal-x0)/N_passos

24
Morais & Nogueira – Física Computacional com Python

contador = 0
# Definindo as condições de contorno
x=x0
y=y0
xpontos=([x0])
ypontos=([y0])
yexato =([y0])
Erro =([0.])

while contador < N_passos:


contador += 1
x = x+h
xpontos=xpontos+[x]
derivadas = h*funcao(x,y)+0.5*h*h*(dfdx(x,y)+funcao(x,y)*dfdy(x,y))
y=y+derivadas
ypontos=ypontos+[y]
yexato=yexato+[exato(x)]
Erro = Erro +[1.-y/exato(x)]

# Gráficos
plt.figure()
plt.subplot(211)
plt.plot(xpontos, ypontos, label=("Taylor h="+str(h)), color='tab:blue')
plt.plot(xpontos, yexato, label="Analítico", color='black')
plt.legend()
plt.ylabel("y")
plt.subplot(212)
plt.plot(xpontos, Erro, label="1 - Calculado/Exato", color='tab:orange',
linestyle='--')
plt.xlabel("x")
plt.ylabel("Erro")
plt.legend()
plt.show()

Exercício: Encontre através do método de Taylor a solução numérica da velocidade do corpo


no problema de um corpo caindo sujeito ao peso 𝑚𝑔 e a resistência do ar dada pela Lei de
Stokes 𝑏𝑣, onde 𝑣 é a velocidade do corpo. Considere o corpo inicialmente parado 𝑣(𝑡 =
0) = 0 m/s. Uma vez que a velocidade terminal para este problema é 𝑣∞ = 𝑚𝑔/𝑏, faça a
iteração até que a velocidade atinja 95% de 𝑣∞ . Por simplicidade, faça 𝑚 = 0,1 kg, 𝑏 = 0,01
N.s/m e 𝑔 = 9,8 m/s². Apresente graficamente seu resultado.
Ao contrário do método de Euler, que pode ser usado para solucionar um conjunto de
EDOs de primeira ordem, o método de Taylor não nos permite isso, pois necessitamos das
derivadas das funções em todas as etapas. Por exemplo, para solucionar a posição no
𝑑𝑣
exercício anterior, necessitamos resolver, além de 𝑚 𝑑𝑡 = 𝑚𝑔 − 𝑏𝑣, a equação para a posição
𝑑𝑥
= 𝑣. Todavia, não podemos usar o método de Taylor, pois embora tenhamos 𝑑𝑣/𝑑𝑡, não
𝑑𝑡
temos explicitamente 𝜕𝑣/𝜕𝑡 e nem 𝜕𝑣/𝜕𝑥.

Métodos de Passos Múltiplos

Método de Adams-Bashforth

25
Morais & Nogueira – Física Computacional com Python

Podemos melhorar a precisão, podemos fazer uso de relações que envolvam mais ordens na
equação de diferença, ide est, além de 𝑓𝑛+1 e 𝑓𝑛 , podemos invocar 𝑓𝑛−1, 𝑓𝑛−2, et cetera.
Desde que
𝑑𝑓
= 𝑔(𝑥, 𝑓)
𝑑𝑥
podemos integrar para obter
𝑓𝑛+1 𝑥𝑛+1

∫ 𝑑𝑓 = ∫ 𝑔(𝑥, 𝑓)𝑑𝑥
𝑓𝑛 𝑥𝑛
𝑥𝑛+1

𝑓𝑛+1 = 𝑓𝑛 + ∫ 𝑔(𝑥, 𝑓)𝑑𝑥


𝑥𝑛

Todavia, não conhecemos a forma de 𝑔 dentro do intervalo de integração. Aí, nós


vamos fazer uma extrapolação linear de 𝑔 sobre este intervalo (ver Figura 11). Note que
𝑔(𝑥) = 𝑎𝑥 + 𝑏
𝑔𝑛−1 = 𝑎𝑥𝑛−1 + 𝑏
𝑔𝑛 = 𝑎𝑥𝑛 + 𝑏
e 𝑥𝑛 − 𝑥𝑛−1 = ℎ. Assim, 𝑎 = (𝑔𝑛 − 𝑔𝑛−1 )/ℎ e 𝑏 = 𝑔𝑛 − 𝑥𝑛 (𝑔𝑛 − 𝑔𝑛−1 )/ℎ. Assim
𝑔𝑛 − 𝑔𝑛−1 𝑔𝑛 − 𝑔𝑛−1
𝑔(𝑥) ≈ 𝑥 + 𝑔𝑛 − 𝑥𝑛
ℎ ℎ
resultando em
𝑥𝑛+1
𝑔𝑛 − 𝑔𝑛−1 𝑔𝑛 − 𝑔𝑛−1
𝑓𝑛+1 ≈ 𝑓𝑛 + ∫ [ 𝑥 + 𝑔𝑛 − 𝑥𝑛 ] 𝑑𝑥
ℎ ℎ
𝑥𝑛
𝑥
𝑔𝑛 − 𝑔𝑛−1 𝑥 2 𝑛+1 𝑔𝑛 − 𝑔𝑛−1 𝑥
𝑓𝑛+1 ≈ 𝑓𝑛 + ( ) + (𝑔𝑛 − 𝑥𝑛 ) (𝑥)𝑥𝑛𝑛+1
ℎ 2 𝑥 ℎ
𝑛

𝑔𝑛 − 𝑔𝑛−1 2 𝑔𝑛 − 𝑔𝑛−1
𝑓𝑛+1 ≈ 𝑓𝑛 + (𝑥𝑛+1 − 𝑥𝑛2 ) + (𝑔𝑛 − 𝑥𝑛 ) (𝑥𝑛+1 − 𝑥𝑛 )
2ℎ ℎ
𝑔𝑛 − 𝑔𝑛−1 2 𝑔𝑛 − 𝑔𝑛−1
𝑓𝑛+1 ≈ 𝑓𝑛 + (𝑥𝑛+1 − 𝑥𝑛2 ) + (𝑔𝑛 − 𝑥𝑛 ) ℎ
2ℎ ℎ
𝑔𝑛 − 𝑔𝑛−1 𝑔𝑛 − 𝑔𝑛−1
𝑓𝑛+1 ≈ 𝑓𝑛 + (𝑥𝑛+1 + 𝑥𝑛 )(𝑥𝑛+1 − 𝑥𝑛 ) + (𝑔𝑛 − 𝑥𝑛 ) ℎ
2ℎ ℎ
𝑔𝑛 − 𝑔𝑛−1 𝑔𝑛 − 𝑔𝑛−1
𝑓𝑛+1 ≈ 𝑓𝑛 + ℎ(𝑥𝑛+1 + 𝑥𝑛 ) + (𝑔𝑛 − 𝑥𝑛 ) ℎ
2ℎ ℎ
𝑔𝑛 − 𝑔𝑛−1
𝑓𝑛+1 ≈ 𝑓𝑛 + ℎ(𝑥𝑛+1 − 2𝑥𝑛 + 𝑥𝑛 ) + 𝑔𝑛 ℎ
2ℎ
𝑔𝑛 − 𝑔𝑛−1
𝑓𝑛+1 ≈ 𝑓𝑛 + ℎ(𝑥𝑛+1 − 𝑥𝑛 ) + 𝑔𝑛 ℎ
2ℎ

26
Morais & Nogueira – Física Computacional com Python

𝑔𝑛 − 𝑔𝑛−1
𝑓𝑛+1 ≈ 𝑓𝑛 + ℎ + 𝑔𝑛 ℎ
2
3 1
𝑓𝑛+1 ≈ 𝑓𝑛 + ℎ ( 𝑔𝑛 − 𝑔𝑛−1 )
2 2
A ordem do erro local neste método de passo duplo é ℎ2 . Poderíamos ter aproximado
a função 𝑔(𝑥) no intervalo por uma outra função polinomial, resultando em uma precisão
maior e num maior número de passos.

Figura 11- Representação da extrapolação de reta da função 𝑔(𝑥).

Note que para a implementação deste algoritmo é necessário o conhecimento de dois


passos antes do passo 𝑛 + 1. Isto pode ser conseguido com um único passo pelo método de
Euler e os passos seguintes usando este método.
Exemplo: Circuito RL.
Considere um circuito elétrico constituído de um resistor com resistência 𝑅 e um
indutor com indutância 𝐿 ligados em série a uma diferença de potencial 𝑉. A diferença de
potencial entre as extremidades do resistor é 𝑅𝐼 e no indutor é 𝐿𝑑𝐼/𝑑𝑡, onde 𝐼(𝑡) é a corrente
elétrica variável no circuito. A equação governante do problema
𝑑𝐼
𝐿 + 𝑅𝐼 = 𝑉
𝑑𝑡
Note que 𝑉 pode ser dependente do tempo, mas por simplicidade vamos considerá-la
constante com valor 𝑉 = 𝑉0:
𝑑𝐼 𝑉0 𝑅
= − 𝐼
𝑑𝑡 𝐿 𝐿

27
Morais & Nogueira – Física Computacional com Python

A solução analítica para esse problema é


𝑉0
𝐼(𝑡) = (1 − 𝑒 −𝑅𝑡/𝐿 )
𝑅
A constante de fase do circuito RL é 𝜏 = 𝐿/𝑅.
Vamos utilizar o método de Adams-Bashforth para resolver este problema
numericamente com 𝑅 = 2 Ω, 𝐿 = 450 𝜇𝐻 e 𝑉0 = 12 Volts com corrente inicial 𝐼(𝑡 = 0) =
𝐼0 = 0 A.
import math as mt
import matplotlib.pyplot as plt

# vamos definir as variáveis do problema no sistema internacional de


unidades
L = 0.000450
R = 2
V = 12.
I = 0.
tempo = 0
tau = L/R
print('A constante de fase do circuito RL é ',tau,' segundos')
# vanmos definir a função governante do problema
def g(V,L,R,I):
return (V/L)-(R*I/L)

# vamos definir o incremento temporal em termos da constante de fase


h = 0.01*tau
tpontos=[tempo]
Ipontos=[I]
# Precisamos dos pontos n e n-1 para aplicar o método de Adams-Bahsforth.
# assim, vamos realizar um passo de Euler para ter dois passos.
tempo += h
I += h*g(V,L,R,I)
tpontos +=[tempo]
Ipontos +=[I]

while tempo < 4*tau:


tempo += h
I += h*(1.5*g(V,L,R,Ipontos[-1])-0.5*g(V,L,R,Ipontos[-2]))
tpontos +=[tempo]
Ipontos +=[I]

print(Ipontos)
plt.xlabel("Tempo (s)")
plt.ylabel("Corrente (ampères)")
plt.plot(tpontos,Ipontos,label='I(t)')
# definindo a reta assintótica da corrente
auxiliart = [0]
auxiliarI = [V/R]
auxiliart += [tempo]
auxiliarI += [V/R]
plt.plot(auxiliart,auxiliarI,':', label='Corrente máxima')

plt.legend()
plt.show()

28
Morais & Nogueira – Física Computacional com Python

Figura 12- Solução numérica do circuito RL com o método de Adams-Bashforth. Note que a corrente do circuito
evolui assintoticamente para o valor da corrente máxima para quando o indutor está carregado.

Exercício: Considere o circuito RL acima, mas agora com diferença de potencial


variável 𝑉 = 12 sen(62,8𝑡) Volts. Resolva este circuito mostrando o gráfico para o tempo
igual a 4 constantes de fase.

O procedimento para o circuito RLC, cujas equações de primeira ordem acopladas


são:
𝑑𝐼 𝑉 𝑅 1
= − 𝐼− 𝑞,
𝑑𝑡 𝐿 𝐿 𝐿𝐶
7

𝑑𝑞
= 𝐼,
𝑑𝑡
8

onde 𝑞 é a carga acumulada no capacitor e 𝐶 é a capacitância expressa em farads. No circuito


RLC, a frequência natural do circuito é 𝜔0 = 1/√𝐿𝐶, o fator de carga é definido como 𝜉 =
𝑅/2𝐿 e a frequência de ressonância com carga é 𝜔 = √𝜔02 − 𝜉 2 . O período com que o
circuito oscila é 𝑇 = 2𝜋/𝜔. A solução analítica deste problema é semelhante a um oscilador
harmônico amortecido, tal que a corrente diminui assintoticamente em um tempo muito
grande.
O código abaixo, utiliza o método de Adams-Bashforth para resolver este circuito em série
com condições iniciais de 𝐼 = 0 ampères e 𝑞 = 0 coulombs e valores dos dispositivos 𝑉 =
12 volts, 𝑅 = 2 Ω , 𝐿 = 0,1 henrys e 𝐶 = 450 𝜇F.
import math as mt

29
Morais & Nogueira – Física Computacional com Python

import matplotlib.pyplot as plt


# vamos definir as variáveis do problema no sistema internacional de
unidades
L = 0.1
R = 2
V = 12.
C = 0.00045
# as variáveis são
q = 0.
I = 0.
tempo = 0

tau = L/R
freq0 = 1./mt.sqrt(L*C)
fatordecarga = R/(2*L)
freq = mt.sqrt((freq0**2)-(fatordecarga**2))
periodo = (2*mt.pi)/freq
#print('A constante de fase do circuito RL é ',tau,' segundos')
print('A frequencia de ressonancia do circuito RLC é ',
round(freq0),'rad/s')
print('O fator de carga é ',round(fatordecarga))
print('A frequencia de ressonancia com carga é ', round(freq),'rad/s')
print(periodo)
# vanmos definir a função governante do problema
def g(V,L,R,I,q,C):
return (V/L)-(R*I/L)-(q/(L*C))
# vamos definir o incremento temporal em termos da constante de fase
h = 0.01*tau
tpontos=[tempo]
qpontos=[q]
Ipontos=[I]
# Precisamos dos pontos n e n-1 para aplicar o método de Adams-Bahsforth.
# assim, vamos realizar um passo de Euler para ter dois passos.
tempo += h
q += h*I
I += h*g(V,L,R,I,q,C)
tpontos +=[tempo]
qpontos +=[q]
Ipontos +=[I]
while tempo < 4*tau:
tempo += h
q += h*(1.5*Ipontos[-1]-0.5*Ipontos[-2])
I += h*(1.5*g(V,L,R,Ipontos[-1],qpontos[-1],C)-0.5*g(V,L,R,Ipontos[-
2],qpontos[-2],C))
qpontos += [q]
tpontos +=[tempo]
Ipontos +=[I]

plt.xlabel("Tempo (s)")
plt.ylabel("Corrente (ampères)")
plt.xlim(0,tempo)
plt.ylim(-1.1*max(Ipontos),1.1*max(Ipontos))
plt.plot(tpontos,Ipontos,label='I(t)')
# definindo a reta assintótica da corrente
auxiliart = [0]
auxiliarI = [0]
auxiliart += [tempo]
auxiliarI += [0]
plt.plot(auxiliart,auxiliarI,':')
# Desenhando o período da oscilação no gráfico
auxiliar2t = [periodo]

30
Morais & Nogueira – Física Computacional com Python

auxiliar2I = [0.25*max(Ipontos)]
auxiliar2t += [2.*periodo]
auxiliar2I += [0.25*max(Ipontos)]
plt.plot(auxiliar2t,auxiliar2I,'o',color='green')
plt.plot(auxiliar2t,auxiliar2I,color='green')
plt.text(1.5*periodo, 0.3*max(Ipontos),'Período',
horizontalalignment='center')

Figura 13- Solução do circuito RLC pelo método de Adams-Bashforth.

Métodos de Runge-Kutta
Os métodos Runge-Kutta de solução de EDOs são os mais utilizados. Ele consiste em
calculas as inclinações em cada passo. Por exemplo, o passo seguinte para a terceira ordem é
na forma
𝑓𝑛+1 = 𝑓𝑛 + ℎ(𝑎1 𝑘1 + 𝑎2 𝑘2 + 𝑎3 𝑘3 )
com
𝑘1 = 𝑔(𝑥𝑛 , 𝑓𝑛 ),
𝑘2 = 𝑔(𝑥𝑛 + 𝑝1 ℎ, 𝑓𝑛 + 𝑞11 ℎ𝑘1 )
𝑘3 = 𝑔(𝑥𝑛 + 𝑝2 ℎ, 𝑓𝑛 + 𝑞21 ℎ𝑘1 + 𝑞22 ℎ𝑘2 )
A expansão em séries de Taylor de 𝑓(𝑥𝑛 + ℎ) em torno de 𝑥𝑛 até a quarta ordem é
ℎ2 𝜕𝑔 𝜕𝑔
𝑓𝑛+1 = 𝑓𝑛 + ℎ𝑔(𝑥𝑛 , 𝑓𝑛 ) + ( +𝑔 )
2 𝜕𝑥 𝜕𝑓
3 2 2
ℎ 𝜕 𝑔 𝜕 𝑔 𝜕𝑔 𝜕𝑔 𝜕 2𝑔 𝜕𝑔 𝜕𝑔
+ ( 2 + 2𝑔 + + 𝑔2 2
+𝑔 )+⋯
6 𝜕𝑥 𝜕𝑥𝜕𝑓 𝜕𝑥 𝜕𝑓 𝜕𝑓 𝜕𝑓 𝜕𝑓
Equação 9

A expansão de Taylor dos termos em é mostrada até a quarta ordem, em vez de até a quinta,
como deveríamos para verificar se os termos de ordem mais alta eventualmente se cancelam,

31
Morais & Nogueira – Física Computacional com Python

mas assumiremos que o método não pode alcançar melhor precisão local do que a quarta
ordem, ou equivalentemente, o erro global de terceira ordem. Isso nos poupará de entrar na
expansão de terceiro nível da função 𝑔 de duas variáveis, que tem 18 termos e não seria
apropriada devido ao seu tamanho. Após prepararmos a expansão em série de Taylor,
precisamos ajustar a equação de recorrência do método, de forma que possa ser comparada
com a série de Taylor (Equação 9).
𝑓𝑛+1 = 𝑓𝑛 + ℎ𝑎1 𝑔
𝜕𝑔 𝜕𝑔
+ ℎ𝑎2 [𝑔 + 𝑝1 ℎ
+ 𝑞11 ℎ 𝑔
𝜕𝑥 𝜕𝑓
2 2 2
ℎ 𝜕 𝑔 𝜕 𝑔 𝜕𝑔 𝜕𝑔
+ (𝑝12 2 + 𝑞11
2 2
𝑔 2
+ 2𝑝1 𝑞11 𝑔 ) + 𝑂2 (ℎ3 )]
2 𝜕𝑥 𝜕𝑓 𝜕𝑥 𝜕𝑓
𝜕𝑔
+ ℎ𝑎3 {𝑔 + 𝑝2 ℎ
𝜕𝑥

𝜕𝑔 𝜕𝑔 𝜕𝑔
+ [𝑞21 ℎ𝑔 + 𝑞22 ℎ (𝑔 + 𝑝1 ℎ + 𝑞11 ℎ𝑔 + 𝑂3 (ℎ2 ))]
𝜕𝑓 𝜕𝑥 𝜕𝑓

1 2
𝜕 2𝑔
+ [(𝑝2 ℎ)
2 𝜕𝑥 2
2
𝜕 2𝑔 𝜕𝑔 𝜕𝑔
+ ℎ2 2 (𝑞21 𝑔 + 𝑞22 (𝑔 + 𝑝1 ℎ + 𝑞11 ℎ 𝑔 + 𝑂4 (ℎ2 )) )]
𝜕𝑓 𝜕𝑥 𝜕𝑓

𝜕𝑔 𝜕𝑔 𝜕𝑔 𝜕𝑔
+ 2𝑝2 ℎ2 [𝑞21 𝑔 + 𝑞22 (𝑔 + 𝑝1 ℎ + 𝑞11 ℎ𝑔 + 𝑂4 (ℎ2 ))]}
𝜕𝑥 𝜕𝑓 𝜕𝑥 𝜕𝑓

Agora, precisamos agrupar os termos da mesma forma que eles são agrupados na série de
Taylor (Equação 9), de modo que possamos estabelecer as condições nos parâmetros que
produzirão os mesmos termos da expansão de Taylor até os termos contendo ℎ4 .
𝑓𝑛+1 = 𝑓𝑛 + ℎ(𝑎1 + 𝑎2 + 𝑎3 )𝑔(𝑥𝑛 , 𝑓𝑛 )
𝜕𝑔 𝜕𝑔 𝜕𝑔 𝜕𝑔 𝜕𝑔
+ ℎ2 [𝑎2 (𝑝1 + 𝑞11 𝑔 ) + 𝑎3 (𝑝2 + 𝑞21 𝑔 + 𝑞22 𝑔 )]
𝜕𝑥 𝜕𝑓 𝜕𝑥 𝜕𝑓 𝜕𝑓
2 2
𝑎2 𝜕 𝑔 𝜕 𝑔 𝜕𝑔 𝜕𝑔
+ ℎ3 { (𝑝12 2 + 𝑞11 2 2
𝑔 2
+ 2𝑝1 𝑞11 𝑔 )
2 𝜕𝑥 𝜕𝑓 𝜕𝑓 𝜕𝑓
𝜕𝑔 𝜕𝑔 𝜕𝑔 𝜕𝑔
+ 𝑎3 (𝑞22 𝑝1 + 𝑞11 𝑞22 𝑔 )
𝜕𝑓 𝜕𝑓 𝜕𝑓 𝜕𝑓
1 𝜕 2𝑔 𝜕 2𝑔 𝜕𝑔 𝜕𝑔
+ [𝑝22 2 + 𝑔2 (𝑞21 + 𝑞22 )2 + 2𝑝 2 𝑔(𝑞 21 + 𝑞22 ) ]}
2 𝜕𝑥 𝜕𝑓 2 𝜕𝑥 𝜕𝑓
3) 2 2 )𝑞
𝜕𝑔 3
𝜕 2𝑔
+ [ℎ𝑂2 (ℎ + ℎ 𝑂3 (ℎ 22 𝑎3 + 𝑞22 𝑎3 𝑔ℎ 𝑂 (ℎ)]
𝜕𝑓 𝜕𝑓 2 5
Equação 10

Comparando as duas expressões (Equação 9) e (Equação 10), obtém-se o seguinte sistema de


equações:

32
Morais & Nogueira – Física Computacional com Python

𝑎1 + 𝑎2 + 𝑎3 = 1
Equação 11

1
𝑝1 𝑎1 + 𝑝2 𝑎3 =
2
Equação 12

1
𝑞11 𝑎2 + 𝑎3 (𝑞21 + 𝑞22 ) =
2
Equação 13

1
𝑎2 𝑝12 + 𝑎3 𝑝22 =
3
Equação 14

1
𝑎2 𝑝1 𝑞11 + 𝑎3 𝑝22 =
3
Equação 15

1
𝑎3 𝑞22 𝑝1 =
6
Equação 16

2
1
𝑎2 𝑞11 + 𝑎3 (𝑞21 + 𝑞22 )2 =
3
Equação 17

1
𝑎3 𝑞22 𝑞11 =
6
Equação 18

À primeira vista, o sistema é fechado, o número de equações é que corresponde ao número de


parâmetros indeterminados. No entanto, apenas 6 equações são independentes, o restante
pode ser obtido a partir dessas 6 equações. Ao dividir a Equação 16 pela Equação 18,
podemos obter 𝑞11 = 𝑝1 . Da mesma forma, subtraindo a Equação 17 da equação Equação 15,
vemos que 𝑝2 = 𝑞21 + 𝑞22. Quando substituímos esses dois resultados no restante das
equações, fica evidente que a Equação 12 e a Equação 13 são iguais, e a Equação 14 e a
Equação 15 as equações são as mesmas. Portanto, duas equações podem ser obtidas de outras
seis, e temos que escolher duas variáveis para obter uma solução para os parâmetros.

Por exemplo, podemos escolher que 𝑝2 = 1, 𝑞11 = 1/2, então obtemos a seguinte equação
de recorrência.

𝑓𝑛+1 = 𝑓𝑛 + (𝑘1 + 4𝑘2 + 𝑘3 )
6
com

33
Morais & Nogueira – Física Computacional com Python

𝑘1 = 𝑔(𝑥𝑛 , 𝑓𝑛 )
ℎ ℎ
𝑘2 = 𝑔 (𝑥𝑛 + , 𝑓𝑛 + 𝑘1 )
2 2
𝑘3 = 𝑔(𝑥𝑛 + ℎ, 𝑓𝑛 − ℎ𝑘1 + 2ℎ𝑘2 )
Agora que terminamos o algoritmo de terceira ordem, você pode se aventurar a tentar obter o
algoritmo de quarta de ordem. Eu me sinto satisfeito e vou apenas postar o algoritmo de
quarta ordem.

𝑓𝑛+1 = 𝑓𝑛 + (𝑘1 + 2𝑘2 + 2𝑘3 + 𝑘4 )
6
com
𝑘1 = 𝑔(𝑥𝑛 , 𝑓𝑛 )
ℎ ℎ
𝑘2 = 𝑔 (𝑥𝑛 + , 𝑓𝑛 + 𝑘1 )
2 2
ℎ ℎ
𝑘3 = 𝑔 (𝑥𝑛 + , 𝑓𝑛 + 𝑘2 )
2 2
𝑘4 = 𝑔(𝑥𝑛 + ℎ, 𝑓𝑛 + ℎ𝑘3 )

Exemplo: Lei de Resfriamento de Fourier


A condução térmica é a transferência de energia térmica entre átomos e/ou moléculas
vizinhas em uma substância devido a um gradiente de temperatura. Em outras palavras, é um
modo do fenômeno de transferência térmica causado por uma diferença de temperatura entre
duas regiões em um mesmo meio ou entre dois meios em contato no qual não se percebe
movimento global da matéria na escala macroscópica, em oposição à convecção que é outra
forma de transferência térmica. A lei da condução térmica, também conhecida como lei de
Fourier, estabelece que o fluxo de calor através de um material é proporcional ao gradiente
negativo de temperatura. Podemos enunciar esta lei de duas formas equivalentes: a forma
integral, em que olhamos para a quantidade de energia que flui para dentro ou para fora de
um corpo como um todo; e a forma diferencial, em que olhamos para os fluxos de energia
localmente. O fluxo de calor é a quantidade de energia que flui através de uma unidade de
área por unidade de tempo.

A forma diferencial da lei de condução térmica de Fourier mostra que a densidade de


fluxo de calor local 𝑞̇ é igual ao produto da condutividade térmica 𝑘(𝑇) e o gradiente de

34
Morais & Nogueira – Física Computacional com Python

temperatura local negativo −𝑑𝑇/𝑑𝑥. A densidade do fluxo de calor é a quantidade de energia


que flui através de uma unidade de área por unidade de tempo
𝑑𝑇
𝑞̇ = −𝑘
𝑑𝑥
onde 𝑞̇ é a densidade de fluxo de calor local expressa em W/m², 𝑘 é a condutividade do
material expressa em W/(m·K) e 𝑇 é a temperatura dada em K.
A condutividade térmica 𝑘 é frequentemente tratada como uma constante, embora isso nem
sempre seja verdade. Embora a condutividade térmica de um material geralmente varie com a
temperatura, a variação pode ser pequena em uma faixa significativa de temperaturas para
alguns materiais comuns. Em materiais anisotrópicos, a condutividade térmica normalmente
varia com a orientação; neste caso 𝑘 é representado por um tensor de segunda ordem. Em
materiais não uniformes, 𝑘 varia com a localização espacial.
Considere agora o problema de um fio de metal de comprimento 𝐿 = 10 m, que recebe calor
a uma taxa de 𝑞̇ = 500 ln(1 + 𝑥/𝐿) W/m² e passa para a outra extremidade. Sabendo que a
condutividade térmica deste metal varia com a temperatura na forma
𝑇
𝑘 = [3 ( ) − 1] W/(m. K)
302
vamos encontrar numericamente como a temperatura da barra varia ao longo da barra, sendo
que em uma extremidade 𝑇 = 300 K. A equação que rege o sistema é
𝑑𝑇 𝑞̇ (𝑥)
=−
𝑑𝑥 𝑘(𝑇)
com condição de contorno 𝑇(𝑥 = 0) = 300 K.
import math as mt
import matplotlib.pyplot as plt

L = 10

def condutividade(T):
return (3*T/302)-1

def qponto(x,L):
return 500*mt.log(1+x/L)

x = 0
T = 300
xpontos = [x]
Tpontos = [T]
h = L/200
while x<L:
x+=h
# Passo 1 do Runge-Kutta de ordem 3
k1 = (qponto(x,L)/condutividade(T))
# Passo 2 do Runge-Kutta de ordem 3
k2 = (qponto(x+0.5*h,L)/condutividade(T+0.5+h*k1))
# Passo 3 do Runge-Kutta de ordem 3
k3 = (qponto(x+h,L)/condutividade(T-h*k1+2*h*k2))
# Passo final do Runge-Kutta de ordem 3
T += h*(k1+4*k2+k3)/6
xpontos += [x]

35
Morais & Nogueira – Física Computacional com Python

Tpontos += [T]

# Gráficos
plt.xlim(0,x)
plt.ylim(300,T)
plt.plot(xpontos,Tpontos)
plt.xlabel('Comprimento (m)')
plt.ylabel('Temperatura (K)')
plt.show()

Figura 14- Solução numérica da propagação de calor por condução com condutividade com dependência linear
pelo método de Runge-Kutta de terceira ordem.

Modelo de Lotka-Volterra

O modelo Lotka–Volterra predador–presa foi inicialmente proposto por Alfred J. Lotka na


teoria das reações químicas autocatalíticas em 1910Esta foi efetivamente a equação logística,
originalmente derivada por Pierre François Verhulst. Em 1920 Lotka estendeu o modelo, via
Andrey Kolmogorov, para "sistemas orgânicos" usando uma espécie de planta e uma espécie
de animal herbívoro e em 1925 ele usou as equações para analisar interações predador-presa
em seu livro sobre biomatemática. O mesmo conjunto de equações foi publicado em 1926 por
Vito Volterra, um matemático e físico, que se interessou pela biologia matemática. O estudo
de Volterra foi inspirada em suas interações com o biólogo marinho Umberto D'Ancona.
D'Ancona estudou as capturas de peixes no Mar Adriático e notou que a porcentagem de
peixes predadores capturados aumentou durante os anos da Primeira Guerra Mundial (1914-
18). Isso o intrigou, pois o esforço de pesca havia sido muito reduzido durante os anos de
guerra. Volterra desenvolveu seu modelo independentemente de Lotka e o usou para explicar
a observação de d'Ancona.

36
Morais & Nogueira – Física Computacional com Python

• O modelo Lotka-Volterra faz uma série de suposições sobre o ambiente e a evolução


das populações de predadores e presas:

• A população de presas encontra alimento suficiente em todos os momentos;

• O suprimento de alimentos da população de predadores depende inteiramente do


tamanho da população de presas;

• A taxa de mudança da população é proporcional ao seu tamanho;

• Durante o processo, o ambiente não muda em favor de uma espécie, e a adaptação


genética é irrelevante;

• Os predadores têm apetite ilimitado.

Figura 15- Retratro de Fase típico do modelo de Lotka-Volterra. Fonte: https://scipy-


cookbook.readthedocs.io/items/LoktaVolterraTutorial.html

Neste caso a solução das equações diferenciais é determinística e contínua. Isso, por
sua vez, implica que as gerações do predador e da presa estão continuamente se sobrepondo.
Sejam 𝑥(𝑡) a população de presas e 𝑦(𝑡) a população de predadores. Podemos considerar que
a taxa com que a população de presas cresce é proporcional ao seu tamanho 𝑑𝑥/𝑑𝑡 ∝ 𝑥 e o a
taxa de mortalidade é proporcional ao número de encontros entre presas e predadores. Esses
encontros são modelados considerando que quanto maior a população de presas e predadores,
mais a probabilidade destes encontros, tal que

37
Morais & Nogueira – Física Computacional com Python

𝑑𝑥
= 𝑎𝑥 − 𝑏𝑥𝑦,
𝑑𝑡
16

onde 𝑎 e 𝑏 são constantes com unidades apropriadas.

Já a taxa com de crescimento dos predadores é proporcional ao encontro com a presas


e a taxa de mortalidade é proporcional ao tamanho da população de predadores:
𝑑𝑦
= 𝑐𝑥𝑦 − 𝑦𝑑,
𝑑𝑡
19

onde 𝑐 e 𝑑 são constantes. As equações Equação 18 e Erro! Fonte de referência não


encontrada. podem ser solucionadas numericamente por qualquer dos métodos apresentados
aqui para equações diferenciais de primeira ordem. Note que estas equações são acopladas.
Podemos obter o retrato de fase do sistema (gráfico de 𝑥 contra 𝑦) dividindo uma equação
pela outra:
𝑑𝑥 𝑥(𝑎 − 𝑏𝑦)
=
𝑑𝑦 𝑦(𝑐𝑥 − 𝑑)
tal que
𝑑 𝑎
(𝑐 − ) 𝑑𝑥 = ( − 𝑏) 𝑑𝑦
𝑥 𝑦
que integrada com valores iniciais 𝑥(0) = 𝑥0 e 𝑦(0) = 𝑦0 , resulta em
𝑐𝑥 + 𝑏𝑦 − 𝑑 ln 𝑥 − 𝑎 ln 𝑦 = 𝑐𝑥0 + 𝑏𝑦0 − 𝑑 ln 𝑥0 − 𝑎 ln 𝑦0 = 𝐸
𝐸 é uma constante, mostrando que esta quantidade é conservada. Ao desenharmos um gráfico
de 𝑥 contra 𝑦, obteremos os retratos de fase do sistema que oscilam em torno de um ponto de
equilíbrio (veja Figura 15). Este ponto de equilíbrio é aquele em que as populações
permanecem constantes. Podemos obter essas populações de equilíbrio fazendo 𝑑𝑥/𝑑𝑡 = 0 e
𝑑𝑦/𝑑𝑡 = 0 nas equações Equação 18 e Erro! Fonte de referência não encontrada.,
respectivamente:
𝑑 𝑎
𝑥𝑒𝑞 = , 𝑦𝑒𝑞 =
𝑐 𝑏
Vamos utilizar o método de Runge-Kutta de quarta ordem para solucionar o problema
de presa-predador de Lotka-Volterra com valores iniciais 𝑥0 = 10 grupos de coelhos e 𝑦0 =
2 grupos de raposas, com valores numéricos das constantes 𝑎 = 15 , 𝑏 = 3, 𝑐 = 2 e 𝑑 = 25.
Assim, as populações de equilíbrio são 𝑥𝑒𝑞 = 12,5 grupos de coelhos e 𝑦𝑒𝑞 = 5 grupos de
raposas. Note que os números das populações não são inteiros. Vamos estudar essa dinâmica
partindo do tempo zero até 2.
import matplotlib.pyplot as plt
import math as mt

38
Morais & Nogueira – Física Computacional com Python

# vamos definir as constantes do problema


a=15 # por ano
b=3 # por raposas por ano
c=2 # por coelhos por ano
d=25 # por ano
# e as populações iniciais
x = 10 # coelhos
y = 2 # raposas
# vamos utilzar t para variável tempo
t = 0
# o incremente temporal será h
h = 0.01
# vamos guardar os valores nas listas xpontos, ypontos e tpontos
xpontos = [x]
ypontos = [y]
tpontos = [t]
# iniciando o Runge-Kutta de quarta ordem, ou RK4 até alcançar o tempo
final
tempofinal = 2 # anos

def gx(a,b,x,y):
return (a*x)-(b*x*y)
def gy(c,d,x,y):
return (c*x*y)-(d*y)

while t<tempofinal:
x1 = x
y1 = y
kx1 = gx(a,b,x1,y1)
ky1 = gy(c,d,x1,y1)
x2 = x+0.5*h*kx1
y2 = y+0.5*h*ky1
kx2 = gx(a,b,x2,y2)
ky2 = gy(c,d,x2,y2)
x3 = x+0.5*h*kx2
y3 = y+0.5*h*ky2
kx3 = gx(a,b,x3,y3)
ky3 = gy(c,d,x3,y3)
x4 = x+h*kx3
y4 = y+h*ky3
kx4 = gx(a,b,x4,y4)
ky4 = gy(c,d,x4,y4)
x += h*(kx1+2*kx2+2*kx3+kx4)/6
y += h*(ky1+2*ky2+2*ky3+ky4)/6
t += h
tpontos += [t]
xpontos += [x]
ypontos += [y]

# As populações de equilíbrio são


xeq = d/c
yeq = a/b

fig, axs = plt.subplots(2)


fig.suptitle('Dinâmica e Retrato de Fase')

plt.xlim(0,tempofinal)
plt.ylim(0,1.05*max(xpontos))
axs[0].plot(tpontos,xpontos, label='coelhos')
axs[0].plot(tpontos,ypontos, label='raposas')

39
Morais & Nogueira – Física Computacional com Python

# vamos desenhar as linhas das populações de equilíbrio


tp = [0]
tp += [tempofinal]
xeqpontos = [xeq]
xeqpontos += [xeq]
yeqpontos = [yeq]
yeqpontos += [yeq]
axs[0].plot(tp,xeqpontos,linestyle='dashed', label='População de equilíbrio
dos coelhos')
axs[0].plot(tp,yeqpontos,linestyle='dashed', label='População de equilíbrio
das raposas')
axs[0].legend()

plt.scatter(xeq,yeq,color='r',label='ponto de equilibrio')
plt.xlim(min(xpontos),max(xpontos))
plt.ylim(min(ypontos),max(ypontos))
axs[1].plot(xpontos,ypontos)
axs[1].legend()
plt.show()

A saída deste código é o gráfico abaixo:

Você pode incluir variações sazonais neste modelo transformando os parâmetros 𝑎, 𝑏,


𝑐 e/ou 𝑑 em funções do tempo, mas lembre-se que ao integrá-las usando o RK4, você deverá
explicitar os valores para a variável de integração em cada passo. Por exemplo, vamos supor
que os coelhos têm uma taxa de crescimento que depende da época de acasalamento, tal que
𝑎0 2𝜋𝑡
𝑎(𝑡) = [1 + cos ( )],
2 𝑃
onde 𝑃 é o período da variação da taxa de crescimento e 𝑎0 é o valor máximo da taxa de
crescimento dos coelhos. O valor médio de 𝑎 é encontrado integrando

40
Morais & Nogueira – Física Computacional com Python

𝑃
1 𝑎0 2𝜋𝑡 𝑎0
𝑎̅ = ∫ [1 + cos ( )] 𝑑𝑡 =
𝑃 2 𝑃 2
0

Vamos ver como esse sistema se comporta com um período 𝑃 = 0,25 anos:

Exemplo: Movimento de Projéteis


Um projétil lançado com velocidade 𝑣⃗0 , onde 𝑣⃗0 faz um ângulo 𝜃 com a direção
perpendicular à aceleração da gravidade está sujeito ao peso dele 𝑚𝑔⃗ e a resistência do ar
−𝑏𝑣𝑣̂, onde 𝑏 é uma constante. A Segunda Lei de Newton para este problema nos dá as
seguintes EDOs:
𝑑𝑣⃗ 𝑏
= 𝑔⃗ − 𝑣𝑣̂
𝑑𝑡 𝑚
𝑑𝑟⃗
= 𝑣⃗
𝑑𝑡
Admitindo o sistema de coordenadas cartesiano com a direção 𝑌 na mesma direção do peso,
podemos escrever o conjunto de EDOs
𝑑𝑣𝑥 𝑏
= − 𝑣𝑥
𝑑𝑡 𝑚
𝑑𝑣𝑦 𝑏
= −𝑔 − 𝑣𝑦
𝑑𝑡 𝑚
𝑑𝑥
= 𝑣𝑥
𝑑𝑡
𝑑𝑦
= 𝑣𝑦
𝑑𝑡
Por simplicidade, vamos considerar 𝑛 = 1 para solucionar o problema onde a massa é 𝑚 =
20 kg e 𝑏 = 5 N.s/m no lançamento oblíquo a um dado ângulo inicial 𝜃 e velocidade inicial
𝑣0 .
import math as mt
import matplotlib.pyplot as plt

m = 20
grav = 9.8
b = 5

# Aqui, apresentamos duas maneiras de obter valores direto do prompt de


comando.
print('Qual o valor da velocidade inicial (m/s)?')
v0 = float(input())
print('Qual o valor do ângulo de lançamento em graus?')
ang = float(input())
# ou você poderia usar diretamente
# ang = float(input('Qual o valor do ângulode lançamento: '))
ang = mt.radians(ang)

41
Morais & Nogueira – Física Computacional com Python

tempo = 0
x = 0
y = 0
vx = v0*mt.cos(ang)
vy = v0*mt.sin(ang)
xpontos = [x]
ypontos = [y]
vxpontos = [vx]
vypontos = [vy]
h = 0.01
print('A velocidade incial na direção x é v0x =', round(vx,3),'m/s')
print('A velocidade incial na direção y é v0y =', round(vy,3),'m/s')
def gvx(b,m,vx):
return -(b/m)*vx
def gvy(grav,b,m,vx):
return -grav-(b/m)*vy

# vamos iterar as equações até que o corpo atinja o solo novamente na


condição de y<0
while y>-0.001:
tempo+=h
# Passo 1 do Runge-Kutta de ordem 3
k1x = vx
k1y = vy
k1vx = gvx(b,m,vx)
k1vy = gvy(grav,b,m,vy)
# Passo 2 do Runge-Kutta de ordem 3
k2x = vx+0.5*h*k1vx
k2y = vy+0.5*h*k1vy
k2vx = gvx(b,m,vx+0.5*h*k1vx)
k2vy = gvy(grav,b,m,vy+0.5*h*k1vy)
# Passo 3 do Runge-Kutta de ordem 3
k3x = vx-h*k1vx+2*h*k2vx
k3y = vy-h*k1vy+2*h*k2vy
k3vx = gvx(b,m,vx-h*k1vx+2*h*k2vx)
k3vy = gvy(grav,b,m,vy-h*k1vy+2*h*k2vy)
# Passo final do Runge-Kutta de ordem 3
x += h*(k1x+4*k2x+k3x)/6
y += h*(k1y+4*k2y+k3y)/6
vx += h*(k1vx+4*k2vx+k3vx)/6
vy += h*(k1vy+4*k2vy+k3vy)/6
xpontos += [x]
ypontos += [y]
vxpontos += [vx]
vypontos += [vy]

# Ontendo o valor máximo de y, ou seja, a altura máxima


ymax = max(ypontos)
ax = plt.gca()
ax.set_aspect(1)
# Definindo os rótulos x e y
plt.xlabel('x (m)')
plt.ylabel('y (m)')
# Definindo os limites do gráfico
plt.xlim(0, x)
plt.ylim(0, 1.1*ymax)
plt.plot(xpontos,ypontos,label='trajetória')
# Desenhando uma seta para indicar a velocidade inicial
plt.arrow(0,0,0.1*v0*mt.cos(ang),0.1*v0*mt.sin(ang),width=0.005*v0)
# Explicitando a o alcance e a altura máxima no gráfico

42
Morais & Nogueira – Física Computacional com Python

plt.text(0.3*max(xpontos),0.25*max(ypontos),'Altura máxima =
'+str(round(max(ypontos),2))+' m')
plt.text(0.3*max(xpontos),0.1*max(ypontos),'Alcance =
'+str(round(max(xpontos),2))+' m')
plt.legend()
plt.show()
plt.savefig(‘nome.png’,dpi=200)

Figura 17- Solução pelo método Runge-Kutta de terceira ordem do lançamento de projéteis com resistência do ar
para uma esfera de massa 20 kg, b = 5 N.s/m.

Projeto: Movimento de Projéteis com vento


O perfil do vento logarítmico é uma relação semiempírica comumente usada para
descrever a distribuição vertical das velocidades médias horizontais do vento dentro da
porção mais baixa da camada limite planetária. O perfil logarítmico das velocidades do vento
é geralmente limitado aos 100 m mais baixos da atmosfera (ou seja, a camada superficial da
camada limite atmosférica. A equação para estimar a velocidade média do vento 𝑢𝑥 (𝑦) na
altura 𝑦 (metros) acima do solo é:
0, 𝑦 < 𝑑 + 𝑦0
𝑢𝑥 (𝑦) = {𝑢0 𝑦−𝑑
ln ( ), 𝑦 ≥ 𝑑 + 𝑦0
𝑘 𝑦0
20

onde 𝑢0 é a velocidade de atrito expressa em m/s, 𝑘 é a constante de von Kármán, que


depende das condições de escoamento, 𝑑 é o deslocamento do plano zero expresso em metros
e 𝑦0 é a rugosidade da superfície em metros (Recoskie, 2017).

43
Morais & Nogueira – Física Computacional com Python

Para diferentes cenários do terreno, o valor de 𝑘 e 𝑦0 são diferentes. A rugosidade pode ser
modelada como
0,001 𝑚 𝐷𝑒𝑠𝑐𝑎𝑚𝑝𝑎𝑑𝑜/á𝑔𝑢𝑎
𝑦0 = { 1,5 𝑚 𝑆𝑢𝑏ú𝑟𝑏𝑖𝑜
3m 𝐶𝑖𝑑𝑎𝑑𝑒 𝑐𝑜𝑚 𝑝𝑟é𝑑𝑖𝑜𝑠 𝑎𝑙𝑡𝑜𝑠
21

Aqui, vamos utilizar a constante de von Kármán igual a 0,4. A forma do perfil de vento pode
ser vista através do código abaixo.
import matplotlib.pyplot as plt
import math as mt

# Para este programa, vamos considerar a velocidade de atrito u0 como


u0 = 12

k =0.4
print('Digite o número para o terreno desejado')
print('1 - terreno descampado')
print('2 - terreno de subúrbio (casas baixas)')
print('3 - terreno de cidade')
opcao = float(input())

if opcao==1:
y0 = 0.001
if opcao==2:
y0 = 1.5
if opcao==3:
y0 = 3

# o deslocamento do plano zero foi definido como


d = 10.

def vento(k,u0,y0,d,y):
return (u0/k)*mt.log((y-d)/y0)

44
Morais & Nogueira – Física Computacional com Python

#vamos definir o incremento na altura como


h = 0.1
y = 0
u = 0
upontos = [u]
ypontos = [y]
while(y<100):
y += h
# Note que para altura menores que d+y0 a velocidade do vento é zero
if(y<d+y0):
u = 0
else:
u = vento(k, u0, y0, d, y)
ypontos += [y]
upontos += [u]

plt.xlim(0,u)
plt.ylim(0,y)
plt.plot(upontos,ypontos)
plt.xlabel('Velocidade do vento (m/s)')
plt.ylabel('Altura (m)')
plt.show()

Figura 18- Perfil logaritmíco da velocidae do vento na direção horizontal com valores de 𝑦0 definidos no
programa. Constante de von Kármán 𝑘 = 0,4, 𝑑 = 10 m e 𝑢0 = 12 m/s.

Um projétil lançado com velocidade 𝑣⃗0 , onde 𝑣⃗0 faz um ângulo 𝜃 com a direção
perpendicular à aceleração da gravidade está sujeito ao peso dele e a resistência do ar
1
𝐹⃗𝑎 = 𝜌𝐶 𝐴𝑣 ∗ 2 𝑣̂ ∗ ,
2 𝐴
22

45
Morais & Nogueira – Física Computacional com Python

onde 𝜌 é a resistência do ar, 𝐴 é a área projetada na direção do movimento e 𝑣⃗ ∗ é a


velocidade relativa do objeto com o ar:
𝑣⃗ ∗ = 𝑣⃗ − 𝑢
⃗⃗
23

Aqui 𝐶𝐴 é o coeficiente de arraste que depende da forma do corpo e das condições de


operação (escoamento laminar ou turbulento). Para escoamentos turbulentos, 𝐶𝐴 = 0,4 para
uma esfera.
A densidade do ar pode ser calculada para baixas altitudes (abaixo de 86 km) através
da equação:
𝑔0 𝑀 (𝑦 − 𝑦𝑟 )
𝜌 = 𝜌0 exp [− ],
𝑅 𝑇𝑟
24

onde 𝜌0 = 1,225 kg/m³ é a densidade do ar no nível do mar, 𝑔0 = 9,81 m/s² é a aceleração


local média da gravidade no nível do mar, 𝑀 = 0,0289644 kg/mol é a massa molar da
atmosfera terrestre para baixas altitudes, 𝑅 = 8,3144598 N.m/(mol.K) é a constante dos
gases ideais, 𝑦𝑟 e 𝑇𝑟 são a altura de referência e a temperatura de referência, respectivamente.
Aqui, utilizaremos 𝑦𝑟 = 0 m e 𝑇𝑟 = 288,15 K.
import matplotlib.pyplot as plt
import math as mt

rho0 = 1.225
Tr = 288.15
yr = 0
R = 8.3144598
M = 0.0289644
g0 = 9.81

constante=g0*M/(R*Tr)

def densidade(rho0,y,yr):
return rho0*mt.exp(-constante*(y-yr))

#vamos definir o incremento na altura como


h = 2.
y = 0.
ypontos = [y]
d = densidade(rho0, y, yr)
dpontos = [d]

while(y<10000):
y += h
d = densidade(rho0,y,yr)
ypontos += [y]
dpontos += [d]
print(y,d)

plt.xlim(rho0,d)
plt.ylim(0,y)
plt.plot(dpontos,ypontos)
plt.xlabel('Densidade (kg/m3)')
plt.ylabel('Altura (m)')

46
Morais & Nogueira – Física Computacional com Python

plt.show()

Por fim, o problema do lançamento de projéteis sem propulsão próximo à superfície da Terra4
pode ser descrito através das equações (Segunda Lei de Newton)
𝑑𝑥 𝑑𝑣𝑥 𝐹𝐴𝑥
= 𝑣𝑥 , =− ,
𝑑𝑡 𝑑𝑡 𝑚
𝑑𝑦 𝑑𝑣𝑥 𝐹𝐴𝑦
= 𝑣𝑦 , = −𝑔 − ,
𝑑𝑡 𝑑𝑡 𝑚
25

onde
1 2
𝑣𝑥 − 𝑢𝑥 1 (𝑣𝑥 − 𝑢𝑥 )3
𝐹𝐴𝑥 = 𝜌𝐶𝐴 𝐴(𝑣𝑥 − 𝑢𝑥 ) = 𝜌𝐶𝐴 𝐴 ,
2 √(𝑣𝑥 − 𝑢𝑥 )2 + 𝑣𝑦2 2 √(𝑣𝑥 − 𝑢𝑥 )2 + 𝑣𝑦2
26

1 𝑣𝑦 1 𝑣𝑦3
𝐹𝐴𝑦 = 𝜌𝐶𝐴 𝐴𝑣𝑦2 = 𝜌𝐶𝐴 𝐴 ,
2 √(𝑣𝑥 − 𝑢𝑥 )2 + 𝑣𝑦2 2 √(𝑣𝑥 − 𝑢𝑥 )2 + 𝑣𝑦2
27

são as componentes da força de arrasto nas direções horizontal e vertical, respectivamente.

Figura 19 - Perfil de densidade do ar em função da altitude.

4
Note que desprezamos as forças inerciais devido a rotação da Terra (força centrífuga e força de
Coriolis), o efeito da curvatura da Terra e a variação da aceleração da gravidade local devido a altura.

47
Morais & Nogueira – Física Computacional com Python

Caso você queira ser mais rigoroso, você poderá utilizar a expressão para a aceleração
da gravidade via Lei da Gravitação Universal de Newton:
𝐺𝑀𝑇 𝐺𝑀𝑇 1 𝑔0
𝑔= = 2 2 = ,
(𝑅𝑇 + 𝑦) 2 𝑅𝑇 𝑦 𝑦 2
(1 + 𝑅 ) (1 + 𝑅 )
𝑇 𝑇
28

com 𝐺 = 6,674184 × 10−11 m³/(kg.s²) sendo a constante da gravitação universal, 𝑀𝑇 =


5,972 × 1024 kg é a massa da Terra e 𝑅𝑇 = 6.378.100 m é o raio médio da Terra. Mas note
que
Faça um código para encontrar o alcance de um projétil esférico de ferro cuja
massa é 300 kg (raio de 20 centímetros) que parte de uma velocidade inicial 𝒗𝟎 = 𝟏𝟎𝟎
m/s fazendo um ângulo 𝜽𝟎 = 𝟑𝟎° com a direção horizontal sujeito a resistência do ar
dada pelas equações Erro! Fonte de referência não encontrada., Erro! Fonte de referência nã
o encontrada. e Erro! Fonte de referência não encontrada. com 𝒖𝟎 = 𝟖 m/s, 𝒅 = 𝟓 m e
rugosidade da sua escolha. Use o método de Runge-Kutta de quarta ordem nas
equações Erro! Fonte de referência não encontrada., Erro! Fonte de referência não en
contrada. e Erro! Fonte de referência não encontrada.Erro! Fonte de referência não
encontrada. e mostre o gráfico da trajetória com os eixos x e y em escala (veja código do
exemplo da Figura 17).

Pêndulo Simples
Um exemplo de movimento harmônico simples é o movimento de um pêndulo. Um pêndulo
simples é uma partícula de massa 𝑚 presa por um fio de comprimento 𝐿 e massa desprezível.
Se a partícula for afastada lateralmente até uma posição onde o fio faz um ângulo 𝜃0 com a
direção vertical, e, em seguida, abandonada, o pêndulo oscilará entre a posição inicial e uma
posição simétrica espelhada na direção vertical.
Para determinar o tipo de oscilação, precisamos escrever a equação de movimento da
partícula. A partícula se move num arco de círculo com raio 𝐿. As forças que agem sobre a
⃗⃗ no fio. A componente tangencial da força resultante é
partícula são o peso 𝑚𝑔⃗ e a tensão 𝑇
𝐹𝑇 = −𝑚𝑔 sen 𝜃,
onde o sinal negativo aparece porque ela tem sentido oposto ao deslocamento. A equação
para o movimento tangencial é a segunda lei de Newton 𝐹𝑇 = 𝑚𝑎, e, como a partícula se
move ao longo de um círculo de raio 𝐿 podemos usar o fato que o arco do ângulo 𝜃 é 𝑠 = 𝐿𝜃,
tal que 𝑎 = 𝑑2 𝑠/𝑑𝑡 2 = 𝐿𝑑2 𝜃/𝑑𝑡 2 . A equação para o movimento tangencial é, portanto,
𝑑2𝜃 𝑔
2
= − sen 𝜃 = −𝜔02 sen 𝜃,
𝑑𝑡 𝐿
onde 𝜔0 = √𝑔/𝐿 é a frequência de oscilação do pêndulo para pequenas oscilações. A
solução deste problema analiticamente requer métodos de aproximação, mas o problema se
torna bastante simples se considerarmos apenas pequenas oscilações, tais que sen 𝜃 ≈ 𝜃,
resultando em

48
Morais & Nogueira – Física Computacional com Python

𝑑2 𝜃
= −𝜔02 θ
𝑑𝑡 2
Esta equação tem solução analítica simples e é um oscilador harmônico simples com período
bem definido

𝐿 2𝜋
𝑃0 = 2𝜋√ =
𝑔 𝜔0

Todavia, para oscilações não tão pequenas, podemos mostrar que o período é melhor
aproximado para
2𝜋 1 𝜃0 9 𝜃0
𝑃= (1 + sen2 + sen4 + ⋯ )
𝜔0 4 2 64 2
Vamos escrever um código para obter numericamente o período em função do ângulo inicial
𝜃0 utilizando o Método de Runge-Kutta.
import numpy as np
import math as mt
import matplotlib.pyplot as plt

# definido a equação
def f(an):
# definindo as condições de operação
g = 9.82 # m/s^2
L = 1.00 # m
return -(g/L)*mt.sin(an)

g = 9.82 # m/s^2
L = 1.00 # m
P0 = 2*mt.pi*mt.sqrt(L/g)
# Definindo o incremento do tempo na simulação
h = 0.000025

angulo0 = np.zeros(400)
periodo = np.zeros(400)

for i in range(1,401):
# fazendo um incremento de meio grau no angulo inicial a cada execução
an = mt.radians(0.1*i)
w = 0.
t = 0.
verifica = True
j = 1
while verifica:
an1 = an
w1 = w
t1 = t
ka1 = w1
kw1 = f(an1)
an2 = an+0.5*h*ka1
w2 = w +0.5*h*kw1
t2 = t+0.5*h
ka2 = w2
kw2 = f(an2)
an3 = an+0.5*h*ka2
w3 = w +0.5*h*kw2

49
Morais & Nogueira – Física Computacional com Python

t3 = t+0.5*h
ka3 = w3
kw3 = f(an3)
an4 = an+h*ka3
w4 = w +h*kw3
t4 = t+h
ka4 = w4
kw4 = f(an4)
an += h*(ka1+2*ka2+2*ka3+ka4)/6
w += h*(kw1+2*kw2+2*kw3+kw4)/6
t += h
if (an<=0):
verifica = False
tempoF = t
angulo0[i-1] = 0.1*i
periodo[i-1] = 4.*(tempoF)/P0

# imprimindo o gráfico
plt.xlim(0,40.1)
plt.ylim(1,1.04)
taux = [0]
taux += [40.1]
angaux = [1.01]
angaux += [1.01]
plt.plot(angulo0,periodo,label='P/P0')
plt.plot(taux,angaux,'--',label='linha de 1%')
plt.xlabel('ângulo (graus)')
plt.ylabel('P/P0')
plt.legend()
plt.show()

50
Morais & Nogueira – Física Computacional com Python

Biblioteca SciPy

Até aqui, desenvolvemos todos os nossos códigos, tal que você pode facilmente ecrevê-los
em outras linguagens de programação. Todavia, existem bibliotecas em Python específicas
para integração numérica. O SciPy é uma coleção de algoritmos matemáticos e funções de
conveniência construídas na extensão NumPy do Python. Ele adiciona poder significativo à
sessão interativa do Python, fornecendo ao usuário comandos e classes de alto nível para
manipular e visualizar dados.
Por exemplo, encontramos o método de Runge-Kutta de 4º ordem na SciPy. A formulação
utilizada é descrita em (Dormand & Prince, 1980).
Exemplos
Considere o caso descrito na seção Velocidade Terminal. Vamos utilizar a função
odeint (integração de EDO usando o RK4) para resolver o mesmo problema.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt

# function that returns dy/dt


def modelo(v,t):
grav = 9.8 # m/s**2
m = 80 # kg
b = 10 # N*s/m
g = grav-(b*v/m)
return g

# condição inicial
v0 = 0 # m/s
# intervalo de integração
tinicial = 0 #tempo inicial
tfinal = 50 # tempo final
h = 0.01 # incremento temporal
# Esta função arrange cria um vetor entre a e b incrementado de h
t = np.arange(tinicial, tfinal, h)

# solve ODE
v = odeint(modelo,v0,t)

# plot results
plt.plot(t,v)
plt.xlabel('tempo')
plt.ylabel('v(t)')
plt.show()

51
Morais & Nogueira – Física Computacional com Python

A função solve_ivp resolve um problema de valor inicial para um sistema de EDOs.


Esta função integra numericamente um sistema de equações diferenciais ordinárias dado um
valor inicial:
𝑑𝑦
= 𝑔(𝑡, 𝑦), 𝑦(𝑡0 ) = 𝑦0
𝑑𝑡
Vamos revisitar o Sistema de Lotka-Volterra e ver como a solução seria “simples”:
import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import solve_ivp
def lotkavolterra(t, z, a, b, c, d):
x, y = z
return [a*x - b*x*y, -c*y + d*x*y]
# paramêtros Lotka-Volterra
a=1.5
b=1
c=3
d=1
# condições inidiciais
x0 = 10
y0 = 5
# intervalor de integração
tinicial = 0
tfinal = 15
# O comando solve_ivp resolve o sistema de EDOs integrando de 0 até 15
[0,15]
# com condições iniciais x0 e y0
sol = solve_ivp(lotkavolterra, [tinicial, tfinal], [x0, y0], args=(a, b, c,
d),dense_output=True)
# A função linspace retorna números uniformemente espaçados em um intervalo
especificado.

52
Morais & Nogueira – Física Computacional com Python

# Retorna num amostras espaçadas uniformemente, calculadas no intervalo


[start, stop].
# O ponto final do intervalo pode opcionalmente ser excluído.
# Aqui o vetor começa de 0 e vai até 15 com 300 pontos
t = np.linspace(0, 15, 300)
# A solução será obita com um array z para os valores x e y
z = sol.sol(t)
plt.plot(t, z.T)
plt.xlabel('t')
plt.ylabel('Populações')
plt.legend(['coelhos', 'raposas'], shadow=True)
plt.xlim(min(t),max(t))
#plt.ylim(0,max(z.T))
plt.title('Sistema Lotka-Volterra')
plt.show()

Método Numerov

O método de Numerov, também chamado de método de Cowell, é um método


numérico para resolver equações diferenciais ordinárias de segunda ordem nas quais o termo
de primeira ordem não aparece. É um método de passo mútiplo linear de quarta ordem. O
método é implícito, mas pode ser explicitado se a equação diferencial for linear. O método de
Numerov foi desenvolvido pelo astrônomo russo Boris Vasilevich Numerov.
Seja a equação

53
Morais & Nogueira – Física Computacional com Python

𝑑2𝑦
= 𝑔(𝑥)𝑦(𝑥) + 𝑠(𝑥)
𝑑𝑥 2
Equação 29

onde 𝑔(𝑥) e  𝑠(𝑥) são funções de 𝑥 . As expansões em séries de Taylor em torno de 𝑥𝑛 com
passo ℎ são:
𝑑𝑦 ℎ2 𝑑 2 𝑦 ℎ3 𝑑 3 𝑦 ℎ4 𝑑 4 𝑦
𝑦𝑛+1 = 𝑦𝑛 + ℎ ( )   + ( 2) + ( 3) + ( 4) + ⋯
𝑑𝑥 𝑛 2 𝑑𝑥 𝑛 6 𝑑𝑥 𝑛 24 𝑑𝑥 𝑛

𝑑𝑦 ℎ2 𝑑 2 𝑦 ℎ3 𝑑 3 𝑦 ℎ4 𝑑 4 𝑦
𝑦𝑛−1 = 𝑦𝑛 − ℎ ( )   + ( 2 ) − ( 3 ) + ( 4 ) + ⋯
𝑑𝑥 𝑛 2 𝑑𝑥 𝑛 6 𝑑𝑥 𝑛 24 𝑑𝑥 𝑛

onde 𝑦𝑛+1 = 𝑦(𝑥𝑛 + ℎ) e 𝑦𝑛−1 = 𝑦(𝑥𝑛 − ℎ). Somando as duas equações acima, temos
𝑑2 𝑦
2
ℎ4 𝑑 4 𝑦
𝑦𝑛+1 + 𝑦𝑛−1 = 2𝑦𝑛 + ℎ ( 2 ) + ( 4 ) + ⋯
𝑑𝑥 𝑛 12 𝑑𝑥 𝑛
𝑑2 𝑦
Uma vez que 𝑑𝑥 2 = 𝑔𝑛 𝑦𝑛 + 𝑠𝑛 = 𝑓𝑛 , temos

2
ℎ4 𝑑 2 𝑓
𝑦𝑛+1 + 𝑦𝑛−1 = 2𝑦𝑛 + ℎ 𝑓𝑛 + ( ) +⋯
12 𝑑𝑥 2 𝑛
Equação 30

Podemos expandir 𝑓 em torno de 𝑥𝑛 para obter


𝑑𝑓 ℎ2 𝑑 2 𝑓 ℎ3 𝑑 3 𝑓 ℎ4 𝑑 4 𝑓
𝑓𝑛+1 = 𝑓𝑛 + ℎ ( )   + ( 2) + ( 3) + ( ) +⋯
𝑑𝑥 𝑛 2 𝑑𝑥 𝑛 6 𝑑𝑥 𝑛 24 𝑑𝑥 4 𝑛

𝑑𝑓 ℎ2 𝑑 2 𝑓 ℎ3 𝑑 3 𝑓 ℎ4 𝑑 4 𝑓
𝑓𝑛−1 = 𝑓𝑛 − ℎ ( )   + ( 2 ) − ( 3 ) + ( ) +⋯
𝑑𝑥 𝑛 2 𝑑𝑥 𝑛 6 𝑑𝑥 𝑛 24 𝑑𝑥 4 𝑛

Somando as duas equações acima, temos


𝑑2𝑓
2
𝑓𝑛+1 + 𝑓𝑛−1 − 2𝑓𝑛 = ℎ ( 2 ) + ⋯
𝑑𝑥 𝑛
Equação 31

Note que os termos de maior ordem foram desprezados, visto que 𝑓 já a derivada segunda de
𝑦. Substituindo Equação 31 na Equação 30, temos
ℎ2
𝑦𝑛+1 = 2𝑦𝑛 − 𝑦𝑛−1 + ℎ2 𝑓𝑛 + (𝑓 + 𝑓𝑛−1 − 2𝑓𝑛 )
12 𝑛+1
ou
𝑦𝑛+1 = 2𝑦𝑛 − 𝑦𝑛−1 + ℎ2 (𝑔𝑛 𝑦𝑛 + 𝑠𝑛 )
ℎ2
+ (𝑔𝑛+1 𝑦𝑛+1 + 𝑠𝑛+1 + 𝑔𝑛−1 𝑦𝑛−1 + 𝑠𝑛−1 − 2𝑔𝑛 𝑦𝑛 − 2𝑠𝑛 )
12
Agrupando os termos em cada passo específico, temos

54
Morais & Nogueira – Física Computacional com Python

5ℎ2 ℎ2 ℎ2
2𝑦𝑛 (1 + 𝑔𝑛 ) − 𝑦𝑛−1 (1 − 𝑔𝑛−1 ) + (𝑠 + 10𝑠𝑛 + 𝑠𝑛−1 )
12 12 12 𝑛+1
𝑦𝑛+1 =
ℎ2
(1 − 𝑔𝑛+1 )
12
32

Note que a iteração da equação 32 requer o conhecimento de dois valores de 𝑦 nos passos 𝑛 e
𝑛 − 1, como requerido para solução de qualquer equação diferencial ordinária de ordem 2.
Exemplo. Considere novamente o exemplo do circuito LC com fonte alternada 𝑉 =
𝑉0 sen 𝜔𝑉 𝑡 (veja equação 7) dada pelas equações
𝑑2𝑞 𝑞 𝑉0
2
=− + sen 𝜔𝑉 𝑡
𝑑𝑡 𝐿𝐶 𝐿
33

com as condições iniciais 𝑞(0) = 𝑞0 e 𝐼(0) = 𝐼0 . Considere o problema onde 𝐿 = 0,1 H, 𝐶 =


450 𝜇F, 𝑉0 = 12 volts e 𝜔𝑉 = 120𝜋 rad/s, com as condições iniciais 𝑞0 = 0 coulombs e
𝐼0 = 0 A.
Para implementar o algoritmo de Numerov, precisamos de valores de 𝑞 em tempos
subsequentes. Podemos achar o valor de 𝑞1 fazendo a aproximação de Euler
𝑑𝑞 𝑞1 − 𝑞0
𝐼0 = ≈ → 𝑞1 = 𝑞0 + ℎ𝐼0
𝑑𝑡 ℎ
Neste caso específico, 𝑞1 = 𝑞0 . Mas podemos inserir este passo de Euler no algoritmo. Para
este problema, a frequência de oscilação quando da ausência de fonte 𝑉0 = 0 volts é 𝜔0 =
1/√𝐿𝐶, tal que o período natural de oscilação é 𝜏0 = 2𝜋√𝐿𝐶. Assim, definirei o passo de
tempo Δ𝑡 = ℎ em função de 𝜏0 . Comparando as equações Equação 29 e 33, vemos que
𝑉
𝑔(𝑡) = −1/𝐿𝐶 e 𝑠(𝑡) = 𝐿0 sen 𝜔𝑉 𝑡.
import math as mt
import matplotlib.pyplot as plt

L = 0.1
C = 0.00045
# as variáveis são
q0 = 0.
I0 = 0.
t0 = 0
# definindo as funções no método de Numerov
g = -1/(L*C)
tau = 2*mt.pi*mt.sqrt(L*C)
# vamos definir o incremento temporal em termos do período
h = 0.01*tau
K = h*h/12

# vanmos definir a função governante do problema


def s(t):
V0 = 12
L = 0.1
omegaV = 120*mt.pi
return (V0/L)*mt.sin(omegaV*t)

tempo = t0

55
Morais & Nogueira – Física Computacional com Python

q = [q0]
t = [tempo]
#passo de Euler
tempo += h
t += [tempo]
q += [I0*h]

#passos Numerov
while tempo < 5*tau:
tempo += h
t += [tempo]
q += [(2*q[-1]*(1+5*K*g)-(q[-2]*(1-
K*g))+K*(s(tempo+h)+10*s(tempo)+s(tempo-h)))/(1-K*g)]

plt.xlabel("Tempo (s)")
plt.ylabel("Carga (coulombs)")
plt.xlim(0,tempo)
plt.ylim(-1.1*max(q),1.1*max(q))
plt.plot(t,q,label='q(t)')
plt.legend()
plt.show()

Oscilador Harmônico Quântico


O oscilador harmônico quântico é o análogo da Mecânica Quântica do oscilador harmônico
clássico. Como um potencial suave arbitrário geralmente pode ser aproximado como um
potencial harmônico na vizinhança de um ponto de equilíbrio estável, é um dos sistemas
modelo mais importantes da Mecânica Quântica. Além disso, é um dos poucos sistemas de
mecânica quântica para os quais uma solução analítica exata é conhecida.
Na Mecânica Quântica, o obtemos a energia do sistema através do operador Hamiltoniano
aplicado na função de onda.
Equação de Schrödinger → Operadores
Neste caso, o Hamiltoniano da partícula sujeita a tal potencial é

56
Morais & Nogueira – Física Computacional com Python

Figura 20- Carga no capacitor com fonte alternada. Note que a carga vai de valores positivos a negativos,
alternando a polaridade no capacitor.

Fazendo GIFs e Filmes

Existe uma grande quantidade de maneiras de se fazer animações em Python. Vamos utilizar
aqui duas maneiras diferentes usando as bibliotecas PIL e Matplotlib Animation. Estas
animações nos serão úteis mais a frente para visualização da dinâmica de sistema de algumas
partículas, como no caso de uma descrição quali-quantitativa da Teoria Cinética dos Gases de
Daniel Bernoulli e da descrição do pêndulo duplo, por exemplo.
Vamos iniciar nossa descrição

Lançamento de Projéteis de novo!


import numpy as np
import matplotlib.pyplot as plt
import math as mt
from matplotlib import animation

# parâmetros
T = 10.
m = 2.
g = 9.8
b = 0.1
v0 = 15
teta = mt.pi/3

v0x = v0*mt.cos(teta)
v0y = v0*mt.sin(teta)
b = 0.1

57
Morais & Nogueira – Física Computacional com Python

# setting a timestep to be 50 ms
dt = 0.05 #s
N = int(T/dt)

# Allocating arrays for 2D problem


v = np.zeros((N+1, 2))
r = np.zeros((N+1, 2))

# initial conditions:
r[0] = np.array([0., 0.])
v[0] = np.array([v0x, v0y])

# Definindo as forças
def forcax(b,v):
return -b*v
def forcay(b,m,g,v):
return -(m*g)-(b*v)
# Dinâmica dentro do intervalo de pontos N
for n in range(N):
v[n+1,0] = v[n,0] + forcax(b,v[n,0])*dt/m
v[n+1,1] = v[n,1] + forcay(b,m,g,v[n,1])*dt/m
r[n+1] = r[n] + v[n]*dt
# Condição de reflexão elástica no chão
if r[n+1,1]<0:
v[n+1,1]=-v[n+1,1]
# Valores máximos obtidos de x e y
rmaximo = np.max(r,axis=0)

alturay = 15*rmaximo[1]/rmaximo[0]
# Configurando os eixos da figura
fig, ax = plt.subplots(figsize=(15,alturay))
## Ajsutando os limites dos eixos
ax.set(xlim=(0, 1.05*rmaximo[0]), ylim=(0, 1.05*rmaximo[1]), xlabel='x
(m)', ylabel='Altura (m)',title='Esfera com resistência do ar')
# Desenhando o primeiro ponto como círculo marker='o' com cor verde c='g'
de green
# vermelho (red) c='r', azul (blue) c='b', etc e tamanho (size) igual a
s=150
scat = ax.scatter(r[0,0], r[0,1], marker='o', c='r', s=200)
# Animando
def animate(i):
scat.set_offsets(r[i])
ani = animation.FuncAnimation(fig, func=animate, frames=N)
## Esta função cria vários arquivos .png na pasta 'esfera-frames' e cria
uma
# página de simulação html que pode ser aberta em qualquer navegador
ani.save('esfera.html', writer=animation.HTMLWriter(fps= 1//dt))
plt.close()
# Este comando salva um filme em formato .mp4
#ani.save('pedra.mp4', fps= 1//dt)

Teoria Cinética dos Gases


Em 1738, o físico matemático Daniel Bernoulli, publicou o livro Hydrodynamica, que lançou
a base para a teoria cinética dos gases. Nesse trabalho, Bernoulli posicionou seu argumento,
ainda sólido até a atualidade, que os gases consistem em muitas moléculas se movendo em
todas as direções, onde elas colidem entre si e esse impacto causa uma pressão na superfície
de contato que podemos sentir. Como exemplos, podemos citar o que nós sentimos como

58
Morais & Nogueira – Física Computacional com Python

calor, que corresponde simplesmente a energia cinética do seu movimento. A teoria não foi
imediatamente aceita, em parte por causa da conservação de energia que não estava bem
estabelecida, e ainda, não era óbvio aos físicos que as colisões entre as moléculas poderiam
ser perfeitamente elásticas.
Considere no nosso problema 𝑁 moléculas idênticas e enumeráveis cada qual com massa 𝑚
localizadas respectivamente nas posições 𝑟⃗𝑖 e tendo velocidades 𝑣⃗𝑖 = 𝑑𝑟⃗𝑖 /𝑑𝑡. A energia
1
cinética de cada molécula é 𝑇𝑖 = 2 𝑚𝑣𝑖2 e a energia cinética total do sistema é
𝑁
1
𝑇 = ∑ 𝑚𝑣𝑖2
2
𝑖=1

Lei de Hooke
Vamos considerar agora o caso em que quatro partículas de massas idênticas estão presas
umas às outras através de molas invisíveis de comprimento 𝐿 e sem massa que obedece a Lei
de Hooke. Isto é, a força agindo entre elas é
𝑟𝑖𝑗 − 𝐿
𝐹𝑖𝑗 = −𝑘 (𝑟⃗𝑖 − 𝑟⃗𝑗 ),
𝑟𝑖𝑗

onde 𝑘 é a constante elástica da mola, 𝑟⃗𝑖 é a posição da partícula 𝑖 e 𝑟𝑖𝑗 = √𝑟⃗𝑖 − 𝑟⃗𝑗 é a
distância entre as partículas. No programa abaixo, vamos utilizar as bibliotecas numpy e
matplotlib. As posições e velocidades iniciais são definidas e as partículas estão confinadas
em uma caixa de lado sete metros centrada na origem.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation

fig, ax = plt.subplots(figsize=(6,6))
ax.set(xlim=(-3.5, 3.5), ylim=(-3.5, 3.5), ylabel='metros',
xlabel='metros', title='Quatro Corpos')

# parametros do problema:
# tempo total de simulação
T = 30.
# massa das partículas
m = 1.
# constante da mola
k = 1.
# comprimento da mola
L = 0.5

# definindo o incremento de tempo


dt = 0.05
# definindo o número de passos
N = int(T/dt)

# Allocando os arrays para o problema


# posição
r = np.zeros((N+1, 4, 2))
# velocidade

59
Morais & Nogueira – Física Computacional com Python

v = np.zeros((N+1, 4, 2))
# forças
f = np.zeros((N+1, 4, 2))

# condições iniciais
r[0,0] = np.array([0., 2.])
r[0,1] = np.array([2., 0.])
r[0,2] = np.array([-1., 0.])
r[0,3] = np.array([-1., 1.])
v[0,0] = np.array([0., 1.])
v[0,1] = np.array([0., 1.])
v[0,2] = np.array([0., -1.])
v[0,3] = np.array([-1., 0.])

# Resolvendo via método de Euler


for n in range(N):
for i in range(4):
for j in range(4):
if i != j:
rij = r[n,i]-r[n,j]
# este comando define a norma do vetor, neste caso é a distância entre as
coordenadas das partículas i e j.
dist = np.linalg.norm(rij)
f[n, i] -= k*(dist-L)*rij/dist
v[n+1] = v[n] + (f[n]/m)*dt
r[n+1] = r[n] + v[n+1]*dt
# condições de reflexão nas paredes
for i in range(4):
if r[n+1,i,0]<-3.5:
v[n+1,i,0] = -v[n+1,i,0]
if r[n+1,i,0]>3.5:
v[n+1,i,0] = -v[n+1,i,0]
if r[n+1,i,1]<-3.5:
v[n+1,i,1] = -v[n+1,i,1]
if r[n+1,i,1]>3.5:
v[n+1,i,1] = -v[n+1,i,1]

# Desenhando a animação
scat = ax.scatter(r[0,:,0], r[0,:,1], marker='o', c=['b', 'k', 'r','g'],
s=100)

def animate(i):
scat.set_offsets(r[i])

ani = animation.FuncAnimation(fig, animate, frames=N)


plt.close()
# Este comando cria vários arquivos .png e depois os junta em uma página
html
ani.save('4corpos.html', writer=animation.HTMLWriter(fps= 1//dt))

Pêndulo Simples

60
Morais & Nogueira – Física Computacional com Python

Uma aproximação bastante comum em Física ocorre com a linearização da equação do


pêndulo simples para o oscilador harmônico. A linearização consiste em aproximar sen 𝜃 ≈
𝜃 na equação
𝑑2𝜃 𝑔 𝑔
2
= − sin 𝜃 ≈ − 𝜃
𝑑𝑡 𝐿 𝐿
Tal que o período do pêndulo é dado por
2𝜋 𝑔
𝑃0 = = 2𝜋√
𝜔0 𝐿
Esta linearização faz sentido apenas quando sen 𝜃 ≈ 𝜃. Usando uma expansão em séries de
Taylor em torno da origem, temos
𝜃3 𝜃5 𝜃7
sen 𝜃 ≈ 𝜃 − + − +⋯
3! 5! 7!
Para um erro de 1%, temos que 𝜃 = 13,99°. Vamos como varia o período do pêndulo
computacionalmente para considerar esta aproximação.

import numpy as np
import math as mt
import matplotlib.pyplot as plt

# definido a equação
def f(an):
# definindo as condições de operação
g = 9.82 # m/s^2
L = 1.00 # m
return -(g/L)*mt.sin(an)

g = 9.82 # m/s^2
L = 1.00 # m
P0 = 2*mt.pi*mt.sqrt(L/g)
# Definindo o incremento do tempo na simulação
h = 0.000025

angulo0 = np.zeros(400)
periodo = np.zeros(400)

for i in range(1,401):
# fazendo um incremento de meio grau no angulo inicial a cada execução
an = mt.radians(0.1*i)
w = 0.
t = 0.
verifica = True
j = 1
while verifica:
an1 = an
w1 = w
t1 = t
ka1 = w1
kw1 = f(an1)
an2 = an+0.5*h*ka1
w2 = w +0.5*h*kw1
t2 = t+0.5*h

61
Morais & Nogueira – Física Computacional com Python

ka2 = w2
kw2 = f(an2)
an3 = an+0.5*h*ka2
w3 = w +0.5*h*kw2
t3 = t+0.5*h
ka3 = w3
kw3 = f(an3)
an4 = an+h*ka3
w4 = w +h*kw3
t4 = t+h
ka4 = w4
kw4 = f(an4)
an += h*(ka1+2*ka2+2*ka3+ka4)/6
w += h*(kw1+2*kw2+2*kw3+kw4)/6
t += h
if (an<=0):
verifica = False
tempoF = t

angulo0[i-1] = 0.1*i
periodo[i-1] = 4.*(tempoF)/P0

print(P0,4*tempoF)

plt.xlim(0,40.1)
plt.ylim(1,1.04)
taux = [0]
taux += [40.1]
angaux = [1.01]
angaux += [1.01]
plt.plot(angulo0,periodo,label='P/P0')
plt.plot(taux,angaux,'--',label='linha de 1%')
plt.xlabel('ângulo (graus)')
plt.ylabel('P/P0')
plt.legend()
plt.show()

Bolinha passando
from PIL import Image, ImageDraw

def ellipse(x, y, offset):


image = Image.new("RGB", (400, 400), "blue")
draw = ImageDraw.Draw(image)
draw.ellipse((x, y, x+offset, y+offset), fill="red")
return image
def make_gif():
frames = []
x = 0
y = 0
offset = 20
for number in range(40):

62
Morais & Nogueira – Física Computacional com Python

frames.append(ellipse(x, y, offset))
x += 10
y += 10

frame_one = frames[0]
frame_one.save("circle.gif", format="GIF", append_images=frames,
save_all=True, duration=100, loop=0)

if _name_ == "_main_":
make_gif()

Pêndulo

# pêndulo
import numpy as np
import matplotlib.pyplot as plt
import math as mt
from matplotlib import animation

# parâmetros
T = 30.
m = 1.
g = 9.8
L = 1.
teta0 = (mt.pi/2)+(mt.pi/6)
teta = teta0
# setting a timestep to be 50 ms
dt = 0.05 #s
N = int(T/dt)

# Allocating arrays for 2D problem


xmaximo = L*mt.sin(teta)

63
Morais & Nogueira – Física Computacional com Python

ymaximo = L*mt.cos(teta)
# vamos guardar os valores de tempo, teta e as posições x e y.
# os valores de x e y iremos guardar no array de duas dimensões r que tem
Nx2 lugares
r = np.zeros((N+1, 2))
r[0] = np.array([xmaximo, ymaximo])
omega = 0.
tempo = 0.
tpontos = [tempo]
tetapts = [(mt.pi-teta)*180/mt.pi]

F0 = 1.
omegaF = mt.sqrt(g/L)#mt.pi

def forca(g,L,teta,F0,omegaF,tempo):
return (g/L)*mt.sin(teta) + F0*mt.sin(omegaF*tempo)

# Vamos solucionar o pêndulo forçado com o método de Runge-Kutta de


terceira ordem
for n in range(N):
# passo 1
k1 = forca(g,L,teta,F0,omegaF,tempo)
h1 = omega
# passo 2
k2 = forca(g,L,teta+0.5*dt*h1,F0,omegaF,tempo+0.5*dt)
h2 = omega+0.5*dt*k1
# passo 3
k3 = forca(g,L,teta-dt*h1+2.*dt*h2,F0,omegaF,tempo+dt)
h3 = dt*(omega-dt*k1+2.*dt*k2)
# passo final
omega += dt*(k1+4.*k2+k3)/6.
teta += dt*(h1+4.*h2+h3)/6
tempo += dt
tpontos += [tempo]
tetapts += [(mt.pi-teta)*180/mt.pi]
r[n+1] = [L*mt.sin(teta),L*mt.cos(teta)]

fig, ax = plt.subplots(figsize=(8,8))
## Ajsutando os limites dos eixos
ax.set(xlim=(-1.05, 1.05), ylim=(-1.05, 1.05), xlabel='x (m)', ylabel='y
(m)',title='Pêndulo Forçado')
# Desenhando o primeiro ponto como círculo marker='o' com cor verde c='g'
de green
# vermelho (red) c='r', azul (blue) c='b', etc e tamanho (size) igual a
s=150
scat = ax.scatter(r[0,0],r[0,1], marker='o', c='r', s=400)

def animate(i):
scat.set_offsets(r[i])
# scot.set_offsets(r[i])
ani = animation.FuncAnimation(fig, func=animate, frames=N)
## Esta função cria vários arquivos .png na pasta 'esfera-frames' e cria
uma
# página de simulação html que pode ser aberta em qualquer navegador
ani.save('pendulo.html', writer=animation.HTMLWriter(fps= 1//dt))

# Este comando salva um filme em formato .mp4


#ani.save('pedra.mp4', fps= 1//dt)
plt.close()

64
Morais & Nogueira – Física Computacional com Python

plt.xlabel('tempo (s)')
plt.ylabel('Ângulo (graus)')
plt.xlim(0,T)
plt.ylim(-100,100)
plt.plot(tpontos,tetapts,label=('Ângulo inicial ='+str((mt.pi-
teta0)*180/mt.pi)))
plt.legend()
plt.show()

#print('a frequencia de oscilação natural é ',round(mt.sqrt(g/L),4))

Pêndulo Duplo

A equação para o pêndulo duplo com comprimentos 𝐿1 e 𝐿2 é

from numpy import sin, cos


import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from collections import deque

g = 9.8 # m/s^2
L1 = 0.5 # m
L2 = 1.0 # m
L = L1 + L2 # m
m1 = 1.0 # kg
m2 = 1.0 # kg
t_total = 5 # tempo de simulação
history_len = 20 # pontos a serem mostrados

def derivs(t, state):


dydx = np.zeros_like(state)
dydx[0] = state[1]
delta = state[2] - state[0]
den1 = (m1+m2) * L1 - m2 * L1 * cos(delta) * cos(delta)
dydx[1] = ((m2 * L1 * state[1] * state[1] * sin(delta) * cos(delta)
+ m2 * g * sin(state[2]) * cos(delta)
+ m2 * L2 * state[3] * state[3] * sin(delta)
- (m1+m2) * g * sin(state[0]))
/ den1)
dydx[2] = state[3]
den2 = (L2/L1) * den1
dydx[3] = ((- m2 * L2 * state[3] * state[3] * sin(delta) * cos(delta)
+ (m1+m2) * g * sin(state[0]) * cos(delta)
- (m1+m2) * L1 * state[1] * state[1] * sin(delta)
- (m1+m2) * g * sin(state[2]))
/ den2)
return dydx

# crie uma matriz de tempo de 0 até t_total separado em passos de 0.02


segundos
dt = 0.02
t = np.arange(0, t_total, dt)

65
Morais & Nogueira – Física Computacional com Python

# an1 e an2 são os ângulos iniciais dados em graus


# w10 e w20 são as velocidades angulares iniciais (graus por segundo)
an1 = 120.
w1 = 0.
an2 = -5.
w2 = 0.

# condição inicial
state = np.radians([an1, w1, an2, w2])

# integrando a EDO usando o método de Euler


y = np.empty((len(t), 4))
y[0] = state
for i in range(1, len(t)):
y[i] = y[i - 1] + derivs(t[i - 1], y[i - 1]) * dt

# Uma estimativa mais precisa pode ser obtida usando scipy:


# y = scipy.integrate.solve_ivp(derivs, t[[0, -1]], state, t_eval=t).y.T

x1 = L1*sin(y[:, 0])
y1 = -L1*cos(y[:, 0])

x2 = L2*sin(y[:, 2]) + x1
y2 = -L2*cos(y[:, 2]) + y1

fig = plt.figure(figsize=(5, 4))


ax = fig.add_subplot(autoscale_on=False, xlim=(-L, L), ylim=(-L, 1.))
ax.set_aspect('equal')
ax.grid()

line, = ax.plot([], [], 'o-', lw=2)


trace, = ax.plot([], [], '.-', lw=1, ms=2)
time_template = 'tempo = %.1fs'
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
history_x, history_y = deque(maxlen=history_len), deque(maxlen=history_len)

def animate(i):
thisx = [0, x1[i], x2[i]]
thisy = [0, y1[i], y2[i]]

if i == 0:
history_x.clear()
history_y.clear()

history_x.appendleft(thisx[2])
history_y.appendleft(thisy[2])

line.set_data(thisx, thisy)
trace.set_data(history_x, history_y)
time_text.set_text(time_template % (i*dt))
return line, trace, time_text

ani = animation.FuncAnimation(
fig, animate, len(y), interval=dt*1000, blit=True)

f = r"C:\Users\gemmer\Documents\Arquivo exel Daniel\PenduloDuplo.gif"


writergif = animation.PillowWriter(fps=30)
ani.save(f, writer=writergif)

66
Morais & Nogueira – Física Computacional com Python

plt.show()

Resumo/Principais lições do capítulo


Insira conteúdo aqui...
Lembre o leitor dos principais pontos abordados no capítulo em um pequeno
parágrafo. Se preferir, use um formato de lista de pontos, conforme mostrado abaixo:
• Desenvolver a resiliência mental é uma parte importante rumo ao sucesso na vida.
• Ponto 2 do texto...
• Ponto 3 do texto...
• etc.

No próximo capítulo, você saberá...


Para realizar uma transição lógica entre os capítulos, informe ao leitor sobre o que
vem a seguir. Ao finalizar seu capítulo, relacione as informações do próximo capítulo com o
que já foi apresentado.

67

Você também pode gostar