Example #1
0
inline double imagePotential(double eps, double epsSolv, double radius, const Eigen::Vector3d & origin,
                             const Eigen::Vector3d & sp, const Eigen::Vector3d & pp) {
    Eigen::Vector3d sp_origin = sp - origin;
    double sp_origin_norm = sp_origin.norm();
    Eigen::Vector3d pp_origin = pp - origin;
    double pp_origin_norm = pp_origin.norm();
    double cos_gamma = sp_origin.dot(pp_origin) / (sp_origin.norm() * pp_origin.norm());
    // Clean-up cos_gamma, Legendre polynomials are only defined for -1 <= x <= 1
    if (numericalZero(cos_gamma - 1)) cos_gamma = 1.0;
    if (numericalZero(cos_gamma + 1)) cos_gamma = -1.0;
    // Image charge position
    Eigen::Vector3d r_img = origin + std::pow(radius / pp_origin_norm, 2) * pp_origin;
    double sp_image_norm = (sp - r_img).norm();
    // Image charge
    double q_img = radius / pp_origin_norm;
    // Permittivity factor
    double factor = (eps - epsSolv) / (eps + epsSolv);

    // Image Green's function
    double G_img = factor * (q_img / sp_image_norm - q_img / sp_origin_norm);
    // Image Green's function
    // Accumulate Legendre polynomial expansion of image potential
    double f_0 = radius / (sp_origin_norm * pp_origin_norm);
    double f_l = f_0;
    for (int l = 1; l <= 200; ++l) {
        f_l = f_l * radius * f_0;
        double C_0_l = (eps - epsSolv) * l / ((eps + epsSolv) * l + epsSolv);
        double pl_x = boost::math::legendre_p(l, cos_gamma);
        G_img += f_l * (C_0_l - factor) * pl_x;
    }

    return G_img / epsSolv;
}
Example #2
0
inline double derivativeImagePotential(double eps, double epsSolv, double radius, const Eigen::Vector3d & origin,
                                       const Eigen::Vector3d & sp,
                                       const Eigen::Vector3d & ppNormal, const Eigen::Vector3d & pp) {
    Eigen::Vector3d sp_origin = sp - origin;
    double sp_origin_norm = sp_origin.norm();
    Eigen::Vector3d pp_origin = pp - origin;
    double pp_origin_norm = pp_origin.norm();
    double cos_gamma = sp_origin.dot(pp_origin) / (sp_origin_norm * pp_origin_norm);
    // Clean-up cos_gamma, Legendre polynomials are only defined for -1 <= x <= 1
    if (numericalZero(cos_gamma - 1)) cos_gamma = 1.0;
    if (numericalZero(cos_gamma + 1)) cos_gamma = -1.0;
    double pp_origin_norm_3 = std::pow(pp_origin_norm, 3);

    Eigen::Vector3d r_img = origin + std::pow(radius / pp_origin_norm, 2) * pp_origin;
    Eigen::Vector3d pp_image = pp - r_img;
    double pp_image_norm_3 = std::pow(pp_image.norm(), 3);
    double factor = (eps - epsSolv) / (eps + epsSolv);

    double der_G_img = factor * (radius / sp_origin_norm) * (pp_origin.dot(ppNormal) / pp_origin_norm_3 - pp_image.dot(ppNormal) / pp_image_norm_3);
    /*
    // Accumulate Legendre polynomial expansion of image potential
    double f_0 = radius / (sp_origin_norm * pp_origin_norm);
    double f_l = f_0;
    double pp_origin_norm_l_3 = pp_origin_norm_3; // To accumulate (pp-origin).norm()^(l+3)
    double pp_origin_norm_l_1 = pp_origin_norm;   // To accumulate (pp-origin).norm()^(l+1)
    for (int l = 1; l <= 200; ++l) {
        f_l = f_l * radius * f_0;
        pp_origin_norm_l_3 *= pp_origin_norm;
        pp_origin_norm_l_1 *= pp_origin_norm;

        double pl_x = boost::math::legendre_p(l, cos_gamma); // P_l(cos_gamma)
        double pl_1_x = boost::math::legendre_p(l+1, cos_gamma); // P_(l+1)(cos_gamma)
        double cos_denom = std::pow(cos_gamma, 2) - 1;

        double tmp_a = ((l+1) * pl_x * pp_origin.dot(ppNormal)) / pp_origin_norm_l_3;
        double tmp_b = ((l+1) * (pl_1_x - cos_gamma * pl_x) ) / (pp_origin_norm_l_1 * cos_denom);
        double tmp_c = sp_origin.dot(ppNormal) / (sp_origin_norm * pp_origin_norm);
        double tmp_d = (pp_origin.dot(sp_origin) * pp_origin.dot(ppNormal)) / (sp_origin_norm * pp_origin_norm_3);
        double tmp_e = tmp_b * (tmp_c - tmp_d);

        double C_0_l = (eps - epsSolv) * l / ((eps + epsSolv) * l + epsSolv);
        double C_l = C_0_l - factor;

        der_G_img += f_l * C_l * (-tmp_a + tmp_e);
    }
    */

    return der_G_img / epsSolv;
}
Example #3
0
 /*! Provides a functor for the evaluation of the system
  *  of first-order ODEs needed by Boost.Odeint
  *  The second-order ODE and the system of first-order ODEs
  *  are reported in the manuscript.
  *  \param[in] rho state vector holding the function and its first derivative
  *  \param[out] drhodr state vector holding the first and second derivative
  *  \param[in] r position on the integration grid
  */
 void operator()(const StateType & rho, StateType & drhodr, const double r)
 {
     // Evaluate the dielectric profile
     double eps = 0.0, epsPrime = 0.0;
     pcm::tie(eps, epsPrime) = eval_(r);
     if (numericalZero(eps)) throw std::domain_error("Division by zero!");
     double gamma_epsilon = epsPrime / eps;
     // System of equations is defined here
     drhodr[0] = rho[1];
     drhodr[1] = -rho[1] * (rho[1] + 2.0/r + gamma_epsilon) + l_ * (l_ + 1) / std::pow(r, 2);
 }
Example #4
0
/*! \fn inline void symmetryBlocking(Eigen::MatrixXd & matrix, int cavitySize, int ntsirr, int nr_irrep)
 *  \param[out] matrix the matrix to be block-diagonalized
 *  \param[in]  cavitySize the size of the cavity (size of the matrix)
 *  \param[in]  ntsirr     the size of the irreducible portion of the cavity (size of the blocks)
 *  \param[in]  nr_irrep   the number of irreducible representations (number of blocks)
 */
inline void symmetryBlocking(Eigen::MatrixXd & matrix, size_t cavitySize, int ntsirr,
                             int nr_irrep)
{
    // This function implements the simmetry-blocking of the PCM
    // matrix due to point group symmetry as reported in:
    // L. Frediani, R. Cammi, C. S. Pomelli, J. Tomasi and K. Ruud, J. Comput.Chem. 25, 375 (2003)
    // u is the character table for the group (t in the paper)
    Eigen::MatrixXd u = Eigen::MatrixXd::Zero(nr_irrep, nr_irrep);
    for (int i = 0; i < nr_irrep; ++i) {
        for (int j = 0; j < nr_irrep; ++j) {
            u(i, j) = parity(i&j);
        }
    }
    // Naming of indices:
    //     a, b, c, d   run over the total size of the cavity (N)
    //     i, j, k, l   run over the number of irreps (n)
    //     p, q, r, s   run over the irreducible size of the cavity (N/n)
    // Instead of forming U (T in the paper) and then perform the dense
    // multiplication, we multiply block-by-block using just the u matrix.
    //      matrix = U * matrix * Ut; U * Ut = Ut * U = id
    // First half-transformation, i.e. first_half = matrix * Ut
    Eigen::MatrixXd first_half = Eigen::MatrixXd::Zero(cavitySize, cavitySize);
    for (int i = 0; i < nr_irrep; ++i) {
        int ioff = i * ntsirr;
        for (int k = 0; k < nr_irrep; ++k) {
            int koff = k * ntsirr;
            for (int j = 0; j < nr_irrep; ++j) {
                int joff = j * ntsirr;
                double ujk = u(j, k) / nr_irrep;
                for (int p = 0; p < ntsirr; ++p) {
                    int a = ioff + p;
                    for (int q = 0; q < ntsirr; ++q) {
                        int b = joff + q;
                        int c = koff + q;
                        first_half(a, c) += matrix(a, b) * ujk;
                    }
                }
            }
        }
    }
    // Second half-transformation, i.e. matrix = U * first_half
    matrix.setZero(cavitySize, cavitySize);
    for (int i = 0; i < nr_irrep; ++i) {
        int ioff = i * ntsirr;
        for (int k = 0; k < nr_irrep; ++k) {
            int koff = k * ntsirr;
            for (int j = 0; j < nr_irrep; ++j) {
                int joff = j * ntsirr;
                double uij = u(i, j);
                for (int p = 0; p < ntsirr; ++p) {
                    int a = ioff + p;
                    int b = joff + p;
                    for (int q = 0; q < ntsirr; ++q) {
                        int c = koff + q;
                        matrix(a, c) += uij * first_half(b, c);
                    }
                }
            }
        }
    }
    // Traverse the matrix and discard numerical zeros
    for (size_t a = 0; a < cavitySize; ++a) {
        for (size_t b = 0; b < cavitySize; ++b) {
            if (numericalZero(matrix(a, b))) {
                matrix(a, b) = 0.0;
            }
        }
    }
}