示例#1
0
    def read(self, filename, format='pwinput'):
        """Load structure from a file, any original data become lost.
l
        filename -- file to be loaded
        format   -- structure formats
                    'pwinput' ( pw.x input, default), 'pwoutput' (pw.x output),
                    'bratoms', 'cif', 'discus', 'pdb', 'pdffit', 'rawxyz', 
                    'xcfg', 'xyz'

        Return instance of data Parser used to process file.  This
        can be inspected for information related to particular format.
        """
        from qecalc.qetask.qeparser.qestructureparser import parser_index
        if self._qeInput == None:
            from qecalc.qetask.qeparser.pwinput import PWInput
            self._qeInput = PWInput()
            self._qeInput.structure = self
            #self._qeInput.parse()

        if format in parser_index:
            module = __import__("qestructureparser.P_" + format, globals(), \
                                locals(), ['P_' + format], -1)
            parser = module.getParser(self._qeInput)
            new_structure = parser.parse(filename)
        else:
            diffpyStruct = Structure()
            parser = diffpyStruct.read(filename, format=format)
            new_structure = QEStructure(qeInput=self._qeInput)
            new_structure._setStructureFromDiffpyStructure(diffpyStruct, \
                                        massList = [], psList = [], ibrav = 0)

        new_structure.lattice._qeInput.update(forceUpdate=True)
        self.__Init(new_structure)
        return parser
示例#2
0
 def __init__(self, ibrav = 1,a = 1. ,b = 1.,c = 1.,
         cBC = 0.,cAC = 0. ,cAB = 0., base = None, lattice = None, qeInput = None ):
     self.formatString = '%# .8f %# .8f %# .8f'
     self._qeInput = qeInput
     #self._qeInput = None
     self._type = 'celldm'
     # Lattice container class, used for lattice operations
     self.__primitiveLattice = Lattice()
     # Lattice vectors in bohr or angstrom:
     self._base = None
     # initialize the lattice if there is enough information 
     if ibrav > 0 and base != None:
         self.setLatticeFromQEVectors(ibrav, base)
     else:
         self.setLattice(ibrav ,a ,b , c, cBC ,cAC ,cAB, base)
     # copy constructor:
     if isinstance(ibrav, QELattice) or lattice != None:
         if lattice.ibrav > 0:
             self.setLattice( ibrav = lattice.ibrav, a = lattice.a, \
                                      b = lattice.b, c = lattice.c,
                                      cBC = lattice.cBC, cAC = lattice.cAC,\
                                      cAB = lattice.cAB)
         else:
             self.setLattice( ibrav = lattice.ibrav, a = lattice.a, \
                                                       base = lattice.base )            
         # copy input:
         from pwinput import PWInput        
         self._qeInput = PWInput()
         self._qeInput.readString( lattice._qeInput.toString() )
示例#3
0
    def __init__(self, atoms=[], lattice=None, filename=None, qeInput=None):
        """
        atoms        -- list of QEAtom atom instances or a QEStructure object
        lattice      -- QELattice object
        filename     -- filename QE input file 
        qeInput      -- pointer to a PWInput parsing object. If not None, 
                        its PWInput.structure and PWInput.structure.lattice 
                        will be  reset to the current instance of the structure       
        """

        Structure.__init__(self)
        self.formatString = '%# .8f %# .8f %# .8f'
        self._atomicPositionsType = 'crystal'
        self._qeInput = qeInput
        self.lattice = QELattice()
        self.lattice._qeInput = self._qeInput

        if lattice != None:

            if self.lattice._qeInput != None:
                self._qeInput = self.lattice._qeInput
            else:
                self.lattice._qeInput = self._qeInput

            self.lattice = QELattice(lattice=lattice)

        # CP and PW inputs are compatible
        from pwinput import PWInput
        from cpinput import CPInput
        if isinstance(atoms, PWInput) or isinstance(atoms, CPInput):
            qeInput = atoms
        elif isinstance(atoms, QEStructure):
            stru = atoms
            self.__dict__.update(stru.__dict__)
            # deep copy of the lattice will deep copy PWInput as well
            self.lattice = QELattice(lattice=stru.lattice)
            self._qeInput = self.lattice._qeInput
            self[:] = stru
        else:
            if self.lattice == None:
                raise "Lattice must be provided"
            self[:] = atoms

        if filename != None:
            qeInput = PWInput(filename=filename)
            qeInput.parse()
            self.parseInput(qeInput)

        if qeInput != None:
            self.lattice._qeInput = qeInput
            self._qeInput = qeInput

        if self.lattice._qeInput != None:
            self.lattice._qeInput.structure = self
            self.lattice._qeInput.structure.lattice = self.lattice

        return
示例#4
0
 def save(self, filename=None):
     """Writes/updates structure into PW config file,
        if the file does not exist, new one will be created"""
     from os.path import exists
     from qecalc.qetask.qeparser.pwinput import PWInput
     if filename != None:
         if not exists(filename):
             f = open(filename, 'w')
         qeInput = PWInput()
         qeInput.readFile(filename)
     else:
         qeInput = self._qeInput
     self._qeInput.update(qeInput=qeInput, forceUpdate=True)
     qeInput.save()
示例#5
0
    def __init__(self, atype=None, xyz=None, mass = None,  \
                 potential = None, lattice=None, optConstraint = None, name=None):
        """Create atom of a specified type at given lattice coordinates.
        Atom(a) creates a copy of Atom instance a.

        atype         -- element symbol string or Atom instance
        xyz           -- fractional(crystal) coordinates
        name          -- atom label
        mass          -- atom mass
        potential     -- pseudopotential file name
        lattice       -- QE coordinate system for fractional coordinates
        optConstraint -- list of up to three constraints for each coordinate 
                         for QE geometry optimization (0 or 1)
        """
        # declare data members
        self.element = None
        self._xyz = numpy.zeros(3, dtype=float)
        self.name = ''
        self._mass = 0
        self._potential = ''
        self.lattice = QELattice()
        from pwinput import PWInput
        self.lattice._qeInput = PWInput()
        self._optConstraint = numpy.array([], dtype = int)
        # assign them as needed
        if isinstance(atype, QEAtom):
            atype_dup = atype.__copy__()
            self.__dict__.update(atype_dup.__dict__)
        else:
            self.element = atype
        # take care of remaining arguments
        if xyz is not None:             self._xyz[:] = xyz
        if name is not None:            self.name = name
        if mass is not None:            self._mass = mass
        if potential is not None:       self._potential = potential
        if lattice is not None:         self.lattice = lattice
        if optConstraint is not None:  self._optConstraint = \
                                        numpy.array(optConstraint, dtype = int)
        return
示例#6
0
def make_fd_supercell(pw: PWInput, q_cry, ucart, skip_minkowski=False):
    import copy
    from math import floor, ceil
    from itertools import product
    """
    Generate nondiagonal supercell with finite displacements
    qe_input: a Pwscf() instance of an input file
    q_cry: perturbation crystal momentum, (m1/n1, m2/n2, m3/n3).
    ucart: displacement of atoms in the unit cell in cartesian alat units
    """
    # find fractional representation of q
    tol = 1E-10
    mlist = []
    nlist = []
    for i in range(3):
        found = False
        for n in range(1, 101):
            m = round(abs(q_cry[i]) * n)
            if abs(abs(q_cry[i]) - m / n) < tol:
                mlist.append(m)
                nlist.append(n)
                found = True
                break
        if not found:
            print(f"Unable to find fractional representation of q = {q[i]}")
            return None

    s_new = find_nondiagonal(mlist, nlist)
    multiplier = s_new[0, 0] * s_new[1, 1] * s_new[2, 2]
    cell_new = np.einsum('ij,xj->xi', s_new, pw.cell)
    nat_new = pw.nat * multiplier

    # Minkowski reduction of lattice vector: linear combination to make them
    # as short as possible
    if skip_minkowski:
        cell_red = np.copy(cell_new)
    else:
        cell_red = minkowski_reduce(cell_new)
    cell_cell = np.einsum('xi,xj->ij', pw.cell, pw.cell)
    redcell_cell = np.einsum('xi,xj->ij', cell_red, pw.cell)
    s_red = redcell_cell @ np.linalg.inv(cell_cell)
    s_red = np.rint(s_red)

    atoms_name_new, atoms_cart_new = atom_supercell(pw, s_new)

    # move atoms to [0, 1)^3 unit cell of cell_red
    atoms_cry_new = np.linalg.inv(cell_red) @ atoms_cart_new
    for iat in range(nat_new):
        for idir in range(3):
            atoms_cart_new[:, iat] -= floor(
                atoms_cry_new[idir, iat]) * cell_red[:, idir]

    # apply displacements
    s_diag = np.diag(s_new)
    for nz, ny, nx in product(range(s_diag[2]), range(s_diag[1]),
                              range(s_diag[0])):
        icell = nx + ny * s_diag[0] + nz * s_diag[0] * s_diag[1]
        phase = np.exp(2j * np.pi *
                       sum([x * y for x, y in zip(q_cry, (nx, ny, nz))]))
        for iat in range(pw.nat):
            atoms_cart_new[:, icell * pw.nat + iat] += (ucart[:, iat] *
                                                        phase).real

    pw_super = PWInput(nat=nat_new,
                       cell=cell_red,
                       atoms_name=atoms_name_new,
                       atoms_cart=atoms_cart_new,
                       input_cards=copy.deepcopy(pw.input_cards),
                       input_namelists=copy.deepcopy(pw.input_namelists))

    if 'ATOMIC_POSITIONS' in pw_super.input_cards.keys():
        input_atmpos = ['ATOMIC_POSITIONS alat \n']
        for iat in range(pw_super.nat):
            line = (
                f" {atoms_name_new[iat]:4s} {atoms_cart_new[0, iat]:18.12f}"
                f" {atoms_cart_new[1, iat]:18.12f} {atoms_cart_new[2, iat]:18.12f}\n"
            )
            input_atmpos.append(line)
        pw_super.input_cards['ATOMIC_POSITIONS'] = input_atmpos

    if 'CELL_PARAMETERS' in pw_super.input_cards.keys():
        input_cell = ['CELL_PARAMETERS alat\n']
        for i in range(3):
            line = (f" {pw_super.cell[0,i]:18.12f} {pw_super.cell[1,i]:18.12f}"
                    f" {pw_super.cell[2,i]:18.12f}\n")
            input_cell.append(line)
        pw_super.input_cards['CELL_PARAMETERS'] = input_cell

    if 'K_POINTS' in pw_super.input_cards.keys():
        nks = np.array(
            [int(x) for x in pw.input_cards['K_POINTS'][1].split()[:3]])
        dks = np.linalg.norm(lat_to_reclat(pw.cell), axis=0) / nks

        nks_new = np.linalg.norm(lat_to_reclat(pw_super.cell),
                                 axis=0) / min(dks)
        nks_new = [ceil(x - 1E-4) for x in nks_new]
        # minus 1E-3 to avoid floating point truncation error (of the input file)
        # If original nk is 8, nks_new can become 8.00001 due to small digits in
        # the input file. If we ceil this, it becomes 9. We want it to be 8, so
        # we subtract a small value, 1E-4, from nks_new.

        input_kpt = ['K_POINTS automatic\n']
        input_kpt.append(
            f" {nks_new[0]:3d}{nks_new[1]:3d}{nks_new[2]:3d}  0 0 0")
        pw_super.input_cards['K_POINTS'] = input_kpt

    # update namelists
    try:
        pw_super.input_namelists['SYSTEM']['ibrav'] = "0"
        pw_super.input_namelists['SYSTEM']['nat'] = f"{pw_super.nat}"
    except KeyError as e:
        print("KeyError in pw_super.input_namelists, keyword {e.args[0]}")

    return pw_super