29template <
class AtomContainer>
34template <
class AtomContainer>
36 const SegId& segid)
const {
38 std::string filename = segid.
FileName();
39 filename = std::regex_replace(filename, std::regex(
"\\$SEGID"),
40 std::to_string(seg.
getId()));
42 std::regex_replace(filename, std::regex(
"\\$SEGNAME"), seg.
getType());
43 return map(seg, filename);
46 return map(seg, state);
50template <
class AtomContainer>
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];
60 return map_pos = map_pos / map_weight;
63template <
class AtomContainer>
67 std::vector<double> weights;
68 if (frag.
exists(mapatom_xml_.at(
"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>>();
75 << frag.
get(
"name").
as<std::string>()
76 <<
" Using atomic masses" << std::flush;
78 frag.
get(mapatom_xml_.at(
"atoms")).template as<std::string>();
80 std::vector<std::string> atom_strings = tok_atoms.
ToVector();
82 for (
auto a_string : atom_strings) {
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 " +
90 double weight =
e.getMass(entries[1]);
92 weights.push_back(weight);
100template <
class AtomContainer>
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>>();
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"] +
114 "If you want to leave a qmatom out, place a ':' instead");
117 std::vector<double> weights = getWeights(frag);
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");
129 std::vector<Index> mapatom_ids;
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);
138 if (map_string ==
":") {
141 atom_id map_result = StringToMapIndex(map_string);
142 mapatom_ids.push_back(map_result.first);
143 seginfo.
mapatoms.push_back(map_result);
146 <<
"WARNING: mdatom'" << md_result.second <<
"' and "
147 << mapatom_xml_[
"name"] <<
" '" << map_result.second
148 <<
"' do not have same element" << std::flush;
151 mapfragment.
weights.push_back(weight);
155 std::vector<Index> frame =
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>() +
167 for (
Index atomid : frame) {
168 if (std::find(mapatom_ids.begin(), mapatom_ids.end(), atomid) ==
170 throw std::runtime_error(
"Atom " + std::to_string(atomid) +
171 " in local frame cannot be found in " +
172 mapatom_xml_[
"atoms"] +
".");
177 seginfo.
fragments.push_back(mapfragment);
180template <
class AtomContainer>
185 std::string molkey =
"topology.molecules.molecule";
186 std::vector<tools::Property*> molecules = topology_map.
Select(molkey);
187 std::string segkey =
"segments.segment";
189 std::vector<tools::Property*> segments = mol->Select(segkey);
193 std::string coordfile_key = mapatom_xml_[
"coords"] +
"_*";
194 std::vector<tools::Property*> files = seg->Select(coordfile_key);
196 seginfo.
coordfiles[file->name()] = file->as<std::string>();
198 std::string segname = seg->get(
"name").as<std::string>();
200 std::string fragkey =
"fragments.fragment";
202 seginfo.
map2md = seg->get(
"map2md").as<
bool>();
204 std::vector<tools::Property*> fragments = seg->Select(fragkey);
206 ParseFragment(seginfo, *frag);
209 Index map_atom_min_id =
212 return a.first < b.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.");
224 segment_info_[segname] = seginfo;
229template <
class AtomContainer>
231 const std::string& map_string)
const {
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.");
238 return std::pair<Index, std::string>(std::stoi(result[0]), result[1]);
240template <
class AtomContainer>
242 const std::string& md_string)
const {
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.");
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");
256 return std::pair<Index, std::string>(atomid, result[1]);
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);
266template <
class AtomContainer>
271 return a.getId() < b.getId();
277 return a.getId() < b.getId();
280 return std::pair<Index, Index>(min_res_id, max_res_id);
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];
294template <
class AtomContainer>
296 Index atomid,
const std::vector<mapAtom*>& fragment_mapatoms)
const {
298 for (; i <
Index(fragment_mapatoms.size()); i++) {
299 if (fragment_mapatoms[i]->getId() == atomid) {
305template <
class AtomContainer>
307 const FragInfo& frag,
const std::vector<mapAtom*>& fragment_mapatoms,
308 const std::vector<const Atom*>& fragment_mdatoms)
const {
309 std::vector<Eigen::Vector3d> local_map_frame;
310 std::vector<Eigen::Vector3d> local_md_frame;
312 Index i = FindVectorIndexFromAtomId(
id, fragment_mapatoms);
313 local_map_frame.push_back(fragment_mapatoms[i]->getPos());
314 local_md_frame.push_back(fragment_mdatoms[i]->getPos());
318 Eigen::Vector3d map_com = CalcWeightedPos(frag.
weights, fragment_mapatoms);
319 Eigen::Vector3d md_com = CalcWeightedPos(frag.
weights, fragment_mdatoms);
321 Eigen::Vector3d shift_map2md = md_com - map_com;
323 Eigen::Matrix3d rot_map = Eigen::Matrix3d::Identity();
324 Eigen::Matrix3d rot_md = Eigen::Matrix3d::Identity();
329 Eigen::Vector3d x_map = local_map_frame[0] - local_map_frame[1];
330 Eigen::Vector3d x_md = local_md_frame[0] - local_md_frame[1];
331 Eigen::Vector3d y_map;
332 Eigen::Vector3d y_md;
333 Eigen::Vector3d z_map;
334 Eigen::Vector3d z_md;
336 y_map = local_map_frame[2] - local_map_frame[1];
337 y_md = local_md_frame[2] - local_md_frame[1];
338 z_map = x_map.cross(y_map);
339 z_md = x_md.cross(y_md);
340 y_map = z_map.cross(x_map);
341 y_md = z_md.cross(x_md);
344 Eigen::Vector3d unit = Eigen::Vector3d::UnitX();
345 if (std::abs(unit.dot(x_map) / x_map.norm()) < 1
e-6) {
346 unit = Eigen::Vector3d::UnitY();
348 y_map = (x_map.cross(unit));
349 if (std::abs(unit.dot(x_md) / x_md.norm()) < 1
e-6) {
350 unit = Eigen::Vector3d::UnitX();
352 y_md = (x_md.cross(unit));
353 z_map = x_map.cross(y_map);
354 z_md = x_md.cross(y_md);
357 if (x_map.squaredNorm() < 1
e-18 || y_map.squaredNorm() < 1
e-18 ||
358 z_map.squaredNorm() < 1
e-18) {
359 throw std::runtime_error(
360 mapatom_xml_.at(
"tag") +
361 " basis vectors are very small, choose different local basis");
363 rot_map.col(0) = x_map.normalized();
364 rot_map.col(1) = y_map.normalized();
365 rot_map.col(2) = z_map.normalized();
367 if (x_md.squaredNorm() < 1
e-18 || y_md.squaredNorm() < 1
e-18 ||
368 z_md.squaredNorm() < 1
e-18) {
369 throw std::runtime_error(
370 "MD basis vectors are very small, choose different local basis");
372 rot_md.col(0) = x_md.normalized();
373 rot_md.col(1) = y_md.normalized();
374 rot_md.col(2) = z_md.normalized();
376 Eigen::Matrix3d rotateMAP2MD = rot_md * rot_map.transpose();
377 for (
mapAtom* atom : fragment_mapatoms) {
378 if (getRank(*atom) > 0 && symmetry < 3) {
379 throw std::runtime_error(
380 "Local frame has less than 3 atoms, thus higher rank multipoles "
381 "cannot be mapped.");
383 atom->Translate(shift_map2md);
384 atom->Rotate(rotateMAP2MD, md_com);
387template <
class AtomContainer>
390 if (segment_info_.count(seg.
getType()) == 0) {
391 throw std::runtime_error(
392 "Could not find a Segment of name: " + seg.
getType() +
" in mapfile.");
395 std::string coordsfiletag =
396 mapatom_xml_.at(
"coords") +
"_" + state.
Type().
ToString();
397 if (seginfo.
coordfiles.count(coordsfiletag) == 0) {
398 throw std::runtime_error(
"Could not find a coordinate file for " +
400 " id:" + std::to_string(seg.
getId()) +
401 " segment/state: " + coordsfiletag);
403 std::string coordsfilename = seginfo.
coordfiles.at(coordsfiletag);
404 return map(seg, coordsfilename);
407template <
class AtomContainer>
409 const Segment& seg,
const std::string& coordfilename)
const {
411 if (segment_info_.count(seg.
getType()) == 0) {
412 throw std::runtime_error(
413 "Could not find a Segment of name: " + seg.
getType() +
" in mapfile.");
417 throw std::runtime_error(
419 "' does not contain the same number of atoms as mapping file: " +
420 std::to_string(seginfo.
mdatoms.size()) +
" vs. " +
421 std::to_string(seg.
size()));
424 std::pair<Index, Index> minmax_map = seginfo.
minmax;
425 std::pair<Index, Index> minmax = CalcAtomIdRange(seg);
427 if ((minmax_map.first - minmax_map.second) !=
428 (minmax.first - minmax.second)) {
429 throw std::runtime_error(
"AtomId range for segment " + seg.
getType() +
":" +
430 std::to_string(seg.
getId()) +
431 " and the mapping do not agree: Segment[" +
432 std::to_string(minmax.first) +
"," +
433 std::to_string(minmax.second) +
"] Map[" +
434 std::to_string(minmax_map.first) +
"," +
435 std::to_string(minmax_map.second) +
"]");
438 Index atomidoffset = minmax.first - minmax_map.first;
441 Result.LoadFromFile(coordfilename);
444 throw std::runtime_error(
445 mapatom_xml_.at(
"tag") +
"Segment '" + seg.
getType() +
446 "' does not contain the same number of atoms as mapping file: " +
447 std::to_string(seginfo.
mapatoms.size()) +
" vs. " +
448 std::to_string(Result.
size()));
453 id.first += atomidoffset;
456 std::vector<mapAtom*> fragment_mapatoms;
458 if (
id.second != Result[
id.first].getElement()) {
459 throw std::runtime_error(
460 "Element of mapping atom " + std::to_string(
id.first) +
":" +
461 id.second +
" does not agree with Element of parsed Atom " +
462 Result[
id.first].getElement());
464 fragment_mapatoms.push_back(&Result[
id.first]);
466 std::vector<const Atom*> fragment_mdatoms;
469 if (atom ==
nullptr) {
470 throw std::runtime_error(
471 "Could not find an atom with name:" +
id.second +
"id" +
472 std::to_string(
id.first) +
" in segment " + seg.
getType());
474 fragment_mdatoms.push_back(atom);
478 PlaceMapAtomonMD(fragment_mapatoms, fragment_mdatoms);
480 MapMapAtomonMD(frag, fragment_mapatoms, fragment_mdatoms);
const std::string & getType() const
std::vector< T >::iterator end()
std::vector< T >::iterator begin()
static std::string GetElementFromString(const std::string &MDName)
const Eigen::Vector3d & getPos() const
Logger is used for thread-safe output of messages.
std::string ToString() const
Identifier for QMstates. Strings like S1 are converted into enum +zero indexed int.
const QMStateType & Type() const
QMState getQMState() const
std::string FileName() const
std::pair< Index, std::string > atom_id
void LoadMappingFile(const std::string &mapfile)
void MapMapAtomonMD(const FragInfo &frag, const std::vector< mapAtom * > &fragment_mapatoms, const std::vector< const Atom * > &fragment_mdatoms) const
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
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
SegmentMapper(Logger &log)
AtomContainer map(const Segment &seg, const SegId &segid) const
typename AtomContainer::Atom_Type mapAtom
std::vector< double > getWeights(const tools::Property &frag) const
const Atom * getAtom(Index id) const
#define XTP_LOG(level, log)
base class for all analysis tools
std::vector< Index > map_local_frame
std::vector< atom_id > mapatom_ids
std::vector< double > weights
std::vector< atom_id > mdatom_ids
std::vector< Index > mdatoms
std::pair< Index, Index > minmax
std::vector< FragInfo > fragments
std::map< std::string, std::string > coordfiles
std::vector< atom_id > mapatoms