예제 #1
0
    def parseLines(self, lines):
        """Parse list of lines in DISCUS format.

        Return PDFFitStructure instance or raise StructureFormatError.
        """
        self.lines = lines
        ilines = self._linesIterator()
        self.stru = PDFFitStructure()
        record_parsers = {
            "cell": self._parse_cell,
            "format": self._parse_format,
            "generator": self._parse_not_implemented,
            "molecule": self._parse_not_implemented,
            "ncell": self._parse_ncell,
            "spcgr": self._parse_spcgr,
            "symmetry": self._parse_not_implemented,
            "title": self._parse_title,
            "shape": self._parse_shape,
        }
        try:
            # parse header
            for self.line in ilines:
                words = self.line.split()
                if not words or words[0][0] == '#': continue
                if words[0] == 'atoms': break
                rp = record_parsers.get(words[0], self._parse_unknown_record)
                rp(words)
            # check if cell has been defined
            if not self.cell_read:
                emsg = "%d: unit cell not defined" % self.nl
                raise StructureFormatError(emsg)
            # parse atoms
            for self.line in ilines:
                words = self.line.split()
                if not words or words[0][0] == '#': continue
                self._parse_atom(words)
            # self consistency check
            exp_natoms = reduce(lambda x, y: x * y, self.stru.pdffit['ncell'])
            # only check if ncell record exists
            if self.ncell_read and exp_natoms != len(self.stru):
                emsg = 'Expected %d atoms, read %d.' % \
                    (exp_natoms, len(self.stru))
                raise StructureFormatError(emsg)
            # take care of superlattice
            if self.stru.pdffit['ncell'][:3] != [1, 1, 1]:
                latpars = list(self.stru.lattice.abcABG())
                superlatpars = [
                    latpars[i] * self.stru.pdffit['ncell'][i] for i in range(3)
                ] + latpars[3:]
                superlattice = Lattice(*superlatpars)
                self.stru.placeInLattice(superlattice)
                self.stru.pdffit['ncell'] = [1, 1, 1, exp_natoms]
        except (ValueError, IndexError):
            exc_type, exc_value, exc_traceback = sys.exc_info()
            emsg = "%d: file is not in DISCUS format" % self.nl
            raise StructureFormatError, emsg, exc_traceback
        return self.stru
예제 #2
0
    def __init__(self, name, *args, **kwargs):
        """Initialize PDFStructure.

        name         -- name of this PDFStructure.
        args, kwargs -- optional arguments passed to parent Structure class
        """
        PDFComponent.__init__(self, name)
        PDFFitStructure.__init__(self, *args, **kwargs)
        return
예제 #3
0
    def __init__(self, name, *args, **kwargs):
        """Initialize PDFStructure.

        name         -- name of this PDFStructure.
        args, kwargs -- optional arguments passed to parent Structure class
        """
        PDFComponent.__init__(self, name)
        PDFFitStructure.__init__(self, *args, **kwargs)
        return
예제 #4
0
    def toLines(self, stru):
        """Convert Structure stru to a list of lines in PDFfit format.

        Return list of strings.
        """
        # build the stru_pdffit dictionary initialized from the defaults
        # in PDFFitStructure
        stru_pdffit = PDFFitStructure().pdffit
        if stru.pdffit:
            stru_pdffit.update(stru.pdffit)
        lines = []
        # default values of standard deviations
        d_sigxyz = numpy.zeros(3, dtype=float)
        d_sigo = 0.0
        d_sigU = numpy.zeros((3,3), dtype=float)
        # here we can start
        l = "title  " + stru.title
        lines.append( l.strip() )
        lines.append( "format pdffit" )
        lines.append( "scale  %9.6f" % stru_pdffit["scale"] )
        lines.append( "sharp  %9.6f, %9.6f, %9.6f, %9.6f" % (
            stru_pdffit["delta2"],
            stru_pdffit["delta1"],
            stru_pdffit["sratio"],
            stru_pdffit["rcut"]) )
        lines.append( "spcgr   " + stru_pdffit["spcgr"] )
        if stru_pdffit.get('spdiameter', 0.0) > 0.0:
            line = 'shape   sphere, %g' % stru_pdffit['spdiameter']
            lines.append(line)
        if stru_pdffit.get('stepcut', 0.0) > 0.0:
            line = 'shape   stepcut, %g' % stru_pdffit['stepcut']
            lines.append(line)
        lat = stru.lattice
        lines.append( "cell   %9.6f, %9.6f, %9.6f, %9.6f, %9.6f, %9.6f" % (
            lat.a, lat.b, lat.c, lat.alpha, lat.beta, lat.gamma) )
        lines.append( "dcell  %9.6f, %9.6f, %9.6f, %9.6f, %9.6f, %9.6f" %
            tuple(stru_pdffit["dcell"]) )
        lines.append( "ncell  %9i, %9i, %9i, %9i" % (1, 1, 1, len(stru)) )
        lines.append( "atoms" )
        for a in stru:
            ad = a.__dict__
            lines.append( "%-4s %17.8f %17.8f %17.8f %12.4f" % (
                a.element.upper(), a.xyz[0], a.xyz[1], a.xyz[2], a.occupancy) )
            sigmas = numpy.concatenate(
                ( ad.get("sigxyz", d_sigxyz),  [ad.get("sigo", d_sigo)] )  )
            lines.append( "    %18.8f %17.8f %17.8f %12.4f" % tuple(sigmas) )
            sigU = ad.get("sigU", d_sigU)
            Uii = ( a.U[0][0], a.U[1][1], a.U[2][2] )
            Uij = ( a.U[0][1], a.U[0][2], a.U[1][2] )
            sigUii = ( sigU[0][0], sigU[1][1], sigU[2][2] )
            sigUij = ( sigU[0][1], sigU[0][2], sigU[1][2] )
            lines.append( "    %18.8f %17.8f %17.8f" % Uii )
            lines.append( "    %18.8f %17.8f %17.8f" % sigUii )
            lines.append( "    %18.8f %17.8f %17.8f" % Uij )
            lines.append( "    %18.8f %17.8f %17.8f" % sigUij )
        return lines
예제 #5
0
    def get_structure(self, ip):
        """get_structure(ip) --> Get a copy of specified phase data.

        ip -- index of existing PdfFit phase starting from 1

        Return Structure object from diffpy.Structure.
        Raise pdffit2.unassignedError if phase ip is undefined.
        """
        from diffpy.Structure import PDFFitStructure
        s = self.save_struct_string(ip)
        stru = PDFFitStructure()
        stru.readStr(s, 'pdffit')
        return stru
예제 #6
0
 def toLines(self, stru):
     """Convert Structure stru to a list of lines in DISCUS format.
     Return list of strings.
     """
     self.stru = stru
     # if necessary, convert self.stru to PDFFitStructure
     if not isinstance(stru, PDFFitStructure):
         self.stru = PDFFitStructure(stru)
     # build the stru_pdffit dictionary initialized from the defaults
     # in PDFFitStructure
     stru_pdffit = PDFFitStructure().pdffit
     if stru.pdffit:
         stru_pdffit.update(stru.pdffit)
     # here we can start
     self.lines = lines = []
     lines.append( "title   " + self.stru.title.strip() )
     lines.append( "spcgr   " + stru_pdffit["spcgr"] )
     if stru_pdffit.get('spdiameter', 0.0) > 0.0:
         line = 'shape   sphere, %g' % stru_pdffit['spdiameter']
         lines.append(line)
     if stru_pdffit.get('stepcut', 0.0) > 0.0:
         line = 'shape   stepcut, %g' % stru_pdffit['stepcut']
         lines.append(line)
     lines.append( "cell   %9.6f, %9.6f, %9.6f, %9.6f, %9.6f, %9.6f" %
             self.stru.lattice.abcABG() )
     lines.append( "ncell  %9i, %9i, %9i, %9i" % (1, 1, 1, len(self.stru)) )
     lines.append( "atoms" )
     for a in self.stru:
         lines.append( "%-4s %17.8f %17.8f %17.8f %12.4f" % (
             a.element.upper(), a.xyz[0], a.xyz[1], a.xyz[2], a.Bisoequiv))
     return lines
예제 #7
0
    def testGenerator(self):
        qmax = 27.0
        gen = self.gen
        gen.setScatteringType('N')
        self.assertEqual('N', gen.getScatteringType())
        gen.setQmax(qmax)
        self.assertAlmostEqual(qmax, gen.getQmax())
        from diffpy.Structure import PDFFitStructure
        stru = PDFFitStructure()
        ciffile = datafile("ni.cif")
        stru.read(ciffile)
        for i in range(4):
            stru[i].Bisoequiv = 1
        gen.setStructure(stru)

        calc = gen._calc
        # Test parameters
        for par in gen.iterPars(recurse=False):
            pname = par.name
            defval = calc._getDoubleAttr(pname)
            self.assertEquals(defval, par.getValue())
            # Test setting values
            par.setValue(1.0)
            self.assertEquals(1.0, par.getValue())
            par.setValue(defval)
            self.assertEquals(defval, par.getValue())

        r = numpy.arange(0, 10, 0.1)
        y = gen(r)

        # Now create a reference PDF. Since the calculator is testing its
        # output, we just have to make sure we can calculate from the
        # PDFGenerator interface.
        from diffpy.srreal.pdfcalculator import PDFCalculator
        calc = PDFCalculator()
        calc.rstep = r[1] - r[0]
        calc.rmin = r[0]
        calc.rmax = r[-1] + 0.5 * calc.rstep
        calc.qmax = qmax
        calc.setScatteringFactorTableByType('N')
        calc.eval(stru)
        yref = calc.pdf

        diff = y - yref
        res = numpy.dot(diff, diff)
        self.assertAlmostEquals(0, res)
        return
예제 #8
0
    def testGenerator(self):
        qmax = 27.0
        gen = PDFGenerator()
        gen.setScatteringType('N')
        self.assertEqual('N', gen.getScatteringType())
        gen.setQmax(qmax)
        self.assertAlmostEqual(qmax, gen.getQmax())
        from diffpy.Structure import PDFFitStructure
        stru = PDFFitStructure()
        ciffile = datafile("ni.cif")
        stru.read(ciffile)
        for i in range(4):
            stru[i].Bisoequiv = 1
        gen.setStructure(stru)

        calc = gen._calc
        # Test parameters
        for par in gen.iterPars(recurse = False):
            pname = par.name
            defval = calc._getDoubleAttr(pname)
            self.assertEquals(defval, par.getValue())
            # Test setting values
            par.setValue(1.0)
            self.assertEquals(1.0, par.getValue())
            par.setValue(defval)
            self.assertEquals(defval, par.getValue())

        r = numpy.arange(0, 10, 0.1)
        y = gen(r)

        # Now create a reference PDF. Since the calculator is testing its
        # output, we just have to make sure we can calculate from the
        # PDFGenerator interface.
        from diffpy.srreal.pdfcalculator import PDFCalculator
        calc = PDFCalculator()
        calc.rstep = r[1] - r[0]
        calc.rmin = r[0]
        calc.rmax = r[-1] + 0.5 * calc.rstep
        calc.qmax = qmax
        calc.setScatteringFactorTableByType('N')
        calc.eval(stru)
        yref = calc.pdf

        diff = y - yref
        res = numpy.dot(diff, diff)
        self.assertAlmostEquals(0, res)
        return
예제 #9
0
    def parseLines(self, lines):
        """Parse list of lines in DISCUS format.

        Return PDFFitStructure instance or raise StructureFormatError.
        """
        self.lines = lines
        ilines = self._linesIterator()
        self.stru = PDFFitStructure()
        record_parsers = {
            "cell": self._parse_cell,
            "format": self._parse_format,
            "generator": self._parse_not_implemented,
            "molecule": self._parse_not_implemented,
            "ncell": self._parse_ncell,
            "spcgr": self._parse_spcgr,
            "symmetry": self._parse_not_implemented,
            "title": self._parse_title,
            "shape": self._parse_shape,
        }
        try:
            # parse header
            for self.line in ilines:
                words = self.line.split()
                if not words or words[0][0] == "#":
                    continue
                if words[0] == "atoms":
                    break
                rp = record_parsers.get(words[0], self._parse_unknown_record)
                rp(words)
            # check if cell has been defined
            if not self.cell_read:
                emsg = "%d: unit cell not defined" % self.nl
                raise StructureFormatError(emsg)
            # parse atoms
            for self.line in ilines:
                words = self.line.replace(",", " ").split()
                if not words or words[0][0] == "#":
                    continue
                self._parse_atom(words)
            # self consistency check
            exp_natoms = reduce(lambda x, y: x * y, self.stru.pdffit["ncell"])
            # only check if ncell record exists
            if self.ncell_read and exp_natoms != len(self.stru):
                emsg = "Expected %d atoms, read %d." % (exp_natoms, len(self.stru))
                raise StructureFormatError(emsg)
            # take care of superlattice
            if self.stru.pdffit["ncell"][:3] != [1, 1, 1]:
                latpars = list(self.stru.lattice.abcABG())
                superlatpars = [latpars[i] * self.stru.pdffit["ncell"][i] for i in range(3)] + latpars[3:]
                superlattice = Lattice(*superlatpars)
                self.stru.placeInLattice(superlattice)
                self.stru.pdffit["ncell"] = [1, 1, 1, exp_natoms]
        except (ValueError, IndexError):
            exc_type, exc_value, exc_traceback = sys.exc_info()
            emsg = "%d: file is not in DISCUS format" % self.nl
            raise StructureFormatError, emsg, exc_traceback
        return self.stru
예제 #10
0
    def copy(self, other=None):
        """copy self to other. if other is None, create an instance

        other -- ref to other object

        returns reference to copied object
        """
        if other is None:
            other = PDFStructure(self.name)
        for a in PDFFitStructure().__dict__:
            setattr(other, a, copy.deepcopy(getattr(self, a)))
        other[:] = copy.deepcopy(self[:])
        return other
예제 #11
0
    def toLines(self, stru):
        """Convert Structure stru to a list of lines in PDFfit format.

        Return list of strings.
        """
        # build the stru_pdffit dictionary initialized from the defaults
        # in PDFFitStructure
        stru_pdffit = PDFFitStructure().pdffit
        if stru.pdffit:
            stru_pdffit.update(stru.pdffit)
        lines = []
        # default values of standard deviations
        d_sigxyz = numpy.zeros(3, dtype=float)
        d_sigo = 0.0
        d_sigU = numpy.zeros((3, 3), dtype=float)
        # here we can start
        l = "title  " + stru.title
        lines.append(l.strip())
        lines.append("format pdffit")
        lines.append("scale  %9.6f" % stru_pdffit["scale"])
        lines.append("sharp  %9.6f, %9.6f, %9.6f, %9.6f" %
                     (stru_pdffit["delta2"], stru_pdffit["delta1"],
                      stru_pdffit["sratio"], stru_pdffit["rcut"]))
        lines.append("spcgr   " + stru_pdffit["spcgr"])
        if stru_pdffit.get('spdiameter', 0.0) > 0.0:
            line = 'shape   sphere, %g' % stru_pdffit['spdiameter']
            lines.append(line)
        if stru_pdffit.get('stepcut', 0.0) > 0.0:
            line = 'shape   stepcut, %g' % stru_pdffit['stepcut']
            lines.append(line)
        lat = stru.lattice
        lines.append("cell   %9.6f, %9.6f, %9.6f, %9.6f, %9.6f, %9.6f" %
                     (lat.a, lat.b, lat.c, lat.alpha, lat.beta, lat.gamma))
        lines.append("dcell  %9.6f, %9.6f, %9.6f, %9.6f, %9.6f, %9.6f" %
                     tuple(stru_pdffit["dcell"]))
        lines.append("ncell  %9i, %9i, %9i, %9i" % (1, 1, 1, len(stru)))
        lines.append("atoms")
        for a in stru:
            ad = a.__dict__
            lines.append(
                "%-4s %17.8f %17.8f %17.8f %12.4f" %
                (a.element.upper(), a.xyz[0], a.xyz[1], a.xyz[2], a.occupancy))
            sigmas = numpy.concatenate(
                (ad.get("sigxyz", d_sigxyz), [ad.get("sigo", d_sigo)]))
            lines.append("    %18.8f %17.8f %17.8f %12.4f" % tuple(sigmas))
            sigU = ad.get("sigU", d_sigU)
            Uii = (a.U[0][0], a.U[1][1], a.U[2][2])
            Uij = (a.U[0][1], a.U[0][2], a.U[1][2])
            sigUii = (sigU[0][0], sigU[1][1], sigU[2][2])
            sigUij = (sigU[0][1], sigU[0][2], sigU[1][2])
            lines.append("    %18.8f %17.8f %17.8f" % Uii)
            lines.append("    %18.8f %17.8f %17.8f" % sigUii)
            lines.append("    %18.8f %17.8f %17.8f" % Uij)
            lines.append("    %18.8f %17.8f %17.8f" % sigUij)
        return lines
예제 #12
0
    def read(self, filename, format='auto'):
        """Load structure from a file, raise ControlFileError for invalid
        or unknown structure format.

        filename -- file to be loaded
        format   -- structure format such as 'pdffit', 'pdb', 'xyz'.  When
                    'auto' all available formats are tried in a row.

        Return instance of StructureParser used to load the data.
        See Structure.read() for more info.
        """
        from diffpy.Structure import StructureFormatError
        try:
            p = PDFFitStructure.read(self, filename, format)
        except StructureFormatError, err:
            import os.path
            emsg = "Unable to read file '%s'\n%s." % (
                    os.path.basename(filename), err)
            raise ControlFileError(emsg)
예제 #13
0
    def read(self, filename, format='auto'):
        """Load structure from a file, raise ControlFileError for invalid
        or unknown structure format.

        filename -- file to be loaded
        format   -- structure format such as 'pdffit', 'pdb', 'xyz'.  When
                    'auto' all available formats are tried in a row.

        Return instance of StructureParser used to load the data.
        See Structure.read() for more info.
        """
        from diffpy.Structure import StructureFormatError
        try:
            p = PDFFitStructure.read(self, filename, format)
        except StructureFormatError, err:
            import os.path
            emsg = "Unable to read file '%s'\n%s." % (
                    os.path.basename(filename), err)
            raise ControlFileError(emsg)
예제 #14
0
    def parseLines(self, lines):
        """Parse list of lines in PDFfit format.

        Return Structure object or raise StructureFormatError.
        """
        p_nl = 0
        rlist = []
        try:
            self.stru = PDFFitStructure()
            stru = self.stru
            cell_line_read = False
            stop = len(lines)
            while stop > 0 and lines[stop - 1].strip() == "":
                stop -= 1
            ilines = iter(lines[:stop])
            # read header of PDFFit file
            for l in ilines:
                p_nl += 1
                words = l.split()
                if len(words) == 0 or words[0][0] == '#':
                    continue
                elif words[0] == 'title':
                    stru.title = l.lstrip()[5:].strip()
                elif words[0] == 'scale':
                    stru.pdffit['scale'] = float(words[1])
                elif words[0] == 'sharp':
                    l1 = l.replace(',', ' ')
                    sharp_pars = [float(w) for w in l1.split()[1:]]
                    if len(sharp_pars) < 4:
                        stru.pdffit['delta2'] = sharp_pars[0]
                        stru.pdffit['sratio'] = sharp_pars[1]
                        stru.pdffit['rcut'] = sharp_pars[2]
                    else:
                        stru.pdffit['delta2'] = sharp_pars[0]
                        stru.pdffit['delta1'] = sharp_pars[1]
                        stru.pdffit['sratio'] = sharp_pars[2]
                        stru.pdffit['rcut'] = sharp_pars[3]
                elif words[0] == 'spcgr':
                    key = 'spcgr'
                    start = l.find(key) + len(key)
                    value = l[start:].strip()
                    stru.pdffit['spcgr'] = value
                elif words[0] == 'shape':
                    self._parse_shape(l)
                elif words[0] == 'cell':
                    cell_line_read = True
                    l1 = l.replace(',', ' ')
                    latpars = [float(w) for w in l1.split()[1:7]]
                    stru.lattice = Lattice(*latpars)
                elif words[0] == 'dcell':
                    l1 = l.replace(',', ' ')
                    stru.pdffit['dcell'] = [float(w) for w in l1.split()[1:7]]
                elif words[0] == 'ncell':
                    l1 = l.replace(',', ' ')
                    stru.pdffit['ncell'] = [int(w) for w in l1.split()[1:5]]
                elif words[0] == 'format':
                    if words[1] != 'pdffit':
                        emsg = "%d: file is not in PDFfit format" % p_nl
                        raise StructureFormatError(emsg)
                elif words[0] == 'atoms' and cell_line_read:
                    break
                else:
                    self.ignored_lines.append(l)
            # Header reading finished, check if required lines were present.
            if not cell_line_read:
                emsg = "%d: file is not in PDFfit format" % p_nl
                raise StructureFormatError(emsg)
            # Load data from atom entries.
            p_natoms = reduce(lambda x, y: x * y, stru.pdffit['ncell'])
            # we are now inside data block
            for l in ilines:
                p_nl += 1
                wl1 = l.split()
                element = wl1[0][0].upper() + wl1[0][1:].lower()
                xyz = [float(w) for w in wl1[1:4]]
                occ = float(wl1[4])
                stru.addNewAtom(element, xyz=xyz, occupancy=occ)
                a = stru.getLastAtom()
                p_nl += 1
                wl2 = ilines.next().split()
                a.sigxyz = [float(w) for w in wl2[0:3]]
                a.sigo = float(wl2[3])
                p_nl += 1
                wl3 = ilines.next().split()
                p_nl += 1
                wl4 = ilines.next().split()
                p_nl += 1
                wl5 = ilines.next().split()
                p_nl += 1
                wl6 = ilines.next().split()
                a.sigU = numpy.zeros((3, 3), dtype=float)
                a.U11 = float(wl3[0])
                a.U22 = float(wl3[1])
                a.U33 = float(wl3[2])
                a.sigU[0, 0] = float(wl4[0])
                a.sigU[1, 1] = float(wl4[1])
                a.sigU[2, 2] = float(wl4[2])
                a.U12 = float(wl5[0])
                a.U13 = float(wl5[1])
                a.U23 = float(wl5[2])
                a.sigU[0, 1] = a.sigU[1, 0] = float(wl6[0])
                a.sigU[0, 2] = a.sigU[2, 0] = float(wl6[1])
                a.sigU[1, 2] = a.sigU[2, 1] = float(wl6[2])
            if len(stru) != p_natoms:
                emsg = "expected %d atoms, read %d" % (p_natoms, len(stru))
                raise StructureFormatError(emsg)
            if stru.pdffit['ncell'][:3] != [1, 1, 1]:
                superlatpars = [
                    latpars[i] * stru.pdffit['ncell'][i] for i in range(3)
                ] + latpars[3:]
                superlattice = Lattice(*superlatpars)
                stru.placeInLattice(superlattice)
                stru.pdffit['ncell'] = [1, 1, 1, p_natoms]
        except (ValueError, IndexError):
            emsg = "%d: file is not in PDFfit format" % p_nl
            exc_type, exc_value, exc_traceback = sys.exc_info()
            raise StructureFormatError, emsg, exc_traceback
        return stru
예제 #15
0
class P_discus(StructureParser):
    """Parser for DISCUS structure format.  The parser chokes
    on molecule and generator records.
    """

    def __init__(self):
        StructureParser.__init__(self)
        self.format = "discus"
        # helper variables
        self.nl = None
        self.lines = None
        self.line = None
        self.stru = None
        self.ignored_lines = []
        self.cell_read = False
        self.ncell_read = False
        return

    def parseLines(self, lines):
        """Parse list of lines in DISCUS format.

        Return PDFFitStructure instance or raise StructureFormatError.
        """
        self.lines = lines
        ilines = self._linesIterator()
        self.stru = PDFFitStructure()
        record_parsers = {
            "cell" : self._parse_cell,
            "format" : self._parse_format,
            "generator" : self._parse_not_implemented,
            "molecule" : self._parse_not_implemented,
            "ncell" : self._parse_ncell,
            "spcgr" : self._parse_spcgr,
            "symmetry" : self._parse_not_implemented,
            "title" : self._parse_title,
            "shape" : self._parse_shape,
        }
        try:
            # parse header
            for self.line in ilines:
                words = self.line.split()
                if not words or words[0][0] == '#': continue
                if words[0] == 'atoms':             break
                rp = record_parsers.get(words[0], self._parse_unknown_record)
                rp(words)
            # check if cell has been defined
            if not self.cell_read:
                emsg = "%d: unit cell not defined" % self.nl
                raise StructureFormatError(emsg)
            # parse atoms
            for self.line in ilines:
                words = self.line.replace(',', ' ').split()
                if not words or words[0][0] == '#': continue
                self._parse_atom(words)
            # self consistency check
            exp_natoms = reduce(lambda x,y : x*y, self.stru.pdffit['ncell'])
            # only check if ncell record exists
            if self.ncell_read and exp_natoms != len(self.stru):
                emsg = 'Expected %d atoms, read %d.' % \
                    (exp_natoms, len(self.stru))
                raise StructureFormatError(emsg)
            # take care of superlattice
            if self.stru.pdffit['ncell'][:3] != [1,1,1]:
                latpars = list(self.stru.lattice.abcABG())
                superlatpars = [ latpars[i]*self.stru.pdffit['ncell'][i]
                                 for i in range(3) ] + latpars[3:]
                superlattice = Lattice(*superlatpars)
                self.stru.placeInLattice(superlattice)
                self.stru.pdffit['ncell'] = [1, 1, 1, exp_natoms]
        except (ValueError, IndexError):
            exc_type, exc_value, exc_traceback = sys.exc_info()
            emsg = "%d: file is not in DISCUS format" % self.nl
            raise StructureFormatError, emsg, exc_traceback
        return self.stru
    # End of parseLines

    def toLines(self, stru):
        """Convert Structure stru to a list of lines in DISCUS format.
        Return list of strings.
        """
        self.stru = stru
        # if necessary, convert self.stru to PDFFitStructure
        if not isinstance(stru, PDFFitStructure):
            self.stru = PDFFitStructure(stru)
        # build the stru_pdffit dictionary initialized from the defaults
        # in PDFFitStructure
        stru_pdffit = PDFFitStructure().pdffit
        if stru.pdffit:
            stru_pdffit.update(stru.pdffit)
        # here we can start
        self.lines = lines = []
        lines.append( "title   " + self.stru.title.strip() )
        lines.append( "spcgr   " + stru_pdffit["spcgr"] )
        if stru_pdffit.get('spdiameter', 0.0) > 0.0:
            line = 'shape   sphere, %g' % stru_pdffit['spdiameter']
            lines.append(line)
        if stru_pdffit.get('stepcut', 0.0) > 0.0:
            line = 'shape   stepcut, %g' % stru_pdffit['stepcut']
            lines.append(line)
        lines.append( "cell   %9.6f, %9.6f, %9.6f, %9.6f, %9.6f, %9.6f" %
                self.stru.lattice.abcABG() )
        lines.append( "ncell  %9i, %9i, %9i, %9i" % (1, 1, 1, len(self.stru)) )
        lines.append( "atoms" )
        for a in self.stru:
            lines.append( "%-4s %17.8f %17.8f %17.8f %12.4f" % (
                a.element.upper(), a.xyz[0], a.xyz[1], a.xyz[2], a.Bisoequiv))
        return lines
    # End of toLines

    def _linesIterator(self):
        """Iterator over self.lines, which increments self.nl
        """
        # ignore trailing empty lines
        stop = len(self.lines)
        while stop > 0 and self.lines[stop-1].strip() == "":
            stop -= 1
        self.nl = 0
        # read header of PDFFit file
        for self.line in self.lines[:stop]:
            self.nl += 1
            yield self.line
        # end of _linesIterator

    def _parse_cell(self, words):
        """Process the cell record from DISCUS structure file.
        """
        # split again on spaces or commas
        words = self.line.replace(',', ' ').split()
        latpars = [ float(w) for w in words[1:7] ]
        try:
            self.stru.lattice.setLatPar(*latpars)
        except ZeroDivisionError:
            emsg = "%d: Invalid lattice parameters - zero cell volume" % \
                    self.nl
            raise StructureFormatError(emsg)
        self.cell_read = True
        return

    def _parse_format(self, words):
        """Process the format record from DISCUS structure file.
        """
        if words[1] == 'pdffit':
            emsg = "%d: file is not in DISCUS format" % self.nl
            raise StructureFormatError(emsg)
        return

    def _parse_ncell(self, words):
        """Process the ncell record from DISCUS structure file.
        """
        # split again on spaces or commas
        words = self.line.replace(',', ' ').split()
        self.stru.pdffit['ncell'] = [ int(w) for w in words[1:5] ]
        self.ncell_read = True
        return

    def _parse_spcgr(self, words):
        """Process the spcgr record from DISCUS structure file.
        """
        self.stru.pdffit['spcgr'] = ''.join(words[1:])
        return

    def _parse_title(self, words):
        """Process the title record from DISCUS structure file.
        """
        self.stru.title = self.line.lstrip()[5:].strip()
        return

    def _parse_shape(self, words):
        """Process the shape record from DISCUS structure file.
        """
        # strip away any commas
        linefixed = " ".join(words).replace(',', ' ')
        wordsfixed = linefixed.split()
        shapetype = wordsfixed[1]
        if shapetype == 'sphere':
            self.stru.pdffit['spdiameter'] = float(words[2])
        elif shapetype == 'stepcut':
            self.stru.pdffit['stepcut'] = float(words[2])
        else:
            emsg = 'Invalid type of particle shape correction %r' % shapetype
            raise StructureFormatError, emsg
        return

    def _parse_atom(self, words):
        """Process atom records in DISCUS structure file.
        """
        element = words[0][0:1].upper() + words[0][1:].lower()
        xyz = [float(w) for w in words[1:4]]
        Biso = float(words[4])
        self.stru.addNewAtom(element, xyz)
        a = self.stru.getLastAtom()
        a.Bisoequiv = Biso
        return

    def _parse_unknown_record(self, words):
        """Process unknown record in DISCUS structure file.
        Silently ignores the line and adds it to self.ignored_lines
        Raises StructureFormatError.
        """
        self.ignored_lines.append(self.line)
        return

    def _parse_not_implemented(self, words):
        """Process the unimplemented records from DISCUS structure file.
        Raises NotImplementedError.
        """
        emsg = "%d: reading of DISCUS record %r is not implemented." % \
                (self.nl, words[0])
        raise NotImplementedError(emsg)