void operator()(GNode item, Galois::UserContext<GNode>& ctx) {
    if (!graph->containsNode(item, Galois::ALL))
      return;
    
    Cavity* cavp = NULL;

    if (Version == detDisjoint) {
      bool used;
      LocalState* localState = (LocalState*) ctx.getLocalState(used);
      if (used) {
        localState->cav.update(item, ctx);
        return;
      } else {
        cavp = &localState->cav;
      }
    }

    if (Version == detDisjoint) {
      cavp->initialize(item);
      cavp->build();
      cavp->computePost();
    } else {
      Cavity cav(graph, ctx.getPerIterAlloc());
      cav.initialize(item);
      cav.build();
      cav.computePost();
      if (Version == detPrefix)
        return;
      cav.update(item, ctx);
    }
  }
Exemple #2
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();
}
Exemple #3
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;
}
Exemple #4
0
void IEFSolver::buildIsotropicMatrix(const Cavity & cav, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
{
  fullPCMMatrix_ = isotropicIEFMatrix(cav, gf_i, profiles::epsilon(gf_o.permittivity()));
  // Symmetrize K := (K + K+)/2
  if (hermitivitize_) {
    hermitivitize(fullPCMMatrix_);
  }
  // Pack into a block diagonal matrix
  // 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();
  // For the moment just packs into a std::vector<Eigen::MatrixXd>
  symmetryPacking(blockPCMMatrix_, fullPCMMatrix_, dimBlock, nrBlocks);

  built_ = true;
}
Exemple #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));
}
Exemple #6
0
/*! \brief Builds the **anisotropic** \f$ \mathbf{T}_\varepsilon \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{T}_\varepsilon \f$ matrix
 *
 *  We use the following definition:
 *  \f[
 *      \mathbf{T}_\varepsilon =
 *      \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)
 *  \f]
 *  The matrix is not symmetrized and is not symmetry packed.
 */
inline Eigen::MatrixXd anisotropicTEpsilon(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
  return ((2 * M_PI * Id - DE * a) * SI + SE * (2 * M_PI * Id + a * DI.adjoint().eval()));
}
Exemple #7
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;
}
Exemple #8
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;
}
Exemple #9
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;
}
Exemple #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;
}