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
def test_writeStr_xyz(self): """check string representation of normal xyz file""" stru = self.stru stru.title = "test of writeStr" stru.lattice = Lattice(1.0, 2.0, 3.0, 90.0, 90.0, 90.0) stru[:] = [Atom('H', [1., 1., 1.]), Atom('Cl', [3., 2., 1.])] s1 = stru.writeStr(self.format) s1 = re.sub('[ \t]+', ' ', s1) s0 = "2\n%s\nH 1 2 3\nCl 3 4 3\n" % stru.title self.assertEqual(s1, s0)
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
def test_write_xyz(self): """check writing of normal xyz file""" stru = self.stru stru.title = "test of writeStr" stru.lattice = Lattice(1.0, 2.0, 3.0, 90.0, 90.0, 90.0) stru[:] = [Atom('H', [1., 1., 1.]), Atom('Cl', [3., 2., 1.])] stru.write(self.tmpname, self.format) f_s = open(self.tmpname).read() f_s = re.sub('[ \t]+', ' ', f_s) s_s = "2\n%s\nH 1 2 3\nCl 3 4 3\n" % stru.title self.assertEqual(f_s, s_s)
def fccAl(): atoms = [ Atom('Al', (0, 0, 0)), Atom('Al', (0.5, 0.5, 0)), Atom('Al', (0.5, 0, 0.5)), Atom('Al', (0, 0.5, 0.5)) ] a = 4.046 alpha = 90. lattice = Lattice(a=a, b=a, c=a, alpha=alpha, beta=alpha, gamma=alpha) return Structure(atoms, lattice, sgid=225)
def fccNi(): atoms = [ Atom('Ni', (0, 0, 0)), Atom('Ni', (0.5, 0.5, 0)), Atom('Ni', (0.5, 0, 0.5)), Atom('Ni', (0, 0.5, 0.5)) ] a = 3.5238 alpha = 90. lattice = Lattice(a=a, b=a, c=a, alpha=alpha, beta=alpha, gamma=alpha) return Structure(atoms, lattice, sgid=225)
def setUp(self): self.stru = Structure( [ Atom('C', [0,0,0]), Atom('C', [1,1,1]) ], lattice=Lattice(1, 1, 1, 90, 90, 120) ) if not self._loaded_structures: self._loaded_structures.update([ ('cdse', Structure(filename=cdsefile)), ('tei', Structure(filename=teifile)), ('pbte', Structure(filename=pbtefile)), ]) self.__dict__.update(self._loaded_structures) self.places = 12 return
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
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
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_pickling(self): """Test pickling of DiffpyStructureParSet. """ stru = Structure([Atom("C", [0, 0.2, 0.5])]) dsps = DiffpyStructureParSet("dsps", stru) data = pickle.dumps(dsps) dsps2 = pickle.loads(data) self.assertEqual(1, len(dsps2.atoms)) self.assertEqual(0.2, dsps2.atoms[0].y.value) return
def test___repr__(self): """Test representation of DiffpyStructureParSet objects. """ lat = Lattice(3, 3, 2, 90, 90, 90) atom = Atom("C", [0, 0.2, 0.5]) stru = Structure([atom], lattice=lat) dsps = DiffpyStructureParSet("dsps", stru) self.assertEqual(repr(stru), repr(dsps)) self.assertEqual(repr(lat), repr(dsps.lattice)) self.assertEqual(repr(atom), repr(dsps.atoms[0])) return
def test___init__(self): """check Structure.__init__() """ atoms = [Atom('C', [0, 0, 0]), Atom('C', [0.5, 0.5, 0.5])] self.assertRaises(ValueError, Structure, atoms, filename=teifile) self.assertRaises(ValueError, Structure, lattice=Lattice(), filename=teifile) self.assertRaises(ValueError, Structure, title='test', filename=teifile) stru1 = Structure(title='my title') self.assertEqual('my title', stru1.title) stru2a = Structure(atoms) stru2b = Structure(iter(atoms)) stru2c = Structure(a for a in atoms) s2a = str(stru2a) self.assertEqual(s2a, str(stru2b)) self.assertEqual(s2a, str(stru2c)) return
def test___setslice__(self): """check Structure.__setslice__() """ a = Atom("Si", (0.1, 0.2, 0.3)) lat = self.stru.lattice self.stru[:] = [a] a0 = self.stru[0] self.assertEqual(1, len(self.stru)) self.assertEqual('Si', a0.element) self.failUnless(lat is a0.lattice) self.failUnless(numpy.array_equal(a.xyz, a0.xyz)) self.failIf(a is a0) self.failIf(lat is a.lattice) return
def test_append(self): """check Structure.append() """ a = Atom("Si", (0.1, 0.2, 0.3)) lat = self.stru.lattice self.stru.append(a) alast = self.stru[-1] self.assertEqual(3, len(self.stru)) self.assertEqual('Si', alast.element) self.failUnless(lat is alast.lattice) self.failUnless(numpy.array_equal(a.xyz, alast.xyz)) self.failIf(a is alast) self.failIf(lat is a.lattice) return
def test_insert(self): """check Structure.insert() """ a = Atom("Si", (0.1, 0.2, 0.3)) lat = self.stru.lattice self.stru.insert(1, a) a1 = self.stru[1] self.assertEqual(3, len(self.stru)) self.assertEqual('Si', a1.element) self.assertTrue(lat is a1.lattice) self.assertTrue(numpy.array_equal(a.xyz, a1.xyz)) self.assertFalse(a is a1) self.assertFalse(lat is a.lattice) return
def test_setStructure(self): """check PairQuantity.setStructure() """ from diffpy.Structure import Structure, Atom from diffpy.srreal.structureadapter import EMPTY stru = Structure([Atom("Ar", [0.1, 0.2, 0.3])]) self.pq.setStructure(stru) adpt = self.pq.getStructure() self.assertEqual(1, adpt.countSites()) self.assertEqual("Ar", adpt.siteAtomType(0)) self.pq.setStructure(EMPTY) adpt = self.pq.getStructure() self.assertEqual(0, adpt.countSites()) return
def test___setitem__(self): """check Structure.__setitem__() """ a = Atom("Si", (0.1, 0.2, 0.3)) lat = self.stru.lattice self.stru[1] = a a1 = self.stru[1] self.assertEqual(2, len(self.stru)) self.assertEqual('Si', a1.element) self.failUnless(lat is a1.lattice) self.failUnless(numpy.array_equal(a.xyz, a1.xyz)) self.failIf(a is a1) self.failIf(lat is a.lattice) return
def test_writeStr_rawxyz(self): """check writing of normal xyz file""" stru = self.stru stru.title = "test of writeStr" stru.lattice = Lattice(1.0, 2.0, 3.0, 90.0, 90.0, 90.0) # plain version stru[:] = [Atom('H', [1., 1., 1.])] s1 = stru.writeStr(self.format) s1 = re.sub('[ \t]+', ' ', s1) s0 = "H 1 2 3\n" # brutal raw version stru[0].element = "" s1 = stru.writeStr(self.format) s0 = "1 2 3\n" self.assertEqual(s1, s0)
def test_getvar(self): """check PDFStructure.getvar() """ from diffpy.Structure import Atom stru = self.stru abcABG = (3.0, 4.0, 5.0, 81, 82, 83) stru.lattice.setLatPar(*abcABG) for i in range(6): self.assertEqual(abcABG[i], stru.getvar('lat(%i)' % (i + 1))) stru.append(Atom('Ni', [0.1, 0.2, 0.3])) self.assertEqual(0.1, stru.getvar('x(1)')) self.assertEqual(0.2, stru.getvar('y(1)')) self.assertEqual(0.3, stru.getvar('z(1)')) # spdiameter self.assertEqual(0.0, stru.getvar('spdiameter')) stru.pdffit['spdiameter'] = 37.7 self.assertEqual(37.7, stru.getvar('spdiameter')) # stepcut self.assertEqual(0.0, stru.getvar('stepcut')) stru.pdffit['stepcut'] = 17.7 self.assertEqual(17.7, stru.getvar('stepcut')) return
def bccFe(): atoms = [Atom('Fe', (0, 0, 0)), Atom('Fe', (0.5, 0.5, 0.5))] a = 2.856 alpha = 90. lattice = Lattice(a=a, b=a, c=a, alpha=alpha, beta=alpha, gamma=alpha) return Structure(atoms, lattice, sgid=229)
def testDiffpyStructureParSet(self): """Test the structure conversion.""" a1 = Atom("Cu", xyz = numpy.array([.0, .1, .2]), Uisoequiv = 0.003) a2 = Atom("Ag", xyz = numpy.array([.3, .4, .5]), Uisoequiv = 0.002) l = Lattice(2.5, 2.5, 2.5, 90, 90, 90) dsstru = Structure([a1,a2], l) # Structure makes copies a1 = dsstru[0] a2 = dsstru[1] s = DiffpyStructureParSet("CuAg", dsstru) self.assertEquals(s.name, "CuAg") def _testAtoms(): # Check the atoms thoroughly self.assertEquals(a1.element, s.Cu0.element) self.assertEquals(a2.element, s.Ag0.element) self.assertEquals(a1.Uisoequiv, s.Cu0.Uiso.getValue()) self.assertEquals(a2.Uisoequiv, s.Ag0.Uiso.getValue()) self.assertEquals(a1.Bisoequiv, s.Cu0.Biso.getValue()) self.assertEquals(a2.Bisoequiv, s.Ag0.Biso.getValue()) for i in xrange(1,4): for j in xrange(i,4): uijstru = getattr(a1, "U%i%i"%(i,j)) uij = getattr(s.Cu0, "U%i%i"%(i,j)).getValue() uji = getattr(s.Cu0, "U%i%i"%(j,i)).getValue() self.assertEquals(uijstru, uij) self.assertEquals(uijstru, uji) bijstru = getattr(a1, "B%i%i"%(i,j)) bij = getattr(s.Cu0, "B%i%i"%(i,j)).getValue() bji = getattr(s.Cu0, "B%i%i"%(j,i)).getValue() self.assertEquals(bijstru, bij) self.assertEquals(bijstru, bji) self.assertEquals(a1.xyz[0], s.Cu0.x.getValue()) self.assertEquals(a1.xyz[1], s.Cu0.y.getValue()) self.assertEquals(a1.xyz[2], s.Cu0.z.getValue()) return def _testLattice(): # Test the lattice self.assertEquals(dsstru.lattice.a, s.lattice.a.getValue()) self.assertEquals(dsstru.lattice.b, s.lattice.b.getValue()) self.assertEquals(dsstru.lattice.c, s.lattice.c.getValue()) self.assertEquals(dsstru.lattice.alpha, s.lattice.alpha.getValue()) self.assertEquals(dsstru.lattice.beta, s.lattice.beta.getValue()) self.assertEquals(dsstru.lattice.gamma, s.lattice.gamma.getValue()) _testAtoms() _testLattice() # Now change some values from the diffpy Structure a1.xyz[1] = 0.123 a1.U11 = 0.321 a1.B32 = 0.111 dsstru.lattice.setLatPar(a=3.0, gamma=121) _testAtoms() _testLattice() # Now change values from the srfit DiffpyStructureParSet s.Cu0.x.setValue(0.456) s.Cu0.U22.setValue(0.441) s.Cu0.B13.setValue(0.550) d = dsstru.lattice.dist(a1.xyz, a2.xyz) s.lattice.b.setValue(4.6) s.lattice.alpha.setValue(91.3) _testAtoms() _testLattice() # Make sure the distance changed self.assertNotEquals(d, dsstru.lattice.dist(a1.xyz, a2.xyz)) return
def parseLines(self, lines): """Parse list of lines in atoms format. Return Structure object or raise StructureFormatError. """ comlist = ["#", "%", "!", "*"] atoms = [] title = "" anext = False sg = None structure = BRAtomsStructure() meta = structure.bratoms pdict = dict.fromkeys(self.plist) # Count the lines ln = 0 try: for line in lines: ln += 1 # Strip comments from the line for c in comlist: idx = line.find(c) if idx != -1: line = line[:idx] # Move on if there is not a line if not line: continue # Move on if there was only white space in the line sline = line.split() if not sline: continue # Check if we have atoms following if sline[0].startswith("atom"): anext = True continue # Check for title if sline[0].startswith("title"): if title: title += "\n" title += line[5:] continue # Get rid of pesky "=" and "," signs while "=" in sline: sline.remove("=") while "," in sline: sline.remove(",") # space group if sline and sline[0].startswith("space"): meta["space"] = line[5:].strip() continue # output if sline and sline[0].startswith("output"): meta["output"] = line[6:].strip() continue # shift if sline and sline[0].startswith("shift"): meta["shift"] = line[5:].strip() continue # Check for other metadata while sline and sline[0].strip() in meta: key = sline.pop(0).strip() if key == "central": key = "core" meta[key] = sline.pop(0).strip() # Check for lattice information. while sline and sline[0].strip() in self.plist: key = sline.pop(0).strip() pdict[key] = float(sline.pop(0)) # Check for atom information if sline and anext: elraw = sline.pop(0).strip() el = elraw[:1].upper() + elraw[1:].lower() x = float(sline.pop(0)) y = float(sline.pop(0)) z = float(sline.pop(0)) tag = "" if sline: tag = sline.pop(0).strip() occ = 1.0 if sline: occ = float(sline.pop(0)) a = Atom( atype = el, xyz = [x,y,z], name = tag, occupancy = occ) atoms.append(a) except (ValueError, IndexError), e: emsg = "%d: file is not in Atoms format" % ln raise StructureFormatError(emsg)
def parseLines(self, lines): """Parse list of lines in atoms format. Return Structure object or raise StructureFormatError. """ comlist = ["#", "%", "!", "*"] atoms = [] title = "" anext = False structure = BRAtomsStructure() meta = structure.bratoms pdict = dict.fromkeys(self.plist) # Count the lines ln = 0 try: for line in lines: ln += 1 # Strip comments from the line for c in comlist: idx = line.find(c) if idx != -1: line = line[:idx] # Move on if there is not a line if not line: continue # Move on if there was only white space in the line sline = line.split() if not sline: continue # Check if we have atoms following if sline[0].startswith("atom"): anext = True continue # Check for title if sline[0].startswith("title"): if title: title += "\n" title += line[5:] continue # Get rid of pesky "=" and "," signs while "=" in sline: sline.remove("=") while "," in sline: sline.remove(",") # space group if sline and sline[0].startswith("space"): meta["space"] = line[5:].strip() continue # output if sline and sline[0].startswith("output"): meta["output"] = line[6:].strip() continue # shift if sline and sline[0].startswith("shift"): meta["shift"] = line[5:].strip() continue # Check for other metadata while sline and sline[0].strip() in meta: key = sline.pop(0).strip() if key == "central": key = "core" meta[key] = sline.pop(0).strip() # Check for lattice information. while sline and sline[0].strip() in self.plist: key = sline.pop(0).strip() pdict[key] = float(sline.pop(0)) # Check for atom information if sline and anext: elraw = sline.pop(0).strip() el = elraw[:1].upper() + elraw[1:].lower() x = float(sline.pop(0)) y = float(sline.pop(0)) z = float(sline.pop(0)) tag = "" if sline: tag = sline.pop(0).strip() occ = 1.0 if sline: occ = float(sline.pop(0)) a = Atom(atype = el, xyz = [x, y, z], label = tag, occupancy = occ) atoms.append(a) except (ValueError, IndexError): emsg = "%d: file is not in Atoms format" % ln raise StructureFormatError(emsg) # Make sure we have atoms. if len(atoms) == 0: raise StructureFormatError("File contains no atoms") # Make sure we have unit cell parameters if pdict["a"] is None: emsg = "Missing definition of cell parameter" raise StructureFormatError(emsg) # Fill in optional information if it was missing. if pdict["alpha"] is None: pdict["alpha"] = 90.0 if pdict["beta"] is None: pdict["beta"] = pdict["alpha"] if pdict["gamma"] is None: pdict["gamma"] = pdict["alpha"] if pdict["b"] is None: pdict["b"] = pdict["a"] if pdict["c"] is None: pdict["c"] = pdict["a"] if meta['core'] is None: meta['core'] = atoms[0].element lat = Lattice(**pdict) structure.title = title structure.lattice = lat structure.extend(atoms) return structure
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 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 carbonzchain(n): "Helper function that returns a z-chain of Carbon atoms." from diffpy.Structure import Structure, Atom rv = Structure([Atom('C', [0, 0, z]) for z in range(n)]) return rv