1818
1919/* *
2020 * @brief Structure of Arrays (SoA) container for the particle data.
21- * This layout is significantly faster for SIMD vectorization and cache locality.
2221 */
2322struct Particle {
24- // Positions
2523 std::vector<real> x, y, z;
26- // Velocities
2724 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)
25+ std::vector<real> ax, ay, az; // Storing for potential tree-build recycling
3126 std::vector<real> m;
3227 std::vector<int > type;
3328
34- /* *
35- * @brief Resizes all buffers and ensures accelerations are zeroed.
36- */
3729 void resize (size_t n) {
3830 x.resize (n, 0 ); y.resize (n, 0 ); z.resize (n, 0 );
3931 vx.resize (n, 0 ); vy.resize (n, 0 ); vz.resize (n, 0 );
4032 ax.assign (n, 0 ); ay.assign (n, 0 ); az.assign (n, 0 );
4133 m.resize (n, 0 ); type.resize (n, 0 );
4234 }
4335
44- /* *
45- * @brief Adds a single particle to the system.
46- */
4736 void addParticle (real px, real py, real pz, real pvx, real pvy, real pvz, real pm, int ptype) {
4837 x.push_back (px); y.push_back (py); z.push_back (pz);
4938 vx.push_back (pvx); vy.push_back (pvy); vz.push_back (pvz);
@@ -62,60 +51,34 @@ struct Particle {
6251 }
6352};
6453
54+ /* * * ALIAS DEFINITION
55+ * This must be here for GravitySoA and Step to recognize 'ParticleSystem'
56+ */
57+ using ParticleSystem = Particle;
58+
6559/* *
66- * @brief Calculates gravity between two indices in the SoA system.
67- * This follows Newton's 3rd law to update both particles simultaneously .
60+ * @brief Calculates direct gravity between two indices in the SoA system.
61+ * Useful for brute-force or small-N components .
6862 */
6963inline void GravitySoA (ParticleSystem &ps, size_t i, size_t j, real dt) {
7064 constexpr real G = real (1.0 );
7165
72- // Get separation vector
7366 real dx = ps.x [j] - ps.x [i];
7467 real dy = ps.y [j] - ps.y [i];
7568 real dz = ps.z [j] - ps.z [i];
7669
77- // Adaptive Softening (DM vs Stars)
78- // Note: eps is based on your pairSoftening logic
7970 real eps = pairSoftening (ps.m [i], ps.m [j]);
80-
81- // r^2 + epsilon^2
8271 real r2 = dx * dx + dy * dy + dz * dz + eps * eps;
8372
84- // Standard Gravity: F = G * m1 * m2 / r^2
8573 real invR2 = real (1.0 ) / r2;
86- real invR = std::sqrt (invR2);
87- real invR3 = invR * invR2;
88-
89- // Common force factor
90- real f_ij = G * invR3;
91-
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;
74+ real invR3 = invR2 / std::sqrt (r2);
75+ real f_base = G * invR3 * dt;
9676
97- // Apply Velocity Kicks (dt)
98- ps.vx [i] += aix * dt;
99- ps.vy [i] += aiy * dt;
100- ps.vz [i] += aiz * dt;
77+ ps.vx [i] += f_base * ps.m [j] * dx;
78+ ps.vy [i] += f_base * ps.m [j] * dy;
79+ ps.vz [i] += f_base * ps.m [j] * dz;
10180
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- }
108-
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- }
81+ ps.vx [j] -= f_base * ps.m [i] * dx;
82+ ps.vy [j] -= f_base * ps.m [i] * dy;
83+ ps.vz [j] -= f_base * ps.m [i] * dz;
12184}
0 commit comments