I'm trying to perform an std::vector
sum reduction with an OpenMP reduction declaration for it:
// g++ -fopenmp MRE.cpp -o MRE
#include <vector>
#include <algorithm>
#include <omp.h>
struct Particles {
std::vector<double> fx;
};
#pragma omp declare reduction(vec_double_plus : std::vector<double> : \
std::transform(omp_out.begin(), omp_out.end(), omp_in.begin(), omp_out.begin(), std::plus<double>()) \
) initializer(omp_priv = decltype(omp_orig)(omp_orig.size()))
int main() {
Particles particles;
// Initialize fx vector with 100 elements
for (int i = 0; i < 100; ++i){
particles.fx.push_back(0.0);
}
// Parallel region to set the values of fx
#pragma omp parallel
{
// Thread-private local vector
std::vector<double> thread_fx(particles.fx.size(), 0.0);
#pragma omp for
for (size_t i = 0; i < particles.fx.size(); ++i){
thread_fx[i] = 1.0; // Assign values to thread_fx
}
// Now we reduce thread_fx into particles.fx
#pragma omp for reduction(vec_double_plus: particles.fx)
for (size_t i = 0; i < particles.fx.size(); ++i) {
particles.fx[i] += thread_fx[i];
}
}
return 0;
}
...but the compiler complains about no reduction declaration for my struct, even though I'm performing the operation on an std::vector
type:
MRE.cpp: In function ‘int main()’:
MRE.cpp:31:57: error: expected ‘)’ before ‘.’ token
31 | #pragma omp for reduction(vec_double_plus: particles.fx)
| ^
| )
MRE.cpp:31:48: error: user defined reduction not found for ‘particles’
31 | #pragma omp for reduction(vec_double_plus: particles.fx)
How do I specifically declare the reduction clause for a std::vector
inside a struct
?
You cannot reduce on struct members, but only on the whole object. I'm not sure what you try to do with the code in the parallel region, but here is a working version that reduces the vector of your Particles.
#include <algorithm>
#include <iostream>
#include <omp.h>
#include <vector>
struct Particles {
std::vector<double> fx;
static void init(Particles &n, const Particles &o) {
n.fx.resize(o.fx.size(), 0);
}
};
#pragma omp declare reduction(vec_double_plus \
:Particles : std::transform(omp_out.fx.begin(), omp_out.fx.end(), \
omp_in.fx.begin(), omp_out.fx.begin(), \
std::plus<double>())) \
initializer(Particles::init(omp_priv, omp_orig))
int main() {
Particles particles;
// Initialize fx vector with 100 elements
particles.fx.resize(100, 0.0);
// Parallel region to set the values of fx
#pragma omp parallel
{
// Thread-private local vector
std::vector<double> thread_fx(particles.fx.size(), 0.0);
#pragma omp for
for (size_t i = 0; i < particles.fx.size(); ++i) {
thread_fx[i] = 1.0; // Assign values to thread_fx
}
// Now we reduce thread_fx into particles.fx
#pragma omp for reduction(vec_double_plus : particles)
for (size_t i = 0; i < particles.fx.size(); ++i) {
particles.fx[i] += thread_fx[i];
}
}
std::cout << particles.fx[0] << ", " << particles.fx[50] << ", "
<< particles.fx[99] << std::endl;
return 0;
}
For an access pattern to the vector as shown in your MRE, you would not need a reduction at all. You can safely write to a shared Particle object, because the different threads access the entries exclusively.