"""Fermi surfaces."""
from asr.core import command, ASRResult, prepare_result
[docs]
def bz_vertices(cell):
import numpy as np
from scipy.spatial import Voronoi
icell = np.linalg.inv(cell) * 2 * np.pi
ind = np.indices((3, 3)).reshape((2, 9)) - 1
G = np.dot(icell, ind).T
vor = Voronoi(G)
bz1 = []
for vertices, points in zip(vor.ridge_vertices, vor.ridge_points):
if -1 not in vertices and 4 in points:
normal = G[points].sum(0)
normal /= (normal**2).sum()**0.5
bz1.append((vor.vertices[vertices], normal))
return bz1
[docs]
def find_contours(eigs_nk, bzk_kv, s_nk=None):
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
minx = np.min(bzk_kv[:, 0:2])
maxx = np.max(bzk_kv[:, 0:2])
npoints = 1000
xi = np.linspace(minx, maxx, npoints)
yi = np.linspace(minx, maxx, npoints)
zis = []
for eigs_k in eigs_nk:
zi = griddata((bzk_kv[:, 0], bzk_kv[:, 1]), eigs_k,
(xi[None, :], yi[:, None]), method='cubic')
zis.append(zi)
contours = []
for n, zi in enumerate(zis):
cs = plt.contour(xi, yi, zi, levels=[0])
paths = cs.collections[0].get_paths()
for path in paths:
vertices = []
for vertex in path.iter_segments(simplify=False):
vertices.append(np.array((vertex[0][0],
vertex[0][1],
vertex[1], 0), float))
vertices = np.array(vertices)
if s_nk is not None:
si = griddata((bzk_kv[:, 0], bzk_kv[:, 1]), s_nk[n],
vertices[:, :2], method='cubic')
vertices[:, -1] = si
contours.append(vertices)
return contours
[docs]
def webpanel(result, row, key_descriptions):
from asr.database.browser import fig
panel = {'title': 'Fermi surface',
'columns': [[fig('fermi_surface.png')]],
'plot_descriptions': [{'function': plot_fermi,
'filenames': ['fermi_surface.png']}],
'sort': 13}
return [panel]
[docs]
def plot_fermi(row, fname,
annotate=True, fontsize=10, svbm=100, scbm=40, lwvbm=2.5,
sfs=1, dpi=200, scale=None, scalecb=None,
bbox_to_anchor=None, angle=0):
from ase.geometry.cell import Cell
from matplotlib import pyplot as plt
cell = Cell(row.cell)
lat = cell.get_bravais_lattice(pbc=row.pbc)
plt.figure(figsize=(4, 3))
ax = lat.plot_bz(vectors=False, pointstyle={'c': 'k', 'marker': '.'})
add_fermi(row, ax=ax, annotate=annotate, s=sfs, scale=scalecb)
plt.savefig(fname, dpi=dpi)
plt.close()
[docs]
def add_fermi(row, ax, annotate=True, s=0.25, scale=None, angle=0,):
from matplotlib import pyplot as plt
import matplotlib.colors as colors
import numpy as np
verts = row.data['results-asr.fermisurface.json']['contours'].copy()
normalize = colors.Normalize(vmin=-1, vmax=1)
rotate = np.array([[np.cos(angle), -np.sin(angle), 0],
[np.sin(angle), np.cos(angle), 0],
[0, 0, 1]])
verts[:, :2] /= (2 * np.pi)
verts[:, :2] = np.dot(rotate[:2, :2], verts[:, :2].T).T
im = ax.scatter(verts[:, 0], verts[:, 1], c=verts[:, -1],
s=s, cmap='viridis', marker=',',
norm=normalize, alpha=1, zorder=2)
rect = np.array([0.85, 0.2, 0.025, 0.6])
if scale is not None:
center = np.array([0, 0.5, 0, 0])
rect = (rect - center) * scale + center
cbaxes = plt.gcf().add_axes(rect)
cbar = plt.colorbar(im, cax=cbaxes, ticks=[-1, -0.5, 0, 0.5, 1])
cbar.ax.tick_params()
cbar.set_label('$\\langle S_z \\rangle$')
return cbaxes
[docs]
@prepare_result
class Result(ASRResult):
formats = {"ase_webpanel": webpanel}
@command('asr.fermisurface',
returns=Result,
requires=['gs.gpw', 'results-asr.structureinfo.json'],
dependencies=['asr.gs@calculate', 'asr.structureinfo'])
def main() -> Result:
import numpy as np
from gpaw import GPAW
from asr.utils.gpw2eigs import gpw2eigs
from gpaw.kpt_descriptor import to1bz
from asr.magnetic_anisotropy import get_spin_axis, get_spin_index
theta, phi = get_spin_axis()
eigs_km, ef, s_kvm = gpw2eigs('gs.gpw', return_spin=True,
theta=theta, phi=phi,
symmetry_tolerance=1e-2)
eigs_mk = eigs_km.T
eigs_mk -= ef
calc = GPAW('gs.gpw', txt=None)
s_mk = s_kvm[:, get_spin_index()].T
A_cv = calc.atoms.get_cell()
B_cv = np.linalg.inv(A_cv).T * 2 * np.pi
bzk_kc = calc.wfs.kd.bzk_kc
bzk_kv = np.dot(bzk_kc, B_cv)
contours = []
selection = ~np.logical_or(eigs_mk.max(1) < 0, eigs_mk.min(1) > 0)
eigs_mk = eigs_mk[selection, :]
s_mk = s_mk[selection, :]
bz2ibz_k = calc.wfs.kd.bz2ibz_k
eigs_mk = eigs_mk[:, bz2ibz_k]
s_mk = s_mk[:, bz2ibz_k]
n = 5
N_xc = np.indices((n, n, 1)).reshape((3, n**2)).T - n // 2
N_xc += np.array((0, 0, n // 2))
N_xv = np.dot(N_xc, B_cv)
eigs_mk = np.repeat(eigs_mk, n**2, axis=1)
s_mk = np.repeat(s_mk, n**2, axis=1)
tmpbzk_kv = (bzk_kv[:, np.newaxis] + N_xv[np.newaxis]).reshape(-1, 3)
tmpcontours = find_contours(eigs_mk, tmpbzk_kv, s_nk=s_mk)
# Only include contours with a part in 1st BZ
for cnt in tmpcontours:
k_kv = cnt.copy()
k_kv = k_kv[:, :3]
k_kv[:, 2] = 0
k_kc = np.dot(k_kv, A_cv.T) / (2 * np.pi)
inds_k = np.linalg.norm(to1bz(k_kc, A_cv) - k_kc, axis=1) < 1e-8
if (inds_k).any():
contours.append(cnt[inds_k, :])
contours = np.concatenate(contours)
data = {'contours': contours}
return data
if __name__ == '__main__':
main.cli()