1 """@namespace IMP.pmi.samplers
2 Sampling of the system.
10 class _SerialReplicaExchange:
11 """Dummy replica exchange class used in non-MPI builds.
12 It should act similarly to IMP.mpi.ReplicaExchange
13 on a single processor.
18 def get_number_of_replicas(self):
21 def create_temperatures(self, tmin, tmax, nrep):
24 def get_my_index(self):
27 def set_my_parameter(self, key, val):
28 self.__params[key] = val
30 def get_my_parameter(self, key):
31 return self.__params[key]
33 def get_friend_index(self, step):
36 def get_friend_parameter(self, key, findex):
37 return self.get_my_parameter(key)
39 def do_exchange(self, myscore, fscore, findex):
42 def set_was_used(self, was_used):
43 self.was_used = was_used
47 def __init__(self, model, start_frame):
50 self.nframe = start_frame - 1
51 self.simulated_annealing =
False
53 def set_simulated_annealing(self, min_temp, max_temp, min_temp_time,
55 self.simulated_annealing =
True
56 self.tempmin = min_temp
57 self.tempmax = max_temp
58 self.timemin = min_temp_time
59 self.timemax = max_temp_time
61 def temp_simulated_annealing(self):
62 if self.nframe % (self.timemin + self.timemax) < self.timemin:
66 temp = self.tempmin + (self.tempmax - self.tempmin) * value
71 """Sample using Monte Carlo"""
80 def __init__(self, model, objects=None, temp=1.0, filterbyname=None,
81 score_moved=
False, start_frame=0):
82 """Setup Monte Carlo sampling
83 @param model The IMP Model
84 @param objects What to sample (a list of Movers)
85 @param temp The MC temperature
86 @param filterbyname Not used
87 @param score_moved If True, attempt to speed up sampling by
88 caching scoring function terms on particles that didn't move
89 @param start_frame The starting frame number
91 super().
__init__(model, start_frame=start_frame)
99 self.selfadaptive =
False
104 self.movers_data = {}
106 self._jax_optimizer =
None
107 self._jax_state =
None
115 self.mc.set_scoring_function(get_restraint_set(self.model))
116 self.mc.set_return_best(
False)
117 self.mc.set_score_moved(score_moved)
118 self.mc.set_kt(self.temp)
119 self.mc.add_mover(self.smv)
122 """Request that sampling of the scoring function is done using
123 JAX instead of IMP's internal C++ implementation (requires
124 that all PMI restraints used have a JAX implementation)."""
126 self._jax_optimizer = self.mc._get_jax_optimizer(
127 nstep * self.get_number_of_movers())
128 self._jax_state = self._jax_optimizer.get_initial_state()
131 """Get the current JAX Model used by the sampler."""
132 return self._jax_state.jm
134 def set_kt(self, temp):
137 if self._jax_state
is not None:
138 self._jax_state.temperature = temp
143 def set_scoring_function(self, objectlist):
145 for ob
in objectlist:
146 rs.add_restraint(ob.get_restraint())
148 self.mc.set_scoring_function(sf)
150 def set_self_adaptive(self, isselfadaptive=True):
151 self.selfadaptive = isselfadaptive
153 def get_number_of_movers(self):
154 return len(self.smv.get_movers())
156 def get_particle_types(self):
159 def optimize(self, nstep):
162 score, self._jax_state = self._jax_optimizer.optimize(
165 score = self.mc.optimize(nstep * self.get_number_of_movers())
168 if self.simulated_annealing:
169 self.set_kt(self.temp_simulated_annealing())
172 if self.selfadaptive:
177 """Modify parameters of individual movers to try to keep acceptance
180 raise NotImplementedError(
181 "Adaptive protocol is not yet implemented for JAX")
182 for i, mv
in enumerate(self.mvs):
184 mvacc = mv.get_number_of_accepted()
185 mvprp = mv.get_number_of_proposed()
186 if mv
not in self.movers_data:
187 accept = float(mvacc) / float(mvprp)
188 self.movers_data[mv] = (mvacc, mvprp)
190 oldmvacc, oldmvprp = self.movers_data[mv]
191 accept = float(mvacc-oldmvacc) / float(mvprp-oldmvprp)
192 self.movers_data[mv] = (mvacc, mvprp)
199 stepsize = mv.get_sigma()
200 if 0.4 > accept
or accept > 0.6:
201 mv.set_sigma(stepsize * 2 * accept)
204 stepsize = mv.get_radius()
205 if 0.4 > accept
or accept > 0.6:
206 mv.set_radius(stepsize * 2 * accept)
209 mr = mv.get_maximum_rotation()
210 mt = mv.get_maximum_translation()
211 if 0.4 > accept
or accept > 0.6:
212 mv.set_maximum_rotation(mr * 2 * accept)
213 mv.set_maximum_translation(mt * 2 * accept)
216 mr = mv.get_maximum_rotation()
217 mt = mv.get_maximum_translation()
218 if 0.4 > accept
or accept > 0.6:
219 mv.set_maximum_rotation(mr * 2 * accept)
220 mv.set_maximum_translation(mt * 2 * accept)
224 if 0.4 > accept
or accept > 0.6:
225 mv.set_radius(mr * 2 * accept)
227 def set_label(self, label):
230 def get_frame_number(self):
233 def get_output(self):
235 for i, mv
in enumerate(self.smv.get_movers()):
236 mvname = mv.get_name()
237 mvacc = mv.get_number_of_accepted()
238 mvprp = mv.get_number_of_proposed()
240 mvacr = float(mvacc) / float(mvprp)
243 output[
"MonteCarlo_Acceptance_" +
244 mvname +
"_" + str(i)] = str(mvacr)
245 if "Nuisances" in mvname:
246 output[
"MonteCarlo_StepSize_" + mvname +
"_" + str(i)] = \
247 str(IMP.core.NormalMover.get_from(mv).get_sigma())
248 if "Weights" in mvname:
249 output[
"MonteCarlo_StepSize_" + mvname +
"_" + str(i)] = \
250 str(IMP.isd.WeightMover.get_from(mv).get_radius())
251 output[
"MonteCarlo_Temperature"] = str(self.mc.get_kt())
252 output[
"MonteCarlo_Nframe"] = str(self.nframe)
257 """Sample using molecular dynamics"""
259 def __init__(self, model, objects, kt, gamma=0.01, maximum_time_step=1.0,
260 sf=
None, use_jax=
False, start_frame=0):
262 @param model The IMP Model
263 @param objects What to sample. Use flat list of particles
264 @param kt Temperature
265 @param gamma Viscosity parameter
266 @param maximum_time_step MD max time step
267 @param start_frame The starting frame number
269 super().
__init__(model, start_frame=start_frame)
274 psamp = obj.get_particles_to_sample()
275 to_sample = psamp[
'Floppy_Bodies_SimplifiedModel'][0]
280 self.model, to_sample, kt/0.0019872041, gamma)
282 self.md.set_maximum_time_step(maximum_time_step)
284 self.md.set_scoring_function(sf)
286 self.md.set_scoring_function(get_restraint_set(self.model))
287 self.md.add_optimizer_state(self.ltstate)
290 """Request that sampling of the scoring function is done using
291 JAX instead of IMP's internal C++ implementation (requires
292 that all PMI restraints used have a JAX implementation)."""
293 raise NotImplementedError(
"JAX currently only supported for MC")
295 def set_kt(self, kt):
296 temp = kt/0.0019872041
297 self.ltstate.set_temperature(temp)
298 self.md.assign_velocities(temp)
300 def set_gamma(self, gamma):
301 self.ltstate.set_gamma(gamma)
303 def optimize(self, nsteps):
306 if self.simulated_annealing:
307 self.set_kt(self.temp_simulated_annealing())
308 return self.md.optimize(nsteps)
310 def get_output(self):
312 output[
"MolecularDynamics_KineticEnergy"] = \
313 str(self.md.get_kinetic_energy())
318 """Sample using conjugate gradients"""
320 def __init__(self, model, objects):
324 self.cg.set_scoring_function(get_restraint_set(self.model))
326 def set_label(self, label):
329 def get_frame_number(self):
332 def optimize(self, nstep):
334 self.cg.optimize(nstep)
336 def set_scoring_function(self, objectlist):
338 for ob
in objectlist:
339 rs.add_restraint(ob.get_restraint())
341 self.cg.set_scoring_function(sf)
343 def get_output(self):
345 output[
"ConjugatedGradients_Nframe"] = str(self.nframe)
349 class _ReplicaExchangeStats:
350 """Statistics for replica exchange.
351 This is in a separate class so that we can pickle it easily for
359 def get_output(self):
361 if self.nattempts != 0:
362 output[
"ReplicaExchange_SwapSuccessRatio"] = str(
363 float(self.nsuccess) / self.nattempts)
364 output[
"ReplicaExchange_MinTempFrequency"] = str(
365 float(self.nmintemp) / self.nattempts)
366 output[
"ReplicaExchange_MaxTempFrequency"] = str(
367 float(self.nmaxtemp) / self.nattempts)
369 output[
"ReplicaExchange_SwapSuccessRatio"] = str(0)
370 output[
"ReplicaExchange_MinTempFrequency"] = str(0)
371 output[
"ReplicaExchange_MaxTempFrequency"] = str(0)
376 """Sample using replica exchange"""
378 def __init__(self, model, tempmin, tempmax, samplerobjects, test=True,
379 replica_exchange_object=
None):
381 samplerobjects can be a list of MonteCarlo or MolecularDynamics
385 self.samplerobjects = samplerobjects
387 self.TEMPMIN_ = tempmin
388 self.TEMPMAX_ = tempmax
390 if replica_exchange_object
is None:
394 print(
'ReplicaExchange: MPI was found. '
395 'Using Parallel Replica Exchange')
398 print(
'ReplicaExchange: Could not find MPI. '
399 'Using Serial Replica Exchange')
400 self.rem = _SerialReplicaExchange()
404 print(
'got existing rex object')
405 self.rem = replica_exchange_object
408 nproc = self.rem.get_number_of_replicas()
410 if nproc % 2 != 0
and not test:
412 "number of replicas has to be even. "
413 "set test=True to run with odd number of replicas.")
415 temp = self.rem.create_temperatures(
420 self.temperatures = temp
422 myindex = self.rem.get_my_index()
424 self.rem.set_my_parameter(
"temp", [self.temperatures[myindex]])
425 for so
in self.samplerobjects:
426 so.set_kt(self.temperatures[myindex])
428 self.stats = _ReplicaExchangeStats()
430 def get_temperatures(self):
431 return self.temperatures
433 def get_my_temp(self):
434 return self.rem.get_my_parameter(
"temp")[0]
436 def get_my_index(self):
437 return self.rem.get_my_index()
439 def swap_temp(self, nframe, score=None):
441 score = self.model.evaluate(
False)
443 _ = self.rem.get_my_index()
444 mytemp = self.rem.get_my_parameter(
"temp")[0]
446 if mytemp == self.TEMPMIN_:
447 self.stats.nmintemp += 1
449 if mytemp == self.TEMPMAX_:
450 self.stats.nmaxtemp += 1
453 myscore = score / mytemp
456 findex = self.rem.get_friend_index(nframe)
457 ftemp = self.rem.get_friend_parameter(
"temp", findex)[0]
459 fscore = score / ftemp
462 flag = self.rem.do_exchange(myscore, fscore, findex)
464 self.stats.nattempts += 1
467 for so
in self.samplerobjects:
469 self.stats.nsuccess += 1
471 def get_output(self):
472 output = self.stats.get_output()
473 output[
"ReplicaExchange_CurrentTemp"] = str(self.get_my_temp())
478 def __init__(self, replica_exchange_object=None):
479 """Query values (ie score, and others)
480 from a set of parallel jobs"""
482 if replica_exchange_object
is None:
486 print(
'MPI_values: MPI was found. '
487 'Using Parallel Replica Exchange')
490 print(
'MPI_values: Could not find MPI. '
491 'Using Serial Replica Exchange')
492 self.rem = _SerialReplicaExchange()
496 print(
'got existing rex object')
497 self.rem = replica_exchange_object
499 def set_value(self, name, value):
500 self.rem.set_my_parameter(name, [value])
502 def get_values(self, name):
504 for i
in range(self.rem.get_number_of_replicas()):
505 v = self.rem.get_friend_parameter(name, i)[0]
509 def get_percentile(self, name):
510 value = self.rem.get_my_parameter(name)[0]
511 values = sorted(self.get_values(name))
512 ind = values.index(value)
513 percentile = float(ind)/len(values)
def __init__
samplerobjects can be a list of MonteCarlo or MolecularDynamics
A class to implement Hamiltonian Replica Exchange.
Maintains temperature during molecular dynamics.
Sample using molecular dynamics.
Modify the transformation of a rigid body.
Simple conjugate gradients optimizer.
def set_use_jax
Request that sampling of the scoring function is done using JAX instead of IMP's internal C++ impleme...
Sample using conjugate gradients.
Create a scoring function on a list of restraints.
Move continuous particle variables by perturbing them within a ball.
Object used to hold a set of restraints.
Simple molecular dynamics simulator.
Code that uses the MPI parallel library.
def set_use_jax
Request that sampling of the scoring function is done using JAX instead of IMP's internal C++ impleme...
A mover that perturbs a Weight particle.
def __init__
Setup Monte Carlo sampling.
Modify a set of continuous variables using a normal distribution.
Basic functionality that is expected to be used by a wide variety of IMP users.
Sample using Monte Carlo.
The general base class for IMP exceptions.
def apply_self_adaptive
Modify parameters of individual movers to try to keep acceptance rate around 50%. ...
Applies a list of movers one at a time.
def get_jax_model
Get the current JAX Model used by the sampler.
Sample using replica exchange.
Inferential scoring building on methods developed as part of the Inferential Structure Determination ...