Gaia / include /simd /neighbor.hpp
ObviousSatire
Add C++ source code and build system
be3cca2
Raw
History Blame Contribute Delete
3.67 kB
#ifndef GAIA_SIMD_NEIGHBOR_HPP
#define GAIA_SIMD_NEIGHBOR_HPP
#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#ifdef __AVX2__
#include <immintrin.h>
#endif
namespace gaia {
namespace simd {
struct Vec3 {
float x, y, z;
Vec3(float x=0, float y=0, float z=0) : x(x), y(y), z(z) {}
};
class SIMDNeighborList {
public:
SIMDNeighborList(float cutoff = 10.0f) : cutoff(cutoff) {
simd_width = 8;
}
void build(const std::vector<Vec3>& positions) {
neighbors.clear();
neighbors.resize(positions.size());
#ifdef __AVX2__
for (int i = 0; i < (int)positions.size(); i++) {
float xi = positions[i].x;
float yi = positions[i].y;
float zi = positions[i].z;
__m256 xi_vec = _mm256_set1_ps(xi);
__m256 yi_vec = _mm256_set1_ps(yi);
__m256 zi_vec = _mm256_set1_ps(zi);
__m256 cutoff_sq = _mm256_set1_ps(cutoff * cutoff);
for (int j = i + 1; j < (int)positions.size(); j += simd_width) {
int remaining = std::min(simd_width, (int)positions.size() - j);
float xj_arr[8] = {0}, yj_arr[8] = {0}, zj_arr[8] = {0};
for (int k = 0; k < remaining; k++) {
xj_arr[k] = positions[j + k].x;
yj_arr[k] = positions[j + k].y;
zj_arr[k] = positions[j + k].z;
}
__m256 xj_vec = _mm256_loadu_ps(xj_arr);
__m256 yj_vec = _mm256_loadu_ps(yj_arr);
__m256 zj_vec = _mm256_loadu_ps(zj_arr);
__m256 dx = _mm256_sub_ps(xi_vec, xj_vec);
__m256 dy = _mm256_sub_ps(yi_vec, yj_vec);
__m256 dz = _mm256_sub_ps(zi_vec, zj_vec);
__m256 dx2 = _mm256_mul_ps(dx, dx);
__m256 dy2 = _mm256_mul_ps(dy, dy);
__m256 dz2 = _mm256_mul_ps(dz, dz);
__m256 r2 = _mm256_add_ps(_mm256_add_ps(dx2, dy2), dz2);
__m256 mask = _mm256_cmp_ps(r2, cutoff_sq, _CMP_LT_OQ);
int mask_int = _mm256_movemask_ps(mask);
for (int k = 0; k < remaining; k++) {
if (mask_int & (1 << k)) {
int idx = j + k;
if (idx < (int)positions.size()) {
neighbors[i].push_back(idx);
neighbors[idx].push_back(i);
}
}
}
}
}
#else
for (int i = 0; i < (int)positions.size(); i++) {
for (int j = i + 1; j < (int)positions.size(); j++) {
float dx = positions[i].x - positions[j].x;
float dy = positions[i].y - positions[j].y;
float dz = positions[i].z - positions[j].z;
float r2 = dx*dx + dy*dy + dz*dz;
if (r2 < cutoff * cutoff) {
neighbors[i].push_back(j);
neighbors[j].push_back(i);
}
}
}
#endif
}
const std::vector<int>& get_neighbors(int i) const {
return neighbors[i];
}
size_t total_pairs() const {
size_t sum = 0;
for (const auto& n : neighbors) sum += n.size();
return sum / 2;
}
private:
float cutoff;
int simd_width;
std::vector<std::vector<int>> neighbors;
};
} // namespace simd
} // namespace gaia
#endif