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'
100 r = _RestartRun(rex, frame, rex_stats)
101 with open(fname,
'wb')
as fh:
104 restarted = property(
lambda self: self._number > 0,
105 doc=
"True iff this simulation has been restarted")
109 """Information about a restarted simulation (usually pickled)"""
110 def __init__(self, rex, frame, rex_stats):
113 self._pck_info = (rex.model, rex)
114 self._rstate = IMP.random_number_generator.get_state()
116 self._rex_stats = rex_stats
118 def execute_macro(self):
119 """Restart the interrupted replica exchange simulation"""
120 m, rex = self._pck_info
121 IMP.random_number_generator.set_state(self._rstate)
122 rex._restart_from_frame = self._frame
123 rex._rex_stats = self._rex_stats
124 return rex.execute_macro()
126 def get_number_of_replicas(self):
127 rex = self._pck_info[1]
128 return rex.replica_exchange_object.get_number_of_replicas()
132 """A macro to help setup and run replica exchange.
133 Supports Monte Carlo and molecular dynamics.
134 Produces trajectory RMF files, best PDB structures,
135 and output stat files.
137 def __init__(self, model, root_hier,
138 monte_carlo_sample_objects=
None,
139 molecular_dynamics_sample_objects=
None,
141 rmf_output_objects=
None,
142 monte_carlo_temperature=1.0,
143 simulated_annealing=
False,
144 simulated_annealing_minimum_temperature=1.0,
145 simulated_annealing_maximum_temperature=2.5,
146 simulated_annealing_minimum_temperature_nframes=100,
147 simulated_annealing_maximum_temperature_nframes=100,
148 replica_exchange_minimum_temperature=1.0,
149 replica_exchange_maximum_temperature=2.5,
150 replica_exchange_swap=
True,
152 number_of_best_scoring_models=500,
153 monte_carlo_steps=10,
155 molecular_dynamics_steps=10,
156 molecular_dynamics_max_time_step=1.0,
157 number_of_frames=1000,
158 save_coordinates_mode=
"lowest_temperature",
159 nframes_write_coordinates=1,
160 write_initial_rmf=
True,
161 initial_rmf_name_suffix=
"initial",
162 stat_file_name_suffix=
"stat",
163 best_pdb_name_suffix=
"model",
166 do_create_directories=
True,
167 global_output_directory=
"./",
169 best_pdb_dir=
"pdbs/",
170 replica_stat_file_suffix=
"stat_replica",
171 em_object_for_rmf=
None,
173 replica_exchange_object=
None,
177 nestor_restraints=
None,
178 nestor_rmf_fname_prefix=
"nested",
181 @param model The IMP model
182 @param root_hier Top-level (System)hierarchy
183 @param monte_carlo_sample_objects Objects for MC sampling, which
184 should generally be a simple list of Mover objects, e.g.
185 from DegreesOfFreedom.get_movers().
186 @param molecular_dynamics_sample_objects Objects for MD sampling,
187 which should generally be a simple list of particles.
188 @param output_objects A list of structural objects and restraints
189 that will be included in output (ie, statistics "stat"
190 files). Any object that provides a get_output() method
191 can be used here. If None is passed
192 the macro will not write stat files.
193 @param rmf_output_objects A list of structural objects and
194 restraints that will be included in rmf. Any object
195 that provides a get_output() method can be used here.
196 @param monte_carlo_temperature MC temp (may need to be optimized
197 based on post-sampling analysis)
198 @param simulated_annealing If True, perform simulated annealing
199 @param simulated_annealing_minimum_temperature Should generally be
200 the same as monte_carlo_temperature.
201 @param simulated_annealing_minimum_temperature_nframes Number of
202 frames to compute at minimum temperature.
203 @param simulated_annealing_maximum_temperature_nframes Number of
205 temps > simulated_annealing_maximum_temperature.
206 @param replica_exchange_minimum_temperature Low temp for REX; should
207 generally be the same as monte_carlo_temperature.
208 @param replica_exchange_maximum_temperature High temp for REX
209 @param replica_exchange_swap Boolean, enable disable temperature
211 @param num_sample_rounds Number of rounds of MC/MD per cycle
212 @param number_of_best_scoring_models Number of top-scoring PDB/mmCIF
213 models to keep around for analysis.
214 @param mmcif If True, write best scoring models in mmCIF format;
215 if False (the default), write in legacy PDB format.
216 @param best_pdb_dir The directory under `global_output_directory`
217 where best-scoring PDB/mmCIF files are written.
218 @param best_pdb_name_suffix Part of the file name for best-scoring
220 @param monte_carlo_steps Number of MC steps per round
221 @param self_adaptive self adaptive scheme for Monte Carlo movers
222 @param molecular_dynamics_steps Number of MD steps per round
223 @param molecular_dynamics_max_time_step Max time step for MD
224 @param number_of_frames Number of REX frames to run
225 @param save_coordinates_mode string: how to save coordinates.
226 "lowest_temperature" (default) only the lowest temperatures
228 "25th_score" all replicas whose score is below the 25th
230 "50th_score" all replicas whose score is below the 50th
232 "75th_score" all replicas whose score is below the 75th
234 @param nframes_write_coordinates How often to write the coordinates
236 @param write_initial_rmf Write the initial configuration
237 @param global_output_directory Folder that will be created to house
239 @param test_mode Set to True to avoid writing any files, just test
241 @param score_moved If True, attempt to speed up Monte Carlo
242 sampling by caching scoring function terms on particles
244 @param use_nestor If True, follows the Nested Sampling workflow
245 of the NestOR module and skips writing stat files and
247 @param nestor_restraints A list of restraints for which
248 likelihoods are to be computed for use by NestOR module.
249 @param nestor_rmf_fname_prefix Prefix to be used for storing .rmf3
250 files generated by NestOR .
251 @param use_jax If set to True, sample the scoring function using
252 JAX instead of IMP's internal C++ implementation (requires
253 that all PMI restraints used have a JAX implementation).
258 self._restart_from_frame = 0
261 if output_objects == []:
264 self.output_objects = []
266 self.output_objects = output_objects
267 self.rmf_output_objects = rmf_output_objects
269 and not root_hier.get_parent()):
270 if self.output_objects
is not None:
271 self.output_objects.append(
273 if self.rmf_output_objects
is not None:
274 self.rmf_output_objects.append(
276 self.root_hier = root_hier
277 states = IMP.atom.get_by_type(root_hier, IMP.atom.STATE_TYPE)
278 self.vars[
"number_of_states"] = len(states)
280 self.root_hiers = states
281 self.is_multi_state =
True
283 self.root_hier = root_hier
284 self.is_multi_state =
False
286 raise TypeError(
"Must provide System hierarchy (root_hier)")
288 self._rmf_restraints = _RMFRestraints(model,
None)
289 self.em_object_for_rmf = em_object_for_rmf
290 self.monte_carlo_sample_objects = monte_carlo_sample_objects
291 self.vars[
"self_adaptive"] = self_adaptive
292 self.molecular_dynamics_sample_objects = \
293 molecular_dynamics_sample_objects
294 self.replica_exchange_object = replica_exchange_object
295 self.molecular_dynamics_max_time_step = \
296 molecular_dynamics_max_time_step
297 self.vars[
"monte_carlo_temperature"] = monte_carlo_temperature
298 self.vars[
"replica_exchange_minimum_temperature"] = \
299 replica_exchange_minimum_temperature
300 self.vars[
"replica_exchange_maximum_temperature"] = \
301 replica_exchange_maximum_temperature
302 self.vars[
"replica_exchange_swap"] = replica_exchange_swap
303 self.vars[
"simulated_annealing"] = simulated_annealing
304 self.vars[
"simulated_annealing_minimum_temperature"] = \
305 simulated_annealing_minimum_temperature
306 self.vars[
"simulated_annealing_maximum_temperature"] = \
307 simulated_annealing_maximum_temperature
308 self.vars[
"simulated_annealing_minimum_temperature_nframes"] = \
309 simulated_annealing_minimum_temperature_nframes
310 self.vars[
"simulated_annealing_maximum_temperature_nframes"] = \
311 simulated_annealing_maximum_temperature_nframes
313 self.vars[
"num_sample_rounds"] = num_sample_rounds
315 "number_of_best_scoring_models"] = number_of_best_scoring_models
316 self.vars[
"monte_carlo_steps"] = monte_carlo_steps
317 self.vars[
"molecular_dynamics_steps"] = molecular_dynamics_steps
318 self.vars[
"number_of_frames"] = number_of_frames
319 if save_coordinates_mode
not in (
"lowest_temperature",
"25th_score",
320 "50th_score",
"75th_score"):
321 raise Exception(
"save_coordinates_mode has unrecognized value")
323 self.vars[
"save_coordinates_mode"] = save_coordinates_mode
324 self.vars[
"nframes_write_coordinates"] = nframes_write_coordinates
325 self.vars[
"write_initial_rmf"] = write_initial_rmf
326 self.vars[
"initial_rmf_name_suffix"] = initial_rmf_name_suffix
327 self.vars[
"best_pdb_name_suffix"] = best_pdb_name_suffix
328 self.vars[
"mmcif"] = mmcif
329 self.vars[
"stat_file_name_suffix"] = stat_file_name_suffix
330 self.vars[
"do_clean_first"] = do_clean_first
331 self.vars[
"do_create_directories"] = do_create_directories
332 self.vars[
"global_output_directory"] = global_output_directory
333 self.vars[
"rmf_dir"] = rmf_dir
334 self.vars[
"best_pdb_dir"] = best_pdb_dir
335 self.vars[
"atomistic"] = atomistic
336 self.vars[
"replica_stat_file_suffix"] = replica_stat_file_suffix
337 self.vars[
"geometries"] =
None
338 self.test_mode = test_mode
339 self.score_moved = score_moved
340 self.use_jax = use_jax
341 self.vars[
"use_nestor"] = self.nest = use_nestor
342 self.nestor_restraints = nestor_restraints
343 self.nestor_rmf_fname = nestor_rmf_fname_prefix
346 """Enable a simulation to be restarted if it is interrupted.
348 If enabled, restart files containing a complete description of
349 the IMP system are written periodically during the simulation.
350 If the simulation is interrupted, it can be restarted using
351 the restart_replica_exchange function, which reads these files.
353 @param frames How often a restart file should be written
354 (number of frames), or zero to not write restart files
355 @param restart_dir The directory under `global_output_directory`
356 where restart files are written.
361 self._restart = _RestartInfo(frames, restart_dir)
364 if self.vars[
"geometries"]
is None:
365 self.vars[
"geometries"] = list(geometries)
367 self.vars[
"geometries"].extend(geometries)
370 print(
"ReplicaExchange: it generates initial.*.rmf3, stat.*.out, "
371 "rmfs/*.rmf3 for each replica ")
372 print(
"--- it stores the best scoring pdb models in pdbs/")
373 print(
"--- the stat.*.out and rmfs/*.rmf3 are saved only at the "
374 "lowest temperature")
375 if self._restart
and self._restart.restarted:
376 print(
"--- this is a restart of a failed simulation")
377 print(
"--- variables:")
378 for k, v
in sorted(self.vars.items(), key=itemgetter(0)):
379 print(
"------", k.ljust(30), v)
381 def get_replica_exchange_object(self):
382 return self.replica_exchange_object
384 def _add_provenance(self, sampler_md, sampler_mc):
385 """Record details about the sampling in the IMP Hierarchies"""
388 method =
"Molecular Dynamics"
389 iterations += self.vars[
"molecular_dynamics_steps"]
391 method =
"Hybrid MD/MC" if sampler_md
else "Monte Carlo"
392 iterations += self.vars[
"monte_carlo_steps"]
394 if iterations == 0
or self.vars[
"number_of_frames"] == 0:
396 iterations *= self.vars[
"num_sample_rounds"]
398 pi = self.model.add_particle(
"sampling")
400 self.model, pi, method, self.vars[
"number_of_frames"],
402 p.set_number_of_replicas(
403 self.replica_exchange_object.get_number_of_replicas())
404 IMP.pmi.tools._add_pmi_provenance(self.root_hier)
407 def _setup_mc_sampler(self):
409 self.model, self.monte_carlo_sample_objects,
410 self.vars[
"monte_carlo_temperature"],
411 score_moved=self.score_moved,
412 start_frame=self._restart_from_frame)
414 sampler_mc.set_use_jax(self.vars[
"monte_carlo_steps"])
415 if self.vars[
"simulated_annealing"]:
416 tmin = self.vars[
"simulated_annealing_minimum_temperature"]
417 tmax = self.vars[
"simulated_annealing_maximum_temperature"]
419 "simulated_annealing_minimum_temperature_nframes"]
421 "simulated_annealing_maximum_temperature_nframes"]
422 sampler_mc.set_simulated_annealing(tmin, tmax, nfmin, nfmax)
423 if self.vars[
"self_adaptive"]:
424 sampler_mc.set_self_adaptive(
425 isselfadaptive=self.vars[
"self_adaptive"])
428 def _setup_md_sampler(self):
430 self.model, self.molecular_dynamics_sample_objects,
431 self.vars[
"monte_carlo_temperature"],
432 maximum_time_step=self.molecular_dynamics_max_time_step,
433 start_frame=self._restart_from_frame)
435 sampler_md.set_use_jax(self.vars[
"molecular_dynamics_steps"])
436 if self.vars[
"simulated_annealing"]:
437 tmin = self.vars[
"simulated_annealing_minimum_temperature"]
438 tmax = self.vars[
"simulated_annealing_maximum_temperature"]
440 "simulated_annealing_minimum_temperature_nframes"]
442 "simulated_annealing_maximum_temperature_nframes"]
443 sampler_md.set_simulated_annealing(tmin, tmax, nfmin, nfmax)
446 def _get_jax_model(self, sampler_mc):
448 return sampler_mc.get_jax_model()
450 def execute_macro(self):
454 self._restart._number += 1
455 restarted = self._restart.restarted
457 stat_file = _StatFile(self.output_objects, self.rmf_output_objects)
458 temp_index_factor = 100000.0
462 if self.monte_carlo_sample_objects
is not None:
463 print(
"Setting up MonteCarlo")
464 sampler_mc = self._setup_mc_sampler()
465 stat_file.append(sampler_mc)
466 samplers.append(sampler_mc)
468 if self.molecular_dynamics_sample_objects
is not None:
469 print(
"Setting up MolecularDynamics")
470 sampler_md = self._setup_md_sampler()
471 stat_file.append(sampler_md)
472 samplers.append(sampler_md)
476 print(
"Setting up ReplicaExchange")
478 self.model, self.vars[
"replica_exchange_minimum_temperature"],
479 self.vars[
"replica_exchange_maximum_temperature"], samplers,
480 replica_exchange_object=self.replica_exchange_object)
481 self.replica_exchange_object = rex.rem
484 rex.stats = self._rex_stats
487 myindex = rex.get_my_index()
488 stat_file.append(rex)
492 min_temp_index = int(min(rex.get_temperatures()) * temp_index_factor)
496 globaldir = self.vars[
"global_output_directory"] +
"/"
497 rmf_dir = globaldir + self.vars[
"rmf_dir"]
498 pdb_dir = globaldir + self.vars[
"best_pdb_dir"]
500 if not self.test_mode
and not self.nest:
501 if self.vars[
"do_clean_first"]:
504 if self.vars[
"do_create_directories"]:
506 os.makedirs(globaldir, exist_ok=
True)
507 os.makedirs(rmf_dir, exist_ok=
True)
508 if not self.is_multi_state:
509 os.makedirs(pdb_dir, exist_ok=
True)
511 for n
in range(self.vars[
"number_of_states"]):
512 os.makedirs(pdb_dir +
"/" + str(n), exist_ok=
True)
521 print(
"Setting up stat file")
522 low_temp_stat_file = globaldir + \
523 self.vars[
"stat_file_name_suffix"] +
"." + \
524 str(myindex) +
".out"
527 if not self.test_mode:
530 if not self.test_mode
and not self.nest:
531 if stat_file.objects
is not None:
532 output.init_stat2(low_temp_stat_file,
534 extralabels=[
"rmf_file",
"rmf_frame_index"],
535 jax_model=self._get_jax_model(sampler_mc),
538 if restarted
and sampler_mc:
539 nline = output._count_stat2_nframe(
540 low_temp_stat_file,
'MonteCarlo_Nframe',
541 self._restart_from_frame)
542 if nline
is not None:
543 output._truncate_stat2_nline(low_temp_stat_file, nline)
545 print(
"Stat file writing is disabled")
547 if stat_file.rmf_objects
is not None and not self.nest:
548 print(
"Stat info being written in the rmf file")
550 if not self.test_mode
and not self.nest:
551 print(
"Setting up replica stat file")
552 replica_stat_file = globaldir + \
553 self.vars[
"replica_stat_file_suffix"] +
"." + \
554 str(myindex) +
".out"
555 if not self.test_mode:
556 output.init_stat2(replica_stat_file, [rex],
557 extralabels=[
"score"],
558 jax_model=self._get_jax_model(sampler_mc),
561 output._truncate_stat2_nline(
562 replica_stat_file, self._restart_from_frame)
564 print(
"Setting up best pdb files")
565 if not self.is_multi_state:
566 if self.vars[
"number_of_best_scoring_models"] > 0:
567 output.init_pdb_best_scoring(
568 pdb_dir +
"/" + self.vars[
"best_pdb_name_suffix"],
570 self.vars[
"number_of_best_scoring_models"],
571 replica_exchange=
True,
572 mmcif=self.vars[
'mmcif'],
573 best_score_file=globaldir +
"best.scores.rex.py")
574 pdbext =
".0.cif" if self.vars[
'mmcif']
else ".0.pdb"
576 pdb_dir +
"/" +
"model.psf",
578 self.vars[
"best_pdb_name_suffix"] + pdbext)
580 if self.vars[
"number_of_best_scoring_models"] > 0:
581 for n
in range(self.vars[
"number_of_states"]):
582 output.init_pdb_best_scoring(
583 pdb_dir +
"/" + str(n) +
"/" +
584 self.vars[
"best_pdb_name_suffix"],
586 self.vars[
"number_of_best_scoring_models"],
587 replica_exchange=
True,
588 mmcif=self.vars[
'mmcif'],
589 best_score_file=globaldir +
"best.scores.rex.py")
590 pdbext =
".0.cif" if self.vars[
'mmcif']
else ".0.pdb"
592 pdb_dir +
"/" + str(n) +
"/" +
"model.psf",
593 pdb_dir +
"/" + str(n) +
"/" +
594 self.vars[
"best_pdb_name_suffix"] + pdbext)
597 if self.em_object_for_rmf
is not None:
598 output_hierarchies = [
600 self.em_object_for_rmf.get_density_as_hierarchy(
603 output_hierarchies = [self.root_hier]
605 if not self.test_mode
and not self.nest
and not restarted:
606 print(
"Setting up and writing initial rmf coordinate file")
607 init_suffix = globaldir + self.vars[
"initial_rmf_name_suffix"]
608 output.init_rmf(init_suffix +
"." + str(myindex) +
".rmf3",
610 listofobjects=stat_file.rmf_objects)
611 if self._rmf_restraints:
612 output.add_restraints_to_rmf(
613 init_suffix +
"." + str(myindex) +
".rmf3",
614 self._rmf_restraints)
615 output.write_rmf(init_suffix +
"." + str(myindex) +
".rmf3")
616 output.close_rmf(init_suffix +
"." + str(myindex) +
".rmf3")
618 if not self.test_mode:
619 mpivs = IMP.pmi.samplers.MPI_values(self.replica_exchange_object)
621 mpivs = _MockMPIValues()
623 self._add_provenance(sampler_md, sampler_mc)
625 if not self.test_mode
and not self.nest:
626 print(
"Setting up production rmf files")
628 rmfname = f
"{rmf_dir}/{myindex}.rs{self._restart._number}.rmf3"
630 rmfname = rmf_dir +
"/" + str(myindex) +
".rmf3"
631 output.init_rmf(rmfname, output_hierarchies,
632 geometries=self.vars[
"geometries"],
633 listofobjects=stat_file.rmf_objects)
635 if self._rmf_restraints:
636 output.add_restraints_to_rmf(rmfname, self._rmf_restraints)
638 if not self.test_mode
and self.nest:
639 print(
"Setting up NestOR rmf files")
640 nestor_rmf_fname = str(self.nestor_rmf_fname) +
'_' + \
641 str(self.replica_exchange_object.get_my_index()) +
'.rmf3'
643 output.init_rmf(nestor_rmf_fname, output_hierarchies,
644 geometries=self.vars[
"geometries"],
645 listofobjects=stat_file.rmf_objects)
647 ntimes_at_low_temp = 0
649 if myindex == 0
and not self.nest:
651 self.replica_exchange_object.set_was_used(
True)
652 nframes = self.vars[
"number_of_frames"]
656 sampled_likelihoods = []
657 for i
in range(self._restart_from_frame, nframes):
658 if self._restart
and i != self._restart_from_frame:
659 self._restart._write_frame(self, i, myindex, rex.stats)
664 for nr
in range(self.vars[
"num_sample_rounds"]):
665 if sampler_md
is not None:
666 score = sampler_md.optimize(
667 self.vars[
"molecular_dynamics_steps"])
668 if sampler_mc
is not None:
669 score = sampler_mc.optimize(
670 self.vars[
"monte_carlo_steps"])
673 self.model).evaluate(
False)
675 and not self.use_jax):
679 self.model).evaluate(
False)
680 assert abs(score - check_score) < 1e-4
681 mpivs.set_value(
"score", score)
683 output.set_output_entry(
"score", score)
685 my_temp_index = int(rex.get_my_temp() * temp_index_factor)
687 if self.vars[
"save_coordinates_mode"] ==
"lowest_temperature":
688 save_frame = (min_temp_index == my_temp_index)
689 elif self.vars[
"save_coordinates_mode"] ==
"25th_score":
690 score_perc = mpivs.get_percentile(
"score")
691 save_frame = (score_perc*100.0 <= 25.0)
692 elif self.vars[
"save_coordinates_mode"] ==
"50th_score":
693 score_perc = mpivs.get_percentile(
"score")
694 save_frame = (score_perc*100.0 <= 50.0)
695 elif self.vars[
"save_coordinates_mode"] ==
"75th_score":
696 score_perc = mpivs.get_percentile(
"score")
697 save_frame = (score_perc*100.0 <= 75.0)
700 if save_frame
and not self.test_mode:
704 print(
"--- frame %s score %s " % (str(i), str(score)))
707 if math.isnan(score):
708 sampled_likelihoods.append(math.nan)
710 likelihood_for_sample = 1
711 for rstrnt
in self.nestor_restraints:
712 likelihood_for_sample *= rstrnt.get_likelihood()
713 sampled_likelihoods.append(likelihood_for_sample)
714 output.write_rmf(nestor_rmf_fname)
716 if not self.test_mode
and not self.nest:
717 if i % self.vars[
"nframes_write_coordinates"] == 0:
718 print(
'--- writing coordinates')
719 if self.vars[
"number_of_best_scoring_models"] > 0:
720 output.write_pdb_best_scoring(score)
721 output.write_rmf(rmfname)
722 output.set_output_entry(
"rmf_file", rmfname)
723 output.set_output_entry(
"rmf_frame_index",
726 output.set_output_entry(
"rmf_file", rmfname)
727 output.set_output_entry(
"rmf_frame_index",
'-1')
728 if stat_file.objects
is not None:
731 jax_model=self._get_jax_model(sampler_mc))
732 ntimes_at_low_temp += 1
734 if not self.test_mode
and not self.nest:
737 jax_model=self._get_jax_model(sampler_mc))
738 if self.vars[
"replica_exchange_swap"]:
739 rex.swap_temp(i, score)
741 if self.nest
and len(sampled_likelihoods) > 0:
742 with open(
"likelihoods_"
743 + str(self.replica_exchange_object.get_my_index()),
745 pickle.dump(sampled_likelihoods, lif)
747 output.close_rmf(nestor_rmf_fname)
749 for p, state
in IMP.pmi.tools._all_protocol_outputs(self.root_hier):
750 p.add_replica_exchange(state, self)
752 if not self.test_mode
and not self.nest:
753 print(
"closing production rmf files")
754 output.close_rmf(rmfname)
758 """Continue a failed ReplicaExchange sampling run.
760 @see ReplicaExchange.set_restart
762 @param restart_dir The directory containing the restart file(s).
769 nproc, myindex = r.get_number_of_replicas(), r.get_my_index()
772 nproc, myindex = 1, 0
774 with open(f
'{restart_dir}/restart.{myindex}.pck',
'rb')
as fh:
776 old_nproc = mc.get_number_of_replicas()
777 if old_nproc != nproc:
779 f
"Mismatch trying to read restart files: the original run used "
780 f
"{old_nproc} replicas and this run has {nproc}")
781 return mc.execute_macro()
785 """A macro to build a IMP::pmi::topology::System based on a
786 TopologyReader object.
788 Easily create multi-state systems by calling this macro
789 repeatedly with different TopologyReader objects!
790 A useful function is get_molecules() which returns the PMI Molecules
791 grouped by state as a dictionary with key = (molecule name),
792 value = IMP.pmi.topology.Molecule
793 Quick multi-state system:
796 reader1 = IMP.pmi.topology.TopologyReader(tfile1)
797 reader2 = IMP.pmi.topology.TopologyReader(tfile2)
798 bs = IMP.pmi.macros.BuildSystem(model)
799 bs.add_state(reader1)
800 bs.add_state(reader2)
801 bs.execute_macro() # build everything including degrees of freedom
802 IMP.atom.show_molecular_hierarchy(bs.get_hierarchy())
803 ### now you have a two state system, you add restraints etc
805 @note The "domain name" entry of the topology reader is not used.
806 All molecules are set up by the component name, but split into rigid bodies
810 _alphabets = {
'DNA': IMP.pmi.alphabets.dna,
811 'RNA': IMP.pmi.alphabets.rna}
813 def __init__(self, model, sequence_connectivity_scale=4.0,
814 force_create_gmm_files=
False, resolutions=[1, 10],
817 @param model An IMP Model
818 @param sequence_connectivity_scale For scaling the connectivity
820 @param force_create_gmm_files If True, will sample and create GMMs
821 no matter what. If False, will only sample if the
822 files don't exist. If number of Gaussians is zero, won't
824 @param resolutions The resolutions to build for structured regions
825 @param name The name of the top-level hierarchy node.
832 self._domain_res = []
834 self.force_create_gmm_files = force_create_gmm_files
835 self.resolutions = resolutions
837 def add_state(self, reader, keep_chain_id=False, fasta_name_map=None,
839 """Add a state using the topology info in a
840 IMP::pmi::topology::TopologyReader object.
841 When you are done adding states, call execute_macro()
842 @param reader The TopologyReader object
843 @param keep_chain_id If True, keep the chain IDs from the
844 original PDB files, if available
845 @param fasta_name_map dictionary for converting protein names
846 found in the fasta file
847 @param chain_ids A list or string of chain IDs for assigning to
848 newly-created molecules, e.g.
849 `string.ascii_uppercase+string.ascii_lowercase+string.digits`.
850 If not specified, chain IDs A through Z are assigned, then
851 AA through AZ, then BA through BZ, and so on, in the same
854 state = self.system.create_state()
855 self._readers.append(reader)
857 these_domain_res = {}
859 if chain_ids
is None:
860 chain_ids = IMP.pmi.output._ChainIDs()
865 for molname
in reader.get_molecules():
866 copies = reader.get_molecules()[molname].domains
867 for nc, copyname
in enumerate(copies):
868 print(
"BuildSystem.add_state: setting up molecule %s copy "
869 "number %s" % (molname, str(nc)))
870 copy = copies[copyname]
873 all_chains = [c
for c
in copy
if c.chain
is not None]
875 chain_id = all_chains[0].chain
877 chain_id = chain_ids[numchain]
879 "No PDBs specified for %s, so keep_chain_id has "
880 "no effect; using default chain ID '%s'"
883 chain_id = chain_ids[numchain]
885 alphabet = IMP.pmi.alphabets.amino_acid
886 fasta_flag = copy[0].fasta_flag
887 if fasta_flag
in self._alphabets:
888 alphabet = self._alphabets[fasta_flag]
890 copy[0].fasta_file, fasta_name_map)
891 seq = seqs[copy[0].fasta_id]
892 print(
"BuildSystem.add_state: molecule %s sequence has "
893 "%s residues" % (molname, len(seq)))
894 orig_mol = state.create_molecule(
895 molname, seq, chain_id, alphabet=alphabet,
896 uniprot=seqs.uniprot.get(copy[0].fasta_id))
900 print(
"BuildSystem.add_state: creating a copy for "
901 "molecule %s" % molname)
902 mol = orig_mol.create_copy(chain_id)
905 for domainnumber, domain
in enumerate(copy):
906 print(
"BuildSystem.add_state: ---- setting up domain %s "
907 "of molecule %s" % (domainnumber, molname))
910 these_domains[domain.get_unique_name()] = domain
911 if domain.residue_range == []
or \
912 domain.residue_range
is None:
913 domain_res = mol.get_residues()
915 start = domain.residue_range[0]+domain.pdb_offset
916 if domain.residue_range[1] ==
'END':
917 end = len(mol.sequence)
919 end = domain.residue_range[1]+domain.pdb_offset
920 domain_res = mol.residue_range(start-1, end-1)
921 print(
"BuildSystem.add_state: -------- domain %s of "
922 "molecule %s extends from residue %s to "
924 % (domainnumber, molname, start, end))
925 if domain.pdb_file ==
"BEADS":
926 print(
"BuildSystem.add_state: -------- domain %s of "
927 "molecule %s represented by BEADS "
928 % (domainnumber, molname))
929 mol.add_representation(
931 resolutions=[domain.bead_size],
932 setup_particles_as_densities=(
933 domain.em_residues_per_gaussian != 0),
935 these_domain_res[domain.get_unique_name()] = \
937 elif domain.pdb_file ==
"IDEAL_HELIX":
938 print(
"BuildSystem.add_state: -------- domain %s of "
939 "molecule %s represented by IDEAL_HELIX "
940 % (domainnumber, molname))
941 emper = domain.em_residues_per_gaussian
942 mol.add_representation(
944 resolutions=self.resolutions,
946 density_residues_per_component=emper,
947 density_prefix=domain.density_prefix,
948 density_force_compute=self.force_create_gmm_files,
950 these_domain_res[domain.get_unique_name()] = \
953 print(
"BuildSystem.add_state: -------- domain %s of "
954 "molecule %s represented by pdb file %s "
955 % (domainnumber, molname, domain.pdb_file))
956 domain_atomic = mol.add_structure(domain.pdb_file,
958 domain.residue_range,
961 domain_non_atomic = domain_res - domain_atomic
962 if not domain.em_residues_per_gaussian:
963 mol.add_representation(
964 domain_atomic, resolutions=self.resolutions,
966 if len(domain_non_atomic) > 0:
967 mol.add_representation(
969 resolutions=[domain.bead_size],
972 print(
"BuildSystem.add_state: -------- domain %s "
973 "of molecule %s represented by gaussians "
974 % (domainnumber, molname))
975 emper = domain.em_residues_per_gaussian
976 creategmm = self.force_create_gmm_files
977 mol.add_representation(
979 resolutions=self.resolutions,
980 density_residues_per_component=emper,
981 density_prefix=domain.density_prefix,
982 density_force_compute=creategmm,
984 if len(domain_non_atomic) > 0:
985 mol.add_representation(
987 resolutions=[domain.bead_size],
988 setup_particles_as_densities=
True,
990 these_domain_res[domain.get_unique_name()] = (
991 domain_atomic, domain_non_atomic)
992 self._domain_res.append(these_domain_res)
993 self._domains.append(these_domains)
994 print(
'BuildSystem.add_state: State', len(self.system.states),
'added')
998 """Return list of all molecules grouped by state.
999 For each state, it's a dictionary of Molecules where key is the
1002 return [s.get_molecules()
for s
in self.system.get_states()]
1004 def get_molecule(self, molname, copy_index=0, state_index=0):
1005 return self.system.get_states()[state_index].
get_molecules()[
1006 molname][copy_index]
1009 max_bead_trans=4.0, max_srb_trans=4.0, max_srb_rot=0.04):
1010 """Builds representations and sets up degrees of freedom"""
1011 print(
"BuildSystem.execute_macro: building representations")
1012 self.root_hier = self.system.build()
1014 print(
"BuildSystem.execute_macro: setting up degrees of freedom")
1016 for nstate, reader
in enumerate(self._readers):
1017 rbs = reader.get_rigid_bodies()
1018 srbs = reader.get_super_rigid_bodies()
1019 csrbs = reader.get_chains_of_super_rigid_bodies()
1022 domains_in_rbs = set()
1024 print(
"BuildSystem.execute_macro: -------- building rigid "
1025 "body %s" % (str(rblist)))
1026 all_res = IMP.pmi.tools.OrderedSet()
1027 bead_res = IMP.pmi.tools.OrderedSet()
1028 for dname
in rblist:
1029 domain = self._domains[nstate][dname]
1030 print(
"BuildSystem.execute_macro: -------- adding %s"
1032 all_res |= self._domain_res[nstate][dname][0]
1033 bead_res |= self._domain_res[nstate][dname][1]
1034 domains_in_rbs.add(dname)
1036 print(
"BuildSystem.execute_macro: -------- creating rigid "
1037 "body with max_trans %s max_rot %s "
1038 "non_rigid_max_trans %s"
1039 % (str(max_rb_trans), str(max_rb_rot),
1040 str(max_bead_trans)))
1041 self.dof.create_rigid_body(all_res,
1042 nonrigid_parts=bead_res,
1043 max_trans=max_rb_trans,
1045 nonrigid_max_trans=max_bead_trans,
1046 name=
"RigidBody %s" % dname)
1049 for dname, domain
in self._domains[nstate].items():
1050 if dname
not in domains_in_rbs:
1051 if domain.pdb_file !=
"BEADS":
1053 "No rigid bodies set for %s. Residues read from "
1054 "the PDB file will not be sampled - only regions "
1055 "missing from the PDB will be treated flexibly. "
1056 "To sample the entire sequence, use BEADS instead "
1057 "of a PDB file name" % dname,
1059 self.dof.create_flexible_beads(
1060 self._domain_res[nstate][dname][1],
1061 max_trans=max_bead_trans)
1064 for srblist
in srbs:
1065 print(
"BuildSystem.execute_macro: -------- building "
1066 "super rigid body %s" % (str(srblist)))
1067 all_res = IMP.pmi.tools.OrderedSet()
1068 for dname
in srblist:
1069 print(
"BuildSystem.execute_macro: -------- adding %s"
1071 all_res |= self._domain_res[nstate][dname][0]
1072 all_res |= self._domain_res[nstate][dname][1]
1074 print(
"BuildSystem.execute_macro: -------- creating super "
1075 "rigid body with max_trans %s max_rot %s "
1076 % (str(max_srb_trans), str(max_srb_rot)))
1077 self.dof.create_super_rigid_body(
1078 all_res, max_trans=max_srb_trans, max_rot=max_srb_rot)
1081 for csrblist
in csrbs:
1082 all_res = IMP.pmi.tools.OrderedSet()
1083 for dname
in csrblist:
1084 all_res |= self._domain_res[nstate][dname][0]
1085 all_res |= self._domain_res[nstate][dname][1]
1086 all_res = list(all_res)
1087 all_res.sort(key=
lambda r: r.get_index())
1088 self.dof.create_main_chain_mover(all_res)
1089 return self.root_hier, self.dof
1094 """A macro for running all the basic operations of analysis.
1095 Includes clustering, precision analysis, and making ensemble density maps.
1096 A number of plots are also supported.
1099 merge_directories=[
"./"],
1100 stat_file_name_suffix=
"stat",
1101 best_pdb_name_suffix=
"model",
1102 do_clean_first=
True,
1103 do_create_directories=
True,
1104 global_output_directory=
"output/",
1105 replica_stat_file_suffix=
"stat_replica",
1106 global_analysis_result_directory=
"./analysis/",
1109 @param model The IMP model
1110 @param stat_file_name_suffix
1111 @param merge_directories The directories containing output files
1112 @param best_pdb_name_suffix
1113 @param do_clean_first
1114 @param do_create_directories
1115 @param global_output_directory Where everything is
1116 @param replica_stat_file_suffix
1117 @param global_analysis_result_directory
1118 @param test_mode If True, nothing is changed on disk
1122 from mpi4py
import MPI
1123 self.comm = MPI.COMM_WORLD
1124 self.rank = self.comm.Get_rank()
1125 self.number_of_processes = self.comm.size
1128 self.number_of_processes = 1
1130 self.test_mode = test_mode
1131 self._protocol_output = []
1132 self.cluster_obj =
None
1134 stat_dir = global_output_directory
1135 self.stat_files = []
1137 for rd
in merge_directories:
1138 stat_files = glob.glob(os.path.join(rd, stat_dir,
"stat.*.out"))
1139 if len(stat_files) == 0:
1140 warnings.warn(
"no stat files found in %s"
1141 % os.path.join(rd, stat_dir),
1143 self.stat_files += stat_files
1146 """Capture details of the modeling protocol.
1147 @param p an instance of IMP.pmi.output.ProtocolOutput or a subclass.
1150 self._protocol_output.append((p, p._last_state))
1153 score_key=
"Total_Score",
1154 rmf_file_key=
"rmf_file",
1155 rmf_file_frame_key=
"rmf_frame_index",
1158 nframes_trajectory=10000):
1159 """ Get a trajectory of the modeling run, for generating
1160 demonstrative movies
1162 @param score_key The score for ranking models
1163 @param rmf_file_key Key pointing to RMF filename
1164 @param rmf_file_frame_key Key pointing to RMF frame number
1165 @param outputdir The local output directory used in the run
1166 @param get_every Extract every nth frame
1167 @param nframes_trajectory Total number of frames of the trajectory
1172 self.stat_files, score_key, rmf_file_key, rmf_file_frame_key,
1174 score_list = list(map(float, trajectory_models[2]))
1176 max_score = max(score_list)
1177 min_score = min(score_list)
1179 bins = [(max_score-min_score)*math.exp(-float(i))+min_score
1180 for i
in range(nframes_trajectory)]
1181 binned_scores = [
None]*nframes_trajectory
1182 binned_model_indexes = [-1]*nframes_trajectory
1184 for model_index, s
in enumerate(score_list):
1185 bins_score_diffs = [abs(s-b)
for b
in bins]
1186 bin_index = min(enumerate(bins_score_diffs), key=itemgetter(1))[0]
1187 if binned_scores[bin_index]
is None:
1188 binned_scores[bin_index] = s
1189 binned_model_indexes[bin_index] = model_index
1191 old_diff = abs(binned_scores[bin_index]-bins[bin_index])
1192 new_diff = abs(s-bins[bin_index])
1193 if new_diff < old_diff:
1194 binned_scores[bin_index] = s
1195 binned_model_indexes[bin_index] = model_index
1197 print(binned_scores)
1198 print(binned_model_indexes)
1200 def _expand_ambiguity(self, prot, d):
1201 """If using PMI2, expand the dictionary to include copies as
1204 This also keeps the states separate.
1209 if '..' in key
or (isinstance(val, tuple)
and len(val) >= 3):
1212 states = IMP.atom.get_by_type(prot, IMP.atom.STATE_TYPE)
1213 if isinstance(val, tuple):
1221 for nst
in range(len(states)):
1223 copies = sel.get_selected_particles(with_representation=
False)
1225 for nc
in range(len(copies)):
1227 newdict[
'%s.%i..%i' % (name, nst, nc)] = \
1228 (start, stop, name, nc, nst)
1230 newdict[
'%s..%i' % (name, nc)] = \
1231 (start, stop, name, nc, nst)
1237 score_key=
"Total_Score",
1238 rmf_file_key=
"rmf_file",
1239 rmf_file_frame_key=
"rmf_frame_index",
1241 prefiltervalue=
None,
1244 alignment_components=
None,
1245 number_of_best_scoring_models=10,
1246 rmsd_calculation_components=
None,
1247 distance_matrix_file=
'distances.mat',
1248 load_distance_matrix_file=
False,
1249 skip_clustering=
False,
1250 number_of_clusters=1,
1252 exit_after_display=
True,
1254 first_and_last_frames=
None,
1255 density_custom_ranges=
None,
1256 write_pdb_with_centered_coordinates=
False,
1258 """Get the best scoring models, compute a distance matrix,
1259 cluster them, and create density maps.
1261 Tuple format: "molname" just the molecule,
1262 or (start,stop,molname,copy_num(optional),state_num(optional)
1263 Can pass None for copy or state to ignore that field.
1264 If you don't pass a specific copy number
1266 @param score_key The score for ranking models.
1267 @param rmf_file_key Key pointing to RMF filename
1268 @param rmf_file_frame_key Key pointing to RMF frame number
1269 @param state_number State number to analyze
1270 @param prefiltervalue Only include frames where the
1271 score key is below this value
1272 @param feature_keys Keywords for which you want to
1273 calculate average, medians, etc.
1274 If you pass "Keyname" it'll include everything that matches
1276 @param outputdir The local output directory used in
1278 @param alignment_components Dictionary with keys=groupname,
1279 values are tuples for aligning the structures
1280 e.g. {"Rpb1": (20,100,"Rpb1"),"Rpb2":"Rpb2"}
1281 @param number_of_best_scoring_models Num models to keep per run
1282 @param rmsd_calculation_components For calculating RMSD
1283 (same format as alignment_components)
1284 @param distance_matrix_file Where to store/read the
1286 @param load_distance_matrix_file Try to load the distance
1288 @param skip_clustering Just extract the best scoring
1289 models and save the pdbs
1290 @param number_of_clusters Number of k-means clusters
1291 @param display_plot Display the distance matrix
1292 @param exit_after_display Exit after displaying distance
1294 @param get_every Extract every nth frame
1295 @param first_and_last_frames A tuple with the first and last
1296 frames to be analyzed. Values are percentages!
1297 Default: get all frames
1298 @param density_custom_ranges For density calculation
1299 (same format as alignment_components)
1300 @param write_pdb_with_centered_coordinates
1301 @param voxel_size Used for the density output
1305 self._outputdir = Path(outputdir).absolute()
1306 self._number_of_clusters = number_of_clusters
1307 for p, state
in self._protocol_output:
1308 p.add_replica_exchange_analysis(state, self, density_custom_ranges)
1319 if not load_distance_matrix_file:
1320 if len(self.stat_files) == 0:
1321 print(
"ERROR: no stat file found in the given path")
1323 my_stat_files = IMP.pmi.tools.chunk_list_into_segments(
1324 self.stat_files, self.number_of_processes)[self.rank]
1327 for k
in (score_key, rmf_file_key, rmf_file_frame_key):
1328 if k
in feature_keys:
1330 "no need to pass " + k +
" to feature_keys.",
1332 feature_keys.remove(k)
1335 my_stat_files, score_key, feature_keys, rmf_file_key,
1336 rmf_file_frame_key, prefiltervalue, get_every, provenance=prov)
1337 rmf_file_list = best_models[0]
1338 rmf_file_frame_list = best_models[1]
1339 score_list = best_models[2]
1340 feature_keyword_list_dict = best_models[3]
1346 if self.number_of_processes > 1:
1350 rmf_file_frame_list)
1351 for k
in feature_keyword_list_dict:
1352 feature_keyword_list_dict[k] = \
1354 feature_keyword_list_dict[k])
1357 score_rmf_tuples = list(zip(score_list,
1359 rmf_file_frame_list,
1360 list(range(len(score_list)))))
1362 if density_custom_ranges:
1363 for k
in density_custom_ranges:
1364 if not isinstance(density_custom_ranges[k], list):
1365 raise Exception(
"Density custom ranges: values must "
1366 "be lists of tuples")
1369 if first_and_last_frames
is not None:
1370 nframes = len(score_rmf_tuples)
1371 first_frame = int(first_and_last_frames[0] * nframes)
1372 last_frame = int(first_and_last_frames[1] * nframes)
1373 if last_frame > len(score_rmf_tuples):
1375 score_rmf_tuples = score_rmf_tuples[first_frame:last_frame]
1378 best_score_rmf_tuples = sorted(
1380 key=
lambda x: float(x[0]))[:number_of_best_scoring_models]
1381 best_score_rmf_tuples = [t+(n,)
for n, t
in
1382 enumerate(best_score_rmf_tuples)]
1384 prov.append(IMP.pmi.io.FilterProvenance(
1385 "Best scoring", 0, number_of_best_scoring_models))
1387 best_score_feature_keyword_list_dict = defaultdict(list)
1388 for tpl
in best_score_rmf_tuples:
1390 for f
in feature_keyword_list_dict:
1391 best_score_feature_keyword_list_dict[f].append(
1392 feature_keyword_list_dict[f][index])
1393 my_best_score_rmf_tuples = IMP.pmi.tools.chunk_list_into_segments(
1394 best_score_rmf_tuples,
1395 self.number_of_processes)[self.rank]
1398 prot_ahead = IMP.pmi.analysis.get_hiers_from_rmf(
1399 self.model, 0, my_best_score_rmf_tuples[0][1])[0]
1400 if rmsd_calculation_components
is not None:
1401 tmp = self._expand_ambiguity(
1402 prot_ahead, rmsd_calculation_components)
1403 if tmp != rmsd_calculation_components:
1404 print(
'Detected ambiguity, expand rmsd components to',
1406 rmsd_calculation_components = tmp
1407 if alignment_components
is not None:
1408 tmp = self._expand_ambiguity(prot_ahead,
1409 alignment_components)
1410 if tmp != alignment_components:
1411 print(
'Detected ambiguity, expand alignment '
1412 'components to', tmp)
1413 alignment_components = tmp
1419 self.model, my_best_score_rmf_tuples[0],
1420 rmsd_calculation_components, state_number=state_number)
1422 self.model, my_best_score_rmf_tuples, alignment_components,
1423 rmsd_calculation_components, state_number=state_number)
1431 all_coordinates = got_coords[0]
1434 alignment_coordinates = got_coords[1]
1437 rmsd_coordinates = got_coords[2]
1440 rmf_file_name_index_dict = got_coords[3]
1443 all_rmf_file_names = got_coords[4]
1449 if density_custom_ranges:
1451 density_custom_ranges, voxel=voxel_size)
1453 dircluster = os.path.join(outputdir,
1454 "all_models."+str(self.rank))
1460 os.mkdir(dircluster)
1463 clusstat = open(os.path.join(
1464 dircluster,
"stat."+str(self.rank)+
".out"),
"w")
1465 for cnt, tpl
in enumerate(my_best_score_rmf_tuples):
1467 rmf_frame_number = tpl[2]
1470 for key
in best_score_feature_keyword_list_dict:
1472 best_score_feature_keyword_list_dict[key][index]
1476 IMP.pmi.analysis.get_hiers_and_restraints_from_rmf(
1477 self.model, rmf_frame_number, rmf_name)
1479 linking_successful = \
1480 IMP.pmi.analysis.link_hiers_and_restraints_to_rmf(
1481 self.model, prots, rs, rmf_frame_number,
1483 if not linking_successful:
1489 states = IMP.atom.get_by_type(
1490 prots[0], IMP.atom.STATE_TYPE)
1491 prot = states[state_number]
1496 coords_f1 = alignment_coordinates[cnt]
1498 coords_f2 = alignment_coordinates[cnt]
1501 coords_f1, coords_f2)
1502 transformation = Ali.align()[1]
1516 rb = rbm.get_rigid_body()
1526 out_pdb_fn = os.path.join(
1527 dircluster, str(cnt)+
"."+str(self.rank)+
".pdb")
1528 out_rmf_fn = os.path.join(
1529 dircluster, str(cnt)+
"."+str(self.rank)+
".rmf3")
1530 o.init_pdb(out_pdb_fn, prot)
1531 tc = write_pdb_with_centered_coordinates
1532 o.write_pdb(out_pdb_fn,
1533 translate_to_geometric_center=tc)
1535 tmp_dict[
"local_pdb_file_name"] = \
1536 os.path.basename(out_pdb_fn)
1537 tmp_dict[
"rmf_file_full_path"] = rmf_name
1538 tmp_dict[
"local_rmf_file_name"] = \
1539 os.path.basename(out_rmf_fn)
1540 tmp_dict[
"local_rmf_frame_number"] = 0
1542 clusstat.write(str(tmp_dict)+
"\n")
1547 h.set_name(
"System")
1549 o.init_rmf(out_rmf_fn, [h], rs)
1551 o.write_rmf(out_rmf_fn)
1552 o.close_rmf(out_rmf_fn)
1554 if density_custom_ranges:
1555 DensModule.add_subunits_density(prot)
1557 if density_custom_ranges:
1558 DensModule.write_mrc(path=dircluster)
1563 if self.number_of_processes > 1:
1569 rmf_file_name_index_dict)
1571 alignment_coordinates)
1578 [best_score_feature_keyword_list_dict,
1579 rmf_file_name_index_dict],
1585 print(
"setup clustering class")
1588 for n, model_coordinate_dict
in enumerate(all_coordinates):
1590 if (alignment_components
is not None
1591 and len(self.cluster_obj.all_coords) == 0):
1593 self.cluster_obj.set_template(alignment_coordinates[n])
1594 self.cluster_obj.fill(all_rmf_file_names[n],
1595 rmsd_coordinates[n])
1596 print(
"Global calculating the distance matrix")
1599 self.cluster_obj.dist_matrix()
1603 self.cluster_obj.do_cluster(number_of_clusters)
1606 self.cluster_obj.plot_matrix(
1607 figurename=os.path.join(outputdir,
1609 if exit_after_display:
1611 self.cluster_obj.save_distance_matrix_file(
1612 file_name=distance_matrix_file)
1619 print(
"setup clustering class")
1621 self.cluster_obj.load_distance_matrix_file(
1622 file_name=distance_matrix_file)
1623 print(
"clustering with %s clusters" % str(number_of_clusters))
1624 self.cluster_obj.do_cluster(number_of_clusters)
1625 [best_score_feature_keyword_list_dict,
1626 rmf_file_name_index_dict] = self.load_objects(
".macro.pkl")
1629 self.cluster_obj.plot_matrix(figurename=os.path.join(
1630 outputdir,
'dist_matrix.pdf'))
1631 if exit_after_display:
1633 if self.number_of_processes > 1:
1641 print(self.cluster_obj.get_cluster_labels())
1642 for n, cl
in enumerate(self.cluster_obj.get_cluster_labels()):
1643 print(
"rank %s " % str(self.rank))
1644 print(
"cluster %s " % str(n))
1645 print(
"cluster label %s " % str(cl))
1646 print(self.cluster_obj.get_cluster_label_names(cl))
1648 len(self.cluster_obj.get_cluster_label_names(cl))
1650 prov + [IMP.pmi.io.ClusterProvenance(cluster_size)]
1653 if density_custom_ranges:
1655 density_custom_ranges,
1658 dircluster = outputdir +
"/cluster." + str(n) +
"/"
1660 os.mkdir(dircluster)
1666 str(self.cluster_obj.get_cluster_label_average_rmsd(cl))}
1667 clusstat = open(dircluster +
"stat.out",
"w")
1668 for k, structure_name
in enumerate(
1669 self.cluster_obj.get_cluster_label_names(cl)):
1672 tmp_dict.update(rmsd_dict)
1673 index = rmf_file_name_index_dict[structure_name]
1674 for key
in best_score_feature_keyword_list_dict:
1676 key] = best_score_feature_keyword_list_dict[
1682 rmf_name = structure_name.split(
"|")[0]
1683 rmf_frame_number = int(structure_name.split(
"|")[1])
1684 clusstat.write(str(tmp_dict) +
"\n")
1689 IMP.pmi.analysis.get_hiers_and_restraints_from_rmf(
1690 self.model, rmf_frame_number, rmf_name)
1692 linking_successful = \
1693 IMP.pmi.analysis.link_hiers_and_restraints_to_rmf(
1694 self.model, prots, rs, rmf_frame_number,
1696 if not linking_successful:
1701 states = IMP.atom.get_by_type(
1702 prots[0], IMP.atom.STATE_TYPE)
1703 prot = states[state_number]
1709 co = self.cluster_obj
1710 model_index = co.get_model_index_from_name(
1712 transformation = co.get_transformation_to_first_member(
1723 rb = rbm.get_rigid_body()
1732 if density_custom_ranges:
1733 DensModule.add_subunits_density(prot)
1738 o.init_pdb(dircluster + str(k) +
".pdb", prot)
1739 o.write_pdb(dircluster + str(k) +
".pdb")
1744 h.set_name(
"System")
1746 o.init_rmf(dircluster + str(k) +
".rmf3", [h], rs)
1747 o.write_rmf(dircluster + str(k) +
".rmf3")
1748 o.close_rmf(dircluster + str(k) +
".rmf3")
1753 if density_custom_ranges:
1754 DensModule.write_mrc(path=dircluster)
1757 if self.number_of_processes > 1:
1760 def get_cluster_rmsd(self, cluster_num):
1761 if self.cluster_obj
is None:
1763 return self.cluster_obj.get_cluster_label_average_rmsd(cluster_num)
1765 def save_objects(self, objects, file_name):
1767 with open(file_name,
'wb')
as outf:
1768 pickle.dump(objects, outf)
1770 def load_objects(self, file_name):
1772 with open(file_name,
'rb')
as inputf:
1773 objects = pickle.load(inputf)
1780 This class contains analysis utilities to investigate ReplicaExchange
1788 def __init__(self, model, stat_files, best_models=None, score_key=None,
1791 Construction of the Class.
1792 @param model IMP.Model()
1793 @param stat_files list of string. Can be ascii stat files,
1795 @param best_models Integer. Number of best scoring models,
1796 if None: all models will be read
1797 @param score_key Use the provided stat key keyword as the score
1798 (by default, the total score is used)
1799 @param alignment boolean (Default=True). Align before computing
1804 self.best_models = best_models
1806 model, stat_files, self.best_models, score_key, cache=
True)
1808 StatHierarchyHandler=self.stath0)
1821 self.clusters.append(c)
1822 for n0
in range(len(self.stath0)):
1824 self.pairwise_rmsd = {}
1825 self.pairwise_molecular_assignment = {}
1826 self.alignment = alignment
1827 self.symmetric_molecules = {}
1828 self.issymmetricsel = {}
1830 self.molcopydict0 = IMP.pmi.tools.get_molecules_dictionary_by_copy(
1832 self.molcopydict1 = IMP.pmi.tools.get_molecules_dictionary_by_copy(
1837 Setup the selection onto which the rmsd is computed
1838 @param kwargs use IMP.atom.Selection keywords
1846 Store names of symmetric molecules
1848 self.symmetric_molecules[molecule_name] = 0
1853 Setup the selection onto which the alignment is computed
1854 @param kwargs use IMP.atom.Selection keywords
1862 def clean_clusters(self):
1863 for c
in self.clusters:
1867 def cluster(self, rmsd_cutoff=10, metric=IMP.atom.get_rmsd):
1869 Cluster the models based on RMSD.
1870 @param rmsd_cutoff Float the distance cutoff in Angstrom
1871 @param metric (Default=IMP.atom.get_rmsd) the metric that will
1872 be used to compute rmsds
1874 self.clean_clusters()
1875 not_clustered = set(range(len(self.stath1)))
1876 while len(not_clustered) > 0:
1877 self.
aggregate(not_clustered, rmsd_cutoff, metric)
1882 Refine the clusters by merging the ones whose centers are close
1883 @param rmsd_cutoff cutoff distance in Angstorms
1885 clusters_copy = self.clusters
1886 for c0, c1
in itertools.combinations(self.clusters, 2):
1887 if c0.center_index
is None:
1889 if c1.center_index
is None:
1891 _ = self.stath0[c0.center_index]
1892 _ = self.stath1[c1.center_index]
1893 rmsd, molecular_assignment = self.
rmsd()
1894 if rmsd <= rmsd_cutoff:
1895 if c1
in self.clusters:
1896 clusters_copy.remove(c1)
1898 self.clusters = clusters_copy
1905 def set_cluster_assignments(self, cluster_ids):
1906 if len(cluster_ids) != len(self.stath0):
1907 raise ValueError(
'cluster ids has to be same length as '
1911 for i
in sorted(list(set(cluster_ids))):
1913 for i, (idx, d)
in enumerate(zip(cluster_ids, self.stath0)):
1914 self.clusters[idx].add_member(i, d)
1918 Return the model data from a cluster
1919 @param cluster IMP.pmi.output.Cluster object
1928 Save the data for the whole models into a pickle file
1929 @param filename string
1931 self.stath0.save_data(filename)
1935 Set the data from an external IMP.pmi.output.Data
1936 @param data IMP.pmi.output.Data
1938 self.stath0.data = data
1939 self.stath1.data = data
1943 Load the data from an external pickled file
1944 @param filename string
1946 self.stath0.load_data(filename)
1947 self.stath1.load_data(filename)
1948 self.best_models = len(self.stath0)
1950 def add_cluster(self, rmf_name_list):
1952 print(
"creating cluster index "+str(len(self.clusters)))
1953 self.clusters.append(c)
1954 current_len = len(self.stath0)
1956 for rmf
in rmf_name_list:
1957 print(
"adding rmf "+rmf)
1958 self.stath0.add_stat_file(rmf)
1959 self.stath1.add_stat_file(rmf)
1961 for n0
in range(current_len, len(self.stath0)):
1962 d0 = self.stath0[n0]
1963 c.add_member(n0, d0)
1968 Save the clusters into a pickle file
1969 @param filename string
1972 with open(filename,
'wb')
as fl:
1973 pickle.dump(self.clusters, fl)
1977 Load the clusters from a pickle file
1978 @param filename string
1979 @param append bool (Default=False), if True. append the clusters
1980 to the ones currently present
1983 self.clean_clusters()
1984 with open(filename,
'rb')
as fl:
1986 self.clusters += pickle.load(fl)
1988 self.clusters = pickle.load(fl)
1997 Compute the cluster center for a given cluster
1999 member_distance = defaultdict(float)
2001 for n0, n1
in itertools.combinations(cluster.members, 2):
2004 rmsd, _ = self.
rmsd()
2005 member_distance[n0] += rmsd
2007 if len(member_distance) > 0:
2008 cluster.center_index = min(member_distance,
2009 key=member_distance.get)
2011 cluster.center_index = cluster.members[0]
2016 Save the coordinates of the current cluster a single rmf file
2018 print(
"saving coordinates", cluster)
2022 if rmf_name
is None:
2023 rmf_name = prefix+
'/'+str(cluster.cluster_id)+
".rmf3"
2025 _ = self.stath1[cluster.members[0]]
2027 o.init_rmf(rmf_name, [self.stath1])
2028 for n1
in cluster.members:
2034 o.write_rmf(rmf_name)
2036 o.close_rmf(rmf_name)
2040 remove structures that are similar
2041 append it to a new cluster
2043 print(
"pruning models")
2045 filtered = [selected]
2046 remaining = range(1, len(self.stath1), 10)
2048 while len(remaining) > 0:
2049 d0 = self.stath0[selected]
2051 for n1
in remaining:
2056 if d <= rmsd_cutoff:
2058 print(
"pruning model %s, similar to model %s, rmsd %s"
2059 % (str(n1), str(selected), str(d)))
2060 remaining = [x
for x
in remaining
if x
not in rm]
2061 if len(remaining) == 0:
2063 selected = remaining[0]
2064 filtered.append(selected)
2067 self.clusters.append(c)
2069 d0 = self.stath0[n0]
2070 c.add_member(n0, d0)
2075 Compute the precision of a cluster
2081 if cluster.center_index
is not None:
2082 members1 = [cluster.center_index]
2084 members1 = cluster.members
2088 for n1
in cluster.members:
2093 tmp_rmsd, _ = self.
rmsd()
2098 precision = rmsd/npairs
2099 cluster.precision = precision
2104 Compute the bipartite precision (ie the cross-precision)
2105 between two clusters
2109 for cn0, n0
in enumerate(cluster1.members):
2111 for cn1, n1
in enumerate(cluster2.members):
2113 tmp_rmsd, _ = self.
rmsd()
2115 print(
"--- rmsd between structure %s and structure "
2116 "%s is %s" % (str(cn0), str(cn1), str(tmp_rmsd)))
2119 precision = rmsd/npairs
2122 def rmsf(self, cluster, molecule, copy_index=0, state_index=0,
2123 cluster_ref=
None, step=1):
2125 Compute the Root mean square fluctuations
2126 of a molecule in a cluster
2127 Returns an IMP.pmi.tools.OrderedDict() where the keys are the
2128 residue indexes and the value is the rmsf
2130 rmsf = IMP.pmi.tools.OrderedDict()
2133 if cluster_ref
is not None:
2134 if cluster_ref.center_index
is not None:
2135 members0 = [cluster_ref.center_index]
2137 members0 = cluster_ref.members
2139 if cluster.center_index
is not None:
2140 members0 = [cluster.center_index]
2142 members0 = cluster.members
2145 copy_index=copy_index, state_index=state_index)
2146 ps0 = s0.get_selected_particles()
2148 residue_indexes = list(IMP.pmi.tools.OrderedSet(
2154 d0 = self.stath0[n0]
2155 for n1
in cluster.members[::step]:
2157 print(
"--- rmsf %s %s" % (str(n0), str(n1)))
2161 self.stath1, molecule=molecule,
2162 residue_indexes=residue_indexes, resolution=1,
2163 copy_index=copy_index, state_index=state_index)
2164 ps1 = s1.get_selected_particles()
2166 d1 = self.stath1[n1]
2169 for n, (p0, p1)
in enumerate(zip(ps0, ps1)):
2170 r = residue_indexes[n]
2182 for stath
in [self.stath0, self.stath1]:
2183 if molecule
not in self.symmetric_molecules:
2185 stath, molecule=molecule, residue_index=r,
2186 resolution=1, copy_index=copy_index,
2187 state_index=state_index)
2190 stath, molecule=molecule, residue_index=r,
2191 resolution=1, state_index=state_index)
2193 ps = s.get_selected_particles()
2202 def save_densities(self, cluster, density_custom_ranges, voxel_size=5,
2203 reference=
"Absolute", prefix=
"./", step=1):
2209 for n1
in cluster.members[::step]:
2210 print(
"density "+str(n1))
2215 dens.add_subunits_density(self.stath1)
2217 dens.write_mrc(path=prefix+
'/', suffix=str(cluster.cluster_id))
2220 def contact_map(self, cluster, contact_threshold=15, log_scale=False,
2221 consolidate=
False, molecules=
None, prefix=
'./',
2222 reference=
"Absolute"):
2226 import matplotlib.pyplot
as plt
2227 import matplotlib.cm
as cm
2228 from scipy.spatial.distance
import cdist
2230 if molecules
is None:
2239 molecules=molecules).get_selected_particles())]
2240 unique_copies = [mol
for mol
in mols
if mol.get_copy_index() == 0]
2241 mol_names_unique = dict((mol.get_name(), mol)
for mol
in unique_copies)
2242 total_len_unique = sum(max(mol.get_residue_indexes())
2243 for mol
in unique_copies)
2250 seqlen = max(mol.get_residue_indexes())
2251 index_dict[mol] = range(prev_stop, prev_stop + seqlen)
2255 for mol
in unique_copies:
2256 seqlen = max(mol.get_residue_indexes())
2257 index_dict[mol] = range(prev_stop, prev_stop + seqlen)
2260 for ncl, n1
in enumerate(cluster.members):
2263 coord_dict = IMP.pmi.tools.OrderedDict()
2265 rindexes = mol.get_residue_indexes()
2266 coords = np.ones((max(rindexes), 3))
2267 for rnum
in rindexes:
2270 selpart = sel.get_selected_particles()
2271 if len(selpart) == 0:
2273 selpart = selpart[0]
2274 coords[rnum - 1, :] = \
2276 coord_dict[mol] = coords
2279 coords = np.concatenate(list(coord_dict.values()))
2280 dists = cdist(coords, coords)
2281 binary_dists = np.where((dists <= contact_threshold)
2282 & (dists >= 1.0), 1.0, 0.0)
2284 binary_dists_dict = {}
2286 len1 = max(mol1.get_residue_indexes())
2288 name1 = mol1.get_name()
2289 name2 = mol2.get_name()
2290 dists = cdist(coord_dict[mol1], coord_dict[mol2])
2291 if (name1, name2)
not in binary_dists_dict:
2292 binary_dists_dict[(name1, name2)] = \
2293 np.zeros((len1, len1))
2294 binary_dists_dict[(name1, name2)] += \
2295 np.where((dists <= contact_threshold)
2296 & (dists >= 1.0), 1.0, 0.0)
2297 binary_dists = np.zeros((total_len_unique, total_len_unique))
2299 for name1, name2
in binary_dists_dict:
2300 r1 = index_dict[mol_names_unique[name1]]
2301 r2 = index_dict[mol_names_unique[name2]]
2302 binary_dists[min(r1):max(r1)+1, min(r2):max(r2)+1] = \
2303 np.where((binary_dists_dict[(name1, name2)] >= 1.0),
2309 contact_freqs = binary_dists
2311 dist_maps.append(dists)
2312 av_dist_map += dists
2313 contact_freqs += binary_dists
2316 contact_freqs = -np.log(1.0-1.0/(len(cluster)+1)*contact_freqs)
2318 contact_freqs = 1.0/len(cluster)*contact_freqs
2319 av_dist_map = 1.0/len(cluster)*contact_freqs
2321 fig = plt.figure(figsize=(100, 100))
2322 ax = fig.add_subplot(111)
2325 gap_between_components = 50
2330 sorted_tuple = sorted(
2332 mol).get_extended_name(), mol)
for mol
in mols)
2333 prot_list = list(zip(*sorted_tuple))[1]
2335 sorted_tuple = sorted(
2337 for mol
in unique_copies)
2338 prot_list = list(zip(*sorted_tuple))[1]
2340 prot_listx = prot_list
2341 nresx = gap_between_components + \
2342 sum([max(mol.get_residue_indexes())
2343 + gap_between_components
for mol
in prot_listx])
2346 prot_listy = prot_list
2347 nresy = gap_between_components + \
2348 sum([max(mol.get_residue_indexes())
2349 + gap_between_components
for mol
in prot_listy])
2354 res = gap_between_components
2355 for mol
in prot_listx:
2356 resoffsetx[mol] = res
2357 res += max(mol.get_residue_indexes())
2359 res += gap_between_components
2363 res = gap_between_components
2364 for mol
in prot_listy:
2365 resoffsety[mol] = res
2366 res += max(mol.get_residue_indexes())
2368 res += gap_between_components
2370 resoffsetdiagonal = {}
2371 res = gap_between_components
2372 for mol
in IMP.pmi.tools.OrderedSet(prot_listx + prot_listy):
2373 resoffsetdiagonal[mol] = res
2374 res += max(mol.get_residue_indexes())
2375 res += gap_between_components
2380 for n, prot
in enumerate(prot_listx):
2381 res = resoffsetx[prot]
2383 for proty
in prot_listy:
2384 resy = resoffsety[proty]
2385 endy = resendy[proty]
2386 ax.plot([res, res], [resy, endy], linestyle=
'-',
2387 color=
'gray', lw=0.4)
2388 ax.plot([end, end], [resy, endy], linestyle=
'-',
2389 color=
'gray', lw=0.4)
2390 xticks.append((float(res) + float(end)) / 2)
2392 prot).get_extended_name())
2396 for n, prot
in enumerate(prot_listy):
2397 res = resoffsety[prot]
2399 for protx
in prot_listx:
2400 resx = resoffsetx[protx]
2401 endx = resendx[protx]
2402 ax.plot([resx, endx], [res, res], linestyle=
'-',
2403 color=
'gray', lw=0.4)
2404 ax.plot([resx, endx], [end, end], linestyle=
'-',
2405 color=
'gray', lw=0.4)
2406 yticks.append((float(res) + float(end)) / 2)
2408 prot).get_extended_name())
2412 tmp_array = np.zeros((nresx, nresy))
2414 for px
in prot_listx:
2415 for py
in prot_listy:
2416 resx = resoffsetx[px]
2417 lengx = resendx[px] - 1
2418 resy = resoffsety[py]
2419 lengy = resendy[py] - 1
2420 indexes_x = index_dict[px]
2421 minx = min(indexes_x)
2422 maxx = max(indexes_x)
2423 indexes_y = index_dict[py]
2424 miny = min(indexes_y)
2425 maxy = max(indexes_y)
2426 tmp_array[resx:lengx, resy:lengy] = \
2427 contact_freqs[minx:maxx, miny:maxy]
2428 ret[(px, py)] = np.argwhere(
2429 contact_freqs[minx:maxx, miny:maxy] == 1.0) + 1
2431 ax.imshow(tmp_array, cmap=colormap, norm=colornorm,
2432 origin=
'lower', alpha=0.6, interpolation=
'nearest')
2434 ax.set_xticks(xticks)
2435 ax.set_xticklabels(xlabels, rotation=90)
2436 ax.set_yticks(yticks)
2437 ax.set_yticklabels(ylabels)
2438 plt.setp(ax.get_xticklabels(), fontsize=6)
2439 plt.setp(ax.get_yticklabels(), fontsize=6)
2442 fig.set_size_inches(0.005 * nresx, 0.005 * nresy)
2443 [i.set_linewidth(2.0)
for i
in ax.spines.values()]
2445 plt.savefig(prefix+
"/contact_map."+str(cluster.cluster_id)+
".pdf",
2446 dpi=300, transparent=
"False")
2449 def plot_rmsd_matrix(self, filename):
2450 self.compute_all_pairwise_rmsd()
2451 distance_matrix = np.zeros(
2452 (len(self.stath0), len(self.stath1)))
2453 for (n0, n1)
in self.pairwise_rmsd:
2454 distance_matrix[n0, n1] = self.pairwise_rmsd[(n0, n1)]
2456 import matplotlib
as mpl
2458 import matplotlib.pylab
as pl
2459 from scipy.cluster
import hierarchy
as hrc
2461 fig = pl.figure(figsize=(10, 8))
2462 ax = fig.add_subplot(212)
2463 dendrogram = hrc.dendrogram(
2464 hrc.linkage(distance_matrix),
2467 leaves_order = dendrogram[
'leaves']
2468 ax.set_xlabel(
'Model')
2469 ax.set_ylabel(
'RMSD [Angstroms]')
2471 ax2 = fig.add_subplot(221)
2473 distance_matrix[leaves_order, :][:, leaves_order],
2474 interpolation=
'nearest')
2475 cb = fig.colorbar(cax)
2476 cb.set_label(
'RMSD [Angstroms]')
2477 ax2.set_xlabel(
'Model')
2478 ax2.set_ylabel(
'Model')
2480 pl.savefig(filename, dpi=300)
2489 Update the cluster id numbers
2491 for n, c
in enumerate(self.clusters):
2494 def get_molecule(self, hier, name, copy):
2502 self.seldict0 = IMP.pmi.tools.get_selections_dictionary(
2503 self.sel0_rmsd.get_selected_particles())
2504 self.seldict1 = IMP.pmi.tools.get_selections_dictionary(
2505 self.sel1_rmsd.get_selected_particles())
2506 for mol
in self.seldict0:
2507 for sel
in self.seldict0[mol]:
2508 self.issymmetricsel[sel] =
False
2509 for mol
in self.symmetric_molecules:
2510 self.symmetric_molecules[mol] = len(self.seldict0[mol])
2511 for sel
in self.seldict0[mol]:
2512 self.issymmetricsel[sel] =
True
2516 self.sel1_alignment, self.sel0_alignment)
2518 for rb
in self.rbs1:
2521 for bead
in self.beads1:
2529 def aggregate(self, idxs, rmsd_cutoff=10, metric=IMP.atom.get_rmsd):
2531 initial filling of the clusters.
2534 print(
"clustering model "+str(n0))
2535 d0 = self.stath0[n0]
2537 print(
"creating cluster index "+str(len(self.clusters)))
2538 self.clusters.append(c)
2539 c.add_member(n0, d0)
2540 clustered = set([n0])
2542 print(
"--- trying to add model " + str(n1) +
" to cluster "
2543 + str(len(self.clusters)))
2544 d1 = self.stath1[n1]
2547 rmsd, _ = self.
rmsd(metric=metric)
2548 if rmsd < rmsd_cutoff:
2549 print(
"--- model "+str(n1)+
" added, rmsd="+str(rmsd))
2550 c.add_member(n1, d1)
2553 print(
"--- model "+str(n1)+
" NOT added, rmsd="+str(rmsd))
2558 merge the clusters that have close members
2560 @param rmsd_cutoff cutoff distance in Angstorms
2561 @param metric Function to calculate distance between two Selections
2562 (by default, IMP.atom.get_rmsd is used)
2570 for c0, c1
in filter(
lambda x: len(x[0].members) > 1,
2571 itertools.combinations(self.clusters, 2)):
2572 n0, n1 = [c.members[0]
for c
in (c0, c1)]
2575 rmsd, _ = self.
rmsd()
2576 if (rmsd < 2*rmsd_cutoff
and
2578 to_merge.append((c0, c1))
2580 for c0, c
in reversed(to_merge):
2584 self.clusters = [c
for c
in
2585 filter(
lambda x: len(x.members) > 0, self.clusters)]
2589 returns true if c0 and c1 have members that are closer than rmsd_cutoff
2591 print(
"check close members for clusters " + str(c0.cluster_id) +
2592 " and " + str(c1.cluster_id))
2593 for n0, n1
in itertools.product(c0.members[1:], c1.members):
2596 rmsd, _ = self.
rmsd(metric=metric)
2597 if rmsd < rmsd_cutoff:
2612 a function that returns the permutation best_sel of sels0 that
2615 best_rmsd2 = float(
'inf')
2617 if self.issymmetricsel[sels0[0]]:
2620 for offset
in range(N):
2621 sels = [sels0[(offset+i) % N]
for i
in range(N)]
2624 r = metric(sel0, sel1)
2626 if rmsd2 < best_rmsd2:
2630 for sels
in itertools.permutations(sels0):
2632 for sel0, sel1
in itertools.takewhile(
2633 lambda x: rmsd2 < best_rmsd2, zip(sels, sels1)):
2634 r = metric(sel0, sel1)
2636 if rmsd2 < best_rmsd2:
2639 return best_sel, best_rmsd2
2641 def compute_all_pairwise_rmsd(self):
2642 for d0
in self.stath0:
2643 for d1
in self.stath1:
2644 rmsd, _ = self.
rmsd()
2646 def rmsd(self, metric=IMP.atom.get_rmsd):
2648 Computes the RMSD. Resolves ambiguous pairs assignments
2652 n0 = self.stath0.current_index
2653 n1 = self.stath1.current_index
2654 if ((n0, n1)
in self.pairwise_rmsd) \
2655 and ((n0, n1)
in self.pairwise_molecular_assignment):
2656 return (self.pairwise_rmsd[(n0, n1)],
2657 self.pairwise_molecular_assignment[(n0, n1)])
2667 molecular_assignment = {}
2668 for molname, sels0
in self.seldict0.items():
2669 sels_best_order, best_rmsd2 = \
2670 self.
rmsd_helper(sels0, self.seldict1[molname], metric)
2672 Ncoords = len(sels_best_order[0].get_selected_particles())
2673 Ncopies = len(self.seldict1[molname])
2674 total_rmsd += Ncoords*best_rmsd2
2675 total_N += Ncoords*Ncopies
2677 for sel0, sel1
in zip(sels_best_order, self.seldict1[molname]):
2678 p0 = sel0.get_selected_particles()[0]
2679 p1 = sel1.get_selected_particles()[0]
2684 molecular_assignment[(molname, c0)] = (molname, c1)
2686 total_rmsd = math.sqrt(total_rmsd/total_N)
2688 self.pairwise_rmsd[(n0, n1)] = total_rmsd
2689 self.pairwise_molecular_assignment[(n0, n1)] = molecular_assignment
2690 self.pairwise_rmsd[(n1, n0)] = total_rmsd
2691 self.pairwise_molecular_assignment[(n1, n0)] = molecular_assignment
2692 return total_rmsd, molecular_assignment
2696 Fix the reference structure for structural alignment, rmsd and
2699 @param reference can be either "Absolute" (cluster center of the
2700 first cluster) or Relative (cluster center of the current
2702 #param cluster the reference IMP.pmi.output.Cluster object
2704 if reference ==
"Absolute":
2706 elif reference ==
"Relative":
2707 if cluster.center_index:
2708 n0 = cluster.center_index
2710 n0 = cluster.members[0]
2715 compute the molecular assignments between multiple copies
2716 of the same sequence. It changes the Copy index of Molecules
2719 _, molecular_assignment = self.
rmsd()
2720 for (m0, c0), (m1, c1)
in molecular_assignment.items():
2721 mol0 = self.molcopydict0[m0][c0]
2722 mol1 = self.molcopydict1[m1][c1]
2725 p1.set_value(cik0, c0)
2729 Undo the Copy index assignment
2732 _, molecular_assignment = self.
rmsd()
2733 for (m0, c0), (m1, c1)
in molecular_assignment.items():
2734 mol0 = self.molcopydict0[m0][c0]
2735 mol1 = self.molcopydict1[m1][c1]
2738 p1.set_value(cik0, c1)
2745 s =
"AnalysisReplicaExchange\n"
2746 s +=
"---- number of clusters %s \n" % str(len(self.clusters))
2747 s +=
"---- number of models %s \n" % str(len(self.stath0))
2750 def __getitem__(self, int_slice_adaptor):
2751 if isinstance(int_slice_adaptor, int):
2752 return self.clusters[int_slice_adaptor]
2753 elif isinstance(int_slice_adaptor, slice):
2754 return self.__iter__(int_slice_adaptor)
2756 raise TypeError(
"Unknown Type")
2759 return len(self.clusters)
2761 def __iter__(self, slice_key=None):
2762 if slice_key
is None:
2763 for i
in range(len(self)):
2766 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.