25#include <boost/archive/binary_iarchive.hpp>
26#include <boost/archive/binary_oarchive.hpp>
27#include <boost/iostreams/device/array.hpp>
28#include <boost/iostreams/stream.hpp>
29#include <boost/serialization/string.hpp>
30#include <boost/serialization/vector.hpp>
47 std::vector<double>
const &
A2) {
52 [](
double a,
double b) { return 0.5 * (a + b); });
76 std::vector<double>
const &B,
78 if (A.size() != B.size()) {
79 throw std::runtime_error(
80 "Error in scalar product: The vector sizes do not match");
83 auto const result = std::inner_product(A.begin(), A.end(), B.begin(), 0.0);
88 std::vector<double>
const &B,
90 std::vector<double> C(A.size());
91 if (A.size() != B.size()) {
92 throw std::runtime_error(
93 "Error in componentwise product: The vector sizes do not match");
96 std::ranges::transform(A, B, C.begin(), std::multiplies<>());
102 std::vector<double>
const &B,
104 std::vector<double> C(A.size() * B.size());
105 auto C_it = C.begin();
117 std::vector<double>
const &B,
119 if (A.size() != B.size()) {
120 throw std::runtime_error(
121 "Error in square distance componentwise: The vector sizes do not "
125 std::vector<double> C(A.size());
127 std::ranges::transform(A, B, C.begin(), [](
double a,
double b) ->
double {
128 return Utils::sqr(a - b);
136std::vector<double>
fcs_acf(std::vector<double>
const &A,
137 std::vector<double>
const &B,
139 if (A.size() != B.size()) {
140 throw std::runtime_error(
141 "Error in fcs_acf: The vector sizes do not match.");
144 auto const C_size = A.size() / 3u;
147 std::vector<double> C{};
150 for (std::size_t i = 0
u; i <
C_size; i++) {
152 for (std::size_t
j = 0
u;
j < 3u;
j++) {
153 auto const a = A[3u * i +
j];
154 auto const b = B[3u * i +
j];
157 C.emplace_back(std::exp(acc));
163void Correlator::initialize_operations() {
166 if (m_tau_lin == 1) {
167 m_tau_lin =
static_cast<int>(std::ceil(m_tau_max / m_dt));
168 m_tau_lin += m_tau_lin % 2;
172 throw std::runtime_error(
"tau_lin must be >= 2");
176 throw std::runtime_error(
"tau_lin must be divisible by 2");
179 if (m_tau_max <= m_dt) {
180 throw std::runtime_error(
"tau_max must be >= delta_t (delta_N too large)");
183 if ((m_tau_max / m_dt) < m_tau_lin) {
184 m_hierarchy_depth = 1;
186 auto const operand = (m_tau_max / m_dt) /
double(m_tau_lin - 1);
188 m_hierarchy_depth =
static_cast<int>(std::ceil(1. + std::log2(
operand)));
193 dim_A = A_obs->n_values();
194 dim_B = B_obs->n_values();
197 throw std::runtime_error(
"dimension of first observable has to be >= 1");
200 throw std::runtime_error(
"dimension of second observable has to be >= 1");
204 if (corr_operation_name ==
"componentwise_product") {
206 m_shape = A_obs->shape();
209 }
else if (corr_operation_name ==
"tensor_product") {
210 m_dim_corr = dim_A * dim_B;
212 m_shape.emplace_back(dim_A);
213 m_shape.emplace_back(dim_B);
216 }
else if (corr_operation_name ==
"square_distance_componentwise") {
218 m_shape = A_obs->shape();
221 }
else if (corr_operation_name ==
"fcs_acf") {
225 throw std::runtime_error(
"missing parameter for fcs_acf: w_x w_y w_z");
228 m_correlation_args_input);
230 throw std::runtime_error(
"dimA must be divisible by 3 for fcs_acf");
231 m_dim_corr = dim_A / 3u;
232 m_shape = A_obs->shape();
233 if (m_shape.back() != 3u)
234 throw std::runtime_error(
235 "the last dimension of dimA must be 3 for fcs_acf");
238 }
else if (corr_operation_name ==
"scalar_product") {
241 m_shape.emplace_back(1u);
245 throw std::invalid_argument(
"correlation operation '" +
246 corr_operation_name +
"' not implemented");
250 if (compressA_name ==
"discard2") {
252 }
else if (compressA_name ==
"discard1") {
254 }
else if (compressA_name ==
"linear") {
257 throw std::invalid_argument(
"unknown compression method '" +
258 compressA_name +
"' for first observable");
261 if (compressB_name ==
"discard2") {
263 }
else if (compressB_name ==
"discard1") {
265 }
else if (compressB_name ==
"linear") {
268 throw std::invalid_argument(
"unknown compression method '" +
269 compressB_name +
"' for second observable");
273void Correlator::initialize_buffers() {
276 A.resize(std::array<int, 2>{{m_hierarchy_depth, m_tau_lin + 1}});
277 std::fill_n(A.data(), A.num_elements(), std::vector<double>(dim_A, 0));
278 B.resize(std::array<int, 2>{{m_hierarchy_depth, m_tau_lin + 1}});
279 std::fill_n(B.data(), B.num_elements(), std::vector<double>(dim_B, 0));
282 A_accumulated_average = std::vector<double>(dim_A, 0);
283 B_accumulated_average = std::vector<double>(dim_B, 0);
286 n_sweeps = std::vector<std::size_t>(
n_result, 0);
287 n_vals = std::vector<long>(m_hierarchy_depth, 0);
289 result.resize(std::array<std::size_t, 2>{{
n_result, m_dim_corr}});
296 newest = std::vector<long>(m_hierarchy_depth, m_tau_lin);
299 for (
int i = 0; i < m_tau_lin + 1; i++) {
303 for (
int j = 1;
j < m_hierarchy_depth;
j++) {
304 for (
int k = 0; k < m_tau_lin / 2; k++) {
305 tau[m_tau_lin + 1 + (
j - 1) * m_tau_lin / 2 + k] =
306 (k + (m_tau_lin / 2) + 1) * (1 <<
j);
313 throw std::runtime_error(
314 "No data can be added after finalize() was called.");
317 if (comm.rank() != 0) {
319 A_obs->operator()(comm);
320 if (A_obs != B_obs) {
321 B_obs->operator()(comm);
337 auto const max_depth = m_hierarchy_depth - 1;
343 auto const modulo = 1 << (i + 1);
344 auto const remainder = (t - (m_tau_lin + 1) * (modulo - 1) - 1) % modulo;
359 newest[i + 1] = (newest[i + 1] + 1) % (m_tau_lin + 1);
361 A[i + 1][newest[i + 1]] =
362 (*compressA)(A[i][(newest[i] + 1) % (m_tau_lin + 1)],
363 A[i][(newest[i] + 2) % (m_tau_lin + 1)]);
364 B[i + 1][newest[i + 1]] =
365 (*compressB)(B[i][(newest[i] + 1) % (m_tau_lin + 1)],
366 B[i][(newest[i] + 2) % (m_tau_lin + 1)]);
369 newest[0] = (newest[0] + 1) % (m_tau_lin + 1);
372 A[0][newest[0]] = A_obs->operator()(comm);
373 if (A_obs != B_obs) {
374 B[0][newest[0]] = B_obs->operator()(comm);
376 B[0][newest[0]] = A[0][newest[0]];
381 for (std::size_t k = 0; k < dim_A; k++) {
382 A_accumulated_average[k] += A[0][newest[0]][k];
385 for (std::size_t k = 0; k < dim_B; k++) {
386 B_accumulated_average[k] += B[0][newest[0]][k];
390 auto const tau =
static_cast<long>(m_tau_lin);
392 for (
long j = 0l;
j < std::min(tau + 1l, n_vals[0]);
j++) {
394 auto const index_old = (newest[0] -
j + tau + 1l) % (tau + 1l);
401 result[
j][k] +=
temp[k];
406 for (
long j = (tau + 1l) / 2l + 1l;
j < std::min(tau + 1l, n_vals[i]);
409 auto const index_old = (newest[i] -
j + tau + 1l) % (tau + 1l);
411 tau +
static_cast<long>(i - 1) * tau / 2l + (
j - tau / 2l + 1l) - 1l;
427 throw std::runtime_error(
"Correlator::finalize() can only be called once.");
437 if (comm.rank() != 0) {
441 for (
int ll = 0;
ll < m_hierarchy_depth - 1;
ll++) {
443 if (n_vals[
ll] > m_tau_lin + 1)
455 auto const max_depth = m_hierarchy_depth - 1;
458 if (i >=
max_depth or n_vals[i] % 2 == 0
or n_vals[i] <= m_tau_lin) {
474 newest[i + 1] = (newest[i + 1] + 1) % (m_tau_lin + 1);
477 (*compressA)(A[i][(newest[i] + 1) % (m_tau_lin + 1)],
478 A[i][(newest[i] + 2) % (m_tau_lin + 1)]);
479 (*compressB)(B[i][(newest[i] + 1) % (m_tau_lin + 1)],
480 B[i][(newest[i] + 2) % (m_tau_lin + 1)]);
482 newest[
ll] = (newest[
ll] + 1) % (m_tau_lin + 1);
484 auto const tau =
static_cast<long>(m_tau_lin);
487 for (
long j = (tau + 1l) / 2l + 1l;
j < std::min(tau + 1l, n_vals[i]);
490 auto const index_old = (newest[i] -
j + tau + 1l) % (tau + 1l);
491 auto const index_res = tau +
static_cast<long>(i - 1) * tau / 2l +
492 (
j - tau / 2l + 1l) - 1l;
514 for (std::size_t i = 0; i <
n_result; i++) {
515 auto const index =
static_cast<index_type>(m_dim_corr * i);
519 static_cast<double>(n_sweeps[i]);
528 std::ranges::transform(tau,
res.begin(),
529 [
dt = m_dt](
auto const &a) { return a * dt; });
534 std::stringstream
ss;
535 boost::archive::binary_oarchive
oa(
ss);
540 oa << m_correlation_args_input;
547 oa << A_accumulated_average;
548 oa << B_accumulated_average;
557 iostreams::stream<iostreams::array_source>
ss(
src);
558 boost::archive::binary_iarchive
ia(
ss);
563 ia >> m_correlation_args_input;
570 ia >> A_accumulated_average;
571 ia >> B_accumulated_average;
573 initialize_operations();
Vector implementation and trait types for boost qvm interoperability.
void const * m_system
for bookkeeping purposes
std::size_t n_values() const
std::string get_internal_state() const final
void set_internal_state(std::string const &) final
std::vector< double > get_lag_times() const
int finalize(boost::mpi::communicator const &comm)
At the end of data collection, go through the whole hierarchy and correlate data left there.
std::vector< double > get_correlation()
Return correlation result.
void update(boost::mpi::communicator const &comm) override
The function to process a new datapoint of A and B.
static DEVICE_QUALIFIER constexpr Vector< T, N > broadcast(typename Base::value_type const &value) noexcept
Create a vector that has all entries set to the same value.
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
std::vector< double > componentwise_product(std::vector< double > const &A, std::vector< double > const &B, Utils::Vector3d const &)
std::vector< double > tensor_product(std::vector< double > const &A, std::vector< double > const &B, Utils::Vector3d const &)
std::vector< double > compress_linear(std::vector< double > const &A1, std::vector< double > const &A2)
Compress computing arithmetic mean: A_compressed=(A1+A2)/2.
std::vector< double > scalar_product(std::vector< double > const &A, std::vector< double > const &B, Utils::Vector3d const &)
std::vector< double > compress_discard1(std::vector< double > const &A1, std::vector< double > const &A2)
Compress discarding the 1st argument and return the 2nd.
std::vector< double > compress_discard2(std::vector< double > const &A1, std::vector< double > const &A2)
Compress discarding the 2nd argument and return the 1st.
std::vector< double > fcs_acf(std::vector< double > const &A, std::vector< double > const &B, Utils::Vector3d const &wsquare)
std::vector< double > square_distance_componentwise(std::vector< double > const &A, std::vector< double > const &B, Utils::Vector3d const &)
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
auto hadamard_product(Vector< T, N > const &a, Vector< U, N > const &b)