IMP  2.3.1
The Integrative Modeling Platform
samplers.py
1 """@namespace IMP.pmi.samplers
2  Sampling of the system.
3 """
4 
5 import IMP
6 import IMP.core
7 
8 class _SerialReplicaExchange(object):
9  """Dummy replica exchange class used in non-MPI builds.
10  It should act similarly to IMP.mpi.ReplicaExchange on a single processor.
11  """
12  def __init__(self):
13  self.__params = {}
14  def get_number_of_replicas(self):
15  return 1
16  def create_temperatures(self, tmin, tmax, nrep):
17  return [tmin]
18  def get_my_index(self):
19  return 0
20  def set_my_parameter(self, key, val):
21  self.__params[key] = val
22  def get_my_parameter(self, key):
23  return self.__params[key]
24  def get_friend_index(self, step):
25  return 0
26  def get_friend_parameter(self, key, findex):
27  return self.get_my_parameter(key)
28  def do_exchange(self, myscore, fscore, findex):
29  return False
30 
31 
32 class MonteCarlo(object):
33 
34  # check that isd is installed
35  try:
36  import IMP.isd
37  isd_available = True
38  except ImportError:
39  isd_available = False
40 
41  def __init__(self, m, objects, temp, filterbyname=None):
42  '''
43  check that the objects containts get_particles_to_sample methods
44  and the particle type is supported
45  list of particles to sample self.losp
46  '''
47 
48  self.losp = [
49  "Rigid_Bodies",
50  "Floppy_Bodies",
51  "Nuisances",
52  "X_coord",
53  "Weights"]
54  self.simulated_annealing = False
55  self.selfadaptive = False
56  # that is -1 because mc has not yet run
57  self.nframe = -1
58  self.temp = temp
59  self.mvs = []
60  self.mvslabels = []
61  self.label = "None"
62  self.m = m
63 
64  for ob in objects:
65  try:
66  ob.get_particles_to_sample()
67  except:
68  print "MonteCarlo: object ", ob, " doesn't have get_particles_to_sample() method"
69 
70  pts = ob.get_particles_to_sample()
71  for k in pts.keys():
72 
73  if "Rigid_Bodies" in k:
74  mvs = self.get_rigid_body_movers(
75  pts[k][0],
76  pts[k][1],
77  pts[k][2])
78  for mv in mvs:
79  mv.set_name(k)
80  self.mvs += mvs
81 
82  if "SR_Bodies" in k:
83  print len(pts[k])
84  mvs = self.get_super_rigid_body_movers(
85  pts[k][0],
86  pts[k][1],
87  pts[k][2])
88  for mv in mvs:
89  mv.set_name(k)
90  self.mvs += mvs
91 
92  if "Floppy_Bodies" in k:
93  mvs = self.get_floppy_body_movers(pts[k][0], pts[k][1])
94  for mv in mvs:
95  mv.set_name(k)
96  self.mvs += mvs
97 
98  if "X_coord" in k:
99  mvs = self.get_X_movers(pts[k][0], pts[k][1])
100  for mv in mvs:
101  mv.set_name(k)
102  self.mvs += mvs
103 
104  if "Nuisances" in k:
105  if not self.isd_available:
106  raise ValueError("isd module needed to use nuisances")
107  mvs = self.get_nuisance_movers(pts[k][0], pts[k][1])
108  for mv in mvs:
109  mv.set_name(k)
110  self.mvs += mvs
111 
112  if "Weights" in k:
113  if not self.isd_available:
114  raise ValueError("isd module needed to use weights")
115  mvs = self.get_weight_movers(pts[k][0], pts[k][1])
116  for mv in mvs:
117  mv.set_name(k)
118  self.mvs += mvs
119 
120  # SerialMover
121  self.smv = IMP.core.SerialMover(self.mvs)
122 
123  self.mc = IMP.core.MonteCarlo(self.m)
124  self.mc.set_return_best(False)
125  self.mc.set_kt(self.temp)
126  self.mc.add_mover(self.smv)
127 
128  def set_kt(self, temp):
129  self.temp = temp
130  self.mc.set_kt(temp)
131 
132  def get_mc(self):
133  return self.mc
134 
135  def set_scoring_function(self, objectlist):
136  rs = IMP.RestraintSet(self.m, 1.0, 'sfo')
137  for ob in objectlist:
138  rs.add_restraint(ob.get_restraint())
140  self.mc.set_scoring_function(sf)
141 
142  def set_simulated_annealing(
143  self,
144  min_temp,
145  max_temp,
146  min_temp_time,
147  max_temp_time):
148  self.simulated_annealing = True
149  self.tempmin = min_temp
150  self.tempmax = max_temp
151  self.timemin = min_temp_time
152  self.timemax = max_temp_time
153 
154  def set_self_adaptive(self, isselfadaptive=True):
155  self.selfadaptive = isselfadaptive
156 
157  def get_nuisance_movers_parameters(self):
158  '''returns a dictionary with the mover parameters
159  for nuisance parameters'''
160  output = {}
161  for i in range(self.get_number_of_movers()):
162  mv = self.smv.get_mover(i)
163  name = mv.get_name()
164  if "Nuisances" in name:
165  stepsize = IMP.core.NormalMover.get_from(mv).get_sigma()
166  output[name] = stepsize
167  return output
168 
169  def get_number_of_movers(self):
170  return len(self.smv.get_movers())
171 
172  def get_particle_types():
173  return self.losp
174 
175  def optimize(self, nstep):
176  self.nframe += 1
177  self.mc.optimize(nstep * self.get_number_of_movers())
178 
179  # apply simulated annealing protocol
180  if self.simulated_annealing:
181  self.temp = self.temp_simulated_annealing()
182  self.mc.set_kt(self.temp)
183 
184  # apply self adaptive protocol
185  if self.selfadaptive:
186  for i, mv in enumerate(self.smv.get_movers()):
187  name = mv.get_name()
188 
189  if "Nuisances" in name:
190  mvacc = mv.get_number_of_accepted()
191  mvprp = mv.get_number_of_proposed()
192  accept = float(mvacc) / float(mvprp)
193  nmv = IMP.core.NormalMover.get_from(mv)
194  stepsize = nmv.get_sigma()
195 
196  if 0.4 > accept or accept > 0.6:
197  nmv.set_sigma(stepsize * 2 * accept)
198  if accept < 0.05:
199  accept = 0.05
200  nmv.set_sigma(stepsize * 2 * accept)
201  if accept > 1.0:
202  accept = 1.0
203  nmv.set_sigma(stepsize * 2 * accept)
204 
205  if "Weights" in name:
206 
207  mvacc = mv.get_number_of_accepted()
208  mvprp = mv.get_number_of_proposed()
209  accept = float(mvacc) / float(mvprp)
210  wmv = IMP.isd.WeightMover.get_from(mv)
211  stepsize = wmv.get_radius()
212 
213  if 0.4 > accept or accept > 0.6:
214  wmv.set_radius(stepsize * 2 * accept)
215  if accept < 0.05:
216  accept = 0.05
217  wmv.set_radius(stepsize * 2 * accept)
218  if accept > 1.0:
219  accept = 1.0
220  wmv.set_radius(stepsize * 2 * accept)
221 
222  def run(self, *args, **kwargs):
223  IMP.pmi.tools.print_deprecation_warning(
224  "MonteCarlo.run",
225  "MonteCarlo.optimize")
226  self.optimize(*args, **kwargs)
227 
228  def get_nuisance_movers(self, nuisances, maxstep):
229  mvs = []
230  for nuisance in nuisances:
231  print nuisance, maxstep
232  mvs.append(
233  IMP.core.NormalMover([nuisance],
234  IMP.FloatKeys([IMP.FloatKey("nuisance")]),
235  maxstep))
236  return mvs
237 
238  def get_rigid_body_movers(self, rbs, maxtrans, maxrot):
239  mvs = []
240  for rb in rbs:
241  mvs.append(IMP.core.RigidBodyMover(rb, maxtrans, maxrot))
242  return mvs
243 
244  def get_super_rigid_body_movers(self, rbs, maxtrans, maxrot):
245  mvs = []
246  for rb in rbs:
247  if len(rb) == 2:
248  # normal Super Rigid Body
249  srbm = IMP.pmi.TransformMover(self.m, maxtrans, maxrot)
250  if len(rb) == 3:
251  # super rigid body with 2D rotation, rb[2] is the axis
252  srbm = IMP.pmi.TransformMover(
253  self.m,
254  IMP.algebra.Vector3D(rb[2]),
255  maxtrans,
256  maxrot)
257  for xyz in rb[0]:
258  srbm.add_xyz_particle(xyz)
259  for rb in rb[1]:
260  srbm.add_rigid_body_particle(rb)
261  mvs.append(srbm)
262  return mvs
263 
264  def get_floppy_body_movers(self, fbs, maxtrans):
265  mvs = []
266  for fb in fbs:
267  # check is that is a rigid body member:
269  # if so force the particles to move anyway
270  floatkeys = [IMP.FloatKey(4), IMP.FloatKey(5), IMP.FloatKey(6)]
271  for fk in floatkeys:
272  fb.set_is_optimized(fk, True)
273  mvs.append(
274  IMP.core.BallMover([fb],
275  IMP.FloatKeys(floatkeys),
276  maxtrans))
277  else:
278  # otherwise use the normal ball mover
279  mvs.append(IMP.core.BallMover([fb], maxtrans))
280  return mvs
281 
282  def get_X_movers(self, fbs, maxtrans):
283  mvs = []
284  Xfloatkey = IMP.core.XYZ.get_xyz_keys()[0]
285  for fb in fbs:
286  # check is that is a rigid body member:
288  raise ValueError("particle is part of a rigid body")
289  else:
290  # otherwise use the normal ball mover
291  mvs.append(IMP.core.NormalMover([fb], [Xfloatkey], maxtrans))
292  return mvs
293 
294  def get_weight_movers(self, weights, maxstep):
295  mvs = []
296  for weight in weights:
297  if(weight.get_number_of_states() > 1):
298  mvs.append(IMP.isd.WeightMover(weight, maxstep))
299  return mvs
300 
301  def temp_simulated_annealing(self):
302  if self.nframe % (self.timemin + self.timemax) < self.timemin:
303  value = 0.0
304  else:
305  value = 1.0
306  temp = self.tempmin + (self.tempmax - self.tempmin) * value
307  return temp
308 
309  def set_label(self, label):
310  self.label = label
311 
312  def get_frame_number(self):
313  return self.nframe
314 
315  def get_output(self):
316  output = {}
317  acceptances = []
318  for i, mv in enumerate(self.smv.get_movers()):
319  mvname = mv.get_name()
320  mvacc = mv.get_number_of_accepted()
321  mvprp = mv.get_number_of_proposed()
322  try:
323  mvacr = float(mvacc) / float(mvprp)
324  except:
325  mvacr = 0.0
326  output["MonteCarlo_Acceptance_" +
327  mvname + "_" + str(i)] = str(mvacr)
328  if "Nuisances" in mvname:
329  output["MonteCarlo_StepSize_" + mvname + "_" +
330  str(i)] = str(IMP.core.NormalMover.get_from(mv).get_sigma())
331  if "Weights" in mvname:
332  output["MonteCarlo_StepSize_" + mvname + "_" +
333  str(i)] = str(IMP.isd.WeightMover.get_from(mv).get_radius())
334  output["MonteCarlo_Temperature"] = str(self.mc.get_kt())
335  output["MonteCarlo_Nframe"] = str(self.nframe)
336  return output
337 
338 
339 class MolecularDynamics(object):
340  def __init__(self,m,objects,kt,gamma=0.01,maximum_time_step=1.0):
341  self.m=m
342  to_sample=[]
343  for obj in objects:
344  to_sample+=obj.get_particles_to_sample()['Floppy_Bodies_SimplifiedModel'][0]
345  self.ltstate=IMP.atom.LangevinThermostatOptimizerState(self.m,to_sample,
346  kt/0.0019872041,
347  gamma)
348  self.md = IMP.atom.MolecularDynamics(self.m)
349  self.md.set_maximum_time_step(maximum_time_step)
350  self.md.add_optimizer_state(self.ltstate)
351  self.simulated_annealing = False
352 
353  def set_kt(self,kt):
354  temp=kt/0.0019872041
355  self.ltstate.set_temperature(temp)
356  self.md.assign_velocities(temp)
357 
358  def set_simulated_annealing(
359  self,
360  min_temp,
361  max_temp,
362  min_temp_time,
363  max_temp_time):
364  self.simulated_annealing = True
365  self.tempmin = min_temp
366  self.tempmax = max_temp
367  self.timemin = min_temp_time
368  self.timemax = max_temp_time
369 
370  def temp_simulated_annealing(self):
371  if self.nframe % (self.timemin + self.timemax) < self.timemin:
372  value = 0.0
373  else:
374  value = 1.0
375  temp = self.tempmin + (self.tempmax - self.tempmin) * value
376  return temp
377 
378  def set_gamma(self,gamma):
379  self.ltstate.set_gamma(gamma)
380 
381  def optimize(self,nsteps):
382  # apply simulated annealing protocol
383  if self.simulated_annealing:
384  self.temp = self.temp_simulated_annealing()
385  self.set_kt(self.temp)
386  self.md.optimize(nsteps)
387 
388  def get_output(self):
389  output={}
390  output["MolecularDynamics_KineticEnergy"]=str(self.md.get_kinetic_energy())
391  return output
392 
393 class ConjugateGradients(object):
394 
395  def __init__(self, m, objects):
396  self.m = m
397  self.nframe = -1
398  self.cg = IMP.core.ConjugateGradients(self.m)
399 
400  def set_label(self, label):
401  self.label = label
402 
403  def get_frame_number(self):
404  return self.nframe
405 
406  def run(self, nstep):
407  self.nframe += 1
408  self.cg.optimize(nstep)
409 
410  def set_scoring_function(self, objectlist):
411  rs = IMP.RestraintSet(self.m, 1.0, 'sfo')
412  for ob in objectlist:
413  rs.add_restraint(ob.get_restraint())
415  self.cg.set_scoring_function(sf)
416 
417  def get_output(self):
418  output = {}
419  acceptances = []
420  output["ConjugatedGradients_Nframe"] = str(self.nframe)
421  return output
422 
423 
424 class ReplicaExchange(object):
425 
426  def __init__(
427  self,
428  model,
429  tempmin,
430  tempmax,
431  samplerobjects,
432  test=True,
433  replica_exchange_object=None):
434  '''
435  samplerobjects can be a list of MonteCarlo or MolecularDynamics
436  '''
437 
438 
439  self.m = model
440  self.samplerobjects = samplerobjects
441  # min and max temperature
442  self.TEMPMIN_ = tempmin
443  self.TEMPMAX_ = tempmax
444 
445  if replica_exchange_object is None:
446  # initialize Replica Exchange class
447  try:
448  import IMP.mpi
449  self.rem = IMP.mpi.ReplicaExchange()
450  except ImportError:
451  self.rem = _SerialReplicaExchange()
452 
453  else:
454  # get the replica exchange class instance from elsewhere
455  print 'got existing rex object'
456  self.rem = replica_exchange_object
457 
458  # get number of replicas
459  nproc = self.rem.get_number_of_replicas()
460 
461  if nproc % 2 != 0 and test == False:
462  raise Exception, "number of replicas has to be even. set test=True to run with odd number of replicas."
463  # create array of temperatures, in geometric progression
464  temp = self.rem.create_temperatures(
465  self.TEMPMIN_,
466  self.TEMPMAX_,
467  nproc)
468  # get replica index
469  self.temperatures = temp
470 
471  myindex = self.rem.get_my_index()
472  # set initial value of the parameter (temperature) to exchange
473  self.rem.set_my_parameter("temp", [self.temperatures[myindex]])
474  for so in self.samplerobjects:
475  so.set_kt(self.temperatures[myindex])
476  self.nattempts = 0
477  self.nmintemp = 0
478  self.nmaxtemp = 0
479  self.nsuccess = 0
480 
481  def get_temperatures(self):
482  return self.temperatures
483 
484  def get_my_temp(self):
485  return self.rem.get_my_parameter("temp")[0]
486 
487  def get_my_index(self):
488  return self.rem.get_my_index()
489 
490  def swap_temp(self, nframe, score=None):
491  if score is None:
492  score = self.m.evaluate(False)
493  # get my replica index and temperature
494  myindex = self.rem.get_my_index()
495  mytemp = self.rem.get_my_parameter("temp")[0]
496 
497  if mytemp == self.TEMPMIN_:
498  self.nmintemp += 1
499 
500  if mytemp == self.TEMPMAX_:
501  self.nmaxtemp += 1
502 
503  # score divided by kbt
504  myscore = score / mytemp
505 
506  # get my friend index and temperature
507  findex = self.rem.get_friend_index(nframe)
508  ftemp = self.rem.get_friend_parameter("temp", findex)[0]
509  # score divided by kbt
510  fscore = score / ftemp
511 
512  # try exchange
513  flag = self.rem.do_exchange(myscore, fscore, findex)
514 
515  self.nattempts += 1
516  # if accepted, change temperature
517  if (flag):
518  for so in self.samplerobjects:
519  so.set_kt(ftemp)
520  self.nsuccess += 1
521 
522  def get_output(self):
523  output = {}
524  acceptances = []
525  if self.nattempts != 0:
526  output["ReplicaExchange_SwapSuccessRatio"] = str(
527  float(self.nsuccess) / self.nattempts)
528  output["ReplicaExchange_MinTempFrequency"] = str(
529  float(self.nmintemp) / self.nattempts)
530  output["ReplicaExchange_MaxTempFrequency"] = str(
531  float(self.nmaxtemp) / self.nattempts)
532  else:
533  output["ReplicaExchange_SwapSuccessRatio"] = str(0)
534  output["ReplicaExchange_MinTempFrequency"] = str(0)
535  output["ReplicaExchange_MaxTempFrequency"] = str(0)
536  output["ReplicaExchange_CurrentTemp"] = str(self.get_my_temp())
537  return output
538 
539 
540 class PyMCMover(object):
541  # only works if the sampled particles are rigid bodies
542 
543  def __init__(self, representation, mcchild, n_mc_steps):
544 
545  # mcchild must be pmi.samplers.MonteCarlo
546  # representation must be pmi.representation
547 
548  self.rbs = representation.get_rigid_bodies()
549 
550  self.mc = mcchild
551  self.n_mc_steps = n_mc_steps
552 
553  def store_move(self):
554  # get all xyz coordinates of all rigid bodies of all copies
555  self.oldcoords = []
556  for copy in self.rbs:
557  crd = []
558  for rb in copy:
559  crd.append(rb.get_reference_frame())
560  self.oldcoords.append(crd)
561 
562  def propose_move(self, prob):
563  self.mc.run(self.n_mc_steps)
564 
565  def reset_move(self):
566  # reset each copy to crd
567  for copy, crd in zip(self.rbs, self.oldcoords):
568  for rb, ref in zip(copy, crd):
569  rb.set_reference_frame(ref)
570 
571  def get_number_of_steps(self):
572  return self.n_mc_steps
573 
574  def set_number_of_steps(self, nsteps):
575  self.n_mc_steps = nsteps
576 
577 
578 class PyMC(object):
579 
580  def __init__(self, model):
581  from math import exp
582  import random
583 
584  self.m = model
585  self.restraints = None
586  self.first_call = True
587  self.nframe = -1
588 
589  def add_mover(self, mv):
590  self.mv = mv
591 
592  def set_kt(self, kT):
593  self.kT = kT
594 
595  def set_return_best(self, thing):
596  pass
597 
598  def set_move_probability(self, thing):
599  pass
600 
601  def get_energy(self):
602  if self.restraints:
603  pot = sum([r.evaluate(False) for r in self.restraints])
604  else:
605  pot = self.m.evaluate(False)
606  return pot
607 
608  def metropolis(self, old, new):
609  deltaE = new - old
610  print ": old %f new %f deltaE %f new_epot: %f" % (old, new, deltaE,
611  self.m.evaluate(
612  False)),
613  kT = self.kT
614  if deltaE < 0:
615  return True
616  else:
617  return exp(-deltaE / kT) > random.uniform(0, 1)
618 
619  def optimize(self, nsteps):
620  self.naccept = 0
621  self.nframe += 1
622  print "=== new MC call"
623  # store initial coordinates
624  if self.first_call:
625  self.mv.store_move()
626  self.first_call = False
627  for i in xrange(nsteps):
628  print "MC step %d " % i,
629  # get total energy
630  old = self.get_energy()
631  # make a MD move
632  self.mv.propose_move(1)
633  # get new total energy
634  new = self.get_energy()
635  if self.metropolis(old, new):
636  # move was accepted: store new conformation
637  self.mv.store_move()
638  self.naccept += 1
639  print "accepted "
640  else:
641  # move rejected: restore old conformation
642  self.mv.reset_move()
643  print " "
644 
645  def get_number_of_forward_steps(self):
646  return self.naccept
647 
648  def set_restraints(self, restraints):
649  self.restraints = restraints
650 
651  def set_scoring_function(self, objects):
652  # objects should be pmi.restraints
653  rs = IMP.RestraintSet(self.m, 1.0, 'sfo')
654  for ob in objects:
655  rs.add_restraint(ob.get_restraint())
656  self.set_restraints([rs])
657 
658  def get_output(self):
659  output = {}
660  acceptances = []
661  output["PyMC_Temperature"] = str(self.kT)
662  output["PyMC_Nframe"] = str(self.nframe)
663  return output
664 
665 
666 # 3
A Monte Carlo optimizer.
Definition: MonteCarlo.h:45
A class to implement Hamiltonian Replica Exchange.
Maintains temperature during molecular dynamics.
Object used to hold a set of restraints.
Modify the transformation of a rigid body.
Simple conjugate gradients optimizer.
Modify a set of continuous variables by perturbing them within a ball.
static bool get_is_setup(const IMP::kernel::ParticleAdaptor &p)
Definition: rigid_bodies.h:500
Simple molecular dynamics optimizer.
Code that uses the MPI parallel library.
Modify the transformation of a rigid body.
Definition: WeightMover.h:24
Modify the transformation of a rigid body.
Modify a set of continuous variables using a normal distribution.
Definition: NormalMover.h:20
Basic functionality that is expected to be used by a wide variety of IMP users.
VectorD< 3 > Vector3D
Definition: VectorD.h:395
static const FloatKeys & get_xyz_keys()
Get a vector containing the keys for x,y,z.
Applies a list of movers one at a time.
Definition: SerialMover.h:23
Inferential scoring building on methods developed as part of the Inferential Structure Determination ...