Você está na página 1de 7

tarefa 14

August 28, 2021

1 Tarefa 14 - PVI Método de passos múltiplos


1.1 Métodos numéricos II 2021.1
[1]: # importando módulos relevantes
import numpy as np
import sympy
import matplotlib.pyplot as plt

1.2 Retomando fórmulas de interpolação de Newton


[2]: f0, f1, f2, f3, f4 = sympy.symbols('f0:5')

s, h, r = sympy.symbols('s,h,r')

[3]: def delta_f(expoente, indice):


if expoente == 0:
return sympy.sympify('f{}'.format(indice))
else:
return delta_f(expoente - 1, indice + 1) - delta_f(expoente - 1, indice)

[4]: def combination(x, y):


return sympy.factorial(x) / (sympy.factorial(y) * sympy.factorial(x - y))

Retomamos a implementação de g(s), utilizando as funções definidas acima. Relembre: a função


g_s recebe um parâmetro s, que nos permite escolher o ponto que embasa nosso polinômio de
aproximação, e um parâmetro n, que é a quantidade de termos desejada do polinômio de interpo-
lação.

[5]: def g_s(s, n, indice_inicial = 0):


aux = sympy.sympify('f{}'.format(indice_inicial))
for k in range(1, n + 1):
aux += combination(s, k) * delta_f(k, indice_inicial)
return aux

1
1.3 Adams-Bashforth de segunda ordem
dS(t)
Vamos encontrar uma aproximação g(t) de = F (S(t), t) para calcular o incremento aproxi-
dt
mado do nosso passo, a integral somada à direita em
∫ ti+1
Si+1 ≈ Si + g(t)dt.
ti

O nosso g(t) é dado pelo polinômio de interpolação de Newton.

[6]: g_1 = g_s(r, 1).expand().simplify().collect((f0, f1))


g_1
[6]:
f0 (1 − r) + f1 r
Fazendo a integração, obtemos o incremento aproximado do passo.

[7]: ordem2 = sympy.integrate(h * g_1, (r, 1, 2)).collect(h / 2)


ordem2
[7]: h (−f0 + 3f1 )
2
A seguir, adaptamos o procedimento anterior para calcular a fórmula de correção.

[8]: g_1P = g_s(r, 1, 1).expand().simplify().collect((f0, f1))


g_1P
[8]:
f1 (1 − r) + f2 r

[9]: sympy.integrate(h * g_1P, (r, 0, 1)).collect(h / 2)


[9]: h (f1 + f2 )
2

1.4 Adams-Bashforth de terceira ordem


O nosso g(t) é dado pelo polinômio de interpolação de Newton.

[10]: g_2 = g_s(r, 2).expand().simplify().collect((f0, f1, f2))


g_2
[10]: ( r2 3r )
( 2 )
( 2
r r
)
f0 − + 1 + f1 −r + 2r + f2 −
2 2 2 2
Fazendo a integração, obtemos o incremento aproximado do passo.

[11]: ordem3 = sympy.integrate(h * g_2, (r, 2, 3))


ordem3
[11]: 5f0 h 4f1 h 23f2 h
− +
12 3 12
A seguir, adaptamos o procedimento anterior para calcular a fórmula de correção.

2
[12]: g_2P = g_s(r, 2, 1).expand().simplify().collect((f1, f2, f3))
g_2P
[12]: ( r2 3r )
( 2 )
( 2
r r
)
f1 − + 1 + f2 −r + 2r + f3 −
2 2 2 2
[13]: sympy.integrate(h * g_2P, (r, 1, 2)).collect(h)
[13]: ( f1 2f2 5f3
)
h − + +
12 3 12

1.5 Adams-Bashforth de quarta ordem


O nosso g(t) é dado pelo polinômio de interpolação de Newton.

[14]: g_3 = g_s(r, 3).expand().simplify().collect((f0, f1, f2, f3))


g_3
[14]: ( r3 11r
) ( 3
r 5r2
) ( 3
r 3r
) ( 3
r r2 r
)
f0 − + r − 2
+ 1 + f1 − + 3r + f2 − + 2r −
2
+ f3 − +
6 6 2 2 2 2 6 2 3
Fazendo a integração, obtemos o incremento aproximado do passo.

[15]: ordem4 = sympy.integrate(h * g_3, (r, 3, 4)).collect(h)


ordem4
[15]: ( 3f0 37f1 59f2 55f3 )
h − + − +
8 24 24 24
A seguir, adaptamos o procedimento anterior para calcular a fórmula de correção.

[16]: g_3P = g_s(r, 3, 1).expand().simplify().collect((f1, f2, f3, f4))


g_3P
[16]: ( r3 11r
) ( 3
r 5r2
) ( 3
r 3r
) ( 3
r r2 r
)
f1 − + r − 2
+ 1 + f2 − + 3r + f3 − + 2r −
2
+ f4 − +
6 6 2 2 2 2 6 2 3
[17]: sympy.integrate(h * g_3P, (r, 2, 3)).collect(h)
[17]: ( f1 5f2 19f3 3f4
)
h − + +
24 24 24 8

1.6 Implementação e solução do PVI


1.6.1 Runge-Kutta de quarta ordem
[18]: def runge_kutta_4th(F, x0, tfinal, t0 = 0, dt = 0.001):
x = [np.array(x0)]
t = t0
while t < tfinal:
F1 = F(x[-1], t)
S2 = x[-1] + dt / 2 * F1
F2 = F(S2, t + dt / 2)
S3 = x[-1] + dt / 2 * F2

3
F3 = F(S3, t + dt / 2)
S4 = x[-1] + dt * F3
F4 = F(S4, t + dt)
x.append(x[-1] + dt / 6 * (F1 + 2 * F2 + 2 * F3 + F4))
t += dt
return x

1.6.2 Adams-Bashforth de quarta ordem

[19]: def adams_bashforth_4th(F, x0, tfinal, t0 = 0, dt = 0.001):


x = runge_kutta_4th(F, x0, t0 + dt * 3, t0, dt)
t = t0 + dt * 3
while t < tfinal:
# prediction
x_next = x[-1] + dt / 24 * (-9 * F(x[-4], t - 3 * dt) + 37 * F(x[-3], t␣
,→- 2 * dt)

- 59 * F(x[-2], t - dt) + 55 * F(x[-1], t))


# correction
x.append(x[-1] + dt / 24 * (F(x[-3], t - 2 * dt) - 5 * F(x[-2], t - dt)
+ 19 * F(x[-1], t) + 9 * F(x_next, t + dt)))
# update t
t += dt
return x

1.6.3 Resolvendo o problema de valor inicial 2 (PVI-2)


{ dS(t) ( ) ( ) ( )
dv(t)
= F (S(t), t) dS(t) −g − m
k
v(t) v0
PVI-2: dt , com dt
= dy(t) , F (S(t), t) = e S0 = =
S(t0 ) = S0 dt v(t) y0
( ) dt
3
.
150

[20]: F_pvi2 = lambda x, t: np.array([ -9.8 - x[0],


x[0] ])
x0_pvi2 = [ 3, 150 ]
x = adams_bashforth_4th(F_pvi2, x0_pvi2, 20)

[21]: t = np.arange(0, 20.001, 0.001)


y = [ xx[1] for xx in x ]
plt.grid(which='major', linestyle=':', color='gray')
plt.plot(t, y)

[21]: [<matplotlib.lines.Line2D at 0x1d7f051d9a0>]

4
1.6.4 Resolvendo o PVI-2 modificado
Solução exata do PVI-2:
( ) ( ( ) − k (t−t ) )
v(t) −g mk + v0 + g k e (
m m 0
) .
S(t) = = ( ) −m
k
y(t) y0 − g m
k (t − t 0 ) − v 0 + g m m
k k e (t−t0 )
− 1

Ou seja, (
m m) m ( − k t )
y(t) = 200 − 9.8 t − 5 + 9.8 e m −1
k k k
Inicializando os parâmetros:

[22]: t0 = 0;
v0, y0 = 5, 200
x0_pvi2M = [ v0, y0 ]
k = 0.25; m = 2
g = 9.8
F_pvi2M = lambda x, t: np.array([ -9.8 - k / m * x[0],
x[0]])

[23]: def y_(t): return y0 - g * m / k * (t - t0) - (v0 + g * m / k) * m / k * (np.


,→exp(- k / m * (t - t0)) - 1)

y_exato = y_(10)
y_exato

[23]: -107.95600046511885

5
Encontrando as soluções aproximadas para os diferentes valores de ∆t:
[24]: dt = [1 / 10 ** i for i in range(5)]
solucoes = []
for i in range(1,5):
solucoes.append(adams_bashforth_4th(F_pvi2M, x0_pvi2M, 10, 0, dt[i]))

Extraindo somente os valores finais y(t) (aproximados):

[25]: yf = [ solucao[-1][-1] for solucao in solucoes]


erros_relativos = [ (y_final - y_exato) / y_exato for y_final in yf ]

[26]: from tabulate import tabulate

[27]: colunas = ["dt", "y_aprox", "erro relativo"]


linhas = [ (d, y, e) for d, y, e in zip(dt, yf, erros_relativos)]
print(tabulate(linhas, colunas, tablefmt = "github"))

| dt | y_aprox | erro relativo |


|-------|-----------|-----------------|
| 1 | -113.421 | 0.0506264 |
| 0.1 | -108.501 | 0.00505025 |
| 0.01 | -108.011 | 0.0005049 |
| 0.001 | -107.961 | 5.04888e-05 |

Obtendo informações a partir das soluções


[28]: # listas de índices do tempo, para cada solução
T = [ np.arange(0, 10 + 0.0001, 0.1),
np.arange(0, 10 + 0.0001, 0.01),
np.arange(0, 10 + 0.0001, 0.001),
np.arange(0, 10 + 0.0001, 0.0001) ]

# listas dos valores de y(t) (trajetória) para cada solução


Y = [ [ xx[1] for xx in solucoes[0] ],
[ xx[1] for xx in solucoes[1] ],
[ xx[1] for xx in solucoes[2] ],
[ xx[1] for xx in solucoes[-1] ] ]

alturas_maximas = list(map(max, Y))


alturas_maximas

[28]: [201.22360449690828,
201.22364412331328,
201.22374680088367,
201.22374760424992]

[29]: indices_maximos = [ Y[i].index(alturas_maximas[i]) for i in range(4) ]


indices_maximos

6
[29]: [5, 49, 495, 4946]

[30]: [ T[i][indices_maximos[i]] for i in range(4) ]

[30]: [0.5, 0.49, 0.495, 0.49460000000000004]

[31]: indices_altura_do_mar = []
for y in Y:
for i in range(len(y)):
if y[i] < 0:
indices_altura_do_mar.append(i - 1)
break
indices_altura_do_mar

[31]: [78, 788, 7885, 78852]

[32]: from tabulate import tabulate


colunas = ["Delta t", "y_max", "t_max", "t_mar", "v(t_mar)"]
linhas = []
for i in range(4):
linhas.append((1 / 10**(i + 1), Y[i][indices_maximos[i]],␣
,→T[i][indices_maximos[i]], T[i][indices_altura_do_mar[i]],␣

,→solucoes[i][indices_altura_do_mar[i]][0]))

print(tabulate(linhas, colunas))

Delta t y_max t_max t_mar v(t_mar)


--------- ------- ------- ------- ----------
0.1 201.224 0.5 7.8 -46.9422
0.01 201.224 0.49 7.88 -47.2552
0.001 201.224 0.495 7.885 -47.2746
0.0001 201.224 0.4946 7.8852 -47.2754

Você também pode gostar