Boundary conditions of newly added csg.CSGeometry is automatically merged

Hi, I post an error of netgen here: bc and mat will be erroneous merged in netgen.csg · Issue #49 · NGSolve/netgen · GitHub

I want to add 2 small cylinders (electrodes) to 1 big cylinder, the boundary conditions are set on the outer surface of the small cylinder. However, If I place them at the same z axis with 0.5 spacing, the bc will be automatically merged. If I offset 1 small cylinder with theta=theta+0.01, then its bc will be preserved. Any hint on this issue?

import numpy as np
from netgen import csg
from ngsolve.comp import Mesh


def cylinder(p0, p1, unit_vec, r, bc="bc"):
    """ a pointed cylinder (numpy interface) """
    # generate CSG primitives
    csg_p0 = csg.Pnt(p0[0], p0[1], p0[2])
    csg_p1 = csg.Pnt(p1[0], p1[1], p1[2])
    csg_vec = csg.Vec(unit_vec[0], unit_vec[1], unit_vec[2])

    # generate cylinder shape
    bot = csg.Plane(csg_p0, -csg_vec)
    top = csg.Plane(csg_p1, csg_vec)
    cy_surface = csg.Cylinder(csg_p0, csg_p1, r)

    # specify bc on top
    top.bc(bc)

    # geo
    cy = top * cy_surface * bot

    return cy


def unit_cylinder(h=1.0, r=0.5, bc="cyl"):
    """ scaled unit z-axis cylinder """
    p0 = [0, 0, 0]
    p1 = [0, 0, h]
    unit_vec = [0, 0, 1]
    return cylinder(p0, p1, unit_vec, r, bc)


def electrode_cylinder(p0=[0, 0, 0], unit_vec=[1, 0, 0], shape=[0.1, 0.1],
                       bc="e0"):
    """
    cylinder electrode (numpy interface)

    shape: NDArray
        [radius, thickness]
    """
    r, thick = shape
    # calculate the center of the other face
    p1 = np.asarray(p0) + thick * np.asarray(unit_vec)

    # generate cylinder electrode with annotation
    ele = cylinder(p0, p1, unit_vec, r, bc)
    ele.mat('agcl')

    return ele


def cylinder_with_electrodes():
    """ [test only, will be deleted] """
    h = 1.0
    r = 0.5
    g0 = unit_cylinder(h=h, r=r)
    g0.mat('g0')

    # generate cylinder electrode
    ele_shape = [0.1, 0.1]  # radius, thick
    thick = ele_shape[1]
    ele_pos = [30, h/2.0]  # angle (degree), z

    # infer locations
    rad = ele_pos[0] * 2 * np.pi / 360.0
    unit_vec = np.array([np.cos(rad), np.sin(rad), 0])
    # warning: a thin contact of electrode with domain will cause
    # netgen failed to generate proper mesh
    p0 = (r - thick/2.0)*unit_vec
    p0[2] = ele_pos[1]

    # place 1st electrode
    ele = electrode_cylinder(p0, unit_vec, shape=ele_shape, bc="e0")
    # geo = g0 + ele

    # place 2nd electrode
    p0[2] += 0.25
    # p0[0] += 0.01  # <-- https://github.com/NGSolve/netgen/issues/49
    ele2 = electrode_cylinder(p0, unit_vec, shape=ele_shape, bc="e1")
    # geo = geo + ele2
    ele = ele - g0
    ele2 = ele2 - g0

    return g0, ele, ele2


if __name__ == "__main__":
    g, ele, ele2 = cylinder_with_electrodes()
    geo = csg.CSGeometry()
    geo.Add(g)
    geo.Add(ele)
    geo.Add(ele2)

    ngmesh = geo.GenerateMesh(maxh=0.1)

    mesh = Mesh(ngmesh)
    # mesh.Curve(3)

    print(mesh.GetBoundaries())
    print(mesh.GetMaterials())

Hi liubenyuan,

there is the possiblity to tell NETGEN to use the correct boundary condition by using the bcmod flag

geo.Add (cyl, bcmod=[(plane,'bc')])

The attached code demonstrates this for the example of a simple cube “in a cube”.

Best,
Michael

https://ngsolve.org/media/kunena/attachments/889/bc_mod.py

Attachment: bc_mod.py

But in order to use bcmod, you should keep top2 within you scope, right?
I need to generate some elementary volumetric shapes, these shapes are the domain to be computed. And then add some electrodes around it, which is written in a separate function, calls csg codes. Is there any other way in doing this?

Thank you. I use your method, and the function electrode_cylinder is now returning both a CSGeometry and its top surface. The bcs are correctly setup using bcmod.

https://github.com/liubenyuan/netgen-note/blob/master/examples/csg_issue_bc_cyl.py

But, why the bc is merging in the original code? Do I have to manually set the bc using bcmod every time using CSG?

Hi, Michael

Your solution using bcmod works for me. But I would like to know, in the function def cylinder_with_electrodes(), line 26, If I set a small offset p0[0] += 0.01, both the bcs of ele1 and ele2 will be kept. But when I comment this line out, the bcs of ele1 and ele2 are merged. Is it a feature of netgen or is it an issue?

Best.

Benyuan

This isn’t a feature, but has historic reasons. It is on the radar to fix this when someone got time to clean that code up.
Basically Netgen detects same objects and uses only the first, this leads to the wrong boundary condition.