2
from theochempy._theochempy import Measure
3
from theochempy._theochempy import Units
4
from theochempy._theochempy.Chemistry import PeriodicTable
6
__all__ = ['ParseError', 'XYZFile']
8
class ParseError(Exception): pass
17
def __init__(self, filename = None):
18
self._filename = filename
24
f=file(self._filename,"r")
26
STATE_START, STATE_NUM_ATOMS, STATE_COMMENT, STATE_ATOM_ROW = range(4)
30
for line_num, line in enumerate(f):
31
m = re.search("^\s*\d+\s*$", line)
33
if state == STATE_START or state == STATE_ATOM_ROW:
34
current_molecule = Molecule()
35
self._molecules.append(current_molecule)
36
state = STATE_NUM_ATOMS
39
raise ParseError("Found number of atoms at invalid position, line %d, file %s. " % (line_num, filename))
42
m = re.search("^\s*([A-Z]+[a-z]*[a-z]*)\s+(-?\d*\.\d+)\s*(-?\d*\.\d+)\s*(-?\d*\.\d+)\s+$", line)
44
if state == STATE_COMMENT or state == STATE_ATOM_ROW:
45
element = PeriodicTable.getElementBySymbol(m.group(1))
47
raise ParseError("Invalid element symbol %s at line %d, file %s" % (m.group(1), line_num, filename))
49
position = Measure.Measure( ( float(m.group(2)), float(m.group(3)), float(m.group(4))), Units.angstrom )
51
current_molecule.atom_list.append( (element, position) )
52
state = STATE_ATOM_ROW
55
raise ParseError("Found atom line at invalid position, line %d, file %s. " % (line_num, filename))
57
m = re.search("^\s*.*\s*$", line)
59
if state == STATE_NUM_ATOMS:
60
current_molecule.comment = line.strip()
64
raise ParseError("Found comment line at invalid position, line %d, file $s. " % (line_num, filename))
68
def comment(self, molecule_index=-1):
69
if len(self._molecules) == 0:
71
return self._molecules[molecule_index].comment
73
def numOfMolecules(self):
74
return len(self._molecules)
76
def numOfAtoms(self, molecule_index=-1):
77
if len(self._molecules) == 0:
79
return len(self._molecules[molecule_index].atom_list)
81
def atom(self, *args):
86
molecule_index = args[0]
89
raise TypeError("Invalid number of arguments %d" % len(args))
91
if len(self._molecules) == 0:
93
return self._molecules[molecule_index].atom_list[atom_index]
96
def createMolecule(self, molecule_index=None):
97
current_molecule = Molecule()
99
if molecule_index is None:
100
self._molecules.append(current_molecule)
101
return len(self._molecules)-1
103
self._molecules.insert(molecule_index, current_molecule)
104
return molecule_index
107
def setComment(self, *args):
112
molecule_index = args[0]
115
raise TypeError("Invalid number of arguments %d" % len(args))
117
self._molecules[molecule_index].comment = comment
120
def addAtom(self, *args):
125
molecule_index = args[0]
128
raise TypeError("Invalid number of arguments %d" % len(args))
130
self._molecules[molecule_index].atom_list.append(atom)
132
def setAtom(self, *args):
138
molecule_index = args[0]
142
raise TypeError("Invalid number of arguments %d" % len(args))
143
self._molecules[molecule_index].atom_list[atom_index] = atom
145
def saveTo(self, filename):
146
f = file(filename, "w")
147
for molecule in self._molecules:
148
f.write(" %d\n" % len(molecule.atom_list))
149
f.write("%s\n" % molecule.comment)
150
for atom in molecule.atom_list:
151
element, coordinate = atom
152
coordinate_angstromg = coordinate.asUnit(Units.angstrom)
153
f.write("%s %20.10f %20.10f %20.10f\n" % (element.symbol(), coordinate_angstromg.value()[0], coordinate_angstromg.value()[1], coordinate_angstromg.value()[2]))