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; }
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; }
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; }
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; }