from aiida import orm, load_profile, engine
_ = load_profile()
import numpy as np
import matplotlib.pyplot as plt
from aiida_kkr.tools import find_parent_structure, plot_kkr, kkrparams
from aiida_kkr.workflows import combine_imps_wc
from masci_tools.io.common_functions import get_alat_from_bravais
from aiida_kkr.calculations import VoronoiCalculation, KkrCalculation
import pandas as pd
import seaborn as sns
from tqdm import tqdm
from matplotlib.gridspec import GridSpec
Version of workflow: 0.7.2
def load_or_create_group(label):
try:
group = orm.load_group(label)
except:
group = orm.Group(label)
group.store()
return group
def get_builder_double_imp(impname1, impname2, add_pos):
# set offset
alat0 = get_alat_from_bravais(np.array(struc.cell))
offset_imp2 = orm.Dict({'index': 50, 'r_offset': add_pos[1]/alat0})
# imp 1 is always in layer 3
single_imp_calc1 = [node for node in group_single_imps_2.nodes if impname1 in node.label][0]
# imp2 in layer 2 or 6
if add_pos[2]==2:
single_imp_calc2 = [node for node in group_single_imps_2.nodes if impname2 in node.label][0]
else:
single_imp_calc2 = [node for node in group_single_imps_6.nodes if impname2 in node.label][0]
group_label = f'new_calcs/Bi2Se3/il_2_{add_pos[2]}_Off_{add_pos[3]}'
calc_label = f'{impname1}:{impname2}:' + group_label.split('/')[-1]
from aiida_kkr.workflows import combine_imps_wc
# set combine_imps inputs
builder = combine_imps_wc.get_builder()
builder.metadata.label = calc_label
return calc_label, group_label, builder
def relabel_kpts(bs):
"""
Relabel high-symmetry points to use convention from https://www.sciencedirect.com/science/article/pii/S0927025610002697?via%3Dihub
"""
k = bs.called[2].inputs.kpoints
klbls = []
k_rename = {
'GAMMA': r'$\Gamma$',
'T': 'Z',
'H_2': 'B',
'H_0': 'B1',
'L': 'L',
'S_0': 'P2',
'S_2': 'Q',
'F': 'F',
}
for i, (ik, klbl) in enumerate(k.labels):
if klbl in k_rename:
klbl = k_rename[klbl]
# print(i, ik, (k.labels[i+1][0]-ik)==1)
if (i==len(k.labels)-1 or i==0) or (abs(ik-k.labels[i+1][0])>1 and abs(ik-k.labels[i-1][0])>1):
klbls.append([ik, klbl])
elif k.labels[i+1][0]-ik==1:
klbl2 = k.labels[i+1][1]
if klbl2 in k_rename:
klbl2 = k_rename[klbl2]
klbl += '|'+klbl2
klbls.append([ik+0.5, klbl])
plt.xticks([i[0] for i in klbls], [i[1] for i in klbls])
def get_add_positions(struc):
"""Get all connecting vectors and distances for impurity dimer configurations"""
done_first = False
struc_aux = orm.StructureData(cell=struc.cell)
for site in struc.sites:
symbol = site.kind_name
if symbol in ['Se', 'Bi']:
if symbol=='Bi' and not done_first:
symbol = 'Sb'
done_first = True
struc_aux.append_atom(position=site.position, symbols=symbol)
# print(struc_aux.sites)
ps = struc_aux.get_pymatgen()
dists = ([np.linalg.norm(i.coords - ps.sites[1].coords) for i in ps.get_all_neighbors(15)[1] if 'Bi' in i.species_string or 'Sb' in i.species_string])
dists_34 = ([np.linalg.norm(i.coords - ps.sites[1].coords) for i in ps.get_all_neighbors(15)[1] if 'Bi' in i.species_string])
dists_33 = ([np.linalg.norm(i.coords - ps.sites[1].coords) for i in ps.get_all_neighbors(15)[1] if 'Sb' in i.species_string])
pos_34 = np.array([i.coords - ps.sites[1].coords for i in ps.get_all_neighbors(15)[1] if 'Bi' in i.species_string])
pos_33 = np.array([i.coords - ps.sites[1].coords for i in ps.get_all_neighbors(15)[1] if 'Sb' in i.species_string])
dists_unique = np.unique(np.round(dists, 3))
num_3, num_4 = 0, -1 # counters to keep track of offset index (for consistent labeling later on)
def get_r(idist, num_3, num_4):
# global num_3, num_4
try:
R = pos_33[abs(np.linalg.norm(pos_33, axis=1)-dists_unique[idist])<1e-3][0]
num_3 += 1
return num_3, num_4, [np.linalg.norm(R), R, 2, num_3]
except:
R = pos_34[abs(np.linalg.norm(pos_34, axis=1)-dists_unique[idist])<1e-3][0]
num_4 += 1
return num_3, num_4, [np.round(np.linalg.norm(R),3), R, 6, num_4]
# new: add all positions
add_positions = {}
for i in range(17):
num_3, num_4, add_positions[i] = get_r(i, num_3, num_4)
# add_positions
return add_positions
# get_add_positions(struc)
def get_imp_outputs(group, plot=False):
"""Extract output of single impurity calculation and plot data"""
print('label spin mom orb. mom rms of calc charge neutrality of imp.')
print(75*'-')
out, names = [], []
for impname in impname_all_3d4d:
nodes = [node for node in group.nodes if impname in node.label]
if len(nodes)==0:
print(impname, 'not found in group')
else:
node = nodes[0]
if node.is_finished_ok:
o = node.outputs.last_calc_output_parameters.get_dict()
o = node.outputs.last_calc_output_parameters.get_dict()
rms =o['convergence_group']['rms']
ms = o['magnetism_group']['spin_moment_per_atom'][0][2]
mo = o['magnetism_group']['orbital_moment_per_atom'][0][2]
if ms<0:
# flip spin and orbital moment to point in +z if necessary
mo *= -1
ms *= -1
charge_neutr = o['total_charge_per_atom'][0] - node.inputs.impurity_info['Zimp']
print(f'{node.label:15} {np.round(ms,3):7} {np.round(mo,3):7} {rms:15} {charge_neutr}')
out.append([ms, mo])
else:
print(node.label, 'not done yet. pk:', node.pk)
out.append([np.NaN, np.NaN])
names.append(impname)
if plot and len(out)>0:
plt.figure(figsize=(8,4))
plt.subplot(1,2,1)
out = np.array(out)
plt.axhline(0, ls=':', color='C0')
plt.plot(out[:,0], 'o--')
m = np.where(abs(np.nan_to_num(out)[:,0])<1e-3)
plt.plot(np.arange(len(out))[m], out[m][:,0], 'o', color='w', ms=3)
plt.ylabel(r'spin moment ($\mu_B$)', color='C0')
plt.xticks(np.arange(len(out)), [ '\n'*(i%2) + n for i, n in enumerate(names)])
plt.axvline(9.5, color='grey', ls=':')
plt.subplot(1,2,2)
plt.axhline(0, ls=':', color='C1')
plt.plot(out[:,1], 'o--', color='C1')
plt.plot(np.arange(len(out))[m], out[m][:,0], 'o', color='w', ms=3)
plt.ylabel(r'orbital moment ($\mu_B$)', color='C1')
plt.xticks(np.arange(len(out)), [ '\n'*(i%2) + n for i, n in enumerate(names)])
plt.axvline(9.5, color='grey', ls=':')
plt.tight_layout()
# save figures to files?
savefigs = False
# mappings of Zimp to element names
Zimp_all_3d4d = list(range(21, 31)) + list(range(39, 49))
impname_all_3d4d = 'Sc Ti V Cr Mn Fe Co Ni Cu Zn Y Zr Nb Mo Tc Ru Rh Pd Ag Cd'.split()
impname_from_Zimp = {Z: impname_all_3d4d[i] for i, Z in enumerate(Zimp_all_3d4d)}
%%capture --no-stdout --no-display
# load data
dos = orm.load_node('e285e27d-814d-43b6-a153-c15e1db78419')
bs = orm.load_node('11a1e725-410f-41d8-8e5b-efdc34154de3')
# create figure
fig = plt.figure(figsize=(9,6))
gs = GridSpec(1, 3, figure=fig)
ax1 = fig.add_subplot(gs[0, :2])
plot_kkr(bs, silent=True, cmap='binary', clim=(0, None), nofig=True, show_cbar=False, noshow=True)
plt.title('')
plt.ylim(-5,3)
plt.ylabel(r'$E-E_\mathrm{F}$ (eV)')
relabel_kpts(bs)
ax2 = fig.add_subplot(gs[0, 2])
plot_kkr(dos, silent=True, sum_spins=True, switch_xy=True, noshow=True, nofig=True, l_channels=False, lw=2)
plt.axhline(0, color='r', ls=':', lw=2)
plt.ylim(-5,3)
plt.xlim(0)
plt.title('')
plt.ylabel('')
plt.xlabel('DOS (1/eV)')
ax2.yaxis.tick_right()
plt.tight_layout()
plt.subplots_adjust(wspace=0.02)
if savefigs:
plt.savefig('Bi2Se3_DOS_bs.pdf')
plt.show()
%%capture --no-stdout --no-display
# load host structure
struc = orm.load_node('0f86ea10-5d45-4ef9-9954-bb8b4cd97db5')
# create duplicate structure for cif file without the empty sites used by the KKR formalism
cell_new = np.array(struc.cell)
struc_aux = orm.StructureData(cell=cell_new)
for isite, site in enumerate(struc.sites): #[:5]):
pos = site.position
# if isite!=0:
# pos -= 2*cell_new[2]
struc_aux.append_atom(position=pos, symbols=site.kind_name)
ps = struc_aux.get_pymatgen()
ps.get_primitive_structure()
# with open('Bi2Se3.cif', 'w') as _f:
# _f.writelines(struc_aux.get_cif().get_content())
# plot_kkr(struc_aux, silent=True, viewer='ngl')
Structure Summary Lattice abc : 9.84101666068092 9.84101666068092 9.841016650502901 angles : 24.273011505037225 24.273011505037225 24.273011432386934 volume : 141.56542449271274 A : -2.068990202273 -1.194532085927 9.5466214732956 B : 2.068990202273 -1.194532085927 9.5466214732956 C : 0.0 2.3890640763878 9.5466214732956 pbc : True True True PeriodicSite: Se (-1.523e-18, 9.612e-18, 5.9) [0.206, 0.206, 0.206] PeriodicSite: X0+ (-9.418e-18, -3.979e-18, 2.95) [0.103, 0.103, 0.103] PeriodicSite: Bi (-4.422e-17, 1.535e-17, 11.43) [0.399, 0.399, 0.399] PeriodicSite: X0+ (-2.396e-17, -6.862e-17, 8.664) [0.3025, 0.3025, 0.3025] PeriodicSite: Se (0.0, 0.0, 0.0) [0.0, 0.0, 0.0] PeriodicSite: X0+ (2.396e-17, 6.862e-17, -8.664) [-0.3025, -0.3025, -0.3025] PeriodicSite: Bi (4.422e-17, -1.535e-17, -11.43) [-0.399, -0.399, -0.399] PeriodicSite: X0+ (9.418e-18, 3.979e-18, -2.95) [-0.103, -0.103, -0.103] PeriodicSite: Se (1.523e-18, -9.612e-18, -5.9) [-0.206, -0.206, -0.206] PeriodicSite: X0+ (-6.53e-17, -9.001e-17, 14.32) [0.5, 0.5, 0.5]
# get impurity configurations (distance, connecting vectors etc.)
add_positions = get_add_positions(struc)
# load groups for single imp. calculations
group_single_imps_2 = load_or_create_group('single_imps:Bi2Se3_il_2')
group_single_imps_6 = load_or_create_group('single_imps:Bi2Se3_il_6')
%%capture --no-stdout --no-display
from aiida_kkr.workflows import kkr_imp_sub_wc
if savefigs:
for iadd in range(17):
calc_label, group_label, builder = get_builder_double_imp('Mn', 'Mn', add_positions[iadd])
group_double_imps = load_or_create_group(group_label)
# print(iadd, group_label, len(group_double_imps.nodes))
if len(group_double_imps.nodes)==0:
raise ValueError(f'no calculation in group {group_label}')
calc = [n for n in group_double_imps.nodes if n.label==calc_label][0]
calc = calc.get_outgoing(node_class=kkr_imp_sub_wc).first().node
plot_kkr(calc, strucplot=True, silent=True, static=True)
# plot single impurity spin and orbital moments
get_imp_outputs(group_single_imps_2, plot=True)
if savefigs:
plt.savefig('Bi2Se3_single_imps_mag.pdf')
label spin mom orb. mom rms of calc charge neutrality of imp. --------------------------------------------------------------------------- Sc:Bi2Se3_il_2 0.0 0.0 3.061e-08 -1.5781659999999995 Ti:Bi2Se3_il_2 0.833 0.081 4.0944e-08 -1.4527399999999986 V:Bi2Se3_il_2 2.62 0.112 4.1168e-08 -1.238187 Cr:Bi2Se3_il_2 3.793 -0.002 5.1319e-08 -1.1149510000000014 Mn:Bi2Se3_il_2 4.49 -0.024 9.7194e-08 -1.1016499999999994 Fe:Bi2Se3_il_2 3.504 -0.318 9.0359e-08 -0.9907210000000006 Co:Bi2Se3_il_2 2.239 -0.537 1.5458e-08 -0.815729000000001 Ni:Bi2Se3_il_2 1.083 -0.223 9.6419e-08 -0.6876479999999994 Cu:Bi2Se3_il_2 0.0 -0.0 6.9826e-09 -0.6161619999999992 Zn:Bi2Se3_il_2 0.0 0.0 5.6491e-08 -0.8529710000000001 Y:Bi2Se3_il_2 0.0 0.0 5.9873e-08 -2.011547 Zr:Bi2Se3_il_2 0.0 -0.0 2.0253e-08 -1.7953150000000022 Nb:Bi2Se3_il_2 1.228 0.234 4.5092e-08 -1.888691999999999 Mo:Bi2Se3_il_2 2.641 0.055 7.351e-08 -1.6423240000000021 Tc:Bi2Se3_il_2 2.849 -0.118 3.3888e-08 -1.4773599999999973 Ru:Bi2Se3_il_2 0.703 -0.374 3.6013e-08 -1.1993069999999975 Rh:Bi2Se3_il_2 0.0 -0.0 3.7876e-08 -1.010468000000003 Pd-mag:Bi2Se3_il_2 0.423 -0.095 6.4276e-08 -0.8726759999999985 Ag:Bi2Se3_il_2 0.0 -0.0 9.705e-08 -0.8844780000000014 Cd:Bi2Se3_il_2 0.0 0.0 5.7306e-08 -1.1867000000000019
# extract single impurity moments, used later again
impnames = [n.label.split(':')[0] for n in group_single_imps_2.nodes]
moments = [n.outputs.last_calc_output_parameters['magnetism_group']['spin_moment_per_atom'][0][2] for n in group_single_imps_2.nodes]
single_imp_moments = {l: abs(moments[i]) for i,l in enumerate(impnames) if 'Pd-mag' not in l}
print('group name tot terminated finished_ok R_ij')
print('-'*55)
not_ok = []
for iadd in range(17): # 3-3 and 3-4
calc_label, group_label, builder = get_builder_double_imp('Mn', 'Mn', add_positions[iadd])
group_double_imps = load_or_create_group(group_label)
N = len(list(group_double_imps.nodes))
Nterminated = len([node for node in group_double_imps.nodes if node.is_terminated])
Nfinished = len([node for node in group_double_imps.nodes if node.is_finished_ok])
not_ok += [(group_label, node.label, node) for node in group_double_imps.nodes if not node.is_finished_ok]
label = group_double_imps.label.split('/')[-1]
print(f'{label} {N:5} {Nterminated:5} {Nfinished:5} ', add_positions[iadd][0])
group name tot terminated finished_ok R_ij ------------------------------------------------------- il_2_2_Off_1 207 207 207 4.13798041460554 il_2_6_Off_0 25 25 25 4.456 il_2_6_Off_1 27 27 27 5.785 il_2_6_Off_2 25 25 25 6.081 il_2_6_Off_3 27 27 27 7.113 il_2_2_Off_2 28 28 28 7.1671923072059665 il_2_6_Off_4 27 27 27 7.355 il_2_2_Off_3 27 27 27 8.27596082921108 il_2_6_Off_5 27 27 27 9.211 il_2_6_Off_6 27 27 27 9.399 il_2_2_Off_4 28 28 28 9.84101666068092 il_2_6_Off_7 27 27 27 10.098 il_2_6_Off_8 27 27 27 10.27 il_2_2_Off_5 28 28 28 10.675602584579572 il_2_2_Off_6 28 28 28 10.948067095695759 il_2_6_Off_9 27 27 27 11.072 il_2_2_Off_7 28 28 28 11.449514065604237
def get_dat_from_node(node, reload=False, verbose=False):
"""Get data from node (neighbor index, radius, Zimp, ..., Jij)"""
if 'Jij_data' in node.extras and not reload:
# load from extra
dat = node.extras['Jij_data']
else:
# load from node if not found as extra already
imp1, imp2, off = node.label.split(':')
# data.append([add_positions[iadd][0], imp1, imp2])
Zimp1, Zimp2 = node.outputs.workflow_info['imps_info_in_exact_cluster']['Zimps']
m1, m2 = np.array(node.outputs.workflow_info['magmoms'])[[0,24]]
if verbose:
print(np.array(node.outputs.workflow_info['magmoms']), m1, m2)
J = node.outputs.JijData.get_array('JijData')[0,3]
m01 = single_imp_moments[impname_from_Zimp[Zimp1]]
m02 = single_imp_moments[impname_from_Zimp[Zimp2]]
uuid_JijData = node.outputs.JijData.uuid
r = add_positions[iadd][1]
R, il, num_neighbors = get_R_num_neighbor(iadd)
dat = [iadd, add_positions[iadd][0], r[0], r[1], r[2], add_positions[iadd][2], Zimp1, Zimp2, num_neighbors, m1, m2, m01, m02, J, uuid_JijData]
node.set_extra('Jij_data', dat)
return dat
def get_R_num_neighbor(iadd):
"""Extract shell Radius, ilayer index and number of neighbors per shell"""
R, _, il, _ = add_positions[iadd]
num_neighbors = len([i for i in ps.get_neighbors_in_shell(origin=ps.sites[2].coords, r=R, dr=0.02) if i.species_string in ['Bi', 'Sb']])
return R, il, num_neighbors
def get_all_equivalent_R(iadd):
"""Extract all equivalent positions for a shell"""
R, _, il, _ = add_positions[iadd]
all_neighbors =np.array( [i.coords for i in ps.get_neighbors_in_shell(origin=ps.sites[2].coords, r=R, dr=0.02) if i.species_string in ['Bi', 'Sb']])
return all_neighbors
from pandas import DataFrame, read_csv
try:
df = read_csv('Jij_table_Bi2Se3.csv', usecols=range(1,16))
data_all = df.to_numpy()
print('loaded data from csv file')
except:
# load from aiida DB
reload = False
data_all = []
for iadd in range(17):
data = []
_, group_label, _ = get_builder_double_imp('Mn', 'Mn', add_positions[iadd])
group_double_imps = load_or_create_group(group_label)
for node in tqdm(group_double_imps.nodes):
if node.is_finished_ok:
dat = get_dat_from_node(node, reload=reload)
data.append(dat)
if len(data)>0:
data_all += data
data_all = np.array(data_all)
# convert to pandas dataframe
df = DataFrame(data_all, columns='i_shell R Rx Ry Rz ilayer2 Zimp1 Zimp2 num_neighbors m1 m2 m01 m02 J J_data_uuid'.split())
# write to file
df.to_csv('Jij_table_Bi2Se3.csv')
df
loaded data from csv file
i_shell | R | Rx | Ry | Rz | ilayer2 | Zimp1 | Zimp2 | num_neighbors | m1 | m2 | m01 | m02 | J | J_data_uuid | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 4.137980 | -2.06899 | -3.583596 | 1.776357e-15 | 2 | 25 | 25 | 6 | 4.423354 | 1.521209e-02 | 4.490406e+00 | 4.490406e+00 | -2.632560e+00 | b624a330-5bfc-4bea-ab9f-9ddcf668cb72 |
1 | 0 | 4.137980 | -2.06899 | -3.583596 | 1.776357e-15 | 2 | 21 | 21 | 6 | -0.000024 | 1.563068e-05 | 8.219073e-08 | 8.219073e-08 | 5.591027e-10 | ef454a29-7cea-46a1-91a5-f3a3d7be55c0 |
2 | 0 | 4.137980 | -2.06899 | -3.583596 | 1.776357e-15 | 2 | 21 | 22 | 6 | -0.000017 | 5.814929e-08 | 8.219073e-08 | 8.329814e-01 | 4.520384e-09 | 192eb738-0d56-4e17-a60d-4f200d53a7fa |
3 | 0 | 4.137980 | -2.06899 | -3.583596 | 1.776357e-15 | 2 | 21 | 23 | 6 | 0.007473 | 2.653298e-02 | 8.219073e-08 | 2.620230e+00 | 5.420881e-02 | c52ada97-1b6b-4e4b-80c9-9aaea28c77df |
4 | 0 | 4.137980 | -2.06899 | -3.583596 | 1.776357e-15 | 2 | 21 | 24 | 6 | 0.003495 | 2.077953e-02 | 8.219073e-08 | 3.792947e+00 | 1.987402e-02 | 19c94a99-c2f3-4b00-9a52-5f530293076e |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
635 | 16 | 11.449514 | -2.06899 | -5.972660 | -9.546621e+00 | 2 | 26 | 27 | 12 | 3.333513 | -2.052537e+00 | 3.503577e+00 | 2.238936e+00 | 5.772191e-02 | 2bfa800d-e90c-45a8-9361-647a0eee300f |
636 | 16 | 11.449514 | -2.06899 | -5.972660 | -9.546621e+00 | 2 | 26 | 28 | 12 | 3.333481 | 9.037085e-01 | 3.503577e+00 | 1.083204e+00 | 6.064192e-02 | c277086a-f844-40f1-a521-9fd1fe4ccd52 |
637 | 16 | 11.449514 | -2.06899 | -5.972660 | -9.546621e+00 | 2 | 27 | 27 | 12 | -2.053403 | -2.052844e+00 | 2.238936e+00 | 2.238936e+00 | -1.062496e-03 | a762f372-d176-4d62-82cf-d4ed4000bbae |
638 | 16 | 11.449514 | -2.06899 | -5.972660 | -9.546621e+00 | 2 | 27 | 28 | 12 | -2.053410 | 9.042098e-01 | 2.238936e+00 | 1.083204e+00 | -1.292432e-01 | cac8d804-76f5-4c2f-8d24-6421fe8f5c02 |
639 | 16 | 11.449514 | -2.06899 | -5.972660 | -9.546621e+00 | 2 | 28 | 28 | 12 | 0.904950 | 9.042293e-01 | 1.083204e+00 | 1.083204e+00 | 1.434417e-02 | 116d5fd5-b9c9-4869-8d9e-d8c320007789 |
640 rows × 15 columns
# count number of magnetic combinations
dd = data_all[data_all[:,-5]>1e-3]
dd = dd[dd[:,-3]>1e-3]
# total pairs, magnetic pairs
len(data_all), len(dd), np.round(len(dd)/len(data_all),2)
(640, 464, 0.72)
def reshape_data_to_arr(data, plot_J=True):
data = np.array(data)
Zimp_all_3d4d = list(range(21, 31)) + list(range(39, 49))
impname_all_3d4d = 'Sc Ti V Cr Mn Fe Co Ni Cu Zn Y Zr Nb Mo Tc Ru Rh Pd Ag Cd'.split()
arr = np.zeros((len(Zimp_all_3d4d), len(Zimp_all_3d4d)))
arr[:,:] = np.NaN
for i1, Z1 in enumerate(Zimp_all_3d4d):
for i2, Z2 in enumerate(Zimp_all_3d4d):
d = data[data[:,6]==Z1]
# print(len(d))
if len(d)>0:
dd = d[d[:,7]==Z2]
if len(dd)>0:
if plot_J:
arr[i1, i2] = dd[0][-2]
else:
arr[i1, i2] = dd[0][-4] + dd[0][-3]
if i1 != i2:
arr[i2, i1] = arr[i1, i2]
return arr
def get_and_plot_data(iadd = 0, plot_J=True, reload=False, vlim=None, hide_threshold=None, **kwargs):
data = data_all[data_all[:,0]==iadd]
if len(data)>0:
arr = reshape_data_to_arr(data)
if hide_threshold is not None:
arr[abs(arr)<hide_threshold] = 0 #np.NaN
import seaborn as sns
# plt.figure(figsize=(18,14))
ivm = 1
cmap='seismic'
if vlim is None:
vlim = abs(np.nan_to_num(arr)).max()
if not plot_J:
ivm = 0
cmap='viridis'
p = sns.heatmap(arr[1:8,1:8], cmap=cmap, vmin=ivm * -vlim, vmax=vlim, **kwargs)
R, _, il1, ioff = add_positions[iadd]
plt.title(f'3-{il1}:{ioff} (R={R:.3f} Ang.)'.replace('3-3', '1-1').replace('3-6', '1-2'))
plt.xticks(np.arange(len(Zimp_all_3d4d[1:8]))+0.5, impname_all_3d4d[1:8])
plt.yticks(np.arange(len(Zimp_all_3d4d[1:8]))+0.5, impname_all_3d4d[1:8])
plt.figure(figsize=(20,20))
for iadd in range(17):
plt.subplot(5,4,1+iadd)
get_and_plot_data(iadd, reload=False, hide_threshold=0.1, vlim=20, cbar=True, square=True, center=0, annot=True, annot_kws={"fontsize": 7}, fmt=".1g")
plt.tight_layout()
if savefigs:
plt.savefig('Jij_maps_all_Bi2Se3.pdf')
plt.show()
kB = 8.6173324e-5 # eV / K
# prefac = 1e-3 * 2/3 / kB
prefac = 1e-3 * 1/3 / kB # 1/3 instead of 2/3 due to definition of Heisenberg Hamiltonian
def get_Tc(imp1, imp2, plot=False, mark_dists=False):
d = data_all[data_all[:,6]==imp1]
dd = d[d[:,7]==imp2]
if len(dd)<17:
return np.NaN, np.NaN, np.NaN, np.NaN
if plot:
plt.plot(dd[:,1], dd[:,-1], '--', color='C0')
ddd = dd[dd[:,5]==2]
plt.plot(ddd[:,1], ddd[:,-1], 'o', color='C0', label='1-1')
ddd = dd[dd[:,5]==6]
plt.plot(ddd[:,1], ddd[:,-1], 's', color='C0', label='1-2')
plt.legend(loc=5)
plt.ylabel(r'$N\cdot J_{ij}$ (meV)', color='C0')
plt.axhline(0, ls=':', color='C0')
plt.xlabel(r'$R_{ij}$ ($\AA$)')
plt.twinx()
Tcs = np.array([np.sum(dd[:1+i,-2]*dd[:1+i,5]) * prefac for i in range(len(dd))])
plt.plot(dd[:,1], Tcs, '-', color='C1')
plt.plot(dd[:,1][dd[:,5]==2], Tcs[dd[:,5]==2], 'o', color='C1')
plt.plot(dd[:,1][dd[:,5]==6], Tcs[dd[:,5]==6], 's', color='C1')
plt.ylabel('$T_c$ (K/c)', color='C1')
# plt.axhline(0, ls=':', color='C1')
plt.xlim(4, 12.5)
plt.tight_layout()
if mark_dists:
plt.axvline(np.min(np.round(dists_33, 3)), ls=':', color='r', label='33')
[plt.axvline(i, ls=':', color='r') for i in np.unique(np.round(dists_33, 3))[1:]]
plt.axvline(np.min(np.round(dists_34, 3)), ls=':', color='m', label='34')
[plt.axvline(i, ls=':', color='m') for i in np.unique(np.round(dists_34, 3))[1:]]
Tc = np.sum(dd[:,-2]*dd[:,8]) * prefac
Tc1 = np.sum(dd[1:,-2]*dd[1:,8]) * prefac
ddd_z, ddd_xy = [], []
for i, iadd in enumerate(dd[:,0]):
z = add_positions[iadd][1][2]
if abs(z)>5:
ddd_z.append(dd[i])
else:
ddd_xy.append(dd[i])
ddd_z, ddd_xy = np.array(ddd_z), np.array(ddd_xy)
Tc_xy = np.sum(ddd_xy[:,-2]*ddd_xy[:,8]) * prefac
Tc_z = np.sum(ddd_z[:,-2]*ddd_z[:,8]) * prefac
return Tc, Tc1, Tc_xy, Tc_z
Zimp_all_3d4d = list(range(21, 31)) + list(range(39, 49))
impname_all_3d4d = 'Sc Ti V Cr Mn Fe Co Ni Cu Zn Y Zr Nb Mo Tc Ru Rh Pd Ag Cd'.split()
Tcs = np.zeros((len(impname_all_3d4d), len(impname_all_3d4d)))
Tcs[:,:] = np.NaN
Tcs1 = Tcs.copy()
Tcs_xy = Tcs.copy()
Tcs_z = Tcs.copy()
for imp1 in range(len(impname_all_3d4d)):
for imp2 in range(imp1, len(impname_all_3d4d)):
Tcs[imp1, imp2], Tcs1[imp1, imp2], Tcs_xy[imp1, imp2], Tcs_z[imp1, imp2] = get_Tc(Zimp_all_3d4d[imp1], Zimp_all_3d4d[imp2])
for imp1 in range(len(impname_all_3d4d)):
for imp2 in range(imp1, len(impname_all_3d4d)):
if imp1 != imp2:
Tcs[imp1, imp2] = (Tcs[imp1, imp2] + Tcs[imp1, imp1] + Tcs[imp2, imp2])/3
Tcs[imp2, imp1] = Tcs[imp1, imp2]
# same for Tc without the first neighbor
Tcs1[imp1, imp2] = (Tcs1[imp1, imp2] + Tcs1[imp1, imp1] + Tcs1[imp2, imp2])/3
Tcs1[imp2, imp1] = Tcs1[imp1, imp2]
Tcs_xy[imp1, imp2] = (Tcs_xy[imp1, imp2] + Tcs_xy[imp1, imp1] + Tcs_xy[imp2, imp2])/3
Tcs_xy[imp2, imp1] = Tcs_xy[imp1, imp2]
Tcs_z[imp1, imp2] = (Tcs_z[imp1, imp2] + Tcs_z[imp1, imp1] + Tcs_z[imp2, imp2])/3
Tcs_z[imp2, imp1] = Tcs_z[imp1, imp2]
m = np.array(list(single_imp_moments.values()))<1e-3
Tcs[m, :] = np.NaN
Tcs[:, m] = np.NaN
Tcs1[m, :] = np.NaN
Tcs1[:, m] = np.NaN
Tcs_xy[m, :] = np.NaN
Tcs_xy[:, m] = np.NaN
Tcs_z[m, :] = np.NaN
Tcs_z[:, m] = np.NaN
# np.savetxt('Tcs_Bi2Se3.txt', np.nan_to_num(Tcs))
cbar = False
plt.figure(figsize=(3,3))
g = sns.heatmap(Tcs[:11,:11], cmap='seismic', center=0, square=True, annot=False, cbar=cbar, vmin=-1000, vmax=1000)
g.set_facecolor('lightgrey')
[f(i, color='k') for f in [plt.axvline, plt.axhline] for i in [0, 11]]
plt.xticks(np.arange(len(Zimp_all_3d4d[:11]))+0.5, impname_all_3d4d[:11])
plt.yticks(np.arange(len(Zimp_all_3d4d[:11]))+0.5, impname_all_3d4d[:11])
if savefigs:
plt.savefig('stiffness_Bi2Se3_3d.svg')
plt.show()
cbar=False
plt.figure(figsize=(16,6))
plt.subplot(1,3,1)
g = sns.heatmap(Tcs[1:8,1:8], cmap='seismic', center=0, square=True, annot=False, cbar=cbar, vmin=-1000, vmax=1000)
g.set_facecolor('lightgrey')
plt.title(r'$T_c$', fontsize=16)
plt.subplot(1,3,2)
g = sns.heatmap(Tcs_xy[1:8,1:8], cmap='seismic', center=0, square=True, annot=False, cbar=cbar, vmin=-1000, vmax=1000)
g.set_facecolor('lightgrey')
plt.title(r'$T_c^\mathrm{intra}$', fontsize=16)
plt.subplot(1,3,3)
g = sns.heatmap(Tcs_z[1:8,1:8]*5, cmap='seismic', center=0, square=True, annot=False, cbar=cbar, vmin=-1000, vmax=1000)
g.set_facecolor('lightgrey')
plt.title(r'$T_c^\mathrm{inter}$', fontsize=16)
# plt.colorbar(g)
for i in range(3):
plt.subplot(1,3,1+i)
[f(i, color='k') for f in [plt.axvline, plt.axhline] for i in [0, 20]]
plt.xticks(np.arange(len(Zimp_all_3d4d[1:8]))+0.5, impname_all_3d4d[1:8])
plt.yticks(np.arange(len(Zimp_all_3d4d[1:8]))+0.5, impname_all_3d4d[1:8])
plt.tight_layout()
plt.annotate(xy=(0.00+0.01, 0.94), text='(a)', xycoords='figure fraction', fontsize=18)
plt.annotate(xy=(0.33+0.01, 0.94), text='(b)', xycoords='figure fraction', fontsize=18)
plt.annotate(xy=(0.66+0.01, 0.94), text='(c)', xycoords='figure fraction', fontsize=18)
if savefigs:
plt.savefig('Tc_intra_inter_Bi2Se3.pdf')
plt.show()
for imp2 in [24, 26]:
imp1 = imp2
d = data_all[data_all[:,6]==imp1]
dd = d[d[:,7]==imp2]
impnames = {23:'V', 24:'Cr', 26: 'Fe'}
label = impnames[imp1]+':'+impnames[imp2]
data_expanded = []
for ddd in dd:
iadd = ddd[0]
r = get_all_equivalent_R(iadd)
for rr in r:
data_expanded.append([rr[0], rr[1], ddd[-2]])
data_expanded = np.array(data_expanded)
# flip y coordinate to have the same orientation as in Bi2Te3 data set
plt.scatter(data_expanded[:,0], -data_expanded[:,1], s=10*abs(data_expanded[:,-1]), c=data_expanded[:,-1], cmap='seismic', lw=0, vmin=-abs(data_expanded[:,-1]).max(), vmax=abs(data_expanded[:,-1]).max())
plt.xlabel(r'$R_{ij,x}$ ($\mathrm{\AA}$)'); plt.ylabel(r'$R_{ij,y}$ ($\mathrm{\AA}$)')
plt.axis('equal')
plt.colorbar()
plt.show()
df_BT = read_csv('Jij_table.csv', usecols=range(1,16))
data_all_BT = df_BT.to_numpy()
data_all_BT = np.array(data_all_BT[:,:-1], dtype=float)
isort_BT = df_BT['i_shell'] + 100*df_BT['Zimp1'] + 10000*df_BT['Zimp2']
isort_BS = df['i_shell'] + 100*df['Zimp1'] + 10000*df['Zimp2']
isort_both = set(isort_BS).intersection(set(isort_BS))
jij_compare = []
for iBS, isort in enumerate(isort_BS):
iBT = np.where(abs(isort_BT-isort)<1e-1)[0]
if len(iBT)>0:
if np.linalg.norm(data_all_BT[iBT,[0,6,7]]-data_all[iBS,[0,6,7]])<1e-3:
jij_compare.append(list(data_all_BT[iBT,[0,6,7]]) + [data_all_BT[iBT[0],-1]] + [data_all[iBS,-2]])
jij_compare = np.array(jij_compare, dtype=float)
Tcs_BT = np.loadtxt('Tcs_Bi2Te3.txt')[2:7,2:7]
Tcs_BS = np.loadtxt('Tcs_Bi2Se3.txt')[2:7,2:7]
%%capture --no-stdout --no-display
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
from scipy.optimize import curve_fit
plt.figure(figsize=(12,6))
plt.subplot(1,2,1)
plt.hist(jij_compare[:,-2]-jij_compare[:,-1], bins=21)
plt.ylabel('count')
plt.xlabel(r'$\left[J_{ij, \mathrm{Bi}_2\mathrm{Te_3}} - J_{ij, \mathrm{Bi}_2\mathrm{Se_3}}\right]$ (meV)')
plt.xlim(-40)
ax = plt.gca()
axins = inset_axes(ax, width="50%", height="60%", loc='lower left',
bbox_to_anchor=(0.10, 0.32, 1, 1), bbox_transform=ax.transAxes)
axins.plot(jij_compare[:,-2], jij_compare[:,-1], '.')
axins.plot([-20,25],[-20,25], color='k', ls='--')
axins.set_xlabel(r'$J_{ij, \mathrm{Bi}_2\mathrm{Te_3}}$ (meV)', labelpad=0)
axins.set_ylabel(r'$J_{ij, \mathrm{Bi}_2\mathrm{Se_3}}$ (meV)', labelpad=-5)
def fitfun(x, a):
return a*x
popt, pcov = curve_fit(fitfun, jij_compare[:,-2], jij_compare[:,-1])
print('fit coefficient:', popt)
x = np.linspace(-20,25,1000)
axins.plot(x, fitfun(x, *popt), color='r', label=f'linear fit\n($m={popt[0]:.2f}$)')
axins.legend()
plt.xlim(-20,25)
plt.subplot(1,2,2)
plt.plot(Tcs_BT.reshape(-1), Tcs_BS.reshape(-1), 'o')
plt.plot([-1e3,1e3], [-1e3,1e3], 'k--')
plt.xlim(-1e3, 1e3)
plt.ylim(-1e3, 1e3)
plt.xlabel(r'$T_c[\mathrm{Bi}_2\mathrm{Te_3}]$ ($K/c$)')
plt.ylabel(r'$T_c[\mathrm{Bi}_2\mathrm{Se_3}]$ ($K/c$)', labelpad=-5)
print('average difference of Tc magnitude in Bi2Te3 and Bi2Se3:', (abs(Tcs_BT).reshape(-1) - abs(Tcs_BS).reshape(-1)).mean(), 'K/c')
plt.tight_layout()
plt.yticks([-1000, -750, -500, -250, 0, 250, 500, 750])
plt.annotate(text='(a)', xy=(0.01, 0.95), xycoords='figure fraction', weight='bold', fontsize=14)
plt.annotate(text='(b)', xy=(0.51, 0.95), xycoords='figure fraction', weight='bold', fontsize=14)
if savefigs:
plt.savefig('comparison_Jij_Tc_size_BT-BS.pdf')
fit coefficient: [0.48876645] average difference of Tc magnitude in Bi2Te3 and Bi2Se3: 197.9083507338599 K/c