Loading...
Searching...
No Matches
HostSurfacePotential.h
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#pragma once
13
14#include "eon/Matter.h"
15#include "eon/Potential.h"
17
18#include <cstddef>
19#include <cstdint>
20#include <memory>
21#include <stdexcept>
22#include <vector>
23
24namespace eonc {
25
26struct SurfaceRecoverable : std::exception {
27 explicit SurfaceRecoverable(int code)
28 : rc{code} {}
29 int rc{0};
30 [[nodiscard]] const char *what() const noexcept override {
31 return "host surface recoverable";
32 }
33};
34
36public:
37 HostSurfacePotential(eon_relax_surface_fn fn, void *user, std::uint64_t epoch)
39 fn_{fn},
40 user_{user},
41 epoch_{epoch} {}
42
43 [[nodiscard]] bool supportsBatchEvaluation() const noexcept override {
44 return true;
45 }
46 [[nodiscard]] unsigned long long surfaceEpoch() const noexcept override {
47 return epoch_;
48 }
49 [[nodiscard]] int lastStatus() const noexcept { return last_; }
50 void setEpoch(std::uint64_t epoch) { epoch_ = epoch; }
51 void bindPath(const std::vector<std::shared_ptr<Matter>> &path) {
52 path_ = path;
53 }
54 void bindBand(const std::vector<std::shared_ptr<Matter>> &path) override {
55 bindPath(path);
56 }
57 [[nodiscard]] bool forwardsStoredCell() const noexcept override {
58 return true;
59 }
60
61 void force(long nAtoms, const double *positions, const int *atomicNrs,
62 double *forces, double *energy, double *variance,
63 const double *box) override {
64 const double *posv[] = {positions};
65 const int *nrv[] = {atomicNrs};
66 double *frcv[] = {forces};
67 const double *boxv[] = {box};
68 double e{0};
69 double var{0};
70 count_calls_ = false;
71 forceBatch(1, nAtoms, posv, nrv, frcv, &e, &var, boxv);
72 count_calls_ = true;
73 if (energy) {
74 *energy = e;
75 }
76 if (variance) {
77 *variance = var;
78 }
79 }
80
81 void forceBatch(long nSystems, long nAtoms, const double *const *positions,
82 const int *const *atomicNrs, double *const *forces,
83 double *energies, double *variances,
84 const double *const *boxes) override {
85 if (!fn_) {
86 throw std::runtime_error("HostSurfacePotential: NULL surface");
87 }
88 const long npos = 3 * nAtoms * nSystems;
89 const long nbox = 9 * nSystems;
90 std::vector<double> pos(static_cast<size_t>(npos), 0.0);
91 std::vector<double> frc(static_cast<size_t>(npos), 0.0);
92 std::vector<double> box(static_cast<size_t>(nbox), 0.0);
93 std::vector<int32_t> z(static_cast<size_t>(nAtoms), 0);
94 std::vector<int64_t> ids(static_cast<size_t>(nSystems), 0);
95 if (atomicNrs && atomicNrs[0]) {
96 for (long a = 0; a < nAtoms; ++a) {
97 z[static_cast<size_t>(a)] = atomicNrs[0][a];
98 }
99 }
100 for (long s = 0; s < nSystems; ++s) {
101 int64_t id = EON_RELAX_IMAGE_NONE;
102 if (positions && positions[s]) {
103 for (size_t i = 0; i < path_.size(); ++i) {
104 if (path_[i] && path_[i]->getPositions().data() == positions[s]) {
105 id = static_cast<int64_t>(i);
106 break;
107 }
108 }
109 }
110 ids[static_cast<size_t>(s)] = id;
111 if (positions && positions[s]) {
112 for (long k = 0; k < 3 * nAtoms; ++k) {
113 pos[static_cast<size_t>(s * 3 * nAtoms + k)] = positions[s][k];
114 }
115 }
116 if (boxes && boxes[s]) {
117 for (long k = 0; k < 9; ++k) {
118 box[static_cast<size_t>(s * 9 + k)] = boxes[s][k];
119 }
120 }
121 }
122 std::vector<double> ebuf(static_cast<size_t>(nSystems), 0.0);
123 std::vector<double> vbuf(static_cast<size_t>(nSystems), 0.0);
124 std::uint64_t new_epoch = epoch_;
128 req.n_images = static_cast<int64_t>(nSystems);
129 req.n_atoms = static_cast<int64_t>(nAtoms);
130 req.positions = pos.data();
131 req.atomic_nrs = z.data();
132 req.boxes = box.data();
133 req.image_ids = ids.data();
134 req.energies = ebuf.data();
135 req.forces = frc.data();
136 req.variances = vbuf.data();
137 req.epoch_out = &new_epoch;
138 last_ = fn_(user_, &req);
139 if (last_ < 0) {
140 throw std::runtime_error("HostSurfacePotential: surface failed");
141 }
142 if (last_ > 0) {
144 }
145 if (new_epoch != epoch_) {
146 epoch_ = new_epoch;
147 }
148 if (count_calls_) {
149 for (long s = 0; s < nSystems; ++s) {
151 }
152 }
153 for (long s = 0; s < nSystems; ++s) {
154 if (energies) {
155 energies[s] = ebuf[static_cast<size_t>(s)];
156 }
157 if (variances) {
158 variances[s] = vbuf[static_cast<size_t>(s)];
159 }
160 if (forces && forces[s]) {
161 for (long k = 0; k < 3 * nAtoms; ++k) {
162 forces[s][k] = frc[static_cast<size_t>(s * 3 * nAtoms + k)];
163 }
164 }
165 }
166 }
167
168private:
170 void *user_;
171 std::uint64_t epoch_{0};
172 int last_{0};
173 bool count_calls_{true};
174 std::vector<std::shared_ptr<Matter>> path_;
175};
176
177} // namespace eonc
int lastStatus() const noexcept
bool forwardsStoredCell() const noexcept override
A host that owns the cell reads the stored matrix.
void bindPath(const std::vector< std::shared_ptr< Matter > > &path)
void setEpoch(std::uint64_t epoch)
bool supportsBatchEvaluation() const noexcept override
Whether this potential supports batched evaluation of N systems in a single call.
HostSurfacePotential(eon_relax_surface_fn fn, void *user, std::uint64_t epoch)
unsigned long long surfaceEpoch() const noexcept override
Host-visible surface generation.
void forceBatch(long nSystems, long nAtoms, const double *const *positions, const int *const *atomicNrs, double *const *forces, double *energies, double *variances, const double *const *boxes) override
std::vector< std::shared_ptr< Matter > > path_
void force(long nAtoms, const double *positions, const int *atomicNrs, double *forces, double *energy, double *variance, const double *box) override
void bindBand(const std::vector< std::shared_ptr< Matter > > &path) override
NEB calls this with the finished band before the first force evaluation, so a host surface can name e...
void recordForceCall() noexcept
Charge one evaluated geometry to this potential and its owning registry.
Potential(PotType a_ptype)
Production default: construction-scope registry, else PotRegistry::get().
Tier-2 C ABI: eOn as a dlopen relaxation engine.
#define EON_RELAX_ABI_MAJOR
#define EON_RELAX_ABI_MINOR
#define EON_RELAX_IMAGE_NONE
int(* eon_relax_surface_fn)(void *user, eon_relax_surface_request_t *req)
Return 0 on success, positive recoverable, negative fatal.
RAII resource manager for the ARTn C library with global synchronization.
Host-surface request: one struct, engine-stamped version, so the callback contract grows behind the v...
const char * what() const noexcept override