#ifndef GAIA_SIMD_NEIGHBOR_HPP #define GAIA_SIMD_NEIGHBOR_HPP #include #include #include #include #ifdef __AVX2__ #include #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& 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& 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> neighbors; }; } // namespace simd } // namespace gaia #endif