Technical Questions
1. How to customize material properties in QTCAD?
You can customize materials in QTCAD by creating instances of the Material
class with your desired properties or by using built-in materials. Key steps include:
Create a custom material: Instantiate
Materialwith a dictionary of properties like permittivity (eps), bandgap (Eg), electron affinity (chi), and effective masses (mc,mv).from qtcad.device import materials as mt custom_mat = mt.Material({ 'name': 'CustomMaterial', 'eps': 12.0, 'Eg': 1.1, 'chi': 4.0, 'mc': [0.26], 'mv': [0.45] })
Use predefined materials: QTCAD provides predefined materials like silicon (
mt.Si) and silicon oxide (mt.SiO2) with default properties which can be modified.Define alloy materials: Use fitting functions to model alloy compositions:
Assign materials to device regions: Use the device’s
Device.new_regionmethod to specify materials and doping for each region.device.new_region('barrier', mt.SiO2) device.new_region('confined', mt.Si, pdoping=0, ndoping=0)
Additional properties: You can also customize advanced parameters such as effective mass tensors, band deformation potentials, and degeneracies, listed in the
Materialdocumentation.
Furthermore, in QTCAD Atoms, the tight-binding and Keating valence force-field model parameters
can also be modified in the Atoms Materials module.
2. Does QTCAD support magnetic fields?
QTCAD can simulate the effects of magnetic fields on electron or hole spins. However, it does not solve for magnetic fields from a given magnetization distribution.
To obtain magnetic field maps for use in QTCAD simulations (e.g., for spin qubit devices), users may utilize other software tools such as:
These tools can generate magnetic field distributions that can be imported into QTCAD for further analysis.
3. How Can I include strain effects in QTCAD simulations?
QTCAD’s Schrödinger solver supports strain effects using the Bir-Pikus formalism
(see Strain theory). Since QTCAD uses
\(\mathbf{k}\cdot\mathbf{p}\) or effective-mass theory under the envelope function
approximation, it focuses on band edges of parabolic bands rather than full band structures.
To include strain in your QTCAD simulation:
Deformation potentials: Strain effects are parametrized by deformation potentials set via material attributes:
cond_band_def_pot(for conduction band / electron calculations)vlnce_band_def_pot(for valence band / hole calculations)
These can be adjusted using the
qtcad.device.materials.Material.set_param()method. See theqtcad.device.materials.Materialdocumentation for details.Strain tensor: The strain tensor can be applied to the device using the
qtcad.device.Device.set_strainmethod. This method accepts:A uniform strain tensor as a 3×3 NumPy array
A spatially varying strain tensor as a function returning a 3×3 array
For examples and usage, refer to this tutorial.
Furthermore, our atomisitc modeling capabilities allow for strain effects to be simulated at the atomic level, providing a more detailed understanding of strain-induced phenomena in quantum devices.
If you have further questions, reach out to us by:
Submitting a ticket to the Nanoacademic Customer Support Center with a description of the issue and any relevant code snippets or error messages.
4. How to eliminate unphysical charge in my device?
Problem description In typical gated quantum dot devices, electrons or holes are confined within a host semiconductor (such as silicon or gallium arsenide), while a wider bandgap semiconductor or oxide forms a potential barrier separating the confined carriers from electrostatic gates used to tune the quantum dots. When strong gate potentials are applied, the conduction band edge (for electrons) or valence band edge (for holes) near the gate surfaces may cross the Fermi level, causing the non-linear Poisson solver to assign a significant charge density in that region. However, this charge accumulation may be unphysical at cryogenic temperatures because carriers cannot tunnel through sufficiently wide potential barriers from doped regions to the gate surfaces. This unphysical charge accumulation can prevent convergence of the Poisson solver.
Illustration
Generate the device mesh by running:
python qtcad/examples/practical_application/1-devicegen.py
Modify the applied gate potentials in Practical Application #2 example by setting:
# Applied potentials
Vtop_1 = -1.0
Vtop_2 = -1.0
Vtop_3 = -1.0
Vbottom_1 = -1.0
Vbottom_2 = -1.0
Vbottom_3 = -1.0
#(Changing from -0.5 V to -1.0 V)
Instead of running the Schrödinger solver, plot the band diagram and hole density below top gate 2:
# Plot band diagram along a vertical linecut below top gate 2
x, y, z = d.mesh.glob_nodes.T
an.plot_bands(d, (235e-9, 500e-9, np.max(z)), (235e-9, 500e-9, np.min(z)))
# Plot hole density along the same linecut
an.plot_linecut(mesh, d.p/1e6, (235e-9, 500e-9, np.max(z)), (235e-9, 500e-9, np.min(z)),
title="Hole density (cm$^{-3}$)")
Observe that the Poisson solver error saturates (around 0.02 V after ~18 iterations), failing to converge.
The band diagram shows strong valence band edge bending above the Fermi level near the gate interface, causing large, likely unphysical hole accumulation detrimental to solver convergence.
Solution: Suppressing Unwanted Charges
Immediately after defining device regions, declare the cap region as an ideal insulator by running:
# Set the cap to be an ideal insulator, in which:
## 1) Classical charge density is forced to zero
## 2) Carrier wave functions vanish in the Schrödinger solver
d.new_insulator("cap")
In this ideal insulator region:
Classical charge density is set exactly to zero
Carrier wave functions are forced to zero
This prevents charge accumulation near the gate interface, enabling the Poisson solver to converge. Band bending disappears near the gate, and hole density plots confirm the absence of unphysical charge accumulation.
Example code snippet
import pathlib
import numpy as np
from device import constants as ct
from device.mesh3d import Mesh, SubMesh
from device import materials as mt
from device import Device
from device.solver_params import SolverParams
from device.poisson import Solver as PoissonSolver
from device import analysis as an
# Load mesh
script_dir = pathlib.Path(__file__).parent.resolve()
path_mesh = str(script_dir / 'meshes' / 'gated_dot.msh2')
scaling = 1e-6
mesh = Mesh(scaling, path_mesh)
# Create device and set temperature
d = Device(mesh)
d.set_temperature(0.1)
# Define doping and material regions
doping = 3e18 * 1e6 # In SI units
d.new_region("cap", mt.GaAs)
d.new_region("barrier", mt.AlGaAs)
d.new_region("dopant_layer", mt.AlGaAs, ndoping=doping)
d.new_region("spacer_layer", mt.AlGaAs)
d.new_region("spacer_dot", mt.AlGaAs)
d.new_region("two_deg", mt.GaAs)
d.new_region("two_deg_dot", mt.GaAs)
d.new_region("substrate", mt.GaAs)
d.new_region("substrate_dot", mt.GaAs)
# Enable ideal insulator behavior for the cap region to suppress charge
# Uncomment the following line to activate:
# d.new_insulator("cap")
# Align bands using GaAs as reference
d.align_bands(mt.GaAs)
# Set applied potentials (strong gate voltages)
Vtop_1 = -1.0
Vtop_2 = -1.0
Vtop_3 = -1.0
Vbottom_1 = -1.0
Vbottom_2 = -1.0
Vbottom_3 = -1.0
barrier = 0.834 * ct.e # Schottky barrier height (n-type)
# Define boundary conditions
d.new_schottky_bnd("top_gate_1", Vtop_1, barrier)
d.new_schottky_bnd("top_gate_2", Vtop_2, barrier)
d.new_schottky_bnd("top_gate_3", Vtop_3, barrier)
d.new_schottky_bnd("bottom_gate_1", Vbottom_1, barrier)
d.new_schottky_bnd("bottom_gate_2", Vbottom_2, barrier)
d.new_schottky_bnd("bottom_gate_3", Vbottom_3, barrier)
d.new_ohmic_bnd("ohmic_bnd")
# Configure and run non-linear Poisson solver
solver_params = SolverParams({"tol": 1e-3, "maxiter": 100}, problem="poisson")
poisson_solver = PoissonSolver(d, solver_params=solver_params)
# Create submesh for quantum dot region and set dot region
submesh = SubMesh(mesh, ["spacer_dot", "two_deg_dot", "substrate_dot"])
d.set_dot_region(submesh)
# Solve Poisson equation
poisson_solver.solve()
# Plot results
x, y, z = d.mesh.glob_nodes.T
an.plot_bands(d, (235e-9, 500e-9, np.max(z)), (235e-9, 500e-9, np.min(z)))
an.plot_linecut(mesh, d.p / 1e6, (235e-9, 500e-9, np.max(z)), (235e-9, 500e-9, np.min(z)),
title="Hole density (cm$^{-3}$)")
5. I encountered an error when running the NEGF solver. What should I do?
If you encounter an error when running the NEGF solver, it is often due to issues with the mesh or boundary conditions. Here are some steps to troubleshoot:
Ensure that the mesh is extruded along the channel direction and that the boundaries are properly defined.
Verify that the boundary conditions are correctly set for the NEGF solver. In particular, two quantum leads—source and drain—must be specified using the
Device.new_quantum_lead_bnd()method. These must be defined on the mainDeviceobject before constructing the NEGFSubDevice.
For more details, see the NEGF solver documentation:
NEGF solver API documentation
If the error persists, please submit a ticket to the Nanoacademic Customer Support Center with a description of the issue and any relevant code snippets or error messages.