about summary refs log tree commit diff
path: root/forces/forces.go
blob: a99433489b0141f74a971cb6c6bba601fd219cf5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package forces

import (
	"../structs"
	"fmt"
	"git.darknebu.la/bit/logplus"
	"gopkg.in/cheggaaa/pb.v1"
	"math"
)

// forces_acting calculates the force inbetween the two given stars s1 and s2
// The function return the force
func accelerationActing(s1 structs.Star2D, s2 structs.Star2D) structs.Vec2 {

	// Gravitational constant
	var G = 6.674E-11

	// the vector from star s1 to star s2
	var r12 = s2.C.Subtract(s1.C)

	// the distance between the stars
	var deltaR = r12.GetLength()

	// the scalar acceleration of star s1 by star s2
	scalarA := G * (s2.M) / math.Pow(deltaR, 2)

	// calculate the direction vector of the vector from s1 to s2
	directionVectorA := r12.GetDirVector()

	// the vector acceleration of scalarA
	A := directionVectorA.Multiply(scalarA)

	return A
}

// accelerations calculates the acceleration acting in between a given star and all the other stars in a given array.
func accelerations(stars_arr []structs.Star2D, nr int) structs.Vec2 {

	var a = /*acceleration*/ structs.Vec2{}
	// Iterate over all the stars in the stars_arr
	for index := range stars_arr {

		// If the current star is not the star itself
		if index != nr {

			// calculate the acceleration and add it to the overall acceleration of the star
			aa := accelerationActing(stars_arr[nr], stars_arr[index])
			a = a.Add(aa)

		}
	}

	return a
}

// accelerationThread calculates the acceleration acting on a given amount of stars in a given range for a given slice of stars
// as a go-routine
func accelerationThread(starSlice []structs.Star2D, localRangeStart int, localRangeEnd int, channel chan structs.Star2D) {

	// iterate over the given range
	for index := localRangeStart; index < localRangeEnd; index++ {

		// Calculate the acceleration acting inbetween the given star and all other stars
		var a = accelerations(starSlice, index)

		// create a new star
		newStar := starSlice[index].Copy()
		newStar.AccelerateVelocity(a, 1)

		// push the new Star into the channel
		channel <- newStar
	}
}

// CalcAllAccelerations calculates all the accelerations acting in between all the stars in the given starSlice slice and
// returns a "new" slice containing the stars with their new velocities
func CalcAllAccelerations(starSlice []structs.Star2D, threads int) []structs.Star2D {
	// create a channel for bundling the stars generated in the go-routines
	channel := make(chan structs.Star2D, 1000)

	sliceLength := len(starSlice)

	// calculate the local range
	// Example: 100 stars with 4 threads = 25 stars / thread
	localRangeLen := sliceLength / threads

	// generate a new slice for storing the stars
	var newSlice []structs.Star2D

	logplus.LogNeutral(fmt.Sprintf("Starting %d workers, each processing %d stars", threads, localRangeLen))

	// start n go threads
	for i := 0; i < threads; i++ {

		// define the local range
		localRangeStart := i * localRangeLen
		localRangeEnd := (i * localRangeLen) + localRangeLen

		// fmt.Printf("starting worker nr. %d, processing %d stars\n", i, localRangeEnd-localRangeStart)

		// calculate the accelerations for all the stars in the given slice in the given range and return them using the
		// given channel
		go accelerationThread(starSlice, localRangeStart, localRangeEnd, channel)
	}

	// Handle errors (10004 stars, but 1250 stars per thread, so 4 stars are not calculate and block the queue)
	if sliceLength > localRangeLen {

		// Calculate the amount of stars and their range
		remainingStars := sliceLength - (localRangeLen * threads)
		localRangeEnd := ((threads - 1) * localRangeLen) + localRangeLen

		// Run the Thread
		// go accelerationThread(starSlice, localRangeEnd, localRangeEnd+remainingStars, channel)
		accelerationThread(starSlice, localRangeEnd, localRangeEnd+remainingStars, channel)
	}

	// Initialize a new progress bar
	bar := pb.New(len(starSlice)).Prefix("Stars: ")

	bar.Start()

	// iterate over the amount of stars
	for i := 0; i < sliceLength; i++ {

		// block until a star is finisehd
		var newStar = <-channel

		// append the star from the channel to the newSlice for returning in the end
		newSlice = append(newSlice, newStar)

		// increment the progress bar and the counter
		bar.Increment()
	}

	bar.Finish()

	return newSlice
}

// Calculate the new positions of the stars using the
func NextTimestep(starSlice []structs.Star2D, deltat float64) []structs.Star2D {
	// create a new slice for storing the "new" stars
	var newSlice []structs.Star2D

	// iterate over all the stars in the old slice
	for index := range starSlice {

		// move the star with it's velocity for time deltat
		newStar := starSlice[index].Copy()
		newStar.Move(deltat)

		// append the new star to the newSlice
		newSlice = append(newSlice, newStar)
	}

	return newSlice
}