I am trying to use Dolfinx Expression to evaluate a UFL expression at an arbitrary point inside of a mesh. I have had a look at various examples, but I cannot seem to get it to work. The present code worked for evaluating the solution directly, but the UFL expression does not work. What am I doing incorrectly?
import sys
import numpy as np
from scipy import optimize as opt
from scipy import special as sp
from mpi4py import MPI as nMPI
from petsc4py import PETSc
import gmsh
import meshio
import ufl
import basix.ufl
from dolfinx.mesh import locate_entities_boundary, meshtags
from dolfinx.io import gmshio
from dolfinx import fem
from dolfinx.fem.petsc import LinearProblem
from dolfinx import io
from dolfinx import geometry
eps = 1.0e-4 # Geometric tolerance
class Hinc:
def __init__(self, kc, H):
self.kc = kc
self.H = H
def eval(self, x):
hy = self.H * np.sin(self.kc * x[1])
hx = np.full_like(hy, 0.0+0.0j, dtype=np.complex128)
hz = np.full_like(hy, 0.0+0j, dtype=np.complex128)
return(hx, hy, hz)
def Model(x):
comm = nMPI.COMM_WORLD
mpiRank = comm.rank
modelRank = 0
a = 2.286 # WR90 width (all dims in cm)
b = 1.016 # WR90 height
r = 1.115 # Circ WG radius
l1 = 2.0 # WR90 length
l2 = 2.0 # Circ WG length
k = 2.0 * np.pi * x[0] / 3.0e10
eta0 = 377.0
kc = 1.84 / r
kr = np.pi / a
beta_c = np.sqrt(k * k - kc * kc) # circ WG imp
beta_r = np.sqrt(k * k - kr * kr) # rect WG imp
lm = 0.3
ls = 0.3
Plot = 1
if mpiRank == modelRank:
gmsh.initialize()
gmsh.option.setNumber('General.Terminal', 1)
gmsh.model.add('WG Transition')
gmsh.model.occ.addBox(-b/2, 0, -r-l1, b, a, r+l1, 1)
gmsh.model.occ.addCylinder(0, 0, 0, 0, l2+a, 0, r, 2, 2*np.pi)
gmsh.model.occ.fuse([(3,1)],[(3,2)], 3, removeObject=True, removeTool=True)
gmsh.model.occ.addBox(0, 0, -l1, r, l2+a, l1+2*r, 4)
gmsh.model.occ.intersect([(3,3)], [(3,4)], 1, removeObject=True, removeTool=True)
gmsh.model.occ.synchronize()
pt = gmsh.model.getEntities(dim=0)
gmsh.model.mesh.setSize(pt, lm)
pt = gmsh.model.getEntitiesInBoundingBox(b/2-eps, -eps, -r-eps, b/2+eps, a+eps, eps)
gmsh.model.mesh.setSize(pt, ls)
pt
gmsh.option.setNumber('Mesh.MeshSizeMin', 0.01)
gmsh.option.setNumber('Mesh.MeshSizeMax', 1.2)
gmsh.option.setNumber('Mesh.Algorithm', 6) #1=Mesh Adapt, 2=Auto, 3=Initial mesh only, 5=Delaunay, 6=Frontal-Delaunay
gmsh.option.setNumber('Mesh.MshFileVersion', 2.2)
gmsh.option.setNumber('Mesh.Format', 1)
gmsh.option.setNumber('Mesh.MinimumCirclePoints', 30)
gmsh.option.setNumber('Mesh.CharacteristicLengthFromCurvature', 1)
gmsh.option.setNumber('Mesh.Tetrahedra', 0)
bb = gmsh.model.getEntities(dim=3)
pt = gmsh.model.getBoundary(bb, combined=True, oriented=False, recursive=False)
WR90Port = []
CircWGPort = []
PEC = []
PMC = []
NoPMC = 1
for bnd in pt:
CoM = gmsh.model.occ.getCenterOfMass(bnd[0], bnd[1])
if np.abs(CoM[0]) < eps and NoPMC == 0:
PMC.append(bnd[1])
elif np.abs(CoM[2] + l1) < eps:
WR90Port.append(bnd[1])
elif np.abs(CoM[1] - l2 - a) < eps:
CircWGPort.append(bnd[1])
else:
PEC.append(bnd[1])
gmsh.model.addPhysicalGroup(3, [1], 1) # Wg interior
gmsh.model.setPhysicalName(3, 1, "WG Interior")
gmsh.model.addPhysicalGroup(2, PEC, 1)
gmsh.model.setPhysicalName(2, 1, "PEC")
gmsh.model.addPhysicalGroup(2, PMC, 2)
gmsh.model.setPhysicalName(2, 2, "PMC")
gmsh.model.addPhysicalGroup(2, WR90Port, 3)
gmsh.model.setPhysicalName(2, 3, "InPort")
gmsh.model.addPhysicalGroup(2, CircWGPort, 4)
gmsh.model.setPhysicalName(2, 4, "Circ WG Port")
gmsh.model.mesh.generate(3)
# gmsh.fltk.run()
mesh, ct, fm = gmshio.model_to_mesh(gmsh.model, comm, modelRank, gdim=3)
if mpiRank == modelRank:
gmsh.finalize()
mesh.topology.create_connectivity(mesh.topology.dim-1, mesh.topology.dim)
elem = basix.ufl.element('Nedelec 1st kind H(curl)', mesh.basix_cell(), degree=2)
V = fem.functionspace(mesh, elem)
u = ufl.TrialFunction(V)
v = ufl.TestFunction(V)
n = ufl.FacetNormal(mesh)
ds = ufl.Measure("ds", domain=mesh, subdomain_data=fm)
# Dirichlet BCs on PECs
facets = fm.find(1)
ubc = fem.Function(V)
ubc.interpolate(lambda x:np.array([0*x[0], 0*x[1], 0*x[2]], dtype=np.complex128))
dofs = fem.locate_dofs_topological(V, mesh.topology.dim-1, facets)
bc = fem.dirichletbc(ubc, dofs)
# Build RHS
uh = fem.Function(V, dtype=np.complex128)
f = Hinc(kr, 1.0+0j)
uh.interpolate(f.eval)
finc = 2.0j * k * eta0 * ufl.inner(ufl.cross(n, uh), v) * ds(3)
uh.name = "Hinc"
# Weak form
L = (ufl.inner(ufl.curl(u), ufl.curl(v)) - k * k * ufl.inner(u, v)) * ufl.dx
# Outgoing at inport
bc1 = 1j * beta_r * ufl.inner(ufl.cross(n, u), ufl.cross(n, v)) * ds(3)
L += bc1
# Circ WG boundary
bc2 = 1j * beta_c * ufl.inner(ufl.cross(n, u), ufl.cross(n, v)) * ds(4)
L += bc2
num_dofs_local = V.dofmap.index_map.size_local * V.dofmap.index_map_bs
num_dofs_global = V.dofmap.index_map.size_global * V.dofmap.index_map_bs
print(f"Number of dofs (owned) by rank {mpiRank}: {num_dofs_local}")
if mpiRank == modelRank:
print(f"Number of dofs global: {num_dofs_global}")
# Solve system of equations
Lin_system = LinearProblem(L, finc, bcs=[bc], petsc_options={"ksp_type":"preonly", "pc_type":"lu"})
E = Lin_system.solve()
# Try out the point evaluation
bb_tree = geometry.bb_tree(mesh, mesh.topology.dim)
points = np.array([[eps, l2+a-eps, 0.0], [r/2, l2+a-eps, 0.0]])
potential_colliding_cells = geometry.compute_collisions_points(bb_tree, points)
colliding_cells = geometry.compute_colliding_cells(mesh, potential_colliding_cells, points)
points_on_proc = []
cells = []
for i, pp in enumerate(points):
if len(colliding_cells.links(i)) > 0:
points_on_proc.append(pp)
cells.append(colliding_cells.links(i)[0])
p_proc = np.array(points_on_proc, dtype=np.float64).reshape(-1, 3)
St = fem.Expression(ufl.cross(ufl.conj(E), ufl.curl(E)), points)
u_val = St.eval(p_proc, cells) / (1.0j * k * eta0)
print(p_proc, u_val)
return np.real(Pinc - Pref)
Model([1.0e10])
I get the following error.
Traceback (most recent call last):
File "/home/bill/Cluster/Fenics2020/FeedHorn/WR90CircTransition.py", line 204, in <module>
Traceback (most recent call last):
File "/home/bill/Cluster/Fenics2020/FeedHorn/WR90CircTransition.py", line 204, in <module>
Model([1.0e10])
File "/home/bill/Cluster/Fenics2020/FeedHorn/WR90CircTransition.py", line 200, in Model
u_val = St.eval(p_proc, cells) / (1.0j * k * eta0)
File "/usr/lib/petscdir/petsc3.15/x86_64-linux-gnu-complex/lib/python3/dist-packages/dolfinx/fem/function.py", line 222, in eval
Model([1.0e10])
File "/home/bill/Cluster/Fenics2020/FeedHorn/WR90CircTransition.py", line 200, in Model
if (tdim := mesh.topology.dim) != (expr_dim := self._cpp_object.X().shape[1]):
AttributeError: 'numpy.ndarray' object has no attribute 'topology'