Loading...
Searching...
No Matches
eonc::pathintegral::RingPolymer Class Reference

Ring-polymer NVT step. More...

#include <PathIntegral.h>

Classes

struct  ModeGle

Public Member Functions

 RingPolymer (long nAtoms, std::vector< double > masses, std::vector< int > atomicNumbers, std::vector< char > free, Options opt)
void setAllBeads (const double *q)
void setBeads (const std::vector< VectorXd > &beads)
 One position vector of length 3 * nAtoms per bead.
const std::vector< VectorXd > & beads () const
const std::vector< VectorXd > & momenta () const
void setMomenta (const std::vector< VectorXd > &momenta)
 One momentum vector of length 3 * nAtoms per bead; fixed coordinates are zeroed.
void thermalMomenta ()
void setHyperplane (const VectorXd &normal, const VectorXd &origin)
 Hold n · (q_centroid - origin) = 0.
void step (Potential &pot, const double *box, bool record)
void nveStep (Potential &pot, const double *box)
 Thermostat-free RPMD step: velocity Verlet with the free ring propagated exactly in normal modes.
double kineticCv () const
double meanForce () const
long batches () const
VectorXd centroid () const
VectorXd centroidVelocity () const
void resetAverages ()
Sample sample (Potential &pot, const double *box, long equilibration, long production)

Private Member Functions

void forces (Potential &pot, const double *box)
void thermostat (double h)
void kick (double h, bool dropParallel)
void propagate (double h)
void projectPosition ()
void projectMomentum ()
void toNormal (const std::vector< VectorXd > &src, std::vector< VectorXd > &dst) const
void fromNormal (const std::vector< VectorXd > &src, std::vector< VectorXd > &dst) const
double gauss ()
void initGle ()

Private Attributes

Options opt_
long nAtoms_ {0}
long nDof_ {0}
long nBeads_ {0}
long nFree_ {0}
std::vector< double > mass_
std::vector< int > atomicNumbers_
std::vector< char > free_
std::vector< long > freeIndex_
MatrixXd modes_
VectorXd omegaK_
std::vector< VectorXd > q_
std::vector< VectorXd > p_
std::vector< VectorXd > f_
std::vector< VectorXd > qnm_
std::vector< VectorXd > pnm_
VectorXd planeNormal_
VectorXd planeOrigin_
bool constrain_ {false}
bool haveForces_ {false}
std::vector< ModeGle > gle_
std::uint64_t rng_
long batches_ {0}
long recorded_ {0}
double kineticSum_ {0.0}
double forceSum_ {0.0}

Detailed Description

Ring-polymer NVT step.

Physical forces on every bead are one forceBatch call, so a calculator group carries the beads together. The classical velocity Verlet step is not used.

Definition at line 92 of file PathIntegral.h.

Constructor & Destructor Documentation

◆ RingPolymer()

eonc::pathintegral::RingPolymer::RingPolymer ( long nAtoms,
std::vector< double > masses,
std::vector< int > atomicNumbers,
std::vector< char > free,
Options opt )

Definition at line 320 of file PathIntegral.cpp.

323 : opt_(std::move(opt)),
324 nAtoms_(nAtoms),
325 nDof_(3 * nAtoms),
326 nBeads_(opt_.beads),
327 atomicNumbers_(std::move(atomicNumbers)),
328 free_(std::move(free)),
329 rng_(opt_.seed == 0 ? 1 : opt_.seed) {
330 if (nAtoms_ < 1 || nBeads_ < 1) {
331 throw std::invalid_argument("path integral needs atoms and beads");
332 }
333 if (static_cast<long>(masses.size()) != nAtoms_ ||
334 static_cast<long>(atomicNumbers_.size()) != nAtoms_ ||
335 static_cast<long>(free_.size()) != nDof_) {
336 throw std::invalid_argument("path integral mass, number or mask size");
337 }
338 if (!(opt_.temperature > 0.0) || !(opt_.kB > 0.0) || !(opt_.hbar > 0.0) ||
339 !(opt_.dt > 0.0) || !(opt_.pileTau > 0.0) || !(opt_.pileScale > 0.0)) {
340 throw std::invalid_argument(
341 "path integral temperature, timestep and damping must be positive");
342 }
343 if (opt_.springs == Springs::Eco && opt_.thermostat == Thermostat::Piglet) {
344 throw std::invalid_argument(
345 "economised springs cannot be combined with a normal-mode GLE");
346 }
347 mass_.assign(static_cast<size_t>(nDof_), 0.0);
348 nFree_ = 0;
349 for (long i = 0; i < nAtoms_; ++i) {
350 if (!(masses[static_cast<size_t>(i)] > 0.0)) {
351 throw std::invalid_argument("path integral atom has no mass");
352 }
353 for (int axis = 0; axis < 3; ++axis) {
354 const long a = 3 * i + axis;
355 mass_[static_cast<size_t>(a)] = masses[static_cast<size_t>(i)];
356 if (free_[static_cast<size_t>(a)]) {
357 freeIndex_.push_back(a);
358 ++nFree_;
359 }
360 }
361 }
362 if (nFree_ < 1) {
363 throw std::invalid_argument("path integral has no free coordinate");
364 }
366 const double omegan =
367 static_cast<double>(nBeads_) * opt_.kB * opt_.temperature / opt_.hbar;
368 if (opt_.springs == Springs::Eco) {
369 const double xmax =
370 opt_.ecoOmegaMax * opt_.hbar / (opt_.kB * opt_.temperature);
371 omegaK_ = omegan * ecoEigenvalues(nBeads_, xmax);
372 } else {
374 }
375 q_.assign(static_cast<size_t>(nBeads_), VectorXd::Zero(nDof_));
376 p_.assign(static_cast<size_t>(nBeads_), VectorXd::Zero(nDof_));
377 f_.assign(static_cast<size_t>(nBeads_), VectorXd::Zero(nDof_));
378 qnm_.assign(static_cast<size_t>(nBeads_), VectorXd::Zero(nDof_));
379 pnm_.assign(static_cast<size_t>(nBeads_), VectorXd::Zero(nDof_));
380 if (opt_.thermostat == Thermostat::Piglet) {
381 initGle();
382 }
384}
std::vector< int > atomicNumbers_
std::vector< long > freeIndex_
std::vector< VectorXd > pnm_
std::vector< double > mass_
std::vector< VectorXd > f_
std::vector< VectorXd > p_
std::vector< VectorXd > q_
std::vector< VectorXd > qnm_
MatrixXd normalModeMatrix(long nBeads)
Orthogonal bead-to-normal-mode matrix. Row k is mode k.
VectorXd trotterEigenvalues(long nBeads)
Dimensionless free-ring eigenvalues, mode 0 equal to 0.
VectorXd ecoEigenvalues(long nBeads, double xmax)

Member Function Documentation

◆ batches()

long eonc::pathintegral::RingPolymer::batches ( ) const
inlinenodiscard

Definition at line 120 of file PathIntegral.h.

◆ beads()

const std::vector< VectorXd > & eonc::pathintegral::RingPolymer::beads ( ) const
inlinenodiscard

Definition at line 102 of file PathIntegral.h.

102{ return q_; }

◆ centroid()

VectorXd eonc::pathintegral::RingPolymer::centroid ( ) const
nodiscard

Definition at line 585 of file PathIntegral.cpp.

585 {
586 VectorXd c = VectorXd::Zero(nDof_);
587 for (long bead = 0; bead < nBeads_; ++bead) {
588 c += q_[static_cast<size_t>(bead)];
589 }
590 c /= static_cast<double>(nBeads_);
591 return c;
592}

◆ centroidVelocity()

VectorXd eonc::pathintegral::RingPolymer::centroidVelocity ( ) const
nodiscard

Definition at line 594 of file PathIntegral.cpp.

594 {
595 std::vector<VectorXd> pnm(static_cast<size_t>(nBeads_),
596 VectorXd::Zero(nDof_));
597 toNormal(p_, pnm);
598 VectorXd v = VectorXd::Zero(nDof_);
599 const double scale = std::sqrt(static_cast<double>(nBeads_));
600 for (long a = 0; a < nDof_; ++a) {
601 const double m = mass_[static_cast<size_t>(a)];
602 if (m > 0.0) {
603 v[a] = pnm[0][a] / (scale * m);
604 }
605 }
606 return v;
607}
void toNormal(const std::vector< VectorXd > &src, std::vector< VectorXd > &dst) const

◆ forces()

void eonc::pathintegral::RingPolymer::forces ( Potential & pot,
const double * box )
private

Definition at line 558 of file PathIntegral.cpp.

558 {
559 double zeroBox[9] = {};
560 const double *cell = box != nullptr ? box : zeroBox;
561 std::vector<const double *> pos(static_cast<size_t>(nBeads_));
562 std::vector<const int *> nrs(static_cast<size_t>(nBeads_));
563 std::vector<double *> frc(static_cast<size_t>(nBeads_));
564 std::vector<const double *> boxes(static_cast<size_t>(nBeads_), cell);
565 for (long bead = 0; bead < nBeads_; ++bead) {
566 pos[static_cast<size_t>(bead)] = q_[static_cast<size_t>(bead)].data();
567 nrs[static_cast<size_t>(bead)] = atomicNumbers_.data();
568 frc[static_cast<size_t>(bead)] = f_[static_cast<size_t>(bead)].data();
569 }
570 std::vector<double> energies(static_cast<size_t>(nBeads_), 0.0);
571 std::vector<double> variances(static_cast<size_t>(nBeads_), 0.0);
572 pot.forceBatch(nBeads_, nAtoms_, pos.data(), nrs.data(), frc.data(),
573 energies.data(), variances.data(), boxes.data());
574 ++batches_;
575 for (long bead = 0; bead < nBeads_; ++bead) {
576 for (long a = 0; a < nDof_; ++a) {
577 if (!free_[static_cast<size_t>(a)]) {
578 f_[static_cast<size_t>(bead)][a] = 0.0;
579 }
580 }
581 }
582 haveForces_ = true;
583}

◆ fromNormal()

void eonc::pathintegral::RingPolymer::fromNormal ( const std::vector< VectorXd > & src,
std::vector< VectorXd > & dst ) const
private

Definition at line 546 of file PathIntegral.cpp.

547 {
548 MatrixXd packed(nDof_, nBeads_);
549 for (long k = 0; k < nBeads_; ++k) {
550 packed.col(k) = src[static_cast<size_t>(k)];
551 }
552 const MatrixXd out = packed * modes_;
553 for (long j = 0; j < nBeads_; ++j) {
554 dst[static_cast<size_t>(j)] = out.col(j);
555 }
556}
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, eOnStorageOrder > MatrixXd
Definition Eigen.h:33

◆ gauss()

double eonc::pathintegral::RingPolymer::gauss ( )
private

Definition at line 487 of file PathIntegral.cpp.

487 {
488 rng_ = rng_ * 6364136223846793005ULL + 1ULL;
489 const double u1 =
490 std::max((rng_ >> 11) * (1.0 / 9007199254740992.0), 1.0e-16);
491 rng_ = rng_ * 6364136223846793005ULL + 1ULL;
492 const double u2 = (rng_ >> 11) * (1.0 / 9007199254740992.0);
493 return std::sqrt(-2.0 * std::log(u1)) * std::cos(2.0 * kPi * u2);
494}

◆ initGle()

void eonc::pathintegral::RingPolymer::initGle ( )
private

Definition at line 386 of file PathIntegral.cpp.

386 {
387 if (nBeads_ == 1) {
388 return;
389 }
390 if (opt_.gleFile.empty()) {
391 throw std::invalid_argument("normal-mode GLE needs a matrix file");
392 }
393 const GleFile file = readGle(opt_.gleFile);
394 long first = 0;
395 if (file.nModes == nBeads_) {
396 first = 1;
397 } else if (file.nModes != nBeads_ - 1) {
398 throw std::invalid_argument(
399 "GLE matrix count must be the bead count or one less");
400 }
401 const double h = 0.5 * opt_.dt;
402 gle_.resize(static_cast<size_t>(nBeads_ - 1));
403 for (long k = 1; k < nBeads_; ++k) {
404 const long src = first + (k - 1);
405 ModeGle mode;
406 mode.drift = file.drift[static_cast<size_t>(src)];
407 mode.covariance = file.covariance[static_cast<size_t>(src)];
408 mode.propagate = (-mode.drift * h).exp();
409 const MatrixXd cov =
410 opt_.kB * (mode.covariance - mode.propagate * mode.covariance *
411 mode.propagate.transpose());
412 mode.noise = factorCovariance(cov);
413 mode.extended = MatrixXd::Zero(file.dim, nFree_);
414 gle_[static_cast<size_t>(k - 1)] = std::move(mode);
415 }
416}
std::vector< ModeGle > gle_

◆ kick()

void eonc::pathintegral::RingPolymer::kick ( double h,
bool dropParallel )
private

Definition at line 681 of file PathIntegral.cpp.

681 {
682 VectorXd removal = VectorXd::Zero(nDof_);
683 if (dropParallel && constrain_) {
684 VectorXd fc = VectorXd::Zero(nDof_);
685 for (long bead = 0; bead < nBeads_; ++bead) {
686 fc += f_[static_cast<size_t>(bead)];
687 }
688 fc /= static_cast<double>(nBeads_);
689 double along = 0.0;
690 for (long a : freeIndex_) {
691 along += planeNormal_[a] * fc[a];
692 }
693 removal = along * planeNormal_;
694 }
695 for (long bead = 0; bead < nBeads_; ++bead) {
696 for (long a : freeIndex_) {
697 p_[static_cast<size_t>(bead)][a] +=
698 (f_[static_cast<size_t>(bead)][a] - removal[a]) * h;
699 }
700 }
701}

◆ kineticCv()

double eonc::pathintegral::RingPolymer::kineticCv ( ) const
nodiscard

Definition at line 609 of file PathIntegral.cpp.

609 {
610 double k = 0.5 * static_cast<double>(nFree_) * opt_.kB * opt_.temperature;
611 if (!haveForces_) {
612 return k;
613 }
614 const VectorXd c = centroid();
615 double virial = 0.0;
616 for (long bead = 0; bead < nBeads_; ++bead) {
617 for (long a : freeIndex_) {
618 virial += (q_[static_cast<size_t>(bead)][a] - c[a]) *
619 f_[static_cast<size_t>(bead)][a];
620 }
621 }
622 k += -0.5 / static_cast<double>(nBeads_) * virial;
623 return k;
624}

◆ meanForce()

double eonc::pathintegral::RingPolymer::meanForce ( ) const
nodiscard

Definition at line 626 of file PathIntegral.cpp.

626 {
627 if (!constrain_ || recorded_ < 1) {
628 return 0.0;
629 }
630 return forceSum_ / static_cast<double>(recorded_);
631}

◆ momenta()

const std::vector< VectorXd > & eonc::pathintegral::RingPolymer::momenta ( ) const
inlinenodiscard

Definition at line 103 of file PathIntegral.h.

103{ return p_; }

◆ nveStep()

void eonc::pathintegral::RingPolymer::nveStep ( Potential & pot,
const double * box )

Thermostat-free RPMD step: velocity Verlet with the free ring propagated exactly in normal modes.

Refused while a hyperplane is set.

Definition at line 801 of file PathIntegral.cpp.

801 {
802 if (constrain_) {
803 throw std::logic_error("path integral NVE step with a hyperplane set");
804 }
805 const double half = 0.5 * opt_.dt;
806 if (!haveForces_) {
807 forces(pot, box);
808 }
809 kick(half, false);
810 propagate(opt_.dt);
811 forces(pot, box);
812 kick(half, false);
813}
void forces(Potential &pot, const double *box)
void kick(double h, bool dropParallel)

◆ projectMomentum()

void eonc::pathintegral::RingPolymer::projectMomentum ( )
private

Definition at line 741 of file PathIntegral.cpp.

741 {
742 if (!constrain_) {
743 return;
744 }
745 VectorXd sum = VectorXd::Zero(nDof_);
746 for (long bead = 0; bead < nBeads_; ++bead) {
747 sum += p_[static_cast<size_t>(bead)];
748 }
749 // p_0 = sum / sqrt(P); remove lambda n from p_0.
750 const double scale = std::sqrt(static_cast<double>(nBeads_));
751 double num = 0.0;
752 double den = 0.0;
753 for (long a : freeIndex_) {
754 const double m = mass_[static_cast<size_t>(a)];
755 num += planeNormal_[a] * (sum[a] / scale) / m;
756 den += planeNormal_[a] * planeNormal_[a] / m;
757 }
758 if (den > 0.0) {
759 const double shift = num / den / scale;
760 for (long bead = 0; bead < nBeads_; ++bead) {
761 for (long a : freeIndex_) {
762 p_[static_cast<size_t>(bead)][a] -= shift * planeNormal_[a];
763 }
764 }
765 }
766}

◆ projectPosition()

void eonc::pathintegral::RingPolymer::projectPosition ( )
private

Definition at line 725 of file PathIntegral.cpp.

725 {
726 if (!constrain_) {
727 return;
728 }
729 const VectorXd c = centroid();
730 double sigma = 0.0;
731 for (long a : freeIndex_) {
732 sigma += planeNormal_[a] * (c[a] - planeOrigin_[a]);
733 }
734 for (long bead = 0; bead < nBeads_; ++bead) {
735 for (long a : freeIndex_) {
736 q_[static_cast<size_t>(bead)][a] -= sigma * planeNormal_[a];
737 }
738 }
739}

◆ propagate()

void eonc::pathintegral::RingPolymer::propagate ( double h)
private

Definition at line 703 of file PathIntegral.cpp.

703 {
704 toNormal(q_, qnm_);
705 toNormal(p_, pnm_);
706 for (long a : freeIndex_) {
707 const double m = mass_[static_cast<size_t>(a)];
708 qnm_[0][a] += pnm_[0][a] / m * h;
709 for (long k = 1; k < nBeads_; ++k) {
710 const double omega = omegaK_[k];
711 const double c = std::cos(omega * h);
712 const double s = std::sin(omega * h);
713 const double pk = pnm_[static_cast<size_t>(k)][a];
714 const double qk = qnm_[static_cast<size_t>(k)][a];
715 pnm_[static_cast<size_t>(k)][a] = c * pk - m * omega * s * qk;
716 qnm_[static_cast<size_t>(k)][a] = c * qk + s * pk / (omega * m);
717 }
718 }
721}
void fromNormal(const std::vector< VectorXd > &src, std::vector< VectorXd > &dst) const

◆ resetAverages()

void eonc::pathintegral::RingPolymer::resetAverages ( )

Definition at line 633 of file PathIntegral.cpp.

633 {
634 recorded_ = 0;
635 kineticSum_ = 0.0;
636 forceSum_ = 0.0;
637}

◆ sample()

Sample eonc::pathintegral::RingPolymer::sample ( Potential & pot,
const double * box,
long equilibration,
long production )

Definition at line 815 of file PathIntegral.cpp.

816 {
817 if (equilibration < 0 || production < 1) {
818 throw std::invalid_argument("path integral sample length");
819 }
820 for (long step = 0; step < equilibration; ++step) {
821 this->step(pot, box, false);
822 }
824 const long batchesBefore = batches_;
825 for (long step = 0; step < production; ++step) {
826 this->step(pot, box, true);
827 }
828 Sample out;
829 out.kineticCv = kineticSum_ / static_cast<double>(recorded_);
830 out.meanForce = meanForce();
831 out.batches = batches_ - batchesBefore;
832 return out;
833}
void step(Potential &pot, const double *box, bool record)

◆ setAllBeads()

void eonc::pathintegral::RingPolymer::setAllBeads ( const double * q)

Definition at line 418 of file PathIntegral.cpp.

418 {
419 if (q == nullptr) {
420 throw std::invalid_argument("path integral positions are missing");
421 }
422 for (long bead = 0; bead < nBeads_; ++bead) {
423 for (long a = 0; a < nDof_; ++a) {
424 q_[static_cast<size_t>(bead)][a] = q[a];
425 }
426 }
427 if (constrain_) {
429 }
430 haveForces_ = false;
431}

◆ setBeads()

void eonc::pathintegral::RingPolymer::setBeads ( const std::vector< VectorXd > & beads)

One position vector of length 3 * nAtoms per bead.

The centroid is projected onto the hyperplane when one is set.

Definition at line 433 of file PathIntegral.cpp.

433 {
434 if (static_cast<long>(beads.size()) != nBeads_) {
435 throw std::invalid_argument("path integral bead count mismatch");
436 }
437 for (long bead = 0; bead < nBeads_; ++bead) {
438 if (beads[static_cast<size_t>(bead)].size() != nDof_) {
439 throw std::invalid_argument("path integral bead has the wrong length");
440 }
441 q_[static_cast<size_t>(bead)] = beads[static_cast<size_t>(bead)];
442 }
443 if (constrain_) {
445 }
446 haveForces_ = false;
447}
const std::vector< VectorXd > & beads() const

◆ setHyperplane()

void eonc::pathintegral::RingPolymer::setHyperplane ( const VectorXd & normal,
const VectorXd & origin )

Hold n · (q_centroid - origin) = 0.

n is normalised on the free coordinates. origin has length 3 * nAtoms.

Definition at line 466 of file PathIntegral.cpp.

467 {
468 if (normal.size() != nDof_ || origin.size() != nDof_) {
469 throw std::invalid_argument("hyperplane vectors have the wrong length");
470 }
471 planeNormal_ = VectorXd::Zero(nDof_);
472 planeOrigin_ = origin;
473 double norm = 0.0;
474 for (long a : freeIndex_) {
475 planeNormal_[a] = normal[a];
476 norm += normal[a] * normal[a];
477 }
478 if (!(norm > 0.0)) {
479 throw std::invalid_argument("hyperplane normal has no free component");
480 }
481 planeNormal_ /= std::sqrt(norm);
482 constrain_ = true;
485}

◆ setMomenta()

void eonc::pathintegral::RingPolymer::setMomenta ( const std::vector< VectorXd > & momenta)

One momentum vector of length 3 * nAtoms per bead; fixed coordinates are zeroed.

Definition at line 449 of file PathIntegral.cpp.

449 {
450 if (static_cast<long>(momenta.size()) != nBeads_) {
451 throw std::invalid_argument("path integral bead count mismatch");
452 }
453 for (long bead = 0; bead < nBeads_; ++bead) {
454 if (momenta[static_cast<size_t>(bead)].size() != nDof_) {
455 throw std::invalid_argument(
456 "path integral momentum has the wrong length");
457 }
458 for (long a = 0; a < nDof_; ++a) {
459 p_[static_cast<size_t>(bead)][a] =
460 free_[static_cast<size_t>(a)] ? momenta[static_cast<size_t>(bead)][a]
461 : 0.0;
462 }
463 }
464}
const std::vector< VectorXd > & momenta() const

◆ step()

void eonc::pathintegral::RingPolymer::step ( Potential & pot,
const double * box,
bool record )

Definition at line 768 of file PathIntegral.cpp.

768 {
769 const double half = 0.5 * opt_.dt;
770 thermostat(half);
772 forces(pot, box);
773 kick(half, true);
775 propagate(half);
776 propagate(half);
778 forces(pot, box);
779 if (record) {
781 if (constrain_) {
782 VectorXd fc = VectorXd::Zero(nDof_);
783 for (long bead = 0; bead < nBeads_; ++bead) {
784 fc += f_[static_cast<size_t>(bead)];
785 }
786 fc /= static_cast<double>(nBeads_);
787 double along = 0.0;
788 for (long a : freeIndex_) {
789 along += planeNormal_[a] * fc[a];
790 }
791 forceSum_ += along;
792 }
793 ++recorded_;
794 }
795 kick(half, true);
797 thermostat(half);
799}

◆ thermalMomenta()

void eonc::pathintegral::RingPolymer::thermalMomenta ( )

Definition at line 496 of file PathIntegral.cpp.

496 {
497 for (long bead = 0; bead < nBeads_; ++bead) {
498 p_[static_cast<size_t>(bead)].setZero();
499 }
500 toNormal(p_, pnm_);
501 const double tSim = static_cast<double>(nBeads_) * opt_.kB * opt_.temperature;
502 for (long k = 0; k < nBeads_; ++k) {
503 const bool gleMode = opt_.thermostat == Thermostat::Piglet && k > 0;
504 if (gleMode) {
505 continue;
506 }
507 for (long a : freeIndex_) {
508 pnm_[static_cast<size_t>(k)][a] =
509 gauss() * std::sqrt(mass_[static_cast<size_t>(a)] * tSim);
510 }
511 }
512 if (opt_.thermostat == Thermostat::Piglet) {
513 for (long k = 1; k < nBeads_; ++k) {
514 ModeGle &mode = gle_[static_cast<size_t>(k - 1)];
515 const MatrixXd factor = factorCovariance(opt_.kB * mode.covariance);
516 MatrixXd noise(mode.extended.rows(), mode.extended.cols());
517 for (long r = 0; r < noise.rows(); ++r) {
518 for (long c = 0; c < noise.cols(); ++c) {
519 noise(r, c) = gauss();
520 }
521 }
522 mode.extended = factor * noise;
523 for (long col = 0; col < nFree_; ++col) {
524 const long a = freeIndex_[static_cast<size_t>(col)];
525 pnm_[static_cast<size_t>(k)][a] =
526 mode.extended(0, col) * std::sqrt(mass_[static_cast<size_t>(a)]);
527 }
528 }
529 }
531 haveForces_ = false;
532}

◆ thermostat()

void eonc::pathintegral::RingPolymer::thermostat ( double h)
private

Definition at line 639 of file PathIntegral.cpp.

639 {
640 toNormal(p_, pnm_);
641 const double tSim = static_cast<double>(nBeads_) * opt_.kB * opt_.temperature;
642 auto langevin = [&](long k, double tau) {
643 const double damp = std::exp(-h / tau);
644 const double noise = std::sqrt(tSim * (1.0 - damp * damp));
645 for (long a : freeIndex_) {
646 const double sm = std::sqrt(mass_[static_cast<size_t>(a)]);
647 double pms = pnm_[static_cast<size_t>(k)][a] / sm;
648 pms = damp * pms + noise * gauss();
649 pnm_[static_cast<size_t>(k)][a] = pms * sm;
650 }
651 };
652 langevin(0, opt_.pileTau);
653 for (long k = 1; k < nBeads_; ++k) {
654 if (opt_.thermostat == Thermostat::Piglet) {
655 ModeGle &mode = gle_[static_cast<size_t>(k - 1)];
656 for (long col = 0; col < nFree_; ++col) {
657 const long a = freeIndex_[static_cast<size_t>(col)];
658 mode.extended(0, col) = pnm_[static_cast<size_t>(k)][a] /
659 std::sqrt(mass_[static_cast<size_t>(a)]);
660 }
661 MatrixXd noise(mode.extended.rows(), mode.extended.cols());
662 for (long r = 0; r < noise.rows(); ++r) {
663 for (long c = 0; c < noise.cols(); ++c) {
664 noise(r, c) = gauss();
665 }
666 }
667 mode.extended = mode.propagate * mode.extended + mode.noise * noise;
668 for (long col = 0; col < nFree_; ++col) {
669 const long a = freeIndex_[static_cast<size_t>(col)];
670 pnm_[static_cast<size_t>(k)][a] =
671 mode.extended(0, col) * std::sqrt(mass_[static_cast<size_t>(a)]);
672 }
673 } else {
674 const double tau = 1.0 / (2.0 * opt_.pileScale * omegaK_[k]);
675 langevin(k, tau);
676 }
677 }
679}

◆ toNormal()

void eonc::pathintegral::RingPolymer::toNormal ( const std::vector< VectorXd > & src,
std::vector< VectorXd > & dst ) const
private

Definition at line 534 of file PathIntegral.cpp.

535 {
536 MatrixXd packed(nDof_, nBeads_);
537 for (long j = 0; j < nBeads_; ++j) {
538 packed.col(j) = src[static_cast<size_t>(j)];
539 }
540 const MatrixXd out = packed * modes_.transpose();
541 for (long k = 0; k < nBeads_; ++k) {
542 dst[static_cast<size_t>(k)] = out.col(k);
543 }
544}

Member Data Documentation

◆ atomicNumbers_

std::vector<int> eonc::pathintegral::RingPolymer::atomicNumbers_
private

Definition at line 149 of file PathIntegral.h.

◆ batches_

long eonc::pathintegral::RingPolymer::batches_ {0}
private

Definition at line 174 of file PathIntegral.h.

174{0};

◆ constrain_

bool eonc::pathintegral::RingPolymer::constrain_ {false}
private

Definition at line 161 of file PathIntegral.h.

161{false};

◆ f_

std::vector<VectorXd> eonc::pathintegral::RingPolymer::f_
private

Definition at line 156 of file PathIntegral.h.

◆ forceSum_

double eonc::pathintegral::RingPolymer::forceSum_ {0.0}
private

Definition at line 177 of file PathIntegral.h.

177{0.0};

◆ free_

std::vector<char> eonc::pathintegral::RingPolymer::free_
private

Definition at line 150 of file PathIntegral.h.

◆ freeIndex_

std::vector<long> eonc::pathintegral::RingPolymer::freeIndex_
private

Definition at line 151 of file PathIntegral.h.

◆ gle_

std::vector<ModeGle> eonc::pathintegral::RingPolymer::gle_
private

Definition at line 171 of file PathIntegral.h.

◆ haveForces_

bool eonc::pathintegral::RingPolymer::haveForces_ {false}
private

Definition at line 162 of file PathIntegral.h.

162{false};

◆ kineticSum_

double eonc::pathintegral::RingPolymer::kineticSum_ {0.0}
private

Definition at line 176 of file PathIntegral.h.

176{0.0};

◆ mass_

std::vector<double> eonc::pathintegral::RingPolymer::mass_
private

Definition at line 148 of file PathIntegral.h.

◆ modes_

MatrixXd eonc::pathintegral::RingPolymer::modes_
private

Definition at line 152 of file PathIntegral.h.

◆ nAtoms_

long eonc::pathintegral::RingPolymer::nAtoms_ {0}
private

Definition at line 144 of file PathIntegral.h.

144{0};

◆ nBeads_

long eonc::pathintegral::RingPolymer::nBeads_ {0}
private

Definition at line 146 of file PathIntegral.h.

146{0};

◆ nDof_

long eonc::pathintegral::RingPolymer::nDof_ {0}
private

Definition at line 145 of file PathIntegral.h.

145{0};

◆ nFree_

long eonc::pathintegral::RingPolymer::nFree_ {0}
private

Definition at line 147 of file PathIntegral.h.

147{0};

◆ omegaK_

VectorXd eonc::pathintegral::RingPolymer::omegaK_
private

Definition at line 153 of file PathIntegral.h.

◆ opt_

Options eonc::pathintegral::RingPolymer::opt_
private

Definition at line 143 of file PathIntegral.h.

◆ p_

std::vector<VectorXd> eonc::pathintegral::RingPolymer::p_
private

Definition at line 155 of file PathIntegral.h.

◆ planeNormal_

VectorXd eonc::pathintegral::RingPolymer::planeNormal_
private

Definition at line 159 of file PathIntegral.h.

◆ planeOrigin_

VectorXd eonc::pathintegral::RingPolymer::planeOrigin_
private

Definition at line 160 of file PathIntegral.h.

◆ pnm_

std::vector<VectorXd> eonc::pathintegral::RingPolymer::pnm_
private

Definition at line 158 of file PathIntegral.h.

◆ q_

std::vector<VectorXd> eonc::pathintegral::RingPolymer::q_
private

Definition at line 154 of file PathIntegral.h.

◆ qnm_

std::vector<VectorXd> eonc::pathintegral::RingPolymer::qnm_
private

Definition at line 157 of file PathIntegral.h.

◆ recorded_

long eonc::pathintegral::RingPolymer::recorded_ {0}
private

Definition at line 175 of file PathIntegral.h.

175{0};

◆ rng_

std::uint64_t eonc::pathintegral::RingPolymer::rng_
private

Definition at line 173 of file PathIntegral.h.


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