Hi,
I have a 2D axi-symmetric problem in which I cannot get the expected behavior of the FacetNormal vector. Below is a simple MWE in which I consider a semi-circle in a rectangular box. I want to integrate the normal vector to the circle on the circle’s circumference. I evaluate it using FacetNormal vector as well as by defining the surface normal by hand. The latter gives correct result that I can easily work out on paper too. But using the FacetNormal vector I get numbers which do not make sense at all. Below is a simple MWE that works it out:
# This script contains an MWE to show that normal vector to the surface is not correct
import dolfinx, gmsh, mpi4py, ufl
from dolfinx.io import gmshio
#%% create geometry
sph_R = 0.3 # radius of sphere
xc, yc = 0.0, 0.9 # location of sphere's center on vertical axis
gmsh.initialize()
gmsh.clear()
occ = gmsh.model.occ
gdim = 2
# displace the circle along y-axis
circ = occ.addDisk(xc, yc, 0, sph_R, sph_R)
cut_box = occ.add_rectangle(xc-sph_R, yc-sph_R, 0, sph_R, 2*sph_R)
occ.synchronize()
half, _ = occ.cut([(gdim, circ)], [(gdim, cut_box)])
box = occ.add_rectangle(0, yc-2*sph_R, 0, 2*sph_R, 4*sph_R)
final = occ.fragment([(gdim, box)], half)
occ.synchronize()
all_doms = gmsh.model.getEntities(gdim)
for j, dom in enumerate(all_doms):
gmsh.model.addPhysicalGroup(dom[0], [dom[1]], j+1)
all_edges = gmsh.model.getEntities(gdim-1)
for j, edge in enumerate(all_edges):
gmsh.model.addPhysicalGroup(edge[0], [edge[1]], edge[1])
gmsh.model.mesh.generate(gdim)
gmsh.model.mesh.refine()
model_rank = 0
mesh, ct, ft = gmshio.model_to_mesh(gmsh.model, mpi4py.MPI.COMM_WORLD, model_rank, gdim)
# gmsh.fltk.run()
gmsh.finalize()
#%% Evaluate integrals
r, z = ufl.SpatialCoordinate(mesh) # let's call horizontal axis as r and vertical z
n = ufl.FacetNormal(mesh) # numerical normal vector
n_an = ufl.as_vector((r/sph_R, (z-yc)/sph_R)) # analytical normal vector
dS = ufl.Measure('dS', domain=mesh, subdomain_data=ft)
sph_bnd_idx = (2, 3)
integrand = dolfinx.fem.form(n_an[0]* dS(sph_bnd_idx)) # outer boundaries
val1 = dolfinx.fem.assemble.assemble_scalar(integrand)
integrand = dolfinx.fem.form(n('-')[0]* dS(sph_bnd_idx)) # outer boundaries
val2 = dolfinx.fem.assemble.assemble_scalar(integrand)
print("Line integral of analytical nr = {}, Line integral of numerical nr = {}".format(val1, val2))
integrand = dolfinx.fem.form(n_an[1]* dS(sph_bnd_idx)) # outer boundaries
val3 = dolfinx.fem.assemble.assemble_scalar(integrand)
integrand = dolfinx.fem.form(n('-')[1]* dS(sph_bnd_idx)) # outer boundaries
val4 = dolfinx.fem.assemble.assemble_scalar(integrand)
print("Line integral of analytical nz = {}, Line integral of numerical nz = {}".format(val3, val4))
I also notice that the result with FacetNormal nz (i.e. n[1] along vertical axis) actually corresponds to the correct answer I should have gotten from n[0] and vice versa. I am unsure if it is a coincidence.
Thanks a lot for help!