Skip to content

Commit 20529c3

Browse files
Added adaptive softening (better one)
1 parent fc2b858 commit 20529c3

1 file changed

Lines changed: 108 additions & 35 deletions

File tree

src/gravity/octree.h

Lines changed: 108 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22
// it under the terms of the GNU General Public License as published by
33
// the Free Software Foundation, either version 3 of the License, or
44
// (at your option) any later version.
5-
65
// This program is distributed in the hope that it will be useful,
76
// but WITHOUT ANY WARRANTY; without even the implied warranty of
87
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
98
// GNU General Public License for more details.
10-
119
// You should have received a copy of the GNU General Public License
1210
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1311

1412
#pragma once
1513
#include "../struct/particle.h"
1614
#include <vector>
15+
#include <cmath>
16+
#include "dt/softening.h"
1717

1818
struct Octree {
1919
// monopole
@@ -25,7 +25,7 @@ struct Octree {
2525
real size; // half-width
2626
bool leaf = true;
2727
Particle* body = nullptr;
28-
Octree* child[8] = {nullptr};
28+
Octree* child[8] = { nullptr };
2929

3030
// symmetric quadrupole tensor (6 independent components)
3131
real Qxx = 0, Qyy = 0, Qzz = 0;
@@ -36,11 +36,25 @@ struct Octree {
3636
x(X), y(Y), z(Z), size(S) {}
3737

3838
~Octree() {
39-
for (auto c : child) delete c;
39+
for (auto c : child) {
40+
delete c;
41+
}
4042
}
4143

4244
int index(const Particle& p) const {
43-
return (p.x > x) * 1 + (p.y > y) * 2 + (p.z > z) * 4;
45+
return (p.x > x) * 1
46+
+ (p.y > y) * 2
47+
+ (p.z > z) * 4;
48+
}
49+
50+
Octree* createChild(int idx) {
51+
real hs = size * real(0.5);
52+
return new Octree(
53+
x + ((idx & 1) ? hs : -hs),
54+
y + ((idx & 2) ? hs : -hs),
55+
z + ((idx & 4) ? hs : -hs),
56+
hs
57+
);
4458
}
4559

4660
void insert(Particle* p) {
@@ -54,27 +68,19 @@ struct Octree {
5468
Particle* old = body;
5569
body = nullptr;
5670
int idx = index(*old);
57-
if (!child[idx])
71+
if (!child[idx]) {
5872
child[idx] = createChild(idx);
73+
}
5974
child[idx]->insert(old);
6075
}
6176

6277
int idx = index(*p);
63-
if (!child[idx])
78+
if (!child[idx]) {
6479
child[idx] = createChild(idx);
80+
}
6581
child[idx]->insert(p);
6682
}
6783

68-
Octree* createChild(int idx) {
69-
real hs = size * real(0.5);
70-
return new Octree(
71-
x + ((idx & 1) ? hs : -hs),
72-
y + ((idx & 2) ? hs : -hs),
73-
z + ((idx & 4) ? hs : -hs),
74-
hs
75-
);
76-
}
77-
7884
void computeMass() {
7985
if (leaf) {
8086
if (body) {
@@ -126,22 +132,26 @@ struct Octree {
126132
real rx = c->cx - cx;
127133
real ry = c->cy - cy;
128134
real rz = c->cz - cz;
129-
real r2 = rx*rx + ry*ry + rz*rz;
135+
real r2 = rx * rx + ry * ry + rz * rz;
130136
real mchild = c->m;
131137

132-
Qxx += mchild * (3*rx*rx - r2);
133-
Qyy += mchild * (3*ry*ry - r2);
134-
Qzz += mchild * (3*rz*rz - r2);
138+
Qxx += mchild * (3 * rx * rx - r2);
139+
Qyy += mchild * (3 * ry * ry - r2);
140+
Qzz += mchild * (3 * rz * rz - r2);
135141

136-
Qxy += mchild * (3*rx*ry);
137-
Qxz += mchild * (3*rx*rz);
138-
Qyz += mchild * (3*ry*rz);
142+
Qxy += mchild * (3 * rx * ry);
143+
Qxz += mchild * (3 * rx * rz);
144+
Qyz += mchild * (3 * ry * rz);
139145
}
140146
}
141147
};
142148

143-
inline void bhAccel(Octree* node, const Particle& p, real theta,
144-
real& ax, real& ay, real& az)
149+
inline void bhAccel(Octree* node,
150+
const Particle& p,
151+
real theta,
152+
real& ax,
153+
real& ay,
154+
real& az)
145155
{
146156
if (!node || node->m == 0)
147157
return;
@@ -150,21 +160,20 @@ inline void bhAccel(Octree* node, const Particle& p, real theta,
150160
if (node->leaf && node->body == &p)
151161
return;
152162

153-
constexpr real G = real(1.0);
163+
constexpr real G = real(1.0);
154164

155165
// Adaptive softening
156-
real eps = node->size * real(0.01);
166+
real eps = nextSoftening(node->size, node->m, dist);
157167

158168
real dx = node->cx - p.x;
159169
real dy = node->cy - p.y;
160170
real dz = node->cz - p.z;
161171

162-
real r2_soft = dx*dx + dy*dy + dz*dz + eps*eps;
172+
real r2_soft = dx * dx + dy * dy + dz * dz + eps * eps;
163173
real dist = std::sqrt(r2_soft);
164174

165175
// BH acceptance criterion
166-
if (node->leaf || (node->size / dist) < theta)
167-
{
176+
if (node->leaf || (node->size / dist) < theta) {
168177
// Monopole
169178
real invDist = real(1.0) / dist;
170179
real invDist2 = invDist * invDist;
@@ -180,7 +189,7 @@ inline void bhAccel(Octree* node, const Particle& p, real theta,
180189
real rx = dx;
181190
real ry = dy;
182191
real rz = dz;
183-
real r2 = rx*rx + ry*ry + rz*rz + real(1e-12); // avoid zero
192+
real r2 = rx * rx + ry * ry + rz * rz + real(1e-12); // avoid zero
184193
real r = std::sqrt(r2);
185194
real invr = real(1.0) / r;
186195
real invr2 = invr * invr;
@@ -219,7 +228,71 @@ inline void bhAccel(Octree* node, const Particle& p, real theta,
219228
}
220229

221230
// Recurse
222-
for (int i = 0; i < 8; i++)
223-
if (node->child[i])
231+
for (int i = 0; i < 8; ++i) {
232+
if (node->child[i]) {
224233
bhAccel(node->child[i], p, theta, ax, ay, az);
225-
}
234+
}
235+
}
236+
}
237+
238+
// Barnes–Hut solver façade, nbody-style, no namespace.
239+
struct BarnesHut {
240+
real theta;
241+
real root_x, root_y, root_z;
242+
real root_size;
243+
Octree* root = nullptr;
244+
245+
BarnesHut(real theta_,
246+
real cx,
247+
real cy,
248+
real cz,
249+
real halfSize)
250+
: theta(theta_)
251+
, root_x(cx)
252+
, root_y(cy)
253+
, root_z(cz)
254+
, root_size(halfSize) {}
255+
256+
~BarnesHut() {
257+
delete root;
258+
}
259+
260+
// Build tree from particles (positions must already be set).
261+
void build(std::vector<Particle>& particles) {
262+
delete root;
263+
root = new Octree(root_x, root_y, root_z, root_size);
264+
265+
for (auto& p : particles) {
266+
root->insert(&p);
267+
}
268+
root->computeMass();
269+
}
270+
271+
// Compute self-gravity accelerations in-place on particles.
272+
// You can adapt this to your own accel storage.
273+
void evalSelfGravity(std::vector<Particle>& particles) const {
274+
if (!root) return;
275+
276+
for (auto& p : particles) {
277+
real ax = 0;
278+
real ay = 0;
279+
real az = 0;
280+
bhAccel(root, p, theta, ax, ay, az);
281+
282+
// store back however your engine does it
283+
p.ax = ax;
284+
p.ay = ay;
285+
p.az = az;
286+
}
287+
}
288+
289+
// Single-point query, like SPH's evalAcceleration.
290+
void evalAtPoint(const Particle& probe,
291+
real& ax,
292+
real& ay,
293+
real& az) const {
294+
ax = ay = az = 0;
295+
if (!root) return;
296+
bhAccel(root, probe, theta, ax, ay, az);
297+
}
298+
};

0 commit comments

Comments
 (0)