36 const QMState& state, std::string gridsize) {
43 <<
" Done setting up CHELPG grid with "
44 << grid.
size() <<
" points " << flush;
50 double N_comp = dmat.cwiseProduct(overlap.
Matrix()).sum();
55 <<
" Numerical Grid with "
62 <<
" Calculated Densities at Numerical Grid, Number of electrons is " << N
65 if (std::abs(N - N_comp) > 0.001) {
68 <<
"WARNING: Calculated Densities at Numerical Grid, Number of "
70 << N <<
" is far away from the the real value " << N_comp
71 <<
", you should increase the accuracy of the integration grid."
75 <<
"WARNING: Electronnumber set to " << N << flush;
80 <<
TimeStamp() <<
" Calculating ESP at CHELPG grid points" << flush;
81#pragma omp parallel for
89 double netcharge = -N;
94 Znuc += atom.getNuccharge();
96 netcharge += double(Znuc);
98 netcharge = std::round(netcharge);
100 <<
TimeStamp() <<
" Netcharge constrained to " << netcharge << flush;
110 <<
" Calculating ESP of nuclei at CHELPG grid points"
113 for (
Index i = 0; i <
Index(gridpoints.size()); i++) {
114 for (
Index j = 0; j < atoms.
size(); j++) {
115 const Eigen::Vector3d& posatom = atoms[j].
getPos();
116 Index Znuc = atoms[j].getNuccharge();
117 double dist_j = (gridpoints[i] - posatom).norm();
118 gridvalues(i) += double(Znuc) / dist_j;
125 const Grid& grid,
double netcharge) {
127 const Index NoOfConstraints =
129 const Index matrixSize = atomlist.
size() + NoOfConstraints;
131 <<
" Setting up Matrices for fitting of size "
132 << matrixSize <<
" x " << matrixSize << flush;
137 <<
" Fittingcenters and " << gridpoints.size()
138 <<
" Gridpoints." << flush;
140 Eigen::MatrixXd Amat = Eigen::MatrixXd::Zero(matrixSize, matrixSize);
141 Eigen::VectorXd Bvec = Eigen::VectorXd::Zero(matrixSize);
143#pragma omp parallel for
144 for (
Index i = 0; i < atomlist.
size(); i++) {
145 for (
Index j = i; j < atomlist.
size(); j++) {
146 for (
const auto& gridpoint : gridpoints) {
147 double dist_i = (atomlist[i].
getPos() - gridpoint).norm();
148 double dist_j = (atomlist[j].
getPos() - gridpoint).norm();
150 Amat(i, j) += 1.0 / dist_i / dist_j;
152 Amat(j, i) = Amat(i, j);
157#pragma omp parallel for
158 for (
Index i = 0; i < atomlist.
size(); i++) {
159 for (
Index j = 0; j <
Index(gridpoints.size()); j++) {
160 double dist_i = (atomlist[i].
getPos() - gridpoints[j]).norm();
161 Bvec(i) += potential(j) / dist_i;
165 for (
Index i = 0; i < atomlist.
size() + 1; i++) {
166 Amat(i, atomlist.
size()) = 1.0;
167 Amat(atomlist.
size(), i) = 1.0;
169 Amat(atomlist.
size(), atomlist.
size()) = 0.0;
170 Bvec(atomlist.
size()) = netcharge;
175 Amat(pair.first, atomlist.
size() + 1 + i) = 1.0;
176 Amat(atomlist.
size() + 1 + i, pair.first) = 1.0;
177 Amat(pair.second, atomlist.
size() + 1 + i) = -1.0;
178 Amat(atomlist.
size() + 1 + i, pair.second) = -1.0;
184 for (
Index index : reg) {
193 Eigen::VectorXd charges;
195 Eigen::JacobiSVD<Eigen::MatrixXd> svd;
197 svd.compute(Amat, Eigen::ComputeThinU | Eigen::ComputeThinV);
198 charges = svd.solve(Bvec);
200 if ((Bvec.size() - svd.nonzeroSingularValues()) != 0) {
202 <<
TimeStamp() << Bvec.size() - svd.nonzeroSingularValues()
203 <<
" Sites could not be fitted and are set to zero." << flush;
206 Eigen::ColPivHouseholderQR<Eigen::MatrixXd> QR(Amat);
207 if (QR.info() != Eigen::ComputationInfo::Success) {
208 throw std::runtime_error(
209 "Espfit: Solving the constrained equation failed. Maybe try SVD.");
211 charges = QR.solve(Bvec);
213 <<
TimeStamp() <<
" Solved linear least square fit ." << flush;
216 charges.conservativeResize(atomlist.
size());
221 <<
" Sum of fitted charges: " << charges.sum() << flush;
222 for (
Index i = 0; i < atomlist.
size(); i++) {
227 double totalPotSq = 0.0;
228 for (
Index k = 0; k <
Index(gridpoints.size()); k++) {
231 double dist = (gridpoints[k] - atom.getPos()).norm();
232 temp += atom.getCharge() / dist;
234 rmse += (potential(k) - temp) * (potential(k) - temp);
235 totalPotSq += potential(k) * potential(k);
238 <<
" RMSE of fit: " << std::sqrt(rmse /
double(gridpoints.size()))
241 <<
" RRMSE of fit: " << std::sqrt(rmse / totalPotSq) << flush;