def test_selfenergy_interpolation(atoms, ntk, filename, begin, end, base, scale, direction=0): from gpaw.transport.sparse_matrix import Banded_Sparse_HSD, CP_Sparse_HSD, Se_Sparse_Matrix from gpaw.transport.selfenergy import LeadSelfEnergy from gpaw.transport.contour import Contour hl_skmm, sl_kmm = get_hs(atoms) dl_skmm = get_lcao_density_matrix(atoms.calc) fermi = atoms.calc.get_fermi_level() wfs = atoms.calc.wfs hl_spkmm, sl_pkmm, dl_spkmm, \ hl_spkcmm, sl_pkcmm, dl_spkcmm = get_pk_hsd(2, ntk, wfs.kd.ibzk_qc, hl_skmm, sl_kmm, dl_skmm, None, wfs.dtype, direction=direction) my_npk = len(wfs.kd.ibzk_qc) / ntk my_nspins = len(wfs.kpt_u) / ( my_npk * ntk) lead_hsd = Banded_Sparse_HSD(wfs.dtype, my_nspins, my_npk) lead_couple_hsd = CP_Sparse_HSD(wfs.dtype, my_nspins, my_npk) for pk in range(my_npk): lead_hsd.reset(0, pk, sl_pkmm[pk], 'S', init=True) lead_couple_hsd.reset(0, pk, sl_pkcmm[pk], 'S', init=True) for s in range(my_nspins): lead_hsd.reset(s, pk, hl_spkmm[s, pk], 'H', init=True) lead_hsd.reset(s, pk, dl_spkmm[s, pk], 'D', init=True) lead_couple_hsd.reset(s, pk, hl_spkcmm[s, pk], 'H', init=True) lead_couple_hsd.reset(s, pk, dl_spkcmm[s, pk], 'D', init=True) lead_se = LeadSelfEnergy(lead_hsd, lead_couple_hsd) begin += fermi end += fermi ee = np.linspace(begin, end, base) cmp_ee = np.linspace(begin, end, base * scale) se = [] cmp_se = [] from scipy import interpolate for e in ee: se.append(lead_se(e).recover()) se = np.array(se) ne, ny, nz= se.shape nie = len(cmp_ee) data = np.zeros([nie, ny, nz], se.dtype) for yy in range(ny): for zz in range(nz): ydata = se[:, yy, zz] f = interpolate.interp1d(ee, ydata) data[:, yy, zz] = f(cmp_ee) inter_se_linear = data for e in cmp_ee: cmp_se.append(lead_se(e).recover()) fd = file(filename, 'w') cPickle.dump((cmp_se, inter_se_linear, ee, cmp_ee), fd, 2) fd.close() for i,e in enumerate(cmp_ee): print(e, np.max(abs(cmp_se[i] - inter_se_linear[i])), 'linear', np.max(abs(cmp_se[i])))
def generate_selfenergy_database(atoms, ntk, filename, direction=0, kt=0.1, bias=[-3, 3], depth=3, comm=None): from gpaw.transport.sparse_matrix import Banded_Sparse_HSD, CP_Sparse_HSD, Se_Sparse_Matrix from gpaw.transport.selfenergy import LeadSelfEnergy from gpaw.transport.contour import Contour hl_skmm, sl_kmm = get_hs(atoms) dl_skmm = get_lcao_density_matrix(atoms.calc) fermi = atoms.calc.get_fermi_level() wfs = atoms.calc.wfs hl_spkmm, sl_pkmm, dl_spkmm, \ hl_spkcmm, sl_pkcmm, dl_spkcmm = get_pk_hsd(2, ntk, wfs.ibzk_qc, hl_skmm, sl_kmm, dl_skmm, None, wfs.dtype, direction=direction) my_npk = len(wfs.ibzk_qc) / ntk my_nspins = len(wfs.kpt_u) / (my_npk * ntk) lead_hsd = Banded_Sparse_HSD(wfs.dtype, my_nspins, my_npk) lead_couple_hsd = CP_Sparse_HSD(wfs.dtype, my_nspins, my_npk) for pk in range(my_npk): lead_hsd.reset(0, pk, sl_pkmm[pk], 'S', init=True) lead_couple_hsd.reset(0, pk, sl_pkcmm[pk], 'S', init=True) for s in range(my_nspins): lead_hsd.reset(s, pk, hl_spkmm[s, pk], 'H', init=True) lead_hsd.reset(s, pk, dl_spkmm[s, pk], 'D', init=True) lead_couple_hsd.reset(s, pk, hl_spkcmm[s, pk], 'H', init=True) lead_couple_hsd.reset(s, pk, dl_spkcmm[s, pk], 'D', init=True) lead_se = LeadSelfEnergy(lead_hsd, lead_couple_hsd) contour = Contour(kt, [fermi] * 2, bias, depth, comm=comm) path = contour.get_plot_path(ex=True) for nid, energy in zip(path.my_nids, path.my_energies): for kpt in wfs.kpt_u: if kpt.q % ntk == 0: flag = str(kpt.k // ntk) + '_' + str(nid) lead_se.s = kpt.s lead_se.pk = kpt.q // ntk data = lead_se(energy) fd = file(flag, 'w') cPickle.dump(data, fd, 2) fd.close()
def initialize_selfenergy_and_green_function(self, tp): self.selfenergies = [] if tp.use_lead: for i in range(tp.lead_num): self.selfenergies.append( LeadSelfEnergy(tp.lead_hsd[i], tp.lead_couple_hsd[i])) self.selfenergies[i].set_bias(tp.bias[i])
def generate_selfenergy_database(atoms, ntk, filename, direction=0, kt=0.1, bias=[-3,3], depth=3, comm=None): from gpaw.transport.sparse_matrix import Banded_Sparse_HSD, CP_Sparse_HSD, Se_Sparse_Matrix from gpaw.transport.selfenergy import LeadSelfEnergy from gpaw.transport.contour import Contour hl_skmm, sl_kmm = get_hs(atoms) dl_skmm = get_lcao_density_matrix(atoms.calc) fermi = atoms.calc.get_fermi_level() wfs = atoms.calc.wfs hl_spkmm, sl_pkmm, dl_spkmm, \ hl_spkcmm, sl_pkcmm, dl_spkcmm = get_pk_hsd(2, ntk, wfs.kd.ibzk_qc, hl_skmm, sl_kmm, dl_skmm, None, wfs.dtype, direction=direction) my_npk = len(wfs.kd.ibzk_qc) / ntk my_nspins = len(wfs.kpt_u) / ( my_npk * ntk) lead_hsd = Banded_Sparse_HSD(wfs.dtype, my_nspins, my_npk) lead_couple_hsd = CP_Sparse_HSD(wfs.dtype, my_nspins, my_npk) for pk in range(my_npk): lead_hsd.reset(0, pk, sl_pkmm[pk], 'S', init=True) lead_couple_hsd.reset(0, pk, sl_pkcmm[pk], 'S', init=True) for s in range(my_nspins): lead_hsd.reset(s, pk, hl_spkmm[s, pk], 'H', init=True) lead_hsd.reset(s, pk, dl_spkmm[s, pk], 'D', init=True) lead_couple_hsd.reset(s, pk, hl_spkcmm[s, pk], 'H', init=True) lead_couple_hsd.reset(s, pk, dl_spkcmm[s, pk], 'D', init=True) lead_se = LeadSelfEnergy(lead_hsd, lead_couple_hsd) contour = Contour(kt, [fermi] * 2, bias, depth, comm=comm) path = contour.get_plot_path(ex=True) for nid, energy in zip(path.my_nids, path.my_energies): for kpt in wfs.kpt_u: if kpt.q % ntk == 0: flag = str(kpt.k // ntk) + '_' + str(nid) lead_se.s = kpt.s lead_se.pk = kpt.q // ntk data = lead_se(energy) fd = file(flag, 'w') cPickle.dump(data, fd, 2) fd.close()
def path_selfenergy(atoms, ntk, filename, begin, end, num=257, direction=0): from gpaw.transport.sparse_matrix import Banded_Sparse_HSD, CP_Sparse_HSD, Se_Sparse_Matrix from gpaw.transport.selfenergy import LeadSelfEnergy from gpaw.transport.contour import Contour hl_skmm, sl_kmm = get_hs(atoms) dl_skmm = get_lcao_density_matrix(atoms.calc) fermi = atoms.calc.get_fermi_level() wfs = atoms.calc.wfs hl_spkmm, sl_pkmm, dl_spkmm, \ hl_spkcmm, sl_pkcmm, dl_spkcmm = get_pk_hsd(2, ntk, wfs.ibzk_qc, hl_skmm, sl_kmm, dl_skmm, None, wfs.dtype, direction=direction) my_npk = len(wfs.ibzk_qc) / ntk my_nspins = len(wfs.kpt_u) / (my_npk * ntk) lead_hsd = Banded_Sparse_HSD(wfs.dtype, my_nspins, my_npk) lead_couple_hsd = CP_Sparse_HSD(wfs.dtype, my_nspins, my_npk) for pk in range(my_npk): lead_hsd.reset(0, pk, sl_pkmm[pk], 'S', init=True) lead_couple_hsd.reset(0, pk, sl_pkcmm[pk], 'S', init=True) for s in range(my_nspins): lead_hsd.reset(s, pk, hl_spkmm[s, pk], 'H', init=True) lead_hsd.reset(s, pk, dl_spkmm[s, pk], 'D', init=True) lead_couple_hsd.reset(s, pk, hl_spkcmm[s, pk], 'H', init=True) lead_couple_hsd.reset(s, pk, dl_spkcmm[s, pk], 'D', init=True) lead_se = LeadSelfEnergy(lead_hsd, lead_couple_hsd) begin += fermi end += fermi ee = np.linspace(begin, end, num) se = [] for e in ee: se.append(lead_se(e).recover()) se = np.array(se) fd = file(filename + '_' + str(world.rank), 'w') cPickle.dump((se, ee), fd, 2) fd.close()
def initialize( self, srf_atoms, tip_atoms, srf_coupling_atoms, tip_coupling_atoms, srf_pl_atoms, tip_pl_atoms, energies, bias=0 ): """ srf_atoms: the atom index of onsite surface atoms tip_atoms: the atom index of onsite tip atoms energies: list of energies, for which the transmission function should be evaluated bias: will be used to precalculate the greenfunctions of surface and tip """ self.bias = bias self.energies = energies self.tip_atoms = tip_atoms self.srf_atoms = srf_atoms self.srf_coupling_atoms = srf_coupling_atoms self.tip_coupling_atoms = tip_coupling_atoms # align potentials for onsite surface, onsite tip and tip principle layers according to surface_pl srf_alignv = self.align_v(calc1=self.srf_pl, index1=srf_pl_atoms[0], calc2=self.srf, index2=srf_atoms[0]) tip_alignv = srf_alignv + self.tip.get_fermi_level() - self.srf.get_fermi_level() # - bias tip_pl_alignv = self.align_v(calc1=self.tip, index1=tip_atoms[-1], calc2=self.tip_pl, index2=tip_pl_atoms[-1]) tip_pl_alignv += tip_alignv self.srf_alignv = srf_alignv self.tip_alignv = tip_alignv # hamiltoian and overlap matrix of onsite tip and srf self.h1, self.s1 = Lead_HS(calc=self.tip, atom_list=tip_atoms, shift=srf_alignv - bias).get_HS() print("shape of onsite tip", np.shape(self.h1), np.shape(self.s1)) self.h2, self.s2 = Lead_HS(calc=self.srf, atom_list=srf_atoms, shift=tip_alignv).get_HS() print("shape of onsite srf", np.shape(self.h2), np.shape(self.s2)) # hamiltoian and overlap matrix of two tip and srf principle layers self.h10, self.s10 = Lead_HS( calc=self.tip_pl, atom_list=tip_pl_atoms, shift=tip_pl_alignv ).get_HS() # 2 and only 2 principle layers print("shape of pl tip", np.shape(self.h10), np.shape(self.s10)) self.h20, self.s20 = Lead_HS( calc=self.srf_pl, atom_list=srf_pl_atoms, shift=-bias ).get_HS() # 2 and only 2 principle layers print("shape of pl srf", np.shape(self.h20), np.shape(self.s20)) nbf1, nbf2 = len(self.h1), len(self.h2) # No. of basis functions of onsite tip and surface atoms pl1, pl2 = len(self.h10) / 2, len(self.h20) / 2 # No. of basis functions per principle layer of tip and srf nenergies = len(energies) # periodic part of the tip hs1_dii = self.h10[:pl1, :pl1], self.s10[:pl1, :pl1] hs1_dij = self.h10[:pl1, pl1 : 2 * pl1], self.s10[:pl1, pl1 : 2 * pl1] # coupling betwen per. and non. per part of the tip h1_im = np.zeros((pl1, nbf1), complex) s1_im = np.zeros((pl1, nbf1), complex) h1_im[:pl1, :pl1], s1_im[:pl1, :pl1] = hs1_dij hs1_dim = [h1_im, s1_im] # periodic part the surface hs2_dii = self.h20[:pl2, :pl2], self.s20[:pl2, :pl2] hs2_dij = self.h20[pl2 : 2 * pl2, :pl2], self.s20[pl2 : 2 * pl2, :pl2] # coupling betwen per. and non. per part of the surface h2_im = np.zeros((pl2, nbf2), complex) s2_im = np.zeros((pl2, nbf2), complex) h2_im[-pl2:, -pl2:], s2_im[-pl2:, -pl2:] = hs2_dij hs2_dim = [h2_im, s2_im] # tip and surface greenfunction self.selfenergy1 = LeadSelfEnergy(hs1_dii, hs1_dij, hs1_dim) self.selfenergy2 = LeadSelfEnergy(hs2_dii, hs2_dij, hs2_dim) self.greenfunction1 = GreenFunction(self.h1, self.s1, [self.selfenergy1]) self.greenfunction2 = GreenFunction(self.h2, self.s2, [self.selfenergy2]) # print 'shape of greenfunction tip:', np.shape(self.greenfunction1) # print 'shape of greenfunction srf:', np.shape(self.greenfunction2) # shift the bands due to the bias self.selfenergy1.set_bias(0.0) self.selfenergy2.set_bias(bias) # extend the surface potentials and basis functions self.setup_stm() # tip and surface greenfunction matrices. nbf1_small = self.ni # XXX Change this for efficiency in the future nbf2_small = self.nj # XXX -||- coupling_list1 = range(nbf1 - nbf1_small, nbf1) # XXX -||- coupling_list2 = range(0, nbf2_small) # XXX -||- self.gft1_emm = np.zeros((nenergies, nbf1_small, nbf1_small), complex) self.gft2_emm = np.zeros((nenergies, nbf2_small, nbf2_small), complex) for e, energy in enumerate(self.energies): gft1_mm = self.greenfunction1(energy)[coupling_list1] gft1_mm = np.take(gft1_mm, coupling_list1, axis=1) gft2_mm = self.greenfunction2(energy)[coupling_list2] gft2_mm = np.take(gft2_mm, coupling_list2, axis=1) self.gft1_emm[e] = gft1_mm self.gft2_emm[e] = gft2_mm
class STM: def __init__(self, srf, tip, srf_pl, tip_pl, eta1=1e-4, eta2=1e-4): self.tip = tip # tip calcualtor self.tip_pl = tip_pl # tip periodic layers calculator self.srf = srf # surface calculator self.srf_pl = srf_pl # surface periodic layers calculator self.eta1 = eta1 self.eta2 = eta2 self.tgd = tip.gd self.sgd = srf.gd # assert tgd.h_cv == sgd.h_cv # assert not (tgd.h_c - sgd.h_c).any() def initialize( self, srf_atoms, tip_atoms, srf_coupling_atoms, tip_coupling_atoms, srf_pl_atoms, tip_pl_atoms, energies, bias=0 ): """ srf_atoms: the atom index of onsite surface atoms tip_atoms: the atom index of onsite tip atoms energies: list of energies, for which the transmission function should be evaluated bias: will be used to precalculate the greenfunctions of surface and tip """ self.bias = bias self.energies = energies self.tip_atoms = tip_atoms self.srf_atoms = srf_atoms self.srf_coupling_atoms = srf_coupling_atoms self.tip_coupling_atoms = tip_coupling_atoms # align potentials for onsite surface, onsite tip and tip principle layers according to surface_pl srf_alignv = self.align_v(calc1=self.srf_pl, index1=srf_pl_atoms[0], calc2=self.srf, index2=srf_atoms[0]) tip_alignv = srf_alignv + self.tip.get_fermi_level() - self.srf.get_fermi_level() # - bias tip_pl_alignv = self.align_v(calc1=self.tip, index1=tip_atoms[-1], calc2=self.tip_pl, index2=tip_pl_atoms[-1]) tip_pl_alignv += tip_alignv self.srf_alignv = srf_alignv self.tip_alignv = tip_alignv # hamiltoian and overlap matrix of onsite tip and srf self.h1, self.s1 = Lead_HS(calc=self.tip, atom_list=tip_atoms, shift=srf_alignv - bias).get_HS() print("shape of onsite tip", np.shape(self.h1), np.shape(self.s1)) self.h2, self.s2 = Lead_HS(calc=self.srf, atom_list=srf_atoms, shift=tip_alignv).get_HS() print("shape of onsite srf", np.shape(self.h2), np.shape(self.s2)) # hamiltoian and overlap matrix of two tip and srf principle layers self.h10, self.s10 = Lead_HS( calc=self.tip_pl, atom_list=tip_pl_atoms, shift=tip_pl_alignv ).get_HS() # 2 and only 2 principle layers print("shape of pl tip", np.shape(self.h10), np.shape(self.s10)) self.h20, self.s20 = Lead_HS( calc=self.srf_pl, atom_list=srf_pl_atoms, shift=-bias ).get_HS() # 2 and only 2 principle layers print("shape of pl srf", np.shape(self.h20), np.shape(self.s20)) nbf1, nbf2 = len(self.h1), len(self.h2) # No. of basis functions of onsite tip and surface atoms pl1, pl2 = len(self.h10) / 2, len(self.h20) / 2 # No. of basis functions per principle layer of tip and srf nenergies = len(energies) # periodic part of the tip hs1_dii = self.h10[:pl1, :pl1], self.s10[:pl1, :pl1] hs1_dij = self.h10[:pl1, pl1 : 2 * pl1], self.s10[:pl1, pl1 : 2 * pl1] # coupling betwen per. and non. per part of the tip h1_im = np.zeros((pl1, nbf1), complex) s1_im = np.zeros((pl1, nbf1), complex) h1_im[:pl1, :pl1], s1_im[:pl1, :pl1] = hs1_dij hs1_dim = [h1_im, s1_im] # periodic part the surface hs2_dii = self.h20[:pl2, :pl2], self.s20[:pl2, :pl2] hs2_dij = self.h20[pl2 : 2 * pl2, :pl2], self.s20[pl2 : 2 * pl2, :pl2] # coupling betwen per. and non. per part of the surface h2_im = np.zeros((pl2, nbf2), complex) s2_im = np.zeros((pl2, nbf2), complex) h2_im[-pl2:, -pl2:], s2_im[-pl2:, -pl2:] = hs2_dij hs2_dim = [h2_im, s2_im] # tip and surface greenfunction self.selfenergy1 = LeadSelfEnergy(hs1_dii, hs1_dij, hs1_dim) self.selfenergy2 = LeadSelfEnergy(hs2_dii, hs2_dij, hs2_dim) self.greenfunction1 = GreenFunction(self.h1, self.s1, [self.selfenergy1]) self.greenfunction2 = GreenFunction(self.h2, self.s2, [self.selfenergy2]) # print 'shape of greenfunction tip:', np.shape(self.greenfunction1) # print 'shape of greenfunction srf:', np.shape(self.greenfunction2) # shift the bands due to the bias self.selfenergy1.set_bias(0.0) self.selfenergy2.set_bias(bias) # extend the surface potentials and basis functions self.setup_stm() # tip and surface greenfunction matrices. nbf1_small = self.ni # XXX Change this for efficiency in the future nbf2_small = self.nj # XXX -||- coupling_list1 = range(nbf1 - nbf1_small, nbf1) # XXX -||- coupling_list2 = range(0, nbf2_small) # XXX -||- self.gft1_emm = np.zeros((nenergies, nbf1_small, nbf1_small), complex) self.gft2_emm = np.zeros((nenergies, nbf2_small, nbf2_small), complex) for e, energy in enumerate(self.energies): gft1_mm = self.greenfunction1(energy)[coupling_list1] gft1_mm = np.take(gft1_mm, coupling_list1, axis=1) gft2_mm = self.greenfunction2(energy)[coupling_list2] gft2_mm = np.take(gft2_mm, coupling_list2, axis=1) self.gft1_emm[e] = gft1_mm self.gft2_emm[e] = gft2_mm def scan(self, height=None, zmin=None, zmax=None): if height is not None: self.current = np.zeros((self.srf.gd.N_c[0], self.srf.gd.N_c[1])) h = 0 h = np.round(height / Bohr / self.srf.gd.h_c[2]).astype(int) for px in range(self.srf.gd.N_c[0]): for py in range(self.srf.gd.N_c[1]): pos = np.array([px, py, h]) V_12 = self.get_Vts(pos) I = self.get_current(V_12) self.current[px, py] = I print("I = ", I) return self.current if height is None: zmin_c = np.round(zmin / Bohr / self.srf.gd.h_c[2]).astype(int) zmax_c = np.round(zmax / Bohr / self.srf.gd.h_c[2]).astype(int) nz = zmax_c - zmin_c self.current = np.zeros((self.srf.gd.N_c[0], self.srf.gd.N_c[1], nz)) for px in range(self.srf.gd.N_c[0]): for py in range(self.srf.gd.N_c[1]): for pz in range(zmin_c, zmax_c): # get coupleing between tip and surface Vts for a given tip position on original srf grids pos = np.array([px, py, pz]) V_12 = self.get_Vts(pos) # get current values I = self.get_current(V_12) self.current[px, py, pz - zmin_c] = I print(I) return self.current def get_current(self, v_12): # get transmission T_e = self.get_transmission(v_12) I = -np.trapz(x=self.energies, y=T_e) return I def get_transmission(self, v_12): nenergies = len(self.energies) T_e = np.empty(nenergies, float) v_21 = dagger(v_12) for e, energy in enumerate(self.energies): gft1 = self.gft1_emm[e] gft2 = self.gft2_emm[e] a1 = gft1 - dagger(gft1) a2 = gft2 - dagger(gft2) v12_a2 = np.dot(v_12, a2) v21_a1 = np.dot(v_21, a1) T = -np.trace(np.dot(v12_a2, v21_a1)) T_e[e] = T self.T_e = T_e return T_e def get_Vts(self, tip_pos): # tip_pos is in terms of grid points, showing the tip apex position respect to the surface grid print("tip_pos is", tip_pos) tip_apex_c = self.tip_apex_c[0] srf_pos_av = self.srf.atoms.get_positions() / Bohr srf_zmax = srf_pos_av[:, 2].max() srf_zmax_c = np.round(srf_zmax / self.srf.gd.h_c[2]).astype(int) srf_ox = self.srf_extension[0] + tip_pos[0] srf_oy = self.srf_extension[1] + tip_pos[1] srf_oz = srf_zmax_c + tip_pos[2] shift = np.array([srf_ox, srf_oy, srf_oz]) shift -= tip_apex_c for tbox in self.tip_coupling_functions: tbox.corner_c += shift for tbox in self.tip_coupling_kinetics: tbox.corner_c += shift # get the combined effective potential on the extended surface grid """ This part needs to be updated for a separate xc calculation """ tip_ox = self.ox tip_oy = self.oy tip_oz = self.oz srf_sx = srf_ox - self.nmx srf_ex = srf_ox + self.npx srf_sy = srf_oy - self.nmy srf_ey = srf_oy + self.npy srf_sz = srf_oz - self.nmz srf_ez = srf_oz + self.npz tip_sx = tip_ox - self.nmx tip_ex = tip_ox + self.npx tip_sy = tip_oy - self.nmy tip_ey = tip_oy + self.npy tip_sz = tip_oz - self.nmz tip_ez = tip_oz + self.npz V_tip = self.tip.get_effective_potential() - self.tip_alignv V_couple = self.extvt_G.copy() V_couple[srf_sx:srf_ex, srf_sy:srf_ey, srf_sz:srf_ez] = V_tip[tip_sx:tip_ex, tip_sy:tip_ey, tip_sz:tip_ez] # get V_ts V_ts = np.zeros((self.ni, self.nj)) for ns in range(len(self.srf_coupling_functions)): sf = self.srf_coupling_functions[ns] sk = self.srf_coupling_kinetics[ns] j1 = sf[0].index j2 = j1 + len(sf[0]) for t in self.tip_coupling_functions: i1 = t.index i2 = i1 + len(t) test_overlap1 = [] test_overlap2 = [] for x in range(9): overlap = t | sf[x] if overlap is not None: test_overlap1.append(overlap.copy()) test_overlap2.append((np.abs(overlap)).sum()) else: test_overlap1.append(overlap) test_overlap2.append(overlap) k = np.argmax(test_overlap2) if test_overlap1[k] is not None: V_ts[i1:i2, j1:j2] += t | sk[k] V_ts[i1:i2, j1:j2] += t | V_couple | sf[k] # return the tbox back :) for tbox in self.tip_coupling_functions: tbox.corner_c -= shift for tbox in self.tip_coupling_kinetics: tbox.corner_c -= shift # print 'np.shape(V_ts)',np.shape(V_ts) return V_ts def setup_stm(self): tip_pos_av = self.tip.atoms.get_positions() / Bohr srf_pos_av = self.srf.atoms.get_positions() / Bohr # get selected tip functions on small grids and apply kinetics self.tip_coupling_functions = [] self.tip_coupling_kinetics = [] i = 0 for a in self.tip_coupling_atoms: setup = self.tip.wfs.setups[a] spos_c = tip_pos_av[a] / self.tip.gd.cell_c # gives the scaled position of tip atoms in tip cell for phit in setup.phit_j: f = AtomCenteredFunctions(self.tip.gd, [phit], spos_c, i) f_kinetic = f.apply_t() self.tip_coupling_functions.append(f) self.tip_coupling_kinetics.append(f_kinetic) i += len(f.f_iG) self.ni = i # print self.tip_coupling_functions[1].size_c # print self.tip_coupling_functions[1].corner_c # print np.shape(self.tip_coupling_functions[1].f_iG) # get tip cutoff and surface extension tip_corner_c = [] temp_min = self.tip_coupling_kinetics[0].corner_c temp_max = self.tip_coupling_kinetics[0].corner_c for f in self.tip_coupling_kinetics: start_c = np.minimum(f.corner_c, temp_min) end_c = np.maximum(f.corner_c + f.size_c, temp_max) temp_min = start_c temp_max = end_c # print "start_c",start_c # in terms of grid points # print "end_c",end_c # in terms of grid points self.tip_zmin = tip_pos_av[:, 2].min() self.tip_apex_index = np.where(tip_pos_av[:, 2] < self.tip_zmin + 0.01) self.tip_apex_c = np.round(tip_pos_av[self.tip_apex_index] / self.tgd.h_c).astype(int) self.ox, self.oy, self.oz = self.tip_apex_c[0] self.npx, self.npy, self.npz = np.round(end_c).astype(int) - self.tip_apex_c[0] self.nmx, self.nmy, self.nmz = self.tip_apex_c[0] - np.round(start_c).astype(int) # get the extension of srf basis functions and effective potentials srf_extension = np.array([self.srf.gd.N_c[0], self.srf.gd.N_c[1], 0]) self.srf_extension = srf_extension print("extension of surface in terms of grids:", srf_extension) # get surface fucntions on small grid with periodic conditions with entension self.srf_coupling_functions = [] self.srf_coupling_kinetics = [] j = 0 for a in self.srf_coupling_atoms: setup = self.srf.wfs.setups[a] spos_c = srf_pos_av[a] / self.srf.gd.cell_c for phit in setup.phit_j: f = AtomCenteredFunctions(self.srf.gd, [phit], spos_c, j) f.corner_c += srf_extension f_kinetic = f.apply_t() self.srf_coupling_functions.append(f.periodic()) self.srf_coupling_kinetics.append(f_kinetic.periodic()) j += len(f.f_iG) self.nj = j # print np.shape(self.srf_coupling_functions[0][0].f_iG), self.srf_coupling_functions[0][0].corner_c # print np.shape(self.srf_coupling_functions[0][8].f_iG), self.srf_coupling_functions[0][8].corner_c # Extend the surface grid and surface effective potential svt_G = self.srf.get_effective_potential() - self.srf_alignv + self.bias ex, ey, ez = srf_extension newsize_c = 2 * srf_extension + self.sgd.N_c extvt_G = np.zeros(newsize_c) extvt_G[ex:-ex, ey:-ey, :] = svt_G extvt_G[:ex, ey:-ey, :] = svt_G[-ex:, :, :] extvt_G[-ex:, ey:-ey, :] = svt_G[:ex, :, :] extvt_G[:, :ey, :] = extvt_G[:, -2 * ey : -ey, :] extvt_G[:, -ey:, :] = extvt_G[:, ey : 2 * ey, :] self.extvt_G = extvt_G extsgd = GridDescriptor(N_c=newsize_c, cell_cv=self.sgd.h_c * (newsize_c), pbc_c=False, comm=mpi.serial_comm) ## Transfer the coner_c of surface basis-functions and srf_kinetics to the extended surface cell # for sbox in self.srf_coupling_functions: # sbox.corner_c += srf_extension # for sbox in self.srf_coupling_kinetics: # sbox.corner_c += srf_extension def align_v(self, calc1, index1, calc2, index2): pos1 = calc1.atoms.positions[index1] pos1_c = np.round(pos1 / Bohr / calc1.wfs.gd.h_c).astype(int) pos1_v = calc1.get_effective_potential()[pos1_c[0], pos1_c[1], pos1_c[2]] pos2 = calc2.atoms.positions[index2] pos2_c = np.round(pos2 / Bohr / calc2.wfs.gd.h_c).astype(int) pos2_v = calc2.get_effective_potential()[pos2_c[0], pos2_c[1], pos2_c[2]] return pos2_v - pos1_v
def initialize(self, srf_atoms, tip_atoms, srf_coupling_atoms, tip_coupling_atoms, srf_pl_atoms, tip_pl_atoms, energies, bias=0): """ srf_atoms: the atom index of onsite surface atoms tip_atoms: the atom index of onsite tip atoms energies: list of energies, for which the transmission function should be evaluated bias: will be used to precalculate the greenfunctions of surface and tip """ self.bias = bias self.energies = energies self.tip_atoms = tip_atoms self.srf_atoms = srf_atoms self.srf_coupling_atoms = srf_coupling_atoms self.tip_coupling_atoms = tip_coupling_atoms #align potentials for onsite surface, onsite tip and tip principle layers according to surface_pl srf_alignv = self.align_v(calc1 = self.srf_pl, index1=srf_pl_atoms[0], calc2=self.srf, index2=srf_atoms[0]) tip_alignv = srf_alignv + self.tip.get_fermi_level() - self.srf.get_fermi_level() #- bias tip_pl_alignv = self.align_v(calc1=self.tip, index1=tip_atoms[-1], calc2=self.tip_pl, index2=tip_pl_atoms[-1]) tip_pl_alignv += tip_alignv self.srf_alignv = srf_alignv self.tip_alignv = tip_alignv #hamiltoian and overlap matrix of onsite tip and srf self.h1, self.s1 = Lead_HS(calc = self.tip, atom_list = tip_atoms, shift = srf_alignv-bias).get_HS() print 'shape of onsite tip', np.shape(self.h1), np.shape(self.s1) self.h2, self.s2 = Lead_HS(calc = self.srf, atom_list = srf_atoms, shift = tip_alignv).get_HS() print 'shape of onsite srf', np.shape(self.h2), np.shape(self.s2) #hamiltoian and overlap matrix of two tip and srf principle layers self.h10, self.s10 = Lead_HS(calc = self.tip_pl, atom_list = tip_pl_atoms, shift = tip_pl_alignv).get_HS() #2 and only 2 principle layers print 'shape of pl tip', np.shape(self.h10), np.shape(self.s10) self.h20, self.s20 = Lead_HS(calc = self.srf_pl, atom_list = srf_pl_atoms, shift = -bias).get_HS() #2 and only 2 principle layers print 'shape of pl srf', np.shape(self.h20), np.shape(self.s20) nbf1, nbf2 = len(self.h1), len(self.h2) #No. of basis functions of onsite tip and surface atoms pl1, pl2 = len(self.h10)/2, len(self.h20)/2 #No. of basis functions per principle layer of tip and srf nenergies = len(energies) #periodic part of the tip hs1_dii = self.h10[:pl1, :pl1], self.s10[:pl1, :pl1] hs1_dij = self.h10[:pl1, pl1:2*pl1], self.s10[:pl1, pl1:2*pl1] #coupling betwen per. and non. per part of the tip h1_im = np.zeros((pl1, nbf1), complex) s1_im = np.zeros((pl1, nbf1), complex) h1_im[:pl1, :pl1], s1_im[:pl1, :pl1] = hs1_dij hs1_dim = [h1_im, s1_im] #periodic part the surface hs2_dii = self.h20[:pl2, :pl2], self.s20[:pl2, :pl2] hs2_dij = self.h20[pl2:2*pl2, :pl2], self.s20[pl2:2*pl2, :pl2] #coupling betwen per. and non. per part of the surface h2_im = np.zeros((pl2, nbf2), complex) s2_im = np.zeros((pl2, nbf2), complex) h2_im[-pl2:, -pl2:], s2_im[-pl2:, -pl2:] = hs2_dij hs2_dim = [h2_im, s2_im] #tip and surface greenfunction self.selfenergy1 = LeadSelfEnergy(hs1_dii, hs1_dij, hs1_dim) self.selfenergy2 = LeadSelfEnergy(hs2_dii, hs2_dij, hs2_dim) self.greenfunction1 = GreenFunction(self.h1, self.s1,[self.selfenergy1]) self.greenfunction2 = GreenFunction(self.h2, self.s2,[self.selfenergy2]) #print 'shape of greenfunction tip:', np.shape(self.greenfunction1) #print 'shape of greenfunction srf:', np.shape(self.greenfunction2) #shift the bands due to the bias self.selfenergy1.set_bias(0.0) self.selfenergy2.set_bias(bias) # extend the surface potentials and basis functions self.setup_stm() #tip and surface greenfunction matrices. nbf1_small = self.ni #XXX Change this for efficiency in the future nbf2_small = self.nj #XXX -||- coupling_list1 = range(nbf1-nbf1_small,nbf1)# XXX -||- coupling_list2 = range(0,nbf2_small)# XXX -||- self.gft1_emm = np.zeros((nenergies, nbf1_small, nbf1_small), complex) self.gft2_emm = np.zeros((nenergies, nbf2_small, nbf2_small), complex) for e, energy in enumerate(self.energies): gft1_mm = self.greenfunction1(energy)[coupling_list1] gft1_mm = np.take(gft1_mm, coupling_list1, axis=1) gft2_mm = self.greenfunction2(energy)[coupling_list2] gft2_mm = np.take(gft2_mm, coupling_list2, axis=1) self.gft1_emm[e] = gft1_mm self.gft2_emm[e] = gft2_mm
class STM: def __init__(self, srf, tip, srf_pl, tip_pl, eta1=1e-4, eta2=1e-4): self.tip = tip # tip calcualtor self.tip_pl = tip_pl # tip periodic layers calculator self.srf = srf # surface calculator self.srf_pl = srf_pl # surface periodic layers calculator self.eta1 = eta1 self.eta2 = eta2 self.tgd = tip.gd self.sgd = srf.gd #assert tgd.h_cv == sgd.h_cv #assert not (tgd.h_c - sgd.h_c).any() def initialize(self, srf_atoms, tip_atoms, srf_coupling_atoms, tip_coupling_atoms, srf_pl_atoms, tip_pl_atoms, energies, bias=0): """ srf_atoms: the atom index of onsite surface atoms tip_atoms: the atom index of onsite tip atoms energies: list of energies, for which the transmission function should be evaluated bias: will be used to precalculate the greenfunctions of surface and tip """ self.bias = bias self.energies = energies self.tip_atoms = tip_atoms self.srf_atoms = srf_atoms self.srf_coupling_atoms = srf_coupling_atoms self.tip_coupling_atoms = tip_coupling_atoms #align potentials for onsite surface, onsite tip and tip principle layers according to surface_pl srf_alignv = self.align_v(calc1 = self.srf_pl, index1=srf_pl_atoms[0], calc2=self.srf, index2=srf_atoms[0]) tip_alignv = srf_alignv + self.tip.get_fermi_level() - self.srf.get_fermi_level() #- bias tip_pl_alignv = self.align_v(calc1=self.tip, index1=tip_atoms[-1], calc2=self.tip_pl, index2=tip_pl_atoms[-1]) tip_pl_alignv += tip_alignv self.srf_alignv = srf_alignv self.tip_alignv = tip_alignv #hamiltoian and overlap matrix of onsite tip and srf self.h1, self.s1 = Lead_HS(calc = self.tip, atom_list = tip_atoms, shift = srf_alignv-bias).get_HS() print 'shape of onsite tip', np.shape(self.h1), np.shape(self.s1) self.h2, self.s2 = Lead_HS(calc = self.srf, atom_list = srf_atoms, shift = tip_alignv).get_HS() print 'shape of onsite srf', np.shape(self.h2), np.shape(self.s2) #hamiltoian and overlap matrix of two tip and srf principle layers self.h10, self.s10 = Lead_HS(calc = self.tip_pl, atom_list = tip_pl_atoms, shift = tip_pl_alignv).get_HS() #2 and only 2 principle layers print 'shape of pl tip', np.shape(self.h10), np.shape(self.s10) self.h20, self.s20 = Lead_HS(calc = self.srf_pl, atom_list = srf_pl_atoms, shift = -bias).get_HS() #2 and only 2 principle layers print 'shape of pl srf', np.shape(self.h20), np.shape(self.s20) nbf1, nbf2 = len(self.h1), len(self.h2) #No. of basis functions of onsite tip and surface atoms pl1, pl2 = len(self.h10)/2, len(self.h20)/2 #No. of basis functions per principle layer of tip and srf nenergies = len(energies) #periodic part of the tip hs1_dii = self.h10[:pl1, :pl1], self.s10[:pl1, :pl1] hs1_dij = self.h10[:pl1, pl1:2*pl1], self.s10[:pl1, pl1:2*pl1] #coupling betwen per. and non. per part of the tip h1_im = np.zeros((pl1, nbf1), complex) s1_im = np.zeros((pl1, nbf1), complex) h1_im[:pl1, :pl1], s1_im[:pl1, :pl1] = hs1_dij hs1_dim = [h1_im, s1_im] #periodic part the surface hs2_dii = self.h20[:pl2, :pl2], self.s20[:pl2, :pl2] hs2_dij = self.h20[pl2:2*pl2, :pl2], self.s20[pl2:2*pl2, :pl2] #coupling betwen per. and non. per part of the surface h2_im = np.zeros((pl2, nbf2), complex) s2_im = np.zeros((pl2, nbf2), complex) h2_im[-pl2:, -pl2:], s2_im[-pl2:, -pl2:] = hs2_dij hs2_dim = [h2_im, s2_im] #tip and surface greenfunction self.selfenergy1 = LeadSelfEnergy(hs1_dii, hs1_dij, hs1_dim) self.selfenergy2 = LeadSelfEnergy(hs2_dii, hs2_dij, hs2_dim) self.greenfunction1 = GreenFunction(self.h1, self.s1,[self.selfenergy1]) self.greenfunction2 = GreenFunction(self.h2, self.s2,[self.selfenergy2]) #print 'shape of greenfunction tip:', np.shape(self.greenfunction1) #print 'shape of greenfunction srf:', np.shape(self.greenfunction2) #shift the bands due to the bias self.selfenergy1.set_bias(0.0) self.selfenergy2.set_bias(bias) # extend the surface potentials and basis functions self.setup_stm() #tip and surface greenfunction matrices. nbf1_small = self.ni #XXX Change this for efficiency in the future nbf2_small = self.nj #XXX -||- coupling_list1 = range(nbf1-nbf1_small,nbf1)# XXX -||- coupling_list2 = range(0,nbf2_small)# XXX -||- self.gft1_emm = np.zeros((nenergies, nbf1_small, nbf1_small), complex) self.gft2_emm = np.zeros((nenergies, nbf2_small, nbf2_small), complex) for e, energy in enumerate(self.energies): gft1_mm = self.greenfunction1(energy)[coupling_list1] gft1_mm = np.take(gft1_mm, coupling_list1, axis=1) gft2_mm = self.greenfunction2(energy)[coupling_list2] gft2_mm = np.take(gft2_mm, coupling_list2, axis=1) self.gft1_emm[e] = gft1_mm self.gft2_emm[e] = gft2_mm def scan(self,height=None,zmin=None,zmax=None): if height is not None: self.current = np.zeros((self.srf.gd.N_c[0],self.srf.gd.N_c[1])) h = 0 h = np.round(height/Bohr/self.srf.gd.h_c[2]).astype(int) for px in range(self.srf.gd.N_c[0]): for py in range(self.srf.gd.N_c[1]): pos = np.array([px,py,h]) V_12 = self.get_Vts(pos) I = self.get_current(V_12) self.current[px,py] = I print 'I = ', I return self.current if height is None: zmin_c = np.round(zmin/Bohr/self.srf.gd.h_c[2]).astype(int) zmax_c = np.round(zmax/Bohr/self.srf.gd.h_c[2]).astype(int) nz = zmax_c - zmin_c self.current = np.zeros((self.srf.gd.N_c[0],self.srf.gd.N_c[1],nz)) for px in range(self.srf.gd.N_c[0]): for py in range(self.srf.gd.N_c[1]): for pz in range(zmin_c,zmax_c): # get coupleing between tip and surface Vts for a given tip position on original srf grids pos = np.array([px,py,pz]) V_12 = self.get_Vts(pos) # get current values I = self.get_current(V_12) self.current[px,py,pz-zmin_c] = I print I return self.current def get_current(self, v_12): # get transmission T_e = self.get_transmission(v_12) I = -np.trapz(x = self.energies, y = T_e) return I def get_transmission(self, v_12): nenergies = len(self.energies) T_e = np.empty(nenergies,float) v_21 = dagger(v_12) for e, energy in enumerate(self.energies): gft1 = self.gft1_emm[e] gft2 = self.gft2_emm[e] a1 = (gft1 - dagger(gft1)) a2 = (gft2 - dagger(gft2)) v12_a2 = np.dot(v_12, a2) v21_a1 = np.dot(v_21, a1) T = -np.trace(np.dot(v12_a2, v21_a1)) T_e[e] = T self.T_e = T_e return T_e def get_Vts(self, tip_pos): # tip_pos is in terms of grid points, showing the tip apex position respect to the surface grid print 'tip_pos is', tip_pos tip_apex_c = self.tip_apex_c[0] srf_pos_av = self.srf.atoms.get_positions() / Bohr srf_zmax = srf_pos_av[:,2].max() srf_zmax_c = np.round(srf_zmax / self.srf.gd.h_c[2]).astype(int) srf_ox = self.srf_extension[0] + tip_pos[0] srf_oy = self.srf_extension[1] + tip_pos[1] srf_oz = srf_zmax_c + tip_pos[2] shift = np.array([srf_ox, srf_oy, srf_oz]) shift -= tip_apex_c for tbox in self.tip_coupling_functions: tbox.corner_c += shift for tbox in self.tip_coupling_kinetics: tbox.corner_c += shift # get the combined effective potential on the extended surface grid """ This part needs to be updated for a separate xc calculation """ tip_ox = self.ox tip_oy = self.oy tip_oz = self.oz srf_sx = srf_ox - self.nmx srf_ex = srf_ox + self.npx srf_sy = srf_oy - self.nmy srf_ey = srf_oy + self.npy srf_sz = srf_oz - self.nmz srf_ez = srf_oz + self.npz tip_sx = tip_ox - self.nmx tip_ex = tip_ox + self.npx tip_sy = tip_oy - self.nmy tip_ey = tip_oy + self.npy tip_sz = tip_oz - self.nmz tip_ez = tip_oz + self.npz V_tip = self.tip.get_effective_potential() - self.tip_alignv V_couple = self.extvt_G.copy() V_couple[srf_sx:srf_ex, srf_sy:srf_ey, srf_sz:srf_ez] = V_tip[tip_sx:tip_ex, tip_sy:tip_ey, tip_sz:tip_ez] #get V_ts V_ts = np.zeros((self.ni,self.nj)) for ns in range(len(self.srf_coupling_functions)): sf = self.srf_coupling_functions[ns] sk = self.srf_coupling_kinetics[ns] j1 = sf[0].index j2 = j1 + len(sf[0]) for t in self.tip_coupling_functions: i1 = t.index i2 = i1 + len(t) test_overlap1 = [] test_overlap2 = [] for x in range(9): overlap = (t | sf[x]) if overlap is not None: test_overlap1.append(overlap.copy()) test_overlap2.append((np.abs(overlap)).sum()) else: test_overlap1.append(overlap) test_overlap2.append(overlap) k = np.argmax(test_overlap2) if test_overlap1[k] != None: V_ts[i1:i2, j1:j2] += (t|sk[k]) V_ts[i1:i2, j1:j2] += (t|V_couple|sf[k]) # return the tbox back :) for tbox in self.tip_coupling_functions: tbox.corner_c -= shift for tbox in self.tip_coupling_kinetics: tbox.corner_c -= shift #print 'np.shape(V_ts)',np.shape(V_ts) return V_ts def setup_stm(self): tip_pos_av = self.tip.atoms.get_positions() / Bohr srf_pos_av = self.srf.atoms.get_positions() / Bohr # get selected tip functions on small grids and apply kinetics self.tip_coupling_functions = [] self.tip_coupling_kinetics = [] i = 0 for a in self.tip_coupling_atoms: setup = self.tip.wfs.setups[a] spos_c = tip_pos_av[a] / self.tip.gd.cell_c #gives the scaled position of tip atoms in tip cell for phit in setup.phit_j: f = AtomCenteredFunctions(self.tip.gd, [phit], spos_c, i) f_kinetic = f.apply_t() self.tip_coupling_functions.append(f) self.tip_coupling_kinetics.append(f_kinetic) i += len(f.f_iG) self.ni = i #print self.tip_coupling_functions[1].size_c #print self.tip_coupling_functions[1].corner_c #print np.shape(self.tip_coupling_functions[1].f_iG) # get tip cutoff and surface extension tip_corner_c = [] temp_min = self.tip_coupling_kinetics[0].corner_c temp_max = self.tip_coupling_kinetics[0].corner_c for f in self.tip_coupling_kinetics: start_c = np.minimum(f.corner_c, temp_min) end_c = np.maximum(f.corner_c+f.size_c, temp_max) temp_min = start_c temp_max = end_c #print "start_c",start_c # in terms of grid points #print "end_c",end_c # in terms of grid points self.tip_zmin = tip_pos_av[:,2].min() self.tip_apex_index = np.where(tip_pos_av[:,2] < self.tip_zmin + 0.01) self.tip_apex_c = np.round(tip_pos_av[self.tip_apex_index] / self.tgd.h_c).astype(int) self.ox, self.oy, self.oz = self.tip_apex_c[0] self.npx, self.npy, self.npz = np.round(end_c).astype(int) - self.tip_apex_c[0] self.nmx, self.nmy, self.nmz = self.tip_apex_c[0] - np.round(start_c).astype(int) # get the extension of srf basis functions and effective potentials srf_extension = np.array([self.srf.gd.N_c[0], self.srf.gd.N_c[1], 0]) self.srf_extension = srf_extension print 'extension of surface in terms of grids:', srf_extension # get surface fucntions on small grid with periodic conditions with entension self.srf_coupling_functions = [] self.srf_coupling_kinetics = [] j = 0 for a in self.srf_coupling_atoms: setup = self.srf.wfs.setups[a] spos_c = srf_pos_av[a] / self.srf.gd.cell_c for phit in setup.phit_j: f = AtomCenteredFunctions(self.srf.gd, [phit], spos_c, j) f.corner_c += srf_extension f_kinetic = f.apply_t() self.srf_coupling_functions.append(f.periodic()) self.srf_coupling_kinetics.append(f_kinetic.periodic()) j += len(f.f_iG) self.nj = j #print np.shape(self.srf_coupling_functions[0][0].f_iG), self.srf_coupling_functions[0][0].corner_c #print np.shape(self.srf_coupling_functions[0][8].f_iG), self.srf_coupling_functions[0][8].corner_c # Extend the surface grid and surface effective potential svt_G = self.srf.get_effective_potential() - self.srf_alignv + self.bias ex,ey,ez = srf_extension newsize_c = 2 * srf_extension + self.sgd.N_c extvt_G = np.zeros(newsize_c) extvt_G[ex:-ex,ey:-ey,:] = svt_G extvt_G[:ex,ey:-ey,:] = svt_G[-ex:,:,:] extvt_G[-ex:,ey:-ey,:] = svt_G[:ex,:,:] extvt_G[:,:ey,:] = extvt_G[:,-2*ey:-ey,:] extvt_G[:,-ey:,:] = extvt_G[:,ey:2*ey,:] self.extvt_G = extvt_G extsgd = GridDescriptor(N_c=newsize_c, cell_cv=self.sgd.h_c*(newsize_c), pbc_c=False, comm=mpi.serial_comm) ## Transfer the coner_c of surface basis-functions and srf_kinetics to the extended surface cell #for sbox in self.srf_coupling_functions: # sbox.corner_c += srf_extension #for sbox in self.srf_coupling_kinetics: # sbox.corner_c += srf_extension def align_v(self,calc1,index1,calc2,index2): pos1 = calc1.atoms.positions[index1] pos1_c = np.round(pos1/Bohr/calc1.wfs.gd.h_c).astype(int) pos1_v = calc1.get_effective_potential()[pos1_c[0],pos1_c[1],pos1_c[2]] pos2 = calc2.atoms.positions[index2] pos2_c = np.round(pos2/Bohr/calc2.wfs.gd.h_c).astype(int) pos2_v = calc2.get_effective_potential()[pos2_c[0],pos2_c[1],pos2_c[2]] return pos2_v - pos1_v