Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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)
Beispiel #4
0
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)