Loading...
Searching...
No Matches
RelaxEngineAbi.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*/
13
14#include "eon/Eigen.h"
15#include "eon/Matter.h"
18#include "eon/Optimizer.h"
19#include "eon/Parameters.h"
20#include "eon_relax_engine.capnp.h"
22#include "version.h"
23
24#include <capnp/serialize.h>
25#include <kj/array.h>
26#include <kj/common.h>
27
28#include <algorithm>
29#include <cmath>
30#include <cstdio>
31#include <cstring>
32#include <memory>
33#include <new>
34#include <stdexcept>
35#include <string>
36#include <vector>
37
38// Library TU. The test alias header is not included here.
39using eonc::Matter;
43using eonc::Optimizer;
46
47extern "C" uint64_t eon_relax_version_hash(void);
48
49namespace {
50
51uint64_t fnv1a64(const char *s) {
52 uint64_t h = 14695981039346656037ULL;
53 if (!s) {
54 return h;
55 }
56 for (const unsigned char *p = reinterpret_cast<const unsigned char *>(s); *p;
57 ++p) {
58 h ^= static_cast<uint64_t>(*p);
59 h *= 1099511628211ULL;
60 }
61 return h;
62}
63
64void set_err(char *errbuf, size_t errlen, const char *msg) {
65 if (!errbuf || errlen == 0) {
66 return;
67 }
68 std::snprintf(errbuf, errlen, "%s", msg ? msg : "");
69}
70
71bool known_kind(eon_relax_kind_t kind) { return EON_RELAX_KIND_IS_KNOWN(kind); }
72
73int neb_status(NudgedElasticBand::NEBStatus st) { return static_cast<int>(st); }
74
75void fill_matter(Matter &m, const eon_relax_band_t *band, long image,
76 uint64_t epoch) {
77 m.resize(band->n_atoms);
78 Eigen::VectorXi z(band->n_atoms);
79 for (long a = 0; a < band->n_atoms; ++a) {
80 z(a) = band->atomic_nrs[a];
81 }
82 m.setAtomicNrs(z);
83 Eigen::VectorXd masses = Eigen::VectorXd::Ones(band->n_atoms);
84 if (band->version.minor >= 1 && band->masses) {
85 for (long a = 0; a < band->n_atoms; ++a) {
86 masses(a) = band->masses[a];
87 }
88 }
89 m.setMasses(masses);
90 AtomMatrix pos(band->n_atoms, 3);
91 const double *src = band->positions + image * 3 * band->n_atoms;
92 // Match Potential::force / Matter storage (AtomMatrix row-major xyz).
93 Eigen::Map<const AtomMatrix> mapped(src, band->n_atoms, 3);
94 pos = mapped;
95 const double *b = band->boxes + image * 9;
96 const Matrix3d cell = Eigen::Map<const Matrix3d>(b);
97 // Cell first. PBC stays off so dest optimizer writes
98 // (setPositionsFree) do not wrap a host-frame x=-0.667 to 9.333
99 // and hop the climbing image onto a wrapped shoulder.
100 m.setPeriodic(false);
101 m.setCell(cell);
102 m.setPositions(pos);
103 if (band->is_fixed) {
104 for (long a = 0; a < band->n_atoms; ++a) {
105 m.setFixed(a, band->is_fixed[a] ? 1 : 0);
106 }
107 } else {
108 for (long a = 0; a < band->n_atoms; ++a) {
109 m.setFixed(a, 0);
110 }
111 }
112 m.setSurfaceEpoch(epoch);
113}
114
115void write_image(double *dst, const Matter &m, long n_atoms) {
116 const AtomMatrix &pos = m.getPositions();
117 Eigen::Map<AtomMatrix> mapped(dst, n_atoms, 3);
118 mapped = pos;
119}
120
121int masses_ok(const eon_relax_band_t *band) {
122 if (!band || band->version.minor < 1 || !band->masses) {
123 return EON_RELAX_OK;
124 }
125 for (int64_t a = 0; a < band->n_atoms; ++a) {
126 const double m = band->masses[a];
127 if (!(m > 0.0) || !std::isfinite(m)) {
129 }
130 }
131 return EON_RELAX_OK;
132}
133
134void stamp_outcome(eon_relax_outcome_t *out, eon_relax_kind_t kind,
135 uint64_t epoch) {
136 std::memset(out, 0, sizeof(*out));
139 out->kind = static_cast<int32_t>(kind);
141 out->surface_epoch = epoch;
142}
143
144void dirty_keep_frame(Matter &m) {
145 const bool pbc = m.getPeriodic();
146 m.setPeriodic(false);
148 m.setPeriodic(pbc);
149}
150
151void dirty_endpoints(NudgedElasticBand &neb) {
152 dirty_keep_frame(*neb.path[0]);
153 dirty_keep_frame(*neb.path[static_cast<size_t>(neb.numImages + 1)]);
154}
155
156int apply_relax_params(Parameters &params, eon_relax_kind_t *kind,
157 uint64_t *epoch, const void *config, size_t config_len,
158 char *errbuf, size_t errlen) {
159 if (config_len % sizeof(::capnp::word) != 0) {
160 set_err(errbuf, errlen, "-13 RelaxEngineParams capnp root");
162 }
163 try {
164 const auto nwords = config_len / sizeof(::capnp::word);
165 std::vector<::capnp::word> words(nwords);
166 std::memcpy(words.data(), config, config_len);
167 ::kj::ArrayPtr<const ::capnp::word> view(words.data(), nwords);
168 ::capnp::FlatArrayMessageReader reader(view);
169 auto root = reader.getRoot<eonc::params_ssot::RelaxEngineParams>();
170 const auto kind_txt = root.getKind();
171 if (kind_txt == "neb") {
172 *kind = EON_RELAX_KIND_NEB;
173 } else if (kind_txt == "saddle") {
174 *kind = EON_RELAX_KIND_SADDLE;
175 } else {
176 set_err(errbuf, errlen, "-11 unknown RelaxEngineParams.kind");
178 }
179 auto neb = root.getNeb();
180 auto &neb_o = ParametersLoadAccess::neb_options(params);
181 neb_o.image_count = static_cast<long>(neb.getImageCount());
182 neb_o.max_iterations = static_cast<long>(neb.getMaxIterations());
183 neb_o.force_tolerance = neb.getForceTolerance();
184 neb_o.climbing_image.enabled = neb.getClimbingImage();
185 neb_o.endpoints.minimize = neb.getMinimizeEndpoints();
186 auto saddle = root.getSaddle();
187 auto &saddle_o = ParametersLoadAccess::saddle_search_options(params);
188 saddle_o.max_iterations = static_cast<long>(saddle.getMaxIterations());
189 saddle_o.converged_force = saddle.getConvergedForce();
190 *epoch = root.getSurfaceEpoch();
191 ParametersLoadAccess::main_options(params).randomSeed =
192 static_cast<long>(root.getRandomSeed());
194 root.getUncertainty();
195 return EON_RELAX_OK;
196 } catch (const std::exception &) {
197 set_err(errbuf, errlen, "-13 RelaxEngineParams capnp root");
199 } catch (...) {
200 set_err(errbuf, errlen, "-13 RelaxEngineParams capnp root");
202 }
203}
204
205} // namespace
206
210 uint64_t epoch{0};
212 bool unusable{false};
213
214 // Stepper state (eon_relax_step): band, objective, and optimizer
215 // persist across calls so quasi-Newton history accumulates on one
216 // surface epoch; eon_relax_reset drops all of it.
217 std::shared_ptr<eonc::HostSurfacePotential> step_pot;
218 std::unique_ptr<NudgedElasticBand> step_neb;
219 std::shared_ptr<NEBObjectiveFunction> step_objf;
220 std::unique_ptr<Optimizer> step_opt;
222 void *step_user{nullptr};
223 double step_baseline{0.0};
225};
226
227static int stamp_rc(EonRelaxEngine *eng, int rc) {
228 if (eng) {
229 eng->last_rc = rc;
230 }
231 return rc;
232}
233
234static int fail_out(EonRelaxEngine *eng, eon_relax_outcome_t *out, int rc,
235 eon_relax_kind_t kind, uint64_t epoch) {
236 if (out) {
237 stamp_outcome(out, kind, epoch);
238 out->status = -1;
239 }
240 return stamp_rc(eng, rc);
241}
242
243static void clear_stepper(EonRelaxEngine *eng) {
244 eng->step_opt.reset();
245 eng->step_objf.reset();
246 eng->step_neb.reset();
247 eng->step_pot.reset();
248 eng->step_surface = nullptr;
249 eng->step_user = nullptr;
250 eng->step_baseline = 0.0;
251 eng->step_iteration = 0;
252}
253
254extern "C" {
255
257 return static_cast<int>((EON_RELAX_ABI_MAJOR << 16) | EON_RELAX_ABI_MINOR);
258}
259
260int eon_relax_available(void) { return 1; }
261
263 if (!out) {
265 }
268 return EON_RELAX_OK;
269}
270
271const char *eon_relax_version_hash_str(void) {
272 static const std::string id =
273 VERSION + "+git." + GIT_HASH_FULL + "+feat." +
274 std::to_string(fnv1a64(FEATURES_STRING.c_str()));
275 return id.c_str();
276}
277
279 return fnv1a64(eon_relax_version_hash_str());
280}
281
282EonRelaxEngine *eon_relax_create(const void *config, size_t config_len,
283 char *errbuf, size_t errlen) {
284 auto make_engine = [&]() -> std::unique_ptr<EonRelaxEngine> {
285 try {
286 return std::make_unique<EonRelaxEngine>();
287 } catch (const std::bad_alloc &) {
288 set_err(errbuf, errlen, "-19 out of memory");
289 return nullptr;
290 }
291 };
292 if (config == nullptr && config_len == 0) {
293 auto eng = make_engine();
294 if (!eng) {
295 return nullptr;
296 }
297 eng->kind = EON_RELAX_KIND_NEB;
298 return eng.release();
299 }
300 if (config == nullptr || config_len == 0) {
301 set_err(errbuf, errlen, "-13 RelaxEngineParams capnp root");
302 return nullptr;
303 }
304 auto eng = make_engine();
305 if (!eng) {
306 return nullptr;
307 }
308 const int prc = apply_relax_params(eng->params, &eng->kind, &eng->epoch,
309 config, config_len, errbuf, errlen);
310 if (prc != EON_RELAX_OK) {
311 return nullptr;
312 }
313 return eng.release();
314}
315
317 if (!eng) {
319 }
320 if (eng->unusable) {
322 }
323 eng->epoch = epoch;
324 if (eng->step_pot) {
325 eng->step_pot->setEpoch(epoch);
326 }
327 eng->last_rc = EON_RELAX_OK;
328 return EON_RELAX_OK;
329}
330
332 if (!eng) {
334 }
335 return eng->last_rc;
336}
337
339 eon_relax_surface_fn surface, void *user,
340 eon_relax_outcome_t *out) {
341 if (!eng) {
343 }
344 if (eng->unusable) {
345 return fail_out(eng, out, EON_RELAX_SURFACE_FATAL, eng->kind, eng->epoch);
346 }
347 if (!band) {
348 return fail_out(eng, out, EON_RELAX_NULL_BAND, eng->kind, eng->epoch);
349 }
350 if (!surface) {
351 return fail_out(eng, out, EON_RELAX_NULL_SURFACE, eng->kind, eng->epoch);
352 }
353 if (!out) {
354 return stamp_rc(eng, EON_RELAX_NULL_OUTCOME);
355 }
356 clear_stepper(eng);
357 if (band->n_atoms <= 0) {
358 return fail_out(eng, out, EON_RELAX_NATOMS, eng->kind, eng->epoch);
359 }
360 if (!band->positions) {
361 return fail_out(eng, out, EON_RELAX_NULL_POSITIONS, eng->kind, eng->epoch);
362 }
363 if (!band->atomic_nrs) {
364 return fail_out(eng, out, EON_RELAX_NULL_ATOMIC_NRS, eng->kind, eng->epoch);
365 }
366 if (!band->boxes) {
367 return fail_out(eng, out, EON_RELAX_NULL_BOXES, eng->kind, eng->epoch);
368 }
369 if (band->version.major != EON_RELAX_ABI_MAJOR) {
370 return fail_out(eng, out, EON_RELAX_ABI_MISMATCH, eng->kind, eng->epoch);
371 }
372 if (!known_kind(eng->kind)) {
373 return fail_out(eng, out, EON_RELAX_UNKNOWN_KIND, eng->kind, eng->epoch);
374 }
375 const int mass_rc = masses_ok(band);
376 if (mass_rc != EON_RELAX_OK) {
377 return fail_out(eng, out, mass_rc, eng->kind, eng->epoch);
378 }
379 stamp_outcome(out, eng->kind, eng->epoch);
380
381 auto pot =
382 std::make_shared<eonc::HostSurfacePotential>(surface, user, eng->epoch);
383 try {
384 if (eng->kind == EON_RELAX_KIND_NEB) {
385 if (band->n_images < 3) {
386 out->status = -1;
388 }
389 const int64_t want =
390 static_cast<int64_t>(eng->params.neb_options().image_count) + 2;
391 if (band->n_images != want) {
392 out->status = -1;
393 return stamp_rc(eng, EON_RELAX_BAND_SIZE);
394 }
395 std::vector<Matter> path;
396 path.reserve(static_cast<size_t>(band->n_images));
397 for (int64_t i = 0; i < band->n_images; ++i) {
398 Matter img(pot, eng->params);
399 fill_matter(img, band, static_cast<long>(i), eng->epoch);
400 path.push_back(std::move(img));
401 }
402 auto neb = std::make_unique<NudgedElasticBand>(std::move(path),
403 eng->params, pot);
404 pot->bindPath(neb->path);
405 dirty_endpoints(*neb);
406 const auto st = neb->compute();
407 if (st == NudgedElasticBand::NEBStatus::INIT ||
408 st == NudgedElasticBand::NEBStatus::RUNNING) {
409 out->status = neb_status(st);
411 }
412 out->status = neb_status(st);
413 NEBObjectiveFunction ranked(neb.get(), eng->params);
414 if (ranked.isUncertain()) {
416 }
417 out->iterations = neb->lastIteration();
418 out->climbing_image = neb->climbingImage;
419 out->max_force = neb->convergenceForce();
420 out->surface_epoch = pot->surfaceEpoch();
421 for (int64_t i = 1; i + 1 < band->n_images; ++i) {
422 write_image(band->positions + i * 3 * band->n_atoms,
423 *neb->path[static_cast<size_t>(i)],
424 static_cast<long>(band->n_atoms));
425 }
426 return stamp_rc(eng, EON_RELAX_OK);
427 }
428
429 if (band->n_images != 1) {
430 out->status = -1;
432 }
433 if (!band->mode) {
434 out->status = -1;
435 return stamp_rc(eng, EON_RELAX_NULL_MODE);
436 }
437 auto matter = std::make_shared<Matter>(pot, eng->params);
438 fill_matter(*matter, band, 0, eng->epoch);
439 AtomMatrix mode(band->n_atoms, 3);
440 Eigen::Map<const AtomMatrix> mmap(band->mode, band->n_atoms, 3);
441 mode = mmap;
442 const double reactant_e = matter->getPotentialEnergy();
443 MinModeSaddleSearch search(matter, mode, reactant_e, eng->params, pot);
444 const int sst = search.run();
445 write_image(band->positions, *matter, static_cast<long>(band->n_atoms));
446 out->iterations = search.getIterationCount();
447 out->surface_epoch = pot->surfaceEpoch();
448 out->status = sst;
449 return stamp_rc(eng, EON_RELAX_OK);
450 } catch (const eonc::SurfaceRecoverable &rec) {
451 out->status = -1;
452 return stamp_rc(eng, rec.rc);
453 } catch (const std::exception &) {
454 out->status = -1;
455 eng->unusable = true;
457 }
458}
459
461 eon_relax_surface_fn surface, void *user,
462 eon_relax_outcome_t *out) {
463 if (!eng) {
465 }
466 if (eng->unusable) {
467 return fail_out(eng, out, EON_RELAX_SURFACE_FATAL, eng->kind, eng->epoch);
468 }
469 if (!band) {
470 return fail_out(eng, out, EON_RELAX_NULL_BAND, eng->kind, eng->epoch);
471 }
472 if (!surface) {
473 return fail_out(eng, out, EON_RELAX_NULL_SURFACE, eng->kind, eng->epoch);
474 }
475 if (!out) {
476 return stamp_rc(eng, EON_RELAX_NULL_OUTCOME);
477 }
478 if (eng->kind == EON_RELAX_KIND_SADDLE) {
479 return fail_out(eng, out, EON_RELAX_INVALID_PARAMETER, eng->kind,
480 eng->epoch);
481 }
482 if (eng->kind != EON_RELAX_KIND_NEB) {
483 return fail_out(eng, out, EON_RELAX_UNKNOWN_KIND, eng->kind, eng->epoch);
484 }
485 if (band->n_atoms <= 0) {
486 return fail_out(eng, out, EON_RELAX_NATOMS, EON_RELAX_KIND_NEB, eng->epoch);
487 }
488 if (!band->positions) {
490 eng->epoch);
491 }
492 if (!band->atomic_nrs) {
494 eng->epoch);
495 }
496 if (!band->boxes) {
498 eng->epoch);
499 }
500 if (band->version.major != EON_RELAX_ABI_MAJOR) {
502 eng->epoch);
503 }
504 const int mass_rc = masses_ok(band);
505 if (mass_rc != EON_RELAX_OK) {
506 return fail_out(eng, out, mass_rc, EON_RELAX_KIND_NEB, eng->epoch);
507 }
508 stamp_outcome(out, EON_RELAX_KIND_NEB, eng->epoch);
509 if (eng->step_neb && (band->n_atoms != eng->step_neb->atoms ||
510 band->n_images != eng->step_neb->numImages + 2)) {
511 out->status = -1;
513 }
514 if (band->n_images < 3) {
515 out->status = -1;
517 }
518 const int64_t want =
519 static_cast<int64_t>(eng->params.neb_options().image_count) + 2;
520 if (band->n_images != want) {
521 out->status = -1;
522 return stamp_rc(eng, EON_RELAX_BAND_SIZE);
523 }
524 if (eng->step_neb &&
525 (eng->step_surface != surface || eng->step_user != user)) {
526 out->status = -1;
528 }
529
530 try {
531 if (!eng->step_neb) {
532 eng->step_pot = std::make_shared<eonc::HostSurfacePotential>(
533 surface, user, eng->epoch);
534 std::vector<Matter> path;
535 path.reserve(static_cast<size_t>(band->n_images));
536 for (int64_t i = 0; i < band->n_images; ++i) {
537 Matter img(eng->step_pot, eng->params);
538 fill_matter(img, band, static_cast<long>(i), eng->epoch);
539 path.push_back(std::move(img));
540 }
541 eng->step_neb = std::make_unique<NudgedElasticBand>(
542 std::move(path), eng->params, eng->step_pot);
543 eng->step_pot->bindPath(eng->step_neb->path);
544 dirty_endpoints(*eng->step_neb);
545 eng->step_neb->E_ref =
546 std::min(eng->step_neb->path[0]->getPotentialEnergy(),
547 eng->step_neb->path[eng->step_neb->numImages + 1]
548 ->getPotentialEnergy());
549 eng->step_neb->updateForces();
550 eng->step_objf = std::make_shared<NEBObjectiveFunction>(
551 eng->step_neb.get(), eng->params);
553 eng->step_objf, eng->params.neb_options().opt_method, eng->params);
554 eng->step_surface = surface;
555 eng->step_user = user;
556 eng->step_baseline = eng->step_neb->convergenceForce();
557 eng->step_iteration = 0;
558 } else {
559 // The host may have moved images between steps (acquisition,
560 // reparameterization); resync and mark the band dirty.
561 for (int64_t i = 0; i < band->n_images; ++i) {
562 fill_matter(*eng->step_neb->path[static_cast<size_t>(i)], band,
563 static_cast<long>(i), eng->epoch);
564 }
565 eng->step_neb->movedAfterForceCall = true;
566 eng->step_neb->updateForces();
567 }
568
569 NudgedElasticBand &neb = *eng->step_neb;
570 const double convForce = neb.convergenceForce();
571 const auto &ci_opt = eng->params.neb_options().climbing_image;
572 const bool ci_active =
573 ci_opt.enabled &&
574 (convForce < eng->step_baseline * ci_opt.trigger_factor ||
575 convForce < ci_opt.trigger_force);
576 neb.setCIEnabled(ci_active);
577
578 const double force_tol = eng->params.neb_options().force_tolerance;
579 const long max_iter = eng->params.neb_options().max_iterations;
580 int status = EON_RELAX_NEB_RUNNING;
581 if (eng->step_objf && eng->step_objf->isUncertain()) {
583 } else if (convForce <= force_tol) {
584 status = EON_RELAX_NEB_GOOD;
585 } else if (eng->step_iteration >= max_iter) {
587 } else {
588 eng->step_opt->step(eng->params.optimizer_options().max_move);
589 ++eng->step_iteration;
590 neb.updateForces();
591 if (eng->step_objf && eng->step_objf->isUncertain()) {
593 } else if (neb.convergenceForce() <= force_tol) {
594 status = EON_RELAX_NEB_GOOD;
595 } else if (eng->step_iteration >= max_iter) {
597 }
598 }
599
600 // Interior images only: eOn never moves the endpoints, and Matter
601 // wraps positions into the cell, so writing them back would hand
602 // the caller a different frame than the one it supplied.
603 for (int64_t i = 1; i + 1 < band->n_images; ++i) {
604 write_image(band->positions + i * 3 * band->n_atoms,
605 *neb.path[static_cast<size_t>(i)],
606 static_cast<long>(band->n_atoms));
607 }
608 out->status = status;
609 out->iterations = eng->step_iteration;
610 out->climbing_image = neb.climbingImage;
611 out->max_force = neb.convergenceForce();
612 out->surface_epoch = eng->step_pot->surfaceEpoch();
613 return stamp_rc(eng, EON_RELAX_OK);
614 } catch (const eonc::SurfaceRecoverable &rec) {
615 out->status = -1;
616 clear_stepper(eng);
617 return stamp_rc(eng, rec.rc);
618 } catch (const std::exception &) {
619 out->status = -1;
620 eng->unusable = true;
622 }
623}
624
626 if (!eng) {
628 }
629 if (eng->unusable) {
631 }
632 clear_stepper(eng);
633 eng->last_rc = EON_RELAX_OK;
634 return EON_RELAX_OK;
635}
636
638 std::unique_ptr<EonRelaxEngine> owned(eng);
639}
640
641const char *eon_relax_status_name(eon_relax_kind_t kind, int status) {
642 if (kind == EON_RELAX_KIND_NEB) {
643 switch (status) {
645 return "GOOD";
647 return "INIT";
649 return "BAD_MAX_ITERATIONS";
651 return "RUNNING";
653 return "MAX_UNCERTAINTY";
654 default:
655 return nullptr;
656 }
657 }
658 if (kind == EON_RELAX_KIND_SADDLE) {
659 const auto msg = MinModeSaddleSearch::statusMessage(status);
660 if (msg == "Unknown status") {
661 return nullptr;
662 }
663 return msg.data();
664 }
665 return nullptr;
666}
667
668} // extern "C"
Eigen::Matrix< double, 3, 3, eOnStorageOrder > Matrix3d
Definition Eigen.h:35
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
static void set_err(char *errbuf, size_t errlen, const char *msg)
The optimizer class is used to serve as an abstract class for all optimizers, as well as to call an o...
int eon_relax_step(EonRelaxEngine *eng, eon_relax_band_t *band, eon_relax_surface_fn surface, void *user, eon_relax_outcome_t *out)
One band optimizer step (kind=NEB only).
int eon_relax_run(EonRelaxEngine *eng, eon_relax_band_t *band, eon_relax_surface_fn surface, void *user, eon_relax_outcome_t *out)
Run the bound engine to completion.
const char * eon_relax_status_name(eon_relax_kind_t kind, int status)
NULL if kind or status is unknown.
static int fail_out(EonRelaxEngine *eng, eon_relax_outcome_t *out, int rc, eon_relax_kind_t kind, uint64_t epoch)
int eon_relax_available(void)
EonRelaxEngine * eon_relax_create(const void *config, size_t config_len, char *errbuf, size_t errlen)
Create.
static int stamp_rc(EonRelaxEngine *eng, int rc)
static void clear_stepper(EonRelaxEngine *eng)
void eon_relax_destroy(EonRelaxEngine *eng)
uint64_t eon_relax_version_hash(void)
64-bit FNV-1a hash of eon_relax_version_hash_str().
int eon_relax_reset(EonRelaxEngine *eng)
Drop the stepper's band state and optimizer history; the next eon_relax_step reinitializes from the c...
int eon_relax_last_error(const EonRelaxEngine *eng)
Last named create/run/step/reset/set_epoch rc on this handle.
int eon_relax_set_surface_epoch(EonRelaxEngine *eng, uint64_t epoch)
const char * eon_relax_version_hash_str(void)
Immortal dest identity string.
int eon_relax_abi_version(void)
(major << 16) | minor.
int eon_relax_abi_stamp(eon_relax_version_t *out)
static constexpr std::string_view statusMessage(int status)
Human-readable message for a status code.
void bindPath(const std::vector< std::shared_ptr< Matter > > &path)
void setEpoch(std::uint64_t epoch)
unsigned long long surfaceEpoch() const noexcept override
Host-visible surface generation.
void setFixed(long int atom, int isFixed)
Broadcast a whole-atom flag onto all three axes.
Definition Matter.cpp:594
const AtomMatrix & getPositions() const
Definition Matter.cpp:375
void setPositions(const AtomMatrix &pos)
Definition Matter.cpp:417
void setCell(const Matrix3d &newCell)
Definition Matter.cpp:344
bool getPeriodic() const noexcept
Definition Matter.h:336
void setPeriodic(bool periodic)
Definition Matter.h:339
void setAtomicNrs(const VectorXi &atmnrs)
Definition Matter.cpp:785
void resize(long int nAtoms)
Definition Matter.cpp:294
void setMasses(const VectorXd &massesIn)
Definition Matter.cpp:555
void setSurfaceEpoch(unsigned long long epoch)
Host surface generation.
Definition Matter.cpp:684
int getIterationCount() const override
void updateForces(bool ci_active)
std::vector< std::shared_ptr< Matter > > path
void setCIEnabled(bool enabled)
Abstract base of the structure optimizers.
Definition Optimizer.h:68
const neb_options_t & neb_options() const
const optimizer_options_t & optimizer_options() const
Tier-2 C ABI: eOn as a dlopen relaxation engine.
#define EON_RELAX_KIND_IS_KNOWN(k)
#define EON_RELAX_ABI_MAJOR
#define EON_RELAX_ABI_MINOR
@ EON_RELAX_NEB_GOOD
@ EON_RELAX_NEB_MAX_UNCERTAINTY
@ EON_RELAX_NEB_BAD_MAX_ITERATIONS
@ EON_RELAX_NEB_RUNNING
@ EON_RELAX_NEB_INIT
@ EON_RELAX_NULL_BAND
@ EON_RELAX_OK
@ EON_RELAX_SURFACE_FATAL
@ EON_RELAX_NULL_ENGINE
@ EON_RELAX_BAND_SIZE
@ EON_RELAX_NULL_ATOMIC_NRS
@ EON_RELAX_NULL_POSITIONS
@ EON_RELAX_NULL_BOXES
@ EON_RELAX_NULL_SURFACE
@ EON_RELAX_UNKNOWN_STATUS
@ EON_RELAX_CAPNP_ROOT
@ EON_RELAX_ABI_MISMATCH
@ EON_RELAX_UNKNOWN_KIND
@ EON_RELAX_SADDLE_NIMAGES
@ EON_RELAX_BAND_TOO_SHORT
@ EON_RELAX_NULL_OUTCOME
@ EON_RELAX_INVALID_PARAMETER
@ EON_RELAX_NATOMS
@ EON_RELAX_NULL_MODE
int(* eon_relax_surface_fn)(void *user, eon_relax_surface_request_t *req)
Return 0 on success, positive recoverable, negative fatal.
eon_relax_kind_t
@ EON_RELAX_KIND_SADDLE
@ EON_RELAX_KIND_NEB
std::unique_ptr< Optimizer > mkOptim(std::shared_ptr< ObjectiveFunction > a_objf, OptType a_otype, const Parameters &a_params)
Definition Optimizer.cpp:55
constexpr long saddle
eon_relax_kind_t kind
std::shared_ptr< eonc::HostSurfacePotential > step_pot
std::shared_ptr< NEBObjectiveFunction > step_objf
eon_relax_surface_fn step_surface
std::unique_ptr< NudgedElasticBand > step_neb
std::unique_ptr< Optimizer > step_opt
static gp_surrogate_options_t & gp_surrogate_options(Parameters &p)
static saddle_search_options_t & saddle_search_options(Parameters &p)
static main_options_t & main_options(Parameters &p)
static neb_options_t & neb_options(Parameters &p)
Caller-owned band.
eon_relax_version_t version
const int32_t * atomic_nrs
const double * boxes
const double * masses
const int32_t * is_fixed
const double * mode
Engine-written result.
eon_relax_version_t version
Version head carried by every wire struct (dlpack DLPackVersion).
Write hole for INI/JSON loaders and nanobind property setters.
Definition Parameters.h:163
struct eonc::neb_options_t::climbing_image_options_t climbing_image