IMP logo
IMP Reference Guide  2.6.0
The Integrative Modeling Platform
pmi/topology/__init__.py
1 """@namespace IMP.pmi.topology
2 Set of python classes to create a multi-state, multi-resolution IMP hierarchy.
3 * Start by creating a System with `mdl = IMP.Model(); s = IMP.pmi.topology.System(mdl)`. The System will store all the states.
4 * Then call System.create_state(). You can easily create a multistate system by calling this function multiples times.
5 * For each State, call State.create_molecule() to add a Molecule (a uniquely named polymer). This function returns the Molecule object which can be passed to various PMI functions.
6 * Some useful functions to help you set up your Molecules:
7  * Access the sequence residues with slicing (Molecule[a:b]) or functions like Molecule.get_atomic_residues() and Molecule.get_non_atomic_residues(). These functions all return python sets for easy set arithmetic using & (and), | (or), - (difference)
8  * Molecule.add_structure() to add structural information from a PDB file.
9  * Molecule.add_representation() to create a representation unit - here you can choose bead resolutions as well as alternate representations like densities or ideal helices.
10  * Molecule.create_clone() lets you set up a molecule with identical representations, just a different chain ID. Use Molecule.create_copy() if you want a molecule with the same sequence but that allows custom representations.
11 * Once data has been added and representations chosen, call System.build() to create a canonical IMP hierarchy.
12 * Following hierarchy construction, setup rigid bodies, flexible beads, etc in IMP::pmi::dof.
13 * Check your representation with a nice printout: IMP::atom::show_with_representation()
14 See a [comprehensive example](https://integrativemodeling.org/nightly/doc/ref/pmi_2multiscale_8py-example.html) for using these classes.
15 
16 Alternatively one can construct the entire topology and degrees of freedom via formatted text file with TopologyReader and IMP::pmi::macros::BuildSystem(). This is used in the [PMI tutorial](@ref rnapolii_stalk).
17 Note that this only allows a limited set of the full options available to PMI users (rigid bodies only, fixed resolutions).
18 """
19 
20 from __future__ import print_function
21 import IMP
22 import IMP.atom
23 import IMP.algebra
24 import IMP.pmi
25 import IMP.pmi.tools
26 import csv
27 import os
28 from collections import defaultdict
29 from . import system_tools
30 from bisect import bisect_left
31 from math import pi,cos,sin
32 from operator import itemgetter
33 
34 def _build_ideal_helix(mdl, residues, coord_finder):
35  """Creates an ideal helix from the specified residue range
36  Residues MUST be contiguous.
37  This function actually adds them to the TempResidue hierarchy
38  """
39  all_res = []
40  for n, res in enumerate(residues):
41  if res.get_has_structure():
42  raise Exception("You tried to build ideal_helix for a residue "
43  "that already has structure:",res)
44  if n>0 and (not res.get_index()==prev_idx+1):
45  raise Exception("Passed non-contiguous segment to build_ideal_helix for",res.get_molecule())
46 
47  rt = res.get_residue_type()
48 
49  rp = IMP.Particle(mdl)
50  rp.set_name("Residue_%i" % res.get_index())
51  this_res = IMP.atom.Residue.setup_particle(rp,res.get_hierarchy())
52 
53  ap = IMP.Particle(mdl)
55  x = 2.3 * cos(n * 2 * pi / 3.6)
56  y = 2.3 * sin(n * 2 * pi / 3.6)
57  z = 6.2 / 3.6 / 2 * n * 2 * pi / 3.6
58  d.set_coordinates(IMP.algebra.Vector3D(x, y, z))
59  d.set_radius(1.0)
60 
61  a = IMP.atom.Atom.setup_particle(ap, IMP.atom.AT_CA)
62  this_res.add_child(a)
63  res.set_structure(this_res)
64  all_res.append(this_res)
65  prev_idx = res.get_index()
66  coord_finder.add_residues(all_res)
67 
68 class _SystemBase(object):
69  """The base class for System, State and Molecule
70  classes. It contains shared functions in common to these classes
71  """
72 
73  def __init__(self,mdl=None):
74  if mdl is None:
75  self.mdl=IMP.Model()
76  else:
77  self.mdl=mdl
78 
79  def _create_hierarchy(self):
80  """create a new hierarchy"""
81  tmp_part=IMP.Particle(self.mdl)
82  return IMP.atom.Hierarchy.setup_particle(tmp_part)
83 
84  def _create_child(self,parent_hierarchy):
85  """create a new hierarchy, set it as child of the input
86  one, and return it"""
87  child_hierarchy=self._create_hierarchy()
88  parent_hierarchy.add_child(child_hierarchy)
89  return child_hierarchy
90 
91  def build(self):
92  """Build the coordinates of the system.
93  Loop through stored(?) hierarchies and set up coordinates!"""
94  pass
95 
96 #------------------------
97 
98 class System(_SystemBase):
99  """This class initializes the root node of the global IMP.atom.Hierarchy."""
100  def __init__(self,mdl=None,name="System"):
101  _SystemBase.__init__(self,mdl)
102  self._number_of_states = 0
103  self.states = []
104  self.built=False
105 
106  # the root hierarchy node
107  self.hier=self._create_hierarchy()
108  self.hier.set_name(name)
109 
110  def get_states(self):
111  return self.states
112 
113  def create_state(self):
114  """returns a new IMP.pmi.representation_new.State(), increment the state index"""
115  self._number_of_states+=1
116  state = State(self,self._number_of_states-1)
117  self.states.append(state)
118  return state
119 
120  def __repr__(self):
121  return self.hier.get_name()
122 
124  """returns the total number of states generated"""
125  return self._number_of_states
126 
127  def get_hierarchy(self):
128  return self.hier
129 
130  def build(self,**kwargs):
131  """call build on all states"""
132  if not self.built:
133  for state in self.states:
134  state.build(**kwargs)
135  self.built=True
136  return self.hier
137 
138 #------------------------
139 
140 class State(_SystemBase):
141  """Stores a list of Molecules all with the same State index.
142  Also stores number of copies of each Molecule for easy Selection.
143  """
144  def __init__(self,system,state_index):
145  """Define a new state
146  @param system the PMI System
147  @param state_index the index of the new state
148  \note It's expected that you will not use this constructor directly,
149  but rather create it with pmi::System::create_molecule()
150  """
151  self.mdl = system.get_hierarchy().get_model()
152  self.system = system
153  self.hier = self._create_child(system.get_hierarchy())
154  self.hier.set_name("State_"+str(state_index))
155  self.molecules = defaultdict(list) # key is molecule name. value are the molecule copies!
156  IMP.atom.State.setup_particle(self.hier,state_index)
157  self.built = False
158 
159  def __repr__(self):
160  return self.system.__repr__()+'.'+self.hier.get_name()
161 
162  def get_molecules(self):
163  """Return a dictionary where key is molecule name and value
164  are the list of all copies of that molecule in setup order"""
165  return self.molecules
166 
167  def get_molecule(self,name,copy_num=0):
168  """Access a molecule by name and copy number
169  @param name The molecule name used during setup
170  @param copy_num The copy number based on input order.
171  Default: 0. Set to 'all' to get all copies
172  """
173  if name not in self.molecules:
174  raise Exception("get_molecule() could not find molname",name)
175  if copy_num=='all':
176  return self.molecules[name]
177  else:
178  if copy_num>len(self.molecules[name])-1:
179  raise Exception("get_molecule() copy number is too high:",copy_num)
180  return self.molecules[name][copy_num]
181 
182  def create_molecule(self,name,sequence='',chain_id=''):
183  """Create a new Molecule within this State
184  @param name the name of the molecule (string) it must not
185  be already used
186  @param sequence sequence (string)
187  @param chain_id Chain id to assign to this molecule
188  """
189  # check whether the molecule name is already assigned
190  if name in self.molecules:
191  raise Exception('Cannot use a molecule name already used')
192 
193  mol = Molecule(self,name,sequence,chain_id,copy_num=0)
194  self.molecules[name].append(mol)
195  return mol
196 
197  def get_hierarchy(self):
198  return self.hier
199 
200  def get_number_of_copies(self,molname):
201  return len(self.molecules[molname])
202 
203  def _register_copy(self,molecule):
204  molname = molecule.get_hierarchy().get_name()
205  if molname not in self.molecules:
206  raise Exception("Trying to add a copy when the original doesn't exist!")
207  self.molecules[molname].append(molecule)
208 
209  def build(self,**kwargs):
210  """call build on all molecules (automatically makes clones)"""
211  if not self.built:
212  for molname in self.molecules:
213  for mol in reversed(self.molecules[molname]):
214  mol.build(**kwargs)
215  self.built=True
216  return self.hier
217 
218 #------------------------
219 
220 class Molecule(_SystemBase):
221  """Stores a named protein chain.
222  This class is constructed from within the State class.
223  It wraps an IMP.atom.Molecule and IMP.atom.Copy
224  Structure is read using this class
225  Resolutions and copies can be registered, but are only created when build() is called
226  """
227 
228  def __init__(self,state,name,sequence,chain_id,copy_num,mol_to_clone=None):
229  """The user should not call this directly; instead call State::create_molecule()
230  @param state The parent PMI State
231  @param name The name of the molecule (string)
232  @param sequence Sequence (string)
233  @param chain_id The chain of this molecule
234  @param copy_num Store the copy number
235  @param mol_to_clone The original molecule (for cloning ONLY)
236  \note It's expected that you will not use this constructor directly,
237  but rather create a Molecule with pmi::State::create_molecule()
238  """
239  # internal data storage
240  self.mdl = state.get_hierarchy().get_model()
241  self.state = state
242  self.sequence = sequence
243  self.built = False
244  self.mol_to_clone = mol_to_clone
245  self.representations = [] # list of stuff to build
246  self.represented = IMP.pmi.tools.OrderedSet() # residues with representation
247  self.coord_finder = _FindCloseStructure() # helps you place beads by storing structure
248  self._ideal_helices = [] # list of OrderedSets of tempresidues set to ideal helix
249 
250  # create root node and set it as child to passed parent hierarchy
251  self.hier = self._create_child(self.state.get_hierarchy())
252  self.hier.set_name(name)
253  IMP.atom.Copy.setup_particle(self.hier,copy_num)
254  IMP.atom.Chain.setup_particle(self.hier,chain_id)
255  # create TempResidues from the sequence (if passed)
256  self.residues=[]
257  for ns,s in enumerate(sequence):
258  r = TempResidue(self,s,ns+1,ns)
259  self.residues.append(r)
260 
261  def __repr__(self):
262  return self.state.__repr__()+'.'+self.get_name()+'.'+ \
263  str(IMP.atom.Copy(self.hier).get_copy_index())
264 
265  def __getitem__(self,val):
266  if isinstance(val,int):
267  return self.residues[val]
268  elif isinstance(val,str):
269  return self.residues[int(val)-1]
270  elif isinstance(val,slice):
271  return IMP.pmi.tools.OrderedSet(self.residues[val])
272  else:
273  print("ERROR: range ends must be int or str. Stride must be int.")
274 
275  def get_hierarchy(self):
276  """Return the IMP Hierarchy corresponding to this Molecule"""
277  return self.hier
278 
279  def get_name(self):
280  """Return this Molecule name"""
281  return self.hier.get_name()
282 
283  def get_state(self):
284  """Return the State containing this Molecule"""
285  return self.state
286 
287  def get_ideal_helices(self):
288  """Returns list of OrderedSets with requested ideal helices"""
289  return self._ideal_helices
290 
291  def residue_range(self,a,b,stride=1):
292  """get residue range. Use integers to get 0-indexing, or strings to get PDB-indexing"""
293  if isinstance(a,int) and isinstance(b,int) and isinstance(stride,int):
294  return IMP.pmi.tools.OrderedSet(self.residues[a:b:stride])
295  elif isinstance(a,str) and isinstance(b,str) and isinstance(stride,int):
296  return IMP.pmi.tools.OrderedSet(self.residues[int(a)-1:int(b)-1:stride])
297  else:
298  print("ERROR: range ends must be int or str. Stride must be int.")
299 
300  def get_residues(self):
301  """ Return all modeled TempResidues as a set"""
302  all_res = IMP.pmi.tools.OrderedSet(self.residues)
303  return all_res
304 
306  """ Return a set of TempResidues that have associated structure coordinates """
307  atomic_res = IMP.pmi.tools.OrderedSet()
308  for res in self.residues:
309  if res.get_has_structure():
310  atomic_res.add(res)
311  return atomic_res
312 
314  """ Return a set of TempResidues that don't have associated structure coordinates """
315  non_atomic_res = IMP.pmi.tools.OrderedSet()
316  for res in self.residues:
317  if not res.get_has_structure():
318  non_atomic_res.add(res)
319  return non_atomic_res
320 
321  def create_copy(self,chain_id):
322  """Create a new Molecule with the same name and sequence but a higher copy number.
323  Returns the Molecule. No structure or representation will be copied!
324  @param chain_id Chain ID of the new molecule
325  """
326  mol = Molecule(self.state,self.get_name(),self.sequence,chain_id,
327  copy_num=self.state.get_number_of_copies(self.get_name()))
328  self.state._register_copy(mol)
329  return mol
330 
331  def create_clone(self,chain_id):
332  """Create a Molecule clone (automatically builds same structure and representation)
333  @param chain_id If you want to set the chain ID of the copy to something
334  \note You cannot add structure or representations to a clone!
335  """
336  mol = Molecule(self.state,self.get_name(),self.sequence,chain_id,
337  copy_num=self.state.get_number_of_copies(self.get_name()),
338  mol_to_clone=self)
339  self.state._register_copy(mol)
340  return mol
341 
342  def add_structure(self,pdb_fn,chain_id,res_range=[],
343  offset=0,model_num=None,ca_only=False,
344  soft_check=False):
345  """Read a structure and store the coordinates.
346  Returns the atomic residues (as a set)
347  @param pdb_fn The file to read
348  @param chain_id Chain ID to read
349  @param res_range Add only a specific set of residues from the PDB file.
350  @param offset Apply an offset to the residue indexes of the PDB file.
351  This number is added to the PDB sequence.
352  @param model_num Read multi-model PDB and return that model
353  @param ca_only Only read the CA positions from the PDB file
354  @param soft_check If True, it only warns if there are sequence mismatches between the pdb and the Molecules sequence. Actually replaces the fasta values.
355  If False (Default), it raises and exit when there are sequence mismatches.
356  \note If you are adding structure without a FASTA file, set soft_check to True
357  """
358  if self.mol_to_clone is not None:
359  raise Exception('You cannot call add_structure() for a clone')
360 
361  self.pdb_fn = pdb_fn
362 
363  # get IMP.atom.Residues from the pdb file
364  rhs = system_tools.get_structure(self.mdl,pdb_fn,chain_id,res_range,offset,ca_only=ca_only)
365  self.coord_finder.add_residues(rhs)
366 
367  if len(self.residues)==0:
368  print("WARNING: Extracting sequence from structure. Potentially dangerous.")
369 
370  # load those into TempResidue object
371  atomic_res = IMP.pmi.tools.OrderedSet() # collect integer indexes of atomic residues to return
372  for nrh,rh in enumerate(rhs):
373  pdb_idx = rh.get_index()
374  raw_idx = pdb_idx - 1
375 
376  # add ALA to fill in gaps
377  while len(self.residues)<pdb_idx:
378  r = TempResidue(self,'A',len(self.residues)+1,len(self.residues))
379  self.residues.append(r)
380 
381  internal_res = self.residues[raw_idx]
382  internal_res.set_structure(rh,soft_check)
383  atomic_res.add(internal_res)
384  return atomic_res
385 
386  def add_representation(self,
387  residues=None,
388  resolutions=[],
389  bead_extra_breaks=[],
390  bead_ca_centers=True,
391  bead_default_coord=[0,0,0],
392  density_residues_per_component=None,
393  density_prefix=None,
394  density_force_compute=False,
395  density_voxel_size=1.0,
396  setup_particles_as_densities=False,
397  ideal_helix=False,
398  color=None):
399  """Set the representation for some residues. Some options (beads, ideal helix)
400  operate along the backbone. Others (density options) are volumetric.
401  Some of these you can combine e.g., beads+densities or helix+densities
402  See @ref pmi_resolution
403  @param residues Set of PMI TempResidues for adding the representation.
404  Can use Molecule slicing to get these, e.g. mol[a:b]+mol[c:d]
405  If None, will select all residues for this Molecule.
406  @param resolutions Resolutions for beads representations.
407  If structured, will average along backbone, breaking at sequence breaks.
408  If unstructured, will just create beads.
409  Pass an integer or list of integers
410  @param bead_extra_breaks Additional breakpoints for splitting beads.
411  The number is the first PDB-style index that belongs in the second bead
412  @param bead_ca_centers Set to True if you want the resolution=1 beads to be at CA centers
413  (otherwise will average atoms to get center). Defaults to True.
414  @param bead_default_coord Advanced feature. Normally beads are placed at the nearest structure.
415  If no structure provided (like an all bead molecule), the beads go here.
416  @param density_residues_per_component Create density (Gaussian Mixture Model)
417  for these residues. Must also supply density_prefix
418  @param density_prefix Prefix (assuming '.txt') to read components from or write to.
419  If exists, will read unless you set density_force_compute=True.
420  Will also write map (prefix+'.mrc').
421  Must also supply density_residues_per_component.
422  @param density_force_compute Set true to force overwrite density file.
423  @param density_voxel_size Advanced feature. Set larger if densities taking too long to rasterize.
424  Set to 0 if you don't want to create the MRC file
425  @param setup_particles_as_densities Set to True if you want each particle to be its own density.
426  Useful for all-atom models or flexible beads.
427  Mutually exclusive with density_ options
428  @param ideal_helix Create idealized helix structures for these residues at resolution 1.
429  Any other resolutions passed will be coarsened from there.
430  Resolution 0 will not work, you may have to use MODELLER to do that (for now).
431  @param color the color applied to the hierarchies generated.
432  Format options: tuple (r,g,b) with values 0 to 1
433  or float (from 0 to 1, a map from Blue to Green to Red)
434  or IMP.display.Color object
435 
436  \note You cannot call add_representation multiple times for the same residues.
437  """
438 
439  # can't customize clones
440  if self.mol_to_clone is not None:
441  raise Exception('You cannot call add_representation() for a clone.'
442  'Maybe use a copy instead')
443 
444  # format input
445  if residues is None:
446  res = IMP.pmi.tools.OrderedSet(self.residues)
447  elif residues==self:
448  res = IMP.pmi.tools.OrderedSet(self.residues)
449  elif hasattr(residues,'__iter__'):
450  if len(residues)==0:
451  raise Exception('You passed an empty set to add_representation')
452  if type(residues) is IMP.pmi.tools.OrderedSet and type(next(iter(residues))) is TempResidue:
453  res = residues
454  elif type(residues) is set and type(next(iter(residues))) is TempResidue:
455  res = IMP.pmi.tools.OrderedSet(residues)
456  elif type(residues) is list and type(residues[0]) is TempResidue:
457  res = IMP.pmi.tools.OrderedSet(residues)
458  else:
459  raise Exception("You passed an iteratible of something other than TempResidue",res)
460  else:
461  raise Exception("add_representation: you must pass a set of residues or nothing(=all residues)")
462 
463  # check that each residue has not been represented yet
464  ov = res & self.represented
465  if ov:
466  raise Exception('You have already added representation for '+self.get_hierarchy().get_name()+': '+ov.__repr__())
467  self.represented|=res
468 
469  # check you aren't creating multiple resolutions without structure
470  if not hasattr(resolutions,'__iter__'):
471  if type(resolutions) is int:
472  resolutions = [resolutions]
473  else:
474  raise Exception("you tried to pass resolutions that are not int or list-of-int")
475  if len(resolutions)>1 and not ideal_helix:
476  for r in res:
477  if not r.get_has_structure():
478  raise Exception('You are creating multiple resolutions for '
479  'unstructured regions. This will have unexpected results.')
480 
481  # check density info is consistent
482  if density_residues_per_component or density_prefix:
483  if not density_residues_per_component and density_prefix:
484  raise Exception('If requesting density, must provide '
485  'density_residues_per_component AND density_prefix')
486  if density_residues_per_component and setup_particles_as_densities:
487  raise Exception('Cannot create both volumetric density '
488  '(density_residues_per_component) AND '
489  'individual densities (setup_particles_as_densities) '
490  'in the same representation')
491  if len(resolutions)>1 and setup_particles_as_densities:
492  raise Exception('You have multiple bead resolutions but are attempting to '
493  'set them all up as individual Densities. '
494  'This could have unexpected results.')
495 
496  # check helix not accompanied by other resolutions (densities OK though!)
497  if ideal_helix:
498  if 0 in resolutions:
499  raise Exception("For ideal helices, cannot build resolution 0: "
500  "you have to do that in MODELLER")
501  if 1 not in resolutions:
502  resolutions = [1] + list(resolutions)
503  self._ideal_helices.append(res)
504 
505  # check residues are all part of this molecule:
506  for r in res:
507  if r.get_molecule()!=self:
508  raise Exception('You are adding residues from a different molecule to',self.__repr__())
509 
510  # store the representation group
511  self.representations.append(_Representation(res,
512  resolutions,
513  bead_extra_breaks,
514  bead_ca_centers,
515  bead_default_coord,
516  density_residues_per_component,
517  density_prefix,
518  density_force_compute,
519  density_voxel_size,
520  setup_particles_as_densities,
521  ideal_helix,
522  color))
523 
524  def build(self):
525  """Create all parts of the IMP hierarchy
526  including Atoms, Residues, and Fragments/Representations and, finally, Copies
527  Will only build requested representations.
528  /note Any residues assigned a resolution must have an IMP.atom.Residue hierarchy
529  containing at least a CAlpha. For missing residues, these can be constructed
530  from the PDB file
531  """
532  if not self.built:
533  # if requested, clone structure and representations BEFORE building original
534  if self.mol_to_clone is not None:
535  for nr,r in enumerate(self.mol_to_clone.residues):
536  if r.get_has_structure():
537  clone = IMP.atom.create_clone(r.get_hierarchy())
538  self.residues[nr].set_structure(
539  IMP.atom.Residue(clone),soft_check=True)
540  for old_rep in self.mol_to_clone.representations:
541  new_res = IMP.pmi.tools.OrderedSet()
542  for r in old_rep.residues:
543  new_res.add(self.residues[r.get_internal_index()])
544  self.represented.add(self.residues[r.get_internal_index()])
545  new_rep = _Representation(new_res,
546  old_rep.bead_resolutions,
547  old_rep.bead_extra_breaks,
548  old_rep.bead_ca_centers,
549  old_rep.bead_default_coord,
550  old_rep.density_residues_per_component,
551  old_rep.density_prefix,
552  old_rep.density_voxel_size,
553  False,
554  old_rep.setup_particles_as_densities,
555  old_rep.ideal_helix,
556  old_rep.color)
557  self.representations.append(new_rep)
558  self.coord_finder = self.mol_to_clone.coord_finder
559 
560  # give a warning for all residues that don't have representation
561  no_rep = [r for r in self.residues if r not in self.represented]
562  if len(no_rep)>0:
563  print('WARNING: Residues without representation in molecule',
564  self.get_name(),':',system_tools.resnums2str(no_rep))
565 
566  # first build any ideal helices (fills in structure for the TempResidues)
567  for rep in self.representations:
568  if rep.ideal_helix:
569  _build_ideal_helix(self.mdl,rep.residues,self.coord_finder)
570 
571  # build all the representations
572  for rep in self.representations:
573  system_tools.build_representation(self.hier,rep,self.coord_finder)
574  self.built = True
575 
576  for res in self.residues:
577  idx = res.get_index()
578 
579  # first off, store the highest resolution available in residue.hier
580  new_ps = IMP.atom.Selection(
581  self.hier,
582  residue_index=res.get_index(),
583  resolution=1).get_selected_particles()
584  if len(new_ps)>0:
585  new_p = new_ps[0]
586  if IMP.atom.Atom.get_is_setup(new_p):
587  # if only found atomic, store the residue
588  new_hier = IMP.atom.get_residue(IMP.atom.Atom(new_p))
589  else:
590  # otherwise just store what you found
591  new_hier = IMP.atom.Hierarchy(new_p)
592  res.hier = new_hier
593  else:
594  res.hier = None
595 
596  print('done building',self.get_hierarchy())
597  return self.hier
598 
599  def get_particles_at_all_resolutions(self,residue_indexes=None):
600  """Helpful utility for getting particles at all resolutions from this molecule.
601  Can optionally pass a set of residue indexes"""
602  if not self.built:
603  raise Exception("Cannot get all resolutions until you build the Molecule")
604  if residue_indexes is None:
605  residue_indexes = [r.get_index() for r in self.get_residues()]
607  residue_indexes=residue_indexes)
608  return ps
609 
610 #------------------------
611 
612 class _Representation(object):
613  """Private class just to store a representation request"""
614  def __init__(self,
615  residues,
616  bead_resolutions,
617  bead_extra_breaks,
618  bead_ca_centers,
619  bead_default_coord,
620  density_residues_per_component,
621  density_prefix,
622  density_force_compute,
623  density_voxel_size,
624  setup_particles_as_densities,
625  ideal_helix,
626  color):
627  self.residues = residues
628  self.bead_resolutions = bead_resolutions
629  self.bead_extra_breaks = bead_extra_breaks
630  self.bead_ca_centers = bead_ca_centers
631  self.bead_default_coord = bead_default_coord
632  self.density_residues_per_component = density_residues_per_component
633  self.density_prefix = density_prefix
634  self.density_force_compute = density_force_compute
635  self.density_voxel_size = density_voxel_size
636  self.setup_particles_as_densities = setup_particles_as_densities
637  self.ideal_helix = ideal_helix
638  self.color = color
639 
640 class _FindCloseStructure(object):
641  """Utility to get the nearest observed coordinate"""
642  def __init__(self):
643  self.coords=[]
644  def add_residues(self,residues):
645  for r in residues:
646  idx = IMP.atom.Residue(r).get_index()
647  ca = IMP.atom.Selection(r,atom_type=IMP.atom.AtomType("CA")).get_selected_particles()[0]
648  xyz = IMP.core.XYZ(ca).get_coordinates()
649  self.coords.append([idx,xyz])
650  self.coords.sort(key=itemgetter(0))
651  def find_nearest_coord(self,query):
652  if self.coords==[]:
653  return None
654  keys = [r[0] for r in self.coords]
655  pos = bisect_left(keys,query)
656  if pos == 0:
657  ret = self.coords[0]
658  elif pos == len(self.coords):
659  ret = self.coords[-1]
660  else:
661  before = self.coords[pos - 1]
662  after = self.coords[pos]
663  if after[0] - query < query - before[0]:
664  ret = after
665  else:
666  ret = before
667  return ret[1]
668 
669 class Sequences(object):
670  """A dictionary-like wrapper for reading and storing sequence data"""
671  def __init__(self,fasta_fn,name_map=None):
672  """read a fasta file and extract all the requested sequences
673  @param fasta_fn sequence file
674  @param name_map dictionary mapping the fasta name to final stored name
675  """
676  self.sequences = IMP.pmi.tools.OrderedDict()
677  self.read_sequences(fasta_fn,name_map)
678  def __len__(self):
679  return len(self.sequences)
680  def __contains__(self,x):
681  return x in self.sequences
682  def __getitem__(self,key):
683  if type(key) is int:
684  try:
685  allseqs = list(self.sequences.keys())
686  return self.sequences[allseqs[key]]
687  except:
688  raise Exception("You tried to access sequence num",key,"but there's only",len(self.sequences.keys()))
689  else:
690  return self.sequences[key]
691  def __iter__(self):
692  return self.sequences.__iter__()
693  def __repr__(self):
694  ret=''
695  for s in self.sequences:
696  ret += '%s\t%s\n'%(s,self.sequences[s])
697  return ret
698  def read_sequences(self,fasta_fn,name_map=None):
699  code = None
700  seq = None
701  with open(fasta_fn,'r') as fh:
702  for (num, line) in enumerate(fh):
703  if line.startswith('>'):
704  if seq is not None:
705  self.sequences[code] = seq.strip('*')
706  code = line.rstrip()[1:]
707  if name_map is not None:
708  try:
709  code = name_map[code]
710  except:
711  pass
712  seq = ''
713  else:
714  line = line.rstrip()
715  if line: # Skip blank lines
716  if seq is None:
717  raise Exception( \
718  "Found FASTA sequence before first header at line %d: %s" % (num + 1, line))
719  seq += line
720  if seq is not None:
721  self.sequences[code] = seq.strip('*')
722 
723 #------------------------
724 
725 
726 class TempResidue(object):
727  """Temporarily stores residue information, even without structure available."""
728  # Consider implementing __hash__ so you can select.
729  def __init__(self,molecule,code,index,internal_index):
730  """setup a TempResidue
731  @param molecule PMI Molecule to which this residue belongs
732  @param code one-letter residue type code
733  @param index PDB index
734  @param internal_index The number in the sequence
735  """
736  self.molecule = molecule
737  self.rtype = IMP.pmi.tools.get_residue_type_from_one_letter_code(code)
738  self.hier = IMP.atom.Residue.setup_particle(IMP.Particle(molecule.mdl),
739  self.rtype,
740  index)
741  self.pdb_index = index
742  self.internal_index = internal_index
743  self._structured = False
744  def __str__(self):
745  return self.get_code()+str(self.get_index())
746  def __repr__(self):
747  return self.__str__()
748  def __key(self):
749  return (self.molecule,self.hier)
750  def __eq__(self,other):
751  return type(other)==type(self) and self.__key() == other.__key()
752  def __hash__(self):
753  return hash(self.__key())
754  def get_index(self):
755  return self.pdb_index
756  def get_internal_index(self):
757  return self.internal_index
758  def get_code(self):
759  return IMP.atom.get_one_letter_code(self.get_residue_type())
760  def get_residue_type(self):
761  return self.rtype
762  def get_hierarchy(self):
763  return self.hier
764  def get_molecule(self):
765  return self.molecule
766  def get_has_structure(self):
767  return self._structured
768  def set_structure(self,res,soft_check=False):
769  if res.get_residue_type()!=self.get_residue_type():
770  if soft_check:
771  print('WARNING: Replacing sequence residue',self.get_index(),self.hier.get_residue_type(),
772  'with PDB type',res.get_residue_type())
773  self.hier.set_residue_type((res.get_residue_type()))
774  self.rtype = res.get_residue_type()
775  else:
776  raise Exception('ERROR: PDB residue index',self.get_index(),'is',
777  IMP.atom.get_one_letter_code(res.get_residue_type()),
778  'and sequence residue is',self.get_code())
779 
780  for a in res.get_children():
781  self.hier.add_child(a)
782  atype = IMP.atom.Atom(a).get_atom_type()
783  a.get_particle().set_name('Atom %s of residue %i'%(atype.__str__().strip('"'),
784  self.hier.get_index()))
785  self._structured = True
786 
787 class TopologyReader(object):
788  """Automatically setup Sytem and Degrees of Freedom with a formatted text file.
789  The topology file should be in a simple pipe-delimited format:
790  @code{.txt}
791 |component_name|domain_name|fasta_fn|fasta_id|pdb_fn|chain|residue_range|pdb_offset|bead_size|em_residues_per_gaussian|rigid_body|super_rigid_body|chain_of_super_rigid_bodies|
792 |Rpb1 |Rpb1_1|1WCM.fasta|1WCM:A|1WCM.pdb|A|1,1140 |0|10|0|1|1,3|1|
793 |Rpb1 |Rpb1_2|1WCM.fasta|1WCM:A|1WCM.pdb|A|1141,1274|0|10|0|2|1,3|1|
794 |Rpb1 |Rpb1_3|1WCM.fasta|1WCM:A|1WCM.pdb|A|1275,-1 |0|10|0|3|1,3|1|
795 |Rpb2 |Rpb2 |1WCM.fasta|1WCM:B|1WCM.pdb|B|all |0|10|0|4|2,3|2|
796  @endcode
797 
798  All filenames are relative to the paths specified in the constructor.
799  These are the fields you can enter:
800  - `component_name`: Name of the component (chain). Serves as the parent
801  hierarchy for this structure.
802  - `domain_name`: Allows subdivision of chains into individual domains.
803  A model consists of a number of individual units, referred to as
804  domains. Each domain can be an individual chain, or a subset of a
805  chain, and these domains are used to set rigid body movers. A chain
806  may be separated into multiple domains if the user wishes different
807  sections to move independently, and/or analyze the portions separately.
808  - `fasta_fn`: Name of FASTA file containing this component.
809  - `fasta_id`: String found in FASTA sequence header line.
810  - `pdb_fn`: Name of PDB file with coordinates (if available).
811  If left empty, will set up as BEADS (you can also specify "BEADS")
812  Can also write "IDEAL_HELIX".
813  - `chain`: Chain ID of this domain in the PDB file.
814  - `residue_range`: Comma delimited pair defining range.
815  Can leave empty or use 'all' for entire sequence from PDB file.
816  - `pdb_offset`: Offset to sync PDB residue numbering with FASTA numbering.
817  - `bead_size`: The size (in residues) of beads used to model areas not
818  covered by PDB coordinates. These will be automatically built.
819  - `em_residues`: The number of Gaussians used to model the electron
820  density of this domain. Set to zero if no EM fitting will be done.
821  The GMM files will be written to <gmm_dir>/<component_name>_<em_res>.txt (and .mrc)
822  - `rigid_body`: Number corresponding to the rigid body containing this object.
823  The number itself is used for grouping things.
824  - `super_rigid_body`: Like a rigid_body, except things are only occasionally rigid
825  - `chain_of_super_rigid_bodies` For a polymer, create SRBs from groups.
826 
827  The file is read in and each part of the topology is stored as a
828  ComponentTopology object for input into IMP::pmi::macros::BuildModel.
829  """
830  def __init__(self,
831  topology_file,
832  resolutions=[1,10],
833  pdb_dir='./',
834  fasta_dir='./',
835  gmm_dir='./'):
836  """Constructor.
837  @param topology_file Pipe-delimited file specifying the topology
838  @param resolutions What resolutions to build for ALL structured components
839  @param pdb_dir Relative path to the pdb directory
840  @param fasta_dir Relative path to the fasta directory
841  @param gmm_dir Relative path to the GMM directory
842  """
843  self.topology_file = topology_file
844  self.component_list = []
845  self.unique_molecules = {}
846  self.resolutions = resolutions
847  self.pdb_dir = pdb_dir
848  self.fasta_dir = fasta_dir
849  self.gmm_dir = gmm_dir
850  self.component_list = self.import_topology_file(topology_file)
851 
852  def write_topology_file(self,outfile):
853  with open(outfile, "w") as f:
854  f.write("|component_name|domain_name|fasta_fn|fasta_id|pdb_fn|chain|residue_range|pdb_offset|bead_size|em_residues_per_gaussian|rigid_body|super_rigid_body|chain_of_super_rigid_bodies|\n")
855  for c in self.component_list:
856  output = c.get_str()+'\n'
857  f.write(output)
858  return outfile
859 
860  def get_component_topologies(self, topology_list = "all"):
861  """ Return list of ComponentTopologies for selected components
862  @param topology_list List of indices to return"""
863  if topology_list == "all":
864  topologies = self.component_list
865  else:
866  topologies=[]
867  for i in topology_list:
868  topologies.append(self.component_list[i])
869  return topologies
870 
871  def get_unique_molecules(self):
872  return self.unique_molecules
873 
874  def import_topology_file(self, topology_file, append=False):
875  """Read system components from topology file. append=False will erase
876  current topology and overwrite with new
877  """
878  is_topology = False
879  is_defaults = False
880  linenum = 1
881  if append==False:
882  self.component_list=[]
883  with open(topology_file) as infile:
884  for line in infile:
885  if line.lstrip()=="" or line[0]=="#":
886  continue
887  elif line.split('|')[1] in ("topology_dictionary","component_name"):
888  is_topology=True
889  is_defaults=False
890  elif line.split('|')[1]=="directories":
891  is_defaults=True
892  print("WARNING: You no longer need to set directories in the topology file. "
893  "Please do so through the TopologyReader constructor. "
894  "Note that new-style paths are relative to the current working directory, "
895  "not the topology file")
896  elif is_topology:
897  # create a component_topology from this line
898  new_component = self._create_component_topology(line, linenum)
899  self.component_list.append(new_component)
900  elif is_defaults:
901  # THIS WILL GO AWAY, switch to files relative to the modeling file!
902  fields = line.split('|')
903  setattr(self,fields[1],IMP.get_relative_path(self.topology_file,fields[2]))
904  else:
905  raise Exception("FOUND A WEIRD LINE")
906  linenum += 1
907  return self.component_list
908 
909  def _create_component_topology(self, component_line, linenum, color="0.1"):
910  """Parse a line of topology values and matches them to their key.
911  Checks each value for correct syntax
912  Returns a list of ComponentTopology objects
913  fields:
914  """
915 
916  c = ComponentTopology()
917  values = [s.strip() for s in component_line.split('|')]
918  errors = []
919 
920  ### Required fields
921  c.name = values[1]
922  c.domain_name = values[2]
923  c._orig_fasta_file = values[3] # in case you need to write the file!
924  c.fasta_file = os.path.join(self.fasta_dir,values[3])
925  c.fasta_id = values[4]
926  c._orig_pdb_input = values[5]
927  pdb_input = values[5]
928  if pdb_input=="None" or pdb_input=="":
929  c.pdb_file = "BEADS"
930  elif pdb_input=="IDEAL_HELIX":
931  c.pdb_file = "IDEAL_HELIX"
932  elif pdb_input=="BEADS":
933  c.pdb_file = "BEADS"
934  else:
935  c.pdb_file = os.path.join(self.pdb_dir,pdb_input)
936 
937  # PDB chain must be one or two characters
938  t_chain = values[6]
939  if len(t_chain)==1 or len(t_chain)==2:
940  c.chain = t_chain
941  else:
942  errors.append("PDB Chain identifier must be one or two characters.")
943  errors.append("For component %s line %d is not correct |%s| was given." % (c.name,linenum,t_chain))
944 
945  # Multiple domains must all use the same fasta file!
946  if c.name not in self.unique_molecules:
947  self.unique_molecules[c.name] = [c]
948  else:
949  if (c.fasta_file!=self.unique_molecules[c.name][0].fasta_file or \
950  c.fasta_id!=self.unique_molecules[c.name][0].fasta_id or \
951  c.chain!=self.unique_molecules[c.name][0].chain):
952  errors.append("All domains with the same component name must have the same sequence. %s doesn't match %s"%(c.domain_name,c.name))
953  self.unique_molecules[c.name].append(c)
954 
955  ### Optional fields
956  # Residue Range
957  f = values[7]
958  if f.strip()=='all' or str(f)=="":
959  c.residue_range = None
960  elif len(f.split(','))==2 and self._is_int(f.split(',')[0]) and self._is_int(f.split(',')[1]):
961  # Make sure that is residue range is given, there are only two values and they are integers
962  c.residue_range = (int(f.split(',')[0]), int(f.split(',')[1]))
963  else:
964  errors.append("Residue Range format for component %s line %d is not correct" % (c.name, linenum))
965  errors.append("Correct syntax is two comma separated integers: |start_res, end_res|. |%s| was given." % f)
966  errors.append("To select all residues, indicate |\"all\"|")
967 
968  # PDB Offset
969  f = values[8]
970  if self._is_int(f):
971  c.pdb_offset=int(f)
972  elif len(f)==0:
973  c.pdb_offset = 0
974  else:
975  errors.append("PDB Offset format for component %s line %d is not correct" % (c.name, linenum))
976  errors.append("The value must be a single integer. |%s| was given." % f)
977 
978  # Bead Size
979  f = values[9]
980  if self._is_int(f):
981  c.bead_size=int(f)
982  elif len(f)==0:
983  c.bead_size = 0
984  else:
985  errors.append("Bead Size format for component %s line %d is not correct" % (c.name, linenum))
986  errors.append("The value must be a single integer. |%s| was given." % f)
987 
988  # EM Residues Per Gaussian
989  f = values[10]
990  if self._is_int(f):
991  if int(f) > 0:
992  c.density_prefix = os.path.join(self.gmm_dir,c.domain_name)
993  c.gmm_file = c.density_prefix+'.txt'
994  c.mrc_file = c.density_prefix+'.gmm'
995 
996  c.em_residues_per_gaussian=int(f)
997  else:
998  c.em_residues_per_gaussian = 0
999  elif len(f)==0:
1000  c.em_residues_per_gaussian = 0
1001  else:
1002  errors.append("em_residues_per_gaussian format for component "
1003  "%s line %d is not correct" % (c.name, linenum))
1004  errors.append("The value must be a single integer. |%s| was given." % f)
1005 
1006  # DOF fields are for new-style topology files
1007  if len(values)>12:
1008  # rigid bodies
1009  f = values[11]
1010  if len(f)>0:
1011  if not self._is_int(f):
1012  errors.append("rigid bodies format for component "
1013  "%s line %d is not correct" % (c.name, linenum))
1014  errors.append("Each RB must be a single integer. |%s| was given." % f)
1015  c.rigid_bodies = f
1016 
1017  # super rigid bodies
1018  f = values[12]
1019  if len(f)>0:
1020  f = f.split(',')
1021  for i in f:
1022  if not self._is_int(i):
1023  errors.append("super rigid bodies format for component "
1024  "%s line %d is not correct" % (c.name, linenum))
1025  errors.append("Each SRB must be a single integer. |%s| was given." % f)
1026  c.super_rigid_bodies = f
1027 
1028  # chain of super rigid bodies
1029  f = values[13]
1030  if len(f)>0:
1031  if not self._is_int(f):
1032  errors.append("em_residues_per_gaussian format for component "
1033  "%s line %d is not correct" % (c.name, linenum))
1034  errors.append("Each CSRB must be a single integer. |%s| was given." % f)
1035  c.chain_of_super_rigid_bodies = f
1036 
1037  # done
1038  if errors:
1039  raise ValueError("Fix Topology File syntax errors and rerun: " \
1040  + "\n".join(errors))
1041  else:
1042  return c
1043 
1044 
1045  def set_gmm_dir(self,gmm_dir):
1046  """Change the GMM dir"""
1047  self.gmm_dir = gmm_dir
1048  for c in self.component_list:
1049  c.gmm_file = os.path.join(self.gmm_dir,c.domain_name+".txt")
1050  c.mrc_file = os.path.join(self.gmm_dir,c.domain_name+".mrc")
1051  print('new gmm',c.gmm_file)
1052 
1053  def set_pdb_dir(self,pdb_dir):
1054  """Change the PDB dir"""
1055  self.pdb_dir = pdb_dir
1056  for c in self.component_list:
1057  if not c._orig_pdb_input in ("","None","IDEAL_HELIX","BEADS"):
1058  c.pdb_file = os.path.join(self.pdb_dir,c._orig_pdb_input)
1059 
1060  def set_fasta_dir(self,fasta_dir):
1061  """Change the FASTA dir"""
1062  self.fasta_dir = fasta_dir
1063  for c in self.component_list:
1064  c.fasta_file = os.path.join(self.fasta_dir,c._orig_fasta_file)
1065 
1066  def set_dir(self, default_dir, new_dir):
1067  """DEPRECATED: This old function sets things relative to topology file"""
1068  print("WARNING: set_dir() is deprecated, use set_gmm_dir, set_pdb_dir, or set_fasta_dir. "
1069  "Paths in the TopologyReader constructor or in those functions are relative "
1070  "to the current working directory, not the topology file.")
1071  if default_dir=="gmm_dir":
1072  self.set_gmm_dir(IMP.get_relative_path(self.topology_file,new_dir))
1073  elif default_dir=="pdb_dir":
1074  self.set_pdb_dir(IMP.get_relative_path(self.topology_file,new_dir))
1075  elif default_dir=="fasta_dir":
1076  self.set_fasta_dir(nIMP.get_relative_path(self.topology_file,new_dir))
1077  else:
1078  raise Exception(default_dir, "is not a correct directory key")
1079 
1080  def _is_int(self, s):
1081  # is this string an integer?
1082  try:
1083  float(s)
1084  return float(s).is_integer()
1085  except ValueError:
1086  return False
1087 
1088  def get_rigid_bodies(self):
1089  """Return list of lists of rigid bodies (as domain name)"""
1090  rbl = defaultdict(list)
1091  for c in self.component_list:
1092  for rbnum in c.rigid_bodies:
1093  rbl[rbnum].append(c.domain_name)
1094  return rbl.values()
1095 
1097  """Return list of lists of super rigid bodies (as domain name)"""
1098  rbl = defaultdict(list)
1099  for c in self.component_list:
1100  for rbnum in c.super_rigid_bodies:
1101  rbl[rbnum].append(c.domain_name)
1102  return rbl.values()
1103 
1105  """Return list of lists of chains of super rigid bodies (as domain name)"""
1106  rbl = defaultdict(list)
1107  for c in self.component_list:
1108  for rbnum in c.chain_of_super_rigid_bodies:
1109  rbl[rbnum].append(c.domain_name)
1110  return rbl.values()
1111 
1112 class ComponentTopology(object):
1113  """Stores the components required to build a standard IMP hierarchy
1114  using IMP.pmi.BuildModel()
1115  """
1116  def __init__(self):
1117  self.name = None
1118  self.num_clones = None
1119  self.domain_name = None
1120  self.fasta_file = None
1121  self._orig_fasta_file = None
1122  self.fasta_id = None
1123  self.pdb_file = None
1124  self._orig_pdb_input = None
1125  self.chain = None
1126  self.residue_range = None
1127  self.pdb_offset = 0
1128  self.bead_size = 10
1129  self.em_residues_per_gaussian = 0
1130  self.gmm_file = ''
1131  self.mrc_file = ''
1132  self.density_prefix = ''
1133  self.color = 0.1
1134  self.rigid_bodies = []
1135  self.super_rigid_bodies = []
1136  self.chain_of_super_rigid_bodies = []
1137  def _l2s(self,l):
1138  l = str(l).strip('[').strip(']')
1139  return l
1140  def __repr__(self):
1141  return self.get_str()
1142  def get_str(self):
1143  res_range = self.residue_range
1144  if self.residue_range is None:
1145  res_range = []
1146  return '|'+'|'.join([self.name,self.domain_name,self._orig_fasta_file,self.fasta_id,
1147  self._orig_pdb_input,self.chain,self._l2s(list(res_range)),str(self.pdb_offset),
1148  str(self.bead_size),str(self.em_residues_per_gaussian),self._l2s(self.rigid_bodies),
1149  self._l2s(self.super_rigid_bodies),self._l2s(self.chain_of_super_rigid_bodies)])+'|'
Stores the components required to build a standard IMP hierarchy using IMP.pmi.BuildModel() ...
def __init__
setup a TempResidue
def build
call build on all molecules (automatically makes clones)
def select_at_all_resolutions
Perform selection using the usual keywords but return ALL resolutions (BEADS and GAUSSIANS).
Definition: tools.py:1562
def get_atomic_residues
Return a set of TempResidues that have associated structure coordinates.
def get_residues
Return all modeled TempResidues as a set.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Definition: atom/Atom.h:241
static Atom setup_particle(Model *m, ParticleIndex pi, Atom other)
Definition: atom/Atom.h:242
def build
call build on all states
def __init__
read a fasta file and extract all the requested sequences
static XYZR setup_particle(Model *m, ParticleIndex pi)
Definition: XYZR.h:48
def get_ideal_helices
Returns list of OrderedSets with requested ideal helices.
Miscellaneous utilities.
Definition: tools.py:1
def get_chains_of_super_rigid_bodies
Return list of lists of chains of super rigid bodies (as domain name)
def __init__
The user should not call this directly; instead call State::create_molecule()
def residue_range
get residue range.
def get_molecule
Access a molecule by name and copy number.
def __init__
Define a new state.
def add_representation
Set the representation for some residues.
static State setup_particle(Model *m, ParticleIndex pi, unsigned int index)
Definition: State.h:36
The type of an atom.
def create_molecule
Create a new Molecule within this State.
def build
Create all parts of the IMP hierarchy including Atoms, Residues, and Fragments/Representations and...
static Residue setup_particle(Model *m, ParticleIndex pi, ResidueType t, int index, int insertion_code)
Definition: Residue.h:157
char get_one_letter_code(ResidueType c)
Get the 1-letter amino acid code from the residue type.
def get_non_atomic_residues
Return a set of TempResidues that don't have associated structure coordinates.
def get_name
Return this Molecule name.
def get_hierarchy
Return the IMP Hierarchy corresponding to this Molecule.
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:72
Stores a named protein chain.
A decorator for keeping track of copies of a molecule.
Definition: Copy.h:28
static Hierarchy setup_particle(Model *m, ParticleIndex pi, ParticleIndexesAdaptor children=ParticleIndexesAdaptor())
Create a Hierarchy of level t by adding the needed attributes.
def set_fasta_dir
Change the FASTA dir.
The standard decorator for manipulating molecular structures.
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
A decorator for a particle representing an atom.
Definition: atom/Atom.h:234
def get_component_topologies
Return list of ComponentTopologies for selected components.
std::string get_relative_path(std::string base, std::string relative)
Return a path to a file relative to another file.
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
def create_clone
Create a Molecule clone (automatically builds same structure and representation)
def add_structure
Read a structure and store the coordinates.
def get_molecules
Return a dictionary where key is molecule name and value are the list of all copies of that molecule ...
static Copy setup_particle(Model *m, ParticleIndex pi, Int number)
Definition: Copy.h:42
def get_state
Return the State containing this Molecule.
A decorator for a residue.
Definition: Residue.h:134
General purpose algebraic and geometric methods that are expected to be used by a wide variety of IMP...
Automatically setup Sytem and Degrees of Freedom with a formatted text file.
The general base class for IMP exceptions.
Definition: exception.h:49
def get_rigid_bodies
Return list of lists of rigid bodies (as domain name)
VectorD< 3 > Vector3D
Definition: VectorD.h:395
Residue get_residue(Atom d, bool nothrow=false)
Return the Residue containing this atom.
Class to handle individual model particles.
Definition: Particle.h:37
Stores a list of Molecules all with the same State index.
int get_copy_index(Hierarchy h)
Walk up the hierarchy to find the current copy index.
Python classes to represent, score, sample and analyze models.
A dictionary-like wrapper for reading and storing sequence data.
def create_copy
Create a new Molecule with the same name and sequence but a higher copy number.
Functionality for loading, creating, manipulating and scoring atomic structures.
def get_particles_at_all_resolutions
Helpful utility for getting particles at all resolutions from this molecule.
static Chain setup_particle(Model *m, ParticleIndex pi, std::string id)
Definition: Chain.h:41
Select hierarchy particles identified by the biological name.
Definition: Selection.h:66
def get_number_of_states
returns the total number of states generated
def get_super_rigid_bodies
Return list of lists of super rigid bodies (as domain name)
def set_dir
DEPRECATED: This old function sets things relative to topology file.
def import_topology_file
Read system components from topology file.
Temporarily stores residue information, even without structure available.
def create_state
returns a new IMP.pmi.representation_new.State(), increment the state index