Loading...
Searching...
No Matches
RGPotEngine.cpp
Go to the documentation of this file.
1// Isolated TU: rgpot only (no eOn Potential.h) — avoids Cap'n Proto Potential
2// clash.
4
5#include <array>
6#include <cctype>
7#include <cstdint>
8#include <cstdlib>
9#include <stdexcept>
10#include <tuple>
11#include <vector>
12
13#include <capnp/message.h>
14
17#include "rgpot/CPMDPot/CPMDPot.hpp"
18#include "rgpot/NWChemPot/NWChemPot.hpp"
19#include "rgpot/rpc/Potentials.capnp.h"
20
21using rgpot::types::AtomMatrix;
22
23namespace {
24
25std::string to_lower(std::string s) {
26 for (char &c : s)
27 c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
28 return s;
29}
30
31std::array<std::array<double, 3>, 3> box_from_row_major(const double *box) {
32 std::array<std::array<double, 3>, 3> out{};
33 for (int i = 0; i < 3; ++i)
34 for (int j = 0; j < 3; ++j)
35 out[static_cast<size_t>(i)][static_cast<size_t>(j)] = box[i * 3 + j];
36 return out;
37}
38
39bool looks_like_dft_xc(const std::string &s) {
40 if (s.empty())
41 return false;
42 static const char *k[] = {"b3lyp", "blyp", "pbe", "pw91", "bp86",
43 "hcth", "ft97", "hfexch", "xperpbe", nullptr};
44 for (int i = 0; k[i]; ++i) {
45 if (s.size() >= std::char_traits<char>::length(k[i]) &&
46 s.compare(0, std::char_traits<char>::length(k[i]), k[i]) == 0)
47 return true;
48 }
49 return false;
50}
51
53int xtb_method_from_paramset(const std::string &paramset) {
54 const std::string p = to_lower(paramset);
55 if (p == "gfnff" || p == "gfn-ff")
57 if (p == "gfn0xtb" || p == "gfn0" || p == "gfn0-xtb")
59 if (p == "gfn1xtb" || p == "gfn1" || p == "gfn1-xtb")
61 if (p == "gfn2xtb" || p == "gfn2" || p == "gfn2-xtb" || p.empty())
63 throw std::runtime_error(
64 "RGPOT(xtb): paramset must be GFNFF, GFN0xTB, GFN1xTB, or GFN2xTB "
65 "(got '" +
66 paramset + "')");
67}
68
69} // namespace
70
72 enum class Backend { Nwchemc, Cpmdc, Metatomic, Xtb };
74 std::unique_ptr<rgpot::NWChemPot> nwchem;
75 std::unique_ptr<rgpot::CPMDPot> cpmd;
76 std::unique_ptr<MetatomicEngineLoader> metatomic;
77 std::unique_ptr<XTBEngineLoader> xtb;
78};
79
81 : impl_(std::make_unique<Impl>()) {
82 backend_ = to_lower(opt.backend);
83 if (backend_ == "nwchem" || backend_ == "nwchemc" ||
84 backend_ == "nwchempot") {
85 backend_ = "nwchemc";
87 ::capnp::MallocMessageBuilder msg;
88 auto params = msg.initRoot<::NWChemParams>();
89 params.setBasis(opt.basis);
90 params.setTheory(opt.theory);
91 params.setScfType(opt.scf_type);
92 params.setCharge(opt.charge);
93 params.setMultiplicity(opt.multiplicity);
94 if (!opt.engine_path.empty())
95 params.setEnginePath(opt.engine_path);
96 else if (!opt.engine_library.empty())
97 params.setEnginePath(opt.engine_library);
98 if (!opt.engine_root.empty())
99 params.setNwchemRoot(opt.engine_root);
100 if (!opt.title.empty())
101 params.setTitle(opt.title);
102 if (opt.memory_mb > 0)
103 params.setMemoryMb(static_cast<uint32_t>(opt.memory_mb));
104 if (!opt.scratch_dir.empty())
105 params.setScratchDir(opt.scratch_dir);
106 // DFT XC as inputBlocks when theory=dft and scfType is an XC label
107 std::string block = opt.input_block;
108 if (block.empty()) {
109 if (const char *env = std::getenv("RGPOT_NWCHEM_INPUT_BLOCK"))
110 block = env;
111 }
112 if (block.empty() && (opt.theory == "dft" || opt.theory == "DFT") &&
113 looks_like_dft_xc(opt.scf_type)) {
114 block = "dft\n xc " + opt.scf_type + "\n mult " +
115 std::to_string(opt.multiplicity) + "\nend";
116 } else if (block.empty() && looks_like_dft_xc(opt.theory)) {
117 block = "dft\n xc " + opt.theory + "\n mult " +
118 std::to_string(opt.multiplicity) + "\nend";
119 }
120 if (!block.empty()) {
121 auto blocks = params.initInputBlocks(1);
122 blocks.set(0, block);
123 }
124 impl_->nwchem = std::make_unique<rgpot::NWChemPot>(params.asReader());
125 if (!impl_->nwchem->available())
126 throw std::runtime_error(
127 "RGPOT(nwchemc): engine not available (set NWCHEMC_LIBRARY / "
128 "RGPOT_NWCHEMC_ENGINE or [RgpotPot] engine_path)");
129 } else if (backend_ == "cpmd" || backend_ == "cpmdc" ||
130 backend_ == "cpmdpot") {
131 backend_ = "cpmdc";
132 impl_->backend = Impl::Backend::Cpmdc;
133 ::capnp::MallocMessageBuilder msg;
134 auto params = msg.initRoot<::CPMDParams>();
135 params.setFunctional(opt.functional);
136 params.setCutOffRy(opt.cutoff_ry);
137 params.setCharge(opt.charge);
138 params.setMultiplicity(opt.multiplicity);
139 if (!opt.engine_path.empty())
140 params.setEnginePath(opt.engine_path);
141 else if (!opt.engine_library.empty())
142 params.setEnginePath(opt.engine_library);
143 if (!opt.engine_root.empty())
144 params.setCpmdRoot(opt.engine_root);
145 if (!opt.title.empty())
146 params.setTitle(opt.title);
147 if (opt.memory_mb > 0)
148 params.setMemoryMb(static_cast<uint32_t>(opt.memory_mb));
149 if (!opt.scratch_dir.empty())
150 params.setScratchDir(opt.scratch_dir);
151 impl_->cpmd = std::make_unique<rgpot::CPMDPot>(params.asReader());
152 if (!impl_->cpmd->available())
153 throw std::runtime_error(
154 "RGPOT(cpmdc): engine not available (set CPMDC_LIBRARY / "
155 "RGPOT_CPMDC_ENGINE or [RgpotPot] engine_path)");
156 } else if (backend_ == "metatomic" || backend_ == "mta" ||
157 backend_ == "metatomicpot") {
158 backend_ = "metatomic";
161 mopt.model_path = opt.model_path;
162 mopt.device = opt.device;
163 mopt.length_unit = opt.length_unit;
167 mopt.engine_path =
168 !opt.engine_path.empty() ? opt.engine_path : opt.engine_library;
170 impl_->metatomic = std::make_unique<MetatomicEngineLoader>(mopt);
171 if (!impl_->metatomic->available())
172 throw std::runtime_error(
173 "RGPOT(metatomic): engine not available (set RGPOT_METATOMIC_ENGINE "
174 "or [RgpotPot] engine_path to libmetatomic_engine.so)");
175 } else if (backend_ == "xtb" || backend_ == "xtbpot" || backend_ == "gfn" ||
176 backend_ == "gfnxtb") {
177 backend_ = "xtb";
178 impl_->backend = Impl::Backend::Xtb;
179 XTBEngineOptions xopt;
180 xopt.method = xtb_method_from_paramset(opt.xtb_paramset);
181 xopt.accuracy = opt.xtb_accuracy;
184 xopt.charge = opt.xtb_charge;
185 xopt.uhf = opt.xtb_uhf;
186 xopt.engine_path =
187 !opt.engine_path.empty() ? opt.engine_path : opt.engine_library;
188 impl_->xtb = std::make_unique<XTBEngineLoader>(xopt);
189 if (!impl_->xtb->available())
190 throw std::runtime_error(
191 "RGPOT(xtb): engine not available (set RGPOT_XTB_ENGINE or "
192 "[RgpotPot] engine_path to libxtb_engine.so)");
193 } else {
194 throw std::runtime_error("RGPOT: unknown backend '" + opt.backend +
195 "' (expected nwchemc, cpmdc, metatomic, or xtb)");
196 }
197}
198
199RGPotEngine::~RGPotEngine() = default;
200
202 if (!impl_)
203 return false;
204 if (impl_->backend == Impl::Backend::Nwchemc && impl_->nwchem)
205 return impl_->nwchem->available();
206 if (impl_->backend == Impl::Backend::Cpmdc && impl_->cpmd)
207 return impl_->cpmd->available();
208 if (impl_->backend == Impl::Backend::Metatomic && impl_->metatomic)
209 return impl_->metatomic->available();
210 if (impl_->backend == Impl::Backend::Xtb && impl_->xtb)
211 return impl_->xtb->available();
212 return false;
213}
214
215void RGPotEngine::force(long N, const double *R, const int *atomicNrs,
216 double *F, double *U, const double *box) const {
217 if (N <= 0)
218 throw std::runtime_error("RGPotEngine::force called with N <= 0");
219
220 AtomMatrix positions(static_cast<int>(N), 3);
221 for (long i = 0; i < N; ++i) {
222 const int ii = static_cast<int>(i);
223 positions(ii, 0) = R[3 * i + 0];
224 positions(ii, 1) = R[3 * i + 1];
225 positions(ii, 2) = R[3 * i + 2];
226 }
227 std::vector<int> atmtypes(atomicNrs, atomicNrs + N);
228 const auto cell = box_from_row_major(box);
229
230 if (impl_->backend == Impl::Backend::Metatomic) {
231 impl_->metatomic->force(N, R, atomicNrs, F, U, nullptr, box);
232 return;
233 }
234 if (impl_->backend == Impl::Backend::Xtb) {
235 impl_->xtb->force(N, R, atomicNrs, F, U, nullptr, box);
236 return;
237 }
238
239 // rgpot >= 2.5.0: operator() returns (energy, forces, variance).
240 std::tuple<double, AtomMatrix, double> result;
241 if (impl_->backend == Impl::Backend::Nwchemc)
242 result = (*impl_->nwchem)(positions, atmtypes, cell);
243 else
244 result = (*impl_->cpmd)(positions, atmtypes, cell);
245
246 *U = std::get<0>(result);
247 const auto &forces = std::get<1>(result);
248 for (long i = 0; i < N; ++i) {
249 const int ii = static_cast<int>(i);
250 F[3 * i + 0] = forces(ii, 0);
251 F[3 * i + 1] = forces(ii, 1);
252 F[3 * i + 2] = forces(ii, 2);
253 }
254}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
bool available() const
RGPotEngine(const RGPotEngineOptions &opt)
std::unique_ptr< Impl > impl_
Definition RGPotEngine.h:54
std::string backend_
Definition RGPotEngine.h:55
void force(long N, const double *R, const int *atomicNrs, double *F, double *U, const double *box) const
std::string scf_type
Definition RGPotEngine.h:10
std::string title
Definition RGPotEngine.h:18
std::string xtb_paramset
Definition RGPotEngine.h:31
std::string basis
Definition RGPotEngine.h:8
std::string scratch_dir
Definition RGPotEngine.h:20
std::string engine_path
Definition RGPotEngine.h:15
std::string backend
Definition RGPotEngine.h:7
std::string extensions_directory
Definition RGPotEngine.h:26
std::string engine_library
Definition RGPotEngine.h:16
double xtb_electronic_temperature
Definition RGPotEngine.h:33
std::string functional
Definition RGPotEngine.h:11
std::string length_unit
Definition RGPotEngine.h:25
bool torch_determinism_strict
Definition RGPotEngine.h:29
std::string device
Definition RGPotEngine.h:24
std::string model_path
Definition RGPotEngine.h:23
std::string engine_root
Definition RGPotEngine.h:17
double uncertainty_threshold
Definition RGPotEngine.h:28
std::string theory
Definition RGPotEngine.h:9
std::string input_block
Definition RGPotEngine.h:21
std::unique_ptr< rgpot::NWChemPot > nwchem
std::unique_ptr< rgpot::CPMDPot > cpmd
std::unique_ptr< MetatomicEngineLoader > metatomic
std::unique_ptr< XTBEngineLoader > xtb
std::string engine_path
double electronic_temperature
@ RGPOT_XTB_METHOD_GFNFF
Definition xtb_c_abi.h:32
@ RGPOT_XTB_METHOD_GFN1
Definition xtb_c_abi.h:34
@ RGPOT_XTB_METHOD_GFN2
Definition xtb_c_abi.h:35
@ RGPOT_XTB_METHOD_GFN0
Definition xtb_c_abi.h:33