23std::pair<std::size_t, std::size_t>
24manualWindow(std::size_t n, std::size_t climbingImage,
int offset) {
25 const auto half =
static_cast<std::size_t
>(std::max(offset, 1));
26 const std::size_t lo = climbingImage > half ? climbingImage - half : 0;
27 const std::size_t hi = std::min(n - 1, climbingImage + half);
31std::vector<Matter> linearResample(
const std::vector<Matter> &sub,
33 const std::size_t n = sub.size();
34 std::vector<double> arc(n, 0.0);
35 for (std::size_t i = 1; i < n; ++i) {
37 sub[i].pbc(sub[i].getPositions() - sub[i - 1].getPositions());
38 arc[i] = arc[i - 1] + diff.norm();
40 const double total = arc.back();
41 std::vector<Matter> placed;
42 placed.reserve(count);
46 placed.push_back(sub.front());
47 for (std::size_t i = 1; i + 1 < count; ++i) {
48 const double target = (total > 1e-12) ? total *
static_cast<double>(i) /
49 static_cast<double>(count - 1)
52 for (std::size_t j = 1; j < n; ++j) {
53 if (arc[j] >= target) {
58 const std::size_t hi = std::min(lo + 1, n - 1);
59 const double span = arc[hi] - arc[lo];
60 const double f = (span > 1e-12) ? (target - arc[lo]) / span : 0.0;
63 f * sub[hi].getPositions());
64 placed.push_back(std::move(image));
67 placed.push_back(sub.back());
75 std::size_t climbingImage,
78 const std::size_t n = energy.size();
79 if (n < 3 || climbingImage == 0 || climbingImage + 1 >= n) {
86 std::tie(lo, hi) = manualWindow(n, climbingImage, cfg.
offset);
88 const double eRef = std::min(energy.front(), energy.back());
89 const double eMax = *std::max_element(energy.begin(), energy.end());
90 const double barrier = eMax - eRef;
91 const bool usable = barrier > 0.0 && cfg.
alpha > 0.0 && cfg.
alpha < 1.0;
93 std::tie(lo, hi) = manualWindow(n, climbingImage, cfg.
offset);
95 const double threshold = eRef + cfg.
alpha * barrier;
98 while (lo > 0 && energy[lo - 1] > threshold) {
101 while (hi + 1 < n && energy[hi + 1] > threshold) {
105 std::tie(lo, hi) = manualWindow(n, climbingImage, cfg.
offset);
109 if (hi <= lo || hi >= n) {
120 if (!window.
valid || path.size() < 3 || window.
hi <= window.
lo ||
121 window.
hi >= path.size()) {
124 for (
const auto &image : path) {
130 std::vector<Matter> sub;
131 sub.reserve(window.
hi - window.
lo + 1);
132 for (std::size_t i = window.
lo; i <= window.
hi; ++i) {
133 sub.push_back(*path[i]);
136 std::vector<Matter> placed;
138 placed = linearResample(sub, path.size());
139 }
else if (sub.size() == path.size()) {
140 std::vector<std::shared_ptr<Matter>> tmp;
141 tmp.reserve(sub.size());
142 for (
const auto &image : sub) {
143 tmp.push_back(std::make_shared<Matter>(image));
146 std::span<std::shared_ptr<Matter>>{tmp.data(), tmp.size()});
147 placed.reserve(tmp.size());
148 for (
const auto &image : tmp) {
149 placed.push_back(*image);
154 if (placed.size() != path.size()) {
157 for (std::size_t i = 0; i < path.size(); ++i) {
158 path[i]->setPositions(placed[i].getPositions());
Window selectWindow(const std::vector< double > &energy, std::size_t climbingImage, const neb_options_t::zoom_options_t &cfg)
Auto: contiguous images around the climbing image whose energy is above E_ref + alpha * barrier.
bool redistributePath(std::vector< std::shared_ptr< Matter > > &path, Window window, neb_options_t::zoom_options_t::Interpolation how)
Place every band image on the window by equal arc length.