IMP logo
IMP Reference Guide  develop.6f18bfa751,2025/09/20
The Integrative Modeling Platform
movers.py
1 import IMP
2 import IMP.core
3 import IMP.algebra
4 import itertools
5 import math
6 import random
7 import numpy as np
8 import scipy.spatial
9 import networkx as nx
10 from IMP.pmi.tools import get_restraint_set
11 
12 
13 class MoverScheme(object):
14  def __init__(self, length):
15  self.length = length
16  self.mover_scheme = None
17  self.score_scheme = {}
18  self.score_initial_weights = {}
19  self.position = 0
20  self.numbermc = 0
21 
22  def add_mover_scheme(self, mover_scheme):
23  if len(mover_scheme) != self.length:
24  raise ("Error")
25  else:
26  mc_scheme = []
27  for mvs in mover_scheme:
28  smv = IMP.core.SerialMover(mvs)
29  mc = IMP.core.MonteCarlo(mvs[0].get_model())
30  mc.set_scoring_function(get_restraint_set(mvs[0].get_model()))
31  mc.set_return_best(False)
32  mc.set_kt(1.0)
33  mc.add_mover(smv)
34  mc_scheme.append(mc)
35  mc.set_name(str(self.numbermc))
36  self.numbermc += 1
37  self.mover_scheme = mc_scheme
38 
39  def add_montecarlo_temperatures(self, temps):
40  self.temps = temps
41 
42  def add_montecarlo_steps(self, steps):
43  self.steps = steps
44 
45  def add_score_scheme(self, score, weigth_scheme):
46  if len(weigth_scheme) != self.length:
47  raise ("Error")
48  else:
49  self.score_scheme[score] = weigth_scheme
50  self.score_initial_weights[score] = score.get_weight()
51 
52  def get_length(self):
53  return self.length
54 
55  def get_position(self, position):
56  movers = self.mover_scheme[position]
57  score_tmp_dict = {}
58  for score in self.score_scheme:
59  score_tmp_dict[score] = self.score_scheme[score][position]
60  return movers, score_tmp_dict
61 
62  def get_and_update(self):
63  mc, score_tmp_dict = self.get_position(self.position)
64  temp = self.temps[self.position]
65  mc.set_kt(temp)
66  steps = self.steps[self.position]
67  self.position += 1
68  if self.position > self.length - 1:
69  self.position = 0
70  return mc, score_tmp_dict, steps
71 
72 
73 class HybridMonteCarloMover(IMP.core.MonteCarloMover):
74  def __init__(self, m, hier, MoverScheme):
75  IMP.core.MonteCarloMover.__init__(
76  self,
77  m,
78  "HybridMonteCarloMover")
79 
80  self.mols = IMP.pmi.tools.get_molecules(hier)
81  self.refframes = {}
82  self.xyzs = {}
83  self.ps = []
84  self.m = m
85  self.rejects = []
86  self.lenrejects = 20
87 
88  self.rbs, self.beads = IMP.pmi.tools.get_rbs_and_beads([hier])
89  for rb in self.rbs:
90  self.ps.append(rb.get_particle())
91  for bead in self.beads:
92  self.ps.append(bead.get_particle())
93 
94  self.indexes = [p.get_index() for p in self.ps]
95 
96  self.do_store_current_coordinates()
97 
98  self.mover_scheme = MoverScheme
99 
100  def do_store_current_coordinates(self):
101  for rb in self.rbs:
102  self.refframes[rb] = rb.get_reference_frame()
103  for bead in self.beads:
104  self.xyzs[bead] = IMP.core.XYZ(bead).get_coordinates()
105 
106  def do_propose(self):
107 
108  self.rejects.append(0)
109  if len(self.rejects) > self.lenrejects:
110  self.rejects.pop(0)
111  print
112  self.rejects, float(sum(self.rejects)) / len(self.rejects)
113 
114  self.do_store_current_coordinates()
115 
116  # rs = get_restraint_set(self.m)
117  # print "Initial",rs.evaluate(False)
118 
119  for i in range(self.mover_scheme.get_length()):
120  mc, score_tmp_dict, steps = self.mover_scheme.get_and_update()
121 
122  mc.reset_statistics()
123 
124  for score in score_tmp_dict:
125  score.set_weight(score_tmp_dict[score])
126 
127  mc.optimize(steps)
128 
129  print(mc.get_name(),
130  float(mc.get_number_of_accepted_steps())
131  / mc.get_number_of_proposed_steps())
132  # print i,steps,rs.evaluate(False)
133 
134  # print "Final",rs.evaluate(False)
135 
136  return IMP.core.MonteCarloMoverResult(self.indexes, 1.0)
137 
138  def do_reject(self):
139  print
140  "REJECT"
141  self.rejects[-1] = 1
142  for rb in self.refframes:
143  rb.set_reference_frame(self.refframes[rb])
144  for bead in self.xyzs:
145  IMP.core.XYZ(bead).set_coordinates(self.xyzs[bead])
146 
147  def do_get_inputs(self):
148  return self.ps
149 
150 
151 class PCAMover(IMP.core.MonteCarloMover):
152  def __init__(self, m, hier, resolution=10, depth=4):
153 
154  IMP.core.MonteCarloMover.__init__(
155  self,
156  m,
157  "PCAMover")
158  self.depth = depth
159  self.propose = 0
160  self.reject = 0
161  self.rejects = []
162  self.lenrejects = 20
163  self.mols = IMP.pmi.tools.get_molecules(hier)
164  self.resolution = resolution
165  self.rbsd = {}
166  self.beadsd = {}
167  self.refframes = {}
168  self.xyzs = {}
169  self.ps = []
170  self.particle_blocks = []
171  for mol in self.mols:
172  rbs, beads = IMP.pmi.tools.get_rbs_and_beads([mol])
173  self.rbsd[mol] = rbs
174  self.beadsd[mol] = beads
175  for rb in self.rbsd[mol]:
176  self.ps.append(rb.get_particle())
177  for bead in self.beadsd[mol]:
178  self.ps.append(bead.get_particle())
179  ps = IMP.atom.Selection(
180  mol, resolution=self.resolution).get_selected_particles()
181  self.particle_blocks.append(ps)
182 
183  self.do_store_current_coordinates()
184 
185  def do_store_current_coordinates(self):
186  for mol in self.mols:
187  for rb in self.rbsd[mol]:
188  self.refframes[rb] = rb.get_reference_frame()
189  for bead in self.beadsd[mol]:
190  self.xyzs[bead] = IMP.core.XYZ(bead).get_coordinates()
191 
192  def get_full_graph(self):
193  '''
194  get the full graph of distances between every particle pair
195  '''
196 
197  pdist_array = np.array(
199  self.particle_blocks))
200  pdist_mat = scipy.spatial.distance.squareform(pdist_array)
201  pdist_mat[pdist_mat <= 10] = 1
202  pdist_mat[pdist_mat > 10] = 0
203  graph = nx.Graph(pdist_mat)
204  return graph
205 
206  def get_list_of_interacting_molecules(self, succ_dict, pointer):
207  if pointer in succ_dict:
208  paths = [path for p in succ_dict[pointer] for path in
209  self.get_list_of_interacting_molecules(succ_dict, p)]
210  ret = [[pointer] + path for path in paths]
211  # print pointer,paths,ret
212  return ret
213  else:
214  return [[pointer]]
215 
216  def get_minimum_spanning_tree(self):
217  """
218  return the minimum spanning tree
219  """
220  graph = self.get_full_graph()
221  graph = nx.minimum_spanning_tree(graph)
222  return graph
223 
224  def get_sublists(self, lst, size):
225  result = [sublist for sublist in
226  (lst[x:x + size] for x in range(len(lst) - size + 1))]
227  return result
228 
229  def get_list_of_connected_mols(self, depth):
230  gr = self.get_minimum_spanning_tree()
231  all_groups = set()
232  if len(gr.edges()) > 0:
233 
234  for node in gr.nodes():
235  succ_dict = nx.dfs_successors(gr, node)
236  paths = [path for p in succ_dict[node] for path in
237  self.get_list_of_interacting_molecules(succ_dict, p)]
238  ret = [[node] + path for path in paths]
239  for path in ret:
240  for s in range(2, min([depth + 1, len(path) + 1,
241  len(self.mols)])):
242  subls = self.get_sublists(path, s)
243  for subl in subls:
244  all_groups.add(frozenset(subl))
245  return all_groups
246  # succ=nx.bfs_successors(gr,0)
247 
248  def do_compute_pcas(self):
249  self.singletons = {}
250  for i, ps in enumerate(self.particle_blocks):
251  mol = self.mols[i]
253  [IMP.core.XYZ(p).get_coordinates() for p in ps])
254  # MB normalize
255  pcan = IMP.bayesianem.NormalizePCA(pca, ps)
256  self.singletons[(mol,)] = pcan
257 
258  if self.depth > 1:
259  all_groups = self.get_list_of_connected_mols(self.depth)
260 
261  for group in all_groups:
262  mols = [self.mols[n] for n in group]
263  ps = IMP.atom.Selection(
264  mols, resolution=self.resolution).get_selected_particles()
266  [IMP.core.XYZ(p).get_coordinates() for p in ps])
267  pcan = IMP.bayesianem.NormalizePCA(pca, ps)
268  self.singletons[tuple(mols)] = pcan
269 
270  def do_get_pairs(self, temp=20):
271  sk = self.singletons.keys()
272 
273  pairs = []
274  for s1, s2 in itertools.combinations(sk, 2):
276  self.singletons[s1].get_principal_values(),
277  self.singletons[s2].get_principal_values())
278  pairs.append(((s1, s2), math.exp(-rms / temp)))
279 
280  return pairs
281 
282  def do_compute_transforms(self, pair):
283  amols = pair[0]
284  bmols = pair[1]
285 
286  arbs = []
287  abeads = []
288  for mol in amols:
289  arbs += self.rbsd[mol]
290  abeads += self.beadsd[mol]
291  apca = self.singletons[amols]
292 
293  brbs = []
294  bbeads = []
295  for mol in bmols:
296  brbs += self.rbsd[mol]
297  bbeads += self.beadsd[mol]
298  bpca = self.singletons[bmols]
299 
300  # transatob=IMP.algebra.get_alignments_from_first_to_second(apca,bpca)
301  # MB get single transformation
302  transatob = IMP.bayesianem.PCAalign(apca, bpca)[0]
303  transbtoa = transatob.get_inverse()
304 
305  return (transatob, transbtoa, arbs, abeads, brbs, bbeads)
306 
307  def weighted_choice(self, choices):
308  total = sum(w for c, w in choices)
309  r = random.uniform(0, total)
310  upto = 0
311  for c, w in choices:
312  if upto + w >= r:
313  return c
314  upto += w
315  assert False, "Shouldn't get here"
316 
317  def do_propose(self):
318  self.rejects.append(0)
319  if len(self.rejects) > self.lenrejects:
320  self.rejects.pop(0)
321 
322  self.propose += 1
323  self.do_store_current_coordinates()
324  self.do_compute_pcas()
325  pairs = self.do_get_pairs()
326  pair = self.weighted_choice(pairs)
327  t = self.do_compute_transforms(pair)
328  # (ta2b,tb2a)=random.choice(zip(t[0],t[1]))
329  # MB no need to randomly select
330  (ta2b, tb2a) = (t[0], t[1])
331 
332  moved_indexes = []
333  for arb in t[2]:
334  IMP.core.transform(arb, ta2b)
335  moved_indexes.append(arb.get_particle_index())
336  for abead in t[3]:
337  IMP.core.transform(IMP.core.XYZ(abead), ta2b)
338  moved_indexes.append(arb.get_particle_index())
339  for brb in t[4]:
340  IMP.core.transform(brb, tb2a)
341  for bbead in t[5]:
342  IMP.core.transform(IMP.core.XYZ(bbead), tb2a)
343  return IMP.core.MonteCarloMoverResult(moved_indexes, 1.0)
344 
345  def do_reject(self):
346  self.rejects[-1] = 1
347 
348  self.reject += 1
349  for rb in self.refframes:
350  rb.set_reference_frame(self.refframes[rb])
351  for bead in self.xyzs:
352  IMP.core.XYZ(bead).set_coordinates(self.xyzs[bead])
353 
354  def do_get_inputs(self):
355  return self.ps
A Monte Carlo optimizer.
Definition: MonteCarlo.h:44
IMP::algebra::Transformation3Ds PCAalign(const IMP::algebra::PrincipalComponentAnalysis &pca1, const IMP::algebra::PrincipalComponentAnalysis &pca2)
def get_molecules
This function returns the parent molecule hierarchies of given objects.
Definition: pmi/tools.py:1159
Miscellaneous utilities.
Definition: pmi/tools.py:1
Return value of the MonteCarloMover::propose() function.
IMP::algebra::PrincipalComponentAnalysis NormalizePCA(const IMP::algebra::PrincipalComponentAnalysis &pca, const IMP::Particles &ps)
void transform(XYZ a, const algebra::Transformation3D &tr)
Apply a transformation to the particle.
A base class for classes which perturb particles.
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
PrincipalComponentAnalysisD< D > get_principal_components(const Vector< VectorD< D > > &ps)
Perform principal components analysis on a set of vectors.
Basic functionality that is expected to be used by a wide variety of IMP users.
General purpose algebraic and geometric methods that are expected to be used by a wide variety of IMP...
double get_distance(const VectorD< D > &v1, const VectorD< D > &v2)
Compute the distance between two vectors.
Definition: VectorD.h:196
Floats get_list_of_bipartite_minimum_sphere_distance(const ParticlesTemps &pss)
Definition: pmi/utilities.h:71
def get_rbs_and_beads
Returns unique objects in original order.
Definition: pmi/tools.py:1135
Select hierarchy particles identified by the biological name.
Definition: Selection.h:70
Applies a list of movers one at a time.
Definition: SerialMover.h:26