QMCPACK
WalkerLogBuffer.h
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 
13 #ifndef QMCPLUSPLUS_WALKERLOGBUFFER_H
14 #define QMCPLUSPLUS_WALKERLOGBUFFER_H
15 
16 
17 #include <Configuration.h>
18 #include "OhmmsPETE/OhmmsArray.h"
19 #include "hdf/hdf_archive.h"
20 
21 #include <unordered_set>
22 
23 
24 namespace qmcplusplus
25 {
26 
27 
28 /// Basic data types for walker log data
29 struct WLog
30 {
31  using Int = long; // integer type
32  using Real = OHMMS_PRECISION_FULL; // real type
33  using Comp = std::complex<Real>; // complex type
34 #ifndef QMC_COMPLEX
35  using PsiVal = Real; // wavefunction type
36 #else
37  using PsiVal = Comp; // wavefunction type
38 #endif
39 };
40 
41 
42 /** Record for an individual walker quantity being logd.
43  *
44  * Helper struct for WalkerLogBuffer.
45  */
47 {
48  /// quantity name
49  std::string name;
50  /// support up to 4D array quantity
51  enum
52  {
53  D0 = 0,
54  D1,
55  D2,
56  D3,
58  };
59  /// array dimension
60  size_t dimension;
61  /// total size
62  size_t size;
63  /// size of 1 unit of data
64  size_t unit_size;
65  /// array shape
67  /// starting row index in buffer
68  size_t buffer_start;
69  /// end range in buffer row
70  size_t buffer_end;
71 
72  WalkerQuantityInfo(const std::string& name_,
73  size_t unit_size_,
74  size_t buffer_start_,
75  size_t n1 = 1,
76  size_t n2 = 0,
77  size_t n3 = 0,
78  size_t n4 = 0)
79  {
80  name = name_;
81  unit_size = unit_size_;
82  buffer_start = buffer_start_;
83  shape[D0] = n1;
84  shape[D1] = n2;
85  shape[D2] = n3;
86  shape[D3] = n4;
87 
88  dimension = 0;
89  size = 1;
90  for (size_t d = 0; d < DMAX; ++d)
91  if (shape[d] > 0)
92  {
93  dimension++;
94  size *= shape[d];
95  }
97  }
98 };
99 
100 
101 /** Data buffer for walker log quantities.
102  *
103  * Each row in the buffer contains all quantities for one walker from a single step.
104  * Rows are added throughout an MC block.
105  * See WalkerLogCollector::collect()
106  *
107  * Buffer data is written to HDF at the end of each MC block.
108  * See WalkerLogManager::writeBuffers()
109  */
110 template<typename T>
112 {
113 public:
114  /// label for this data in HDF file
115  std::string label;
116  /// marks first WalkerLogCollector::collect() call
118  /// HDF file pointer
120 
121 private:
122  /// index of current quantity during WalkerLogCollector::collect()
124  /** buffer row location data for each walker quantity
125  * used to populate "data_layout" field in HDF file
126  */
127  std::vector<WalkerQuantityInfo> quantity_info;
128  /// total size of walker data stored in a buffer row
130  /// the walker data buffer itself
132 
133 public:
135  {
136  label = "?";
137  first_collect = true;
138  walker_data_size = 0;
139  quantity_index = 0;
140  resetBuffer();
141  }
142 
143  /// current number of rows in the data buffer
144  inline size_t nrows() { return buffer.size(0); }
145 
146  /// current number of columns in the data buffer (row size)
147  inline size_t ncols() { return buffer.size(1); }
148 
149  /// resize the buffer to zero
150  inline void resetBuffer() { buffer.resize(0, buffer.size(1)); }
151 
152  /// reset member variables at end of each WalkerLogCollector::collect() call
153  inline void resetCollect()
154  {
155  if (quantity_index != quantity_info.size())
156  throw std::runtime_error(
157  "WalkerLogBuffer quantity_index has not been moved through all quantities prior during collect() call.");
158  first_collect = false;
159  quantity_index = 0;
160  }
161 
162  /// compare row size of this buffer to another one
163  inline bool sameAs(const WalkerLogBuffer<T>& ref) { return buffer.size(1) == ref.buffer.size(1); }
164 
165  /// collect data for a single walker quantity of scalar type into the current buffer row
166  inline void collect(const std::string& name, const T& value)
167  {
168  size_t irow = 0;
169  if (first_collect)
170  { // cache walker quantity info on first collect
171  WalkerQuantityInfo wqi_(name, 1, walker_data_size);
172  quantity_info.push_back(wqi_);
175  }
176  else
177  { // make a new buffer row if needed
178  if (quantity_index == 0)
179  makeNewRow();
180  irow = buffer.size(0) - 1;
181  }
182  // place the scalar walker quantity into the current buffer row
183  auto& wqi = quantity_info[quantity_index];
184  buffer(irow, wqi.buffer_start) = value;
185  quantity_index++;
186  }
187 
188 
189  /// collect data for a single walker quantity of array type into the current buffer row
190  template<unsigned D>
191  inline void collect(const std::string& name, Array<T, D> arr)
192  {
193  size_t n1 = arr.size(0);
194  size_t n2, n3, n4;
195  n2 = n3 = n4 = 0;
196  if (D > 4)
197  throw std::runtime_error("WalkerLogBuffer::collect Only arrays up to dimension 4 are currently supported.");
198  if (D > 1)
199  n2 = arr.size(1);
200  if (D > 2)
201  n3 = arr.size(2);
202  if (D > 3)
203  n4 = arr.size(3);
204  size_t irow = 0;
205  if (first_collect)
206  { // cache walker quantity info on first collect
207  WalkerQuantityInfo wqi_(name, 1, walker_data_size, n1, n2, n3, n4);
208  quantity_info.push_back(wqi_);
211  }
212  else
213  { // make a new buffer row if needed
214  if (quantity_index == 0)
215  makeNewRow();
216  irow = buffer.size(0) - 1;
217  }
218  // place the array walker quantity into the current buffer row
219  auto& wqi = quantity_info[quantity_index];
220  auto& arr1d = arr.storage();
221  for (size_t n = 0; n < arr1d.size(); ++n)
222  buffer(irow, wqi.buffer_start + n) = arr1d[n];
223  quantity_index++;
224  }
225 
226 
227  /// collect data for a single walker quantity of complex array type into the current buffer row
228  template<unsigned D>
229  inline void collect(const std::string& name, Array<std::complex<T>, D> arr)
230  {
231  size_t n1 = arr.size(0);
232  size_t n2, n3, n4;
233  n2 = n3 = n4 = 0;
234  if (D > 4)
235  throw std::runtime_error("WalkerLogBuffer::collect Only arrays up to dimension 4 are currently supported.");
236  if (D > 1)
237  n2 = arr.size(1);
238  if (D > 2)
239  n3 = arr.size(2);
240  if (D > 3)
241  n4 = arr.size(3);
242  size_t irow = 0;
243  if (first_collect)
244  { // cache walker quantity info on first collect
245  WalkerQuantityInfo wqi_(name, 2, walker_data_size, n1, n2, n3, n4);
246  quantity_info.push_back(wqi_);
249  }
250  else
251  { // make a new buffer row if needed
252  if (quantity_index == 0)
253  makeNewRow();
254  irow = buffer.size(0) - 1;
255  }
256  // place the complex array walker quantity into the current buffer row
257  auto& wqi = quantity_info[quantity_index];
258  auto& arr1d = arr.storage();
259  size_t n = 0;
260  for (size_t i = 0; i < arr1d.size(); ++i)
261  {
262  buffer(irow, wqi.buffer_start + n) = std::real(arr1d[i]);
263  ++n;
264  buffer(irow, wqi.buffer_start + n) = std::imag(arr1d[i]);
265  ++n;
266  }
267  quantity_index++;
268  }
269 
270 
271  /// add a data row from another buffer to this one
272  inline void addRow(WalkerLogBuffer<T> other, size_t i)
273  {
274  auto& other_buffer = other.buffer;
275  if (first_collect)
276  {
277  resetRowSize(other_buffer.size(1));
279  first_collect = false;
280  }
281  else
282  {
283  if (buffer.size(1) != other_buffer.size(1))
284  throw std::runtime_error("WalkerLogBuffer::add_row Row sizes must match.");
285  makeNewRow();
286  }
287  size_t ib = buffer.size(0) - 1;
288  for (size_t j = 0; j < buffer.size(1); ++j)
289  buffer(ib, j) = other_buffer(i, j);
290  }
291 
292 
293  /// write a summary of quantities in the buffer
294  inline void writeSummary(std::string pad = " ")
295  {
296  std::string pad2 = pad + " ";
297  std::string pad3 = pad2 + " ";
298  app_log() << std::endl;
299  app_log() << pad << "WalkerLogBuffer(" << label << ")" << std::endl;
300  app_log() << pad2 << "nrows = " << buffer.size(0) << std::endl;
301  app_log() << pad2 << "row_size = " << buffer.size(1) << std::endl;
302  for (size_t n = 0; n < quantity_info.size(); ++n)
303  {
304  auto& wqi = quantity_info[n];
305  app_log() << pad2 << "quantity " << n << ": " << wqi.dimension << " " << wqi.size << " " << wqi.unit_size
306  << " " << wqi.buffer_start << " " << wqi.buffer_end << " (" << wqi.name << ")" << std::endl;
307  }
308  app_log() << pad << "end WalkerLogBuffer(" << label << ")" << std::endl;
309  }
310 
311  /// write the data_layout for all walker quantities in the HDF file
312  inline void registerHDFData(hdf_archive& f)
313  {
314  auto& top = label;
315  f.push(top);
316  f.push("data_layout");
317  for (auto& wqi : quantity_info)
318  {
319  f.push(wqi.name);
320  f.write(wqi.dimension, "dimension");
321  f.write(wqi.shape, "shape");
322  f.write(wqi.size, "size");
323  f.write(wqi.unit_size, "unit_size");
324  f.write(wqi.buffer_start, "index_start");
325  f.write(wqi.buffer_end, "index_end");
326  f.pop();
327  }
328  f.pop();
329  f.pop();
330  if (!f.open_groups())
331  throw std::runtime_error("WalkerLogBuffer(" + label +
332  ")::register_hdf_data() some hdf groups are still open at the end of registration");
333  hdf_file_pointer = 0;
334  }
335 
336 
337  /// write the buffer data into the HDF file
339 
340 
341  /// write the buffer data into the HDF file
342  inline void writeHDF(hdf_archive& f, hsize_t& file_pointer)
343  {
344  auto& top = label;
345  hsize_t dims[2];
346  dims[0] = buffer.size(0);
347  dims[1] = buffer.size(1);
348  if (dims[0] > 0)
349  {
350  f.push(top);
351  h5d_append(f.top(), "data", file_pointer, buffer.dim(), dims, buffer.data());
352  f.pop();
353  }
354  f.flush();
355  }
356 
357 private:
358  /// make space as quantities are added to the buffer for the first time
359  inline void resetRowSize(size_t row_size)
360  {
361  auto nrows = buffer.size(0);
362  if (nrows == 0)
363  nrows++;
364  if (nrows != 1)
365  throw std::runtime_error("WalkerLogBuffer::reset_rowsize row_size (number of columns) should only be changed "
366  "during growth of the first row.");
367  auto buffer_old(buffer);
368  buffer.resize(nrows, row_size);
369  std::copy_n(buffer_old.data(), buffer_old.size(), buffer.data());
370  if (buffer.size(0) != 1)
371  throw std::runtime_error(
372  "WalkerLogBuffer::reset_rowsize buffer should contain only a single row upon completion.");
373  if (buffer.size(1) != row_size)
374  throw std::runtime_error("WalkerLogBuffer::reset_rowsize length of buffer row should match the requested "
375  "row_size following the reset/udpate.");
376  }
377 
378  /// allocate a full new row at the end of the buffer
379  inline void makeNewRow()
380  {
381  size_t nrows = buffer.size(0);
382  size_t row_size = buffer.size(1);
383  if (row_size == 0)
384  throw std::runtime_error("WalkerLogBuffer::makeNewRow Cannot make a new row of size zero.");
385  nrows++;
386  // resizing buffer(type Array) doesn't preserve data. Thus keep old data and copy over
387  auto buffer_old(buffer);
388  buffer.resize(nrows, row_size);
389  std::copy_n(buffer_old.data(), buffer_old.size(), buffer.data());
390  }
391 };
392 
393 extern template class WalkerLogBuffer<WLog::Int>;
394 extern template class WalkerLogBuffer<WLog::Real>;
395 
396 } // namespace qmcplusplus
397 
398 #endif
void collect(const std::string &name, Array< T, D > arr)
collect data for a single walker quantity of array type into the current buffer row ...
void writeSummary(std::string pad=" ")
write a summary of quantities in the buffer
bool first_collect
marks first WalkerLogCollector::collect() call
Array< T, 2 > buffer
the walker data buffer itself
size_t quantity_index
index of current quantity during WalkerLogCollector::collect()
void addRow(WalkerLogBuffer< T > other, size_t i)
add a data row from another buffer to this one
WalkerQuantityInfo(const std::string &name_, size_t unit_size_, size_t buffer_start_, size_t n1=1, size_t n2=0, size_t n3=0, size_t n4=0)
void write(T &data, const std::string &aname)
write the data to the group aname and check status runtime error is issued on I/O error ...
Definition: hdf_archive.h:259
bool h5d_append(hid_t grp, const std::string &aname, hsize_t &current, hsize_t ndims, const hsize_t *const dims, const T *const first, hsize_t chunk_size=1, hid_t xfer_plist=H5P_DEFAULT)
QMCTraits::RealType real
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
hid_t top() const
return the top of the group stack
Definition: hdf_archive.h:192
bool open_groups()
check if any groups are open group stack will have entries if so
Definition: hdf_archive.h:198
Data buffer for walker log quantities.
void collect(const std::string &name, const T &value)
collect data for a single walker quantity of scalar type into the current buffer row ...
std::ostream & app_log()
Definition: OutputManager.h:65
Type_t * data()
Definition: OhmmsArray.h:87
TinyVector< size_t, DMAX > shape
array shape
size_t unit_size
size of 1 unit of data
void collect(const std::string &name, Array< std::complex< T >, D > arr)
collect data for a single walker quantity of complex array type into the current buffer row ...
OHMMS_PRECISION_FULL Real
class to handle hdf file
Definition: hdf_archive.h:51
Record for an individual walker quantity being logd.
std::string name
quantity name
void writeHDF(hdf_archive &f, hsize_t &file_pointer)
write the buffer data into the HDF file
void resize(const std::array< SIZET, D > &dims)
Resize the container.
Definition: OhmmsArray.h:65
std::string label
label for this data in HDF file
std::vector< WalkerQuantityInfo > quantity_info
buffer row location data for each walker quantity used to populate "data_layout" field in HDF file ...
Container_t & storage()
Definition: OhmmsArray.h:60
float imag(const float &c)
imaginary part of a scalar. Cannot be replaced by std::imag due to AFQMC specific needs...
size_t buffer_end
end range in buffer row
bool sameAs(const WalkerLogBuffer< T > &ref)
compare row size of this buffer to another one
size_t size() const
Definition: OhmmsArray.h:57
size_t nrows()
current number of rows in the data buffer
std::complex< Real > Comp
void push(const std::string &gname, bool createit=true)
push a group to the group stack
sycl::event copy_n(sycl::queue &aq, const T1 *restrict VA, size_t array_size, T2 *restrict VC, const std::vector< sycl::event > &events)
Definition: syclBLAS.cpp:548
void resetCollect()
reset member variables at end of each WalkerLogCollector::collect() call
void registerHDFData(hdf_archive &f)
write the data_layout for all walker quantities in the HDF file
void resetBuffer()
resize the buffer to zero
Basic data types for walker log data.
std::vector< int > dims
unsigned dim() const
Definition: OhmmsArray.h:55
void writeHDF(hdf_archive &f)
write the buffer data into the HDF file
size_t walker_data_size
total size of walker data stored in a buffer row
void resetRowSize(size_t row_size)
make space as quantities are added to the buffer for the first time
size_t dimension
array dimension
void makeNewRow()
allocate a full new row at the end of the buffer
size_t ncols()
current number of columns in the data buffer (row size)
hsize_t hdf_file_pointer
HDF file pointer.
void flush()
flush a file
Definition: hdf_archive.h:146
size_t buffer_start
starting row index in buffer