gmsh and FreeFem++

gmsh and FreeFem++#

[1]:
import matplotlib.pyplot as plt

%matplotlib inline
%config InlineBackend.figure_format='retina'
[2]:
from zeroheliumkit import Structure, Rectangle, Square, Ring, Circle, Layer
from zeroheliumkit.src.settings import GRAY, BLUE, YELLOW2
from zeroheliumkit.src.plotting import ColorHandler
[3]:
save_dir = "dump"
[4]:
### Creating geometry
[5]:
device = Structure()
device.add(Layer("wafer", Square(20)))
device.add(Layer("gnd", Square(20)))
device.gnd.cut(Rectangle(3, 9))
device.gnd.cut(Rectangle(9, 3))
device.gnd.cut(Rectangle(9, 3, (0,5)))
device.add(Layer("bottom", Circle(3)))
device.bottom.add(Ring(3.5, 8))
device.add(Layer("etch", Square(20)))
device.etch.cut(device.gnd.polygons)

device.bottom.remove_holes()
device.gnd.remove_holes()

device.colors = ColorHandler({
    "wafer": GRAY,
    "bottom": YELLOW2,
    "gnd": (BLUE, 0.85)
})
device.quickplot(size="medium", show_idx=True)
[5]:
<Axes: >
../_images/notebooks_gmshfem_5_1.png
[6]:
### Creating Mesh
[7]:
from zeroheliumkit.fem import GMSHmaker, ExtrudeSettings, MeshSettings, PECSettings, BoxFieldMeshSettings
[8]:
# extrude parameters
d_wafer     = 10
d_metal1    = 0.2
d_metal2    = 0.1
d_diel      = 1.5
d_vac       = 20
d_He        = d_diel + d_metal2
[9]:
Volumes = {
    'wafer':        ExtrudeSettings(device.wafer.polygons, -d_wafer, d_wafer, 'DIELECTRIC'),
    'trap':         ExtrudeSettings(device.bottom.polygons, 0, d_metal1, 'METAL'),
    'dielectric':   ExtrudeSettings(device.gnd.polygons, 0, d_diel, 'DIELECTRIC', ('trap',)),
    'top':          ExtrudeSettings(device.gnd.polygons, d_diel, d_metal2, 'METAL'),
    'helium':       ExtrudeSettings(device.wafer.polygons, 0, d_He, 'HELIUM', ('trap', 'dielectric','top')),
    'vacuum':       ExtrudeSettings(device.wafer.polygons, d_He, d_vac, 'VACUUM', ('dielectric', 'top'))
}

PECs = {
    'mid':   PECSettings(device.bottom.polygons, [0], volume=Volumes['trap']),
    'out':   PECSettings(device.bottom.polygons, [1,2], volume=Volumes['trap']),
    'top':   PECSettings(device.gnd.polygons, [0,1], volume=Volumes['top']),
}

scale = 4 # scaling factor for meshing. default 1.8

mesh = MeshSettings(
    dim = 3,
    fields = {
        "Box": [BoxFieldMeshSettings(Thickness=4, VIn=scale * 0.2, VOut=scale * 2, box=[-10, 10, 10, 10, -5, 5]),
                BoxFieldMeshSettings(Thickness=2, VIn=scale * 0.1, VOut=scale * 2, box=[-8, 8, -8, 8, -2, 2])]
    }
)
[10]:
meshMKR = GMSHmaker(
    extrude = Volumes,
    surfaces = None,
    pecs = PECs,
    mesh = mesh,
    save = {"dir": save_dir, "filename": "dot"},
    open_gmsh = False,
    debug_mode = False
)
on 0: mesh is constructed
on 0: mesh saved
Gmsh generation  |███| 1/1 [100%] in 2.8s (0.36/s)

Below is an example of created geometry and a mesh using GMSH.

30a188dfefc24d2e80889cd95ea4655e

[11]:
meshMKR.print_physical()
Volume        ID
----------  ----
METAL          1
DIELECTRIC     2
VACUUM         3
HELIUM         4

 #-----------------------------------

Surface      ID
---------  ----
mid           5
out           6
top           7
[12]:
### Helium Surface Displacement calculations
[13]:
s = Structure()
s.add(Layer('etch', device.etch.polygons, color=(BLUE,1)))
s.quickplot(size="medium", show_line_idx=True)

# We want to make boundary with line id 1 and 11 to be open boundary (Neumann boundary),
# at all other boundaries displacement is set to 0 (Dirichlet boundary)
[13]:
<Axes: >
../_images/notebooks_gmshfem_14_1.png
[14]:
from zeroheliumkit.fem.heliumsurface import GMSHmaker2D, HeliumSurfaceFreeFEM
[15]:
gmshmkr = GMSHmaker2D(layout = s.etch,
                      electode_config = {"type": "polygon",
                                         "bound": {"layer": ("etch", (0,)), "exclude": [1,11], "value": 0}},
                      mesh_config = [{"Thickness": 5, "VIn": 0.9, "VOut": 0.9, "box": [-20, -10, 20, 10]}],
                      filename = "heliumsurface",
                      savedir = save_dir)
gmshmkr.disable_consoleOutput()
gmshmkr.create_mesh()
#gmshmkr.open_gmsh()
gmshmkr.finalize()

Warning : Boolean fragments skipped - too few arguments
Gmsh generation  |███| 1/1 [100%] in 0.1s (9.62/s)
[16]:
hsfreefem = HeliumSurfaceFreeFEM(fem_config=gmshmkr.export_physical(), save_edp=True)
res = hsfreefem.run_pyfreefem()

# plotting results of helium surface displacement for a bulk helium distance of 10 cm from the gnd surface
# note: the geometry units are in micrometers, so the bulk helium distance is set to 0.01 (10 cm)
hsfreefem.plot_results(res, bulk_helium_distance=0.01)
../_images/notebooks_gmshfem_17_0.png
[17]:
curvature_config = hsfreefem.get_code_config(bulk_helium_distances=[0, 0.001, 0.01, 0.02], surface_helium_level=d_He)
# curvature_config
[ ]:
### Creating FreeFem configuration
[18]:
from zeroheliumkit.fem.freefemer import FFconfigurator, ExtractConfig, FreeFEM
[19]:
He_level = d_He

var_eps = {
        'DIELECTRIC': 11.0,
        'METAL': 1.0,
        'HELIUM': 1.057,
        'VACUUM': 1.0,
}

ffc = FFconfigurator(config_file="dump/dot.yaml",
                     dielectric_constants=var_eps,
                     ff_polynomial=2,
                     extract_opt=[ExtractConfig("result1", 'phi', 'xy', (-10,10,201), (-10,10,201), d_He),
                                  ExtractConfig("result2", 'phi', 'xy', (-10,10,201), (-10,10,201), curvature_config),
                                  ExtractConfig("result3", 'Ez', 'yz', (-10,10,101), (-2,2,101), 0.0)
                                  ],
                     msh_refinements=None
                     )
[20]:
pyff = FreeFEM(config_file="dump/dot.yaml")
[21]:
await pyff.run(cores=3, remove=True)
[ ]:
### Parsing FEM results
[22]:
from zeroheliumkit.fem.fieldreader import FreeFemResultParser, FieldAnalyzer
from zeroheliumkit.src.settings import BLACK, WHITE
[23]:
ffparser = FreeFemResultParser("dump/metadata.yaml")
                result1        result2                 result3
--------------  -------------  ----------------------  -------------
Quantity        phi            phi                     Ez
Plane           xy             xy                      yz
X Min           -10            -10                     -10
X Max           10             10                      10
X Num           201            201                     101
Y Min           -10            -10                     -2
Y Max           10             10                      2
Y Num           201            201                     101
Slices          1              4                       1
Slice Values    [1.6]          [0, 0.001, 0.01, 0.02]  [0.0]
Curved Surface  False          True                    False
Schema          (1, 201, 201)  (4, 201, 201)           (1, 101, 101)
Control Electrodes: ['mid', 'out', 'top']
[24]:
ffparser.get_capacitance_matrix()
[24]:
[[-321.433, 266.481, 67.7825],
 [258.134, -1859.7, 1725.85],
 [63.2999, 1593.21, -1793.63]]
[25]:
ffparser.load_data("dump/results/", "result1")

cc1 = ffparser.get_coupling_constants(slice_value=1.6, round_with_decimals=6)
fa = FieldAnalyzer(cc1)
[ ]:
voltages = {
    "mid": 1,
    "out": 2,
    "top": -0.1
}

fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(111)

fa.set_voltages(voltages)
fa.plot2D_data(ax=ax, zero_line=False, cmap='RdYlBu')
device.gnd.plot(ax=ax, edgecolor=BLACK)

ax.set_aspect("equal")

plt.show()
../_images/notebooks_gmshfem_29_0.png