34 double swap_accept = 0.0;
39 int quench_displacements = 0;
40 int consecutive_rejected_trials = 0;
41 double totalAccept = 0.0;
42 std::unique_ptr<Matter> minTrial = std::make_unique<Matter>(
pot,
params);
43 std::unique_ptr<Matter> swapTrial = std::make_unique<Matter>(
pot,
params);
45 std::string conFilename =
48 QUILL_LOG_CRITICAL(
log,
"Failed to load {}", conFilename);
49 throw std::runtime_error(
"failed to load " + conFilename);
53 std::vector<long> Elements;
55 if (
params.basin_hopping_options().swap_probability > 0 &&
56 Elements.size() == 1) {
58 QUILL_LOG_CRITICAL(
log,
59 "error: [Basin Hopping] swap move probability must be "
60 "zero if there is only one element type\n");
61 throw std::invalid_argument(
62 "[Basin Hopping] swap_probability must be zero with one element type");
66 params.basin_hopping_options().initial_random_structure_probability;
67 if (randomProb > 0.0) {
68 QUILL_LOG_DEBUG(
log,
"generating random structure with probability {:.4f}",
72 if (u <
params.basin_hopping_options().initial_random_structure_probability) {
74 for (
int i = 0; i <
current->numberOfFreeAtoms(); i++) {
75 for (
int j = 0; j < 3; j++) {
79 randomPositions *=
current->getCell();
80 current->setPositionsFree(randomPositions);
91 double currentEnergy =
current->getPotentialEnergy();
92 double minimumEnergy = currentEnergy;
94 auto minimumEnergyStructure = std::make_shared<Matter>(
pot,
params);
95 *minimumEnergyStructure = *
current;
96 int nsteps =
params.basin_hopping_options().steps +
97 params.basin_hopping_options().quenching_steps;
100 log,
"[Basin Hopping] {:4s} {:12s} {:12s} {:12s} {:4s} {:5s} {:5s}",
101 "step",
"current",
"trial",
"global min",
"fc",
"ar",
"md");
103 log,
"[Basin Hopping] {:4s} {:12s} {:12s} {:12s} {:4s} {:5s} {:5s}",
104 "----",
"-------",
"-----",
"----------",
"--",
"--",
"--");
106 int recentAccept = 0;
107 double curDisplacement =
params.basin_hopping_options().displacement;
109 for (
int step = 0; step < nsteps; step++) {
113 params.basin_hopping_options().swap_probability &&
114 step <
params.basin_hopping_options().steps) {
118 *minTrial = *swapTrial;
122 if (step >=
params.basin_hopping_options().steps) {
123 quench_displacements++;
126 trial->setPositions(
current->getPositions() + displacement);
129 trial,
params.basin_hopping_options().push_apart_distance);
134 if (
params.debug_options().write_movies) {
136 QUILL_LOG_WARNING(
log,
"Failed to append trials movie frame");
140 minTrial->relax(
true);
142 double deltaE = minTrial->getPotentialEnergy() - currentEnergy;
144 if (step >=
params.basin_hopping_options().steps) {
151 params.main_options().temperature);
154 bool accepted =
false;
157 if (
params.basin_hopping_options().significant_structure) {
159 }
else if (swapMove) {
167 if (step <
params.basin_hopping_options().steps) {
172 currentEnergy = minTrial->getPotentialEnergy();
174 if (currentEnergy < minimumEnergy) {
175 minimumEnergy = currentEnergy;
176 *minimumEnergyStructure = *minTrial;
178 QUILL_LOG_WARNING(
log,
"Failed to write min.con");
182 if (
params.basin_hopping_options().write_unique) {
183 bool newStructure =
true;
188 params.structure_comparison_options().energy_difference) {
191 params.structure_comparison_options()
192 .indistinguishable_atoms)) {
193 newStructure =
false;
200 auto currentCopy = std::make_shared<Matter>(
pot,
params);
205 snprintf(fname, 128,
"min_%.5i.con", step + 1);
207 QUILL_LOG_WARNING(
log,
"Failed to write {}", fname);
211 snprintf(fname, 128,
"energy_%.5i.dat", step + 1);
214 std::ofstream fh(fname);
216 fh << std::format(
"{:.10e}\n", currentEnergy);
221 consecutive_rejected_trials = 0;
223 consecutive_rejected_trials++;
226 if (
params.debug_options().write_movies) {
228 QUILL_LOG_WARNING(
log,
"Failed to append basin-hopping movie frame");
232 if (minimumEnergy <
params.basin_hopping_options().stop_energy) {
236 if (consecutive_rejected_trials ==
237 params.basin_hopping_options().jump_max &&
238 step <
params.basin_hopping_options().steps) {
239 consecutive_rejected_trials = 0;
241 for (
int j = 0; j <
params.basin_hopping_options().jump_steps; j++) {
247 if (
params.basin_hopping_options().significant_structure) {
249 current,
params.basin_hopping_options().push_apart_distance);
251 currentEnergy =
current->getPotentialEnergy();
252 if (currentEnergy < minimumEnergy) {
253 minimumEnergy = currentEnergy;
254 *minimumEnergyStructure = *
current;
260 int nadjust =
params.basin_hopping_options().adjust_period;
261 double adjustFraction =
params.basin_hopping_options().adjust_fraction;
263 if (nadjust != 0 && (step + 1) % nadjust == 0 &&
264 params.basin_hopping_options().adjust_displacement) {
266 static_cast<double>(recentAccept) /
static_cast<double>(nadjust);
267 if (recentRatio >
params.basin_hopping_options().target_ratio) {
268 curDisplacement *= 1.0 + adjustFraction;
270 curDisplacement *= 1.0 - adjustFraction;
278 std::string resultsFilename(
"results.dat");
280 if (
params.debug_options().write_movies) {
281 std::string movieFilename(
"movie.con");
289 env.job_type =
"basin_hopping";
290 env.random_seed =
params.main_options().randomSeed;
291 env.extras.emplace_back(
"minimum_energy", minimumEnergy);
292 const double nsteps_ratio =
params.basin_hopping_options().steps;
293 env.extras.emplace_back(
"acceptance_ratio",
294 nsteps_ratio ? totalAccept / nsteps_ratio : 0.0);
295 if (
params.basin_hopping_options().swap_probability > 0) {
296 env.extras.emplace_back(
297 "swap_acceptance_ratio",
300 env.extras.emplace_back(
301 "total_normal_displacement_steps",
303 env.extras.emplace_back(
"total_jump_steps",
305 env.extras.emplace_back(
"total_swap_steps",
307 env.writeResultsDat(resultsFilename);
311 std::string productFilename(
"min.con");
312 if (
eonc::io::io_ok(minimumEnergyStructure->matter2con(productFilename))) {
315 QUILL_LOG_ERROR(
log,
"Failed to write {}", productFilename);