QMCPACK
WalkerLogManager.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2024 QMCPACK developers.
6 //
7 // File developed by: Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
8 //
9 // File created by: Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 #include "WalkerLogManager.h"
13 #include "WalkerLogInput.h"
14 #include "Concurrency/Info.hpp"
15 
16 
17 namespace qmcplusplus
18 {
19 
20 
21 WalkerLogManager::WalkerLogManager(WalkerLogInput& inp, bool allow_logs, std::string series_root, Communicate* comm)
22 {
24  file_root = series_root;
25  bool driver_allows_logs = allow_logs; // driver allows logs or not
26 
27  bool logs_requested = inp.present; // xml input present or not
28  // determine whether walker logs will be active
29  state.logs_active = logs_requested && driver_allows_logs;
30 
31  if (state.logs_active)
32  {
33  if (Concurrency::getWorkerId() == 0)
34  {
35  app_log() << "\n WalkerLogManager::put() " << std::endl;
36  app_log() << " logs requested : " << logs_requested << std::endl;
37  app_log() << " driver allows logs : " << driver_allows_logs << std::endl;
38  app_log() << " logs active : " << state.logs_active << std::endl;
39  app_log() << std::endl;
40  }
41  // retrieve input data
42  state.step_period = inp.get<int>("step_period");
43  state.verbose = inp.get<bool>("verbose");
44  bool quantiles = inp.get<bool>("quantiles");
45  write_particle_data = inp.get<bool>("particle");
46  write_min_data = inp.get<bool>("min") && quantiles;
47  write_max_data = inp.get<bool>("max") && quantiles;
48  write_med_data = inp.get<bool>("median") && quantiles;
49  }
50 
51  // label min energy walker buffers for HDF file write
52  wmin_property_int_buffer.label = "wmin_property_int";
53  wmin_property_real_buffer.label = "wmin_property_real";
54  wmin_particle_real_buffer.label = "wmin_particle_real";
55 
56  // label max energy walker buffers for HDF file write
57  wmax_property_int_buffer.label = "wmax_property_int";
58  wmax_property_real_buffer.label = "wmax_property_real";
59  wmax_particle_real_buffer.label = "wmax_particle_real";
60 
61  // label median energy walker buffers for HDF file write
62  wmed_property_int_buffer.label = "wmed_property_int";
63  wmed_property_real_buffer.label = "wmed_property_real";
64  wmed_particle_real_buffer.label = "wmed_particle_real";
65 
66  // walker quantity information ("data_layout") has not be put in the HDF file yet
67  registered_hdf = false;
68 }
69 
70 
71 std::unique_ptr<WalkerLogCollector> WalkerLogManager::makeCollector() const
72 {
73  if (state.verbose)
74  app_log() << "WalkerLogManager::makeCollector " << std::endl;
75  return std::make_unique<WalkerLogCollector>(state);
76 }
77 
78 
80 {
81  collectors_in_run_ = std::move(collectors);
82  if (!state.logs_active)
83  return; // no-op for driver if logs are inactive
84  if (collectors_in_run_.empty())
85  throw std::runtime_error("BUG collectors are empty but walker logs are active");
86  if (state.verbose)
87  app_log() << "WalkerLogManager::startRun " << std::endl;
88  // check data size consistency among the log collector buffers
90  // open the logs file
92 }
93 
94 
96 {
97  if (!state.logs_active)
98  return; // no-op for driver if logs are inactive
99  if (state.verbose)
100  app_log() << "WalkerLogManager::stopRun " << std::endl;
101  collectors_in_run_.clear();
102  // close the logs file
103  closeFile();
104 }
105 
106 
108 {
110  if (!state.logs_active)
111  return; // no-op for driver if logs are inactive
112  if (state.verbose)
113  app_log() << "WalkerLogManager::writeBuffers " << std::endl;
114 
115  if (write_min_data)
116  { // resize min energy walker buffers to zero rows
120  }
121  if (write_max_data)
122  { // resize max energy walker buffers to zero rows
126  }
127  if (write_med_data)
128  { // resize median energy walker buffers to zero rows
132  }
133 
134  // collect energy information and extract info from min/max/median energy walkers
136  {
137  // gather per energy and step data for all walker throughout the MC block
138  for (size_t c = 0; c < collectors.size(); ++c)
139  {
140  WalkerLogCollector& tc = collectors[c];
141  tc.checkBuffers();
142  for (size_t r = 0; r < tc.energies.size(); ++r)
143  energy_order.push_back(std::make_tuple(tc.steps[r], tc.energies[r], c, r));
144  }
145  // sort the data by step and energy to enable selection of min/max/median energy walker data
146  std::sort(energy_order.begin(), energy_order.end());
147  // select out the min/max/median energy walker data and store in rank-level buffers
148  size_t n = 0;
149  size_t n1, n2;
150  size_t prev_step;
151  for (auto& v : energy_order)
152  {
153  auto step = std::get<0>(v);
154  if (n == 0)
155  {
156  n1 = n;
157  prev_step = step;
158  }
159  if (step != prev_step || n == energy_order.size() - 1)
160  {
161  // for a given step, find data for min/max/median energy walkers
162  // n1/n2 are indices of the first/last data in energy_order for this step
163  if (step != prev_step)
164  n2 = n - 1;
165  if (n == energy_order.size() - 1)
166  n2 = n;
167  auto nmin = n1; // index of minimum energy walker for this step
168  auto nmax = n2; // index of maximum energy walker for this step
169  auto nmed = (n1 + n2) / 2; // index of median energy walker for this step
170  size_t c, r;
171  if (write_min_data)
172  { // cache data for minimum energy walker
173  c = std::get<2>(energy_order[nmin]);
174  r = std::get<3>(energy_order[nmin]);
175  WalkerLogCollector& tc = collectors[c];
176  wmin_property_int_buffer.addRow(tc.walker_property_int_buffer, r);
177  wmin_property_real_buffer.addRow(tc.walker_property_real_buffer, r);
178  wmin_particle_real_buffer.addRow(tc.walker_particle_real_buffer, r);
179  }
180  if (write_max_data)
181  { // cache data for maximum energy walker
182  c = std::get<2>(energy_order[nmax]);
183  r = std::get<3>(energy_order[nmax]);
184  WalkerLogCollector& tc = collectors[c];
185  wmax_property_int_buffer.addRow(tc.walker_property_int_buffer, r);
186  wmax_property_real_buffer.addRow(tc.walker_property_real_buffer, r);
187  wmax_particle_real_buffer.addRow(tc.walker_particle_real_buffer, r);
188  }
189  if (write_med_data)
190  { // cache data for median energy walker
191  c = std::get<2>(energy_order[nmed]);
192  r = std::get<3>(energy_order[nmed]);
193  WalkerLogCollector& tc = collectors[c];
194  wmed_property_int_buffer.addRow(tc.walker_property_int_buffer, r);
195  wmed_property_real_buffer.addRow(tc.walker_property_real_buffer, r);
196  wmed_particle_real_buffer.addRow(tc.walker_particle_real_buffer, r);
197  }
198  // reset pointers
199  n1 = n;
200  prev_step = step;
201  }
202  n++;
203  }
204  energy_order.resize(0);
205  }
206 
207  // write buffer data to file
208  writeBuffersHDF();
209 }
210 
211 
213 {
214  if (state.verbose)
215  app_log() << "WalkerLogManager::checkCollectors" << std::endl;
216  if (collectors.size() > 0)
217  {
218  bool all_same = true;
219  WalkerLogCollector& ref = collectors[0];
220  for (int i = 0; i < collectors.size(); ++i)
221  {
222  WalkerLogCollector& tc = collectors[i];
226  }
227  if (!all_same)
228  {
229  throw std::runtime_error(
230  "WalkerLogManager::checkCollectors log buffer widths of collectors do not match\n contiguous write is "
231  "impossible\n this was first caused by collectors contributing array logs from identical, but "
232  "differently named, particlesets such as e, e2, e3 ... (fixed)\n please check the WalkerLogManager "
233  "summaries printed above");
234  }
235  }
236 }
237 
238 
240 {
241  if (state.verbose)
242  app_log() << "WalkerLogManager::openFile " << std::endl;
243  openHDFFile(collectors);
244 }
245 
246 
248 {
249  if (state.verbose)
250  app_log() << "WalkerLogManager::closeFile " << std::endl;
251  closeHDFFile();
252 }
253 
254 
256 {
257  if (state.verbose)
258  app_log() << "WalkerLogManager::openHDFFile " << std::endl;
259  if (collectors.size() == 0)
260  throw std::runtime_error("WalkerLogManager::openHDFFile no log collectors exist, cannot open file");
261  // each rank opens a wlogs.h5 file
262  int nprocs = communicator->size();
263  int rank = communicator->rank();
264  std::array<char, 32> ptoken;
265  std::string file_name = file_root;
266  if (nprocs > 1)
267  { // extend the file name to include processor/rank information
268  int length{0};
269  if (nprocs > 10000)
270  length = std::snprintf(ptoken.data(), ptoken.size(), ".p%05d", rank);
271  else if (nprocs > 1000)
272  length = std::snprintf(ptoken.data(), ptoken.size(), ".p%04d", rank);
273  else
274  length = std::snprintf(ptoken.data(), ptoken.size(), ".p%03d", rank);
275  if (length < 0)
276  throw std::runtime_error("Error generating filename");
277  file_name.append(ptoken.data(), length);
278  }
279  file_name += ".wlogs.h5";
280  if (state.verbose)
281  app_log() << "WalkerLogManager::openHDFFile opening logs hdf file " << file_name << std::endl;
282  // create the hdf archive
283  hdf_file = std::make_unique<hdf_archive>();
284  // open the file
285  bool successful = hdf_file->create(file_name);
286  if (!successful)
287  throw std::runtime_error("WalkerLogManager::openHDFFile failed to open hdf file " + file_name);
288 }
289 
290 
292 {
294  if (state.verbose)
295  app_log() << "WalkerLogManager::writeBuffersHDF " << std::endl;
296  WalkerLogCollector& tc_lead = collectors[0];
297  if (!registered_hdf)
298  { // write walker quantity information ("data_layout") for each buffer in the HDF file
299  // create data_layout for all-walker buffers
304  if (write_min_data)
305  { // create data_layout for min energy walker buffers
309  }
310  if (write_max_data)
311  { // create data_layout for max energy walker buffers
315  }
316  if (write_med_data)
317  { // create data_layout for median energy walker buffers
321  }
322  // walker quantity information ("data_layout") has now been added to HDF, do not repeat
323  registered_hdf = true;
324  }
325  // write data for all-walker buffers to HDF
326  for (int ip = 0; ip < collectors.size(); ++ip)
327  {
328  WalkerLogCollector& tc = collectors[ip];
333  }
334  if (write_min_data)
335  { // write data for min energy walker buffers to HDF
339  }
340  if (write_max_data)
341  { // write data for max energy walker buffers to HDF
345  }
346  if (write_med_data)
347  { // write data for median energy walker buffers to HDF
351  }
352 }
353 
354 
356 {
357  if (state.verbose)
358  app_log() << "WalkerLogManager::closeHDFFile " << std::endl;
359  hdf_file.reset();
360 }
361 
362 
363 } // namespace qmcplusplus
std::string file_root
file prefix for the current driver
bool write_min_data
whether to write full data for the minimum energy walker at each step
void closeHDFFile()
close the logs file (HDF format)
RefVector< WalkerLogCollector > collectors_in_run_
void addRow(WalkerLogBuffer< T > other, size_t i)
add a data row from another buffer to this one
Abstraction of information on executor environments.
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
int rank() const
return the rank
Definition: Communicate.h:116
void checkCollectors(const RefVector< WalkerLogCollector > &collectors) const
check consistency of walker buffer row sizes
bool verbose
controls verbosity of log file writes
bool write_med_data
whether to write full data for the median energy walker at each step
int step_period
period between MC steps for data collection
WalkerLogBuffer< WLog::Int > walker_property_int_buffer
buffer containing integer walker properties
bool registered_hdf
whether walker quantity data ("data_layout") has been recorded in HDF
std::vector< std::tuple< size_t, WLog::Real, size_t, size_t > > energy_order
used to sort energy information for identifying walkers by energy quantile
std::ostream & app_log()
Definition: OutputManager.h:65
void startRun(RefVector< WalkerLogCollector > &&collectors)
open the logs file and check consistency of the collectors at the start of a run
WalkerLogBuffer< WLog::Int > wmed_property_int_buffer
buffer containing integer properties for the median energy walkers
void checkBuffers()
Check that all buffers have the same number of rows.
WalkerLogBuffer< WLog::Real > walker_property_real_buffer
buffer containing real-valued walker properties
Crowd-level resource for walker log collection.
void stopRun()
close the logs file at the end of a run
bool write_max_data
whether to write full data for the maximum energy walker at each step
int size() const
return the number of tasks
Definition: Communicate.h:118
std::string label
label for this data in HDF file
bool logs_active
whether logs are active in the current driver
void writeBuffersHDF()
write data buffers to the logs file (HDF format)
Wrapping information on parallelism.
Definition: Communicate.h:68
WalkerLogBuffer< WLog::Real > walker_particle_real_buffer
buffer containing per-particle walker data
void openFile(const RefVector< WalkerLogCollector > &collectors)
open the logs file
void writeBuffers()
collect min/max/median walker data and write buffered walker log data to file
void closeFile()
close the logs file
WalkerLogBuffer< WLog::Real > wmed_property_real_buffer
buffer containing real-valued properties for the median energy walkers
WalkerLogBuffer< WLog::Real > wmax_particle_real_buffer
buffer containing per-particle properties for the maximum energy walkers
bool sameAs(const WalkerLogBuffer< T > &ref)
compare row size of this buffer to another one
WalkerLogState state
output state
std::unique_ptr< hdf_archive > hdf_file
access to HDF file
unsigned int getWorkerId()
WalkerLogBuffer< WLog::Real > wmax_property_real_buffer
buffer containing real-valued properties for the maximum energy walkers
WalkerLogBuffer< WLog::Real > wmin_property_real_buffer
buffer containing real-valued properties for the minimum energy walkers
bool write_particle_data
whether to write per-particle data for all walkers
WalkerLogBuffer< WLog::Int > wmax_property_int_buffer
buffer containing integer properties for the maximum energy walkers
WalkerLogBuffer< WLog::Int > wmin_property_int_buffer
buffer containing integer properties for the minimum energy walkers
std::vector< std::reference_wrapper< T > > RefVector
WalkerLogBuffer< WLog::Real > wmin_particle_real_buffer
buffer containing per-particle properties for the minimum energy walkers
std::vector< WLog::Real > energies
LocalEnergy information for each walker throughout the MC block.
void registerHDFData(hdf_archive &f)
write the data_layout for all walker quantities in the HDF file
void resetBuffer()
resize the buffer to zero
void writeHDF(hdf_archive &f)
write the buffer data into the HDF file
WalkerLogBuffer< WLog::Real > wmed_particle_real_buffer
buffer containing per-particle properties for the median energy walkers
void openHDFFile(const RefVector< WalkerLogCollector > &collectors)
open the logs file (HDF format)
T get(const std::string &name) const
Definition: InputSection.h:92
WalkerLogManager(WalkerLogInput &inp, bool allow_logs, std::string series_root, Communicate *comm=0)
std::vector< size_t > steps
MC step information for each walker throughout the MC block.
std::unique_ptr< WalkerLogCollector > makeCollector() const
create a WalkerLogCollector
hsize_t hdf_file_pointer
HDF file pointer.
Native representation for walker logs input.