37 const QMState& state, std::string gridsize) {
44 <<
" Done setting up CHELPG grid with "
45 << grid.
size() <<
" points " << flush;
51 double N_comp = dmat.cwiseProduct(overlap.
Matrix()).sum();
56 <<
" Numerical Grid with "
63 <<
" Calculated Densities at Numerical Grid, Number of electrons is " << N
66 if (std::abs(N - N_comp) > 0.001) {
69 <<
"WARNING: Calculated Densities at Numerical Grid, Number of "
71 << N <<
" is far away from the the real value " << N_comp
72 <<
", you should increase the accuracy of the integration grid."
76 <<
"WARNING: Electronnumber set to " << N << flush;
81 <<
TimeStamp() <<
" Calculating ESP at CHELPG grid points" << flush;
82#pragma omp parallel for
90 double netcharge = -N;
95 Znuc += atom.getNuccharge();
97 netcharge += double(Znuc);
99 netcharge = std::round(netcharge);
101 <<
TimeStamp() <<
" Netcharge constrained to " << netcharge << flush;
111 <<
" Calculating ESP of nuclei at CHELPG grid points"
114 for (
Index i = 0; i <
Index(gridpoints.size()); i++) {
115 for (
Index j = 0; j < atoms.
size(); j++) {
116 const Eigen::Vector3d& posatom = atoms[j].
getPos();
117 Index Znuc = atoms[j].getNuccharge();
118 double dist_j = (gridpoints[i] - posatom).norm();
119 gridvalues(i) += double(Znuc) / dist_j;
126 const Grid& grid,
double netcharge) {
128 const Index NoOfConstraints =
130 const Index matrixSize = atomlist.
size() + NoOfConstraints;
132 <<
" Setting up Matrices for fitting of size "
133 << matrixSize <<
" x " << matrixSize << flush;
138 <<
" Fittingcenters and " << gridpoints.size()
139 <<
" Gridpoints." << flush;
141 Eigen::MatrixXd Amat = Eigen::MatrixXd::Zero(matrixSize, matrixSize);
142 Eigen::VectorXd Bvec = Eigen::VectorXd::Zero(matrixSize);
144#pragma omp parallel for
145 for (
Index i = 0; i < atomlist.
size(); i++) {
146 for (
Index j = i; j < atomlist.
size(); j++) {
147 for (
const auto& gridpoint : gridpoints) {
148 double dist_i = (atomlist[i].
getPos() - gridpoint).norm();
149 double dist_j = (atomlist[j].
getPos() - gridpoint).norm();
151 Amat(i, j) += 1.0 / dist_i / dist_j;
153 Amat(j, i) = Amat(i, j);
158#pragma omp parallel for
159 for (
Index i = 0; i < atomlist.
size(); i++) {
160 for (
Index j = 0; j <
Index(gridpoints.size()); j++) {
161 double dist_i = (atomlist[i].
getPos() - gridpoints[j]).norm();
162 Bvec(i) += potential(j) / dist_i;
166 for (
Index i = 0; i < atomlist.
size() + 1; i++) {
167 Amat(i, atomlist.
size()) = 1.0;
168 Amat(atomlist.
size(), i) = 1.0;
170 Amat(atomlist.
size(), atomlist.
size()) = 0.0;
171 Bvec(atomlist.
size()) = netcharge;
176 Amat(pair.first, atomlist.
size() + 1 + i) = 1.0;
177 Amat(atomlist.
size() + 1 + i, pair.first) = 1.0;
178 Amat(pair.second, atomlist.
size() + 1 + i) = -1.0;
179 Amat(atomlist.
size() + 1 + i, pair.second) = -1.0;
185 for (
Index index : reg) {
194 Eigen::VectorXd charges;
196#if EIGEN_VERSION_AT_LEAST(3, 5, 0)
197 Eigen::JacobiSVD<Eigen::MatrixXd, Eigen::ComputeThinU | Eigen::ComputeThinV>
202 Eigen::JacobiSVD<Eigen::MatrixXd> svd;
204 svd.compute(Amat, Eigen::ComputeThinU | Eigen::ComputeThinV);
206 charges = svd.solve(Bvec);
208 if ((Bvec.size() - svd.nonzeroSingularValues()) != 0) {
210 <<
TimeStamp() << Bvec.size() - svd.nonzeroSingularValues()
211 <<
" Sites could not be fitted and are set to zero." << flush;
214 Eigen::ColPivHouseholderQR<Eigen::MatrixXd> QR(Amat);
215 if (QR.info() != Eigen::ComputationInfo::Success) {
216 throw std::runtime_error(
217 "Espfit: Solving the constrained equation failed. Maybe try SVD.");
219 charges = QR.solve(Bvec);
221 <<
TimeStamp() <<
" Solved linear least square fit ." << flush;
224 charges.conservativeResize(atomlist.
size());
229 <<
" Sum of fitted charges: " << charges.sum() << flush;
230 for (
Index i = 0; i < atomlist.
size(); i++) {
235 double totalPotSq = 0.0;
236 for (
Index k = 0; k <
Index(gridpoints.size()); k++) {
239 double dist = (gridpoints[k] - atom.getPos()).norm();
240 temp += atom.getCharge() / dist;
242 rmse += (potential(k) - temp) * (potential(k) - temp);
243 totalPotSq += potential(k) * potential(k);
246 <<
" RMSE of fit: " << std::sqrt(rmse /
double(gridpoints.size()))
249 <<
" RRMSE of fit: " << std::sqrt(rmse / totalPotSq) << flush;