PhysicalTrees.jl

Distributed octrees for N-body simulation

PhysicalTrees.jl is a package in the JuliaAstroSim ecosystem. It builds and queries space-partitioning octrees over particle data, in a way that is

  • Unitful — positions, smoothing lengths and box sizes carry their physical units (kpc, Myr, M⊙, …) end to end; unit errors are caught at the call site rather than producing silent nonsense.
  • Distributed — the build pipeline is split across multiple workers and the tree is rebuilt in place after data movement.
  • Composable — sits on top of PhysicalParticles.jl and re-exports its PVector, Star, Massless, extent and datadimension, so the rest of the ecosystem is one using away.

Why an octree?

An N-body simulation needs to evaluate gravity (or SPH kernels) between every pair of nearby particles. A naïve double loop is $\mathcal O(N^2)$; an octree brings this down to $\mathcal O(N\log N)$ by only descending into a node when the field it represents could materially contribute.

Package Features

Quick start

using PhysicalParticles, PhysicalTrees, Unitful, UnitfulAstro
using Distributed
addprocs(2)
@everywhere using PhysicalParticles, PhysicalTrees, UnitfulAstro

# Six unitful particles in a (-1, 1)³ kpc cube
pos = [PVector( 1.0,  1.0,  1.0, u"kpc"),
       PVector(-1.0, -1.0, -1.0, u"kpc"),
       PVector( 1.0,  0.0, -1.0, u"kpc"),
       PVector(-1.0,  0.0,  1.0, u"kpc"),
       PVector( 0.0,  0.0, -1.0, u"kpc"),
       PVector(-1.0,  0.0,  0.0, u"kpc")]

particles = StructArray(Star(uAstro) for _ in 1:6)
assign_particles(particles, :Pos, pos)

# Build the tree across workers 1 and 2
tree = octree(particles, pids = workers())

# Find particles inside a unit-radius cube around the origin
ngb = ngb_treefind_variable(PVector(0.0, 0.0, 0.0, u"kpc"), 1.0u"kpc", tree)

# Tear down on all workers when done
unregister(tree)

Manual Outline

Library Reference

Package ecosystem