[UPDATED POST BELOW WITH SHORTER MWE, HOPEFULLY CLEARER - LEAVING THIS ONE FOR CONTEXT]
For a shell problem, I need to implement a source term \mathbf{f} defined at the dofs of a mixed function space Z. In this MWE we have two unknowns: u
and theta
.
My source term is the componentwise summation of a global vector expression, evaluated at several points in the domain: [p_1,p_2,...p_n], and in the most general and simplified case, takes on the form:
\mathbf{f} = [...,f_{ui},f_{\theta i},...]^T =\Sigma_{p=1}^{n} [..., \frac{\partial N_i}{\partial \xi}\frac{\partial \xi}{\partial x} , N_i,...] . The reasons for doing this are complicated to explain and for this MWE this is sufficient. Here i is the ith node and N and \xi refer to the element shape function and parent coordinate, respectively. Following @kamensky 's answer to this post: I have the following MWE. However, I am not sure I handle the global dof numbering correctly because I am not getting the results I expected when I apply this to my problem. Also, I would really appreciate a cleaner way of implementing this if it is possible. I’m still using dolfin 2019 because I need doflin-adjoint. thank you in advance for your help
from dolfin import *
import numpy as np
from ufl import JacobianInverse
mesh = UnitSquareMesh(1,1)
J_inv = project(JacobianInverse(mesh))
tree = mesh.bounding_box_tree()
P2 = FiniteElement("P", triangle, degree=2)
bubble = FiniteElement("B", triangle, degree=3)
Z = FunctionSpace(mesh, MixedElement([P2 + bubble] + [P2]))
z = Function(Z)
u, theta = split(z)
# Evaluate the i-th basis function at point x:
def basis_func(i,x):
cell_index = tree.compute_first_entity_collision(Point(*x))
cell_global_dofs = Z.dofmap().cell_dofs(cell_index)
for local_dof in range(0, len(cell_global_dofs)):
if(i==cell_global_dofs[local_dof]):
cell = Cell(mesh, cell_index)
values = np.array([0,])
return Z.element().evaluate_basis(local_dof, x,
cell.get_vertex_coordinates(),
cell.orientation())[0]
# If none of this cell's shape functions map to the i-th basis function,
# then the i-th basis function is zero at x.
return 0.0
# Evaluate the i-th basis function n-th derivative in direction j at point x:
def basis_func_derivs(i, j, x, n=1):
cell_index = tree.compute_first_entity_collision(Point(*x))
cell_global_dofs = Z.dofmap().cell_dofs(cell_index)
for local_dof in range(0, len(cell_global_dofs)):
if(i==cell_global_dofs[local_dof]):
cell = Cell(mesh, cell_index)
values = np.array([0,])
return Z.element().evaluate_basis_derivatives(local_dof, n, x,
cell.get_vertex_coordinates(),
cell.orientation())[j]
# If none of this cell's shape functions map to the i-th basis function,
# then the i-th basis function is zero at x.
return 0.0
# Build a Python list of all basis functions:
list_of_basis_funcs = []
list_of_basis_funcs_derivs = []
for i in range(0,Z.dim()):
list_of_basis_funcs += [(lambda i: lambda x : basis_func(i,x))(i),]
for i in range(0,Z.dim()):
list_of_basis_funcs_derivs += [(lambda i: lambda x : basis_func_derivs(i,0,x,n=1))(i),]
def f_u(i,x):
# the term corresponding to u
return list_of_basis_funcs_derivs[i](x)*J_inv(x).reshape(2,2)[0,0]
def f_theta(i,x):
# term corresponding to theta
return list_of_basis_funcs[i](x)
# Some points for the source term:
pts = [[0.1, 0.75], [0.78, 0.18]]
f_vec = np.zeros(Z.dim())
for pt in pts:
f_vec += np.array([f_u(i,pt) for i in range(Z.dim())])
f_vec += np.array([f_theta(i,pt) for i in range(Z.dim())])
f=Function(Z)
f.vector()[:] = f_vec