Beispiel #1
0
    def __init__(self,
                 system,
                 nreplicas,
                 mc_runner,
                 minima,
                 energy_accuracy,
                 compare_structures=None,
                 mindist=None,
                 copy_minima=True,
                 config_tests=None,
                 minimizer=None,
                 debug=True,
                 **kwargs):
        super(NestedSamplingSAExact, self).__init__(system, nreplicas,
                                                    mc_runner, **kwargs)
        self.debug = debug
        if copy_minima:
            self.minima = [_UnboundMinimum(m) for m in minima]
        else:
            self.minima = minima
        if self.verbose:
            self._check_minima()

        self.compare_structures = compare_structures
        if compare_structures is None:
            try:
                self.compare_structures = self.system.get_compare_exact()
            except NotImplementedError or AttributeError:
                pass

        self.mindist = mindist
        if mindist is None:
            try:
                self.mindist = self.system.get_mindist()
            except NotImplementedError or AttributeError:
                pass

        self.config_tests = config_tests
        if config_tests is None:
            try:
                self.config_tests = self.system.get_config_tests()
            except NotImplementedError or AttributeError:
                pass

        self.minimizer = minimizer
        if self.minimizer is None:
            self.minimizer = self.system.get_minimizer()

        self.minima_searcher = _MinimaSearcher(self.minima, energy_accuracy,
                                               self.compare_structures)
        self.sa_sampler = SASampler(self.minima, self.system.k)

        self.count_sampled_minima = 0
Beispiel #2
0
 def __init__(self, natoms=6):
     self.system = LJClusterSENS(natoms, 5.)
     self.ndof = natoms * 3 - 6
     self.natoms = natoms
     
     self.database = build_database(self.system, nminima=2)
     
     self.sampler = SASampler(self.database.minima(), self.ndof)
Beispiel #3
0
    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)
Beispiel #4
0
    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
Beispiel #5
0
class SamplerSystem(object):
    def __init__(self, natoms=6):
        self.system = LJClusterSENS(natoms, 5.)
        self.ndof = natoms * 3 - 6
        self.natoms = natoms
        
        self.database = build_database(self.system, nminima=2)
        
        self.sampler = SASampler(self.database.minima(), self.ndof)
    
    def sample_configuration(self, Emax):
        m, x = self.sampler.sample_coords(Emax)
        E = self.sampler.compute_energy(x, m)
        return E, x
    
    def __call__(self, *args, **kwargs):
        Emax = args[2]
#        print "walking with Emax", Emax
        E, x = self.sample_configuration(Emax)
        
        res = Result(x=x, energy=E, naccept=5, nsteps=10, Emax=Emax)
        return res
Beispiel #6
0
 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
Beispiel #7
0
 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)
Beispiel #8
0
    def __init__(self, system, nreplicas, mc_runner, 
                  minima, energy_accuracy, compare_structures=None, mindist=None,
                  copy_minima=True, config_tests=None, minimizer=None,
                  debug=True,
                  **kwargs):
        super(NestedSamplingSAExact, self).__init__(system, nreplicas, mc_runner, **kwargs)
        self.debug = debug
        if copy_minima:
            self.minima = [_UnboundMinimum(m) for m in minima]
        else:
            self.minima = minima
        if self.verbose:
            self._check_minima()
        
        self.compare_structures = compare_structures
        if compare_structures is None:
            try:
                self.compare_structures = self.system.get_compare_exact()
            except NotImplementedError or AttributeError:
                pass
        
        self.mindist = mindist
        if mindist is None:
            try:
                self.mindist = self.system.get_mindist()
            except NotImplementedError or AttributeError:
                pass

        self.config_tests = config_tests
        if config_tests is None:
            try:
                self.config_tests = self.system.get_config_tests()
            except NotImplementedError or AttributeError:
                pass

        self.minimizer = minimizer
        if self.minimizer is None:
            self.minimizer = self.system.get_minimizer()
        
        self.minima_searcher = _MinimaSearcher(self.minima, energy_accuracy, self.compare_structures)
        self.sa_sampler = SASampler(self.minima, self.system.k)

        
        self.count_sampled_minima = 0
Beispiel #9
0
 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
Beispiel #10
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 #11
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 #12
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 #13
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)
Beispiel #14
0
class NestedSamplingSAExact(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,
                 energy_accuracy,
                 compare_structures=None,
                 mindist=None,
                 copy_minima=True,
                 config_tests=None,
                 minimizer=None,
                 debug=True,
                 **kwargs):
        super(NestedSamplingSAExact, self).__init__(system, nreplicas,
                                                    mc_runner, **kwargs)
        self.debug = debug
        if copy_minima:
            self.minima = [_UnboundMinimum(m) for m in minima]
        else:
            self.minima = minima
        if self.verbose:
            self._check_minima()

        self.compare_structures = compare_structures
        if compare_structures is None:
            try:
                self.compare_structures = self.system.get_compare_exact()
            except NotImplementedError or AttributeError:
                pass

        self.mindist = mindist
        if mindist is None:
            try:
                self.mindist = self.system.get_mindist()
            except NotImplementedError or AttributeError:
                pass

        self.config_tests = config_tests
        if config_tests is None:
            try:
                self.config_tests = self.system.get_config_tests()
            except NotImplementedError or AttributeError:
                pass

        self.minimizer = minimizer
        if self.minimizer is None:
            self.minimizer = self.system.get_minimizer()

        self.minima_searcher = _MinimaSearcher(self.minima, energy_accuracy,
                                               self.compare_structures)
        self.sa_sampler = SASampler(self.minima, self.system.k)

        self.count_sampled_minima = 0

    def _check_minima(self):
        for m in self.minima:
            assert m.energy is not None
            assert m.fvib is not None
            assert m.pgorder is not None
            assert m.normal_modes is not None

    def _compute_energy_in_SA(self, replica):
        """compute the energy of the coordinates in replica.coords in the harmonic superposition approximation
        
        This is where most of the difficulty is in the algorithm.  
        
        This is also where all the system dependence is
        """
        # quench to nearest minimum
        qresult = self.minimizer(replica.x)

        # check if that minimum is in the database.  reject if not
        m, transformation = self.minima_searcher.get_minima(
            qresult.energy, qresult.coords)
        if m is None:
            return None

        # put replica.coords into best alignment with the structure stored in m.coords
        # this involves accounting for symmetries of the Hamiltonian like translational,
        # rotational and permutations symmetries.  You can use the coordinates in qresult.coords
        # to help find the best permutation.  Ultimately it must be aligned with the structure in m.coords
        # The hessian eigenvectors were computed with a given permutation
        # e.g. account for trivial translational and rotational degrees of freedom
        x = replica.x.copy()
        if transformation is not None:
            # transformation is the set of transformations that put qresult.coords into exact
            # alignment with m.coords.  If we apply these transformations to replica.x then
            # replica.x will be in good (although not perfect) alignment already with m.coords
            x = self.compare_structures.apply_transformation(x, transformation)

        # Do a final round of optimization to further improve the alignment
        if self.mindist is not None:
            dist, x0, x = self.mindist(m.coords.copy(), x)
            if self.debug:
                diff = np.linalg.norm(x0 - m.coords)
                if diff > .01:
                    with open("error.xyz", "w") as fout:
                        from pele.utils.xyz import write_xyz
                        write_xyz(fout, x0)
                        write_xyz(fout, m.coords)

                    raise Exception(
                        "warning, mindist appears to have changed x0.  the norm of the difference is %g"
                        % diff)

                assert (x0 == m.coords).all()

        energy = self.sa_sampler.compute_energy(x, m)

        return energy

    def _attempt_swap(self, replica, Emax):
        # sample a configuration from the harmonic superposition approximation
        m, xsampled = self.sa_sampler.sample_coords(Emax)

        # if the configuration fails the config test then reject the swap
        #        print "attempting swap"
        if self.config_tests is not None:
            for test in self.config_tests:
                if not test(coords=xsampled):
                    return None

        # if the energy returned by full energy function is too high, then reject the swap
        Esampled = self.system.get_energy(xsampled)
        if Esampled >= Emax:
            return None

        # compute the energy of the replica within the superposition approximation.
        E_SA = self._compute_energy_in_SA(replica)

        # reject if the energy is too high
        if E_SA is None or E_SA >= Emax:
            # no swap done
            return None

        if self.verbose:
            print "accepting swap: Eold %g Enew %g Eold_SA %g Emax %g" % (
                replica.energy, Esampled, E_SA, Emax)
        self.count_sampled_minima += 1

        return Replica(xsampled, Esampled, from_random=False)

    def do_monte_carlo_chain(self, replicas, Emax):
        #        replicas = super(NestedSamplingSAExact, self).do_monte_carlo_chain(replicas, Emax)

        # try to swap this configuration with one sampled from the HSA
        for i in xrange(len(replicas)):
            r = replicas[i]
            rnew = self._attempt_swap(r, Emax)
            if rnew is not None:
                replicas[i] = rnew

        # do a monte carlo walk
        replicas = super(NestedSamplingSAExact,
                         self).do_monte_carlo_chain(replicas, Emax)

        return replicas
Beispiel #15
0
class NestedSamplingSAExact(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, energy_accuracy, compare_structures=None, mindist=None,
                  copy_minima=True, config_tests=None, minimizer=None,
                  debug=True,
                  **kwargs):
        super(NestedSamplingSAExact, self).__init__(system, nreplicas, mc_runner, **kwargs)
        self.debug = debug
        if copy_minima:
            self.minima = [_UnboundMinimum(m) for m in minima]
        else:
            self.minima = minima
        if self.verbose:
            self._check_minima()
        
        self.compare_structures = compare_structures
        if compare_structures is None:
            try:
                self.compare_structures = self.system.get_compare_exact()
            except NotImplementedError or AttributeError:
                pass
        
        self.mindist = mindist
        if mindist is None:
            try:
                self.mindist = self.system.get_mindist()
            except NotImplementedError or AttributeError:
                pass

        self.config_tests = config_tests
        if config_tests is None:
            try:
                self.config_tests = self.system.get_config_tests()
            except NotImplementedError or AttributeError:
                pass

        self.minimizer = minimizer
        if self.minimizer is None:
            self.minimizer = self.system.get_minimizer()
        
        self.minima_searcher = _MinimaSearcher(self.minima, energy_accuracy, self.compare_structures)
        self.sa_sampler = SASampler(self.minima, self.system.k)

        
        self.count_sampled_minima = 0
        
    def _check_minima(self):
        for m in self.minima:
            assert m.energy is not None
            assert m.fvib is not None
            assert m.pgorder is not None
            assert m.normal_modes is not None

    def _compute_energy_in_SA(self, replica):
        """compute the energy of the coordinates in replica.coords in the harmonic superposition approximation
        
        This is where most of the difficulty is in the algorithm.  
        
        This is also where all the system dependence is
        """
        # quench to nearest minimum
        qresult = self.minimizer(replica.x)
        
        # check if that minimum is in the database.  reject if not
        m, transformation = self.minima_searcher.get_minima(qresult.energy, qresult.coords)
        if m is None:
            return None
        
        # put replica.coords into best alignment with the structure stored in m.coords
        # this involves accounting for symmetries of the Hamiltonian like translational, 
        # rotational and permutations symmetries.  You can use the coordinates in qresult.coords
        # to help find the best permutation.  Ultimately it must be aligned with the structure in m.coords
        # The hessian eigenvectors were computed with a given permutation
        # e.g. account for trivial translational and rotational degrees of freedom
        x = replica.x.copy()
        if transformation is not None:
            # transformation is the set of transformations that put qresult.coords into exact
            # alignment with m.coords.  If we apply these transformations to replica.x then
            # replica.x will be in good (although not perfect) alignment already with m.coords 
            x = self.compare_structures.apply_transformation(x, transformation)
            
        # Do a final round of optimization to further improve the alignment
        if self.mindist is not None:
            dist, x0, x = self.mindist(m.coords.copy(), x)
            if self.debug:
                diff = np.linalg.norm(x0 - m.coords)
                if diff > .01:
                    with open("error.xyz", "w") as fout:
                        from pele.utils.xyz import write_xyz
                        write_xyz(fout, x0)
                        write_xyz(fout, m.coords)
                        
                    raise Exception("warning, mindist appears to have changed x0.  the norm of the difference is %g" % diff)
                    
                assert (x0 == m.coords).all()
        
        energy = self.sa_sampler.compute_energy(x, m)
        
        return energy

    def _attempt_swap(self, replica, Emax):
        # sample a configuration from the harmonic superposition approximation
        m, xsampled = self.sa_sampler.sample_coords(Emax)

        # if the configuration fails the config test then reject the swap
#        print "attempting swap"
        if self.config_tests is not None:
            for test in self.config_tests:
                if not test(coords=xsampled):
                    return None
        
        # if the energy returned by full energy function is too high, then reject the swap
        Esampled = self.system.get_energy(xsampled)
        if Esampled >= Emax:
            return None
        
        # compute the energy of the replica within the superposition approximation.
        E_SA = self._compute_energy_in_SA(replica)
        
        # reject if the energy is too high
        if E_SA is None or E_SA >= Emax:
            # no swap done
            return None

        if self.verbose:
            print "accepting swap: Eold %g Enew %g Eold_SA %g Emax %g" % (replica.energy, Esampled, E_SA, Emax)
        self.count_sampled_minima += 1
        
        return Replica(xsampled, Esampled, from_random=False)
        

    def do_monte_carlo_chain(self, replicas, Emax):
#        replicas = super(NestedSamplingSAExact, self).do_monte_carlo_chain(replicas, Emax)
        
        # try to swap this configuration with one sampled from the HSA
        for i in xrange(len(replicas)):
            r = replicas[i]
            rnew = self._attempt_swap(r, Emax)
            if rnew is not None:
                replicas[i] = rnew
        
        # do a monte carlo walk
        replicas = super(NestedSamplingSAExact, self).do_monte_carlo_chain(replicas, Emax)
        
        return replicas