| | | |

Método dos Elementos Finitos

Ajude a manter o site livre, gratuito e sem propagandas. Colabore!

1.1 Interpolação e projeção

Seja dado um intervalo I=[x0,x1], x0x1. O espaço vetorial das funções afins em I é definido por

P1(I):={v:v(x)=c0+c1x,xI,c0,c1}. (1.1)

Observamos que dado vP1(I), temos que v é unicamente determinada pelos valores

α0=v(x0), (1.2)
α1=v(x1).

Como consequência, existe exatamente uma única função vP1(I) para quaisquer dados valores α0 e α1. Desta observação, introduzimos a chamada base nodal (base lagrangiana111Joseph-Louis Lagrange, 1736 - 1813, matemático italiano. Fonte: Wikipédia: Joseph-Louis Lagrange.) {φ0,φ1} para P1(I), definida por

φj(xi)={1,i=j,0,ij, (1.3)

com i,j=0,1. Consulte a Figura 1.1.

Refer to caption
Figura 1.1: Base nodal para o espaço P1([x0,x1]).

Com esta base, toda função vP1(I) pode ser escrita como uma combinação linear das funções φ0 e φ1 com coeficientes α0 e α1 (graus de liberdade), i.e.

v(x)=α0φ0(x)+α1φ1(x). (1.4)

Além disso, observamos que

φ0(x)=xx1x0x1, (1.5)
φ1(x)=xx0x1x0. (1.6)

Uma extensão do espaço P1(I) é o espaço das funções afins por partes. Dado I=[l0,l1], l0l1, consideramos uma partição (malha) de I com n+1 pontos

={l0=x0,x1,,xn=l1} (1.7)

e, portanto, com n células Ii=[xi1,xi] de comprimento (tamanho da malha) hi=xixi1, i=1,2,,n. Na malha definimos o seguinte espaço das funções afins por partes

Vh:={v:vC0(),v|IiP1(Ii),i=1,2,,n}. (1.8)

Observamos que toda função vVh é unicamente determinada por seus valores nodais {αi=v(xi)}i=0n. Reciprocamente, todo conjunto de valores nodais {αi}i=0n determina unicamente uma função vVh. Desta observação, temos que os valores nodais determinam os graus de liberdade com a base nodal {φj}j=0n para Vh definida pelas funções afins por partes tais que

φj(xi)={1,i=j,0,ij, (1.9)

com i,j=0,1,,n. Ou seja, temos que

v(x)=j=0nαjφj(x). (1.10)

Podemos verificar que

φi(x)={(xxi1)/hi,xIi,(xi+1x)/hi+1,xIi+1,0,noutros casos (1.11)

consulte, Figura 1.2. É notável que φi(x) tem suporte compacto IiIi+1.

Refer to caption
Figura 1.2: Base nodal para o espaço das funções afins por parte.

1.1.1 Interpolação

Interpolação é uma técnica de aproximação de funções. Dada uma função contínua f em I=[l0,l1], definimos o operador de interpolação π:C0(I)Vh por

πf(x)=j=0nf(xj)φj(x) (1.12)

Observamos que πf(x) é igual a f(x) nos nodos xj, j=0,1,2,,n.

Exemplo 1.1.1.

O Código 1 implementa a interpolação da função f(x)=3sen(2πx) no espaço de elementos finitos Vh das funções afins por partes com 5 células sobre o intervalo I=[1/4,3/4].

Código 1: mef1d_interp_lin.py
1from mpi4py import MPI
2import ufl
3from dolfinx import mesh, fem, io
4
5# malha
6l0, l1 = 0.25, 0.75
7domain = mesh.create_interval(MPI.COMM_WORLD, nx=5, points=[l0, l1])
8x = ufl.SpatialCoordinate(domain)
9
10# espaço (FEniCSx API)
11V = fem.functionspace(domain, ("Lagrange", 1))
12
13# função exata
14def fun(x, module=ufl):
15 return 3.0 * module.sin(2.0 * module.pi * x)
16
17# interpolação
18pif = fem.Function(V)
19pts = V.element.interpolation_points
20expr = fem.Expression(fun(x[0]), pts)
21pif.interpolate(expr)
22
23# store mesh and pif for later visualization in Paraview
24with io.XDMFFile(domain.comm, "mesh.xdmf", "w") as xdmf:
25 xdmf.write_mesh(domain)
26 xdmf.write_function(pif)
Refer to caption
Figura 1.3: Interpolação da função f(x)=3sen(2πx) no espaço de elementos finitos Vh das funções afins por partes com 5 células sobre o intervalo I=[1/4,3/4].

A visualização da função πf pode ser feita usando o Paraview. Alternativamente, podemos usar o Matplotlib para esboçar os gráficos de f e πf em Python. O código para isso é mostrado a seguir e produz o gráfico da Figura 1.3.

1# gráfico
2import numpy as np
3import matplotlib.pyplot as plt
4
5# coordenadas e valores locais
6x_dofs_local = V.tabulate_dof_coordinates()[:, 0]
7pif_local = pif.x.array.real
8
9# junta em rank 0 (MPI-safe)
10comm = domain.comm
11all_x = comm.gather(x_dofs_local, root=0)
12all_y = comm.gather(pif_local, root=0)
13print(f"Rank {comm.rank}: {len(x_dofs_local)} dofs localmente")
14
15if comm.rank == 0:
16 x_dofs = np.concatenate(all_x)
17 y_dofs = np.concatenate(all_y)
18
19 # remove duplicatas de nós de fronteira entre partições
20 order = np.argsort(x_dofs)
21 x_dofs = x_dofs[order]
22 y_dofs = y_dofs[order]
23 x_unique, idx = np.unique(x_dofs, return_index=True)
24 y_unique = y_dofs[idx]
25
26 # gráfico
27 xx = np.linspace(l0, l1, 400)
28 fig, ax = plt.subplots()
29 ax.plot(xx, fun(xx, module=np), color="C0", label="$f$")
30 ax.plot(x_unique, y_unique, ls="-", marker="o", color="C1", label=r"$\pi f$")
31
32 ax.grid(True)
33 ax.set_xlabel("$x$")
34 ax.set_ylabel("$y$")
35 ax.legend()
36
37 plt.show()

Agora, vamos buscar medir o erro de interpolação, i.e. fπf. Para tanto, podemos usar a norma L2 definida por

vL2(I)=(Iv2𝑑x)1/2. (1.13)

Lembramos que valem a desigualdade triangular

v+wL2(I)vL2(I)+wL2(I) (1.14)

e a desigualdade de Cauchy-Schwarz222Também conhecida como desigualdade de Cauchy–Bunyakovsky–Schwarz. Augustin-Louis Cauchy, 1789 - 1857, matemático francês. Viktor Yakovlevich Bunyakovsky, 1804 - 1889, matemático Russo. Karl Hermann Amandus Schwarz, 1843 - 1921, matemático alemão.

Ivw𝑑xvL2(I)wL2(I), (1.15)

para qualquer funções v,wL2(I).

Proposição 1.1.1.(Erro de interpolação: P1(I))

O interpolador πf:C0(I)P1(I) satisfaz as estimativas

fπfL2(I) Ch2f′′L2(I), (1.16)
(fπf)L2(I) Chf′′L2(I), (1.17)

onde C é uma constante e h=x1x0.

Demonstração.

Denotemos o erro de interpolação por e=fπf. Do teorema fundamental do cálculo, temos

e(y)=e(x0)+x0ye(x)𝑑x, (1.18)

onde e(x0)=f(x0)πf(x0)=0. Daí, usando a desigualdade de Cauchy-Schwarz (1.15), temos

e(y) =x0ye𝑑x (1.19)
x0y|e|𝑑x (1.20)
I1|e|𝑑x (1.21)
(I12𝑑x)1/2(I(e)2𝑑x)1/2 (1.22)
=h1/2(I(e)2𝑑x)1/2, (1.23)

donde

e(y)2hI(e)2𝑑x=heL2(I)2. (1.24)

Então, integrando em I obtemos

eL2(I)2=Ie2(y)𝑑y
IheL2(I)2dy=h2eL2(I)2,

ou seja, temos a seguinte desigualdade

eL2(I)CheL2(I), (1.25)

com C=1.

Agora, observando que e(x0)=e(x1)=0, o teorema de Rolle333Michel Rolle, 1652 - 1719, matemático francês. Fonte: Wikipédia: Michel Rolle. garante a existência de um ponto x~I tal que e(x~)=0, donde do teorema fundamental do cálculo e da desigualdade de Cauchy-Schwarz, segue que

e(y) =e(x~)+x~ye′′𝑑x (1.26)
=x~ye′′𝑑x (1.27)
I1|e′′|𝑑x (1.28)
h1/2(I(e′′)2)1/2. (1.29)

Então, elevando ao quadrado e integrando em I, obtemos

eL2(I)2Ch2e′′L2(I)2, (1.30)

a qual, observando que e′′=f′′, equivale a segunda estimativa procurada, i.e.

(fπf)L2(I)Chf′′L2(I). (1.31)

Por fim, de (1.30) e de (1.25), obtemos a primeira estimativa desejada

fπfL2(I)Ch2f′′L2(I). (1.32)

Vamos, agora, generalizar o resultado da Proposição 1.1.1 para a interpolação no espaço Vh das funções lineares por parte.

O seguinte resultado fornece uma estimativa do erro de interpolação em relação ao tamanho hi de cada elemento da malha.

Proposição 1.1.2.(Erro de interpolação: Vh)

O interpolador πf satisfaz as estimativas

fπfL2(I)2 Ci=1nhi4f′′L2(Ii)2, (1.33)
(fπf)L2(I)2 Ci=1nhi2f′′L2(Ii)2. (1.34)
Demonstração.

Ambas desigualdades seguem da desigualdade triangular e da Proposição 1.1.1. Por exemplo, para a primeira desigualdade, temos

fπfL2(I)2 i=1nfπfL2(Ii)2 (1.36)
i=1nChi4f′′L2(Ii)2. (1.37)

Exemplo 1.1.2.(Estimativa da taxa do erro de interpolação)

A Tabela 1.1 apresenta uma análise numérica da convergência de malha na interpolação da função f(x)=3sen(2πx) no espaço Vh das funções afins por partes. A estimativa da taxa de convergência α é dada assumindo que

fπhfL2(I)Chα, (1.38)

onde πh:C0(I)Vh é o operador de interpolação e h é o tamanho da malha. Assim, a taxa α pode ser estimada por

αlog(fπh1fL2(I)/fπh2fL2(I))log(h1/h2), (1.39)

com h1 e h2 sendo dois tamanhos de malha distintos. Da Proposição 1.1.2, esperamos que α2.

Tabela 1.1: Análise da convergência de malha na interpolação da função f(x)=3sen(2πx) no espaço Vh das funções afins por partes.
n h fπfL2(I) α
5 1.00e1 7.54e1
10 5.00e2 1.90e1 2.00
20 2.50e2 4.75e2 2.00
40 1.25e2 1.19e2 2.00

O cálculo aproximado do erro fπfL2(I) pode ser feito pelo seguinte código.

Código 2: ex_mef1d_interp_lin_taxa.py
1from mpi4py import MPI
2import ufl
3import numpy as np
4import dolfinx.cpp as cpp
5from dolfinx import mesh, geometry, fem, io
6
7# malha
8l0, l1 = 0.25, 0.75
9domain = mesh.create_interval(MPI.COMM_WORLD, nx=5, points=[l0, l1])
10x = ufl.SpatialCoordinate(domain)
11
12# espaço (FEniCSx API)
13V = fem.functionspace(domain, ("Lagrange", 1))
14
15# função exata
16def fun(x, module=ufl):
17 return 3.0 * module.sin(2.0 * module.pi * x)
18
19# interpolação
20pif = fem.Function(V)
21pts = V.element.interpolation_points
22expr = fem.Expression(fun(x[0]), pts)
23pif.interpolate(expr)
24
25# avalia uma função u em um ponto arbitrário
26def fem_fun_eval(u, point, domain=domain, V=V):
27 point = np.asarray(point)
28 # encontra a célula que contém o ponto
29 bb_tree = geometry.bb_tree(domain, domain.topology.dim)
30 cell_candidates = geometry.compute_collisions_points(bb_tree, point)
31 colliding_cells = geometry.compute_colliding_cells(domain, cell_candidates, point)
32
33 # avalia a função na célula encontrada (se houver)
34 if len(colliding_cells.links(0)) > 0:
35 cell = colliding_cells.links(0)[0]
36 # Evaluate at point
37 u_val = u.eval(point, [cell])
38 return u_val[0] # retorna o valor escalar
39 else:
40 return None # ponto fora do domínio ou não encontrado na partição local
41
42
43# estimativa da taxa de convergência usando os pontos de interpolação
44xx = np.linspace(l0, l1, 100)
45fun_vals = fun(xx, module=np)
46
47pif_vals = np.empty_like(xx)
48for i, pt in enumerate(xx):
49 val = fem_fun_eval(pif, [[pt,0,0]])
50 pif_vals[i] = val
51
52l2err = np.linalg.norm(fun_vals - pif_vals)
53
54# h_max da malha (compatível com versões recentes do dolfinx)
55tdim = domain.topology.dim
56num_cells_local = domain.topology.index_map(tdim).size_local
57cells_local = np.arange(num_cells_local, dtype=np.int32)
58
59# Compatibilidade entre versões do dolfinx
60if hasattr(mesh, "h"):
61 h_local = mesh.h(domain, tdim, cells_local)
62else:
63 h_local = cpp.mesh.h(domain._cpp_object, tdim, cells_local)
64
65hmax_local = np.max(h_local) if h_local.size > 0 else 0.0
66hmax = domain.comm.allreduce(hmax_local, op=MPI.MAX)
67
68print(f"Erro L2 da interpolação: {l2err:.2e}, h = {hmax:.4e}")

1.1.2 Projeção L2

Dada uma função fL2(I), definimos o operador de projeção L2 Ph:L2(I)Vh por

I(fPhf)v𝑑x=0,vVh. (1.40)

Como Vh=span{φi}i=0n é um espaço de dimensão finita (dim(Vh)=n+1), a condição (1.40) é equivalente a

I(fPhf)φi𝑑x=0, (1.41)

para todo i=0,1,,n. Além disso, como PhfVh, temos

Phf=j=0nξjφj, (1.42)

onde ξj, j=0,1,,n, são n+1 incógnitas a determinar. Logo,

I(fPhf)φi𝑑x=0 (1.43)
Ifφi𝑑x=IPhfφi𝑑x (1.44)
Ifφi𝑑x=I(j=0nξjφj)φi𝑑x (1.45)
j=0nξjIφjφi𝑑x=Ifφi𝑑x, (1.46)

para i=0,1,,n.

Observamos que (1.46) consiste em um sistema de n+1 equações lineares para as n+1 incógnitas ξj, j=0,1,,n. Este, por sua vez, pode ser escrito na seguinte forma matricial

M𝝃=𝒃, (1.47)

onde M=[mi,j]i,j=0n+1 é chamada de matriz de massa

mi,j=Iφjφi𝑑x, (1.48)

o vetor das incógnitas é 𝝃=(ξ0,ξ1,,ξn) e 𝒃=(b0,b1,,bn) é chamado de vetor de carga

bi=Ifφi𝑑x. (1.49)

Ou seja, a projeção L2 de f no espaço Vh é

Phf=j=0nξjφj, (1.50)

onde 𝝃=(ξ0,ξ1,,ξn) é solução do sistema (1.47).

Exemplo 1.1.3.

A Figura 1.4 ilustra a projeção L2 da função f(x)=3sen(2πx) no espaço Vh das funções lineares por partes em uma malha uniforme do intervalo I=[1/4,3/4] com n=5 células. A projeção é obtida pela solução do sistema linear (1.47) usando o Código 3.

Refer to caption
Figura 1.4: Projeção L2 de f(x)=3sen(2πx) no espaço Vh das funções lineares por partes sobre uma malha com 5 células.
Código 3: ex_mef1d_proj.py
1from mpi4py import MPI
2import ufl
3import numpy as np
4from dolfinx import mesh, fem
5from dolfinx.fem.petsc import LinearProblem
6
7# malha
8l0, l1 = 0.25, 0.75
9domain = mesh.create_interval(MPI.COMM_WORLD, nx=5, points=[l0, l1])
10x = ufl.SpatialCoordinate(domain)
11
12# espaço (FEniCSx API)
13V = fem.functionspace(domain, ("Lagrange", 1))
14
15# função exata
16def fun(x, module=ufl):
17 return 3.0 * module.sin(2.0 * module.pi * x)
18
19# projeção
20u = ufl.TrialFunction(V)
21v = ufl.TestFunction(V)
22a = ufl.dot(u, v) * ufl.dx
23L = ufl.dot(fun(x[0]), v) * ufl.dx
24problem = LinearProblem(a, L, bcs=[],
25 petsc_options_prefix="projecao")
26phf = problem.solve()

O próximo teorema mostra que Phf é a função que melhor aproxima f dentre todas as funções do espaço Vh.

Teorema 1.1.1.(A melhor aproximação)

A projeção L2 satisfaz

fPhfL2(I)fvL2(I),vVh. (1.51)
Demonstração.

Dado vVh, temos

fPhfL2(I)2=I|fPhf|2𝑑x (1.52)
=I(fPhf)(fv+vPhf)dx (1.53)
=I(fPhf)(fv)dx+I(fPhf)(vPhf)𝑑x=0 (1.54)
=I(fPhf)(fv)dx (1.55)
fPhfL2(I)fvL2(I), (1.56)

donde segue o resultado. ∎

O próximo teorema fornece uma estimativa a-priori do erro fPhfL2(I) em relação ao tamanho da malha.

Teorema 1.1.2.(Erro de projeção)

A projeção L2 satisfaz

fPhfL2(I)2Ci=1nhi4f′′L2(Ii)2. (1.57)
Demonstração.

Tomando a interpolação πfVh, temos do Teorema da melhor aproximação (Teorema 1.1.1) e da estimativa do erro de interpolação (Proposição 1.1.2) que

fPhfL2(I)2 fπfL2(I)2 (1.58)
Ci=1nhi4f′′L2(Ii)2. (1.59)

Exemplo 1.1.4.(Estimativa da taxa do erro de projeção)

A Tabela 1.2 apresenta uma análise numérica da convergência de malha na projeção L2 da função f(x)=3sen(2πx) no espaço Vh das funções afins por partes. A estimativa da taxa de convergência α é dada assumindo que

fPhfL2(I)Chα. (1.60)

Verifique!

Tabela 1.2: Análise da convergência de malha na projeção L2 da função f(x)=3sen(2πx) no espaço Vh das funções afins por partes.
n h fPhfL2(I) α
5 1.00e1 3.42e1
10 5.00e2 8.36e2 2.03
20 2.50e2 2.15e2 1.96
40 1.25e2 5.10e3 2.08

1.1.3 Exercícios

E. 1.1.1.

Faça um código para verificar as estimativas da Proposição 1.1.1 para o caso da interpolação da função f(x)=3sen(2πx) no espaço P1 das funções lineares.

E. 1.1.2.

Faça um código para verificar as estimativas da Proposição 1.1.2 no caso da interpolação da função f(x)=3sen(2πx) no espaço Vh das funções lineares por partes.

E. 1.1.3.

Faça um código para interpolar a função f(x)=3sen(2πx) no espaço das funções quadráticas

P2(I)={v:v(x)=c0+c1x+c2x2,xI,c0,c1,c2}. (1.61)

Então, verifique as estimativas de erro de interpolação para este caso.

E. 1.1.4.

Faça um código para interpolar a função f(x)=3sen(2πx) no espaço das funções quadráticas por partes

Vh,2={v:vC0(),v|IiP2(Ii),i=1,2,,n}. (1.62)

Então, verifique as estimativas de erro de interpolação para este caso.

E. 1.1.5.

Faça um código para computar a projeção L2 Phf da função f(x)=xcos(x) no espaço Vh das funções lineares por partes em uma malha com n células no intervalo I=[0,π]. Para n=10, faça o esboço dos gráficos de f e Phf e compute o erro fPhfL2(I). Estime a taxa de convergência do erro.

E. 1.1.6.

Faça um código para computar a projeção L2 Phf da função f(x)=xcos(x) no espaço Vh,2 das funções quadráticas por partes em uma malha com n células no intervalo I=[0,π]. Para n=10, faça o esboço dos gráficos de f e Phf e compute o erro fPhfL2(I). Estime a taxa de convergência do erro.


Envie seu comentário

Aproveito para agradecer a todas/os que de forma assídua ou esporádica contribuem enviando correções, sugestões e críticas!

Opcional. Preencha seu nome para que eu possa lhe contatar.
Opcional. Preencha seu e-mail para que eu possa lhe contatar.
As informações preenchidas são enviadas por e-mail para o desenvolvedor do site e tratadas de forma privada. Consulte a política de uso de dados para mais informações.

Licença Creative Commons
Este texto é disponibilizado nos termos da Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional. Ícones e elementos gráficos podem estar sujeitos a condições adicionais.

Pedro H A Konzen
| | | |