votca 2026-dev
Loading...
Searching...
No Matches
polarregion.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// Standard includes
21#include <iomanip>
22#include <numeric>
23
24// Local VOTCA includes
29#include "votca/xtp/qmregion.h"
31
32#include <stdexcept>
33
34namespace votca {
35namespace xtp {
36
38 max_iter_ = prop.get("max_iter").as<Index>();
39 deltaD_ = prop.get("tolerance_dipole").as<double>();
40 deltaE_ = prop.get("tolerance_energy").as<double>();
41 exp_damp_ = prop.get("exp_damp").as<double>();
42}
43
45
46 if (!E_hist_.filled()) {
47 return false;
48 }
49 double Echange = E_hist_.getDiff().Etotal();
50 std::string info = "not converged";
51 bool converged = false;
52 if (std::abs(Echange) < deltaE_) {
53 info = "converged";
54 converged = true;
55 }
57 << TimeStamp() << " Region:" << this->identify() << " " << this->getId()
58 << " is " << info << " deltaE=" << Echange << std::flush;
59 return converged;
60}
61
63
64 eeInteractor eeinteractor;
65 double e = 0.0;
66#pragma omp parallel for reduction(+ : e)
67 for (Index i = 0; i < size(); ++i) {
68 for (Index j = 0; j < size(); ++j) {
69 if (i == j) {
70 continue;
71 }
72 PolarSegment& seg1 = segments_[i];
73 const PolarSegment& seg2 = segments_[j];
74 e += eeinteractor.ApplyStaticField<PolarSegment, Estatic::noE_V>(seg2,
75 seg1);
76 }
77 }
78
79 return 0.5 * e;
80}
81
83#pragma omp declare reduction(CustomPlus : eeInteractor::E_terms : omp_out += \
84 omp_in)
85
86 eeInteractor eeinteractor(exp_damp_);
87
89
90#pragma omp parallel for reduction(CustomPlus : terms)
91 for (Index i = 0; i < size(); ++i) {
92 for (Index j = 0; j < i; ++j) {
93 terms += eeinteractor.CalcPolarEnergy(segments_[i], segments_[j]);
94 }
95 }
96
97#pragma omp parallel for reduction(CustomPlus : terms)
98 for (Index i = 0; i < size(); ++i) {
99 terms.E_indu_indu() +=
101 }
102
103#pragma omp parallel for reduction(CustomPlus : terms)
104 for (Index i = 0; i < size(); ++i) {
105 for (const PolarSite& site : segments_[i]) {
106 terms.E_internal() += site.InternalEnergy();
107 }
108 }
109 return terms;
110}
111
113 double e = 0.0;
114#pragma omp parallel for reduction(+ : e)
115 for (Index i = 0; i < size(); ++i) {
116 for (const PolarSite& site : segments_[i]) {
117 e += site.deltaQ_V_ext();
118 }
119 }
120 return e;
121}
122
124 for (PolarSegment& seg : segments_) {
125 for (PolarSite& site : seg) {
126 site.Reset();
127 }
128 }
129}
130
132 const Energy_terms& e = this->E_hist_.back();
133 prop.add("E_static", std::to_string(e.Estatic() * tools::conv::hrt2ev));
134 prop.add("E_polar", std::to_string(e.Epolar() * tools::conv::hrt2ev));
135 prop.add("E_total", std::to_string(e.Etotal() * tools::conv::hrt2ev));
136}
137
139 Index dof_polarization = 0;
140 for (const PolarSegment& seg : segments_) {
141 dof_polarization += seg.size() * 3;
142 }
143 return dof_polarization;
144}
145
147 Index dof_polarization = CalcPolDoF();
148 Eigen::VectorXd initial_induced_dipoles =
149 Eigen::VectorXd::Zero(dof_polarization);
150 eeInteractor interactor(exp_damp_);
151 Index index = 0;
152 for (const PolarSegment& seg : segments_) {
153 initial_induced_dipoles.segment(index, 3 * seg.size()) =
154 interactor.Cholesky_IntraSegment(seg);
155 index += 3 * seg.size();
156 }
157 return initial_induced_dipoles;
158}
159
161 Index dof_polarization = CalcPolDoF();
162 Eigen::VectorXd last_induced_dipoles =
163 Eigen::VectorXd::Zero(dof_polarization);
164 Index index = 0;
165 for (const PolarSegment& seg : segments_) {
166 for (const PolarSite& site : seg) {
167 last_induced_dipoles.segment<3>(index) = site.Induced_Dipole();
168 index += 3;
169 }
170 }
171 return last_induced_dipoles;
172}
173
174void PolarRegion::WriteInducedDipolesToSegments(const Eigen::VectorXd& x) {
175 Index index = 0;
176 for (PolarSegment& seg : segments_) {
177 for (PolarSite& site : seg) {
178 site.setInduced_Dipole(x.segment<3>(index));
179 index += 3;
180 }
181 }
182}
183
185 const Eigen::VectorXd& initial_guess) {
186 Eigen::VectorXd b = Eigen::VectorXd::Zero(initial_guess.size());
187 Index index = 0;
188 for (PolarSegment& seg : segments_) {
189 for (const PolarSite& site : seg) {
190 auto V = site.V() + site.V_noE();
191 b.segment<3>(index) = -V;
192 index += 3;
193 }
194 }
195 eeInteractor interactor(exp_damp_);
196 DipoleDipoleInteraction A(interactor, segments_);
197 Eigen::ConjugateGradient<DipoleDipoleInteraction, Eigen::Lower | Eigen::Upper,
198 Eigen::DiagonalPreconditioner<double>>
199 cg;
200 cg.setMaxIterations(max_iter_);
201 cg.setTolerance(deltaD_);
202 cg.compute(A);
203 Eigen::VectorXd x = cg.solveWithGuess(b, initial_guess);
204
206 << TimeStamp() << " CG: #iterations: " << cg.iterations()
207 << ", estimated error: " << cg.error() << std::flush;
208
209 if (cg.info() == Eigen::ComputationInfo::NoConvergence) {
210 info_ = false;
211 errormsg_ = "PCG iterations did not converge";
212 }
213
214 if (cg.info() == Eigen::ComputationInfo::NumericalIssue) {
215 info_ = false;
216 errormsg_ = "PCG had a numerical issue";
217 }
218 return x;
219}
220
221void PolarRegion::Evaluate(std::vector<std::unique_ptr<Region>>& regions) {
222
223 std::vector<double> energies = ApplyInfluenceOfOtherRegions(regions);
224 Energy_terms e_contrib;
225 e_contrib.E_static_ext() =
226 std::accumulate(energies.begin(), energies.end(), 0.0);
228 << " Calculated static-static and polar-static "
229 "interaction with other regions"
230 << std::flush;
231 e_contrib.E_static_static() = StaticInteraction();
233 << " Calculated static interaction in region "
234 << std::flush;
235 Index dof_polarization = CalcPolDoF();
237 << TimeStamp() << " Starting Solving for classical polarization with "
238 << dof_polarization << " degrees of freedom." << std::flush;
239
240 Eigen::VectorXd initial_induced_dipoles;
241 if (!E_hist_.filled() || segments_.size() == 1) {
242 initial_induced_dipoles = CalcInducedDipoleInsideSegments();
243 } else {
244 initial_induced_dipoles = ReadInducedDipolesFromLastIteration();
245 }
246
247 Eigen::VectorXd x; // if only one segment
248 // it is solved exactly through the initial guess
249 if (segments_.size() != 1) {
250 x = CalcInducedDipolesViaPCG(initial_induced_dipoles);
251 if (!info_) {
252 return;
253 }
254 } else {
255 x = initial_induced_dipoles;
256 }
257
259
262 << " Calculated polar interaction in region"
263 << std::flush;
264 e_contrib.E_polar_ext() = PolarEnergy_extern();
266 << " Calculated polar interaction with other regions"
267 << std::flush;
268
269 XTP_LOG(Log::info, log_) << std::setprecision(10)
270 << " Internal static energy [hrt]= "
271 << e_contrib.E_static_static() << std::flush;
272 XTP_LOG(Log::info, log_) << std::setprecision(10)
273 << " External static energy [hrt]= "
274 << e_contrib.E_static_ext() << std::flush;
276 << std::setprecision(10)
277 << " Total static energy [hrt]= " << e_contrib.Estatic() << std::flush;
278
279 XTP_LOG(Log::info, log_) << std::setprecision(10)
280 << " internal dQ-dQ energy [hrt]= "
281 << e_contrib.E_indu_indu() << std::flush;
282
283 XTP_LOG(Log::info, log_) << std::setprecision(10)
284 << " internal Q-dQ energy [hrt]= "
285 << e_contrib.E_indu_stat() << std::flush;
286
287 XTP_LOG(Log::info, log_) << std::setprecision(10)
288 << " Internal energy [hrt]= "
289 << e_contrib.E_internal() << std::flush;
290
291 XTP_LOG(Log::info, log_) << std::setprecision(10)
292 << " External polar energy [hrt]= "
293 << e_contrib.E_polar_ext() << std::flush;
294
296 << std::setprecision(10)
297 << " Total polar energy [hrt]= " << e_contrib.Epolar() << std::flush;
298
300 << std::setprecision(10) << " Total energy [hrt]= " << e_contrib.Etotal()
301 << std::flush;
302 E_hist_.push_back(e_contrib);
303 return;
304}
305
307 // QMregions always have lower ids than other regions
309 return 0.0;
310}
312 bool noE_V = true;
313 if (this->getId() < region.getId()) {
314 noE_V = false;
315 }
316
317 double e = 0;
318#pragma omp parallel for reduction(+ : e)
319 for (Index i = 0; i < Index(segments_.size()); i++) {
320 PolarSegment& pseg1 = segments_[i];
321 double e_thread = 0.0;
322 eeInteractor ee;
323 for (const PolarSegment& pseg2 : region) {
324 if (noE_V) {
326 ee.ApplyInducedField<Estatic::noE_V>(pseg2, pseg1);
327 } else {
328 e_thread += ee.ApplyStaticField<PolarSegment, Estatic::V>(pseg2, pseg1);
329 e_thread += ee.ApplyInducedField<Estatic::V>(pseg2, pseg1);
330 }
331 e += e_thread;
332 }
333 }
334 return e;
335}
336
338 // Static regions always have higher ids than other regions
339
340 double e = 0.0;
341#pragma omp parallel for reduction(+ : e)
342 for (Index i = 0; i < Index(segments_.size()); i++) {
343 double e_thread = 0.0;
344 PolarSegment& pseg = segments_[i];
345 eeInteractor ee;
346 for (const StaticSegment& sseg : region) {
347 e_thread += ee.ApplyStaticField<StaticSegment, Estatic::V>(sseg, pseg);
348 }
349 e += e_thread;
350 }
351
352 return e;
353}
354
358
362
364 // Delegated: the background owns the periodic sums, the foreground
365 // bookkeeping and the parameters they must all share, so assembling
366 // them here would mean reaching into it for all three.
367 return region.ApplyFieldTo(segments_);
368}
369
370} // namespace xtp
371} // namespace votca
class to manage program options with xml serialization functionality
Definition property.h:55
Property & add(const std::string &key, const std::string &value)
add a new property to structure
Definition property.cc:108
Property & get(const std::string &key)
get existing property
Definition property.cc:79
T as() const
return value as type
Definition property.h:283
void addInternalPolarContrib(const eeInteractor::E_terms &induction_terms)
The periodic Ewald background, as a Region.
Definition ewaldregion.h:76
double ApplyFieldTo(std::vector< PolarSegment > &foreground) const
Index size() const override
Definition mmregion.h:45
std::vector< PolarSegment > segments_
Definition mmregion.h:87
void WriteToCpt(CheckpointWriter &w) const override
Definition mmregion.cc:45
void ReadFromCpt(CheckpointReader &r) override
Definition mmregion.cc:58
Eigen::VectorXd CalcInducedDipoleInsideSegments() const
PolarRegion(Index id, Logger &log)
Definition polarregion.h:47
void AppendResult(tools::Property &prop) const override
void WriteInducedDipolesToSegments(const Eigen::VectorXd &x)
double InteractwithEwaldRegion(const EwaldRegion &region) override
void ReadFromCpt(CheckpointReader &r) override
double InteractwithQMRegion(const QMRegion &region) override
void Initialize(const tools::Property &prop) override
bool Converged() const override
eeInteractor::E_terms PolarEnergy() const
Eigen::VectorXd CalcInducedDipolesViaPCG(const Eigen::VectorXd &initial_guess)
Eigen::VectorXd ReadInducedDipolesFromLastIteration() const
std::string identify() const override
Definition polarregion.h:49
hist< Energy_terms > E_hist_
Definition polarregion.h:92
void WriteToCpt(CheckpointWriter &w) const override
double InteractwithPolarRegion(const PolarRegion &region) override
void Evaluate(std::vector< std::unique_ptr< Region > > &regions) override
void Reset() override
double InteractwithStaticRegion(const StaticRegion &region) override
double PolarEnergy_extern() const
Class to represent Atom/Site in electrostatic+polarization.
Definition polarsite.h:36
void ApplyQMFieldToPolarSegments(std::vector< PolarSegment > &segments) const
Definition qmregion.cc:770
std::vector< double > ApplyInfluenceOfOtherRegions(std::vector< std::unique_ptr< Region > > &regions)
Definition region.cc:33
Index getId() const
Definition region.h:80
std::string errormsg_
Definition region.h:92
Logger & log_
Definition region.h:106
Timestamp returns the current time as a string Example: cout << TimeStamp().
Definition logger.h:224
Mediates interaction between polar and static sites.
double ApplyStaticField(const T &segment1, PolarSegment &segment2) const
double ApplyInducedField(const PolarSegment &segment1, PolarSegment &segment2) const
E_terms CalcPolarEnergy(const S1 &segment1, const S2 &segment2) const
Eigen::VectorXd Cholesky_IntraSegment(const PolarSegment &seg) const
double CalcPolarEnergy_IntraSegment(const PolarSegment &seg) const
#define XTP_LOG(level, log)
Definition logger.h:40
const double hrt2ev
Definition constants.h:53
Charge transport classes.
Definition ERIs.h:28
ClassicalSegment< PolarSite > PolarSegment
ClassicalSegment< StaticSite > StaticSegment
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26