45 throw std::runtime_error(
"ParallelReplicaJob::runFromMatter: null Matter");
50 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Minimizing initial position");
53 QUILL_LOG_ERROR(
log,
"Failed to write reactant.con");
56 auto trajectory = std::make_shared<Matter>(
pot,
params);
62 if (
params.hyperdynamics_options().bias_potential ==
65 trajectory->setBiasPotential(&bondBoost);
71 int stateCheckInterval =
static_cast<int>(
72 std::floor(
params.parallel_replica_options().state_check_interval /
73 params.dynamics_options().time_step +
75 int recordInterval =
static_cast<int>(
76 std::floor(
params.parallel_replica_options().record_interval /
77 params.dynamics_options().time_step +
79 if (stateCheckInterval < 1)
80 stateCheckInterval = 1;
81 if (recordInterval < 1)
84 std::vector<std::shared_ptr<Matter>> mdSnapshots;
85 std::vector<double> mdTimes;
86 double transitionTime = 0;
88 size_t refineForceCalls = 0;
90 double simulationTime = 0.0;
93 log,
"[ParallelReplica] {:>8} {:>12} {:>10} {:>12} {:>12} {:>10}",
94 "Step",
"Time (s)",
"KE",
"PE",
"TE",
"KinT");
98 "[ParallelReplica] {:>8} {:>12} {:>10} {:>10} {:>12} {:>12} {:>10}",
99 "Step",
"Time (s)",
"Boost",
"KE",
"PE",
"TE",
"KinT");
102 for (
int step = 1; step <=
params.dynamics_options().steps; step++) {
103 if (
params.hyperdynamics_options().bias_potential ==
112 if (
params.hyperdynamics_options().bias_potential ==
114 double boostPotential = bondBoost.
boost();
115 double kB =
params.constants().kB;
116 boost = std::exp(boostPotential / kB /
params.main_options().temperature);
117 simulationTime +=
params.dynamics_options().time_step * boost;
119 simulationTime +=
params.dynamics_options().time_step;
122 double kinE = trajectory->getKineticEnergy();
123 double potE = trajectory->getPotentialEnergy();
124 double kinT = (2.0 * kinE / (trajectory->numberOfFreeAtoms() * 3) /
127 if (step %
params.debug_options().write_movies_interval == 0) {
128 if (
params.hyperdynamics_options().bias_potential ==
131 "[ParallelReplica] {:>8} {:>12.4e} {:>10.4f} "
132 "{:>12.4f} {:>12.4f} {:>10.2f}",
134 simulationTime *
params.constants().timeUnit * 1e-15,
135 kinE, potE, kinE + potE, kinT);
137 double boostPotential = bondBoost.
boost();
140 "[ParallelReplica] {:>8} {:>12.4e} {:>10.3e} "
141 "{:>10.4f} {:>12.4f} {:>12.4f} {:>10.2f}",
142 step, simulationTime *
params.constants().timeUnit * 1e-15, boost,
143 kinE, potE + boostPotential, kinE + potE + boostPotential, kinT);
148 if (step % recordInterval == 0 &&
149 params.parallel_replica_options().refine_transition) {
150 auto snap = std::make_shared<Matter>(
pot,
params);
152 mdSnapshots.push_back(std::move(snap));
153 mdTimes.push_back(simulationTime);
157 if (step % stateCheckInterval == 0 ||
158 step ==
params.dynamics_options().steps) {
159 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Checking for transition");
162 minimized = *trajectory;
166 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Transition occurred");
168 if (
params.parallel_replica_options().refine_transition &&
169 !mdSnapshots.empty() && !mdTimes.empty()) {
170 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Refining transition time");
176 if (snapshotIndex < 0)
178 if (snapshotIndex >=
static_cast<int>(mdSnapshots.size()))
179 snapshotIndex =
static_cast<int>(mdSnapshots.size()) - 1;
181 transitionTime = mdTimes[
static_cast<size_t>(snapshotIndex)];
182 transitionStructure =
183 *mdSnapshots[
static_cast<size_t>(snapshotIndex)];
185 transitionStructure = *trajectory;
186 transitionTime = simulationTime;
188 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Transition time: {:.3e} s",
189 transitionTime *
params.constants().timeUnit * 1e-15);
192 trajectory->assignKeepingBias(transitionStructure);
194 if (
params.parallel_replica_options().auto_stop) {
198 }
else if (step + 1 ==
params.dynamics_options().steps &&
199 transitionTime == 0) {
201 if (
params.parallel_replica_options().refine_transition &&
202 !mdSnapshots.empty()) {
205 "[ParallelReplica] Simulation ended without seeing a transition");
207 log,
"[ParallelReplica] Refining anyways to prevent bias...");
213 transitionStructure = *trajectory;
221 std::unique_ptr<Matter> product;
222 if (transitionTime != 0) {
223 int decorrelationSteps =
static_cast<int>(
224 std::floor(
params.parallel_replica_options().corr_time /
225 params.dynamics_options().time_step +
227 if (decorrelationSteps < 0) {
228 decorrelationSteps = 0;
230 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Decorrelating: {} steps",
232 for (
int dstep = 1; dstep <= decorrelationSteps; ++dstep) {
235 product = std::make_unique<Matter>(
pot,
params);
236 *product = *trajectory;
239 QUILL_LOG_ERROR(
log,
"Failed to write product.con");
244 std::string resultsFilename(
"results.dat");
247 std::ofstream out(resultsFilename, std::ios::binary);
250 "{} potential_type\n",
251 magic_enum::enum_name<PotType>(
params.potential_options().potential));
252 out << std::format(
"{} random_seed\n",
params.main_options().randomSeed);
253 out << std::format(
"{:f} potential_energy_reactant\n",
255 out << std::format(
"{} force_calls_refine\n", refineForceCalls);
256 out << std::format(
"{} total_force_calls\n",
259 if (transitionTime == 0) {
260 out <<
"0 transition_found\n";
261 out << std::format(
"{:e} simulation_time_s\n",
262 simulationTime *
params.constants().timeUnit *
265 out <<
"1 transition_found\n";
266 out << std::format(
"{:e} transition_time_s\n",
267 transitionTime *
params.constants().timeUnit *
269 out << std::format(
"{:e} correlation_time_s\n",
270 params.parallel_replica_options().corr_time *
271 params.constants().timeUnit * 1.0e-15);
272 out << std::format(
"{:f} potential_energy_product\n",
273 product->getPotentialEnergy());
275 out << std::format(
"{:f} speedup\n",
277 (
params.dynamics_options().steps *
278 params.dynamics_options().time_step));
286 trajectory->setBiasPotential(
nullptr);