Fuzion Logo
flang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

benchmarks_game/nbody_marray.fz


# https://benchmarksgame-team.pages.debian.net/benchmarksgame/description/nbody.html#nbody
# fz -unsafeIntrinsics=on -modules=java.base nbody.fz
# version using marray instead of array
nbody_marray is

  PI := f64 3.141592653589793
  SOLAR_MASS := f64 4 * PI * PI
  DAYS_PER_YEAR := f64 365.24

  body(x, y, z, vx, vy, vz, mass f64) is
  # change velocity
  body(b body, vx, vy, vz f64) =>
    body b.x b.y b.z vx vy vz b.mass

  jupiter := body 4.84143144246472090 -1.16032004402742839 -1.03622044471123109E-1 (1.66007664274403694E-3 * DAYS_PER_YEAR) (7.69901118419740425E-3 * DAYS_PER_YEAR) (-6.90460016972063023E-5 * DAYS_PER_YEAR) (9.54791938424326609E-4 * SOLAR_MASS)

  saturn := body 8.34336671824457987 4.12479856412430479 -4.03523417114321381E-1 (-2.76742510726862411E-3 * DAYS_PER_YEAR) (4.99852801234917238E-3 * DAYS_PER_YEAR) (2.30417297573763929E-5 * DAYS_PER_YEAR) (2.85885980666130812E-4 * SOLAR_MASS)

  uranus := body 1.28943695621391310E+1 -1.51111514016986312E+1 -2.23307578892655734E-1 (2.96460137564761618E-3 * DAYS_PER_YEAR) (2.37847173959480950E-3 * DAYS_PER_YEAR) (-2.96589568540237556E-5 * DAYS_PER_YEAR) (4.36624404335156298E-5 * SOLAR_MASS)

  neptune := body 1.53796971148509165E+1 -2.59193146099879641E+1 1.79258772950371181E-1 (2.68067772490389322E-3 * DAYS_PER_YEAR) (1.62824170038242295E-3 * DAYS_PER_YEAR) (-9.51592254519715870E-5 * DAYS_PER_YEAR) (5.15138902046611451E-5 * SOLAR_MASS)

  sun := body 0 0 0 0 0 0 SOLAR_MASS

  advance (bodies marray body, dt f64) =>
    for i in (0..bodies.length-1) do
      for j in (i+1..bodies.length-1) do
        dx := bodies[i].x - bodies[j].x
        dy := bodies[i].y - bodies[j].y
        dz := bodies[i].z - bodies[j].z

        dSquared := dx * dx + dy * dy + dz * dz
        distance := f64s.sqrt dSquared
        mag := dt / (dSquared * distance)

        vx := bodies[i].vx - dx * bodies[j].mass * mag
        vy := bodies[i].vy - dy * bodies[j].mass * mag
        vz := bodies[i].vz - dz * bodies[j].mass * mag

        bodies[i] := body bodies[i] vx vy vz

        vx := bodies[j].vx + dx * bodies[i].mass * mag
        vy := bodies[j].vy + dy * bodies[i].mass * mag
        vz := bodies[j].vz + dz * bodies[i].mass * mag

        bodies[j] := body bodies[j] vx vy vz

    for i in (0..bodies.length-1) do
      b := bodies[i]
      bodies[i] := body (b.x + dt * b.vx) (b.y + dt * b.vy) (b.z + dt * b.vz) b.vx b.vy b.vz b.mass

  energy_of_body(b body) =>
    b.mass * (b.vx * b.vx
            + b.vy * b.vy
            + b.vz * b.vz)

  energy (bodies marray body) =>
    ((0..bodies.length-1).map f64 (i ->
        bodyA := bodies[i]

        # NYI better name for var x. unit is kg²/m
        x := (bodies.asList.drop(i+1).map f64 (bodyB ->
            dx := bodyA.x - bodyB.x
            dy := bodyA.y - bodyB.y
            dz := bodyA.z - bodyB.z
            distance := f64s.sqrt (dx*dx + dy*dy + dz*dz)
            bodyA.mass * bodyB.mass / distance
          )).fold(f64s.sum)

        - x + 0.5 * energy_of_body bodyA
      )).fold(f64s.sum)

  n := 1

  startConstellation := [ sun, jupiter, saturn, uranus, neptune ]

  px := startConstellation
    .asStream
    .map f64 (body -> body.vx * body.mass)
    .fold f64s.sum

  py := startConstellation
    .asStream
    .map f64 (body -> body.vy * body.mass)
    .fold f64s.sum

  pz := startConstellation
    .asStream
    .map f64 (body -> body.vz * body.mass)
    .fold f64s.sum

  offsettedSun := body startConstellation[0] (-px / SOLAR_MASS) (-py / SOLAR_MASS) (-pz / SOLAR_MASS)
  movingBodies := marray 5 [offsettedSun, jupiter, saturn, uranus, neptune].internalArray

  say (energy movingBodies)

  for _ in (0..n-1) do
    advance movingBodies 0.01

  say (energy movingBodies)