def test_findParameters(self):
     """check FitStructure.findParameters()
     """
     stru = self.stru
     stru.read(datafile('Ni.stru'), format='pdffit')
     for a in stru.initial:
         a.Uiso = 0.00126651
     stru.constraints['lat(4)'] = Constraint('@1')
     stru.constraints['y(2)'] = Constraint('@3 + 0.4')
     stru.constraints['u11(3)'] = Constraint('@7 * 3.0')
     pd = stru.findParameters()
     self.assertEqual([1, 3, 7], sorted(pd.keys()))
     self.assertEqual(90, pd[1].initialValue())
     self.assertEqual(0.5 - 0.4, pd[3].initialValue())
     self.assertEqual(0.00126651 / 3.0, pd[7].initialValue())
     return
 def test___init__(self):
     """check Constraint.__init__()
     """
     self.failUnless(1 in self.c.parguess)
     self.assertEqual(1, len(self.c.parguess))
     c1 = Constraint('2*@2 + 3.0', 13.0)
     self.assertEqual(1, len(c1.parguess))
     self.assertEqual(5.0, c1.parguess[2])
     return
Example #3
0
    def constrain(self, var, par, fcon=None):
        """Constrain a variable to a parameter.

        A variable can be constrained to a number or equation string.
        var     -- variable to constrain, such as x(1)
        par     -- parameter which to constrain the variable. This can be
                   an integer or an equation string containing a reference
                   to another parameter. Equation strings use standard c++
                   syntax. The value of a constrained parameter is accessed
                   as @p in an equation string, where p is the parameter.
                   e.g.
                   >>>  constrain(x(1), 1)
                   >>>  constrain(x(2), "0.5+@1")
        fcon    -- 'IDENT', 'FCOMP', or 'FSQR', old-style constraint formulas:
                       'IDENT'  @par
                       'FCOMP'  1.0-@par
                       'FSQR'   @par*@par
        """
        curfit = self._fits[-1]
        if isinstance(curfit, Calculation):
            raise ControlRuntimeError, \
                "Cannot define constrain for calculation."
        if callable(var):
            var = var()
        if fcon is not None:
            if fcon == "IDENT":
                formula = "@%i" % par
            elif fcon == 'FCOMP':
                formula = "1.0-@%i" % par
            elif fcon == 'FSQR':
                formula = "@%i*@%i" % (par, par)
            else:
                raise ControlRuntimeError, "invalid value of fcon %r" % fcon
        elif type(par) is types.IntType:
            formula = "@%i" % par
        else:
            formula = par
        if var in PdfFitSandbox._dataset_vars:
            curdataset = curfit.datasets[self._curdataset]
            curdataset.constraints[var] = Constraint(formula)
        else:
            curphase = curfit.strucs[self._curphase]
            curphase.constraints[var] = Constraint(formula)
        return
 def test_changeParameterIndex(self):
     """check FitStructure.changeParameterIndex()
     """
     stru = self.stru
     stru.constraints['pscale'] = Constraint('@7+3')
     stru.changeParameterIndex(7, 13)
     self.assertEqual('@13+3', stru.constraints['pscale'].formula)
     stru.changeParameterIndex(2, 19)
     self.assertEqual('@13+3', stru.constraints['pscale'].formula)
     return
 def test_applyParameters(self):
     """check FitStructure.applyParameters()
     """
     stru = self.stru
     stru.read(datafile('Ni.stru'), format='pdffit')
     for a in stru.initial:
         a.Uiso = 0.00126651
     stru.constraints['lat(4)'] = Constraint('@1')
     stru.constraints['u11(3)'] = Constraint('@7 * 3.0')
     pd = stru.findParameters()
     # adjust Parameter instances in pd
     pd[1].setInitial(99)
     pd[7].setInitial(0.5)
     stru.applyParameters(pd)
     self.assertEqual(99, stru.lattice.alpha)
     self.assertEqual(1.5, stru[2].U11)
     # pd values can be floats
     pd[1] = 89
     stru.applyParameters(pd)
     self.assertEqual(89, stru.lattice.alpha)
     return
    def applyTextCtrlChange(self, id, value):
        """Update a structure according to a change in a TextCtrl.

        id      --  textctrl id
        value   --  new value
        """
        self.mainFrame.needsSave()
        var = self._id2varname[id]
        formula = value.strip()
        if formula != "":
            self.constraints[var] = Constraint(formula)
            return self.constraints[var].formula
        else:
            self.constraints.pop(var, None)
            return ""
    def processFormula(self, value, parname):
        """Process a formula that was entered into a textCtrl."""
        formula = value.strip()
        oldconst = self.constraints.get(parname)
        oldformula = ""
        if oldconst:
            oldformula = oldconst.formula
        if formula == "":
            self.constraints.pop(parname, None)
        elif oldformula != formula:
            # Let the PDFGui error handler take care of this
            self.constraints[parname] = Constraint(formula)
            self.mainFrame.needsSave()

        return
 def test_insertAtoms(self):
     """check FitStructure.insertAtoms()
     """
     from diffpy.Structure import Atom
     stru = self.stru
     stru.read(datafile('Ni.stru'), format='pdffit')
     cns = Constraint('@1')
     stru.constraints['x(2)'] = cns
     stru.insertAtoms(0, [Atom('Na', (0, 0, 0))])
     self.assertEqual(5, len(stru))
     self.assertEqual(1, len(stru.constraints))
     self.failUnless(cns is stru.constraints['x(3)'])
     stru.insertAtoms(5, [Atom('Cl', (0, 0, 0))])
     self.failUnless(['x(3)'] == stru.constraints.keys())
     return
 def test_deleteAtoms(self):
     """check FitStructure.deleteAtoms()
     """
     stru = self.stru
     stru.read(datafile('Ni.stru'), format='pdffit')
     cns = Constraint('@1')
     stru.constraints['x(2)'] = cns
     stru.deleteAtoms([3])
     self.assertEqual(['x(2)'], stru.constraints.keys())
     self.failUnless(cns is stru.constraints.values()[0])
     stru.deleteAtoms([0])
     self.assertEqual(['x(1)'], stru.constraints.keys())
     self.failUnless(cns is stru.constraints.values()[0])
     stru.deleteAtoms([0])
     self.assertEqual({}, stru.constraints)
     return
Example #10
0
class TestConstraint(unittest.TestCase):
    """test methods of TestConstraint"""

    def setUp(self):
        self.c = Constraint('@1')
        return

    def test___init__(self):
        """check Constraint.__init__()
        """
        self.assertTrue(1 in self.c.parguess)
        self.assertEqual(1, len(self.c.parguess))
        c1 = Constraint('2*@2 + 3.0', 13.0)
        self.assertEqual(1, len(c1.parguess))
        self.assertEqual(5.0, c1.parguess[2])
        return

    def test_guess(self):
        """check Constraint.guess()
        """
        self.c.guess(9)
        self.assertEqual(1, len(self.c.parguess))
        self.assertEqual(9, self.c.parguess[1])
        return

    def test___setattr__(self):
        """check Constraint.__setattr__()
        """
        self.c.guess(9)
        self.c.formula = '9*@7 +18'
        self.assertEqual(1, len(self.c.parguess))
        self.assertEqual(-1.0, self.c.parguess[7])
        self.assertRaises(ControlSyntaxError, setattr,
                self.c, 'formula', '')
        self.assertRaises(ControlSyntaxError, setattr,
                self.c, 'formula', '@@1')
        self.assertRaises(ControlSyntaxError, setattr, self.c,
                'formula', '@1*/55')
        self.assertRaises(ControlSyntaxError, setattr, self.c,
                'formula', '@1**3')
        return

    def test_evalFormula(self):
        """check Constraint.evalFormula()
        """
        value = self.c.evalFormula({1 : 5.0})
        self.assertEqual(5.0, value)
        self.c.formula = 'sin(@3)'
        from math import pi, sqrt
        value = self.c.evalFormula({3 : pi/3.0})
        self.assertAlmostEqual(sqrt(0.75), value, 8)
        return
class TestConstraint(unittest.TestCase):
    """test methods of TestConstraint"""
    def setUp(self):
        self.c = Constraint('@1')
        return

    def test___init__(self):
        """check Constraint.__init__()
        """
        self.failUnless(1 in self.c.parguess)
        self.assertEqual(1, len(self.c.parguess))
        c1 = Constraint('2*@2 + 3.0', 13.0)
        self.assertEqual(1, len(c1.parguess))
        self.assertEqual(5.0, c1.parguess[2])
        return

    def test_guess(self):
        """check Constraint.guess()
        """
        self.c.guess(9)
        self.assertEqual(1, len(self.c.parguess))
        self.assertEqual(9, self.c.parguess[1])
        return

    def test___setattr__(self):
        """check Constraint.__setattr__()
        """
        self.c.guess(9)
        self.c.formula = '9*@7 +18'
        self.assertEqual(1, len(self.c.parguess))
        self.assertEqual(-1.0, self.c.parguess[7])
        self.assertRaises(ControlSyntaxError, setattr, self.c, 'formula', '')
        self.assertRaises(ControlSyntaxError, setattr, self.c, 'formula',
                          '@@1')
        self.assertRaises(ControlSyntaxError, setattr, self.c, 'formula',
                          '@1*/55')
        self.assertRaises(ControlSyntaxError, setattr, self.c, 'formula',
                          '@1**3')
        return

    def test_evalFormula(self):
        """check Constraint.evalFormula()
        """
        value = self.c.evalFormula({1: 5.0})
        self.assertEqual(5.0, value)
        self.c.formula = 'sin(@3)'
        from math import pi, sqrt
        value = self.c.evalFormula({3: pi / 3.0})
        self.assertAlmostEqual(sqrt(0.75), value, 8)
        return
    def applyCellChange(self, i, j, value):
        """Update an atom according to a change in a cell.

        i       --  cell position
        j       --  cell position
        value   --  new value

        returns the new value stored in the data object, or None if value is
        somehow invalid.
        """
        self.mainFrame.needsSave()
        key = self.lAtomConstraints[j-1] + '('+`i+1`+')'
        formula = value.strip()
        if formula != "":
            self.constraints[key] = Constraint(formula)
            return self.constraints[key].formula
        else:
            self.constraints.pop(key, None)
            return ""
        return
Example #13
0
 def setUp(self):
     self.c = Constraint('@1')
     return
Example #14
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 SpaceGroup from diffpy.structure
        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 #15
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
 def setUp(self):
     self.c = Constraint('@1')
     return