NBodyJS: An NBody Simulation Written in Kotlin
by C. Campo
NBodyJS is a simple project I’ve had around for the past few years in various forms. It is a JavaScript nbody simulation. It is currently written in Kotlin. Initially I wrote it in plain JavaScript, then rewrote in Scala, and finally, rewrote in Kotlin. Both the Scala and Kotlin versions transpile to readable JavaScript, using ScalaJS for Scala and Kotlin’s builtin JavaScript support. The Kotlin implementation is by far my favorite, and the language itself is a joy to write in. NBodyJS utilizes the HTML5 canvas element for display, and kotlinjs to transpile Kotlin to JavaScript.
See it in action and play around! You can also view the code on GitHub.
Some Background on Nbody Simulations (warning: math!)
Within a gravity simulation composed of \(n\) bodies, the magnitude of the force \(\mathbf{F}_i\) acting on each body \(i\), is determined by Newton’s law of universal gravitation:
\[\mathbf{F}_i = \sum_{j = 1\atop j\not = i}^n G\frac{m_i m_j}{\mathbf{r}_{ij}^2}\hat{\mathbf{r}}_{ij}\]where \(G\) is the gravitational constant, \(m_i\) is the mass of body \(i\), \(m_j\) is the mass of body \(j\), and \(\mathbf{r}_{ij}\) is the distance vector from \(i\) to \(j\).
In the case of gravity simulations, the forces due to gravity get exceedingly large as bodies get closer to each other (due to the inversesquare law nature of the gravitational force), and hence bodies tend to rapidly accelerate and zoom off when they seemingly “collide”. To compensate for this, a softening length \(R^2\) has been applied in the gravity calculation to prevent bodies from zipping off into the abyss when they get near eachother. Also, \(G\) has been set to 1 for simplicity in NBodyJS.
We can then use Newton’s second law \(\mathbf{F} = m\mathbf{a}\) to solve for the acceleration, and then numerically integrate it to get the positions and velocities of all bodies. In Kotlin, the code to compute the acceleration due to gravity looks like this:
The Algorithm
To compute the positions and velocities of all of the bodies, NBodyJS utilizes the Velocity Verlet method of numerical integration. Verlet integration is a secondorder method, which offers more stability than simpler, first order solutions such as Euler’s method, yet at no significant additional computational cost.
For the algorithm to work, first you need to specify the initial conditions of the simulation; namely the initial positions and velocities of all the bodies at some start time \(t\). Then, the Velocity Verlet algorithm consists of the following steps:
 Calculate the acceleration \(\mathbf{a}(t)\) of each body due to gravity (or whatever force(s) you want) at time \(t\), using Newton’s laws.

Calculate the position \(\mathbf{x}(t + dt)\) of each body at time \(t + dt\) (where \(dt\) is a small time step), using the approximation
\[\mathbf{x}(t + dt) = \mathbf{x}(t) + \mathbf{v}(t)dt + \mathbf{a}(t)\frac{dt^2}{2}\]  Calculate the acceleration \(\mathbf{a}(t + dt)\), again using Newton’s laws and the forces in play.

Calculate the velocity \(\mathbf{v}(t + dt)\) using the approximation
\[\mathbf{v}(t + dt) = \mathbf{v}(t) + (\mathbf{a}(t) + \mathbf{a}(t + dt))\frac{dt}{2}\]
In Kotlin, the integration code is extremely simple:
This algorithm is executed every time you take a time step, \(dt\). Since every body exerts a force on every other body, computing the accelerations is done in \(O(n^2)\) time.
There are more efficient, yet similarly accurate algorithms out there, so feel free to implement your own version if you feel like experimenting! Also, note that this method can be used to integrate Newton’s laws for nearly any force(s), not just gravity!
Subscribe via RSS