Gated Quantum Dot

The aim of this tutorial is to demonstrate how the builder can be used to accelerate the generation of meshes appropriate for modelling semiconductor nanodevices. Here, the demonstration is made for the following gated quantum-dot system:

gated_dot

Fig. 16 gated_dot

The left-hand side of the above figure shows the layout for this example device, which can be found here. This layout file is in .gds format and can be visualized and modified using, e.g. KLayout. In the above picture, the red rectangle represents the simulation domain, while the blue rectangles represent metallic gates deposited on top of the chip that are used to control the confinement potential used to achieve confinement of single charge carriers in the x-y plane.

The right-hand side of the above figure illustrates the heterostructure stack, i.e., the multiple layers of materials used to confine charge carriers in the z direction. Each layer will be labeled differently to represent the role it plays in the heterostructure, and will be assigned a certain number of mesh layers depending on how accurate the simulation should be in each region. In this example, the mismatch between conduction band edges of GaAs and AlGaAs is used to form a Barrier isolating electrons in the substrate from the Cap region, and an n-doped layer is used to bend the conduction band edge and form a triangular confinement potential in the region indicated as 2DEG in the above figure. Finally, a Spacer region is used to isolate the quantum dot formed in the 2DEG from the dopants.

Setup

Constants

Next we define some constants that will be useful in setting up the device in the subsequent steps. All lengths are given in nanometers.

# Mesh characteristic lengths
char_len = 50  # Note that this is very low
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 = 5
substrate_thick = 100 - two_deg_thick

Initialization

The Builder is based on the principle of taking a two dimensional shape and creating or editing three dimensional geometry through extrusion and etching, as well as using these shapes to define surfaces. Thus our first step will be to load an OASIS layout file with the two dimensional shapes we are going to use.

In order to do that, we initialize the instance and load the layout we are going to use. Each qtcad.builder.Builder instance corresponds to one Gmsh process and multiple instances can coexist. The layout can be imported as an OASIS file saved with the .oas extension. In this example we will load the gds file found gated_qd.oas. For example, in KLayout, this is done using File > Save As by selecting OASIS files in the drop-down menu 'Type' under the file name field.

builder = Builder(name="Quantum Dot").load_layout(
    save_dir / "layouts" / "gated_qd.oas", cell_name="builder"
)

In the constructor we provided a name for the model that we are going to create. Then we instructed the Builder to load the layout file. By default, all layers from the cell named builder are loaded (see qtcad.builder.MaskContainer.load_layout for details). Each layer becomes a qtcad.builder.Mask mask object containing multiple qtcad.builder.Polygon` objects. The shape names are read from the "name" user property. Alternatively, they can be set using text labels (as has been done in Advanced features). Using qtcad.builder.Builder.use_mask we will later select a particular mask. By default, this selects all shapes within that mask for subsequent operations. If we would like to be more specific, we can use qtcad.builder.Builder.use_shapes to select one or multiple shapes. The names of the physical surfaces and volumes that qtcad.builder.Builder creates are then derived from the names of the shapes. In general, the names of the physical groups are automatically generated base on the shape names (qtcad.builder.Builder.group_from_shape, if the shape has no name then one will be generated), on the name of the mask (qtcad.builder.Builder.group_from_mask) or on a given string (qtcad.builder.Builder.set_group_name). For extrusions, the base, top, and side surfaces will bear the name of the volume the bound with the suffixes "_base", "_top", and "_side", respectively.

Using qtcad.builder.Builder.print_mask_tree, we can print out the result of loading the layout file.

builder.print_mask_tree()
Layout
├── Mask 1 "dot-region"
│   └── 0  Polygon  "dot_region"
├── Mask 4 "gates"
│   ├── 0  Polygon  "top_gate_2"
│   ├── 1  Polygon  "top_gate_1"
│   ├── 2  Polygon  "bottom_gate_1"
│   ├── 3  Polygon  "bottom_gate_3"
│   ├── 4  Polygon  "bottom_gate_2"
│   └── 5  Polygon  "top_gate_3"
└── Mask 0 "footprint"
    └── 0  Polygon  "footprint"

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

We can also view the shapes in the masks using qtcad.builder.Builder.view_shapes:

builder.use_mask("gates").view_shapes(save="out/layout_gates.svg", angles=(0, 0, 90))
gated qd
<qtcad.builder.builder.Builder object at 0x7f5996b46270>

In this case, we have loaded three Masks. The first contains the shapes that we will later use to define the electrostatic gate surfaces on the device. Second, the "footprint" mask contains a simple rectangle with the outline of the device. Lastly, the "dot-region" mask contains the outline of the region that we will later declare as the “dot-region” where no classical charges are allowed.

Creating the heterostructure

Now that we have loaded our layouts, we will define the create the basic layer structure of the device as shown in Fig. 16. In order to accomplish this, we will extrude the rectangle in the "footprint" mask.

The Builder (qtcad.builder.Builder) uses the builder pattern meaning that most operations are implemented as chained method calls. To create the heterostructure stack we then run the following code:

(
    builder.set_mesh_size(char_len)
    .set_min_elements(1)
    .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)
    #
    # Cap
    #
    .set_group_name("cap")
    .extrude(cap_thick)
)
<qtcad.builder.builder.Builder object at 0x7f5996b46270>

Above, wrapping the code in parenthesis allows to put the chained method calls on separate lines. In the second line we tell the Builder to use the characteristic length char_len when meshing the subsequently created volumes. Calling qtcad.builder.Builder.set_min_elements tells the Builder to ensure that there are will be at least two mesh cells along the narrowest dimension of the created entities (surfaces or volumes).

In the fourth line, we tell the Builder to use the mask named "footprint" for the upcoming operations. This will automatically select the only shape in this mask for the subsequent operations. Here, this is a simple rectangle with the appropriate dimensions (see Fig. 17).

gated_dot

Fig. 17 The footprint layout.

Subsequently, we save the current z coordinate for subsequent use. The z coordinate can be set with qtcad.builder.Builder.set_z_from_group or qtcad.builder.Builder.set_z_from_group and will be automatically advanced with each extrusion. Then, we tell builder to name the created surfaces/volumes based on the string "substrate" (rather than the name of the shape, see also Selection of shapes and naming modes) and extrude this shape by substrate_thick in line ten to create a volume named substrate__dg_vol. This process is then repeated with all subsequent layers. (Another way to change the name in this case would be to use qtcad.builder.Builder.rename_shape.)

At any point we can call qtcad.builder.Builder.view to open a Gmsh GUI window with the current model.

dg.view(True, volume_labels=True)

If we pass True as the first argument, the view process will pause the execution of the main process. Otherwise, execution will continue while the window is open. As can be seen in stack, each created volume derives it’s name from the name of the shape in the mask we set above. In this script we we use the save option to protduce an svg figure.

builder.view(
    surfaces=False,
    volume_labels=True,
    angles=(-90, 0, 85),
    save="out/heterostructure.svg",
    zoom=0.8,
)
gated qd
<qtcad.builder.builder.Builder object at 0x7f5996b46270>

Creating a dot region

The volume that will later be used to model the quantum features of the device will be a subregion of the total volume which has to be designated by its own physical groups. Furthermore, we typically desire a finer mesh in this region. In our case the dot region spans from the bottom of the substrate to the top of the spacer and will be created by simply extruding the first shape of the dot_region between the appropriate z coordinates.

To create the dot region we run the following:

dot_height = builder.get_z_from_group("spacer") - builder.get_z_from_group(
    "substrate", bottom=True
)
(
    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_shape()
    .extrude(dot_height)
)
<qtcad.builder.builder.Builder object at 0x7f5996b46270>

In line one we compute the total height of the dot region. We then set the Builder z-coordinate to the bottom of the substrate in line three. In line four, we switch the Builder to overlay mode, meaning that newly created volumes will be named according to the scheme [name of intersecting volume].[name of newly created volume] (see also qtcad.builder.Builder.FragmentationMode). This will allow us to disambiguate the different heterostructure layers of the dot region. Then we instruct the generator to take the minimum of the mesh size set with qtcad.builder.Builder.set_mesh_size using qtcad.builder.Builder.minimum_mesh_size and the mesh sizes already present in our heterostructure. Subsequently, we select the mask "dot-region" (see Fig. 18) and subsequently tell builder to derive the names of the created volume from the names of the shapes in the mask. Finally, we extrude the dot region.

../../../_images/dot_region.png

Fig. 18 The dot region layout.

Below we can see the result of these operations. Note that the part of the dot region intersecting with the substrate is called substrate.dot_region.

builder.view(
    surfaces=False,
    volume_labels=True,
    angles=(-82, 0, 90),
    save="out/model_dr.svg",
    zoom=2,
)
gated qd
<qtcad.builder.builder.Builder object at 0x7f5996b46270>

Adding the gate surfaces

Lastly, we add the surfaces that will be used to define the boundary conditions later on. These surfaces are the back gate at the bottom of the substrate and the control gates on the top of the device.

To add the surfaces we execute the following:

(
    #
    # Back Gate
    #
    builder.set_mesh_size(char_len)
    .use_mask("footprint")
    .use_shape("footprint")
    .displace_mode()
    .set_group_name("ohmic_bnd")
    .set_z_from_group("substrate", bottom=True)
    .add_surface()
    #
    # Control Gates
    #
    .use_mask("gates")
    .set_mesh_size(dot_char_len)
    .set_z_from_group("cap")
    .group_from_shape()
    .add_surface()
)
<qtcad.builder.builder.Builder object at 0x7f5996b46270>

First, we select the coarser characteristic length and select the mask "footprint" as well as the the shape "footprint" within that mask (the mask now contains multiple shapes due to our copying and renaming while building the heterostructure). We then rename the selected shape create the back gate at the bottom. Subsequently we switch back to the displace_mode so that the names of the surfaces we create will be directly derived from the shape names (see also qtcad.builder.Builder.displace_mode). Finally we create the back gate surface the call to add_surface in line eight. Then, we use the the mask "gates" (see Fig. 19) to at the control gates at the bottom of the device. As we haven’t selected specific shapes within that mask, all shapes will be used at once to create the surfaces for the control gates.

../../../_images/layout_gates.png

Fig. 19 The gates layout.

../../../_images/user_prop.png

Fig. 20 The user property used to configure the names of shapes.

This results in the following (only showing the surfaces we just created):

builder.view(
    surface_labels=True,
    surfaces=True,
    angles=(-80, 0, 10),
    save="out/surfs.svg",
    zoom=0.8,
    groups=[
        "ohmic_bnd",
        "top_gate_1",
        "top_gate_2",
        "top_gate_3",
        "bottom_gate_1",
        "bottom_gate_2",
        "bottom_gate_3",
    ],
)
gated qd
<qtcad.builder.builder.Builder object at 0x7f5996b46270>

We see, that each gate is named according to the name of the shape.

Meshing

Finally, we can save the mesh generated from the instructions above to the disk using the qtcad.builder.Builder.mesh method:

builder.mesh(3, algorithm3d=MeshAlgorithm3D.HXT, show_gmsh_output=True).write(
    save_dir / "meshes/gated_dot.msh"
)
/home/hiro/Documents/org/roam/code/qtcad_flake/qtcad/packages/builder/src/qtcad/builder/core/util/decorators.py:33: UserWarning: Encountered disconnected volumes: 3D Meshing 9 volumes with 2 connected components
  return func(self, *args, **kwargs)

nodes:   0%|          | 0/82346 [00:00<?, ?it/s]
nodes:   0%|          | 0/82346 [00:00<?, ?it/s]
nodes: 100%|██████████| 82346/82346 [00:00<00:00, 4991316.92it/s]
nodes: 100%|██████████| 82346/82346 [00:00<00:00, 4912235.03it/s]
nodes: 100%|██████████| 82346/82346 [00:00<00:00, 4858885.49it/s]

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

Here the first argument sets the meshing dimension and the save input gives the path and name of the output mesh we wish to save. By default, the output mesh will not be saved. However here we have specified that the output mesh should be saved to the meshes/ directory under the name gated_dot.msh. We refer to qtcad.builder.Builder.mesh for further details.

The resulting mesh is shown below. Note how thinner layers use smaller mesh-sizes, as does the dot-region.

builder.view(
    surfaces=False,
    volume_labels=True,
    angles=(-90, 0, 85),
    save="out/mesh.png",
)

builder.view(
    surfaces=False,
    volume_labels=True,
    angles=(-90, 0, 85),
    save="out/mesh_dr.png",
    groups=["substrate.dot_region", "two_deg.dot_region", "spacer.dot_region"],
)
gated qd
gated qd
<qtcad.builder.builder.Builder object at 0x7f5996b46270>

Total running time of the script: (1 minutes 0.520 seconds)

Gallery generated by Sphinx-Gallery