def __getAtoms(self): """Build the atom list for the molecule """ molecule = self.__molecule file = self.__fd file.toBOF() ret = file.findString("Atoms and basis sets") if ret == '': raise ParseError("Keyword not found 'Atoms and basis sets'") file.skipLines(2) line = file.readline() molecule.numOfAtomTypes = int( re.compile("Number of atom types:\s*([0-9]+)").search(line).group( 1)) line = file.readline() molecule.numOfAtoms = int( re.compile("Total number of atoms:\s*([0-9]+)").search(line).group( 1)) # O 1 8 42 30 [10s5p2d1f|4s3p2d1f] file.skipLines(3) regexp = re.compile( "^\s*(.+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\[.*\])\s+") for i in xrange(0, self.__molecule.numOfAtomTypes): line = file.readline() res = regexp.match(line) numForThisAtomType = int(res.group(2)) for j in xrange(0, numForThisAtomType): atom = Atom() atom.symbol = res.group(1) atom.charge = int(res.group(3)) atom.primitives = int(res.group(4)) atom.contracted = int(res.group(5)) atom.basis = res.group(6) molecule.atomList.append(atom)
def __readSymmetry(self): self.__symmetries=[] check=['X','Y','Z','XY','XZ','YZ','XYZ'] f = self.__infile f.toBOF() f.findString("&symmetry") if f.isAtEOF(): # no symmetry section return line=f.readline() self.__symmetries=line.upper().split() for k in self.__symmetries: if k not in check: raise ParseError('Unknown symmetry key %s' % k, f.name,f.currentPos()+1)
def __readBasis(self): # {{{ basOptions=[] # no options for now self.__basis={} f = self.__infile f.toBOF() linetuple=f.findRegexp("^\s*\[\s*basis.*\]\s*$") line=linetuple[0] if f.isAtEOF(): # no basis section ? how weird return optionsDict = self.__buildOptionsDict(line,basOptions) regexp1 = re.compile("^\s*(\d*)\s+(.*)\s*$") regexp2 = re.compile("^\s*([a-zA-Z]\w*)\s+(.*)\s*$") regexp3 = re.compile("^\s*"+re.escape("*")+"\s+(.*)\s*$") line = f.readline() while not (f.isAtEOF() or line.strip()[0] == '['): line=string.strip(line) if line == '' or line[0] == "#": line = f.readline() continue match1 = regexp1.match(line) match2 = regexp2.match(line) match3 = regexp3.match(line) if match1 != None: # the assignment to an id theid = int(match1.group(1)) if theid > len(self.__zmatrixparser.zmatrix()) or theid < 1: raise ParseError('Wrong id parameter %d' % int(theid), f.name,f.currentPos()+1) if not self.__basis.has_key(theid): self.__basis[theid]=match1.group(2) elif match2 != None: theatom = match2.group(1) list=[] for atom in self.__zmatrixparser: if atom[self.AtomListSymbol].lower() == theatom.lower(): list.append(int(atom[self.AtomListId])) for i in list: if not self.__basis.has_key(i): self.__basis[i]=match2.group(2) elif match3 != None: #print "matched all" for i in xrange(1,len(self.__zmatrixparser.zmatrix())+1): if not self.__basis.has_key(i): self.__basis[i]=match3.group(1) line = f.readline()
def __readBasis(self): f = self.__infile f.toBOF() f.findString("&basis") if f.isAtEOF(): # no basis section return # this re search for key = anything self.__basis={} regexp1 = re.compile("^\s*(\d*)\s+(.*)\s*$") regexp2 = re.compile("^\s*([a-zA-Z]\w*)\s+(.*)\s*$") regexp3 = re.compile("^\s*"+re.escape("*")+"\s+(.*)\s*$") line = f.readline() while not (f.isAtEOF() or line[0] == '&'): line=string.strip(line) if line == '' or line[0] == "#": line = f.readline() continue match1 = regexp1.match(line) match2 = regexp2.match(line) match3 = regexp3.match(line) if match1 != None: # the assignment to an id theid = int(match1.group(1)) if theid > len(self.__zmatrix) or theid < 1: raise ParseError('Wrong id parameter %d' % int(theid), f.name,f.currentPos()+1) if not self.__basis.has_key(theid): self.__basis[theid]=match1.group(2) elif match2 != None: theatom = match2.group(1) list=[] for atom in self.__zmatrix: if atom[self.AtomListSymbol].lower() == theatom.lower(): list.append(int(atom[self.AtomListId])) for i in list: if not self.__basis.has_key(i): self.__basis[i]=match2.group(2) elif match3 != None: #print "matched all" for i in xrange(1,len(self.__zmatrix)+1): if not self.__basis.has_key(i): self.__basis[i]=match3.group(1) line = f.readline()
def __readSymmetry(self): # {{{ self.__symmetries=[] check=['X','Y','Z','XY','XZ','YZ','XYZ'] f = self.__infile f.toBOF() linetuple=f.findRegexp("^\s*\[\s*symmetry.*\]\s*$") line=linetuple[0] if f.isAtEOF(): # no symmetry section return symOptions=[] # no options for now optionsDict = self.__buildOptionsDict(line,symOptions) line=f.readline() self.__symmetries=line.upper().split() for k in self.__symmetries: if k not in check: raise ParseError('Unknown symmetry key %s' % k, f.name,f.currentPos()+1)
def __readSymmetry(self): self.__symmetries=[] check=['X','Y','Z','XY','XZ','YZ','XYZ'] f = self.__infile f.toBOF() f.findString("[symmetry") if f.isAtEOF(): # no symmetry section return line=f.readline() while not (f.isAtEOF() or line[0] == '['): line=string.strip(line) if line == '' or line[0] == "#": line = f.readline() continue self.__symmetries=line.upper().split() for k in self.__symmetries: if k not in check: raise ParseError('Unknown symmetry key %s' % k, f.name,f.currentPos()+1) line=f.readline()
def __cartesianCoords(self): cart=[] for currentAtom in self.__zmatrix: carttmp=[] if self.__zmatrix.index(currentAtom) == 0: # first atom, place in the center if self.__basis.has_key( int(currentAtom[self.AtomListId]) ): basis = self.__basis[ int(currentAtom[self.AtomListId] ) ] else: basis = '' #print '-> basis ',basis,' ', int(currentAtom[self.AtomListId]) cart.append( (currentAtom[self.AtomListSymbol], Vector(0.0,0.0,0.0), basis)) elif self.__zmatrix.index(currentAtom) == 1: # the second atom. Place along the z axis at the bond distance if self.__basis.has_key( int(currentAtom[self.AtomListId]) ): basis = self.__basis[ int(currentAtom[self.AtomListId] ) ] else: basis = '' #print '-> basis ',basis,' ', int(currentAtom[self.AtomListId]) cart.append( (currentAtom[self.AtomListSymbol], Vector(0.0, 0.0, float(currentAtom[self.AtomListBondValue])), basis)) elif self.__zmatrix.index(currentAtom) == 2: # {{{ # third atom. copy into a temporary buffer the cart position of 1 and 2 # WARNING: atom 1 for zmatrix enumeration is element 0 in the cartesian list # so always decrease indexes by one. Also remember that zmatrix storagement is # per-string. Id's are strings, distances and angles too... always convert to # int or float to manage idx = int(currentAtom[self.AtomListBondId])-1 carttmp.append( deepcopy(cart[idx]) ) idx = int(currentAtom[self.AtomListAngleId])-1 carttmp.append( deepcopy(cart[idx]) ) # center the bond reference angle # now carttmp holds: # in position 0 the bond lenght reference atom # in position 1 the angle reference atom # choose the first atom and set as the center of the world # create a new tuple object with the cartesian parameters firstAtom=carttmp[0] firstAtomCoords=firstAtom[1] secondAtom=carttmp[1] secondAtomCoords=secondAtom[1] newcenter = (firstAtomCoords.x(), firstAtomCoords.y(), firstAtomCoords.z()) # remember: newcenter is a tuple for xyz # translate each atom by carttmp for atom in carttmp: atom[1].translate(-newcenter[0],-newcenter[1],-newcenter[2]) # keep the translated transformation, to revert it later translation=(newcenter[0],newcenter[1],newcenter[2]) # done... now carttmp holds the translated elements. # please note that firstAtom and secondAtom are a reference in the # list carttmp, so they get updated too. # now work on the second atom, rotate the whole carttmp so to have # the second atom on z # the length of zy ryz=math.sqrt(secondAtomCoords.y()**2+secondAtomCoords.z()**2) if ryz > 1e-10: # the cosine of the angle rapp=secondAtomCoords.z()/ryz # choose the correct quadrant sign=1 if secondAtomCoords.y() < 0: sign=-1 xangle=sign*math.acos(rapp) else: if secondAtomCoords.y() < 0: xangle=math.pi else: xangle=0.0 # now rotate along x for atom in carttmp[:]: atom[1].rotateX(-xangle) # do the same on the y axis # the lenght of xz rxz=math.sqrt(secondAtomCoords.x()**2+secondAtomCoords.z()**2) if rxz > 1e-10 : # the cosine of the angle rapp=secondAtomCoords.z()/rxz # choose the correct quadrant sign=1 if secondAtomCoords.x() < 0: sign=-1 yangle=sign*math.acos(rapp) else: if secondAtomCoords.x() < 0: yangle=math.pi else: yangle=0.0 # now rotate along y for atom in carttmp: atom[1].rotateY(-yangle) # keep the rotation transformation close at hand, to revert it later rotation=(xangle, yangle, 0.0) # it's time to place our new atom vec=Vector(0.0, 0.0, float(currentAtom[self.AtomListBondValue])) angle=float(currentAtom[self.AtomListAngleValue])*math.pi/180 vec.rotateX(angle) # ok.. time to backtransform and regain the position against the # original system. Rotate only the current atom vector, since # we no longer care about the other atoms. vec.rotateY(rotation[1]) vec.rotateX(rotation[0]) vec.translate(translation[0],translation[1],translation[2]) # time to add the atom to our cartesian list if self.__basis.has_key( int(currentAtom[self.AtomListId]) ): basis = self.__basis[ int(currentAtom[self.AtomListId] ) ] else: basis = '' #print '-> basis ',basis,' ', int(currentAtom[self.AtomListId]) cart.append( (currentAtom[self.AtomListSymbol], vec, basis)) # }}} elif self.__zmatrix.index(currentAtom) >= 3: # {{{ # ok... the same as for index = 2, plus the dihedral rotation # cut and paste of the previous section, stripped of the comments # should we merge with the previous case ? idx = int(currentAtom[self.AtomListBondId])-1 carttmp.append( deepcopy(cart[idx]) ) idx = int(currentAtom[self.AtomListAngleId])-1 carttmp.append( deepcopy(cart[idx]) ) # add the dihedral reference angle idx = int(currentAtom[self.AtomListDihedralId])-1 carttmp.append( deepcopy(cart[idx]) ) # now carttmp holds: # in position 2 the dihedral reference atom firstAtom=carttmp[0] firstAtomCoords=firstAtom[1] secondAtom=carttmp[1] secondAtomCoords=secondAtom[1] thirdAtom=carttmp[2] thirdAtomCoords=thirdAtom[1] newcenter = (firstAtomCoords.x(), firstAtomCoords.y(), firstAtomCoords.z()) for atom in carttmp: atom[1].translate(-newcenter[0],-newcenter[1],-newcenter[2]) translation=(newcenter[0],newcenter[1],newcenter[2]) ryz=math.sqrt(secondAtomCoords.y()**2+secondAtomCoords.z()**2) if ryz > 1e-10: rapp=secondAtomCoords.z()/ryz sign=1 if secondAtomCoords.y() < 0: sign=-1 xangle=sign*math.acos(rapp) else: if secondAtomCoords.y() < 0: xangle=math.pi else: xangle=0.0 for atom in carttmp: atom[1].rotateX(-xangle) rxz=math.sqrt(secondAtomCoords.x()**2+secondAtomCoords.z()**2) if rxz > 1e-10 : rapp=secondAtomCoords.z()/rxz sign=1 if secondAtomCoords.x() < 0: sign=-1 yangle=sign*math.acos(rapp) else: if secondAtomCoords.x() < 0: yangle=math.pi else: yangle=0.0 for atom in carttmp: atom[1].rotateY(-yangle) # now we need to rotate the atoms along the z axis so the third # atom is on the yz plane rxy=math.sqrt(thirdAtomCoords.x()**2+thirdAtomCoords.y()**2) if rxy > 1e-10 : rapp=thirdAtomCoords.y()/rxy sign=1 if thirdAtomCoords.x() < 0: sign=-1 zangle=sign*math.acos(rapp) else: raise ParseError('Third atom %d is collinear with %d and %d at specification for atom %d' % (int(currentAtom[self.AtomListDihedralId]), int(currentAtom[self.AtomListBondId]), int(currentAtom[self.AtomListAngleId]), int(currentAtom[self.AtomListId])) ,None,None) for atom in carttmp: atom[1].rotateZ(-zangle) rotation=(xangle, yangle, zangle) # it's time to place our new atom vec=Vector(0.0, 0.0, float(currentAtom[self.AtomListBondValue])) angle=float(currentAtom[self.AtomListAngleValue])*math.pi/180 vec.rotateX(angle) angle=float(currentAtom[self.AtomListDihedralValue])*math.pi/180 vec.rotateZ(angle) vec.rotateZ(rotation[2]) vec.rotateY(rotation[1]) vec.rotateX(rotation[0]) vec.translate(translation[0],translation[1],translation[2]) if self.__basis.has_key( int(currentAtom[self.AtomListId]) ): basis = self.__basis[ int(currentAtom[self.AtomListId] ) ] else: basis = '' #print '-> basis ',basis,' ', int(currentAtom[self.AtomListId]) cart.append( (currentAtom[self.AtomListSymbol], vec, basis)) # }}} return cart
def __readZMat(self): pt=ptable.PTable() self.__zmatrix=[] f = self.__infile currentRead=0 f.toBOF() f.findString("[zmatrix") if f.isAtEOF(): raise ParseError('Unable to find [zmatrix] section',f.name,f.currentPos()+1) line = f.readline() # AtomSymbol IdentifierNum [id distance [id angle [id dihedral]]] while not (f.isAtEOF() or line[0] == '['): line=string.strip(line) if line == '' or line[0] == "#": # the line is empty or a comment... skip line = f.readline() continue currentRead=currentRead+1 # call the replacement function. It replaces occurences of parameters into the # zmatrix. btw.. what about this sub into the parameters list itself? line = self.__parseParameters(line) elems=line.split() expectedElems=currentRead*2 if expectedElems > 8: expectedElems = 8 if len(elems) != expectedElems: print line raise ParseError('Wrong format. Expected elements %d found %d' % (expectedElems, len(elems)),f.name,f.currentPos()+1) # parse the consistency of the line # does the atomtype exists? if pt.getElementBySymbol(elems[self.AtomListSymbol]) == None: raise ParseError('Unknown atom type %s' % elems[self.AtomListSymbol],f.name,f.currentPos()+1) # the current identifier must match the currentRead parameter try: theid=int(elems[self.AtomListId]) except ValueError: raise ParseError('Non integer value as id at field 2' ,f.name,f.currentPos()+1) if int(elems[self.AtomListId]) != currentRead: raise ParseError('Error in identifier. Expected %d, found %d.' % (currentRead, int(elems[self.AtomListId])),f.name,f.currentPos()+1) # for each identifier check if its' integer and lower than the # current identifier num (but greater than one! :)), and also if # the associated data is numeric temp=[] for i in range(2,expectedElems,2): try: theid=int(elems[i]) except ValueError: raise ParseError('Non integer value as id at field %d' % (i+1) ,f.name,f.currentPos()+1) # check if there's no duplicated id in this line try: temp.index(theid) except ValueError: pass else: raise ParseError('Duplicated id at field %d' % (i+1) ,f.name,f.currentPos()+1) temp.append(theid) try: theval=float(elems[i+1]) except ValueError: raise ParseError('Non numeric value given as parameter at field %d' % (i+2), f.name,f.currentPos()+1) if theid < 1 or theid >= currentRead: raise ParseError('Wrong id parameter at field %d' % (i+1), f.name,f.currentPos()+1) # ok... the line seems valid. # Pack the line in a tuple and add to an array self.__zmatrix.append(tuple(elems)) #print tuple(elems) # new line and restart line = f.readline()
def __readZMat(self): # {{{ # the mighty parser object. He knows everything self.__zmatrixparser = zmatrixparser.ZMatrixParser() f = self.__infile f.toBOF() linetuple=f.findRegexp("^\s*\[\s*zmatrix.*\]\s*$") line=linetuple[0] if f.isAtEOF(): raise ParseError('Unable to find [zmatrix] section',f.name,f.currentPos()+1) zmatOptions=("distanceunit", "angleunit", "dihedralunit", "format") optionsDict = self.__buildOptionsDict(line,zmatOptions) zmatrixbegin = f.currentPos()+1 # {{{ check the distance unit flag if optionsDict.has_key('distanceunit'): if optionsDict['distanceunit'] == 'angstrom': self.__zmatrixparser.setDistanceUnit(zmatrixparser.ZMatrixParser.Unit_DistanceAngstrom) elif optionsDict['distanceunit'] == 'bohr': self.__zmatrixparser.setDistanceUnit(zmatrixparser.ZMatrixParser.Unit_DistanceBohr) else: raise ParseError('Unknown value for key distanceunit in [zmatrix] section',f.name,f.currentPos()+1) else: self.__zmatrixparser.setDistanceUnit(zmatrixparser.ZMatrixParser.Unit_DistanceBohr) # }}} # {{{ check the angle unit flag if optionsDict.has_key('angleunit'): if optionsDict['angleunit'] == 'radians': self.__zmatrixparser.setAngleUnit(zmatrixparser.ZMatrixParser.Unit_AngleRadians) elif optionsDict['angleunit'] == 'degrees': self.__zmatrixparser.setAngleUnit(zmatrixparser.ZMatrixParser.Unit_AngleDegrees) else: raise ParseError('Unknown value for key angleunit in [zmatrix] section',f.name,f.currentPos()+1) else: self.__zmatrixparser.setAngleUnit(zmatrixparser.ZMatrixParser.Unit_AngleDegrees) # }}} # {{{ check the dihedral unit flag if optionsDict.has_key('dihedralunit'): if optionsDict['dihedralunit'] == 'radians': self.__zmatrixparser.setDihedralUnit(zmatrixparser.ZMatrixParser.Unit_DihedralRadians) elif optionsDict['dihedralunit'] == 'degrees': self.__zmatrixparser.setDihedralUnit(zmatrixparser.ZMatrixParser.Unit_DihedralDegrees) else: raise ParseError('Unknown value for key dihedralunit in [zmatrix] section',f.name,f.currentPos()+1) else: self.__zmatrixparser.setDihedralUnit(zmatrixparser.ZMatrixParser.Unit_DihedralDegrees) # }}} # {{{ check the format flag if optionsDict.has_key('format'): if optionsDict['format'] == 'internal': self.__zmatrixparser.setFormat(zmatrixparser.ZMatrixParser.Format_Internal) elif optionsDict['format'] == 'gaussian': self.__zmatrixparser.setFormat(zmatrixparser.ZMatrixParser.Format_Gaussian) elif optionsDict['format'] == 'dalton': self.__zmatrixparser.setFormat(zmatrixparser.ZMatrixParser.Format_Dalton) else: raise ParseError('Unknown value for key format in [zmatrix] section',f.name,f.currentPos()+1) else: self.__zmatrixparser.setFormat(zmatrixparser.ZMatrixParser.Format_Internal) # }}} zmat=[] line = f.readline().strip() while not (f.isAtEOF() or line[0] == '['): if line == '' or line[0] == "#": # the line is empty or a comment... skip line = f.readline().strip() continue # call the replacement function. It replaces occurences of # parameters into the zmatrix. line = self.__parseParameters(line) # append the line in a tuple that will be fed into our parser object zmat = zmat + [line] line = f.readline().strip() try: self.__zmatrixparser.parse(zmat) except ZMatrixParser.ParseException, e: raise ParseError('Error type %d in [zmatrix] section: %s' % (e.code, e.message),f.name,zmatrixbegin+e.line+1)
def __getVibrational(self): """ parse and read the vibrational section for the current molecule. Note that the format of this section in dalton 1.2 is Eigenvalues of mass-weighted Hessian ------------------------------------ Column 1 Column 2 Column 3 Column 4 1 1.279649E-42 1.279649E-42 4.094095E-04 9.790871E-44 Column 5 Column 6 1 9.790871E-44 -1.212226E-21 Normal coordinates in Cartesian basis ------------------------------------- Column 1 Column 2 Column 3 Column 4 1 0.02333068 0.00000000 0.00000000 0.00000000 2 0.00000000 0.02333068 0.00000000 0.00000000 3 0.00000000 0.00000000 0.02273544 0.00000000 4 0.00000000 0.00000000 0.00000000 0.00537355 6 0.00000000 0.00000000 -0.00120607 0.00000000 Column 5 Column 6 3 0.00000000 0.00523645 5 0.00537355 0.00000000 6 0.00000000 0.00523645 So note that - informations are represented in blocks of 4 columns at a time. - rows which have zero values for each column aren't written """ file = self.__fd file.toEOF() line = file.findString("Eigenvalues of mass-weighted Hessian", 1, 1) if line == '': return file.skipLines(4) degOfFreedom = self.__molecule.numOfAtoms * 3 # in the above example, 2 blocks, one made with 4 columns, # the other made of 2 columns numOfBlocks = (degOfFreedom + 3) / 4 # how many columns make the last block, in the above case 2 # (the columns 5 and 6) lastLineEntries = degOfFreedom % 4 if lastLineEntries == 0: lastLineEntries = 4 eigenvalues = [] for i in xrange(0, numOfBlocks): columns = 4 if i == numOfBlocks - 1: # is the last block columns = lastLineEntries restring = "^\s+\d*\s+" for j in xrange(0, columns): restring = restring + "(-?\d\.\d+[DdEe][+-]\d\d)" if j == columns - 1: restring = restring + "\s*$" else: restring = restring + "\s+" regexp = re.compile(restring) line = file.readline() res = regexp.search(line) transl = string.maketrans('dD', 'ee') for j in xrange(0, columns): eigenvalues.append( float(string.translate(res.group(j + 1), transl))) file.skipLines(2) # get the normal modes line = file.findString("Normal coordinates in Cartesian basis") if line == '': raise ParseError( "Unable to find keyword 'Normal coordinates in Cartesian basis'" ) file.skipLines(4) eigenvectors = [] for i in xrange(0, numOfBlocks): columns = 4 eig = [] if i == numOfBlocks - 1: # is the last block columns = lastLineEntries restring = "^\s+(\d+)\s+" for j in xrange(0, columns): restring = restring + "(-?\d\.\d+)" if j == columns - 1: restring = restring + "\s*$" else: restring = restring + "\s+" regexp = re.compile(restring) for j in xrange(0, columns): eig.append([]) lastExistingEntry = 0 j = 0 while j < degOfFreedom: line = file.readline() res = regexp.search(line) if res == None: # this means that we are at the end but some of the # remaining data misses 'cause they are zero for k in xrange(lastExistingEntry, degOfFreedom): for l in xrange(0, columns): eig[l].append(0.0) break else: if int(res.group(1)) != j + 1: # a number was skipped in the dalton printout, # because the printing routine automatically # eat lines with all zeroes. We need the zeroes, # so we take control over the line-by-line reading # routine and place the missing zeroes for k in xrange(lastExistingEntry + 1, int(res.group(1))): for l in xrange(0, columns): eig[l].append(0.0) j = j + 1 for l in xrange(0, columns): eig[l].append( float(string.translate(res.group(l + 2), transl))) lastExistingEntry = int(res.group(1)) j = j + 1 # finished reading the block... put the eigenvectors # in the array for l in xrange(0, columns): eigenvectors.append(eig[l]) # and step to the next block file.skipLines(2) # pack them into normalMode objects for i in xrange(0, degOfFreedom): normalmode = NormalMode() normalmode.frequency = math.sqrt(abs(eigenvalues[i])) if eigenvalues[i] < 0: normalmode.frequency = -normalmode.frequency normalmode.coordinates = eigenvectors[i] self.__molecule.normalModeList.append(normalmode) # sort the NormalMode list self.__molecule.normalModeList.sort(normalModeSort)
def __getGeometry(self): # get the starting geometry file = self.__fd file.toBOF() ret = file.findString("Cartesian Coordinates") if ret == '': raise ParseError("Keyword not found 'Cartesian Coordinates'") file.skipLines(5) # catches 1 O x 0.0000000000 # and also 7 H 1 x 0.0000000000 regexp1 = re.compile("^\s+\d+\s+.+\s+.+\s+x\s+(-?\d+\.\d+)\s*") # catches 2 y 0.0000000000 regexp2 = re.compile("^\s+\d+\s+[yz]\s*(-?\d+\.\d+)\s*") geometry = Geometry() self.__molecule.geometryList.append(geometry) for i in xrange(0, self.__molecule.numOfAtoms): pos = Position() line = file.readline() res = regexp1.search(line) pos.x = float(res.group(1)) line = file.readline() res = regexp2.search(line) pos.y = float(res.group(1)) line = file.readline() res = regexp2.search(line) pos.z = float(res.group(1)) geometry.posList.append(pos) file.readline() # get the energy ret = file.findRegexp("^\s*Final\s+.*\senergy:\s*(-\d+\.\d+)\s*$") if ret[0] == '': raise ParseError('No Final energy in this output') geometry.energy = float(ret[1][0]) # try to get other geometries from the optimization save = file.currentPos() ret = file.findString("Next geometry (au)") if ret == '': # there are no other geometries return file.toPos(save) geolist = file.occurrences("Next geometry (au)") for i in geolist: file.toPos(i) file.skipLines(2) regexp = re.compile( "^\s+.*\s+\d*\s+(-?\d+\.\d+)\s+(-?\d+\.\d+)\s+(-?\d+\.\d+)\s*$" ) geometry = Geometry() self.__molecule.geometryList.append(geometry) for j in xrange(0, self.__molecule.numOfAtoms): pos = Position() line = file.readline() res = regexp.search(line) pos.x = float(res.group(1)) pos.y = float(res.group(2)) pos.z = float(res.group(3)) geometry.posList.append(pos) # catch the subsequent energy ret = file.findRegexp("^\s*Final\s+.*\senergy:\s*(-\d+\.\d+)\s*$") if ret[0] == '': raise ParseError( 'No Final energy in this output during optimization, pos %d' % i) geometry.energy = float(ret[1][0])