337 {
338 const int size =
static_cast<int>(
atoms.rows()) * 3;
340 auto pot =
matter->getPotential();
341
344 if (!force0.allFinite()) {
345 QUILL_LOG_ERROR(
log,
"[Hessian] non-finite forces at undisplaced geometry; "
346 "aborting FD Hessian");
347 return false;
348 }
349
350
351 std::vector<double> steps{1.0};
353 steps.push_back(-1.0);
354 }
356 steps.push_back(2.0);
357 steps.push_back(-2.0);
358 }
359 const int perColumn = static_cast<int>(steps.size());
360 const long nAtoms =
matter->numberOfAtoms();
361 const VectorXi nrs =
matter->getAtomicNrs();
363 matter->getPeriodic() ?
matter->getCell() : Matrix3d::Zero().eval();
364
365
366 constexpr int kChunkColumns = 32;
367 std::vector<Matter> displaced;
368 for (int c0 = 0; c0 < size; c0 += kChunkColumns) {
369 const int c1 = std::min(size, c0 + kChunkColumns);
370 const long n = static_cast<long>(c1 - c0) * perColumn;
371 displaced.assign(static_cast<size_t>(n), base);
372 std::vector<const double *> posPtr, boxPtr;
373 std::vector<const int *> nrsPtr;
374 std::vector<double *> frcPtr;
375 for (int i = c0; i < c1; ++i) {
376 for (int k = 0; k < perColumn; ++k) {
377 Matter &m = displaced[static_cast<size_t>((i - c0) * perColumn + k)];
379 p(
atoms(i / 3), i % 3) += steps[
static_cast<size_t>(k)] * dr;
380 m.setPositions(p);
381 }
382 }
383 for (auto &m : displaced) {
384 posPtr.push_back(m.getPositions().data());
385 nrsPtr.push_back(nrs.data());
386 frcPtr.push_back(m.forcesData());
387 boxPtr.push_back(box.data());
388 }
389 std::vector<double> energies(static_cast<size_t>(n)),
390 variances(static_cast<size_t>(n));
391 pot->forceBatch(n, nAtoms, posPtr.data(), nrsPtr.data(), frcPtr.data(),
392 energies.data(), variances.data(), boxPtr.data());
393 for (long j = 0; j < n; ++j) {
394 displaced[static_cast<size_t>(j)].setComputedPotential(
395 energies[static_cast<size_t>(j)], variances[static_cast<size_t>(j)]);
396 }
397 for (int i = c0; i < c1; ++i) {
398 auto forces = [&](
int k) ->
const AtomMatrix & {
399 return displaced[static_cast<size_t>((i - c0) * perColumn + k)]
400 .getForces();
401 };
403 const AtomMatrix &fMinus = perColumn > 1 ? forces(1) : force0;
404 const AtomMatrix &fPlus2 = perColumn > 2 ? forces(2) : force0;
405 const AtomMatrix &fMinus2 = perColumn > 3 ? forces(3) : force0;
406 if (!fPlus.allFinite() || !fMinus.allFinite() || !fPlus2.allFinite() ||
407 !fMinus2.allFinite()) {
409 "[Hessian] non-finite forces for FD column {}; "
410 "aborting FD Hessian",
411 i);
412 return false;
413 }
416 for (int j = 0; j < size; j++) {
417 const double effMass = std::sqrt(
matter->getMass(
atoms(j / 3)) *
421 }
422 }
423 }
425}
Eigen::Matrix< double, 3, 3, eOnStorageOrder > Matrix3d
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
bool finalizeHessian(int size)
constexpr double safe_div(double num, double denom, double fallback=0.0)
M fdForceDerivative(FdScheme scheme, double dr, const M &f0, const M &fPlus, const M &fMinus, const M &fPlus2, const M &fMinus2)
Derivative of a sampled force map along one real step of length dr.