1 """@namespace IMP.pmi.macros
2 Protocols for sampling structures and analyzing them.
16 from pathlib
import Path
18 from operator
import itemgetter
19 from collections
import defaultdict
29 """Replace samplers.MPI_values when in test mode"""
30 def get_percentile(self, name):
35 """All restraints that are written out to the RMF file"""
36 def __init__(self, model, user_restraints):
38 self._user_restraints = user_restraints
if user_restraints
else []
41 return (len(self._user_restraints)
42 + self._rmf_rs.get_number_of_restraints())
47 def __getitem__(self, i):
49 def __init__(self, r):
50 self.r = IMP.RestraintSet.get_from(r)
52 def get_restraint(self):
55 lenuser = len(self._user_restraints)
57 return self._user_restraints[i]
58 elif 0 <= i - lenuser < self._rmf_rs.get_number_of_restraints():
59 r = self._rmf_rs.get_restraint(i - lenuser)
60 return FakePMIWrapper(r)
62 raise IndexError(
"Out of range")
66 """All output statistics objects to add to stat files and/or RMFs"""
67 def __init__(self, output_objects, rmf_output_objects):
68 self.objects = self.rmf_objects =
None
70 if output_objects
is not None:
71 self.objects = output_objects[:]
72 if rmf_output_objects
is not None:
73 self.rmf_objects = rmf_output_objects[:]
75 def append(self, obj):
76 if self.objects
is not None:
77 self.objects.append(obj)
78 if self.rmf_objects
is not None:
79 self.rmf_objects.append(obj)
83 """Parameters for writing restart files"""
84 def __init__(self, frames, restart_dir):
86 self._restart_dir = restart_dir
91 def _write_frame(self, rex, frame, myindex, rex_stats):
92 """Possibly write a restart file for the replica exchange run `rex`"""
93 if frame % self._frames != 0:
95 print(f
'--- writing restart file at frame {frame}')
96 d = Path(rex.vars[
"global_output_directory"]) / self._restart_dir
97 d.mkdir(exist_ok=
True)
98 fname = d / f
'restart.{myindex}.pck'
101 prev = d / f
'restart.{myindex}.prev.pck'
104 self._write_readme(d /
'README.txt')
106 r = _RestartRun(rex, frame, rex_stats)
107 with open(fname,
'wb')
as fh:
110 def _write_readme(self, fname):
111 with open(fname,
'w')
as fh:
113 This directory contains files that can be used to restart an interrupted
114 simulation. To do so, use the IMP.pmi.macros.restart_replica_exchange function.
116 Restart files are Python pickles that contain the current configuration of
117 the IMP model (e.g. coordinates), the scoring function, and the PMI sampler
118 (e.g. Monte Carlo movers and acceptance statistics). Each replica has its own
119 internal state and thus its own restart file. Files for the previous restart
120 are also kept (with a .prev.pck extension) in case the most recent restart
123 Restart files contain IMP internal state and so will probably not work with
124 a different version of IMP, or on a different operating system. As with all
125 Python pickles, these files may contain executable Python code and so you
126 should not use a restart file from an untrusted source.
129 restarted = property(
lambda self: self._number > 0,
130 doc=
"True iff this simulation has been restarted")
134 """Information about a restarted simulation (usually pickled)"""
135 def __init__(self, rex, frame, rex_stats):
138 self._pck_info = (rex.model, rex)
139 self._rstate = IMP.random_number_generator.get_state()
141 self._rex_stats = rex_stats
143 def execute_macro(self):
144 """Restart the interrupted replica exchange simulation"""
145 m, rex = self._pck_info
146 IMP.random_number_generator.set_state(self._rstate)
147 rex._restart._number += 1
148 rex._restart_from_frame = self._frame
149 rex._rex_stats = self._rex_stats
150 return rex.execute_macro()
152 def get_number_of_replicas(self):
153 rex = self._pck_info[1]
154 return rex.replica_exchange_object.get_number_of_replicas()
158 """A macro to help setup and run replica exchange.
159 Supports Monte Carlo and molecular dynamics.
160 Produces trajectory RMF files, best PDB structures,
161 and output stat files.
163 def __init__(self, model, root_hier,
164 monte_carlo_sample_objects=
None,
165 molecular_dynamics_sample_objects=
None,
167 rmf_output_objects=
None,
168 monte_carlo_temperature=1.0,
169 simulated_annealing=
False,
170 simulated_annealing_minimum_temperature=1.0,
171 simulated_annealing_maximum_temperature=2.5,
172 simulated_annealing_minimum_temperature_nframes=100,
173 simulated_annealing_maximum_temperature_nframes=100,
174 replica_exchange_minimum_temperature=1.0,
175 replica_exchange_maximum_temperature=2.5,
176 replica_exchange_swap=
True,
178 number_of_best_scoring_models=500,
179 monte_carlo_steps=10,
181 molecular_dynamics_steps=10,
182 molecular_dynamics_max_time_step=1.0,
183 number_of_frames=1000,
184 save_coordinates_mode=
"lowest_temperature",
185 nframes_write_coordinates=1,
186 write_initial_rmf=
True,
187 initial_rmf_name_suffix=
"initial",
188 stat_file_name_suffix=
"stat",
189 best_pdb_name_suffix=
"model",
192 do_create_directories=
True,
193 global_output_directory=
"./",
195 best_pdb_dir=
"pdbs/",
196 replica_stat_file_suffix=
"stat_replica",
197 em_object_for_rmf=
None,
199 replica_exchange_object=
None,
203 nestor_restraints=
None,
204 nestor_rmf_fname_prefix=
"nested",
207 @param model The IMP model
208 @param root_hier Top-level (System)hierarchy
209 @param monte_carlo_sample_objects Objects for MC sampling, which
210 should generally be a simple list of Mover objects, e.g.
211 from DegreesOfFreedom.get_movers().
212 @param molecular_dynamics_sample_objects Objects for MD sampling,
213 which should generally be a simple list of particles.
214 @param output_objects A list of structural objects and restraints
215 that will be included in output (ie, statistics "stat"
216 files). Any object that provides a get_output() method
217 can be used here. If None is passed
218 the macro will not write stat files.
219 @param rmf_output_objects A list of structural objects and
220 restraints that will be included in rmf. Any object
221 that provides a get_output() method can be used here.
222 @param monte_carlo_temperature MC temp (may need to be optimized
223 based on post-sampling analysis)
224 @param simulated_annealing If True, perform simulated annealing
225 @param simulated_annealing_minimum_temperature Should generally be
226 the same as monte_carlo_temperature.
227 @param simulated_annealing_minimum_temperature_nframes Number of
228 frames to compute at minimum temperature.
229 @param simulated_annealing_maximum_temperature_nframes Number of
231 temps > simulated_annealing_maximum_temperature.
232 @param replica_exchange_minimum_temperature Low temp for REX; should
233 generally be the same as monte_carlo_temperature.
234 @param replica_exchange_maximum_temperature High temp for REX
235 @param replica_exchange_swap Boolean, enable disable temperature
237 @param num_sample_rounds Number of rounds of MC/MD per cycle
238 @param number_of_best_scoring_models Number of top-scoring PDB/mmCIF
239 models to keep around for analysis.
240 @param mmcif If True, write best scoring models in mmCIF format;
241 if False (the default), write in legacy PDB format.
242 @param best_pdb_dir The directory under `global_output_directory`
243 where best-scoring PDB/mmCIF files are written.
244 @param best_pdb_name_suffix Part of the file name for best-scoring
246 @param monte_carlo_steps Number of MC steps per round
247 @param self_adaptive self adaptive scheme for Monte Carlo movers
248 @param molecular_dynamics_steps Number of MD steps per round
249 @param molecular_dynamics_max_time_step Max time step for MD
250 @param number_of_frames Number of REX frames to run
251 @param save_coordinates_mode string: how to save coordinates.
252 "lowest_temperature" (default) only the lowest temperatures
254 "25th_score" all replicas whose score is below the 25th
256 "50th_score" all replicas whose score is below the 50th
258 "75th_score" all replicas whose score is below the 75th
260 @param nframes_write_coordinates How often to write the coordinates
262 @param write_initial_rmf Write the initial configuration
263 @param global_output_directory Folder that will be created to house
265 @param test_mode Set to True to avoid writing any files, just test
267 @param score_moved If True, attempt to speed up Monte Carlo
268 sampling by caching scoring function terms on particles
270 @param use_nestor If True, follows the Nested Sampling workflow
271 of the NestOR module and skips writing stat files and
273 @param nestor_restraints A list of restraints for which
274 likelihoods are to be computed for use by NestOR module.
275 @param nestor_rmf_fname_prefix Prefix to be used for storing .rmf3
276 files generated by NestOR .
277 @param use_jax If set to True, sample the scoring function using
278 JAX instead of IMP's internal C++ implementation (requires
279 that all PMI restraints used have a JAX implementation).
284 self._restart_from_frame = 0
287 if output_objects == []:
290 self.output_objects = []
292 self.output_objects = output_objects
293 self.rmf_output_objects = rmf_output_objects
295 and not root_hier.get_parent()):
296 if self.output_objects
is not None:
297 self.output_objects.append(
299 if self.rmf_output_objects
is not None:
300 self.rmf_output_objects.append(
302 self.root_hier = root_hier
303 states = IMP.atom.get_by_type(root_hier, IMP.atom.STATE_TYPE)
304 self.vars[
"number_of_states"] = len(states)
306 self.root_hiers = states
307 self.is_multi_state =
True
309 self.root_hier = root_hier
310 self.is_multi_state =
False
312 raise TypeError(
"Must provide System hierarchy (root_hier)")
314 self._rmf_restraints = _RMFRestraints(model,
None)
315 self.em_object_for_rmf = em_object_for_rmf
316 self.monte_carlo_sample_objects = monte_carlo_sample_objects
317 self.vars[
"self_adaptive"] = self_adaptive
318 self.molecular_dynamics_sample_objects = \
319 molecular_dynamics_sample_objects
320 self.replica_exchange_object = replica_exchange_object
321 self.molecular_dynamics_max_time_step = \
322 molecular_dynamics_max_time_step
323 self.vars[
"monte_carlo_temperature"] = monte_carlo_temperature
324 self.vars[
"replica_exchange_minimum_temperature"] = \
325 replica_exchange_minimum_temperature
326 self.vars[
"replica_exchange_maximum_temperature"] = \
327 replica_exchange_maximum_temperature
328 self.vars[
"replica_exchange_swap"] = replica_exchange_swap
329 self.vars[
"simulated_annealing"] = simulated_annealing
330 self.vars[
"simulated_annealing_minimum_temperature"] = \
331 simulated_annealing_minimum_temperature
332 self.vars[
"simulated_annealing_maximum_temperature"] = \
333 simulated_annealing_maximum_temperature
334 self.vars[
"simulated_annealing_minimum_temperature_nframes"] = \
335 simulated_annealing_minimum_temperature_nframes
336 self.vars[
"simulated_annealing_maximum_temperature_nframes"] = \
337 simulated_annealing_maximum_temperature_nframes
339 self.vars[
"num_sample_rounds"] = num_sample_rounds
341 "number_of_best_scoring_models"] = number_of_best_scoring_models
342 self.vars[
"monte_carlo_steps"] = monte_carlo_steps
343 self.vars[
"molecular_dynamics_steps"] = molecular_dynamics_steps
344 self.vars[
"number_of_frames"] = number_of_frames
345 if save_coordinates_mode
not in (
"lowest_temperature",
"25th_score",
346 "50th_score",
"75th_score"):
347 raise Exception(
"save_coordinates_mode has unrecognized value")
349 self.vars[
"save_coordinates_mode"] = save_coordinates_mode
350 self.vars[
"nframes_write_coordinates"] = nframes_write_coordinates
351 self.vars[
"write_initial_rmf"] = write_initial_rmf
352 self.vars[
"initial_rmf_name_suffix"] = initial_rmf_name_suffix
353 self.vars[
"best_pdb_name_suffix"] = best_pdb_name_suffix
354 self.vars[
"mmcif"] = mmcif
355 self.vars[
"stat_file_name_suffix"] = stat_file_name_suffix
356 self.vars[
"do_clean_first"] = do_clean_first
357 self.vars[
"do_create_directories"] = do_create_directories
358 self.vars[
"global_output_directory"] = global_output_directory
359 self.vars[
"rmf_dir"] = rmf_dir
360 self.vars[
"best_pdb_dir"] = best_pdb_dir
361 self.vars[
"atomistic"] = atomistic
362 self.vars[
"replica_stat_file_suffix"] = replica_stat_file_suffix
363 self.vars[
"geometries"] =
None
364 self.test_mode = test_mode
365 self.score_moved = score_moved
366 self.use_jax = use_jax
367 self.vars[
"use_nestor"] = self.nest = use_nestor
368 self.nestor_restraints = nestor_restraints
369 self.nestor_rmf_fname = nestor_rmf_fname_prefix
372 self._jax_space = self._get_jax_free_space()
375 """Enable a simulation to be restarted if it is interrupted.
377 If enabled, restart files containing a complete description of
378 the IMP system are written periodically during the simulation,
379 one per replica. If the simulation is interrupted, it can be
380 restarted using the restart_replica_exchange function, which
381 reads these files. Files for the previous restart are also kept
382 (with a .prev.pck extension) in case the most recent restart
385 Restart files contain IMP internal state and so will probably
386 not work with a different version of IMP, or on a different
387 operating system. As with all Python pickles, these files may
388 contain executable Python code and so you should not use a
389 restart file from an untrusted source.
391 @param frames How often a restart file should be written
392 (number of frames), or zero to not write restart files
393 @param restart_dir The directory under `global_output_directory`
394 where restart files are written.
399 self._restart = _RestartInfo(frames, restart_dir)
402 if self.vars[
"geometries"]
is None:
403 self.vars[
"geometries"] = list(geometries)
405 self.vars[
"geometries"].extend(geometries)
408 print(
"ReplicaExchange: it generates initial.*.rmf3, stat.*.out, "
409 "rmfs/*.rmf3 for each replica ")
410 print(
"--- it stores the best scoring pdb models in pdbs/")
411 print(
"--- the stat.*.out and rmfs/*.rmf3 are saved only at the "
412 "lowest temperature")
413 if self._restart
and self._restart.restarted:
414 print(
"--- this is a restart of a failed simulation")
415 print(
"--- variables:")
416 for k, v
in sorted(self.vars.items(), key=itemgetter(0)):
417 print(
"------", k.ljust(30), v)
419 def get_replica_exchange_object(self):
420 return self.replica_exchange_object
422 def _add_provenance(self, sampler_md, sampler_mc):
423 """Record details about the sampling in the IMP Hierarchies"""
426 method =
"Molecular Dynamics"
427 iterations += self.vars[
"molecular_dynamics_steps"]
429 method =
"Hybrid MD/MC" if sampler_md
else "Monte Carlo"
430 iterations += self.vars[
"monte_carlo_steps"]
432 if iterations == 0
or self.vars[
"number_of_frames"] == 0:
434 iterations *= self.vars[
"num_sample_rounds"]
436 pi = self.model.add_particle(
"sampling")
438 self.model, pi, method, self.vars[
"number_of_frames"],
440 p.set_number_of_replicas(
441 self.replica_exchange_object.get_number_of_replicas())
442 IMP.pmi.tools._add_pmi_provenance(self.root_hier)
445 def _setup_mc_sampler(self):
447 self.model, self.monte_carlo_sample_objects,
448 self.vars[
"monte_carlo_temperature"],
449 score_moved=self.score_moved,
450 start_frame=self._restart_from_frame)
452 sampler_mc.set_use_jax(self.vars[
"monte_carlo_steps"])
453 if self.vars[
"simulated_annealing"]:
454 tmin = self.vars[
"simulated_annealing_minimum_temperature"]
455 tmax = self.vars[
"simulated_annealing_maximum_temperature"]
457 "simulated_annealing_minimum_temperature_nframes"]
459 "simulated_annealing_maximum_temperature_nframes"]
460 sampler_mc.set_simulated_annealing(tmin, tmax, nfmin, nfmax)
461 if self.vars[
"self_adaptive"]:
462 sampler_mc.set_self_adaptive(
463 isselfadaptive=self.vars[
"self_adaptive"])
466 def _setup_md_sampler(self):
468 self.model, self.molecular_dynamics_sample_objects,
469 self.vars[
"monte_carlo_temperature"],
470 maximum_time_step=self.molecular_dynamics_max_time_step,
471 start_frame=self._restart_from_frame)
473 sampler_md.set_use_jax(self.vars[
"molecular_dynamics_steps"])
474 if self.vars[
"simulated_annealing"]:
475 tmin = self.vars[
"simulated_annealing_minimum_temperature"]
476 tmax = self.vars[
"simulated_annealing_maximum_temperature"]
478 "simulated_annealing_minimum_temperature_nframes"]
480 "simulated_annealing_maximum_temperature_nframes"]
481 sampler_md.set_simulated_annealing(tmin, tmax, nfmin, nfmax)
484 def _get_jax_free_space(self):
489 def _get_jax_data(self, sampler_mc):
491 return IMP.pmi.tools._JAXData(
492 model=sampler_mc.get_jax_model(),
493 space=self._jax_space)
495 def execute_macro(self):
497 restarted = self._restart.restarted
if self._restart
else False
499 stat_file = _StatFile(self.output_objects, self.rmf_output_objects)
500 temp_index_factor = 100000.0
504 if self.monte_carlo_sample_objects
is not None:
505 print(
"Setting up MonteCarlo")
506 sampler_mc = self._setup_mc_sampler()
507 stat_file.append(sampler_mc)
508 samplers.append(sampler_mc)
510 if self.molecular_dynamics_sample_objects
is not None:
511 print(
"Setting up MolecularDynamics")
512 sampler_md = self._setup_md_sampler()
513 stat_file.append(sampler_md)
514 samplers.append(sampler_md)
518 print(
"Setting up ReplicaExchange")
520 self.model, self.vars[
"replica_exchange_minimum_temperature"],
521 self.vars[
"replica_exchange_maximum_temperature"], samplers,
522 replica_exchange_object=self.replica_exchange_object)
523 self.replica_exchange_object = rex.rem
526 rex.stats = self._rex_stats
529 myindex = rex.get_my_index()
530 stat_file.append(rex)
534 min_temp_index = int(min(rex.get_temperatures()) * temp_index_factor)
538 globaldir = self.vars[
"global_output_directory"] +
"/"
539 rmf_dir = globaldir + self.vars[
"rmf_dir"]
540 pdb_dir = globaldir + self.vars[
"best_pdb_dir"]
542 if not self.test_mode
and not self.nest:
543 if self.vars[
"do_clean_first"]:
546 if self.vars[
"do_create_directories"]:
548 os.makedirs(globaldir, exist_ok=
True)
549 os.makedirs(rmf_dir, exist_ok=
True)
550 if not self.is_multi_state:
551 os.makedirs(pdb_dir, exist_ok=
True)
553 for n
in range(self.vars[
"number_of_states"]):
554 os.makedirs(pdb_dir +
"/" + str(n), exist_ok=
True)
563 print(
"Setting up stat file")
564 low_temp_stat_file = globaldir + \
565 self.vars[
"stat_file_name_suffix"] +
"." + \
566 str(myindex) +
".out"
569 if not self.test_mode:
572 if not self.test_mode
and not self.nest:
573 if stat_file.objects
is not None:
574 output.init_stat2(low_temp_stat_file,
576 extralabels=[
"rmf_file",
"rmf_frame_index"],
577 jax_data=self._get_jax_data(sampler_mc),
580 if restarted
and sampler_mc:
581 nline = output._count_stat2_nframe(
582 low_temp_stat_file,
'MonteCarlo_Nframe',
583 self._restart_from_frame)
584 if nline
is not None:
585 output._truncate_stat2_nline(low_temp_stat_file, nline)
587 print(
"Stat file writing is disabled")
589 if stat_file.rmf_objects
is not None and not self.nest:
590 print(
"Stat info being written in the rmf file")
592 if not self.test_mode
and not self.nest:
593 print(
"Setting up replica stat file")
594 replica_stat_file = globaldir + \
595 self.vars[
"replica_stat_file_suffix"] +
"." + \
596 str(myindex) +
".out"
597 if not self.test_mode:
598 output.init_stat2(replica_stat_file, [rex],
599 extralabels=[
"score"],
600 jax_data=self._get_jax_data(sampler_mc),
603 output._truncate_stat2_nline(
604 replica_stat_file, self._restart_from_frame)
606 print(
"Setting up best pdb files")
607 if not self.is_multi_state:
608 if self.vars[
"number_of_best_scoring_models"] > 0:
609 output.init_pdb_best_scoring(
610 pdb_dir +
"/" + self.vars[
"best_pdb_name_suffix"],
612 self.vars[
"number_of_best_scoring_models"],
613 replica_exchange=
True,
614 mmcif=self.vars[
'mmcif'],
615 best_score_file=globaldir +
"best.scores.rex.py")
616 pdbext =
".0.cif" if self.vars[
'mmcif']
else ".0.pdb"
618 pdb_dir +
"/" +
"model.psf",
620 self.vars[
"best_pdb_name_suffix"] + pdbext)
622 if self.vars[
"number_of_best_scoring_models"] > 0:
623 for n
in range(self.vars[
"number_of_states"]):
624 output.init_pdb_best_scoring(
625 pdb_dir +
"/" + str(n) +
"/" +
626 self.vars[
"best_pdb_name_suffix"],
628 self.vars[
"number_of_best_scoring_models"],
629 replica_exchange=
True,
630 mmcif=self.vars[
'mmcif'],
631 best_score_file=globaldir +
"best.scores.rex.py")
632 pdbext =
".0.cif" if self.vars[
'mmcif']
else ".0.pdb"
634 pdb_dir +
"/" + str(n) +
"/" +
"model.psf",
635 pdb_dir +
"/" + str(n) +
"/" +
636 self.vars[
"best_pdb_name_suffix"] + pdbext)
639 if self.em_object_for_rmf
is not None:
640 output_hierarchies = [
642 self.em_object_for_rmf.get_density_as_hierarchy(
645 output_hierarchies = [self.root_hier]
647 if not self.test_mode
and not self.nest
and not restarted:
648 print(
"Setting up and writing initial rmf coordinate file")
649 init_suffix = globaldir + self.vars[
"initial_rmf_name_suffix"]
650 output.init_rmf(init_suffix +
"." + str(myindex) +
".rmf3",
652 listofobjects=stat_file.rmf_objects)
653 if self._rmf_restraints:
654 output.add_restraints_to_rmf(
655 init_suffix +
"." + str(myindex) +
".rmf3",
656 self._rmf_restraints)
657 output.write_rmf(init_suffix +
"." + str(myindex) +
".rmf3")
658 output.close_rmf(init_suffix +
"." + str(myindex) +
".rmf3")
660 if not self.test_mode:
661 mpivs = IMP.pmi.samplers.MPI_values(self.replica_exchange_object)
663 mpivs = _MockMPIValues()
665 self._add_provenance(sampler_md, sampler_mc)
667 if not self.test_mode
and not self.nest:
668 print(
"Setting up production rmf files")
670 rmfname = f
"{rmf_dir}/{myindex}.rs{self._restart._number}.rmf3"
672 rmfname = rmf_dir +
"/" + str(myindex) +
".rmf3"
673 output.init_rmf(rmfname, output_hierarchies,
674 geometries=self.vars[
"geometries"],
675 listofobjects=stat_file.rmf_objects)
677 if self._rmf_restraints:
678 output.add_restraints_to_rmf(rmfname, self._rmf_restraints)
680 if not self.test_mode
and self.nest:
681 print(
"Setting up NestOR rmf files")
682 nestor_rmf_fname = str(self.nestor_rmf_fname) +
'_' + \
683 str(self.replica_exchange_object.get_my_index()) +
'.rmf3'
685 output.init_rmf(nestor_rmf_fname, output_hierarchies,
686 geometries=self.vars[
"geometries"],
687 listofobjects=stat_file.rmf_objects)
689 ntimes_at_low_temp = 0
691 if myindex == 0
and not self.nest:
693 self.replica_exchange_object.set_was_used(
True)
694 nframes = self.vars[
"number_of_frames"]
698 sampled_likelihoods = []
699 for i
in range(self._restart_from_frame, nframes):
700 if self._restart
and i != self._restart_from_frame:
701 self._restart._write_frame(self, i, myindex, rex.stats)
706 for nr
in range(self.vars[
"num_sample_rounds"]):
707 if sampler_md
is not None:
708 score = sampler_md.optimize(
709 self.vars[
"molecular_dynamics_steps"])
710 if sampler_mc
is not None:
711 score = sampler_mc.optimize(
712 self.vars[
"monte_carlo_steps"])
715 self.model).evaluate(
False)
717 and not self.use_jax):
721 self.model).evaluate(
False)
722 assert abs(score - check_score) < 1e-4
723 mpivs.set_value(
"score", score)
725 output.set_output_entry(
"score", score)
727 my_temp_index = int(rex.get_my_temp() * temp_index_factor)
729 if self.vars[
"save_coordinates_mode"] ==
"lowest_temperature":
730 save_frame = (min_temp_index == my_temp_index)
731 elif self.vars[
"save_coordinates_mode"] ==
"25th_score":
732 score_perc = mpivs.get_percentile(
"score")
733 save_frame = (score_perc*100.0 <= 25.0)
734 elif self.vars[
"save_coordinates_mode"] ==
"50th_score":
735 score_perc = mpivs.get_percentile(
"score")
736 save_frame = (score_perc*100.0 <= 50.0)
737 elif self.vars[
"save_coordinates_mode"] ==
"75th_score":
738 score_perc = mpivs.get_percentile(
"score")
739 save_frame = (score_perc*100.0 <= 75.0)
742 if save_frame
and not self.test_mode:
746 print(
"--- frame %s score %s " % (str(i), str(score)))
749 if math.isnan(score):
750 sampled_likelihoods.append(math.nan)
752 likelihood_for_sample = 1
753 for rstrnt
in self.nestor_restraints:
754 likelihood_for_sample *= rstrnt.get_likelihood()
755 sampled_likelihoods.append(likelihood_for_sample)
756 output.write_rmf(nestor_rmf_fname)
758 if not self.test_mode
and not self.nest:
759 if i % self.vars[
"nframes_write_coordinates"] == 0:
760 print(
'--- writing coordinates')
761 if self.vars[
"number_of_best_scoring_models"] > 0:
762 output.write_pdb_best_scoring(score)
763 output.write_rmf(rmfname)
764 output.set_output_entry(
"rmf_file", rmfname)
765 output.set_output_entry(
"rmf_frame_index",
768 output.set_output_entry(
"rmf_file", rmfname)
769 output.set_output_entry(
"rmf_frame_index",
'-1')
770 if stat_file.objects
is not None:
773 jax_data=self._get_jax_data(sampler_mc))
774 ntimes_at_low_temp += 1
776 if not self.test_mode
and not self.nest:
779 jax_data=self._get_jax_data(sampler_mc))
780 if self.vars[
"replica_exchange_swap"]:
781 rex.swap_temp(i, score)
783 if self.nest
and len(sampled_likelihoods) > 0:
784 with open(
"likelihoods_"
785 + str(self.replica_exchange_object.get_my_index()),
787 pickle.dump(sampled_likelihoods, lif)
789 output.close_rmf(nestor_rmf_fname)
791 for p, state
in IMP.pmi.tools._all_protocol_outputs(self.root_hier):
792 p.add_replica_exchange(state, self)
794 if not self.test_mode
and not self.nest:
795 print(
"closing production rmf files")
796 output.close_rmf(rmfname)
800 """Continue a failed ReplicaExchange sampling run.
802 @see ReplicaExchange.set_restart
804 @param restart_dir The directory containing the restart file(s).
805 @param prev If True, use the previous restart
806 (e.g. `restart.0.prev.pck`) rather than the most recent
807 restart (e.g. `restart.0.pck`)
814 nproc, myindex = r.get_number_of_replicas(), r.get_my_index()
817 nproc, myindex = 1, 0
819 ext =
'prev.pck' if prev
else 'pck'
820 with open(f
'{restart_dir}/restart.{myindex}.{ext}',
'rb')
as fh:
822 old_nproc = mc.get_number_of_replicas()
823 if old_nproc != nproc:
825 f
"Mismatch trying to read restart files: the original run used "
826 f
"{old_nproc} replicas and this run has {nproc}")
827 return mc.execute_macro()
831 """A macro to build a IMP::pmi::topology::System based on a
832 TopologyReader object.
834 Easily create multi-state systems by calling this macro
835 repeatedly with different TopologyReader objects!
836 A useful function is get_molecules() which returns the PMI Molecules
837 grouped by state as a dictionary with key = (molecule name),
838 value = IMP.pmi.topology.Molecule
839 Quick multi-state system:
842 reader1 = IMP.pmi.topology.TopologyReader(tfile1)
843 reader2 = IMP.pmi.topology.TopologyReader(tfile2)
844 bs = IMP.pmi.macros.BuildSystem(model)
845 bs.add_state(reader1)
846 bs.add_state(reader2)
847 bs.execute_macro() # build everything including degrees of freedom
848 IMP.atom.show_molecular_hierarchy(bs.get_hierarchy())
849 ### now you have a two state system, you add restraints etc
851 @note The "domain name" entry of the topology reader is not used.
852 All molecules are set up by the component name, but split into rigid bodies
856 _alphabets = {
'DNA': IMP.pmi.alphabets.dna,
857 'RNA': IMP.pmi.alphabets.rna}
859 def __init__(self, model, sequence_connectivity_scale=4.0,
860 force_create_gmm_files=
False, resolutions=[1, 10],
863 @param model An IMP Model
864 @param sequence_connectivity_scale For scaling the connectivity
866 @param force_create_gmm_files If True, will sample and create GMMs
867 no matter what. If False, will only sample if the
868 files don't exist. If number of Gaussians is zero, won't
870 @param resolutions The resolutions to build for structured regions
871 @param name The name of the top-level hierarchy node.
878 self._domain_res = []
880 self.force_create_gmm_files = force_create_gmm_files
881 self.resolutions = resolutions
883 def add_state(self, reader, keep_chain_id=False, fasta_name_map=None,
885 """Add a state using the topology info in a
886 IMP::pmi::topology::TopologyReader object.
887 When you are done adding states, call execute_macro()
888 @param reader The TopologyReader object
889 @param keep_chain_id If True, keep the chain IDs from the
890 original PDB files, if available
891 @param fasta_name_map dictionary for converting protein names
892 found in the fasta file
893 @param chain_ids A list or string of chain IDs for assigning to
894 newly-created molecules, e.g.
895 `string.ascii_uppercase+string.ascii_lowercase+string.digits`.
896 If not specified, chain IDs A through Z are assigned, then
897 AA through AZ, then BA through BZ, and so on, in the same
900 state = self.system.create_state()
901 self._readers.append(reader)
903 these_domain_res = {}
905 if chain_ids
is None:
906 chain_ids = IMP.pmi.output._ChainIDs()
911 for molname
in reader.get_molecules():
912 copies = reader.get_molecules()[molname].domains
913 for nc, copyname
in enumerate(copies):
914 print(
"BuildSystem.add_state: setting up molecule %s copy "
915 "number %s" % (molname, str(nc)))
916 copy = copies[copyname]
919 all_chains = [c
for c
in copy
if c.chain
is not None]
921 chain_id = all_chains[0].chain
923 chain_id = chain_ids[numchain]
925 "No PDBs specified for %s, so keep_chain_id has "
926 "no effect; using default chain ID '%s'"
929 chain_id = chain_ids[numchain]
931 alphabet = IMP.pmi.alphabets.amino_acid
932 fasta_flag = copy[0].fasta_flag
933 if fasta_flag
in self._alphabets:
934 alphabet = self._alphabets[fasta_flag]
936 copy[0].fasta_file, fasta_name_map)
937 seq = seqs[copy[0].fasta_id]
938 print(
"BuildSystem.add_state: molecule %s sequence has "
939 "%s residues" % (molname, len(seq)))
940 orig_mol = state.create_molecule(
941 molname, seq, chain_id, alphabet=alphabet,
942 uniprot=seqs.uniprot.get(copy[0].fasta_id))
946 print(
"BuildSystem.add_state: creating a copy for "
947 "molecule %s" % molname)
948 mol = orig_mol.create_copy(chain_id)
951 for domainnumber, domain
in enumerate(copy):
952 print(
"BuildSystem.add_state: ---- setting up domain %s "
953 "of molecule %s" % (domainnumber, molname))
956 these_domains[domain.get_unique_name()] = domain
957 if domain.residue_range == []
or \
958 domain.residue_range
is None:
959 domain_res = mol.get_residues()
961 start = domain.residue_range[0]+domain.pdb_offset
962 if domain.residue_range[1] ==
'END':
963 end = len(mol.sequence)
965 end = domain.residue_range[1]+domain.pdb_offset
966 domain_res = mol.residue_range(start-1, end-1)
967 print(
"BuildSystem.add_state: -------- domain %s of "
968 "molecule %s extends from residue %s to "
970 % (domainnumber, molname, start, end))
971 if domain.pdb_file ==
"BEADS":
972 print(
"BuildSystem.add_state: -------- domain %s of "
973 "molecule %s represented by BEADS "
974 % (domainnumber, molname))
975 mol.add_representation(
977 resolutions=[domain.bead_size],
978 setup_particles_as_densities=(
979 domain.em_residues_per_gaussian != 0),
981 these_domain_res[domain.get_unique_name()] = \
983 elif domain.pdb_file ==
"IDEAL_HELIX":
984 print(
"BuildSystem.add_state: -------- domain %s of "
985 "molecule %s represented by IDEAL_HELIX "
986 % (domainnumber, molname))
987 emper = domain.em_residues_per_gaussian
988 mol.add_representation(
990 resolutions=self.resolutions,
992 density_residues_per_component=emper,
993 density_prefix=domain.density_prefix,
994 density_force_compute=self.force_create_gmm_files,
996 these_domain_res[domain.get_unique_name()] = \
999 print(
"BuildSystem.add_state: -------- domain %s of "
1000 "molecule %s represented by pdb file %s "
1001 % (domainnumber, molname, domain.pdb_file))
1002 domain_atomic = mol.add_structure(domain.pdb_file,
1004 domain.residue_range,
1007 domain_non_atomic = domain_res - domain_atomic
1008 if not domain.em_residues_per_gaussian:
1009 mol.add_representation(
1010 domain_atomic, resolutions=self.resolutions,
1012 if len(domain_non_atomic) > 0:
1013 mol.add_representation(
1015 resolutions=[domain.bead_size],
1018 print(
"BuildSystem.add_state: -------- domain %s "
1019 "of molecule %s represented by gaussians "
1020 % (domainnumber, molname))
1021 emper = domain.em_residues_per_gaussian
1022 creategmm = self.force_create_gmm_files
1023 mol.add_representation(
1025 resolutions=self.resolutions,
1026 density_residues_per_component=emper,
1027 density_prefix=domain.density_prefix,
1028 density_force_compute=creategmm,
1030 if len(domain_non_atomic) > 0:
1031 mol.add_representation(
1033 resolutions=[domain.bead_size],
1034 setup_particles_as_densities=
True,
1036 these_domain_res[domain.get_unique_name()] = (
1037 domain_atomic, domain_non_atomic)
1038 self._domain_res.append(these_domain_res)
1039 self._domains.append(these_domains)
1040 print(
'BuildSystem.add_state: State', len(self.system.states),
'added')
1044 """Return list of all molecules grouped by state.
1045 For each state, it's a dictionary of Molecules where key is the
1048 return [s.get_molecules()
for s
in self.system.get_states()]
1050 def get_molecule(self, molname, copy_index=0, state_index=0):
1051 return self.system.get_states()[state_index].
get_molecules()[
1052 molname][copy_index]
1055 max_bead_trans=4.0, max_srb_trans=4.0, max_srb_rot=0.04):
1056 """Builds representations and sets up degrees of freedom"""
1057 print(
"BuildSystem.execute_macro: building representations")
1058 self.root_hier = self.system.build()
1060 print(
"BuildSystem.execute_macro: setting up degrees of freedom")
1062 for nstate, reader
in enumerate(self._readers):
1063 rbs = reader.get_rigid_bodies()
1064 srbs = reader.get_super_rigid_bodies()
1065 csrbs = reader.get_chains_of_super_rigid_bodies()
1068 domains_in_rbs = set()
1070 print(
"BuildSystem.execute_macro: -------- building rigid "
1071 "body %s" % (str(rblist)))
1072 all_res = IMP.pmi.tools.OrderedSet()
1073 bead_res = IMP.pmi.tools.OrderedSet()
1074 for dname
in rblist:
1075 domain = self._domains[nstate][dname]
1076 print(
"BuildSystem.execute_macro: -------- adding %s"
1078 all_res |= self._domain_res[nstate][dname][0]
1079 bead_res |= self._domain_res[nstate][dname][1]
1080 domains_in_rbs.add(dname)
1082 print(
"BuildSystem.execute_macro: -------- creating rigid "
1083 "body with max_trans %s max_rot %s "
1084 "non_rigid_max_trans %s"
1085 % (str(max_rb_trans), str(max_rb_rot),
1086 str(max_bead_trans)))
1087 self.dof.create_rigid_body(all_res,
1088 nonrigid_parts=bead_res,
1089 max_trans=max_rb_trans,
1091 nonrigid_max_trans=max_bead_trans,
1092 name=
"RigidBody %s" % dname)
1095 for dname, domain
in self._domains[nstate].items():
1096 if dname
not in domains_in_rbs:
1097 if domain.pdb_file !=
"BEADS":
1099 "No rigid bodies set for %s. Residues read from "
1100 "the PDB file will not be sampled - only regions "
1101 "missing from the PDB will be treated flexibly. "
1102 "To sample the entire sequence, use BEADS instead "
1103 "of a PDB file name" % dname,
1105 self.dof.create_flexible_beads(
1106 self._domain_res[nstate][dname][1],
1107 max_trans=max_bead_trans)
1110 for srblist
in srbs:
1111 print(
"BuildSystem.execute_macro: -------- building "
1112 "super rigid body %s" % (str(srblist)))
1113 all_res = IMP.pmi.tools.OrderedSet()
1114 for dname
in srblist:
1115 print(
"BuildSystem.execute_macro: -------- adding %s"
1117 all_res |= self._domain_res[nstate][dname][0]
1118 all_res |= self._domain_res[nstate][dname][1]
1120 print(
"BuildSystem.execute_macro: -------- creating super "
1121 "rigid body with max_trans %s max_rot %s "
1122 % (str(max_srb_trans), str(max_srb_rot)))
1123 self.dof.create_super_rigid_body(
1124 all_res, max_trans=max_srb_trans, max_rot=max_srb_rot)
1127 for csrblist
in csrbs:
1128 all_res = IMP.pmi.tools.OrderedSet()
1129 for dname
in csrblist:
1130 all_res |= self._domain_res[nstate][dname][0]
1131 all_res |= self._domain_res[nstate][dname][1]
1132 all_res = list(all_res)
1133 all_res.sort(key=
lambda r: r.get_index())
1134 self.dof.create_main_chain_mover(all_res)
1135 return self.root_hier, self.dof
1140 """A macro for running all the basic operations of analysis.
1141 Includes clustering, precision analysis, and making ensemble density maps.
1142 A number of plots are also supported.
1145 merge_directories=[
"./"],
1146 stat_file_name_suffix=
"stat",
1147 best_pdb_name_suffix=
"model",
1148 do_clean_first=
True,
1149 do_create_directories=
True,
1150 global_output_directory=
"output/",
1151 replica_stat_file_suffix=
"stat_replica",
1152 global_analysis_result_directory=
"./analysis/",
1155 @param model The IMP model
1156 @param stat_file_name_suffix
1157 @param merge_directories The directories containing output files
1158 @param best_pdb_name_suffix
1159 @param do_clean_first
1160 @param do_create_directories
1161 @param global_output_directory Where everything is
1162 @param replica_stat_file_suffix
1163 @param global_analysis_result_directory
1164 @param test_mode If True, nothing is changed on disk
1168 from mpi4py
import MPI
1169 self.comm = MPI.COMM_WORLD
1170 self.rank = self.comm.Get_rank()
1171 self.number_of_processes = self.comm.size
1174 self.number_of_processes = 1
1176 self.test_mode = test_mode
1177 self._protocol_output = []
1178 self.cluster_obj =
None
1180 stat_dir = global_output_directory
1181 self.stat_files = []
1183 for rd
in merge_directories:
1184 stat_files = glob.glob(os.path.join(rd, stat_dir,
"stat.*.out"))
1185 if len(stat_files) == 0:
1186 warnings.warn(
"no stat files found in %s"
1187 % os.path.join(rd, stat_dir),
1189 self.stat_files += stat_files
1192 """Capture details of the modeling protocol.
1193 @param p an instance of IMP.pmi.output.ProtocolOutput or a subclass.
1196 self._protocol_output.append((p, p._last_state))
1199 score_key=
"Total_Score",
1200 rmf_file_key=
"rmf_file",
1201 rmf_file_frame_key=
"rmf_frame_index",
1204 nframes_trajectory=10000):
1205 """ Get a trajectory of the modeling run, for generating
1206 demonstrative movies
1208 @param score_key The score for ranking models
1209 @param rmf_file_key Key pointing to RMF filename
1210 @param rmf_file_frame_key Key pointing to RMF frame number
1211 @param outputdir The local output directory used in the run
1212 @param get_every Extract every nth frame
1213 @param nframes_trajectory Total number of frames of the trajectory
1218 self.stat_files, score_key, rmf_file_key, rmf_file_frame_key,
1220 score_list = list(map(float, trajectory_models[2]))
1222 max_score = max(score_list)
1223 min_score = min(score_list)
1225 bins = [(max_score-min_score)*math.exp(-float(i))+min_score
1226 for i
in range(nframes_trajectory)]
1227 binned_scores = [
None]*nframes_trajectory
1228 binned_model_indexes = [-1]*nframes_trajectory
1230 for model_index, s
in enumerate(score_list):
1231 bins_score_diffs = [abs(s-b)
for b
in bins]
1232 bin_index = min(enumerate(bins_score_diffs), key=itemgetter(1))[0]
1233 if binned_scores[bin_index]
is None:
1234 binned_scores[bin_index] = s
1235 binned_model_indexes[bin_index] = model_index
1237 old_diff = abs(binned_scores[bin_index]-bins[bin_index])
1238 new_diff = abs(s-bins[bin_index])
1239 if new_diff < old_diff:
1240 binned_scores[bin_index] = s
1241 binned_model_indexes[bin_index] = model_index
1243 print(binned_scores)
1244 print(binned_model_indexes)
1246 def _expand_ambiguity(self, prot, d):
1247 """If using PMI2, expand the dictionary to include copies as
1250 This also keeps the states separate.
1255 if '..' in key
or (isinstance(val, tuple)
and len(val) >= 3):
1258 states = IMP.atom.get_by_type(prot, IMP.atom.STATE_TYPE)
1259 if isinstance(val, tuple):
1267 for nst
in range(len(states)):
1269 copies = sel.get_selected_particles(with_representation=
False)
1271 for nc
in range(len(copies)):
1273 newdict[
'%s.%i..%i' % (name, nst, nc)] = \
1274 (start, stop, name, nc, nst)
1276 newdict[
'%s..%i' % (name, nc)] = \
1277 (start, stop, name, nc, nst)
1283 score_key=
"Total_Score",
1284 rmf_file_key=
"rmf_file",
1285 rmf_file_frame_key=
"rmf_frame_index",
1287 prefiltervalue=
None,
1290 alignment_components=
None,
1291 number_of_best_scoring_models=10,
1292 rmsd_calculation_components=
None,
1293 distance_matrix_file=
'distances.mat',
1294 load_distance_matrix_file=
False,
1295 skip_clustering=
False,
1296 number_of_clusters=1,
1298 exit_after_display=
True,
1300 first_and_last_frames=
None,
1301 density_custom_ranges=
None,
1302 write_pdb_with_centered_coordinates=
False,
1304 """Get the best scoring models, compute a distance matrix,
1305 cluster them, and create density maps.
1307 Tuple format: "molname" just the molecule,
1308 or (start,stop,molname,copy_num(optional),state_num(optional)
1309 Can pass None for copy or state to ignore that field.
1310 If you don't pass a specific copy number
1312 @param score_key The score for ranking models.
1313 @param rmf_file_key Key pointing to RMF filename
1314 @param rmf_file_frame_key Key pointing to RMF frame number
1315 @param state_number State number to analyze
1316 @param prefiltervalue Only include frames where the
1317 score key is below this value
1318 @param feature_keys Keywords for which you want to
1319 calculate average, medians, etc.
1320 If you pass "Keyname" it'll include everything that matches
1322 @param outputdir The local output directory used in
1324 @param alignment_components Dictionary with keys=groupname,
1325 values are tuples for aligning the structures
1326 e.g. {"Rpb1": (20,100,"Rpb1"),"Rpb2":"Rpb2"}
1327 @param number_of_best_scoring_models Num models to keep per run
1328 @param rmsd_calculation_components For calculating RMSD
1329 (same format as alignment_components)
1330 @param distance_matrix_file Where to store/read the
1332 @param load_distance_matrix_file Try to load the distance
1334 @param skip_clustering Just extract the best scoring
1335 models and save the pdbs
1336 @param number_of_clusters Number of k-means clusters
1337 @param display_plot Display the distance matrix
1338 @param exit_after_display Exit after displaying distance
1340 @param get_every Extract every nth frame
1341 @param first_and_last_frames A tuple with the first and last
1342 frames to be analyzed. Values are percentages!
1343 Default: get all frames
1344 @param density_custom_ranges For density calculation
1345 (same format as alignment_components)
1346 @param write_pdb_with_centered_coordinates
1347 @param voxel_size Used for the density output
1351 self._outputdir = Path(outputdir).absolute()
1352 self._number_of_clusters = number_of_clusters
1353 for p, state
in self._protocol_output:
1354 p.add_replica_exchange_analysis(state, self, density_custom_ranges)
1365 if not load_distance_matrix_file:
1366 if len(self.stat_files) == 0:
1367 print(
"ERROR: no stat file found in the given path")
1369 my_stat_files = IMP.pmi.tools.chunk_list_into_segments(
1370 self.stat_files, self.number_of_processes)[self.rank]
1373 for k
in (score_key, rmf_file_key, rmf_file_frame_key):
1374 if k
in feature_keys:
1376 "no need to pass " + k +
" to feature_keys.",
1378 feature_keys.remove(k)
1381 my_stat_files, score_key, feature_keys, rmf_file_key,
1382 rmf_file_frame_key, prefiltervalue, get_every, provenance=prov)
1383 rmf_file_list = best_models[0]
1384 rmf_file_frame_list = best_models[1]
1385 score_list = best_models[2]
1386 feature_keyword_list_dict = best_models[3]
1392 if self.number_of_processes > 1:
1396 rmf_file_frame_list)
1397 for k
in feature_keyword_list_dict:
1398 feature_keyword_list_dict[k] = \
1400 feature_keyword_list_dict[k])
1403 score_rmf_tuples = list(zip(score_list,
1405 rmf_file_frame_list,
1406 list(range(len(score_list)))))
1408 if density_custom_ranges:
1409 for k
in density_custom_ranges:
1410 if not isinstance(density_custom_ranges[k], list):
1411 raise Exception(
"Density custom ranges: values must "
1412 "be lists of tuples")
1415 if first_and_last_frames
is not None:
1416 nframes = len(score_rmf_tuples)
1417 first_frame = int(first_and_last_frames[0] * nframes)
1418 last_frame = int(first_and_last_frames[1] * nframes)
1419 if last_frame > len(score_rmf_tuples):
1421 score_rmf_tuples = score_rmf_tuples[first_frame:last_frame]
1424 best_score_rmf_tuples = sorted(
1426 key=
lambda x: float(x[0]))[:number_of_best_scoring_models]
1427 best_score_rmf_tuples = [t+(n,)
for n, t
in
1428 enumerate(best_score_rmf_tuples)]
1430 prov.append(IMP.pmi.io.FilterProvenance(
1431 "Best scoring", 0, number_of_best_scoring_models))
1433 best_score_feature_keyword_list_dict = defaultdict(list)
1434 for tpl
in best_score_rmf_tuples:
1436 for f
in feature_keyword_list_dict:
1437 best_score_feature_keyword_list_dict[f].append(
1438 feature_keyword_list_dict[f][index])
1439 my_best_score_rmf_tuples = IMP.pmi.tools.chunk_list_into_segments(
1440 best_score_rmf_tuples,
1441 self.number_of_processes)[self.rank]
1444 prot_ahead = IMP.pmi.analysis.get_hiers_from_rmf(
1445 self.model, 0, my_best_score_rmf_tuples[0][1])[0]
1446 if rmsd_calculation_components
is not None:
1447 tmp = self._expand_ambiguity(
1448 prot_ahead, rmsd_calculation_components)
1449 if tmp != rmsd_calculation_components:
1450 print(
'Detected ambiguity, expand rmsd components to',
1452 rmsd_calculation_components = tmp
1453 if alignment_components
is not None:
1454 tmp = self._expand_ambiguity(prot_ahead,
1455 alignment_components)
1456 if tmp != alignment_components:
1457 print(
'Detected ambiguity, expand alignment '
1458 'components to', tmp)
1459 alignment_components = tmp
1465 self.model, my_best_score_rmf_tuples[0],
1466 rmsd_calculation_components, state_number=state_number)
1468 self.model, my_best_score_rmf_tuples, alignment_components,
1469 rmsd_calculation_components, state_number=state_number)
1477 all_coordinates = got_coords[0]
1480 alignment_coordinates = got_coords[1]
1483 rmsd_coordinates = got_coords[2]
1486 rmf_file_name_index_dict = got_coords[3]
1489 all_rmf_file_names = got_coords[4]
1495 if density_custom_ranges:
1497 density_custom_ranges, voxel=voxel_size)
1499 dircluster = os.path.join(outputdir,
1500 "all_models."+str(self.rank))
1506 os.mkdir(dircluster)
1509 clusstat = open(os.path.join(
1510 dircluster,
"stat."+str(self.rank)+
".out"),
"w")
1511 for cnt, tpl
in enumerate(my_best_score_rmf_tuples):
1513 rmf_frame_number = tpl[2]
1516 for key
in best_score_feature_keyword_list_dict:
1518 best_score_feature_keyword_list_dict[key][index]
1522 IMP.pmi.analysis.get_hiers_and_restraints_from_rmf(
1523 self.model, rmf_frame_number, rmf_name)
1525 linking_successful = \
1526 IMP.pmi.analysis.link_hiers_and_restraints_to_rmf(
1527 self.model, prots, rs, rmf_frame_number,
1529 if not linking_successful:
1535 states = IMP.atom.get_by_type(
1536 prots[0], IMP.atom.STATE_TYPE)
1537 prot = states[state_number]
1542 coords_f1 = alignment_coordinates[cnt]
1544 coords_f2 = alignment_coordinates[cnt]
1547 coords_f1, coords_f2)
1548 transformation = Ali.align()[1]
1562 rb = rbm.get_rigid_body()
1572 out_pdb_fn = os.path.join(
1573 dircluster, str(cnt)+
"."+str(self.rank)+
".pdb")
1574 out_rmf_fn = os.path.join(
1575 dircluster, str(cnt)+
"."+str(self.rank)+
".rmf3")
1576 o.init_pdb(out_pdb_fn, prot)
1577 tc = write_pdb_with_centered_coordinates
1578 o.write_pdb(out_pdb_fn,
1579 translate_to_geometric_center=tc)
1581 tmp_dict[
"local_pdb_file_name"] = \
1582 os.path.basename(out_pdb_fn)
1583 tmp_dict[
"rmf_file_full_path"] = rmf_name
1584 tmp_dict[
"local_rmf_file_name"] = \
1585 os.path.basename(out_rmf_fn)
1586 tmp_dict[
"local_rmf_frame_number"] = 0
1588 clusstat.write(str(tmp_dict)+
"\n")
1593 h.set_name(
"System")
1595 o.init_rmf(out_rmf_fn, [h], rs)
1597 o.write_rmf(out_rmf_fn)
1598 o.close_rmf(out_rmf_fn)
1600 if density_custom_ranges:
1601 DensModule.add_subunits_density(prot)
1603 if density_custom_ranges:
1604 DensModule.write_mrc(path=dircluster)
1609 if self.number_of_processes > 1:
1615 rmf_file_name_index_dict)
1617 alignment_coordinates)
1624 [best_score_feature_keyword_list_dict,
1625 rmf_file_name_index_dict],
1631 print(
"setup clustering class")
1634 for n, model_coordinate_dict
in enumerate(all_coordinates):
1636 if (alignment_components
is not None
1637 and len(self.cluster_obj.all_coords) == 0):
1639 self.cluster_obj.set_template(alignment_coordinates[n])
1640 self.cluster_obj.fill(all_rmf_file_names[n],
1641 rmsd_coordinates[n])
1642 print(
"Global calculating the distance matrix")
1645 self.cluster_obj.dist_matrix()
1649 self.cluster_obj.do_cluster(number_of_clusters)
1652 self.cluster_obj.plot_matrix(
1653 figurename=os.path.join(outputdir,
1655 if exit_after_display:
1657 self.cluster_obj.save_distance_matrix_file(
1658 file_name=distance_matrix_file)
1665 print(
"setup clustering class")
1667 self.cluster_obj.load_distance_matrix_file(
1668 file_name=distance_matrix_file)
1669 print(
"clustering with %s clusters" % str(number_of_clusters))
1670 self.cluster_obj.do_cluster(number_of_clusters)
1671 [best_score_feature_keyword_list_dict,
1672 rmf_file_name_index_dict] = self.load_objects(
".macro.pkl")
1675 self.cluster_obj.plot_matrix(figurename=os.path.join(
1676 outputdir,
'dist_matrix.pdf'))
1677 if exit_after_display:
1679 if self.number_of_processes > 1:
1687 print(self.cluster_obj.get_cluster_labels())
1688 for n, cl
in enumerate(self.cluster_obj.get_cluster_labels()):
1689 print(
"rank %s " % str(self.rank))
1690 print(
"cluster %s " % str(n))
1691 print(
"cluster label %s " % str(cl))
1692 print(self.cluster_obj.get_cluster_label_names(cl))
1694 len(self.cluster_obj.get_cluster_label_names(cl))
1696 prov + [IMP.pmi.io.ClusterProvenance(cluster_size)]
1699 if density_custom_ranges:
1701 density_custom_ranges,
1704 dircluster = outputdir +
"/cluster." + str(n) +
"/"
1706 os.mkdir(dircluster)
1712 str(self.cluster_obj.get_cluster_label_average_rmsd(cl))}
1713 clusstat = open(dircluster +
"stat.out",
"w")
1714 for k, structure_name
in enumerate(
1715 self.cluster_obj.get_cluster_label_names(cl)):
1718 tmp_dict.update(rmsd_dict)
1719 index = rmf_file_name_index_dict[structure_name]
1720 for key
in best_score_feature_keyword_list_dict:
1722 key] = best_score_feature_keyword_list_dict[
1728 rmf_name = structure_name.split(
"|")[0]
1729 rmf_frame_number = int(structure_name.split(
"|")[1])
1730 clusstat.write(str(tmp_dict) +
"\n")
1735 IMP.pmi.analysis.get_hiers_and_restraints_from_rmf(
1736 self.model, rmf_frame_number, rmf_name)
1738 linking_successful = \
1739 IMP.pmi.analysis.link_hiers_and_restraints_to_rmf(
1740 self.model, prots, rs, rmf_frame_number,
1742 if not linking_successful:
1747 states = IMP.atom.get_by_type(
1748 prots[0], IMP.atom.STATE_TYPE)
1749 prot = states[state_number]
1755 co = self.cluster_obj
1756 model_index = co.get_model_index_from_name(
1758 transformation = co.get_transformation_to_first_member(
1769 rb = rbm.get_rigid_body()
1778 if density_custom_ranges:
1779 DensModule.add_subunits_density(prot)
1784 o.init_pdb(dircluster + str(k) +
".pdb", prot)
1785 o.write_pdb(dircluster + str(k) +
".pdb")
1790 h.set_name(
"System")
1792 o.init_rmf(dircluster + str(k) +
".rmf3", [h], rs)
1793 o.write_rmf(dircluster + str(k) +
".rmf3")
1794 o.close_rmf(dircluster + str(k) +
".rmf3")
1799 if density_custom_ranges:
1800 DensModule.write_mrc(path=dircluster)
1803 if self.number_of_processes > 1:
1806 def get_cluster_rmsd(self, cluster_num):
1807 if self.cluster_obj
is None:
1809 return self.cluster_obj.get_cluster_label_average_rmsd(cluster_num)
1811 def save_objects(self, objects, file_name):
1813 with open(file_name,
'wb')
as outf:
1814 pickle.dump(objects, outf)
1816 def load_objects(self, file_name):
1818 with open(file_name,
'rb')
as inputf:
1819 objects = pickle.load(inputf)
1826 This class contains analysis utilities to investigate ReplicaExchange
1834 def __init__(self, model, stat_files, best_models=None, score_key=None,
1837 Construction of the Class.
1838 @param model IMP.Model()
1839 @param stat_files list of string. Can be ascii stat files,
1841 @param best_models Integer. Number of best scoring models,
1842 if None: all models will be read
1843 @param score_key Use the provided stat key keyword as the score
1844 (by default, the total score is used)
1845 @param alignment boolean (Default=True). Align before computing
1850 self.best_models = best_models
1852 model, stat_files, self.best_models, score_key, cache=
True)
1854 StatHierarchyHandler=self.stath0)
1867 self.clusters.append(c)
1868 for n0
in range(len(self.stath0)):
1870 self.pairwise_rmsd = {}
1871 self.pairwise_molecular_assignment = {}
1872 self.alignment = alignment
1873 self.symmetric_molecules = {}
1874 self.issymmetricsel = {}
1876 self.molcopydict0 = IMP.pmi.tools.get_molecules_dictionary_by_copy(
1878 self.molcopydict1 = IMP.pmi.tools.get_molecules_dictionary_by_copy(
1883 Setup the selection onto which the rmsd is computed
1884 @param kwargs use IMP.atom.Selection keywords
1892 Store names of symmetric molecules
1894 self.symmetric_molecules[molecule_name] = 0
1899 Setup the selection onto which the alignment is computed
1900 @param kwargs use IMP.atom.Selection keywords
1908 def clean_clusters(self):
1909 for c
in self.clusters:
1913 def cluster(self, rmsd_cutoff=10, metric=IMP.atom.get_rmsd):
1915 Cluster the models based on RMSD.
1916 @param rmsd_cutoff Float the distance cutoff in Angstrom
1917 @param metric (Default=IMP.atom.get_rmsd) the metric that will
1918 be used to compute rmsds
1920 self.clean_clusters()
1921 not_clustered = set(range(len(self.stath1)))
1922 while len(not_clustered) > 0:
1923 self.
aggregate(not_clustered, rmsd_cutoff, metric)
1928 Refine the clusters by merging the ones whose centers are close
1929 @param rmsd_cutoff cutoff distance in Angstorms
1931 clusters_copy = self.clusters
1932 for c0, c1
in itertools.combinations(self.clusters, 2):
1933 if c0.center_index
is None:
1935 if c1.center_index
is None:
1937 _ = self.stath0[c0.center_index]
1938 _ = self.stath1[c1.center_index]
1939 rmsd, molecular_assignment = self.
rmsd()
1940 if rmsd <= rmsd_cutoff:
1941 if c1
in self.clusters:
1942 clusters_copy.remove(c1)
1944 self.clusters = clusters_copy
1951 def set_cluster_assignments(self, cluster_ids):
1952 if len(cluster_ids) != len(self.stath0):
1953 raise ValueError(
'cluster ids has to be same length as '
1957 for i
in sorted(list(set(cluster_ids))):
1959 for i, (idx, d)
in enumerate(zip(cluster_ids, self.stath0)):
1960 self.clusters[idx].add_member(i, d)
1964 Return the model data from a cluster
1965 @param cluster IMP.pmi.output.Cluster object
1974 Save the data for the whole models into a pickle file
1975 @param filename string
1977 self.stath0.save_data(filename)
1981 Set the data from an external IMP.pmi.output.Data
1982 @param data IMP.pmi.output.Data
1984 self.stath0.data = data
1985 self.stath1.data = data
1989 Load the data from an external pickled file
1990 @param filename string
1992 self.stath0.load_data(filename)
1993 self.stath1.load_data(filename)
1994 self.best_models = len(self.stath0)
1996 def add_cluster(self, rmf_name_list):
1998 print(
"creating cluster index "+str(len(self.clusters)))
1999 self.clusters.append(c)
2000 current_len = len(self.stath0)
2002 for rmf
in rmf_name_list:
2003 print(
"adding rmf "+rmf)
2004 self.stath0.add_stat_file(rmf)
2005 self.stath1.add_stat_file(rmf)
2007 for n0
in range(current_len, len(self.stath0)):
2008 d0 = self.stath0[n0]
2009 c.add_member(n0, d0)
2014 Save the clusters into a pickle file
2015 @param filename string
2018 with open(filename,
'wb')
as fl:
2019 pickle.dump(self.clusters, fl)
2023 Load the clusters from a pickle file
2024 @param filename string
2025 @param append bool (Default=False), if True. append the clusters
2026 to the ones currently present
2029 self.clean_clusters()
2030 with open(filename,
'rb')
as fl:
2032 self.clusters += pickle.load(fl)
2034 self.clusters = pickle.load(fl)
2043 Compute the cluster center for a given cluster
2045 member_distance = defaultdict(float)
2047 for n0, n1
in itertools.combinations(cluster.members, 2):
2050 rmsd, _ = self.
rmsd()
2051 member_distance[n0] += rmsd
2053 if len(member_distance) > 0:
2054 cluster.center_index = min(member_distance,
2055 key=member_distance.get)
2057 cluster.center_index = cluster.members[0]
2062 Save the coordinates of the current cluster a single rmf file
2064 print(
"saving coordinates", cluster)
2068 if rmf_name
is None:
2069 rmf_name = prefix+
'/'+str(cluster.cluster_id)+
".rmf3"
2071 _ = self.stath1[cluster.members[0]]
2073 o.init_rmf(rmf_name, [self.stath1])
2074 for n1
in cluster.members:
2080 o.write_rmf(rmf_name)
2082 o.close_rmf(rmf_name)
2086 remove structures that are similar
2087 append it to a new cluster
2089 print(
"pruning models")
2091 filtered = [selected]
2092 remaining = range(1, len(self.stath1), 10)
2094 while len(remaining) > 0:
2095 d0 = self.stath0[selected]
2097 for n1
in remaining:
2102 if d <= rmsd_cutoff:
2104 print(
"pruning model %s, similar to model %s, rmsd %s"
2105 % (str(n1), str(selected), str(d)))
2106 remaining = [x
for x
in remaining
if x
not in rm]
2107 if len(remaining) == 0:
2109 selected = remaining[0]
2110 filtered.append(selected)
2113 self.clusters.append(c)
2115 d0 = self.stath0[n0]
2116 c.add_member(n0, d0)
2121 Compute the precision of a cluster
2127 if cluster.center_index
is not None:
2128 members1 = [cluster.center_index]
2130 members1 = cluster.members
2134 for n1
in cluster.members:
2139 tmp_rmsd, _ = self.
rmsd()
2144 precision = rmsd/npairs
2145 cluster.precision = precision
2150 Compute the bipartite precision (ie the cross-precision)
2151 between two clusters
2155 for cn0, n0
in enumerate(cluster1.members):
2157 for cn1, n1
in enumerate(cluster2.members):
2159 tmp_rmsd, _ = self.
rmsd()
2161 print(
"--- rmsd between structure %s and structure "
2162 "%s is %s" % (str(cn0), str(cn1), str(tmp_rmsd)))
2165 precision = rmsd/npairs
2168 def rmsf(self, cluster, molecule, copy_index=0, state_index=0,
2169 cluster_ref=
None, step=1):
2171 Compute the Root mean square fluctuations
2172 of a molecule in a cluster
2173 Returns an IMP.pmi.tools.OrderedDict() where the keys are the
2174 residue indexes and the value is the rmsf
2176 rmsf = IMP.pmi.tools.OrderedDict()
2179 if cluster_ref
is not None:
2180 if cluster_ref.center_index
is not None:
2181 members0 = [cluster_ref.center_index]
2183 members0 = cluster_ref.members
2185 if cluster.center_index
is not None:
2186 members0 = [cluster.center_index]
2188 members0 = cluster.members
2191 copy_index=copy_index, state_index=state_index)
2192 ps0 = s0.get_selected_particles()
2194 residue_indexes = list(IMP.pmi.tools.OrderedSet(
2200 d0 = self.stath0[n0]
2201 for n1
in cluster.members[::step]:
2203 print(
"--- rmsf %s %s" % (str(n0), str(n1)))
2207 self.stath1, molecule=molecule,
2208 residue_indexes=residue_indexes, resolution=1,
2209 copy_index=copy_index, state_index=state_index)
2210 ps1 = s1.get_selected_particles()
2212 d1 = self.stath1[n1]
2215 for n, (p0, p1)
in enumerate(zip(ps0, ps1)):
2216 r = residue_indexes[n]
2228 for stath
in [self.stath0, self.stath1]:
2229 if molecule
not in self.symmetric_molecules:
2231 stath, molecule=molecule, residue_index=r,
2232 resolution=1, copy_index=copy_index,
2233 state_index=state_index)
2236 stath, molecule=molecule, residue_index=r,
2237 resolution=1, state_index=state_index)
2239 ps = s.get_selected_particles()
2248 def save_densities(self, cluster, density_custom_ranges, voxel_size=5,
2249 reference=
"Absolute", prefix=
"./", step=1):
2255 for n1
in cluster.members[::step]:
2256 print(
"density "+str(n1))
2261 dens.add_subunits_density(self.stath1)
2263 dens.write_mrc(path=prefix+
'/', suffix=str(cluster.cluster_id))
2266 def contact_map(self, cluster, contact_threshold=15, log_scale=False,
2267 consolidate=
False, molecules=
None, prefix=
'./',
2268 reference=
"Absolute"):
2272 import matplotlib.pyplot
as plt
2273 import matplotlib.cm
as cm
2274 from scipy.spatial.distance
import cdist
2276 if molecules
is None:
2285 molecules=molecules).get_selected_particles())]
2286 unique_copies = [mol
for mol
in mols
if mol.get_copy_index() == 0]
2287 mol_names_unique = dict((mol.get_name(), mol)
for mol
in unique_copies)
2288 total_len_unique = sum(max(mol.get_residue_indexes())
2289 for mol
in unique_copies)
2296 seqlen = max(mol.get_residue_indexes())
2297 index_dict[mol] = range(prev_stop, prev_stop + seqlen)
2301 for mol
in unique_copies:
2302 seqlen = max(mol.get_residue_indexes())
2303 index_dict[mol] = range(prev_stop, prev_stop + seqlen)
2306 for ncl, n1
in enumerate(cluster.members):
2309 coord_dict = IMP.pmi.tools.OrderedDict()
2311 rindexes = mol.get_residue_indexes()
2312 coords = np.ones((max(rindexes), 3))
2313 for rnum
in rindexes:
2316 selpart = sel.get_selected_particles()
2317 if len(selpart) == 0:
2319 selpart = selpart[0]
2320 coords[rnum - 1, :] = \
2322 coord_dict[mol] = coords
2325 coords = np.concatenate(list(coord_dict.values()))
2326 dists = cdist(coords, coords)
2327 binary_dists = np.where((dists <= contact_threshold)
2328 & (dists >= 1.0), 1.0, 0.0)
2330 binary_dists_dict = {}
2332 len1 = max(mol1.get_residue_indexes())
2334 name1 = mol1.get_name()
2335 name2 = mol2.get_name()
2336 dists = cdist(coord_dict[mol1], coord_dict[mol2])
2337 if (name1, name2)
not in binary_dists_dict:
2338 binary_dists_dict[(name1, name2)] = \
2339 np.zeros((len1, len1))
2340 binary_dists_dict[(name1, name2)] += \
2341 np.where((dists <= contact_threshold)
2342 & (dists >= 1.0), 1.0, 0.0)
2343 binary_dists = np.zeros((total_len_unique, total_len_unique))
2345 for name1, name2
in binary_dists_dict:
2346 r1 = index_dict[mol_names_unique[name1]]
2347 r2 = index_dict[mol_names_unique[name2]]
2348 binary_dists[min(r1):max(r1)+1, min(r2):max(r2)+1] = \
2349 np.where((binary_dists_dict[(name1, name2)] >= 1.0),
2355 contact_freqs = binary_dists
2357 dist_maps.append(dists)
2358 av_dist_map += dists
2359 contact_freqs += binary_dists
2362 contact_freqs = -np.log(1.0-1.0/(len(cluster)+1)*contact_freqs)
2364 contact_freqs = 1.0/len(cluster)*contact_freqs
2365 av_dist_map = 1.0/len(cluster)*contact_freqs
2367 fig = plt.figure(figsize=(100, 100))
2368 ax = fig.add_subplot(111)
2371 gap_between_components = 50
2376 sorted_tuple = sorted(
2378 mol).get_extended_name(), mol)
for mol
in mols)
2379 prot_list = list(zip(*sorted_tuple))[1]
2381 sorted_tuple = sorted(
2383 for mol
in unique_copies)
2384 prot_list = list(zip(*sorted_tuple))[1]
2386 prot_listx = prot_list
2387 nresx = gap_between_components + \
2388 sum([max(mol.get_residue_indexes())
2389 + gap_between_components
for mol
in prot_listx])
2392 prot_listy = prot_list
2393 nresy = gap_between_components + \
2394 sum([max(mol.get_residue_indexes())
2395 + gap_between_components
for mol
in prot_listy])
2400 res = gap_between_components
2401 for mol
in prot_listx:
2402 resoffsetx[mol] = res
2403 res += max(mol.get_residue_indexes())
2405 res += gap_between_components
2409 res = gap_between_components
2410 for mol
in prot_listy:
2411 resoffsety[mol] = res
2412 res += max(mol.get_residue_indexes())
2414 res += gap_between_components
2416 resoffsetdiagonal = {}
2417 res = gap_between_components
2418 for mol
in IMP.pmi.tools.OrderedSet(prot_listx + prot_listy):
2419 resoffsetdiagonal[mol] = res
2420 res += max(mol.get_residue_indexes())
2421 res += gap_between_components
2426 for n, prot
in enumerate(prot_listx):
2427 res = resoffsetx[prot]
2429 for proty
in prot_listy:
2430 resy = resoffsety[proty]
2431 endy = resendy[proty]
2432 ax.plot([res, res], [resy, endy], linestyle=
'-',
2433 color=
'gray', lw=0.4)
2434 ax.plot([end, end], [resy, endy], linestyle=
'-',
2435 color=
'gray', lw=0.4)
2436 xticks.append((float(res) + float(end)) / 2)
2438 prot).get_extended_name())
2442 for n, prot
in enumerate(prot_listy):
2443 res = resoffsety[prot]
2445 for protx
in prot_listx:
2446 resx = resoffsetx[protx]
2447 endx = resendx[protx]
2448 ax.plot([resx, endx], [res, res], linestyle=
'-',
2449 color=
'gray', lw=0.4)
2450 ax.plot([resx, endx], [end, end], linestyle=
'-',
2451 color=
'gray', lw=0.4)
2452 yticks.append((float(res) + float(end)) / 2)
2454 prot).get_extended_name())
2458 tmp_array = np.zeros((nresx, nresy))
2460 for px
in prot_listx:
2461 for py
in prot_listy:
2462 resx = resoffsetx[px]
2463 lengx = resendx[px] - 1
2464 resy = resoffsety[py]
2465 lengy = resendy[py] - 1
2466 indexes_x = index_dict[px]
2467 minx = min(indexes_x)
2468 maxx = max(indexes_x)
2469 indexes_y = index_dict[py]
2470 miny = min(indexes_y)
2471 maxy = max(indexes_y)
2472 tmp_array[resx:lengx, resy:lengy] = \
2473 contact_freqs[minx:maxx, miny:maxy]
2474 ret[(px, py)] = np.argwhere(
2475 contact_freqs[minx:maxx, miny:maxy] == 1.0) + 1
2477 ax.imshow(tmp_array, cmap=colormap, norm=colornorm,
2478 origin=
'lower', alpha=0.6, interpolation=
'nearest')
2480 ax.set_xticks(xticks)
2481 ax.set_xticklabels(xlabels, rotation=90)
2482 ax.set_yticks(yticks)
2483 ax.set_yticklabels(ylabels)
2484 plt.setp(ax.get_xticklabels(), fontsize=6)
2485 plt.setp(ax.get_yticklabels(), fontsize=6)
2488 fig.set_size_inches(0.005 * nresx, 0.005 * nresy)
2489 [i.set_linewidth(2.0)
for i
in ax.spines.values()]
2491 plt.savefig(prefix+
"/contact_map."+str(cluster.cluster_id)+
".pdf",
2492 dpi=300, transparent=
"False")
2495 def plot_rmsd_matrix(self, filename):
2496 self.compute_all_pairwise_rmsd()
2497 distance_matrix = np.zeros(
2498 (len(self.stath0), len(self.stath1)))
2499 for (n0, n1)
in self.pairwise_rmsd:
2500 distance_matrix[n0, n1] = self.pairwise_rmsd[(n0, n1)]
2502 import matplotlib
as mpl
2504 import matplotlib.pylab
as pl
2505 from scipy.cluster
import hierarchy
as hrc
2507 fig = pl.figure(figsize=(10, 8))
2508 ax = fig.add_subplot(212)
2509 dendrogram = hrc.dendrogram(
2510 hrc.linkage(distance_matrix),
2513 leaves_order = dendrogram[
'leaves']
2514 ax.set_xlabel(
'Model')
2515 ax.set_ylabel(
'RMSD [Angstroms]')
2517 ax2 = fig.add_subplot(221)
2519 distance_matrix[leaves_order, :][:, leaves_order],
2520 interpolation=
'nearest')
2521 cb = fig.colorbar(cax)
2522 cb.set_label(
'RMSD [Angstroms]')
2523 ax2.set_xlabel(
'Model')
2524 ax2.set_ylabel(
'Model')
2526 pl.savefig(filename, dpi=300)
2535 Update the cluster id numbers
2537 for n, c
in enumerate(self.clusters):
2540 def get_molecule(self, hier, name, copy):
2548 self.seldict0 = IMP.pmi.tools.get_selections_dictionary(
2549 self.sel0_rmsd.get_selected_particles())
2550 self.seldict1 = IMP.pmi.tools.get_selections_dictionary(
2551 self.sel1_rmsd.get_selected_particles())
2552 for mol
in self.seldict0:
2553 for sel
in self.seldict0[mol]:
2554 self.issymmetricsel[sel] =
False
2555 for mol
in self.symmetric_molecules:
2556 self.symmetric_molecules[mol] = len(self.seldict0[mol])
2557 for sel
in self.seldict0[mol]:
2558 self.issymmetricsel[sel] =
True
2562 self.sel1_alignment, self.sel0_alignment)
2564 for rb
in self.rbs1:
2567 for bead
in self.beads1:
2575 def aggregate(self, idxs, rmsd_cutoff=10, metric=IMP.atom.get_rmsd):
2577 initial filling of the clusters.
2580 print(
"clustering model "+str(n0))
2581 d0 = self.stath0[n0]
2583 print(
"creating cluster index "+str(len(self.clusters)))
2584 self.clusters.append(c)
2585 c.add_member(n0, d0)
2586 clustered = set([n0])
2588 print(
"--- trying to add model " + str(n1) +
" to cluster "
2589 + str(len(self.clusters)))
2590 d1 = self.stath1[n1]
2593 rmsd, _ = self.
rmsd(metric=metric)
2594 if rmsd < rmsd_cutoff:
2595 print(
"--- model "+str(n1)+
" added, rmsd="+str(rmsd))
2596 c.add_member(n1, d1)
2599 print(
"--- model "+str(n1)+
" NOT added, rmsd="+str(rmsd))
2604 merge the clusters that have close members
2606 @param rmsd_cutoff cutoff distance in Angstorms
2607 @param metric Function to calculate distance between two Selections
2608 (by default, IMP.atom.get_rmsd is used)
2616 for c0, c1
in filter(
lambda x: len(x[0].members) > 1,
2617 itertools.combinations(self.clusters, 2)):
2618 n0, n1 = [c.members[0]
for c
in (c0, c1)]
2621 rmsd, _ = self.
rmsd()
2622 if (rmsd < 2*rmsd_cutoff
and
2624 to_merge.append((c0, c1))
2626 for c0, c
in reversed(to_merge):
2630 self.clusters = [c
for c
in
2631 filter(
lambda x: len(x.members) > 0, self.clusters)]
2635 returns true if c0 and c1 have members that are closer than rmsd_cutoff
2637 print(
"check close members for clusters " + str(c0.cluster_id) +
2638 " and " + str(c1.cluster_id))
2639 for n0, n1
in itertools.product(c0.members[1:], c1.members):
2642 rmsd, _ = self.
rmsd(metric=metric)
2643 if rmsd < rmsd_cutoff:
2658 a function that returns the permutation best_sel of sels0 that
2661 best_rmsd2 = float(
'inf')
2663 if self.issymmetricsel[sels0[0]]:
2666 for offset
in range(N):
2667 sels = [sels0[(offset+i) % N]
for i
in range(N)]
2670 r = metric(sel0, sel1)
2672 if rmsd2 < best_rmsd2:
2676 for sels
in itertools.permutations(sels0):
2678 for sel0, sel1
in itertools.takewhile(
2679 lambda x: rmsd2 < best_rmsd2, zip(sels, sels1)):
2680 r = metric(sel0, sel1)
2682 if rmsd2 < best_rmsd2:
2685 return best_sel, best_rmsd2
2687 def compute_all_pairwise_rmsd(self):
2688 for d0
in self.stath0:
2689 for d1
in self.stath1:
2690 rmsd, _ = self.
rmsd()
2692 def rmsd(self, metric=IMP.atom.get_rmsd):
2694 Computes the RMSD. Resolves ambiguous pairs assignments
2698 n0 = self.stath0.current_index
2699 n1 = self.stath1.current_index
2700 if ((n0, n1)
in self.pairwise_rmsd) \
2701 and ((n0, n1)
in self.pairwise_molecular_assignment):
2702 return (self.pairwise_rmsd[(n0, n1)],
2703 self.pairwise_molecular_assignment[(n0, n1)])
2713 molecular_assignment = {}
2714 for molname, sels0
in self.seldict0.items():
2715 sels_best_order, best_rmsd2 = \
2716 self.
rmsd_helper(sels0, self.seldict1[molname], metric)
2718 Ncoords = len(sels_best_order[0].get_selected_particles())
2719 Ncopies = len(self.seldict1[molname])
2720 total_rmsd += Ncoords*best_rmsd2
2721 total_N += Ncoords*Ncopies
2723 for sel0, sel1
in zip(sels_best_order, self.seldict1[molname]):
2724 p0 = sel0.get_selected_particles()[0]
2725 p1 = sel1.get_selected_particles()[0]
2730 molecular_assignment[(molname, c0)] = (molname, c1)
2732 total_rmsd = math.sqrt(total_rmsd/total_N)
2734 self.pairwise_rmsd[(n0, n1)] = total_rmsd
2735 self.pairwise_molecular_assignment[(n0, n1)] = molecular_assignment
2736 self.pairwise_rmsd[(n1, n0)] = total_rmsd
2737 self.pairwise_molecular_assignment[(n1, n0)] = molecular_assignment
2738 return total_rmsd, molecular_assignment
2742 Fix the reference structure for structural alignment, rmsd and
2745 @param reference can be either "Absolute" (cluster center of the
2746 first cluster) or Relative (cluster center of the current
2748 #param cluster the reference IMP.pmi.output.Cluster object
2750 if reference ==
"Absolute":
2752 elif reference ==
"Relative":
2753 if cluster.center_index:
2754 n0 = cluster.center_index
2756 n0 = cluster.members[0]
2761 compute the molecular assignments between multiple copies
2762 of the same sequence. It changes the Copy index of Molecules
2765 _, molecular_assignment = self.
rmsd()
2766 for (m0, c0), (m1, c1)
in molecular_assignment.items():
2767 mol0 = self.molcopydict0[m0][c0]
2768 mol1 = self.molcopydict1[m1][c1]
2771 p1.set_value(cik0, c0)
2775 Undo the Copy index assignment
2778 _, molecular_assignment = self.
rmsd()
2779 for (m0, c0), (m1, c1)
in molecular_assignment.items():
2780 mol0 = self.molcopydict0[m0][c0]
2781 mol1 = self.molcopydict1[m1][c1]
2784 p1.set_value(cik0, c1)
2791 s =
"AnalysisReplicaExchange\n"
2792 s +=
"---- number of clusters %s \n" % str(len(self.clusters))
2793 s +=
"---- number of models %s \n" % str(len(self.stath0))
2796 def __getitem__(self, int_slice_adaptor):
2797 if isinstance(int_slice_adaptor, int):
2798 return self.clusters[int_slice_adaptor]
2799 elif isinstance(int_slice_adaptor, slice):
2800 return self.__iter__(int_slice_adaptor)
2802 raise TypeError(
"Unknown Type")
2805 return len(self.clusters)
2807 def __iter__(self, slice_key=None):
2808 if slice_key
is None:
2809 for i
in range(len(self)):
2812 for i
in range(len(self))[slice_key]:
Simplify creation of constraints and movers for an IMP Hierarchy.
def rmsd
Computes the RMSD.
def set_reference
Fix the reference structure for structural alignment, rmsd and chain assignment.
def load_clusters
Load the clusters from a pickle file.
A class to implement Hamiltonian Replica Exchange.
def precision
Compute the precision of a cluster.
CheckLevel get_check_level()
Get the current audit mode.
Extends the functionality of IMP.atom.Molecule.
A macro for running all the basic operations of analysis.
A container for models organized into clusters.
Sample using molecular dynamics.
def aggregate
initial filling of the clusters.
A member of a rigid body, it has internal (local) coordinates.
A macro to help setup and run replica exchange.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Set of Python classes to create a multi-state, multi-resolution IMP hierarchy.
def prune_redundant_structures
remove structures that are similar append it to a new cluster
def rmsf
Compute the Root mean square fluctuations of a molecule in a cluster Returns an IMP.pmi.tools.OrderedDict() where the keys are the residue indexes and the value is the rmsf.
static XYZR setup_particle(Model *m, ParticleIndex pi)
Utility classes and functions for reading and storing PMI files.
def get_best_models
Given a list of stat files, read them all and find the best models.
A helper output for model evaluation.
def set_rmsd_selection
Setup the selection onto which the rmsd is computed.
def get_cluster_data
Return the model data from a cluster.
def __init__
Construction of the Class.
def get_molecules
Return list of all molecules grouped by state.
def set_data
Set the data from an external IMP.pmi.output.Data.
def undo_apply_molecular_assignments
Undo the Copy index assignment.
def set_alignment_selection
Setup the selection onto which the alignment is computed.
def rmsd_helper
a function that returns the permutation best_sel of sels0 that minimizes metric
An unbounded space with no periodic boundary conditions.
def save_coordinates
Save the coordinates of the current cluster a single rmf file.
def clustering
Get the best scoring models, compute a distance matrix, cluster them, and create density maps...
def apply_molecular_assignments
compute the molecular assignments between multiple copies of the same sequence.
This class contains analysis utilities to investigate ReplicaExchange results.
Add uncertainty to a particle.
A macro to build a IMP::pmi::topology::System based on a TopologyReader object.
def set_restart
Enable a simulation to be restarted if it is interrupted.
def merge_aggregates
merge the clusters that have close members
Represent the root node of the global IMP.atom.Hierarchy.
double get_distance(XYZR a, XYZR b)
Compute the sphere distance between a and b.
A class to cluster structures.
def add_protocol_output
Capture details of the modeling protocol.
static Uncertainty setup_particle(Model *m, ParticleIndex pi, Float uncertainty)
def compute_cluster_center
Compute the cluster center for a given cluster.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
def get_modeling_trajectory
Get a trajectory of the modeling run, for generating demonstrative movies.
Warning related to handling of structures.
A decorator for keeping track of copies of a molecule.
static Hierarchy setup_particle(Model *m, ParticleIndex pi, ParticleIndexesAdaptor children=ParticleIndexesAdaptor())
Create a Hierarchy of level t by adding the needed attributes.
def get_trajectory_models
Given a list of stat files, read them all and find a trajectory of models.
The standard decorator for manipulating molecular structures.
Performs alignment and RMSD calculation for two sets of coordinates.
def update_seldicts
Update the seldicts.
def update_clusters
Update the cluster id numbers.
void transform(XYZ a, const algebra::Transformation3D &tr)
Apply a transformation to the particle.
Code that uses the MPI parallel library.
def restart_replica_exchange
Continue a failed ReplicaExchange sampling run.
def refine
Refine the clusters by merging the ones whose centers are close.
A decorator for a particle with x,y,z coordinates.
Class for easy writing of PDBs, RMFs, and stat files.
def set_symmetric
Store names of symmetric molecules.
Warning for an expected, but missing, file.
Support for the JAX Python library.
Tools for clustering and cluster analysis.
Transformation3D get_identity_transformation_3d()
Return a transformation that does not do anything.
Classes for writing output files and processing them.
def deprecated_object
Python decorator to mark a class as deprecated.
Sample using Monte Carlo.
Create movers and set up constraints for PMI objects.
def merge
merge two clusters
def add_state
Add a state using the topology info in a IMP::pmi::topology::TopologyReader object.
The general base class for IMP exceptions.
static SampleProvenance setup_particle(Model *m, ParticleIndex pi, std::string method, int frames, int iterations, int replicas)
class to link stat files to several rmf files
Mapping between FASTA one-letter codes and residue types.
def save_data
Save the data for the whole models into a pickle file.
Class to handle individual particles of a Model object.
def execute_macro
Builds representations and sets up degrees of freedom.
def bipartite_precision
Compute the bipartite precision (ie the cross-precision) between two clusters.
def read_coordinates_of_rmfs
Read in coordinates of a set of RMF tuples.
int get_copy_index(Hierarchy h)
Walk up the hierarchy to find the current copy index.
def cluster
Cluster the models based on RMSD.
static bool get_is_setup(Model *m, ParticleIndex pi)
def save_clusters
Save the clusters into a pickle file.
def have_close_members
returns true if c0 and c1 have members that are closer than rmsd_cutoff
void add_geometries(RMF::FileHandle file, const display::GeometriesTemp &r)
Add geometries to the file.
algebra::Transformation3D get_transformation_aligning_first_to_second(const Selection &s1, const Selection &s2)
Get the transformation to align two selections.
A dictionary-like wrapper for reading and storing sequence data.
void add_provenance(Model *m, ParticleIndex pi, Provenance p)
Add provenance to part of the model.
Hierarchies get_leaves(const Selection &h)
Select hierarchy particles identified by the biological name.
Compute mean density maps from structures.
def load_data
Load the data from an external pickled file.
Support for the RMF file format for storing hierarchical molecular data and markup.
Sample using replica exchange.
Warning for probably incorrect input parameters.
def add_provenance
Add provenance information in prov (a list of _TempProvenance objects) to each of the IMP hierarchies...
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.