Maxwell eigenvalue problem in cylindrical coordinates


I am trying to solve Maxwell eigenvalue problem for a cavity resonator. I followed the tutorial i the documentation on the solution to the maxwell eigenvalue problem because my problem has the same weak form. My geometry, however, is symmetric in the azimuthal coordinate i.e. the 3D geometry is the revolution of some face. Because of azimuthal symmetry of the fields, the problem can be reduced to a 2D problem. My question is, is there a way to specify to that the Fes or Curl should be in cylindrical coordinates?

Secondly, I have the geometry for the 2D face. Is there a way to revolve this face to get a 3D object? Thanks in advance.

You need to write the axisymmetrical variational formulation “in code”. So basically a *x in integrals and operators in axisymmetrical form.

Yes you can revolve a 2D shape using netgen-occ:

shape.Revolve(Axix((0,0,0),Y), 360)

Thanks a lot for your reply. I have now done this. Although I don’t have the correct eigenmodes yet, I think that there is a problem with my formulation of the variational form.

I tried rotating the 2D shape and got this error: ‘netgen.libngpy._geom2d.SplineGeometry’. Apologies, I am not yet too familiar with the different objects.

not geom2d, with occ, here at the bottom there is an example:

if you post a minimal example maybe we can help.

geo = SplineGeometry()
# get cavity geometry
cav_geom = pd.read_csv('geodata.n')  # array of points that define the contour of the geometry

pnts = list(cav_geom.itertuples(index=False, name=None))
pts = [geo.AppendPoint(*pnt) for pnt in pnts]

curves = [ ]  # list
for count in range(1, len(pts)):
    curves.append([["line", pts[count-1], pts[count]], f"l{count}"])
    # add last point to first
    if count+1 == len(pts):
        curves.append([["line", pts[count], pts[0]], f"l{0}"])

[geo.Append(c) for c, bc in curves];

This is what I have for the geometry. I then go ahead to mesh the geometry using

ngmesh = geo.GenerateMesh(maxh=0.05)
mesh = Mesh(ngmesh)

I have attached the mesh

In this case, I would like to rotate the face 180 deg. I could as well define only a half of the face and revolve 360 degs.

To create a 3d geometry you’ll need to use the opencascade interface (the old geom2d doesn’t support that). you can use
netgen.occ.SplineApproximation or netgen.occ.SplineInterpolation for a bspline curve. This can then be revolved

Thanks a lot. It works!
However, I get this revolving the bottom profile (points plotted using matplotlib) in the following figure.

Is there another ‘Spline____’ , method that neither interpolates nor approximates the geometry? The input points are the exact representation of the model and I would like the points to be connected using straight lines instead of interpolated over.

There is a BSplineCurve with a suspicious comment in the code:

  m.def("BSplineCurve", [](std::vector<gp_Pnt> vpoles, int degree) {
      // not yet working ????

what I remember is that the start and endpoints are not duplicated correctly. But I think for order=1 this should work.


geo = BSplineCurve(pnts, 1)

I got the following image

instead of

Ah sorry, what you want to do is easier with a workplane:

wp = WorkPlane()
for p in pnts[1:]:
face = wp.Face()

with pnts a list of points in 2d plane. Note that orientation of the curve plays a role in defining inside and outside, so you might need to .Reverse() the curve afterwards

To do 2d simulations on this put this face into a OCCGeometry object with dim argument:

geo2d = OCCGeometry(face, dim=2)

for 3d revolve it and drop the dim argument (dim=3 is default)

Thanks a whole lot. This gives me exactly what I want. And thanks for the heads-up about the .Reverse(), it probably would have been my next question.

I tried looking at the documentation for OCCGeometry but couldn’t figure out what ‘dim’ means.

I don’t understand what you mean by “drop the dim argument”.

Hello, this may be something trivial, and I may have missed it while going through the documentation, but I could not find how to apply boundary conditions to the WorkPlane object. I want to apply a Dirichlet boundary condition to the contour of the WorkPlane except for the bottom and the sides.

I used the following as a test and printed the FreeDofs.
fes = HCurl(mesh, order=3, dirichlet=[1, 2, 3, 4, 5, 6, 7, 8, 9])

However, I don’t know at what point (during the creation of the face, mesh? or the fes?) to give names to the boundaries or how to go about it. I would appreciate any help on this.

I was able to name the boundary edges using

# name the boundaries
face.edges.Max(X).name = "r"
face.edges.Min(X).name = "l"
face.edges.Min(Y).name = "b"

where face is a WorkPlane object.

I could not name the top part using

face.edges.Max(Y).name = "t"

because it consists of so many edges. This is not a problem for me since the top contour is the ‘rest’ of the edges in the WorkPlane object.

you can name it with

face.edges[Y > value]

with value some value where center of edge is larger than the value

Thanks. Got it. And how do I set the Dirichlet boundary condition on these edges?

Thanks for your help so far. This is my code currently:

cav_geom = pd.read_csv('geodata.n')  # reads the geometry contour points
pnts = list(cav_geom.itertuples(index=False, name=None))

wp = WorkPlane()
for p in pnts[1:]:
face = wp.Face()

# name the boundaries
face.edges.Max(X).name =  "r"
face.edges.Max(X).col = (1,0,0)
face.edges.Min(X).name = "l"
face.edges.Min(X).col = (1,0,0)
face.edges.Min(Y).name = "b"
face.edges.Min(Y).col = (1,0,0)

geo = OCCGeometry(face, dim=2)

# mesh
ngmesh = geo.GenerateMesh(maxh=0.05)
mesh = Mesh(ngmesh)

# fes
fes =  HCurl(mesh, order=3, dirichlet='default')   #<- I set the Dirichlet boundary condition here, but it does not have any effect

mu0 = 4*pi*1e-7
c0 = 299792458
u, v = fes.TnT()

a = BilinearForm(y*curl(u)*curl(v)*dx)
m = BilinearForm(y*u*v*dx)

apre = BilinearForm(y*curl(u)*curl(v)*dx + y*u*v*dx)
pre = Preconditioner(apre, "direct", inverse="sparsecholesky")

with TaskManager():

    # build gradient matrix as sparse matrix (and corresponding scalar FESpace)
    gradmat, fesh1 = fes.CreateGradient()

    gradmattrans = gradmat.CreateTranspose() # transpose sparse matrix
    math1 = gradmattrans @ m.mat @ gradmat   # multiply matrices
    math1[0, 0] += 1     # fix the 1-dim kernel
    invh1 = math1.Inverse(inverse="sparsecholesky")

    # build the Poisson projector with operator Algebra:
    proj = IdentityMatrix() - gradmat @ invh1 @ gradmattrans @ m.mat

    projpre = proj @ pre.mat

    evals, evecs = solvers.PINVIT(a.mat, m.mat, pre=projpre, num=5, maxit=20);

I have not been able to figure out how to set a value, say 5 or 10, on these edges.

have a look into the docu:
1.3 Dirichlet boundary conditions

I already looked but will have a look once more to try and figure it out. Thanks once again.

Hello Christopher. I switched to solving the MEVP on a simpler geometry because I have problems meshing my geometry. I think that the geometry has too many points. One option would be to write the geometry generator using ngsolve’s native geometry builder with lines and ellipse sections. However, I wonder if there is a way to convert the input geometry to a smooth solid block before meshing.

For the simpler geometry (a square and a circle), solving the MEVP for H returns the correct TM eigenmodes. For curl curl E, however, the Dirichlet BC has to be enforced. When I do this, some modes are not calculated. On a careful observation and comparison with results from another software, I noticed that the missing TE modes are those that have a non-vanishing component, which makes me think that the Dirichlet condition applied is \mathbf{u}=0 instead of \mathbf{n} \times \mathbf{u}=0. See the comparison plots below for a circle (first 20 modes calculated, + represents numerical solution).

curl curl H

curl curl E

How do I enforce just \mathbf{n} \times \mathbf{u}=0 in ngsolve?