| // Copyright ©2019 The Gonum Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package barneshut_test |
| |
| import ( |
| "log" |
| |
| "golang.org/x/exp/rand" |
| |
| "gonum.org/v1/gonum/spatial/barneshut" |
| "gonum.org/v1/gonum/spatial/r2" |
| ) |
| |
| type mass struct { |
| d r2.Vec |
| v r2.Vec |
| m float64 |
| } |
| |
| func (m *mass) Coord2() r2.Vec { return m.d } |
| func (m *mass) Mass() float64 { return m.m } |
| func (m *mass) move(f r2.Vec) { |
| m.v = m.v.Add(f.Scale(1 / m.m)) |
| m.d = m.d.Add(m.v) |
| } |
| |
| func Example_galaxy() { |
| rnd := rand.New(rand.NewSource(1)) |
| |
| // Make 1000 stars in random locations. |
| stars := make([]*mass, 1000) |
| p := make([]barneshut.Particle2, len(stars)) |
| for i := range stars { |
| s := &mass{ |
| d: r2.Vec{ |
| X: 100 * rnd.Float64(), |
| Y: 100 * rnd.Float64(), |
| }, |
| v: r2.Vec{ |
| X: rnd.NormFloat64(), |
| Y: rnd.NormFloat64(), |
| }, |
| m: 10 * rnd.Float64(), |
| } |
| stars[i] = s |
| p[i] = s |
| } |
| vectors := make([]r2.Vec, len(stars)) |
| |
| // Make a plane to calculate approximate forces |
| plane := barneshut.Plane{Particles: p} |
| |
| // Run a simulation for 100 updates. |
| for i := 0; i < 1000; i++ { |
| // Build the data structure. For small systems |
| // this step may be omitted and ForceOn will |
| // perform the naive quadratic calculation |
| // without building the data structure. |
| err := plane.Reset() |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| // Calculate the force vectors using the theta |
| // parameter... |
| const theta = 0.5 |
| // and an imaginary gravitational constant. |
| const G = 10 |
| for j, s := range stars { |
| vectors[j] = plane.ForceOn(s, theta, barneshut.Gravity2).Scale(G) |
| } |
| |
| // Update positions. |
| for j, s := range stars { |
| s.move(vectors[j]) |
| } |
| |
| // Rendering stars is left as an exercise for |
| // the reader. |
| } |
| } |