def makeRecipe(ciffile, datname): """Create a fitting recipe for crystalline PDF data.""" # Work directly with a custom PDFContribution to load the data contribution = PDFContribution("nickel") contribution.loadData(datname) contribution.setCalculationRange(xmin = 1, xmax = 20, dx = 0.1) # and the phase stru = Structure() stru.read(ciffile) contribution.addStructure("nickel", stru) ## Make the FitRecipe and add the FitContribution. recipe = FitRecipe() recipe.addContribution(contribution) ## Configure the fit variables phase = contribution.nickel.phase from diffpy.srfit.structure import constrainAsSpaceGroup sgpars = constrainAsSpaceGroup(phase, "Fm-3m") for par in sgpars.latpars: recipe.addVar(par) for par in sgpars.adppars: recipe.addVar(par, 0.005) recipe.addVar(contribution.scale, 1) recipe.addVar(contribution.qdamp, 0.03, fixed = True) recipe.addVar(contribution.nickel.delta2, 5) # Give the recipe away so it can be used! return recipe
def test___getitem__(self): """check Structure.__getitem__() """ stru = self.stru self.assertTrue(stru[0] is stru.tolist()[0]) intidx = list(range(len(stru)))[::-1] self.assertEqual(stru[intidx].tolist(), stru.tolist()[::-1]) flagidx = (numpy.arange(len(stru)) > 0) self.assertEqual(stru[flagidx].tolist(), stru.tolist()[1:]) cdse = Structure(self.cdse) self.assertEqual([cdse[0], cdse[-2]], cdse[0, -2].tolist()) cdse013 = cdse.tolist() cdse013.pop(2) self.assertEqual(cdse013, cdse[:2, 3].tolist()) self.assertRaises(IndexError, cdse.__getitem__, 'Cd1') cdse.assignUniqueLabels() self.assertTrue(cdse[0] is cdse['Cd1']) cdse[0].label = 'Hohenzollern' self.assertRaises(IndexError, cdse.__getitem__, 'Cd1') self.assertTrue(cdse[0] is cdse['Hohenzollern']) self.assertEqual([cdse[0], cdse[3], cdse[1]], cdse['Hohenzollern', 3:0:-2].tolist()) stru.label = ['A', 'B'] self.assertTrue(stru[0] is stru['A']) self.assertTrue(stru[1] is stru['B']) stru[1].label = 'A' self.assertRaises(IndexError, stru.__getitem__, 'A') return
def test_rwStr_pdb_CdSe(self): """check conversion to PDB file format""" stru = self.stru stru.read(datafile('CdSe_bulk.stru'), 'pdffit') s = stru.writeStr(self.format) # all lines should be 80 characters long linelens = [len(l) for l in s.split('\n') if l != ""] self.assertEqual(linelens, len(linelens) * [80]) # now clean and re-read structure stru = Structure() stru.readStr(s, self.format) s_els = [a.element for a in stru] f_els = ['Cd', 'Cd', 'Se', 'Se'] self.assertEqual(s_els, f_els) s_lat = [ stru.lattice.a, stru.lattice.b, stru.lattice.c, stru.lattice.alpha, stru.lattice.beta, stru.lattice.gamma ] f_lat = [4.235204, 4.235204, 6.906027, 90.0, 90.0, 120.0] self.assertTrue(numpy.allclose(s_lat, f_lat, atol=5e-4)) a0 = stru[0] s_Uii = [a0.U[i, i] for i in range(3)] f_Uii = [0.01303035, 0.01303035, 0.01401959] self.assertTrue(numpy.allclose(s_Uii, f_Uii, atol=5e-4)) s_sigUii = [a0.sigU[i, i] for i in range(3)] f_sigUii = [0.00011127, 0.00011127, 0.00019575] self.assertTrue(numpy.allclose(s_sigUii, f_sigUii, atol=5e-4)) s_title = stru.title f_title = "Cell structure file of CdSe #186" self.assertEqual(s_title, f_title)
def test___getitem__(self): """check Structure.__getitem__() """ stru = self.stru self.assertTrue(stru[0] is stru.tolist()[0]) intidx = list(range(len(stru)))[::-1] self.assertEqual(stru[intidx].tolist(), stru.tolist()[::-1]) flagidx = (numpy.arange(len(stru)) > 0) self.assertEqual(stru[flagidx].tolist(), stru.tolist()[1:]) cdse = Structure(self.cdse) self.assertEqual([cdse[0], cdse[-2]], cdse[0, -2].tolist()) cdse013 = cdse.tolist() cdse013.pop(2) self.assertEqual(cdse013, cdse[:2,3].tolist()) self.assertRaises(IndexError, cdse.__getitem__, 'Cd1') cdse.assignUniqueLabels() self.assertTrue(cdse[0] is cdse['Cd1']) cdse[0].label = 'Hohenzollern' self.assertRaises(IndexError, cdse.__getitem__, 'Cd1') self.assertTrue(cdse[0] is cdse['Hohenzollern']) self.assertEqual([cdse[0], cdse[3], cdse[1]], cdse['Hohenzollern', 3:0:-2].tolist()) stru.label = ['A', 'B'] self.assertTrue(stru[0] is stru['A']) self.assertTrue(stru[1] is stru['B']) stru[1].label = 'A' self.assertRaises(IndexError, stru.__getitem__, 'A') return
def test_rwStr_pdb_CdSe(self): """check conversion to PDB file format""" stru = self.stru stru.read(datafile('CdSe_bulk.stru'), 'pdffit') s = stru.writeStr(self.format) # all lines should be 80 characters long linelens = [len(l) for l in s.split('\n') if l != ""] self.assertEqual(linelens, len(linelens)*[80]) # now clean and re-read structure stru = Structure() stru.readStr(s, self.format) s_els = [a.element for a in stru] f_els = ['Cd', 'Cd', 'Se', 'Se'] self.assertEqual(s_els, f_els) s_lat = [stru.lattice.a, stru.lattice.b, stru.lattice.c, stru.lattice.alpha, stru.lattice.beta, stru.lattice.gamma] f_lat = [4.235204, 4.235204, 6.906027, 90.0, 90.0, 120.0] self.assertTrue(numpy.allclose(s_lat, f_lat, atol=5e-4)) a0 = stru[0] s_Uii = [a0.U[i,i] for i in range(3)] f_Uii = [0.01303035, 0.01303035, 0.01401959] self.assertTrue(numpy.allclose(s_Uii, f_Uii, atol=5e-4)) s_sigUii = [a0.sigU[i,i] for i in range(3)] f_sigUii = [0.00011127, 0.00011127, 0.00019575] self.assertTrue(numpy.allclose(s_sigUii, f_sigUii, atol=5e-4)) s_title = stru.title f_title = "Cell structure file of CdSe #186" self.assertEqual(s_title, f_title)
def parseLines(self, lines): """Parse list of lines in RAWXYZ format. Return Structure object or raise StructureFormatError. """ linefields = [l.split() for l in lines] # prepare output structure stru = Structure() # find first valid record start = 0 for field in linefields: if len(field) == 0 or field[0] == "#": start += 1 else: break # find the last valid record stop = len(lines) while stop > start and len(linefields[stop-1]) == 0: stop -= 1 # get out for empty structure if start >= stop: return stru # here we have at least one valid record line # figure out xyz layout from the first line for plain and raw formats floatfields = [ isfloat(f) for f in linefields[start] ] nfields = len(linefields[start]) if nfields not in (3, 4): emsg = ("%d: invalid RAWXYZ format, expected 3 or 4 columns" % (start + 1)) raise StructureFormatError(emsg) if floatfields[:3] == [True, True, True]: el_idx, x_idx = (None, 0) elif floatfields[:4] == [False, True, True, True]: el_idx, x_idx = (0, 1) else: emsg = "%d: invalid RAWXYZ format" % (start + 1) raise StructureFormatError(emsg) # now try to read all record lines try: p_nl = start for fields in linefields[start:] : p_nl += 1 if fields == []: continue elif len(fields) != nfields: emsg = ('%d: all lines must have ' + 'the same number of columns') % p_nl raise StructureFormatError(emsg) element = el_idx is not None and fields[el_idx] or "" xyz = [ float(f) for f in fields[x_idx:x_idx+3] ] if len(xyz) == 2: xyz.append(0.0) stru.addNewAtom(element, xyz=xyz) except ValueError: emsg = "%d: invalid number" % p_nl exc_type, exc_value, exc_traceback = sys.exc_info() e = StructureFormatError(emsg) six.reraise(StructureFormatError, e, exc_traceback) return stru
def parseLines(self, lines): """Parse list of lines in RAWXYZ format. Return Structure object or raise StructureFormatError. """ linefields = [l.split() for l in lines] # prepare output structure stru = Structure() # find first valid record start = 0 for field in linefields: if len(field) == 0 or field[0] == "#": start += 1 else: break # find the last valid record stop = len(lines) while stop > start and len(linefields[stop - 1]) == 0: stop -= 1 # get out for empty structure if start >= stop: return stru # here we have at least one valid record line # figure out xyz layout from the first line for plain and raw formats floatfields = [isfloat(f) for f in linefields[start]] nfields = len(linefields[start]) if nfields not in (3, 4): emsg = ("%d: invalid RAWXYZ format, expected 3 or 4 columns" % (start + 1)) raise StructureFormatError(emsg) if floatfields[:3] == [True, True, True]: el_idx, x_idx = (None, 0) elif floatfields[:4] == [False, True, True, True]: el_idx, x_idx = (0, 1) else: emsg = "%d: invalid RAWXYZ format" % (start + 1) raise StructureFormatError(emsg) # now try to read all record lines try: p_nl = start for fields in linefields[start:]: p_nl += 1 if fields == []: continue elif len(fields) != nfields: emsg = ('%d: all lines must have ' + 'the same number of columns') % p_nl raise StructureFormatError(emsg) element = el_idx is not None and fields[el_idx] or "" xyz = [float(f) for f in fields[x_idx:x_idx + 3]] if len(xyz) == 2: xyz.append(0.0) stru.addNewAtom(element, xyz=xyz) except ValueError: emsg = "%d: invalid number" % p_nl exc_type, exc_value, exc_traceback = sys.exc_info() e = StructureFormatError(emsg) six.reraise(StructureFormatError, e, exc_traceback) return stru
def test_angle(self): """check Structure.angle() """ cdse = Structure(filename=cdsefile) cdse.assignUniqueLabels() self.assertEqual(109, round(cdse.angle(0, 2, 1))) self.assertEqual(109, round(cdse.angle("Cd1", "Se1", "Cd2"))) return
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.__setitem__(slice(None), 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 main(): # load structure from a specified file, by default "lj50.xyz" filename = len(sys.argv) > 1 and sys.argv[1] or "lj50.xyz" stru = Structure() stru.read(filename) # create an instance of LennardJonesCalculator ljcalc = LennardJonesCalculator() # calculate and print the LJ potential. print("LJ potential of %s is %g" % (filename, ljcalc(stru)))
def test__get_lattice(self): """check Structure._get_lattice() """ lat = Lattice() stru = Structure() self.assertEqual((1, 1, 1, 90, 90, 90), stru.lattice.abcABG()) stru2 = Structure(lattice=lat) self.assertTrue(lat is stru2.lattice) return
def loadStructureFile(filename, format="auto"): """Load structure from specified file. Return a tuple of (Structure, fileformat). """ from diffpy.structure import Structure stru = Structure() p = stru.read(filename, format) fileformat = p.format return (stru, fileformat)
def test_label(self): """check Structure.label """ cdse = Structure(filename=cdsefile) self.assertEqual(4 * [''], cdse.label.tolist()) cdse.assignUniqueLabels() self.assertEqual('Cd1 Cd2 Se1 Se2'.split(), cdse.label.tolist()) cdse.label = cdse.label.lower() self.assertEqual('cd1 cd2 se1 se2'.split(), cdse.label.tolist()) return
def test_huge_occupancy(self): """check structure with huge occupancy can be read. """ self.stru.read(datafile('Ni.stru'), self.format) self.stru[0].occupancy = 16e16 s_s = self.stru.writeStr(self.format) stru1 = Structure() stru1.readStr(s_s, self.format) self.assertEqual(16e16, stru1[0].occupancy) return
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.__setitem__(slice(None), 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_and_read(self): """high-level check of P_cif.tostring() """ # high-level check stru_check = Structure() stru_check.read(self.cdsebulkpdffitfile) s_s = stru_check.writeStr('cif') stru = Structure() stru.readStr(s_s, 'cif') self.assertAlmostEqual(4.2352, stru.lattice.a, self.places) self.assertAlmostEqual(4.2352, stru.lattice.b, self.places) self.assertAlmostEqual(6.90603, stru.lattice.c, self.places) self.assertEqual(4, len(stru)) a0 = stru[0] self.assertEqual('Cd', a0.element) self.assertTrue(numpy.allclose([0.3334, 0.6667, 0.0], a0.xyz)) self.assertTrue(a0.anisotropy) self.assertAlmostEqual(0.01303, a0.U[0, 0]) self.assertAlmostEqual(0.01303, a0.U[1, 1]) self.assertAlmostEqual(0.01402, a0.U[2, 2]) a3 = stru[3] self.assertEqual('Se', a3.element) self.assertTrue(numpy.allclose([0.6666, 0.333300, 0.87667], a3.xyz)) self.assertAlmostEqual(0.015673, a3.U[0, 0]) self.assertAlmostEqual(0.015673, a3.U[1, 1]) self.assertAlmostEqual(0.046164, a3.U[2, 2]) return
def test_is_hexagonal(self): p1 = Phase( point_group="321", structure=Structure(lattice=Lattice(1, 1, 2, 90, 90, 120)), ) p2 = Phase( point_group="m-3m", structure=Structure(lattice=Lattice(1, 1, 1, 90, 90, 90)), ) assert p1.is_hexagonal assert not p2.is_hexagonal
def test___copy__(self): """check Structure.__copy__() """ cdse = Structure(filename=cdsefile) cdse_str = cdse.writeStr('pdffit') cdse2 = copy.copy(cdse) self.assertEqual(cdse_str, cdse2.writeStr('pdffit')) self.assertFalse(cdse.lattice is cdse2.lattice) sameatoms = set(cdse).intersection(cdse2) self.assertFalse(sameatoms) return
def makeData(strufile, q, datname, scale, a, Uiso, sig, bkgc, nl=1): """Make some fake data and save it to file. Make some data to fit. This uses iofq to calculate an intensity curve, and adds to it a background, broadens the peaks, and noise. strufile-- A filename holding the sample structure q -- The q-range to calculate over. datname -- The name of the file we're saving to. scale -- The scale factor a -- The lattice constant to use Uiso -- The thermal factor for all atoms sig -- The broadening factor bkgc -- A parameter that gives minor control of the background. nl -- Noise level (0, inf), default 1, larger -> less noise. """ from diffpy.structure import Structure S = Structure() S.read(strufile) # Set the lattice parameters S.lattice.setLatPar(a, a, a) # Set a DW factor for a in S: a.Uisoequiv = Uiso y = iofq(S, q) # We want to broaden the peaks as well. This simulates instrument effects. q0 = q[len(q) // 2] g = numpy.exp(-0.5 * ((q - q0) / sig)**2) y = numpy.convolve(y, g, mode='same') / sum(g) # Add a polynomial background. bkgd = (q + bkgc)**2 * (1.5 * max(q) - q)**5 bkgd *= 0.2 * max(y) / max(bkgd) y += bkgd # Multipy by a scale factor y *= scale # Calculate the uncertainty u = (y / nl)**0.5 # And apply the noise if nl > 0: y = numpy.random.poisson(y * nl) / nl # Now save it numpy.savetxt(datname, numpy.transpose([q, y, u])) return
def makeData(strufile, q, datname, scale, a, Uiso, sig, bkgc, nl = 1): """Make some fake data and save it to file. Make some data to fit. This uses iofq to calculate an intensity curve, and adds to it a background, broadens the peaks, and noise. strufile-- A filename holding the sample structure q -- The q-range to calculate over. datname -- The name of the file we're saving to. scale -- The scale factor a -- The lattice constant to use Uiso -- The thermal factor for all atoms sig -- The broadening factor bkgc -- A parameter that gives minor control of the background. nl -- Noise level (0, inf), default 1, larger -> less noise. """ from diffpy.structure import Structure S = Structure() S.read(strufile) # Set the lattice parameters S.lattice.setLatPar(a, a, a) # Set a DW factor for a in S: a.Uisoequiv = Uiso y = iofq(S, q) # We want to broaden the peaks as well. This simulates instrument effects. q0 = q[len(q) // 2] g = numpy.exp(-0.5*((q-q0)/sig)**2) y = numpy.convolve(y, g, mode='same')/sum(g) # Add a polynomial background. bkgd = (q + bkgc)**2 * (1.5*max(q) - q)**5 bkgd *= 0.2 * max(y) / max(bkgd) y += bkgd # Multipy by a scale factor y *= scale # Calculate the uncertainty u = (y/nl)**0.5 # And apply the noise if nl > 0: y = numpy.random.poisson(y*nl) / nl # Now save it numpy.savetxt(datname, numpy.transpose([q, y, u])) return
def setUp(self): # load test structures once if TestSuperCell.stru_cdse is None: cdsefile = datafile("CdSe_bulk.stru") TestSuperCell.stru_cdse = Structure(filename=cdsefile) if TestSuperCell.stru_ni is None: nifile = datafile("Ni.stru") TestSuperCell.stru_ni = Structure(filename=nifile) # bring them to the instance self.stru_cdse = TestSuperCell.stru_cdse self.stru_ni = TestSuperCell.stru_ni return
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 test___isub__(self): """check Structure.__isub__() """ cdse = Structure(filename=cdsefile) lat = cdse.lattice lst = cdse.tolist() cdse -= cdse[2:] self.assertEqual(2, len(cdse)) self.assertEqual(4, len(lst)) self.assertEqual('Cd', cdse[0].element) self.assertEqual('Cd', cdse[1].element) self.assertEqual(lat, cdse.lattice) self.assertEqual(lst[:2], cdse.tolist()) return
def main(): s = input('Enter rmin: ') if s.strip(): distprint.rmin = float(s) print("rmin = %g" % distprint.rmin) s = input('Enter rmax: ') if s.strip(): distprint.rmax = float(s) print("rmax = %g" % distprint.rmax) print() linesep = 78 * '-' # C60bucky print(linesep) input('Press enter for distances in C60 molecule.') distprint.eval(bucky) # nickel print(linesep) input('Press enter for distances in a nickel crystal.') distprint.eval(nickel) # objcryst sphalerite print(linesep) input('Press enter for distances in objcryst loaded sphalerite.cif.') crst = get_pyobjcryst_sphalerite() distprint.eval(crst) print(linesep) input('Press enter for distances in diffpy.structure sphalerite.cif.') crst = Structure(filename='datafiles/sphalerite.cif') distprint.eval(crst) return
def _get_phase(data_group): """Return phase information from a phase data group in an EMsoft dot product file. Parameters ---------- data_group : h5py.Group HDF5 group with the property data sets. Returns ------- name : str Phase name. point_group : str Phase point group. structure : diffpy.structure.Structure Phase structure. """ name = re.search(r"([A-z0-9]+)", data_group["MaterialName"][:][0].decode()).group(1) point_group = re.search(r"\[([A-z0-9]+)\]", data_group["Point Group"][:][0].decode()).group(1) lattice = Lattice(*tuple( data_group[f"Lattice Constant {i}"][:] for i in ["a", "b", "c", "alpha", "beta", "gamma"])) structure = Structure(title=name, lattice=lattice) return name, point_group, structure
def test_init_phase( self, name, point_group, space_group, color, color_alias, color_rgb, structure ): p = Phase( name=name, point_group=point_group, space_group=space_group, structure=structure, color=color, ) if name is None: assert p.name == structure.title else: assert p.name == str(name) if space_group is None: assert p.space_group is None else: assert p.space_group.number == space_group if point_group == "43": point_group = "432" if isinstance(point_group, Symmetry): point_group = point_group.name assert p.point_group.name == point_group assert p.color == color_alias assert np.allclose(p.color_rgb, color_rgb, atol=1e-6) if structure is not None: assert p.structure == structure else: assert p.structure == Structure()
def test_init_with_single_structure(self): structure = Structure() names = ["a", "b"] pl = PhaseList(names=names, structures=structure) assert pl.names == names assert pl.structures == [structure] * 2
def __init__(self, name=None, space_group=None, point_group=None, structure=None, color=None): """ Parameters ---------- name : str, optional Phase name. Overwrites the name in the `structure` object. space_group : int or diffpy.structure.spacegroups.SpaceGroup,\ optional Space group describing the symmetry operations resulting from associating the point group with a Bravais lattice, according to the International Tables of Crystallography. If None is passed (default), it is set to None. point_group : str or orix.quaternion.symmetry.Symmetry, optional Point group describing the symmetry operations of the phase's crystal structure, according to the International Tables of Crystallography. If None is passed (default) and `space_group` is None, it set to None. If None is passed but `space_group` is not None, it is derived from the space group. If both `point_group` and `space_group` is not None, the space group needs to be derived from the point group. structure : diffpy.structure.Structure, optional Unit cell with atoms and a lattice. If None is passed (default), a default :class:`diffpy.structure.Structure` object is created. color : str, optional Phase color. If None is passed (default), it is set to 'tab:blue' (first among the default Matplotlib colors). Examples -------- >>> from diffpy.structure import Atom, Lattice, Structure >>> from orix.crystal_map import Phase >>> p = Phase( ... name="al", ... space_group=225, ... structure=Structure( ... atoms=[Atom("al", [0, 0, 0])], ... lattice=Lattice(0.405, 0.405, 0.405, 90, 90, 90) ... ) ... ) >>> p <name: al. space group: Fm-3m. point group: m-3m. proper point \ ... group: 432. color: tab:blue> >>> p.structure [al 0.000000 0.000000 0.000000 1.0000] >>> p.structure.lattice Lattice(a=0.405, b=0.405, c=0.405, alpha=90, beta=90, gamma=90) """ self.structure = structure if structure is not None else Structure() if name is not None: self.name = name self.space_group = space_group # Needs to be set before point group self.point_group = point_group self.color = color if color is not None else "tab:blue"
def test_add_structure(self): """check PdfFit.add_structure() """ from diffpy.structure import Structure ni = Structure(filename=datafile('Ni.stru')) self.P.add_structure(ni) self.assertEqual(4, self.P.num_atoms()) return
def test_write_and_read(self): """high-level check of P_cif.tostring() """ # high-level check stru_check = Structure() stru_check.read(self.cdsebulkpdffitfile) s_s = stru_check.writeStr('cif') stru = Structure() stru.readStr(s_s, 'cif') self.assertAlmostEqual(4.2352, stru.lattice.a, self.places) self.assertAlmostEqual(4.2352, stru.lattice.b, self.places) self.assertAlmostEqual(6.90603, stru.lattice.c, self.places) self.assertEqual(4, len(stru)) a0 = stru[0] self.assertEqual('Cd', a0.element) self.assertTrue(numpy.allclose([0.3334, 0.6667, 0.0], a0.xyz)) self.assertTrue(a0.anisotropy) self.assertAlmostEqual(0.01303, a0.U[0,0]) self.assertAlmostEqual(0.01303, a0.U[1,1]) self.assertAlmostEqual(0.01402, a0.U[2,2]) a3 = stru[3] self.assertEqual('Se', a3.element) self.assertTrue(numpy.allclose([0.6666, 0.333300, 0.87667], a3.xyz)) self.assertAlmostEqual(0.015673, a3.U[0,0]) self.assertAlmostEqual(0.015673, a3.U[1,1]) self.assertAlmostEqual(0.046164, a3.U[2,2]) return
def test_rwStr_xcfg_CdSe(self): """check conversion to XCFG file format""" stru = self.stru stru.read(datafile('CdSe_bulk.stru'), 'pdffit') s = stru.writeStr(self.format) stru = Structure() stru.readStr(s, self.format) s_els = [a.element for a in stru] f_els = ['Cd', 'Cd', 'Se', 'Se'] self.assertEqual(s_els, f_els) s_lat = [stru.lattice.a, stru.lattice.b, stru.lattice.c, stru.lattice.alpha, stru.lattice.beta, stru.lattice.gamma] f_lat = [4.235204, 4.235204, 6.906027, 90.0, 90.0, 120.0] self.assertTrue(numpy.allclose(s_lat, f_lat)) a0 = stru[0] s_Uii = [a0.U[i,i] for i in range(3)] f_Uii = [0.01303035, 0.01303035, 0.01401959] self.assertTrue(numpy.allclose(s_Uii, f_Uii))
def test___imul__(self): """check Structure.__imul__() """ cdse = Structure(filename=cdsefile) lat = cdse.lattice els = cdse.element xyz = cdse.xyz lst = cdse.tolist() cdse *= 2 self.assertEqual(8, len(cdse)) self.assertEqual(lst, cdse[:4].tolist()) self.assertEqual(numpy.tile(els, 2).tolist(), cdse.element.tolist()) self.assertTrue(numpy.array_equal(numpy.tile(xyz, (2, 1)), cdse.xyz)) self.assertEqual(8, len(set(cdse))) self.assertEqual(8 * [lat], [a.lattice for a in cdse]) self.stru *= -3 self.assertEqual(0, len(self.stru)) return
def nickel_phase(): return Phase( name="nickel", space_group=225, structure=Structure( lattice=Lattice(3.5236, 3.5236, 3.5236, 90, 90, 90), atoms=[Atom(xyz=[0, 0, 0], atype="Ni", Uisoequiv=0.006332)], ), )
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_init_set_to_nones(self): phase_ids = [1, 2] pl = PhaseList(ids=phase_ids) assert pl.ids == phase_ids assert pl.names == [""] * 2 assert pl.point_groups == [None] * 2 assert pl.space_groups == [None] * 2 assert pl.colors == ["tab:blue", "tab:orange"] assert pl.structures == [Structure()] * 2
def test_add_phase_in_empty_phaselist(self): """Add Phase to empty PhaseList.""" sg_no = 10 name = "a" pl = PhaseList() pl.add(Phase(name, space_group=sg_no)) assert pl.ids == [0] assert pl.names == [name] assert pl.space_groups == [GetSpaceGroup(sg_no)] assert pl.structures == [Structure()]
def _parseCifBlock(self, blockname): """Translate CIF file block, skip blocks without _atom_site_label. Updates data members stru, eau. blockname -- name of top level block in self.ciffile No return value. """ block = self.ciffile[blockname] if '_atom_site_label' not in block: return # here block contains structure, initialize output data self.stru = Structure() self.labelindex.clear() # execute specialized block parsers self._parse_lattice(block) self._parse_atom_site_label(block) self._parse_atom_site_aniso_label(block) self._parse_space_group_symop_operation_xyz(block) 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 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 test_stepcut_parsing(self): """check parsing of stepcut record from a file. """ stru = self.stru stru.read(datafile('Ni.stru'), self.format) self.assertEqual(0, stru.pdffit['stepcut']) snoshape = stru.writeStr(format=self.format) self.assertTrue(not re.search('(?m)^shape', snoshape)) # produce a string with non-zero stepcut stru.pdffit['stepcut'] = 13 s13 = stru.writeStr(format=self.format) self.assertTrue(re.search('(?m)^shape +stepcut, ', s13)) stru13 = Structure() stru13.readStr(s13) self.assertEqual(13, stru13.pdffit['stepcut']) with open(datafile('Ni.stru')) as fp: ni_lines = fp.readlines() ni_lines.insert(3, 'shape invalid, 7\n') sbad = ''.join(ni_lines) self.assertRaises(StructureFormatError, self.stru.readStr, sbad, format=self.format) return
def main(): import getopt # default parameters try: opts, args = getopt.getopt(sys.argv[1:], "hV", ["help", "version"]) except getopt.GetoptError as errmsg: print(errmsg, file=sys.stderr) sys.exit(2) # process options for o, a in opts: if o in ("-h", "--help"): usage() sys.exit() elif o in ("-V", "--version"): version() sys.exit() if len(args) < 1: usage('brief') sys.exit() # process arguments from diffpy.structure.parsers import inputFormats, outputFormats try: infmt, outfmt = args[0].split('..', 1) if infmt not in inputFormats(): print("'%s' is not valid input format" % infmt, file=sys.stderr) sys.exit(2) if outfmt not in outputFormats(): print("'%s' is not valid output format" % outfmt, file=sys.stderr) sys.exit(2) except ValueError: print("invalid format specification '%s' does not contain .." % args[0], file=sys.stderr) sys.exit(2) # ready to do some real work try: strufile = args[1] stru = Structure() if args[1] == "-": stru.readStr(sys.stdin.read(), infmt) else: stru.read(strufile, infmt) sys.stdout.write( stru.writeStr(outfmt) ) except IndexError: print("strufile not specified", file=sys.stderr) sys.exit(2) except IOError as xxx_todo_changeme: (errno, errmsg) = xxx_todo_changeme.args print("%s: %s" % (strufile, errmsg), file=sys.stderr) sys.exit(1) except StructureFormatError as errmsg: print("%s: %s" % (strufile, errmsg), file=sys.stderr) sys.exit(1) return
def setUp(self): self.stru = Structure() self.format = "pdffit" self.places = 8
# class DistancePrinter # define nickel structure data nickel_discus_data = ''' title Ni spcgr P1 cell 3.523870, 3.523870, 3.523870, 90.000000, 90.000000, 90.000000 ncell 1, 1, 1, 4 atoms NI 0.00000000 0.00000000 0.00000000 0.1000 NI 0.00000000 0.50000000 0.50000000 0.1000 NI 0.50000000 0.00000000 0.50000000 0.1000 NI 0.50000000 0.50000000 0.00000000 0.1000 ''' nickel = Structure() nickel.readStr(nickel_discus_data, format='discus') bucky = Structure(filename='datafiles/C60bucky.stru', format='discus') distprint = DistancePrinter() distprint._setDoubleAttr('rmax', 10) def get_pyobjcryst_sphalerite(): from pyobjcryst import loadCrystal crst = loadCrystal('datafiles/sphalerite.cif') return crst def main(): s = input('Enter rmin: ') if s.strip(): distprint.rmin = float(s) print("rmin = %g" % distprint.rmin)
def makeLaMnO3_P1(): from diffpy.structure import Structure stru = Structure() stru.read(datafile('LaMnO3.stru')) return stru
def setStructure(self, strufile): """Set the structure used in the calculation. strufile -- The name of a structure file. A diffpy.structure.Structure object will be created from the file, and that object will be passed to the 'iofq' function whenever it is called. This will create the refinement Parameters using the DiffpyStructureParSet adapter from diffpy.srfit.structure.diffpyparset. DiffpyStructureParSet is a ParameterSet object that organizes and gives attribute access to Parameters and ParameterSets adapted from a diffpy Structure object. The Parameters embedded in the DiffpyStructureParSet are proxies for attributes of the diffpy.structure.Structure object that is needed by the 'iofq' function. The Parameters will be accessible by name under the 'phase' attribute of this generator, and are organized hierarchically: phase - lattice (retrieved with 'getLattice') - a - b - c - alpha - beta - gamma - scatterers (retrieved with 'getScatterers') - atom1 (the name depends on the element) - x - y - z - occ - U11 - U22 - U33 - U12 - U13 - U23 - Uiso - etc. The diffpy.structure.Structure instance is held within the DiffpyStructureParSet as the 'stru' attribute. """ # Load the structure from file from diffpy.structure import Structure stru = Structure() stru.read(strufile) # Create a ParameterSet designed to interface with # diffpy.structure.Structure objects that organizes the Parameter # hierarchy. Note that the DiffpyStructureParSet holds a handle to the # loaded structure that we use in the __call__ method below. # # We pass the diffpy.structure.Structure instance, and give the # DiffpyStructureParSet the name "phase". parset = DiffpyStructureParSet("phase", stru) # Put this ParameterSet in the ProfileGenerator. self.addParameterSet(parset) return
# Discard atom if (x/a)**2 + (y/b)**2 + (z/c)**2 > 1 if d > 1: delList.append(j) for i in delList: newS.pop(i) return newS # ---------------------------------------------------------------------------- if __name__ == "__main__": import os.path datadir = "../../tests/testdata" S = Structure() S.read(os.path.join(datadir, "CdSe_bulk.stru"), "pdffit") newS = makeEllipsoid(S, 12) newS.write("CdSe_d24.stru", "pdffit") newS = makeEllipsoid(S, 20, 10, 10) newS.write("CdSe_a20_b10_c10.stru", "pdffit") newS = makeEllipsoid(S, 20, 15, 10) newS.write("CdSe_a20_b15_c10.stru", "pdffit") S = Structure() S.read(os.path.join(datadir, "Ni.stru"), "pdffit") newS = makeEllipsoid(S, 10) newS.write("Ni_d20.stru", "pdffit") newS = makeEllipsoid(S, 20, 4) newS.write("Ni_a20_b4_c20.stru", "pdffit") newS = makeEllipsoid(S, 20, 15, 10) newS.write("Ni_a20_b15_c10.stru", "pdffit")
def parseLines(self, lines): """Parse list of lines in PDB format. Return Structure instance or raise StructureFormatError. """ try: stru = Structure() scale = numpy.identity(3, dtype=float) scaleU = numpy.zeros(3, dtype=float) p_nl = 0 for line in lines: p_nl += 1 # skip blank lines if not line.strip(): continue # make sure line has 80 characters if len(line) < 80: line = "%-80s" % line words = line.split() record = words[0] if record == "TITLE": continuation = line[8:10] if continuation.strip(): stru.title += line[10:].rstrip() else: stru.title = line[10:].rstrip() elif record == "CRYST1": a = float(line[7:15]) b = float(line[15:24]) c = float(line[24:33]) alpha = float(line[33:40]) beta = float(line[40:47]) gamma = float(line[47:54]) stru.lattice.setLatPar(a, b, c, alpha, beta, gamma) scale = numpy.transpose(stru.lattice.recbase) elif record == "SCALE1": sc = numpy.zeros((3,3), dtype=float) sc[0,:] = [float(x) for x in line[10:40].split()] scaleU[0] = float(line[45:55]) elif record == "SCALE2": sc[1,:] = [float(x) for x in line[10:40].split()] scaleU[1] = float(line[45:55]) elif record == "SCALE3": sc[2,:] = [float(x) for x in line[10:40].split()] scaleU[2] = float(line[45:55]) base = numpy.transpose(numpy.linalg.inv(sc)) abcABGcryst = numpy.array(stru.lattice.abcABG()) stru.lattice.setLatBase(base) abcABGscale = numpy.array(stru.lattice.abcABG()) reldiff = numpy.fabs(1.0 - abcABGscale/abcABGcryst) if not numpy.all(reldiff < 1.0e-4): emsg = "%d: " % p_nl + \ "SCALE and CRYST1 are not consistent." raise StructureFormatError(emsg) if numpy.any(scaleU != 0.0): emsg = "Origin offset not yet implemented." raise NotImplementedError(emsg) elif record in ("ATOM", "HETATM"): name = line[12:16].strip() rc = [float(x) for x in line[30:54].split()] try: occupancy = float(line[54:60]) except ValueError: occupancy = 1.0 try: B = float(line[60:66]) uiso = B/(8*pi**2) except ValueError: uiso = 0.0 element = line[76:78].strip() if element == "": # get element from the first 2 characters of name element = line[12:14].strip() element = element[0].upper() + element[1:].lower() stru.addNewAtom(element, occupancy=occupancy, label=name) last_atom = stru.getLastAtom() last_atom.xyz_cartn = rc last_atom.Uisoequiv = uiso elif record == "SIGATM": sigrc = [float(x) for x in line[30:54].split()] sigxyz = numpy.dot(scale, sigrc) try: sigo = float(line[54:60]) except ValueError: sigo = 0.0 try: sigB = float(line[60:66]) sigU = numpy.identity(3)*sigB/(8*pi**2) except ValueError: sigU = numpy.zeros((3,3), dtype=float) last_atom.sigxyz = sigxyz last_atom.sigo = sigo last_atom.sigU = sigU elif record == "ANISOU": last_atom.anisotropy = True Uij = [ float(x)*1.0e-4 for x in line[28:70].split() ] Ua = last_atom.U for i in range(3): Ua[i,i] = Uij[i] Ua[0,1] = Ua[1,0] = Uij[3] Ua[0,2] = Ua[2,0] = Uij[4] Ua[1,2] = Ua[2,1] = Uij[5] elif record == "SIGUIJ": sigUij = [ float(x)*1.0e-4 for x in line[28:70].split() ] for i in range(3): last_atom.sigU[i,i] = sigUij[i] last_atom.sigU[0,1] = last_atom.sigU[1,0] = sigUij[3] last_atom.sigU[0,2] = last_atom.sigU[2,0] = sigUij[4] last_atom.sigU[1,2] = last_atom.sigU[2,1] = sigUij[5] elif record in P_pdb.validRecords: pass else: emsg = "%d: invalid record name '%r'" % (p_nl, record) raise StructureFormatError(emsg) except (ValueError, IndexError): emsg = "%d: invalid PDB record" % p_nl exc_type, exc_value, exc_traceback = sys.exc_info() e = StructureFormatError(emsg) six.reraise(StructureFormatError, e, exc_traceback) return stru
def __copy__(self): rv = MyDerivedStructure() Structure.__copy__(self, target=rv) return rv
def parseLines(self, lines): """Parse list of lines in PDB format. Return Structure object or raise StructureFormatError. """ xcfg_Number_of_particles = None xcfg_A = None xcfg_H0 = numpy.zeros((3,3), dtype=float) xcfg_H0_set = numpy.zeros((3,3), dtype=bool) xcfg_NO_VELOCITY = False xcfg_entry_count = None p_nl = 0 p_auxiliary_re = re.compile(r"^auxiliary\[(\d+)\] =") p_auxiliary = {} stru = Structure() # ignore trailing blank lines stop = len(lines) for line in reversed(lines): if line.strip(): break stop -= 1 # iterator over the valid data lines ilines = iter(lines[:stop]) try: # read XCFG header for line in ilines: p_nl += 1 stripped_line = line.strip() # blank lines and lines starting with # are ignored if stripped_line == "" or line[0] == '#': continue elif xcfg_Number_of_particles is None: if line.find("Number of particles =") != 0: emsg = ("%d: first line must " + "contain 'Number of particles ='") % p_nl raise StructureFormatError(emsg) xcfg_Number_of_particles = int(line[21:].split(None, 1)[0]) p_natoms = xcfg_Number_of_particles elif line.find("A =") == 0: xcfg_A = float(line[3:].split(None, 1)[0]) elif line.find("H0(") == 0: i, j = (int(line[3]) - 1, int(line[5]) - 1) xcfg_H0[i,j] = float(line[10:].split(None, 1)[0]) xcfg_H0_set[i,j] = True elif line.find(".NO_VELOCITY.") == 0: xcfg_NO_VELOCITY = True elif line.find("entry_count =") == 0: xcfg_entry_count = int(line[13:].split(None, 1)[0]) elif p_auxiliary_re.match(line): m = p_auxiliary_re.match(line) idx = int(m.group(1)) p_auxiliary[idx] = line[m.end():].split(None, 1)[0] else: break # check header for consistency if numpy.any(xcfg_H0_set == False): emsg = "H0 tensor is not properly defined" raise StructureFormatError(emsg) p_auxnum = len(p_auxiliary) and max(p_auxiliary.keys())+1 for i in range(p_auxnum): if not i in p_auxiliary: p_auxiliary[i] = "aux%d" % i sorted_aux_keys = sorted(p_auxiliary.keys()) if p_auxnum != 0: stru.xcfg = { 'auxiliaries' : [ p_auxiliary[k] for k in sorted_aux_keys ] } ecnt = len(p_auxiliary) + (3 if xcfg_NO_VELOCITY else 6) if ecnt != xcfg_entry_count: emsg = ("%d: auxiliary fields are " "not consistent with entry_count") % p_nl raise StructureFormatError(emsg) # define proper lattice stru.lattice.setLatBase(xcfg_H0) # here we are inside the data block p_element = None for line in ilines: p_nl += 1 words = line.split() # ignore atom mass if len(words) == 1 and isfloat(words[0]): continue # parse element allowing empty symbol elif len(words) <= 1: w = line.strip() p_element = w[:1].upper() + w[1:].lower() elif len(words) == xcfg_entry_count and p_element is not None: fields = [float(w) for w in words] xyz = [xcfg_A * xi for xi in fields[:3]] stru.addNewAtom(p_element, xyz=xyz) a = stru[-1] _assign_auxiliaries(a, fields, auxiliaries=p_auxiliary, no_velocity=xcfg_NO_VELOCITY) else: emsg = "%d: invalid record" % p_nl raise StructureFormatError(emsg) if len(stru) != p_natoms: emsg = "expected %d atoms, read %d" % (p_natoms, len(stru)) raise StructureFormatError(emsg) except (ValueError, IndexError): emsg = "%d: file is not in XCFG format" % p_nl exc_type, exc_value, exc_traceback = sys.exc_info() e = StructureFormatError(emsg) six.reraise(StructureFormatError, e, exc_traceback) return stru
def makeRecipe(ciffile, datname): """Create a fitting recipe for crystalline PDF data.""" ## The Profile # This will be used to store the observed and calculated PDF profile. profile = Profile() # Load data and add it to the Profile. Unlike in other examples, we use a # class (PDFParser) to help us load the data. This class will read the data # and relevant metadata from a two- to four-column data file generated # with PDFGetX2 or PDFGetN. The metadata will be passed to the PDFGenerator # when they are associated in the FitContribution, which saves some # configuration steps. parser = PDFParser() parser.parseFile(datname) profile.loadParsedData(parser) profile.setCalculationRange(xmax = 20) ## The ProfileGenerator # The PDFGenerator is for configuring and calculating a PDF profile. Here, # we want to refine a Structure object from diffpy.structure. We tell the # PDFGenerator that with the 'setStructure' method. All other configuration # options will be inferred from the metadata that is read by the PDFParser. # In particular, this will set the scattering type (x-ray or neutron), the # Qmax value, as well as initial values for the non-structural Parameters. generator = PDFGenerator("G") stru = Structure() stru.read(ciffile) generator.setStructure(stru) ## The FitContribution # Here we associate the Profile and ProfileGenerator, as has been done # before. contribution = FitContribution("nickel") contribution.addProfileGenerator(generator) contribution.setProfile(profile, xname = "r") ## Make the FitRecipe and add the FitContribution. recipe = FitRecipe() recipe.addContribution(contribution) ## Configure the fit variables # The PDFGenerator class holds the ParameterSet associated with the # Structure passed above in a data member named "phase". (We could have # given the ParameterSet a name other than "phase" when we added it to the # PDFGenerator.) The ParameterSet in this case is a StructureParameterSet, # the documentation for which is found in the # diffpy.srfit.structure.diffpystructure module. phase = generator.phase # We start by constraining the phase to the known space group. We could do # this by hand, but there is a method in diffpy.srfit.structure named # 'constrainAsSpaceGroup' for this purpose. The constraints will by default # be applied to the sites, the lattice and to the ADPs. See the method # documentation for more details. The 'constrainAsSpaceGroup' method may # create new Parameters, which it returns in a SpaceGroupParameters object. from diffpy.srfit.structure import constrainAsSpaceGroup sgpars = constrainAsSpaceGroup(phase, "Fm-3m") # The SpaceGroupParameters object returned by 'constrainAsSpaceGroup' holds # the free Parameters allowed by the space group constraints. Once a # structure is constrained, we need (should) only use the Parameters # provided in the SpaceGroupParameters, as the relevant structure # Parameters are constrained to these. # # We know that the space group does not allow for any free sites because # each atom is on a special position. There is one free (cubic) lattice # parameter and one free (isotropic) ADP. We can access these Parameters in # the xyzpars, latpars, and adppars members of the SpaceGroupParameters # object. for par in sgpars.latpars: recipe.addVar(par) for par in sgpars.adppars: recipe.addVar(par, 0.005) # We now select non-structural parameters to refine. # This controls the scaling of the PDF. recipe.addVar(generator.scale, 1) # This is a peak-damping resolution term. recipe.addVar(generator.qdamp, 0.01) # This is a vibrational correlation term that sharpens peaks at low-r. recipe.addVar(generator.delta2, 5) # Give the recipe away so it can be used! return recipe
class TestP_pdffit(unittest.TestCase): """test Parser for PDFFit file format""" def setUp(self): self.stru = Structure() self.format = "pdffit" self.places = 8 def test_read_pdffit_ZnSb(self): """check reading of ZnSb pdffit structure file""" stru = self.stru stru.read(datafile('ZnSb_RT_Q28X_VM_20_fxiso.rstr'), self.format) f_title = "Cell structure file of Zn4Sb3 #167 interstitial" self.assertEqual(stru.title, f_title) self.assertAlmostEqual(stru.pdffit['scale'], 0.826145) self.assertAlmostEqual(stru.pdffit['delta2'], 4.687951) self.assertAlmostEqual(stru.pdffit['delta1'], 0.01) self.assertAlmostEqual(stru.pdffit['sratio'], 1.02) self.assertAlmostEqual(stru.pdffit['rcut'], 0.03) self.assertEqual(stru.pdffit['spcgr'], 'R-3c') s_lat = [ stru.lattice.a, stru.lattice.b, stru.lattice.c, stru.lattice.alpha, stru.lattice.beta, stru.lattice.gamma ] f_lat = [12.309436, 12.309436, 12.392839, 90.0, 90.0, 120.0] self.assertTrue(numpy.allclose(s_lat, f_lat)) s_dcell = stru.pdffit['dcell'] f_dcell = [0.000008, 0.000008, 0.000013, 0.0, 0.0, 0.0] self.assertTrue(numpy.allclose(s_dcell, f_dcell)) self.assertEqual(stru.pdffit['ncell'], [1,1,1,66]) s_els = [a.element for a in stru] self.assertEqual(s_els, 36*['Zn']+30*['Sb']) a0 = stru[0] s_xyz = a0.xyz f_xyz = [0.09094387, 0.24639539, 0.40080261]; s_o = a0.occupancy f_o = 0.9 s_sigxyz = a0.sigxyz f_sigxyz = [ 0.00000079, 0.00000076, 0.00000064]; s_sigo = a0.sigo f_sigo = 0.0 s_U = [ a0.U[i][i] for i in range(3) ] f_U = 3*[0.01] self.assertTrue(numpy.allclose(s_xyz, f_xyz)) self.assertTrue(numpy.allclose(s_sigxyz, f_sigxyz)) self.assertTrue(numpy.allclose(s_U, f_U)) self.assertAlmostEqual(s_o, f_o) self.assertAlmostEqual(s_sigo, f_sigo) def test_read_pdffit_Ni(self): """check reading of Ni pdffit structure file""" stru = self.stru stru.read(datafile('Ni.stru'), self.format) f_title = "structure Ni FCC" self.assertEqual(stru.title, f_title) self.assertEqual(stru.pdffit['spcgr'], 'Fm-3m') s_lat = [ stru.lattice.a, stru.lattice.b, stru.lattice.c, stru.lattice.alpha, stru.lattice.beta, stru.lattice.gamma ] f_lat = [3.52, 3.52, 3.52, 90.0, 90.0, 90.0] for i in range(len(s_lat)): self.assertAlmostEqual(s_lat[i], f_lat[i]) self.assertEqual(stru.pdffit['ncell'], [1,1,1,4]) s_els = [a.element for a in stru] self.assertEqual(s_els, 4*['Ni']) a0 = stru[0] s_xyz = a0.xyz f_xyz = [0.0, 0.0, 0.0]; s_o = a0.occupancy f_o = 1.0 s_U = [ a0.U[i][i] for i in range(3) ] f_U = 3*[0.00126651] for i in range(3): self.assertAlmostEqual(s_xyz[i], f_xyz[i]) self.assertAlmostEqual(s_U[i], f_U[i]) self.assertAlmostEqual(s_o, f_o) def test_read_pdffit_Ni_prim123(self): """check reading of Ni_prim supercell 1x2x3""" stru = self.stru stru.read(datafile('Ni_prim123.stru'), self.format) s_lat = [ stru.lattice.a, stru.lattice.b, stru.lattice.c, stru.lattice.alpha, stru.lattice.beta, stru.lattice.gamma ] f_lat = [2.489016, 2*2.489016, 3*2.489016, 60.0, 60.0, 60.0] for i in range(len(s_lat)): self.assertAlmostEqual(s_lat[i], f_lat[i]) s_els = [a.element for a in stru] self.assertEqual(s_els, 6*['Ni']) a5 = stru[5] s_xyz = a5.xyz f_xyz = [0.0, 1.0/2.0, 2.0/3.0]; for i in range(3): self.assertAlmostEqual(s_xyz[i], f_xyz[i]) s_o = a5.occupancy f_o = 1.0 self.assertAlmostEqual(s_o, f_o) s_U = [ a5.U[ij[0],ij[1]] for ij in [(0,0), (1,1), (2,2), (0,1), (0,2), (1,2)] ] f_U = 3*[0.00126651] + 3*[-0.00042217] for i in range(len(s_U)): self.assertAlmostEqual(s_U[i], f_U[i]) return def test_read_pdffit_bad(self): """check exceptions when reading invalid pdffit file""" stru = self.stru self.assertRaises(StructureFormatError, stru.read, datafile('Ni-bad.stru'), self.format) self.assertRaises(StructureFormatError, stru.read, datafile('bucky.xyz'), self.format) return def test_writeStr_pdffit(self): """check writing of normal xyz file""" stru = self.stru stru.read(datafile('Ni.stru'), self.format) with open(datafile('Ni.stru')) as fp: f_s = fp.read() f_s = re.sub('[ \t]+', ' ', f_s) f_s = re.sub('[ \t]+\n', '\n', f_s) s_s = stru.writeStr(self.format) s_s = re.sub('[ \t]+', ' ', s_s) self.assertEqual(f_s, s_s) return def test_huge_occupancy(self): """check structure with huge occupancy can be read. """ self.stru.read(datafile('Ni.stru'), self.format) self.stru[0].occupancy = 16e16 s_s = self.stru.writeStr(self.format) stru1 = Structure() stru1.readStr(s_s, self.format) self.assertEqual(16e16, stru1[0].occupancy) return def test_ignored_lines(self): """check skipping of ignored lines in the header """ r1 = 'ignored record 1' r2 = 'ignored record 2' with open(datafile('Ni.stru')) as fp: ni_lines = fp.readlines() ni_lines.insert(2, r1 + '\n') ni_lines.insert(4, r2 + '\n') s_s1 = "".join(ni_lines) p = self.stru.readStr(s_s1, self.format) self.assertEqual([r1, r2], p.ignored_lines) ni_lines.insert(-3, r1 + '\n') s_s2 = "".join(ni_lines) self.assertRaises(StructureFormatError, self.stru.readStr, s_s2, self.format) return def test_spdiameter_parsing(self): """check parsing of spdiameter record from a file. """ stru = self.stru stru.read(datafile('Ni.stru'), self.format) self.assertEqual(0, stru.pdffit['spdiameter']) snoshape = stru.writeStr(format=self.format) self.assertTrue(not re.search('(?m)^shape', snoshape)) # produce a string with non-zero spdiameter stru.pdffit['spdiameter'] = 13 s13 = stru.writeStr(format=self.format) self.assertTrue(re.search('(?m)^shape +sphere, ', s13)) stru13 = Structure() stru13.readStr(s13) self.assertEqual(13, stru13.pdffit['spdiameter']) with open(datafile('Ni.stru')) as fp: ni_lines = fp.readlines() ni_lines.insert(3, 'shape invalid, 7\n') sbad = ''.join(ni_lines) self.assertRaises(StructureFormatError, self.stru.readStr, sbad, format=self.format) return def test_stepcut_parsing(self): """check parsing of stepcut record from a file. """ stru = self.stru stru.read(datafile('Ni.stru'), self.format) self.assertEqual(0, stru.pdffit['stepcut']) snoshape = stru.writeStr(format=self.format) self.assertTrue(not re.search('(?m)^shape', snoshape)) # produce a string with non-zero stepcut stru.pdffit['stepcut'] = 13 s13 = stru.writeStr(format=self.format) self.assertTrue(re.search('(?m)^shape +stepcut, ', s13)) stru13 = Structure() stru13.readStr(s13) self.assertEqual(13, stru13.pdffit['stepcut']) with open(datafile('Ni.stru')) as fp: ni_lines = fp.readlines() ni_lines.insert(3, 'shape invalid, 7\n') sbad = ''.join(ni_lines) self.assertRaises(StructureFormatError, self.stru.readStr, sbad, format=self.format) return