Attempt at vectorising the NBody simulation…
// NBody
private struct NBody
{
public double3 xyz, vxyz;
public double mass;
}
[BurstCompile]
private unsafe struct NBodyBurst : IJob
{
public uint advancements;
public double result;
public void Execute()
{
result = NBody(advancements);
}
private double NBody(uint advancements)
{
NBody* sun = stackalloc NBody[5];
NBody* end = sun + 4;
InitializeBodies(sun, end);
Energy(sun, end);
while (advancements-- > 0)
{
Advance(sun, end, 0.01d);
}
Energy(sun, end);
return sun[0].xyz.x + sun[0].xyz.y;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void InitializeBodies(NBody* sun, NBody* end)
{
const double pi = 3.141592653589793;
const double solarmass = 4 * pi * pi;
const double daysPerYear = 365.24;
unchecked
{
sun[1] = new NBody
{ // Jupiter
xyz = new double3( 4.84143144246472090e+00,
-1.16032004402742839e+00,
-1.03622044471123109e-01 ),
vxyz = new double3( 1.66007664274403694e-03 * daysPerYear,
7.69901118419740425e-03 * daysPerYear,
-6.90460016972063023e-05 * daysPerYear),
mass = 9.54791938424326609e-04 * solarmass
};
sun[2] = new NBody
{ // Saturn
xyz = new double3(8.34336671824457987e+00,
4.12479856412430479e+00,
-4.03523417114321381e-01),
vxyz = new double3(
-2.76742510726862411e-03 * daysPerYear,
4.99852801234917238e-03 * daysPerYear,
2.30417297573763929e-05 * daysPerYear),
mass = 2.85885980666130812e-04 * solarmass
};
sun[3] = new NBody
{ // Uranus
xyz = new double3(1.28943695621391310e+01,
-1.51111514016986312e+01,
-2.23307578892655734e-01),
vxyz = new double3(2.96460137564761618e-03 * daysPerYear,
2.37847173959480950e-03 * daysPerYear,
-2.96589568540237556e-05 * daysPerYear),
mass = 4.36624404335156298e-05 * solarmass
};
sun[4] = new NBody
{ // Neptune
xyz = new double3(1.53796971148509165e+01,
-2.59193146099879641e+01,
1.79258772950371181e-01),
vxyz = new double3(2.68067772490389322e-03 * daysPerYear,
1.62824170038242295e-03 * daysPerYear,
-9.51592254519715870e-05 * daysPerYear),
mass = 5.15138902046611451e-05 * solarmass
};
double3 v = new double3();
for (NBody* planet = sun + 1; planet <= end; ++planet)
{
double mass = planet->mass;
v += planet->vxyz * mass;
}
sun->mass = solarmass;
sun->vxyz = v / -solarmass;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Energy(NBody* sun, NBody* end)
{
unchecked
{
double e = 0.0;
double imass;
double3 ixyz, ivxyz;
NBody* bj;
NBody* bi;
double jmass;
double3 dxyz;
for (bi = sun; bi <= end; ++bi)
{
imass = bi->mass;
ixyz = bi->xyz;
ivxyz = bi->vxyz;
e += 0.5 * imass * (math.length(ivxyz) * math.length(ivxyz));
for (bj = bi + 1; bj <= end; ++bj)
{
jmass = bj->mass;
dxyz = ixyz - bj->xyz;
e -= imass * jmass / Math.Sqrt(math.dot(dxyz,dxyz));
}
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double GetD2(double dx, double dy, double dz)
{
double d2 = dx * dx + dy * dy + dz * dz;
return d2 * Math.Sqrt(d2);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Advance(NBody* sun, NBody* end, double distance)
{
unchecked
{
double3 ixyz, ivxyz, dxyz;
double jmass, imass, mag;
NBody* bi, bj;
for (bi = sun; bi < end; ++bi)
{
ixyz = bi->xyz;
ivxyz = bi->vxyz;
imass = bi->mass;
for (bj = bi + 1; bj <= end; ++bj)
{
dxyz = bj->xyz - ixyz;
jmass = bj->mass;
mag = distance / math.lengthsq(dxyz);
bj->vxyz = bj->vxyz - dxyz * imass * mag;
ivxyz = ivxyz + dxyz * jmass * mag;
}
bi->vxyz = ivxyz;
bi->xyz = ixyz + ivxyz * distance;
}
end->xyz = end->xyz + end->vxyz * distance;
}
}
}
My theory is that the use of double3 should allow Burst to vectorise more operations??