Skip to content
Snippets Groups Projects
Commit be364e7c authored by Joseph Weston's avatar Joseph Weston
Browse files

merge branch 'feature/current-interpolation'

Generalize 'plotter.current_interpolation' to work for 1D and 3D,
and slightly refactor the code with more thorough comments.
parents e450adb9 b5d0b28b
No related branches found
No related tags found
No related merge requests found
Pipeline #
......@@ -1781,6 +1781,35 @@ def spectrum(syst, x, y=None, params=None, mask=None, file=None,
return output_fig(fig, file=file, show=show)
# Smoothing functions used with 'interpolate_current'.
# We generate the smoothing function by convolving the current
# defined on a line between the two sites with
# f(ρ, z) = (1 - ρ^2 - z^2)^2 Θ(1 - ρ^2 - z^2), where ρ and z are
# cylindrical coords defined with respect to the hopping.
# 'F' is the result of the convolution.
def _smoothing(rho, z):
r = 1 - rho * rho
r[r < 0] = 0
r = np.sqrt(r)
m = np.clip(z, -r, r)
rr = r * r
rrrr = rr * rr
mm = m * m
return m * (mm * (mm/5 - (2/3) * rr) + rrrr) + (8 / 15) * rrrr * r
# We need to normalize the smoothing function so that it has unit cross
# section in the plane perpendicular to the hopping. This is equivalent
# to normalizing the integral of 'f' over the unit hypersphere to 1.
# The smoothing function goes as F(ρ) = (16/15) (1 - ρ^2)^(5/2) in the
# plane perpendicular to the hopping, so the cross section is:
# A_n = (16 / 15) * σ_n * ∫_0^1 ρ^(n-1) (1 - ρ^2)^(5/2) dρ
# where σ_n is the surface element prefactor (2 in 2D, 2π in 3D). Rather
# that calculate A_n every time, we hard code its value for 1, 2 and 3D.
_smoothing_cross_sections = [16 / 15, np.pi / 3, 32 * np.pi / 105]
def interpolate_current(syst, current, relwidth=None, abswidth=None, n=9):
"""Interpolate currents in a system onto a regular grid.
......@@ -1791,7 +1820,7 @@ def interpolate_current(syst, current, relwidth=None, abswidth=None, n=9):
To make this vector field easier to visualize and interpret at different
length scales, it is smoothed by convoluting it with the bell-shaped bump
function ``f(r) = max(1 - (2*r / width)**2, 0)**2``. The bump width is
determined by the `max_res` and `width` parameters.
determined by the `relwidth` or `abswidth` parameters.
This routine samples the smoothed field on a regular (square or cubic)
grid.
......@@ -1808,7 +1837,7 @@ def interpolate_current(syst, current, relwidth=None, abswidth=None, n=9):
of the length of the longest side of the bounding box. This argument
is only used if `abswidth` is not given.
abswidth : float or `None`
Absolute width ot the bumps used to generate the field. Takes
Absolute width of the bumps used to generate the field. Takes
precedence over `relwidth`. If neither is given, the bump width is set
to four times the length of the shortest hopping.
n : int
......@@ -1872,11 +1901,7 @@ def interpolate_current(syst, current, relwidth=None, abswidth=None, n=9):
else:
width = abswidth
# TODO: Generalize 'factor' prefactor to arbitrary dimensions and remove
# this check. This check is done here to keep changes local
if dim != 2:
raise ValueError("'interpolate_current' only works for 2D systems.")
factor = (3 / np.pi) / (width / 2)
# Define length scale in terms of the bump width.
scale = 2 / width
lens *= scale
......@@ -1899,19 +1924,6 @@ def interpolate_current(syst, current, relwidth=None, abswidth=None, n=9):
slices[:, :, 0] = np.floor((min_hops - bbox_min) * grid_density)
slices[:, :, 1] = np.ceil((max_hops + 1.5*width - bbox_min) * grid_density)
# F is the antiderivative of the smoothing function
# f(ρ, z) = (1 - ρ^2 - z^2)^2 Θ(1 - ρ^2 - z^2), with respect to
# z,with F(ρ, -∞) = 0 and where Θ is the heaviside function.
def F(rho, z):
r = 1 - rho * rho
r[r < 0] = 0
r = np.sqrt(r)
m = np.clip(z, -r, r)
rr = r * r
rrrr = rr * rr
mm = m * m
return m * (mm * (mm/5 - (2/3) * rr) + rrrr) + (8 / 15) * rrrr * r
# Interpolate the field for each hopping.
for i in range(len(current)):
......@@ -1919,6 +1931,10 @@ def interpolate_current(syst, current, relwidth=None, abswidth=None, n=9):
# Zero volume: nothing to do.
continue
if np.isclose(current[i], 0):
# Current is 0, skip costly interpolation
continue
field_slice = [slice(*slices[i, d]) for d in range(dim)]
# Coordinates of the grid points that are within range of the current
......@@ -1934,11 +1950,13 @@ def interpolate_current(syst, current, relwidth=None, abswidth=None, n=9):
z *= scale
rho *= scale
magns = F(rho, z) - F(rho, z - lens[i])
magns *= current[i] * factor
magns = _smoothing(rho, z) - _smoothing(rho, z - lens[i])
magns *= current[i]
field[field_slice] += dirs[i] * magns[..., None]
field *= scale / _smoothing_cross_sections[dim - 1]
# 'field' contains contributions from both hoppings (i, j) and (j, i)
return field, ((region[0][0], region[0][-1]), (region[1][0], region[1][-1]))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment