votca 2026-dev
Loading...
Searching...
No Matches
ewaldregion.h
Go to the documentation of this file.
1/*
2 * Copyright 2009-2026 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#pragma once
21#ifndef VOTCA_XTP_EWALDREGION_H
22#define VOTCA_XTP_EWALDREGION_H
23
24// Local VOTCA includes
25#include <memory>
26
32#include "votca/xtp/region.h"
33
34namespace votca {
35namespace xtp {
36class QMRegion;
37class PolarRegion;
38class StaticRegion;
39
76class EwaldRegion : public Region {
77 public:
78 EwaldRegion(Index id, Logger& log) : Region(id, log) {}
79 ~EwaldRegion() override = default;
80
81 std::string identify() const override { return "ewaldregion"; }
82
83 void Initialize(const tools::Property& prop) override;
84
85 // Always true: this region is frozen, so it can never be the reason a
86 // job fails to converge. See this class's own documentation.
87 bool Converged() const override { return true; }
88
89 void Evaluate(std::vector<std::unique_ptr<Region>>& regions) override;
90
91 // No-op: there is no per-iteration state to clear.
92 void Reset() override {}
93
94 Index size() const override;
95
96 double charge() const override;
97
98 double Etotal() const override;
99
100 void WriteToCpt(CheckpointWriter& w) const override;
101
102 void ReadFromCpt(CheckpointReader& r) override;
103
104 void WritePDB(csg::PDBWriter& writer) const override;
105
106 protected:
107 void AppendResult(tools::Property& prop) const override;
108
109 // All three are genuinely 0.0, not placeholders: the background is
110 // frozen and no other region polarizes it. See this class's own
111 // documentation, point 1.
112 double InteractwithQMRegion(const QMRegion&) override { return 0.0; }
113 double InteractwithPolarRegion(const PolarRegion&) override { return 0.0; }
114 double InteractwithStaticRegion(const StaticRegion&) override { return 0.0; }
115 double InteractwithEwaldRegion(const EwaldRegion&) override { return 0.0; }
116
117 public:
118 // The converged periodic background, as written by the ewaldbackground
119 // calculator. Read-only to consumers: nothing in a job re-polarizes it.
120 const EwaldRegistry& Registry() const { return registry_; }
121
122 // The convergence parameters the background was converged WITH, read
123 // from the same checkpoint rather than re-specified by the job. See
124 // EwaldParameters for why that distinction matters.
125 const EwaldParameters& Parameters() const { return params_; }
126
127 // Accumulates this periodic background's field into every site of
128 // `foreground`, which is the polar region's own segment list.
129 //
130 // The four contributions, matching legacy's own ER - EC + EK + E0
131 // decomposition:
132 //
133 // + real space (erfc), with the foreground's own copies SUPPRESSED
134 // so they are not counted twice -- they are about to be treated
135 // explicitly by the polar region instead
136 // + reciprocal space, over the FULL periodic density. This still
137 // contains the foreground segments in their neutral state: the
138 // k-sum is over the whole lattice and cannot have a hole cut in it
139 // + shape/surface term
140 // - the erf-screened field of exactly those neutral foreground
141 // copies, which removes what the reciprocal sum just put back
142 //
143 // The last term uses the NEUTRAL multipoles together with the
144 // background's own converged induced dipoles, not the job's charge
145 // state -- because that is what the reciprocal sum actually placed
146 // there. Using the job's state instead would remove something that was
147 // never added, and would make a charged job differ from the background
148 // for the wrong reason.
149 //
150 // Returns 0.0: the energy is not implemented yet (see the warning this
151 // emits on first use).
152 double ApplyFieldTo(std::vector<PolarSegment>& foreground) const;
153
154 // Declares the COMPLETE foreground: the union of every region that owns
155 // segments of the job's topology. JobTopology calls this once, after it
156 // has built the regions and before any of them is evaluated.
157 //
158 // Why it cannot be left to ApplyFieldTo's argument. Each client region
159 // asks for its own segments, but the background copies that must be
160 // suppressed are those of the WHOLE carved-out cluster. In a QM + polar
161 // job the QM region holds the central segment, so the polar region
162 // hands over everything except it -- and its neutral background copy
163 // would be left sitting underneath the QM density, a ghost molecule in
164 // every sum, with no symptom to notice it by.
165 //
166 // Positions are the job-local ones, after JobTopology::ShiftPBC: the
167 // background registry is in cell coordinates and the job is recentred,
168 // so the two frames differ by a lattice vector. BuildSums snaps that
169 // out. Only the lattice image is taken from these centroids, so any
170 // reasonable centre of a segment will do.
172 const std::vector<std::pair<Index, Eigen::Vector3d>>& foreground);
173
174 // The background's electrostatic POTENTIAL at arbitrary points, for a
175 // QM region that takes its environment as a potential on a grid rather
176 // than as a field on sites.
177 //
178 // The same four terms ApplyFieldTo assembles -- real space with the
179 // foreground copies suppressed, reciprocal space, shape, minus the erf
180 // half of the suppressed copies -- and both channels of each, so what
181 // comes back is the potential of the permanent background TOGETHER
182 // WITH its converged induced dipoles.
183 //
184 // GAUGE. phi carries an arbitrary additive constant: the k = 0 term is
185 // omitted, i.e. the uniform neutralising background. Every term here
186 // is evaluated through the same energy routines the classical channels
187 // use, with a unit test charge, so the constant is the one every
188 // validated number in this code was computed with. A charged region
189 // embedded in phi shifts by q * phi_0, so this is not a free choice --
190 // see unit_probe_potential_reproduces_the_static_energy, which pins it.
191 //
192 // Requires a declared foreground (RegisterForeground): a point is not
193 // a segment, so there is nothing to fall back on.
194 Eigen::VectorXd PotentialAt(const std::vector<Eigen::Vector3d>& points) const;
195
196 private:
197 // Built once, on first use, from the calling region's geometry. The
198 // foreground's positions are fixed for the whole job even though its
199 // dipoles change every SCF iteration, so the sums -- and the neighbour
200 // cache inside the real-space one -- stay valid throughout. Mutable
201 // for the same reason EwaldRealSpaceSum's own cache is: this is lazily
202 // built state behind a const interface, not mutable physics.
203 //
204 // What is cached is specific to the foreground it was built for:
205 // foreground_copies_ decides which background copies the real-space sum
206 // suppresses, and that list is baked into real_sum_'s constructor along
207 // with a neighbour cache keyed to those positions.
208 //
209 // Built from registered_foreground_ when RegisterForeground has been
210 // called, which is the case inside a JobTopology. The argument is a
211 // FALLBACK for direct use of this class without one -- the unit tests,
212 // and any single-client setup -- and is only correct when there is
213 // exactly one client region. Either way every later call is checked
214 // against what was built.
215 void BuildSums(const std::vector<PolarSegment>& fallback) const;
216 // Every segment a client asks about must be part of the foreground the
217 // sums were built for. A subset, not an equality: each client region
218 // asks only about its own share of the union.
220 const std::vector<PolarSegment>& foreground) const;
221
222 mutable std::unique_ptr<EwaldRealSpaceSum> real_sum_;
223 mutable std::unique_ptr<EwaldReciprocalSpaceSum> recip_sum_;
224 mutable std::unique_ptr<EwaldShapeCorrection> shape_;
225 mutable std::unique_ptr<EwaldRealSpaceInteractor> interactor_;
226 // (segment id, position) of each suppressed foreground copy, so the
227 // erf correction removes exactly the copies the real-space sum
228 // dropped.
229 mutable std::vector<std::pair<Index, Eigen::Vector3d>> foreground_copies_;
230 // (segment id, centroid) of the foreground the sums were built for.
231 // Keyed on the FOREGROUND's own centroid, not the background copy's:
232 // foreground_copies_ holds the latter, which is derived from the id
233 // alone, so two different foregrounds sharing a segment id would look
234 // identical there.
235 mutable std::vector<std::pair<Index, Eigen::Vector3d>> built_foreground_;
236 // What RegisterForeground was told. Empty means nobody declared a
237 // foreground and BuildSums falls back to its argument.
238 std::vector<std::pair<Index, Eigen::Vector3d>> registered_foreground_;
239 mutable bool warned_no_energy_ = false;
240
241 std::string checkpoint_file_;
244 bool loaded_ = false;
245};
246
247} // namespace xtp
248} // namespace votca
249
250#endif // VOTCA_XTP_EWALDREGION_H
class to manage program options with xml serialization functionality
Definition property.h:55
void Reset() override
Definition ewaldregion.h:92
std::string identify() const override
Definition ewaldregion.h:81
EwaldParameters params_
double Etotal() const override
bool Converged() const override
Definition ewaldregion.h:87
void Initialize(const tools::Property &prop) override
void CheckForegroundIsSubset(const std::vector< PolarSegment > &foreground) const
Eigen::VectorXd PotentialAt(const std::vector< Eigen::Vector3d > &points) const
void Evaluate(std::vector< std::unique_ptr< Region > > &regions) override
std::vector< std::pair< Index, Eigen::Vector3d > > built_foreground_
void WritePDB(csg::PDBWriter &writer) const override
EwaldRegistry registry_
std::unique_ptr< EwaldShapeCorrection > shape_
double charge() const override
double InteractwithQMRegion(const QMRegion &) override
std::unique_ptr< EwaldReciprocalSpaceSum > recip_sum_
std::unique_ptr< EwaldRealSpaceSum > real_sum_
std::vector< std::pair< Index, Eigen::Vector3d > > registered_foreground_
void RegisterForeground(const std::vector< std::pair< Index, Eigen::Vector3d > > &foreground)
std::unique_ptr< EwaldRealSpaceInteractor > interactor_
std::string checkpoint_file_
const EwaldRegistry & Registry() const
EwaldRegion(Index id, Logger &log)
Definition ewaldregion.h:78
Index size() const override
void AppendResult(tools::Property &prop) const override
double ApplyFieldTo(std::vector< PolarSegment > &foreground) const
~EwaldRegion() override=default
double InteractwithPolarRegion(const PolarRegion &) override
const EwaldParameters & Parameters() const
std::vector< std::pair< Index, Eigen::Vector3d > > foreground_copies_
void BuildSums(const std::vector< PolarSegment > &fallback) const
double InteractwithStaticRegion(const StaticRegion &) override
void ReadFromCpt(CheckpointReader &r) override
double InteractwithEwaldRegion(const EwaldRegion &) override
void WriteToCpt(CheckpointWriter &w) const override
Logger is used for thread-safe output of messages.
Definition logger.h:164
Region(Index id, Logger &log)
Definition region.h:51
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
The Ewald convergence parameters a background was converged with.