Loading...
Searching...
No Matches
MobileAtoms.cpp
Go to the documentation of this file.
1/*
2** This file is part of eOn.
3**
4** SPDX-License-Identifier: BSD-3-Clause
5**
6** Copyright (c) 2010--present, eOn Development Team
7** All rights reserved.
8**
9** Repo:
10** https://github.com/TheochemUI/eOn
11*/
12#include "eon/MobileAtoms.h"
13
14#include <cctype>
15#include <string>
16#include <unordered_set>
17#include <vector>
18
19namespace eonc {
20
21bool atomListMeansAll(const std::string &atomList) {
22 if (atomList.empty()) {
23 return true;
24 }
25 // Trim and case-fold "all"
26 size_t b = 0;
27 while (b < atomList.size() &&
28 std::isspace(static_cast<unsigned char>(atomList[b]))) {
29 ++b;
30 }
31 size_t e = atomList.size();
32 while (e > b && std::isspace(static_cast<unsigned char>(atomList[e - 1]))) {
33 --e;
34 }
35 if (e <= b) {
36 return true;
37 }
38 if (e - b != 3) {
39 return false;
40 }
41 auto lower = [](char c) {
42 return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
43 };
44 return lower(atomList[b]) == 'a' && lower(atomList[b + 1]) == 'l' &&
45 lower(atomList[b + 2]) == 'l';
46}
47
48VectorXi freeAtomIndices(const Matter *matter) {
49 const long n = matter->numberOfAtoms();
50 std::vector<int> free;
51 free.reserve(static_cast<size_t>(matter->numberOfFreeAtoms()));
52 for (long i = 0; i < n; ++i) {
53 if (!matter->getFixed(i)) {
54 free.push_back(static_cast<int>(i));
55 }
56 }
57 VectorXi out(static_cast<Eigen::Index>(free.size()));
58 for (Eigen::Index k = 0; k < out.size(); ++k) {
59 out(k) = free[static_cast<size_t>(k)];
60 }
61 return out;
62}
63
64VectorXi resolveMobileAtoms(const Matter *matter, const std::string &atomList) {
65 if (atomListMeansAll(atomList)) {
66 return freeAtomIndices(matter);
67 }
68 const long n = matter->numberOfAtoms();
69 std::vector<int> mobile;
70 std::unordered_set<int> seen;
71 std::string token;
72 for (size_t p = 0; p <= atomList.size(); ++p) {
73 const char c = (p < atomList.size()) ? atomList[p] : ',';
74 if (c == ',' || c == ' ' || c == '\t' || p == atomList.size()) {
75 if (!token.empty()) {
76 try {
77 const long idx = std::stol(token);
78 if (idx >= 0 && idx < n && !matter->getFixed(idx) &&
79 seen.insert(static_cast<int>(idx)).second) {
80 mobile.push_back(static_cast<int>(idx));
81 }
82 } catch (const std::exception &) {
83 // skip non-integer tokens
84 }
85 token.clear();
86 }
87 } else {
88 token.push_back(c);
89 }
90 }
91 VectorXi out(static_cast<Eigen::Index>(mobile.size()));
92 for (Eigen::Index k = 0; k < out.size(); ++k) {
93 out(k) = mobile[static_cast<size_t>(k)];
94 }
95 return out;
96}
97
98VectorXi resolveMobileAtoms(const Matter *matter, const VectorXi &candidates) {
99 const long n = matter->numberOfAtoms();
100 std::vector<int> mobile;
101 std::unordered_set<int> seen;
102 mobile.reserve(static_cast<size_t>(candidates.size()));
103 for (Eigen::Index k = 0; k < candidates.size(); ++k) {
104 const long idx = candidates(k);
105 if (idx >= 0 && idx < n && !matter->getFixed(idx) &&
106 seen.insert(static_cast<int>(idx)).second) {
107 mobile.push_back(static_cast<int>(idx));
108 }
109 }
110 VectorXi out(static_cast<Eigen::Index>(mobile.size()));
111 for (Eigen::Index k = 0; k < out.size(); ++k) {
112 out(k) = mobile[static_cast<size_t>(k)];
113 }
114 return out;
115}
116
117VectorXd packMobileRows(const AtomMatrix &full, const VectorXi &mobile) {
118 VectorXd packed(3 * mobile.size());
119 for (Eigen::Index a = 0; a < mobile.size(); ++a) {
120 packed.segment<3>(3 * a) = full.row(mobile(a));
121 }
122 return packed;
123}
124
125void unpackMobileRows(const VectorXd &packed, const VectorXi &mobile,
126 AtomMatrix &full) {
127 for (Eigen::Index a = 0; a < mobile.size(); ++a) {
128 full.row(mobile(a)) = packed.segment<3>(3 * a);
129 }
130}
131
132VectorXd mobileForces(Matter *matter, const VectorXi &mobile) {
133 const AtomMatrix forces = matter->getForces();
134 return packMobileRows(forces, mobile);
135}
136
137} // namespace eonc
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
const AtomMatrix & getForces() const
Definition Matter.cpp:324
long int numberOfAtoms() const
Definition Matter.cpp:209
long int numberOfFreeAtoms() const
Definition Matter.cpp:475
int getFixed(long int atom) const
1 if every Cartesian axis of the atom is fixed, else 0.
Definition Matter.cpp:402
RAII resource manager for the ARTn C library with global synchronization.
bool atomListMeansAll(const std::string &atomList)
Whether atomList means "every free atom" (empty, "all", case-insensitive).
VectorXi resolveMobileAtoms(const Matter *matter, const std::string &atomList)
PHVA-class mobile set for FD Hessian and matrix-free Krylov (Lanczos / Davidson).
void unpackMobileRows(const VectorXd &packed, const VectorXi &mobile, AtomMatrix &full)
Write a 3*n_mobile vector into full AtomMatrix rows (other rows unchanged).
VectorXi freeAtomIndices(const Matter *matter)
Free (unfixed) atom indices in ascending order.
VectorXd packMobileRows(const AtomMatrix &full, const VectorXi &mobile)
Pack full (n_atoms,3) rows of mobile atoms into a 3*n_mobile vector.
VectorXd mobileForces(Matter *matter, const VectorXi &mobile)
Force components on mobile atoms after Matter has a valid force cache (calls getForces under the hood...