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
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
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
def setUp(self): self.c = Constraint('@1') return
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
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