Source code for diffpy.structure.parsers.p_xyz

#!/usr/bin/env python
##############################################################################
#
# diffpy.structure  by DANSE Diffraction group
#                   Simon J. L. Billinge
#                   (c) 2007 trustees of the Michigan State University.
#                   All rights reserved.
#
# File coded by:    Pavol Juhas
#
# See AUTHORS.txt for a list of people who contributed.
# See LICENSE_DANSE.txt for license information.
#
##############################################################################

"""Parser for XYZ file format, where

    * First line gives number of atoms.
    * Second line has optional title.
    * Remaining lines contain element, `x, y, z`.
"""

import sys

from diffpy.structure import Structure
from diffpy.structure.parsers import StructureParser
from diffpy.structure.structureerrors import StructureFormatError


[docs] class P_xyz(StructureParser): """Parser for standard XYZ structure format. Attributes ---------- format : str Format name, default "xyz". """ def __init__(self): StructureParser.__init__(self) self.format = "xyz" return
[docs] def parseLines(self, lines): """Parse list of lines in XYZ format. Parameters ---------- lines : list of str List of lines in XYZ format. Returns ------- Structure Parsed structure instance. Raises ------ StructureFormatError Invalid XYZ format. """ linefields = [line.split() for line 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 # first valid line gives number of atoms try: lfs = linefields[start] w1 = linefields[start][0] if len(lfs) == 1 and str(int(w1)) == w1: p_natoms = int(w1) stru.title = lines[start + 1].strip() start += 2 else: emsg = "%d: invalid XYZ format, missing number of atoms" % (start + 1) raise StructureFormatError(emsg) except (IndexError, ValueError): exc_type, exc_value, exc_traceback = sys.exc_info() emsg = "%d: invalid XYZ format, missing number of atoms" % (start + 1) e = StructureFormatError(emsg) raise e.with_traceback(exc_traceback) # 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 p_natoms == 0 or start >= stop: return stru # here we have at least one valid record line nfields = len(linefields[start]) if nfields != 4: emsg = "%d: invalid XYZ format, expected 4 columns" % (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 = fields[0] element = element[0].upper() + element[1:].lower() xyz = [float(f) for f in fields[1:4]] stru.addNewAtom(element, xyz=xyz) except ValueError: exc_type, exc_value, exc_traceback = sys.exc_info() emsg = "%d: invalid number format" % p_nl e = StructureFormatError(emsg) raise e.with_traceback(exc_traceback) # finally check if all the atoms have been read if p_natoms is not None and len(stru) != p_natoms: emsg = "expected %d atoms, read %d" % (p_natoms, len(stru)) raise StructureFormatError(emsg) return stru
[docs] def toLines(self, stru): """Convert Structure stru to a list of lines in XYZ format. Parameters ---------- stru : Structure Structure to be converted. Returns ------- list of str List of lines in XYZ format. """ lines = [] lines.append(str(len(stru))) lines.append(stru.title) for a in stru: rc = a.xyz_cartn s = "%-3s %g %g %g" % (a.element, rc[0], rc[1], rc[2]) lines.append(s) return lines
# End of class P_xyz # Routines -------------------------------------------------------------------
[docs] def getParser(): """Return new `parser` object for XYZ format. Returns ------- P_xcfg Instance of `P_xyz`. """ return P_xyz()