Пример #1
0
    def calculate(self, atoms, properties, system_changes):
        Calculator.calculate(self, atoms, properties, system_changes)

        # construct neighbor list
        i_p, j_p, r_p, r_pc = neighbour_list('ijdD',
                                             atoms=atoms,
                                             cutoff=self.cutoff)

        nb_atoms = len(self.atoms)
        nb_pairs = len(i_p)

        # normal vectors
        n_pc = (r_pc.T / r_p).T
        nx_p, ny_p, nz_p = n_pc.T

        # construct triplet list
        first_i = first_neighbours(nb_atoms, i_p)
        ij_t, ik_t = triplet_list(first_i)

        # calculate energy
        G_t = self.G(r_pc[ij_t], r_pc[ik_t])
        xi_p = np.bincount(ij_t, weights=G_t, minlength=nb_pairs)
        F_p = self.F(r_p, xi_p)
        epot = 0.5 * np.sum(F_p)

        d1G_t = self.d1G(r_pc[ij_t], r_pc[ik_t])
        d2F_d2G_t = (self.d2F(r_p[ij_t], xi_p[ij_t]) *
                     self.d2G(r_pc[ij_t], r_pc[ik_t]).T).T
        # calculate forces (per pair)
        fx_p = \
            self.d1F(r_p, xi_p) * n_pc[:, 0] + \
            self.d2F(r_p, xi_p) * np.bincount(ij_t, d1G_t[:, 0], minlength=nb_pairs) + \
            np.bincount(ik_t, d2F_d2G_t[:, 0], minlength=nb_pairs)
        fy_p = \
            self.d1F(r_p, xi_p) * n_pc[:, 1] + \
            self.d2F(r_p, xi_p) * np.bincount(ij_t, d1G_t[:, 1], minlength=nb_pairs) + \
            np.bincount(ik_t, d2F_d2G_t[:, 1], minlength=nb_pairs)
        fz_p = \
            self.d1F(r_p, xi_p) * n_pc[:, 2] + \
            self.d2F(r_p, xi_p) * np.bincount(ij_t, d1G_t[:, 2], minlength=nb_pairs) + \
            np.bincount(ik_t, d2F_d2G_t[:, 2], minlength=nb_pairs)

        # collect atomic forces
        fx_n = 0.5 * (np.bincount(i_p, weights=fx_p) -
                      np.bincount(j_p, weights=fx_p))
        fy_n = 0.5 * (np.bincount(i_p, weights=fy_p) -
                      np.bincount(j_p, weights=fy_p))
        fz_n = 0.5 * (np.bincount(i_p, weights=fz_p) -
                      np.bincount(j_p, weights=fz_p))

        f_n = np.transpose([fx_n, fy_n, fz_n])

        self.results = {'energy': epot, 'forces': f_n}
Пример #2
0
    def calculate_hessian_matrix(self, atoms, divide_by_masses=False):
        """
        Calculate the Hessian matrix for a bond order potential.
        For an atomic configuration with N atoms in d dimensions the hessian matrix is a symmetric, hermitian matrix
        with a shape of (d*N,d*N). The matrix is in general a sparse matrix, which consists of dense blocks of shape (d,d), which
        are the mixed second derivatives.

        Parameters
        ----------
        atoms: ase.Atoms
            Atomic configuration in a local or global minima.

        divide_by_masses: bool
        	if true return the dynamic matrix else hessian matrix 

		Returns
		-------
		bsr_matrix
			either hessian or dynamic matrix

        Restrictions
        ----------
        This method is currently only implemented for three dimensional systems
        """

        # construct neighbor list
        i_p, j_p, r_p, r_pc = neighbour_list('ijdD',
                                             atoms=atoms,
                                             cutoff=2 * self.cutoff)
        mask_p = r_p > self.cutoff

        nb_atoms = len(self.atoms)
        nb_pairs = len(i_p)

        # reverse pairs
        tr_p = find_indices_of_reversed_pairs(i_p, j_p, r_p)

        # normal vectors
        n_pc = (r_pc.T / r_p).T
        nx_p, ny_p, nz_p = n_pc.T

        # construct triplet list
        first_i = first_neighbours(nb_atoms, i_p)
        ij_t, ik_t, jk_t = triplet_list(first_i, r_p, self.cutoff, i_p, j_p)
        first_ij = first_neighbours(len(i_p), ij_t)

        nb_triplets = len(ij_t)

        # basic triplet and pair terms
        G_t = self.G(r_pc[ij_t], r_pc[ik_t])
        xi_p = np.bincount(ij_t, weights=G_t, minlength=nb_pairs)
        F_p = self.F(r_p, xi_p)

        # Hessian term #4
        d1F_p = self.d1F(r_p, xi_p)
        d1F_p[
            mask_p] = 0.0  # we need to explicitly exclude everything with r > cutoff
        H_temp_pcc = (d1F_p *
                      (np.eye(3) -
                       (n_pc.reshape(-1, 3, 1) * n_pc.reshape(-1, 1, 3))).T /
                      r_p).T
        H_pcc = -H_temp_pcc

        # Hessian term #1
        d11F_p = self.d11F(r_p, xi_p)
        d11F_p[mask_p] = 0.0
        H_temp_pcc = (d11F_p *
                      (n_pc.reshape(-1, 3, 1) * n_pc.reshape(-1, 1, 3)).T).T
        H_pcc -= H_temp_pcc

        # Hessian term #2
        d12F_p = self.d12F(r_p, xi_p)
        d12F_p[mask_p] = 0.0

        d2G_tc = self.d2G(r_pc[ij_t], r_pc[ik_t])
        H_temp_t = (
            d12F_p[ij_t] *
            (d2G_tc.reshape(-1, 3, 1) * n_pc[ij_t].reshape(-1, 1, 3)).T).T

        H_temp_pcc = np.empty_like(H_temp_pcc)
        for x in range(3):
            for y in range(3):
                H_temp_pcc[:, x, y] = np.bincount(
                    tr_p[jk_t], weights=H_temp_t[:, x, y],
                    minlength=nb_pairs) - np.bincount(
                        ij_t, weights=H_temp_t[:, x, y],
                        minlength=nb_pairs) - np.bincount(
                            tr_p[ik_t],
                            weights=H_temp_t[:, x, y],
                            minlength=nb_pairs)
        H_pcc += H_temp_pcc

        d1G_tc = self.d1G(r_pc[ij_t], r_pc[ik_t])

        H_temp_t = (
            d12F_p[ij_t] *
            (d1G_tc.reshape(-1, 3, 1) * n_pc[ij_t].reshape(-1, 1, 3)).T).T

        for x in range(3):
            for y in range(3):
                H_temp_pcc[:, x, y] = -np.bincount(
                    ij_t, weights=H_temp_t[:, x, y], minlength=nb_pairs
                ) - np.bincount(
                    tr_p[ij_t], weights=H_temp_t[:, x, y], minlength=nb_pairs)
        H_pcc += H_temp_pcc

        # Hessian term #5
        d2F_p = self.d2F(r_p, xi_p)
        d2F_p[mask_p] = 0.0

        d22G_tcc = self.d22G(r_pc[ij_t], r_pc[ik_t])

        H_temp_t = (d2F_p[ij_t] * d22G_tcc.T).T

        for x in range(3):
            for y in range(3):
                H_temp_pcc[:, x, y] = -np.bincount(
                    ik_t, weights=H_temp_t[:, x, y], minlength=nb_pairs)
                # H_temp_pcc[:, x, y] = np.bincount(tr_p[jk_t], weights=H_temp_t[:, x, y], minlength=nb_pairs) - np.bincount(ij_t, weights=H_temp_t[:, x, y], minlength=nb_pairs) - np.bincount(tr_p[ik_t], weights=H_temp_t[:, x, y], minlength=nb_pairs)
        H_pcc += H_temp_pcc

        d11G_tcc = self.d11G(r_pc[ij_t], r_pc[ik_t])

        H_temp_t = (d2F_p[ij_t] * d11G_tcc.T).T

        for x in range(3):
            for y in range(3):
                H_temp_pcc[:, x, y] = -np.bincount(
                    ij_t, weights=H_temp_t[:, x, y], minlength=nb_pairs)
                # H_temp_pcc[:, x, y] = np.bincount(tr_p[jk_t], weights=H_temp_t[:, x, y], minlength=nb_pairs) - np.bincount(ij_t, weights=H_temp_t[:, x, y], minlength=nb_pairs) - np.bincount(tr_p[ik_t], weights=H_temp_t[:, x, y], minlength=nb_pairs)
        H_pcc += H_temp_pcc

        Hxx_p = +H_pcc[:, 0, 0]
        Hyy_p = +H_pcc[:, 1, 1]
        Hzz_p = +H_pcc[:, 2, 2]
        Hyz_p = +H_pcc[:, 1, 2]
        Hxz_p = +H_pcc[:, 0, 2]
        Hxy_p = +H_pcc[:, 0, 1]
        Hzy_p = +H_pcc[:, 2, 1]
        Hzx_p = +H_pcc[:, 2, 0]
        Hyx_p = +H_pcc[:, 1, 0]

        d1x2xG_t = self.d1x2xG(r_pc[ij_t], r_pc[ik_t])
        d1y2yG_t = self.d1y2yG(r_pc[ij_t], r_pc[ik_t])
        d1z2zG_t = self.d1z2zG(r_pc[ij_t], r_pc[ik_t])
        d1y2zG_t = self.d1y2zG(r_pc[ij_t], r_pc[ik_t])
        d1x2zG_t = self.d1x2zG(r_pc[ij_t], r_pc[ik_t])
        d1x2yG_t = self.d1x2yG(r_pc[ij_t], r_pc[ik_t])
        d1z2yG_t = self.d1z2yG(r_pc[ij_t], r_pc[ik_t])
        d1z2xG_t = self.d1z2xG(r_pc[ij_t], r_pc[ik_t])
        d1y2xG_t = self.d1y2xG(r_pc[ij_t], r_pc[ik_t])
        Hxx_t = d2F_p[ij_t] * d1x2xG_t
        Hyy_t = d2F_p[ij_t] * d1y2yG_t
        Hzz_t = d2F_p[ij_t] * d1z2zG_t
        Hyz_t = d2F_p[ij_t] * d1y2zG_t
        Hxz_t = d2F_p[ij_t] * d1x2zG_t
        Hxy_t = d2F_p[ij_t] * d1x2yG_t
        Hzy_t = d2F_p[ij_t] * d1z2yG_t
        Hzx_t = d2F_p[ij_t] * d1z2xG_t
        Hyx_t = d2F_p[ij_t] * d1y2xG_t
        Hxx_p += np.bincount(
            jk_t, weights=Hxx_t, minlength=nb_pairs) - np.bincount(
                tr_p[ij_t], weights=Hxx_t, minlength=nb_pairs) - np.bincount(
                    ik_t, weights=Hxx_t, minlength=nb_pairs)
        Hyy_p += np.bincount(
            jk_t, weights=Hyy_t, minlength=nb_pairs) - np.bincount(
                tr_p[ij_t], weights=Hyy_t, minlength=nb_pairs) - np.bincount(
                    ik_t, weights=Hyy_t, minlength=nb_pairs)
        Hzz_p += np.bincount(
            jk_t, weights=Hzz_t, minlength=nb_pairs) - np.bincount(
                tr_p[ij_t], weights=Hzz_t, minlength=nb_pairs) - np.bincount(
                    ik_t, weights=Hzz_t, minlength=nb_pairs)
        Hyz_p += np.bincount(
            jk_t, weights=Hyz_t, minlength=nb_pairs) - np.bincount(
                tr_p[ij_t], weights=Hyz_t, minlength=nb_pairs) - np.bincount(
                    ik_t, weights=Hyz_t, minlength=nb_pairs)
        Hxz_p += np.bincount(
            jk_t, weights=Hxz_t, minlength=nb_pairs) - np.bincount(
                tr_p[ij_t], weights=Hxz_t, minlength=nb_pairs) - np.bincount(
                    ik_t, weights=Hxz_t, minlength=nb_pairs)
        Hxy_p += np.bincount(
            jk_t, weights=Hxy_t, minlength=nb_pairs) - np.bincount(
                tr_p[ij_t], weights=Hxy_t, minlength=nb_pairs) - np.bincount(
                    ik_t, weights=Hxy_t, minlength=nb_pairs)
        Hzy_p += np.bincount(
            jk_t, weights=Hzy_t, minlength=nb_pairs) - np.bincount(
                tr_p[ij_t], weights=Hzy_t, minlength=nb_pairs) - np.bincount(
                    ik_t, weights=Hzy_t, minlength=nb_pairs)
        Hzx_p += np.bincount(
            jk_t, weights=Hzx_t, minlength=nb_pairs) - np.bincount(
                tr_p[ij_t], weights=Hzx_t, minlength=nb_pairs) - np.bincount(
                    ik_t, weights=Hzx_t, minlength=nb_pairs)
        Hyx_p += np.bincount(
            jk_t, weights=Hyx_t, minlength=nb_pairs) - np.bincount(
                tr_p[ij_t], weights=Hyx_t, minlength=nb_pairs) - np.bincount(
                    ik_t, weights=Hyx_t, minlength=nb_pairs)

        # Hessian term #3

        ## Terms involving D_1 * D_1
        d1G_t = self.d1G(r_pc[ij_t], r_pc[ik_t])

        d22F_p = self.d22F(r_p, xi_p)
        d22F_p[mask_p] = 0.0

        d1xG_p = np.bincount(ij_t, weights=d1G_t[:, 0], minlength=nb_pairs)
        d1yG_p = np.bincount(ij_t, weights=d1G_t[:, 1], minlength=nb_pairs)
        d1zG_p = np.bincount(ij_t, weights=d1G_t[:, 2], minlength=nb_pairs)

        d1G_p = np.transpose([d1xG_p, d1yG_p, d1zG_p])
        H_pcc = -(d22F_p *
                  (d1G_p.reshape(-1, 3, 1) * d1G_p.reshape(-1, 1, 3)).T).T

        ## Terms involving D_2 * D_2
        d2G_t = self.d2G(r_pc[ij_t], r_pc[ik_t])

        d2xG_p = np.bincount(ij_t, weights=d2G_t[:, 0], minlength=nb_pairs)
        d2yG_p = np.bincount(ij_t, weights=d2G_t[:, 1], minlength=nb_pairs)
        d2zG_p = np.bincount(ij_t, weights=d2G_t[:, 2], minlength=nb_pairs)

        d2G_p = np.transpose([d2xG_p, d2yG_p, d2zG_p])

        Q = ((d22F_p * d2G_p.T).T[ij_t].reshape(-1, 3, 1) *
             d2G_t.reshape(-1, 1, 3))
        H_temp_pcc = np.zeros_like(H_temp_pcc)
        for x in range(3):
            for y in range(3):
                H_temp_pcc[:, x, y] = -np.bincount(
                    ik_t, weights=Q[:, x, y], minlength=nb_pairs)
                # H_temp_pcc[:, x, y] = np.bincount(tr_p[jk_t], weights=H_temp_t[:, x, y], minlength=nb_pairs) - np.bincount(ij_t, weights=H_temp_t[:, x, y], minlength=nb_pairs) - np.bincount(tr_p[ik_t], weights=H_temp_t[:, x, y], minlength=nb_pairs)
        H_pcc += H_temp_pcc

        Hxx_p += H_pcc[:, 0, 0]
        Hyy_p += H_pcc[:, 1, 1]
        Hzz_p += H_pcc[:, 2, 2]
        Hyz_p += H_pcc[:, 1, 2]
        Hxz_p += H_pcc[:, 0, 2]
        Hxy_p += H_pcc[:, 0, 1]
        Hzy_p += H_pcc[:, 2, 1]
        Hzx_p += H_pcc[:, 2, 0]
        Hyx_p += H_pcc[:, 1, 0]

        for il_im in range(nb_triplets):
            il = ij_t[il_im]
            im = ik_t[il_im]
            lm = jk_t[il_im]
            for t in range(first_ij[il], first_ij[il + 1]):
                ij = ik_t[t]
                if ij != il and ij != im:
                    r_p_ij = np.array([r_pc[ij]])
                    r_p_il = np.array([r_pc[il]])
                    r_p_im = np.array([r_pc[im]])
                    H_pcc = (0.5 * d22F_p[ij] *
                             (self.d2G(r_p_ij, r_p_il).reshape(-1, 3, 1) *
                              self.d2G(r_p_ij, r_p_im).reshape(-1, 1, 3)).T).T
                    Hxx_p[lm] += H_pcc[:, 0, 0]
                    Hyy_p[lm] += H_pcc[:, 1, 1]
                    Hzz_p[lm] += H_pcc[:, 2, 2]
                    Hyz_p[lm] += H_pcc[:, 1, 2]
                    Hxz_p[lm] += H_pcc[:, 0, 2]
                    Hxy_p[lm] += H_pcc[:, 0, 1]
                    Hzy_p[lm] += H_pcc[:, 2, 1]
                    Hzx_p[lm] += H_pcc[:, 2, 0]
                    Hyx_p[lm] += H_pcc[:, 1, 0]

        ## Terms involving D_1 * D_2
        # Was d2*d1
        Q = ((d22F_p * d1G_p.T).T[ij_t].reshape(-1, 3, 1) *
             d2G_t.reshape(-1, 1, 3))

        H_temp_pcc = np.zeros_like(H_temp_pcc)
        for x in range(3):
            for y in range(3):
                H_temp_pcc[:, x, y] = np.bincount(
                    jk_t, weights=Q[:, x, y],
                    minlength=nb_pairs) - np.bincount(
                        ik_t, weights=Q[:, x, y], minlength=nb_pairs)
                # H_temp_pcc[:, x, y] = np.bincount(tr_p[jk_t], weights=H_temp_t[:, x, y], minlength=nb_pairs) - np.bincount(ij_t, weights=H_temp_t[:, x, y], minlength=nb_pairs) - np.bincount(tr_p[ik_t], weights=H_temp_t[:, x, y], minlength=nb_pairs)
        H_pcc = H_temp_pcc

        H_pcc -= (d22F_p *
                  (d2G_p.reshape(-1, 3, 1) * d1G_p.reshape(-1, 1, 3)).T).T

        Hxx_p += H_pcc[:, 0, 0]
        Hyy_p += H_pcc[:, 1, 1]
        Hzz_p += H_pcc[:, 2, 2]
        Hyz_p += H_pcc[:, 1, 2]
        Hxz_p += H_pcc[:, 0, 2]
        Hxy_p += H_pcc[:, 0, 1]
        Hzy_p += H_pcc[:, 2, 1]
        Hzx_p += H_pcc[:, 2, 0]
        Hyx_p += H_pcc[:, 1, 0]

        # Add the conjugate terms (symmetrize Hessian)
        Hxx_p += Hxx_p[tr_p]
        Hyy_p += Hyy_p[tr_p]
        Hzz_p += Hzz_p[tr_p]
        tmp = Hyz_p.copy()
        Hyz_p += Hzy_p[tr_p]
        Hzy_p += tmp[tr_p]
        tmp = Hxz_p.copy()
        Hxz_p += Hzx_p[tr_p]
        Hzx_p += tmp[tr_p]
        tmp = Hxy_p.copy()
        Hxy_p += Hyx_p[tr_p]
        Hyx_p += tmp[tr_p]

        # Construct diagonal terms from off-diagonal terms
        Hxx_a = -np.bincount(i_p, weights=Hxx_p)
        Hyy_a = -np.bincount(i_p, weights=Hyy_p)
        Hzz_a = -np.bincount(i_p, weights=Hzz_p)
        Hyz_a = -np.bincount(i_p, weights=Hyz_p)
        Hxz_a = -np.bincount(i_p, weights=Hxz_p)
        Hxy_a = -np.bincount(i_p, weights=Hxy_p)
        Hzy_a = -np.bincount(i_p, weights=Hzy_p)
        Hzx_a = -np.bincount(i_p, weights=Hzx_p)
        Hyx_a = -np.bincount(i_p, weights=Hyx_p)

        # Construct full off-diagonal term
        H_pcc = np.transpose([[Hxx_p, Hyx_p, Hzx_p], [Hxy_p, Hyy_p, Hzy_p],
                              [Hxz_p, Hyz_p, Hzz_p]])

        # Construct full diagonal term
        H_acc = np.transpose([[Hxx_a, Hxy_a, Hxz_a], [Hyx_a, Hyy_a, Hyz_a],
                              [Hzx_a, Hzy_a, Hzz_a]])

        if divide_by_masses:
            mass_nat = atoms.get_masses()
            geom_mean_mass_n = np.sqrt(mass_nat[i_p] * mass_nat[j_p])
            return \
                bsr_matrix(((H_pcc.T/(2 * geom_mean_mass_n)).T, j_p, first_i), shape=(3*nb_atoms, 3*nb_atoms)) \
                + bsr_matrix(((H_acc.T/(2 * mass_nat)).T, np.arange(nb_atoms), np.arange(nb_atoms+1)),
                     shape=(3*nb_atoms, 3*nb_atoms))
        else:
            return \
                bsr_matrix((H_pcc/2, j_p, first_i), shape=(3*nb_atoms, 3*nb_atoms)) \
                + bsr_matrix((H_acc/2, np.arange(nb_atoms), np.arange(nb_atoms+1)),
                     shape=(3*nb_atoms, 3*nb_atoms))