42 throw std::runtime_error(
"ReplicaExchangeJob::runFromMatter: null Matter");
48 static_cast<long>(
params.replica_exchange_options.sampling_time /
49 params.dynamics_options.time_step +
51 long exchangePeriodSteps =
52 static_cast<long>(
params.replica_exchange_options.exchange_period /
53 params.dynamics_options.time_step +
55 const double kB =
params.constants.kB;
56 if (samplingSteps <= 0)
58 if (exchangePeriodSteps <= 0)
59 exchangePeriodSteps = 1;
61 QUILL_LOG_DEBUG(
log,
"Running Replica Exchange");
65 const long nReplicas =
params.replica_exchange_options.replicas;
66 std::vector<std::shared_ptr<Matter>> replica(nReplicas);
67 std::vector<std::unique_ptr<Dynamics>> replicaDynamics(nReplicas);
71 const bool perImage =
pot->needsPerImageInstance();
72 for (
long i = 0; i < nReplicas; i++) {
74 replica[i] = std::make_shared<Matter>(replicaPot,
params);
76 replicaDynamics[i] = std::make_unique<Dynamics>(replica[i].get(),
params);
79 std::vector<double> replicaTemperature(nReplicas);
81 QUILL_LOG_DEBUG(
log,
"Temperature distribution:");
82 if (
params.replica_exchange_options.temperature_distribution ==
"linear") {
83 for (
long i = 0; i < nReplicas; i++) {
84 replicaTemperature[i] =
85 params.replica_exchange_options.temperature_low +
86 static_cast<double>(i) /
static_cast<double>(nReplicas - 1) *
87 (
params.replica_exchange_options.temperature_high -
88 params.replica_exchange_options.temperature_low);
89 replicaDynamics[i]->setTemperature(replicaTemperature[i]);
91 }
else if (
params.replica_exchange_options.temperature_distribution ==
93 double kTemp = std::log(
params.replica_exchange_options.temperature_high /
94 params.replica_exchange_options.temperature_low) /
95 static_cast<double>(nReplicas - 1);
96 for (
long i = 0; i < nReplicas; i++) {
97 replicaTemperature[i] =
params.replica_exchange_options.temperature_low *
98 std::exp(kTemp *
static_cast<double>(i));
99 replicaDynamics[i]->setTemperature(replicaTemperature[i]);
100 QUILL_LOG_DEBUG(
log,
"replica: {} temperature {:.0f}", i + 1,
101 replicaTemperature[i]);
106 log,
"Replica Exchange sampling for {:.0f} fs; {} steps; {} replicas.",
107 params.replica_exchange_options.sampling_time * 10.18, samplingSteps,
108 params.replica_exchange_options.replicas);
111 const bool canParallel =
params.main_options.parallel &&
112 (
pot->isSharedInstanceThreadSafe() || perImage);
114 for (
long step = 1; step <= samplingSteps; step++) {
115 if (canParallel && nReplicas > 1) {
117 std::vector<std::thread> threads;
118 threads.reserve(nReplicas);
119 for (
long i = 0; i < nReplicas; i++) {
120 threads.emplace_back([&, i] { replicaDynamics[i]->oneStep(); });
122 for (
auto &t : threads) {
126 for (
long i = 0; i < nReplicas; i++) {
127 replicaDynamics[i]->oneStep();
132 if ((step % exchangePeriodSteps) == 0) {
134 trial <
params.replica_exchange_options.exchange_trials; trial++) {
136 double energyLow = replica[i]->getPotentialEnergy();
137 double energyHigh = replica[i + 1]->getPotentialEnergy();
138 double kbTLow = kB * replicaTemperature[i];
139 double kbTHigh = kB * replicaTemperature[i + 1];
141 std::min(1.0, std::exp((energyHigh - energyLow) *
146 "step: {} trial swap, i {}, elow: {:.5f}, ehigh: "
147 "{:.5f}, pAcc: {:.5f}, rand: {}",
148 step, i, energyLow, energyHigh, pAcc, rnd);
150 QUILL_LOG_INFO(
log,
"swap");
151 std::swap(replica[i], replica[i + 1]);
152 replicaDynamics[i]->setThermalVelocity();
153 replicaDynamics[i + 1]->setThermalVelocity();
155 QUILL_LOG_INFO(
log,
"no swap");
163 if (!replica.empty()) {