32 auto true_params = std::make_shared<Parameters>(
params);
34 params.gp_surrogate_options().sub_job;
35 auto initial = std::make_shared<Matter>(
pot, *true_params);
38 throw std::runtime_error(
"failed to load " + reactantFilename);
40 auto final_state = std::make_shared<Matter>(
pot, *true_params);
43 throw std::runtime_error(
"failed to load " + productFilename);
49std::shared_ptr<NudgedElasticBand>
51 std::shared_ptr<Matter> final_state) {
52 if (!initial || !final_state) {
53 throw std::runtime_error(
"GPSurrogateJob::runFromMatter: null Matter");
56 auto true_params = std::make_shared<Parameters>(
params);
58 params.gp_surrogate_options().sub_job;
60 std::make_unique<Parameters>(*true_params), *
runtime_);
61 auto pyparams = std::make_shared<Parameters>(
params);
65 initial->setPotential(
pot);
66 final_state->setPotential(
pot);
68 *initial, *final_state,
params.neb_options().image_count);
72 magic_enum::enum_name<PotType>(
pot->getType()));
78 surpot->train_optimize(features, targets);
79 auto neb = std::make_unique<NudgedElasticBand>(initial, final_state,
81 auto status_neb{
neb->compute()};
82 bool job_not_finished{
true};
84 while (job_not_finished) {
90 EONC_LOG_TRACE(
"Must handle update to the GP, update number {}", n_gp);
91 auto [maxUnc, maxIndex] =
93 auto [feature, target] =
97 surpot->train_optimize(features, targets);
100 params.optimizer_options().converged_force * 0.8;
101 for (
auto &&obj :
neb->path) {
102 obj->setPotential(surpot);
104 if (!(pyparams->gp_surrogate_options().linear_path_always)) {
106 std::vector<Matter> previous;
107 previous.reserve(
neb->path.size());
108 for (
const auto &image :
neb->path) {
109 previous.push_back(*image);
111 neb = std::make_unique<NudgedElasticBand>(std::move(previous), *pyparams,
115 neb = std::make_unique<NudgedElasticBand>(initial, final_state, *pyparams,
118 status_neb =
neb->compute();
120 std::string nebFilename(std::format(
"neb_final_gpr_{:03d}.con", n_gp));
123 neb->path,
neb->tangent,
neb->eigenmode_solvers,
neb->numImages,
124 params.debug_options().estimate_neb_eigenvalues, nebFilename,
125 static_cast<size_t>(n_gp),
neb->reactantEnergy))) {
126 throw std::runtime_error(
"Failed to write file: " + nebFilename);
135 neb->printImageData();
138 std::shared_ptr<NudgedElasticBand> out(
neb.release());
147 std::unique_ptr<NudgedElasticBand>
neb) {
148 std::string resultsFilename =
"results.dat";
151 std::ofstream fileResults(resultsFilename);
154 throw std::runtime_error(
"Failed to open file: " + resultsFilename);
157 fileResults << static_cast<int>(status) <<
" termination_reason\n";
158 fileResults << magic_enum::enum_name(status) <<
" termination_reason_text\n";
159 fileResults << magic_enum::enum_name<PotType>(
160 params.potential_options().potential)
161 <<
" potential_type\n";
162 fileResults << std::format(
"{:.6f} energy_reference\n",
neb->reactantEnergy);
163 fileResults <<
neb->numImages <<
" number_of_images\n";
165 for (
long i = 0; i <=
neb->numImages + 1; i++) {
166 fileResults << std::format(
167 "{:.6f} image{}_energy\n",
168 neb->path[i]->getPotentialEnergy() -
neb->reactantEnergy, i);
169 fileResults << std::format(
"{:.6f} image{}_force\n",
170 neb->path[i]->getForces().norm(), i);
171 fileResults << std::format(
"{:.6f} image{}_projected_force\n",
172 neb->projectedForce[i]->norm(), i);
175 fileResults <<
neb->numExtrema <<
" number_of_extrema\n";
176 for (
long i = 0; i <
neb->numExtrema; i++) {
177 fileResults << std::format(
"{:.6f} extremum{}_position\n",
178 neb->extremumPosition[i], i);
179 fileResults << std::format(
"{:.6f} extremum{}_energy\n",
180 neb->extremumEnergy[i], i);
185 std::string nebFilename =
"neb.con";
189 neb->path,
neb->tangent,
neb->eigenmode_solvers,
neb->numImages,
190 params.debug_options().estimate_neb_eigenvalues, nebFilename,
191 std::nullopt,
neb->reactantEnergy))) {
192 throw std::runtime_error(
"Failed to write file: " + nebFilename);
196 neb->printImageData(
true);
204 MatrixXd features(matobjs.size(), matobjs.front().numberOfFreeAtoms() * 3);
206 matobjs.front().numberOfFreeAtoms() * 3);
207 for (
long idx{0}; idx < features.rows(); idx++) {
208 features.row(idx) = matobjs[idx].getPositionsFreeV();
210 std::ostringstream oss;
217 MatrixXd features(matobjs.size(), matobjs.front()->numberOfFreeAtoms() * 3);
219 matobjs.front()->numberOfFreeAtoms() * 3);
220 for (
long idx{0}; idx < features.rows(); idx++) {
221 features.row(idx) = matobjs[idx]->getPositionsFreeV();
223 std::ostringstream oss;
229 std::shared_ptr<Potential> true_pot) {
232 const auto nrows = matobjs.size();
233 const auto ncols = (matobjs.front().numberOfFreeAtoms() * 3) + 1;
235 for (
long idx{0}; idx < targets.rows(); idx++) {
236 matobjs[idx].setPotential(true_pot);
237 targets.row(idx)[0] = matobjs[idx].getPotentialEnergy();
238 targets.block(idx, 1, 1, ncols - 1) =
239 matobjs[idx].getForcesFreeV().array() * -1;
241 std::ostringstream oss;
247 std::shared_ptr<Potential> true_pot) {
248 const auto nrows = matobjs.size();
249 const auto ncols = (matobjs.front()->numberOfFreeAtoms() * 3) + 1;
251 for (
long idx{0}; idx < targets.rows(); idx++) {
252 matobjs[idx]->setPotential(true_pot);
253 targets.row(idx)[0] = matobjs[idx]->getPotentialEnergy();
254 targets.block(idx, 1, 1, ncols - 1) =
255 matobjs[idx]->getForcesFreeV().array() * -1;
257 std::ostringstream oss;
262std::vector<Matter>
getMidSlice(
const std::vector<Matter> &matobjs) {
266 if (matobjs.size() < 3) {
267 throw std::invalid_argument(
"getMidSlice: need at least three images");
269 const std::size_t n = matobjs.size();
270 const std::size_t twoThirds =
271 static_cast<std::size_t
>(((n - 2) * 2.0 / 3.0) + 1.0);
272 return {matobjs.front(), matobjs.back(), matobjs[twoThirds]};
276 Eigen::VectorXd target(ncols);
282std::pair<double, Eigen::VectorXd::Index>
284 if (matobjs.size() < 3) {
285 throw std::invalid_argument(
286 "getMaxUncertainty: need at least three images");
288 Eigen::VectorXd pathUncertainty{Eigen::VectorXd::Zero(matobjs.size() - 2)};
289 for (
auto idx{0}; idx < pathUncertainty.size(); idx++) {
290 pathUncertainty[idx] = matobjs[idx + 1]->getEnergyVariance();
292 Eigen::VectorXd::Index maxIndex;
293 double maxUnc{pathUncertainty.maxCoeff()};
294 pathUncertainty.maxCoeff(&maxIndex);
295 return std::make_pair(maxUnc, maxIndex);
297std::pair<Eigen::VectorXd, Eigen::VectorXd>
299 std::shared_ptr<Potential> true_pot) {
301 Matter candidate{*matobjs[maxIndex + 1]};
302 return std::make_pair<Eigen::VectorXd, Eigen::VectorXd>(
306 std::shared_ptr<Potential> true_pot) {
307 if (matobjs.empty()) {
308 throw std::invalid_argument(
"accuratePES: empty path");
310 Eigen::VectorXd predEnergies{Eigen::VectorXd::Zero(matobjs.size())};
311 Eigen::VectorXd trueEnergies{Eigen::VectorXd::Zero(matobjs.size())};
312 for (
auto idx{0}; idx < predEnergies.size(); idx++) {
313 auto incoming = matobjs[idx]->getPotential();
314 predEnergies[idx] = matobjs[idx]->getPotentialEnergy();
315 matobjs[idx]->setPotential(true_pot);
316 trueEnergies[idx] = matobjs[idx]->getPotentialEnergy();
317 matobjs[idx]->setPotential(incoming);
319 Eigen::VectorXd difference = predEnergies - trueEnergies;
320 const auto maxAbs = difference.array().abs().maxCoeff();
321 std::ostringstream oss;
323 << predEnergies <<
"\ntrue\n"
324 << trueEnergies <<
"\ndifference\n"
325 << difference <<
"\n maxAbs: " << maxAbs;
327 return maxAbs < 0.05;
333 assert(m1.cols() == m2.cols());
334 MatrixXd res(m1.rows() + m2.rows(), m2.cols());
339 assert(data.cols() == newrow.size());
340 data.conservativeResize(data.rows() + 1, data.cols());
341 data.row(data.rows() - 1) = newrow;
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, eOnStorageOrder > MatrixXd
#define EONC_LOG_TRACE(...)
Convenience macro for one-shot logging without storing a logger.
#define EONC_LOG_CRITICAL(...)
std::shared_ptr< NudgedElasticBand > runFromMatter(std::shared_ptr< Matter > initial, std::shared_ptr< Matter > final_state)
Matter-first NEB surrogate path (endpoints as Matter).
std::vector< std::string > run() override
Virtual run; used solely for dynamic dispatch.
std::vector< std::string > returnFiles
void saveData(NudgedElasticBand::NEBStatus status, std::unique_ptr< NudgedElasticBand > neb)
std::shared_ptr< Potential > pot
Runtime * runtime_
Always valid: either owned_runtime_.get() or a caller-owned Runtime.
VectorXd getForcesFreeV() const
void setPotential(std::shared_ptr< Potential > pot)
VectorXd getPositionsFreeV() const
double getPotentialEnergy() const
long int numberOfFreeAtoms() const
MatrixXd vertCat(const MatrixXd &m1, const MatrixXd &m2)
void addVectorRow(MatrixXd &data, const Eigen::VectorXd &newrow)
std::vector< Matter > linearPath(const Matter &initImg, const Matter &finalImg, const size_t nimgs)
MatrixXd get_targets(std::vector< Matter > &matobjs, std::shared_ptr< Potential > true_pot)
MatrixXd get_features(const std::vector< Matter > &matobjs)
bool accuratePES(std::vector< std::shared_ptr< Matter > > &matobjs, std::shared_ptr< Potential > true_pot)
std::pair< double, Eigen::VectorXd::Index > getMaxUncertainty(const std::vector< std::shared_ptr< Matter > > &matobjs)
std::vector< Matter > getMidSlice(const std::vector< Matter > &matobjs)
std::pair< Eigen::VectorXd, Eigen::VectorXd > getNewDataPoint(const std::vector< std::shared_ptr< Matter > > &matobjs, std::shared_ptr< Potential > true_pot)
Eigen::VectorXd make_target(Matter &m1, std::shared_ptr< Potential > true_pot)
std::string getRelevantFile(std::string filename)
std::unique_ptr< Job > makeJob(std::unique_ptr< Parameters > params, Runtime &runtime)
Borrow: caller keeps Runtime alive.
constexpr bool io_ok(IoStatus s) noexcept
eonc::io::IoStatus writePathCon(const std::vector< std::shared_ptr< Matter > > &path, const std::vector< std::shared_ptr< AtomMatrix > > &tangent, const std::vector< std::shared_ptr< EigenmodeStrategy > > &eigenmode_solvers, long numImages, bool estimateEigenvalues, std::string filename, std::optional< size_t > bandIndex, double referenceEnergy)
Write a NEB band as a multi-frame .con via readcon ConFrameBuilder::clone().
RAII resource manager for the ARTn C library with global synchronization.
std::shared_ptr< eonc::SurrogatePotential > makeSurrogatePotential(eonc::PotType a_ptype, const eonc::Parameters &a_params, Args &&...a_args)
static main_options_t & main_options(Parameters &p)
static neb_options_t & neb_options(Parameters &p)
static optimizer_options_t & optimizer_options(Parameters &p)
static potential_options_t & potential_options(Parameters &p)
struct eonc::neb_options_t::climbing_image_options_t climbing_image