Loading...
Searching...
No Matches
ReplicaExchangeJob Class Reference

#include <ReplicaExchangeJob.h>

Inheritance diagram for ReplicaExchangeJob:

Public Member Functions

 ~ReplicaExchangeJob ()=default
std::vector< std::string > run (void)
 Virtual run; used solely for dynamic dispatch.
std::shared_ptr< MatterrunFromMatter (std::shared_ptr< Matter > initial)
 Matter-first; returns replica-0 Matter after sampling.
 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 saveData ()

Private Attributes

size_t forceCalls {0}
std::shared_ptr< Matterpos
std::vector< std::string > returnFiles
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 22 of file ReplicaExchangeJob.h.

Constructor & Destructor Documentation

◆ ~ReplicaExchangeJob()

Member Function Documentation

◆ 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
std::shared_ptr< Potential > pot
Definition Job.h:55
Parameters params
Definition Job.h:54
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)} {}

◆ run()

std::vector< std::string > ReplicaExchangeJob::run ( void )
virtual

Virtual run; used solely for dynamic dispatch.

Implements eonc::Job.

Definition at line 27 of file ReplicaExchangeJob.cpp.

27 {
28 std::string posFilename =
29 eonc::helpers::getRelevantFile(params.main_options.conFilename);
30 pos = std::make_shared<Matter>(pot, params);
31 if (!eonc::io::io_ok(pos->con2matter(posFilename))) {
32 QUILL_LOG_CRITICAL(log, "Failed to load {}", posFilename);
33 throw std::runtime_error("failed to load " + posFilename);
34 }
35 (void)runFromMatter(pos);
36 return returnFiles;
37}
std::vector< std::string > returnFiles
std::shared_ptr< Matter > pos
eonc::log::Scoped log
std::shared_ptr< Matter > runFromMatter(std::shared_ptr< Matter > initial)
Matter-first; returns replica-0 Matter after sampling.
std::string getRelevantFile(std::string filename)
constexpr bool io_ok(IoStatus s) noexcept
Definition ConFileIO.h:38

◆ runFromMatter()

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

Matter-first; returns replica-0 Matter after sampling.

Definition at line 40 of file ReplicaExchangeJob.cpp.

40 {
41 if (!initial) {
42 throw std::runtime_error("ReplicaExchangeJob::runFromMatter: null Matter");
43 }
44 pos = initial;
45 pos->setPotential(pot);
46
47 long samplingSteps =
48 static_cast<long>(params.replica_exchange_options.sampling_time /
49 params.dynamics_options.time_step +
50 0.5);
51 long exchangePeriodSteps =
52 static_cast<long>(params.replica_exchange_options.exchange_period /
53 params.dynamics_options.time_step +
54 0.5);
55 const double kB = params.constants.kB;
56 if (samplingSteps <= 0)
57 samplingSteps = 1;
58 if (exchangePeriodSteps <= 0)
59 exchangePeriodSteps = 1;
60
61 QUILL_LOG_DEBUG(log, "Running Replica Exchange");
62
63 long refForceCalls = PotRegistry::get().total_force_calls();
64
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);
68
69 // Per-image potentials: each replica gets its own potential instance when
70 // the potential requires it (e.g. ML potentials with internal state)
71 const bool perImage = pot->needsPerImageInstance();
72 for (long i = 0; i < nReplicas; i++) {
73 auto replicaPot = perImage ? eonc::helpers::makePotential(params) : pot;
74 replica[i] = std::make_shared<Matter>(replicaPot, params);
75 *replica[i] = *pos;
76 replicaDynamics[i] = std::make_unique<Dynamics>(replica[i].get(), params);
77 }
78
79 std::vector<double> replicaTemperature(nReplicas);
80
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]);
90 }
91 } else if (params.replica_exchange_options.temperature_distribution ==
92 "exponential") {
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]);
102 }
103 }
104
105 QUILL_LOG_DEBUG(
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);
109
110 // Parallel replica dynamics when enabled and potential supports it
111 const bool canParallel = params.main_options.parallel &&
112 (pot->isSharedInstanceThreadSafe() || perImage);
113
114 for (long step = 1; step <= samplingSteps; step++) {
115 if (canParallel && nReplicas > 1) {
116 // Parallel: each replica runs its MD step in a separate thread
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(); });
121 }
122 for (auto &t : threads) {
123 t.join();
124 }
125 } else {
126 for (long i = 0; i < nReplicas; i++) {
127 replicaDynamics[i]->oneStep();
128 }
129 }
130
131 // Metropolis replica exchange
132 if ((step % exchangePeriodSteps) == 0) {
133 for (long trial = 0;
134 trial < params.replica_exchange_options.exchange_trials; trial++) {
135 long i = eonc::helpers::randomInt(0, nReplicas - 2);
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];
140 double pAcc =
141 std::min(1.0, std::exp((energyHigh - energyLow) *
142 (eonc::safemath::safe_recip(kbTHigh, 0.0) -
143 eonc::safemath::safe_recip(kbTLow, 0.0))));
144 double rnd = eonc::helpers::randomDouble();
145 QUILL_LOG_INFO(log,
146 "step: {} trial swap, i {}, elow: {:.5f}, ehigh: "
147 "{:.5f}, pAcc: {:.5f}, rand: {}",
148 step, i, energyLow, energyHigh, pAcc, rnd);
149 if (rnd < pAcc) {
150 QUILL_LOG_INFO(log, "swap");
151 std::swap(replica[i], replica[i + 1]);
152 replicaDynamics[i]->setThermalVelocity();
153 replicaDynamics[i + 1]->setThermalVelocity();
154 } else {
155 QUILL_LOG_INFO(log, "no swap");
156 }
157 }
158 }
159 }
160
161 forceCalls = PotRegistry::get().total_force_calls() - refForceCalls;
162 saveData();
163 if (!replica.empty()) {
164 *pos = *replica[0];
165 }
166 return pos;
167}
static PotRegistry & get() noexcept
Process-lifetime singleton.
size_t total_force_calls() const noexcept
long randomInt(int lower, int upper)
double randomDouble()
std::shared_ptr< Potential > makePotential(const Parameters &params)
quill::Logger * get() noexcept
Get or create the default "combi" logger.
Definition EonLogger.h:44
constexpr double safe_recip(double x, double fallback=0.0)
Definition SafeMath.h:29

◆ saveData()

void ReplicaExchangeJob::saveData ( )
private

Definition at line 169 of file ReplicaExchangeJob.cpp.

169 {
170 std::string resultsFilename("results.dat");
171 returnFiles.push_back(resultsFilename);
172
173 std::ofstream out(resultsFilename, std::ios::binary);
174 if (out) {
175 out << std::format("{} termination_reason\n", 0);
176 out << "GOOD termination_reason_text\n";
177 out << "replica_exchange job_type\n";
178 out << std::format("{} random_seed\n", params.main_options.randomSeed);
179 out << std::format(
180 "{} potential_type\n",
181 magic_enum::enum_name<PotType>(params.potential_options.potential));
182 out << std::format("{} force_calls_sampling\n", forceCalls);
183 }
184
185 std::string posFilename("pos_out.con");
186 returnFiles.push_back(posFilename);
187 if (pos) {
188 if (!eonc::io::io_ok(pos->matter2con(posFilename))) {
189 QUILL_LOG_ERROR(log, "Failed to write {}", posFilename);
190 }
191 }
192}

Member Data Documentation

◆ forceCalls

Definition at line 33 of file ReplicaExchangeJob.h.

33{0};

◆ log

◆ pos

std::shared_ptr<Matter> eonc::ReplicaExchangeJob::pos
private

Definition at line 35 of file ReplicaExchangeJob.h.

◆ returnFiles

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

Definition at line 38 of file ReplicaExchangeJob.h.


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