IMP logo
IMP Reference Guide  2.7.0
The Integrative Modeling Platform
lib/IMP/pmi/restraints/em.py
1 """@namespace IMP.pmi.restraints.em
2 Restraints for handling electron microscopy maps.
3 """
4 
5 from __future__ import print_function
6 import IMP
7 import IMP.core
8 import IMP.algebra
9 import IMP.atom
10 import IMP.container
11 import IMP.isd
12 import IMP.pmi.tools
13 import IMP.pmi.metadata
14 import IMP.isd.gmm_tools
15 import sys
16 import re
17 import os
18 from math import sqrt
19 
20 class GaussianEMRestraint(object):
21  """Fit Gaussian-decorated particles to an EM map
22  (also represented with a set of Gaussians)
23  \note This class wraps an isd::GaussianEMRestraint
24  """
25  def __init__(self, densities,
26  target_fn='',
27  target_ps=[],
28  cutoff_dist_model_model=0.0,
29  cutoff_dist_model_data=0.0,
30  target_mass_scale=1.0,
31  target_mass=None,
32  target_radii_scale=3.0,
33  model_radii_scale=1.0,
34  slope=0.0,
35  spherical_gaussians=False,
36  close_pair_container=None,
37  backbone_slope=False,
38  scale_target_to_mass=False,
39  weight=1.0,
40  target_is_rigid_body=False,
41  local=False,
42  representation=None):
43  """Constructor.
44  @param densities The Gaussian-decorated particles to be restrained
45  @param target_fn GMM file of the target density map
46  (alternatively, pass the ps)
47  @param target_ps List of Gaussians of the target map
48  (alternatively, pass the filename)
49  @param cutoff_dist_model_model Distance in model-model close
50  pair container
51  @param cutoff_dist_model_data Distance in model-data close pair
52  container. Usually can set to zero because we multiply the
53  target radii
54  @param target_mass_scale Scale up the target densities so that
55  the mass is accurate.
56  Needed if the GMM you generated was not already scaled.
57  To make it the same as model mass, set scale_to_target_mass=True
58  @param target_mass Sets the mass of the target density to the given value. Default is None. This
59  will override target_mass_scale argument
60  @param target_radii_scale Scale the target density radii -
61  only used for the close pair container.
62  If you keep this at 3.0 or so you don't have to use cutoff dist.
63  @param model_radii_scale Scale the model density radii - only used
64  for the close pair container
65  @param slope Linear term added to help bring model into the density
66  @param spherical_gaussians Set to True for a speed bonus when
67  the model densities are spheres. (This means you don't have
68  to do a matrix multiplication if they rotate.)
69  @param close_pair_container Pass a close pair container for
70  the model if you already have one (e.g. for an excluded
71  volume restraint.) May give a speed bonus.
72  @param backbone_slope Only apply slope to backbone particles -
73  only matters for atomic
74  @param scale_target_to_mass Set True if you would need to scale
75  target to EXACTLY the model mass
76  @param weight The restraint weight
77  @param target_is_rigid_body Set True if you want to put the target density particles
78  into a rigid body that need to be sampled (e.g.,when you need to fit one density
79  against another one). Default is False.
80  @param local Only consider density particles that are within the
81  specified model-density cutoff (experimental)
82  """
83 
84  # some parameters
85  self.label = "None"
86  self.sigmaissampled = False
87  self.sigmamaxtrans = 0.3
88  self.sigmamin = 1.0
89  self.sigmamax = 100.0
90  self.sigmainit = 1.0
91  self.label = "None"
92  self.densities = densities
93  self.em_root_hier = None
94 
95  # setup target GMM
96  self.m = self.densities[0].get_model()
97 
98  if scale_target_to_mass:
99  def hierarchy_mass(h):
100  leaves = IMP.atom.get_leaves(h)
101  return sum(IMP.atom.Mass(p).get_mass() for p in leaves)
102  target_mass = sum(hierarchy_mass(h) for h in densities)
103  print('will set target mass to', target_mass)
104  print('will scale target mass by', target_mass_scale)
105 
106  if target_fn != '':
107  self._set_dataset(target_fn, representation)
108  self.target_ps = []
110  target_fn,
111  self.target_ps,
112  self.m,
113  radius_scale=target_radii_scale,
114  mass_scale=target_mass_scale)
115  elif target_ps != []:
116  self.target_ps = target_ps
117  else:
118  print('Gaussian EM restraint: must provide target density file or properly set up target densities')
119  return
120 
121  if target_mass:
122  tmass=sum([IMP.atom.Mass(p).get_mass() for p in self.target_ps])
123  scale=target_mass/tmass
124  for p in self.target_ps:
125  ms=IMP.atom.Mass(p).get_mass()
126  IMP.atom.Mass(p).set_mass(ms*scale)
127 
128  if representation:
129  for p in representation._protocol_output:
130  p.add_em3d_restraint(self.target_ps, self.densities, self)
131 
132  # setup model GMM
133  self.model_ps = []
134  for h in self.densities:
135  self.model_ps += [ k.get_particle() for k in IMP.atom.get_leaves(h) ]
136  if model_radii_scale != 1.0:
137  for p in self.model_ps:
138  rmax = sqrt(max(IMP.core.Gaussian(p).get_variances())) * \
139  model_radii_scale
140  if not IMP.core.XYZR.get_is_setup(p):
142  else:
143  IMP.core.XYZR(p).set_radius(rmax)
144  #wrap target particles in rigid body if requested
145  if target_is_rigid_body:
146  #p = IMP.Particle(self.m)
147  #self.rb=IMP.core.RigidBody.setup_particle(p,self.target_ps)
148  self.rb=IMP.atom.create_rigid_body(self.target_ps)
149  else:
150  self.rb=None
151 
152  # sigma particle
153  self.sigmaglobal = IMP.pmi.tools.SetupNuisance(self.m, self.sigmainit,
154  self.sigmamin, self.sigmamax,
155  self.sigmaissampled).get_particle()
156 
157  # create restraint
158  print('target num particles', len(self.target_ps), \
159  'total weight', sum([IMP.atom.Mass(p).get_mass()
160  for p in self.target_ps]))
161  print('model num particles', len(self.model_ps), \
162  'total weight', sum([IMP.atom.Mass(p).get_mass()
163  for p in self.model_ps]))
164 
165  update_model=not spherical_gaussians
166  log_score=False
167  self.gaussianEM_restraint = IMP.isd.GaussianEMRestraint(
168  self.m,
169  IMP.get_indexes(self.model_ps),
170  IMP.get_indexes(self.target_ps),
171  self.sigmaglobal.get_particle().get_index(),
172  cutoff_dist_model_model,
173  cutoff_dist_model_data,
174  slope,
175  update_model, backbone_slope, local)
176 
177  print('done EM setup')
178  self.rs = IMP.RestraintSet(self.m, 'GaussianEMRestraint')
179  self.rs.add_restraint(self.gaussianEM_restraint)
180  self.set_weight(weight)
181 
182  def _set_dataset(self, target_fn, representation):
183  """Set the dataset to point to the input file"""
184  if representation:
185  self.dataset = representation.get_file_dataset(target_fn)
186  if self.dataset:
187  return
188  l = IMP.pmi.metadata.FileLocation(target_fn)
189  self.dataset = IMP.pmi.metadata.EMDensityDataset(l)
190  # If the GMM was derived from an MRC file that exists, add that too
191  m = re.match('(.*\.mrc)\..*\.txt$', target_fn)
192  if m and os.path.exists(m.group(1)):
193  l = IMP.pmi.metadata.FileLocation(path=m.group(1),
194  details='Original MRC file from which the GMM was derived')
195  self.dataset.add_parent(IMP.pmi.metadata.EMDensityDataset(l))
196 
197  def center_target_density_on_model(self):
198  target_com = IMP.algebra.Vector3D(0, 0, 0)
199  target_mass = 0.0
200  for p in self.target_ps:
201  mass = IMP.atom.Mass(p).get_mass()
202  pos = IMP.core.XYZ(p).get_coordinates()
203  target_com += pos * mass
204  target_mass += mass
205  target_com /= target_mass
206  print('target com', target_com)
207  model_com = IMP.algebra.Vector3D(0, 0, 0)
208  model_mass = 0.0
209  for p in self.model_ps:
210  mass = IMP.atom.Mass(p).get_mass()
211  pos = IMP.core.XYZ(p).get_coordinates()
212  model_com += pos * mass
213  model_mass += mass
214  model_com /= model_mass
215  print('model com', model_com)
216 
217  v = target_com - model_com
218  print('translating with', -v)
220  for p in self.target_ps:
221  IMP.core.transform(IMP.core.RigidBody(p), transformation)
222  # IMP.pmi.tools.translate_hierarchies(self.densities,v)
223 
224  def get_center_of_mass(self, target=True):
225  '''Returns the geometric center of the GMM particles
226  @param target = True - returns target map gmm COM
227  @param target = False - returns model gmm COM'''
228  com = IMP.algebra.Vector3D(0, 0, 0)
229  total_mass = 0.0
230  if target:
231  ps = self.target_ps
232  else:
233  ps = self.model_ps
234  for p in ps:
235  mass = IMP.atom.Mass(p).get_mass()
236  pos = IMP.core.XYZ(p).get_coordinates()
237  com += pos * mass
238  total_mass += mass
239  com /= total_mass
240  return com
241 
242  def center_target_density_on_origin(self):
243  target_com = self.get_center_of_mass()
244  print('target com', target_com)
245  model_com = IMP.algebra.Vector3D(0, 0, 0)
246  print('model com', model_com)
247  v = target_com - model_com
248  print('translating with', -v)
250  for p in self.target_ps:
251  IMP.core.transform(IMP.core.RigidBody(p), transformation)
252  # IMP.pmi.tools.translate_hierarchies(self.densities,v)
253 
254  def center_model_on_target_density(self, input_object):
255  if type(input_object) is IMP.pmi.representation.Representation:
256  hier = input_object.prot
257  elif type(input_object) is IMP.pmi.topology.State:
258  hier = input_object.get_hierarchy()
259  else:
260  raise Exception("Input must be a Representation or topology.State object")
261  target_com = self.get_center_of_mass()
262  print('target com', target_com)
263  model_com = self.get_center_of_mass(target=False)
264  print('model com', model_com)
265  v = target_com - model_com
266  print('translating with', v)
268 
269  rigid_bodies = set()
270  XYZRs = set()
271 
272  for p in IMP.atom.get_leaves(hier):
274  rb = IMP.core.RigidBodyMember(p).get_rigid_body()
275  rigid_bodies.add(rb)
277  XYZRs.add(p)
278 
279  for rb in list(rigid_bodies):
280  IMP.core.transform(rb, transformation)
281 
282  for p in list(XYZRs):
283  IMP.core.transform(IMP.core.XYZ(p), transformation)
284 
285  def center_on_target_density(self):
286  target_com = self.get_center_of_mass()
287  print('target com', target_com)
288  model_com = self.get_center_of_mass(target=False)
289  print('model com', model_com)
290  v = target_com - model_com
291  print('translating with', v)
293 
294  rigid_bodies = set()
295  XYZRs = set()
296 
297  for p in self.model_ps:
299  rb = IMP.core.RigidBodyMember(p).get_rigid_body()
300  rigid_bodies.add(rb)
302  XYZRs.add(p)
303 
304  for rb in list(rigid_bodies):
305  IMP.core.transform(rb, transformation)
306 
307  for p in list(XYZRs):
308  IMP.core.transform(IMP.core.XYZ(p), transformation)
309 
310 
311 
312 
313  def set_weight(self,weight):
314  self.weight = weight
315  self.rs.set_weight(weight)
316 
317  def set_label(self, label):
318  self.label = label
319 
320  def add_to_model(self):
321  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
322 
323  def get_particles_to_sample(self):
324  ps = {}
325  if self.sigmaissampled:
326  ps["Nuisances_GaussianEMRestraint_sigma_" +
327  self.label] = ([self.sigmaglobal], self.sigmamaxtrans)
328  if self.rb:
329  ps["Rigid_Bodies_GaussianEMRestraint"] = (
330  [self.rb],
331  4,
332  0.03)
333  return ps
334 
335  def get_rigid_body(self):
336  if self.rb is None:
337  raise Exception("No rigid body created for GMM particles. Ensure target_is_rigid_body is set to True")
338  return self.rb
339 
340  def get_density_as_hierarchy(self):
341  if self.em_root_hier is None:
342  self.em_root_hier = IMP.atom.Copy.setup_particle(IMP.Particle(self.m),0)
343  self.em_root_hier.set_name("GaussianEMRestraint_density_"+self.label)
344  for p in self.target_ps:
345  self.em_root_hier.add_child(p)
346  return self.em_root_hier
347 
349  ''' Can add a target GMM to a Hierarchy.
350  For PMI2 a state object may also be passed'''
351  if type(inp) is IMP.pmi.topology.State:
352  inp.get_hierarchy().add_child(self.get_density_as_hierarchy())
353  elif type(inp) is IMP.atom.Hierarchy:
354  inp.add_child(self.get_density_as_hierarchy())
355  else:
356  raise Exception("Can only add a density to a PMI State object or IMP.atom.Hierarchy. You passed a", type(inp))
357 
358  def get_restraint_set(self):
359  return self.rs
360 
361  def get_output(self):
362  self.m.update()
363  output = {}
364  score = self.weight * self.rs.unprotected_evaluate(None)
365  output["_TotalScore"] = str(score)
366  output["GaussianEMRestraint_" +
367  self.label] = str(score)
368  output["GaussianEMRestraint_sigma_" +
369  self.label] = str(self.sigmaglobal.get_scale())
370  return output
371 
372  def evaluate(self):
373  return self.weight * self.rs.unprotected_evaluate(None)
374 
375  def write_target_gmm_to_mrc(self, fileout=None, voxel_size=5.0):
376  '''Writes target GMM file to MRC'''
377  if fileout is None:
378  fileout="Gaussian_map_" + self.label + ".mrc"
379  IMP.isd.gmm_tools.write_gmm_to_map(self.target_ps, fileout, voxel_size)
380  return fileout
381 
382 
383 #-------------------------------------------
384 
386  """Fit particles to an EM map. This creates a simulate density map and updates them every eval.
387  \note Wraps an em::FitRestraint
388  """
389  def __init__(self,
390  ps,
391  dmap,
392  resolution,
393  origin=None,
394  voxel_size=None,
395  weight=1.0,
396  label=""):
397  """Constructor
398  @param ps The particles to restrain. Currently these must be atomic particles.
399  @param map_fn The EM density map to fit to
400  @param resolution Map resolution
401  @param origin In case you need to tell IMP the correct origin
402  @param voxel_size In case you need to tell IMP the angstroms per pixel
403  @param weight The data weight
404  @param label Extra PMI label
405  """
406  print('FitRestraint: setup')
407  #print('\tmap_fn',map_fn)
408  print('\tresolution',resolution)
409  print('\tvoxel_size',voxel_size)
410  print('\torigin',origin)
411  print('\tweight',weight)
412 
413  # some parameters
414  self.mdl = ps[0].get_model()
415  self.label = label
416  self.dmap = dmap #IMP.em.read_map(map_fn,IMP.em.MRCReaderWriter())
417  #dh = self.dmap.get_header()
418  #dh.set_resolution(resolution)
419  if voxel_size:
420  self.dmap.update_voxel_size(voxel_size)
421  if origin is not None:
422  if type(origin)==IMP.algebra.Vector3D:
423  self.dmap.set_origin(origin)
424  elif type(origin)==list:
425  self.dmap.set_origin(*origin)
426  else:
427  print('FitRestraint did not recognize format of origin')
428  exit()
429  fr = IMP.em.FitRestraint(ps,self.dmap)
430  self.rs = IMP.RestraintSet(self.mdl,weight,"FitRestraint")
431  self.rs.add_restraint(fr)
432  self.set_weight(weight)
433 
434  def set_weight(self,weight):
435  self.weight = weight
436  self.rs.set_weight(weight)
437 
438  def set_label(self, label):
439  self.label = label
440 
441  def add_to_model(self):
442  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
443 
444  def get_restraint_set(self):
445  return self.rs
446 
447  def get_output(self):
448  self.mdl.update()
449  output = {}
450  score = self.weight * self.rs.unprotected_evaluate(None)
451  output["_TotalScore"] = str(score)
452  output["EMRestraint_" + self.label] = str(score)
453  return output
454 
455  def evaluate(self):
456  return self.weight * self.rs.unprotected_evaluate(None)
457 
458 
459 #-------------------------------------------
460 
461 class ElectronMicroscopy2D(object):
462 
463  def __init__(
464  self,
465  representation,
466  images,
467  resolution=None):
468 
469  self.weight=1.0
470  self.m = representation.prot.get_model()
471  self.rs = IMP.RestraintSet(self.m, 'em2d')
472  self.label = "None"
473 
474  # IMP.atom.get_by_type
475  particles = IMP.pmi.tools.select(
476  representation,
477  resolution=resolution)
478 
479  em2d = None
480  self.rs.add_restraint(em2d)
481 
482  def set_label(self, label):
483  self.label = label
484 
485  def add_to_model(self):
486  IMP.pmi.tools.add_restraint_to_model(self.m, self.rs)
487 
488  def get_restraint(self):
489  return self.rs
490 
491  def set_weight(self,weight):
492  self.weight=weight
493  self.rs.set_weigth(self.weight)
494 
495  def get_output(self):
496  self.m.update()
497  output = {}
498  score = self.weight*self.rs.unprotected_evaluate(None)
499  output["_TotalScore"] = str(score)
500  output["ElectronMicroscopy2D_" + self.label] = str(score)
501  return output
Tools for handling Gaussian Mixture Models.
Definition: gmm_tools.py:1
Add mass to a particle.
Definition: Mass.h:23
Simple 3D transformation class.
Fit Gaussian-decorated particles to an EM map (also represented with a set of Gaussians) ...
A member of a rigid body, it has internal (local) coordinates.
Definition: rigid_bodies.h:508
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Definition: rigid_bodies.h:509
Classes for attaching metadata to PMI objects.
Definition: metadata.py:1
def write_target_gmm_to_mrc
Writes target GMM file to MRC.
Various classes to hold sets of particles.
static XYZR setup_particle(Model *m, ParticleIndex pi)
Definition: XYZR.h:48
double get_mass(ResidueType c)
Get the mass from the residue type.
Miscellaneous utilities.
Definition: tools.py:1
def add_target_density_to_hierarchy
Can add a target GMM to a Hierarchy.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Definition: XYZR.h:47
Object used to hold a set of restraints.
Definition: RestraintSet.h:36
ParticleIndexPairs get_indexes(const ParticlePairsTemp &ps)
The standard decorator for manipulating molecular structures.
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
void transform(XYZ a, const algebra::Transformation3D &tr)
Apply a transformation to the particle.
Restraint between two Gaussian Mixture Models, "model" and "density".
def add_restraint_to_model
Add a PMI restraint to the model.
Definition: tools.py:37
A 3D electron microscopy dataset.
Definition: metadata.py:91
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
def get_center_of_mass
Returns the geometric center of the GMM particles.
def write_gmm_to_map
write density map from GMM.
Definition: gmm_tools.py:111
static Copy setup_particle(Model *m, ParticleIndex pi, Int number)
Definition: Copy.h:42
An individual file or directory.
Definition: metadata.py:166
Basic functionality that is expected to be used by a wide variety of IMP users.
General purpose algebraic and geometric methods that are expected to be used by a wide variety of IMP...
Calculate score based on fit to EM map.
Definition: FitRestraint.h:39
The general base class for IMP exceptions.
Definition: exception.h:49
VectorD< 3 > Vector3D
Definition: VectorD.h:395
IMP::core::RigidBody create_rigid_body(Hierarchy h)
Class to handle individual particles of a Model object.
Definition: Particle.h:41
Stores a list of Molecules all with the same State index.
def select
this function uses representation=SimplifiedModel it returns the corresponding selected particles rep...
Definition: tools.py:731
A decorator for a rigid body.
Definition: rigid_bodies.h:75
Set up the representation of all proteins and nucleic acid macromolecules.
Functionality for loading, creating, manipulating and scoring atomic structures.
Hierarchies get_leaves(const Selection &h)
def decorate_gmm_from_text
read the output from write_gmm_to_text, decorate as Gaussian and Mass
Definition: gmm_tools.py:22
Inferential scoring building on methods developed as part of the Inferential Structure Determination ...
A decorator for a particle with x,y,z coordinates and a radius.
Definition: XYZR.h:27