Vector Poisson equation#
In this example we consider the vector Poisson equation with homogeneous Dirichlet boundary conditions:
\[
\begin{align}
- \nabla^2 \mathbf{u} = \mathbf{f} \quad \mbox{in} ~ \Omega, \quad \quad
\mathbf{u} = 0 \quad \mbox{on} ~ \partial \Omega.
\end{align}
\]
The Variational Formulation#
The corresponding variational formulation, using \(\mathbf{H}^1\) formulation, i.e. all components are in \(H^1\), reads
\[
\begin{align}
\text{find $\mathbf{u} \in V$ such that} \quad
a(\mathbf{u},\mathbf{v}) = l(\mathbf{v}) \quad \forall \mathbf{v} \in V,
\end{align}
\]
where
\(V \subset \mathbf{H}_0^1(\Omega)\),
\(a(\mathbf{u},\mathbf{v}) := \int_{\Omega} \nabla \mathbf{u} : \nabla \mathbf{v} ~ d\Omega\),
\(l(\mathbf{v}) := \int_{\Omega} \mathbf{f} \cdot \mathbf{v} ~ d\Omega\).
Formal Model#
from sympde.expr import BilinearForm, LinearForm, integral
from sympde.expr import find, EssentialBC, Norm, SemiNorm
from sympde.topology import VectorFunctionSpace, Cube, element_of
from sympde.calculus import grad, inner, dot
from sympy import pi, sin, Tuple, Matrix
domain = Cube()
V = VectorFunctionSpace('V', domain)
x,y,z = domain.coordinates
u,v = [element_of(V, name=i) for i in ['u', 'v']]
# bilinear form
a = BilinearForm((u,v), integral(domain , inner(grad(v), grad(u))))
# linear form
f1 = 3*pi**2*sin(pi*x)*sin(pi*y)*sin(pi*z)
f2 = 3*pi**2*sin(pi*x)*sin(pi*y)*sin(pi*z)
f3 = 3*pi**2*sin(pi*x)*sin(pi*y)*sin(pi*z)
f = Tuple(f1, f2, f3)
l = LinearForm(v, integral(domain, dot(f,v)))
# Dirichlet boundary conditions
bc = [EssentialBC(u, 0, domain.boundary)]
# Variational problem
equation = find(u, forall=v, lhs=a(u, v), rhs=l(v), bc=bc)
Discretization#
We shall need the discretize function from PsyDAC.
from psydac.api.discretization import discretize
degree = [2,2,2]
ncells = [8,8,8]
# Create computational domain from topological domain
domain_h = discretize(domain, ncells=ncells, comm=None)
# Create discrete spline space
Vh = discretize(V, domain_h, degree=degree)
# Discretize equation
equation_h = discretize(equation, domain_h, [Vh, Vh])
Solving the PDE#
uh = equation_h.solve()
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
Cell In[5], line 1
----> 1 uh = equation_h.solve()
File /opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages/psydac/api/equation.py:198, in DiscreteEquation.solve(self, **kwargs)
196 def solve(self, **kwargs):
--> 198 self.assemble(**kwargs)
200 # Free arguments of current equation
201 free_args = set(self.lhs.free_args + self.rhs.free_args)
File /opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages/psydac/api/equation.py:178, in DiscreteEquation.assemble(self, **kwargs)
176 # Matrix (left-hand side)
177 if assemble_lhs:
--> 178 A = self.lhs.assemble(reset=True, **kwargs)
179 if self.bc:
180 apply_essential_bc(A, *self.bc)
File /opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages/psydac/api/fem.py:532, in DiscreteBilinearForm.assemble(self, reset, **kwargs)
529 if reset:
530 reset_arrays(*self.global_matrices)
--> 532 self._func(*args, *self._threads_args)
533 if self._matrix and self._update_ghost_regions:
534 self._matrix.exchange_assembly_data()
File ~/work/IGA-Python/IGA-Python/chapter2/__psydac__/dependencies_lr7xfr33.py:97, in assemble_matrix_lr7xfr33(global_test_basis_v_1, global_test_basis_v_2, global_test_basis_v_3, global_trial_basis_u_1, global_trial_basis_u_2, global_trial_basis_u_3, global_span_v_1, global_span_v_2, global_span_v_3, global_x1, global_x2, global_x3, test_v_p1, test_v_p2, test_v_p3, trial_u_p1, trial_u_p2, trial_u_p3, n_element_1, n_element_2, n_element_3, k1, k2, k3, pad1, pad2, pad3, g_mat_u_0_v_0_lr7xfr33, g_mat_u_1_v_1_lr7xfr33, g_mat_u_2_v_2_lr7xfr33)
95 contribution_v_0_u_0_lr7xfr33 += u_0_x1*v_0_x1 + u_0_x2*v_0_x2 + u_0_x3*v_0_x3
96 contribution_v_1_u_1_lr7xfr33 += u_1_x1*v_1_x1 + u_1_x2*v_1_x2 + u_1_x3*v_1_x3
---> 97 contribution_v_2_u_2_lr7xfr33 += u_2_x1*v_2_x1 + u_2_x2*v_2_x2 + u_2_x3*v_2_x3
101 l_mat_u_0_v_0_lr7xfr33[i_basis_1,i_basis_2,i_basis_3,2 - i_basis_1 + j_basis_1,2 - i_basis_2 + j_basis_2,2 - i_basis_3 + j_basis_3] = contribution_v_0_u_0_lr7xfr33
102 l_mat_u_1_v_1_lr7xfr33[i_basis_1,i_basis_2,i_basis_3,2 - i_basis_1 + j_basis_1,2 - i_basis_2 + j_basis_2,2 - i_basis_3 + j_basis_3] = contribution_v_1_u_1_lr7xfr33
KeyboardInterrupt:
Computing the error norm#
When the analytical solution is available, you might be interested in computing the \(L^2\) norm or \(H^1_0\) semi-norm. SymPDE allows you to do so, by creating the Norm object. In this example, the analytical solution is given by
\[
u_e = \sin(\pi x) \sin(\pi y) \sin(\pi z)
\]
Computing the \(L^2\) norm#
ue1 = sin(pi*x)*sin(pi*y)*sin(pi*z)
ue2 = sin(pi*x)*sin(pi*y)*sin(pi*z)
ue3 = sin(pi*x)*sin(pi*y)*sin(pi*z)
ue = Tuple(ue1, ue2, ue3)
u = element_of(V, name='u')
error = Matrix([u[0]-ue[0], u[1]-ue[1], u[2]-ue[2]])
# create the formal Norm object
l2norm = Norm(error, domain, kind='l2')
# discretize the norm
l2norm_h = discretize(l2norm, domain_h, Vh)
# assemble the norm
l2_error = l2norm_h.assemble(u=uh)
# print the result
print(l2_error)
Computing the \(H^1\) semi-norm#
# create the formal Norm object
h1norm = SemiNorm(error, domain, kind='h1')
# discretize the norm
h1norm_h = discretize(h1norm, domain_h, Vh)
# assemble the norm
h1_error = h1norm_h.assemble(u=uh)
# print the result
print(h1_error)
Computing the \(H^1\) norm#
# create the formal Norm object
h1norm = Norm(error, domain, kind='h1')
# discretize the norm
h1norm_h = discretize(h1norm, domain_h, Vh)
# assemble the norm
h1_error = h1norm_h.assemble(u=uh)
# print the result
print(h1_error)