Пример #1
0
    def fit_force_and_energy(self, confs, forces, glob_confs, energies, ncores=1):
        """ Fit the GP to a set of training energies using a 2- and
        3-body single species force-force, energy-energy, and energy-forces kernel 
        functions. The 2-body Gaussian process is first fitted, then the 3-body GP 
        is fitted to the difference between the training energies (and forces) and 
        the 2-body predictions of energies (and forces) on the training configurations.

        Args:
            confs (list): List of M x 5 arrays containing coordinates and
                atomic numbers of atoms within a cutoff from the central one
            forces (array) : Array containing the vector forces on 
                the central atoms of the training configurations
            glob_confs (list of lists): List of configurations arranged so that
                grouped configurations belong to the same snapshot
            energies (array) : Array containing the total energy of each snapshot
            ncores (int): number of CPUs to use for the gram matrix evaluation
        """

        hypotetical_model_name = "models/MODEL_ker_TwoBodySingleSpecies_ntr_%i.json" %(len(energies)+len(forces))
        try:
            model_2b = models.TwoBodySingleSpeciesModel.from_json(hypotetical_model_name)
            self.rep_sig = model_2b.rep_sig
            self.gp_2b = model_2b.gp
            if self.rep_sig:
                self.rep_energies = utility.get_repulsive_energies(
                    glob_confs, self.rep_sig)
                energies -= self.rep_energies
                self.rep_forces = utility.get_repulsive_forces(confs, self.rep_sig)
                forces -= self.rep_forces

            print("Loaded 2-body model to bootstart training")

        except:
            if self.rep_sig:
                self.rep_sig = utility.find_repulstion_sigma(confs)
                self.rep_energies = utility.get_repulsive_energies(
                    glob_confs, self.rep_sig)
                energies -= self.rep_energies
                self.rep_forces = utility.get_repulsive_forces(confs, self.rep_sig)
                forces -= self.rep_forces

            self.gp_2b.fit_force_and_energy(
                confs, forces, glob_confs, energies, ncores=ncores)

        two_body_forces = self.gp_2b.predict(confs, ncores=ncores)
        two_body_energies = self.gp_2b.predict_energy(
            glob_confs, ncores=ncores)
        self.gp_3b.fit_force_and_energy(
            confs, forces - two_body_forces, glob_confs, energies - two_body_energies, ncores=ncores)
Пример #2
0
    def fit_force_and_energy(self,
                             confs,
                             forces,
                             glob_confs,
                             energies,
                             ncores=1):
        """ Fit the GP to a set of training forces and energies using 
        2-body single species force-force, energy-force and energy-energy kernels

        Args:
            confs (list): List of M x 5 arrays containing coordinates and
                atomic numbers of atoms within a cutoff from the central one
            forces (array) : Array containing the vector forces on 
                the central atoms of the training configurations
            glob_confs (list of lists): List of configurations arranged so that
                grouped configurations belong to the same snapshot
            energies (array) : Array containing the total energy of each snapshot
            ncores (int): number of CPUs to use for the gram matrix evaluation

        """
        if self.rep_sig:
            self.rep_sig = utility.find_repulstion_sigma(confs)
            self.rep_energies = utility.get_repulsive_energies(
                glob_confs, self.rep_sig)
            energies -= self.rep_energies
            self.rep_forces = utility.get_repulsive_forces(confs, self.rep_sig)
            forces -= self.rep_forces

        self.gp.fit_force_and_energy(confs,
                                     forces,
                                     glob_confs,
                                     energies,
                                     ncores=ncores)
Пример #3
0
    def build_grid(self, start, num, ncores=1):
        """ Build the mapped 2-body potential. 
        Calculates the energy predicted by the GP for two atoms at distances that range from
        start to r_cut, for a total of num points. These energies are stored and a 1D spline
        interpolation is created, which can be used to predict the energy and, through its
        analytic derivative, the force associated to any couple of atoms.
        The total force or local energy can then be calculated for any atom by summing the 
        pairwise contributions of every other atom within a cutoff distance r_cut.
        The prediction is done by the ``calculator`` module which is built to work within 
        the ase python package.

        Args:
            start (float): smallest interatomic distance for which the energy is predicted
                by the GP and stored inn the 2-body mapped potential
            num (int): number of points to use in the grid of the mapped potential   

        """

        self.grid_start = start
        self.grid_num = num

        dists = np.linspace(start, self.r_cut, num)

        confs = np.zeros((num, 1, 5))
        confs[:, 0, 0] = dists
        confs[:, 0, 3], confs[:, 0, 4] = self.element, self.element
        confs = list(confs)

        grid_data = self.gp.predict_energy(confs, ncores=ncores, mapping=True)
        if self.rep_sig:
            grid_data += utility.get_repulsive_energies(confs,
                                                        self.rep_sig,
                                                        mapping=True)
        self.grid = interpolation.Spline1D(dists, grid_data)
Пример #4
0
    def predict_energy(self, glob_confs, return_std=False, ncores=1):
        """ Predict the local energies of the central atoms of confs using the
        2- and 3-body GPs. The total force is the sum of the two predictions.

        Args:
            glob_confs (list of lists): List of configurations arranged so that
                grouped configurations belong to the same snapshot
            return_std (bool): if True, returns the standard deviation 
                associated to predictions according to the GP framework

        Returns:
            energies (array) : Array containing the total energy of each snapshot
            energies_errors (array): errors associated to the energies predictions,
                returned only if return_std is True
        """

        if return_std:
            if self.rep_sig:
                rep_energies = utility.get_repulsive_energies(
                    glob_confs, self.rep_sig)
                force_2b, std_2b = self.gp_2b.predict_energy(
                    glob_confs, return_std, ncores=ncores)
                energy_2b += rep_energies
            else:
                energy_2b, std_2b = self.gp_2b.predict_energy(
                    glob_confs, return_std, ncores=ncores)
            energy_3b, std_3b = self.gp_2b.predict_energy(
                glob_confs, return_std, ncores=ncores)
            return energy_2b + energy_3b, std_2b + std_3b
        else:
            if self.rep_sig:
                rep_energies = utility.get_repulsive_energies(
                    glob_confs, self.rep_sig)
                return self.gp_2b.predict_energy(glob_confs, return_std, ncores=ncores) + rep_energies +\
                    self.gp_3b.predict_energy(
                        glob_confs, return_std, ncores=ncores)
            else:
                return self.gp_2b.predict_energy(glob_confs, return_std, ncores=ncores) + \
                    self.gp_3b.predict_energy(
                        glob_confs, return_std, ncores=ncores)
Пример #5
0
    def fit_energy(self, glob_confs, energies, ncores=1):
        """ Fit the GP to a set of training energies using a 2- and
        3-body single species energy-energy kernel functions. The 2-body Gaussian
        process is first fitted, then the 3-body GP is fitted to the difference
        between the training energies and the 2-body predictions of energies on the 
        training configurations.

        Args:
            glob_confs (list of lists): List of configurations arranged so that
                grouped configurations belong to the same snapshot
            energies (array) : Array containing the total energy of each snapshot
            ncores (int): number of CPUs to use for the gram matrix evaluation
        """
        hypotetical_model_name = "models/MODEL_ker_TwoBodyManySpecies_ntr_%i.json" %(len(energies))
        try:
            model_2b = models.TwoBodyManySpeciesModel.from_json(hypotetical_model_name)
            self.rep_sig = model_2b.rep_sig
            self.gp_2b = model_2b.gp
            if self.rep_sig:
                self.rep_energies = utility.get_repulsive_energies(
                        glob_confs, self.rep_sig)
                energies -= self.rep_energies
            print("Loaded 2-body model to bootstart training")
        
        except:
            if self.rep_sig:
                self.rep_sig = utility.find_repulstion_sigma(glob_confs)
                self.rep_energies = utility.get_repulsive_energies(
                    glob_confs, self.rep_sig)
                energies -= self.rep_energies

        self.gp_2b.fit_energy(glob_confs, energies, ncores=1)

        ntr = len(glob_confs)
        two_body_energies = self.gp_2b.predict_energy(
            glob_confs, ncores=ncores)

        self.gp_3b.fit_energy(glob_confs, energies -
                              two_body_energies, ncores=ncores)
Пример #6
0
    def fit_energy(self, glob_confs, energies, ncores=1):
        """ Fit the GP to a set of training energies using a 
        2-body single species energy-energy kernel

        Args:
            glob_confs (list of lists): List of configurations arranged so that
                grouped configurations belong to the same snapshot
            energies (array) : Array containing the total energy of each snapshot
            ncores (int): number of CPUs to use for the gram matrix evaluation
        """

        if self.rep_sig:
            self.rep_sig = utility.find_repulstion_sigma(glob_confs)
            self.rep_energies = utility.get_repulsive_energies(
                glob_confs, self.rep_sig)
            energies -= self.rep_energies

        self.gp.fit_energy(glob_confs, energies, ncores=ncores)
Пример #7
0
    def build_grid(self, start, num_2b, num_3b, ncores=1):
        """Function used to create the three different 2-body energy grids for 
        atoms of elements 0-0, 0-1, and 1-1, and the four different 3-body energy grids for 
        atoms of elements 0-0-0, 0-0-1, 0-1-1, and 1-1-1. The function calls the
        ``build_grid_3b`` function for each of the 3-body grids to build.

        Args:
            start (float): smallest interatomic distance for which the energy is predicted
                by the GP and stored inn the 3-body mapped potential
            num (int): number of points to use in the grid of the 2-body mapped potentials
            num_3b (int): number of points to use to generate the list of distances used to
                generate the triplets of atoms for the 3-body mapped potentials
            ncores (int): number of CPUs to use to calculate the energy predictions
        """

        self.grid_start = start
        self.grid_num_2b = num_2b
        self.grid_num_3b = num_2b

        perm_list_2b = list(combinations_with_replacement(self.elements, 2))
        perm_list_3b = list(combinations_with_replacement(self.elements, 3))

        dists_2b = np.linspace(start, self.r_cut, num_2b)
        confs_2b = np.zeros((num_2b, 1, 5))
        confs_2b[:, 0, 0] = dists_2b

        for pair in perm_list_2b:  # in this for loop, predicting then save for each individual one
            confs_2b[:, 0, 3], confs_2b[:, 0,
                                  4] = pair[0], pair[1]

            mapped_energies = self.gp_2b.predict_energy(
                list(confs_2b), ncores=ncores, mapping=True)
            if self.rep_sig:
                mapped_energies += utility.get_repulsive_energies(
                    confs_2b, self.rep_sig, mapping=True)
            self.grid_2b[pair] = interpolation.Spline1D(dists_2b, mapped_energies)


        dists_3b = np.linspace(start, self.r_cut, num_3b)

        for trip in perm_list_3b:

            self.grid_3b[trip] = self.build_grid_3b(
                dists_3b,  trip[0],  trip[1],  trip[2], ncores = ncores)
Пример #8
0
    def predict_energy(self, glob_confs, return_std=False, ncores=1):
        """ Predict the global energies of the central atoms of confs using a GP

        Args:
            glob_confs (list of lists): List of configurations arranged so that
                grouped configurations belong to the same snapshot
            return_std (bool): if True, returns the standard deviation 
                associated to predictions according to the GP framework

        Returns:
            energies (array) : Array containing the total energy of each snapshot
            energies_errors (array): errors associated to the energies predictions,
                returned only if return_std is True

        """
        if self.rep_sig:
            rep_energies = utility.get_repulsive_energies(
                glob_confs, self.rep_sig)
            return self.gp.predict_energy(
                glob_confs, return_std, ncores=ncores) + rep_energies
        else:
            return self.gp.predict_energy(glob_confs,
                                          return_std,
                                          ncores=ncores)
Пример #9
0
    def build_grid(self, start, num_2b, num_3b, ncores=1):
        """ Build the mapped 2- and 3-body potentials. 
        Calculates the energy predicted by the GP for two and three atoms at all possible combination 
        of num distances ranging from start to r_cut. The energy for the 3-body mapped grid is 
        calculated only for ``valid`` triplets of atoms, i.e. sets of three distances which 
        form a triangle (this is checked via the triangle inequality). 
        The grid building exploits all the permutation invariances to reduce the number of energy
        calculations needed to fill the grid.
        The computed 2-body energies are stored in an array of values, and a 1D spline interpolation is created.
        The computed 3-body energies are stored in a 3D cube of values, and a 3D spline interpolation is 
        created.
        The total force or local energy can then be calculated for any atom by summing the pairwise and
        triplet contributions of every valid couple and triplet of atoms of which one is always the central one.
        The prediction is done by the ``calculator`` module, which is built to work within 
        the ase python package.

        Args:
            start (float): smallest interatomic distance for which the energy is predicted
                by the GP and stored inn the 3-body mapped potential
            num_2b (int):number of points to use in the grid of the 2-body mapped potential 
            num_3b (int): number of points to use to generate the list of distances used to
                generate the triplets of atoms for the 2-body mapped potential
            ncores (int): number of CPUs to use to calculate the energy predictions
        """

        dists_2b = np.linspace(start, self.r_cut, num_2b)

        confs = np.zeros((num_2b, 1, 5))
        confs[:, 0, 0] = dists_2b
        confs[:, 0, 3], confs[:, 0, 4] = self.element, self.element

        grid_data = self.gp_2b.predict_energy(
            confs, ncores=ncores, mapping=True)
        if self.rep_sig:
            grid_data += utility.get_repulsive_energies(
                confs, self.rep_sig, mapping=True)
        grid_2b = interpolation.Spline1D(dists_2b, grid_data)

        # Mapping 3 body part
        dists_3b = np.linspace(start, self.r_cut, num_3b)
        inds, r_ij_x, r_ki_x, r_ki_y = self.generate_triplets(dists_3b)

        confs = np.zeros((len(r_ij_x), 2, 5))
        confs[:, 0, 0] = r_ij_x  # Element on the x axis
        confs[:, 1, 0] = r_ki_x  # Reshape into confs shape: this is x2
        confs[:, 1, 1] = r_ki_y  # Reshape into confs shape: this is y2

        # Permutations of elements
        confs[:, :, 3] = self.element  # Central element is always element 1
        # Element on the x axis is always element 2
        confs[:, 0, 4] = self.element
        # Element on the xy plane is always element 3
        confs[:, 1, 4] = self.element

        grid_3b = np.zeros((num_3b, num_3b, num_3b))

        grid_3b[inds] = self.gp_3b.predict_energy(
            confs, ncores=ncores, mapping=True).flatten()

        for ind_i in range(num_3b):
            for ind_j in range(ind_i + 1):
                for ind_k in range(ind_j + 1):
                    grid_3b[ind_i, ind_k, ind_j] = grid_3b[ind_i, ind_j, ind_k]
                    grid_3b[ind_j, ind_i, ind_k] = grid_3b[ind_i, ind_j, ind_k]
                    grid_3b[ind_j, ind_k, ind_i] = grid_3b[ind_i, ind_j, ind_k]
                    grid_3b[ind_k, ind_i, ind_j] = grid_3b[ind_i, ind_j, ind_k]
                    grid_3b[ind_k, ind_j, ind_i] = grid_3b[ind_i, ind_j, ind_k]

        grid_3b = interpolation.Spline3D(dists_3b, dists_3b, dists_3b, grid_3b)

        self.grid_2b = grid_2b
        self.grid_3b = grid_3b
        self.grid_num_2b = num_2b
        self.grid_num_3b = num_3b
        self.grid_start = start