co-normal value on a 1D surface segment

More
3 years 4 months ago #3852 by Guosheng Fu
Hi Michael,

Please see the attached minimal example where I use the 1D normal. I need it for the evaluation of the element boundary of surface segments (codim 2). For this purpose, the co-normal shall (consistently) take -1 on the left end point and +1 on the right end point, which was what the gfn trying to do in the code.
I can not make it work using the consistent tangential vector
Code:
from ngsolve import * from ngsolve.meshes import MakeStructured2DMesh N = 4 mesh = MakeStructured2DMesh(nx=N, ny=1, mapping=lambda x, y: (x, y/N)) gfn = GridFunction(Compress(SurfaceL2(mesh, order=1, definedon=mesh.Boundaries("bottom")))) count = 0 for e in mesh.Elements(BND): if e.mat=="bottom": if e.vertices[0].nr > e.vertices[1].nr: gfn.vec[2*count+1] = -1 else: gfn.vec[2*count+1] = 1 count += 1 n = specialcf.normal(2) # HDiv interpolation gfInterp = GridFunction(HDiv(mesh, order=1)) gfInterp.Set(gfn*n, definedon=mesh.Boundaries("bottom")) Draw(gfInterp[1], mesh) ## V = Compress(H1(mesh, definedon=mesh.Boundaries("bottom"))) u,v = V.TnT() t = specialcf.tangential(2) t1 = specialcf.tangential(2, consistent=True) f = LinearForm(V) # This works f += t*t1*v*ds(element_boundary=True, definedon=mesh.Boundaries("bottom")) # f += gfn*v*ds(element_boundary=True, definedon=mesh.Boundaries("bottom")) f.Assemble() print(f.vec)

Best,
Guosheng
More
3 years 4 months ago #3855 by mneunteufel
Hi Guosheng,

yes, you are right, there is a detail missing for the consistent tangential vector for 1D manifolds.

Until this is fixed you can rotate the normal vector, which does not change from element to element.
Code:
n = specialcf.normal(2) t1 = CF( (-n[1],n[0]) )
With this I got the correct results for your minimal example.

Best,
Michael
More
3 years 4 months ago #3856 by joachim
Hi Guosheng,

we can now access Jacobians, and the coordinates from the reference element via special CoefficientFunctions (thx to Michael). This allows to build the co-normal vector.

The Logging - CoefficientFunction is useful to inspect the function evaluations.

- Joachim

Code:
from netgen.geom2d import unit_square from ngsolve import * mesh = Mesh(unit_square.GenerateMesh(maxh=0.3)) fes = SurfaceL2(mesh, order=1) u,v = fes.TnT() f = LinearForm(fes) t = specialcf.tangential(2) jac = specialcf.JacobianMatrix(2,1)[:,0] xref = specialcf.xref(1) conormal = (2*xref[0]-1)*jac from ngsolve.fem import LoggingCF conormal = LoggingCF (conormal) f += conormal*t *v * ds("bottom", element_boundary=True) f.Assemble()
More
3 years 4 months ago #3862 by Guosheng Fu
Thanks!
I've now moved to a 3D mesh with a embedded 2D surface. I use mixed FEM to discrete a Laplace operator on the surface.
The following test case does not work: mesh is a unit cube, and the "flat surface" is simply its top boundary.
I use HDivSurface/SurfaceL2 spaces to build the finite element pair on "top" boundary, but it seems that I can not use these spaces directly here as the bilinear form assembler complained about inconsistent # of DOFs. Any idea what's going on?!
Code:
from ngsolve.meshes import MakeStructured3DMesh from ngsolve import * mesh = MakeStructured3DMesh(hexes=False, nx=10, ny=10, nz=2) V = Compress(HDivSurface(mesh, order=1, definedon=mesh.Boundaries("top"))) W = Compress(SurfaceL2(mesh, order=0, definedon=mesh.Boundaries("top"))) fes = V*W (u, p), (v, q) = fes.TnT() a = BilinearForm(fes) a += (u.Trace()*v.Trace()-div(u).Trace()*q.Trace()-p.Trace()*div(v).Trace())*ds("top") a.Assemble()
More
3 years 4 months ago #3863 by mneunteufel
Hi Guosheng,

a definedon-check was missing in the HDivSurface, should be fixed in the next nightly-build.

Best,
Michael
More
3 years 4 months ago #3865 by Guosheng Fu
Hi Michael,

Thanks for the very quick fix. I will check it out.
Also, I just realized that your co-normal is not exactly what I am looking for... I haven't express the problem clear enough. In the attached file, I depicted what I want: a scalar function a 1D surface mesh that acts exactly as the 1D normal direction for a plain 1D mesh, that is, given an orientation of the line segment, it should return a -1 on the left end of the segment and +1 on the right end of segment. (I don't think it should be called a co-normal as it is a lower dimensional quantity)... Since I couldn't function such a built-in function, the above surfaceL2 gridfunction gfn is a hacker that do the job.

Since the tangential/normal directions are quantities defined on edges, not vertices, the associated value on left/right endpoints of the segments will always be the same, which is not what I want.

*** More background: I use this "co-normal" to reinforce nodal continuity of a SurfaceL2 function:
Code:
# u is a surface L2 trial function # v is a H1 trial function # this bilinearform shall return nodal continuity of u (hybridized!) a += u*v*con*ds(element_boundary=True)

This has been a very fruitful discussion! Thanks again for the quick responses.


This browser does not support PDFs. Please download the PDF to view it: Download PDF



Best,
Guosheng
Attachments:
Time to create page: 0.111 seconds