Loading...
Searching...
No Matches
eonc::geometry Namespace Reference

Classes

struct  atom
struct  by_atom

Functions

RotationMatrix rotationExtract (const AtomMatrix r1, const AtomMatrix r2)
bool rotationMatch (const Matter &m1, const Matter &m2, const double max_diff)
void projectOutRotTrans (Eigen::VectorXd &step, const AtomMatrix &positions)
void rotationRemove (const AtomMatrix r1, std::shared_ptr< Matter > m2)
void rotationRemove (const std::shared_ptr< Matter > m1, std::shared_ptr< Matter > m2)
void translationRemove (Matter &m1, const AtomMatrix r1)
void translationRemove (Matter &m1, const Matter &m2)
double maxAtomMotion (const AtomMatrix v1)
double maxAtomMotionV (const VectorXd v1)
long numAtomsMoved (const AtomMatrix v1, double cutoff)
AtomMatrix maxAtomMotionApplied (const AtomMatrix v1, double maxMotion)
VectorXd maxAtomMotionAppliedV (const VectorXd v1, double maxMotion)
AtomMatrix maxMotionApplied (const AtomMatrix v1, double maxMotion)
VectorXd maxMotionAppliedV (const VectorXd v1, double maxMotion)
bool identical (const Matter &m1, const Matter &m2, const double distanceDifference)
bool sortedR (const Matter &m1, const Matter &m2, const double distanceDifference)
void pushApart (std::shared_ptr< Matter > m1, double minDistance)

Function Documentation

◆ identical()

bool eonc::geometry::identical ( const Matter & m1,
const Matter & m2,
const double distanceDifference )

Definition at line 369 of file GeometryAnalysis.cpp.

370 {
371
372 AtomMatrix r1 = m1.getPositions();
373 AtomMatrix r2 = m2.getPositions();
374
375 std::set<int> matched;
376 double tolerance = distanceDifference;
377
378 if (r1.rows() != r2.rows()) {
379 return false;
380 }
381 int N = r1.rows();
382
383 for (int i = 0; i < N; i++) {
384 if (std::fabs((m1.pbc(r1.row(i) - r2.row(i))).norm()) < tolerance &&
385 m1.getAtomicNr(i) == m2.getAtomicNr(i)) {
386 matched.insert(i);
387 }
388 }
389
390 for (int j = 0; j < N; j++) {
391
392 if (matched.count(j) == 1)
393 continue;
394
395 for (int k = 0; k < N; k++) {
396 if (matched.count(j) == 1)
397 break;
398
399 if (std::fabs((m1.pbc(r1.row(j) - r2.row(k))).norm()) < tolerance &&
400 m1.getAtomicNr(j) == m2.getAtomicNr(k)) {
401 matched.insert(j);
402 }
403 }
404 }
405
406 if (matched.size() == static_cast<unsigned>(N)) {
407 return true;
408 } else {
409 return false;
410 }
411}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
AtomMatrix pbc(const AtomMatrix &diff) const
Definition Matter.h:163
long getAtomicNr(long int atom) const
Definition Matter.cpp:392
const AtomMatrix & getPositions() const
Definition Matter.cpp:236

◆ maxAtomMotion()

double eonc::geometry::maxAtomMotion ( const AtomMatrix v1)

Definition at line 269 of file GeometryAnalysis.cpp.

269 {
270 return v1.rowwise().norm().maxCoeff();
271}

◆ maxAtomMotionApplied()

AtomMatrix eonc::geometry::maxAtomMotionApplied ( const AtomMatrix v1,
double maxMotion )

Definition at line 308 of file GeometryAnalysis.cpp.

309 {
310 AtomMatrix v2(v1);
311
312 double max = maxAtomMotion(v1);
313 if (max > maxMotion) {
314 v2 *= maxMotion / max;
315 }
316 return v2;
317}
double maxAtomMotion(const AtomMatrix v1)

◆ maxAtomMotionAppliedV()

VectorXd eonc::geometry::maxAtomMotionAppliedV ( const VectorXd v1,
double maxMotion )

Definition at line 319 of file GeometryAnalysis.cpp.

320 {
321 VectorXd v2(v1);
322
323 double max = maxAtomMotionV(v1);
324 if (max > maxMotion) {
325 v2 *= maxMotion / max;
326 }
327 return v2;
328}
double maxAtomMotionV(const VectorXd v1)

◆ maxAtomMotionV()

double eonc::geometry::maxAtomMotionV ( const VectorXd v1)

Definition at line 273 of file GeometryAnalysis.cpp.

273 {
274 double max = 0.0;
275 long n = v1.rows();
276 if (n < 3) {
277 // Vector too short for 3D atom grouping; treat as single displacement
278 return v1.norm();
279 }
280 for (long i = 0; i + 3 <= n; i += 3) {
281 double norm = v1.segment<3>(i).norm();
282 if (max < norm) {
283 max = norm;
284 }
285 }
286 // Handle trailing elements (vector size not multiple of 3)
287 long rem = n % 3;
288 if (rem > 0) {
289 double norm = v1.tail(rem).norm();
290 if (max < norm) {
291 max = norm;
292 }
293 }
294 return max;
295}

◆ maxMotionApplied()

AtomMatrix eonc::geometry::maxMotionApplied ( const AtomMatrix v1,
double maxMotion )

Definition at line 330 of file GeometryAnalysis.cpp.

331 {
332 AtomMatrix v2(v1);
333
334 double max = v1.norm();
335 if (max > maxMotion) {
336 v2 *= maxMotion / max;
337 }
338 return v2;
339}

◆ maxMotionAppliedV()

VectorXd eonc::geometry::maxMotionAppliedV ( const VectorXd v1,
double maxMotion )

Definition at line 341 of file GeometryAnalysis.cpp.

342 {
343 VectorXd v2(v1);
344
345 double max = v1.norm();
346 if (max > maxMotion) {
347 v2 *= maxMotion / max;
348 }
349 return v2;
350}

◆ numAtomsMoved()

long eonc::geometry::numAtomsMoved ( const AtomMatrix v1,
double cutoff )

Definition at line 297 of file GeometryAnalysis.cpp.

297 {
298 long num = 0;
299 for (int i = 0; i < v1.rows(); i++) {
300 double norm = v1.row(i).norm();
301 if (norm >= cutoff) {
302 num += 1;
303 }
304 }
305 return num;
306}

◆ projectOutRotTrans()

void eonc::geometry::projectOutRotTrans ( Eigen::VectorXd & step,
const AtomMatrix & positions )

Definition at line 132 of file GeometryAnalysis.cpp.

133 {
134 long nAtoms = positions.rows();
135 long dof = nAtoms * 3;
136
137 // 1. Compute center of mass (unweighted geometric center)
138 Eigen::Vector3d com = Eigen::Vector3d::Zero();
139 for (long i = 0; i < nAtoms; ++i) {
140 com(0) += positions(i, 0);
141 com(1) += positions(i, 1);
142 com(2) += positions(i, 2);
143 }
144 com /= static_cast<double>(nAtoms);
145
146 // 2. Construct 6 basis vectors for rigid-body translation and rotation
147 std::vector<Eigen::VectorXd> basis;
148 basis.reserve(6);
149
150 // Translational basis vectors
151 for (int d = 0; d < 3; ++d) {
152 Eigen::VectorXd t = Eigen::VectorXd::Zero(dof);
153 for (long j = 0; j < nAtoms; ++j) {
154 t(3 * j + d) = 1.0;
155 }
156 basis.push_back(t);
157 }
158
159 // Rotational basis vectors (infinitesimal rotations around COM)
160 Eigen::VectorXd rx = Eigen::VectorXd::Zero(dof);
161 Eigen::VectorXd ry = Eigen::VectorXd::Zero(dof);
162 Eigen::VectorXd rz = Eigen::VectorXd::Zero(dof);
163
164 for (long i = 0; i < nAtoms; ++i) {
165 double x = positions(i, 0) - com(0);
166 double y = positions(i, 1) - com(1);
167 double z = positions(i, 2) - com(2);
168 // Rotation around x-axis: cross(xhat, r) = (0, -z, y)
169 rx(3 * i + 1) = -z;
170 rx(3 * i + 2) = y;
171 // Rotation around y-axis: cross(yhat, r) = (z, 0, -x)
172 ry(3 * i + 0) = z;
173 ry(3 * i + 2) = -x;
174 // Rotation around z-axis: cross(zhat, r) = (-y, x, 0)
175 rz(3 * i + 0) = -y;
176 rz(3 * i + 1) = x;
177 }
178 basis.push_back(rx);
179 basis.push_back(ry);
180 basis.push_back(rz);
181
182 // 3. Modified Gram-Schmidt orthonormalization
183 std::vector<Eigen::VectorXd> ortho;
184 ortho.reserve(6);
185
186 for (auto &v : basis) {
187 Eigen::VectorXd u = v;
188 for (const auto &e : ortho) {
189 u -= u.dot(e) * e;
190 }
191 // Handles linear molecules where one rotational mode is degenerate
192 if (u.norm() > 1e-9) {
193 u.normalize();
194 ortho.push_back(u);
195 }
196 }
197
198 // 4. Project out rigid-body components from step
199 for (const auto &e : ortho) {
200 step -= step.dot(e) * e;
201 }
202}

◆ pushApart()

void eonc::geometry::pushApart ( std::shared_ptr< Matter > m1,
double minDistance )

Definition at line 485 of file GeometryAnalysis.cpp.

485 {
486 if (minDistance <= 0)
487 return;
488
489 AtomMatrix r1 = m1->getPositions();
490 AtomMatrix Force(r1.rows(), 3);
491 double f = 0.025;
492 double cut = minDistance;
493 double pushAparts = 500;
494 for (int p = 0; p < r1.rows(); p++) {
495 for (int axis = 0; axis <= 2; axis++) {
496 Force(p, axis) = 0;
497 }
498 }
499 for (int count = 0; count < pushAparts; count++) {
500 int moved = 0;
501 for (int i = 0; i < r1.rows(); i++) {
502 for (int j = i + 1; j < r1.rows(); j++) {
503 double d = m1->distance(i, j);
504 if (d < cut) {
505 moved++;
506 for (int axis = 0; axis <= 2; axis++) {
507 double componant = f * (r1(i, axis) - r1(j, axis)) / d;
508 Force(i, axis) += componant;
509 Force(j, axis) -= componant;
510 }
511 }
512 }
513 }
514 if (moved == 0)
515 break;
516 for (int k = 0; k < r1.rows(); k++) {
517 for (int axis = 0; axis <= 2; axis++) {
518 r1(k, axis) += Force(k, axis);
519 Force(k, axis) = 0;
520 }
521 }
522 m1->setPositions(r1);
523 }
524}

◆ rotationExtract()

RotationMatrix eonc::geometry::rotationExtract ( const AtomMatrix r1,
const AtomMatrix r2 )

Definition at line 21 of file GeometryAnalysis.cpp.

22 {
24
25 // Determine optimal rotation
26 // Horn, J. Opt. Soc. Am. A, 1987
27 Matrix3d m = r1.transpose() * r2;
28
29 double sxx = m(0, 0);
30 double sxy = m(0, 1);
31 double sxz = m(0, 2);
32 double syx = m(1, 0);
33 double syy = m(1, 1);
34 double syz = m(1, 2);
35 double szx = m(2, 0);
36 double szy = m(2, 1);
37 double szz = m(2, 2);
38
39 Matrix4d n;
40 n.setZero();
41 n(0, 1) = syz - szy;
42 n(0, 2) = szx - sxz;
43 n(0, 3) = sxy - syx;
44
45 n(1, 2) = sxy + syx;
46 n(1, 3) = szx + sxz;
47
48 n(2, 3) = syz + szy;
49
50 n += n.transpose().eval();
51
52 n(0, 0) = sxx + syy + szz;
53 n(1, 1) = sxx - syy - szz;
54 n(2, 2) = -sxx + syy - szz;
55 n(3, 3) = -sxx - syy + szz;
56
57 Eigen::SelfAdjointEigenSolver<Matrix4d> es(n);
58 Eigen::Vector4d maxv = es.eigenvectors().col(3);
59
60 double aa = maxv[0] * maxv[0];
61 double bb = maxv[1] * maxv[1];
62 double cc = maxv[2] * maxv[2];
63 double dd = maxv[3] * maxv[3];
64 double ab = maxv[0] * maxv[1];
65 double ac = maxv[0] * maxv[2];
66 double ad = maxv[0] * maxv[3];
67 double bc = maxv[1] * maxv[2];
68 double bd = maxv[1] * maxv[3];
69 double cd = maxv[2] * maxv[3];
70
71 R(0, 0) = aa + bb - cc - dd;
72 R(0, 1) = 2 * (bc - ad);
73 R(0, 2) = 2 * (bd + ac);
74 R(1, 0) = 2 * (bc + ad);
75 R(1, 1) = aa - bb + cc - dd;
76 R(1, 2) = 2 * (cd - ab);
77 R(2, 0) = 2 * (bd - ac);
78 R(2, 1) = 2 * (cd + ab);
79 R(2, 2) = aa - bb - cc + dd;
80
81 return R;
82}
Eigen::Matrix< double, 3, 3, eOnStorageOrder > RotationMatrix
Definition Eigen.h:38
Eigen::Matrix< double, 3, 3, eOnStorageOrder > Matrix3d
Definition Eigen.h:35
Eigen::Matrix< double, 4, 4, eOnStorageOrder > Matrix4d
Definition Eigen.h:36

◆ rotationMatch()

bool eonc::geometry::rotationMatch ( const Matter & m1,
const Matter & m2,
const double max_diff )

Definition at line 84 of file GeometryAnalysis.cpp.

85 {
86 AtomMatrix r1 = m1.getPositions();
87 AtomMatrix r2 = m2.getPositions();
88
89 // Align centroids
90 Eigen::VectorXd c1(3);
91 Eigen::VectorXd c2(3);
92
93 c1[0] = r1.col(0).sum();
94 c1[1] = r1.col(1).sum();
95 c1[2] = r1.col(2).sum();
96 c2[0] = r2.col(0).sum();
97 c2[1] = r2.col(1).sum();
98 c2[2] = r2.col(2).sum();
99 c1 /= r1.rows();
100 c2 /= r2.rows();
101
102 for (int i = 0; i < r1.rows(); i++) {
103 r1(i, 0) -= c1[0];
104 r1(i, 1) -= c1[1];
105 r1(i, 2) -= c1[2];
106
107 r2(i, 0) -= c2[0];
108 r2(i, 1) -= c2[1];
109 r2(i, 2) -= c2[2];
110 }
111
113
114 // Eigen is transposed relative to numpy
115 r2 = r2 * R;
116
117 for (int i = 0; i < r1.rows(); i++) {
118 double diff = (r2.row(i) - r1.row(i)).norm();
119 if (diff > max_diff) {
120 return false;
121 }
122 }
123 return true;
124}
RotationMatrix rotationExtract(const AtomMatrix r1, const AtomMatrix r2)

◆ rotationRemove() [1/2]

void eonc::geometry::rotationRemove ( const AtomMatrix r1,
std::shared_ptr< Matter > m2 )

Definition at line 204 of file GeometryAnalysis.cpp.

205 {
206 // Skip for extended systems (slabs/surfaces with frozen atoms).
207 // Rigid-body rotation and translation are not well-defined when the
208 // system is anchored by frozen atoms.
209 if (m2->numberOfFixedAtoms() > 0) {
210 return;
211 }
212
213 AtomMatrix r2 = m2->getPositions();
214 long n = r1_passed.size();
215
216 // Compute displacement as flat 3N vector
217 Eigen::VectorXd step(n);
218 Eigen::Map<const Eigen::VectorXd> r1_flat(r1_passed.data(), n);
219 Eigen::Map<const Eigen::VectorXd> r2_flat(r2.data(), n);
220 step = r2_flat - r1_flat;
221
222 // Project out rigid-body translation and rotation
223 projectOutRotTrans(step, r1_passed);
224
225 // Reconstruct positions: r1 + projected step
226 Eigen::VectorXd result = r1_flat + step;
227 AtomMatrix resultMat(r1_passed.rows(), 3);
228 Eigen::Map<Eigen::VectorXd>(resultMat.data(), n) = result;
229
230 m2->setPositions(resultMat);
231}
void projectOutRotTrans(Eigen::VectorXd &step, const AtomMatrix &positions)

◆ rotationRemove() [2/2]

void eonc::geometry::rotationRemove ( const std::shared_ptr< Matter > m1,
std::shared_ptr< Matter > m2 )

Definition at line 233 of file GeometryAnalysis.cpp.

234 {
235 AtomMatrix r1 = m1->getPositions();
236 rotationRemove(r1, m2);
237 return;
238}
void rotationRemove(const AtomMatrix r1, std::shared_ptr< Matter > m2)

◆ sortedR()

bool eonc::geometry::sortedR ( const Matter & m1,
const Matter & m2,
const double distanceDifference )

Definition at line 413 of file GeometryAnalysis.cpp.

414 {
415 EONC_LOG_INFO("In sortedR");
416 AtomMatrix r1 = m1.getPositions();
417 AtomMatrix r2 = m2.getPositions();
418 double tolerance = distanceDifference;
419 int matches = 0;
420
421 if (r1.rows() != r2.rows()) {
422 return false;
423 }
424
425 // Allocate memory for rdf1 and rdf2
426 std::vector<std::set<atom, by_atom>> rdf1(r1.rows());
427 std::vector<std::set<atom, by_atom>> rdf2(r2.rows());
428
429 for (int i2 = 0; i2 < r2.rows(); i2++) {
430 rdf2[i2].clear();
431 for (int j2 = 0; j2 < r2.rows(); j2++) {
432 if (j2 == i2)
433 continue;
434 atom a2;
435 a2.r = m2.distance(i2, j2);
436 a2.z = m2.getAtomicNr(j2);
437 rdf2[i2].insert(a2);
438 rdf2[j2].insert(a2);
439 }
440 }
441
442 for (int i1 = 0; i1 < r1.rows(); i1++) {
443 if (matches == i1 - 2) {
444 return false;
445 }
446 for (int j1 = 0; j1 < r1.rows(); j1++) {
447 if (j1 == i1)
448 continue;
449 atom a;
450 a.r = m1.distance(i1, j1);
451 a.z = m1.getAtomicNr(j1);
452 rdf1[i1].insert(a);
453 rdf1[j1].insert(a);
454 }
455 for (int x = 0; x < r2.rows(); x++) {
456 auto it2 = rdf2[x].begin();
457 auto it = rdf1[i1].begin();
458 int c = 0;
459 int counter = 0;
460 for (; c < r1.rows(); c++) {
461 if (it == rdf1[i1].end() || it2 == rdf2[x].end())
462 break;
463 atom k1 = *it;
464 atom k2 = *it2;
465 if (std::fabs(k1.r - k2.r) < tolerance && k1.z == k2.z) {
466 counter++;
467 } else {
468 EONC_LOG_INFO("No match");
469 break;
470 }
471 ++it;
472 ++it2;
473 }
474 if (counter == r1.rows()) {
475 matches++;
476 } else {
477 EONC_LOG_INFO("No match");
478 }
479 }
480 }
481
482 return matches >= r1.rows();
483}
#define EONC_LOG_INFO(...)
Definition EonLogger.h:250
double distance(long index1, long index2) const
Definition Matter.cpp:360

◆ translationRemove() [1/2]

void eonc::geometry::translationRemove ( Matter & m1,
const AtomMatrix r1 )

Definition at line 240 of file GeometryAnalysis.cpp.

240 {
241 AtomMatrix r1 = m1.getPositions();
242 AtomMatrix r2 = r2_passed;
243
244 // net displacement
245 Eigen::VectorXd disp(3);
246 AtomMatrix r12 = m1.pbc(r2 - r1);
247
248 disp[0] = r12.col(0).sum();
249 disp[1] = r12.col(1).sum();
250 disp[2] = r12.col(2).sum();
251 disp /= r1.rows();
252
253 for (int i = 0; i < r1.rows(); i++) {
254 r1(i, 0) += disp[0];
255 r1(i, 1) += disp[1];
256 r1(i, 2) += disp[2];
257 }
258
259 m1.setPositions(r1);
260 return;
261}
void setPositions(const AtomMatrix &pos)
Definition Matter.cpp:273

◆ translationRemove() [2/2]

void eonc::geometry::translationRemove ( Matter & m1,
const Matter & m2 )

Definition at line 263 of file GeometryAnalysis.cpp.

263 {
264 AtomMatrix r2 = m2.getPositions();
265 translationRemove(m1, r2);
266 return;
267}
void translationRemove(Matter &m1, const AtomMatrix r1)