#A* ------------------------------------------------------------------- #B* This file contains source code for the PyMOL computer program #C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific. #D* ------------------------------------------------------------------- #E* It is unlawful to modify or remove this copyright notice. #F* ------------------------------------------------------------------- #G* Please see the accompanying LICENSE file for further information. #H* ------------------------------------------------------------------- #I* Additional authors of this source file include: #-* Scott Dixon, Metaphorics, LLC #-* #-* #Z* ------------------------------------------------------------------- from chempy import feedback import string import copy default_extra = { # atomic number, and normal valency (for tinker) # NOTE: THIS SET IS ONLY USED IF THERE ARE NO TINKER RECORDS # IN THE PARAMETER FILE # bromine 'BR' : [ 35 , 1 ], # carbon 'C' : [ 6 , 3 ], 'CA' : [ 6 , 3 ], 'CB' : [ 6 , 3 ], 'CC' : [ 6 , 3 ], 'CF' : [ 6 , 3 ], 'CK' : [ 6 , 3 ], 'CM' : [ 6 , 3 ], 'CN' : [ 6 , 3 ], 'CQ' : [ 6 , 3 ], 'CR' : [ 6 , 3 ], 'CT' : [ 6 , 4 ], 'CV' : [ 6 , 3 ], 'CW' : [ 6 , 3 ], 'CY' : [ 6 , 2 ], 'CX' : [ 6 , 2 ], 'C5' : [ 6 , 3 ], 'C*' : [ 6 , 3 ], # calcium 'C0' : [ 20 , 3 ], # chloride 'Cl' : [ 17 , 1 ], # fluorine 'F' : [ 9 , 1 ], # hydrogen 'H' : [ 1 , 1 ], 'H1' : [ 1 , 1 ], 'H2' : [ 1 , 1 ], 'H3' : [ 1 , 1 ], 'H4' : [ 1 , 1 ], 'H5' : [ 1 , 1 ], 'HA' : [ 1 , 1 ], 'HC' : [ 1 , 1 ], 'HO' : [ 1 , 1 ], 'HP' : [ 1 , 1 ], 'HS' : [ 1 , 1 ], 'HW' : [ 1 , 2 ], # iodine 'I' : [ 53 , 1 ], # chloride anion 'IM' : [ 17 , 0 ], # sodium cation 'IP' : [ 11 , 0 ], # magnesium 'MG' : [ 12 , 0 ], # nitrogen 'N' : [ 7 , 3 ], 'N*' : [ 7 , 2 ], 'N2' : [ 7 , 3 ], 'N3' : [ 7 , 4 ], 'NA' : [ 7 , 3 ], 'NB' : [ 7 , 2 ], 'NC' : [ 7 , 2 ], 'NX' : [ 7 , 2 ], 'NZ' : [ 7 , 3 ], # 'OW' : [ 8 , 2 ], 'OH' : [ 8 , 2 ], 'OS' : [ 8 , 2 ], 'O' : [ 8 , 1 ], 'O2' : [ 8 , 1 ], 'OM' : [ 8 , 1 ], 'OZ' : [ 8 , 1 ], 'P' : [ 15 , 4 ], 'S' : [ 16 , 2 ], 'SO' : [ 16 , 4 ], 'SX' : [ 16 , 2 ], 'SH' : [ 16 , 2 ], # copper 'CU' : [ 29 , 0 ], # iron 'FE' : [ 26 , 0 ], # lithium 'Li' : [ 3 , 0 ], # potassium 'K' : [ 19 , 0 ], # rubidium 'Rb' : [ 37 , 0 ], # cesium 'Cs' : [ 55 , 0 ], # calcium (alternate) 'Ca' : [ 20 , 0 ], # dummy 'X ' : [ 6 , 1 ], # zinc 'Z0' : [ 30 , 0 ], 'Z4' : [ 30 , 4 ], 'Z5' : [ 30 , 5 ], } class Parameters: def __init__(self,fname): if feedback['actions']: print ' '+str(self.__class__)+': loading from "%s"...' % fname f = open(fname) # skip l = f.readline() # read names & molecular weights self.type = [] self.mw = {} while 1: l = string.strip(f.readline()) if not len(l): break a2 = string.strip(l[0:2]) self.type.append(a2) self.mw[a2] = [float(l[3:13]),string.strip(l[34:])] # skip 1 l = f.readline() # read bonds self.bond = {} while 1: l = string.strip(f.readline()) if not len(l): break a5 = l[0:5] self.bond[a5] = [float(l[5:12]),float(l[12:22]), string.strip(l[22:])] # read angles self.angle = {} while 1: l = string.strip(f.readline()) if not len(l): break a5 = l[0:8] self.angle[a5] = [float(l[8:16]),float(l[16:28]), string.strip(l[28:])] # read torsion self.torsion = {} while 1: l = string.strip(f.readline()) if not len(l): break a5 = l[0:11] if self.torsion.has_key(a5): self.torsion[a5].extend( [int(l[11:15]), float(l[15:27]), float(l[27:36]), abs(int(float(l[40:52]))), string.strip(l[52:])]) else: self.torsion[a5] = [int(l[11:15]), float(l[15:27]), float(l[27:36]), abs(int(float(l[40:52]))), string.strip(l[52:])] # read impropers self.improper = {} while 1: l = string.strip(f.readline()) if not len(l): break a5 = l[0:11] self.improper[a5] = [float(l[15:27]), float(l[27:40]), abs(int(float(l[40:51]))), string.strip(l[51:])] # skip while 1: l = string.strip(f.readline()) if not len(l): break # read vdw equivalents self.vdw_eq = {} while 1: l = string.strip(f.readline()) if not len(l): break a4 = string.strip(l[0:4]) l = l[4:] while len(l): self.vdw_eq[string.strip(l[0:4])] = a4 l = l[4:] # skip l = string.strip(f.readline()) # read vdw parameters self.vdw = {} while 1: l = string.strip(f.readline()) if not len(l): break l = ' ' + l a4 = string.strip(l[0:4]) self.vdw[a4] = [float(l[4:20]), float(l[20:37]), string.strip(l[37:])] # read extra tinker information if present self.extra = {} while 1: l = f.readline() if not l: break if l[0:6] == 'TINKER': self.extra[string.strip(l[6:12])] = [ int(l[12:18]), int(l[18:24])] if not len(self.extra.keys()): self.extra = default_extra # now generate redundant equivalents for a in self.vdw_eq.keys(): self.vdw[a] = self.vdw[self.vdw_eq[a]] for a in self.bond.keys(): k = a[3:5]+'-'+a[0:2] self.bond[k] = self.bond[a] for a in self.angle.keys(): k = a[6:8]+'-'+a[3:5]+'-'+a[0:2] self.angle[k] = self.angle[a] def dump(self): for b in self.type: print b kees = self.mw.keys() kees.sort() for b in kees: print b,self.mw[b] kees = self.vdw_eq.keys() kees.sort() for b in kees: print b,self.vdw_eq[b] kees = self.vdw.keys() kees.sort() for b in kees: print b,self.vdw[b] kees = self.bond.keys() kees.sort() for b in kees: print b,self.bond[b] kees = self.angle.keys() kees.sort() for b in kees: print b,self.angle[b] kees = self.torsion.keys() kees.sort() for b in kees: print b,self.torsion[b] kees = self.improper.keys() kees.sort() for b in kees: print b,self.improper[b] kees = self.vdw.keys() kees.sort() for b in kees: print b,self.vdw[b] class Topology: def __init__(self,model): self.model = model if feedback['actions']: print ' '+str(self.__class__)+': searching...' # get a connected version too cmodel = copy.deepcopy(model).convert_to_connected() # find atom types in molecule self.present = {} for a in model.atom: self.present[a.text_type] = 1 # copy bonds self.bond = {} for b in model.bond: a0 = b.index[0] a1 = b.index[1] if a0 < a1: self.bond[(a0,a1)] = 1 else: self.bond[(a1,a0)] = 1 # find angles self.angle = {} ang = self.angle for b in model.bond: a0 = b.index[0] a1 = b.index[1] for c in cmodel.bond[a0]: # a0 in center a2 = c.index[0] if a2 not in (a0,a1): # outside atom if a1 < a2: an = (a1,a0,a2) else: an = (a2,a0,a1) ang[an] = 1 a2 = c.index[1] if a2 not in (a0,a1): # outside atom if a1 < a2: an = (a1,a0,a2) else: an = (a2,a0,a1) ang[an] = 1 for c in cmodel.bond[a1]: # a1 in center a2 = c.index[0] if a2 not in (a0,a1): # outside atom if a0 < a2: an = (a0,a1,a2) else: an = (a2,a1,a0) ang[an] = 1 a2 = c.index[1] if a2 not in (a0,a1): # outside atom if a0 < a2: an = (a0,a1,a2) else: an = (a2,a1,a0) ang[an] = 1 # find torsions self.torsion = {} tors = self.torsion for b in model.bond: # use bond as center of torsion a1 = b.index[0] a2 = b.index[1] for c in cmodel.bond[a1]: a0 = c.index[0] if a0 not in (a1,a2): # outside atom for d in cmodel.bond[a2]: a3 = d.index[0] if a3 not in (a0,a1,a2): # outside atom if a0 < a3: to = (a0,a1,a2,a3) else: to = (a3,a2,a1,a0) tors[to] = 1 a3 = d.index[1] if a3 not in (a0,a1,a2): # outside atom if a0 < a3: to = (a0,a1,a2,a3) else: to = (a3,a2,a1,a0) tors[to] = 1 a0 = c.index[1] if a0 not in (a1,a2): # outside atom for d in cmodel.bond[a2]: a3 = d.index[0] if a3 not in (a0,a1,a2): # outside atom if a0 < a3: to = (a0,a1,a2,a3) else: to = (a3,a2,a1,a0) tors[to] = 1 a3 = d.index[1] if a3 not in (a0,a1,a2): # outside atom if a0 < a3: to = (a0,a1,a2,a3) else: to = (a3,a2,a1,a0) tors[to] = 1 # find impropers (only autogenerates for atoms with 3 bonds) self.improper = {} impr = self.improper a2 = 0 for a in model.atom: # a2 is the center atom bnd = cmodel.bond[a2] if len(bnd) == 3: lst = [] for b in bnd: at = b.index[0] if at == a2: at = b.index[1] lst.append(at) lst.sort() impr[(lst[0],lst[1],a2,lst[2])] = 1 a2 = a2 + 1 if feedback['actions']: print ' '+str(self.__class__)+': found:' print ' '+str(self.__class__)+': types %6d' % ( len(self.present.keys())) print ' '+str(self.__class__)+': bonds %6d' % ( len(self.bond.keys())) print ' '+str(self.__class__)+': angles %6d' % ( len(self.angle.keys())) print ' '+str(self.__class__)+': torsions %6d' % ( len(self.torsion.keys())) print ' '+str(self.__class__)+': impropers %6d' % ( len(self.improper.keys())) def dump(self): kees = self.present.keys() kees.sort() for b in kees: print b kees = self.bond.keys() kees.sort() for b in kees: print b kees = self.angle.keys() kees.sort() for b in kees: print b kees = self.torsion.keys() kees.sort() for b in kees: print b kees = self.improper.keys() kees.sort() for b in kees: print b def get_list(self): return [self.bond.keys(), self.angle.keys(), self.torsion.keys(), self.improper.keys()] class Subset: def __init__(self,par,top): if feedback['actions']: print ' '+str(self.__class__)+': applying parameter set to topology...' self.model = top.model self.present = copy.deepcopy(top.present) atype = [] for a in self.model.atom: atype.append(a.text_type) # extra tinker info (atomic number, valency) self.miss_extra = [] self.extra = {} s_extra = self.extra present = top.present p_extra = par.extra for kee in present.keys(): if p_extra.has_key(kee): s_extra[kee] = p_extra[kee] else: self.miss_extra.append(kee) # molecular weight self.miss_mw = [] self.mw = {} s_mw = self.mw present = top.present p_mw = par.mw for kee in present.keys(): if p_mw.has_key(kee): s_mw[kee] = p_mw[kee] else: self.miss_mw.append(kee) # van der waals self.miss_vdw = [] self.vdw = {} s_vdw = self.vdw present = top.present p_vdw = par.vdw for kee in present.keys(): if p_vdw.has_key(kee): s_vdw[kee] = p_vdw[kee] else: self.miss_vdw.append(kee) # bonds self.miss_bond = [] self.bond = {} s_bond = self.bond bond = top.bond p_bond = par.bond for a in bond.keys(): kee = "%-2s-%-2s" % (atype[a[0]],atype[a[1]]) if p_bond.has_key(kee): s_bond[kee] = p_bond[kee] else: self.miss_bond.append((a,kee)) # angles self.miss_angle = [] self.angle = {} s_angle = self.angle angle = top.angle p_angle = par.angle for a in angle.keys(): kee = "%-2s-%-2s-%-2s" % (atype[a[0]],atype[a[1]],atype[a[2]]) if p_angle.has_key(kee): s_angle[kee] = p_angle[kee] else: self.miss_angle.append((a,kee)) # torsions self.miss_torsion = [] self.torsion = {} s_torsion = self.torsion torsion = top.torsion p_torsion = par.torsion for a in torsion.keys(): at0=atype[a[0]] at1=atype[a[1]] at2=atype[a[2]] # center atom at3=atype[a[3]] while 1: # not a real loop, just "else" avoidance kee1 = "%-2s-%-2s-%-2s-%-2s" % (at0,at1,at2,at3) if p_torsion.has_key(kee1): s_torsion[kee1] = p_torsion[kee1] break kee2 = "%-2s-%-2s-%-2s-%-2s" % (at3,at2,at1,at0) if p_torsion.has_key(kee2): s_torsion[kee2] = p_torsion[kee2] break kee = "X -%-2s-%-2s-X " % (at1,at2) if p_torsion.has_key(kee): s_torsion[kee1] = p_torsion[kee] break kee = "X -%-2s-%-2s-X " % (at2,at1) if p_torsion.has_key(kee): s_torsion[kee2] = p_torsion[kee] break self.miss_torsion.append((a,kee1)) break # impropers self.miss_improper = [] self.improper = {} s_improper = self.improper improper = top.improper p_improper = par.improper for a in improper.keys(): at0=atype[a[0]] at1=atype[a[1]] at2=atype[a[2]] # center atom at3=atype[a[3]] while 1: # not a real loop, just "else" avoidance kee1 = "%-2s-%-2s-%-2s-%-2s" % (at1,at3,at2,at0) if p_improper.has_key(kee1): s_improper[kee1] = p_improper[kee1] break kee2 = "%-2s-%-2s-%-2s-%-2s" % (at3,at1,at2,at0) if p_improper.has_key(kee2): s_improper[kee2] = p_improper[kee2] break kee3 = "%-2s-%-2s-%-2s-%-2s" % (at0,at3,at2,at1) if p_improper.has_key(kee3): s_improper[kee3] = p_improper[kee3] break kee4 = "%-2s-%-2s-%-2s-%-2s" % (at3,at0,at2,at1) if p_improper.has_key(kee4): s_improper[kee4] = p_improper[kee4] break kee5 = "%-2s-%-2s-%-2s-%-2s" % (at0,at1,at2,at3) if p_improper.has_key(kee5): s_improper[kee5] = p_improper[kee5] break kee6 = "%-2s-%-2s-%-2s-%-2s" % (at1,at0,at2,at3) if p_improper.has_key(kee6): s_improper[kee6] = p_improper[kee6] break kee = "X -%-2s-%-2s-%-2s" % (at3,at2,at0) if p_improper.has_key(kee): s_improper[kee1] = p_improper[kee] break kee = "X -%-2s-%-2s-%-2s" % (at1,at2,at0) if p_improper.has_key(kee): s_improper[kee2] = p_improper[kee] break kee = "X -%-2s-%-2s-%-2s" % (at3,at2,at1) if p_improper.has_key(kee): s_improper[kee3] = p_improper[kee] break kee = "X -%-2s-%-2s-%-2s" % (at0,at2,at1) if p_improper.has_key(kee): s_improper[kee4] = p_improper[kee] break kee = "X -%-2s-%-2s-%-2s" % (at1,at2,at3) if p_improper.has_key(kee): s_improper[kee5] = p_improper[kee] break kee = "X -%-2s-%-2s-%-2s" % (at0,at2,at3) if p_improper.has_key(kee): s_improper[kee6] = p_improper[kee] break kee = "X -X -%-2s-%-2s" % (at2,at0) if p_improper.has_key(kee): s_improper[kee1] = p_improper[kee] break kee = "X -X -%-2s-%-2s" % (at2,at1) if p_improper.has_key(kee): s_improper[kee3] = p_improper[kee] break kee = "X -X -%-2s-%-2s" % (at2,at3) if p_improper.has_key(kee): s_improper[kee5] = p_improper[kee] break self.miss_improper.append((a,kee1)) break if feedback['actions']: print ' '+str(self.__class__)+': missing:' print ' '+str(self.__class__)+': mol. wts. %6d' % ( len(self.miss_mw)) print ' '+str(self.__class__)+': vdw %6d' % ( len(self.miss_vdw)) print ' '+str(self.__class__)+': bonds %6d' % ( len(self.miss_bond)) print ' '+str(self.__class__)+': angles %6d' % ( len(self.miss_angle)) print ' '+str(self.__class__)+': torsions %6d' % ( len(self.miss_torsion)) print ' '+str(self.__class__)+': impropers %6d (usually okay)' % ( len(self.miss_improper)) print ' '+str(self.__class__)+': extra tinker info %6d' % ( len(self.miss_extra)) def dump(self): kees = self.mw.keys() kees.sort() for b in kees: print b,self.mw[b] kees = self.bond.keys() kees.sort() for b in kees: print b,self.bond[b] kees = self.angle.keys() kees.sort() for b in kees: print b,self.angle[b] kees = self.torsion.keys() kees.sort() for b in kees: print b,self.torsion[b] kees = self.improper.keys() kees.sort() for b in kees: print b,self.improper[b] kees = self.vdw.keys() kees.sort() for b in kees: print b,self.vdw[b] def dump_missing(self,impropers=0): if len(self.miss_mw): print ' '+str(self.__class__)+': missing molecular weights...' for b in self.miss_mw: print " ",b if len(self.miss_vdw): print ' '+str(self.__class__)+': missing van der Waalss...' for b in self.miss_vdw: print " ",b if len(self.miss_bond): print ' '+str(self.__class__)+': missing bonds...' for b in self.miss_bond: print " ",b if len(self.miss_angle): print ' '+str(self.__class__)+': missing angless...' for b in self.miss_angle: print " ",b if len(self.miss_torsion): print ' '+str(self.__class__)+': missing torsions...' for b in self.miss_torsion: print " ",b if impropers: if len(self.miss_improper): print ' '+str(self.__class__)+': missing impropers...' for b in self.miss_improper: print " ",b def complete(self): if not ( len(self.miss_mw) or len(self.miss_vdw) or len(self.miss_bond) or len(self.miss_angle) or len(self.miss_torsion) ): return 1 else: return 0 def assign_types(self): c = 0 self.mapping = {} map = self.mapping kees = self.present.keys() label = [] type = [] kees.sort() for a in kees: c = c + 1 st = str(c) label.append(st) type.append(a) map[a] = st # assign numeric types for a in self.model.atom: a.numeric_type = map[a.text_type] def write_tinker_prm(self,fname,proofread=None,smooth=None): c = 0 self.mapping = {} map = self.mapping kees = self.present.keys() label = [] type = [] kees.sort() if proofread: for a in kees: label.append(a) type.append(a) map[a] = a else: for a in kees: c = c + 1 st = str(c) label.append(st) type.append(a) map[a] = st # assign numeric types as per the parameter we're writing for a in self.model.atom: a.numeric_type = map[a.text_type] f = open(fname,'w') if smooth: f.write(''' forcefield SMOOTH AMBER vdwtype GAUSSIAN gausstype LJ-2 ''') else: f.write(''' forcefield AMBER95 vdwtype LENNARD-JONES ''') f.write(''' radiusrule ARITHMETIC radiustype R-MIN radiussize RADIUS epsilonrule GEOMETRIC vdw-14-use vdw-scale 2.0 chg-14-use chg-scale 1.2 dielectric 1.0 ''') # types for c in range(len(self.present)): at = type[c] f.write("atom %6s %6s %-2s %-25s %3d %10.3f%6d\n" % ( label[c],label[c],at,'"'+self.mw[at][1][0:23]+'"', self.extra[at][0], self.mw[at][0],self.extra[at][1])) # van der waals for c in range(len(self.present)): at = type[c] f.write("vdw %8s %10.4f %10.4f\n" % ( map[at],self.vdw[at][0],self.vdw[at][1])) # bonds bond = {} for a in self.bond.keys(): kee = (map[string.strip(a[0:2])],map[string.strip(a[3:5])]) bond[kee] = a kees = bond.keys() kees.sort() for a in kees: kee = bond[a] f.write("bond %6s%5s %10.1f %10.4f\n" % ( a[0],a[1],self.bond[kee][0],self.bond[kee][1])) # angles angle = {} for a in self.angle.keys(): kee = (map[string.strip(a[0:2])], map[string.strip(a[3:5])], map[string.strip(a[6:8])], ) angle[kee] = a kees = angle.keys() kees.sort() for a in kees: kee = angle[a] f.write("angle %5s%5s%5s%9.2f %8.2f\n" % ( a[0],a[1],a[2],self.angle[kee][0],self.angle[kee][1])) # impropers if not smooth: improper = {} for a in self.improper.keys(): kee = (map[string.strip(a[0:2])], map[string.strip(a[3:5])], map[string.strip(a[6:8])], map[string.strip(a[9:11])], ) improper[kee] = a kees = improper.keys() kees.sort() for a in kees: kee = improper[a] f.write("imptors %5s%5s%5s%5s %10.3f%7.1f%3d\n" % ( a[0],a[1],a[2],a[3],self.improper[kee][0], self.improper[kee][1],self.improper[kee][2])) else: improper = {} for a in self.improper.keys(): kee = (map[string.strip(a[0:2])], map[string.strip(a[3:5])], map[string.strip(a[6:8])], map[string.strip(a[9:11])], ) improper[kee] = a kees = improper.keys() kees.sort() for a in kees: kee = improper[a] f.write("improper %5s%5s%5s%5s %10.2f 0.00\n" % ( a[2],a[0],a[1],a[3],self.improper[kee][0]*3.5)) # torsions torsion = {} for a in self.torsion.keys(): kee = (map[string.strip(a[0:2])], map[string.strip(a[3:5])], map[string.strip(a[6:8])], map[string.strip(a[9:11])], ) torsion[kee] = a kees = torsion.keys() kees.sort() for a in kees: kee = torsion[a] st = "torsion %5s%5s%5s%5s " % ( a[0],a[1],a[2],a[3]) lst = self.torsion[kee] div = lst[0] lst = lst[1:] while len(lst): st = st + "%10.3f%7.1f%3d " % ( lst[0]/div,lst[1],lst[2]) lst = lst[5:] while len(st)>79: st = string.replace(st,' ',' ') f.write(st+"\n") # null charge records for c in range(len(self.present)): a = label[c] f.write("charge %6s %10.4f\n" % (a,0.0)) f.close() def get_list(self): list = [] c = 0 self.mapping = {} map = self.mapping kees = self.present.keys() label = [] type = [] kees.sort() for a in kees: c = c + 1 st = str(c) type.append(a) map[a] = c # assign numeric types as per the parameter we're writing for a in self.model.atom: a.numeric_type = map[a.text_type] # types typ_list = [] for c in range(len(self.present)): at = type[c] typ_list.append((map[at],self.extra[at][0],self.mw[at][0],self.extra[at][1])) list.append(typ_list) # van der waals vdw_list = [] for c in range(len(self.present)): at = type[c] vdw_list.append((map[at],self.vdw[at][0],self.vdw[at][1])) list.append(vdw_list) # bonds bnd_list = [] bond = {} for a in self.bond.keys(): kee = (map[string.strip(a[0:2])],map[string.strip(a[3:5])]) bond[kee] = a kees = bond.keys() kees.sort() for a in kees: kee = bond[a] bnd_list.append((a[0],a[1],self.bond[kee][0],self.bond[kee][1])) list.append(bnd_list) # angles ang_list = [] angle = {} for a in self.angle.keys(): kee = (map[string.strip(a[0:2])], map[string.strip(a[3:5])], map[string.strip(a[6:8])], ) angle[kee] = a kees = angle.keys() kees.sort() for a in kees: kee = angle[a] ang_list.append((a[0],a[1],a[2],self.angle[kee][0],self.angle[kee][1])) list.append(ang_list) # impropers imp_list = [] improper = {} for a in self.improper.keys(): kee = (map[string.strip(a[0:2])], map[string.strip(a[3:5])], map[string.strip(a[6:8])], map[string.strip(a[9:11])], ) improper[kee] = a kees = improper.keys() kees.sort() for a in kees: kee = improper[a] imp_list.append((a[0],a[1],a[2],a[3],self.improper[kee][0], self.improper[kee][1],self.improper[kee][2])) list.append(imp_list) # torsions tor_list = [] torsion = {} for a in self.torsion.keys(): kee = (map[string.strip(a[0:2])], map[string.strip(a[3:5])], map[string.strip(a[6:8])], map[string.strip(a[9:11])], ) torsion[kee] = a kees = torsion.keys() kees.sort() for a in kees: kee = torsion[a] tor = [ a[0],a[1],a[2],a[3] ] lst = self.torsion[kee] div = lst[0] lst = lst[1:] while len(lst): tor.extend([lst[0]/div,lst[1],lst[2]]) lst = lst[5:] tor_list.append(tor) list.append(tor_list) return list