21#include "rgpot/ForceStructs.hpp"
22#include "rgpot/pot_caps.hpp"
37 requires(!std::is_base_of_v<eonc::IPluginLoader, std::remove_cvref_t<Cfg>>)
43 requires(!std::is_base_of_v<eonc::IPluginLoader, std::remove_cvref_t<Cfg>>)
67 eonc::PluginLoader::instance()) {}
76 void force(
long N,
const double *R,
const int *atomicNrs,
double *F,
77 double *U,
double *variance,
const double *box)
override {
78 rgpot::ForceInput in{
static_cast<size_t>(N), R, atomicNrs, box};
79 rgpot::ForceOut out{F, 0.0, 0.0};
80 pot_.forceImpl(in, &out);
82 if (variance !=
nullptr) {
83 *variance = out.variance;
96 throw std::logic_error(
"rgpot kernel did not return a stress tensor");
106 return pot_.caps().batched;
117 void forceBatch(
long nSystems,
long nAtoms,
const double *
const *positions,
118 const int *
const *atomicNrs,
double *
const *forces,
119 double *energies,
double *variances,
120 const double *
const *boxes)
override {
121 const auto n =
static_cast<size_t>(nSystems);
122 std::vector<rgpot::ForceInput> in;
123 std::vector<rgpot::ForceOut> out;
126 for (
size_t i = 0; i < n; ++i) {
127 in.push_back(rgpot::ForceInput{
static_cast<size_t>(nAtoms), positions[i],
128 atomicNrs[i], boxes[i]});
129 out.push_back(rgpot::ForceOut{forces[i], 0.0, 0.0});
133 rgpot::ForceBatch{.nSystems = n, .in = in.data(), .out = out.data()});
136 for (
size_t i = 0; i < n; ++i) {
137 energies[i] = out[i].energy;
138 if (variances !=
nullptr) {
139 variances[i] = out[i].variance;
141 if (out[i].has_stress) {
150 return pot_.caps().reentrancy == rgpot::Reentrancy::SharedInstance;
157 return !
pot_.caps().periodic;
161 const auto caps =
pot_.caps();
162 return caps.perImageInstances ||
163 caps.reentrancy == rgpot::Reentrancy::PerInstance;
166 [[nodiscard]]
const RPot &
kernel() const noexcept {
return pot_; }
171 if constexpr (
requires(
const RPot &k) { k.config().cutoff; }) {
172 return pot_.config().cutoff;
185 const auto caps =
pot_.caps();
186 using R = rgpot::Reentrancy;
187 if (caps.reentrancy != R::SharedInstance &&
188 caps.reentrancy != R::PerInstance &&
189 caps.reentrancy != R::ProcessSerial) {
190 throw std::runtime_error(
"rgpot kernel advertised an unknown reentrancy");
199 for (
int row = 0; row < 3; ++row) {
200 for (
int col = 0; col < 3; ++col) {
201 stress_(row, col) = out.stress[row * 3 + col];
215std::shared_ptr<eonc::Potential>
217 return std::make_shared<RgpotAdapter<RPot>>(ptype, params);
221template <
class RPot,
class Cfg>
222std::shared_ptr<eonc::Potential>
224 return std::make_shared<RgpotAdapter<RPot>>(ptype, params, cfg);
Eigen::Matrix< double, 3, 3, eOnStorageOrder > Matrix3d
std::shared_ptr< eonc::Potential > makeRgpotDefault(eonc::PotType ptype, const eonc::Parameters ¶ms)
Factory arm helper for kernels whose parameters are fixed tabulated data with no eOn-side configurati...
std::shared_ptr< eonc::Potential > makeRgpot(eonc::PotType ptype, const eonc::Parameters ¶ms, const Cfg &cfg)
Factory arm helper: construct the kernel from its config and wrap it.
RgpotAdapter(eonc::PotType ptype, const eonc::Parameters ¶ms, RPot &&kernel)
Take a pre-built kernel (ExprPot and other move-only constructors).
bool isThreadSafe() const noexcept override
Whether this potential's force() can be called from multiple threads on the SAME instance.
bool supportsBatchEvaluation() const noexcept override
Reports whether the kernel serves a batch natively.
bool requiresIsolatedMoleculeLayout() const noexcept override
Kernels that do not implement periodic boundaries must not have their coordinates wrapped.
eonc::IPluginLoader & loader_
RgpotAdapter(eonc::PotType ptype, const eonc::Parameters ¶ms)
Kernels with no configuration surface default-construct in place.
bool computesStress() const noexcept override
True when force() leaves a Cauchy stress that cauchyStress() can read until the next force() on this ...
void force(long N, const double *R, const int *atomicNrs, double *F, double *U, double *variance, const double *box) override
RgpotAdapter(eonc::PotType ptype, const eonc::Parameters ¶ms, eonc::IPluginLoader &loader)
Test seam: injected loader, no process-default search-path mutation.
const RPot & kernel() const noexcept
void validateCaps() const
void storeStress(const rgpot::ForceOut &out)
void finishConstruct(const eonc::Parameters ¶ms)
RgpotAdapter(eonc::PotType ptype, const eonc::Parameters ¶ms, const Cfg &cfg)
Kernels construct in place from their config: several hold mutexes or other immovable state,...
bool needsPerImageInstance() const noexcept override
Whether NEB should create separate Potential instances per image for true parallel force evaluation.
Matrix3d cauchyStress() const override
Cauchy stress from the last force() that reported one.
double finiteCutoff() const noexcept override
Classical kernels expose config().cutoff.
RgpotAdapter(eonc::PotType ptype, const eonc::Parameters ¶ms, const Cfg &cfg, eonc::IPluginLoader &loader)
Test seam: injected loader, no process-default search-path mutation.
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
Hands eOn's batch straight to the kernel.
RgpotAdapter(eonc::PotType ptype, const eonc::Parameters ¶ms, RPot &&kernel, eonc::IPluginLoader &loader)
Test seam: injected loader, no process-default search-path mutation.
const potential_options_t & potential_options() const
static PluginLoader & instance()
Thread-safe singleton accessor (Meyer's pattern).
void on_force_call(PotType t) noexcept override
static PotRegistry & get() noexcept
Process-lifetime singleton.
std::atomic< size_t > forceCallCounter
Potential(PotType a_ptype)
Production default: construction-scope registry, else PotRegistry::get().
RAII resource manager for the ARTn C library with global synchronization.
std::string potentialsPath