Hi,
I have a problem where I need to use the co-normal to a surface boundary in order to find a weak version of the (vector) mean curvature. An example code is given below
from ngsolve import *
from netgen.csg import *
from netgen.meshing import MeshingStep
from ngsolve.webgui import Draw
geo = CSGeometry()
sphere = Sphere(Pnt(0,0,0), 1)
bot = Plane(Pnt(0,0,0), Vec(0,0,-1))
finitesphere = sphere * bot
geo.AddSurface(sphere, finitesphere.bc("surface"))
geo.NameEdge(sphere,bot, "bottom")
mesh = Mesh(geo.GenerateMesh(maxh=0.1))
V1 = VectorH1(mesh, order=1, definedon=mesh.Boundaries("surface"))
nu = specialcf.normal(mesh.dim)
Ps = Id(mesh.dim) - OuterProduct(nu, nu)
tang = specialcf.tangential(mesh.dim)
xsi = CF((0, 0, -1))
# xsi = CF((0, 0, -sqrt(tang[0]**2+tang[1]**2))) also works
(kappa, eta) = V1.TnT()
M = BilinearForm(V1)
l = LinearForm(V1)
M += kappa*eta*ds
M.Assemble()
l += -InnerProduct(Ps, Grad(eta).Trace())*ds
l += InnerProduct(xsi, eta)*ds(definedon=mesh.BBoundaries("bottom"))
l.Assemble()
kappa_h = GridFunction(V1)
kappa_h.vec.data = M.mat.Inverse(V1.FreeDofs())*l.vec
Draw(kappa_h)
I tried to use
xsi = Cross(tang, nu)
but the result is a zero Coefficient Function. What should I do in order to get that co-normal working no matter the shape of the boundary? Is there some specific CF I am not aware? Or should I use other CFs like specialcf.JacobianMatrix(3,) and special.xref() to compute it manually by rotating tang?
Thanks a lot for any help.
Best,
Alessandro
Hi Alessandro,
The surface’s normal vector is not well-defined on the co-dimension two boundary. It is therefore zero.
You can use an indicator function being 1 only on the specific edges
gfF = GridFunction(FacetSurface(mesh, order=0))
gfF.Set(1, definedon=mesh.BBoundaries("bottom"))
and use it in combination with element_boundary=True. It loops over all surface elements, and for each element, it loops over its boundaries
xsi = Cross(nu, tang)
l += InnerProduct(xsi, eta) * gfF * ds(element_boundary=True)
Please note, that the edges will be evaluated from both sides, computing a ‘‘jump’’. If you want it only from one boundary you can use an additional indicator function via the L2Surface space.
Best,
Michael
1 Like
Thanks a lot for the quick answer, works perfectly!
Best,
Alessandro
I have been trying to extend the above to 1D open line in 2D without success, any tip?
I tried:
- using the FacetSurface, but the code crashes.
- using Nodal spaces but it says there are no evaluators for bbnd
- Using :
jac = specialcf.JacobianMatrix(2,1)[:,0]
xref = specialcf.xref(1)
conormal = (2*xref[0]-1)*jac
as discussed in previous questions together with different integrations on the bboundary or on the boundary done elementwise.
Thanks a lot,
Alessandro
Hi Alessandro,
in 2D most spaces become either H1 or L2 and so some spaces are not implemented in 1D. The specialcf.tangential takes the role of the co-normal vector for 1D domains.
The indicator function can be constructed using an H1-GridFunction, setting the corresponding vertex dofs to 1.
Best,
Michael
1 Like
Yes, I see, I was eventually able to figure it out but forgot to update this. Thanks a lot for the help!