Example #1
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
Example #2
0
 def getLatticeParameters(self):
     """Extract lattice parameters after pwscf geometry optimization
        Returns a list of 6 parameters: A, B, C, cos(BC), cos(AC), cos(AB)"""
     from qelattice import QELattice
     # obtain lattice from PWSCF input file:
     lat = QELattice(fname=self.pwscfInput)
     pwscfOut = read_file(self.pwscfOutput)
     key_a_0 = find_key_from_string(pwscfOut, 'lattice parameter (a_0)')
     a_0 = float(string.split(pwscfOut[key_a_0])[4])
     if lat.type == 'traditional':
         a_0 = a_0 * 0.529177249  # convert back to angstrom
     keyEnd = max(
         find_all_keys_from_marker_string(pwscfOut, '!', 'total energy'))
     keyCellPar = find_key_from_string_afterkey(pwscfOut, keyEnd, \
                                               'CELL_PARAMETERS (alat)') + 1
     latticeVectors = [
         [
             float(valstr) * a_0
             for valstr in string.split(pwscfOut[keyCellPar])
         ],
         [
             float(valstr) * a_0
             for valstr in string.split(pwscfOut[keyCellPar + 1])
         ],
         [
             float(valstr) * a_0
             for valstr in string.split(pwscfOut[keyCellPar + 2])
         ]
     ]
     lat.setLatticeFromQEVectors(lat.ibrav, latticeVectors)
     return [lat.a, lat.b, lat.c, lat.cBC, lat.cAC, lat.cAB]
Example #3
0
    def setStructureFromDiffpyStructure(self, structure, massList = [], psList = [], ibrav = 0):
        """
        structure - diffpy.Structure object
        ibrav - Lattice index
        psList - list of strings with pseudopotential names
        diffpyStructure object will be modified with reduced atomic positions
        """      
        diffpyLattice = structure.lattice
        
        self.structure = structure
               
        
        #set lattice and  convert to bohr units
        qeLattice = QELattice(ibrav = 0, a = 1.889725989, base = diffpyLattice.base)
        
        
        self.lattice = qeLattice
        self.lattice.type = 'generic cubic'

        atomNames = []
        for a in structure:
            if self._element(a) not in atomNames:
                atomNames.append(self._element(a))
        
        #print atomNames
        #print len(massList)
        for i, elem in enumerate(atomNames):
            if len(massList) - 1 < i:
                mass = 0
            else:
                mass = massList[i]
            if len(psList) - 1 < i:
                ps = ''
            else:
                ps = psList[i]               
            self.atomicSpecies[elem] =  AtomicSpecies(elem, mass, ps)
        
        for atom in structure:
            self.optConstraints.append([])        
        
        # for i, atom in enumerate(structure):
            # elem = self._element(atom)
            # if len(massList) - 1 < i:
                # mass = 0
            # else:
                # mass = massList[i]
            # if len(psList) - 1 < i:
                # ps = ''
            # else:
                # ps = psList[i]
            # self.atomicSpecies[elem] =  AtomicSpecies(elem, mass, ps)
            # self.optConstraints.append([])

#        for atom, mass, ps in zip(structure, massList, psList):
#            elem = self._element(atom)
#            self.atomicSpecies[elem] =  AtomicSpecies(elem, mass, ps)
#            self.optConstraints.append([])

        self.nat = len(structure)
        self.ntyp = len(self.atomicSpecies)        
Example #4
0
    def reduce(self, ibrav=None):
        """
        Reduces a structure instance with nonprimitive lattice ( i.e. solves
        for equivalent atomic positions) according to specified  lattice type (ibrav). 
        Each ibrav number corresponds to a specific primitive lattice 
        (see QE documentation).         
        """

        ib = self.lattice.ibrav
        if ibrav != None:
            ib = ibrav

        a = self.lattice.diffpy().a
        b = self.lattice.diffpy().b
        c = self.lattice.diffpy().c
        cAB = cosd(self.lattice.diffpy().gamma)
        cBC = cosd(self.lattice.diffpy().alpha)
        cAC = cosd(self.lattice.diffpy().beta)
        if ib > 0:
            qeLattice = QELattice(ibrav = ib, a = a, b = b, c = c,  cBC =  cBC, \
                              cAC = cAC, cAB = cAB)
        else:
            qeLattice = QELattice(ibrav=ib, base=self.lattice.base)

        qeLattice._qeInput = self._qeInput

        reducedStructure = QEStructure(self)

        reducedStructure.placeInLattice(qeLattice)

        # collect atoms that are at equivalent position to some previous atom
        duplicates = set([
            a1 for i0, a0 in enumerate(reducedStructure)
            for a1 in reducedStructure[i0 + 1:] if a0.element == a1.element
            and equalPositions(a0.xyz, a1.xyz, eps=1e-4)
        ])

        # Filter out duplicate atoms.  Use slice assignment so that
        # reducedStructure is not replaced with a list.
        self.lattice = qeLattice
        self[:] = [a for a in reducedStructure if not a in duplicates]

        self._qeInput.structure = self
        return
Example #5
0
 def __init__(self, qeConf):
     """the structure is initialized from PWSCF config file
        'lattice' and 'structure' are automatically updated"""
     self.filename = qeConf.filename
     self.atomicSpecies = OrderedDict()
     self.formatString = '%# .8f %# .8f %# .8f'
     # optConstraints three 1/0 for each coordinate of each atom
     self.optConstraints = []
     self.qeConf = qeConf
     self.lattice = QELattice()
     self.structure = Structure(lattice=self.lattice.diffpy())
     self.nat = None
     self.ntyp = None
Example #6
0
    def _setStructureFromDiffpyStructure(self,
                                         structure,
                                         massList=[],
                                         psList=[],
                                         ibrav=0):
        """
        structure - diffpy.Structure object
        ibrav - Lattice index
        psList - list of strings with potential names
        diffpyStructure object will be modified with reduced atomic positions
        """
        diffpyLattice = structure.lattice

        qeLattice = QELattice(ibrav=0, base=diffpyLattice.base)
        qeLattice.a = 1.889725989 * qeLattice.a
        qeLattice._qeInput = self._qeInput

        self.lattice = qeLattice
        self.lattice.type = 'generic cubic'

        atomNames = []
        for a in structure:
            if self._element(a) not in atomNames:
                atomNames.append(self._element(a))

        atomicSpecies = {}
        for i, elem in enumerate(atomNames):
            if len(massList) - 1 < i:
                mass = 0
            else:
                mass = massList[i]
            if len(psList) - 1 < i:
                ps = ''
            else:
                ps = psList[i]
            atomicSpecies[elem] = (mass, ps)

        self[:] = []
        for atom in structure:
            elem = self._element(atom)
            self.addNewAtom(atype = elem, xyz = atom.xyz, \
                            mass = atomicSpecies[elem][0], \
                            potential = atomicSpecies[elem][1],\
                            lattice = self.lattice, optConstraint = [])
Example #7
0
 def setStructureFromPWSCF(self):
     """ Loads structure from PWSCF config file"""
     self.lattice = QELattice(fname=self.filename)
     self.structure = Structure(lattice=self.lattice.diffpy())
     self.nat = int(self.qeConf.namelist('system').param('nat'))
     self.ntyp = int(self.qeConf.namelist('system').param('ntyp'))
     atomicLines = self.qeConf.card('atomic_positions').getLines()
     self.atomicPositionsType = self.qeConf.card(
         'atomic_positions').argument()
     if self.atomicPositionsType == 'bohr' or self.atomicPositionsType == 'angstrom':
         raise NotImplementedError
     if self.atomicPositionsType == None:
         self.atomicPositionsType = 'alat'
     for line in atomicLines:
         if '!' not in line:
             words = line.split()
             coords = [float(w) for w in words[1:4]]
             constraint = []
             if len(words) > 4:
                 constraint = [int(c) for c in words[4:7]]
             self.optConstraints.append(numpy.array(constraint, dtype=int))
             atomSymbol = words[0]
             if self.atomicPositionsType == 'alat':
                 coords = self.lattice.diffpy().fractional(
                     numpy.array(coords[0:3]) * self.lattice.a0)
             if self.atomicPositionsType == 'crystal':
                 coords = numpy.array(coords[0:3])
             self.structure.addNewAtom(atomSymbol,
                                       xyz=numpy.array(coords[0:3]))
             # parse mass ATOMIC_SPECIES section:
             atomicSpeciesLines = self.qeConf.card(
                 'atomic_species').getLines()
             for line in atomicSpeciesLines:
                 if '!' not in line:
                     atomicSpeciesWords = line.split()
                     element = atomicSpeciesWords[0]
                     mass = float(atomicSpeciesWords[1])
                     ps = atomicSpeciesWords[2]
                     self.atomicSpecies[element] = AtomicSpecies(
                         element, mass, ps)
Example #8
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
Example #9
0
    def _setReducedStructureFromDiffpyStructure(self,
                                                structure,
                                                ibrav,
                                                massList=[],
                                                psList=[]):
        """
        structure - diffpy.Structure object
        ibrav - Lattice index
        psList - list of strings with potential names
        diffpyStructure object will be modified with reduced atomic positions
        """
        import copy

        diffpyLattice = copy.deepcopy(structure.lattice)

        a = diffpyLattice.a
        b = diffpyLattice.b
        c = diffpyLattice.c
        cAB = cosd(diffpyLattice.gamma)
        cBC = cosd(diffpyLattice.alpha)
        cAC = cosd(diffpyLattice.beta)

        qeLattice = QELattice(ibrav = ibrav, a = a, b = b, c = c,  cBC =  cBC, \
                              cAC = cAC, cAB = cAB)

        qeLattice._qeInput = self._qeInput
        self.lattice = qeLattice
        # make a deep copy:
        reducedStructure = Structure(atoms=structure)

        reducedStructure.placeInLattice(Lattice(base=qeLattice.diffpy().base))

        # collect atoms that are at equivalent position to some previous atom
        duplicates = set([
            a1 for i0, a0 in enumerate(reducedStructure)
            for a1 in reducedStructure[i0 + 1:]
            if self._element(a0) == self._element(a1)
            and equalPositions(a0.xyz, a1.xyz, eps=1e-4)
        ])

        # Filter out duplicate atoms.  Use slice assignment so that
        # reducedStructure is not replaced with a list.
        reducedStructure[:] = [
            a for a in reducedStructure if not a in duplicates
        ]

        atomNames = []
        for a in reducedStructure:
            if self._element(a) not in atomNames:
                atomNames.append(self._element(a))

        atomicSpecies = {}
        for i, elem in enumerate(atomNames):
            if len(massList) - 1 < i:
                mass = 0
            else:
                mass = massList[i]
            if len(psList) - 1 < i:
                ps = ''
            else:
                ps = psList[i]
            atomicSpecies[elem] = (mass, ps)

        self[:] = []

        # convert to bohr units
        self.lattice.setLattice(ibrav, self.lattice.a*1.889725989, \
                                 self.lattice.b*1.889725989,
                                 self.lattice.c*1.889725989)

        for atom in reducedStructure:
            elem = self._element(atom)
            self.addNewAtom(atype = elem, xyz = atom.xyz, \
                            mass = atomicSpecies[elem][0], \
                            potential = atomicSpecies[elem][1],\
                            lattice = self.lattice, optConstraint = [])
Example #10
0
    def setReducedStructureFromDiffpyStructure(self, structure, ibrav, massList = [], psList = []):
        """
        structure - diffpy.Structure object
        ibrav - Lattice index
        psList - list of strings with pseudopotential names
        diffpyStructure object will be modified with reduced atomic positions
        """

        #self.atomicSpecies = OrderedDict()
        #self.optConstraints = []
        #self.atomicPositionsType = 'crystal'

        diffpyLattice = structure.lattice

        a = diffpyLattice.a
        b = diffpyLattice.b
        c = diffpyLattice.c
        cAB = cosd(diffpyLattice.gamma)
        cBC = cosd(diffpyLattice.alpha)
        cAC = cosd(diffpyLattice.beta)

        qeLattice = QELattice(ibrav = ibrav, a = a, b = b, c = c,  cBC =  cBC, \
                              cAC = cAC, cAB = cAB)

        self.lattice = qeLattice
        # make a deep copy (does not wok now)
        #reducedStructure = Structure(diffpyStructure)
        reducedStructure = structure

        reducedStructure.placeInLattice(Lattice(base=qeLattice.diffpy().base))

        # collect atoms that are at equivalent position to some previous atom
        duplicates = set([a1
            for i0, a0 in enumerate(reducedStructure) for a1 in reducedStructure[i0+1:]
                if   self._element(a0) == self._element(a1) and equalPositions(a0.xyz, a1.xyz, eps=1e-4)])

        
        # Filter out duplicate atoms.  Use slice assignment so that
        # reducedStructure is not replaced with a list.
        reducedStructure[:] = [a for a in reducedStructure if not a in duplicates]

        self.structure = reducedStructure

        atomNames = []
        for a in reducedStructure:
            if self._element(a) not in atomNames:
                atomNames.append(self._element(a))
        
        #print atomNames
        #print len(massList)
        for i, elem in enumerate(atomNames):
            if len(massList) - 1 < i:
                mass = 0
            else:
                mass = massList[i]
            if len(psList) - 1 < i:
                ps = ''
            else:
                ps = psList[i]      
            #print mass, ps
            # atomDict[a] = 
        # for i, atom in enumerate(reducedStructure):
            # elem = self._element(atom)
            # if len(massList) - 1 < i:
                # mass = 0
            # else:
                # mass = massList[i]
            # if len(psList) - 1 < i:
                # ps = ''
            # else:
                # ps = psList[i]            
            self.atomicSpecies[elem] =  AtomicSpecies(elem, mass, ps)
        
        for atom in reducedStructure:
            self.optConstraints.append([])

        # convert to bohr units
        self.lattice.setLattice(ibrav, self.lattice.a*1.889725989, \
                                 self.lattice.b*1.889725989,
                                 self.lattice.c*1.889725989)

        self.nat = len(reducedStructure)
        self.ntyp = len(self.atomicSpecies)
Example #11
0
 def _setReducedStructureFromMatterStructure(self,
                                             structure,
                                             ibrav,
                                             massList=[],
                                             psList=[]):
     """
     structure - matter.Structure object
     ibrav - Lattice index
     psList - list of strings with potential names
     matterStructure object will be modified with reduced atomic positions
     """
     import copy
     matterLattice = copy.deepcopy(structure.lattice)
     # there is a big problem with what Nikolay is doing because he is initializing QELattice with abcalbega which
     # leaves room for errors in how the basis vectors are chosen compared to the old lattice
     a = matterLattice.a
     b = matterLattice.b
     c = matterLattice.c
     cAB = cosd(matterLattice.gamma)
     cBC = cosd(matterLattice.alpha)
     cAC = cosd(matterLattice.beta)
     qeLattice = QELattice(ibrav = ibrav, a = a, b = b, c = c,  cBC =  cBC, \
                           cAC = cAC, cAB = cAB)
     #what he should do is initialize the vectors of QELattice with the vectors of matterLattice
     #
     qeLattice._qeInput = self._qeInput
     self.lattice = qeLattice
     # make a deep copy:
     reducedStructure = Structure(atoms=structure)
     reducedStructure.placeInLattice(Lattice(base=qeLattice.matter().base))
     # collect atoms that are at equivalent position to some previous atom
     duplicates = set([
         a1 for i0, a0 in enumerate(reducedStructure)
         for a1 in reducedStructure[i0 + 1:] if a0.symbol == a1.symbol
         and equalPositions(a0.xyz, a1.xyz, eps=1e-4)
     ])
     # Filter out duplicate atoms.  Use slice assignment so that
     # reducedStructure is not replaced with a list.
     reducedStructure[:] = [
         a for a in reducedStructure if not a in duplicates
     ]
     atomNames = []
     for a in reducedStructure:
         if a.symbol not in atomNames:
             atomNames.append(a.symbol)
     atomicSpecies = {}
     for i, elem in enumerate(atomNames):
         if len(massList) - 1 < i:
             mass = 0
         else:
             mass = massList[i]
         if len(psList) - 1 < i:
             ps = ''
         else:
             ps = psList[i]
         atomicSpecies[elem] = (mass, ps)
     self[:] = []
     # convert to bohr units
     self.lattice.setLattice(ibrav, self.lattice.a*1.889725989, \
                              self.lattice.b*1.889725989,
                              self.lattice.c*1.889725989)
     for atom in reducedStructure:
         self.addNewAtom(atype = atom.symbol, xyz = atom.xyz, \
                         mass = atomicSpecies[atom.symbol][0], \
                         potential = atomicSpecies[atom.symbol][1],\
                         lattice = self.lattice, optConstraint = [])
Example #12
0
    def setStructureFromPWOutput(self, pwscfOutputFile):
        """
        Loads structure from PWSCF output file. If there was geometry
        optimization (relax or vc-relax), the structure will be reinitialized
        from the last step of the optimization
        """
        file = open(pwscfOutputFile)
        pwscfOut = file.readlines()
        pseudoList = []
        atomList = []
        massList = []
        self.atomicSpecies = OrderedDict()
        self.atomicPositionsType = 'alat'
        # parse beginning:
        for i, line in enumerate(pwscfOut):
            if 'lattice parameter (a_0)' in line:
                a_0 = float(line.split()[4])
            if 'bravais-lattice index' in line:
                ibrav = int(line.split('=')[1])
            if 'number of atoms/cell' in line:
                self.nat = int(line.split('=')[1])
            if 'number of atomic types' in line:
                self.ntyp = int(line.split('=')[1])
            if 'PseudoPot.' in line:
                pseudoList.append(line.split('read from file')[1].strip())
            if 'atomic species   valence    mass     pseudopotential' in line:
                for j in range(self.ntyp):
                    atomList.append(pwscfOut[i + j + 1].split()[0])
                    massList.append(float(pwscfOut[i + j + 1].split()[2]))
            if 'crystal axes: (cart. coord. in units of a_0)' in line:
                latticeVectors = [
                    [float(f) * a_0 for f in pwscfOut[i + 1].split()[3:6]],
                    [float(f) * a_0 for f in pwscfOut[i + 2].split()[3:6]],
                    [float(f) * a_0 for f in pwscfOut[i + 3].split()[3:6]]
                ]
                self.lattice = QELattice(ibrav=ibrav, base=latticeVectors)
            if 'site n.     atom                  positions (a_0 units)' in line:
                self.structure = Structure(lattice=self.lattice.matter())
                for n in range(self.nat):
                    words = pwscfOut[i + n + 1].split()
                    atomSymbol = words[1]
                    coords = [float(w) for w in words[6:9]]
                    constraint = []
                    self.optConstraints.append(
                        numpy.array(constraint, dtype=int))
                    #print numpy.array(coords[0:3])*a_0
                    coords = self.lattice.matter().fractional(
                        numpy.array(coords[0:3]) * a_0)
                    self.structure.addNewAtom(atomSymbol,
                                              xyz=numpy.array(coords[0:3]))

        for a, m, p in zip(atomList, massList, pseudoList):
            self.atomicSpecies[a] = AtomicSpecies(a, m, p)

        #print 'Input structure from output file: ', self.toString()
        #Parse end:
        # Find all geometry optimization steps
        posList = [
            i for i, line in enumerate(pwscfOut) if '!    total energy' in line
        ]
        lastSection = pwscfOut[posList[-1]:]
        for i, line in enumerate(lastSection):
            if 'CELL_PARAMETERS (alat)' in line:
                latticeVectors = [
                    [float(f) * a_0 for f in lastSection[i + 1].split()],
                    [float(f) * a_0 for f in lastSection[i + 2].split()],
                    [float(f) * a_0 for f in lastSection[i + 3].split()]
                ]
                self.lattice = QELattice(ibrav=ibrav, base=latticeVectors)
                print self.lattice.matter().base
            if 'ATOMIC_POSITIONS (alat)' in line:
                self.structure = Structure(lattice=self.lattice.matter())
                for n in range(self.nat):
                    words = lastSection[i + n + 1].split()
                    atomSymbol = words[0]
                    coords = [float(w) for w in words[1:4]]
                    constraint = []
                    if len(words) > 4:
                        constraint = [int(c) for c in words[4:7]]
                    self.optConstraints.append(
                        numpy.array(constraint, dtype=int))
                    #print numpy.array(coords[0:3])*a_0
                    coords = self.lattice.matter().fractional(
                        numpy.array(coords[0:3]) * a_0)
                    self.structure.addNewAtom(atomSymbol,
                                              xyz=numpy.array(coords[0:3]))