eOn 3.2.0
Long-timescale dynamics: aKMC, NEB, parallel replica
☾
Toggle main menu visibility
Loading...
Searching...
No Matches
IDPPObjectiveFunction.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
13
#include "
eon/IDPPObjectiveFunction.hpp
"
14
15
#include <algorithm>
16
#include <cmath>
17
18
namespace
eonc
{
19
20
namespace
{
21
VectorXd packFree(
const
Matter
&m,
const
AtomMatrix
&forces) {
22
const
long
nfree = m.numberOfFreeAtoms();
23
AtomMatrix
freeF(nfree, 3);
24
long
k = 0;
25
for
(
long
i = 0; i < m.numberOfAtoms(); ++i) {
26
if
(!m.getFixed(i)) {
27
freeF.row(k++) = forces.row(i);
28
}
29
}
30
return
VectorXd(VectorXd::Map(freeF.data(), 3 * nfree));
31
}
32
}
// namespace
33
34
double
IDPPObjectiveFunction::getEnergy
() {
35
double
energy = 0.0;
36
int
natoms =
matter
->numberOfAtoms();
37
AtomMatrix
pos =
matter
->getPositions();
38
39
// Loop over unique pairs
40
for
(
int
i = 0; i < natoms; ++i) {
41
for
(
int
j = i + 1; j < natoms; ++j) {
42
// Respect PBC
43
double
r =
matter
->pbc(pos.row(i) - pos.row(j)).norm();
44
45
// Weight function w = 1 / r^4
46
// Avoid division by zero if atoms overlap perfectly (unlikely in IDPP but
47
// possible)
48
if
(r < 1e-4)
49
r = 1e-4;
50
51
double
diff = r -
d_target
(i, j);
52
double
r2 = r * r;
53
double
weight = 1.0 / (r2 * r2);
// 1/r^4
54
55
energy += 0.5 * weight * diff * diff;
56
}
57
}
58
return
energy;
59
}
60
61
VectorXd
IDPPObjectiveFunction::getGradient
(
bool
/*fdstep*/
) {
62
int
natoms =
matter
->numberOfAtoms();
63
AtomMatrix
pos =
matter
->getPositions();
64
AtomMatrix
forces = AtomMatrix::Zero(natoms, 3);
65
66
for
(
int
i = 0; i < natoms; ++i) {
67
for
(
int
j = i + 1; j < natoms; ++j) {
68
// Vector pointing from j to i
69
Eigen::RowVector3d dr_vec =
matter
->pbc(pos.row(i) - pos.row(j));
70
double
r = dr_vec.norm();
71
72
if
(r < 1e-4)
73
r = 1e-4;
74
75
double
diff = r -
d_target
(i, j);
76
double
r2 = r * r;
77
78
// Derivative of E_pair = 0.5 * (1/r^4) * (r - d_target)^2
79
// dE/dr = (r - d_target)/r^4 - 2(r - d_target)^2 / r^5
80
// Simplified: (r - d_target) * (1 - 2(r - d_target)/r) / r^4
81
82
double
r4 = r2 * r2;
83
double
dEdr = (diff * (1.0 - 2.0 * diff / r)) / r4;
84
85
// Force contribution: F = -dE/dr * (dr_vec / r)
86
Eigen::RowVector3d f_contribution = -dEdr * (dr_vec / r);
87
88
forces.row(i) += f_contribution;
89
forces.row(j) -= f_contribution;
// Newton's 3rd law
90
}
91
}
92
93
// dV/dx on free atoms only. Frozen rows stay in `forces` for Newton's
94
// third law during the pair loop, then are dropped.
95
return
packFree(*
matter
, forces) * -1.0;
96
}
97
98
MatrixXd
CollectiveIDPPObjectiveFunction::getDistanceMatrix
(
const
Matter
&m) {
99
int
natoms = m.
numberOfAtoms
();
100
MatrixXd
d(natoms, natoms);
101
auto
pos = m.
getPositions
();
102
for
(
int
i = 0; i < natoms; ++i) {
103
for
(
int
j = 0; j < natoms; ++j) {
104
d(i, j) = m.
pbc
(pos.row(i) - pos.row(j)).norm();
105
}
106
}
107
return
d;
108
}
109
110
MatrixXd
111
CollectiveIDPPObjectiveFunction::getIDPPForces
(
const
Matter
&m,
112
const
MatrixXd
&dTarget) {
113
int
natoms = m.
numberOfAtoms
();
114
AtomMatrix
forces = AtomMatrix::Zero(natoms, 3);
115
auto
pos = m.
getPositions
();
116
117
for
(
int
i = 0; i < natoms; ++i) {
118
for
(
int
j = i + 1; j < natoms; ++j) {
119
Eigen::RowVector3d dr_vec = m.
pbc
(pos.row(i) - pos.row(j));
120
double
r = dr_vec.norm();
121
if
(r < 1e-4)
122
r = 1e-4;
123
124
double
diff = r - dTarget(i, j);
125
// SOTA Weighting: w = 1/r^4. Gradient logic matches Smidstrup/ASE
126
double
r2 = r * r;
127
double
r5 = r2 * r2 * r;
128
double
dEdr = (diff / r5) * (2.0 * dTarget(i, j) - r);
129
130
Eigen::RowVector3d f = -dEdr * (dr_vec / r);
// -dE/dr * r_hat
131
forces.row(i) += f;
132
forces.row(j) -= f;
133
}
134
}
135
return
forces;
136
}
137
138
VectorXd
CollectiveIDPPObjectiveFunction::getGradient
(
bool
/*fdstep*/
) {
139
int
nImgs =
path
.size() - 2;
// Exclude fixed endpoints
140
int
nfree =
static_cast<
int
>
(
path
[0].numberOfFreeAtoms());
141
VectorXd totalGradient(3 * nfree * nImgs);
142
double
maxForce = 0.0;
143
144
// 1. Compute Raw IDPP Forces and Tangents
145
std::vector<AtomMatrix> rawForces(
path
.size());
146
std::vector<AtomMatrix> tangents(
path
.size());
147
148
// We compute for 1..N (moving images)
149
for
(
size_t
i = 1; i <= nImgs; ++i) {
150
// Interpolate Target
151
double
xi =
static_cast<
double
>
(i) / (nImgs + 1);
152
MatrixXd
dTarget = (1.0 - xi) *
dInit
+ xi *
dFinal
;
153
154
rawForces[i] =
getIDPPForces
(
path
[i], dTarget);
155
156
// Simple Tangent: Next - Prev
157
AtomMatrix
nextPos =
path
[i + 1].getPositions();
158
AtomMatrix
prevPos =
path
[i - 1].getPositions();
159
tangents[i] =
path
[i].pbc(nextPos - prevPos);
160
const
double
tnorm = tangents[i].norm();
161
if
(tnorm > 1e-10) {
162
tangents[i] /= tnorm;
163
}
164
}
165
166
// 2. Project Forces and Add Springs (The "NEB" part of IDPP-NEB)
167
double
k =
params
.neb_options().spring.constant;
168
169
for
(
size_t
i = 1; i <= nImgs; ++i) {
170
AtomMatrix
f = rawForces[i];
171
AtomMatrix
t = tangents[i];
172
173
// Perpendicular Force (IDPP optimization)
174
double
f_dot_t =
matDot
(f, t);
175
AtomMatrix
f_perp = f - f_dot_t * t;
176
177
// Spring Force (Spacing optimization)
178
double
distNext =
path
[i].distanceTo(
path
[i + 1]);
179
double
distPrev =
path
[i].distanceTo(
path
[i - 1]);
180
AtomMatrix
f_spring = k * (distNext - distPrev) * t;
181
182
AtomMatrix
f_neb = f_perp + f_spring;
183
184
VectorXd freeForce = packFree(
path
[i], f_neb);
185
totalGradient.segment(3 * nfree *
static_cast<
int
>
(i - 1), 3 * nfree) =
186
freeForce * -1.0;
187
188
// Free-atom residuals only. Frozen pair rows stay in f_neb for
189
// Newton's third law and must not pin lastMaxForce.
190
maxForce = std::max(maxForce, freeForce.lpNorm<Eigen::Infinity>());
191
}
192
193
lastMaxForce
= maxForce;
194
return
totalGradient;
195
}
196
197
}
// namespace eonc
matDot
double matDot(const AtomMatrix &a, const AtomMatrix &b)
SIMD-optimized dot product for contiguous Eigen matrices.
Definition
Eigen.h:50
MatrixXd
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, eOnStorageOrder > MatrixXd
Definition
Eigen.h:33
AtomMatrix
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition
Eigen.h:37
IDPPObjectiveFunction.hpp
eonc::CollectiveIDPPObjectiveFunction::getDistanceMatrix
MatrixXd getDistanceMatrix(const Matter &m)
Definition
IDPPObjectiveFunction.cpp:98
eonc::CollectiveIDPPObjectiveFunction::lastMaxForce
double lastMaxForce
Definition
IDPPObjectiveFunction.hpp:132
eonc::CollectiveIDPPObjectiveFunction::dInit
MatrixXd dInit
Definition
IDPPObjectiveFunction.hpp:131
eonc::CollectiveIDPPObjectiveFunction::path
std::vector< Matter > & path
Definition
IDPPObjectiveFunction.hpp:130
eonc::CollectiveIDPPObjectiveFunction::dFinal
MatrixXd dFinal
Definition
IDPPObjectiveFunction.hpp:131
eonc::CollectiveIDPPObjectiveFunction::getGradient
VectorXd getGradient(bool fdstep=false) override
Definition
IDPPObjectiveFunction.cpp:138
eonc::CollectiveIDPPObjectiveFunction::getIDPPForces
MatrixXd getIDPPForces(const Matter &m, const MatrixXd &dTarget)
Definition
IDPPObjectiveFunction.cpp:111
eonc::IDPPObjectiveFunction::d_target
MatrixXd d_target
Definition
IDPPObjectiveFunction.hpp:70
eonc::IDPPObjectiveFunction::matter
std::shared_ptr< Matter > matter
Definition
IDPPObjectiveFunction.hpp:25
eonc::IDPPObjectiveFunction::getEnergy
double getEnergy() override
Definition
IDPPObjectiveFunction.cpp:34
eonc::IDPPObjectiveFunction::getGradient
VectorXd getGradient(bool fdstep=false) override
Definition
IDPPObjectiveFunction.cpp:61
eonc::Matter
Definition
Matter.h:90
eonc::Matter::getPositions
const AtomMatrix & getPositions() const
Definition
Matter.cpp:308
eonc::Matter::numberOfAtoms
long int numberOfAtoms() const
Definition
Matter.cpp:273
eonc::Matter::pbc
AtomMatrix pbc(const AtomMatrix &diff) const
Definition
Matter.cpp:810
eonc::ObjectiveFunction::params
const Parameters & params
Definition
ObjectiveFunction.h:22
eonc
RAII resource manager for the ARTn C library with global synchronization.
Definition
ARTnSaddleSearch.cpp:23
client
IDPPObjectiveFunction.cpp
Generated by
1.17.0
Generated by
Doxygen 1.17.0
Analytics by
Antics
provided by
TurtleTech ehf