IMP logo
IMP Reference Guide  2.15.0
The Integrative Modeling Platform
system_tools.py
1 from __future__ import print_function, division
2 import IMP
3 import IMP.atom
5 import IMP.pmi
6 import IMP.pmi.tools
7 from collections import defaultdict
8 from math import pi
9 import os
10 import warnings
11 
12 
13 def resnums2str(res):
14  """Take iterable of TempResidues and return compatified string"""
15  if len(res) == 0:
16  return ''
17  idxs = [r.get_index() for r in res]
18  idxs.sort()
19  all_ranges = []
20  cur_range = [idxs[0], idxs[0]]
21  for idx in idxs[1:]:
22  if idx != cur_range[1]+1:
23  all_ranges.append(cur_range)
24  cur_range = [idx, idx]
25  cur_range[1] = idx
26  all_ranges.append(cur_range)
27  ret = ''
28  for nr, r in enumerate(all_ranges):
29  ret += '%i-%i' % (r[0], r[1])
30  if nr < len(all_ranges)-1:
31  ret += ', '
32  return ret
33 
34 
35 def _select_ca_or_p(hiers, **kwargs):
36  """Select all CA (amino acids) or P (nucleic acids) as appropriate"""
37  sel_p = IMP.atom.Selection(hiers, atom_type=IMP.atom.AT_P, **kwargs)
38  ps = sel_p.get_selected_particles()
39  if ps:
40  # detected nucleotides. Selecting phosphorous instead of CA
41  return ps
42  else:
43  sel = IMP.atom.Selection(hiers, atom_type=IMP.atom.AT_CA, **kwargs)
44  return sel.get_selected_particles()
45 
46 
47 def get_structure(model, pdb_fn, chain_id, res_range=None, offset=0,
48  model_num=None, ca_only=False):
49  """read a structure from a PDB file and return a list of residues
50  @param model The IMP model
51  @param pdb_fn The file to read (in traditional PDB or mmCIF format)
52  @param chain_id Chain ID to read
53  @param res_range Add only a specific set of residues.
54  res_range[0] is the starting and res_range[1] is the ending
55  residue index
56  The ending residue can be "END", that will take everything
57  to the end of the sequence.
58  None gets you all.
59  @param offset Apply an offset to the residue indexes of the PDB file
60  @param model_num Read multi-model PDB and return that model (0-based index)
61  @param ca_only Read only CA atoms (by default, all non-waters are read)
62  """
63  # Read file in mmCIF format if requested
64  if pdb_fn.endswith('.cif'):
65  read_file = IMP.atom.read_mmcif
66  read_multi_file = IMP.atom.read_multimodel_mmcif
67  else:
68  read_file = IMP.atom.read_pdb
69  read_multi_file = IMP.atom.read_multimodel_pdb
70  if ca_only:
72  else:
74 
75  reader = read_file if model_num is None else read_multi_file
76  mh = reader(pdb_fn, model,
78  sel))
79  if model_num is not None:
80  mh = mh[model_num]
81 
82  if res_range == [] or res_range is None:
83  ps = _select_ca_or_p(mh, chain=chain_id)
84  else:
85  start = res_range[0]
86  end = res_range[1]
87  if end == "END":
88  end = IMP.atom.Residue(
89  mh.get_children()[0].get_children()[-1]).get_index()
90  ps = _select_ca_or_p(mh, chain=chain_id,
91  residue_indexes=range(start, end+1))
92  ret = []
93 
94  for p in ps:
95  res = IMP.atom.Residue(IMP.atom.Atom(p).get_parent())
96  res.set_index(res.get_index() + offset)
97  ret.append(res)
98  if len(ret) == 0:
99  warnings.warn(
100  "no residues selected from %s in range %s" % (pdb_fn, res_range),
102  return ret
103 
104 
105 def build_bead(model, residues, input_coord=None):
106  """Generates a single bead"""
107 
108  ds_frag = (residues[0].get_index(), residues[-1].get_index())
109  prt = IMP.Particle(model)
111  ptem = IMP.core.XYZR(prt)
112  mass = IMP.atom.get_mass_from_number_of_residues(len(residues))
113 
114  if ds_frag[0] == ds_frag[-1]:
115  rt = residues[0].get_residue_type()
116  h = IMP.atom.Residue.setup_particle(prt, rt, ds_frag[0])
117  h.set_name('%i_bead' % (ds_frag[0]))
118  prt.set_name('%i_bead' % (ds_frag[0]))
119  try:
121  except IMP.ValueException:
123  IMP.atom.ResidueType("ALA"))
125  ptem.set_radius(radius)
126  else:
128  h.set_name('%i-%i_bead' % (ds_frag[0], ds_frag[-1]))
129  prt.set_name('%i-%i_bead' % (ds_frag[0], ds_frag[-1]))
130  h.set_residue_indexes(range(ds_frag[0], ds_frag[-1] + 1))
131  volume = IMP.atom.get_volume_from_mass(mass)
132  radius = 0.8 * (3.0 / 4.0 / pi * volume) ** (1.0 / 3.0)
133  ptem.set_radius(radius)
134 
136  try:
137  if tuple(input_coord) is not None:
138  ptem.set_coordinates(input_coord)
139  except TypeError:
140  pass
141  return h
142 
143 
144 def build_necklace(model, residues, resolution, input_coord=None):
145  """Generates a string of beads with given length"""
146  out_hiers = []
147  for chunk in list(IMP.pmi.tools.list_chunks_iterator(residues,
148  resolution)):
149  out_hiers.append(build_bead(model, chunk, input_coord=input_coord))
150  return out_hiers
151 
152 
153 def build_ca_centers(model, residues):
154  """Create a bead on the CA position with coarsened size and mass"""
155  out_hiers = []
156  for tempres in residues:
157  residue = tempres.get_hierarchy()
158  rp1 = IMP.Particle(model)
159  rp1.set_name("Residue_%i" % residue.get_index())
160  rt = residue.get_residue_type()
161  this_res = IMP.atom.Residue.setup_particle(rp1, residue)
162  try:
164  except IMP.ValueException:
166  IMP.atom.ResidueType("ALA"))
167  try:
168  mass = IMP.atom.get_mass(rt)
169  except Exception:
171  calpha = IMP.atom.Selection(
172  residue, atom_type=IMP.atom.AT_CA).get_selected_particles()
173  cp = IMP.atom.Selection(
174  residue, atom_type=IMP.atom.AT_P).get_selected_particles()
175 
176  if len(calpha) == 1:
177  central_atom = calpha[0]
178  elif len(cp) == 1:
179  central_atom = cp[0]
180  else:
181  raise("build_ca_centers: weird selection (no Ca, no "
182  "nucleotide P or ambiguous selection found)")
184  shape = IMP.algebra.Sphere3D(
185  IMP.core.XYZ(central_atom).get_coordinates(), radius)
186  IMP.core.XYZR.setup_particle(rp1, shape)
188  out_hiers.append(this_res)
189  return out_hiers
190 
191 
192 def setup_bead_as_gaussian(mh):
193  """Setup bead as spherical gaussian, using radius as variance"""
194  p = mh.get_particle()
195  center = IMP.core.XYZ(p).get_coordinates()
196  rad = IMP.core.XYZR(p).get_radius()
200  [rad]*3)
202 
203 
204 def show_representation(node):
205  print(node)
207  repr = IMP.atom.Representation(node)
208  resolutions = repr.get_resolutions()
209  for r in resolutions:
210  print('---- resolution %i ----' % r)
211  IMP.atom.show_molecular_hierarchy(repr.get_representation(r))
212  return True
213  else:
214  return False
215 
216 
217 def _get_color_for_representation(rep):
218  """Return an IMP.display.Color object (or None) for the given
219  Representation."""
220  if rep.color is not None:
221  if isinstance(rep.color, float):
222  return IMP.display.get_rgb_color(rep.color)
223  elif isinstance(rep.color, str):
224  return IMP.display.Color(*IMP.pmi.tools.color2rgb(rep.color))
225  elif hasattr(rep.color, '__iter__') and len(rep.color) == 3:
226  return IMP.display.Color(*rep.color)
227  elif isinstance(rep.color, IMP.display.Color):
228  return rep.color
229  else:
230  raise TypeError("Color must be Chimera color name, a hex "
231  "string, a float or (r,g,b) tuple")
232 
233 
234 def _add_fragment_provenance(fragment, first_residue, rephandler):
235  """Track the original source of a fragment's structure.
236  If the residues in the given fragment were extracted from a PDB
237  file, add suitable provenance information to the Model (the name
238  of that file, chain ID, and residue index offset)."""
239  pdb_element = rephandler.pdb_for_residue.get(first_residue.get_index())
240  if pdb_element:
241  m = fragment.get_model()
242  p = IMP.Particle(m, "input structure")
244  p, pdb_element.filename, pdb_element.chain_id, pdb_element.offset)
245  IMP.core.add_provenance(m, fragment, sp)
246 
247 
248 def build_representation(parent, rep, coord_finder, rephandler):
249  """Create requested representation.
250  For beads, identifies continuous segments and sets up as Representation.
251  If any volume-based representations (e.g.,densities) are requested,
252  will instead create a single Representation node.
253  All reps are added as children of the passed parent.
254  @param parent The Molecule to which we'll add add representations
255  @param rep What to build. An instance of pmi::topology::_Representation
256  @param coord_finder A _FindCloseStructure object to help localize beads
257  """
258  built_reps = []
259  atomic_res = 0
260  ca_res = 1
261  model = parent.hier.get_model()
262  color = _get_color_for_representation(rep)
263 
264  # first get the primary representation (currently, the smallest bead size)
265  # eventually we won't require beads to be present at all
266  primary_resolution = min(rep.bead_resolutions)
267 
268  # if collective densities, will return single node with everything
269  # below we sample or read the GMMs and add them as representation
270  # flag indicating grouping nonlinear segments with one GMM
271  single_node = False
272  if rep.density_residues_per_component:
273  single_node = True
274  num_components = (len(rep.residues)
275  // rep.density_residues_per_component+1)
276  rep_dict = defaultdict(list)
277  segp = IMP.Particle(model)
278  root_representation = IMP.atom.Representation.setup_particle(
279  segp, primary_resolution)
280  built_reps.append(root_representation)
281  res_nums = [r.get_index() for r in rep.residues]
282  IMP.atom.Fragment.setup_particle(segp, res_nums)
283  density_frag = IMP.atom.Fragment.setup_particle(
284  IMP.Particle(model), res_nums)
285  density_frag.get_particle().set_name(
286  "Densities %i" % rep.density_residues_per_component)
287  density_ps = []
288 
289  if os.path.exists(rep.density_prefix + '.txt') \
290  and not rep.density_force_compute:
292  rep.density_prefix + '.txt', density_ps, model)
293  if (len(density_ps) != num_components
294  or not os.path.exists(rep.density_prefix + '.txt')
295  or rep.density_force_compute):
296  fit_coords = []
297  total_mass = 0.0
298  for r in rep.residues:
299  for p in IMP.core.get_leaves(r.hier):
300  fit_coords.append(IMP.core.XYZ(p).get_coordinates())
301  total_mass += IMP.atom.Mass(p).get_mass()
302 
303  # fit GMM
304  density_ps = []
306  num_components,
307  model,
308  density_ps,
309  min_covar=4.0,
310  mass_multiplier=total_mass)
311 
313  rep.density_prefix + '.txt')
314  if rep.density_voxel_size > 0.0:
316  density_ps, rep.density_prefix + '.mrc',
317  rep.density_voxel_size, fast=True)
318 
319  for n, d in enumerate(density_ps):
320  d.set_name('Density #%d' % n)
321  density_frag.add_child(d)
322  root_representation.add_representation(
323  density_frag, IMP.atom.DENSITIES,
324  rep.density_residues_per_component)
325 
326  # get continuous segments from residues
327  segments = []
328  rsort = sorted(list(rep.residues), key=lambda r: r.get_index())
329  prev_idx = rsort[0].get_index()-1
330  prev_structure = rsort[0].get_has_structure()
331  cur_seg = []
332  force_break = False
333  for nr, r in enumerate(rsort):
334  if (r.get_index() != prev_idx+1
335  or r.get_has_structure() != prev_structure or force_break):
336  segments.append(cur_seg)
337  cur_seg = []
338  force_break = False
339  cur_seg.append(r)
340  prev_idx = r.get_index()
341  prev_structure = r.get_has_structure()
342  if r.get_index()-1 in rep.bead_extra_breaks:
343  force_break = True
344  if cur_seg != []:
345  segments.append(cur_seg)
346 
347  # for each segment, merge into beads
348  name_all = 'frags:'
349  name_count = 0
350  for frag_res in segments:
351  res_nums = [r.get_index() for r in frag_res]
352  rrange = "%i-%i" % (res_nums[0], res_nums[-1])
353  name = "Frag_" + rrange
354  if name_count < 3:
355  name_all += rrange + ','
356  elif name_count == 3:
357  name_all += '...'
358  name_count += 1
359  segp = IMP.Particle(model, name)
360  IMP.atom.Fragment.setup_particle(segp, res_nums)
361  if not single_node:
362  this_representation = IMP.atom.Representation.setup_particle(
363  segp, primary_resolution)
364  built_reps.append(this_representation)
365  for resolution in rep.bead_resolutions:
366  fp = IMP.Particle(model)
367  this_resolution = IMP.atom.Fragment.setup_particle(fp, res_nums)
368  this_resolution.set_name("%s: Res %i" % (name, resolution))
369  if frag_res[0].get_has_structure():
370  _add_fragment_provenance(this_resolution, frag_res[0],
371  rephandler)
372  # if structured, merge particles as needed
373  if resolution == atomic_res:
374  for residue in frag_res:
375  this_resolution.add_child(residue.get_hierarchy())
376  elif resolution == ca_res and rep.bead_ca_centers:
377  beads = build_ca_centers(model, frag_res)
378  for bead in beads:
379  this_resolution.add_child(bead)
380  else:
382  "X")
383  for residue in frag_res:
384  tempc.add_child(IMP.atom.create_clone(residue.hier))
386  tempc, resolution)
387  for bead in beads.get_children():
388  this_resolution.add_child(bead)
389  del tempc
390  del beads
391  else:
392  # if unstructured, create necklace
393  input_coord = coord_finder.find_nearest_coord(
394  min(r.get_index() for r in frag_res))
395  if input_coord is None:
396  input_coord = rep.bead_default_coord
397  beads = build_necklace(model,
398  frag_res,
399  resolution,
400  input_coord)
401  for bead in beads:
402  this_resolution.add_child(bead)
403 
404  # if requested, color all resolutions the same
405  if color:
406  for lv in IMP.core.get_leaves(this_resolution):
408 
409  # finally decide where to put this resolution
410  # if volumetric, collect resolutions from different
411  # segments together
412  if single_node:
413  rep_dict[resolution] += this_resolution.get_children()
414  else:
415  if resolution == primary_resolution:
416  this_representation.add_child(this_resolution)
417  else:
418  this_representation.add_representation(this_resolution,
419  IMP.atom.BALLS,
420  resolution)
421  # if individual beads to be setup as Gaussians:
422  if rep.setup_particles_as_densities:
423  for p in IMP.core.get_leaves(this_resolution):
424  setup_bead_as_gaussian(p)
425  this_resolution.set_name(
426  this_resolution.get_name() + ' Densities %i' % resolution)
427  this_representation.add_representation(this_resolution,
428  IMP.atom.DENSITIES,
429  resolution)
430 
431  if single_node:
432  root_representation.set_name(name_all.strip(',') + ": Base")
433  d = root_representation.get_representations(IMP.atom.DENSITIES)
434  d[0].set_name('%s: ' % name_all + d[0].get_name())
435  for resolution in rep.bead_resolutions:
436  this_resolution = IMP.atom.Fragment.setup_particle(
437  IMP.Particle(model),
438  [r.get_index() for r in rep.residues])
439  this_resolution.set_name("%s: Res %i" % (name_all, resolution))
440  for hier in rep_dict[resolution]:
441  this_resolution.add_child(hier)
442  if resolution == primary_resolution:
443  root_representation.add_child(this_resolution)
444  else:
445  root_representation.add_representation(this_resolution,
446  IMP.atom.BALLS,
447  resolution)
448  return built_reps
def list_chunks_iterator
Yield successive length-sized chunks from a list.
Definition: tools.py:659
Tools for handling Gaussian Mixture Models.
Definition: gmm_tools.py:1
Add mass to a particle.
Definition: Mass.h:23
double get_volume_from_residue_type(ResidueType rt)
Return an estimate for the volume of a given residue.
Simple 3D transformation class.
Represent an RGB color.
Definition: Color.h:24
static Gaussian setup_particle(Model *m, ParticleIndex pi)
Definition: core/Gaussian.h:48
void show_molecular_hierarchy(Hierarchy h)
Print out the molecular hierarchy.
static Fragment setup_particle(Model *m, ParticleIndex pi)
Definition: Fragment.h:63
double get_mass(const Selection &s)
Get the total mass of a hierarchy, in Daltons.
static XYZR setup_particle(Model *m, ParticleIndex pi)
Definition: XYZR.h:48
Select atoms which are selected by both selectors.
Definition: pdb.h:348
double get_mass(ResidueType c)
Get the mass from the residue type.
static StructureProvenance setup_particle(Model *m, ParticleIndex pi, std::string filename, std::string chain_id, int residue_offset)
Definition: provenance.h:157
Color get_rgb_color(double f)
Return the color for f from the RGB color map.
double get_mass_from_number_of_residues(unsigned int num_aa)
Estimate the mass of a protein from the number of amino acids.
Miscellaneous utilities.
Definition: tools.py:1
double get_ball_radius_from_volume_3d(double volume)
Return the radius of a sphere with a given volume.
Definition: Sphere3D.h:35
static Residue setup_particle(Model *m, ParticleIndex pi, ResidueType t, int index, int insertion_code)
Definition: Residue.h:158
static Representation setup_particle(Model *m, ParticleIndex pi)
GenericHierarchies get_leaves(Hierarchy mhd)
Get all the leaves of the bit of hierarchy.
A reference frame in 3D.
def color2rgb
Given a Chimera color name or hex color value, return RGB.
Definition: tools.py:1626
Warning related to handling of structures.
A Gaussian distribution in 3D.
Definition: Gaussian3D.h:24
def fit_gmm_to_points
fit a GMM to some points.
Definition: gmm_tools.py:233
A decorator for a representation.
double get_volume_from_mass(double m, ProteinDensityReference ref=ALBER)
Estimate the volume of a protein from its mass.
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
static Mass setup_particle(Model *m, ParticleIndex pi, Float mass)
Definition: Mass.h:48
The type for a residue.
PDBSelector * get_default_pdb_selector()
Definition: pdb.h:473
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
static Colored setup_particle(Model *m, ParticleIndex pi, Color color)
Definition: Colored.h:62
def write_gmm_to_map
write density map from GMM.
Definition: gmm_tools.py:115
A decorator for a residue.
Definition: Residue.h:135
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Hierarchy create_simplified_along_backbone(Chain input, const IntRanges &residue_segments, bool keep_detailed=false)
Rotation3D get_identity_rotation_3d()
Return a rotation that does not do anything.
Definition: Rotation3D.h:356
Class to handle individual particles of a Model object.
Definition: Particle.h:41
Select all CA ATOM records.
Definition: pdb.h:77
Python classes to represent, score, sample and analyze models.
def write_gmm_to_text
write a list of gaussians to text.
Definition: gmm_tools.py:64
Functionality for loading, creating, manipulating and scoring atomic structures.
void add_provenance(Model *m, ParticleIndex pi, Provenance p)
Add provenance to part of the model.
static Chain setup_particle(Model *m, ParticleIndex pi, std::string id)
Definition: Chain.h:81
An exception for an invalid value being passed to IMP.
Definition: exception.h:137
Select hierarchy particles identified by the biological name.
Definition: Selection.h:66
Select all ATOM and HETATM records with the given chain ids.
Definition: pdb.h:189
def decorate_gmm_from_text
read the output from write_gmm_to_text, decorate as Gaussian and Mass
Definition: gmm_tools.py:23
A decorator for a particle with x,y,z coordinates and a radius.
Definition: XYZR.h:27