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_volume.

advanced features

Fig. 21 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. 22 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()
)
[02:02:38 PM] INFO     Adding layer dot_region                                                                                                                masks.py:741
              INFO     Adding layer footprint                                                                                                                 masks.py:741
              INFO     Adding layer gates                                                                                                                     masks.py:741
              INFO     Renaming shape 0 to 'footprint'                                                                                                        masks.py:760
              INFO     Renaming shape 1 to 'gate_1'                                                                                                           masks.py:760
              INFO     Renaming shape 0 to 'gate_2'                                                                                                           masks.py:760
              INFO     Renaming shape 0 to 'dot_region'                                                                                                       masks.py:760
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 0x7f17464fb110>

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'                                                                                                                   builder.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"
└── Mask 5 "vertical"
    ├── 0  Polygon  "vertical_gate_2"
    └── 1  Polygon  "vertical_gate_1"
              INFO     Using mask 'gates-vertical'                                                                                                          builder.py:750
              INFO     Viewing shapes: ['gate_2', 'gate_1', 'vertical_gate_2', 'vertical_gate_1'] using a temporary builder instance                       builder.py:1922

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

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
[02:02:40 PM] INFO     Using mask 'gates'                                                                                                                   builder.py:750
              INFO     Setting z-coordinate to 60                                                                                                           builder.py:849
              INFO     Extruding shape 0 from mask 'bottom_horizontal' with name 'bottom_gate_2' by 10 at z=60                                             builder.py:2695
              INFO     Creating new physical group with name 'bottom_gate_2_bottom'                                                                        builder.py:2482
              INFO     Creating new physical group with name 'bottom_gate_2_side'                                                                          builder.py:2482
              INFO     Creating new physical group with name 'bottom_gate_2_top'                                                                           builder.py:2482
              INFO     Creating new physical group with name 'bottom_gate_2'                                                                               builder.py:2482
              INFO     Extruding shape 1 from mask 'bottom_horizontal' with name 'bottom_gate_1' by 10 at z=60                                             builder.py:2695
              INFO     Creating new physical group with name 'bottom_gate_1_bottom'                                                                        builder.py:2482
              INFO     Creating new physical group with name 'bottom_gate_1_side'                                                                          builder.py:2482
              INFO     Creating new physical group with name 'bottom_gate_1_top'                                                                           builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
              INFO     Creating new physical group with name 'bottom_gate_1'                                                                               builder.py:2482
[02:02:41 PM] INFO     Setting z-coordinate to 70                                                                                                           builder.py:849
              INFO     Saving /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_gates.svg    builder.py:1863

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

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
[02:02:42 PM] INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_gates_surfs.svg

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

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=2 * 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. 23 The gates before adding padding.

advanced features

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

[02:02:43 PM] INFO     Using mask 'vertical'                                                                                                                builder.py:750
              INFO     Setting z-coordinate to 80                                                                                                           builder.py:849
              INFO     Extruding shape 0 from mask 'bottom_vertical' with name 'bottom_vertical_gate_2' by 10 at z=80                                      builder.py:2695
              INFO     Creating new physical group with name 'bottom_vertical_gate_2_bottom'                                                               builder.py:2482
              INFO     Creating new physical group with name 'bottom_vertical_gate_2_side'                                                                 builder.py:2482
              INFO     Creating new physical group with name 'bottom_vertical_gate_2_top'                                                                  builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
              INFO     Creating new physical group with name 'bottom_vertical_gate_2'                                                                      builder.py:2482
              INFO     Extruding shape 1 from mask 'bottom_vertical' with name 'bottom_vertical_gate_1' by 10 at z=80                                      builder.py:2695
              INFO     Creating new physical group with name 'bottom_vertical_gate_1_bottom'                                                               builder.py:2482
              INFO     Creating new physical group with name 'bottom_vertical_gate_1_side'                                                                 builder.py:2482
              INFO     Creating new physical group with name 'bottom_vertical_gate_1_top'                                                                  builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
              INFO     Creating new physical group with name 'bottom_vertical_gate_1'                                                                      builder.py:2482
              INFO     Setting z-coordinate to 90                                                                                                           builder.py:849
              INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_gates_vertical_raw.
                       png
[02:02:44 PM] INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_gates_vertical.png

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

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_volume(group: str | list[str] | Callable[[PhysicalGroup], bool], thickness: float, padding_suffix: str = '_padding', noclip: bool = False, polygonize: bool = True) 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.

  • polygonize – If True, the newly created volumes will be recreated from their hull meshes to avoid problems with curved OpenCASCADE solids (default is True).

(
    builder.use_mask("footprint")
    .fill_mode()
    .pad_volume(
        lambda group: "gate" in group.name,
        gate_padding,
        padding_suffix="_padding",
    )
    .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
[02:02:46 PM] INFO     Using mask 'footprint'                                                                                                               builder.py:750
              INFO     Padding Physical Group 'bottom_gate_2' of dimension 3 with a layer of 5 (clipping with shapes with shapes: [('footprint', 0)])       builder.py:442
              INFO     Creating new physical group with name 'bottom_gate_2_padding_bottom'                                                                builder.py:2482
              INFO     Creating new physical group with name 'bottom_gate_2_padding_side'                                                                  builder.py:2482
              INFO     Creating new physical group with name 'bottom_gate_2_padding_top'                                                                   builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:02:47 PM] INFO     Creating new physical group with name 'bottom_gate_2_padding'                                                                       builder.py:2482
              INFO     Padding Physical Group 'bottom_gate_1' of dimension 3 with a layer of 5 (clipping with shapes with shapes: [('footprint', 0)])       builder.py:442
              INFO     Creating new physical group with name 'bottom_gate_1_padding_bottom'                                                                builder.py:2482
              INFO     Creating new physical group with name 'bottom_gate_1_padding_side'                                                                  builder.py:2482
              INFO     Creating new physical group with name 'bottom_gate_1_padding_top'                                                                   builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:02:48 PM] INFO     Creating new physical group with name 'bottom_gate_1_padding'                                                                       builder.py:2482
              INFO     Padding Physical Group 'bottom_vertical_gate_2' of dimension 3 with a layer of 5 (clipping with shapes with shapes: [('footprint',   builder.py:442
                       0)])
              INFO     Creating new physical group with name 'bottom_vertical_gate_2_padding_bottom'                                                       builder.py:2482
              INFO     Creating new physical group with name 'bottom_vertical_gate_2_padding_side'                                                         builder.py:2482
              INFO     Creating new physical group with name 'bottom_vertical_gate_2_padding_top'                                                          builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:02:49 PM] INFO     Creating new physical group with name 'bottom_vertical_gate_2_padding'                                                              builder.py:2482
              INFO     Padding Physical Group 'bottom_vertical_gate_1' of dimension 3 with a layer of 5 (clipping with shapes with shapes: [('footprint',   builder.py:442
                       0)])
[02:02:50 PM] INFO     Creating new physical group with name 'bottom_vertical_gate_1_padding_bottom'                                                       builder.py:2482
              INFO     Creating new physical group with name 'bottom_vertical_gate_1_padding_side'                                                         builder.py:2482
              INFO     Creating new physical group with name 'bottom_vertical_gate_1_padding_top'                                                          builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:02:51 PM] INFO     Creating new physical group with name 'bottom_vertical_gate_1_padding'                                                              builder.py:2482
              INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_gates_padding_raw.p
                       ng

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

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
[02:02:53 PM] INFO     Merging groups ['bottom_gate_2_padding', 'bottom_gate_1_padding', 'bottom_vertical_gate_2_padding',                                 builder.py:1377
                       'bottom_vertical_gate_1_padding'] into 'padding'
              INFO     Creating new physical group with name 'padding'                                                                                     builder.py:2482
              INFO     Merging groups ['bottom_gate_2_padding_bottom', 'bottom_gate_2_padding_side', 'bottom_gate_2_padding_top',                          builder.py:1377
                       '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 'padding_surfaces'                                                                            builder.py:2482
              INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_gates_padding.png

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

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,
    )
)
[02:02:55 PM] INFO     Using mask 'footprint'                                                                                                               builder.py:750
              INFO     Setting z-coordinate to 0                                                                                                            builder.py:849
              INFO     Using mask 'footprint'                                                                                                               builder.py:750
              INFO     Extruding shape 0 from mask 'footprint' with name 'footprint' by 90 at z=0                                                          builder.py:2695
              INFO     Creating new physical group with name 'substrate_bottom'                                                                            builder.py:2482
              INFO     Creating new physical group with name 'substrate_side'                                                                              builder.py:2482
              INFO     Creating new physical group with name 'substrate_top'                                                                               builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:03:09 PM] INFO     Creating new physical group with name 'padding_bottom'                                                                              builder.py:2482
              INFO     Creating new physical group with name 'padding_side'                                                                                builder.py:2482
              INFO     Creating new physical group with name 'padding_top'                                                                                 builder.py:2482
[02:03:10 PM] INFO     Creating new physical group with name 'substrate'                                                                                   builder.py:2482
              INFO     Setting z-coordinate to 90                                                                                                           builder.py:849
              INFO     Extruding shape 0 from mask 'footprint' with name 'footprint' by 10 at z=90                                                         builder.py:2695
              INFO     Creating new physical group with name 'two_deg_bottom'                                                                              builder.py:2482
              INFO     Creating new physical group with name 'two_deg_side'                                                                                builder.py:2482
              INFO     Creating new physical group with name 'two_deg_top'                                                                                 builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:03:15 PM] INFO     Creating new physical group with name 'two_deg'                                                                                     builder.py:2482
              INFO     Setting z-coordinate to 100                                                                                                          builder.py:849
              INFO     Extruding shape 0 from mask 'footprint' with name 'footprint' by 5 at z=100                                                         builder.py:2695
              INFO     Creating new physical group with name 'spacer_bottom'                                                                               builder.py:2482
              INFO     Creating new physical group with name 'spacer_side'                                                                                 builder.py:2482
              INFO     Creating new physical group with name 'spacer_top'                                                                                  builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:03:16 PM] INFO     Creating new physical group with name 'spacer'                                                                                      builder.py:2482
              INFO     Setting z-coordinate to 105                                                                                                          builder.py:849
              INFO     Extruding shape 0 from mask 'footprint' with name 'footprint' by 5 at z=105                                                         builder.py:2695
              INFO     Creating new physical group with name 'dopant_bottom'                                                                               builder.py:2482
              INFO     Creating new physical group with name 'dopant_side'                                                                                 builder.py:2482
              INFO     Creating new physical group with name 'dopant_top'                                                                                  builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:03:17 PM] INFO     Creating new physical group with name 'dopant'                                                                                      builder.py:2482
              INFO     Setting z-coordinate to 110                                                                                                          builder.py:849
              INFO     Extruding shape 0 from mask 'footprint' with name 'footprint' by 15 at z=110                                                        builder.py:2695
              INFO     Creating new physical group with name 'barrier_bottom'                                                                              builder.py:2482
              INFO     Creating new physical group with name 'barrier_side'                                                                                builder.py:2482
              INFO     Creating new physical group with name 'barrier_top'                                                                                 builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:03:18 PM] INFO     Creating new physical group with name 'barrier'                                                                                     builder.py:2482
              INFO     Setting z-coordinate to 125                                                                                                          builder.py:849
              INFO     Extruding shape 0 from mask 'footprint' with name 'footprint' by 10 at z=125                                                        builder.py:2695
              INFO     Creating new physical group with name 'cap_bottom'                                                                                  builder.py:2482
              INFO     Creating new physical group with name 'cap_side'                                                                                    builder.py:2482
              INFO     Creating new physical group with name 'cap_top'                                                                                     builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
              INFO     Creating new physical group with name 'cap'                                                                                         builder.py:2482
[02:03:19 PM] INFO     Setting z-coordinate to 135                                                                                                          builder.py:849

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

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. 25 The dot region

              INFO     Setting z-coordinate to 0.0                                                                                                          builder.py:849
              INFO     Using mask 'dot_region'                                                                                                              builder.py:750
              INFO     Extruding shape 0 from mask 'dot_region' with name 'dot_region' by 105 at z=0.0                                                     builder.py:2695
              INFO     Creating new physical group with name 'dot_region_bottom'                                                                           builder.py:2482
              INFO     Creating new physical group with name 'dot_region_side'                                                                             builder.py:2482
              INFO     Creating new physical group with name 'dot_region_top'                                                                              builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:03:23 PM] INFO     Creating new physical group with name 'substrate.dot_region_side'                                                                   builder.py:2482
              INFO     Creating new physical group with name 'spacer.dot_region_side'                                                                      builder.py:2482
              INFO     Creating new physical group with name 'two_deg_top.dot_region'                                                                      builder.py:2482
              INFO     Creating new physical group with name 'substrate_top.dot_region'                                                                    builder.py:2482
              INFO     Creating new physical group with name 'two_deg.dot_region_side'                                                                     builder.py:2482
              INFO     Creating new physical group with name 'spacer.dot_region'                                                                           builder.py:2482
              INFO     Creating new physical group with name 'two_deg.dot_region'                                                                          builder.py:2482
              INFO     Creating new physical group with name 'spacer_top.dot_region_top'                                                                   builder.py:2482
              INFO     Creating new physical group with name 'substrate_bottom.dot_region_bottom'                                                          builder.py:2482
              INFO     Creating new physical group with name 'substrate.dot_region'                                                                        builder.py:2482
              INFO     Setting z-coordinate to 105.0                                                                                                        builder.py:849
              INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_dot_region.png

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

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. 26 The top gates before adding padding.

[02:03:25 PM] INFO     Using mask 'gates'                                                                                                                   builder.py:750
              INFO     Depositing on top surfaces clipped to shape 0 with name 'top_horizontal_gate_2' by 10                                                builder.py:310
              INFO     Creating new physical group with name 'top_horizontal_gate_2_bottom'                                                                builder.py:2482
              INFO     Creating new physical group with name 'top_horizontal_gate_2_side'                                                                  builder.py:2482
              INFO     Creating new physical group with name 'top_horizontal_gate_2_top'                                                                   builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:03:26 PM] INFO     Creating new physical group with name 'top_horizontal_gate_2'                                                                       builder.py:2482
              INFO     Depositing on top surfaces clipped to shape 1 with name 'top_horizontal_gate_1' by 10                                                builder.py:310
              INFO     Creating new physical group with name 'top_horizontal_gate_1_bottom'                                                                builder.py:2482
              INFO     Creating new physical group with name 'top_horizontal_gate_1_side'                                                                  builder.py:2482
              INFO     Creating new physical group with name 'top_horizontal_gate_1_top'                                                                   builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:03:27 PM] INFO     Creating new physical group with name 'top_horizontal_gate_1'                                                                       builder.py:2482
[02:03:28 PM] INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_top_gates_raw.png

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

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

(
    builder.use_mask("footprint")
    .fill_mode()
    .pad_volume(
        lambda group: group.dim == 3 and "top_horizontal" in group.name,
        thickness=gate_padding,
    )
    .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. 27 The top gates with padding.

[02:03:31 PM] INFO     Using mask 'footprint'                                                                                                               builder.py:750
[02:03:32 PM] INFO     Padding Physical Group 'top_horizontal_gate_2' of dimension 3 with a layer of 5 (clipping with shapes with shapes: [('footprint',    builder.py:442
                       0)])
              INFO     Creating new physical group with name 'top_horizontal_gate_2_padding_bottom'                                                        builder.py:2482
              INFO     Creating new physical group with name 'top_horizontal_gate_2_padding_side'                                                          builder.py:2482
              INFO     Creating new physical group with name 'top_horizontal_gate_2_padding_top'                                                           builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:03:37 PM] INFO     Creating new physical group with name 'cap_bottom'                                                                                  builder.py:2482
              INFO     Creating new physical group with name 'top_horizontal_gate_2_padding'                                                               builder.py:2482
[02:03:38 PM] INFO     Padding Physical Group 'top_horizontal_gate_1' of dimension 3 with a layer of 5 (clipping with shapes with shapes: [('footprint',    builder.py:442
                       0)])
              INFO     Creating new physical group with name 'top_horizontal_gate_1_padding_bottom'                                                        builder.py:2482
              INFO     Creating new physical group with name 'top_horizontal_gate_1_padding_side'                                                          builder.py:2482
              INFO     Creating new physical group with name 'top_horizontal_gate_1_padding_top'                                                           builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:03:44 PM] INFO     Creating new physical group with name 'top_horizontal_gate_1_padding'                                                               builder.py:2482
              INFO     Merging groups ['padding', 'top_horizontal_gate_2_padding', 'top_horizontal_gate_1_padding'] into 'padding'                         builder.py:1377
              INFO     Merging groups ['padding_surfaces', 'padding_top', 'top_horizontal_gate_2_padding_bottom', 'top_horizontal_gate_2_padding_side',    builder.py:1377
                       'top_horizontal_gate_2_padding_top', 'top_horizontal_gate_1_padding_bottom', 'top_horizontal_gate_1_padding_side',
                       'top_horizontal_gate_1_padding_top'] into 'padding_surfaces'
              INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_top_gates.png

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

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

Builder.grow(thickness: float, noclip: bool = False, exact: bool = False, num_tries: int = 10, i_know_what_im_doing: bool = False, polygonize: bool = True) 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.

Warning

Due to problems in OpenCASCADE, this operation might fail. If it does it may help to retry with a different thickness or polygonize=False. The warning can be suppressed with i_know_what_im_doing=True.

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

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

  • exact – If exact=True do not try to slightly adjust the growth thickness in case growth fails and crash straightaway.

  • num_tries – If exact=False, try up to num_tries times to successively slightly reduce the thickness (by 0.1% each time) and retry.

  • i_know_what_im_doing – If False, a warning will be issued because this operation is known to be somewhat unstable due to problems in OpenCASCADE.

  • polygonize – If True, the newly created volumes will be recreated from their hull meshes to avoid problems with curved OpenCASCADE solids (default is True).

(
    builder.use_mask("vertical")
    .displace_mode()
    .copy_mask(
        "top_vertical",
        transformer=lambda shape: shape.named("top_" + shape.name),
    )
    .grow(gate_thick)
    .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. 28 The top vertical gates created using the grow operation.

[02:03:47 PM] INFO     Using mask 'vertical'                                                                                                                builder.py:750
/home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:376: UserWarning: Due to problems in OpenCASCADE, the grow operation might fail.
If it does it may help to retry with a different thickness or
.``polygonize=False``.
  warnings.warn(
              INFO     Growing top surfaces clipped to shape 0 with name 'top_vertical_gate_2' by 10                                                       builder.py:3386
/home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:3399: UserWarning: Intersection - BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection
  to_grow, merged_boxes = self._get_top_volume(offset)
[02:03:48 PM] INFO     Failed to grow. Shrinking by 0.1%                                                                                                   builder.py:3434
/home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:396: UserWarning: Difference - BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning
  self._grow_shape(shape, thickness, exact, num_tries, polygonize)
[02:03:50 PM] INFO     Creating new physical group with name 'top_vertical_gate_2_bottom'                                                                  builder.py:2482
              INFO     Creating new physical group with name 'top_vertical_gate_2_side'                                                                    builder.py:2482
              INFO     Creating new physical group with name 'top_vertical_gate_2_top'                                                                     builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:04:00 PM] INFO     Creating new physical group with name 'top_vertical_gate_2'                                                                         builder.py:2482
              INFO     Growing top surfaces clipped to shape 1 with name 'top_vertical_gate_1' by 10                                                       builder.py:3386
/home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:3399: UserWarning: Intersection - BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection BOPAlgo_AlertAcquiredSelfIntersection
  to_grow, merged_boxes = self._get_top_volume(offset)
[02:04:03 PM] INFO     Failed to grow. Shrinking by 0.1%                                                                                                   builder.py:3434
/home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/builder.py:396: UserWarning: Difference - BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning BOPAlgo_AlertBadPositioning
  self._grow_shape(shape, thickness, exact, num_tries, polygonize)
[02:04:05 PM] INFO     Creating new physical group with name 'top_vertical_gate_1_bottom'                                                                  builder.py:2482
              INFO     Creating new physical group with name 'top_vertical_gate_1_side'                                                                    builder.py:2482
              INFO     Creating new physical group with name 'top_vertical_gate_1_top'                                                                     builder.py:2482
              INFO     Fragmenting...                                                                                                                    fragmenter.py:234
[02:04:17 PM] INFO     Creating new physical group with name 'top_vertical_gate_1'                                                                         builder.py:2482
              INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_top_gates_vertical.
                       png

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

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. 29 The final mesh of the device.

advanced features

Fig. 30 The final mesh highlighting the dot region.

[02:04:19 PM] INFO     Preparing to mesh                                                                                                                   builder.py:1502
[02:04:20 PM] INFO     Detecting appropriate random factor                                                                                                 builder.py:3608
              INFO     Increased random factor from 1e-09 to 2.1782153498347614e-05                                                                        builder.py:3626
              INFO     Random factor is now appropriate                                                                                                    builder.py:3632
              INFO     Meshing                                                                                                                             builder.py:1518
/home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/util/decorators.py:32: UserWarning: Encountered disconnected volumes: 3D Meshing 27 volumes with 8 connected components
  return func(self, *args, **kwargs)
/home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/util/decorators.py:32: UserWarning: 24 ill-shaped tets are still in the mesh
  return func(self, *args, **kwargs)
[02:04:22 PM] INFO     Checking mesh conformity                                                                                                            builder.py:3688
              INFO     Writing /tmp/tmpi4_jfqqv/mesh.msh                                                                                                   builder.py:1604
[02:04:23 PM] INFO     Checking connectivity                                                                                                               builder.py:3715

nodes:   0%|          | 0/5175 [00:00<?, ?it/s]
nodes:   0%|          | 0/5175 [00:00<?, ?it/s]
nodes: 100%|██████████| 5175/5175 [00:00<00:00, 3562370.46it/s]
nodes: 100%|██████████| 5175/5175 [00:00<00:00, 3037861.89it/s]
nodes: 100%|██████████| 5175/5175 [00:00<00:00, 2814147.96it/s]
              INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_final_mesh.png
[02:04:27 PM] INFO     Saving                                                                                                                              builder.py:1863
                       /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/figs/advanced_features_final_mesh_dot_regi
                       on.png

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

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")
[02:04:41 PM] INFO     Writing /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/meshes/demo.msh                    builder.py:1604
              INFO     Writing /home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/examples/tutorials/meshes/demo.xao                    builder.py:1604

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

Total running time of the script: (2 minutes 4.383 seconds)

Gallery generated by Sphinx-Gallery