8 IUPAC_CONVENTION=
'iupac'
9 TYPE_AMINO_ACID =
'AMINO_ACID'
22 return 'resid' in x
and 'name' in x
26 atom_dict = {
'segid':
'',
30 pseudoatom_char =
'*',
'%',
'#'
32 def __init__(self, sequence, ignore_warnings=False, sequence_match=(1,1)):
34 self.sequence = sequence
36 self.offset = sequence_match[1]-sequence_match[0]
37 self.ignore = ignore_warnings
38 self.pseudo_dict = Load(pseudoatoms_dict)
40 def extract_contributions(self, contribs):
50 c = c[:c.rfind(
')')+1]
52 new_contribs.append(c)
56 def split_contribution(self, contrib):
58 words = contrib.split(
'(')
59 atoms = [word.split(
')')[0]
for word
in words
if word]
63 def resolve_pseudoatom(self, residue_type, atom_name):
67 elif '#' in atom_name:
70 atom_name = atom_name.replace(char,
'%')
77 group = self.pseudo_dict[residue_type][atom_name]
81 key = atom_name, residue_type
83 if not key
in self.missing_atoms:
85 msg =
'Could not resolve pseudoatom %s.%s.' % (residue_type, atom_name)
92 self.missing_atoms.append(key)
98 def to_iupac(self, residue_type, atom_name):
100 raise NotImplementedError
102 iupac_name = self.thesaurus.convert_atom(residue_type,
108 iupac_name = self.thesaurus.convert_atom(residue_type,
116 key = atom_name, residue_type
118 if not key
in self.missing_atoms:
120 if '*' in atom_name
or '#' in atom_name:
122 msg =
'Pseudoatoms not upported: %s' % atom_name
131 msg =
'Warning: atom %s not found in residue %s.' % key
134 raise KeyError, msg % key
136 self.missing_atoms.append(key)
142 def resolve_dihedral_name(self, atoms):
144 raise NotImplementedError
146 names = [a[
'name']
for a
in atoms]
149 res_type = self.sequence[atoms[1][
'resid']]
152 print 'Residue number overflow in atoms', atoms
155 for dihedral
in self.connectivity[res_type].dihedrals.values():
157 keys = [k
for k
in dihedral.keys()
if 'atom' in k]
164 if name[-1]
in (
'-',
'+'):
167 atom_names.append(name)
169 if atom_names == names:
170 return dihedral[
'name']
172 msg =
'Could not determine name of dihedral angles defined by atoms %s.' % str(names)
180 def extract_atom(self, a):
182 atom = dict(self.atom_dict)
190 words = [x
for x
in words
if x <>
'"']
192 for i
in range(len(words)):
203 for key
in atom.keys():
208 atom[key] = words[i+1][:-1]
210 atom[key] = words[i+1]
216 raise KeyError,
'Value or keyword "%s" unknown. Source: "%s", decomposed into "%s"' % \
217 (word, str(a), str(words))
219 atom[
'resid'] = int(atom[
'resid']) + self.offset
220 atom[
'name'] = atom[
'name'].upper()
224 def build_contributions(self, atoms):
231 res_type = self.sequence[a[
'resid']]
234 print 'Residue number overflow in atoms', atoms
237 atom_name = a[
'name']
239 if atom_name[-1]
in self.pseudoatom_char:
240 group = self.resolve_pseudoatom(res_type, atom_name)
248 group1, group2 = groups
252 res_1 = atoms[0][
'resid']
253 res_2 = atoms[1][
'resid']
255 for i
in range(len(group1)):
259 for j
in range(len(group2)):
261 if (res_1, name_1) <> (res_2, group2[j]):
262 contribs.append(((res_1, name_1), (res_2, group2[j])))
266 def extract_target_values(self, line):
268 end = line.rfind(
')')
270 values = line[end+1:].split()
273 distances = [float(x)
for x
in values[:3]]
279 val = line.split(
'volume=')
282 volume = float(val[1].split()[0].split(
',')[0])
287 return distances, volume
289 def read_contents(self, filename):
293 filename = os.path.expanduser(filename)
296 lines = f.readlines()
305 if not x
or x[0] ==
'!':
308 not_valid = [kw
for kw
in keywords
if kw
in x]
313 all += x.lower() +
' '
315 return [x.strip()
for x
in all.split(
'assi')]
317 def find_contributions(self, line):
319 contribs = [del_comment(x).strip()
for x
in line.split(
'or')]
323 if 1
in [x.count(
'resid')
for x
in contribs]:
329 start = line.find(
'(')
332 atoms[-1][-1] += line
335 stop = line.find(
')')
337 selection = [x.strip()
for x
in line[start:stop+1].split(
'or')]
339 for i
in range(len(selection)):
351 atoms.append(selection)
362 for i
in range(len(atoms)):
366 for atom
in atoms[i]:
370 if n >= 0
and len(atom[n+1:].strip()) > 3:
371 distances = atom[n+1:].strip()
387 contribs.append(
'%s %s' % (i,j))
389 contribs[0] +=
' ' + distances
394 if distances
is None and volume
is None:
395 raise ValueError,
"could not find either volume or "\
396 "distance: %s %s %s" % (distances,volume,contributions)
397 if distances
is None:
398 distances = [volume**(-1./6),0,0]
401 volume = dist ** (-6)
402 lower = dist - distances[1]
403 upper = dist + distances[2]
404 return (tuple(contributions), dist, lower, upper, volume)
406 def read_distances(self, filename, key, naming_system=IUPAC_CONVENTION,
408 """reads a tbl file and parses distance restraints.
411 self.naming_system = naming_system
413 assigns = self.read_contents(filename)
416 self.missing_atoms = []
421 contribs = self.find_contributions(line)
423 if False in [check_assigns(x)
for x
in contribs]:
426 distances, volume = self.extract_target_values(contribs[0])
428 if (distances
is None and volume
is None):
429 distances, volume = self.extract_target_values(contribs[-1])
431 new_contribs = self.extract_contributions(contribs)
435 for contrib
in new_contribs:
437 atoms = self.split_contribution(contrib)
438 atoms = [self.extract_atom(x)
for x
in atoms]
440 contributions += self.build_contributions(atoms)
443 r = self.create_distance_restraint(distances, volume,
453 d = decompose_restraints(restraints)
455 for _type
in d.keys():
460 for _type, val
in d.items():
463 new_key = key +
'_%s' % _type
469 d = {key: d.values()[0]}
471 d = {key: restraints}
475 def read_dihedrals(self, filename, key, naming_system=IUPAC_CONVENTION):
477 self.naming_system = naming_system
479 assigns = self.read_contents(filename)
482 self.missing_atoms = []
487 contribs = [del_comment(x).strip()
for x
in line.split(
'or')]
489 values, volume = self.extract_target_values(contribs[0])
490 new_contribs = self.extract_contributions(contribs)
495 if len(new_contribs) > 1:
496 raise ValueError,
'Inconsistency in data file, multiple contributions detected.'
498 atoms = self.split_contribution(new_contribs[0])
499 atoms = [self.extract_atom(x)
for x
in atoms]
501 name = self.resolve_dihedral_name(atoms)
503 r = create_dihedral_restraint(seq_number, name, values, atoms)
511 def read_rdcs(self, filename, key, naming_system=IUPAC_CONVENTION):
513 self.naming_system = naming_system
515 assigns = self.read_contents(filename)
518 self.missing_atoms = []
521 fake_atom_names = (
'OO',
'X',
'Y',
'Z')
525 contribs = [del_comment(x).strip()
for x
in line.split(
'or')]
526 distances, volume = self.extract_target_values(contribs[0])
527 new_contribs = self.extract_contributions(contribs)
531 for contrib
in new_contribs:
533 atoms = self.split_contribution(contrib)
534 atoms = [self.extract_atom(x)
for x
in atoms]
536 atoms = [a
for a
in atoms
if not a[
'name']
in fake_atom_names]
538 contributions += self.build_contributions(atoms)
541 r = create_rdc_restraint(seq_number, distances[0], contributions)
549 if __name__ ==
'__main__':
552 sequence = read_sequence_file(
'seq.dat', first_residue_number=1)
553 reader = TBLReader(sequence, ignore_warnings=
True)
554 reader.read_distances(noe, key=
'test')