/*! \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; }
/*! \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; }
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; }
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); } }
/*! \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)); }
/*! \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(); }
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; }
/*! \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; }
/*! 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; }
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; }
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"); }
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)!"); } }
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()); }
/*! \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!"); }
/*! \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!"); }