votca 2026-dev
Loading...
Searching...
No Matches
espfit.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2020 The VOTCA Development Team
3 * (http://www.votca.org)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License")
6 *
7 * You may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20// VOTCA includes
22
23// Local VOTCA includes
24#include "votca/xtp/aomatrix.h"
25#include "votca/xtp/citations.h"
27#include "votca/xtp/espfit.h"
28#include "votca/xtp/grid.h"
29#include "votca/xtp/orbitals.h"
30#include "votca/xtp/vxc_grid.h"
31
32namespace votca {
33namespace xtp {
34using std::flush;
35
37 const QMState& state, std::string gridsize) {
38 citations::Cite("Breneman:1990");
39 const Eigen::MatrixXd dmat = orbitals.DensityMatrixFull(state);
40 // setting up grid
41 Grid grid;
42 grid.setupCHELPGGrid(orbitals.QMAtoms());
44 << " Done setting up CHELPG grid with "
45 << grid.size() << " points " << flush;
46
47 // Calculating nuclear potential at gridpoints
48 AOBasis basis = orbitals.getDftBasis();
49 AOOverlap overlap;
50 overlap.Fill(basis);
51 double N_comp = dmat.cwiseProduct(overlap.Matrix()).sum();
52
53 Vxc_Grid numintgrid;
54 numintgrid.GridSetup(gridsize, orbitals.QMAtoms(), basis);
55 XTP_LOG(Log::info, log_) << TimeStamp() << " Setup " << gridsize
56 << " Numerical Grid with "
57 << numintgrid.getGridSize() << " gridpoints."
58 << flush;
59 DensityIntegration<Vxc_Grid> numway(numintgrid);
60 double N = numway.IntegrateDensity(dmat);
62 << TimeStamp()
63 << " Calculated Densities at Numerical Grid, Number of electrons is " << N
64 << flush;
65
66 if (std::abs(N - N_comp) > 0.001) {
67 XTP_LOG(Log::error, log_) << "=======================" << flush;
69 << "WARNING: Calculated Densities at Numerical Grid, Number of "
70 "electrons "
71 << N << " is far away from the the real value " << N_comp
72 << ", you should increase the accuracy of the integration grid."
73 << flush;
74 N = N_comp;
76 << "WARNING: Electronnumber set to " << N << flush;
77 XTP_LOG(Log::error, log_) << "=======================" << flush;
78 }
79
81 << TimeStamp() << " Calculating ESP at CHELPG grid points" << flush;
82#pragma omp parallel for
83 for (Index i = 0; i < grid.size(); i++) {
84 grid.getGridValues()(i) =
85 numway.IntegratePotential(grid.getGridPositions()[i]);
86 }
87
88 XTP_LOG(Log::info, log_) << TimeStamp() << " Electron contribution calculated"
89 << flush;
90 double netcharge = -N;
91 if (!state.isTransition()) {
92 EvalNuclearPotential(orbitals.QMAtoms(), grid);
93 Index Znuc = 0;
94 for (const QMAtom& atom : orbitals.QMAtoms()) {
95 Znuc += atom.getNuccharge();
96 }
97 netcharge += double(Znuc);
98 }
99 netcharge = std::round(netcharge);
101 << TimeStamp() << " Netcharge constrained to " << netcharge << flush;
102 return FitPartialCharges(orbitals, grid, netcharge);
103 ;
104}
105
107
108 const std::vector<Eigen::Vector3d>& gridpoints = grid.getGridPositions();
109 Eigen::VectorXd& gridvalues = grid.getGridValues();
111 << " Calculating ESP of nuclei at CHELPG grid points"
112 << flush;
113
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;
120 }
121 }
122 return;
123}
124
126 const Grid& grid, double netcharge) {
127 const QMMolecule& atomlist = orbitals.QMAtoms();
128 const Index NoOfConstraints =
129 1 + Index(regionconstraint_.size()) + Index(pairconstraint_.size());
130 const Index matrixSize = atomlist.size() + NoOfConstraints;
132 << " Setting up Matrices for fitting of size "
133 << matrixSize << " x " << matrixSize << flush;
134
135 const std::vector<Eigen::Vector3d>& gridpoints = grid.getGridPositions();
136 const Eigen::VectorXd& potential = grid.getGridValues();
137 XTP_LOG(Log::info, log_) << TimeStamp() << " Using " << atomlist.size()
138 << " Fittingcenters and " << gridpoints.size()
139 << " Gridpoints." << flush;
140
141 Eigen::MatrixXd Amat = Eigen::MatrixXd::Zero(matrixSize, matrixSize);
142 Eigen::VectorXd Bvec = Eigen::VectorXd::Zero(matrixSize);
143// setting up Amat_
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();
150
151 Amat(i, j) += 1.0 / dist_i / dist_j;
152 }
153 Amat(j, i) = Amat(i, j);
154 }
155 }
156
157 // setting up Bvec
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;
163 }
164 }
165 // Total charge constraint
166 for (Index i = 0; i < atomlist.size() + 1; i++) {
167 Amat(i, atomlist.size()) = 1.0;
168 Amat(atomlist.size(), i) = 1.0;
169 }
170 Amat(atomlist.size(), atomlist.size()) = 0.0;
171 Bvec(atomlist.size()) = netcharge; // netcharge!!!!
172
173 // Pairconstraint
174 for (Index i = 0; i < Index(pairconstraint_.size()); i++) {
175 const std::pair<Index, Index>& pair = pairconstraint_[i];
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;
180 }
181
182 // Regionconstraint
183 for (Index i = 0; i < Index(regionconstraint_.size()); i++) {
185 for (Index index : reg) {
186 Amat(index, atomlist.size() + i + 1 + pairconstraint_.size()) = 1.0;
187 Amat(atomlist.size() + i + 1 + pairconstraint_.size(), index) = 1.0;
188 }
189 Bvec(atomlist.size() + i + 1 + pairconstraint_.size()) = reg.value();
190 }
191
192 XTP_LOG(Log::info, log_) << TimeStamp() << " Solving linear Equation "
193 << flush;
194 Eigen::VectorXd charges;
195 if (do_svd_) {
196#if EIGEN_VERSION_AT_LEAST(3, 5, 0)
197 Eigen::JacobiSVD<Eigen::MatrixXd, Eigen::ComputeThinU | Eigen::ComputeThinV>
198 svd;
199 svd.setThreshold(conditionnumber_);
200 svd.compute(Amat);
201#else
202 Eigen::JacobiSVD<Eigen::MatrixXd> svd;
203 svd.setThreshold(conditionnumber_);
204 svd.compute(Amat, Eigen::ComputeThinU | Eigen::ComputeThinV);
205#endif
206 charges = svd.solve(Bvec);
207 XTP_LOG(Log::info, log_) << TimeStamp() << " SVD Done. " << flush;
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;
212 }
213 } else {
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.");
218 }
219 charges = QR.solve(Bvec);
221 << TimeStamp() << " Solved linear least square fit ." << flush;
222 }
223 // remove constraints from charges
224 charges.conservativeResize(atomlist.size());
225 StaticSegment seg =
226 StaticSegment(orbitals.QMAtoms().getType(), orbitals.QMAtoms().getId());
227
229 << " Sum of fitted charges: " << charges.sum() << flush;
230 for (Index i = 0; i < atomlist.size(); i++) {
231 seg.push_back(StaticSite(atomlist[i], charges(i)));
232 }
233 // get RMSE
234 double rmse = 0.0;
235 double totalPotSq = 0.0;
236 for (Index k = 0; k < Index(gridpoints.size()); k++) {
237 double temp = 0.0;
238 for (const StaticSite& atom : seg) {
239 double dist = (gridpoints[k] - atom.getPos()).norm();
240 temp += atom.getCharge() / dist;
241 }
242 rmse += (potential(k) - temp) * (potential(k) - temp);
243 totalPotSq += potential(k) * potential(k);
244 }
246 << " RMSE of fit: " << std::sqrt(rmse / double(gridpoints.size()))
247 << flush;
249 << " RRMSE of fit: " << std::sqrt(rmse / totalPotSq) << flush;
250
251 return seg;
252}
253
254} // namespace xtp
255} // namespace votca
Container to hold Basisfunctions for all atoms.
Definition aobasis.h:42
void Fill(const AOBasis &aobasis) final
const Eigen::MatrixXd & Matrix() const
Definition aomatrix.h:52
const std::string & getType() const
void push_back(const T &atom)
const Eigen::Vector3d & getPos() const
double IntegratePotential(const Eigen::Vector3d &rvector) const
double IntegrateDensity(const Eigen::MatrixXd &density_matrix)
std::vector< QMFragment< double > > regionconstraint_
Definition espfit.h:74
Logger & log_
Definition espfit.h:64
StaticSegment FitPartialCharges(const Orbitals &orbitals, const Grid &grid, double netcharge)
Definition espfit.cc:125
std::vector< std::pair< Index, Index > > pairconstraint_
Definition espfit.h:68
StaticSegment Fit2Density(const Orbitals &orbitals, const QMState &state, std::string gridsize)
Definition espfit.cc:36
double conditionnumber_
Definition espfit.h:66
void EvalNuclearPotential(const QMMolecule &atoms, Grid &grid)
Definition espfit.cc:106
void setupCHELPGGrid(const QMMolecule &Atomlist)
Definition grid.h:54
Eigen::VectorXd & getGridValues()
Definition grid.h:48
Index size()
Definition grid.h:50
const std::vector< Eigen::Vector3d > & getGridPositions() const
Definition grid.h:44
Container for molecular orbitals and derived one-particle data.
Definition orbitals.h:47
Eigen::MatrixXd DensityMatrixFull(const QMState &state) const
Definition orbitals.cc:150
const QMMolecule & QMAtoms() const
Return read-only access to the molecular geometry.
Definition orbitals.h:262
const AOBasis & getDftBasis() const
Return the DFT AO basis, throwing if it has not been initialized.
Definition orbitals.h:342
container for QM atoms
Definition qmatom.h:37
const T & value() const
Definition qmfragment.h:59
Identifier for QMstates. Strings like S1 are converted into enum +zero indexed int.
Definition qmstate.h:135
bool isTransition() const
Definition qmstate.h:156
Class to represent Atom/Site in electrostatic.
Definition staticsite.h:37
Timestamp returns the current time as a string Example: cout << TimeStamp().
Definition logger.h:224
Index getGridSize() const
Definition vxc_grid.h:41
void GridSetup(const std::string &type, const QMMolecule &atoms, const AOBasis &basis)
Definition vxc_grid.cc:230
#define XTP_LOG(level, log)
Definition logger.h:40
void Cite(const std::string &key)
marks a reference as used (thread safe; unknown keys are printed as such)
Definition citations.cc:289
Charge transport classes.
Definition ERIs.h:28
ClassicalSegment< StaticSite > StaticSegment
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26