1 #ifndef CASM_MonteDriver_impl
2 #define CASM_MonteDriver_impl
4 #include <boost/filesystem.hpp>
5 #include <boost/filesystem/fstream.hpp>
19 template <
typename RunType>
26 m_dir(m_settings.output_directory()),
27 m_drive_mode(m_settings.drive_mode()),
29 m_conditions_list(make_conditions_list(
primclex, m_settings)),
30 m_debug(m_settings.debug()),
31 m_enum(m_settings.is_enumeration()
46 template <
typename RunType>
48 m_log.check(
"For existing calculations");
50 if (!m_settings.write_json() && !m_settings.write_csv()) {
51 throw std::runtime_error(
52 std::string(
"No valid monte carlo output format.\n") +
53 " Expected [\"data\"][\"storage\"][\"output_format\"] to contain a "
54 "string or array of strings.\n" +
55 " Valid options are 'csv' or 'json'.");
59 Index start_i = _find_starting_conditions();
63 std::vector<Index> repeats;
64 for (
Index i = start_i; i < m_conditions_list.size(); ++i) {
65 if (fs::exists(m_dir.conditions_dir(i))) {
70 if (start_i == m_conditions_list.size()) {
71 m_log <<
"calculations already complete." << std::endl;
76 if (start_i > 0 || repeats.size() > 0) {
77 m_log <<
"found existing calculations\n";
78 m_log <<
"will begin with condition " << start_i <<
"\n";
83 m_log <<
"will overwrite existing results for condition(s): " << json
87 m_log <<
"did not find existing calculations\n";
91 if (m_settings.dependent_runs()) {
95 m_mc.set_state(m_conditions_list[0], m_settings);
98 if (m_settings.dependent_runs() &&
99 m_settings.is_equilibration_passes_first_run()) {
100 auto equil_passes = m_settings.equilibration_passes_first_run();
103 m_log <<
"write: " << m_dir.initial_state_firstruneq_json(0) <<
"\n"
107 fs::create_directories(m_dir.conditions_dir(0));
108 to_json(m_mc.configdof(), json)
109 .
write(m_dir.initial_state_firstruneq_json(0));
111 m_log.begin(
"Equilibration passes");
112 m_log << equil_passes <<
" equilibration passes\n" << std::endl;
114 MonteCounter equil_counter(m_settings, m_mc.steps_per_pass());
115 while (equil_counter.
pass() != equil_passes) {
126 m_mc.set_configdof(configdof,
127 std::string(
"Using: ") +
128 m_dir.final_state_json(start_i - 1).string());
133 for (
Index i = start_i; i < m_conditions_list.size(); i++) {
134 if (!m_settings.dependent_runs()) {
135 m_mc.set_state(m_conditions_list[i], m_settings);
137 m_mc.set_conditions(m_conditions_list[i]);
139 m_log.custom(
"Continue with existing DoF");
154 template <
typename RunType>
157 Index start_max = m_conditions_list.size();
158 Index start_json = m_settings.write_json() ? 0 : start_max;
159 Index start_csv = m_settings.write_csv() ? 0 : start_max;
161 fs::ifstream csv_results;
163 std::stringstream ss;
168 if (m_settings.write_json() && fs::exists(m_dir.results_json())) {
169 json_results.
read(m_dir.results_json());
172 while (json_results.
begin()->size() > start_json &&
173 fs::exists(m_dir.final_state_json(start_i)) && start_i < start_max) {
177 start_max = start_json;
181 if (m_settings.write_csv() && fs::exists(m_dir.results_csv())) {
182 csv_results.open(m_dir.results_csv());
185 std::getline(csv_results, str);
189 while (!csv_results.eof() &&
190 fs::exists(m_dir.final_state_json(start_csv)) &&
191 start_i < start_max) {
193 std::getline(csv_results, str);
197 start_max = start_csv;
202 start_i =
std::min(start_json, start_csv);
208 if (m_settings.write_json() && fs::exists(m_dir.results_json())) {
212 for (
auto it = json_results.
begin(); it != json_results.
end(); ++it) {
214 for (
Index i = 0; i < start_i; ++i) {
215 ref.push_back((*it)[i]);
218 m_log <<
"update: " << m_dir.results_json() <<
"\n";
219 finished_results.
write(m_dir.results_json());
223 if (m_settings.write_csv() && fs::exists(m_dir.results_csv())) {
224 m_log <<
"update: " << m_dir.results_csv() <<
"\n";
225 fs::ofstream out(m_dir.results_csv());
233 template <
typename RunType>
235 fs::create_directories(m_dir.conditions_dir(cond_index));
238 if (m_settings.is_equilibration_passes_each_run()) {
240 m_log <<
"write: " << m_dir.initial_state_runeq_json(cond_index) <<
"\n"
244 to_json(m_mc.configdof(), json)
245 .
write(m_dir.initial_state_runeq_json(cond_index));
246 auto equil_passes = m_settings.equilibration_passes_each_run();
248 m_log.begin(
"Equilibration passes");
249 m_log << equil_passes <<
" equilibration passes\n" << std::endl;
251 MonteCounter equil_counter(m_settings, m_mc.steps_per_pass());
252 while (equil_counter.
pass() != equil_passes) {
260 m_log <<
"write: " << m_dir.initial_state_json(cond_index) <<
"\n"
263 to_json(m_mc.configdof(), json).
write(m_dir.initial_state_json(cond_index));
265 std::stringstream ss;
266 ss <<
"Conditions " << cond_index;
267 m_log.begin(ss.str());
271 MonteCounter run_counter(m_settings, m_mc.steps_per_pass());
279 m_log <<
"pass: " << run_counter.
pass() <<
" "
280 <<
"step: " << run_counter.
step() <<
" "
281 <<
"samples: " << run_counter.
samples() <<
"\n"
285 if (m_mc.must_converge()) {
289 throw std::runtime_error(
290 std::string(
"Error in 'MonteDriver<RunType>::single_run()'\n") +
291 " Conflicting input: Minimum number of passes, steps, or "
292 "samples not met,\n" +
293 " but maximum number of passes, steps, or samples are met.");
296 if (m_mc.check_convergence_time()) {
299 m_log <<
"samples: " << m_mc.sample_times().size() << std::endl;
302 if (m_mc.is_converged()) {
318 if (res && m_enum && m_enum->on_accept()) {
319 m_enum->insert(m_mc.config());
326 m_log <<
"pass: " << run_counter.
pass() <<
" "
327 <<
"step: " << run_counter.
step() <<
" "
328 <<
"take sample " << m_mc.sample_times().size() <<
"\n"
331 m_mc.sample_data(run_counter);
333 if (m_enum && m_enum->on_sample()) {
334 m_enum->insert(m_mc.config());
341 double s = m_log.lap_time();
343 m_log <<
"run time: " <<
s <<
" (s), " <<
s / run_counter.
pass()
351 m_log <<
"write: " << m_dir.final_state_json(cond_index) <<
"\n" << std::endl;
352 to_json(m_mc.configdof(), json).
write(m_dir.final_state_json(cond_index));
354 m_log.write(
"Output files");
355 m_mc.write_results(cond_index);
359 m_enum->save_configs();
376 template <
typename RunType>
377 std::vector<typename MonteDriver<RunType>::CondType>
380 std::vector<CondType> conditions_list;
382 switch (m_drive_mode) {
385 std::vector<CondType> custom_cond(settings.custom_conditions());
387 while (fs::exists(m_dir.conditions_json(i))) {
391 if (existing != custom_cond[i]) {
392 m_err_log.error(
"Conditions mismatch");
393 m_err_log <<
"existing conditions: " << m_dir.conditions_json(i)
395 m_err_log << existing <<
"\n\n";
396 m_err_log <<
"specified custom conditions " << i <<
":\n";
397 m_err_log << custom_cond[i] <<
"\n" << std::endl;
398 throw std::runtime_error(
399 "ERROR: custom_conditions list has changed.");
407 CondType init_cond(settings.initial_conditions());
408 CondType final_cond(settings.final_conditions());
409 CondType cond_increment(settings.incremental_conditions());
411 CondType incrementing_cond = init_cond;
413 int num_increments = 1 + (final_cond - init_cond) / cond_increment;
415 for (
int i = 0; i < num_increments; i++) {
416 conditions_list.push_back(incrementing_cond);
417 incrementing_cond += cond_increment;
421 while (fs::exists(m_dir.conditions_json(i)) &&
422 i < conditions_list.size()) {
426 if (existing != conditions_list[i]) {
427 m_err_log.error(
"Conditions mismatch");
428 m_err_log <<
"existing conditions: " << m_dir.conditions_json(i)
430 m_err_log << existing <<
"\n";
431 m_err_log <<
"incremental conditions " << i <<
":\n";
432 m_err_log << conditions_list[i] <<
"\n" << std::endl;
433 throw std::runtime_error(
434 "ERROR: initial_conditions or incremental_conditions has "
440 return conditions_list;
444 throw std::runtime_error(
"ERROR: An invalid drive mode was given.");
449 template <
typename RunType>
451 typedef typename RunType::EventType EventType;
453 const EventType &
event = monte_run.propose();
455 if (monte_run.check(event)) {
456 monte_run.accept(event);
461 monte_run.reject(event);
std::set< std::string > & s
Track the number of passes, steps and samples taken in a Monte Carlo calculation.
bool sample_time() const
Returns true if based on period and current number of steps it is time to take a sample.
bool maximums_met() const
Check if maximum number of pass, step, and samples has been met.
size_type samples() const
Number of samples taken.
bool is_complete() const
Check if requested number of pass, step, or samples has been met.
bool minimums_met() const
Check if minimum number of pass, step, and samples has been met.
size_type steps_per_pass() const
Number of steps per pass.
size_type step() const
Number of steps into the current pass.
void increment_samples()
Increments the number of samples taken and resets counter until the next sample should be taken.
size_type pass() const
Number of complete passes performed.
void run()
Run everything requested by the MonteSettings.
void single_run(Index cond_index)
Converge the MonteCarlo for conditions 'cond_index'.
RunType::SettingsType SettingsType
MonteDriver(const PrimClex &primclex, const SettingsType &settings, Log &_log, Log &_err_log)
Constructor via MonteSettings.
RunType::CondType CondType
std::vector< CondType > make_conditions_list(const PrimClex &primclex, const SettingsType &settings)
Index _find_starting_conditions() const
Check for existing calculations to find starting conditions.
PrimClex is the top-level data structure for a CASM project.
iterator begin()
Returns const_iterator to beginning of JSON object or JSON array.
iterator end()
Returns iterator to end of JSON object or JSON array.
bool read(std::istream &stream)
Reads json from the stream.
void write(const std::string &file_name, unsigned int indent=2, unsigned int prec=12) const
Write json to file.
jsonParser & put_array()
Puts new empty JSON array.
void from_json(CanonicalConditions &conditions, const PrimClex &primclex, const jsonParser &json)
Read CanonicalConditions from JSON format.
bool monte_carlo_step(RunType &monte_run)
Perform a single monte carlo step, return true if accepted.
jsonParser & to_json(const CanonicalConditions &conditions, jsonParser &json)
Store CanonicalConditions in JSON format.
T min(const T &A, const T &B)
INDEX_TYPE Index
For long integer indexing: