Exemple #1
0
    def get_band_info(self,b_i,k_i=None):
        """Get band information for given band index `b_i`. If `k_i` is given, returns info at that point
        Fermi energy is subtracted from all energies. When a plot commnad is called, the Fermi energy is updated if provided.
        """
        def at_minmax(_bands,_pros,func,k_i=None):
            _bands_ = _bands.flatten() - self._efermi # subtract fermi energy
            if isinstance(k_i,int):
                extrema = _bands_[k_i]
                k = float(self._kpath[k_i])
                kp = self._data.kpoints[k_i]
                pros = _pros[:,k_i,:].sum(axis=0).flatten()
            else:
                extrema = func(_bands_)
                where, = np.where(_bands_ == extrema) # unpack singelton
                k, kp = [float(self._kpath[w]) for w in where], self._data.kpoints[where]
                pros = _pros[:,where[0],:].sum(axis=0).flatten()
            return vp.Dict2Data({'e':float(extrema),'k':k,'kp':kp.tolist(),
                    'pros':{l.replace('-',''):float(p) for p,l in zip(pros,self._data.pro_bands.labels)}})

        if self._data.bands.ISPIN == 1:
            b = self._data.bands.evals[:,b_i]
            p = self._data.pro_bands.pros[:,:,b_i,:]

            if isinstance(k_i,int): # single kpoint
                return at_minmax(b,p,np.min,k_i=k_i)

            return vp.Dict2Data({'min':at_minmax(b,p,np.min,k_i=k_i),'max':at_minmax(b,p,np.max,k_i=k_i)})

        else: # spin-polarized
            bu = self._data.bands.evals.SpinUp[:,b_i]
            pu = self._data.pro_bands.pros.SpinUp[:,:,b_i,:]

            _minu = at_minmax(bu,pu,np.min,k_i=k_i)
            _maxu = at_minmax(bu,pu,np.max,k_i=k_i)

            bd = self._data.bands.evals.SpinDown[:,b_i]
            pd = self._data.pro_bands.pros.SpinDown[:,:,b_i,:]

            _mind = at_minmax(bd,pd,np.min,k_i=k_i)
            _maxd = at_minmax(bd,pd,np.max,k_i=k_i)

            if isinstance(k_i,int): # single kpoint
                return vp.Dict2Data({'SpinUp':_minu,'SpinDown':_mind})

            return vp.Dict2Data({'SpinUp':{'min':_minu,'max':_maxu},'SpinDown':{'min':_mind,'max':_maxd}})
Exemple #2
0
def export_outcar(path=None):
    """
    - Read potential at ionic sites from OUTCAR.
    """
    if path is None:
        path = './OUTCAR'
    if not os.path.isfile(path):
        return print("{} does not exist!".format(path))
    # Raeding it
    with open(r'{}'.format(path), 'r') as f:
        lines = f.readlines()
    # Processing
    for i, l in enumerate(lines):
        if 'NIONS' in l:
            N = int(l.split()[-1])
            nlines = np.ceil(N / 5).astype(int)
        if 'electrostatic' in l:
            start_index = i + 3
            stop_index = start_index + nlines
        if 'fractional' in l:
            first = i + 1
        if 'vectors are now' in l:
            b_first = i + 5
        if 'NION' in l:
            ion_line = l
        if 'NKPTS' in l:
            kpt_line = l

    NKPTS, NKDIMS, NBANDS = [int(v) for v in re.findall(r"\d+", kpt_line)]
    NEDOS, NIONS = [int(v) for v in re.findall(r"\d+", ion_line)]
    n_kbi = (NKPTS, NBANDS, NIONS)
    # Data manipulation
    # Potential
    data = lines[start_index:stop_index]
    initial = np.loadtxt(StringIO(''.join(data[:-1]))).reshape((-1))
    last = np.loadtxt(StringIO(data[-1]))
    pot_arr = np.hstack([initial, last]).reshape((-1, 2))
    pot_arr[:, 0] = pot_arr[:, 0] - 1  # Ion index fixing
    # Nearest neighbors
    pos = lines[first:first + N]
    pos_arr = np.loadtxt(StringIO('\n'.join(pos)))
    pos_arr[
        pos_arr > 0.98] = pos_arr[pos_arr > 0.98] - 1  # Fixing outer layers
    # positions and potential
    pos_pot = np.hstack([pos_arr, pot_arr[:, 1:]])
    basis = np.loadtxt(StringIO(''.join(lines[b_first:b_first + 3])))
    final_dict = {
        'ion_pot': pot_arr,
        'positions': pos_arr,
        'site_pot': pos_pot,
        'basis': basis[:, :3],
        'rec_basis': basis[:, 3:],
        'n_kbi': n_kbi
    }
    return vp.Dict2Data(final_dict)
Exemple #3
0
 def at_minmax(_bands,_pros,func,k_i=None):
     _bands_ = _bands.flatten() - self._efermi # subtract fermi energy
     if isinstance(k_i,int):
         extrema = _bands_[k_i]
         k = float(self._kpath[k_i])
         kp = self._data.kpoints[k_i]
         pros = _pros[:,k_i,:].sum(axis=0).flatten()
     else:
         extrema = func(_bands_)
         where, = np.where(_bands_ == extrema) # unpack singelton
         k, kp = [float(self._kpath[w]) for w in where], self._data.kpoints[where]
         pros = _pros[:,where[0],:].sum(axis=0).flatten()
     return vp.Dict2Data({'e':float(extrema),'k':k,'kp':kp.tolist(),
             'pros':{l.replace('-',''):float(p) for p,l in zip(pros,self._data.pro_bands.labels)}})
Exemple #4
0
def download_structure(formula, mp_id=None, max_sites=None,min_sites=None, api_key=None,save_key = False):
    """Download structure data from Materials project website.
    - **Parameters**
        - formula: chemical formula of the material.
        - mp_id: Materials project id of material.
        - max_sites: maximum number of sites in structure to download.
        - min_sites: minimum number of sites in structure to download.
    > max_sites and min_sites are used to filter the number of sites in structure, or use mp_id to download a specific structure.
    - **One Time API Key**
        - api_key: API key from Materials project websit, if you use save_key=True, never required again.
        - save_key: Save API key to file. You can save any time of key or device changed.
    - **Return**
        - structure: Structure data containing attributes `poscars` and `cifs` as list.
                    Each item in list has attributes `content` and `write` to write to file.
    """
    mp = sio.InvokeMaterialsProject(api_key= api_key)
    mp.request(formula=formula,mp_id=mp_id,max_sites=max_sites,min_sites=min_sites) # make a request
    if save_key and isinstance(api_key,str):
        mp.save_api_key(api_key)
    if mp.success:
        return vp.Dict2Data({'poscars':mp.poscars,'cifs':mp.cifs})
    else:
        return print('Connection was not sccessful. Try again later.')
Exemple #5
0
def export_potential(locpot=None, e=True, m=False):
    """
    - Returns Data from LOCPOT and similar structure files like CHG. Loads only single set out of 2/4 magnetization data to avoid performance/memory cost while can load electrostatic and one set of magnetization together.
    - **Parameters**
        - locpot: path/to/LOCPOT or similar stuructured file like CHG. LOCPOT is auto picked in CWD.
        - e     : Electric potential/charge density. Default is True.
        - m     : Magnetization density m. Default is False. If True, picks `m` for spin polarized case, and `m_x` for non-colinear case. Additionally it can take 'x','y' and 'z' in case of non-colinear calculations.
    - **Exceptions**
        - Would raise index error if magnetization density set is not present in LOCPOT/CHG in case `m` is not False.
    """
    if locpot is None:
        if os.path.isfile('LOCPOT'):
            locpot = 'LOCPOT'
        else:
            return print('./LOCPOT not found.')
    else:
        if not os.path.isfile(locpot):
            return print("File {!r} does not exist!".format(locpot))
    if m not in [True, False, 'x', 'y', 'z']:
        return print(
            "m expects one of [True,False,'x','y','z'], got {}".format(e))
    # data fixing after reading islice from file.
    def fix_data(islice_gen, shape):
        new_gen = (float(l) for line in islice_gen for l in line.split())
        COUNT = np.prod(shape).astype(int)
        data = np.fromiter(new_gen, dtype=float,
                           count=COUNT)  # Count is must for performance
        # data written on LOCPOT is in shape of (NGz,NGy,NGx)
        N_reshape = [shape[2], shape[1], shape[0]]
        data = data.reshape(N_reshape).transpose([2, 1, 0])
        return data

    # Reading File
    with open(locpot, 'r') as f:
        lines = []
        f.seek(0)
        for i in range(8):
            lines.append(f.readline())
        N = sum([int(v) for v in lines[6].split()])
        f.seek(0)
        poscar = []
        for i in range(N + 8):
            poscar.append(f.readline())
        f.readline()  # Empty one
        Nxyz = [int(v) for v in f.readline().split()]  # Grid line read
        nlines = np.ceil(np.prod(Nxyz) / 5).astype(int)
        #islice is faster generator for reading potential
        pot_dict = {}
        if e == True:
            pot_dict.update({'e': fix_data(islice(f, nlines), Nxyz)})
            ignore_set = 0  # Pointer already ahead.
        else:
            ignore_set = nlines  # Needs to move pointer to magnetization
        #reading Magnetization if True
        ignore_n = np.ceil(N / 5).astype(int) + 1  #Some kind of useless data
        if m == True:
            print(
                "m = True would pick m_x for non-colinear case, and m for ISPIN=2.\nUse m='x' for non-colinear or keep in mind that m will refer to m_x."
            )
            start = ignore_n + ignore_set
            pot_dict.update(
                {'m': fix_data(islice(f, start, start + nlines), Nxyz)})
        elif m == 'x':
            start = ignore_n + ignore_set
            pot_dict.update(
                {'m_x': fix_data(islice(f, start, start + nlines), Nxyz)})
        elif m == 'y':
            start = 2 * ignore_n + nlines + ignore_set
            pot_dict.update(
                {'m_y': fix_data(islice(f, start, start + nlines), Nxyz)})
        elif m == 'z':
            start = 3 * ignore_n + 2 * nlines + ignore_set
            pot_dict.update(
                {'m_z': fix_data(islice(f, start, start + nlines), Nxyz)})

    # Read Info
    basis = np.loadtxt(StringIO(''.join(poscar[2:5]))) * float(
        poscar[1].strip())
    system = poscar[0].strip()
    ElemName = poscar[5].split()
    ElemIndex = [int(v) for v in poscar[6].split()]
    ElemIndex.insert(0, 0)
    ElemIndex = list(np.cumsum(ElemIndex))
    positions = np.loadtxt(StringIO(''.join(poscar[8:N + 9])))

    final_dict = dict(SYSTEM=system,
                      ElemName=ElemName,
                      ElemIndex=ElemIndex,
                      basis=basis,
                      positions=positions)
    final_dict = {**final_dict, **pot_dict}
    return vp.Dict2Data(final_dict)
Exemple #6
0
    def get_en_diff(self,b1_i,b2_i,k1_i=None,k2_i=None):
        """Get energy difference between two bands at given two kpoints indices. Index 2 is considered at higher energy.
        - b1_i, b2_i : band indices of the two bands, minimum energy difference is calculated.
        - k1_i, k2_i : k-point indices of the two bands.

        > If k1_i and k2_i are not provided, `min(b2_i) - max(b1_i)` is calculated which is equivalent to band gap.

        Returns: Data with follwoing attributes which can be used to annotate the difference on plot.
            de     : energy difference
            coords : np.array([[k1,e1],[k2,e2]]) #E_Fermi is subtracted either from system or when user provides in a plot command.
            eqv_coords: list(coords) at equivalent k-points if exit. Do not appear if k1_i and k2_i are provided.

        For spin-polarized case, 4 blocks of above data are returned which are accessible by
        `u1u2, u1d2, d1u2, d1d2` and they collects energy difference between 2 given bands at 2 different spin.

        """
        if k1_i and k2_i == None:
            raise ValueError('When you provide `k1_i`, `k2_i` cannot be None. They both can be None at same time.')
        if k1_i == None and k2_i:
            raise ValueError('When you provide `k2_i`, `k1_i` cannot be None. They both can be None at same time.')

        def format_coords(b1_max,b2_min):
            "maximum of b1 and min of b2 is taken for energy difference of two bands when kpoint not given."
            combs = []
            for k1 in b1_max.k:
                for k2 in b2_min.k:
                    combs.append(np.array([[k1,b1_max.e],[k2,b2_min.e]]))

            _out = {'coords':combs[0]}
            if combs[1:]:
                _out['eqv_coords'] = combs[1:]
            return _out

        if self._data.bands.ISPIN == 1:
            if isinstance(k1_i,int):
                b1 = self.get_band_info(b1_i,k_i=k1_i)
                b2 = self.get_band_info(b2_i,k_i=k2_i)
                return vp.Dict2Data({'de':b2.e - b1.e, 'coords': np.array([[b1.k,b1.e],[b2.k, b2.e]])})
            else:
                b1 = self.get_band_info(b1_i,k_i=None).max
                b2 = self.get_band_info(b2_i,k_i=None).min

                return vp.Dict2Data({'de':b2.e - b1.e, **format_coords(b1,b2)})
        else:
            if isinstance(k1_i,int):
                b1u = self.get_band_info(b1_i,k_i=k1_i).SpinUp
                b1d = self.get_band_info(b1_i,k_i=k1_i).SpinDown
                b2u = self.get_band_info(b2_i,k_i=k2_i).SpinUp
                b2d = self.get_band_info(b2_i,k_i=k2_i).SpinDown

                return vp.Dict2Data({
                    'u1u2':{'de':b2u.e - b1u.e, 'coords':np.array([[b1u.k, b1u.e], [b2u.k, b2u.e]])},
                    'd1d2':{'de':b2d.e - b1d.e, 'coords':np.array([[b1d.k, b1d.e], [b2d.k, b2d.e]])},
                    'd1u2':{'de':b2u.e - b1d.e, 'coords':np.array([[b1d.k, b1d.e], [b2u.k, b2u.e]])},
                    'u1d2':{'de':b2d.e - b1u.e, 'coords':np.array([[b1u.k, b1u.e], [b2d.k, b2d.e]])}
                })
            else:
                b1u = self.get_band_info(b1_i,k_i=None).SpinUp.max # max in lower band
                b1d = self.get_band_info(b1_i,k_i=None).SpinDown.max
                b2u = self.get_band_info(b2_i,k_i=None).SpinUp.min # min in upper band
                b2d = self.get_band_info(b2_i,k_i=None).SpinDown.min

                return vp.Dict2Data({
                    'u1u2':{'de':b2u.e - b1u.e, **format_coords(b1u,b2u)},
                    'd1d2':{'de':b2d.e - b1d.e, **format_coords(b1d,b2d)},
                    'd1u2':{'de':b2u.e - b1d.e, **format_coords(b1d,b2u)},
                    'u1d2':{'de':b2d.e - b1u.e, **format_coords(b1u,b2d)}
                })