votca 2026-dev
Loading...
Searching...
No Matches
ewaldregistry.cc
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// Standard includes
21#include <sstream>
22#include <stdexcept>
23
24// Local VOTCA includes
26
27namespace votca {
28namespace xtp {
29
30namespace {
31
32std::string StateTag(EwaldChargeState state) {
33 switch (state) {
35 return "neutral";
37 return "electron";
39 return "hole";
40 }
41 // Unreachable for a valid enum value; kept explicit rather than relying
42 // on undefined behaviour if the enum is ever extended without updating
43 // this function.
44 throw std::runtime_error("EwaldRegistry: unknown EwaldChargeState");
45}
46
47bool TagToState(const std::string& tag, EwaldChargeState& state) {
48 if (tag == "neutral") {
50 return true;
51 }
52 if (tag == "electron") {
54 return true;
55 }
56 if (tag == "hole") {
58 return true;
59 }
60 return false;
61}
62
63std::string GroupName(Index id, EwaldChargeState state) {
64 return std::to_string(id) + "_" + StateTag(state);
65}
66
67} // namespace
68
70 PolarSegment segment) {
71 // RANK GUARD. Every Ewald kernel reads getCharge() and
72 // getStaticDipole() and nothing else, so a rank-2 site's quadrupole is
73 // parsed, stored, and then silently dropped: a wrong energy with no
74 // symptom to notice it by. Checked here because this is the one place
75 // every segment passes through on its way into a background or a
76 // region.
77 for (const PolarSite& site : segment) {
78 if (site.getRank() > 1) {
79 std::stringstream message;
80 message << "EwaldRegistry: segment " << id << ", site " << site.getId()
81 << " (" << site.getElement() << ") has rank " << site.getRank()
82 << ". This Ewald implementation handles charges and dipoles "
83 "(rank <= 1) only -- higher multipoles would be read and "
84 "then ignored, giving a wrong energy with no symptom. Use "
85 "a rank 0 or rank 1 .mps.";
86 throw std::runtime_error(message.str());
87 }
88 }
89 // PolarSegment has no default constructor, so operator[] (which would
90 // value-initialize a fresh entry before assigning into it) is not usable
91 // here; insert_or_assign constructs the entry directly from the moved
92 // argument instead.
93 store_.insert_or_assign(Key(id, state), std::move(segment));
94}
95
97 return store_.find(Key(id, state)) != store_.end();
98}
99
101 auto it = store_.find(Key(id, state));
102 if (it == store_.end()) {
103 std::stringstream message;
104 message << "EwaldRegistry: no entry for segment id " << id << " in state '"
105 << StateTag(state) << "'";
106 throw std::out_of_range(message.str());
107 }
108 return it->second;
109}
110
112 auto it = store_.find(Key(id, state));
113 if (it == store_.end()) {
114 std::stringstream message;
115 message << "EwaldRegistry: no entry for segment id " << id << " in state '"
116 << StateTag(state) << "'";
117 throw std::out_of_range(message.str());
118 }
119 return it->second;
120}
121
123 store_.erase(Key(id, state));
124}
125
126std::vector<Index> EwaldRegistry::AllIds() const {
127 std::vector<Index> ids;
128 for (const auto& entry : store_) {
129 Index id = entry.first.first;
130 if (ids.empty() || ids.back() != id) {
131 ids.push_back(id);
132 }
133 }
134 return ids;
135}
136
137std::vector<EwaldChargeState> EwaldRegistry::StatesFor(Index id) const {
138 std::vector<EwaldChargeState> states;
139 for (const auto& entry : store_) {
140 if (entry.first.first == id) {
141 states.push_back(entry.first.second);
142 }
143 }
144 return states;
145}
146
148 Index size = static_cast<Index>(store_.size());
149 w(size, "size");
150 CheckpointWriter ww = w.openChild("entries");
151 for (const auto& entry : store_) {
152 Index id = entry.first.first;
153 EwaldChargeState state = entry.first.second;
154 const PolarSegment& seg = entry.second;
155 CheckpointWriter www = ww.openChild(GroupName(id, state));
156 seg.WriteToCpt(www);
157 }
158}
159
161 Index size;
162 r(size, "size");
163 store_.clear();
164 CheckpointReader rr = r.openChild("entries");
165 std::vector<std::string> names = rr.getChildGroupNames();
166 if (Index(names.size()) != size) {
167 std::stringstream message;
168 message << "EwaldRegistry: size inconsistency reading checkpoint ("
169 << names.size() << " groups found, " << size << " expected)";
170 throw std::runtime_error(message.str());
171 }
172 for (const std::string& name : names) {
173 // Group names are "<id>_<statetag>"; split on the last underscore
174 // rather than the first, since the id portion never contains one.
175 std::size_t split = name.rfind('_');
176 if (split == std::string::npos) {
177 throw std::runtime_error(
178 "EwaldRegistry: malformed checkpoint group name '" + name + "'");
179 }
180 Index id = std::stoi(name.substr(0, split));
181 std::string tag = name.substr(split + 1);
182 EwaldChargeState state;
183 if (!TagToState(tag, state)) {
184 throw std::runtime_error("EwaldRegistry: unknown charge state tag '" +
185 tag + "' in checkpoint group name '" + name +
186 "'");
187 }
188 CheckpointReader rrr = rr.openChild(name);
189 store_.insert_or_assign(Key(id, state), PolarSegment(rrr));
190 }
191}
192
193} // namespace xtp
194} // namespace votca
virtual void WriteToCpt(CheckpointWriter &w) const
std::vector< std::string > getChildGroupNames() const
CheckpointReader openChild(const std::string &childName) const
CheckpointWriter openChild(const std::string &childName) const
std::map< Key, PolarSegment, KeyLess > store_
bool Has(Index id, EwaldChargeState state) const
std::pair< Index, EwaldChargeState > Key
std::vector< EwaldChargeState > StatesFor(Index id) const
std::vector< Index > AllIds() const
void WriteToCpt(CheckpointWriter &w) const
const PolarSegment & Get(Index id, EwaldChargeState state) const
void Erase(Index id, EwaldChargeState state)
void Register(Index id, EwaldChargeState state, PolarSegment segment)
void ReadFromCpt(CheckpointReader &r)
Class to represent Atom/Site in electrostatic+polarization.
Definition polarsite.h:36
Charge transport classes.
Definition ERIs.h:28
ClassicalSegment< PolarSite > PolarSegment
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26