votca 2026-dev
Loading...
Searching...
No Matches
topology.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2023 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 <map>
22#include <queue>
23#include <set>
24
25// Third party includes
26#include <boost/lexical_cast.hpp>
27
28// VOTCA includes
29#include <votca/csg/pdbwriter.h>
30#include <votca/tools/globals.h>
31#include <votca/tools/version.h>
32
33// Local VOTCA includes
34#include "votca/xtp/atom.h"
36#include "votca/xtp/segment.h"
37#include "votca/xtp/topology.h"
38
39namespace votca {
40namespace xtp {
41
43 segments_ = top.segments_;
44 time_ = top.time_;
45 step_ = top.step_;
46 this->setBox(top.getBox());
47 CopyPairs(top);
48}
49
50void Topology::CopyPairs(const Topology &top) {
51 // the pairs point to the segments of their topology: re-create them for
52 // the copied segments and copy their data (couplings, outer-sphere
53 // reorganization energies, pair type) through the checkpoint record
54 for (const QMPair *pair : top.NBList()) {
55 const Segment &seg1 = segments_[pair->Seg1()->getId()];
56 const Segment &seg2 = segments_[pair->Seg2()->getId()];
57 QMPair &copy = nblist_.Add(seg1, seg2, pair->R());
59 pair->WriteData(d); // allocates d.pair_type, ReadData frees it
60 copy.ReadData(d, segments_);
61 }
62}
63
65 if (&top != this) {
66 segments_ = top.segments_;
67 time_ = top.time_;
68 step_ = top.step_;
69 this->setBox(top.getBox());
70 nblist_.Cleanup();
71 CopyPairs(top);
72 }
73 return *this;
74}
75
76Segment &Topology::AddSegment(std::string segment_name) {
77 Index segment_id = Index(segments_.size());
78 segments_.push_back(Segment(segment_name, segment_id));
79 return segments_.back();
80}
81
82// +++++++++++++++++ //
83// Periodic Boundary //
84// +++++++++++++++++ //
85void Topology::setBox(const Eigen::Matrix3d &box,
87
88 // Determine box type automatically in case boxtype == typeAuto
89 if (boxtype == csg::BoundaryCondition::typeAuto) {
90 boxtype = AutoDetectBoxType(box);
91 }
92
93 if (bc_ != nullptr) {
94 if (Log::verbose()) {
95 std::cout << "Removing periodic box. Creating new... " << std::endl;
96 }
97 }
98 bc_.reset(nullptr);
99 switch (boxtype) {
101 bc_.reset(new csg::TriclinicBox());
102 break;
104 bc_.reset(new csg::OrthorhombicBox());
105 break;
106 default:
107 bc_.reset(new csg::OpenBox());
108 break;
109 }
110
111 bc_->setBox(box);
112}
113
115 const Eigen::Matrix3d &box) {
116
117 // Set box type to OpenBox in case "box" is the zero matrix,
118 // to OrthorhombicBox in case "box" is a diagonal matrix,
119 // or to TriclinicBox otherwise
120
121 if (box.isApproxToConstant(0)) {
122 std::cout << "WARNING: No box vectors specified in trajectory."
123 "Using open-box boundary conditions. "
124 << std::endl;
126 }
127
128 else if ((box - Eigen::Matrix3d(box.diagonal().asDiagonal()))
129 .isApproxToConstant(0)) {
131 }
132
133 else {
135 }
136
138}
139
140Eigen::Vector3d Topology::PbShortestConnect(const Eigen::Vector3d &r1,
141 const Eigen::Vector3d &r2) const {
142 return bc_->BCShortestConnection(r1, r2);
143}
144
146 const Segment &seg2) const {
147 double R2 = std::numeric_limits<double>::max();
148 for (const Atom &atom1 : seg1) {
149 for (const Atom &atom2 : seg2) {
150 double R2_test =
151 PbShortestConnect(atom1.getPos(), atom2.getPos()).squaredNorm();
152 if (R2_test < R2) {
153 R2 = R2_test;
154 }
155 }
156 }
157 return std::sqrt(R2);
158}
159
160std::vector<const Segment *> Topology::FindAllSegmentsOnMolecule(
161 const Segment &seg1, const Segment &seg2) const {
162 const std::vector<Index> &ids1 = seg1.getMoleculeIds();
163 const std::vector<Index> &ids2 = seg2.getMoleculeIds();
164 std::vector<Index> common_elements;
165 std::set_intersection(ids1.begin(), ids1.end(), ids2.begin(), ids2.end(),
166 std::back_inserter(common_elements));
167 std::vector<const Segment *> results;
168 if (common_elements.empty() || common_elements.size() > 1) {
169 return results;
170 }
171 Index molid = common_elements[0];
172
173 for (const Segment &seg : segments_) {
174 if (std::find(seg.getMoleculeIds().begin(), seg.getMoleculeIds().end(),
175 molid) != seg.getMoleculeIds().end()) {
176 results.push_back(&seg);
177 }
178 }
179 return results;
180}
181
182std::vector<const Segment *> Topology::FindLinkingSegments(
183 const Segment &seg1, const Segment &seg2) const {
184 std::vector<const Segment *> results;
185
186 // Segment adjacency graph from Atom::getExternalBondPartnerSegmentId().
187 // Rebuilt on every call instead of cached: the function is called rarely
188 // (only for pairs with linkers) and a cache could become stale if
189 // segments_ changes.
190 std::map<Index, std::vector<Index>> segment_adjacency;
191 for (const Segment &seg : segments_) {
192 for (const Atom &atom : seg) {
193 if (!atom.hasExternalBond()) {
194 continue;
195 }
196 Index partner_segment_id = atom.getExternalBondPartnerSegmentId();
197 if (partner_segment_id == -1) {
198 continue;
199 }
200 segment_adjacency[seg.getId()].push_back(partner_segment_id);
201 }
202 }
203
204 // Breadth-first search, which yields the shortest bond path. predecessor
205 // stores for each visited segment the segment it was reached from.
206 std::map<Index, Index> predecessor;
207 std::set<Index> visited;
208 std::queue<Index> to_visit;
209 visited.insert(seg1.getId());
210 to_visit.push(seg1.getId());
211 bool found = false;
212 while (!to_visit.empty() && !found) {
213 Index current = to_visit.front();
214 to_visit.pop();
215 for (Index neighbor : segment_adjacency[current]) {
216 if (visited.count(neighbor) > 0) {
217 continue;
218 }
219 visited.insert(neighbor);
220 predecessor[neighbor] = current;
221 if (neighbor == seg2.getId()) {
222 found = true;
223 break;
224 }
225 to_visit.push(neighbor);
226 }
227 }
228
229 if (!found) {
230 // Not connected by bonds; empty result as in FindAllSegmentsOnMolecule.
231 return results;
232 }
233
234 // Walk back from seg2 to seg1 via predecessor, excluding both ends, and
235 // reverse to get the segments in seg1-to-seg2 chain order (needed for a
236 // planned PBC correction that follows the chain bond by bond).
237 std::vector<Index> path_segment_ids;
238 Index current = predecessor.at(seg2.getId());
239 while (current != seg1.getId()) {
240 path_segment_ids.push_back(current);
241 current = predecessor.at(current);
242 }
243 std::reverse(path_segment_ids.begin(), path_segment_ids.end());
244
245 for (Index segment_id : path_segment_ids) {
246 results.push_back(&getSegment(segment_id));
247 }
248 return results;
249}
250
251void Topology::WriteToPdb(std::string filename) const {
252
253 csg::PDBWriter writer;
254 writer.Open(filename, false);
255 writer.WriteHeader("Frame:" + std::to_string(this->getStep()));
256 writer.WriteBox(this->getBox() * tools::conv::bohr2ang);
257 for (const Segment &seg : segments_) {
258 writer.WriteContainer(seg);
259 }
260 writer.Close();
261}
262
264 w(votca::tools::ToolsVersionStr(), "XTPVersion");
265 w(topology_version(), "version");
266 w(time_, "time");
267 w(step_, "step");
268 w(this->getBox(), "box");
269 CheckpointWriter ww = w.openChild("segments");
270 for (const Segment &seg : segments_) {
271 CheckpointWriter u = ww.openChild("segment" + std::to_string(seg.getId()));
272 seg.WriteToCpt(u);
273 }
274 CheckpointWriter www = w.openChild("neighborlist");
275 nblist_.WriteToCpt(www);
276}
277
279 r(time_, "time");
280 r(step_, "step");
281 Eigen::Matrix3d box;
282 r(box, "box");
283 setBox(box);
284 CheckpointReader v = r.openChild("segments");
285 segments_.clear();
286 Index count = v.getNumDataSets();
287 segments_.reserve(count);
288 for (Index i = 0; i < count; i++) {
289 CheckpointReader w = v.openChild("segment" + std::to_string(i));
290 segments_.push_back(Segment(w));
291 }
292 CheckpointReader rr = r.openChild("neighborlist");
293 nblist_.ReadFromCpt(rr, segments_);
294}
295
296} // namespace xtp
297} // namespace votca
void WriteHeader(std::string header)
Definition pdbwriter.cc:41
void WriteBox(const Eigen::Matrix3d &box)
Definition pdbwriter.cc:62
void Close() override
Definition pdbwriter.cc:51
void WriteContainer(T &container)
Definition pdbwriter.h:102
void Open(std::string file, bool bAppend=false) override
Definition pdbwriter.cc:33
CheckpointReader openChild(const std::string &childName) const
CheckpointWriter openChild(const std::string &childName) const
void ReadData(const data &d, const std::vector< Segment > &segments)
Definition qmpair.cc:102
const std::vector< Index > & getMoleculeIds() const
Definition segment.h:93
void WriteToCpt(CheckpointWriter &w) const
Definition topology.cc:263
Index getStep() const
Definition topology.h:75
std::unique_ptr< csg::BoundaryCondition > bc_
Definition topology.h:105
Segment & AddSegment(std::string segment_name)
Definition topology.cc:76
std::vector< Segment > segments_
Definition topology.h:103
Eigen::Vector3d PbShortestConnect(const Eigen::Vector3d &r1, const Eigen::Vector3d &r2) const
Definition topology.cc:140
void setBox(const Eigen::Matrix3d &box, csg::BoundaryCondition::eBoxtype boxtype=csg::BoundaryCondition::typeAuto)
Definition topology.cc:85
std::vector< const Segment * > FindAllSegmentsOnMolecule(const Segment &seg1, const Segment &seg2) const
Definition topology.cc:160
csg::BoundaryCondition::eBoxtype AutoDetectBoxType(const Eigen::Matrix3d &box)
Definition topology.cc:114
const Eigen::Matrix3d & getBox() const
Definition topology.h:64
std::vector< const Segment * > FindLinkingSegments(const Segment &seg1, const Segment &seg2) const
Definition topology.cc:182
void ReadFromCpt(CheckpointReader &r)
Definition topology.cc:278
void WriteToPdb(std::string filename) const
Definition topology.cc:251
QMNBList & NBList()
Definition topology.h:70
Topology & operator=(const Topology &top)
Definition topology.cc:64
double GetShortestDist(const Segment &seg1, const Segment &seg2) const
Definition topology.cc:145
Segment & getSegment(Index id)
Definition topology.h:55
static constexpr int topology_version()
Definition topology.h:117
void CopyPairs(const Topology &top)
Definition topology.cc:50
const double bohr2ang
Definition constants.h:49
const std::string & ToolsVersionStr()
Definition version.cc:33
Charge transport classes.
Definition ERIs.h:28
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
static bool verbose()
Definition globals.h:32