예제 #1
0
/*! \brief Builds the **anisotropic** IEFPCM matrix
 *  \param[in] cav the discretized cavity
 *  \param[in] gf_i Green's function inside the cavity
 *  \param[in] gf_o Green's function outside the cavity
 *  \return the \f$ \mathbf{K} = \mathbf{T}^{-1}\mathbf{R}\mathbf{A} \f$ matrix
 *
 *  This function calculates the PCM matrix. We use the following definitions:
 *  \f[
 *     \begin{align}
 *       \mathbf{T} &=
 *      \left(2\pi\mathbf{I} - \mathbf{D}_\mathrm{e}\mathbf{A}\right)\mathbf{S}_\mathrm{i}
 *      +\mathbf{S}_\mathrm{e}\left(2\pi\mathbf{I} +
 *      \mathbf{A}\mathbf{D}_\mathrm{i}^\dagger\right) \\
 *      \mathbf{R} &=
 *      \left(2\pi\mathbf{A}^{-1} - \mathbf{D}_\mathrm{e}\right) -
 *      \mathbf{S}_\mathrm{e}\mathbf{S}^{-1}_\mathrm{i}\left(2\pi\mathbf{A}^{-1}-\mathbf{D}_\mathrm{i}\right)
 *     \end{align}
 *  \f]
 *  The matrix is not symmetrized and is not symmetry packed.
 */
inline Eigen::MatrixXd anisotropicIEFMatrix(const Cavity & cav, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
{
  // The total size of the cavity
  size_t cavitySize = cav.size();
  // The number of irreps in the group
  int nrBlocks = cav.pointGroup().nrIrrep();
  // The size of the irreducible portion of the cavity
  int dimBlock = cav.irreducible_size();

  // Compute SI, DI and SE, DE on the whole cavity, regardless of symmetry
  TIMER_ON("Computing SI");
  Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements());
  TIMER_OFF("Computing SI");
  TIMER_ON("Computing DI");
  Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements());
  TIMER_OFF("Computing DI");
  TIMER_ON("Computing SE");
  Eigen::MatrixXd SE = gf_o.singleLayer(cav.elements());
  TIMER_OFF("Computing SE");
  TIMER_ON("Computing DE");
  Eigen::MatrixXd DE = gf_o.doubleLayer(cav.elements());
  TIMER_OFF("Computing DE");

  // Perform symmetry blocking
  // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix
  // into "block diagonal" when all other manipulations are done.
  if (cav.pointGroup().nrGenerators() != 0) {
    TIMER_ON("Symmetry blocking");
    symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks);
    symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks);
    symmetryBlocking(DE, cavitySize, dimBlock, nrBlocks);
    symmetryBlocking(SE, cavitySize, dimBlock, nrBlocks);
    TIMER_OFF("Symmetry blocking");
  }

  Eigen::MatrixXd a = cav.elementArea().asDiagonal();
  Eigen::MatrixXd Id = Eigen::MatrixXd::Identity(cavitySize, cavitySize);

  // 1. Form T
  TIMER_ON("Assemble T matrix");
  Eigen::MatrixXd fullPCMMatrix = ((2 * M_PI * Id - DE * a) * SI + SE * (2 * M_PI * Id + a * DI.adjoint().eval()));
  TIMER_OFF("Assemble T matrix");
  // 2. Invert T using LU decomposition with full pivoting
  //    This is a rank-revealing LU decomposition, this allows us
  //    to test if T is invertible before attempting to invert it.
  TIMER_ON("Invert T matrix");
  Eigen::FullPivLU<Eigen::MatrixXd> T_LU(fullPCMMatrix);
  if (!(T_LU.isInvertible())) PCMSOLVER_ERROR("T matrix is not invertible!", BOOST_CURRENT_FUNCTION);
  fullPCMMatrix = T_LU.inverse();
  TIMER_OFF("Invert T matrix");
  Eigen::FullPivLU<Eigen::MatrixXd> SI_LU(SI);
  if (!(SI_LU.isInvertible())) PCMSOLVER_ERROR("SI matrix is not invertible!", BOOST_CURRENT_FUNCTION);
  TIMER_ON("Assemble T^-1R matrix");
  fullPCMMatrix *= ((2 * M_PI * Id - DE * a) - SE * SI_LU.inverse() * (2 * M_PI * Id - DI * a));
  TIMER_OFF("Assemble T^-1R matrix");

  return fullPCMMatrix;
}
예제 #2
0
 /*! \brief Retrieve constant iterator from map given object identifier
  * \param[in] objID  the object's identification string
  */
 CallbackConstIter retrieve(const std::string & objID) const {
   if (objID.empty())
     PCMSOLVER_ERROR("No object identification string provided to the Factory.");
   CallbackConstIter i = callbacks_.find(objID);
   if (i == callbacks_.end())
     PCMSOLVER_ERROR("The unknown object ID " + objID +
                     " occurred in the Factory.");
   return i;
 }
예제 #3
0
void IEFSolver::buildAnisotropicMatrix(const Cavity & cav, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
{
    // The total size of the cavity
    size_t cavitySize = cav.size();
    // The number of irreps in the group
    int nrBlocks = cav.pointGroup().nrIrrep();
    // The size of the irreducible portion of the cavity
    int dimBlock = cav.irreducible_size();

    // Compute SI, DI and SE, DE on the whole cavity, regardless of symmetry
    Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements());
    Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements());
    Eigen::MatrixXd SE = gf_o.singleLayer(cav.elements());
    Eigen::MatrixXd DE = gf_o.doubleLayer(cav.elements());

    // Perform symmetry blocking
    // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix
    // into "block diagonal" when all other manipulations are done.
    if (cav.pointGroup().nrGenerators() != 0) {
        symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks);
        symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks);
        symmetryBlocking(DE, cavitySize, dimBlock, nrBlocks);
        symmetryBlocking(SE, cavitySize, dimBlock, nrBlocks);
    }

    Eigen::MatrixXd a = cav.elementArea().asDiagonal();
    Eigen::MatrixXd aInv = a.inverse();

    // 1. Form T
    fullPCMMatrix_ = ((2 * M_PI * aInv - DE) * a * SI + SE * a * (2 * M_PI * aInv + DI.adjoint().eval()));
    // 2. Invert T using LU decomposition with full pivoting
    //    This is a rank-revealing LU decomposition, this allows us
    //    to test if T is invertible before attempting to invert it.
    Eigen::FullPivLU<Eigen::MatrixXd> T_LU(fullPCMMatrix_);
    if (!(T_LU.isInvertible())) PCMSOLVER_ERROR("T matrix is not invertible!");
    fullPCMMatrix_ = T_LU.inverse();
    Eigen::FullPivLU<Eigen::MatrixXd> SI_LU(SI);
    if (!(SI_LU.isInvertible())) PCMSOLVER_ERROR("SI matrix is not invertible!");
    fullPCMMatrix_ *= ((2 * M_PI * aInv - DE) - SE * SI_LU.inverse() * (2 * M_PI * aInv - DI));
    fullPCMMatrix_ *= a;
    // 5. Symmetrize K := (K + K+)/2
    if (hermitivitize_) {
        hermitivitize(fullPCMMatrix_);
    }
    // Pack into a block diagonal matrix
    // For the moment just packs into a std::vector<Eigen::MatrixXd>
    symmetryPacking(blockPCMMatrix_, fullPCMMatrix_, dimBlock, nrBlocks);
    std::ofstream matrixOut("PCM_matrix");
    matrixOut << "fullPCMMatrix" << std::endl;
    matrixOut << fullPCMMatrix_ << std::endl;
    for (int i = 0; i < nrBlocks; ++i) {
        matrixOut << "Block number " << i << std::endl;
        matrixOut << blockPCMMatrix_[i] << std::endl;
    }

    built_ = true;
}
예제 #4
0
void tangent_and_bitangent(const Eigen::Vector3d & n_,
    Eigen::Vector3d & t_, Eigen::Vector3d & b_)
{
  double rmin = 0.99;
  double n0 = n_(0), n1 = n_(1), n2 = n_(2);
  if (std::abs(n0) <= rmin) {
    rmin = std::abs(n0);
    t_(0) = 0.0;
    t_(1) = - n2 / std::sqrt(1.0 - std::pow(n0, 2));
    t_(2) =   n1 / std::sqrt(1.0 - std::pow(n0, 2));
  }
  if (std::abs(n1) <= rmin) {
    rmin = std::abs(n1);
    t_(0) =   n2 / std::sqrt(1.0 - std::pow(n1, 2));
    t_(1) =   0.0;
    t_(2) = - n0 / std::sqrt(1.0 - std::pow(n1, 2));
  }
  if (std::abs(n2) <= rmin) {
    rmin = std::abs(n2);
    t_(0) =  n1 / std::sqrt(1.0 - std::pow(n2, 2));
    t_(1) = -n0 / std::sqrt(1.0 - std::pow(n2, 2));
    t_(2) =  0.0;
  }
  b_ = n_.cross(t_);
  // Check that the calculated Frenet-Serret frame is left-handed (levogiro)
  // by checking that the determinant of the matrix whose columns are the normal,
  // tangent and bitangent vectors has determinant 1 (the system is orthonormal!)
  Eigen::Matrix3d M;
  M.col(0) = n_;
  M.col(1) = t_;
  M.col(2) = b_;
  if (boost::math::sign(M.determinant()) != 1) {
    PCMSOLVER_ERROR("Frenet-Serret local frame is not left-handed!", BOOST_CURRENT_FUNCTION);
  }
}
예제 #5
0
/*! \brief Builds the **anisotropic** \f$ \mathbf{R}_\infty \f$ matrix
 *  \param[in] cav the discretized cavity
 *  \param[in] gf_i Green's function inside the cavity
 *  \param[in] gf_o Green's function outside the cavity
 *  \return the \f$ \mathbf{R}_\infty\mathbf{A} \f$ matrix
 *
 *  We use the following definition:
 *  \f[
 *      \mathbf{R}_\infty =
 *      \left(2\pi\mathbf{A}^{-1} - \mathbf{D}_\mathrm{e}\right) -
 *      \mathbf{S}_\mathrm{e}\mathbf{S}^{-1}_\mathrm{i}\left(2\pi\mathbf{A}^{-1}-\mathbf{D}_\mathrm{i}\right)
 *  \f]
 *  The matrix is not symmetrized and is not symmetry packed.
 */
inline Eigen::MatrixXd anisotropicRinfinity(const Cavity & cav, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
{
  // The total size of the cavity
  size_t cavitySize = cav.size();
  // The number of irreps in the group
  int nrBlocks = cav.pointGroup().nrIrrep();
  // The size of the irreducible portion of the cavity
  int dimBlock = cav.irreducible_size();

  // Compute SI, DI and SE, DE on the whole cavity, regardless of symmetry
  Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements());
  Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements());
  Eigen::MatrixXd SE = gf_o.singleLayer(cav.elements());
  Eigen::MatrixXd DE = gf_o.doubleLayer(cav.elements());

  // Perform symmetry blocking
  // If the group is C1 avoid symmetry blocking, we will just pack the matrix
  // into "block diagonal" when all other manipulations are done.
  if (cav.pointGroup().nrGenerators() != 0) {
    symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks);
    symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks);
    symmetryBlocking(DE, cavitySize, dimBlock, nrBlocks);
    symmetryBlocking(SE, cavitySize, dimBlock, nrBlocks);
  }

  Eigen::MatrixXd a = cav.elementArea().asDiagonal();
  Eigen::MatrixXd Id = Eigen::MatrixXd::Identity(cavitySize, cavitySize);

  // Form T
  Eigen::FullPivLU<Eigen::MatrixXd> SI_LU(SI);
  if (!(SI_LU.isInvertible())) PCMSOLVER_ERROR("SI matrix is not invertible!", BOOST_CURRENT_FUNCTION);
  return ((2 * M_PI * Id - DE * a) - SE * SI_LU.inverse() * (2 * M_PI * Id - DI * a));
}
예제 #6
0
/*! \brief Builds the CPCM matrix
 *  \param[in] cav the discretized cavity
 *  \param[in] gf_i Green's function inside the cavity
 *  \param[in] epsilon permittivity outside the cavity
 *  \param[in] correction CPCM correction factor
 *  \return the \f$ \mathbf{K} = f(\varepsilon)\mathbf{S}^{-1} \f$ matrix
 *
 *  This function calculates the PCM matrix.
 *  The matrix is not symmetrized and is not symmetry packed.
 */
inline Eigen::MatrixXd CPCMMatrix(const Cavity & cav, const IGreensFunction & gf_i, double epsilon, double correction)
{
  // The total size of the cavity
  size_t cavitySize = cav.size();
  // The number of irreps in the group
  int nrBlocks = cav.pointGroup().nrIrrep();
  // The size of the irreducible portion of the cavity
  int dimBlock = cav.irreducible_size();

  // Compute SI and DI on the whole cavity, regardless of symmetry
  TIMER_ON("Computing SI");
  Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements());
  TIMER_OFF("Computing SI");

  // Perform symmetry blocking
  // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix
  // into "block diagonal" when all other manipulations are done.
  if (cav.pointGroup().nrGenerators() != 0) {
    TIMER_ON("Symmetry blocking");
    symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks);
    TIMER_OFF("Symmetry blocking");
  }

  double fact = (epsilon - 1.0)/(epsilon + correction);
  // Invert SI  using LU decomposition with full pivoting
  // This is a rank-revealing LU decomposition, this allows us
  // to test if SI is invertible before attempting to invert it.
  Eigen::FullPivLU<Eigen::MatrixXd> SI_LU(SI);
  if (!(SI_LU.isInvertible()))
    PCMSOLVER_ERROR("SI matrix is not invertible!", BOOST_CURRENT_FUNCTION);
  return fact * SI_LU.inverse();
}
예제 #7
0
void IEFSolver::buildIsotropicMatrix(const Cavity & cav, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
{
    // The total size of the cavity
    size_t cavitySize = cav.size();
    // The number of irreps in the group
    int nrBlocks = cav.pointGroup().nrIrrep();
    // The size of the irreducible portion of the cavity
    int dimBlock = cav.irreducible_size();

    // Compute SI and DI on the whole cavity, regardless of symmetry
    Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements());
    Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements());

    // Perform symmetry blocking
    // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix
    // into "block diagonal" when all other manipulations are done.
    if (cav.pointGroup().nrGenerators() != 0) {
        symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks);
        symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks);
    }

    Eigen::MatrixXd a = cav.elementArea().asDiagonal();
    Eigen::MatrixXd aInv = Eigen::MatrixXd::Zero(cavitySize, cavitySize);
    aInv = a.inverse();

    // Tq = -Rv -> q = -(T^-1 * R)v = -Kv
    // T = (2 * M_PI * fact * aInv - DI) * a * SI; R = (2 * M_PI * aInv - DI)
    // fullPCMMatrix_ = K = T^-1 * R * a
    // 1. Form T
    double epsilon = profiles::epsilon(gf_o.permittivity());
    double fact = (epsilon + 1.0)/(epsilon - 1.0);
    fullPCMMatrix_ = (2 * M_PI * fact * aInv - DI) * a * SI;
    // 2. Invert T using LU decomposition with full pivoting
    //    This is a rank-revealing LU decomposition, this allows us
    //    to test if T is invertible before attempting to invert it.
    Eigen::FullPivLU<Eigen::MatrixXd> T_LU(fullPCMMatrix_);
    if (!(T_LU.isInvertible()))
        PCMSOLVER_ERROR("T matrix is not invertible!");
    fullPCMMatrix_ = T_LU.inverse();
    // 3. Multiply T^-1 and R
    fullPCMMatrix_ *= (2 * M_PI * aInv - DI);
    // 4. Multiply by a
    fullPCMMatrix_ *= a;
    // 5. Symmetrize K := (K + K+)/2
    if (hermitivitize_) {
        hermitivitize(fullPCMMatrix_);
    }
    // Pack into a block diagonal matrix
    // For the moment just packs into a std::vector<Eigen::MatrixXd>
    symmetryPacking(blockPCMMatrix_, fullPCMMatrix_, dimBlock, nrBlocks);
    std::ofstream matrixOut("PCM_matrix");
    matrixOut << "fullPCMMatrix" << std::endl;
    matrixOut << fullPCMMatrix_ << std::endl;
    for (int i = 0; i < nrBlocks; ++i) {
        matrixOut << "Block number " << i << std::endl;
        matrixOut << blockPCMMatrix_[i] << std::endl;
    }

    built_ = true;
}
예제 #8
0
/*! \brief Builds the **isotropic** IEFPCM matrix
 *  \param[in] cav the discretized cavity
 *  \param[in] gf_i Green's function inside the cavity
 *  \param[in] epsilon permittivity outside the cavity
 *  \return the \f$ \mathbf{K} = \mathbf{T}^{-1}\mathbf{R}\mathbf{A} \f$ matrix
 *
 *  This function calculates the PCM matrix. We use the following definitions:
 *  \f[
 *     \begin{align}
 *       \mathbf{T} &=
 *      \left(2\pi\frac{\varepsilon+1}{\varepsilon-1}\mathbf{I} - \mathbf{D}_\mathrm{i}\mathbf{A}\right)\mathbf{S}_\mathrm{i} \\
 *      \mathbf{R} &=
 *      \left(2\pi\mathbf{A}^{-1} - \mathbf{D}_\mathrm{i}\right)
 *     \end{align}
 *  \f]
 *  The matrix is not symmetrized and is not symmetry packed.
 */
inline Eigen::MatrixXd isotropicIEFMatrix(const Cavity & cav, const IGreensFunction & gf_i, double epsilon)
{
  // The total size of the cavity
  size_t cavitySize = cav.size();
  // The number of irreps in the group
  int nrBlocks = cav.pointGroup().nrIrrep();
  // The size of the irreducible portion of the cavity
  int dimBlock = cav.irreducible_size();

  // Compute SI and DI on the whole cavity, regardless of symmetry
  TIMER_ON("Computing SI");
  Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements());
  TIMER_OFF("Computing SI");
  TIMER_ON("Computing DI");
  Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements());
  TIMER_OFF("Computing DI");

  // Perform symmetry blocking
  // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix
  // into "block diagonal" when all other manipulations are done.
  if (cav.pointGroup().nrGenerators() != 0) {
    TIMER_ON("Symmetry blocking");
    symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks);
    symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks);
    TIMER_OFF("Symmetry blocking");
  }

  Eigen::MatrixXd a = cav.elementArea().asDiagonal();
  Eigen::MatrixXd Id = Eigen::MatrixXd::Identity(cavitySize, cavitySize);

  // Tq = -Rv -> q = -(T^-1 * R)v = -Kv
  // T = (2 * M_PI * fact * aInv - DI) * a * SI; R = (2 * M_PI * aInv - DI)
  // fullPCMMatrix_ = K = T^-1 * R * a
  // 1. Form T
  double fact = (epsilon + 1.0)/(epsilon - 1.0);
  TIMER_ON("Assemble T matrix");
  Eigen::MatrixXd fullPCMMatrix = (2 * M_PI * fact * Id - DI * a) * SI;
  TIMER_OFF("Assemble T matrix");
  // 2. Invert T using LU decomposition with full pivoting
  //    This is a rank-revealing LU decomposition, this allows us
  //    to test if T is invertible before attempting to invert it.
  TIMER_ON("Invert T matrix");
  Eigen::FullPivLU<Eigen::MatrixXd> T_LU(fullPCMMatrix);
  if (!(T_LU.isInvertible()))
    PCMSOLVER_ERROR("T matrix is not invertible!", BOOST_CURRENT_FUNCTION);
  fullPCMMatrix = T_LU.inverse();
  TIMER_OFF("Invert T matrix");
  // 3. Multiply T^-1 and R
  TIMER_ON("Assemble T^-1R matrix");
  fullPCMMatrix *= (2 * M_PI * Id - DI * a);
  TIMER_OFF("Assemble T^-1R matrix");

  return fullPCMMatrix;
}
예제 #9
0
파일: Logger.hpp 프로젝트: loriab/pcmsolver
        /*! Constructor
         *  \param[in] name name for the log file
         *  The build parameters are logged first
         */
        logger(const std::string & name, printLevel print = coarse)
		: globalPrintLevel_(print), policy_(new logPolicy)
        {
            if(!policy_) {
                PCMSOLVER_ERROR("LOGGER: Unable to create the logger instance");
            }
            policy_->open_ostream(name);
            // Write the logfile header
            logStream_ << "\t\tPCMSolver execution log\n"
                << buildInfo() << "\n\t\tLog started : " << getTime() << std::endl;
        }
예제 #10
0
void CPCMSolver::buildSystemMatrix_impl(const Cavity & cavity, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
{
    if (!isotropic_) PCMSOLVER_ERROR("C-PCM is defined only for isotropic environments!");

    // The total size of the cavity
    size_t cavitySize = cavity.size();
    // The number of irreps in the group
    int nrBlocks = cavity.pointGroup().nrIrrep();
    // The size of the irreducible portion of the cavity
    int dimBlock = cavity.irreducible_size();

    // Compute SI on the whole cavity, regardless of symmetry
    Eigen::MatrixXd SI = gf_i.singleLayer(cavity.elements());

    // Perform symmetry blocking only for the SI matrix as the DI matrix is not used.
    // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix
    // into "block diagonal" when all other manipulations are done.
    if (cavity.pointGroup().nrGenerators() != 0) {
        symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks);
    }

    double epsilon = profiles::epsilon(gf_o.permittivity());
    double fact = (epsilon - 1.0)/(epsilon + correction_);
    // Invert SI  using LU decomposition with full pivoting
    // This is a rank-revealing LU decomposition, this allows us
    // to test if SI is invertible before attempting to invert it.
    Eigen::FullPivLU<Eigen::MatrixXd> SI_LU(SI);
    if (!(SI_LU.isInvertible()))
        PCMSOLVER_ERROR("SI matrix is not invertible!");
    fullPCMMatrix_ = fact * SI_LU.inverse();
    // 5. Symmetrize K := (K + K+)/2
    if (hermitivitize_) {
        hermitivitize(fullPCMMatrix_);
    }
    symmetryPacking(blockPCMMatrix_, fullPCMMatrix_, dimBlock, nrBlocks);

    built_ = true;
}
예제 #11
0
void CPCMSolver::buildSystemMatrix_impl(const ICavity & cavity,
                                        const IGreensFunction & gf_i,
                                        const IGreensFunction & gf_o,
                                        const IBoundaryIntegralOperator & op) {
  if (!isotropic_)
    PCMSOLVER_ERROR("C-PCM is defined only for isotropic environments!");
  TIMER_ON("Computing S");
  double epsilon = gf_o.permittivity();
  S_ = op.computeS(cavity, gf_i);
  S_ /= (epsilon - 1.0) / (epsilon + correction_);
  // Get in Hermitian form
  if (hermitivitize_)
    utils::hermitivitize(S_);
  TIMER_OFF("Computing S");

  // Symmetry-pack
  // The number of irreps in the group
  int nrBlocks = cavity.pointGroup().nrIrrep();
  // The size of the irreducible portion of the cavity
  int dimBlock = cavity.irreducible_size();
  utils::symmetryPacking(blockS_, S_, dimBlock, nrBlocks);

  built_ = true;
}
예제 #12
0
void Input::reader(const std::string & filename) {
  Getkw input_ = Getkw(filename, false, true);
  units_ = input_.getStr("UNITS");
  CODATAyear_ = input_.getInt("CODATA");
  initBohrToAngstrom(bohrToAngstrom, CODATAyear_);

  const Section & mol = input_.getSect("MOLECULE");
  MEPfromMolecule_ = true;
  if (mol.isDefined()) {
    geometry_ = mol.getDblVec("GEOMETRY");
    MEPfromMolecule_ = mol.getBool("MEP");
  }

  const Section & cavity = input_.getSect("CAVITY");

  cavityType_ = cavity.getStr("TYPE");
  area_ = cavity.getDbl("AREA");
  if (cavityType_ == "RESTART") {
    cavFilename_ = cavity.getStr("NPZFILE");
  }

  scaling_ = cavity.getBool("SCALING");
  radiiSet_ = detail::uppercase(cavity.getStr("RADIISET"));
  minimalRadius_ = cavity.getDbl("MINRADIUS");
  mode_ = detail::uppercase(cavity.getStr("MODE"));
  if (mode_ == "EXPLICIT") {
    std::vector<double> spheresInput = cavity.getDblVec("SPHERES");
    int j = 0;
    int nAtoms = int(spheresInput.size() / 4);
    for (int i = 0; i < nAtoms; ++i) {
      Eigen::Vector3d center;
      center = (Eigen::Vector3d() << spheresInput[j],
                spheresInput[j + 1],
                spheresInput[j + 2])
                   .finished();
      Sphere sph(center, spheresInput[j + 3]);
      spheres_.push_back(sph);
      j += 4;
    }
    // Initialize molecule from spheres only when molecule section is absent
    if (!mol.isDefined())
      molecule_ = Molecule(spheres_);
  } else if (mode_ == "ATOMS") {
    atoms_ = cavity.getIntVec("ATOMS");
    radii_ = cavity.getDblVec("RADII");
  }

  // Get the contents of the Medium section
  const Section & medium = input_.getSect("MEDIUM");
  // Get the name of the solvent
  std::string name = medium.getStr("SOLVENT");
  if (name == "EXPLICIT") {
    hasSolvent_ = false;
    // Get the probe radius
    probeRadius_ = medium.getDbl("PROBERADIUS");
    // Get the contents of the Green<inside> section...
    const Section & inside = medium.getSect("GREEN<INSIDE>");
    // ...and initialize the data members
    greenInsideType_ = inside.getStr("TYPE") + "_" + inside.getStr("DER");
    epsilonInside_ = inside.getDbl("EPS");
    // Get the contents of the Green<outside> section...
    const Section & outside = medium.getSect("GREEN<OUTSIDE>");
    // ...and initialize the data members
    greenOutsideType_ = outside.getStr("TYPE") + "_" + outside.getStr("DER");
    epsilonStaticOutside_ = outside.getDbl("EPS");
    epsilonDynamicOutside_ = outside.getDbl("EPSDYN");
    epsilonStatic1_ = outside.getDbl("EPS1");
    epsilonDynamic1_ = outside.getDbl("EPSDYN1");
    epsilonStatic2_ = outside.getDbl("EPS2");
    epsilonDynamic2_ = outside.getDbl("EPSDYN2");
    center_ = outside.getDbl("CENTER");
    width_ = outside.getDbl("WIDTH");
    origin_ = outside.getDblVec("INTERFACEORIGIN");
    if (outside.getStr("TYPE") == "SPHERICALDIFFUSE") {
      greenOutsideType_ += "_" + outside.getStr("PROFILE");
    }
    maxL_ = outside.getInt("MAXL");
  } else { // This part must be reviewed!! Some data members are not initialized...
    // Just initialize the solvent object in this class
    hasSolvent_ = true;
    if (solvents().find(name) == solvents().end()) {
      PCMSOLVER_ERROR("Solvent " + name + " NOT found!");
    } else {
      solvent_ = solvents()[name];
    }
    probeRadius_ = solvent_.probeRadius * angstromToBohr();
    // Specification of the solvent by name means isotropic PCM
    // We have to initialize the Green's functions data here, Solvent class
    // is an helper class and should not be used in the core classes.
    greenInsideType_ = "VACUUM_DERIVATIVE";
    epsilonInside_ = 1.0;
    greenOutsideType_ = "UNIFORMDIELECTRIC_DERIVATIVE";
    epsilonStaticOutside_ = solvent_.epsStatic;
    epsilonDynamicOutside_ = solvent_.epsDynamic;
  }
  integratorType_ = medium.getStr("DIAGONALINTEGRATOR");
  integratorScaling_ = medium.getDbl("DIAGONALSCALING");

  solverType_ = medium.getStr("SOLVERTYPE");
  correction_ = medium.getDbl("CORRECTION");
  hermitivitize_ = medium.getBool("MATRIXSYMM");
  isDynamic_ = medium.getBool("NONEQUILIBRIUM");

  const Section & chgdist = input_.getSect("CHARGEDISTRIBUTION");
  if (chgdist.isDefined()) {
    // Set monopoles
    if (chgdist.getKey<std::vector<double> >("MONOPOLES").isDefined()) {
      std::vector<double> mono = chgdist.getDblVec("MONOPOLES");
      int j = 0;
      int n = int(mono.size() / 4);
      multipoles_.monopoles = Eigen::VectorXd::Zero(n);
      multipoles_.monopolesSites = Eigen::Matrix3Xd::Zero(3, n);
      for (int i = 0; i < n; ++i) {
        multipoles_.monopolesSites.col(i) =
            (Eigen::Vector3d() << mono[j], mono[j + 1], mono[j + 2]).finished();
        multipoles_.monopoles(i) = mono[j + 3];
        j += 4;
      }
    }
    // Set dipoles
    if (chgdist.getKey<std::vector<double> >("DIPOLES").isDefined()) {
      std::vector<double> dipo = chgdist.getDblVec("DIPOLES");
      int j = 0;
      int n = int(dipo.size() / 6);
      multipoles_.dipoles = Eigen::Matrix3Xd::Zero(3, n);
      multipoles_.dipolesSites = Eigen::Matrix3Xd::Zero(3, n);
      for (int i = 0; i < n; ++i) {
        multipoles_.dipolesSites.col(i) =
            (Eigen::Vector3d() << dipo[j], dipo[j + 1], dipo[j + 2]).finished();
        multipoles_.dipoles.col(i) =
            (Eigen::Vector3d() << dipo[j + 3], dipo[j + 4], dipo[j + 5]).finished();
        j += 6;
      }
    }
  }

  providedBy_ = std::string("API-side");
}
예제 #13
0
void Input::initMolecule() {
  // Gather information necessary to build molecule_
  // 1. number of atomic centers
  int nuclei = int(geometry_.size() / 4);
  // 2. position and charges of atomic centers
  Eigen::Matrix3Xd centers = Eigen::Matrix3Xd::Zero(3, nuclei);
  Eigen::VectorXd charges = Eigen::VectorXd::Zero(nuclei);
  int j = 0;
  for (int i = 0; i < nuclei; ++i) {
    centers.col(i) =
        (Eigen::Vector3d() << geometry_[j], geometry_[j + 1], geometry_[j + 2])
            .finished();
    charges(i) = geometry_[j + 3];
    j += 4;
  }
  // 3. list of atoms and list of spheres
  std::vector<Atom> radiiSet;
  std::vector<Atom> atoms;
  atoms.reserve(nuclei);
  // FIXME Code duplication in function initMolecule in interface/Meddle.cpp
  tie(radiiSetName_, radiiSet) = utils::bootstrapRadiiSet().create(radiiSet_);
  for (int i = 0; i < charges.size(); ++i) {
    int index = int(charges(i)) - 1;
    atoms.push_back(radiiSet[index]);
    if (scaling_)
      atoms[i].radiusScaling = 1.2;
  }
  // Based on the creation mode (Implicit or Atoms)
  // the spheres list might need postprocessing
  if (mode_ == "IMPLICIT" || mode_ == "ATOMS") {
    for (int i = 0; i < charges.size(); ++i) {
      // Convert to Bohr and multiply by scaling factor (alpha)
      double radius = atoms[i].radius * angstromToBohr() * atoms[i].radiusScaling;
      spheres_.push_back(Sphere(centers.col(i), radius));
    }
    if (mode_ == "ATOMS") {
      // Loop over the atomsInput array to get which atoms will have a user-given
      // radius
      for (size_t i = 0; i < atoms_.size(); ++i) {
        int index =
            atoms_[i] - 1; // -1 to go from human readable to machine readable
        // Put the new Sphere in place of the implicit-generated one
        spheres_[index] = Sphere(centers.col(index), radii_[i]);
      }
    }
  }

  // 4. masses
  Eigen::VectorXd masses = Eigen::VectorXd::Zero(nuclei);
  for (int i = 0; i < masses.size(); ++i) {
    masses(i) = atoms[i].mass;
  }
  // 5. molecular point group
  // FIXME currently hardcoded to C1

  // OK, now get molecule_
  molecule_ = Molecule(nuclei, charges, masses, centers, atoms, spheres_);
  // Check that all atoms have a radius attached
  std::vector<Atom>::const_iterator res =
      std::find_if(atoms.begin(), atoms.end(), invalid);
  if (res != atoms.end()) {
    std::cout << molecule_ << std::endl;
    PCMSOLVER_ERROR("Some atoms do not have a radius attached. Please specify a "
                    "radius for all atoms (see "
                    "http://pcmsolver.readthedocs.org/en/latest/users/input.html)!");
  }
}
예제 #14
0
 Eigen::MatrixXd doubleLayer(const AnisotropicLiquid<DerivativeTraits, PurisimaIntegrator> & /* gf */, const std::vector<Element> & e) const {
   PCMSOLVER_ERROR("PurisimaIntegrator::doubleLayer not implemented yet for AnisotropicLiquid", BOOST_CURRENT_FUNCTION);
   return Eigen::MatrixXd::Zero(e.size(), e.size());
 }
예제 #15
0
 /*! \brief Subscribes object with objID to factory
  * \param[in] objID  the object's identification string
  * \param[in] functor the creation function related to the object type given
  */
 void subscribe(const std::string & objID, const CreateObject & functor) {
   bool done = this->registerObject(objID, functor);
   if (!done)
     PCMSOLVER_ERROR("Subscription of object ID " + objID + " to factory failed!");
 }
예제 #16
0
 /*! \brief Unsubscribes object with objID from factory
  *  \param objID the object's identification string
  */
 void unsubscribe(const std::string & objID) {
   bool done = this->unRegisterObject(objID);
   if (!done)
     PCMSOLVER_ERROR("Unsubscription of object ID " + objID +
                     " from factory failed!");
 }