Skip to content

Commit

Permalink
major refactor of the gate voltage composer
Browse files Browse the repository at this point in the history
  • Loading branch information
b-vanstraaten committed Jul 19, 2024
1 parent e39db1a commit 60a8b8e
Show file tree
Hide file tree
Showing 39 changed files with 671 additions and 452 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ voltage_composer = GateVoltageComposer(n_gate=model.n_gate)
vx_min, vx_max = -5, 5
vy_min, vy_max = -5, 5
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(0, vy_min, vx_max, 400, 1, vy_min, vy_max, 400)
vg = voltage_composer._do2d(0, vy_min, vx_max, 400, 1, vy_min, vy_max, 400)

# run the simulation with the quantum dot array open such that the number of charge carriers is not fixed
n_open = model.ground_state_open(vg) # n_open is a (100, 100, 2) array encoding the
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Project information
project = 'Qarray'
author = 'Barnaby van Straaten'
release = '1.1.1'
release = '1.3.0'

# Add any Sphinx extension module names here, as strings.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx_rtd_theme']
Expand Down
13 changes: 13 additions & 0 deletions docs/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,21 @@ so we can combine them to create more complex noise models.

.. code:: python
from qarray import ChargeSensedDotArray, GateVoltageComposer
from qarray.noise_models import WhiteNoise, TelegraphNoise, NoNoise
# defining the capacitance matrices
Cdd = [[0., 0.1], [0.1, 0.]] # an (n_dot, n_dot) array of the capacitive coupling between dots
Cgd = [[1., 0.2, 0.05], [0.2, 1., 0.05], ] # an (n_dot, n_gate) array of the capacitive coupling between gates and dots
Cds = [[0.02, 0.01]] # an (n_sensor, n_dot) array of the capacitive coupling between dots and sensors
Cgs = [[0.06, 0.05, 1]] # an (n_sensor, n_gate) array of the capacitive coupling between gates and sensor dots
# creating the model
model = ChargeSensedDotArray(
Cdd=Cdd, Cgd=Cgd, Cds=Cds, Cgs=Cgs,
coulomb_peak_width=0.05, T=100
)
# defining a white noise model with an amplitude of 1e-2
white_noise = WhiteNoise(amplitude=1e-2)
Expand Down
Binary file modified docs/source/figures/getting_started_example.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/source/figures/latching.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 14 additions & 3 deletions docs/source/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,19 @@ to perform a scan of the quantum dot system. These arrays contain the simulated
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(
x_gate = 0, x_min = -5, x_max = 5 , x_res = 100,
y_gate = 0, y_min = -5, y_max = 5 , y_res = 100
x_gate = 'P1', x_min = -5, x_max = 5 , x_res = 100,
y_gate = 'P2', y_min = -5, y_max = 5 , y_res = 100
)
This scan sweeps the gate voltages of the quantum dot system from -5 to 5 in both the x and y directions, with 100 points in each direction. The :code:`do2d` method returns a (100, 100, 2) array encoding the gate voltage for each gate at each point in the measurement. To
sweep over the virtualised plunger gates simply use the arguments 'vP1' and 'vP2' instead of 'P1' and 'P2'. To sweep over the detuning and onsite energy
use the

.. code:: python
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(
x_gate = 'e1_2', x_min = -5, x_max = 5 , x_res = 100,
y_gate = 'U1_2', y_min = -5, y_max = 5 , y_res = 100
)
Now that we have the gate voltage arrays, we can calculate the charge configuration of the quantum dot system at each of these voltage configurations. We can do this for an open dot array (where the array is able freely exchange charge carriers with the reservoir) or a closed dot array (where the number of charge carriers is fixed).
Expand Down Expand Up @@ -193,7 +204,7 @@ method will return the gate voltages corresponding to the middle of the [0, 1] -
vx_min, vx_max = -5, 5
vy_min, vy_max = -5, 5
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(0, vy_min, vx_max, 200, 1, vy_min, vy_max, 200)
vg = voltage_composer.do2d('P1', vy_min, vx_max, 200, 'P2', vy_min, vy_max, 200)
# centering the voltage sweep on the [0, 1] - [1, 0] interdot charge transition on the side of a charge sensor coulomb peak
vg += model.optimal_Vg([0.5, 0.5, 0.6])
Expand Down
7 changes: 4 additions & 3 deletions examples/charge_sensing.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from qarray import ChargeSensedDotArray, GateVoltageComposer
import matplotlib.pyplot as plt
import numpy as np

from qarray import ChargeSensedDotArray

# defining the capacitance matrices
Cdd = [[0., 0.1], [0.1, 0.]] # an (n_dot, n_dot) array of the capacitive coupling between dots
Expand All @@ -15,13 +15,14 @@
coulomb_peak_width=0.05, T=100
)

voltage_composer = GateVoltageComposer(model.n_gate)

# defining the min and max values for the dot voltage sweep
vx_min, vx_max = -2, 2
vy_min, vy_max = -2, 2
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(0, vy_min, vx_max, 100, 1, vy_min, vy_max, 100)
vg = model.gate_voltage_composer.do2d(1, vy_min, vx_max, 100, 2, vy_min, vy_max, 100)

z, n = model.do2d_open(1, vy_min, vx_max, 100, 2, vy_min, vy_max, 100)

# centering the voltage sweep on the [0, 1] - [1, 0] interdot charge transition on the side of a charge sensor coulomb peak
vg += model.optimal_Vg([0.5, 0.5, 0.6])
Expand Down
10 changes: 6 additions & 4 deletions examples/default_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@
model.run_gui()

# a helper class designed to make it easy to create gate voltage arrays for nd sweeps
voltage_composer = GateVoltageComposer(n_gate=model.n_gate)
voltage_composer = GateVoltageComposer(n_gate=model.n_gate, n_dot=model.n_dot)
voltage_composer.virtual_gate_matrix = -np.linalg.pinv(model.cdd_inv @ model.cgd)
voltage_composer.virtual_gate_origin = np.zeros(model.n_gate)

# defining the min and max values for the dot voltage sweep
# defining the min and max values for the dot voltage sweep
vx_min, vx_max = -5, 5
vy_min, vy_max = -5, 5
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(0, vy_min, vx_max, 400, 1, vy_min, vy_max, 400)
vg = voltage_composer.do2d('e1_2', vy_min, vx_max, 400, 'U1_2', vy_min, vy_max, 400)

# run the simulation with the quantum dot array open such that the number of charge carriers is not fixed
n_open = model.ground_state_open(vg) # n_open is a (100, 100, 2) array encoding the
Expand All @@ -49,11 +51,11 @@

# plot the results
fig, ax = plt.subplots(1, 2, figsize=(10, 5))
ax[0].imshow(z_open.T, extent=(vx_min, vx_max, vy_min, vy_max), origin='lower', cmap='binary')
ax[0].imshow(z_open, extent=(vx_min, vx_max, vy_min, vy_max), origin='lower', cmap='binary')
ax[0].set_title('Open Dot Array')
ax[0].set_xlabel('Vx')
ax[0].set_ylabel('Vy')
ax[1].imshow(z_closed.T, extent=(vx_min, vx_max, vy_min, vy_max), origin='lower', cmap='binary')
ax[1].imshow(z_closed, extent=(vx_min, vx_max, vy_min, vy_max), origin='lower', cmap='binary')
ax[1].set_title('Closed Dot Array')
ax[1].set_xlabel('Vx')
ax[1].set_ylabel('Vy')
Expand Down
78 changes: 55 additions & 23 deletions examples/double_dot.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"metadata": {
"collapsed": true,
"ExecuteTime": {
"end_time": "2024-05-09T14:55:46.979885Z",
"start_time": "2024-05-09T14:55:46.977717Z"
"end_time": "2024-07-19T20:22:21.015893Z",
"start_time": "2024-07-19T20:22:20.292484Z"
}
},
"source": [
Expand All @@ -23,14 +23,14 @@
"\n",
"from qarray import (DotArray, GateVoltageComposer, dot_occupation_changes)"
],
"execution_count": 16,
"outputs": []
"outputs": [],
"execution_count": 1
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2024-05-09T14:55:46.992206Z",
"start_time": "2024-05-09T14:55:46.989325Z"
"end_time": "2024-07-19T20:22:21.019704Z",
"start_time": "2024-07-19T20:22:21.016954Z"
}
},
"cell_type": "code",
Expand All @@ -53,33 +53,45 @@
"voltage_composer = GateVoltageComposer(n_gate=model.n_gate)"
],
"id": "433b3691c25e5baa",
"execution_count": 17,
"outputs": []
"outputs": [],
"execution_count": 2
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2024-05-09T14:55:46.995935Z",
"start_time": "2024-05-09T14:55:46.993152Z"
"end_time": "2024-07-19T20:22:21.257810Z",
"start_time": "2024-07-19T20:22:21.020433Z"
}
},
"cell_type": "code",
"source": [
"# using the dot voltage composer to create the dot voltage array for the 2d sweep\n",
"vg = voltage_composer.do2d(\n",
" x_gate=0, x_min = -10, x_max = 5, x_res = 400,\n",
" y_gate=1, y_min = -10, y_max = 5, y_res = 400\n",
"vg = voltage_composer._do2d(\n",
" x_gate=1, x_min = -10, x_max = 5, x_res = 400,\n",
" y_gate=2, y_min = -10, y_max = 5, y_res = 400\n",
")"
],
"id": "6f75223d6cd3f24",
"execution_count": 18,
"outputs": []
"outputs": [
{
"ename": "AttributeError",
"evalue": "'GateVoltageComposer' object has no attribute '_do2d'",
"output_type": "error",
"traceback": [
"\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[0;31mAttributeError\u001B[0m Traceback (most recent call last)",
"Cell \u001B[0;32mIn[3], line 2\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;66;03m# using the dot voltage composer to create the dot voltage array for the 2d sweep\u001B[39;00m\n\u001B[0;32m----> 2\u001B[0m vg \u001B[38;5;241m=\u001B[39m voltage_composer\u001B[38;5;241m.\u001B[39m_do2d(\n\u001B[1;32m 3\u001B[0m x_gate\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m1\u001B[39m, x_min \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m10\u001B[39m, x_max \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m5\u001B[39m, x_res \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m400\u001B[39m,\n\u001B[1;32m 4\u001B[0m y_gate\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m2\u001B[39m, y_min \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m10\u001B[39m, y_max \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m5\u001B[39m, y_res \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m400\u001B[39m\n\u001B[1;32m 5\u001B[0m )\n",
"\u001B[0;31mAttributeError\u001B[0m: 'GateVoltageComposer' object has no attribute '_do2d'"
]
}
],
"execution_count": 3
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2024-05-09T14:55:47.332984Z",
"start_time": "2024-05-09T14:55:47.003416Z"
"end_time": "2024-07-19T20:22:21.258596Z",
"start_time": "2024-07-19T20:22:21.258545Z"
}
},
"cell_type": "code",
Expand All @@ -98,14 +110,14 @@
"plt.ylabel('Vg1 (V)')"
],
"id": "2218463f9e18a09a",
"execution_count": 19,
"outputs": []
"outputs": [],
"execution_count": null
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2024-05-09T14:55:47.701449Z",
"start_time": "2024-05-09T14:55:47.333992Z"
"end_time": "2024-07-19T20:22:27.077023Z",
"start_time": "2024-07-19T20:22:27.062959Z"
}
},
"cell_type": "code",
Expand All @@ -124,8 +136,28 @@
"plt.ylabel('Vg1 (V)')"
],
"id": "270ce317b1ed9212",
"execution_count": 20,
"outputs": []
"outputs": [
{
"ename": "NameError",
"evalue": "name 'vg' is not defined",
"output_type": "error",
"traceback": [
"\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[0;31mNameError\u001B[0m Traceback (most recent call last)",
"Cell \u001B[0;32mIn[4], line 3\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;66;03m# calculating the dot occupation changes for the 2d sweep for an closed double dot containing 2 holes \u001B[39;00m\n\u001B[1;32m 2\u001B[0m t0 \u001B[38;5;241m=\u001B[39m time\u001B[38;5;241m.\u001B[39mtime()\n\u001B[0;32m----> 3\u001B[0m n \u001B[38;5;241m=\u001B[39m model\u001B[38;5;241m.\u001B[39mground_state_closed(vg, n_charges\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m2\u001B[39m) \u001B[38;5;66;03m# computing the ground state by calling the function\u001B[39;00m\n\u001B[1;32m 4\u001B[0m t1 \u001B[38;5;241m=\u001B[39m time\u001B[38;5;241m.\u001B[39mtime()\n\u001B[1;32m 5\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mElapsed time: \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mt1\u001B[38;5;250m \u001B[39m\u001B[38;5;241m-\u001B[39m\u001B[38;5;250m \u001B[39mt0\u001B[38;5;132;01m:\u001B[39;00m\u001B[38;5;124m.2f\u001B[39m\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m s or one pixel every \u001B[39m\u001B[38;5;132;01m{\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;241m1e6\u001B[39m\u001B[38;5;250m \u001B[39m\u001B[38;5;241m*\u001B[39m\u001B[38;5;250m \u001B[39m(t1\u001B[38;5;250m \u001B[39m\u001B[38;5;241m-\u001B[39m\u001B[38;5;250m \u001B[39mt0)\u001B[38;5;250m \u001B[39m\u001B[38;5;241m/\u001B[39m\u001B[38;5;250m \u001B[39m(vg\u001B[38;5;241m.\u001B[39msize\u001B[38;5;250m \u001B[39m\u001B[38;5;241m/\u001B[39m\u001B[38;5;241m/\u001B[39m\u001B[38;5;250m \u001B[39m\u001B[38;5;241m2\u001B[39m)\u001B[38;5;132;01m:\u001B[39;00m\u001B[38;5;124m.2f\u001B[39m\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m us\u001B[39m\u001B[38;5;124m'\u001B[39m)\n",
"\u001B[0;31mNameError\u001B[0m: name 'vg' is not defined"
]
}
],
"execution_count": 4
},
{
"metadata": {},
"cell_type": "code",
"outputs": [],
"execution_count": null,
"source": "",
"id": "c6c65273e481269a"
}
],
"metadata": {
Expand Down
2 changes: 1 addition & 1 deletion examples/double_dot.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
vx_min, vx_max = -5, 5
vy_min, vy_max = -5, 5
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(0, vy_min, vx_max, 500, 1, vy_min, vy_max, 500)
vg = voltage_composer.do2d('vP1', vy_min, vx_max, 500, 'vP2', vy_min, vy_max, 500)

# creating the figure and axes
fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)
Expand Down
4 changes: 2 additions & 2 deletions examples/figure_3b.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
)
model.max_charge_carriers = 2

voltage_composer = GateVoltageComposer(n_gate=model.n_gate)
voltage_composer = GateVoltageComposer(n_gate=model.n_gate, n_dot=model.n_dot)

vx_min, vx_max = -1.4, 0.6
vy_min, vy_max = -1, 1
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(0, vy_min, vx_max, 200, 3, vy_min, vy_max, 200)
vg = voltage_composer.do2d(1, vy_min, vx_max, 200, 4, vy_min, vy_max, 200)
vg += model.optimal_Vg(np.array([0.7, 0.57, 0.52, 1]))

n = model.ground_state_open(vg)
Expand Down
13 changes: 6 additions & 7 deletions examples/figure_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

voltage_composer = GateVoltageComposer(
n_gate=model.n_gate,
n_dot=model.n_dot,
virtual_gate_matrix=virtual_gate_matrix,
virtual_gate_origin=virtual_gate_origin
)
Expand All @@ -54,19 +55,17 @@
vx_min, vx_max = -1.6, 1.6
vy_min, vy_max = -2.4, 2.4

vg = voltage_composer.do2d_virtual(1, vy_min, vx_max, N, 3, vy_min, vy_max, N)

# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg_lt = voltage_composer.do2d_virtual(1, vx_min, vx_max, N, 0, vy_min, vy_max, N)
vg_lb = voltage_composer.do2d_virtual(1, vx_min, vx_max, N, 4, -vy_min, -vy_max, N)
vg_rt = voltage_composer.do2d_virtual(3, -vx_min, -vx_max, N, 0, vy_min, vy_max, N)
vg_rb = voltage_composer.do2d_virtual(3, -vx_min, -vx_max, N, 4, -vy_min, -vy_max, N)
vg_lt = voltage_composer.do2d('vP2', vx_min, vx_max, N, 'vP1', vy_min, vy_max, N)
vg_lb = voltage_composer.do2d('vP2', vx_min, vx_max, N, 'vP5', -vy_min, -vy_max, N)
vg_rt = voltage_composer.do2d('vP4', -vx_min, -vx_max, N, 'vP1', vy_min, vy_max, N)
vg_rb = voltage_composer.do2d('vP4', -vx_min, -vx_max, N, 'vP5', -vy_min, -vy_max, N)

vg = vg_lt + vg_lb + vg_rt + vg_rb
scale = -0.5
shift = -0.

vg = vg + voltage_composer.do1d(2, shift - scale, shift + scale, N)[:, np.newaxis, :]
vg = vg + voltage_composer.do1d('vP3', shift - scale, shift + scale, N)[:, np.newaxis, :]

t0 = time.time()
n = model.ground_state_closed(vg, 5)
Expand Down
18 changes: 0 additions & 18 deletions examples/gate_voltage_composer_tricks.py

This file was deleted.

6 changes: 3 additions & 3 deletions examples/latching.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""
An example demonstrating the use of the latching models
"""
from matplotlib import pyplot as plt
import numpy as np
from matplotlib import pyplot as plt

from qarray import ChargeSensedDotArray, GateVoltageComposer, WhiteNoise, LatchingModel, TelegraphNoise

Expand All @@ -29,7 +29,7 @@
# # probability of the a charge transition from (1, 1) to (0, 2) when the (0, 2) is lower in energy per pixel
# )

white_noise = WhiteNoise(amplitude=1e-3)
white_noise = WhiteNoise(amplitude=1e-10)

# defining a telegraph noise model with p01 = 5e-4, p10 = 5e-3 and an amplitude of 1e-2
random_telegraph_noise = TelegraphNoise(p01=5e-4, p10=5e-3, amplitude=1e-2)
Expand Down Expand Up @@ -64,7 +64,7 @@
vx_min, vx_max = -0.5, 0.5
vy_min, vy_max = -0.5, 0.5
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d_virtual(0, vy_min, vx_max, 100, 1, vy_min, vy_max, 100)
vg = voltage_composer.do2d(1, vy_min, vx_max, 100, 2, vy_min, vy_max, 100)


# creating the figure and axes
Expand Down
2 changes: 1 addition & 1 deletion examples/linear_quadruple_dot.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
vx_min, vx_max = -10, 10
vy_min, vy_max = -10, 10
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(0, vy_min, vx_max, 200, 3, vy_min, vy_max, 200)
vg = voltage_composer.do2d(1, vy_min, vx_max, 200, 4, vy_min, vy_max, 200)

# creating the figure and axes
fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)
Expand Down
2 changes: 1 addition & 1 deletion examples/linear_triple_dot.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
vx_min, vx_max = -5, 10
vy_min, vy_max = -5, 10
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(0, vy_min, vx_max, 1000, 2, vy_min, vy_max, 1000)
vg = voltage_composer._do2d(1, vy_min, vx_max, 1000, 3, vy_min, vy_max, 1000)

# creating the figure and axes
fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)
Expand Down
2 changes: 1 addition & 1 deletion examples/noise_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
vx_min, vx_max = -2, 2
vy_min, vy_max = -2, 2
# using the dot voltage composer to create the dot voltage array for the 2d sweep
vg = voltage_composer.do2d(0, vy_min, vx_max, 100, 1, vy_min, vy_max, 100)
vg = voltage_composer._do2d(1, vy_min, vx_max, 100, 3, vy_min, vy_max, 100)
vg += model.optimal_Vg([0.5, 1.5, 0.7])

# creating the figure and axes
Expand Down
Loading

0 comments on commit 60a8b8e

Please sign in to comment.