Last active
June 4, 2021 08:51
-
-
Save jenska/b79eb5ac4474dc0cbdb03511bf7a55f0 to your computer and use it in GitHub Desktop.
accelerated SIMD n-body (https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/nbody-swift-7.html)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* The Computer Language Benchmarks Game | |
https://salsa.debian.org/benchmarksgame-team/benchmarksgame/ | |
contributed by Ralph Ganszky | |
Added dummy element to tuple (because I read an article that this helps | |
to block less writing back to memory) and store data in | |
UnsafedMutablePointer to reduce overhead of array access. | |
modified by Patrick Sy | |
modified by Jens Kaiser | |
*/ | |
import Foundation | |
import simd | |
typealias Body = ( | |
r: simd_double3, | |
v: simd_double3, | |
m: simd_double1, | |
d: simd_double1 | |
) | |
let nPlanets: Int = 5 | |
let solarMass: Double = 4 * Double.pi * Double.pi | |
let daysPerYear: Double = 365.24 | |
let sun: Body = ( | |
r: simd_double3(x: 0.0, y: 0.0, z: 0.0), | |
v: simd_double3(x: 0.0, y: 0.0, z: 0.0), | |
m: solarMass, d: 0.0 | |
) | |
let jupiter: Body = ( | |
r: simd_double3(x: 4.8414314424647209, | |
y: -1.16032004402742839, | |
z: -0.103622044471123109), | |
v: simd_double3(x: 1.66007664274403694e-03 * daysPerYear, | |
y: 7.69901118419740425e-03 * daysPerYear, | |
z: -6.90460016972063023e-05 * daysPerYear), | |
m: 9.54791938424326609e-04 * solarMass, d: 0.0 | |
) | |
let saturn: Body = ( | |
r: simd_double3(x: 8.34336671824457987, | |
y: 4.12479856412430479, | |
z: -4.03523417114321381e-01), | |
v: simd_double3(x: -2.76742510726862411e-03 * daysPerYear, | |
y: 4.99852801234917238e-03 * daysPerYear, | |
z: 2.30417297573763929e-05 * daysPerYear), | |
m: 2.85885980666130812e-04 * solarMass, d: 0.0 | |
) | |
let uranus: Body = ( | |
r: simd_double3(x: 1.28943695621391310e+01, | |
y: -1.51111514016986312e+01, | |
z: -2.23307578892655734e-01), | |
v: simd_double3(x: 2.96460137564761618e-03 * daysPerYear, | |
y: 2.37847173959480950e-03 * daysPerYear, | |
z: -2.96589568540237556e-05 * daysPerYear), | |
m: 4.36624404335156298e-05 * solarMass, d: 0.0 | |
) | |
let neptune: Body = ( | |
r: simd_double3(x: 1.53796971148509165e+01, | |
y: -2.59193146099879641e+01, | |
z: 1.79258772950371181e-01), | |
v: simd_double3(x: 2.68067772490389322e-03 * daysPerYear, | |
y: 1.62824170038242295e-03 * daysPerYear, | |
z: -9.51592254519715870e-05 * daysPerYear), | |
m: 5.15138902046611451e-05 * solarMass, d: 0.0 | |
) | |
let bodies: UnsafeMutablePointer<Body> = UnsafeMutablePointer<Body>.allocate(capacity: nPlanets) | |
defer { | |
bodies.deallocate() | |
} | |
bodies[0] = sun | |
bodies[1] = jupiter | |
bodies[2] = saturn | |
bodies[3] = uranus | |
bodies[4] = neptune | |
func advance(dt: simd_double1) { | |
for i in 0..<nPlanets { | |
let iBody: Body = bodies[i] | |
for j in i+1..<nPlanets { | |
let jBody: Body = bodies[j] | |
let d: simd_double3 = iBody.r - jBody.r | |
let dSquared: simd_double1 = simd_length_squared(d) | |
let mag: simd_double1 = dt / (dSquared * dSquared.squareRoot()) | |
// dSquared.squareRoot() == distance | |
bodies[i].v -= d * (jBody.m * mag) | |
bodies[j].v += d * (iBody.m * mag) | |
} | |
} | |
for i in 0..<nPlanets { | |
bodies[i].r = bodies[i].r + bodies[i].v * dt | |
} | |
} | |
func energy() -> simd_double1 { | |
var energy: simd_double1 = 0.0 | |
for i in 0..<nPlanets { | |
let iBody: Body = bodies[i] | |
energy += 0.5 * iBody.m * simd_length_squared(iBody.v) | |
for j in i+1..<nPlanets { | |
let jBody: Body = bodies[j] | |
let d: simd_double3 = iBody.r - jBody.r | |
let distance: simd_double1 = simd_length(d) | |
energy -= (iBody.m * jBody.m) / distance | |
} | |
} | |
return energy | |
} | |
var n: Int = 1000 | |
if CommandLine.argc > 1 { | |
if let m: Int = Int(CommandLine.arguments[1]) { | |
n = m | |
} | |
} | |
// Adjust momentum of the sun | |
var p: simd_double3 = simd_double3(x: 0.0, y: 0.0, z: 0.0) | |
for i in 0..<nPlanets { | |
p += bodies[i].v * bodies[i].m | |
} | |
bodies[0].v = -p / solarMass | |
print(String(format: "%.9f", energy())) | |
for _ in 0..<n { | |
advance(dt: 0.01) | |
} | |
print(String(format: "%.9f", energy())) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment