Advanced features

This tutorial walks through the creation of an imaginary device with overlapping gates to demonstrate some more advanced features like qtcad.builder.Builder.grow and qtcad.builder.Builder.pad_group.

advanced features

Fig. 24 The device that will be created in this tutorial.

We begin by importing the necessary modules and defining some characteristic lengths and layer thicknesses.

# sphinx_gallery_thumbnail_path = 'auto_examples/tutorials/images/sphx_glr_advanced_features_010.png'

from qtcad.builder import Builder, MeshAlgorithm3D
from pathlib import Path
import sys

script_dir = Path(sys.argv[0]).resolve().parent


# Mesh characteristic lengths
char_len = 50  # Note that this is very low and for demonstration purposes only
dot_char_len = char_len / 2

# Thickness of each material layer
cap_thick = 10
barrier_thick = 15
dopant_thick = 5
spacer_thick = 5
two_deg_thick = 10
substrate_thick = 100 - two_deg_thick

dot_height = substrate_thick + two_deg_thick + spacer_thick

gate_thick = 10
gate_padding = 5

Next, we initialize a new instance of qtcad.builder.Builder and load our photomask layout from an oasis file (demo_dot.oas).

layout

Fig. 25 The photomask layout for the device.

Note

In contrast to Gated Quantum Dot the shape names are defined through text labels in the layout file. For layers containing only one shape, it might be simpler to use qtcad.builder.Builder.group_from_mask and omit naming the shapes.

builder = (
    Builder(name="Demo")
    .load_layout(script_dir / "layouts" / "demo_dot.oas")
    .print_mask_tree()
)
[15:26:50] INFO     Loading layout from cache                           misc.py:266
                    /home/hiro/.cache/qtcad/builder/layout_e0c8531ef967
                    00b82a123ac19191a7d7fece40782812929eed5f780e81526e1
                    9_None_name_None_-9.pkl
           INFO     Adding mask 'dot_region' from cache                masks.py:750
           INFO     Adding mask 'footprint' from cache                 masks.py:750
           INFO     Adding mask 'gates' from cache                     masks.py:750
Layout
├── Mask 4 "dot_region"
│   └── 0  Polygon  "dot_region"
├── Mask 2 "footprint"
│   └── 0  Polygon  "footprint"
└── Mask 3 "gates"
    ├── 0  Polygon  "gate_2"
    └── 1  Polygon  "gate_1"

Above, we see that the layout contains three masks. The “footprint” mask defines the overall device footprint which we will later use to clip the volumes we create. The “gates” mask contains two rectangles which we will use as a basis to create gates later on. Finally, there is the “dot_region” mask which we will use to identify a region of the device that’s going to contain the quantum dot, i.e. charges confined in three dimensions, and in which all classical charges are excluded.

Next, we set the mesh size we are going to use for the subsequent operations.

builder.set_mesh_size(char_len)
<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

Bottom Gates

Now that the masks have been added, we are ready to create the gate volumes and surfaces. We will create four sets of gates in total. Horizontal and vertical lower gates, and horizontal and vertical upper gates.

To that end, we copy the “gates” mask and transform the shapes contained therein by rotating them 90 degrees and renaming them to “vertical_<original_name>”.

(
    builder.use_mask("gates")
    .copy_mask(
        "vertical",
        transformer=lambda shape: shape.named("vertical_" + shape.name),
        rotate=90,
    )
    .print_mask_tree()
    .use_mask(["gates", "vertical"])
    .view_shapes(save="figs/advanced_features_gates_shapes.svg")
)
advanced features
           INFO     Using mask 'gates' (implicitly selecting shapes  builder.py:801
                    [Polygon 0 'gate_2', Polygon 1 'gate_1'])
Layout
├── Mask 4 "dot_region"
│   └── 0  Polygon  "dot_region"
├── Mask 2 "footprint"
│   └── 0  Polygon  "footprint"
├── Mask 3 "gates"
│   ├── 0  Polygon  "gate_2"
│   └── 1  Polygon  "gate_1"
└── Mask 5 "vertical"
    ├── 0  Polygon  "vertical_gate_2"
    └── 1  Polygon  "vertical_gate_1"
           INFO     Using mask 'gates-vertical' (implicitly          builder.py:801
                    selecting shapes [Polygon 0 'vertical_gate_2',
                    Polygon 1 'vertical_gate_1'])
           INFO     Viewing shapes: [Polygon 0 'gate_2', Polygon 1  builder.py:1987
                    'gate_1', Polygon 2 'vertical_gate_2', Polygon
                    3 'vertical_gate_1'] using a temporary builder
                    instance

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

Next, we create the bottom set of horizontal gates, again by copying and renaming the “gates” mask.

(
    builder.use_mask("gates")
    .copy_mask(
        "bottom_horizontal",
        transformer=lambda shape: shape.named("bottom_" + shape.name),
    )
    .set_z(substrate_thick - 2 * (gate_padding + gate_thick))
    .extrude(gate_thick)
    .view(
        volume_labels=True,
        surfaces=True,
        save="figs/advanced_features_gates.svg",
    )
)
advanced features
           INFO     Using mask 'gates' (implicitly selecting shapes  builder.py:801
                    [Polygon 0 'gate_2', Polygon 1 'gate_1'])
           INFO     Setting z-coordinate to 60                       builder.py:903
           INFO     Extruding shape 0 from mask 'bottom_horizontal' builder.py:2794
                    with name 'bottom_gate_2' by 10 at z=60
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_2_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_2_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_2_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_2_hull'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_2'
           INFO     Extruding shape 1 from mask 'bottom_horizontal' builder.py:2794
                    with name 'bottom_gate_1' by 10 at z=60
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_1_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_1_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_1_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_1_hull'
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_1'
           INFO     Setting z-coordinate to 70                       builder.py:903
           INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

If we show the surface labels, we see that the bottom, side and top of the created volumes receive distinct labels.

builder.view(
    volume_labels=False,
    surface_labels=True,
    angles=(-45, 0, 45),
    save="figs/advanced_features_gates_surfs.svg",
)
advanced features
[15:26:51] INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

Now, we create the vertical set of gates.

(
    builder.use_mask("vertical")
    .copy_mask(
        "bottom_vertical",
        transformer=lambda shape: shape.named("bottom_" + shape.name),
    )
    .set_z(offset=1.99 * gate_padding)
    .extrude(gate_thick)
    .quick_mesh()
    .view(
        volume_labels=True,
        surfaces=True,
        angles=(-85, 0, 45),
        save="figs/advanced_features_gates_vertical_raw.png",  # caption: The gates before adding padding.;
        show_volume_faces=True,
    )
    .view(
        volume_labels=True,
        surfaces=True,
        angles=(-90, 0, 45),
        save="figs/advanced_features_gates_vertical.png",  # caption: Side view showing the gap between the vertical and horizontal gates.;
        show_volume_faces=True,
    )
)
advanced features

Fig. 26 The gates before adding padding.

advanced features

Fig. 27 Side view showing the gap between the vertical and horizontal gates.

           INFO     Using mask 'vertical' (implicitly selecting      builder.py:801
                    shapes [Polygon 0 'bottom_gate_2', Polygon 1
                    'bottom_gate_1'])
           INFO     Setting z-coordinate to 79.95                    builder.py:903
           INFO     Extruding shape 0 from mask 'bottom_vertical'   builder.py:2794
                    with name 'bottom_vertical_gate_2' by 10 at
                    z=79.95
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_2_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_2_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_2_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_2_hull'
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_2'
           INFO     Extruding shape 1 from mask 'bottom_vertical'   builder.py:2794
                    with name 'bottom_vertical_gate_1' by 10 at
                    z=79.95
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_1_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_1_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_1_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_1_hull'
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_1'
           INFO     Setting z-coordinate to 89.95                    builder.py:903
           INFO     Saving figure                                   builder.py:1926
[15:26:52] INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

Above, we used qtcad.builder.Builder.quick_mesh to generate a quick preview of the mesh and show_volume_faces=True to highlight the faces of the volumes. The colors indicate the physical group of the volumes.

Next, we’ll add an “oxide” padding layer around the gates. We will use qtcad.builder.Builder.fill_mode to ensure that the padding does not affect the groups the surfaces of the gates are assigned to. The qtcad.builder.Builder.use_mask method selects the “footprint” mask and the shape contained therein which will be used to clip the padding volumes (see also Padding).

Builder.pad_group(group: str | list[str] | Callable[[PhysicalGroup], bool], thickness: float, padding_suffix: str = '_padding', noclip: bool = False, grow_complexity: float = 10.0, grow_accuracy: int = 100, min_curve_nodes: int = 20) Self

[🏗️ Operation] Add a padding layer of thickness around the volumes in volume group with name group_name. The newly created padding volume will be named group_name + padding_suffix and clipped horizontally by the currently selected shapes unless noclip is True.

Parameters:
  • group – The group(s) to pad. See get_group for details on the allowed types.

  • thickness – The padding thickness.

  • padding_suffix – Suffix to append to the group name for the new volume.

  • noclip – If True, no horizontal clipping will occur. Default is False.

  • grow_complexity – See grow().

  • grow_accuracy – See grow().

  • min_curve_nodes – See grow().

Below, we are enlarging the padding with by 1% to avoid shapes that almost but not quite touch.

(
    builder.use_mask("footprint")
    .fill_mode()
    .pad_group(
        lambda group: "gate" in group.name and group.dim == 3,
        gate_padding * 1.01,
        padding_suffix="_padding",
        grow_complexity=10,
        grow_accuracy=400,
    )
    .view()
    .quick_mesh()
    .view(
        volume_labels=True,
        surfaces=True,
        angles=(-85, 0, 45),
        save="figs/advanced_features_gates_padding_raw.png",
        show_volume_faces=True,
    )
)
advanced features
           INFO     Using mask 'footprint' (implicitly selecting     builder.py:801
                    shapes [Polygon 0 'bottom_vertical_gate_2',
                    Polygon 1 'bottom_vertical_gate_1'])
           INFO     Padding Physical Group 'bottom_gate_2' of        builder.py:462
                    dimension 3 with a layer of thickness 5.05
                    (clipping with shapes with shapes: [Polygon 0
                    'footprint'])
           INFO     Growing volume (3, 5)...                        builder.py:3290
[15:26:54] INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_2_padding_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_2_padding_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_2_padding_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_2_padding_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:26:55] INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_2_padding'
           INFO     Padding Physical Group 'bottom_gate_1' of        builder.py:462
                    dimension 3 with a layer of thickness 5.05
                    (clipping with shapes with shapes: [Polygon 0
                    'footprint'])
           INFO     Growing volume (3, 8)...                        builder.py:3290
[15:26:57] INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_1_padding_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_1_padding_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_1_padding_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_1_padding_hull'
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_gate_1_padding'
           INFO     Padding Physical Group 'bottom_vertical_gate_2'  builder.py:462
                    of dimension 3 with a layer of thickness 5.05
                    (clipping with shapes with shapes: [Polygon 0
                    'footprint'])
           INFO     Growing volume (3, 11)...                       builder.py:3290
[15:26:59] INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_2_padding_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_2_padding_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_2_padding_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_2_padding_hull'
           INFO     Fragmenting...                                fragmenter.py:218
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/util/misc.py:122: RuntimeWarning: invalid value encountered in scalar divide
  elevation = math.acos(normal[2] / np.linalg.norm(normal))
[15:27:01] INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_2_padding'
           INFO     Padding Physical Group 'bottom_vertical_gate_1'  builder.py:462
                    of dimension 3 with a layer of thickness 5.05
                    (clipping with shapes with shapes: [Polygon 0
                    'footprint'])
           INFO     Growing volume (3, 18)...                       builder.py:3290
[15:27:03] INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_1_padding_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_1_padding_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_1_padding_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_1_padding_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:27:07] INFO     Creating new physical group with name           builder.py:2580
                    'bottom_vertical_gate_1_padding'
           INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

The above operation generates a lot of groups (all ending in _padding as configured above). To reduce clutter and make the assignment of materials easier, we will merge all padding groups groups using qtcad.builder.Builder.merge_groups.

Builder.merge_groups(groups: str | list[str] | Callable[[PhysicalGroup], bool], into: str) Self

[⚡ Utility] Merge multiple physical groups groups into the (potentially new) group new.

Parameters:
  • groups – Group(s) to merge. See get_group for details.

  • into – The name of a new or existing group to merge into.

(
    builder.merge_groups(
        lambda group: "padding" in group.name and group.dim == 3, "padding"
    )
    .merge_groups(
        lambda group: "padding" in group.name and group.dim == 2, "padding_surfaces"
    )
    .quick_mesh()
    .view(
        volume_labels=True,
        surfaces=True,
        angles=(-85, 0, 45),
        save="figs/advanced_features_gates_padding.png",
        show_volume_faces=True,
    )
)
advanced features
[15:27:08] INFO     Merging groups ['bottom_gate_2_padding',        builder.py:1439
                    'bottom_gate_1_padding',
                    'bottom_vertical_gate_2_padding',
                    'bottom_vertical_gate_1_padding'] into
                    'padding'
           INFO     Creating new physical group with name 'padding' builder.py:2580
           INFO     Merging groups ['bottom_gate_2_padding_bottom', builder.py:1439
                    'bottom_gate_2_padding_side',
                    'bottom_gate_2_padding_top',
                    'bottom_gate_1_padding_bottom',
                    'bottom_gate_1_padding_side',
                    'bottom_gate_1_padding_top',
                    'bottom_vertical_gate_2_padding_bottom',
                    'bottom_vertical_gate_2_padding_side',
                    'bottom_vertical_gate_2_padding_top',
                    'bottom_vertical_gate_1_padding_bottom',
                    'bottom_vertical_gate_1_padding_side',
                    'bottom_vertical_gate_1_padding_top'] into
                    'padding_surfaces'
           INFO     Creating new physical group with name           builder.py:2580
                    'padding_surfaces'
           INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

Heterostructure

Next we will create the heterostructure layers that confine particles in the quantum dot along the growth direction, similar to Gated Quantum Dot. We will use qtcad.builder.Builder.fill_mode to create the volume around the gates without altering them. We also use qtcad.builder.Builder.set_min_elements to make sure the final mesh will be fine enough to resolve the layer structure. In actual applications the argument should be larger than two.

(
    builder.use_mask("footprint")
    .fill_mode()
    .set_z(0)
    # .set_min_elements(2)
    .use_mask("footprint")
    #
    # Substrate
    #
    .set_group_name("substrate")
    .extrude(substrate_thick)
    #
    # Electron confinement region
    #
    .set_group_name("two_deg")
    .extrude(two_deg_thick)
    #
    # Spacer
    #
    .set_group_name("spacer")
    .extrude(spacer_thick)
    #
    # Dopant
    #
    .set_group_name("dopant")
    .extrude(dopant_thick)
    #
    # Barrier
    #
    .set_group_name("barrier")
    .extrude(barrier_thick)
    #
    # Caps
    #
    .set_group_name("cap")
    .extrude(cap_thick)
    .quick_mesh()
    .view(
        volume_labels=True,
        surfaces=True,
        angles=(-85, 0, 45),
        show_volume_faces=True,
    )
)
[15:27:09] INFO     Using mask 'footprint' (implicitly selecting     builder.py:801
                    shapes [Polygon 0 'footprint'])
           INFO     Setting z-coordinate to 0                        builder.py:903
           INFO     Using mask 'footprint' (implicitly selecting     builder.py:801
                    shapes [Polygon 0 'footprint'])
           INFO     Extruding shape 0 from mask 'footprint' with    builder.py:2794
                    name 'footprint' by 90 at z=0
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:27:34] INFO     Creating new physical group with name           builder.py:2580
                    'padding_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'padding_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'padding_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'padding_hull'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate'
[15:27:35] INFO     Setting z-coordinate to 90                       builder.py:903
           INFO     Extruding shape 0 from mask 'footprint' with    builder.py:2794
                    name 'footprint' by 10 at z=90
           INFO     Creating new physical group with name           builder.py:2580
                    'two_deg_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'two_deg_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'two_deg_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'two_deg_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:27:42] INFO     Creating new physical group with name 'two_deg' builder.py:2580
           INFO     Setting z-coordinate to 100                      builder.py:903
           INFO     Extruding shape 0 from mask 'footprint' with    builder.py:2794
                    name 'footprint' by 5 at z=100
           INFO     Creating new physical group with name           builder.py:2580
                    'spacer_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'spacer_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'spacer_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'spacer_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:27:43] INFO     Creating new physical group with name 'spacer'  builder.py:2580
           INFO     Setting z-coordinate to 105                      builder.py:903
           INFO     Extruding shape 0 from mask 'footprint' with    builder.py:2794
                    name 'footprint' by 5 at z=105
           INFO     Creating new physical group with name           builder.py:2580
                    'dopant_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'dopant_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'dopant_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'dopant_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:27:44] INFO     Creating new physical group with name 'dopant'  builder.py:2580
           INFO     Setting z-coordinate to 110                      builder.py:903
           INFO     Extruding shape 0 from mask 'footprint' with    builder.py:2794
                    name 'footprint' by 15 at z=110
           INFO     Creating new physical group with name           builder.py:2580
                    'barrier_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'barrier_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'barrier_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'barrier_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:27:45] INFO     Creating new physical group with name 'barrier' builder.py:2580
           INFO     Setting z-coordinate to 125                      builder.py:903
           INFO     Extruding shape 0 from mask 'footprint' with    builder.py:2794
                    name 'footprint' by 10 at z=125
           INFO     Creating new physical group with name           builder.py:2580
                    'cap_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'cap_side'
           INFO     Creating new physical group with name 'cap_top' builder.py:2580
           INFO     Creating new physical group with name           builder.py:2580
                    'cap_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:27:46] INFO     Creating new physical group with name 'cap'     builder.py:2580
           INFO     Setting z-coordinate to 135                      builder.py:903

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

Dot region

Finally, we will create the quantum dot region. We will use qtcad.builder.Builder.set_z_from_group to position the bottom of the dot region at the bottom of the substrate layer. We then use qtcad.builder.Builder.overlay_mode to create the dot region while maintaining the layer structure (see Extrusion and fragmentation modes). We use qtcad.builder.Builder.group_from_mask to name the shape contained in the “dot_region” mask accordingly.

(
    builder.set_z_from_group("substrate", bottom=True)
    .overlay_mode()
    .set_mesh_size(dot_char_len)
    .minimum_mesh_size()
    .use_mask("dot_region")
    .group_from_mask()
    .extrude(dot_height)
    .quick_mesh()
    .view(
        volume_labels=True,
        surfaces=True,
        angles=(-45, 0, 45),
        save="figs/advanced_features_dot_region.png",  # caption: The dot region;
        show_volume_faces=True,
        groups=lambda g: "dot_region" in g.name,
    )
)
advanced features

Fig. 28 The dot region

           INFO     Setting z-coordinate to 0.0                      builder.py:903
           INFO     Using mask 'dot_region' (implicitly selecting    builder.py:801
                    shapes [Polygon 0 'dot_region'])
           INFO     Extruding shape 0 from mask 'dot_region' with   builder.py:2794
                    name 'dot_region' by 105 at z=0.0
           INFO     Creating new physical group with name           builder.py:2580
                    'dot_region_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'dot_region_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'dot_region_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'dot_region_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:27:48] INFO     Creating new physical group with name           builder.py:2580
                    'two_deg_top.dot_region'
           INFO     Creating new physical group with name           builder.py:2580
                    'spacer.dot_region_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate.dot_region_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'two_deg.dot_region_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'spacer_top.dot_region_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate_top.dot_region'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate_bottom.dot_region_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate.dot_region'
           INFO     Creating new physical group with name           builder.py:2580
                    'spacer.dot_region'
           INFO     Creating new physical group with name           builder.py:2580
                    'two_deg.dot_region'
           INFO     Setting z-coordinate to 105.0                    builder.py:903
[15:27:49] INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

Top gates

Now we will add the upper set of gates. These are similar to the bottom gates, but we will position them on top of the cap layer. To achieve this, we will copy the mask containing the shapes of the Horizontal gates and use qtcad.builder.Builder.deposit to create the gate volumes atop the device. (Note that extrude would have the same effect in this case.) We are using qtcad.builder.Builder.displace_mode to make sure the bottom surfaces of the created volumes retain their names.

Builder.deposit(height: float, noclip: bool = False) Self

[🏗️ Operation] Deposit the currently selected shape(s) into the model up from the current z coordinate by height length units. This is done by adding new material atop the topmost surfaces of the model. If noclip=True, the new material is deposited on the whole top surface of the model, rather than clipped by the currently selected shapes.

See also grow, etch and cut.

Parameters:
  • height – The distance by which to deposit the shape(s) up into the model.

  • noclip – Whether to deposit the shape without horizontally clipping to the current shapes.

(
    builder.use_mask("gates")
    .set_mesh_size(char_len)
    .displace_mode()
    .group_from_shape()
    .copy_mask(
        "top_horizontal",
        transformer=lambda shape: shape.named("top_horizontal_" + shape.name),
    )
    .deposit(gate_thick)
    .quick_mesh()
    .view(
        volume_labels=True,
        surfaces=True,
        angles=(-45, 0, 45),
        save="figs/advanced_features_top_gates_raw.png",  # caption: The top gates before adding padding.;
        show_volume_faces=True,
    )
)
advanced features

Fig. 29 The top gates before adding padding.

           INFO     Using mask 'gates' (implicitly selecting shapes  builder.py:801
                    [Polygon 0 'gate_2', Polygon 1 'gate_1'])
           INFO     Depositing on top surfaces clipped to shape 0    builder.py:327
                    with name 'top_horizontal_gate_2' by 10
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_2_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_2_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_2_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_2_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:27:50] INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_2'
           INFO     Depositing on top surfaces clipped to shape 1    builder.py:327
                    with name 'top_horizontal_gate_1' by 10
[15:27:51] INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_1_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_1_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_1_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_1_hull'
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_1'
[15:27:52] INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

As before, we add a padding layer around the horizontal top gates using qtcad.builder.Builder.pad_group.

(
    builder.use_mask("footprint")
    .fill_mode()
    .pad_group(
        lambda group: group.dim == 3 and "top_horizontal" in group.name,
        thickness=gate_padding * 1.01,
        grow_accuracy=400,
    )
    .merge_groups(lambda group: "padding" in group.name and group.dim == 3, "padding")
    .merge_groups(
        lambda group: "padding" in group.name and group.dim == 2, "padding_surfaces"
    )
    .quick_mesh()
    .view(
        volume_labels=True,
        surfaces=True,
        angles=(-85, 0, 45),
        save="figs/advanced_features_top_gates.png",  # caption: The top gates with padding.;
        show_volume_faces=True,
    )
)
advanced features

Fig. 30 The top gates with padding.

[15:27:53] INFO     Using mask 'footprint' (implicitly selecting     builder.py:801
                    shapes [Polygon 0 'top_horizontal_gate_2',
                    Polygon 1 'top_horizontal_gate_1'])
           INFO     Padding Physical Group 'top_horizontal_gate_2'   builder.py:462
                    of dimension 3 with a layer of thickness 5.05
                    (clipping with shapes with shapes: [Polygon 0
                    'footprint'])
           INFO     Growing volume (3, 58)...                       builder.py:3290
[15:27:55] INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_2_padding_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_2_padding_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_2_padding_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_2_padding_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:27:59] INFO     Creating new physical group with name           builder.py:2580
                    'cap_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'cap_hull'
[15:28:00] INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_2_padding'
           INFO     Padding Physical Group 'top_horizontal_gate_1'   builder.py:462
                    of dimension 3 with a layer of thickness 5.05
                    (clipping with shapes with shapes: [Polygon 0
                    'footprint'])
           INFO     Growing volume (3, 63)...                       builder.py:3290
[15:28:03] INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_1_padding_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_1_padding_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_1_padding_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_1_padding_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:28:09] INFO     Creating new physical group with name           builder.py:2580
                    'top_horizontal_gate_1_padding'
[15:28:10] INFO     Merging groups ['padding',                      builder.py:1439
                    'top_horizontal_gate_2_padding',
                    'top_horizontal_gate_1_padding'] into 'padding'
           INFO     Merging groups ['padding_surfaces',             builder.py:1439
                    'padding_top',
                    'top_horizontal_gate_2_padding_bottom',
                    'top_horizontal_gate_2_padding_side',
                    'top_horizontal_gate_2_padding_top',
                    'top_horizontal_gate_2_padding_hull',
                    'top_horizontal_gate_1_padding_bottom',
                    'top_horizontal_gate_1_padding_side',
                    'top_horizontal_gate_1_padding_top',
                    'top_horizontal_gate_1_padding_hull'] into
                    'padding_surfaces'
           INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

Finally, we use qtcad.builder.Builder.grow (see Deposition and Growth) to create the top vertical gates.

Builder.grow(thickness: float, noclip: bool = False, grow_complexity: float = 3.0, grow_accuracy: int = 100, min_curve_nodes: int = 20, polygonize: bool = False) Self

[🏗️ Operation] Emulate a physical ‘growth’ operation to add material to the current topmost volumes. In contrast to deposit, this will not only add material to the top of the volumes but also to their sides. The currently active shapes are used to horizontally clip the new volumes unless noclip is True.

The resulting surfaces are labelled similar to the extrude command. However, there is some ambiguity as to what surfaces are to be considered to be on top and what surfaces are on the side. Here, we choose surfaces whose (average) normal vector projected on the x-y plane is 10% larger than its projection on the z-axis to be on the “side”. Surfaces can be created/renamed using assign_to_group, add_surface or deposit_surface.

Parameters:
  • thickness – The distance by which to grow the selected shapes. Must be positive.

  • noclip – If True, do not clip the created volumes horizontally.

  • grow_complexity – Controls the geometric detail of the resulting CAD object. A value of 10 means the resulting object will have at most roughly 10 times the number of nodes (points) of the original object. Higher values preserve more detail but increase the number of faces and edges, which can slow down subsequent CAD operations.

  • grow_accuracy – Controls how closely the growth follows the fine details of the original shape. A higher value captures sharp corners and small crevices more precisely. Lower values “smooth over” these details, creating a simpler and rounder wrap around the original object.

  • min_curve_nodes – Minimum number of nodes to use for discretizing curves when approximating the shapes for growth.

  • polygonize – Deprecated.

(
    builder.use_mask("vertical")
    .displace_mode()
    .copy_mask(
        "top_vertical",
        transformer=lambda shape: shape.named("top_" + shape.name),
    )
    .grow(
        gate_thick,
        grow_accuracy=300,
    )
    .quick_mesh()
    .view(
        volume_labels=False,
        surfaces=False,
        angles=(-85, 0, 45),
        save="figs/advanced_features_top_gates_vertical.png",  # caption: The top vertical gates created using the grow operation.;
        show_volume_faces=True,
    )
)
advanced features

Fig. 31 The top vertical gates created using the grow operation.

[15:28:11] INFO     Using mask 'vertical' (implicitly selecting      builder.py:801
                    shapes [Polygon 0 'vertical_gate_2', Polygon 1
                    'vertical_gate_1'])
           INFO     Growing top surfaces clipped to shape 0 with    builder.py:3332
                    name 'top_vertical_gate_2' by 10
[15:28:12] INFO     Growing volume (3, 70)...                       builder.py:3290
[15:28:14] INFO     Creating new physical group with name           builder.py:2580
                    'top_vertical_gate_2_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_vertical_gate_2_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_vertical_gate_2_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_vertical_gate_2_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:28:19] INFO     Creating new physical group with name           builder.py:2580
                    'top_vertical_gate_2'
[15:28:20] INFO     Growing top surfaces clipped to shape 1 with    builder.py:3332
                    name 'top_vertical_gate_1' by 10
           INFO     Growing volume (3, 77)...                       builder.py:3290
[15:28:22] INFO     Creating new physical group with name           builder.py:2580
                    'top_vertical_gate_1_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_vertical_gate_1_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_vertical_gate_1_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'top_vertical_gate_1_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:30:00] INFO     Creating new physical group with name           builder.py:2580
                    'top_vertical_gate_1'
[15:31:35] INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

Mesh generation

We create the final mesh using the default Delaunay algorithm with qtcad.builder.Builder.mesh, enabling output from Gmsh and conformity checking. Due to the complexity of the geometry, we will see some warnings “ill shaped tets”. For applications, the HXT algorithm is preferable, but takes considerably more time on this model.

(
    builder.mesh(
        algorithm3d=MeshAlgorithm3D.Delaunay,
        show_gmsh_output=True,
        check_connectivity=True,
    )
    .view(
        volume_labels=True,
        surfaces=True,
        angles=(-45, 0, 45),
        save="figs/advanced_features_final_mesh.png",  # caption: The final mesh of the device.;
    )
    .view(
        volume_labels=True,
        surfaces=True,
        angles=(-45, 0, 45),
        save="figs/advanced_features_final_mesh_dot_region.png",  # caption: The final mesh highlighting the dot region.;
        groups=lambda g: "dot_region" in g.name,
    )
)
advanced features

Fig. 32 The final mesh of the device.

advanced features

Fig. 33 The final mesh highlighting the dot region.

[15:31:36] INFO     Preparing to mesh                               builder.py:1561
[15:31:37] INFO     Detecting appropriate random factor             builder.py:3681
           INFO     Increased random factor from                    builder.py:3699
                    4.425455132591868e-07 to 0.3328457071905143
           INFO     Random factor is now appropriate                builder.py:3705
           INFO     Meshing                                         builder.py:1577
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: No elements in volume 78
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 38 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 50 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 49 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 57 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 32 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 67 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 264 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 244 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 24 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 35 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 79 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 9 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 3 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 17 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 45 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 34 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
/home/hiro/Documents/roam_code/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:1598: UserWarning: 27 ill-shaped tets are still in the mesh
  self._model.mesh.generate(dimension)
[15:31:38] INFO     Checking mesh conformity                        builder.py:3767
[15:31:39] INFO     Writing                                         builder.py:1663
                    ../../../../../../../../../../../tmp/tmp2mo3e7b
                    k/mesh.msh
           INFO     Checking connectivity                           builder.py:3794

nodes:   0%|          | 0/6590 [00:00<?, ?it/s]
nodes:   0%|          | 0/6590 [00:00<?, ?it/s]
nodes: 100%|██████████| 6590/6590 [00:00<00:00, 11379359.14it/s]
nodes: 100%|██████████| 6590/6590 [00:00<00:00, 9485402.66it/s]
nodes: 100%|██████████| 6590/6590 [00:00<00:00, 8597344.75it/s]
[15:31:40] INFO     Saving figure                                   builder.py:1926
[15:31:43] INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

We also export the mesh and geometry to disk in the msh and xao formats, respectively, for later use.

builder.write(script_dir / "meshes" / "demo.msh")
builder.write(script_dir / "meshes" / "demo.xao")
[15:31:44] INFO     Writing meshes/demo.msh                         builder.py:1663
[15:31:45] INFO     Writing meshes/demo.xao                         builder.py:1663

<qtcad.builder.builder.Builder object at 0x75dd20e5b4d0>

Total running time of the script: (4 minutes 55.298 seconds)

Gallery generated by Sphinx-Gallery