40 {
41 if (!initial) {
42 throw std::runtime_error("ParallelReplicaJob::runFromMatter: null Matter");
43 }
46
47 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Minimizing initial position");
50 QUILL_LOG_ERROR(
log,
"Failed to write reactant.con");
51 }
52
53 auto trajectory = std::make_shared<Matter>(
pot,
params);
56 BondBoost bondBoost(trajectory.get(),
params);
57
58 if (
params.hyperdynamics_options.bias_potential ==
60 bondBoost.initialize();
61 trajectory->setBiasPotential(&bondBoost);
62 }
63
65
66 int stateCheckInterval = static_cast<int>(
67 std::floor(
params.parallel_replica_options.state_check_interval /
68 params.dynamics_options.time_step +
69 0.5));
70 int recordInterval = static_cast<int>(
71 std::floor(
params.parallel_replica_options.record_interval /
72 params.dynamics_options.time_step +
73 0.5));
74 if (stateCheckInterval < 1)
75 stateCheckInterval = 1;
76 if (recordInterval < 1)
77 recordInterval = 1;
78
79 std::vector<std::shared_ptr<Matter>> mdSnapshots;
80 std::vector<double> mdTimes;
81 double transitionTime = 0;
83 size_t refineForceCalls = 0;
84
85 double simulationTime = 0.0;
87 QUILL_LOG_DEBUG(
88 log,
"[ParallelReplica] {:>8} {:>12} {:>10} {:>12} {:>12} {:>10}",
89 "Step", "Time (s)", "KE", "PE", "TE", "KinT");
90 } else {
91 QUILL_LOG_DEBUG(
93 "[ParallelReplica] {:>8} {:>12} {:>10} {:>10} {:>12} {:>12} {:>10}",
94 "Step", "Time (s)", "Boost", "KE", "PE", "TE", "KinT");
95 }
96
97 for (
int step = 1; step <=
params.dynamics_options.steps; step++) {
98 if (
params.hyperdynamics_options.bias_potential ==
100
101
102
103 bondBoost.advance();
104 }
105 dynamics.oneStep();
106 double boost = 1.0;
107 if (
params.hyperdynamics_options.bias_potential ==
109 double boostPotential = bondBoost.boost();
110 double kB =
params.constants.kB;
111 boost = std::exp(boostPotential / kB /
params.main_options.temperature);
112 simulationTime +=
params.dynamics_options.time_step * boost;
113 } else {
114 simulationTime +=
params.dynamics_options.time_step;
115 }
116
117 double kinE = trajectory->getKineticEnergy();
118 double potE = trajectory->getPotentialEnergy();
119 double kinT = (2.0 * kinE / (trajectory->numberOfFreeAtoms() * 3) /
121
122 if (step %
params.debug_options.write_movies_interval == 0) {
125 "[ParallelReplica] {:>8} {:>12.4e} {:>10.4f} "
126 "{:>12.4f} {:>12.4f} {:>10.2f}",
127 step,
128 simulationTime *
params.constants.timeUnit * 1e-15,
129 kinE, potE, kinE + potE, kinT);
130 } else {
131 double boostPotential = bondBoost.boost();
132 QUILL_LOG_DEBUG(
134 "[ParallelReplica] {:>8} {:>12.4e} {:>10.3e} "
135 "{:>10.4f} {:>12.4f} {:>12.4f} {:>10.2f}",
136 step, simulationTime *
params.constants.timeUnit * 1e-15, boost,
137 kinE, potE + boostPotential, kinE + potE + boostPotential, kinT);
138 }
139 }
140
141
142 if (step % recordInterval == 0 &&
143 params.parallel_replica_options.refine_transition) {
144 auto snap = std::make_shared<Matter>(
pot,
params);
145 *snap = *trajectory;
146 mdSnapshots.push_back(std::move(snap));
147 mdTimes.push_back(simulationTime);
148 }
149
150
151 if (step % stateCheckInterval == 0 ||
152 step ==
params.dynamics_options.steps) {
153 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Checking for transition");
154
156 minimized = *trajectory;
157 minimized.relax();
158
159 if (!minimized.compare(*
reactant) && transitionTime == 0) {
160 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Transition occurred");
161
162 if (
params.parallel_replica_options.refine_transition &&
163 !mdSnapshots.empty() && !mdTimes.empty()) {
164 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Refining transition time");
165 int snapshotIndex;
166 {
167 eonc::ForceCallTimer timer(refineForceCalls);
169 }
170 if (snapshotIndex < 0)
171 snapshotIndex = 0;
172 if (snapshotIndex >= static_cast<int>(mdSnapshots.size()))
173 snapshotIndex = static_cast<int>(mdSnapshots.size()) - 1;
174
175 transitionTime = mdTimes[static_cast<size_t>(snapshotIndex)];
176 transitionStructure =
177 *mdSnapshots[static_cast<size_t>(snapshotIndex)];
178 } else {
179 transitionStructure = *trajectory;
180 transitionTime = simulationTime;
181 }
182 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Transition time: {:.3e} s",
183 transitionTime *
params.constants.timeUnit * 1e-15);
184
185 }
else if (step + 1 ==
params.dynamics_options.steps &&
186 transitionTime == 0) {
187
188 if (
params.parallel_replica_options.refine_transition &&
189 !mdSnapshots.empty()) {
190 QUILL_LOG_DEBUG(
192 "[ParallelReplica] Simulation ended without seeing a transition");
193 QUILL_LOG_DEBUG(
194 log,
"[ParallelReplica] Refining anyways to prevent bias...");
195 {
196 eonc::ForceCallTimer timer(refineForceCalls);
198 }
199 }
200 transitionStructure = *trajectory;
201 }
202
203 mdSnapshots.clear();
204 mdTimes.clear();
205 }
206 }
207
208
209 int decorrelationSteps =
210 static_cast<int>(std::floor(
params.parallel_replica_options.corr_time /
211 params.dynamics_options.time_step +
212 0.5));
213 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Decorrelating: {} steps",
214 decorrelationSteps);
215 for (int step = 1; step <= decorrelationSteps; step++) {
216 dynamics.oneStep(step);
217 }
218 QUILL_LOG_DEBUG(
log,
"[ParallelReplica] Decorrelation complete");
219
220
222 product = *trajectory;
223 product.relax();
225 QUILL_LOG_ERROR(
log,
"Failed to write product.con");
226 }
227
228
229 std::string resultsFilename("results.dat");
231 {
232 std::ofstream out(resultsFilename, std::ios::binary);
233 if (out) {
234 out << std::format(
235 "{} potential_type\n",
236 magic_enum::enum_name<PotType>(
params.potential_options.potential));
237 out << std::format(
"{} random_seed\n",
params.main_options.randomSeed);
238 out << std::format("{:f} potential_energy_reactant\n",
240 out << std::format("{} force_calls_refine\n", refineForceCalls);
241 out << std::format("{} total_force_calls\n",
243
244 if (transitionTime == 0) {
245 out << "0 transition_found\n";
246 out << std::format("{:e} simulation_time_s\n",
247 simulationTime *
params.constants.timeUnit *
248 1.0e-15);
249 } else {
250 out << "1 transition_found\n";
251 out << std::format("{:e} transition_time_s\n",
252 transitionTime *
params.constants.timeUnit *
253 1.0e-15);
254 out << std::format("{:e} correlation_time_s\n",
255 params.parallel_replica_options.corr_time *
256 params.constants.timeUnit * 1.0e-15);
257 out << std::format("{:f} potential_energy_product\n",
258 product.getPotentialEnergy());
259 }
260 out << std::format("{:f} speedup\n",
261 simulationTime / (
params.dynamics_options.steps *
262 params.dynamics_options.time_step));
263 }
264 }
265
266
267
268
269
270 trajectory->setBiasPotential(nullptr);
271
272 return trajectory;
273}
static const char BOND_BOOST[]
int refineTransition(const std::vector< std::shared_ptr< Matter > > &snapshots, bool fake=false)
void dephase(Matter &trajectory)
static PotRegistry & get() noexcept
Process-lifetime singleton.