IMP logo
IMP Reference Guide  2.13.0
The Integrative Modeling Platform
precision_rmsd.py
1 from __future__ import print_function
2 import os,sys
3 import numpy
4 import string
5 import IMP
6 import IMP.em
7 import pyRMSD.RMSDCalculator
8 
9 def parse_custom_ranges(ranges_file):
10  with open(ranges_file) as fh:
11  d = {}
12  exec(fh.read(), d)
13  return d['density_custom_ranges']
14 
15 
16 def get_particles_from_superposed(cluster_conform_i, cluster_conform_0, align, ps, trans):
17  def _to_vector3ds(numpy_array):
18  # No need to fit the whole array - we only need 4 non-coplanar points,
19  # so 100 should be plenty
20  return [IMP.algebra.Vector3D(c) for c in numpy_array[:100]]
21 
22  if align:
23  calculator = pyRMSD.RMSDCalculator.RMSDCalculator("QCP_SERIAL_CALCULATOR", numpy.array([cluster_conform_0, cluster_conform_i]))
24  else:
25  calculator = pyRMSD.RMSDCalculator.RMSDCalculator("NOSUP_SERIAL_CALCULATOR", numpy.array([cluster_conform_0, cluster_conform_i]))
26 
27  rmsd, superposed_fit = calculator.pairwise(0, 1, get_superposed_coordinates = True)
28  # Get transformation from pyRMSD reference on the first call.
29  # This is somewhat inefficient (since we are essentially repeating
30  # the pyRMSD calculation) but pyRMSD doesn't appear to make its
31  # reference orientation available.
32  if trans is None:
34  _to_vector3ds(superposed_fit[0]), _to_vector3ds(cluster_conform_0))
35 
36  for particle_index in range(len(superposed_fit[1])):
37  # Transform from pyRMSD back to original reference
38  IMP.core.XYZ(ps[particle_index]).set_coordinates(trans * IMP.algebra.Vector3D(superposed_fit[1][particle_index]))
39 
40  return rmsd, ps, trans
41 
42 class GetModelDensity(object):
43  """Compute mean density maps from structures.
44  Keeps a dictionary of density maps,
45  keys are in the custom ranges. When you call add_subunits_density, it adds
46  particle coordinates to the existing density maps.
47  """
48 
49  def __init__(self, custom_ranges=None, resolution=20.0, voxel=5.0, bead_names = None):
50  """Constructor.
51  @param list of particles decorated with mass, radius, and XYZ
52  @param resolution The MRC resolution of the output map (in Angstrom unit)
53  @param voxel The voxel size for the output map (lower is slower)
54  """
55 
56  self.MRCresolution = resolution
57  self.voxel = voxel
58  self.count_models = 0.0
59  self.densities={}
60  self.bead_names = bead_names
61  self.custom_ranges=custom_ranges
62 
63  # for each custom range get the particle indices that will be added to the density for that custom range
64  self.particle_indices_in_custom_ranges={}
65 
66  for density_name in self.custom_ranges:
67  self.particle_indices_in_custom_ranges[density_name]=[]
68 
69  # go through each bead, put it in the appropriate custom range(s)
70  for index,beadname in enumerate(self.bead_names):
71  for density_name in self.custom_ranges:
72  for domain in self.custom_ranges[density_name]: # each domain in the list custom_ranges[density_name]
73  if self._is_contained(beadname,domain):
74  self.particle_indices_in_custom_ranges[density_name].append(index)
75  #print(beadname,"is in",domain)
76  break # already added particle to this custom range
77 
78  def normalize_density(self):
79  pass
80 
81  def _create_density_from_particles(self, ps, name,
82  kernel_type='GAUSSIAN'):
83  '''Internal function for adding to densities.
84  pass XYZR particles with mass and create a density from them.
85  kernel type options are GAUSSIAN, BINARIZED_SPHERE, and SPHERE.'''
86  kd = {
87  'GAUSSIAN': IMP.em.GAUSSIAN,
88  'BINARIZED_SPHERE': IMP.em.BINARIZED_SPHERE,
89  'SPHERE': IMP.em.SPHERE}
90  dmap = IMP.em.SampledDensityMap(ps, self.MRCresolution, self.voxel)
91  dmap.calcRMS()
92  dmap.set_was_used(True)
93 
94  if name not in self.densities:
95  self.densities[name] = dmap
96  else:
97  bbox1 = IMP.em.get_bounding_box(self.densities[name])
98  bbox2 = IMP.em.get_bounding_box(dmap)
99  bbox1 += bbox2
100  dmap3 = IMP.em.create_density_map(bbox1,self.voxel)
101  dmap3.set_was_used(True)
102  dmap3.add(dmap)
103  dmap3.add(self.densities[name])
104  self.densities[name] = dmap3
105 
106  def _is_contained(self,bead_name,domain):
107  """ domain can be the name of a single protein or a tuple (start_residue,end_residue,protein_name)
108  bead is a string of type moleculeName_startResidue_endResidue
109  """
110 
111  (bead_protein, bead_res_start,
112  bead_res_end, bead_copy) = bead_name.split("_")
113 
114  # protein name and copy number check
115  if isinstance(domain, tuple):
116  domain_protein = domain[2]
117  else:
118  domain_protein = domain
119  # A period indicates that we have a copy number
120  if "." in domain_protein:
121  spl = domain_protein.split(".")
122  domain_protein = spl[0]
123  domain_copy = int(spl[1])
124  else:
125  domain_copy = bead_copy = -1
126 
127  if bead_protein != domain_protein or int(bead_copy) != domain_copy:
128  return False
129 
130  # residue range check
131  if isinstance(domain, tuple):
132  bead_residues = set(range(int(bead_res_start),int(bead_res_end)+1))
133  domain_residues = set(range(int(domain[0]),int(domain[1])+1))
134  return not domain_residues.isdisjoint(bead_residues)
135  else:
136  return True
137 
138  def add_subunits_density(self, ps):
139  """Add a frame to the densities.
140  @param ps List of particles decorated with XYZR and Mass.
141  """
142  self.count_models += 1.0
143  # initialize custom list of particles
144  particles_custom_ranges={}
145  for density_name in self.custom_ranges:
146  particles_custom_ranges[density_name]=[]
147 
148  # add each particle to the relevant custom list
149  for density_name in self.custom_ranges:
150  for particle_index in self.particle_indices_in_custom_ranges[density_name]:
151  particles_custom_ranges[density_name].append(ps[particle_index])
152 
153  #finally, add each custom particle list to the density
154  for density_name in self.custom_ranges:
155  self._create_density_from_particles(particles_custom_ranges[density_name],density_name)
156 
157  def get_density_keys(self):
158  return list(self.densities.keys())
159 
160  def get_density(self,name):
161  """Get the current density for some component name"""
162  if name not in self.densities:
163  return None
164  else:
165  return self.densities[name]
166 
167  def write_mrc(self, path="./",file_prefix=""):
168  for density_name in self.densities:
169  self.densities[density_name].multiply(1. / self.count_models)
170  IMP.em.write_map(
171  self.densities[density_name],
172  path + "/" + file_prefix + "_"+ density_name + ".mrc",
def get_density
Get the current density for some component name.
Compute mean density maps from structures.
Class for sampling a density map from particles.
DensityMap * multiply(const DensityMap *m1, const DensityMap *m2)
Return a density map for which voxel i contains the result of m1[i]*m2[i].
DensityMap * create_density_map(const IMP::algebra::GridD< 3, S, V, E > &arg)
Create a density map from an arbitrary IMP::algebra::GridD.
Definition: DensityMap.h:633
def add_subunits_density
Add a frame to the densities.
Basic utilities for handling cryo-electron microscopy 3D density maps.
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
algebra::BoundingBoxD< 3 > get_bounding_box(const DensityMap *m)
Definition: DensityMap.h:464
VectorD< 3 > Vector3D
Definition: VectorD.h:421
Transformation3D get_transformation_aligning_first_to_second(Vector3Ds a, Vector3Ds b)