1212#include " aux/eigensupport.h"
1313#include " aux/arange.h"
1414#include " aux/matrixmarket.h"
15+ #include < cmath>
1516#include < exception>
1617#include < iterator>
1718#include < range/v3/numeric/accumulate.hpp>
@@ -241,12 +242,33 @@ void SystemEnergy::normalize() {
241242 }
242243}
243244
245+ /* *
246+ * @brief Checks if the current energy is the lowest so far and saves the configuration if so.
247+ *
248+ * The output is hardcoded to PQR format, tagged with the step number and energy.
249+ *
250+ * @return True if a new minimum energy was encountered
251+ */
252+ bool SystemEnergy::updateMinimumEnergy (const double current_energy) {
253+ if (!dump_minimum_energy_configuration || current_energy >= minimum_energy) {
254+ return false ;
255+ }
256+ minimum_energy = current_energy;
257+ const auto filename = MPI::prefix + " mininum_energy.pqr" ;
258+ faunus_logger->debug (" {}: saving {} ({:.2f} kT) at step {}" , name, filename, minimum_energy, getNumberOfSteps ());
259+ PQRWriter (PQRWriter::Style::PQR).save (filename, spc.groups , spc.geometry .getLength ());
260+ return true ;
261+ }
262+
244263void SystemEnergy::_sample () {
245264 const auto energies = calculateEnergies (); // current energy from all terms in Hamiltonian
246265 const auto total_energy = ranges::accumulate (energies, 0.0 );
266+ updateMinimumEnergy (total_energy);
247267 if (std::isfinite (total_energy)) {
248268 mean_energy += total_energy;
249269 mean_squared_energy += total_energy * total_energy;
270+ } else {
271+ faunus_logger->warn (" {}: non-finite energy excluded from averages at step {}" , name, getNumberOfSteps ());
250272 }
251273 *output_stream << fmt::format (" {:10d}{}{:.6E}" , getNumberOfSteps (), separator, total_energy);
252274 for (auto energy : energies) {
@@ -256,19 +278,26 @@ void SystemEnergy::_sample() {
256278}
257279
258280void SystemEnergy::_to_json (json& j) const {
259- j = {{" file" , file_name}, {" init" , initial_energy}, {" final" , calculateEnergies ()}};
281+ j = {{" file" , file_name},
282+ {" init" , initial_energy},
283+ {" final" , calculateEnergies ()},
284+ {" save_min_conf" , dump_minimum_energy_configuration}};
260285 if (!mean_energy.empty ()) {
261286 j[" mean" ] = mean_energy.avg ();
262287 j[" Cv/kB" ] = mean_squared_energy.avg () - std::pow (mean_energy.avg (), 2 );
263288 }
264289 roundJSON (j, 5 );
265290}
266291
267- void SystemEnergy::_from_json (const json& j) { file_name = MPI::prefix + j.at (" file" ).get <std::string>(); }
292+ void SystemEnergy::_from_json (const json& j) {
293+ file_name = MPI::prefix + j.at (" file" ).get <std::string>();
294+ dump_minimum_energy_configuration = j.value (" save_min_conf" , false );
295+ }
268296
269297void SystemEnergy::createOutputStream () {
270298 output_stream = IO::openCompressedOutputStream (file_name, true );
271- if (const auto suffix = file_name.substr (file_name.find_last_of (' .' ) + 1 ); suffix == " csv" ) {
299+ const bool is_csv_file = file_name.substr (file_name.find_last_of (' .' ) + 1 ) == " csv" ;
300+ if (is_csv_file) {
272301 separator = " ," ;
273302 } else {
274303 separator = " " ;
0 commit comments