Is the point going to align with a degree of freedom, or can it be at an arbitrary position in your domain?
You can consider something along the lines of:
from mpi4py import MPI
import dolfinx
import ufl
import numpy as np
comm = MPI.COMM_WORLD
mesh = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, 10, 10)
def determine_ownership_and_pull_back(mesh, points):
tol = float(1e2 * np.finfo(points.dtype).eps)
if dolfinx.__version__ == "0.8.0":
_, _, recv_points, cells = dolfinx.cpp.geometry.determine_point_ownership(
mesh._cpp_object, points, tol
)
recv_points = np.array(points).reshape(-1, 3)
elif dolfinx.__version__ == "0.9.0.0":
collision_data = dolfinx.cpp.geometry.determine_point_ownership(
mesh._cpp_object, points, tol
)
recv_points = collision_data.dest_points
cells = collision_data.dest_cells
else:
raise RuntimeError("Unsupported version of dolfinx")
mesh_nodes = mesh.geometry.x
cmap = mesh.geometry.cmap
ref_x = np.zeros((len(cells), mesh.topology.dim), dtype=mesh.geometry.x.dtype)
for i, (point, cell) in enumerate(zip(recv_points, cells)):
geom_dofs = mesh.geometry.dofmap[cell]
ref_x[i] = cmap.pull_back(point.reshape(-1, 3), mesh_nodes[geom_dofs])
return cells, ref_x
V = dolfinx.fem.functionspace(mesh, ("Lagrange", 2))
u = dolfinx.fem.Function(V)
u.interpolate(lambda x: x[0]**2 + np.sin(x[1]))
if MPI.COMM_WORLD.rank == 0:
points = np.array([[0.5, 0.5,0], [0.3, 0.2,0]], dtype=np.float64)
else:
points = np.empty((0, 3), dtype=np.float64)
cells, ref_x = determine_ownership_and_pull_back(mesh, points)
grad_u = ufl.grad(u)
mag_grad = ufl.sqrt(ufl.inner(grad_u, grad_u))
u_comp = grad_u[0]
for ufl_expr in [grad_u, mag_grad, u_comp]:
for cell, point in zip(cells, ref_x):
expr = dolfinx.fem.Expression(ufl_expr,point, comm=MPI.COMM_SELF)
print(str(ufl_expr), cell, point, expr.eval(mesh, np.array([cell], dtype=np.int32)))
if you just want to do it at a small subset of points.
To get individual components you can do u.sub(i).collapse()
to get that single component.