Skip to content

Commit b124d06

Browse files
Update to SoA
1 parent c17e9ff commit b124d06

1 file changed

Lines changed: 94 additions & 27 deletions

File tree

src/struct/particle.h

Lines changed: 94 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,110 @@
1212
#pragma once
1313
#include "floatdef.h"
1414
#include "dt/softening.h"
15+
#include <vector>
1516
#include <cmath>
17+
#include <algorithm>
1618

17-
struct alignas(32) Particle {
18-
real x, y, z;
19-
real vx, vy, vz;
20-
real m;
21-
int type;
19+
/**
20+
* @brief Structure of Arrays (SoA) container for the particle data.
21+
* This layout is significantly faster for SIMD vectorization and cache locality.
22+
*/
23+
struct ParticleSystem {
24+
// Positions
25+
std::vector<real> x, y, z;
26+
// Velocities
27+
std::vector<real> vx, vy, vz;
28+
// Accelerations (used for force summation)
29+
std::vector<real> ax, ay, az;
30+
// Masses and Types (0 = Star, 1 = Dark Matter)
31+
std::vector<real> m;
32+
std::vector<int> type;
33+
34+
/**
35+
* @brief Resizes all buffers and ensures accelerations are zeroed.
36+
*/
37+
void resize(size_t n) {
38+
x.resize(n, 0); y.resize(n, 0); z.resize(n, 0);
39+
vx.resize(n, 0); vy.resize(n, 0); vz.resize(n, 0);
40+
ax.assign(n, 0); ay.assign(n, 0); az.assign(n, 0);
41+
m.resize(n, 0); type.resize(n, 0);
42+
}
43+
44+
/**
45+
* @brief Adds a single particle to the system.
46+
*/
47+
void addParticle(real px, real py, real pz, real pvx, real pvy, real pvz, real pm, int ptype) {
48+
x.push_back(px); y.push_back(py); z.push_back(pz);
49+
vx.push_back(pvx); vy.push_back(pvy); vz.push_back(pvz);
50+
ax.push_back(0); ay.push_back(0); az.push_back(0);
51+
m.push_back(pm);
52+
type.push_back(ptype);
53+
}
54+
55+
size_t size() const { return x.size(); }
56+
57+
void clear() {
58+
x.clear(); y.clear(); z.clear();
59+
vx.clear(); vy.clear(); vz.clear();
60+
ax.clear(); ay.clear(); az.clear();
61+
m.clear(); type.clear();
62+
}
2263
};
2364

24-
inline void Gravity(Particle &a, Particle &b, real dt) {
25-
constexpr real G = real(1.0);
65+
/**
66+
* @brief Calculates gravity between two indices in the SoA system.
67+
* This follows Newton's 3rd law to update both particles simultaneously.
68+
*/
69+
inline void GravitySoA(ParticleSystem &ps, size_t i, size_t j, real dt) {
70+
constexpr real G = real(1.0);
71+
72+
// Get separation vector
73+
real dx = ps.x[j] - ps.x[i];
74+
real dy = ps.y[j] - ps.y[i];
75+
real dz = ps.z[j] - ps.z[i];
2676

27-
real eps = pairSoftening(a.m, b.m);
77+
// Adaptive Softening (DM vs Stars)
78+
// Note: eps is based on your pairSoftening logic
79+
real eps = pairSoftening(ps.m[i], ps.m[j]);
2880

29-
real dx = b.x - a.x;
30-
real dy = b.y - a.y;
31-
real dz = b.z - a.z;
81+
// r^2 + epsilon^2
82+
real r2 = dx * dx + dy * dy + dz * dz + eps * eps;
3283

33-
real r2 = dx * dx + dy * dy + dz * dz + eps * eps;
84+
// Standard Gravity: F = G * m1 * m2 / r^2
85+
real invR2 = real(1.0) / r2;
86+
real invR = std::sqrt(invR2);
87+
real invR3 = invR * invR2;
3488

35-
real invR2 = real(1.0) / r2;
36-
real invR = std::sqrt(invR2);
37-
real invR3 = invR * invR2;
89+
// Common force factor
90+
real f_ij = G * invR3;
3891

39-
real ax = G * b.m * dx * invR3;
40-
real ay = G * b.m * dy * invR3;
41-
real az = G * b.m * dz * invR3;
92+
// Acceleration on i due to j
93+
real aix = f_ij * ps.m[j] * dx;
94+
real aiy = f_ij * ps.m[j] * dy;
95+
real aiz = f_ij * ps.m[j] * dz;
4296

43-
real bx = -G * a.m * dx * invR3;
44-
real by = -G * a.m * dy * invR3;
45-
real bz = -G * a.m * dz * invR3;
97+
// Apply Velocity Kicks (dt)
98+
ps.vx[i] += aix * dt;
99+
ps.vy[i] += aiy * dt;
100+
ps.vz[i] += aiz * dt;
46101

47-
a.vx += ax * dt;
48-
a.vy += ay * dt;
49-
a.vz += az * dt;
102+
// Apply Velocity Kicks to j (Newton's 3rd Law: a_j = -a_i * (m_i / m_j))
103+
// We multiply by m_i here because f_ij only contained G and r^-3
104+
ps.vx[j] -= (f_ij * ps.m[i] * dx) * dt;
105+
ps.vy[j] -= (f_ij * ps.m[i] * dy) * dt;
106+
ps.vz[j] -= (f_ij * ps.m[i] * dz) * dt;
107+
}
50108

51-
b.vx += bx * dt;
52-
b.vy += by * dt;
53-
b.vz += bz * dt;
109+
/**
110+
* @brief Contiguous Drift step (Update Positions).
111+
* High locality ensures the compiler can vectorize this with SIMD.
112+
*/
113+
inline void DriftSoA(ParticleSystem &ps, real dt) {
114+
const size_t n = ps.size();
115+
#pragma omp parallel for schedule(static)
116+
for (size_t i = 0; i < n; ++i) {
117+
ps.x[i] += ps.vx[i] * dt;
118+
ps.y[i] += ps.vy[i] * dt;
119+
ps.z[i] += ps.vz[i] * dt;
120+
}
54121
}

0 commit comments

Comments
 (0)