""" Functionality to analyse bias triangles
@author: amjzwerver
"""
# %%
import numpy as np
import qtt
import qtt.pgeometry
import matplotlib.pyplot as plt
from qcodes.plots.qcmatplotlib import MatPlot
from qtt.data import diffDataset
[docs]def plotAnalysedLines(clicked_pts, linePoints1_2, linePt3_vert, linePt3_horz, linePt3_ints, intersect_point):
""" Plots lines based on three points clicked.
Args:
clicked_pts (array): lines between the three points (1-2), (2-3).
linePoints1_2 (array): line fitted through points 1 and 2.
linePt3_vert (array): vertical line through point 3.
linePt3_horz (array): horizontal line through point 3.
linePt3_ints (array): line through point 3 and its vert/horz intersection
with the line through point 1,2.
intersect_point (array): intersection point point 3, line1_2.
"""
qtt.pgeometry.plot2Dline(linePoints1_2, ':c', alpha=.5)
qtt.pgeometry.plot2Dline(linePt3_vert, ':b', alpha=.4)
qtt.pgeometry.plot2Dline(linePt3_horz, ':b', alpha=.4)
qtt.pgeometry.plot2Dline(linePt3_ints, ':b', alpha=.4)
qtt.pgeometry.plotPoints(intersect_point, '.b')
qtt.pgeometry.plotPoints(clicked_pts[:, 2:3], '.b')
linePt3_ints_short = np.column_stack((intersect_point, clicked_pts[:, 2:3]))
qtt.pgeometry.plotPoints(linePt3_ints_short, 'b')
[docs]def perpLineIntersect(ds, description, vertical=True, points=None, fig=588, diff_dir='xy'):
""" Takes three points in a graph and calculates the length of a linepiece
between a line through points 1,2 and a vertical/horizontal line
through the third point. Uses the currently active figure.
Args:
ds (dataset): dataset with charge stability diagram and gate voltage in mV.
description: TODO
vertical (bool): find intersection of point with line vertically (True)
or horizontally (False).
points (None or array): if None, then let the user select points.
fig (int): figure number.
diff_dir (None or 'xy'): specification of differentiation direction.
Returns:
(dict): 'intersection_point' = intersection point
'distance' = length of line from 3rd clicked point to line
through clicked points 1 and 2
'clicked_points' = coordinates of the three clicked points
"""
if diff_dir is not None:
diffDataset(ds, diff_dir='xy')
array_name = 'diff_dir_xy'
else:
array_name = ds.default_parameter_name()
plt.figure(fig)
plt.clf()
MatPlot(ds.arrays[array_name], num=fig)
ax = plt.gca()
ax.set_autoscale_on(False)
if description == 'lever_arm' and vertical:
print('''Please click three points;
Point 1: on the addition line for the dot represented on the vertical axis
Point 2: further on the addition line for the dot represented on the vertical axis
Point 3: on the triple point at the addition line for the dot represented on the horizontal axis
where both dot levels are aligned''')
elif description == 'lever_arm' and not vertical:
print('''Please click three points;
Point 1: on the addition line for the dot represented on the horizontal axis
Point 2: further on the addition line for the dot represented on the horizontal axis
Point 3: on the triple point at the addition line for the dot represented on the horizontal axis
where both dot levels are aligned''')
elif description == 'E_charging':
print('''Please click three points;
Point 1: on the (0, 1) - (0,2) addition line
Point 2: further on the (0, 1) - (0,2) addition line
Point 3: on the (0, 0) - (0, 1) addition line ''')
else:
# Do something here such that no three points need to be clicked
raise Exception('''Please make sure that the description argument of this function
is either 'lever_arm' or 'E_charging' ''')
if points is not None:
clicked_pts = points
else:
plt.title('Select three points')
plt.draw()
plt.pause(1e-3)
clicked_pts = qtt.pgeometry.ginput(3, '.c')
qtt.pgeometry.plotPoints(clicked_pts, ':c')
qtt.pgeometry.plotLabels(clicked_pts)
linePoints1_2 = qtt.pgeometry.fitPlane(clicked_pts[:, 0:2].T)
yy = clicked_pts[:, [2, 2]]
yy[1, -1] += 1
line_vertical = qtt.pgeometry.fitPlane(yy.T)
xx = clicked_pts[:, [2, 2]]
xx[0, -1] += 1
line_horizontal = qtt.pgeometry.fitPlane(xx.T)
if vertical:
i = qtt.pgeometry.intersect2lines(linePoints1_2, line_vertical)
intersectPoint = qtt.pgeometry.dehom(i)
line = intersectPoint[:, [0, 0]]
line[0, -1] += 1
else:
i = qtt.pgeometry.intersect2lines(linePoints1_2, line_horizontal)
intersectPoint = qtt.pgeometry.dehom(i)
line = intersectPoint[:, [0, 0]]
line[1, -1] += 1
linePt3_ints = qtt.pgeometry.fitPlane(line.T)
line_length = np.linalg.norm(intersectPoint - clicked_pts[:, 2:3])
# visualize
plotAnalysedLines(clicked_pts, linePoints1_2, line_vertical, line_horizontal, linePt3_ints, intersectPoint)
return {'intersection_point': intersectPoint, 'distance': line_length, 'clicked_points': clicked_pts,
'array_names': [array.name for array in ds.default_parameter_array().set_arrays]}
[docs]def lever_arm(bias, results, fig=None):
""" Calculates the lever arm of a dot by using bias triangles in charge sensing. Uses currently active figure.
Args:
bias (float): bias in uV between source and drain while taking the bias triangles.
results (dict): dictionary returned from the function perpLineIntersect
containing three points, the intersection point
between a line through 1,2 and the third point and the
length from points 3 to the intersection (horz/vert).
fig (bool): adds lever arm to title of already existing figure with points.
Returns:
lev_arm (float): the lever arm of the assigned dot in uV/mV.
"""
line_length = results['distance']
# in uV/mV
lev_arm = abs(bias / line_length)
if fig and len(plt.get_fignums()) != 0:
ax = plt.gca()
ax.set_autoscale_on(False)
if np.round(results['clicked_points'][0, 2], 2) == np.round(results['intersection_point'][0], 2):
gate = ax.get_ylabel()
else:
gate = ax.get_xlabel()
title = r'Lever arm %s: %.2f $\mu$eV/mV' % (gate, lev_arm)
plt.annotate('Length %s: %.2f mV' % (gate, line_length), xy=(0.05, 0.1), xycoords='axes fraction', color='k')
plt.annotate(title, xy=(0.05, 0.05), xycoords='axes fraction', color='k')
ax.set_title(title)
return lev_arm
[docs]def E_charging(lev_arm, results, fig=None):
"""
Calculates the charging energy of a dot by using charge stability diagrams.
Uses currently active figure.
Args:
lev_arm (float): lever arm for the gate to the dot.
results (dict): dictionary returned from the function perpLineIntersect
containing three points, the intersection point
between a line through 1,2 and the third point and the
length from points 3 to the intersection (horz/vert).
fig (bool): adds charging energy to title of already existing figure with points.
Returns:
E_charging (float): the charging energy for the dot.
"""
line_length = results['distance']
E_c = line_length * lev_arm
if fig and len(plt.get_fignums()) != 0:
ax = plt.gca()
ax.set_autoscale_on(False)
if np.round(results['clicked_points'][0, 2], 2) == np.round(results['intersection_point'][0], 2):
gate = ax.get_ylabel()[:2]
else:
gate = ax.get_xlabel()[:2]
title = 'E_charging %s: %.2f meV' % (gate, E_c / 1000)
plt.annotate('Length %s: %.2f mV' % (gate, line_length), xy=(0.05, 0.1), xycoords='axes fraction', color='k')
plt.annotate(title, xy=(0.05, 0.05), xycoords='axes fraction', color='k')
ax.set_title(title)
return E_c