Skip to content

Commit c14a8d4

Browse files
author
Roberto Di Remigio
committed
Refactor creation of PCM matrices in the various solvers
1 parent c88b8b0 commit c14a8d4

File tree

4 files changed

+430
-152
lines changed

4 files changed

+430
-152
lines changed

src/solver/CPCMSolver.cpp

Lines changed: 31 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -38,69 +38,48 @@
3838
#include "Element.hpp"
3939
#include "IGreensFunction.hpp"
4040
#include "MathUtils.hpp"
41+
#include "SolverImpl.hpp"
4142

4243
void CPCMSolver::buildSystemMatrix_impl(const Cavity & cavity, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
4344
{
44-
if (!isotropic_) PCMSOLVER_ERROR("C-PCM is defined only for isotropic environments!");
45+
if (!isotropic_) PCMSOLVER_ERROR("C-PCM is defined only for isotropic environments!");
46+
fullPCMMatrix_ = CPCMMatrix(cavity, gf_i, profiles::epsilon(gf_o.permittivity()), correction_);
47+
// Symmetrize K := (K + K+)/2
48+
if (hermitivitize_) {
49+
hermitivitize(fullPCMMatrix_);
50+
}
51+
// Symmetry-pack
52+
// The number of irreps in the group
53+
int nrBlocks = cavity.pointGroup().nrIrrep();
54+
// The size of the irreducible portion of the cavity
55+
int dimBlock = cavity.irreducible_size();
56+
symmetryPacking(blockPCMMatrix_, fullPCMMatrix_, dimBlock, nrBlocks);
4557

46-
// The total size of the cavity
47-
size_t cavitySize = cavity.size();
48-
// The number of irreps in the group
49-
int nrBlocks = cavity.pointGroup().nrIrrep();
50-
// The size of the irreducible portion of the cavity
51-
int dimBlock = cavity.irreducible_size();
52-
53-
// Compute SI on the whole cavity, regardless of symmetry
54-
Eigen::MatrixXd SI = gf_i.singleLayer(cavity.elements());
55-
56-
// Perform symmetry blocking only for the SI matrix as the DI matrix is not used.
57-
// If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix
58-
// into "block diagonal" when all other manipulations are done.
59-
if (cavity.pointGroup().nrGenerators() != 0) {
60-
symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks);
61-
}
62-
63-
double epsilon = profiles::epsilon(gf_o.permittivity());
64-
double fact = (epsilon - 1.0)/(epsilon + correction_);
65-
// Invert SI using LU decomposition with full pivoting
66-
// This is a rank-revealing LU decomposition, this allows us
67-
// to test if SI is invertible before attempting to invert it.
68-
Eigen::FullPivLU<Eigen::MatrixXd> SI_LU(SI);
69-
if (!(SI_LU.isInvertible()))
70-
PCMSOLVER_ERROR("SI matrix is not invertible!");
71-
fullPCMMatrix_ = fact * SI_LU.inverse();
72-
// 5. Symmetrize K := (K + K+)/2
73-
if (hermitivitize_) {
74-
hermitivitize(fullPCMMatrix_);
75-
}
76-
symmetryPacking(blockPCMMatrix_, fullPCMMatrix_, dimBlock, nrBlocks);
77-
78-
built_ = true;
58+
built_ = true;
7959
}
8060

8161
Eigen::VectorXd CPCMSolver::computeCharge_impl(const Eigen::VectorXd & potential, int irrep) const
8262
{
83-
// The potential and charge vector are of dimension equal to the
84-
// full dimension of the cavity. We have to select just the part
85-
// relative to the irrep needed.
86-
int fullDim = fullPCMMatrix_.rows();
87-
Eigen::VectorXd charge = Eigen::VectorXd::Zero(fullDim);
88-
int nrBlocks = blockPCMMatrix_.size();
89-
int irrDim = fullDim/nrBlocks;
90-
charge.segment(irrep*irrDim, irrDim) =
91-
- blockPCMMatrix_[irrep] * potential.segment(irrep*irrDim, irrDim);
92-
return charge;
63+
// The potential and charge vector are of dimension equal to the
64+
// full dimension of the cavity. We have to select just the part
65+
// relative to the irrep needed.
66+
int fullDim = fullPCMMatrix_.rows();
67+
Eigen::VectorXd charge = Eigen::VectorXd::Zero(fullDim);
68+
int nrBlocks = blockPCMMatrix_.size();
69+
int irrDim = fullDim/nrBlocks;
70+
charge.segment(irrep*irrDim, irrDim) =
71+
- blockPCMMatrix_[irrep] * potential.segment(irrep*irrDim, irrDim);
72+
return charge;
9373
}
9474

9575
std::ostream & CPCMSolver::printSolver(std::ostream & os)
9676
{
97-
os << "Solver Type: C-PCM" << std::endl;
98-
if (hermitivitize_) {
99-
os << "PCM matrix hermitivitized";
100-
} else {
101-
os << "PCM matrix NOT hermitivitized (matches old DALTON)";
102-
}
77+
os << "Solver Type: C-PCM" << std::endl;
78+
if (hermitivitize_) {
79+
os << "PCM matrix hermitivitized";
80+
} else {
81+
os << "PCM matrix NOT hermitivitized (matches old DALTON)";
82+
}
10383

104-
return os;
84+
return os;
10585
}
106-

src/solver/IEFSolver.cpp

Lines changed: 13 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "Element.hpp"
4141
#include "IGreensFunction.hpp"
4242
#include "MathUtils.hpp"
43+
#include "SolverImpl.hpp"
4344

4445
void IEFSolver::buildSystemMatrix_impl(const Cavity & cavity, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
4546
{
@@ -49,119 +50,36 @@ void IEFSolver::buildSystemMatrix_impl(const Cavity & cavity, const IGreensFunct
4950

5051
void IEFSolver::buildAnisotropicMatrix(const Cavity & cav, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
5152
{
52-
// The total size of the cavity
53-
size_t cavitySize = cav.size();
54-
// The number of irreps in the group
55-
int nrBlocks = cav.pointGroup().nrIrrep();
56-
// The size of the irreducible portion of the cavity
57-
int dimBlock = cav.irreducible_size();
58-
59-
// Compute SI, DI and SE, DE on the whole cavity, regardless of symmetry
60-
Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements());
61-
Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements());
62-
Eigen::MatrixXd SE = gf_o.singleLayer(cav.elements());
63-
Eigen::MatrixXd DE = gf_o.doubleLayer(cav.elements());
64-
65-
// Perform symmetry blocking
66-
// If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix
67-
// into "block diagonal" when all other manipulations are done.
68-
if (cav.pointGroup().nrGenerators() != 0) {
69-
symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks);
70-
symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks);
71-
symmetryBlocking(DE, cavitySize, dimBlock, nrBlocks);
72-
symmetryBlocking(SE, cavitySize, dimBlock, nrBlocks);
73-
}
74-
75-
Eigen::MatrixXd a = cav.elementArea().asDiagonal();
76-
Eigen::MatrixXd aInv = a.inverse();
77-
78-
// 1. Form T
79-
fullPCMMatrix_ = ((2 * M_PI * aInv - DE) * a * SI + SE * a * (2 * M_PI * aInv + DI.adjoint().eval()));
80-
// 2. Invert T using LU decomposition with full pivoting
81-
// This is a rank-revealing LU decomposition, this allows us
82-
// to test if T is invertible before attempting to invert it.
83-
Eigen::FullPivLU<Eigen::MatrixXd> T_LU(fullPCMMatrix_);
84-
if (!(T_LU.isInvertible())) PCMSOLVER_ERROR("T matrix is not invertible!");
85-
fullPCMMatrix_ = T_LU.inverse();
86-
Eigen::FullPivLU<Eigen::MatrixXd> SI_LU(SI);
87-
if (!(SI_LU.isInvertible())) PCMSOLVER_ERROR("SI matrix is not invertible!");
88-
fullPCMMatrix_ *= ((2 * M_PI * aInv - DE) - SE * SI_LU.inverse() * (2 * M_PI * aInv - DI));
89-
fullPCMMatrix_ *= a;
90-
// 5. Symmetrize K := (K + K+)/2
53+
fullPCMMatrix_ = anisotropicIEFMatrix(cav, gf_i, gf_o);
54+
// Symmetrize K := (K + K+)/2
9155
if (hermitivitize_) {
9256
hermitivitize(fullPCMMatrix_);
9357
}
9458
// Pack into a block diagonal matrix
59+
// The number of irreps in the group
60+
int nrBlocks = cav.pointGroup().nrIrrep();
61+
// The size of the irreducible portion of the cavity
62+
int dimBlock = cav.irreducible_size();
9563
// For the moment just packs into a std::vector<Eigen::MatrixXd>
9664
symmetryPacking(blockPCMMatrix_, fullPCMMatrix_, dimBlock, nrBlocks);
97-
std::ofstream matrixOut("PCM_matrix");
98-
matrixOut << "fullPCMMatrix" << std::endl;
99-
matrixOut << fullPCMMatrix_ << std::endl;
100-
for (int i = 0; i < nrBlocks; ++i) {
101-
matrixOut << "Block number " << i << std::endl;
102-
matrixOut << blockPCMMatrix_[i] << std::endl;
103-
}
10465

10566
built_ = true;
10667
}
10768

10869
void IEFSolver::buildIsotropicMatrix(const Cavity & cav, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
10970
{
110-
// The total size of the cavity
111-
size_t cavitySize = cav.size();
112-
// The number of irreps in the group
113-
int nrBlocks = cav.pointGroup().nrIrrep();
114-
// The size of the irreducible portion of the cavity
115-
int dimBlock = cav.irreducible_size();
116-
117-
// Compute SI and DI on the whole cavity, regardless of symmetry
118-
Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements());
119-
Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements());
120-
121-
// Perform symmetry blocking
122-
// If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix
123-
// into "block diagonal" when all other manipulations are done.
124-
if (cav.pointGroup().nrGenerators() != 0) {
125-
symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks);
126-
symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks);
127-
}
128-
129-
Eigen::MatrixXd a = cav.elementArea().asDiagonal();
130-
Eigen::MatrixXd aInv = Eigen::MatrixXd::Zero(cavitySize, cavitySize);
131-
aInv = a.inverse();
132-
133-
// Tq = -Rv -> q = -(T^-1 * R)v = -Kv
134-
// T = (2 * M_PI * fact * aInv - DI) * a * SI; R = (2 * M_PI * aInv - DI)
135-
// fullPCMMatrix_ = K = T^-1 * R * a
136-
// 1. Form T
137-
double epsilon = profiles::epsilon(gf_o.permittivity());
138-
double fact = (epsilon + 1.0)/(epsilon - 1.0);
139-
fullPCMMatrix_ = (2 * M_PI * fact * aInv - DI) * a * SI;
140-
// 2. Invert T using LU decomposition with full pivoting
141-
// This is a rank-revealing LU decomposition, this allows us
142-
// to test if T is invertible before attempting to invert it.
143-
Eigen::FullPivLU<Eigen::MatrixXd> T_LU(fullPCMMatrix_);
144-
if (!(T_LU.isInvertible()))
145-
PCMSOLVER_ERROR("T matrix is not invertible!");
146-
fullPCMMatrix_ = T_LU.inverse();
147-
// 3. Multiply T^-1 and R
148-
fullPCMMatrix_ *= (2 * M_PI * aInv - DI);
149-
// 4. Multiply by a
150-
fullPCMMatrix_ *= a;
151-
// 5. Symmetrize K := (K + K+)/2
71+
fullPCMMatrix_ = isotropicIEFMatrix(cav, gf_i, profiles::epsilon(gf_o.permittivity()));
72+
// Symmetrize K := (K + K+)/2
15273
if (hermitivitize_) {
15374
hermitivitize(fullPCMMatrix_);
15475
}
15576
// Pack into a block diagonal matrix
77+
// The number of irreps in the group
78+
int nrBlocks = cav.pointGroup().nrIrrep();
79+
// The size of the irreducible portion of the cavity
80+
int dimBlock = cav.irreducible_size();
15681
// For the moment just packs into a std::vector<Eigen::MatrixXd>
15782
symmetryPacking(blockPCMMatrix_, fullPCMMatrix_, dimBlock, nrBlocks);
158-
std::ofstream matrixOut("PCM_matrix");
159-
matrixOut << "fullPCMMatrix" << std::endl;
160-
matrixOut << fullPCMMatrix_ << std::endl;
161-
for (int i = 0; i < nrBlocks; ++i) {
162-
matrixOut << "Block number " << i << std::endl;
163-
matrixOut << blockPCMMatrix_[i] << std::endl;
164-
}
16583

16684
built_ = true;
16785
}

src/solver/PCMSolver.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22
/*
33
* PCMSolver, an API for the Polarizable Continuum Model
44
* Copyright (C) 2013-2015 Roberto Di Remigio, Luca Frediani and contributors
5-
*
5+
*
66
* This file is part of PCMSolver.
7-
*
7+
*
88
* PCMSolver is free software: you can redistribute it and/or modify
99
* it under the terms of the GNU Lesser General Public License as published by
1010
* the Free Software Foundation, either version 3 of the License, or
1111
* (at your option) any later version.
12-
*
12+
*
1313
* PCMSolver is distributed in the hope that it will be useful,
1414
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1515
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1616
* GNU Lesser General Public License for more details.
17-
*
17+
*
1818
* You should have received a copy of the GNU Lesser General Public License
1919
* along with PCMSolver. If not, see <http://www.gnu.org/licenses/>.
20-
*
20+
*
2121
* For information on the complete list of contributors to the
2222
* PCMSolver API, see: <http://pcmsolver.readthedocs.org/>
2323
*/

0 commit comments

Comments
 (0)