class NestedSamplingSA(NestedSampling): """overload get_starting_configuration() in order to introduce sampling from known minima Parameters ---------- system : pele system object nreplicas : int number of replicas takestep : callable object to do the step taking. must be callable and have attribute takestep.stepsize minima : list of Minimum objects """ def __init__(self, replicas, mc_runner, minima, ndof, config_tests=None, debug=False, minprob=None, energy_offset=None, copy_minima=True, center_minima=False, energy_onset = None, **kwargs): super(NestedSamplingSA, self).__init__(replicas, mc_runner, **kwargs) self.minima = minima self.bh_sampler = SASampler(self.minima, ndof, copy_minima=copy_minima, center_minima=center_minima) if minprob is None: raise ValueError("minprob cannot be None") self.minprob = minprob if energy_offset is None: self.energy_offset = 2.5 else: self.energy_offset = energy_offset self.debug = debug self.config_tests = config_tests self._energy_max_database = energy_onset if self.debug and self.config_tests is None: print "warning, not using config tests" self.count_sampled_minima = 0 # def get_starting_configuration_minima_HA(self, Emax): # """using the Harmonic Approximation sample a new configuration starting from a minimum sampled uniformly according to phase space volume # # Notes # ----- # displace minimum configuration along its eigenvectors # # """ # m = self.bh_sampler.sample_minimum(Emax) # x = self.bh_sampler.sample_coords_from_basin(m, Emax) # pot = self.system.get_potential() # e = pot.getEnergy(x) # return x, e def get_starting_configuration_minima_single(self, Emax): """return a minimum sampled uniformly according to phase space volume""" m = self.bh_sampler.sample_minimum(Emax) x, e = m.coords.copy(), m.energy # self.system.center_coords(x) if self.config_tests is not None: for test in self.config_tests: t = test(coords=x) if not t: print "warning: minimum from database failed configuration test", m.energy raise ConfigTestError() return x, e def get_starting_configuration_minima(self, Emax): """return a minimum sampled uniformly according to phase space volume Notes ----- some of the minima in the database don't satisfy the configuration checks. So we sample over and over again until we get one that passes """ self.count_sampled_minima += 1 while True: try: return self.get_starting_configuration_minima_single(Emax) except ConfigTestError: pass def onset_prob_func(self, Emax): """return the probability of sampling from a minimum The probability depends on Emax. For high Emax the probability is 0. the probability increases as Emax get's lower, reaching a maximum of self.minprob. value of Emax where the probabilty starts to get large is energy_max_database + energy_offset where energy_max_database is the maximum energy minimum in the database. This behaviour can be adjusted with parameter energy_offset. parameter <energy_onset_width> determines the speed at which it turns on. the optimal probability of sampling from the database scales approximately as 1/nreplicas, this has been shown analytically (see Stefano's thesis pp.29-32). """ #if not hasattr(self, "_energy_max_database"): if self._energy_max_database == None: self._energy_max_database = float(max([m.energy for m in self.minima])) max_prob = float(self.minprob) energy_onset_width = 1. dE = self._energy_max_database + self.energy_offset - Emax f = dE / energy_onset_width if np.log(np.finfo('d').max) <= (-f): onset_prob = 0. else: onset_prob = max_prob / (1. + np.exp(-f)) return float(onset_prob)/self.nreplicas def get_starting_configurations(self, Emax): """this function overloads the function in NestedSampling""" # choose a replica randomly configs = self.get_starting_configurations_from_replicas() # replace each starting configuration with a one chosen # from the minima with probability onset_prob onset_prob = self.onset_prob_func(Emax) for i in range(len(configs)): if np.random.uniform(0,1) < onset_prob: x, energy = self.get_starting_configuration_minima(Emax) configs[i] = Replica(x, energy, from_random=False) if self.verbose: print "sampling from minima, E minimum:", energy, "with probability:", onset_prob return configs
class NestedSamplingSA(NestedSampling): """overload get_starting_configuration() in order to introduce sampling from known minima Parameters ---------- system : pele system object nreplicas : int number of replicas takestep : callable object to do the step taking. must be callable and have attribute takestep.stepsize minima : list of Minimum objects """ def __init__(self, system, nreplicas, mc_runner, minima, minprob=None, energy_offset=None, **kwargs): super(NestedSamplingSA, self).__init__(system, nreplicas, mc_runner, **kwargs) self.minima = minima self.bh_sampler = SASampler(self.minima, self.system.k) if minprob is None: raise ValueError("minprob cannot be None") self.minprob = minprob if energy_offset is None: self.energy_offset = 2.5 else: self.energy_offset = energy_offset self.count_sampled_minima = 0 def get_starting_configuration_minima_HA(self, Emax): """using the Harmonic Approximation sample a new configuration starting from a minimum sampled uniformly according to phase space volume Notes ----- displace minimum configuration along its eigenvectors """ m = self.bh_sampler.sample_minimum(Emax) x = self.bh_sampler.sample_coords_from_basin(m, Emax) pot = self.system.get_potential() e = pot.getEnergy(x) return x, e def get_starting_configuration_minima_single(self, Emax): """return a minimum sampled uniformly according to phase space volume""" m = self.bh_sampler.sample_minimum(Emax) x, e = m.coords, m.energy self.system.center_coords(x) if True: accept_tests = self.system.get_config_tests() for test in accept_tests: t = test(coords=x) if not t: print "warning: minimum from database failed configuration test", m._id, m.energy raise ConfigTestError() return x, e def get_starting_configuration_minima(self, Emax): """return a minimum sampled uniformly according to phase space volume Notes ----- some of the minima in the database don't satisfy the configuration checks. So we sample over and over again until we get one that passes """ self.count_sampled_minima += 1 while True: try: return self.get_starting_configuration_minima_single(Emax) except ConfigTestError: pass def onset_prob_func(self, Emax): """return the probability of sampling from a minimum The probability depends on Emax. For high Emax the probability is 0. the probability increases as Emax get's lower, reaching a maximum of self.minprob. value of Emax where the probabilty starts to get large is energy_max_database + energy_offset where energy_max_database is the maximum energy minimum in the database. This behavior can be adjusted with parameter energy_offset. parameter b determines the speed at which it turns on. """ if not hasattr(self, "_energy_max_database"): self._energy_max_database = float( max([m.energy for m in self.minima])) max_prob = float(self.minprob) energy_onset_width = 1. dE = self._energy_max_database + self.energy_offset - Emax f = dE / energy_onset_width if f > 100: onset_prob = 0. else: onset_prob = max_prob / (1. + np.exp(-f)) return onset_prob def get_starting_configurations(self, Emax): """this function overloads the function in NestedSampling""" # choose a replica randomly configs = self.get_starting_configurations_from_replicas() # replace each starting configuration with a one chosen # from the minima with probability prob onset_prob = self.onset_prob_func(Emax) prob = onset_prob / float(self.nreplicas) for i in range(len(configs)): if np.random.uniform(0, 1) < prob: x, energy = self.get_starting_configuration_minima(Emax) configs[i] = Replica(x, energy, from_random=False) if self.verbose: print "sampling from minima, E minimum:", energy, "with probability:", prob return configs
class TestBuildDatabase(unittest.TestCase): def setUp(self): self.natoms = 6 self.system = LJCluster(self.natoms) # create a database self.database = self.system.create_database() # add some minima to the database bh = self.system.get_basinhopping(self.database, outstream=None) while self.database.number_of_minima() < 2: bh.run(1) get_thermodynamic_information(self.system, self.database) get_all_normalmodes(self.system, self.database) self.ndof = self.natoms * 3 - 6 self.sampler = SASampler(self.database.minima(), self.ndof) # def test(self): # for m in self.database.minima(): # print m.energy # print self.sampler.compute_weights(-11.7) # for i in range(10): # m = self.sampler.sample_minimum(-11) # print m._id def compute_weights(self, Emax, k): print [m.energy for m in self.database.minima()], Emax lweights = [ - np.log(m.pgorder) + 0.5 * k * np.log(Emax - m.energy) - 0.5 * m.fvib for m in self.database.minima() if m.energy < Emax] lweights = np.array(lweights) if lweights.size <= 1: return lweights lwmax = lweights.max() lweights -= lwmax return np.exp(lweights) def test1(self): Emax = -11.7 minima, weights = self.sampler.compute_weights(0.) minima, weights = self.sampler.compute_weights(Emax) self.assertAlmostEqual(weights[0], 0.81256984, 3) self.assertAlmostEqual(weights[1], 1., 7) new_weights = self.compute_weights(Emax, self.ndof) print weights print new_weights def test2(self): Emax = -11.7 minima, weights = self.sampler.compute_weights(Emax) minima, weights = self.sampler.compute_weights(Emax) self.assertAlmostEqual(weights[0], 0.81256984, 3) self.assertAlmostEqual(weights[1], 1., 7) def test3(self): m = self.sampler.sample_minimum(-11.7) self.assertIn(m, self.database.minima()) def test4(self): """check that the HSA energy is computed correctly""" pot = self.system.get_potential() for m in self.database.minima(): x = m.coords.copy() x += np.random.uniform(-1e-3, 1e-3, x.shape) ehsa = self.sampler.compute_energy(x, m, x0=m.coords) ecalc = pot.getEnergy(x) ecompare = (ehsa - ecalc) / (ecalc - m.energy) print ehsa - m.energy, ecalc - m.energy, m.energy, ecompare self.assertAlmostEqual(ecompare, 0., 1) def test_rotation(self): """assert that the HSA energy is *not* invariant under rotation""" pot = self.system.get_potential() aa = rotations.random_aa() rmat = rotations.aa2mx(aa) from pele.mindist import TransformAtomicCluster tform = TransformAtomicCluster(can_invert=True) for m in self.database.minima(): x = m.coords.copy() # randomly move the atoms by a small amount x += np.random.uniform(-1e-3, 1e-3, x.shape) ehsa1 = self.sampler.compute_energy(x, m, x0=m.coords) ecalc = pot.getEnergy(x) # now rotate by a random matrix xnew = x.copy() tform.rotate(xnew, rmat) ehsa2 = self.sampler.compute_energy(xnew, m, x0=m.coords) ecalc2 = pot.getEnergy(xnew) self.assertAlmostEqual(ecalc, ecalc2, 5) self.assertNotAlmostEqual(ehsa1, ehsa2, 1) # def test_rotation_2(self): # """assert that the HSA energy *is* invariant under rotation *if* the initial coords are also rotated""" # pot = self.system.get_potential() # aa = rotations.random_aa() # rmat = rotations.aa2mx(aa) # from pele.mindist import TransformAtomicCluster # tform = TransformAtomicCluster(can_invert=True) # for m in self.database.minima(): # x = m.coords.copy() # # randomly move the atoms by a small amount # x += np.random.uniform(-1e-3, 1e-3, x.shape) # ehsa1 = self.sampler.compute_energy(x, m, x0=m.coords) # ecalc = pot.getEnergy(x) # # now rotate by a random matrix # xnew = x.copy() # tform.rotate(xnew, rmat) # xmnew = m.coords.copy() # tform.rotate(xmnew, rmat) # ehsa2 = self.sampler.compute_energy(xnew, m, x0=xmnew) # ecalc2 = pot.getEnergy(xnew) # self.assertAlmostEqual(ecalc, ecalc2, 5) # self.assertAlmostEqual(ehsa1, ehsa2, 3) def test_permutation(self): """assert that the HSA energy is not invariant under permutation""" pot = self.system.get_potential() perm = range(self.natoms) np.random.shuffle(perm) from pele.mindist import TransformAtomicCluster tform = TransformAtomicCluster(can_invert=True) for m in self.database.minima(): x = m.coords.copy() # randomly move the atoms by a small amount x += np.random.uniform(-1e-3, 1e-3, x.shape) ehsa1 = self.sampler.compute_energy(x, m, x0=m.coords) ecalc = pot.getEnergy(x) # now rotate by a random matrix xnew = x.copy() xnew = tform.permute(xnew, perm) ehsa2 = self.sampler.compute_energy(xnew, m, x0=m.coords) ecalc2 = pot.getEnergy(xnew) self.assertAlmostEqual(ecalc, ecalc2, 5) self.assertNotAlmostEqual(ehsa1, ehsa2, 1)
class TestBuildDatabase(unittest.TestCase): def setUp(self): self.natoms = 6 self.system = LJCluster(self.natoms) # create a database self.database = self.system.create_database() # add some minima to the database bh = self.system.get_basinhopping(self.database, outstream=None) while self.database.number_of_minima() < 2: bh.run(1) get_thermodynamic_information(self.system, self.database) get_all_normalmodes(self.system, self.database) self.ndof = self.natoms * 3 - 6 self.sampler = SASampler(self.database.minima(), self.ndof) # def test(self): # for m in self.database.minima(): # print m.energy # print self.sampler.compute_weights(-11.7) # for i in range(10): # m = self.sampler.sample_minimum(-11) # print m._id def test1(self): Emax = -11.7 minima, weights = self.sampler.compute_weights(0.) minima, weights = self.sampler.compute_weights(Emax) self.assertAlmostEqual(weights[0], 0.81256984, 3) self.assertAlmostEqual(weights[1], 1., 7) def test2(self): Emax = -11.7 minima, weights = self.sampler.compute_weights(Emax) minima, weights = self.sampler.compute_weights(Emax) self.assertAlmostEqual(weights[0], 0.81256984, 3) self.assertAlmostEqual(weights[1], 1., 7) def test3(self): m = self.sampler.sample_minimum(-11.7) self.assertIn(m, self.database.minima()) def test4(self): """check that the HSA energy is computed correctly""" pot = self.system.get_potential() for m in self.database.minima(): x = m.coords.copy() x += np.random.uniform(-1e-3, 1e-3, x.shape) ehsa = self.sampler.compute_energy(x, m, x0=m.coords) ecalc = pot.getEnergy(x) ecompare = (ehsa - ecalc) / (ecalc - m.energy) print ehsa - m.energy, ecalc - m.energy, m.energy, ecompare self.assertAlmostEqual(ecompare, 0., 1) def test_rotation(self): """assert that the HSA energy is *not* invariant under rotation""" pot = self.system.get_potential() aa = rotations.random_aa() rmat = rotations.aa2mx(aa) from pele.mindist import TransformAtomicCluster tform = TransformAtomicCluster(can_invert=True) for m in self.database.minima(): x = m.coords.copy() # randomly move the atoms by a small amount x += np.random.uniform(-1e-3, 1e-3, x.shape) ehsa1 = self.sampler.compute_energy(x, m, x0=m.coords) ecalc = pot.getEnergy(x) # now rotate by a random matrix xnew = x.copy() tform.rotate(xnew, rmat) ehsa2 = self.sampler.compute_energy(xnew, m, x0=m.coords) ecalc2 = pot.getEnergy(xnew) self.assertAlmostEqual(ecalc, ecalc2, 5) self.assertNotAlmostEqual(ehsa1, ehsa2, 1) # def test_rotation_2(self): # """assert that the HSA energy *is* invariant under rotation *if* the initial coords are also rotated""" # pot = self.system.get_potential() # aa = rotations.random_aa() # rmat = rotations.aa2mx(aa) # from pele.mindist import TransformAtomicCluster # tform = TransformAtomicCluster(can_invert=True) # for m in self.database.minima(): # x = m.coords.copy() # # randomly move the atoms by a small amount # x += np.random.uniform(-1e-3, 1e-3, x.shape) # ehsa1 = self.sampler.compute_energy(x, m, x0=m.coords) # ecalc = pot.getEnergy(x) # # now rotate by a random matrix # xnew = x.copy() # tform.rotate(xnew, rmat) # xmnew = m.coords.copy() # tform.rotate(xmnew, rmat) # ehsa2 = self.sampler.compute_energy(xnew, m, x0=xmnew) # ecalc2 = pot.getEnergy(xnew) # self.assertAlmostEqual(ecalc, ecalc2, 5) # self.assertAlmostEqual(ehsa1, ehsa2, 3) def test_permutation(self): """assert that the HSA energy is not invariant under permutation""" pot = self.system.get_potential() perm = range(self.natoms) np.random.shuffle(perm) from pele.mindist import TransformAtomicCluster tform = TransformAtomicCluster(can_invert=True) for m in self.database.minima(): x = m.coords.copy() # randomly move the atoms by a small amount x += np.random.uniform(-1e-3, 1e-3, x.shape) ehsa1 = self.sampler.compute_energy(x, m, x0=m.coords) ecalc = pot.getEnergy(x) # now rotate by a random matrix xnew = x.copy() xnew = tform.permute(xnew, perm) ehsa2 = self.sampler.compute_energy(xnew, m, x0=m.coords) ecalc2 = pot.getEnergy(xnew) self.assertAlmostEqual(ecalc, ecalc2, 5) self.assertNotAlmostEqual(ehsa1, ehsa2, 1)