def rpa_dt(axes, rs, nx=32): """ calculate kinetic finite size error assuming RPA U(k) and S(k) Args: raxes (np.array): reciprocal space lattice rs (float): Wigner-Seitz radius i.e. density parameter Return: float: kinetic finite size correction """ from qharv.inspect import axes_pos density = (4 * np.pi / 3 * rs**3.)**(-1) # get RPA U(k) and S(k) kf = heg_kfermi(rs) fuk = lambda k: gaskell_rpa_uk(k, rs, kf) fsk = effective_fsk_from_fuk(fuk, rs) # setup integration grid raxes = axes_pos.raxes(axes) qgrid = mp_grid(raxes, nx) # perform quadrature # weights rvol = axes_pos.volume(raxes) intnorm = 1. / (2 * np.pi)**3 * rvol / nx**3 * density # sum qmags = np.linalg.norm(qgrid, axis=1) integrand = lambda k: 0.5 * k**2 * fuk(k)**2 * fsk(k) dtlr = intnorm * integrand(qmags).sum() return dtlr
def heg_jas(rs, axes, nr, nsh0=5, kc=None, zoom=1e10): # note zoom of 1e10 keeps 10 digits when grouping kshells # probably too high of a resolution, but this is QMCPACK default kf = heg_kfermi(rs) # assume unpolarized if kc is None: kc = kf from qharv.inspect import axes_pos rcut = axes_pos.rwsc(axes) # step 1: build short-range Jastrow uuc, udc = get_rpa_coeff(rs, rcut, nr) j2sr = fusr(rcut, uuc, udc) # step 2: find unique kmags raxes = axes_pos.raxes(axes) kvecs = get_kshells(nsh0, raxes) kmags = np.linalg.norm(kvecs, axis=-1) sel = (0 < kmags) & (kmags < kc) import static_correlation as sc #ukmags = np.unique(kmags[sel]) # no tolerance option kmags1 = kmags[sel] sels = sc.kshell_sels(kmags1, zoom) ukmags = np.array([kmags1[s].mean() for s in sels]) # step 3: get Ulr urpa = gaskell_rpa_uk(ukmags, rs, kf) usrk = evaluate_ft(ukmags, j2sr, rcut) ulrk = usrk - urpa return ukmags, ulrk, uuc, udc
def sofk_snapshot(axes, pos, nkmax=5, legal_kvecs=None): """ calculate the structure factor of a snapshot of a crystal structure given 'axes' and 'pos' of atoms. 'nkmax' is the number of kvectors to include in each of x,y,z directions. return 2 lists: legal kvectors, and S(k) of each kvector Args: axes (np.array): crystal lattice vectors. pos (np.array): positions of atoms. nkmax (int,optional): maximum number of kvectors in each spatial dimension, default is 5. Used only if legal_kvecs is not give. leagal_kvecs (np.array,optional): kvectors upon which S(k) is defined, default is to recalculate up to nkmax. Returns: (np.array,np.array): (kvecs,S(k)) """ from qharv.inspect.axes_pos import raxes rho = lambda kvec: np.exp(1j * np.dot(pos, kvec)).sum() reclat = raxes(axes) if legal_kvecs is None: import chiesa_correction as chc cube_pts = chc.cubic_pos(nkmax) legal_kvecs = np.dot(cube_pts[1:], reclat) sk_arr = np.array([(rho(kvec) * rho(-kvec)).real / len(pos) for kvec in legal_kvecs]) return legal_kvecs, sk_arr
def detect_p21c_layers(mols, kfracs=None): from qharv.inspect import axes_pos # setup S(k) calculation from qharv_db import grsk if kfracs is None: kfracs = np.array([ [0, -8, 16], [0, 8, 16], ]) axes = mols.get_cell() raxes = axes_pos.raxes(axes) kvecs = np.dot(kfracs, raxes) # detect layers layers = find_layers(mols) groups = extract_layers(layers, [mols]) grps = [g[0] for g in groups] # loop through 3 layers at a time nlayer = len(grps) layer_desc = [] for ilayer in range(1, nlayer-1): pos0 = grps[ilayer-1] pos1 = grps[ilayer] pos2 = grps[ilayer+1] pos = np.concatenate([pos0, pos1, pos2], axis=0) sk1 = grsk.Sk(kvecs, pos) layer_desc.append(sk1.sum()) return layer_desc
def get_all_rhok(fwf, kbrags, norb=None, ispin=0, show_progress=True): from qharv.seed import wf_h5 from qharv.inspect import axes_pos from rsgub.grids.forlib.find_gvecs import calc_rhok fp = wf_h5.read(fwf) axes = wf_h5.get(fp, 'axes') # calculate ukbrags raxes = axes_pos.raxes(axes) kcand = np.dot(kbrags, np.linalg.inv(raxes)) ukbrags = np.round(kcand).astype(int) # check ukbrags kbrags1 = np.dot(ukbrags, raxes) assert np.allclose(kbrags, kbrags1) # calculate rhok gvecs = wf_h5.get(fp, 'gvectors') ntwist = wf_h5.get(fp, 'nkpt')[ispin] # store complex numbers in real view data = np.zeros([ntwist, 2*len(ukbrags)]) if show_progress: from progressbar import ProgressBar bar = ProgressBar(maxval=ntwist) for itwist in range(ntwist): cmat = wf_h5.get_cmat(fp, itwist, ispin, norb=norb) val = 2*calc_rhok(ukbrags, gvecs, cmat) data[itwist, :] = val.view(float) if show_progress: bar.update(itwist) fp.close() return data
def legal_kvecs(axes, nsh, eps=1e-8): from qharv.inspect import axes_pos raxes = axes_pos.raxes(axes) gvecs = axes_pos.cubic_pos(2*nsh+1)-nsh kvecs = np.dot(gvecs, raxes) kmags = np.linalg.norm(kvecs, axis=-1) sel = (kmags>eps) & (kvecs[:, 2]>=0) return kvecs[sel]
def get_qvecs_and_intnorm(axes, mx): from qharv.inspect import axes_pos # get qvectors raxes = axes_pos.raxes(axes) fvecs = 1./mx*axes_pos.cubic_pos(mx) qvecs = np.dot(fvecs, raxes) qvecs -= qvecs.mean(axis=0) # calculate integration norm intnorm = axes_pos.volume(raxes)/mx**3/(2*np.pi)**3 return qvecs, intnorm
def calc_nk1d_fsc(uk, unkm, nelec, rs=3.25, mx=8): from qharv.inspect import axes_pos from solith.li_nofk.expt_jofp import flip_and_clamp from solith.dft_calc.bcc_crystal import get_cubic_axes from chiesa_correction import IsotropicMomentumDistributionFSC axes = get_cubic_axes(rs, nelec) raxes = axes_pos.raxes(axes) fsc = IsotropicMomentumDistributionFSC(rs) fsc.init_missing_qvecs(raxes, mx) fnk = flip_and_clamp(uk, unkm, kind='linear') kvs = np.array([[k, 0, 0] for k in uk]) dnk_fsc = fsc.evaluate_fsc(fnk, kvs) return np.array(dnk_fsc)
def get_momenta_and_weights(fp, ispin, ikpt, kmax, ecore, efermi): """ Histogram psig^2 for a single determinant of Kohn-Sham orbitals at a single twist. Select states with momenta k<kmax and energy ecore<e<efermi. Args: fp (h5py.File): pwscf.pwscf.h5 file pointer ispin (int): determinant index (0: unpolarized, 0/1: polarized) ikpt (int): twist vector index kmax (float): maximum momentum to record ecore (float): Core state energy bound. States below ecore are excluded efermi (float): Fermi energy Return: (np.array, np.array): (momenta, weights) """ # get reciprocal lattice vectors to do lattice transformation axes = wf_h5.get(fp, 'axes') raxes = axes_pos.raxes(axes) # Bloch function momenta (kvecs) gvecs = wf_h5.get(fp, 'gvectors') kvecs = np.dot(gvecs, raxes) # crystal momentum (tvec) kpath = wf_h5.kpoint_path(ikpt) utvec = fp[os.path.join(kpath, 'reduced_k')].value tvec = np.dot(utvec, raxes) # true momentum = crystal + Bloch momentum mykvecs = kvecs + tvec[np.newaxis, :] # keep kvectors below kmax mykmags = np.linalg.norm(mykvecs, axis=1) sel = mykmags < kmax momenta = mykvecs[sel] # accumulate occupation weights = np.zeros(len(momenta)) # keep states below the Fermi level and outside the core nstate = fp[os.path.join(kpath, 'spin_%d' % ispin, 'number_of_states')].value[0] evals = fp[os.path.join(kpath, 'spin_%d' % ispin, 'eigenvalues')].value esel = (evals > ecore) & (evals < efermi) states = np.arange(nstate) for istate in states[esel]: psig = wf_h5.get_orb_in_pw(fp, ikpt, ispin, istate) pg2 = psig.conj() * psig if not np.allclose(pg2.imag, 0): raise RuntimeError('dot not zero') pg2 = pg2.real[sel] weights += pg2 return momenta, weights
def get_explicit_kpaths(seek_json, dk=0.025): """ convert implicit kpath info to explicit list of kpoints make simple edits to the JSON file returned from the seeK-path website so that it would be accepted by seekpath.getpaths.get_explicit_from_implicit example of implicit kpath: 'path':[ ['GAMMA', 'H'], ['H', 'N'], ['N', 'GAMMA'], ['GAMMA', 'P'], ['P', 'H'], ['P', 'N'] ], 'kpoints_rel':[ 'GAMMA':[0.0,0.0,0.0], 'H':[0.5,-0.5,0.5], 'N':[0.0,0.0,0.5], 'P':[0.25,0.25,0.25] ] example of explicity kpath: 'kpoints_labels':['Gamma','',...,'N'], 'kpoints_abs': array([ [0.,0.,0.] [0.018,0.,0.018], ..., [1.618,1.618,3.236] ]) Args: seek_json (str): JSON file pasted from seeK-path website dk (float, optional): spacing in reciprocal space in Hartree a.u. Return: dict: return value of seekpath.getpaths.get_explicit_from_implicit """ from qharv.inspect import axes_pos # need raxes with open(seek_json, 'r') as f: data = json.load(f) # end with data['point_coords'] = data['kpoints'] data['reciprocal_primitive_lattice'] = axes_pos.raxes( data['primitive_lattice']) kpaths = seekpath.getpaths.get_explicit_from_implicit(data, dk) return kpaths
def write_detsk(h5file, ikpt, fwf, ispin, nsh0, kc): """Calculate determinant S(k) at given twist Args: h5file (tables.file.File): hdf5 file handle ikpt (int): twist index fwf (str): wf h5 file e.g. pwscf.pwscf.h5 ispin (int): spin index, use 0 for unpolarized nsh0 (int): number of shells to use kc (float): PW cutoff """ from qharv.seed import wf_h5 from qharv.inspect.axes_pos import raxes from qharv.reel.config_h5 import save_dict from solith.li_nofk.forlib.det import calc_detsk from chiesa_correction import mirror_xyz, cubic_pos # creat slab for twist gname = 'twist%s' % str(ikpt).zfill(3) slab = h5file.create_group('/', gname, '') # read wf file fp = wf_h5.read(fwf) gvecs = wf_h5.get(fp, 'gvectors') cmat = wf_h5.get_cmat(fp, ikpt, ispin) wf_h5.normalize_cmat(cmat) axes = wf_h5.get(fp, 'axes') fp.close() raxes = raxes(axes) # decide which qvectors to calculate S(q) qvecs = mirror_xyz(cubic_pos(nsh0)) kvecs = np.dot(qvecs, raxes) kmags = np.linalg.norm(kvecs, axis=-1) qsel = (1e-8 < kmags) & (kmags < kc) # calculate S(k) sk0 = calc_detsk(qvecs[qsel], gvecs, cmat) # save arr_dict = { 'raxes': raxes, 'gvecs': qvecs[qsel], 'sk0': sk0 } save_dict(arr_dict, h5file, slab)
def get_det_nk(fp, efermi, ecore=-np.inf, kmax=np.inf, ispin=0): """Calculate momentum distribution from Kohn-Sham determinant same as get_momentum_distribution, but faster Args: fp (h5py.File): pwscf.pwscf.h5 file pointer efermi (float): Fermi energy ecore (float, optional): core energy, default -np.inf kmax (float, optional): maximum k magnitude to record, default np.inf ispin (int, optiona): default 0 Return: (np.array, np.array): (kvecs, nkm), kvectors and n(k) mean (no error) """ from solith.li_nofk.forlib.det import nofk # need Kohn-Sham eigenvalues to decide which states to use bands = wf_h5.get_bands(fp, ispin=ispin) nt, nstate = bands.shape # need kgrid info: basis (raxes), unshifted (kvecs0), twists (tvecs) axes = wf_h5.get(fp, 'axes') raxes = axes_pos.raxes(axes) gvecs = wf_h5.get(fp, 'gvectors') utvecs = wf_h5.get_twists(fp) tvecs = np.dot(utvecs, raxes) kvecs0 = np.dot(gvecs, raxes) # calculate n(k) at each twist kvecsl = [] nkml = [] for it in range(nt): kvecs = kvecs0 + tvecs[it] # current twist # histogram orb^2 cmat = wf_h5.get_cmat(fp, it, ispin, nstate) nocc, npw = cmat.shape weights = nofk(kvecs, cmat, bands[it], kmax, ecore, efermi) # save within a cutoff kmags = np.linalg.norm(kvecs, axis=-1) sel = kmags < kmax kvecsl.append(kvecs[sel]) nkml.append(weights[sel]) kvecs = np.concatenate(kvecsl, axis=0) nkm = np.concatenate(nkml) return kvecs, nkm
def get_rhok(fwf, kbrags, norb=None, itwist=0, ispin=0): from qharv.seed import wf_h5 from qharv.inspect import axes_pos from rsgub.grids.forlib.find_gvecs import calc_rhok fp = wf_h5.read(fwf) axes = wf_h5.get(fp, 'axes') gvecs = wf_h5.get(fp, 'gvectors') cmat = wf_h5.get_cmat(fp, itwist, ispin, norb=norb) fp.close() # calculate ukbrags raxes = axes_pos.raxes(axes) kcand = np.dot(kbrags, np.linalg.inv(raxes)) ukbrags = np.round(kcand).astype(int) # check ukbrags kbrags1 = np.dot(ukbrags, raxes) assert np.allclose(kbrags, kbrags1) # calculate rhok val = 2*calc_rhok(ukbrags, gvecs, cmat) return val
def get_bands(nscf_out, tgrid0): """Get bands and kgrid info from nscf output data contains: kvecs, bands, tgrid, raxes, gvecs kvecs (nk, ndim) are reciprocal points possible in the irreducible wedge kvecs are in 2\pi/alat units bands (nk, nstate) are the Kohn-Sham eigenvalues bands are in eV units tgrid (ndim) is grid size in each dimension !!!! currently assumed to be the same as x raxes (ndim, ndim) is the reciprocal lattice gvecs (nk, ndim) are reciprocal lattice points (kvecs) converted to integers Args: nscf_out (str): output file tgrid0 (int): grid along x Return: dict: data """ from qharv.inspect import axes_pos import qe_reader as qer # get bands data = qer.parse_nscf_bands(nscf_out) kvecs = data['kvecs'] # get raxes, gvecs tgrid = np.array([tgrid0] * 3) axes = qer.read_out_cell(nscf_out) raxes = axes_pos.raxes(axes) gcand = np.dot(kvecs, np.linalg.inv(raxes / tgrid)) gvecs = np.around(gcand).astype(int) data['tgrid'] = tgrid data['raxes'] = raxes data['gvecs'] = gvecs data.pop('nkpt') return data
def get_tgrid_raxes(nscf_in, ndim=3): from qharv.inspect import axes_pos tgrid, tshift = get_tgrid_tshift(nscf_in) axes = get_axes(nscf_in, ndim=ndim) raxes = axes_pos.raxes(axes) return tgrid, raxes