Loading...
Searching...
No Matches
ProcessSearchJob Class Reference

Declaration of the Process Search job. More...

#include <ProcessSearchJob.h>

Inheritance diagram for ProcessSearchJob:

Public Member Functions

 ProcessSearchJob (std::unique_ptr< Parameters > parameters)
 Process Search job Constructor.
 ~ProcessSearchJob ()=default
 Process Search job De-constructor.
std::vector< std::string > run (void) override
 Kicks off the Process Search.
Public Member Functions inherited from eonc::Job
 Job (std::unique_ptr< Parameters > parameters)
 Job (std::shared_ptr< Potential > potPassed, const Parameters &parameters)
virtual ~Job ()=default
JobType getType ()

Private Member Functions

int doProcessSearch (void)
 Runs the correct saddle search; also checks if the run was successful.
void printEndState (int status)
 Logs the run status and makes sure the run was successful.
void saveData (int status)
 Writes the results from the run to file.

Private Attributes

eonc::log::Scoped log
std::vector< std::string > returnFiles
 Container for the results of the run.
std::unique_ptr< SaddleSearchMethodsaddleSearch
 Pulled from parameters.
std::shared_ptr< Matterinitial
 Initial configuration.
std::shared_ptr< Mattersaddle
 Configuration used during the saddle point search.
std::shared_ptr< Matterdisplacement
 Configuration used during the saddle point search.
std::shared_ptr< Mattermin1
 First minimum from the saddle.
std::shared_ptr< Mattermin2
 Second minimum from the saddle.
double barriersValues [2] {0.0, 0.0}
double prefactorsValues [2] {0.0, 0.0}
size_t fCallsSaddle {0}
 Force calls to find the saddle.
size_t fCallsMin {0}
 Force calls to minimize.
size_t fCallsPrefactors {0}
 Force calls to find the prefactors.

Additional Inherited Members

Protected Attributes inherited from eonc::Job
JobType jtype
Parameters params
std::shared_ptr< Potentialpot

Detailed Description

Declaration of the Process Search job.

Definition at line 45 of file ProcessSearchJob.h.

Constructor & Destructor Documentation

◆ ProcessSearchJob()

eonc::ProcessSearchJob::ProcessSearchJob ( std::unique_ptr< Parameters > parameters)
inline

Process Search job Constructor.

Parameters
*paramsdefined by the config.init file

Definition at line 51 of file ProcessSearchJob.h.

52 : Job(std::move(parameters)),
53 fCallsSaddle{0},
54 fCallsMin{0},
size_t fCallsPrefactors
Force calls to find the prefactors.
size_t fCallsMin
Force calls to minimize.
size_t fCallsSaddle
Force calls to find the saddle.
Job(std::unique_ptr< Parameters > parameters)
Definition Job.h:58

◆ ~ProcessSearchJob()

Process Search job De-constructor.

Member Function Documentation

◆ doProcessSearch()

int ProcessSearchJob::doProcessSearch ( void )
private

Runs the correct saddle search; also checks if the run was successful.

Definition at line 165 of file ProcessSearchJob.cpp.

165 {
166 Matter matterTemp(pot, params);
167 long status;
168 size_t fctmp{0};
169
170 fctmp = pot->forceCallCounter;
171 status = saddleSearch->run();
172 if (params.saddle_search_options.method == "min_mode" &&
173 params.saddle_search_options.minmode_method ==
175 fCallsSaddle += saddleSearch->getForceCalls();
176 } else if (params.saddle_search_options.method == "artn") {
177 fCallsSaddle += saddleSearch->getForceCalls();
178 } else {
179 fCallsSaddle += pot->forceCallCounter - fctmp;
180 }
181 EONC_LOG_DEBUG("Got {} calls in the saddle search, with previous {}",
182 fCallsSaddle, fctmp);
183
184 if (status != MinModeSaddleSearch::STATUS_GOOD) {
185 return status;
186 }
187
188 AtomMatrix posSaddle = saddle->getPositions();
189 AtomMatrix displacedPos;
190
191 *min1 = *saddle;
192
193 displacedPos =
194 posSaddle - saddleSearch->getEigenvector() *
195 params.process_search_options.minimization_offset;
196 min1->setPositions(displacedPos);
197
198 *min2 = *saddle;
199 displacedPos =
200 posSaddle + saddleSearch->getEigenvector() *
201 params.process_search_options.minimization_offset;
202 min2->setPositions(displacedPos);
203
204 // Minimize both endpoints concurrently when the shared potential instance is
205 // safe to call from multiple threads, or when each endpoint owns a separate
206 // potential instance.
207 QUILL_LOG_DEBUG(log, "Starting Minimization 1 & 2");
208 bool converged1{false}, converged2{false};
209 long fc1_before = min1->getPotentialCalls();
210 long fc2_before = min2->getPotentialCalls();
211
212 bool canParallel =
213 pot->isSharedInstanceThreadSafe() || pot->needsPerImageInstance();
214 if (params.main_options.parallel && canParallel) {
215 std::thread t1([&] {
216 converged1 =
217 min1->relax(false, params.debug_options.write_movies, false, "min1");
218 });
219 converged2 =
220 min2->relax(false, params.debug_options.write_movies, false, "min2");
221 t1.join();
222 } else {
223 converged1 =
224 min1->relax(false, params.debug_options.write_movies, false, "min1");
225 converged2 =
226 min2->relax(false, params.debug_options.write_movies, false, "min2");
227 }
228
229 fCallsMin += (min1->getPotentialCalls() - fc1_before) +
230 (min2->getPotentialCalls() - fc2_before);
231 QUILL_LOG_DEBUG(log, "Min1: {} fcalls, Min2: {} fcalls",
232 min1->getPotentialCalls() - fc1_before,
233 min2->getPotentialCalls() - fc2_before);
234
235 if (!converged1 || !converged2) {
237 }
238
239 if (!(initial->compare(*min1)) && initial->compare(*min2)) {
240 matterTemp = *min1;
241 *min1 = *min2;
242 *min2 = matterTemp;
243 }
244
245 if (!initial->compare(*min1)) {
246 // Report how far off the endpoint landed. Whether the minimisation
247 // stopped just outside the state-identity tolerance or relaxed into a
248 // different state entirely calls for opposite fixes, and the status
249 // alone does not distinguish them.
250 const double tol = params.structure_comparison_options.distance_difference;
251 auto countMoved = [&](const Matter &m) {
252 long moved = 0;
253 for (long i = 0; i < initial->numberOfAtoms(); ++i) {
254 if (initial
255 ->pbc(initial->getPositions().row(i) - m.getPositions().row(i))
256 .norm() > tol) {
257 ++moved;
258 }
259 }
260 return moved;
261 };
262 QUILL_LOG_INFO(log,
263 "initial != min1: {} of {} atoms past the {} A tolerance "
264 "for min1 ({} for min2); largest separation {} A",
265 countMoved(*min1), initial->numberOfAtoms(), tol,
266 countMoved(*min2), initial->perAtomNorm(*min1));
268 }
269
270 if (initial->compare(*min2)) {
271 QUILL_LOG_DEBUG(log, "both minima are the initial state");
273 }
274
275 if (!params.process_search_options.minimize_first) {
276 min1 = initial;
277 }
278
279 barriersValues[0] = saddle->getPotentialEnergy() - min1->getPotentialEnergy();
280 barriersValues[1] = saddle->getPotentialEnergy() - min2->getPotentialEnergy();
281
282 if ((params.saddle_search_options.max_energy < barriersValues[0]) ||
283 (params.saddle_search_options.max_energy < barriersValues[1])) {
285 }
286
287 if (barriersValues[0] < 0.0 || barriersValues[1] < 0.0) {
289 }
290
291 if (!params.prefactor_options.default_value) {
292 fctmp = min1->getPotentialCalls();
293 int prefStatus;
294 double pref1, pref2;
296 params, min1.get(), saddle.get(), min2.get(), pref1, pref2);
297 if (prefStatus == -1) {
298 EONC_LOG_ERROR("Prefactor: bad calculation");
300 }
301 fCallsPrefactors += min1->getPotentialCalls() - fctmp;
302
303 if ((pref1 > params.prefactor_options.max_value) ||
304 (pref1 < params.prefactor_options.min_value)) {
305 EONC_LOG_ERROR("Bad reactant-to-saddle prefactor: {}", pref1);
307 }
308 if ((pref2 > params.prefactor_options.max_value) ||
309 (pref2 < params.prefactor_options.min_value)) {
310 EONC_LOG_ERROR("Bad product-to-saddle prefactor: {}", pref2);
312 }
313 prefactorsValues[0] = pref1;
314 prefactorsValues[1] = pref2;
315
316 } else {
317 prefactorsValues[0] = params.prefactor_options.default_value;
318 prefactorsValues[1] = params.prefactor_options.default_value;
319 }
321}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
#define EONC_LOG_DEBUG(...)
Definition EonLogger.h:244
#define EONC_LOG_ERROR(...)
Definition EonLogger.h:262
eonc::log::Scoped log
std::shared_ptr< Matter > min1
First minimum from the saddle.
double prefactorsValues[2]
std::shared_ptr< Matter > min2
Second minimum from the saddle.
std::shared_ptr< Matter > saddle
Configuration used during the saddle point search.
std::shared_ptr< Matter > initial
Initial configuration.
std::unique_ptr< SaddleSearchMethod > saddleSearch
Pulled from parameters.
std::shared_ptr< Potential > pot
Definition Job.h:55
Parameters params
Definition Job.h:54
static const char MINMODE_GPRDIMER[]
int getPrefactors(const Parameters &parameters, Matter *min1, Matter *saddle, Matter *min2, double &pref1, double &pref2)
Definition Prefactor.cpp:22

◆ printEndState()

void ProcessSearchJob::printEndState ( int status)
private

Logs the run status and makes sure the run was successful.

Definition at line 393 of file ProcessSearchJob.cpp.

393 {
394 auto msg = saddleSearch->describeStatus(status);
395 if (status == MinModeSaddleSearch::STATUS_GOOD) {
396 QUILL_LOG_DEBUG(log, "[Saddle Search] {}", msg);
397 } else {
398 QUILL_LOG_ERROR(log, "[Saddle Search] {}", msg);
399 }
400}

◆ run()

std::vector< std::string > ProcessSearchJob::run ( void )
overridevirtual

Kicks off the Process Search.

Implements eonc::Job.

Definition at line 34 of file ProcessSearchJob.cpp.

34 {
35 std::string reactantFilename("pos.con");
36 std::string displacementFilename("displacement.con");
37 std::string modeFilename("direction.dat");
38 size_t fctmp{0};
39 initial = std::make_shared<Matter>(pot, params);
40 if (params.saddle_search_options.method == "min_mode" ||
41 params.saddle_search_options.method == "basin_hopping" ||
42 params.saddle_search_options.method == "bgsd") {
43 displacement = std::make_shared<Matter>(pot, params);
44 } else if (params.saddle_search_options.method == "dynamics") {
45 displacement = nullptr;
46 }
47 saddle = std::make_shared<Matter>(pot, params);
48 // Give min2 its own potential for parallel endpoint minimization
49 auto min2Pot = (pot->needsPerImageInstance() && params.main_options.parallel)
51 : pot;
52 min1 = std::make_shared<Matter>(pot, params);
53 min2 = std::make_shared<Matter>(min2Pot, params);
54
55 if (!eonc::io::io_ok(initial->con2matter(reactantFilename))) {
56 EONC_LOG_CRITICAL("Failed to load {}", reactantFilename);
57 exit(1);
58 }
59
60 if (params.process_search_options.minimize_first) {
61 QUILL_LOG_DEBUG(log, "Minimizing initial structure\n");
62 fctmp = initial->getPotentialCalls();
63 initial->relax();
64 fCallsMin += initial->getPotentialCalls() - fctmp;
65 QUILL_LOG_DEBUG(log, "Initial minimization took {} fcalls",
66 initial->getPotentialCalls() - fctmp);
67 }
68
71
72 if (params.saddle_search_options.method == "min_mode" ||
73 params.saddle_search_options.method == "basin_hopping" ||
74 params.saddle_search_options.method == "bgsd") {
75 if (params.saddle_search_options.displace_type ==
77 // Load displacement.con, or synthesize from pos.con + direction.dat
78 // (#79).
80 *saddle, *initial, displacementFilename, modeFilename,
81 params.saddle_search_options.displace_magnitude)) {
82 EONC_LOG_CRITICAL("Failed to load {} (and no usable {})",
83 displacementFilename, modeFilename);
84 exit(1);
85 }
86 *min1 = *min2 = *initial;
87 } else {
88 *saddle = *min1 = *min2 = *initial;
89 }
90 } else {
91 // ARTn and dynamics start from the initial minimum
92 *saddle = *min1 = *min2 = *initial;
93 }
94
95 AtomMatrix mode;
96 const bool useARTnAsMinMode =
97 params.saddle_search_options.method == "min_mode" &&
98 params.saddle_search_options.minmode_method == "artn";
99
100 if (params.saddle_search_options.method == "min_mode") {
101 if (params.saddle_search_options.displace_type ==
103 mode = eonc::helpers::loadMode(modeFilename, initial->numberOfAtoms());
104 }
105#ifdef WITH_ARTN
106 // ARTn as a min-mode drop-in: eOn displaces, seeds the mode, ARTn
107 // takes over from the displaced structure.
108 if (useARTnAsMinMode) {
110 std::make_unique<ARTnSaddleSearch>(saddle, pot, mode, params);
111 } else
112#endif
113 {
114 saddleSearch = std::make_unique<MinModeSaddleSearch>(
115 saddle, mode, initial->getPotentialEnergy(), params, pot);
116 }
117#ifdef WITH_ARTN
118 } else if (params.saddle_search_options.method == "artn") {
119 // ARTn handles its own push from the minimum, eigenmode estimation,
120 // and perpendicular relaxation internally.
121 AtomMatrix artnMode = AtomMatrix::Zero(initial->numberOfAtoms(), 3);
122 if (params.saddle_search_options.displace_type ==
124 artnMode =
125 eonc::helpers::loadMode(modeFilename, initial->numberOfAtoms());
126 }
128 std::make_unique<ARTnSaddleSearch>(saddle, pot, artnMode, params);
129#endif
130 } else if (params.saddle_search_options.method == "basin_hopping") {
132 std::make_unique<BasinHoppingSaddleSearch>(min1, saddle, pot, params);
133 } else if (params.saddle_search_options.method == "dynamics") {
134 saddleSearch = std::make_unique<DynamicsSaddleSearch>(saddle, params);
135 } else if (params.saddle_search_options.method == "bgsd") {
136 saddleSearch = std::make_unique<BiasedGradientSquaredDescent>(
137 saddle, initial->getPotentialEnergy(), params);
138 }
139
140#ifndef WITH_ARTN
141 // Post-dispatch guard for both ARTn entry points so users without a
142 // WITH_ARTN build get a clean per-case error instead of a silent
143 // fall-through. Two distinct messages so downstream tooling and the
144 // integration tests can match on the specific entry point.
145 if (params.saddle_search_options.method == "artn") {
146 throw std::runtime_error(
147 "saddle_search.method=artn requires a build with ARTn support "
148 "(reconfigure with -Dwith_artn=true)");
149 }
150 if (useARTnAsMinMode) {
151 throw std::runtime_error(
152 "saddle_search.minmode_method=artn requires a build with ARTn "
153 "support (reconfigure with -Dwith_artn=true)");
154 }
155#endif
156
157 int status = doProcessSearch();
158
159 printEndState(status);
160 saveData(status);
161
162 return returnFiles;
163}
#define EONC_LOG_CRITICAL(...)
Definition EonLogger.h:268
std::shared_ptr< Matter > displacement
Configuration used during the saddle point search.
std::vector< std::string > returnFiles
Container for the results of the run.
int doProcessSearch(void)
Runs the correct saddle search; also checks if the run was successful.
void saveData(int status)
Writes the results from the run to file.
void printEndState(int status)
Logs the run status and makes sure the run was successful.
const char DISP_LOAD[]
Definition EpiCenters.h:20
bool loadOrSynthesizeDisplacement(Matter &target, const Matter &initial, const std::string &displacementPath, const std::string &modePath, double scale)
AtomMatrix loadMode(FILE *modeFile, int nAtoms)
std::shared_ptr< Potential > makePotential(const Parameters &params)
constexpr bool io_ok(IoStatus s) noexcept
Definition ConFileIO.h:38

◆ saveData()

void ProcessSearchJob::saveData ( int status)
private

Writes the results from the run to file.

Definition at line 323 of file ProcessSearchJob.cpp.

323 {
324 std::string resultsFilename("results.dat");
325 returnFiles.push_back(resultsFilename);
326
327 std::ofstream out(resultsFilename, std::ios::binary);
328 if (out) {
329 out << std::format("{} termination_reason\n", status);
330 out << std::format("{} termination_reason_text\n",
331 saddleSearch->describeStatus(status));
332 out << std::format("{} random_seed\n", params.main_options.randomSeed);
333 out << std::format(
334 "{} potential_type\n",
335 magic_enum::enum_name<PotType>(params.potential_options.potential));
336 out << std::format("{} total_force_calls\n",
338 out << std::format("{} force_calls_minimization\n", fCallsMin);
339 out << std::format("{} force_calls_saddle\n", fCallsSaddle);
340 out << std::format("{:.12e} potential_energy_saddle\n",
341 saddle->getPotentialEnergy());
342 out << std::format("{:.12e} potential_energy_reactant\n",
343 min1->getPotentialEnergy());
344 out << std::format("{:.12e} potential_energy_product\n",
345 min2->getPotentialEnergy());
346 out << std::format("{:.12e} barrier_reactant_to_product\n",
347 barriersValues[0]);
348 out << std::format("{:.12e} barrier_product_to_reactant\n",
349 barriersValues[1]);
350 if (params.saddle_search_options.method == "min_mode") {
351 out << std::format("{:.12e} displacement_saddle_distance\n",
352 displacement->perAtomNorm(*saddle));
353 } else {
354 out << std::format("{:.12e} displacement_saddle_distance\n", 0.0);
355 }
356 if (params.saddle_search_options.method == "dynamics") {
357 auto ds = dynamic_cast<DynamicsSaddleSearch &>(*saddleSearch);
358 out << std::format("{:.12e} simulation_time\n",
359 ds.time * params.constants.timeUnit);
360 out << std::format("{:.12e} md_temperature\n",
361 params.saddle_search_options.dynamics.temperature);
362 }
363 out << std::format("{} force_calls_prefactors\n", fCallsPrefactors);
364 out << std::format("{:.12e} prefactor_reactant_to_product\n",
366 out << std::format("{:.12e} prefactor_product_to_reactant\n",
368 }
369
370 std::string reactantFilename("reactant.con");
371 returnFiles.push_back(reactantFilename);
372 if (!eonc::io::io_ok(min1->matter2con(reactantFilename))) {
373 QUILL_LOG_ERROR(log, "Failed to write {}", reactantFilename);
374 }
375
376 std::string modeFilename("mode.dat");
377 returnFiles.push_back(modeFilename);
378 eonc::helpers::saveMode(modeFilename, saddle, saddleSearch->getEigenvector());
379
380 std::string saddleFilename("saddle.con");
381 returnFiles.push_back(saddleFilename);
382 if (!eonc::io::io_ok(saddle->matter2con(saddleFilename))) {
383 QUILL_LOG_ERROR(log, "Failed to write {}", saddleFilename);
384 }
385
386 std::string productFilename("product.con");
387 returnFiles.push_back(productFilename);
388 if (!eonc::io::io_ok(min2->matter2con(productFilename))) {
389 QUILL_LOG_ERROR(log, "Failed to write {}", productFilename);
390 }
391}
void saveMode(FILE *modeFile, std::shared_ptr< Matter > matter, AtomMatrix mode)
Write a mode; constrained axes are emitted as 0.

Member Data Documentation

◆ barriersValues

double eonc::ProcessSearchJob::barriersValues[2] {0.0, 0.0}
private

Array containg the value of the potential barriers from reactant to product and vice versa

Definition at line 92 of file ProcessSearchJob.h.

92{0.0, 0.0};

◆ displacement

std::shared_ptr<Matter> eonc::ProcessSearchJob::displacement
private

Configuration used during the saddle point search.

Definition at line 84 of file ProcessSearchJob.h.

◆ fCallsMin

Force calls to minimize.

Definition at line 100 of file ProcessSearchJob.h.

100{0};

◆ fCallsPrefactors

Force calls to find the prefactors.

Definition at line 102 of file ProcessSearchJob.h.

102{0};

◆ fCallsSaddle

Force calls to find the saddle.

Definition at line 98 of file ProcessSearchJob.h.

98{0};

◆ initial

std::shared_ptr<Matter> eonc::ProcessSearchJob::initial
private

Initial configuration.

Definition at line 80 of file ProcessSearchJob.h.

◆ log

◆ min1

std::shared_ptr<Matter> eonc::ProcessSearchJob::min1
private

First minimum from the saddle.

Definition at line 86 of file ProcessSearchJob.h.

◆ min2

std::shared_ptr<Matter> eonc::ProcessSearchJob::min2
private

Second minimum from the saddle.

Definition at line 88 of file ProcessSearchJob.h.

◆ prefactorsValues

double eonc::ProcessSearchJob::prefactorsValues[2] {0.0, 0.0}
private

Array containg the value of the prefactors of the matter from reactant to product and vice versa

Definition at line 95 of file ProcessSearchJob.h.

95{0.0, 0.0};

◆ returnFiles

std::vector<std::string> eonc::ProcessSearchJob::returnFiles
private

Container for the results of the run.

Definition at line 71 of file ProcessSearchJob.h.

◆ saddle

std::shared_ptr<Matter> eonc::ProcessSearchJob::saddle
private

Configuration used during the saddle point search.

Definition at line 82 of file ProcessSearchJob.h.

◆ saddleSearch


The documentation for this class was generated from the following files: