Loading...
Searching...
No Matches
ParallelReplicaJob Class Reference

#include <ParallelReplicaJob.h>

Inheritance diagram for ParallelReplicaJob:

Public Member Functions

 ~ParallelReplicaJob ()=default
std::vector< std::string > run () override
 Virtual run; used solely for dynamic dispatch.
std::shared_ptr< MatterrunFromMatter (std::shared_ptr< Matter > initial)
 Matter-first entry; returns final trajectory Matter.
 Job (std::unique_ptr< Parameters > parameters)
 Job (std::shared_ptr< Potential > potPassed, const Parameters &parameters)
Public Member Functions inherited from eonc::Job
 Job (std::unique_ptr< Parameters > parameters)
 Job (std::shared_ptr< Potential > potPassed, const Parameters &parameters)
virtual ~Job ()=default
JobType getType ()

Private Member Functions

void dephase (Matter &trajectory)
int refineTransition (const std::vector< std::shared_ptr< Matter > > &snapshots, bool fake=false)

Private Attributes

std::vector< std::string > returnFiles
std::shared_ptr< Matterreactant
eonc::log::Scoped log

Additional Inherited Members

Protected Attributes inherited from eonc::Job
JobType jtype
Parameters params
std::shared_ptr< Potentialpot

Detailed Description

Definition at line 23 of file ParallelReplicaJob.h.

Constructor & Destructor Documentation

◆ ~ParallelReplicaJob()

Member Function Documentation

◆ dephase()

void ParallelReplicaJob::dephase ( Matter & trajectory)
private

Definition at line 275 of file ParallelReplicaJob.cpp.

275 {
276 Dynamics dynamics(&trajectory, params);
277
278 int dephaseSteps =
279 static_cast<int>(std::floor(params.parallel_replica_options.dephase_time /
280 params.dynamics_options.time_step +
281 0.5));
282 if (dephaseSteps < 1)
283 dephaseSteps = 1;
284 const long maxLoops =
285 std::max(1L, params.parallel_replica_options.dephase_loop_max);
286 QUILL_LOG_DEBUG(log, "[ParallelReplica] Dephasing: {} steps (max {} loops)",
287 dephaseSteps, maxLoops);
288
289 Matter initial(pot, params);
290 initial = trajectory;
291
292 for (long loop = 0; loop < maxLoops; ++loop) {
293 trajectory = initial;
294 dynamics.setThermalVelocity();
295
296 for (int step = 1; step <= dephaseSteps; step++) {
297 dynamics.oneStep(step);
298 }
299
300 Matter minimized(pot, params);
301 minimized = trajectory;
302 minimized.relax();
303
304 if (minimized.compare(*reactant)) {
305 QUILL_LOG_DEBUG(log, "[ParallelReplica] Dephasing successful");
306 return;
307 }
308 QUILL_LOG_DEBUG(
309 log,
310 "[ParallelReplica] Transition occured during dephasing; Restarting");
311 }
312 // Exhausted retries: keep last dephased trajectory rather than hang.
313 QUILL_LOG_DEBUG(log,
314 "[ParallelReplica] Dephase loop max reached; continuing");
315}
eonc::log::Scoped log
std::shared_ptr< Matter > reactant
std::shared_ptr< Potential > pot
Definition Job.h:55
Parameters params
Definition Job.h:54
bool relax(bool quiet=false, bool writeMovie=false, bool checkpoint=false, std::string prefixMovie=std::string(), std::string prefixCheckpoint=std::string(), bool retainMovieFrames=false)
Definition Matter.cpp:257

◆ Job() [1/2]

eonc::Job::Job ( std::shared_ptr< Potential > potPassed,
const Parameters & parameters )
inline

Definition at line 63 of file Job.h.

64 : jtype{parameters.main_options.job},
65 params{parameters},
66 pot{potPassed} {}
JobType jtype
Definition Job.h:53
struct eonc::Parameters::main_options_t main_options

◆ Job() [2/2]

eonc::Job::Job ( std::unique_ptr< Parameters > parameters)
inline

Definition at line 58 of file Job.h.

59 : jtype{parameters->main_options.job},
60 params{*std::move(parameters)},
61 pot{helpers::makePotential(params.potential_options.potential,
62 params)} {}

◆ refineTransition()

int ParallelReplicaJob::refineTransition ( const std::vector< std::shared_ptr< Matter > > & snapshots,
bool fake = false )
private

Definition at line 317 of file ParallelReplicaJob.cpp.

318 {
319 int lo = 0;
320 int hi = static_cast<int>(snapshots.size()) - 1;
321
322 while ((hi - lo) > 1) {
323 int mid = lo + (hi - lo) / 2;
324 Matter snapshot(*snapshots[mid]);
325 snapshot.relax(true);
326
327 bool stillReactant;
328 if (!fake) {
329 stillReactant = snapshot.compare(*reactant);
330 } else {
331 stillReactant = static_cast<bool>(eonc::helpers::randomInt(0, 1));
332 }
333
334 if (stillReactant) {
335 lo = mid;
336 } else {
337 hi = mid;
338 }
339 }
340
341 return (lo + hi) / 2 + 1;
342}
long randomInt(int lower, int upper)

◆ run()

std::vector< std::string > ParallelReplicaJob::run ( )
overridevirtual

Virtual run; used solely for dynamic dispatch.

Implements eonc::Job.

Definition at line 25 of file ParallelReplicaJob.cpp.

25 {
26 reactant = std::make_shared<Matter>(pot, params);
27 {
28 const auto posIn =
29 eonc::helpers::getRelevantFile(params.main_options.conFilename);
30 if (!eonc::io::io_ok(reactant->con2matter(posIn))) {
31 QUILL_LOG_CRITICAL(log, "Failed to load {}", posIn);
32 throw std::runtime_error("failed to load " + posIn);
33 }
34 }
36 return returnFiles;
37}
std::vector< std::string > returnFiles
std::shared_ptr< Matter > runFromMatter(std::shared_ptr< Matter > initial)
Matter-first entry; returns final trajectory Matter.
std::string getRelevantFile(std::string filename)
constexpr bool io_ok(IoStatus s) noexcept
Definition ConFileIO.h:38

◆ runFromMatter()

std::shared_ptr< Matter > ParallelReplicaJob::runFromMatter ( std::shared_ptr< Matter > initial)

Matter-first entry; returns final trajectory Matter.

Definition at line 40 of file ParallelReplicaJob.cpp.

40 {
41 if (!initial) {
42 throw std::runtime_error("ParallelReplicaJob::runFromMatter: null Matter");
43 }
44 reactant = initial;
45 reactant->setPotential(pot);
46
47 QUILL_LOG_DEBUG(log, "[ParallelReplica] Minimizing initial position");
48 reactant->relax();
49 if (!eonc::io::io_ok(reactant->matter2con("reactant.con"))) {
50 QUILL_LOG_ERROR(log, "Failed to write reactant.con");
51 }
52
53 auto trajectory = std::make_shared<Matter>(pot, params);
54 *trajectory = *reactant;
55 Dynamics dynamics(trajectory.get(), params);
56 BondBoost bondBoost(trajectory.get(), params);
57
58 if (params.hyperdynamics_options.bias_potential ==
60 bondBoost.initialize();
61 trajectory->setBiasPotential(&bondBoost);
62 }
63
64 dephase(*trajectory);
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;
82 Matter transitionStructure(pot, params);
83 size_t refineForceCalls = 0;
84
85 double simulationTime = 0.0;
86 if (params.hyperdynamics_options.bias_potential == Hyperdynamics::NONE) {
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(
92 log,
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 // oneStep() evaluates accelerations (and therefore boost()) more than
101 // once. Advance the equilibration counter here, once per MD step, so
102 // ParallelReplica and SafeHyper share the same rmd_time schedule.
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) /
120 params.constants.kB);
121
122 if (step % params.debug_options.write_movies_interval == 0) {
123 if (params.hyperdynamics_options.bias_potential == Hyperdynamics::NONE) {
124 QUILL_LOG_DEBUG(log,
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(
133 log,
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 // Snapshots for refinement
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 // Check for transition
151 if (step % stateCheckInterval == 0 ||
152 step == params.dynamics_options.steps) {
153 QUILL_LOG_DEBUG(log, "[ParallelReplica] Checking for transition");
154
155 Matter minimized(pot, params);
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);
168 snapshotIndex = refineTransition(mdSnapshots);
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 // Fake refinement to prevent force-call bias (only if snapshots exist)
188 if (params.parallel_replica_options.refine_transition &&
189 !mdSnapshots.empty()) {
190 QUILL_LOG_DEBUG(
191 log,
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);
197 refineTransition(mdSnapshots, true);
198 }
199 }
200 transitionStructure = *trajectory;
201 }
202
203 mdSnapshots.clear();
204 mdTimes.clear();
205 }
206 }
207
208 // Decorrelation dynamics
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 // Minimize final structure
221 Matter product(pot, params);
222 product = *trajectory;
223 product.relax();
224 if (!eonc::io::io_ok(product.matter2con("product.con"))) {
225 QUILL_LOG_ERROR(log, "Failed to write product.con");
226 }
227
228 // Write results
229 std::string resultsFilename("results.dat");
230 returnFiles.push_back(resultsFilename);
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",
239 reactant->getPotentialEnergy());
240 out << std::format("{} force_calls_refine\n", refineForceCalls);
241 out << std::format("{} total_force_calls\n",
242 PotRegistry::get().total_force_calls());
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 // bondBoost is a stack local of this function and setBiasPotential does not
267 // own it, so the trajectory must not carry the pointer past the return.
268 // getBiasForces reads a null bias potential as zero bias, which is what a
269 // Matter that is no longer being boosted means.
270 trajectory->setBiasPotential(nullptr);
271
272 return trajectory;
273}
static const char NONE[]
Definition BondBoost.h:76
static const char BOND_BOOST[]
Definition BondBoost.h:77
int refineTransition(const std::vector< std::shared_ptr< Matter > > &snapshots, bool fake=false)
void dephase(Matter &trajectory)
static PotRegistry & get() noexcept
Process-lifetime singleton.

Member Data Documentation

◆ log

◆ reactant

std::shared_ptr<Matter> eonc::ParallelReplicaJob::reactant
private

Definition at line 33 of file ParallelReplicaJob.h.

◆ returnFiles

std::vector<std::string> eonc::ParallelReplicaJob::returnFiles
private

Definition at line 32 of file ParallelReplicaJob.h.


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