IMP logo
IMP Reference Guide  develop.63b38c487d,2024/12/22
The Integrative Modeling Platform
fit_fft.py
1 #!/usr/bin/env python
2 
3 import math
4 import IMP.multifit
5 import IMP.atom
6 import IMP.em
7 from IMP import ArgumentParser
8 import os
9 import sys
10 
11 __doc__ = "Fit subunits into a density map with FFT."
12 
13 multiproc_exception = None
14 try:
15  import multiprocessing
16  # Detect whether we are running Windows Python via Wine. Wine does not
17  # currently support some named pipe functions which the multiprocessing
18  # module needs: http://bugs.winehq.org/show_bug.cgi?id=17273
19  if sys.platform == 'win32' and 'WINELOADERNOEXEC' in os.environ:
20  multiproc_exception = "Wine does not currently support multiprocessing"
21 except ImportError as detail:
22  multiproc_exception = str(detail)
23 
24 
25 def _get_context():
26  # Use 'forkserver' rather than 'fork' start method if we can; 'fork' does
27  # not work well with multithreaded processes or CUDA
28  if 'forkserver' in multiprocessing.get_all_start_methods():
29  return multiprocessing.get_context('forkserver')
30  else:
31  return multiprocessing.get_context()
32 
33 
34 class Fitter:
35 
36  def __init__(
37  self,
38  em_map,
39  spacing,
40  resolution,
41  origin,
42  density_threshold,
43  pdb,
44  fits_fn,
45  angle,
46  num_fits,
47  angles_per_voxel,
48  ref_pdb=''):
49  self.em_map = em_map
50  self.spacing = spacing
51  self.resolution = resolution
52  self.threshold = density_threshold
53  self.originx = origin[0]
54  self.originy = origin[1]
55  self.originz = origin[2]
56  self.pdb = pdb
57  self.fits_fn = fits_fn
58  self.angle = angle
59  self.num_fits = num_fits
60  self.angles_per_voxel = angles_per_voxel
61  self.ref_pdb = ref_pdb
62 
63  def run(self):
64  print("resolution is:", self.resolution)
65  dmap = IMP.em.read_map(self.em_map)
66  dmap.get_header().set_resolution(self.resolution)
67  dmap.update_voxel_size(self.spacing)
68  dmap.set_origin(IMP.algebra.Vector3D(self.originx,
69  self.originy,
70  self.originz))
71  dmap.set_was_used(True)
72  dmap.get_header().show()
73  mdl = IMP.Model()
74  mol2fit = IMP.atom.read_pdb(self.pdb, mdl)
75  mh_xyz = IMP.core.XYZs(IMP.core.get_leaves(mol2fit))
76  _ = IMP.atom.create_rigid_body(mol2fit)
78  ff.set_was_used(True)
79  fits = ff.do_global_fitting(dmap, self.threshold, mol2fit,
80  self.angle / 180.0 * math.pi,
81  self.num_fits, self.spacing, 0.5,
82  True, self.angles_per_voxel)
83  fits.set_was_used(True)
84  final_fits = fits.best_fits_
85  if self.ref_pdb != '':
86  ref_mh = IMP.atom.read_pdb(self.ref_pdb, mdl)
87  ref_mh_xyz = IMP.core.XYZs(IMP.core.get_leaves(ref_mh))
88  cur_low = [1e4, 0]
89  for i, fit in enumerate(final_fits):
90  fit.set_index(i)
91  if self.ref_pdb != '':
92  trans = fit.get_fit_transformation()
93  IMP.atom.transform(mol2fit, trans)
94  rmsd = IMP.atom.get_rmsd(mh_xyz, ref_mh_xyz)
95  if rmsd < cur_low[0]:
96  cur_low[0] = rmsd
97  cur_low[1] = i
98  fit.set_rmsd_to_reference(rmsd)
99  IMP.atom.transform(mol2fit, trans.get_inverse())
100  if self.ref_pdb != '':
101  print('from all fits, lowest rmsd to ref:', cur_low)
102  IMP.multifit.write_fitting_solutions(self.fits_fn, final_fits)
103 
104 
105 def do_work(f):
106  f.run()
107 
108 
109 def parse_args():
110  desc = """Fit subunits into a density map with FFT."""
111  p = ArgumentParser(description=desc)
112  p.add_argument("-c", "--cpu", dest="cpus", type=int, default=1,
113  help="number of cpus to use (default 1)")
114  p.add_argument("-a", "--angle", dest="angle", type=float, default=30,
115  help="angle delta (degrees) for FFT rotational "
116  "search (default 30)")
117 
118  p.add_argument("-n", "--num", dest="num", type=int,
119  default=100, help="Number of fits to report (default 100)")
120 
121  p.add_argument("-v", "--angle_voxel", dest="angle_voxel", type=int,
122  default=10,
123  help="Number of angles to keep per voxel (default 10)")
124 
125  p.add_argument("assembly_file", help="assembly file name")
126 
127  # p.add_argument("-n", "--num", dest="num", type="int",
128  # default=100,
129  # help="Number of fits to report"
130  # "(default 100)")
131 
132  return p.parse_args()
133 
134 
135 def run(asmb_fn, options):
136  if multiproc_exception is None and options.cpus > 1:
137  work_units = []
138  asmb_input = IMP.multifit.read_settings(asmb_fn)
139  asmb_input.set_was_used(True)
140  em_map = asmb_input.get_assembly_header().get_dens_fn()
141  resolution = asmb_input.get_assembly_header().get_resolution()
142  spacing = asmb_input.get_assembly_header().get_spacing()
143  origin = asmb_input.get_assembly_header().get_origin()
144  for i in range(asmb_input.get_number_of_component_headers()):
145  fits_fn = asmb_input.get_component_header(i).get_transformations_fn()
146  pdb_fn = asmb_input.get_component_header(i).get_filename()
147  f = Fitter(
148  em_map,
149  spacing,
150  resolution,
151  origin,
152  asmb_input.get_assembly_header().get_threshold(),
153  pdb_fn,
154  fits_fn,
155  options.angle,
156  options.num,
157  options.angle_voxel)
158  if multiproc_exception is None and options.cpus > 1:
159  work_units.append(f)
160  else:
161  if options.cpus > 1:
162  options.cpus = 1
163  print("""
164 The Python 'multiprocessing' module (available in Python 2.6 and later) is
165 needed to run on multiple CPUs, and could not be found
166 (Python error: '%s').
167 Running on a single processor.""" % multiproc_exception, file=sys.stderr)
168  f.run()
169  if multiproc_exception is None and options.cpus > 1:
170  # No point in spawning more processes than components
171  nproc = min(options.cpus, asmb_input.get_number_of_component_headers())
172  ctx = _get_context()
173  p = ctx.Pool(processes=nproc)
174  _ = list(p.imap_unordered(do_work, work_units))
175  p.close()
176 
177 
178 def main():
179  args = parse_args()
180  run(args.assembly_file, args)
181 
182 
183 if __name__ == "__main__":
184  main()
Fit a molecule inside its density by local or global FFT.
SettingsData * read_settings(const char *filename)
GenericHierarchies get_leaves(Hierarchy mhd)
Get all the leaves of the bit of hierarchy.
void read_pdb(TextInput input, int model, Hierarchy h)
Class for storing model, its restraints, constraints, and particles.
Definition: Model.h:86
double get_rmsd(const Selection &s0, const Selection &s1)
void transform(Hierarchy h, const algebra::Transformation3D &tr)
Transform a hierarchy. This is aware of rigid bodies.
Fitting atomic structures into a cryo-electron microscopy density map.
Basic utilities for handling cryo-electron microscopy 3D density maps.
void write_fitting_solutions(const char *fitting_fn, const FittingSolutionRecords &fit_sols, int num_sols=-1)
Write fitting solutions to a file.
std::ostream & show(Hierarchy h, std::ostream &out=std::cout)
Print the hierarchy using a given decorator to display each node.
VectorD< 3 > Vector3D
Definition: VectorD.h:408
IMP::core::RigidBody create_rigid_body(Hierarchy h)
double get_resolution(Model *m, ParticleIndex pi)
Estimate the resolution of the hierarchy as used by Representation.
Functionality for loading, creating, manipulating and scoring atomic structures.