def test_Uisotropy(self):
     """check isotropy value for ADP-s at specified sites.
     """
     sg225 = GetSpaceGroup(225)
     corepos = [[0, 0, 0], [0.1, 0.13, 0.17]]
     eau = ExpandAsymmetricUnit(sg225, corepos)
     self.assertEqual([True, False], eau.Uisotropy)
     sc = SymmetryConstraints(sg225, eau.expandedpos)
     self.assertEqual(4 * [True] + 192 * [False], sc.Uisotropy)
     return
Example #2
0
 def test_UFormula_g186c_eqxyz(self):
     '''Check rotated U formulas at the symmetry positions of c-site in 186.
     '''
     sg186 = GetSpaceGroup(186)
     crules = [
             {'U11': 'A', 'U22': 'A', 'U33': 'C',
                 'U12': 'D', 'U13': 'E', 'U23': '-E'},
             {'U11': 'A', 'U22': '2*A-2*D', 'U33': 'C',
                 'U12': 'A-D', 'U13': 'E', 'U23': '2*E'},
             {'U11': '2*A-2*D', 'U22': 'A', 'U33': 'C',
                 'U12': 'A-D', 'U13': '-2*E', 'U23': '-E'},
             {'U11': 'A', 'U22': 'A', 'U33': 'C',
                 'U12': 'D', 'U13': '-E', 'U23': 'E'},
             {'U11': 'A', 'U22': '2*A-2*D', 'U33': 'C',
                 'U12': 'A-D', 'U13': '-E', 'U23': '-2*E'},
             {'U11': '2*A-2*D', 'U22': 'A', 'U33': 'C',
                 'U12': 'A-D', 'U13': '2*E', 'U23': 'E'},
             ]
     self.assertEqual(6, len(self.g186c.eqxyz))
     gc = self.g186c
     for idx in range(6):
         self.assertEqual(crules[idx], gc.UFormula(gc.eqxyz[idx], 'ABCDEF'))
     uiso = numpy.array([[2, 1, 0], [1, 2, 0], [0, 0, 2]])
     eau = ExpandAsymmetricUnit(sg186, [gc.xyz], [uiso])
     for u in eau.expandedUijs:
         du = numpy.linalg.norm((uiso - u).flatten())
         self.assertAlmostEqual(0.0, du, 8)
     symcon = SymmetryConstraints(sg186, sum(eau.expandedpos, []),
             sum(eau.expandedUijs, []))
     upd = dict(symcon.Upars)
     self.assertEqual(2.0, upd['U110'])
     self.assertEqual(2.0, upd['U330'])
     self.assertEqual(1.0, upd['U120'])
     self.assertEqual(0.0, upd['U130'])
     uisod = {'U11' : 2.0, 'U22' : 2.0, 'U33' : 2.0,
              'U12' : 1.0, 'U13' : 0.0, 'U23' : 0.0}
     for ufms in symcon.UFormulas():
         for n, fm in ufms.items():
             self.assertEqual(uisod[n], eval(fm, upd))
     return
    def _constrainXYZs(self, positions):
        """Constrain the positions.

        positions   --  The coordinates of the scatterers.

        """

        from diffpy.Structure.SymmetryUtilities import SymmetryConstraints

        sg = self.sg
        sgoffset = self.sgoffset

        # We do this without ADPs here so we can skip much complication. See
        # the _constrainADPs method for details.
        g = SymmetryConstraints(sg, positions, sgoffset=sgoffset)

        scatterers = self.scatterers
        self._xyzpars = BaseSpaceGroupParameters("xyzpars")

        # Make proxies to the free xyz parameters
        xyznames = [name[:1]+"_"+name[1:] for name, val in g.pospars]
        for pname in xyznames:
            name, idx = pname.rsplit('_', 1)
            idx = int(idx)
            par = scatterers[idx].get(name)
            newpar = self.__addPar(pname, par)
            self._xyzpars.addParameter(newpar)

        # Constrain non-free xyz parameters
        fpos = g.positionFormulas(xyznames)
        for idx, tmp in enumerate(zip(scatterers, fpos)):
            scatterer, fp = tmp

            # Extract the constraint equation from the formula
            for parname, formula in fp.items():
                _makeconstraint(parname, formula, scatterer, idx,
                        self._parameters)

        return
Example #4
0
    def _constrainXYZs(self, positions):
        """Constrain the positions.

        positions   --  The coordinates of the scatterers.

        """

        from diffpy.Structure.SymmetryUtilities import SymmetryConstraints

        sg = self.sg
        sgoffset = self.sgoffset

        # We do this without ADPs here so we can skip much complication. See
        # the _constrainADPs method for details.
        g = SymmetryConstraints(sg, positions, sgoffset=sgoffset)

        scatterers = self.scatterers
        self._xyzpars = BaseSpaceGroupParameters("xyzpars")

        # Make proxies to the free xyz parameters
        xyznames = [name[:1] + "_" + name[1:] for name, val in g.pospars]
        for pname in xyznames:
            name, idx = pname.rsplit('_', 1)
            idx = int(idx)
            par = scatterers[idx].get(name)
            newpar = self.__addPar(pname, par)
            self._xyzpars.addParameter(newpar)

        # Constrain non-free xyz parameters
        fpos = g.positionFormulas(xyznames)
        for idx, tmp in enumerate(zip(scatterers, fpos)):
            scatterer, fp = tmp

            # Extract the constraint equation from the formula
            for parname, formula in fp.items():
                _makeconstraint(parname, formula, scatterer, idx,
                                self._parameters)

        return
 def test___init__(self):
     """check SymmetryConstraints.__init__()
     """
     sg225 = GetSpaceGroup(225)
     # initialize from nested lists and arrays from ExpandAsymmetricUnit
     eau = ExpandAsymmetricUnit(sg225, [[0, 0, 0]])
     sc0 = SymmetryConstraints(sg225, eau.expandedpos)
     self.assertEqual(1, len(sc0.coremap))
     # initialize from list of arrays of coordinates
     poslistarrays = [xyz for xyz in sc0.positions]
     sc1 = SymmetryConstraints(sg225, poslistarrays)
     self.assertEqual(1, len(sc1.coremap))
     # initialize from list of lists of coordinates
     poslistlist = [list(xyz) for xyz in poslistarrays]
     sc2 = SymmetryConstraints(sg225, poslistlist)
     self.assertEqual(1, len(sc2.coremap))
     # initialize from nx3 array
     posarray = numpy.array(poslistlist)
     sc3 = SymmetryConstraints(sg225, posarray)
     self.assertEqual(1, len(sc3.coremap))
     # finally initialize from a single coordinate
     sc4 = SymmetryConstraints(sg225, [0, 0, 0])
     self.assertEqual(1, len(sc4.coremap))
     return
 def test_corepos(self):
     """test_corepos - find positions in the asymmetric unit.
     """
     sg225 = GetSpaceGroup(225)
     corepos = [[0, 0, 0], [0.1, 0.13, 0.17]]
     eau = ExpandAsymmetricUnit(sg225, corepos)
     sc = SymmetryConstraints(sg225, eau.expandedpos)
     self.assertEqual(2, len(sc.corepos))
     self.assertTrue(numpy.all(corepos[0] == sc.corepos[0]))
     self.assertTrue(numpy.all(corepos[1] == sc.corepos[1]))
     self.assertEqual(2, len(sc.coremap))
     mapped_count = sum([len(idcs) for idcs in sc.coremap.values()])
     self.assertEqual(len(sc.positions), mapped_count)
     self.assertTrue(sc.coremap[0] == range(4))
     self.assertTrue(sc.coremap[4] == range(4, 4 + 192))
     return
 def test_UparValues(self):
     """check SymmetryConstraints.UparValues()
     """
     places = 12
     sg1 = GetSpaceGroup(1)
     sg225 = GetSpaceGroup(225)
     pos = [[0, 0, 0]]
     Uijs = [[[0.1, 0.4, 0.5], [0.4, 0.2, 0.6], [0.5, 0.6, 0.3]]]
     sc1 = SymmetryConstraints(sg1, pos, Uijs)
     duv = 0.1 * numpy.arange(1, 7) - sc1.UparValues()
     self.assertAlmostEqual(0, max(numpy.fabs(duv)), places)
     sc225 = SymmetryConstraints(sg225, pos, Uijs)
     self.assertEqual(1, len(sc225.UparValues()))
     self.assertAlmostEqual(0.2, sc225.UparValues()[0], places)
     return
 def test_UparSymbols(self):
     """check SymmetryConstraints.UparSymbols()
     """
     sg1 = GetSpaceGroup(1)
     sg225 = GetSpaceGroup(225)
     pos = [[0, 0, 0]]
     Uijs = numpy.zeros((1, 3, 3))
     sc1 = SymmetryConstraints(sg1, pos, Uijs)
     self.assertEqual(6, len(sc1.UparSymbols()))
     sc225 = SymmetryConstraints(sg225, pos, Uijs)
     self.assertEqual(['U110'], sc225.UparSymbols())
     return
Example #9
0
    def applySymmetryConstraints(self, spacegroup, indices, posflag, Uijflag,
            sgoffset=[0,0,0]):
        """Generate symmetry constraints for positions and thermal factors.
        Both positions and thermal factors may get corrected to reflect
        space group symmetry.  Old positional and thermal constraints get
        erased.  New parameter indices start at fist decade after the last
        used parameter.

        spacegroup  -- instance of Structure.SpaceGroup
        indices     -- list of integer indices of atoms to be expanded
        posflag     -- required bool flag for constraining positions
        Uijflag     -- required bool flag for Uij constrainment
        sgoffset    -- optional offset of space group origin [0,0,0]
        """
        if not posflag and not Uijflag:     return
        # need to do something
        from diffpy.Structure.SymmetryUtilities import SymmetryConstraints
        # get unique sorted indices
        tobeconstrained = dict.fromkeys(indices)
        uindices = tobeconstrained.keys()
        uindices.sort()
        # remove old constraints
        pospat = re.compile(r'^([xyz])\((\d+)\)')
        Uijpat = re.compile(r'^(u11|u22|u33|u12|u13|u23)\((\d+)\)')
        for var in self.constraints.keys():
            mpos = posflag and pospat.match(var)
            mUij = Uijflag and Uijpat.match(var)
            if mpos and (int(mpos.group(2)) - 1) in tobeconstrained:
                del self.constraints[var]
            elif mUij and (int(mUij.group(2)) - 1) in tobeconstrained:
                del self.constraints[var]
        # find the largest used parameter index; pidxused must have an element
        pidxused = [i for i in self.owner.updateParameters()] + [0]
        # new parameters will start at the next decade
        parzeroidx = 10*(max(pidxused)/10) + 10
        # dictionary of parameter indices and their values
        newparvalues = {}
        selatoms = [self.initial[i] for i in uindices]
        selpos = [a.xyz for a in selatoms]
        selUijs = [a.U for a in selatoms]
        symcon = SymmetryConstraints(spacegroup, selpos, selUijs,
                sgoffset=sgoffset, eps=self.symposeps)
        # deal with positions
        if posflag:
            # fix positions:
            for a, xyz in zip(selatoms, symcon.positions):  a.xyz = xyz
            possymbols, parvalues = _makeParNames(symcon.pospars, parzeroidx)
            newparvalues.update(parvalues)
            eqns = symcon.positionFormulasPruned(possymbols)
            for aidx, eq in zip(uindices, eqns):
                siteidx = aidx + 1
                for barevar, formula in eq.items():
                    var = barevar + "(%i)" % siteidx
                    self.constraints[var] = Constraint(formula)
        # deal with temperature factors
        if Uijflag:
            # fix thermals
            for a, Uij in zip(selatoms, symcon.Uijs):  a.U = Uij
            Usymbols, parvalues = _makeParNames(symcon.Upars, parzeroidx)
            newparvalues.update(parvalues)
            eqns = symcon.UFormulasPruned(Usymbols)
            for aidx, eq in zip(uindices, eqns):
                siteidx = aidx + 1
                for barevar, formula in eq.items():
                    # keys in formula dictionary are uppercase
                    var = barevar.lower() + "(%i)" % siteidx
                    self.constraints[var] = Constraint(formula)
        # update parameter values in parent Fitting
        self.owner.updateParameters()
        for pidx, pvalue in newparvalues.iteritems():
            parobj = self.owner.parameters[pidx]
            parobj.setInitial(pvalue)
        # and finally remember this space group
        self.initial.pdffit["spcgr"] = spacegroup.short_name
        self.initial.pdffit["sgoffset"] = list(sgoffset)
        return
Example #10
0
    def _constrainADPs(self, positions):
        """Constrain the ADPs.

        positions   --  The coordinates of the scatterers.

        """

        from diffpy.Structure.SymmetryUtilities import stdUsymbols
        from diffpy.Structure.SymmetryUtilities import SymmetryConstraints

        if not self.constrainadps: return

        sg = self.sg
        sgoffset = self.sgoffset
        scatterers = self.scatterers
        isosymbol = self.isosymbol
        adpsymbols = self.adpsymbols
        adpmap = dict(zip(stdUsymbols, adpsymbols))
        self._adppars = BaseSpaceGroupParameters("adppars")

        # Prepare ADPs. Note that not all scatterers have constrainable ADPs.
        # For example, MoleculeParSet from objcryststructure does not. We
        # discard those.
        nonadps = []
        Uijs = []
        for sidx, scatterer in enumerate(scatterers):

            pars = [scatterer.get(symb) for symb in adpsymbols]

            if None in pars:
                nonadps.append(sidx)
                continue

            Uij = numpy.zeros((3, 3), dtype=float)
            for idx, par in enumerate(pars):
                i, j = _idxtoij[idx]
                Uij[i, j] = Uij[j, i] = par.getValue()

            Uijs.append(Uij)

        # Discard any positions for the nonadps
        positions = list(positions)
        nonadps.reverse()
        [positions.pop(idx) for idx in nonadps]

        # Now we can create symmetry constraints without having to worry about
        # the nonadps
        g = SymmetryConstraints(sg, positions, Uijs, sgoffset=sgoffset)

        adpnames = [adpmap[name[:3]] + "_" + name[3:] for name, val in g.Upars]

        # Make proxies to the free adp parameters. We start by filtering out
        # the isotropic ones so we can use the isotropic parameter.
        isoidx = []
        isonames = []
        for pname in adpnames:
            name, idx = pname.rsplit('_', 1)
            idx = int(idx)
            # Check for isotropic ADPs
            scatterer = scatterers[idx]
            if isosymbol and g.Uisotropy[idx] and idx not in isoidx:
                isoidx.append(idx)
                par = scatterer.get(isosymbol)
                if par is not None:
                    parname = "%s_%i" % (isosymbol, idx)
                    newpar = self.__addPar(parname, par)
                    self._adppars.addParameter(newpar)
                    isonames.append(newpar.name)
            else:
                par = scatterer.get(name)
                if par is not None:
                    newpar = self.__addPar(pname, par)
                    self._adppars.addParameter(newpar)

        # Constrain dependent isotropics
        for idx, isoname in zip(isoidx[:], isonames):
            for j in g.coremap[idx]:
                if j == idx: continue
                isoidx.append(j)
                scatterer = scatterers[j]
                scatterer.constrain(isosymbol, isoname, ns=self._parameters)

        fadp = g.UFormulas(adpnames)

        # Constrain dependent anisotropics. We use the fact that an
        # anisotropic cannot be dependent on an isotropic.
        for idx, tmp in enumerate(zip(scatterers, fadp)):
            if idx in isoidx: continue
            scatterer, fa = tmp
            # Extract the constraint equation from the formula
            for stdparname, formula in fa.items():
                pname = adpmap[stdparname]
                _makeconstraint(pname, formula, scatterer, idx,
                                self._parameters)
Example #11
0
    def applySymmetryConstraints(self,
                                 spacegroup,
                                 indices,
                                 posflag,
                                 Uijflag,
                                 sgoffset=[0, 0, 0]):
        """Generate symmetry constraints for positions and thermal factors.
        Both positions and thermal factors may get corrected to reflect
        space group symmetry.  Old positional and thermal constraints get
        erased.  New parameter indices start at fist decade after the last
        used parameter.

        spacegroup  -- instance of Structure.SpaceGroup
        indices     -- list of integer indices of atoms to be expanded
        posflag     -- required bool flag for constraining positions
        Uijflag     -- required bool flag for Uij constrainment
        sgoffset    -- optional offset of space group origin [0,0,0]
        """
        if not posflag and not Uijflag: return
        # need to do something
        from diffpy.Structure.SymmetryUtilities import SymmetryConstraints
        # get unique sorted indices
        tobeconstrained = dict.fromkeys(indices)
        uindices = tobeconstrained.keys()
        uindices.sort()
        # remove old constraints
        pospat = re.compile(r'^([xyz])\((\d+)\)')
        Uijpat = re.compile(r'^(u11|u22|u33|u12|u13|u23)\((\d+)\)')
        for var in self.constraints.keys():
            mpos = posflag and pospat.match(var)
            mUij = Uijflag and Uijpat.match(var)
            if mpos and (int(mpos.group(2)) - 1) in tobeconstrained:
                del self.constraints[var]
            elif mUij and (int(mUij.group(2)) - 1) in tobeconstrained:
                del self.constraints[var]
        # find the largest used parameter index; pidxused must have an element
        pidxused = [i for i in self.owner.updateParameters()] + [0]
        # new parameters will start at the next decade
        parzeroidx = 10 * (max(pidxused) / 10) + 10
        # dictionary of parameter indices and their values
        newparvalues = {}
        selatoms = [self.initial[i] for i in uindices]
        selpos = [a.xyz for a in selatoms]
        selUijs = [a.U for a in selatoms]
        symcon = SymmetryConstraints(spacegroup,
                                     selpos,
                                     selUijs,
                                     sgoffset=sgoffset,
                                     eps=self.symposeps)
        # deal with positions
        if posflag:
            # fix positions:
            for a, xyz in zip(selatoms, symcon.positions):
                a.xyz = xyz
            possymbols, parvalues = _makeParNames(symcon.pospars, parzeroidx)
            newparvalues.update(parvalues)
            eqns = symcon.positionFormulasPruned(possymbols)
            for aidx, eq in zip(uindices, eqns):
                siteidx = aidx + 1
                for barevar, formula in eq.items():
                    var = barevar + "(%i)" % siteidx
                    self.constraints[var] = Constraint(formula)
        # deal with temperature factors
        if Uijflag:
            # fix thermals
            for a, Uij in zip(selatoms, symcon.Uijs):
                a.U = Uij
            Usymbols, parvalues = _makeParNames(symcon.Upars, parzeroidx)
            newparvalues.update(parvalues)
            eqns = symcon.UFormulasPruned(Usymbols)
            for aidx, eq in zip(uindices, eqns):
                siteidx = aidx + 1
                for barevar, formula in eq.items():
                    # keys in formula dictionary are uppercase
                    var = barevar.lower() + "(%i)" % siteidx
                    self.constraints[var] = Constraint(formula)
        # update parameter values in parent Fitting
        self.owner.updateParameters()
        for pidx, pvalue in newparvalues.iteritems():
            parobj = self.owner.parameters[pidx]
            parobj.setInitial(pvalue)
        # and finally remember this space group
        self.initial.pdffit["spcgr"] = spacegroup.short_name
        self.initial.pdffit["sgoffset"] = list(sgoffset)
        return