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()
157 class _TotalScoreObject:
158 """A simple wrapper object for the total score. It contains a
159 single attribute, `score`."""
165 """A macro to help setup and run replica exchange.
166 Supports Monte Carlo and molecular dynamics.
167 Produces trajectory RMF files, best PDB structures,
168 and output stat files.
170 def __init__(self, model, root_hier,
171 monte_carlo_sample_objects=
None,
172 molecular_dynamics_sample_objects=
None,
174 rmf_output_objects=
None,
175 monte_carlo_temperature=1.0,
176 simulated_annealing=
False,
177 simulated_annealing_minimum_temperature=1.0,
178 simulated_annealing_maximum_temperature=2.5,
179 simulated_annealing_minimum_temperature_nframes=100,
180 simulated_annealing_maximum_temperature_nframes=100,
181 replica_exchange_minimum_temperature=1.0,
182 replica_exchange_maximum_temperature=2.5,
183 replica_exchange_swap=
True,
185 number_of_best_scoring_models=500,
186 monte_carlo_steps=10,
188 molecular_dynamics_steps=10,
189 molecular_dynamics_max_time_step=1.0,
190 number_of_frames=1000,
191 save_coordinates_mode=
"lowest_temperature",
192 nframes_write_coordinates=1,
193 write_initial_rmf=
True,
194 initial_rmf_name_suffix=
"initial",
195 stat_file_name_suffix=
"stat",
196 best_pdb_name_suffix=
"model",
199 do_create_directories=
True,
200 global_output_directory=
"./",
202 best_pdb_dir=
"pdbs/",
203 replica_stat_file_suffix=
"stat_replica",
204 em_object_for_rmf=
None,
206 replica_exchange_object=
None,
210 nestor_restraints=
None,
211 nestor_rmf_fname_prefix=
"nested",
214 @param model The IMP model
215 @param root_hier Top-level (System)hierarchy
216 @param monte_carlo_sample_objects Objects for MC sampling, which
217 should generally be a simple list of Mover objects, e.g.
218 from DegreesOfFreedom.get_movers().
219 @param molecular_dynamics_sample_objects Objects for MD sampling,
220 which should generally be a simple list of particles.
221 @param output_objects A list of structural objects and restraints
222 that will be included in output (ie, statistics "stat"
223 files). Any object that provides a get_output() method
224 can be used here. If None is passed
225 the macro will not write stat files.
226 @param rmf_output_objects A list of structural objects and
227 restraints that will be included in rmf. Any object
228 that provides a get_output() method can be used here.
229 @param monte_carlo_temperature MC temp (may need to be optimized
230 based on post-sampling analysis)
231 @param simulated_annealing If True, perform simulated annealing
232 @param simulated_annealing_minimum_temperature Should generally be
233 the same as monte_carlo_temperature.
234 @param simulated_annealing_minimum_temperature_nframes Number of
235 frames to compute at minimum temperature.
236 @param simulated_annealing_maximum_temperature_nframes Number of
238 temps > simulated_annealing_maximum_temperature.
239 @param replica_exchange_minimum_temperature Low temp for REX; should
240 generally be the same as monte_carlo_temperature.
241 @param replica_exchange_maximum_temperature High temp for REX
242 @param replica_exchange_swap Boolean, enable disable temperature
244 @param num_sample_rounds Number of rounds of MC/MD per cycle
245 @param number_of_best_scoring_models Number of top-scoring PDB/mmCIF
246 models to keep around for analysis.
247 @param mmcif If True, write best scoring models in mmCIF format;
248 if False (the default), write in legacy PDB format.
249 @param best_pdb_dir The directory under `global_output_directory`
250 where best-scoring PDB/mmCIF files are written.
251 @param best_pdb_name_suffix Part of the file name for best-scoring
253 @param monte_carlo_steps Number of MC steps per round
254 @param self_adaptive self adaptive scheme for Monte Carlo movers
255 @param molecular_dynamics_steps Number of MD steps per round
256 @param molecular_dynamics_max_time_step Max time step for MD
257 @param number_of_frames Number of REX frames to run
258 @param save_coordinates_mode string: how to save coordinates.
259 "lowest_temperature" (default) only the lowest temperatures
261 "25th_score" all replicas whose score is below the 25th
263 "50th_score" all replicas whose score is below the 50th
265 "75th_score" all replicas whose score is below the 75th
267 @param nframes_write_coordinates How often to write the coordinates
269 @param write_initial_rmf Write the initial configuration
270 @param global_output_directory Folder that will be created to house
272 @param test_mode Set to True to avoid writing any files, just test
274 @param score_moved If True, attempt to speed up Monte Carlo
275 sampling by caching scoring function terms on particles
277 @param use_nestor If True, follows the Nested Sampling workflow
278 of the NestOR module and skips writing stat files and
280 @param nestor_restraints A list of restraints for which
281 likelihoods are to be computed for use by NestOR module.
282 @param nestor_rmf_fname_prefix Prefix to be used for storing .rmf3
283 files generated by NestOR .
284 @param use_jax If set to True, sample the scoring function using
285 JAX instead of IMP's internal C++ implementation (requires
286 that all PMI restraints used have a JAX implementation).
291 self._restart_from_frame = 0
294 if output_objects == []:
297 self.output_objects = []
299 self.output_objects = output_objects
300 self.rmf_output_objects = rmf_output_objects
301 self._total_score_obj = _TotalScoreObject()
303 and not root_hier.get_parent()):
304 if self.output_objects
is not None:
305 self.output_objects.append(
307 if self.rmf_output_objects
is not None:
308 self.rmf_output_objects.append(
310 self.root_hier = root_hier
311 states = IMP.atom.get_by_type(root_hier, IMP.atom.STATE_TYPE)
312 self.vars[
"number_of_states"] = len(states)
314 self.root_hiers = states
315 self.is_multi_state =
True
317 self.root_hier = root_hier
318 self.is_multi_state =
False
320 raise TypeError(
"Must provide System hierarchy (root_hier)")
322 self._rmf_restraints = _RMFRestraints(model,
None)
323 self.em_object_for_rmf = em_object_for_rmf
324 self.monte_carlo_sample_objects = monte_carlo_sample_objects
325 self.vars[
"self_adaptive"] = self_adaptive
326 self.molecular_dynamics_sample_objects = \
327 molecular_dynamics_sample_objects
328 self.replica_exchange_object = replica_exchange_object
329 self.molecular_dynamics_max_time_step = \
330 molecular_dynamics_max_time_step
331 self.vars[
"monte_carlo_temperature"] = monte_carlo_temperature
332 self.vars[
"replica_exchange_minimum_temperature"] = \
333 replica_exchange_minimum_temperature
334 self.vars[
"replica_exchange_maximum_temperature"] = \
335 replica_exchange_maximum_temperature
336 self.vars[
"replica_exchange_swap"] = replica_exchange_swap
337 self.vars[
"simulated_annealing"] = simulated_annealing
338 self.vars[
"simulated_annealing_minimum_temperature"] = \
339 simulated_annealing_minimum_temperature
340 self.vars[
"simulated_annealing_maximum_temperature"] = \
341 simulated_annealing_maximum_temperature
342 self.vars[
"simulated_annealing_minimum_temperature_nframes"] = \
343 simulated_annealing_minimum_temperature_nframes
344 self.vars[
"simulated_annealing_maximum_temperature_nframes"] = \
345 simulated_annealing_maximum_temperature_nframes
347 self.vars[
"num_sample_rounds"] = num_sample_rounds
349 "number_of_best_scoring_models"] = number_of_best_scoring_models
350 self.vars[
"monte_carlo_steps"] = monte_carlo_steps
351 self.vars[
"molecular_dynamics_steps"] = molecular_dynamics_steps
352 self.vars[
"number_of_frames"] = number_of_frames
353 if save_coordinates_mode
not in (
"lowest_temperature",
"25th_score",
354 "50th_score",
"75th_score"):
355 raise Exception(
"save_coordinates_mode has unrecognized value")
357 self.vars[
"save_coordinates_mode"] = save_coordinates_mode
358 self.vars[
"nframes_write_coordinates"] = nframes_write_coordinates
359 self.vars[
"write_initial_rmf"] = write_initial_rmf
360 self.vars[
"initial_rmf_name_suffix"] = initial_rmf_name_suffix
361 self.vars[
"best_pdb_name_suffix"] = best_pdb_name_suffix
362 self.vars[
"mmcif"] = mmcif
363 self.vars[
"stat_file_name_suffix"] = stat_file_name_suffix
364 self.vars[
"do_clean_first"] = do_clean_first
365 self.vars[
"do_create_directories"] = do_create_directories
366 self.vars[
"global_output_directory"] = global_output_directory
367 self.vars[
"rmf_dir"] = rmf_dir
368 self.vars[
"best_pdb_dir"] = best_pdb_dir
369 self.vars[
"atomistic"] = atomistic
370 self.vars[
"replica_stat_file_suffix"] = replica_stat_file_suffix
371 self.vars[
"geometries"] =
None
372 self.test_mode = test_mode
373 self.score_moved = score_moved
374 self.use_jax = use_jax
375 self.vars[
"use_nestor"] = self.nest = use_nestor
376 self.nestor_restraints = nestor_restraints
377 self.nestor_rmf_fname = nestor_rmf_fname_prefix
380 self._jax_space = self._get_jax_free_space()
383 """Enable a simulation to be restarted if it is interrupted.
385 If enabled, restart files containing a complete description of
386 the IMP system are written periodically during the simulation,
387 one per replica. If the simulation is interrupted, it can be
388 restarted using the restart_replica_exchange function, which
389 reads these files. Files for the previous restart are also kept
390 (with a .prev.pck extension) in case the most recent restart
393 Restart files contain IMP internal state and so will probably
394 not work with a different version of IMP, or on a different
395 operating system. As with all Python pickles, these files may
396 contain executable Python code and so you should not use a
397 restart file from an untrusted source.
399 @param frames How often a restart file should be written
400 (number of frames), or zero to not write restart files
401 @param restart_dir The directory under `global_output_directory`
402 where restart files are written.
407 self._restart = _RestartInfo(frames, restart_dir)
410 if self.vars[
"geometries"]
is None:
411 self.vars[
"geometries"] = list(geometries)
413 self.vars[
"geometries"].extend(geometries)
416 print(
"ReplicaExchange: it generates initial.*.rmf3, stat.*.out, "
417 "rmfs/*.rmf3 for each replica ")
418 print(
"--- it stores the best scoring pdb models in pdbs/")
419 print(
"--- the stat.*.out and rmfs/*.rmf3 are saved only at the "
420 "lowest temperature")
421 if self._restart
and self._restart.restarted:
422 print(
"--- this is a restart of a failed simulation")
423 print(
"--- variables:")
424 for k, v
in sorted(self.vars.items(), key=itemgetter(0)):
425 print(
"------", k.ljust(30), v)
427 def get_replica_exchange_object(self):
428 return self.replica_exchange_object
430 def _add_provenance(self, sampler_md, sampler_mc):
431 """Record details about the sampling in the IMP Hierarchies"""
434 method =
"Molecular Dynamics"
435 iterations += self.vars[
"molecular_dynamics_steps"]
437 method =
"Hybrid MD/MC" if sampler_md
else "Monte Carlo"
438 iterations += self.vars[
"monte_carlo_steps"]
440 if iterations == 0
or self.vars[
"number_of_frames"] == 0:
442 iterations *= self.vars[
"num_sample_rounds"]
444 pi = self.model.add_particle(
"sampling")
446 self.model, pi, method, self.vars[
"number_of_frames"],
448 p.set_number_of_replicas(
449 self.replica_exchange_object.get_number_of_replicas())
450 IMP.pmi.tools._add_pmi_provenance(self.root_hier)
453 def _setup_mc_sampler(self):
455 self.model, self.monte_carlo_sample_objects,
456 self.vars[
"monte_carlo_temperature"],
457 score_moved=self.score_moved,
458 start_frame=self._restart_from_frame)
460 sampler_mc.set_use_jax(self.vars[
"monte_carlo_steps"])
461 if self.vars[
"simulated_annealing"]:
462 tmin = self.vars[
"simulated_annealing_minimum_temperature"]
463 tmax = self.vars[
"simulated_annealing_maximum_temperature"]
465 "simulated_annealing_minimum_temperature_nframes"]
467 "simulated_annealing_maximum_temperature_nframes"]
468 sampler_mc.set_simulated_annealing(tmin, tmax, nfmin, nfmax)
469 if self.vars[
"self_adaptive"]:
470 sampler_mc.set_self_adaptive(
471 isselfadaptive=self.vars[
"self_adaptive"])
474 def _setup_md_sampler(self):
476 self.model, self.molecular_dynamics_sample_objects,
477 self.vars[
"monte_carlo_temperature"],
478 maximum_time_step=self.molecular_dynamics_max_time_step,
479 start_frame=self._restart_from_frame)
481 sampler_md.set_use_jax(self.vars[
"molecular_dynamics_steps"])
482 if self.vars[
"simulated_annealing"]:
483 tmin = self.vars[
"simulated_annealing_minimum_temperature"]
484 tmax = self.vars[
"simulated_annealing_maximum_temperature"]
486 "simulated_annealing_minimum_temperature_nframes"]
488 "simulated_annealing_maximum_temperature_nframes"]
489 sampler_md.set_simulated_annealing(tmin, tmax, nfmin, nfmax)
492 def _get_jax_free_space(self):
497 def _get_jax_data(self, sampler_mc):
499 return IMP.pmi.tools._JAXData(
500 model=sampler_mc.get_jax_model(),
501 space=self._jax_space)
503 def execute_macro(self):
505 restarted = self._restart.restarted
if self._restart
else False
507 stat_file = _StatFile(self.output_objects, self.rmf_output_objects)
508 temp_index_factor = 100000.0
512 if self.monte_carlo_sample_objects
is not None:
513 print(
"Setting up MonteCarlo")
514 sampler_mc = self._setup_mc_sampler()
515 stat_file.append(sampler_mc)
516 samplers.append(sampler_mc)
518 if self.molecular_dynamics_sample_objects
is not None:
519 print(
"Setting up MolecularDynamics")
520 sampler_md = self._setup_md_sampler()
521 stat_file.append(sampler_md)
522 samplers.append(sampler_md)
526 print(
"Setting up ReplicaExchange")
528 self.model, self.vars[
"replica_exchange_minimum_temperature"],
529 self.vars[
"replica_exchange_maximum_temperature"], samplers,
530 replica_exchange_object=self.replica_exchange_object)
531 self.replica_exchange_object = rex.rem
534 rex.stats = self._rex_stats
537 myindex = rex.get_my_index()
538 stat_file.append(rex)
542 min_temp_index = int(min(rex.get_temperatures()) * temp_index_factor)
546 globaldir = self.vars[
"global_output_directory"] +
"/"
547 rmf_dir = globaldir + self.vars[
"rmf_dir"]
548 pdb_dir = globaldir + self.vars[
"best_pdb_dir"]
550 if not self.test_mode
and not self.nest:
551 if self.vars[
"do_clean_first"]:
554 if self.vars[
"do_create_directories"]:
556 os.makedirs(globaldir, exist_ok=
True)
557 os.makedirs(rmf_dir, exist_ok=
True)
558 if not self.is_multi_state:
559 os.makedirs(pdb_dir, exist_ok=
True)
561 for n
in range(self.vars[
"number_of_states"]):
562 os.makedirs(pdb_dir +
"/" + str(n), exist_ok=
True)
571 print(
"Setting up stat file")
572 low_temp_stat_file = globaldir + \
573 self.vars[
"stat_file_name_suffix"] +
"." + \
574 str(myindex) +
".out"
577 if not self.test_mode:
580 if not self.test_mode
and not self.nest:
581 if stat_file.objects
is not None:
582 output.init_stat2(low_temp_stat_file,
584 extralabels=[
"rmf_file",
"rmf_frame_index"],
585 jax_data=self._get_jax_data(sampler_mc),
588 if restarted
and sampler_mc:
589 nline = output._count_stat2_nframe(
590 low_temp_stat_file,
'MonteCarlo_Nframe',
591 self._restart_from_frame)
592 if nline
is not None:
593 output._truncate_stat2_nline(low_temp_stat_file, nline)
595 print(
"Stat file writing is disabled")
597 if stat_file.rmf_objects
is not None and not self.nest:
598 print(
"Stat info being written in the rmf file")
600 if not self.test_mode
and not self.nest:
601 print(
"Setting up replica stat file")
602 replica_stat_file = globaldir + \
603 self.vars[
"replica_stat_file_suffix"] +
"." + \
604 str(myindex) +
".out"
605 if not self.test_mode:
606 output.init_stat2(replica_stat_file, [rex],
607 extralabels=[
"score"],
608 jax_data=self._get_jax_data(sampler_mc),
611 output._truncate_stat2_nline(
612 replica_stat_file, self._restart_from_frame)
614 print(
"Setting up best pdb files")
615 if not self.is_multi_state:
616 if self.vars[
"number_of_best_scoring_models"] > 0:
617 output.init_pdb_best_scoring(
618 pdb_dir +
"/" + self.vars[
"best_pdb_name_suffix"],
620 self.vars[
"number_of_best_scoring_models"],
621 replica_exchange=
True,
622 mmcif=self.vars[
'mmcif'],
623 best_score_file=globaldir +
"best.scores.rex.py")
624 pdbext =
".0.cif" if self.vars[
'mmcif']
else ".0.pdb"
626 pdb_dir +
"/" +
"model.psf",
628 self.vars[
"best_pdb_name_suffix"] + pdbext)
630 if self.vars[
"number_of_best_scoring_models"] > 0:
631 for n
in range(self.vars[
"number_of_states"]):
632 output.init_pdb_best_scoring(
633 pdb_dir +
"/" + str(n) +
"/" +
634 self.vars[
"best_pdb_name_suffix"],
636 self.vars[
"number_of_best_scoring_models"],
637 replica_exchange=
True,
638 mmcif=self.vars[
'mmcif'],
639 best_score_file=globaldir +
"best.scores.rex.py")
640 pdbext =
".0.cif" if self.vars[
'mmcif']
else ".0.pdb"
642 pdb_dir +
"/" + str(n) +
"/" +
"model.psf",
643 pdb_dir +
"/" + str(n) +
"/" +
644 self.vars[
"best_pdb_name_suffix"] + pdbext)
647 if self.em_object_for_rmf
is not None:
648 output_hierarchies = [
650 self.em_object_for_rmf.get_density_as_hierarchy(
653 output_hierarchies = [self.root_hier]
655 if not self.test_mode
and not self.nest
and not restarted:
656 print(
"Setting up and writing initial rmf coordinate file")
657 init_suffix = globaldir + self.vars[
"initial_rmf_name_suffix"]
658 output.init_rmf(init_suffix +
"." + str(myindex) +
".rmf3",
660 listofobjects=stat_file.rmf_objects)
661 if self._rmf_restraints:
662 output.add_restraints_to_rmf(
663 init_suffix +
"." + str(myindex) +
".rmf3",
664 self._rmf_restraints)
665 output.write_rmf(init_suffix +
"." + str(myindex) +
".rmf3")
666 output.close_rmf(init_suffix +
"." + str(myindex) +
".rmf3")
668 if not self.test_mode:
669 mpivs = IMP.pmi.samplers.MPI_values(self.replica_exchange_object)
671 mpivs = _MockMPIValues()
673 self._add_provenance(sampler_md, sampler_mc)
675 if not self.test_mode
and not self.nest:
676 print(
"Setting up production rmf files")
678 rmfname = f
"{rmf_dir}/{myindex}.rs{self._restart._number}.rmf3"
680 rmfname = rmf_dir +
"/" + str(myindex) +
".rmf3"
681 output.init_rmf(rmfname, output_hierarchies,
682 geometries=self.vars[
"geometries"],
683 listofobjects=stat_file.rmf_objects)
685 if self._rmf_restraints:
686 output.add_restraints_to_rmf(rmfname, self._rmf_restraints)
688 if not self.test_mode
and self.nest:
689 print(
"Setting up NestOR rmf files")
690 nestor_rmf_fname = str(self.nestor_rmf_fname) +
'_' + \
691 str(self.replica_exchange_object.get_my_index()) +
'.rmf3'
693 output.init_rmf(nestor_rmf_fname, output_hierarchies,
694 geometries=self.vars[
"geometries"],
695 listofobjects=stat_file.rmf_objects)
697 ntimes_at_low_temp = 0
699 if myindex == 0
and not self.nest:
701 self.replica_exchange_object.set_was_used(
True)
702 nframes = self.vars[
"number_of_frames"]
706 sampled_likelihoods = []
707 for i
in range(self._restart_from_frame, nframes):
708 if self._restart
and i != self._restart_from_frame:
709 self._restart._write_frame(self, i, myindex, rex.stats)
714 for nr
in range(self.vars[
"num_sample_rounds"]):
715 if sampler_md
is not None:
716 score = sampler_md.optimize(
717 self.vars[
"molecular_dynamics_steps"])
718 if sampler_mc
is not None:
719 score = sampler_mc.optimize(
720 self.vars[
"monte_carlo_steps"])
723 self.model).evaluate(
False)
725 and not self.use_jax):
729 self.model).evaluate(
False)
730 assert abs(score - check_score) < 1e-4
731 mpivs.set_value(
"score", score)
733 output.set_output_entry(
"score", score)
735 self._total_score_obj.score = score
737 my_temp_index = int(rex.get_my_temp() * temp_index_factor)
739 if self.vars[
"save_coordinates_mode"] ==
"lowest_temperature":
740 save_frame = (min_temp_index == my_temp_index)
741 elif self.vars[
"save_coordinates_mode"] ==
"25th_score":
742 score_perc = mpivs.get_percentile(
"score")
743 save_frame = (score_perc*100.0 <= 25.0)
744 elif self.vars[
"save_coordinates_mode"] ==
"50th_score":
745 score_perc = mpivs.get_percentile(
"score")
746 save_frame = (score_perc*100.0 <= 50.0)
747 elif self.vars[
"save_coordinates_mode"] ==
"75th_score":
748 score_perc = mpivs.get_percentile(
"score")
749 save_frame = (score_perc*100.0 <= 75.0)
752 if save_frame
and not self.test_mode:
756 print(
"--- frame %s score %s " % (str(i), str(score)))
759 if math.isnan(score):
760 sampled_likelihoods.append(math.nan)
762 likelihood_for_sample = 1
763 for rstrnt
in self.nestor_restraints:
764 likelihood_for_sample *= rstrnt.get_likelihood()
765 sampled_likelihoods.append(likelihood_for_sample)
766 output.write_rmf(nestor_rmf_fname)
768 if not self.test_mode
and not self.nest:
769 if i % self.vars[
"nframes_write_coordinates"] == 0:
770 print(
'--- writing coordinates')
771 if self.vars[
"number_of_best_scoring_models"] > 0:
772 output.write_pdb_best_scoring(score)
773 output.write_rmf(rmfname)
774 output.set_output_entry(
"rmf_file", rmfname)
775 output.set_output_entry(
"rmf_frame_index",
778 output.set_output_entry(
"rmf_file", rmfname)
779 output.set_output_entry(
"rmf_frame_index",
'-1')
780 if stat_file.objects
is not None:
783 jax_data=self._get_jax_data(sampler_mc))
784 ntimes_at_low_temp += 1
786 if not self.test_mode
and not self.nest:
789 jax_data=self._get_jax_data(sampler_mc))
790 if self.vars[
"replica_exchange_swap"]:
791 rex.swap_temp(i, score)
793 if self.nest
and len(sampled_likelihoods) > 0:
794 with open(
"likelihoods_"
795 + str(self.replica_exchange_object.get_my_index()),
797 pickle.dump(sampled_likelihoods, lif)
799 output.close_rmf(nestor_rmf_fname)
801 for p, state
in IMP.pmi.tools._all_protocol_outputs(self.root_hier):
802 p.add_replica_exchange(state, self)
804 if not self.test_mode
and not self.nest:
805 print(
"closing production rmf files")
806 output.close_rmf(rmfname)
810 """Continue a failed ReplicaExchange sampling run.
812 @see ReplicaExchange.set_restart
814 @param restart_dir The directory containing the restart file(s).
815 @param prev If True, use the previous restart
816 (e.g. `restart.0.prev.pck`) rather than the most recent
817 restart (e.g. `restart.0.pck`)
824 nproc, myindex = r.get_number_of_replicas(), r.get_my_index()
827 nproc, myindex = 1, 0
829 ext =
'prev.pck' if prev
else 'pck'
830 with open(f
'{restart_dir}/restart.{myindex}.{ext}',
'rb')
as fh:
832 old_nproc = mc.get_number_of_replicas()
833 if old_nproc != nproc:
835 f
"Mismatch trying to read restart files: the original run used "
836 f
"{old_nproc} replicas and this run has {nproc}")
837 return mc.execute_macro()
841 """A macro to build a IMP::pmi::topology::System based on a
842 TopologyReader object.
844 Easily create multi-state systems by calling this macro
845 repeatedly with different TopologyReader objects!
846 A useful function is get_molecules() which returns the PMI Molecules
847 grouped by state as a dictionary with key = (molecule name),
848 value = IMP.pmi.topology.Molecule
849 Quick multi-state system:
852 reader1 = IMP.pmi.topology.TopologyReader(tfile1)
853 reader2 = IMP.pmi.topology.TopologyReader(tfile2)
854 bs = IMP.pmi.macros.BuildSystem(model)
855 bs.add_state(reader1)
856 bs.add_state(reader2)
857 bs.execute_macro() # build everything including degrees of freedom
858 IMP.atom.show_molecular_hierarchy(bs.get_hierarchy())
859 ### now you have a two state system, you add restraints etc
861 @note The "domain name" entry of the topology reader is not used.
862 All molecules are set up by the component name, but split into rigid bodies
866 _alphabets = {
'DNA': IMP.pmi.alphabets.dna,
867 'RNA': IMP.pmi.alphabets.rna}
869 def __init__(self, model, sequence_connectivity_scale=4.0,
870 force_create_gmm_files=
False, resolutions=[1, 10],
873 @param model An IMP Model
874 @param sequence_connectivity_scale For scaling the connectivity
876 @param force_create_gmm_files If True, will sample and create GMMs
877 no matter what. If False, will only sample if the
878 files don't exist. If number of Gaussians is zero, won't
880 @param resolutions The resolutions to build for structured regions
881 @param name The name of the top-level hierarchy node.
888 self._domain_res = []
890 self.force_create_gmm_files = force_create_gmm_files
891 self.resolutions = resolutions
893 def add_state(self, reader, keep_chain_id=False, fasta_name_map=None,
895 """Add a state using the topology info in a
896 IMP::pmi::topology::TopologyReader object.
897 When you are done adding states, call execute_macro()
898 @param reader The TopologyReader object
899 @param keep_chain_id If True, keep the chain IDs from the
900 original PDB files, if available
901 @param fasta_name_map dictionary for converting protein names
902 found in the fasta file
903 @param chain_ids A list or string of chain IDs for assigning to
904 newly-created molecules, e.g.
905 `string.ascii_uppercase+string.ascii_lowercase+string.digits`.
906 If not specified, chain IDs A through Z are assigned, then
907 AA through AZ, then BA through BZ, and so on, in the same
910 state = self.system.create_state()
911 self._readers.append(reader)
913 these_domain_res = {}
915 if chain_ids
is None:
916 chain_ids = IMP.pmi.output._ChainIDs()
921 for molname
in reader.get_molecules():
922 copies = reader.get_molecules()[molname].domains
923 for nc, copyname
in enumerate(copies):
924 print(
"BuildSystem.add_state: setting up molecule %s copy "
925 "number %s" % (molname, str(nc)))
926 copy = copies[copyname]
929 all_chains = [c
for c
in copy
if c.chain
is not None]
931 chain_id = all_chains[0].chain
933 chain_id = chain_ids[numchain]
935 "No PDBs specified for %s, so keep_chain_id has "
936 "no effect; using default chain ID '%s'"
939 chain_id = chain_ids[numchain]
941 alphabet = IMP.pmi.alphabets.amino_acid
942 fasta_flag = copy[0].fasta_flag
943 if fasta_flag
in self._alphabets:
944 alphabet = self._alphabets[fasta_flag]
946 copy[0].fasta_file, fasta_name_map)
947 seq = seqs[copy[0].fasta_id]
948 print(
"BuildSystem.add_state: molecule %s sequence has "
949 "%s residues" % (molname, len(seq)))
950 orig_mol = state.create_molecule(
951 molname, seq, chain_id, alphabet=alphabet,
952 uniprot=seqs.uniprot.get(copy[0].fasta_id))
956 print(
"BuildSystem.add_state: creating a copy for "
957 "molecule %s" % molname)
958 mol = orig_mol.create_copy(chain_id)
961 for domainnumber, domain
in enumerate(copy):
962 print(
"BuildSystem.add_state: ---- setting up domain %s "
963 "of molecule %s" % (domainnumber, molname))
966 these_domains[domain.get_unique_name()] = domain
967 if domain.residue_range == []
or \
968 domain.residue_range
is None:
969 domain_res = mol.get_residues()
971 start = domain.residue_range[0]+domain.pdb_offset
972 if domain.residue_range[1] ==
'END':
973 end = len(mol.sequence)
975 end = domain.residue_range[1]+domain.pdb_offset
976 domain_res = mol.residue_range(start-1, end-1)
977 print(
"BuildSystem.add_state: -------- domain %s of "
978 "molecule %s extends from residue %s to "
980 % (domainnumber, molname, start, end))
981 if domain.pdb_file ==
"BEADS":
982 print(
"BuildSystem.add_state: -------- domain %s of "
983 "molecule %s represented by BEADS "
984 % (domainnumber, molname))
985 mol.add_representation(
987 resolutions=[domain.bead_size],
988 setup_particles_as_densities=(
989 domain.em_residues_per_gaussian != 0),
991 these_domain_res[domain.get_unique_name()] = \
993 elif domain.pdb_file ==
"IDEAL_HELIX":
994 print(
"BuildSystem.add_state: -------- domain %s of "
995 "molecule %s represented by IDEAL_HELIX "
996 % (domainnumber, molname))
997 emper = domain.em_residues_per_gaussian
998 mol.add_representation(
1000 resolutions=self.resolutions,
1002 density_residues_per_component=emper,
1003 density_prefix=domain.density_prefix,
1004 density_force_compute=self.force_create_gmm_files,
1006 these_domain_res[domain.get_unique_name()] = \
1009 print(
"BuildSystem.add_state: -------- domain %s of "
1010 "molecule %s represented by pdb file %s "
1011 % (domainnumber, molname, domain.pdb_file))
1012 domain_atomic = mol.add_structure(domain.pdb_file,
1014 domain.residue_range,
1017 domain_non_atomic = domain_res - domain_atomic
1018 if not domain.em_residues_per_gaussian:
1019 mol.add_representation(
1020 domain_atomic, resolutions=self.resolutions,
1022 if len(domain_non_atomic) > 0:
1023 mol.add_representation(
1025 resolutions=[domain.bead_size],
1028 print(
"BuildSystem.add_state: -------- domain %s "
1029 "of molecule %s represented by gaussians "
1030 % (domainnumber, molname))
1031 emper = domain.em_residues_per_gaussian
1032 creategmm = self.force_create_gmm_files
1033 mol.add_representation(
1035 resolutions=self.resolutions,
1036 density_residues_per_component=emper,
1037 density_prefix=domain.density_prefix,
1038 density_force_compute=creategmm,
1040 if len(domain_non_atomic) > 0:
1041 mol.add_representation(
1043 resolutions=[domain.bead_size],
1044 setup_particles_as_densities=
True,
1046 these_domain_res[domain.get_unique_name()] = (
1047 domain_atomic, domain_non_atomic)
1048 self._domain_res.append(these_domain_res)
1049 self._domains.append(these_domains)
1050 print(
'BuildSystem.add_state: State', len(self.system.states),
'added')
1054 """Return list of all molecules grouped by state.
1055 For each state, it's a dictionary of Molecules where key is the
1058 return [s.get_molecules()
for s
in self.system.get_states()]
1060 def get_molecule(self, molname, copy_index=0, state_index=0):
1061 return self.system.get_states()[state_index].
get_molecules()[
1062 molname][copy_index]
1065 max_bead_trans=4.0, max_srb_trans=4.0, max_srb_rot=0.04):
1066 """Builds representations and sets up degrees of freedom"""
1067 print(
"BuildSystem.execute_macro: building representations")
1068 self.root_hier = self.system.build()
1070 print(
"BuildSystem.execute_macro: setting up degrees of freedom")
1072 for nstate, reader
in enumerate(self._readers):
1073 rbs = reader.get_rigid_bodies()
1074 srbs = reader.get_super_rigid_bodies()
1075 csrbs = reader.get_chains_of_super_rigid_bodies()
1078 domains_in_rbs = set()
1080 print(
"BuildSystem.execute_macro: -------- building rigid "
1081 "body %s" % (str(rblist)))
1082 all_res = IMP.pmi.tools.OrderedSet()
1083 bead_res = IMP.pmi.tools.OrderedSet()
1084 for dname
in rblist:
1085 domain = self._domains[nstate][dname]
1086 print(
"BuildSystem.execute_macro: -------- adding %s"
1088 all_res |= self._domain_res[nstate][dname][0]
1089 bead_res |= self._domain_res[nstate][dname][1]
1090 domains_in_rbs.add(dname)
1092 print(
"BuildSystem.execute_macro: -------- creating rigid "
1093 "body with max_trans %s max_rot %s "
1094 "non_rigid_max_trans %s"
1095 % (str(max_rb_trans), str(max_rb_rot),
1096 str(max_bead_trans)))
1097 self.dof.create_rigid_body(all_res,
1098 nonrigid_parts=bead_res,
1099 max_trans=max_rb_trans,
1101 nonrigid_max_trans=max_bead_trans,
1102 name=
"RigidBody %s" % dname)
1105 for dname, domain
in self._domains[nstate].items():
1106 if dname
not in domains_in_rbs:
1107 if domain.pdb_file !=
"BEADS":
1109 "No rigid bodies set for %s. Residues read from "
1110 "the PDB file will not be sampled - only regions "
1111 "missing from the PDB will be treated flexibly. "
1112 "To sample the entire sequence, use BEADS instead "
1113 "of a PDB file name" % dname,
1115 self.dof.create_flexible_beads(
1116 self._domain_res[nstate][dname][1],
1117 max_trans=max_bead_trans)
1120 for srblist
in srbs:
1121 print(
"BuildSystem.execute_macro: -------- building "
1122 "super rigid body %s" % (str(srblist)))
1123 all_res = IMP.pmi.tools.OrderedSet()
1124 for dname
in srblist:
1125 print(
"BuildSystem.execute_macro: -------- adding %s"
1127 all_res |= self._domain_res[nstate][dname][0]
1128 all_res |= self._domain_res[nstate][dname][1]
1130 print(
"BuildSystem.execute_macro: -------- creating super "
1131 "rigid body with max_trans %s max_rot %s "
1132 % (str(max_srb_trans), str(max_srb_rot)))
1133 self.dof.create_super_rigid_body(
1134 all_res, max_trans=max_srb_trans, max_rot=max_srb_rot)
1137 for csrblist
in csrbs:
1138 all_res = IMP.pmi.tools.OrderedSet()
1139 for dname
in csrblist:
1140 all_res |= self._domain_res[nstate][dname][0]
1141 all_res |= self._domain_res[nstate][dname][1]
1142 all_res = list(all_res)
1143 all_res.sort(key=
lambda r: r.get_index())
1144 self.dof.create_main_chain_mover(all_res)
1145 return self.root_hier, self.dof
1150 """A macro for running all the basic operations of analysis.
1151 Includes clustering, precision analysis, and making ensemble density maps.
1152 A number of plots are also supported.
1155 merge_directories=[
"./"],
1156 stat_file_name_suffix=
"stat",
1157 best_pdb_name_suffix=
"model",
1158 do_clean_first=
True,
1159 do_create_directories=
True,
1160 global_output_directory=
"output/",
1161 replica_stat_file_suffix=
"stat_replica",
1162 global_analysis_result_directory=
"./analysis/",
1165 @param model The IMP model
1166 @param stat_file_name_suffix
1167 @param merge_directories The directories containing output files
1168 @param best_pdb_name_suffix
1169 @param do_clean_first
1170 @param do_create_directories
1171 @param global_output_directory Where everything is
1172 @param replica_stat_file_suffix
1173 @param global_analysis_result_directory
1174 @param test_mode If True, nothing is changed on disk
1178 from mpi4py
import MPI
1179 self.comm = MPI.COMM_WORLD
1180 self.rank = self.comm.Get_rank()
1181 self.number_of_processes = self.comm.size
1184 self.number_of_processes = 1
1186 self.test_mode = test_mode
1187 self._protocol_output = []
1188 self.cluster_obj =
None
1190 stat_dir = global_output_directory
1191 self.stat_files = []
1193 for rd
in merge_directories:
1194 stat_files = glob.glob(os.path.join(rd, stat_dir,
"stat.*.out"))
1195 if len(stat_files) == 0:
1196 warnings.warn(
"no stat files found in %s"
1197 % os.path.join(rd, stat_dir),
1199 self.stat_files += stat_files
1202 """Capture details of the modeling protocol.
1203 @param p an instance of IMP.pmi.output.ProtocolOutput or a subclass.
1206 self._protocol_output.append((p, p._last_state))
1209 score_key=
"Total_Score",
1210 rmf_file_key=
"rmf_file",
1211 rmf_file_frame_key=
"rmf_frame_index",
1214 nframes_trajectory=10000):
1215 """ Get a trajectory of the modeling run, for generating
1216 demonstrative movies
1218 @param score_key The score for ranking models
1219 @param rmf_file_key Key pointing to RMF filename
1220 @param rmf_file_frame_key Key pointing to RMF frame number
1221 @param outputdir The local output directory used in the run
1222 @param get_every Extract every nth frame
1223 @param nframes_trajectory Total number of frames of the trajectory
1228 self.stat_files, score_key, rmf_file_key, rmf_file_frame_key,
1230 score_list = list(map(float, trajectory_models[2]))
1232 max_score = max(score_list)
1233 min_score = min(score_list)
1235 bins = [(max_score-min_score)*math.exp(-float(i))+min_score
1236 for i
in range(nframes_trajectory)]
1237 binned_scores = [
None]*nframes_trajectory
1238 binned_model_indexes = [-1]*nframes_trajectory
1240 for model_index, s
in enumerate(score_list):
1241 bins_score_diffs = [abs(s-b)
for b
in bins]
1242 bin_index = min(enumerate(bins_score_diffs), key=itemgetter(1))[0]
1243 if binned_scores[bin_index]
is None:
1244 binned_scores[bin_index] = s
1245 binned_model_indexes[bin_index] = model_index
1247 old_diff = abs(binned_scores[bin_index]-bins[bin_index])
1248 new_diff = abs(s-bins[bin_index])
1249 if new_diff < old_diff:
1250 binned_scores[bin_index] = s
1251 binned_model_indexes[bin_index] = model_index
1253 print(binned_scores)
1254 print(binned_model_indexes)
1256 def _expand_ambiguity(self, prot, d):
1257 """If using PMI2, expand the dictionary to include copies as
1260 This also keeps the states separate.
1265 if '..' in key
or (isinstance(val, tuple)
and len(val) >= 3):
1268 states = IMP.atom.get_by_type(prot, IMP.atom.STATE_TYPE)
1269 if isinstance(val, tuple):
1277 for nst
in range(len(states)):
1279 copies = sel.get_selected_particles(with_representation=
False)
1281 for nc
in range(len(copies)):
1283 newdict[
'%s.%i..%i' % (name, nst, nc)] = \
1284 (start, stop, name, nc, nst)
1286 newdict[
'%s..%i' % (name, nc)] = \
1287 (start, stop, name, nc, nst)
1293 score_key=
"Total_Score",
1294 rmf_file_key=
"rmf_file",
1295 rmf_file_frame_key=
"rmf_frame_index",
1297 prefiltervalue=
None,
1300 alignment_components=
None,
1301 number_of_best_scoring_models=10,
1302 rmsd_calculation_components=
None,
1303 distance_matrix_file=
'distances.mat',
1304 load_distance_matrix_file=
False,
1305 skip_clustering=
False,
1306 number_of_clusters=1,
1308 exit_after_display=
True,
1310 first_and_last_frames=
None,
1311 density_custom_ranges=
None,
1312 write_pdb_with_centered_coordinates=
False,
1314 """Get the best scoring models, compute a distance matrix,
1315 cluster them, and create density maps.
1317 Tuple format: "molname" just the molecule,
1318 or (start,stop,molname,copy_num(optional),state_num(optional)
1319 Can pass None for copy or state to ignore that field.
1320 If you don't pass a specific copy number
1322 @param score_key The score for ranking models.
1323 @param rmf_file_key Key pointing to RMF filename
1324 @param rmf_file_frame_key Key pointing to RMF frame number
1325 @param state_number State number to analyze
1326 @param prefiltervalue Only include frames where the
1327 score key is below this value
1328 @param feature_keys Keywords for which you want to
1329 calculate average, medians, etc.
1330 If you pass "Keyname" it'll include everything that matches
1332 @param outputdir The local output directory used in
1334 @param alignment_components Dictionary with keys=groupname,
1335 values are tuples for aligning the structures
1336 e.g. {"Rpb1": (20,100,"Rpb1"),"Rpb2":"Rpb2"}
1337 @param number_of_best_scoring_models Num models to keep per run
1338 @param rmsd_calculation_components For calculating RMSD
1339 (same format as alignment_components)
1340 @param distance_matrix_file Where to store/read the
1342 @param load_distance_matrix_file Try to load the distance
1344 @param skip_clustering Just extract the best scoring
1345 models and save the pdbs
1346 @param number_of_clusters Number of k-means clusters
1347 @param display_plot Display the distance matrix
1348 @param exit_after_display Exit after displaying distance
1350 @param get_every Extract every nth frame
1351 @param first_and_last_frames A tuple with the first and last
1352 frames to be analyzed. Values are percentages!
1353 Default: get all frames
1354 @param density_custom_ranges For density calculation
1355 (same format as alignment_components)
1356 @param write_pdb_with_centered_coordinates
1357 @param voxel_size Used for the density output
1361 self._outputdir = Path(outputdir).absolute()
1362 self._number_of_clusters = number_of_clusters
1363 for p, state
in self._protocol_output:
1364 p.add_replica_exchange_analysis(state, self, density_custom_ranges)
1375 if not load_distance_matrix_file:
1376 if len(self.stat_files) == 0:
1377 print(
"ERROR: no stat file found in the given path")
1379 my_stat_files = IMP.pmi.tools.chunk_list_into_segments(
1380 self.stat_files, self.number_of_processes)[self.rank]
1383 for k
in (score_key, rmf_file_key, rmf_file_frame_key):
1384 if k
in feature_keys:
1386 "no need to pass " + k +
" to feature_keys.",
1388 feature_keys.remove(k)
1391 my_stat_files, score_key, feature_keys, rmf_file_key,
1392 rmf_file_frame_key, prefiltervalue, get_every, provenance=prov)
1393 rmf_file_list = best_models[0]
1394 rmf_file_frame_list = best_models[1]
1395 score_list = best_models[2]
1396 feature_keyword_list_dict = best_models[3]
1402 if self.number_of_processes > 1:
1406 rmf_file_frame_list)
1407 for k
in feature_keyword_list_dict:
1408 feature_keyword_list_dict[k] = \
1410 feature_keyword_list_dict[k])
1413 score_rmf_tuples = list(zip(score_list,
1415 rmf_file_frame_list,
1416 list(range(len(score_list)))))
1418 if density_custom_ranges:
1419 for k
in density_custom_ranges:
1420 if not isinstance(density_custom_ranges[k], list):
1421 raise Exception(
"Density custom ranges: values must "
1422 "be lists of tuples")
1425 if first_and_last_frames
is not None:
1426 nframes = len(score_rmf_tuples)
1427 first_frame = int(first_and_last_frames[0] * nframes)
1428 last_frame = int(first_and_last_frames[1] * nframes)
1429 if last_frame > len(score_rmf_tuples):
1431 score_rmf_tuples = score_rmf_tuples[first_frame:last_frame]
1434 best_score_rmf_tuples = sorted(
1436 key=
lambda x: float(x[0]))[:number_of_best_scoring_models]
1437 best_score_rmf_tuples = [t+(n,)
for n, t
in
1438 enumerate(best_score_rmf_tuples)]
1440 prov.append(IMP.pmi.io.FilterProvenance(
1441 "Best scoring", 0, number_of_best_scoring_models))
1443 best_score_feature_keyword_list_dict = defaultdict(list)
1444 for tpl
in best_score_rmf_tuples:
1446 for f
in feature_keyword_list_dict:
1447 best_score_feature_keyword_list_dict[f].append(
1448 feature_keyword_list_dict[f][index])
1449 my_best_score_rmf_tuples = IMP.pmi.tools.chunk_list_into_segments(
1450 best_score_rmf_tuples,
1451 self.number_of_processes)[self.rank]
1454 prot_ahead = IMP.pmi.analysis.get_hiers_from_rmf(
1455 self.model, 0, my_best_score_rmf_tuples[0][1])[0]
1456 if rmsd_calculation_components
is not None:
1457 tmp = self._expand_ambiguity(
1458 prot_ahead, rmsd_calculation_components)
1459 if tmp != rmsd_calculation_components:
1460 print(
'Detected ambiguity, expand rmsd components to',
1462 rmsd_calculation_components = tmp
1463 if alignment_components
is not None:
1464 tmp = self._expand_ambiguity(prot_ahead,
1465 alignment_components)
1466 if tmp != alignment_components:
1467 print(
'Detected ambiguity, expand alignment '
1468 'components to', tmp)
1469 alignment_components = tmp
1475 self.model, my_best_score_rmf_tuples[0],
1476 rmsd_calculation_components, state_number=state_number)
1478 self.model, my_best_score_rmf_tuples, alignment_components,
1479 rmsd_calculation_components, state_number=state_number)
1487 all_coordinates = got_coords[0]
1490 alignment_coordinates = got_coords[1]
1493 rmsd_coordinates = got_coords[2]
1496 rmf_file_name_index_dict = got_coords[3]
1499 all_rmf_file_names = got_coords[4]
1505 if density_custom_ranges:
1507 density_custom_ranges, voxel=voxel_size)
1509 dircluster = os.path.join(outputdir,
1510 "all_models."+str(self.rank))
1516 os.mkdir(dircluster)
1519 clusstat = open(os.path.join(
1520 dircluster,
"stat."+str(self.rank)+
".out"),
"w")
1521 for cnt, tpl
in enumerate(my_best_score_rmf_tuples):
1523 rmf_frame_number = tpl[2]
1526 for key
in best_score_feature_keyword_list_dict:
1528 best_score_feature_keyword_list_dict[key][index]
1532 IMP.pmi.analysis.get_hiers_and_restraints_from_rmf(
1533 self.model, rmf_frame_number, rmf_name)
1535 linking_successful = \
1536 IMP.pmi.analysis.link_hiers_and_restraints_to_rmf(
1537 self.model, prots, rs, rmf_frame_number,
1539 if not linking_successful:
1545 states = IMP.atom.get_by_type(
1546 prots[0], IMP.atom.STATE_TYPE)
1547 prot = states[state_number]
1552 coords_f1 = alignment_coordinates[cnt]
1554 coords_f2 = alignment_coordinates[cnt]
1557 coords_f1, coords_f2)
1558 transformation = Ali.align()[1]
1572 rb = rbm.get_rigid_body()
1582 out_pdb_fn = os.path.join(
1583 dircluster, str(cnt)+
"."+str(self.rank)+
".pdb")
1584 out_rmf_fn = os.path.join(
1585 dircluster, str(cnt)+
"."+str(self.rank)+
".rmf3")
1586 o.init_pdb(out_pdb_fn, prot)
1587 tc = write_pdb_with_centered_coordinates
1588 o.write_pdb(out_pdb_fn,
1589 translate_to_geometric_center=tc)
1591 tmp_dict[
"local_pdb_file_name"] = \
1592 os.path.basename(out_pdb_fn)
1593 tmp_dict[
"rmf_file_full_path"] = rmf_name
1594 tmp_dict[
"local_rmf_file_name"] = \
1595 os.path.basename(out_rmf_fn)
1596 tmp_dict[
"local_rmf_frame_number"] = 0
1598 clusstat.write(str(tmp_dict)+
"\n")
1603 h.set_name(
"System")
1605 o.init_rmf(out_rmf_fn, [h], rs)
1607 o.write_rmf(out_rmf_fn)
1608 o.close_rmf(out_rmf_fn)
1610 if density_custom_ranges:
1611 DensModule.add_subunits_density(prot)
1613 if density_custom_ranges:
1614 DensModule.write_mrc(path=dircluster)
1619 if self.number_of_processes > 1:
1625 rmf_file_name_index_dict)
1627 alignment_coordinates)
1634 [best_score_feature_keyword_list_dict,
1635 rmf_file_name_index_dict],
1641 print(
"setup clustering class")
1644 for n, model_coordinate_dict
in enumerate(all_coordinates):
1646 if (alignment_components
is not None
1647 and len(self.cluster_obj.all_coords) == 0):
1649 self.cluster_obj.set_template(alignment_coordinates[n])
1650 self.cluster_obj.fill(all_rmf_file_names[n],
1651 rmsd_coordinates[n])
1652 print(
"Global calculating the distance matrix")
1655 self.cluster_obj.dist_matrix()
1659 self.cluster_obj.do_cluster(number_of_clusters)
1662 self.cluster_obj.plot_matrix(
1663 figurename=os.path.join(outputdir,
1665 if exit_after_display:
1667 self.cluster_obj.save_distance_matrix_file(
1668 file_name=distance_matrix_file)
1675 print(
"setup clustering class")
1677 self.cluster_obj.load_distance_matrix_file(
1678 file_name=distance_matrix_file)
1679 print(
"clustering with %s clusters" % str(number_of_clusters))
1680 self.cluster_obj.do_cluster(number_of_clusters)
1681 [best_score_feature_keyword_list_dict,
1682 rmf_file_name_index_dict] = self.load_objects(
".macro.pkl")
1685 self.cluster_obj.plot_matrix(figurename=os.path.join(
1686 outputdir,
'dist_matrix.pdf'))
1687 if exit_after_display:
1689 if self.number_of_processes > 1:
1697 print(self.cluster_obj.get_cluster_labels())
1698 for n, cl
in enumerate(self.cluster_obj.get_cluster_labels()):
1699 print(
"rank %s " % str(self.rank))
1700 print(
"cluster %s " % str(n))
1701 print(
"cluster label %s " % str(cl))
1702 print(self.cluster_obj.get_cluster_label_names(cl))
1704 len(self.cluster_obj.get_cluster_label_names(cl))
1706 prov + [IMP.pmi.io.ClusterProvenance(cluster_size)]
1709 if density_custom_ranges:
1711 density_custom_ranges,
1714 dircluster = outputdir +
"/cluster." + str(n) +
"/"
1716 os.mkdir(dircluster)
1722 str(self.cluster_obj.get_cluster_label_average_rmsd(cl))}
1723 clusstat = open(dircluster +
"stat.out",
"w")
1724 for k, structure_name
in enumerate(
1725 self.cluster_obj.get_cluster_label_names(cl)):
1728 tmp_dict.update(rmsd_dict)
1729 index = rmf_file_name_index_dict[structure_name]
1730 for key
in best_score_feature_keyword_list_dict:
1732 key] = best_score_feature_keyword_list_dict[
1738 rmf_name = structure_name.split(
"|")[0]
1739 rmf_frame_number = int(structure_name.split(
"|")[1])
1740 clusstat.write(str(tmp_dict) +
"\n")
1745 IMP.pmi.analysis.get_hiers_and_restraints_from_rmf(
1746 self.model, rmf_frame_number, rmf_name)
1748 linking_successful = \
1749 IMP.pmi.analysis.link_hiers_and_restraints_to_rmf(
1750 self.model, prots, rs, rmf_frame_number,
1752 if not linking_successful:
1757 states = IMP.atom.get_by_type(
1758 prots[0], IMP.atom.STATE_TYPE)
1759 prot = states[state_number]
1765 co = self.cluster_obj
1766 model_index = co.get_model_index_from_name(
1768 transformation = co.get_transformation_to_first_member(
1779 rb = rbm.get_rigid_body()
1788 if density_custom_ranges:
1789 DensModule.add_subunits_density(prot)
1794 o.init_pdb(dircluster + str(k) +
".pdb", prot)
1795 o.write_pdb(dircluster + str(k) +
".pdb")
1800 h.set_name(
"System")
1802 o.init_rmf(dircluster + str(k) +
".rmf3", [h], rs)
1803 o.write_rmf(dircluster + str(k) +
".rmf3")
1804 o.close_rmf(dircluster + str(k) +
".rmf3")
1809 if density_custom_ranges:
1810 DensModule.write_mrc(path=dircluster)
1813 if self.number_of_processes > 1:
1816 def get_cluster_rmsd(self, cluster_num):
1817 if self.cluster_obj
is None:
1819 return self.cluster_obj.get_cluster_label_average_rmsd(cluster_num)
1821 def save_objects(self, objects, file_name):
1823 with open(file_name,
'wb')
as outf:
1824 pickle.dump(objects, outf)
1826 def load_objects(self, file_name):
1828 with open(file_name,
'rb')
as inputf:
1829 objects = pickle.load(inputf)
1836 This class contains analysis utilities to investigate ReplicaExchange
1844 def __init__(self, model, stat_files, best_models=None, score_key=None,
1847 Construction of the Class.
1848 @param model IMP.Model()
1849 @param stat_files list of string. Can be ascii stat files,
1851 @param best_models Integer. Number of best scoring models,
1852 if None: all models will be read
1853 @param score_key Use the provided stat key keyword as the score
1854 (by default, the total score is used)
1855 @param alignment boolean (Default=True). Align before computing
1860 self.best_models = best_models
1862 model, stat_files, self.best_models, score_key, cache=
True)
1864 StatHierarchyHandler=self.stath0)
1877 self.clusters.append(c)
1878 for n0
in range(len(self.stath0)):
1880 self.pairwise_rmsd = {}
1881 self.pairwise_molecular_assignment = {}
1882 self.alignment = alignment
1883 self.symmetric_molecules = {}
1884 self.issymmetricsel = {}
1886 self.molcopydict0 = IMP.pmi.tools.get_molecules_dictionary_by_copy(
1888 self.molcopydict1 = IMP.pmi.tools.get_molecules_dictionary_by_copy(
1893 Setup the selection onto which the rmsd is computed
1894 @param kwargs use IMP.atom.Selection keywords
1902 Store names of symmetric molecules
1904 self.symmetric_molecules[molecule_name] = 0
1909 Setup the selection onto which the alignment is computed
1910 @param kwargs use IMP.atom.Selection keywords
1918 def clean_clusters(self):
1919 for c
in self.clusters:
1923 def cluster(self, rmsd_cutoff=10, metric=IMP.atom.get_rmsd):
1925 Cluster the models based on RMSD.
1926 @param rmsd_cutoff Float the distance cutoff in Angstrom
1927 @param metric (Default=IMP.atom.get_rmsd) the metric that will
1928 be used to compute rmsds
1930 self.clean_clusters()
1931 not_clustered = set(range(len(self.stath1)))
1932 while len(not_clustered) > 0:
1933 self.
aggregate(not_clustered, rmsd_cutoff, metric)
1938 Refine the clusters by merging the ones whose centers are close
1939 @param rmsd_cutoff cutoff distance in Angstorms
1941 clusters_copy = self.clusters
1942 for c0, c1
in itertools.combinations(self.clusters, 2):
1943 if c0.center_index
is None:
1945 if c1.center_index
is None:
1947 _ = self.stath0[c0.center_index]
1948 _ = self.stath1[c1.center_index]
1949 rmsd, molecular_assignment = self.
rmsd()
1950 if rmsd <= rmsd_cutoff:
1951 if c1
in self.clusters:
1952 clusters_copy.remove(c1)
1954 self.clusters = clusters_copy
1961 def set_cluster_assignments(self, cluster_ids):
1962 if len(cluster_ids) != len(self.stath0):
1963 raise ValueError(
'cluster ids has to be same length as '
1967 for i
in sorted(list(set(cluster_ids))):
1969 for i, (idx, d)
in enumerate(zip(cluster_ids, self.stath0)):
1970 self.clusters[idx].add_member(i, d)
1974 Return the model data from a cluster
1975 @param cluster IMP.pmi.output.Cluster object
1984 Save the data for the whole models into a pickle file
1985 @param filename string
1987 self.stath0.save_data(filename)
1991 Set the data from an external IMP.pmi.output.Data
1992 @param data IMP.pmi.output.Data
1994 self.stath0.data = data
1995 self.stath1.data = data
1999 Load the data from an external pickled file
2000 @param filename string
2002 self.stath0.load_data(filename)
2003 self.stath1.load_data(filename)
2004 self.best_models = len(self.stath0)
2006 def add_cluster(self, rmf_name_list):
2008 print(
"creating cluster index "+str(len(self.clusters)))
2009 self.clusters.append(c)
2010 current_len = len(self.stath0)
2012 for rmf
in rmf_name_list:
2013 print(
"adding rmf "+rmf)
2014 self.stath0.add_stat_file(rmf)
2015 self.stath1.add_stat_file(rmf)
2017 for n0
in range(current_len, len(self.stath0)):
2018 d0 = self.stath0[n0]
2019 c.add_member(n0, d0)
2024 Save the clusters into a pickle file
2025 @param filename string
2028 with open(filename,
'wb')
as fl:
2029 pickle.dump(self.clusters, fl)
2033 Load the clusters from a pickle file
2034 @param filename string
2035 @param append bool (Default=False), if True. append the clusters
2036 to the ones currently present
2039 self.clean_clusters()
2040 with open(filename,
'rb')
as fl:
2042 self.clusters += pickle.load(fl)
2044 self.clusters = pickle.load(fl)
2053 Compute the cluster center for a given cluster
2055 member_distance = defaultdict(float)
2057 for n0, n1
in itertools.combinations(cluster.members, 2):
2060 rmsd, _ = self.
rmsd()
2061 member_distance[n0] += rmsd
2063 if len(member_distance) > 0:
2064 cluster.center_index = min(member_distance,
2065 key=member_distance.get)
2067 cluster.center_index = cluster.members[0]
2072 Save the coordinates of the current cluster a single rmf file
2074 print(
"saving coordinates", cluster)
2078 if rmf_name
is None:
2079 rmf_name = prefix+
'/'+str(cluster.cluster_id)+
".rmf3"
2081 _ = self.stath1[cluster.members[0]]
2083 o.init_rmf(rmf_name, [self.stath1])
2084 for n1
in cluster.members:
2090 o.write_rmf(rmf_name)
2092 o.close_rmf(rmf_name)
2096 remove structures that are similar
2097 append it to a new cluster
2099 print(
"pruning models")
2101 filtered = [selected]
2102 remaining = range(1, len(self.stath1), 10)
2104 while len(remaining) > 0:
2105 d0 = self.stath0[selected]
2107 for n1
in remaining:
2112 if d <= rmsd_cutoff:
2114 print(
"pruning model %s, similar to model %s, rmsd %s"
2115 % (str(n1), str(selected), str(d)))
2116 remaining = [x
for x
in remaining
if x
not in rm]
2117 if len(remaining) == 0:
2119 selected = remaining[0]
2120 filtered.append(selected)
2123 self.clusters.append(c)
2125 d0 = self.stath0[n0]
2126 c.add_member(n0, d0)
2131 Compute the precision of a cluster
2137 if cluster.center_index
is not None:
2138 members1 = [cluster.center_index]
2140 members1 = cluster.members
2144 for n1
in cluster.members:
2149 tmp_rmsd, _ = self.
rmsd()
2154 precision = rmsd/npairs
2155 cluster.precision = precision
2160 Compute the bipartite precision (ie the cross-precision)
2161 between two clusters
2165 for cn0, n0
in enumerate(cluster1.members):
2167 for cn1, n1
in enumerate(cluster2.members):
2169 tmp_rmsd, _ = self.
rmsd()
2171 print(
"--- rmsd between structure %s and structure "
2172 "%s is %s" % (str(cn0), str(cn1), str(tmp_rmsd)))
2175 precision = rmsd/npairs
2178 def rmsf(self, cluster, molecule, copy_index=0, state_index=0,
2179 cluster_ref=
None, step=1):
2181 Compute the Root mean square fluctuations
2182 of a molecule in a cluster
2183 Returns an IMP.pmi.tools.OrderedDict() where the keys are the
2184 residue indexes and the value is the rmsf
2186 rmsf = IMP.pmi.tools.OrderedDict()
2189 if cluster_ref
is not None:
2190 if cluster_ref.center_index
is not None:
2191 members0 = [cluster_ref.center_index]
2193 members0 = cluster_ref.members
2195 if cluster.center_index
is not None:
2196 members0 = [cluster.center_index]
2198 members0 = cluster.members
2201 copy_index=copy_index, state_index=state_index)
2202 ps0 = s0.get_selected_particles()
2204 residue_indexes = list(IMP.pmi.tools.OrderedSet(
2210 d0 = self.stath0[n0]
2211 for n1
in cluster.members[::step]:
2213 print(
"--- rmsf %s %s" % (str(n0), str(n1)))
2217 self.stath1, molecule=molecule,
2218 residue_indexes=residue_indexes, resolution=1,
2219 copy_index=copy_index, state_index=state_index)
2220 ps1 = s1.get_selected_particles()
2222 d1 = self.stath1[n1]
2225 for n, (p0, p1)
in enumerate(zip(ps0, ps1)):
2226 r = residue_indexes[n]
2238 for stath
in [self.stath0, self.stath1]:
2239 if molecule
not in self.symmetric_molecules:
2241 stath, molecule=molecule, residue_index=r,
2242 resolution=1, copy_index=copy_index,
2243 state_index=state_index)
2246 stath, molecule=molecule, residue_index=r,
2247 resolution=1, state_index=state_index)
2249 ps = s.get_selected_particles()
2258 def save_densities(self, cluster, density_custom_ranges, voxel_size=5,
2259 reference=
"Absolute", prefix=
"./", step=1):
2265 for n1
in cluster.members[::step]:
2266 print(
"density "+str(n1))
2271 dens.add_subunits_density(self.stath1)
2273 dens.write_mrc(path=prefix+
'/', suffix=str(cluster.cluster_id))
2276 def contact_map(self, cluster, contact_threshold=15, log_scale=False,
2277 consolidate=
False, molecules=
None, prefix=
'./',
2278 reference=
"Absolute"):
2282 import matplotlib.pyplot
as plt
2283 import matplotlib.cm
as cm
2284 from scipy.spatial.distance
import cdist
2286 if molecules
is None:
2295 molecules=molecules).get_selected_particles())]
2296 unique_copies = [mol
for mol
in mols
if mol.get_copy_index() == 0]
2297 mol_names_unique = dict((mol.get_name(), mol)
for mol
in unique_copies)
2298 total_len_unique = sum(max(mol.get_residue_indexes())
2299 for mol
in unique_copies)
2306 seqlen = max(mol.get_residue_indexes())
2307 index_dict[mol] = range(prev_stop, prev_stop + seqlen)
2311 for mol
in unique_copies:
2312 seqlen = max(mol.get_residue_indexes())
2313 index_dict[mol] = range(prev_stop, prev_stop + seqlen)
2316 for ncl, n1
in enumerate(cluster.members):
2319 coord_dict = IMP.pmi.tools.OrderedDict()
2321 rindexes = mol.get_residue_indexes()
2322 coords = np.ones((max(rindexes), 3))
2323 for rnum
in rindexes:
2326 selpart = sel.get_selected_particles()
2327 if len(selpart) == 0:
2329 selpart = selpart[0]
2330 coords[rnum - 1, :] = \
2332 coord_dict[mol] = coords
2335 coords = np.concatenate(list(coord_dict.values()))
2336 dists = cdist(coords, coords)
2337 binary_dists = np.where((dists <= contact_threshold)
2338 & (dists >= 1.0), 1.0, 0.0)
2340 binary_dists_dict = {}
2342 len1 = max(mol1.get_residue_indexes())
2344 name1 = mol1.get_name()
2345 name2 = mol2.get_name()
2346 dists = cdist(coord_dict[mol1], coord_dict[mol2])
2347 if (name1, name2)
not in binary_dists_dict:
2348 binary_dists_dict[(name1, name2)] = \
2349 np.zeros((len1, len1))
2350 binary_dists_dict[(name1, name2)] += \
2351 np.where((dists <= contact_threshold)
2352 & (dists >= 1.0), 1.0, 0.0)
2353 binary_dists = np.zeros((total_len_unique, total_len_unique))
2355 for name1, name2
in binary_dists_dict:
2356 r1 = index_dict[mol_names_unique[name1]]
2357 r2 = index_dict[mol_names_unique[name2]]
2358 binary_dists[min(r1):max(r1)+1, min(r2):max(r2)+1] = \
2359 np.where((binary_dists_dict[(name1, name2)] >= 1.0),
2365 contact_freqs = binary_dists
2367 dist_maps.append(dists)
2368 av_dist_map += dists
2369 contact_freqs += binary_dists
2372 contact_freqs = -np.log(1.0-1.0/(len(cluster)+1)*contact_freqs)
2374 contact_freqs = 1.0/len(cluster)*contact_freqs
2375 av_dist_map = 1.0/len(cluster)*contact_freqs
2377 fig = plt.figure(figsize=(100, 100))
2378 ax = fig.add_subplot(111)
2381 gap_between_components = 50
2386 sorted_tuple = sorted(
2388 mol).get_extended_name(), mol)
for mol
in mols)
2389 prot_list = list(zip(*sorted_tuple))[1]
2391 sorted_tuple = sorted(
2393 for mol
in unique_copies)
2394 prot_list = list(zip(*sorted_tuple))[1]
2396 prot_listx = prot_list
2397 nresx = gap_between_components + \
2398 sum([max(mol.get_residue_indexes())
2399 + gap_between_components
for mol
in prot_listx])
2402 prot_listy = prot_list
2403 nresy = gap_between_components + \
2404 sum([max(mol.get_residue_indexes())
2405 + gap_between_components
for mol
in prot_listy])
2410 res = gap_between_components
2411 for mol
in prot_listx:
2412 resoffsetx[mol] = res
2413 res += max(mol.get_residue_indexes())
2415 res += gap_between_components
2419 res = gap_between_components
2420 for mol
in prot_listy:
2421 resoffsety[mol] = res
2422 res += max(mol.get_residue_indexes())
2424 res += gap_between_components
2426 resoffsetdiagonal = {}
2427 res = gap_between_components
2428 for mol
in IMP.pmi.tools.OrderedSet(prot_listx + prot_listy):
2429 resoffsetdiagonal[mol] = res
2430 res += max(mol.get_residue_indexes())
2431 res += gap_between_components
2436 for n, prot
in enumerate(prot_listx):
2437 res = resoffsetx[prot]
2439 for proty
in prot_listy:
2440 resy = resoffsety[proty]
2441 endy = resendy[proty]
2442 ax.plot([res, res], [resy, endy], linestyle=
'-',
2443 color=
'gray', lw=0.4)
2444 ax.plot([end, end], [resy, endy], linestyle=
'-',
2445 color=
'gray', lw=0.4)
2446 xticks.append((float(res) + float(end)) / 2)
2448 prot).get_extended_name())
2452 for n, prot
in enumerate(prot_listy):
2453 res = resoffsety[prot]
2455 for protx
in prot_listx:
2456 resx = resoffsetx[protx]
2457 endx = resendx[protx]
2458 ax.plot([resx, endx], [res, res], linestyle=
'-',
2459 color=
'gray', lw=0.4)
2460 ax.plot([resx, endx], [end, end], linestyle=
'-',
2461 color=
'gray', lw=0.4)
2462 yticks.append((float(res) + float(end)) / 2)
2464 prot).get_extended_name())
2468 tmp_array = np.zeros((nresx, nresy))
2470 for px
in prot_listx:
2471 for py
in prot_listy:
2472 resx = resoffsetx[px]
2473 lengx = resendx[px] - 1
2474 resy = resoffsety[py]
2475 lengy = resendy[py] - 1
2476 indexes_x = index_dict[px]
2477 minx = min(indexes_x)
2478 maxx = max(indexes_x)
2479 indexes_y = index_dict[py]
2480 miny = min(indexes_y)
2481 maxy = max(indexes_y)
2482 tmp_array[resx:lengx, resy:lengy] = \
2483 contact_freqs[minx:maxx, miny:maxy]
2484 ret[(px, py)] = np.argwhere(
2485 contact_freqs[minx:maxx, miny:maxy] == 1.0) + 1
2487 ax.imshow(tmp_array, cmap=colormap, norm=colornorm,
2488 origin=
'lower', alpha=0.6, interpolation=
'nearest')
2490 ax.set_xticks(xticks)
2491 ax.set_xticklabels(xlabels, rotation=90)
2492 ax.set_yticks(yticks)
2493 ax.set_yticklabels(ylabels)
2494 plt.setp(ax.get_xticklabels(), fontsize=6)
2495 plt.setp(ax.get_yticklabels(), fontsize=6)
2498 fig.set_size_inches(0.005 * nresx, 0.005 * nresy)
2499 [i.set_linewidth(2.0)
for i
in ax.spines.values()]
2501 plt.savefig(prefix+
"/contact_map."+str(cluster.cluster_id)+
".pdf",
2502 dpi=300, transparent=
"False")
2505 def plot_rmsd_matrix(self, filename):
2506 self.compute_all_pairwise_rmsd()
2507 distance_matrix = np.zeros(
2508 (len(self.stath0), len(self.stath1)))
2509 for (n0, n1)
in self.pairwise_rmsd:
2510 distance_matrix[n0, n1] = self.pairwise_rmsd[(n0, n1)]
2512 import matplotlib
as mpl
2514 import matplotlib.pylab
as pl
2515 from scipy.cluster
import hierarchy
as hrc
2517 fig = pl.figure(figsize=(10, 8))
2518 ax = fig.add_subplot(212)
2519 dendrogram = hrc.dendrogram(
2520 hrc.linkage(distance_matrix),
2523 leaves_order = dendrogram[
'leaves']
2524 ax.set_xlabel(
'Model')
2525 ax.set_ylabel(
'RMSD [Angstroms]')
2527 ax2 = fig.add_subplot(221)
2529 distance_matrix[leaves_order, :][:, leaves_order],
2530 interpolation=
'nearest')
2531 cb = fig.colorbar(cax)
2532 cb.set_label(
'RMSD [Angstroms]')
2533 ax2.set_xlabel(
'Model')
2534 ax2.set_ylabel(
'Model')
2536 pl.savefig(filename, dpi=300)
2545 Update the cluster id numbers
2547 for n, c
in enumerate(self.clusters):
2550 def get_molecule(self, hier, name, copy):
2558 self.seldict0 = IMP.pmi.tools.get_selections_dictionary(
2559 self.sel0_rmsd.get_selected_particles())
2560 self.seldict1 = IMP.pmi.tools.get_selections_dictionary(
2561 self.sel1_rmsd.get_selected_particles())
2562 for mol
in self.seldict0:
2563 for sel
in self.seldict0[mol]:
2564 self.issymmetricsel[sel] =
False
2565 for mol
in self.symmetric_molecules:
2566 self.symmetric_molecules[mol] = len(self.seldict0[mol])
2567 for sel
in self.seldict0[mol]:
2568 self.issymmetricsel[sel] =
True
2572 self.sel1_alignment, self.sel0_alignment)
2574 for rb
in self.rbs1:
2577 for bead
in self.beads1:
2585 def aggregate(self, idxs, rmsd_cutoff=10, metric=IMP.atom.get_rmsd):
2587 initial filling of the clusters.
2590 print(
"clustering model "+str(n0))
2591 d0 = self.stath0[n0]
2593 print(
"creating cluster index "+str(len(self.clusters)))
2594 self.clusters.append(c)
2595 c.add_member(n0, d0)
2596 clustered = set([n0])
2598 print(
"--- trying to add model " + str(n1) +
" to cluster "
2599 + str(len(self.clusters)))
2600 d1 = self.stath1[n1]
2603 rmsd, _ = self.
rmsd(metric=metric)
2604 if rmsd < rmsd_cutoff:
2605 print(
"--- model "+str(n1)+
" added, rmsd="+str(rmsd))
2606 c.add_member(n1, d1)
2609 print(
"--- model "+str(n1)+
" NOT added, rmsd="+str(rmsd))
2614 merge the clusters that have close members
2616 @param rmsd_cutoff cutoff distance in Angstorms
2617 @param metric Function to calculate distance between two Selections
2618 (by default, IMP.atom.get_rmsd is used)
2626 for c0, c1
in filter(
lambda x: len(x[0].members) > 1,
2627 itertools.combinations(self.clusters, 2)):
2628 n0, n1 = [c.members[0]
for c
in (c0, c1)]
2631 rmsd, _ = self.
rmsd()
2632 if (rmsd < 2*rmsd_cutoff
and
2634 to_merge.append((c0, c1))
2636 for c0, c
in reversed(to_merge):
2640 self.clusters = [c
for c
in
2641 filter(
lambda x: len(x.members) > 0, self.clusters)]
2645 returns true if c0 and c1 have members that are closer than rmsd_cutoff
2647 print(
"check close members for clusters " + str(c0.cluster_id) +
2648 " and " + str(c1.cluster_id))
2649 for n0, n1
in itertools.product(c0.members[1:], c1.members):
2652 rmsd, _ = self.
rmsd(metric=metric)
2653 if rmsd < rmsd_cutoff:
2668 a function that returns the permutation best_sel of sels0 that
2671 best_rmsd2 = float(
'inf')
2673 if self.issymmetricsel[sels0[0]]:
2676 for offset
in range(N):
2677 sels = [sels0[(offset+i) % N]
for i
in range(N)]
2680 r = metric(sel0, sel1)
2682 if rmsd2 < best_rmsd2:
2686 for sels
in itertools.permutations(sels0):
2688 for sel0, sel1
in itertools.takewhile(
2689 lambda x: rmsd2 < best_rmsd2, zip(sels, sels1)):
2690 r = metric(sel0, sel1)
2692 if rmsd2 < best_rmsd2:
2695 return best_sel, best_rmsd2
2697 def compute_all_pairwise_rmsd(self):
2698 for d0
in self.stath0:
2699 for d1
in self.stath1:
2700 rmsd, _ = self.
rmsd()
2702 def rmsd(self, metric=IMP.atom.get_rmsd):
2704 Computes the RMSD. Resolves ambiguous pairs assignments
2708 n0 = self.stath0.current_index
2709 n1 = self.stath1.current_index
2710 if ((n0, n1)
in self.pairwise_rmsd) \
2711 and ((n0, n1)
in self.pairwise_molecular_assignment):
2712 return (self.pairwise_rmsd[(n0, n1)],
2713 self.pairwise_molecular_assignment[(n0, n1)])
2723 molecular_assignment = {}
2724 for molname, sels0
in self.seldict0.items():
2725 sels_best_order, best_rmsd2 = \
2726 self.
rmsd_helper(sels0, self.seldict1[molname], metric)
2728 Ncoords = len(sels_best_order[0].get_selected_particles())
2729 Ncopies = len(self.seldict1[molname])
2730 total_rmsd += Ncoords*best_rmsd2
2731 total_N += Ncoords*Ncopies
2733 for sel0, sel1
in zip(sels_best_order, self.seldict1[molname]):
2734 p0 = sel0.get_selected_particles()[0]
2735 p1 = sel1.get_selected_particles()[0]
2740 molecular_assignment[(molname, c0)] = (molname, c1)
2742 total_rmsd = math.sqrt(total_rmsd/total_N)
2744 self.pairwise_rmsd[(n0, n1)] = total_rmsd
2745 self.pairwise_molecular_assignment[(n0, n1)] = molecular_assignment
2746 self.pairwise_rmsd[(n1, n0)] = total_rmsd
2747 self.pairwise_molecular_assignment[(n1, n0)] = molecular_assignment
2748 return total_rmsd, molecular_assignment
2752 Fix the reference structure for structural alignment, rmsd and
2755 @param reference can be either "Absolute" (cluster center of the
2756 first cluster) or Relative (cluster center of the current
2758 #param cluster the reference IMP.pmi.output.Cluster object
2760 if reference ==
"Absolute":
2762 elif reference ==
"Relative":
2763 if cluster.center_index:
2764 n0 = cluster.center_index
2766 n0 = cluster.members[0]
2771 compute the molecular assignments between multiple copies
2772 of the same sequence. It changes the Copy index of Molecules
2775 _, molecular_assignment = self.
rmsd()
2776 for (m0, c0), (m1, c1)
in molecular_assignment.items():
2777 mol0 = self.molcopydict0[m0][c0]
2778 mol1 = self.molcopydict1[m1][c1]
2781 p1.set_value(cik0, c0)
2785 Undo the Copy index assignment
2788 _, molecular_assignment = self.
rmsd()
2789 for (m0, c0), (m1, c1)
in molecular_assignment.items():
2790 mol0 = self.molcopydict0[m0][c0]
2791 mol1 = self.molcopydict1[m1][c1]
2794 p1.set_value(cik0, c1)
2801 s =
"AnalysisReplicaExchange\n"
2802 s +=
"---- number of clusters %s \n" % str(len(self.clusters))
2803 s +=
"---- number of models %s \n" % str(len(self.stath0))
2806 def __getitem__(self, int_slice_adaptor):
2807 if isinstance(int_slice_adaptor, int):
2808 return self.clusters[int_slice_adaptor]
2809 elif isinstance(int_slice_adaptor, slice):
2810 return self.__iter__(int_slice_adaptor)
2812 raise TypeError(
"Unknown Type")
2815 return len(self.clusters)
2817 def __iter__(self, slice_key=None):
2818 if slice_key
is None:
2819 for i
in range(len(self)):
2822 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.