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 """Enable a simulation to be restarted if it is interrupted.
374 If enabled, restart files containing a complete description of
375 the IMP system are written periodically during the simulation,
376 one per replica. If the simulation is interrupted, it can be
377 restarted using the restart_replica_exchange function, which
378 reads these files. Files for the previous restart are also kept
379 (with a .prev.pck extension) in case the most recent restart
382 Restart files contain IMP internal state and so will probably
383 not work with a different version of IMP, or on a different
384 operating system. As with all Python pickles, these files may
385 contain executable Python code and so you should not use a
386 restart file from an untrusted source.
388 @param frames How often a restart file should be written
389 (number of frames), or zero to not write restart files
390 @param restart_dir The directory under `global_output_directory`
391 where restart files are written.
396 self._restart = _RestartInfo(frames, restart_dir)
399 if self.vars[
"geometries"]
is None:
400 self.vars[
"geometries"] = list(geometries)
402 self.vars[
"geometries"].extend(geometries)
405 print(
"ReplicaExchange: it generates initial.*.rmf3, stat.*.out, "
406 "rmfs/*.rmf3 for each replica ")
407 print(
"--- it stores the best scoring pdb models in pdbs/")
408 print(
"--- the stat.*.out and rmfs/*.rmf3 are saved only at the "
409 "lowest temperature")
410 if self._restart
and self._restart.restarted:
411 print(
"--- this is a restart of a failed simulation")
412 print(
"--- variables:")
413 for k, v
in sorted(self.vars.items(), key=itemgetter(0)):
414 print(
"------", k.ljust(30), v)
416 def get_replica_exchange_object(self):
417 return self.replica_exchange_object
419 def _add_provenance(self, sampler_md, sampler_mc):
420 """Record details about the sampling in the IMP Hierarchies"""
423 method =
"Molecular Dynamics"
424 iterations += self.vars[
"molecular_dynamics_steps"]
426 method =
"Hybrid MD/MC" if sampler_md
else "Monte Carlo"
427 iterations += self.vars[
"monte_carlo_steps"]
429 if iterations == 0
or self.vars[
"number_of_frames"] == 0:
431 iterations *= self.vars[
"num_sample_rounds"]
433 pi = self.model.add_particle(
"sampling")
435 self.model, pi, method, self.vars[
"number_of_frames"],
437 p.set_number_of_replicas(
438 self.replica_exchange_object.get_number_of_replicas())
439 IMP.pmi.tools._add_pmi_provenance(self.root_hier)
442 def _setup_mc_sampler(self):
444 self.model, self.monte_carlo_sample_objects,
445 self.vars[
"monte_carlo_temperature"],
446 score_moved=self.score_moved,
447 start_frame=self._restart_from_frame)
449 sampler_mc.set_use_jax(self.vars[
"monte_carlo_steps"])
450 if self.vars[
"simulated_annealing"]:
451 tmin = self.vars[
"simulated_annealing_minimum_temperature"]
452 tmax = self.vars[
"simulated_annealing_maximum_temperature"]
454 "simulated_annealing_minimum_temperature_nframes"]
456 "simulated_annealing_maximum_temperature_nframes"]
457 sampler_mc.set_simulated_annealing(tmin, tmax, nfmin, nfmax)
458 if self.vars[
"self_adaptive"]:
459 sampler_mc.set_self_adaptive(
460 isselfadaptive=self.vars[
"self_adaptive"])
463 def _setup_md_sampler(self):
465 self.model, self.molecular_dynamics_sample_objects,
466 self.vars[
"monte_carlo_temperature"],
467 maximum_time_step=self.molecular_dynamics_max_time_step,
468 start_frame=self._restart_from_frame)
470 sampler_md.set_use_jax(self.vars[
"molecular_dynamics_steps"])
471 if self.vars[
"simulated_annealing"]:
472 tmin = self.vars[
"simulated_annealing_minimum_temperature"]
473 tmax = self.vars[
"simulated_annealing_maximum_temperature"]
475 "simulated_annealing_minimum_temperature_nframes"]
477 "simulated_annealing_maximum_temperature_nframes"]
478 sampler_md.set_simulated_annealing(tmin, tmax, nfmin, nfmax)
481 def _get_jax_model(self, sampler_mc):
483 return sampler_mc.get_jax_model()
485 def execute_macro(self):
487 restarted = self._restart.restarted
if self._restart
else False
489 stat_file = _StatFile(self.output_objects, self.rmf_output_objects)
490 temp_index_factor = 100000.0
494 if self.monte_carlo_sample_objects
is not None:
495 print(
"Setting up MonteCarlo")
496 sampler_mc = self._setup_mc_sampler()
497 stat_file.append(sampler_mc)
498 samplers.append(sampler_mc)
500 if self.molecular_dynamics_sample_objects
is not None:
501 print(
"Setting up MolecularDynamics")
502 sampler_md = self._setup_md_sampler()
503 stat_file.append(sampler_md)
504 samplers.append(sampler_md)
508 print(
"Setting up ReplicaExchange")
510 self.model, self.vars[
"replica_exchange_minimum_temperature"],
511 self.vars[
"replica_exchange_maximum_temperature"], samplers,
512 replica_exchange_object=self.replica_exchange_object)
513 self.replica_exchange_object = rex.rem
516 rex.stats = self._rex_stats
519 myindex = rex.get_my_index()
520 stat_file.append(rex)
524 min_temp_index = int(min(rex.get_temperatures()) * temp_index_factor)
528 globaldir = self.vars[
"global_output_directory"] +
"/"
529 rmf_dir = globaldir + self.vars[
"rmf_dir"]
530 pdb_dir = globaldir + self.vars[
"best_pdb_dir"]
532 if not self.test_mode
and not self.nest:
533 if self.vars[
"do_clean_first"]:
536 if self.vars[
"do_create_directories"]:
538 os.makedirs(globaldir, exist_ok=
True)
539 os.makedirs(rmf_dir, exist_ok=
True)
540 if not self.is_multi_state:
541 os.makedirs(pdb_dir, exist_ok=
True)
543 for n
in range(self.vars[
"number_of_states"]):
544 os.makedirs(pdb_dir +
"/" + str(n), exist_ok=
True)
553 print(
"Setting up stat file")
554 low_temp_stat_file = globaldir + \
555 self.vars[
"stat_file_name_suffix"] +
"." + \
556 str(myindex) +
".out"
559 if not self.test_mode:
562 if not self.test_mode
and not self.nest:
563 if stat_file.objects
is not None:
564 output.init_stat2(low_temp_stat_file,
566 extralabels=[
"rmf_file",
"rmf_frame_index"],
567 jax_model=self._get_jax_model(sampler_mc),
570 if restarted
and sampler_mc:
571 nline = output._count_stat2_nframe(
572 low_temp_stat_file,
'MonteCarlo_Nframe',
573 self._restart_from_frame)
574 if nline
is not None:
575 output._truncate_stat2_nline(low_temp_stat_file, nline)
577 print(
"Stat file writing is disabled")
579 if stat_file.rmf_objects
is not None and not self.nest:
580 print(
"Stat info being written in the rmf file")
582 if not self.test_mode
and not self.nest:
583 print(
"Setting up replica stat file")
584 replica_stat_file = globaldir + \
585 self.vars[
"replica_stat_file_suffix"] +
"." + \
586 str(myindex) +
".out"
587 if not self.test_mode:
588 output.init_stat2(replica_stat_file, [rex],
589 extralabels=[
"score"],
590 jax_model=self._get_jax_model(sampler_mc),
593 output._truncate_stat2_nline(
594 replica_stat_file, self._restart_from_frame)
596 print(
"Setting up best pdb files")
597 if not self.is_multi_state:
598 if self.vars[
"number_of_best_scoring_models"] > 0:
599 output.init_pdb_best_scoring(
600 pdb_dir +
"/" + self.vars[
"best_pdb_name_suffix"],
602 self.vars[
"number_of_best_scoring_models"],
603 replica_exchange=
True,
604 mmcif=self.vars[
'mmcif'],
605 best_score_file=globaldir +
"best.scores.rex.py")
606 pdbext =
".0.cif" if self.vars[
'mmcif']
else ".0.pdb"
608 pdb_dir +
"/" +
"model.psf",
610 self.vars[
"best_pdb_name_suffix"] + pdbext)
612 if self.vars[
"number_of_best_scoring_models"] > 0:
613 for n
in range(self.vars[
"number_of_states"]):
614 output.init_pdb_best_scoring(
615 pdb_dir +
"/" + str(n) +
"/" +
616 self.vars[
"best_pdb_name_suffix"],
618 self.vars[
"number_of_best_scoring_models"],
619 replica_exchange=
True,
620 mmcif=self.vars[
'mmcif'],
621 best_score_file=globaldir +
"best.scores.rex.py")
622 pdbext =
".0.cif" if self.vars[
'mmcif']
else ".0.pdb"
624 pdb_dir +
"/" + str(n) +
"/" +
"model.psf",
625 pdb_dir +
"/" + str(n) +
"/" +
626 self.vars[
"best_pdb_name_suffix"] + pdbext)
629 if self.em_object_for_rmf
is not None:
630 output_hierarchies = [
632 self.em_object_for_rmf.get_density_as_hierarchy(
635 output_hierarchies = [self.root_hier]
637 if not self.test_mode
and not self.nest
and not restarted:
638 print(
"Setting up and writing initial rmf coordinate file")
639 init_suffix = globaldir + self.vars[
"initial_rmf_name_suffix"]
640 output.init_rmf(init_suffix +
"." + str(myindex) +
".rmf3",
642 listofobjects=stat_file.rmf_objects)
643 if self._rmf_restraints:
644 output.add_restraints_to_rmf(
645 init_suffix +
"." + str(myindex) +
".rmf3",
646 self._rmf_restraints)
647 output.write_rmf(init_suffix +
"." + str(myindex) +
".rmf3")
648 output.close_rmf(init_suffix +
"." + str(myindex) +
".rmf3")
650 if not self.test_mode:
651 mpivs = IMP.pmi.samplers.MPI_values(self.replica_exchange_object)
653 mpivs = _MockMPIValues()
655 self._add_provenance(sampler_md, sampler_mc)
657 if not self.test_mode
and not self.nest:
658 print(
"Setting up production rmf files")
660 rmfname = f
"{rmf_dir}/{myindex}.rs{self._restart._number}.rmf3"
662 rmfname = rmf_dir +
"/" + str(myindex) +
".rmf3"
663 output.init_rmf(rmfname, output_hierarchies,
664 geometries=self.vars[
"geometries"],
665 listofobjects=stat_file.rmf_objects)
667 if self._rmf_restraints:
668 output.add_restraints_to_rmf(rmfname, self._rmf_restraints)
670 if not self.test_mode
and self.nest:
671 print(
"Setting up NestOR rmf files")
672 nestor_rmf_fname = str(self.nestor_rmf_fname) +
'_' + \
673 str(self.replica_exchange_object.get_my_index()) +
'.rmf3'
675 output.init_rmf(nestor_rmf_fname, output_hierarchies,
676 geometries=self.vars[
"geometries"],
677 listofobjects=stat_file.rmf_objects)
679 ntimes_at_low_temp = 0
681 if myindex == 0
and not self.nest:
683 self.replica_exchange_object.set_was_used(
True)
684 nframes = self.vars[
"number_of_frames"]
688 sampled_likelihoods = []
689 for i
in range(self._restart_from_frame, nframes):
690 if self._restart
and i != self._restart_from_frame:
691 self._restart._write_frame(self, i, myindex, rex.stats)
696 for nr
in range(self.vars[
"num_sample_rounds"]):
697 if sampler_md
is not None:
698 score = sampler_md.optimize(
699 self.vars[
"molecular_dynamics_steps"])
700 if sampler_mc
is not None:
701 score = sampler_mc.optimize(
702 self.vars[
"monte_carlo_steps"])
705 self.model).evaluate(
False)
707 and not self.use_jax):
711 self.model).evaluate(
False)
712 assert abs(score - check_score) < 1e-4
713 mpivs.set_value(
"score", score)
715 output.set_output_entry(
"score", score)
717 my_temp_index = int(rex.get_my_temp() * temp_index_factor)
719 if self.vars[
"save_coordinates_mode"] ==
"lowest_temperature":
720 save_frame = (min_temp_index == my_temp_index)
721 elif self.vars[
"save_coordinates_mode"] ==
"25th_score":
722 score_perc = mpivs.get_percentile(
"score")
723 save_frame = (score_perc*100.0 <= 25.0)
724 elif self.vars[
"save_coordinates_mode"] ==
"50th_score":
725 score_perc = mpivs.get_percentile(
"score")
726 save_frame = (score_perc*100.0 <= 50.0)
727 elif self.vars[
"save_coordinates_mode"] ==
"75th_score":
728 score_perc = mpivs.get_percentile(
"score")
729 save_frame = (score_perc*100.0 <= 75.0)
732 if save_frame
and not self.test_mode:
736 print(
"--- frame %s score %s " % (str(i), str(score)))
739 if math.isnan(score):
740 sampled_likelihoods.append(math.nan)
742 likelihood_for_sample = 1
743 for rstrnt
in self.nestor_restraints:
744 likelihood_for_sample *= rstrnt.get_likelihood()
745 sampled_likelihoods.append(likelihood_for_sample)
746 output.write_rmf(nestor_rmf_fname)
748 if not self.test_mode
and not self.nest:
749 if i % self.vars[
"nframes_write_coordinates"] == 0:
750 print(
'--- writing coordinates')
751 if self.vars[
"number_of_best_scoring_models"] > 0:
752 output.write_pdb_best_scoring(score)
753 output.write_rmf(rmfname)
754 output.set_output_entry(
"rmf_file", rmfname)
755 output.set_output_entry(
"rmf_frame_index",
758 output.set_output_entry(
"rmf_file", rmfname)
759 output.set_output_entry(
"rmf_frame_index",
'-1')
760 if stat_file.objects
is not None:
763 jax_model=self._get_jax_model(sampler_mc))
764 ntimes_at_low_temp += 1
766 if not self.test_mode
and not self.nest:
769 jax_model=self._get_jax_model(sampler_mc))
770 if self.vars[
"replica_exchange_swap"]:
771 rex.swap_temp(i, score)
773 if self.nest
and len(sampled_likelihoods) > 0:
774 with open(
"likelihoods_"
775 + str(self.replica_exchange_object.get_my_index()),
777 pickle.dump(sampled_likelihoods, lif)
779 output.close_rmf(nestor_rmf_fname)
781 for p, state
in IMP.pmi.tools._all_protocol_outputs(self.root_hier):
782 p.add_replica_exchange(state, self)
784 if not self.test_mode
and not self.nest:
785 print(
"closing production rmf files")
786 output.close_rmf(rmfname)
790 """Continue a failed ReplicaExchange sampling run.
792 @see ReplicaExchange.set_restart
794 @param restart_dir The directory containing the restart file(s).
795 @param prev If True, use the previous restart
796 (e.g. `restart.0.prev.pck`) rather than the most recent
797 restart (e.g. `restart.0.pck`)
804 nproc, myindex = r.get_number_of_replicas(), r.get_my_index()
807 nproc, myindex = 1, 0
809 ext =
'prev.pck' if prev
else 'pck'
810 with open(f
'{restart_dir}/restart.{myindex}.{ext}',
'rb')
as fh:
812 old_nproc = mc.get_number_of_replicas()
813 if old_nproc != nproc:
815 f
"Mismatch trying to read restart files: the original run used "
816 f
"{old_nproc} replicas and this run has {nproc}")
817 return mc.execute_macro()
821 """A macro to build a IMP::pmi::topology::System based on a
822 TopologyReader object.
824 Easily create multi-state systems by calling this macro
825 repeatedly with different TopologyReader objects!
826 A useful function is get_molecules() which returns the PMI Molecules
827 grouped by state as a dictionary with key = (molecule name),
828 value = IMP.pmi.topology.Molecule
829 Quick multi-state system:
832 reader1 = IMP.pmi.topology.TopologyReader(tfile1)
833 reader2 = IMP.pmi.topology.TopologyReader(tfile2)
834 bs = IMP.pmi.macros.BuildSystem(model)
835 bs.add_state(reader1)
836 bs.add_state(reader2)
837 bs.execute_macro() # build everything including degrees of freedom
838 IMP.atom.show_molecular_hierarchy(bs.get_hierarchy())
839 ### now you have a two state system, you add restraints etc
841 @note The "domain name" entry of the topology reader is not used.
842 All molecules are set up by the component name, but split into rigid bodies
846 _alphabets = {
'DNA': IMP.pmi.alphabets.dna,
847 'RNA': IMP.pmi.alphabets.rna}
849 def __init__(self, model, sequence_connectivity_scale=4.0,
850 force_create_gmm_files=
False, resolutions=[1, 10],
853 @param model An IMP Model
854 @param sequence_connectivity_scale For scaling the connectivity
856 @param force_create_gmm_files If True, will sample and create GMMs
857 no matter what. If False, will only sample if the
858 files don't exist. If number of Gaussians is zero, won't
860 @param resolutions The resolutions to build for structured regions
861 @param name The name of the top-level hierarchy node.
868 self._domain_res = []
870 self.force_create_gmm_files = force_create_gmm_files
871 self.resolutions = resolutions
873 def add_state(self, reader, keep_chain_id=False, fasta_name_map=None,
875 """Add a state using the topology info in a
876 IMP::pmi::topology::TopologyReader object.
877 When you are done adding states, call execute_macro()
878 @param reader The TopologyReader object
879 @param keep_chain_id If True, keep the chain IDs from the
880 original PDB files, if available
881 @param fasta_name_map dictionary for converting protein names
882 found in the fasta file
883 @param chain_ids A list or string of chain IDs for assigning to
884 newly-created molecules, e.g.
885 `string.ascii_uppercase+string.ascii_lowercase+string.digits`.
886 If not specified, chain IDs A through Z are assigned, then
887 AA through AZ, then BA through BZ, and so on, in the same
890 state = self.system.create_state()
891 self._readers.append(reader)
893 these_domain_res = {}
895 if chain_ids
is None:
896 chain_ids = IMP.pmi.output._ChainIDs()
901 for molname
in reader.get_molecules():
902 copies = reader.get_molecules()[molname].domains
903 for nc, copyname
in enumerate(copies):
904 print(
"BuildSystem.add_state: setting up molecule %s copy "
905 "number %s" % (molname, str(nc)))
906 copy = copies[copyname]
909 all_chains = [c
for c
in copy
if c.chain
is not None]
911 chain_id = all_chains[0].chain
913 chain_id = chain_ids[numchain]
915 "No PDBs specified for %s, so keep_chain_id has "
916 "no effect; using default chain ID '%s'"
919 chain_id = chain_ids[numchain]
921 alphabet = IMP.pmi.alphabets.amino_acid
922 fasta_flag = copy[0].fasta_flag
923 if fasta_flag
in self._alphabets:
924 alphabet = self._alphabets[fasta_flag]
926 copy[0].fasta_file, fasta_name_map)
927 seq = seqs[copy[0].fasta_id]
928 print(
"BuildSystem.add_state: molecule %s sequence has "
929 "%s residues" % (molname, len(seq)))
930 orig_mol = state.create_molecule(
931 molname, seq, chain_id, alphabet=alphabet,
932 uniprot=seqs.uniprot.get(copy[0].fasta_id))
936 print(
"BuildSystem.add_state: creating a copy for "
937 "molecule %s" % molname)
938 mol = orig_mol.create_copy(chain_id)
941 for domainnumber, domain
in enumerate(copy):
942 print(
"BuildSystem.add_state: ---- setting up domain %s "
943 "of molecule %s" % (domainnumber, molname))
946 these_domains[domain.get_unique_name()] = domain
947 if domain.residue_range == []
or \
948 domain.residue_range
is None:
949 domain_res = mol.get_residues()
951 start = domain.residue_range[0]+domain.pdb_offset
952 if domain.residue_range[1] ==
'END':
953 end = len(mol.sequence)
955 end = domain.residue_range[1]+domain.pdb_offset
956 domain_res = mol.residue_range(start-1, end-1)
957 print(
"BuildSystem.add_state: -------- domain %s of "
958 "molecule %s extends from residue %s to "
960 % (domainnumber, molname, start, end))
961 if domain.pdb_file ==
"BEADS":
962 print(
"BuildSystem.add_state: -------- domain %s of "
963 "molecule %s represented by BEADS "
964 % (domainnumber, molname))
965 mol.add_representation(
967 resolutions=[domain.bead_size],
968 setup_particles_as_densities=(
969 domain.em_residues_per_gaussian != 0),
971 these_domain_res[domain.get_unique_name()] = \
973 elif domain.pdb_file ==
"IDEAL_HELIX":
974 print(
"BuildSystem.add_state: -------- domain %s of "
975 "molecule %s represented by IDEAL_HELIX "
976 % (domainnumber, molname))
977 emper = domain.em_residues_per_gaussian
978 mol.add_representation(
980 resolutions=self.resolutions,
982 density_residues_per_component=emper,
983 density_prefix=domain.density_prefix,
984 density_force_compute=self.force_create_gmm_files,
986 these_domain_res[domain.get_unique_name()] = \
989 print(
"BuildSystem.add_state: -------- domain %s of "
990 "molecule %s represented by pdb file %s "
991 % (domainnumber, molname, domain.pdb_file))
992 domain_atomic = mol.add_structure(domain.pdb_file,
994 domain.residue_range,
997 domain_non_atomic = domain_res - domain_atomic
998 if not domain.em_residues_per_gaussian:
999 mol.add_representation(
1000 domain_atomic, resolutions=self.resolutions,
1002 if len(domain_non_atomic) > 0:
1003 mol.add_representation(
1005 resolutions=[domain.bead_size],
1008 print(
"BuildSystem.add_state: -------- domain %s "
1009 "of molecule %s represented by gaussians "
1010 % (domainnumber, molname))
1011 emper = domain.em_residues_per_gaussian
1012 creategmm = self.force_create_gmm_files
1013 mol.add_representation(
1015 resolutions=self.resolutions,
1016 density_residues_per_component=emper,
1017 density_prefix=domain.density_prefix,
1018 density_force_compute=creategmm,
1020 if len(domain_non_atomic) > 0:
1021 mol.add_representation(
1023 resolutions=[domain.bead_size],
1024 setup_particles_as_densities=
True,
1026 these_domain_res[domain.get_unique_name()] = (
1027 domain_atomic, domain_non_atomic)
1028 self._domain_res.append(these_domain_res)
1029 self._domains.append(these_domains)
1030 print(
'BuildSystem.add_state: State', len(self.system.states),
'added')
1034 """Return list of all molecules grouped by state.
1035 For each state, it's a dictionary of Molecules where key is the
1038 return [s.get_molecules()
for s
in self.system.get_states()]
1040 def get_molecule(self, molname, copy_index=0, state_index=0):
1041 return self.system.get_states()[state_index].
get_molecules()[
1042 molname][copy_index]
1045 max_bead_trans=4.0, max_srb_trans=4.0, max_srb_rot=0.04):
1046 """Builds representations and sets up degrees of freedom"""
1047 print(
"BuildSystem.execute_macro: building representations")
1048 self.root_hier = self.system.build()
1050 print(
"BuildSystem.execute_macro: setting up degrees of freedom")
1052 for nstate, reader
in enumerate(self._readers):
1053 rbs = reader.get_rigid_bodies()
1054 srbs = reader.get_super_rigid_bodies()
1055 csrbs = reader.get_chains_of_super_rigid_bodies()
1058 domains_in_rbs = set()
1060 print(
"BuildSystem.execute_macro: -------- building rigid "
1061 "body %s" % (str(rblist)))
1062 all_res = IMP.pmi.tools.OrderedSet()
1063 bead_res = IMP.pmi.tools.OrderedSet()
1064 for dname
in rblist:
1065 domain = self._domains[nstate][dname]
1066 print(
"BuildSystem.execute_macro: -------- adding %s"
1068 all_res |= self._domain_res[nstate][dname][0]
1069 bead_res |= self._domain_res[nstate][dname][1]
1070 domains_in_rbs.add(dname)
1072 print(
"BuildSystem.execute_macro: -------- creating rigid "
1073 "body with max_trans %s max_rot %s "
1074 "non_rigid_max_trans %s"
1075 % (str(max_rb_trans), str(max_rb_rot),
1076 str(max_bead_trans)))
1077 self.dof.create_rigid_body(all_res,
1078 nonrigid_parts=bead_res,
1079 max_trans=max_rb_trans,
1081 nonrigid_max_trans=max_bead_trans,
1082 name=
"RigidBody %s" % dname)
1085 for dname, domain
in self._domains[nstate].items():
1086 if dname
not in domains_in_rbs:
1087 if domain.pdb_file !=
"BEADS":
1089 "No rigid bodies set for %s. Residues read from "
1090 "the PDB file will not be sampled - only regions "
1091 "missing from the PDB will be treated flexibly. "
1092 "To sample the entire sequence, use BEADS instead "
1093 "of a PDB file name" % dname,
1095 self.dof.create_flexible_beads(
1096 self._domain_res[nstate][dname][1],
1097 max_trans=max_bead_trans)
1100 for srblist
in srbs:
1101 print(
"BuildSystem.execute_macro: -------- building "
1102 "super rigid body %s" % (str(srblist)))
1103 all_res = IMP.pmi.tools.OrderedSet()
1104 for dname
in srblist:
1105 print(
"BuildSystem.execute_macro: -------- adding %s"
1107 all_res |= self._domain_res[nstate][dname][0]
1108 all_res |= self._domain_res[nstate][dname][1]
1110 print(
"BuildSystem.execute_macro: -------- creating super "
1111 "rigid body with max_trans %s max_rot %s "
1112 % (str(max_srb_trans), str(max_srb_rot)))
1113 self.dof.create_super_rigid_body(
1114 all_res, max_trans=max_srb_trans, max_rot=max_srb_rot)
1117 for csrblist
in csrbs:
1118 all_res = IMP.pmi.tools.OrderedSet()
1119 for dname
in csrblist:
1120 all_res |= self._domain_res[nstate][dname][0]
1121 all_res |= self._domain_res[nstate][dname][1]
1122 all_res = list(all_res)
1123 all_res.sort(key=
lambda r: r.get_index())
1124 self.dof.create_main_chain_mover(all_res)
1125 return self.root_hier, self.dof
1130 """A macro for running all the basic operations of analysis.
1131 Includes clustering, precision analysis, and making ensemble density maps.
1132 A number of plots are also supported.
1135 merge_directories=[
"./"],
1136 stat_file_name_suffix=
"stat",
1137 best_pdb_name_suffix=
"model",
1138 do_clean_first=
True,
1139 do_create_directories=
True,
1140 global_output_directory=
"output/",
1141 replica_stat_file_suffix=
"stat_replica",
1142 global_analysis_result_directory=
"./analysis/",
1145 @param model The IMP model
1146 @param stat_file_name_suffix
1147 @param merge_directories The directories containing output files
1148 @param best_pdb_name_suffix
1149 @param do_clean_first
1150 @param do_create_directories
1151 @param global_output_directory Where everything is
1152 @param replica_stat_file_suffix
1153 @param global_analysis_result_directory
1154 @param test_mode If True, nothing is changed on disk
1158 from mpi4py
import MPI
1159 self.comm = MPI.COMM_WORLD
1160 self.rank = self.comm.Get_rank()
1161 self.number_of_processes = self.comm.size
1164 self.number_of_processes = 1
1166 self.test_mode = test_mode
1167 self._protocol_output = []
1168 self.cluster_obj =
None
1170 stat_dir = global_output_directory
1171 self.stat_files = []
1173 for rd
in merge_directories:
1174 stat_files = glob.glob(os.path.join(rd, stat_dir,
"stat.*.out"))
1175 if len(stat_files) == 0:
1176 warnings.warn(
"no stat files found in %s"
1177 % os.path.join(rd, stat_dir),
1179 self.stat_files += stat_files
1182 """Capture details of the modeling protocol.
1183 @param p an instance of IMP.pmi.output.ProtocolOutput or a subclass.
1186 self._protocol_output.append((p, p._last_state))
1189 score_key=
"Total_Score",
1190 rmf_file_key=
"rmf_file",
1191 rmf_file_frame_key=
"rmf_frame_index",
1194 nframes_trajectory=10000):
1195 """ Get a trajectory of the modeling run, for generating
1196 demonstrative movies
1198 @param score_key The score for ranking models
1199 @param rmf_file_key Key pointing to RMF filename
1200 @param rmf_file_frame_key Key pointing to RMF frame number
1201 @param outputdir The local output directory used in the run
1202 @param get_every Extract every nth frame
1203 @param nframes_trajectory Total number of frames of the trajectory
1208 self.stat_files, score_key, rmf_file_key, rmf_file_frame_key,
1210 score_list = list(map(float, trajectory_models[2]))
1212 max_score = max(score_list)
1213 min_score = min(score_list)
1215 bins = [(max_score-min_score)*math.exp(-float(i))+min_score
1216 for i
in range(nframes_trajectory)]
1217 binned_scores = [
None]*nframes_trajectory
1218 binned_model_indexes = [-1]*nframes_trajectory
1220 for model_index, s
in enumerate(score_list):
1221 bins_score_diffs = [abs(s-b)
for b
in bins]
1222 bin_index = min(enumerate(bins_score_diffs), key=itemgetter(1))[0]
1223 if binned_scores[bin_index]
is None:
1224 binned_scores[bin_index] = s
1225 binned_model_indexes[bin_index] = model_index
1227 old_diff = abs(binned_scores[bin_index]-bins[bin_index])
1228 new_diff = abs(s-bins[bin_index])
1229 if new_diff < old_diff:
1230 binned_scores[bin_index] = s
1231 binned_model_indexes[bin_index] = model_index
1233 print(binned_scores)
1234 print(binned_model_indexes)
1236 def _expand_ambiguity(self, prot, d):
1237 """If using PMI2, expand the dictionary to include copies as
1240 This also keeps the states separate.
1245 if '..' in key
or (isinstance(val, tuple)
and len(val) >= 3):
1248 states = IMP.atom.get_by_type(prot, IMP.atom.STATE_TYPE)
1249 if isinstance(val, tuple):
1257 for nst
in range(len(states)):
1259 copies = sel.get_selected_particles(with_representation=
False)
1261 for nc
in range(len(copies)):
1263 newdict[
'%s.%i..%i' % (name, nst, nc)] = \
1264 (start, stop, name, nc, nst)
1266 newdict[
'%s..%i' % (name, nc)] = \
1267 (start, stop, name, nc, nst)
1273 score_key=
"Total_Score",
1274 rmf_file_key=
"rmf_file",
1275 rmf_file_frame_key=
"rmf_frame_index",
1277 prefiltervalue=
None,
1280 alignment_components=
None,
1281 number_of_best_scoring_models=10,
1282 rmsd_calculation_components=
None,
1283 distance_matrix_file=
'distances.mat',
1284 load_distance_matrix_file=
False,
1285 skip_clustering=
False,
1286 number_of_clusters=1,
1288 exit_after_display=
True,
1290 first_and_last_frames=
None,
1291 density_custom_ranges=
None,
1292 write_pdb_with_centered_coordinates=
False,
1294 """Get the best scoring models, compute a distance matrix,
1295 cluster them, and create density maps.
1297 Tuple format: "molname" just the molecule,
1298 or (start,stop,molname,copy_num(optional),state_num(optional)
1299 Can pass None for copy or state to ignore that field.
1300 If you don't pass a specific copy number
1302 @param score_key The score for ranking models.
1303 @param rmf_file_key Key pointing to RMF filename
1304 @param rmf_file_frame_key Key pointing to RMF frame number
1305 @param state_number State number to analyze
1306 @param prefiltervalue Only include frames where the
1307 score key is below this value
1308 @param feature_keys Keywords for which you want to
1309 calculate average, medians, etc.
1310 If you pass "Keyname" it'll include everything that matches
1312 @param outputdir The local output directory used in
1314 @param alignment_components Dictionary with keys=groupname,
1315 values are tuples for aligning the structures
1316 e.g. {"Rpb1": (20,100,"Rpb1"),"Rpb2":"Rpb2"}
1317 @param number_of_best_scoring_models Num models to keep per run
1318 @param rmsd_calculation_components For calculating RMSD
1319 (same format as alignment_components)
1320 @param distance_matrix_file Where to store/read the
1322 @param load_distance_matrix_file Try to load the distance
1324 @param skip_clustering Just extract the best scoring
1325 models and save the pdbs
1326 @param number_of_clusters Number of k-means clusters
1327 @param display_plot Display the distance matrix
1328 @param exit_after_display Exit after displaying distance
1330 @param get_every Extract every nth frame
1331 @param first_and_last_frames A tuple with the first and last
1332 frames to be analyzed. Values are percentages!
1333 Default: get all frames
1334 @param density_custom_ranges For density calculation
1335 (same format as alignment_components)
1336 @param write_pdb_with_centered_coordinates
1337 @param voxel_size Used for the density output
1341 self._outputdir = Path(outputdir).absolute()
1342 self._number_of_clusters = number_of_clusters
1343 for p, state
in self._protocol_output:
1344 p.add_replica_exchange_analysis(state, self, density_custom_ranges)
1355 if not load_distance_matrix_file:
1356 if len(self.stat_files) == 0:
1357 print(
"ERROR: no stat file found in the given path")
1359 my_stat_files = IMP.pmi.tools.chunk_list_into_segments(
1360 self.stat_files, self.number_of_processes)[self.rank]
1363 for k
in (score_key, rmf_file_key, rmf_file_frame_key):
1364 if k
in feature_keys:
1366 "no need to pass " + k +
" to feature_keys.",
1368 feature_keys.remove(k)
1371 my_stat_files, score_key, feature_keys, rmf_file_key,
1372 rmf_file_frame_key, prefiltervalue, get_every, provenance=prov)
1373 rmf_file_list = best_models[0]
1374 rmf_file_frame_list = best_models[1]
1375 score_list = best_models[2]
1376 feature_keyword_list_dict = best_models[3]
1382 if self.number_of_processes > 1:
1386 rmf_file_frame_list)
1387 for k
in feature_keyword_list_dict:
1388 feature_keyword_list_dict[k] = \
1390 feature_keyword_list_dict[k])
1393 score_rmf_tuples = list(zip(score_list,
1395 rmf_file_frame_list,
1396 list(range(len(score_list)))))
1398 if density_custom_ranges:
1399 for k
in density_custom_ranges:
1400 if not isinstance(density_custom_ranges[k], list):
1401 raise Exception(
"Density custom ranges: values must "
1402 "be lists of tuples")
1405 if first_and_last_frames
is not None:
1406 nframes = len(score_rmf_tuples)
1407 first_frame = int(first_and_last_frames[0] * nframes)
1408 last_frame = int(first_and_last_frames[1] * nframes)
1409 if last_frame > len(score_rmf_tuples):
1411 score_rmf_tuples = score_rmf_tuples[first_frame:last_frame]
1414 best_score_rmf_tuples = sorted(
1416 key=
lambda x: float(x[0]))[:number_of_best_scoring_models]
1417 best_score_rmf_tuples = [t+(n,)
for n, t
in
1418 enumerate(best_score_rmf_tuples)]
1420 prov.append(IMP.pmi.io.FilterProvenance(
1421 "Best scoring", 0, number_of_best_scoring_models))
1423 best_score_feature_keyword_list_dict = defaultdict(list)
1424 for tpl
in best_score_rmf_tuples:
1426 for f
in feature_keyword_list_dict:
1427 best_score_feature_keyword_list_dict[f].append(
1428 feature_keyword_list_dict[f][index])
1429 my_best_score_rmf_tuples = IMP.pmi.tools.chunk_list_into_segments(
1430 best_score_rmf_tuples,
1431 self.number_of_processes)[self.rank]
1434 prot_ahead = IMP.pmi.analysis.get_hiers_from_rmf(
1435 self.model, 0, my_best_score_rmf_tuples[0][1])[0]
1436 if rmsd_calculation_components
is not None:
1437 tmp = self._expand_ambiguity(
1438 prot_ahead, rmsd_calculation_components)
1439 if tmp != rmsd_calculation_components:
1440 print(
'Detected ambiguity, expand rmsd components to',
1442 rmsd_calculation_components = tmp
1443 if alignment_components
is not None:
1444 tmp = self._expand_ambiguity(prot_ahead,
1445 alignment_components)
1446 if tmp != alignment_components:
1447 print(
'Detected ambiguity, expand alignment '
1448 'components to', tmp)
1449 alignment_components = tmp
1455 self.model, my_best_score_rmf_tuples[0],
1456 rmsd_calculation_components, state_number=state_number)
1458 self.model, my_best_score_rmf_tuples, alignment_components,
1459 rmsd_calculation_components, state_number=state_number)
1467 all_coordinates = got_coords[0]
1470 alignment_coordinates = got_coords[1]
1473 rmsd_coordinates = got_coords[2]
1476 rmf_file_name_index_dict = got_coords[3]
1479 all_rmf_file_names = got_coords[4]
1485 if density_custom_ranges:
1487 density_custom_ranges, voxel=voxel_size)
1489 dircluster = os.path.join(outputdir,
1490 "all_models."+str(self.rank))
1496 os.mkdir(dircluster)
1499 clusstat = open(os.path.join(
1500 dircluster,
"stat."+str(self.rank)+
".out"),
"w")
1501 for cnt, tpl
in enumerate(my_best_score_rmf_tuples):
1503 rmf_frame_number = tpl[2]
1506 for key
in best_score_feature_keyword_list_dict:
1508 best_score_feature_keyword_list_dict[key][index]
1512 IMP.pmi.analysis.get_hiers_and_restraints_from_rmf(
1513 self.model, rmf_frame_number, rmf_name)
1515 linking_successful = \
1516 IMP.pmi.analysis.link_hiers_and_restraints_to_rmf(
1517 self.model, prots, rs, rmf_frame_number,
1519 if not linking_successful:
1525 states = IMP.atom.get_by_type(
1526 prots[0], IMP.atom.STATE_TYPE)
1527 prot = states[state_number]
1532 coords_f1 = alignment_coordinates[cnt]
1534 coords_f2 = alignment_coordinates[cnt]
1537 coords_f1, coords_f2)
1538 transformation = Ali.align()[1]
1552 rb = rbm.get_rigid_body()
1562 out_pdb_fn = os.path.join(
1563 dircluster, str(cnt)+
"."+str(self.rank)+
".pdb")
1564 out_rmf_fn = os.path.join(
1565 dircluster, str(cnt)+
"."+str(self.rank)+
".rmf3")
1566 o.init_pdb(out_pdb_fn, prot)
1567 tc = write_pdb_with_centered_coordinates
1568 o.write_pdb(out_pdb_fn,
1569 translate_to_geometric_center=tc)
1571 tmp_dict[
"local_pdb_file_name"] = \
1572 os.path.basename(out_pdb_fn)
1573 tmp_dict[
"rmf_file_full_path"] = rmf_name
1574 tmp_dict[
"local_rmf_file_name"] = \
1575 os.path.basename(out_rmf_fn)
1576 tmp_dict[
"local_rmf_frame_number"] = 0
1578 clusstat.write(str(tmp_dict)+
"\n")
1583 h.set_name(
"System")
1585 o.init_rmf(out_rmf_fn, [h], rs)
1587 o.write_rmf(out_rmf_fn)
1588 o.close_rmf(out_rmf_fn)
1590 if density_custom_ranges:
1591 DensModule.add_subunits_density(prot)
1593 if density_custom_ranges:
1594 DensModule.write_mrc(path=dircluster)
1599 if self.number_of_processes > 1:
1605 rmf_file_name_index_dict)
1607 alignment_coordinates)
1614 [best_score_feature_keyword_list_dict,
1615 rmf_file_name_index_dict],
1621 print(
"setup clustering class")
1624 for n, model_coordinate_dict
in enumerate(all_coordinates):
1626 if (alignment_components
is not None
1627 and len(self.cluster_obj.all_coords) == 0):
1629 self.cluster_obj.set_template(alignment_coordinates[n])
1630 self.cluster_obj.fill(all_rmf_file_names[n],
1631 rmsd_coordinates[n])
1632 print(
"Global calculating the distance matrix")
1635 self.cluster_obj.dist_matrix()
1639 self.cluster_obj.do_cluster(number_of_clusters)
1642 self.cluster_obj.plot_matrix(
1643 figurename=os.path.join(outputdir,
1645 if exit_after_display:
1647 self.cluster_obj.save_distance_matrix_file(
1648 file_name=distance_matrix_file)
1655 print(
"setup clustering class")
1657 self.cluster_obj.load_distance_matrix_file(
1658 file_name=distance_matrix_file)
1659 print(
"clustering with %s clusters" % str(number_of_clusters))
1660 self.cluster_obj.do_cluster(number_of_clusters)
1661 [best_score_feature_keyword_list_dict,
1662 rmf_file_name_index_dict] = self.load_objects(
".macro.pkl")
1665 self.cluster_obj.plot_matrix(figurename=os.path.join(
1666 outputdir,
'dist_matrix.pdf'))
1667 if exit_after_display:
1669 if self.number_of_processes > 1:
1677 print(self.cluster_obj.get_cluster_labels())
1678 for n, cl
in enumerate(self.cluster_obj.get_cluster_labels()):
1679 print(
"rank %s " % str(self.rank))
1680 print(
"cluster %s " % str(n))
1681 print(
"cluster label %s " % str(cl))
1682 print(self.cluster_obj.get_cluster_label_names(cl))
1684 len(self.cluster_obj.get_cluster_label_names(cl))
1686 prov + [IMP.pmi.io.ClusterProvenance(cluster_size)]
1689 if density_custom_ranges:
1691 density_custom_ranges,
1694 dircluster = outputdir +
"/cluster." + str(n) +
"/"
1696 os.mkdir(dircluster)
1702 str(self.cluster_obj.get_cluster_label_average_rmsd(cl))}
1703 clusstat = open(dircluster +
"stat.out",
"w")
1704 for k, structure_name
in enumerate(
1705 self.cluster_obj.get_cluster_label_names(cl)):
1708 tmp_dict.update(rmsd_dict)
1709 index = rmf_file_name_index_dict[structure_name]
1710 for key
in best_score_feature_keyword_list_dict:
1712 key] = best_score_feature_keyword_list_dict[
1718 rmf_name = structure_name.split(
"|")[0]
1719 rmf_frame_number = int(structure_name.split(
"|")[1])
1720 clusstat.write(str(tmp_dict) +
"\n")
1725 IMP.pmi.analysis.get_hiers_and_restraints_from_rmf(
1726 self.model, rmf_frame_number, rmf_name)
1728 linking_successful = \
1729 IMP.pmi.analysis.link_hiers_and_restraints_to_rmf(
1730 self.model, prots, rs, rmf_frame_number,
1732 if not linking_successful:
1737 states = IMP.atom.get_by_type(
1738 prots[0], IMP.atom.STATE_TYPE)
1739 prot = states[state_number]
1745 co = self.cluster_obj
1746 model_index = co.get_model_index_from_name(
1748 transformation = co.get_transformation_to_first_member(
1759 rb = rbm.get_rigid_body()
1768 if density_custom_ranges:
1769 DensModule.add_subunits_density(prot)
1774 o.init_pdb(dircluster + str(k) +
".pdb", prot)
1775 o.write_pdb(dircluster + str(k) +
".pdb")
1780 h.set_name(
"System")
1782 o.init_rmf(dircluster + str(k) +
".rmf3", [h], rs)
1783 o.write_rmf(dircluster + str(k) +
".rmf3")
1784 o.close_rmf(dircluster + str(k) +
".rmf3")
1789 if density_custom_ranges:
1790 DensModule.write_mrc(path=dircluster)
1793 if self.number_of_processes > 1:
1796 def get_cluster_rmsd(self, cluster_num):
1797 if self.cluster_obj
is None:
1799 return self.cluster_obj.get_cluster_label_average_rmsd(cluster_num)
1801 def save_objects(self, objects, file_name):
1803 with open(file_name,
'wb')
as outf:
1804 pickle.dump(objects, outf)
1806 def load_objects(self, file_name):
1808 with open(file_name,
'rb')
as inputf:
1809 objects = pickle.load(inputf)
1816 This class contains analysis utilities to investigate ReplicaExchange
1824 def __init__(self, model, stat_files, best_models=None, score_key=None,
1827 Construction of the Class.
1828 @param model IMP.Model()
1829 @param stat_files list of string. Can be ascii stat files,
1831 @param best_models Integer. Number of best scoring models,
1832 if None: all models will be read
1833 @param score_key Use the provided stat key keyword as the score
1834 (by default, the total score is used)
1835 @param alignment boolean (Default=True). Align before computing
1840 self.best_models = best_models
1842 model, stat_files, self.best_models, score_key, cache=
True)
1844 StatHierarchyHandler=self.stath0)
1857 self.clusters.append(c)
1858 for n0
in range(len(self.stath0)):
1860 self.pairwise_rmsd = {}
1861 self.pairwise_molecular_assignment = {}
1862 self.alignment = alignment
1863 self.symmetric_molecules = {}
1864 self.issymmetricsel = {}
1866 self.molcopydict0 = IMP.pmi.tools.get_molecules_dictionary_by_copy(
1868 self.molcopydict1 = IMP.pmi.tools.get_molecules_dictionary_by_copy(
1873 Setup the selection onto which the rmsd is computed
1874 @param kwargs use IMP.atom.Selection keywords
1882 Store names of symmetric molecules
1884 self.symmetric_molecules[molecule_name] = 0
1889 Setup the selection onto which the alignment is computed
1890 @param kwargs use IMP.atom.Selection keywords
1898 def clean_clusters(self):
1899 for c
in self.clusters:
1903 def cluster(self, rmsd_cutoff=10, metric=IMP.atom.get_rmsd):
1905 Cluster the models based on RMSD.
1906 @param rmsd_cutoff Float the distance cutoff in Angstrom
1907 @param metric (Default=IMP.atom.get_rmsd) the metric that will
1908 be used to compute rmsds
1910 self.clean_clusters()
1911 not_clustered = set(range(len(self.stath1)))
1912 while len(not_clustered) > 0:
1913 self.
aggregate(not_clustered, rmsd_cutoff, metric)
1918 Refine the clusters by merging the ones whose centers are close
1919 @param rmsd_cutoff cutoff distance in Angstorms
1921 clusters_copy = self.clusters
1922 for c0, c1
in itertools.combinations(self.clusters, 2):
1923 if c0.center_index
is None:
1925 if c1.center_index
is None:
1927 _ = self.stath0[c0.center_index]
1928 _ = self.stath1[c1.center_index]
1929 rmsd, molecular_assignment = self.
rmsd()
1930 if rmsd <= rmsd_cutoff:
1931 if c1
in self.clusters:
1932 clusters_copy.remove(c1)
1934 self.clusters = clusters_copy
1941 def set_cluster_assignments(self, cluster_ids):
1942 if len(cluster_ids) != len(self.stath0):
1943 raise ValueError(
'cluster ids has to be same length as '
1947 for i
in sorted(list(set(cluster_ids))):
1949 for i, (idx, d)
in enumerate(zip(cluster_ids, self.stath0)):
1950 self.clusters[idx].add_member(i, d)
1954 Return the model data from a cluster
1955 @param cluster IMP.pmi.output.Cluster object
1964 Save the data for the whole models into a pickle file
1965 @param filename string
1967 self.stath0.save_data(filename)
1971 Set the data from an external IMP.pmi.output.Data
1972 @param data IMP.pmi.output.Data
1974 self.stath0.data = data
1975 self.stath1.data = data
1979 Load the data from an external pickled file
1980 @param filename string
1982 self.stath0.load_data(filename)
1983 self.stath1.load_data(filename)
1984 self.best_models = len(self.stath0)
1986 def add_cluster(self, rmf_name_list):
1988 print(
"creating cluster index "+str(len(self.clusters)))
1989 self.clusters.append(c)
1990 current_len = len(self.stath0)
1992 for rmf
in rmf_name_list:
1993 print(
"adding rmf "+rmf)
1994 self.stath0.add_stat_file(rmf)
1995 self.stath1.add_stat_file(rmf)
1997 for n0
in range(current_len, len(self.stath0)):
1998 d0 = self.stath0[n0]
1999 c.add_member(n0, d0)
2004 Save the clusters into a pickle file
2005 @param filename string
2008 with open(filename,
'wb')
as fl:
2009 pickle.dump(self.clusters, fl)
2013 Load the clusters from a pickle file
2014 @param filename string
2015 @param append bool (Default=False), if True. append the clusters
2016 to the ones currently present
2019 self.clean_clusters()
2020 with open(filename,
'rb')
as fl:
2022 self.clusters += pickle.load(fl)
2024 self.clusters = pickle.load(fl)
2033 Compute the cluster center for a given cluster
2035 member_distance = defaultdict(float)
2037 for n0, n1
in itertools.combinations(cluster.members, 2):
2040 rmsd, _ = self.
rmsd()
2041 member_distance[n0] += rmsd
2043 if len(member_distance) > 0:
2044 cluster.center_index = min(member_distance,
2045 key=member_distance.get)
2047 cluster.center_index = cluster.members[0]
2052 Save the coordinates of the current cluster a single rmf file
2054 print(
"saving coordinates", cluster)
2058 if rmf_name
is None:
2059 rmf_name = prefix+
'/'+str(cluster.cluster_id)+
".rmf3"
2061 _ = self.stath1[cluster.members[0]]
2063 o.init_rmf(rmf_name, [self.stath1])
2064 for n1
in cluster.members:
2070 o.write_rmf(rmf_name)
2072 o.close_rmf(rmf_name)
2076 remove structures that are similar
2077 append it to a new cluster
2079 print(
"pruning models")
2081 filtered = [selected]
2082 remaining = range(1, len(self.stath1), 10)
2084 while len(remaining) > 0:
2085 d0 = self.stath0[selected]
2087 for n1
in remaining:
2092 if d <= rmsd_cutoff:
2094 print(
"pruning model %s, similar to model %s, rmsd %s"
2095 % (str(n1), str(selected), str(d)))
2096 remaining = [x
for x
in remaining
if x
not in rm]
2097 if len(remaining) == 0:
2099 selected = remaining[0]
2100 filtered.append(selected)
2103 self.clusters.append(c)
2105 d0 = self.stath0[n0]
2106 c.add_member(n0, d0)
2111 Compute the precision of a cluster
2117 if cluster.center_index
is not None:
2118 members1 = [cluster.center_index]
2120 members1 = cluster.members
2124 for n1
in cluster.members:
2129 tmp_rmsd, _ = self.
rmsd()
2134 precision = rmsd/npairs
2135 cluster.precision = precision
2140 Compute the bipartite precision (ie the cross-precision)
2141 between two clusters
2145 for cn0, n0
in enumerate(cluster1.members):
2147 for cn1, n1
in enumerate(cluster2.members):
2149 tmp_rmsd, _ = self.
rmsd()
2151 print(
"--- rmsd between structure %s and structure "
2152 "%s is %s" % (str(cn0), str(cn1), str(tmp_rmsd)))
2155 precision = rmsd/npairs
2158 def rmsf(self, cluster, molecule, copy_index=0, state_index=0,
2159 cluster_ref=
None, step=1):
2161 Compute the Root mean square fluctuations
2162 of a molecule in a cluster
2163 Returns an IMP.pmi.tools.OrderedDict() where the keys are the
2164 residue indexes and the value is the rmsf
2166 rmsf = IMP.pmi.tools.OrderedDict()
2169 if cluster_ref
is not None:
2170 if cluster_ref.center_index
is not None:
2171 members0 = [cluster_ref.center_index]
2173 members0 = cluster_ref.members
2175 if cluster.center_index
is not None:
2176 members0 = [cluster.center_index]
2178 members0 = cluster.members
2181 copy_index=copy_index, state_index=state_index)
2182 ps0 = s0.get_selected_particles()
2184 residue_indexes = list(IMP.pmi.tools.OrderedSet(
2190 d0 = self.stath0[n0]
2191 for n1
in cluster.members[::step]:
2193 print(
"--- rmsf %s %s" % (str(n0), str(n1)))
2197 self.stath1, molecule=molecule,
2198 residue_indexes=residue_indexes, resolution=1,
2199 copy_index=copy_index, state_index=state_index)
2200 ps1 = s1.get_selected_particles()
2202 d1 = self.stath1[n1]
2205 for n, (p0, p1)
in enumerate(zip(ps0, ps1)):
2206 r = residue_indexes[n]
2218 for stath
in [self.stath0, self.stath1]:
2219 if molecule
not in self.symmetric_molecules:
2221 stath, molecule=molecule, residue_index=r,
2222 resolution=1, copy_index=copy_index,
2223 state_index=state_index)
2226 stath, molecule=molecule, residue_index=r,
2227 resolution=1, state_index=state_index)
2229 ps = s.get_selected_particles()
2238 def save_densities(self, cluster, density_custom_ranges, voxel_size=5,
2239 reference=
"Absolute", prefix=
"./", step=1):
2245 for n1
in cluster.members[::step]:
2246 print(
"density "+str(n1))
2251 dens.add_subunits_density(self.stath1)
2253 dens.write_mrc(path=prefix+
'/', suffix=str(cluster.cluster_id))
2256 def contact_map(self, cluster, contact_threshold=15, log_scale=False,
2257 consolidate=
False, molecules=
None, prefix=
'./',
2258 reference=
"Absolute"):
2262 import matplotlib.pyplot
as plt
2263 import matplotlib.cm
as cm
2264 from scipy.spatial.distance
import cdist
2266 if molecules
is None:
2275 molecules=molecules).get_selected_particles())]
2276 unique_copies = [mol
for mol
in mols
if mol.get_copy_index() == 0]
2277 mol_names_unique = dict((mol.get_name(), mol)
for mol
in unique_copies)
2278 total_len_unique = sum(max(mol.get_residue_indexes())
2279 for mol
in unique_copies)
2286 seqlen = max(mol.get_residue_indexes())
2287 index_dict[mol] = range(prev_stop, prev_stop + seqlen)
2291 for mol
in unique_copies:
2292 seqlen = max(mol.get_residue_indexes())
2293 index_dict[mol] = range(prev_stop, prev_stop + seqlen)
2296 for ncl, n1
in enumerate(cluster.members):
2299 coord_dict = IMP.pmi.tools.OrderedDict()
2301 rindexes = mol.get_residue_indexes()
2302 coords = np.ones((max(rindexes), 3))
2303 for rnum
in rindexes:
2306 selpart = sel.get_selected_particles()
2307 if len(selpart) == 0:
2309 selpart = selpart[0]
2310 coords[rnum - 1, :] = \
2312 coord_dict[mol] = coords
2315 coords = np.concatenate(list(coord_dict.values()))
2316 dists = cdist(coords, coords)
2317 binary_dists = np.where((dists <= contact_threshold)
2318 & (dists >= 1.0), 1.0, 0.0)
2320 binary_dists_dict = {}
2322 len1 = max(mol1.get_residue_indexes())
2324 name1 = mol1.get_name()
2325 name2 = mol2.get_name()
2326 dists = cdist(coord_dict[mol1], coord_dict[mol2])
2327 if (name1, name2)
not in binary_dists_dict:
2328 binary_dists_dict[(name1, name2)] = \
2329 np.zeros((len1, len1))
2330 binary_dists_dict[(name1, name2)] += \
2331 np.where((dists <= contact_threshold)
2332 & (dists >= 1.0), 1.0, 0.0)
2333 binary_dists = np.zeros((total_len_unique, total_len_unique))
2335 for name1, name2
in binary_dists_dict:
2336 r1 = index_dict[mol_names_unique[name1]]
2337 r2 = index_dict[mol_names_unique[name2]]
2338 binary_dists[min(r1):max(r1)+1, min(r2):max(r2)+1] = \
2339 np.where((binary_dists_dict[(name1, name2)] >= 1.0),
2345 contact_freqs = binary_dists
2347 dist_maps.append(dists)
2348 av_dist_map += dists
2349 contact_freqs += binary_dists
2352 contact_freqs = -np.log(1.0-1.0/(len(cluster)+1)*contact_freqs)
2354 contact_freqs = 1.0/len(cluster)*contact_freqs
2355 av_dist_map = 1.0/len(cluster)*contact_freqs
2357 fig = plt.figure(figsize=(100, 100))
2358 ax = fig.add_subplot(111)
2361 gap_between_components = 50
2366 sorted_tuple = sorted(
2368 mol).get_extended_name(), mol)
for mol
in mols)
2369 prot_list = list(zip(*sorted_tuple))[1]
2371 sorted_tuple = sorted(
2373 for mol
in unique_copies)
2374 prot_list = list(zip(*sorted_tuple))[1]
2376 prot_listx = prot_list
2377 nresx = gap_between_components + \
2378 sum([max(mol.get_residue_indexes())
2379 + gap_between_components
for mol
in prot_listx])
2382 prot_listy = prot_list
2383 nresy = gap_between_components + \
2384 sum([max(mol.get_residue_indexes())
2385 + gap_between_components
for mol
in prot_listy])
2390 res = gap_between_components
2391 for mol
in prot_listx:
2392 resoffsetx[mol] = res
2393 res += max(mol.get_residue_indexes())
2395 res += gap_between_components
2399 res = gap_between_components
2400 for mol
in prot_listy:
2401 resoffsety[mol] = res
2402 res += max(mol.get_residue_indexes())
2404 res += gap_between_components
2406 resoffsetdiagonal = {}
2407 res = gap_between_components
2408 for mol
in IMP.pmi.tools.OrderedSet(prot_listx + prot_listy):
2409 resoffsetdiagonal[mol] = res
2410 res += max(mol.get_residue_indexes())
2411 res += gap_between_components
2416 for n, prot
in enumerate(prot_listx):
2417 res = resoffsetx[prot]
2419 for proty
in prot_listy:
2420 resy = resoffsety[proty]
2421 endy = resendy[proty]
2422 ax.plot([res, res], [resy, endy], linestyle=
'-',
2423 color=
'gray', lw=0.4)
2424 ax.plot([end, end], [resy, endy], linestyle=
'-',
2425 color=
'gray', lw=0.4)
2426 xticks.append((float(res) + float(end)) / 2)
2428 prot).get_extended_name())
2432 for n, prot
in enumerate(prot_listy):
2433 res = resoffsety[prot]
2435 for protx
in prot_listx:
2436 resx = resoffsetx[protx]
2437 endx = resendx[protx]
2438 ax.plot([resx, endx], [res, res], linestyle=
'-',
2439 color=
'gray', lw=0.4)
2440 ax.plot([resx, endx], [end, end], linestyle=
'-',
2441 color=
'gray', lw=0.4)
2442 yticks.append((float(res) + float(end)) / 2)
2444 prot).get_extended_name())
2448 tmp_array = np.zeros((nresx, nresy))
2450 for px
in prot_listx:
2451 for py
in prot_listy:
2452 resx = resoffsetx[px]
2453 lengx = resendx[px] - 1
2454 resy = resoffsety[py]
2455 lengy = resendy[py] - 1
2456 indexes_x = index_dict[px]
2457 minx = min(indexes_x)
2458 maxx = max(indexes_x)
2459 indexes_y = index_dict[py]
2460 miny = min(indexes_y)
2461 maxy = max(indexes_y)
2462 tmp_array[resx:lengx, resy:lengy] = \
2463 contact_freqs[minx:maxx, miny:maxy]
2464 ret[(px, py)] = np.argwhere(
2465 contact_freqs[minx:maxx, miny:maxy] == 1.0) + 1
2467 ax.imshow(tmp_array, cmap=colormap, norm=colornorm,
2468 origin=
'lower', alpha=0.6, interpolation=
'nearest')
2470 ax.set_xticks(xticks)
2471 ax.set_xticklabels(xlabels, rotation=90)
2472 ax.set_yticks(yticks)
2473 ax.set_yticklabels(ylabels)
2474 plt.setp(ax.get_xticklabels(), fontsize=6)
2475 plt.setp(ax.get_yticklabels(), fontsize=6)
2478 fig.set_size_inches(0.005 * nresx, 0.005 * nresy)
2479 [i.set_linewidth(2.0)
for i
in ax.spines.values()]
2481 plt.savefig(prefix+
"/contact_map."+str(cluster.cluster_id)+
".pdf",
2482 dpi=300, transparent=
"False")
2485 def plot_rmsd_matrix(self, filename):
2486 self.compute_all_pairwise_rmsd()
2487 distance_matrix = np.zeros(
2488 (len(self.stath0), len(self.stath1)))
2489 for (n0, n1)
in self.pairwise_rmsd:
2490 distance_matrix[n0, n1] = self.pairwise_rmsd[(n0, n1)]
2492 import matplotlib
as mpl
2494 import matplotlib.pylab
as pl
2495 from scipy.cluster
import hierarchy
as hrc
2497 fig = pl.figure(figsize=(10, 8))
2498 ax = fig.add_subplot(212)
2499 dendrogram = hrc.dendrogram(
2500 hrc.linkage(distance_matrix),
2503 leaves_order = dendrogram[
'leaves']
2504 ax.set_xlabel(
'Model')
2505 ax.set_ylabel(
'RMSD [Angstroms]')
2507 ax2 = fig.add_subplot(221)
2509 distance_matrix[leaves_order, :][:, leaves_order],
2510 interpolation=
'nearest')
2511 cb = fig.colorbar(cax)
2512 cb.set_label(
'RMSD [Angstroms]')
2513 ax2.set_xlabel(
'Model')
2514 ax2.set_ylabel(
'Model')
2516 pl.savefig(filename, dpi=300)
2525 Update the cluster id numbers
2527 for n, c
in enumerate(self.clusters):
2530 def get_molecule(self, hier, name, copy):
2538 self.seldict0 = IMP.pmi.tools.get_selections_dictionary(
2539 self.sel0_rmsd.get_selected_particles())
2540 self.seldict1 = IMP.pmi.tools.get_selections_dictionary(
2541 self.sel1_rmsd.get_selected_particles())
2542 for mol
in self.seldict0:
2543 for sel
in self.seldict0[mol]:
2544 self.issymmetricsel[sel] =
False
2545 for mol
in self.symmetric_molecules:
2546 self.symmetric_molecules[mol] = len(self.seldict0[mol])
2547 for sel
in self.seldict0[mol]:
2548 self.issymmetricsel[sel] =
True
2552 self.sel1_alignment, self.sel0_alignment)
2554 for rb
in self.rbs1:
2557 for bead
in self.beads1:
2565 def aggregate(self, idxs, rmsd_cutoff=10, metric=IMP.atom.get_rmsd):
2567 initial filling of the clusters.
2570 print(
"clustering model "+str(n0))
2571 d0 = self.stath0[n0]
2573 print(
"creating cluster index "+str(len(self.clusters)))
2574 self.clusters.append(c)
2575 c.add_member(n0, d0)
2576 clustered = set([n0])
2578 print(
"--- trying to add model " + str(n1) +
" to cluster "
2579 + str(len(self.clusters)))
2580 d1 = self.stath1[n1]
2583 rmsd, _ = self.
rmsd(metric=metric)
2584 if rmsd < rmsd_cutoff:
2585 print(
"--- model "+str(n1)+
" added, rmsd="+str(rmsd))
2586 c.add_member(n1, d1)
2589 print(
"--- model "+str(n1)+
" NOT added, rmsd="+str(rmsd))
2594 merge the clusters that have close members
2596 @param rmsd_cutoff cutoff distance in Angstorms
2597 @param metric Function to calculate distance between two Selections
2598 (by default, IMP.atom.get_rmsd is used)
2606 for c0, c1
in filter(
lambda x: len(x[0].members) > 1,
2607 itertools.combinations(self.clusters, 2)):
2608 n0, n1 = [c.members[0]
for c
in (c0, c1)]
2611 rmsd, _ = self.
rmsd()
2612 if (rmsd < 2*rmsd_cutoff
and
2614 to_merge.append((c0, c1))
2616 for c0, c
in reversed(to_merge):
2620 self.clusters = [c
for c
in
2621 filter(
lambda x: len(x.members) > 0, self.clusters)]
2625 returns true if c0 and c1 have members that are closer than rmsd_cutoff
2627 print(
"check close members for clusters " + str(c0.cluster_id) +
2628 " and " + str(c1.cluster_id))
2629 for n0, n1
in itertools.product(c0.members[1:], c1.members):
2632 rmsd, _ = self.
rmsd(metric=metric)
2633 if rmsd < rmsd_cutoff:
2648 a function that returns the permutation best_sel of sels0 that
2651 best_rmsd2 = float(
'inf')
2653 if self.issymmetricsel[sels0[0]]:
2656 for offset
in range(N):
2657 sels = [sels0[(offset+i) % N]
for i
in range(N)]
2660 r = metric(sel0, sel1)
2662 if rmsd2 < best_rmsd2:
2666 for sels
in itertools.permutations(sels0):
2668 for sel0, sel1
in itertools.takewhile(
2669 lambda x: rmsd2 < best_rmsd2, zip(sels, sels1)):
2670 r = metric(sel0, sel1)
2672 if rmsd2 < best_rmsd2:
2675 return best_sel, best_rmsd2
2677 def compute_all_pairwise_rmsd(self):
2678 for d0
in self.stath0:
2679 for d1
in self.stath1:
2680 rmsd, _ = self.
rmsd()
2682 def rmsd(self, metric=IMP.atom.get_rmsd):
2684 Computes the RMSD. Resolves ambiguous pairs assignments
2688 n0 = self.stath0.current_index
2689 n1 = self.stath1.current_index
2690 if ((n0, n1)
in self.pairwise_rmsd) \
2691 and ((n0, n1)
in self.pairwise_molecular_assignment):
2692 return (self.pairwise_rmsd[(n0, n1)],
2693 self.pairwise_molecular_assignment[(n0, n1)])
2703 molecular_assignment = {}
2704 for molname, sels0
in self.seldict0.items():
2705 sels_best_order, best_rmsd2 = \
2706 self.
rmsd_helper(sels0, self.seldict1[molname], metric)
2708 Ncoords = len(sels_best_order[0].get_selected_particles())
2709 Ncopies = len(self.seldict1[molname])
2710 total_rmsd += Ncoords*best_rmsd2
2711 total_N += Ncoords*Ncopies
2713 for sel0, sel1
in zip(sels_best_order, self.seldict1[molname]):
2714 p0 = sel0.get_selected_particles()[0]
2715 p1 = sel1.get_selected_particles()[0]
2720 molecular_assignment[(molname, c0)] = (molname, c1)
2722 total_rmsd = math.sqrt(total_rmsd/total_N)
2724 self.pairwise_rmsd[(n0, n1)] = total_rmsd
2725 self.pairwise_molecular_assignment[(n0, n1)] = molecular_assignment
2726 self.pairwise_rmsd[(n1, n0)] = total_rmsd
2727 self.pairwise_molecular_assignment[(n1, n0)] = molecular_assignment
2728 return total_rmsd, molecular_assignment
2732 Fix the reference structure for structural alignment, rmsd and
2735 @param reference can be either "Absolute" (cluster center of the
2736 first cluster) or Relative (cluster center of the current
2738 #param cluster the reference IMP.pmi.output.Cluster object
2740 if reference ==
"Absolute":
2742 elif reference ==
"Relative":
2743 if cluster.center_index:
2744 n0 = cluster.center_index
2746 n0 = cluster.members[0]
2751 compute the molecular assignments between multiple copies
2752 of the same sequence. It changes the Copy index of Molecules
2755 _, molecular_assignment = self.
rmsd()
2756 for (m0, c0), (m1, c1)
in molecular_assignment.items():
2757 mol0 = self.molcopydict0[m0][c0]
2758 mol1 = self.molcopydict1[m1][c1]
2761 p1.set_value(cik0, c0)
2765 Undo the Copy index assignment
2768 _, molecular_assignment = self.
rmsd()
2769 for (m0, c0), (m1, c1)
in molecular_assignment.items():
2770 mol0 = self.molcopydict0[m0][c0]
2771 mol1 = self.molcopydict1[m1][c1]
2774 p1.set_value(cik0, c1)
2781 s =
"AnalysisReplicaExchange\n"
2782 s +=
"---- number of clusters %s \n" % str(len(self.clusters))
2783 s +=
"---- number of models %s \n" % str(len(self.stath0))
2786 def __getitem__(self, int_slice_adaptor):
2787 if isinstance(int_slice_adaptor, int):
2788 return self.clusters[int_slice_adaptor]
2789 elif isinstance(int_slice_adaptor, slice):
2790 return self.__iter__(int_slice_adaptor)
2792 raise TypeError(
"Unknown Type")
2795 return len(self.clusters)
2797 def __iter__(self, slice_key=None):
2798 if slice_key
is None:
2799 for i
in range(len(self)):
2802 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
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.
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.