Ejemplo n.º 1
0
def supercell(S, mno):
    """Perform supercell expansion for a structure.

    New lattice parameters are multiplied and fractional coordinates
    divided by corresponding multiplier.  New atoms are grouped with
    their source in the original cell.

    S   -- an instance of Structure from diffpy.Structure.
    mno -- sequence of 3 integers for cell multipliers along
           the a, b and c axes.

    Return a new expanded structure instance.
    Raise TypeError when S is not Structure instance.
    Raise ValueError for invalid mno argument.
    """
    # check arguments
    if len(mno) != 3:
        emsg = "Argument mno must contain 3 numbers."
        raise ValueError, emsg
    elif min(mno) < 1:
        emsg = "Multipliers must be greater or equal 1"
        raise ValueError, emsg
    if not isinstance(S, Structure):
        emsg = "The first argument must be a Structure instance."
        raise TypeError, emsg

    # convert mno to a tuple of integers so it can be used as range limit.
    mno = (int(mno[0]), int(mno[1]), int(mno[2]))

    # create return instance
    newS = Structure(S)
    if mno == (1, 1, 1):
        return newS

    # back to business
    ijklist = [(i,j,k)
                for i in range(mno[0])
                    for j in range(mno[1])
                        for k in range(mno[2])]
    # numpy.floor returns float array
    mnofloats = numpy.array(mno, dtype=float)

    # build a list of new atoms
    newAtoms = []
    for a in S:
        for ijk in ijklist:
            adup = Atom(a)
            adup.xyz = (a.xyz + ijk)/mnofloats
            newAtoms.append(adup)
    # newS can own references in newAtoms, no need to make copies
    newS.__setslice__(0, len(newS), newAtoms, copy=False)

    # take care of lattice parameters
    newS.lattice.setLatPar(
            a=mno[0]*S.lattice.a,
            b=mno[1]*S.lattice.b,
            c=mno[2]*S.lattice.c )
    return newS
Ejemplo n.º 2
0
def supercell(S, mno):
    """Perform supercell expansion for a structure.

    New lattice parameters are multiplied and fractional coordinates
    divided by corresponding multiplier.  New atoms are grouped with
    their source in the original cell.

    S   -- an instance of Structure from diffpy.Structure.
    mno -- sequence of 3 integers for cell multipliers along
           the a, b and c axes.

    Return a new expanded structure instance.
    Raise TypeError when S is not Structure instance.
    Raise ValueError for invalid mno argument.
    """
    # check arguments
    if len(mno) != 3:
        emsg = "Argument mno must contain 3 numbers."
        raise ValueError, emsg
    elif min(mno) < 1:
        emsg = "Multipliers must be greater or equal 1"
        raise ValueError, emsg
    if not isinstance(S, Structure):
        emsg = "The first argument must be a Structure instance."
        raise TypeError, emsg

    # convert mno to a tuple of integers so it can be used as range limit.
    mno = (int(mno[0]), int(mno[1]), int(mno[2]))

    # create return instance
    newS = Structure(S)
    if mno == (1, 1, 1):
        return newS

    # back to business
    ijklist = [(i, j, k) for i in range(mno[0]) for j in range(mno[1])
               for k in range(mno[2])]
    # numpy.floor returns float array
    mnofloats = numpy.array(mno, dtype=float)

    # build a list of new atoms
    newAtoms = []
    for a in S:
        for ijk in ijklist:
            adup = Atom(a)
            adup.xyz = (a.xyz + ijk) / mnofloats
            newAtoms.append(adup)
    # newS can own references in newAtoms, no need to make copies
    newS.__setslice__(0, len(newS), newAtoms, copy=False)

    # take care of lattice parameters
    newS.lattice.setLatPar(a=mno[0] * S.lattice.a,
                           b=mno[1] * S.lattice.b,
                           c=mno[2] * S.lattice.c)
    return newS
Ejemplo n.º 3
0
    def expandAsymmetricUnit(self, spacegroup, indices, sgoffset=[0, 0, 0]):
        """Perform symmetry expansion for atoms at given indices.
        Temperature factors may be corrected to reflect the symmetry.
        All constraints for expanded atoms are erased with the exception
        of the occupancy("occ".  Constraints of unaffected atoms are adjusted
        for new positions self.initial.

        spacegroup  -- instance of Structure.SpaceGroup
        indices     -- list of integer indices of atoms to be expanded
        sgoffset    -- optional offset of space group origin [0,0,0]
        """
        from diffpy.Structure.SymmetryUtilities import ExpandAsymmetricUnit
        acd = self._popAtomConstraints()
        # get unique, reverse sorted indices
        ruindices = dict.fromkeys(indices).keys()
        ruindices.sort()
        ruindices.reverse()
        coreatoms = [self.initial[i] for i in ruindices]
        corepos = [a.xyz for a in coreatoms]
        coreUijs = [a.U for a in coreatoms]
        eau = ExpandAsymmetricUnit(spacegroup,
                                   corepos,
                                   coreUijs,
                                   sgoffset=sgoffset,
                                   eps=self.symposeps)
        # build a nested list of new atoms:
        newatoms = []
        for i in range(len(coreatoms)):
            ca = coreatoms[i]
            caocc_con = None
            if ca in acd and "occ" in acd[ca]:
                caocc_con = acd[ca]["occ"]
            eca = []  # expanded core atom
            for j in range(eau.multiplicity[i]):
                a = Atom(ca)
                a.xyz = eau.expandedpos[i][j]
                a.U = eau.expandedUijs[i][j]
                eca.append(a)
                if caocc_con is None: continue
                # make a copy of occupancy constraint
                acd[a] = {"occ": copy.copy(caocc_con)}
            newatoms.append(eca)
        # insert new atoms where they belong
        for i, atomlist in zip(ruindices, newatoms):
            self.initial[i:i + 1] = atomlist
        # remember this spacegroup as the last one used
        self.initial.pdffit["spcgr"] = spacegroup.short_name
        self.initial.pdffit["sgoffset"] = list(sgoffset)
        # tidy constraints
        self._restoreAtomConstraints(acd)
        return
Ejemplo n.º 4
0
    def expandAsymmetricUnit(self, spacegroup, indices, sgoffset=[0, 0, 0]):
        """Perform symmetry expansion for atoms at given indices.
        Temperature factors may be corrected to reflect the symmetry.
        All constraints for expanded atoms are erased with the exception
        of the occupancy("occ".  Constraints of unaffected atoms are adjusted
        for new positions self.initial.

        spacegroup  -- instance of Structure.SpaceGroup
        indices     -- list of integer indices of atoms to be expanded
        sgoffset    -- optional offset of space group origin [0,0,0]
        """
        from diffpy.Structure.SymmetryUtilities import ExpandAsymmetricUnit

        acd = self._popAtomConstraints()
        # get unique, reverse sorted indices
        ruindices = dict.fromkeys(indices).keys()
        ruindices.sort()
        ruindices.reverse()
        coreatoms = [self.initial[i] for i in ruindices]
        corepos = [a.xyz for a in coreatoms]
        coreUijs = [a.U for a in coreatoms]
        eau = ExpandAsymmetricUnit(spacegroup, corepos, coreUijs, sgoffset=sgoffset, eps=self.symposeps)
        # build a nested list of new atoms:
        newatoms = []
        for i in range(len(coreatoms)):
            ca = coreatoms[i]
            caocc_con = None
            if ca in acd and "occ" in acd[ca]:
                caocc_con = acd[ca]["occ"]
            eca = []  # expanded core atom
            for j in range(eau.multiplicity[i]):
                a = Atom(ca)
                a.xyz = eau.expandedpos[i][j]
                a.U = eau.expandedUijs[i][j]
                eca.append(a)
                if caocc_con is None:
                    continue
                # make a copy of occupancy constraint
                acd[a] = {"occ": copy.copy(caocc_con)}
            newatoms.append(eca)
        # insert new atoms where they belong
        for i, atomlist in zip(ruindices, newatoms):
            self.initial[i : i + 1] = atomlist
        # remember this spacegroup as the last one used
        self.initial.pdffit["spcgr"] = spacegroup.short_name
        self.initial.pdffit["sgoffset"] = list(sgoffset)
        # tidy constraints
        self._restoreAtomConstraints(acd)
        return
Ejemplo n.º 5
0
    def expandSuperCell(self, mno):
        """Perform supercell expansion for this structure and adjust
        constraints for positions and lattice parameters.  New lattice
        parameters are multiplied and fractional coordinates divided by
        corresponding multiplier.  New atoms are grouped with their source
        in the original cell.

        mno -- tuple or list of three positive integer cell multipliers along
        the a, b, c axis
        """
        # check argument
        if tuple(mno) == (1, 1, 1):     return
        if min(mno) < 1:
            raise ControlValueError("mno must contain 3 positive integers")
        # back to business
        acd = self._popAtomConstraints()
        mnofloats = numpy.array(mno[:3], dtype=float)
        ijklist = [(i,j,k) for i in range(mno[0])
                    for j in range(mno[1]) for k in range(mno[2])]
        # build a list of new atoms
        newatoms = []
        for a in self.initial:
            for ijk in ijklist:
                adup = Atom(a)
                adup.xyz = (a.xyz + ijk)/mnofloats
                newatoms.append(adup)
                # does atom a have any constraint?
                if a not in acd:    continue
                # add empty constraint dictionary for duplicate atom
                acd[adup] = {}
                for barevar, con in acd[a].iteritems():
                    formula = con.formula
                    if barevar in ("x", "y", "z"):
                        symidx = "xyz".index(barevar)
                        if ijk[symidx] != 0:
                            formula += " + %i" % ijk[symidx]
                        if mno[symidx] > 1:
                            formula = "(%s)/%.1f" % (formula, mno[symidx])
                            formula = re.sub(r'\((@\d+)\)', r'\1', formula)
                    # keep other formulas intact and add constraint
                    # for barevar of the duplicate atom
                    acd[adup][barevar] = Constraint(formula)
        # replace original atoms with newatoms
        self.initial[:] = newatoms
        for ai, an in zip(self.initial, newatoms):
            if an in acd:
                acd[ai] = acd[an]
        # and rebuild their constraints
        self._restoreAtomConstraints(acd)
        # take care of lattice parameters
        self.initial.lattice.setLatPar(
                a=mno[0]*self.initial.lattice.a,
                b=mno[1]*self.initial.lattice.b,
                c=mno[2]*self.initial.lattice.c )
        # adjust lattice constraints if present
        latvars = ( "lat(1)", "lat(2)", "lat(3)" )
        for var, multiplier in zip(latvars, mno):
            if var in self.constraints and multiplier > 1:
                con = self.constraints[var]
                formula = "%.0f*(%s)" % (multiplier, con.formula)
                formula = re.sub(r'\((@\d+)\)', r'\1', formula)
                con.formula = formula
        return
Ejemplo n.º 6
0
    def expandSuperCell(self, mno):
        """Perform supercell expansion for this structure and adjust
        constraints for positions and lattice parameters.  New lattice
        parameters are multiplied and fractional coordinates divided by
        corresponding multiplier.  New atoms are grouped with their source
        in the original cell.

        mno -- tuple or list of three positive integer cell multipliers along
        the a, b, c axis
        """
        # check argument
        if tuple(mno) == (1, 1, 1): return
        if min(mno) < 1:
            raise ControlValueError("mno must contain 3 positive integers")
        # back to business
        acd = self._popAtomConstraints()
        mnofloats = numpy.array(mno[:3], dtype=float)
        ijklist = [(i, j, k) for i in range(mno[0]) for j in range(mno[1])
                   for k in range(mno[2])]
        # build a list of new atoms
        newatoms = []
        for a in self.initial:
            for ijk in ijklist:
                adup = Atom(a)
                adup.xyz = (a.xyz + ijk) / mnofloats
                newatoms.append(adup)
                # does atom a have any constraint?
                if a not in acd: continue
                # add empty constraint dictionary for duplicate atom
                acd[adup] = {}
                for barevar, con in acd[a].iteritems():
                    formula = con.formula
                    if barevar in ("x", "y", "z"):
                        symidx = "xyz".index(barevar)
                        if ijk[symidx] != 0:
                            formula += " + %i" % ijk[symidx]
                        if mno[symidx] > 1:
                            formula = "(%s)/%.1f" % (formula, mno[symidx])
                            formula = re.sub(r'\((@\d+)\)', r'\1', formula)
                    # keep other formulas intact and add constraint
                    # for barevar of the duplicate atom
                    acd[adup][barevar] = Constraint(formula)
        # replace original atoms with newatoms
        self.initial[:] = newatoms
        for ai, an in zip(self.initial, newatoms):
            if an in acd:
                acd[ai] = acd[an]
        # and rebuild their constraints
        self._restoreAtomConstraints(acd)
        # take care of lattice parameters
        self.initial.lattice.setLatPar(a=mno[0] * self.initial.lattice.a,
                                       b=mno[1] * self.initial.lattice.b,
                                       c=mno[2] * self.initial.lattice.c)
        # adjust lattice constraints if present
        latvars = ("lat(1)", "lat(2)", "lat(3)")
        for var, multiplier in zip(latvars, mno):
            if var in self.constraints and multiplier > 1:
                con = self.constraints[var]
                formula = "%.0f*(%s)" % (multiplier, con.formula)
                formula = re.sub(r'\((@\d+)\)', r'\1', formula)
                con.formula = formula
        return