votca 2026-dev
Loading...
Searching...
No Matches
segmentmapper.cc
Go to the documentation of this file.
1/*
2 * Copyright 2016 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 <regex>
22
23// Local VOTCA includes
25
26namespace votca {
27namespace xtp {
28
29template <class AtomContainer>
33
34template <class AtomContainer>
36 const SegId& segid) const {
37 if (segid.hasFile()) {
38 std::string filename = segid.FileName();
39 filename = std::regex_replace(filename, std::regex("\\$SEGID"),
40 std::to_string(seg.getId()));
41 filename =
42 std::regex_replace(filename, std::regex("\\$SEGNAME"), seg.getType());
43 return map(seg, filename);
44 } else {
45 QMState state = segid.getQMState();
46 return map(seg, state);
47 }
48}
49
50template <class AtomContainer>
51template <typename T>
53 const std::vector<double>& weights, const T& atoms) const {
54 Eigen::Vector3d map_pos = Eigen::Vector3d::Zero();
55 double map_weight = 0.0;
56 for (Index i = 0; i < Index(atoms.size()); i++) {
57 map_pos += atoms[i]->getPos() * weights[i];
58 map_weight += weights[i];
59 }
60 return map_pos = map_pos / map_weight;
61}
62
63template <class AtomContainer>
65 const tools::Property& frag) const {
66
67 std::vector<double> weights;
68 if (frag.exists(mapatom_xml_.at("weights"))) {
69 weights =
70 frag.get(mapatom_xml_.at("weights")).template as<std::vector<double>>();
71 } else if (frag.exists("weights")) {
72 weights = frag.get("weights").template as<std::vector<double>>();
73 } else {
74 XTP_LOG(Log::error, log_) << " Did not find weights for fragment "
75 << frag.get("name").as<std::string>()
76 << " Using atomic masses" << std::flush;
77 std::string frags =
78 frag.get(mapatom_xml_.at("atoms")).template as<std::string>();
79 tools::Tokenizer tok_atoms(frags, " \t\n");
80 std::vector<std::string> atom_strings = tok_atoms.ToVector();
82 for (auto a_string : atom_strings) {
83 tools::Tokenizer tok_atom(a_string, ":");
84 std::vector<std::string> entries = tok_atom.ToVector();
85 if (entries.size() != 2) {
86 throw std::runtime_error("Cannot get weight from Element for " +
87 a_string);
88 }
89
90 double weight = e.getMass(entries[1]);
91 XTP_LOG(Log::info, log_) << entries[1] << ":" << weight << " ";
92 weights.push_back(weight);
93 }
94 XTP_LOG(Log::error, log_) << std::endl;
95 }
96
97 return weights;
98}
99
100template <class AtomContainer>
102 const tools::Property& frag) {
103 std::vector<std::string> map_atoms =
104 frag.get(mapatom_xml_["atoms"]).template as<std::vector<std::string>>();
105 std::vector<std::string> md_atoms =
106 frag.get("mdatoms").as<std::vector<std::string>>();
107
108 if (md_atoms.size() != map_atoms.size()) {
109 throw std::runtime_error(
110 "Mapping for segment " + seginfo.segname + " fragment " +
111 frag.get("name").as<std::string>() +
112 " does not have same numbers of md and " + mapatom_xml_["atoms"] +
113 "."
114 "If you want to leave a qmatom out, place a ':' instead");
115 }
116
117 std::vector<double> weights = getWeights(frag);
118
119 if (md_atoms.size() != weights.size()) {
120 throw std::runtime_error("Mapping for segment " + seginfo.segname +
121 " fragment " + frag.get("name").as<std::string>() +
122 " does not have same numbers of md and weights. "
123 "If you want to leave a " +
124 mapatom_xml_["name"] +
125 " out, place a '0' instead");
126 }
127
128 FragInfo mapfragment;
129 std::vector<Index> mapatom_ids;
130
131 for (Index i = 0; i < Index(map_atoms.size()); i++) {
132 const std::string& map_string = map_atoms[i];
133 const std::string& md_string = md_atoms[i];
134 const double& weight = weights[i];
135 atom_id md_result = StringToMDIndex(md_string);
136 seginfo.mdatoms.push_back(md_result.first);
137
138 if (map_string == ":") {
139 continue;
140 }
141 atom_id map_result = StringToMapIndex(map_string);
142 mapatom_ids.push_back(map_result.first);
143 seginfo.mapatoms.push_back(map_result);
144 if (Atom::GetElementFromString(md_result.second) != map_result.second) {
146 << "WARNING: mdatom'" << md_result.second << "' and "
147 << mapatom_xml_["name"] << " '" << map_result.second
148 << "' do not have same element" << std::flush;
149 }
150 mapfragment.mapatom_ids.push_back(map_result);
151 mapfragment.weights.push_back(weight);
152 mapfragment.mdatom_ids.push_back(md_result);
153 }
154
155 std::vector<Index> frame =
156 tools::Tokenizer(getFrame(frag), " \t\n").ToVector<Index>();
157 if (frame.size() > 3) {
158 throw std::runtime_error(
159 "Local frame for segment " + seginfo.segname + " fragment " +
160 frag.get("name").as<std::string>() +
161 " has more than 3 atoms, please specify only up to three atoms");
162 } else if (frame.empty()) {
163 throw std::runtime_error("No local frame for segment " + seginfo.segname +
164 " fragment " + frag.get("name").as<std::string>() +
165 " specified");
166 }
167 for (Index atomid : frame) {
168 if (std::find(mapatom_ids.begin(), mapatom_ids.end(), atomid) ==
169 mapatom_ids.end()) {
170 throw std::runtime_error("Atom " + std::to_string(atomid) +
171 " in local frame cannot be found in " +
172 mapatom_xml_["atoms"] + ".");
173 }
174 }
175
176 mapfragment.map_local_frame = frame;
177 seginfo.fragments.push_back(mapfragment);
178}
179
180template <class AtomContainer>
181void SegmentMapper<AtomContainer>::LoadMappingFile(const std::string& mapfile) {
182 tools::Property topology_map;
183 topology_map.LoadFromXML(mapfile);
184
185 std::string molkey = "topology.molecules.molecule";
186 std::vector<tools::Property*> molecules = topology_map.Select(molkey);
187 std::string segkey = "segments.segment";
188 for (tools::Property* mol : molecules) {
189 std::vector<tools::Property*> segments = mol->Select(segkey);
190 for (tools::Property* seg : segments) {
191 Seginfo seginfo;
192
193 std::string coordfile_key = mapatom_xml_["coords"] + "_*";
194 std::vector<tools::Property*> files = seg->Select(coordfile_key);
195 for (tools::Property* file : files) {
196 seginfo.coordfiles[file->name()] = file->as<std::string>();
197 }
198 std::string segname = seg->get("name").as<std::string>();
199 seginfo.segname = segname;
200 std::string fragkey = "fragments.fragment";
201
202 seginfo.map2md = seg->get("map2md").as<bool>();
203
204 std::vector<tools::Property*> fragments = seg->Select(fragkey);
205 for (tools::Property* frag : fragments) {
206 ParseFragment(seginfo, *frag);
207 }
208
209 Index map_atom_min_id =
210 std::min_element(seginfo.mapatoms.begin(), seginfo.mapatoms.end(),
211 [](const atom_id& a, const atom_id& b) {
212 return a.first < b.first;
213 })
214 ->first;
215 if (map_atom_min_id != 0) {
216 throw std::runtime_error(
217 mapatom_xml_["atoms"] + " for segment " + seginfo.segname +
218 " do not start at zero index. Each segment "
219 "should have its own coordinate file. If you use an old ctp "
220 "mapping file run 'xtp_update_mapfile' on it.");
221 }
222
223 seginfo.minmax = CalcAtomIdRange(seginfo.mdatoms);
224 segment_info_[segname] = seginfo;
225 }
226 }
227}
228
229template <class AtomContainer>
231 const std::string& map_string) const {
232 tools::Tokenizer tok(map_string, ":");
233 std::vector<std::string> result = tok.ToVector();
234 if (result.size() != 2) {
235 throw std::runtime_error("Entry " + map_string +
236 " is not properly formatted.");
237 }
238 return std::pair<Index, std::string>(std::stoi(result[0]), result[1]);
239}
240template <class AtomContainer>
242 const std::string& md_string) const {
243 tools::Tokenizer tok(md_string, ":");
244 std::vector<std::string> result = tok.ToVector();
245 if (result.size() != 3) {
246 throw std::runtime_error("Entry " + md_string +
247 " is not properly formatted.");
248 }
249 Index atomid = 0;
250 try {
251 atomid = std::stoi(result[2]);
252 } catch (std::invalid_argument&) {
253 throw std::runtime_error("Atom entry " + md_string +
254 " is not well formatted");
255 }
256 return std::pair<Index, std::string>(atomid, result[1]);
257}
258
259template <class AtomContainer>
261 const std::vector<Index>& seg) const {
262 Index max_res_id = *std::max_element(seg.begin(), seg.end());
263 Index min_res_id = *std::min_element(seg.begin(), seg.end());
264 return std::pair<Index, Index>(min_res_id, max_res_id);
265}
266template <class AtomContainer>
268 const Segment& seg) const {
269 Index max_res_id = std::max_element(seg.begin(), seg.end(),
270 [](const Atom& a, const Atom& b) {
271 return a.getId() < b.getId();
272 })
273 ->getId();
274
275 Index min_res_id = std::min_element(seg.begin(), seg.end(),
276 [](const Atom& a, const Atom& b) {
277 return a.getId() < b.getId();
278 })
279 ->getId();
280 return std::pair<Index, Index>(min_res_id, max_res_id);
281}
282
283template <class AtomContainer>
285 const std::vector<mapAtom*>& fragment_mapatoms,
286 const std::vector<const Atom*>& fragment_mdatoms) const {
287 for (Index i = 0; i < Index(fragment_mapatoms.size()); i++) {
288 const Atom* a = fragment_mdatoms[i];
289 mapAtom* b = fragment_mapatoms[i];
290 b->setPos(a->getPos());
291 // No meaningful local frame/rotation exists in this case (that is
292 // exactly why this method, rather than MapMapAtomonMD, is being
293 // used at all) -- the identity is the natural, correct transform
294 // here, matching this method's own, existing, direct position
295 // copy (a->getPos(), no rotation applied to it either).
296 TransferExternalBondDirection(b, a, Eigen::Matrix3d::Identity());
297 }
298}
299
300template <class AtomContainer>
302 Index atomid, const std::vector<mapAtom*>& fragment_mapatoms) const {
303 Index i = 0;
304 for (; i < Index(fragment_mapatoms.size()); i++) {
305 if (fragment_mapatoms[i]->getId() == atomid) {
306 break;
307 }
308 }
309 return i;
310}
311template <class AtomContainer>
313 const FragInfo& frag, const std::vector<mapAtom*>& fragment_mapatoms,
314 const std::vector<const Atom*>& fragment_mdatoms) const {
315 std::vector<Eigen::Vector3d> local_map_frame;
316 std::vector<Eigen::Vector3d> local_md_frame;
317 for (Index id : frag.map_local_frame) {
318 Index i = FindVectorIndexFromAtomId(id, fragment_mapatoms);
319 local_map_frame.push_back(fragment_mapatoms[i]->getPos());
320 local_md_frame.push_back(fragment_mdatoms[i]->getPos());
321 }
322
323 Index symmetry = frag.map_local_frame.size();
324 Eigen::Vector3d map_com = CalcWeightedPos(frag.weights, fragment_mapatoms);
325 Eigen::Vector3d md_com = CalcWeightedPos(frag.weights, fragment_mdatoms);
326
327 Eigen::Vector3d shift_map2md = md_com - map_com;
328
329 Eigen::Matrix3d rot_map = Eigen::Matrix3d::Identity();
330 Eigen::Matrix3d rot_md = Eigen::Matrix3d::Identity();
331
332 // building local frame
333 if (symmetry > 1) {
334 // middle atom is the origin
335 Eigen::Vector3d x_map = local_map_frame[0] - local_map_frame[1];
336 Eigen::Vector3d x_md = local_md_frame[0] - local_md_frame[1];
337 Eigen::Vector3d y_map;
338 Eigen::Vector3d y_md;
339 Eigen::Vector3d z_map;
340 Eigen::Vector3d z_md;
341 if (symmetry == 3) {
342 y_map = local_map_frame[2] - local_map_frame[1];
343 y_md = local_md_frame[2] - local_md_frame[1];
344 z_map = x_map.cross(y_map);
345 z_md = x_md.cross(y_md);
346 y_map = z_map.cross(x_map);
347 y_md = z_md.cross(x_md);
348
349 } else {
350 Eigen::Vector3d unit = Eigen::Vector3d::UnitX();
351 if (std::abs(unit.dot(x_map) / x_map.norm()) < 1e-6) {
352 unit = Eigen::Vector3d::UnitY();
353 }
354 y_map = (x_map.cross(unit));
355 if (std::abs(unit.dot(x_md) / x_md.norm()) < 1e-6) {
356 unit = Eigen::Vector3d::UnitX();
357 }
358 y_md = (x_md.cross(unit));
359 z_map = x_map.cross(y_map);
360 z_md = x_md.cross(y_md);
361 }
362
363 if (x_map.squaredNorm() < 1e-18 || y_map.squaredNorm() < 1e-18 ||
364 z_map.squaredNorm() < 1e-18) {
365 throw std::runtime_error(
366 mapatom_xml_.at("tag") +
367 " basis vectors are very small, choose different local basis");
368 }
369 rot_map.col(0) = x_map.normalized();
370 rot_map.col(1) = y_map.normalized();
371 rot_map.col(2) = z_map.normalized();
372
373 if (x_md.squaredNorm() < 1e-18 || y_md.squaredNorm() < 1e-18 ||
374 z_md.squaredNorm() < 1e-18) {
375 throw std::runtime_error(
376 "MD basis vectors are very small, choose different local basis");
377 }
378 rot_md.col(0) = x_md.normalized();
379 rot_md.col(1) = y_md.normalized();
380 rot_md.col(2) = z_md.normalized();
381 }
382 Eigen::Matrix3d rotateMAP2MD = rot_md * rot_map.transpose();
383 for (Index i = 0; i < Index(fragment_mapatoms.size()); i++) {
384 mapAtom* atom = fragment_mapatoms[i];
385 if (getRank(*atom) > 0 && symmetry < 3) {
386 throw std::runtime_error(
387 "Local frame has less than 3 atoms, thus higher rank multipoles "
388 "cannot be mapped.");
389 }
390 atom->Translate(shift_map2md);
391 atom->Rotate(rotateMAP2MD, md_com);
392 // Direction is translation-invariant by construction (unlike an
393 // atom's own position), so only the rotation part of this
394 // fragment's own MD->QM-template transform applies here -- no
395 // shift_map2md/md_com involved at all, matching the same
396 // "rotate the difference only" principle Atom::Rotate/
397 // QMAtom::Rotate's own, existing implementation already uses for
398 // ordinary positions.
399 TransferExternalBondDirection(atom, fragment_mdatoms[i], rotateMAP2MD);
400 }
401}
402template <class AtomContainer>
404 QMState state) const {
405 if (segment_info_.count(seg.getType()) == 0) {
406 throw std::runtime_error(
407 "Could not find a Segment of name: " + seg.getType() + " in mapfile.");
408 }
409 Seginfo seginfo = segment_info_.at(seg.getType());
410 std::string coordsfiletag =
411 mapatom_xml_.at("coords") + "_" + state.Type().ToString();
412 if (seginfo.coordfiles.count(coordsfiletag) == 0) {
413 throw std::runtime_error("Could not find a coordinate file for " +
414 seg.getType() +
415 " id:" + std::to_string(seg.getId()) +
416 " segment/state: " + coordsfiletag);
417 }
418 std::string coordsfilename = seginfo.coordfiles.at(coordsfiletag);
419 return map(seg, coordsfilename);
420}
421
422template <class AtomContainer>
424 const Segment& seg, const std::string& coordfilename) const {
425
426 if (segment_info_.count(seg.getType()) == 0) {
427 throw std::runtime_error(
428 "Could not find a Segment of name: " + seg.getType() + " in mapfile.");
429 }
430 Seginfo seginfo = segment_info_.at(seg.getType());
431 if (Index(seginfo.mdatoms.size()) != seg.size()) {
432 throw std::runtime_error(
433 "Segment '" + seg.getType() +
434 "' does not contain the same number of atoms as mapping file: " +
435 std::to_string(seginfo.mdatoms.size()) + " vs. " +
436 std::to_string(seg.size()));
437 }
438
439 std::pair<Index, Index> minmax_map = seginfo.minmax;
440 std::pair<Index, Index> minmax = CalcAtomIdRange(seg);
441
442 if ((minmax_map.first - minmax_map.second) !=
443 (minmax.first - minmax.second)) {
444 throw std::runtime_error("AtomId range for segment " + seg.getType() + ":" +
445 std::to_string(seg.getId()) +
446 " and the mapping do not agree: Segment[" +
447 std::to_string(minmax.first) + "," +
448 std::to_string(minmax.second) + "] Map[" +
449 std::to_string(minmax_map.first) + "," +
450 std::to_string(minmax_map.second) + "]");
451 }
452
453 Index atomidoffset = minmax.first - minmax_map.first;
454
455 AtomContainer Result(seg.getType(), seg.getId());
456 Result.LoadFromFile(coordfilename);
457
458 // Real, direct fix -- worked through directly with the user, given
459 // this check's own earlier, exact equality requirement was
460 // genuinely too strict: only the number of atoms actually
461 // GENUINELY used later in this same function
462 // (Result[id.first], further below, for every real qmatoms index)
463 // needs to exist at all -- confirmed directly, by tracing every
464 // real use of Result throughout this same function, that
465 // correctness only ever genuinely requires each such index to be
466 // in range, not that every single atom in the coordinate file gets
467 // referenced by some qmatoms entry at all. A coordinate file with
468 // MORE atoms than are actually referenced is a real, legitimate use
469 // case (e.g. deliberately reusing the same, single template file
470 // across several, differently-truncated mappings of the same
471 // underlying fragment -- a real, direct case this exact check
472 // originally, wrongly rejected) -- only genuinely too FEW atoms in
473 // the file is a real, direct problem (a genuine, real
474 // out-of-bounds risk below).
475 if (Result.size() < Index(seginfo.mapatoms.size())) {
476 throw std::runtime_error(
477 mapatom_xml_.at("tag") + "Segment '" + seg.getType() +
478 "' does not contain enough atoms for the mapping file: needs at "
479 "least " +
480 std::to_string(seginfo.mapatoms.size()) + ", has " +
481 std::to_string(Result.size()));
482 }
483 // The real, actual safety guarantee needed -- every individual,
484 // real qmatoms index referenced by the mapping file must itself be
485 // in range, regardless of the file's own total atom count (the
486 // check above alone does not guarantee this on its own, e.g. if the
487 // mapping file's own qmatoms indices were not simply 0..N-1 at all
488 // for some reason).
489 for (const atom_id& id : seginfo.mapatoms) {
490 if (id.first < 0 || id.first >= Result.size()) {
491 throw std::runtime_error(
492 mapatom_xml_.at("tag") + "Segment '" + seg.getType() +
493 "' references " + mapatom_xml_.at("atoms") + " index " +
494 std::to_string(id.first) +
495 ", which is out of range for the coordinate file '" + coordfilename +
496 "' (" + std::to_string(Result.size()) + " atoms).");
497 }
498 }
499
500 // Built incrementally, below, across all of this segment's own
501 // fragments -- deliberately spans the WHOLE segment, not just one
502 // fragment at a time, since a bonded partner can genuinely be in a
503 // different fragment of the same segment (used only by
504 // TransferBondedPartners, in a second pass after the main loop
505 // below, once this is complete for the whole segment).
506 std::map<Index, mapAtom*> md_id_to_map_atom;
507
508 for (FragInfo& frag : seginfo.fragments) {
509 for (atom_id& id : frag.mdatom_ids) {
510 id.first += atomidoffset;
511 }
512
513 std::vector<mapAtom*> fragment_mapatoms;
514 for (const atom_id& id : frag.mapatom_ids) {
515 if (id.second != Result[id.first].getElement()) {
516 throw std::runtime_error(
517 "Element of mapping atom " + std::to_string(id.first) + ":" +
518 id.second + " does not agree with Element of parsed Atom " +
519 Result[id.first].getElement());
520 }
521 fragment_mapatoms.push_back(&Result[id.first]);
522 }
523 std::vector<const Atom*> fragment_mdatoms;
524 for (const atom_id& id : frag.mdatom_ids) {
525 const Atom* atom = seg.getAtom(id.first);
526 if (atom == nullptr) {
527 throw std::runtime_error(
528 "Could not find an atom with name:" + id.second + "id" +
529 std::to_string(id.first) + " in segment " + seg.getType());
530 }
531 fragment_mdatoms.push_back(atom);
532 }
533
534 for (Index i = 0; i < Index(fragment_mdatoms.size()); i++) {
535 md_id_to_map_atom[fragment_mdatoms[i]->getId()] = fragment_mapatoms[i];
536 }
537
538 if (seginfo.map2md) {
539 PlaceMapAtomonMD(fragment_mapatoms, fragment_mdatoms);
540 } else {
541 MapMapAtomonMD(frag, fragment_mapatoms, fragment_mdatoms);
542 }
543 }
544
545 // Second pass: now that md_id_to_map_atom is complete for the whole
546 // segment, translate each atom's own, raw, MD-level bonded-partner
547 // IDs into the corresponding QM-level ones. Deliberately a separate
548 // pass, after the main loop above, rather than done inline within
549 // it -- a bonded partner found while processing an earlier fragment
550 // might belong to a later fragment not yet added to the lookup at
551 // that point.
552 for (FragInfo& frag : seginfo.fragments) {
553 for (const atom_id& id : frag.mdatom_ids) {
554 const Atom* md_atom = seg.getAtom(id.first);
555 if (md_atom == nullptr) {
556 continue;
557 }
558 auto it = md_id_to_map_atom.find(id.first);
559 if (it != md_id_to_map_atom.end()) {
560 TransferBondedPartners(it->second, md_atom, md_id_to_map_atom);
561 }
562 }
563 }
564
565 // Real, direct fix for a real, direct mistake in the earlier
566 // relaxation of this function's own atom-count check (further
567 // above): that fix correctly confirmed every real qmatoms index is
568 // in range for Result[id.first] -- but missed that this function
569 // used to simply `return Result;` directly, the WHOLE loaded
570 // template file, not just the atoms actually referenced by
571 // seginfo.mapatoms. Before that check's own earlier, strict
572 // equality requirement was relaxed, this was harmless (equal
573 // counts implicitly meant "every atom is referenced" too) -- but
574 // once a coordinate file is legitimately allowed to have MORE
575 // atoms than are referenced (the whole point of that fix), simply
576 // returning Result directly leaks every genuinely unreferenced
577 // template atom straight into the final, real QMMolecule/
578 // StaticSegment/PolarSegment -- confirmed directly, this exact way,
579 // from the user's own real, direct mapchecker output: an extra,
580 // spurious H atom (single_thio.xyz's own 8th, deliberately
581 // unreferenced atom) showing up in the actual mapped
582 // "P3HTbackbone_1" segment, at exactly its own position.
583 //
584 // Fixed by building a real, separate, filtered AtomContainer
585 // containing only the atoms genuinely referenced by
586 // seginfo.mapatoms, in the SAME order the mapping file's own
587 // qmatoms entries actually appear in (matching mdatoms' own,
588 // already-established, canonical parallel order) -- but, critically
589 // (a real, direct, second mistake caught and fixed here, worked
590 // through directly with the user, in this same, real return-Result
591 // bug): NOT simply copying each atom's own, original id_ forward.
592 // The mapping file's own qmatoms entries are never required to be
593 // sequential OR contiguous at all -- reordering a fully-referenced
594 // set (e.g. 0:C 2:H 1:H 3:H, referencing every atom, just not in
595 // file order) is explicitly a real, intended, legitimate use of
596 // this same mapping mechanism, not merely the newer, adjacent
597 // "leave some atoms out" case. Simply copying id_ forward would
598 // silently give filtered[1] the atom whose own, original id was 2,
599 // not 1 -- breaking the getId()-matches-position invariant this
600 // whole codebase relies on elsewhere (e.g.
601 // IPodCoupling::EvalJob's own fragment-A/B classification, which
602 // compares atom.getId() directly against atom counts). Each copied
603 // atom's own id is therefore explicitly renumbered, via setID(), to
604 // match its own, real, new position within filtered -- not
605 // reconstructed from scratch, since that would be unsafe,
606 // generically, for StaticSite/PolarSite specifically (their own
607 // real ClassicalSegment::LoadFromFile, classicalsegment.cc,
608 // genuinely carries real multipole/rank data beyond plain
609 // element/position, which a from-scratch reconstruction would
610 // silently drop) -- setID() (added directly to StaticSite,
611 // staticsite.h, matching QMAtom's own, already-existing setID()
612 // naming exactly) preserves everything else about the atom exactly,
613 // mutating only its own id.
614 AtomContainer filtered(seg.getType(), seg.getId());
615 for (const atom_id& id : seginfo.mapatoms) {
616 mapAtom atom_copy = Result[id.first];
617 atom_copy.setID(filtered.size());
618 filtered.push_back(atom_copy);
619 }
620 filtered.calcPos();
621 return filtered;
622}
623
624template class SegmentMapper<QMMolecule>;
625template class SegmentMapper<StaticSegment>;
626template class SegmentMapper<PolarSegment>;
627
628} // namespace xtp
629} // namespace votca
information about an element
Definition elements.h:42
class to manage program options with xml serialization functionality
Definition property.h:55
Property & get(const std::string &key)
get existing property
Definition property.cc:79
bool exists(const std::string &key) const
check whether property exists
Definition property.cc:122
T as() const
return value as type
Definition property.h:283
std::vector< Property * > Select(const std::string &filter)
select property based on a filter
Definition property.cc:185
void LoadFromXML(std::string filename)
Definition property.cc:238
break string into words
Definition tokenizer.h:72
std::vector< T > ToVector()
store all words in a vector of type T, does type conversion.
Definition tokenizer.h:109
const std::string & getType() const
void push_back(const T &atom)
std::vector< T >::iterator end()
std::vector< T >::iterator begin()
static std::string GetElementFromString(const std::string &MDName)
Definition atom.cc:71
const Eigen::Vector3d & getPos() const
Definition atom.h:81
Logger is used for thread-safe output of messages.
Definition logger.h:164
std::string ToString() const
Definition qmstate.cc:35
Identifier for QMstates. Strings like S1 are converted into enum +zero indexed int.
Definition qmstate.h:135
const QMStateType & Type() const
Definition qmstate.h:154
QMState getQMState() const
Definition segid.h:63
std::string FileName() const
Definition segid.h:62
bool hasFile() const
Definition segid.h:61
std::pair< Index, std::string > atom_id
void LoadMappingFile(const std::string &mapfile)
std::map< std::string, Seginfo > segment_info_
void MapMapAtomonMD(const FragInfo &frag, const std::vector< mapAtom * > &fragment_mapatoms, const std::vector< const Atom * > &fragment_mdatoms) const
std::map< std::string, std::string > mapatom_xml_
void ParseFragment(Seginfo &seginfo, const tools::Property &frag)
std::pair< Index, Index > CalcAtomIdRange(const Segment &seg) const
atom_id StringToMapIndex(const std::string &map_string) const
atom_id StringToMDIndex(const std::string &md_string) const
Index getRank(const mapAtom &atom) const
void TransferExternalBondDirection(mapAtom *, const Atom *, const Eigen::Matrix3d &) const
void PlaceMapAtomonMD(const std::vector< mapAtom * > &fragment_mapatoms, const std::vector< const Atom * > &fragment_mdatoms) const
Index FindVectorIndexFromAtomId(Index atomid, const std::vector< mapAtom * > &fragment_mapatoms) const
Eigen::Vector3d CalcWeightedPos(const std::vector< double > &weights, const T &atoms) const
std::string getFrame(const tools::Property &frag) const
AtomContainer map(const Segment &seg, const SegId &segid) const
typename AtomContainer::Atom_Type mapAtom
std::vector< double > getWeights(const tools::Property &frag) const
void TransferBondedPartners(mapAtom *, const Atom *, const std::map< Index, mapAtom * > &) const
const Atom * getAtom(Index id) const
Definition segment.cc:32
#define XTP_LOG(level, log)
Definition logger.h:40
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
std::vector< Index > map_local_frame
std::vector< atom_id > mapatom_ids
std::vector< atom_id > mdatom_ids
std::pair< Index, Index > minmax
std::vector< FragInfo > fragments
std::map< std::string, std::string > coordfiles
std::vector< atom_id > mapatoms