about summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xSourcebin0 -> 3302760 bytes
-rw-r--r--csv/csv.go56
-rw-r--r--draw/draw.go69
-rw-r--r--file/file.go31
-rw-r--r--forces/forces.go117
-rw-r--r--main.go31
-rw-r--r--out_0.pngbin0 -> 3367531 bytes
-rw-r--r--structs/star.go29
-rw-r--r--structs/structs.go23
-rw-r--r--structs/vector2D.go63
10 files changed, 239 insertions, 180 deletions
diff --git a/Source b/Source
new file mode 100755
index 0000000..b35d91d
--- /dev/null
+++ b/Source
Binary files differdiff --git a/csv/csv.go b/csv/csv.go
index 7a0fa9f..aca131b 100644
--- a/csv/csv.go
+++ b/csv/csv.go
@@ -1,75 +1,39 @@
 package csv
 
 import (
+	"../file"
 	"../structs"
-	"encoding/csv"
-	"log"
-	"math/rand"
-	"os"
+	"git.darknebu.la/bit/logplus"
 	"strconv"
-	"time"
 )
 
-// openStar2DCSV opens the file at the given path and reads its content. It then returns the content inform of a slice
-// of slices
-func openStar2DCSV(path string) [][]string {
-
-	// Open the file located at the given path
-	b, err := os.Open(path)
-
-	// Handle errors
-	if err != nil {
-		log.Printf("openStar2DsCSV Panic! (cannot read file from %s)", path)
-	}
-
-	// Close the file afre reading it's content
-	defer b.Close()
-
-	// Parse the files conten usin a csv-reader
-	lines, err := csv.NewReader(b).ReadAll()
-
-	// Handle errors
-	if err != nil {
-		log.Println("openStar2DsCSV Panic! (cannot read the files content)")
-	}
-
-	return lines
-}
-
 // Import gets a file, a starting line, an ending line and  a struct. It then adds the content of the file to the struct
 // For finding the length of the .csv, you can use the following command in linux:
 // $ cat <csv> | wc -l
 func Import(path string, start int, end int, slice []structs.Star2D) []structs.Star2D {
-	lines := openStar2DCSV(path)
-
-	// seed the random number generator
-	rand.Seed(time.Now().UTC().UnixNano())
+	f, _ := file.Open(path)
+	lines, _ := f.ReadCSV()
 
-	// iterate over all the lines in the given range
 	for linenr, line := range lines[start:end] {
 		x, errx := strconv.ParseFloat(line[0], 64)
 		y, erry := strconv.ParseFloat(line[1], 64)
 
 		// Handle errors
 		if errx != nil {
-			log.Printf("error reading value from csv in line nr. %d (%s)", linenr, errx)
+			logplus.LogFError("error reading value from csv in line nr. %d (%s)", linenr, errx)
 		}
 		if erry != nil {
-			log.Printf("error reading value from csv in line nr. %d (%s)", linenr, erry)
+			logplus.LogFError("error reading value from csv in line nr. %d (%s)", linenr, erry)
 		}
 
-		// TODO: Export the code below to its own function
-		var mass float64 = float64(10000 + rand.Intn(100000-10000))
-
 		// Create a temporary star for assembling the star
-		tempStar2D := structs.Star2D{
-			structs.Coord{X: x, Y: y},
-			structs.Force{X: 0, Y: 0},
-			mass,
+		tempStar := structs.Star2D{
+			C: structs.Vec2{X: x, Y: y},
+			M: 50000,
 		}
 
 		// Add the Temporary star to the slice
-		slice = append(slice, tempStar2D)
+		slice = append(slice, tempStar)
 
 	}
 
diff --git a/draw/draw.go b/draw/draw.go
index 1823493..a5d5f0d 100644
--- a/draw/draw.go
+++ b/draw/draw.go
@@ -33,41 +33,32 @@ func saveImage(dc *gg.Context, path string) {
 	dc.SavePNG(path)
 }
 
-// drawStar2D draws the given stars to the given context
-func drawStar2D(dc *gg.Context, star structs.Star2D) {
-	// the radius can be any value inbetween 1e4 and 1e5
-
-	// Define the default star radius as 1 and change it according to the stars mass
-	radius := 1
-	switch {
-	case star.Mass < 10000:
-		radius = 1
-	case star.Mass < 50000 && star.Mass > 10000:
-		radius = 2
-	case star.Mass < 100000 && star.Mass > 50000:
-		radius = 3
+// drawStar draws the given stars to the given context
+func drawStar(dc *gg.Context, star structs.Star2D) {
+
+	// set radius of the star to 2
+	R := 2.0
+
+	// if the star has a greater mass than the default 5E4, it's radius is increased to 5
+	if star.M > 5E4 {
+		R = 5
 	}
 
-	// Draw the star
-	dc.DrawPoint(star.C.X/50, star.C.Y/50, float64(radius))
+	// draw the star / point
+	dc.DrawPoint(star.C.X/50, star.C.Y/50, R)
 	dc.Fill()
 	dc.Stroke()
 }
 
-// vectorLength calculates the length of the given vector
-func vectorLength(force structs.Force) float64 {
-	return math.Sqrt(math.Pow(force.X, 2) + math.Pow(force.Y, 2))
-}
-
-func drawForce(dc *gg.Context, star structs.Star2D) {
-	// controll the length of the vector
+func drawVelocity(dc *gg.Context, star structs.Star2D) {
+	// scaling factor for a better view of the velocity difference
 	var scalingFactor float64 = 15
 
 	// Move the "cursor" to the start position of the vector
 	dc.MoveTo(star.C.X/50, star.C.Y/50)
 
 	// calculate the length of the vector
-	vecLength := vectorLength(star.F)
+	vecLength := star.V.GetLength()
 
 	// Use a sigmoid function to generate useful values for coloring the vectors according to their
 	// strength
@@ -76,31 +67,31 @@ func drawForce(dc *gg.Context, star structs.Star2D) {
 	// Set the color to a blue / red
 	dc.SetRGB(val, 0, 1-val)
 
-	// trace the Vector
-	FxUnit := star.F.X / math.Abs(vecLength)
-	FyUnit := star.F.Y / math.Abs(vecLength)
+	// calculate the direction vector
+	FUnit := (&star.V).Divide(vecLength)
 
-	dc.LineTo(star.C.X/50+(FxUnit*scalingFactor), star.C.Y/50+(FyUnit*scalingFactor))
+	// set end-position of the vector line
+	dc.LineTo(star.C.X/50+(FUnit.X*scalingFactor), star.C.Y/50+(FUnit.Y*scalingFactor))
 
-	// css
+	// set line width
 	dc.SetLineWidth(3)
 
 	// And finally: DRAW (stroke) the vector
 	dc.Stroke()
 }
 
-// drawStar2Ds draws all the stars in the given slice to the given context
-func drawStars2D(dc *gg.Context, slice []structs.Star2D) {
-	// draw all the forces in the given slice
+// drawStars draws all the stars in the given slice to the given context
+func drawStars(dc *gg.Context, slice []structs.Star2D) {
+	// draw all the velocity in the given slice
 	for _, star := range slice {
-		drawForce(dc, star)
+		drawVelocity(dc, star)
 	}
 
 	dc.SetRGB(1, 1, 1)
 
 	// draw all the stars in the given slice
 	for _, star := range slice {
-		drawStar2D(dc, star)
+		drawStar(dc, star)
 	}
 }
 
@@ -111,7 +102,17 @@ func Slice(slice []structs.Star2D, path string) {
 	dc := initializePlot()
 
 	// draw all the stars in the given slice
-	drawStars2D(dc, slice)
+	drawStars(dc, slice)
+
+	dc.SetRGB(1, 1, 1)
+
+	// drawing the 4 big stars as bigger white dots
+	//dc.DrawCircle(600, 600, 5)
+	//dc.DrawCircle(-600, 600, 5)
+	//dc.DrawCircle(-600, 0, 5)
+	//dc.DrawCircle(600, -600, 5)
+
+	dc.Fill()
 
 	// save the plot to the given path
 	saveImage(dc, path)
diff --git a/file/file.go b/file/file.go
new file mode 100644
index 0000000..ce6ac9c
--- /dev/null
+++ b/file/file.go
@@ -0,0 +1,31 @@
+package file
+
+import (
+	"encoding/csv"
+	"git.darknebu.la/bit/logplus"
+	"os"
+)
+
+type File struct {
+	f *os.File
+}
+
+func Open(path string) (File, error) {
+	file, err := os.Open(path)
+	if err != nil {
+		logplus.LogFError("openStarsCSV Panic! (cannot read file from %s)", path)
+	}
+	return File{f: file}, err
+}
+
+func (file *File) ReadCSV() ([][]string, error) {
+	lines, err := csv.NewReader(file.f).ReadAll()
+	if err != nil {
+		logplus.LogError("openStarsCSV Panic! (cannot read the files content)")
+	}
+	return lines, err
+}
+
+func (file *File) Close() error {
+	return file.f.Close()
+}
diff --git a/forces/forces.go b/forces/forces.go
index 7763f87..a994334 100644
--- a/forces/forces.go
+++ b/forces/forces.go
@@ -1,87 +1,81 @@
 package forces
 
 import (
-	"../llog"
 	"../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 forceActing(s1 structs.Star2D, s2 structs.Star2D) structs.Force {
+func accelerationActing(s1 structs.Star2D, s2 structs.Star2D) structs.Vec2 {
+
 	// Gravitational constant
-	var G float64 = 6.674e-11
+	var G = 6.674E-11
 
-	// Distance between the stars
-	var r21 = math.Sqrt(math.Pow(s2.C.X-s1.C.X, 2) + math.Pow(s2.C.Y-s1.C.Y, 2))
+	// the vector from star s1 to star s2
+	var r12 = s2.C.Subtract(s1.C)
 
-	// Unit vector pointing from s1 to s2
-	rhat := structs.Force{s2.C.X - s1.C.X, s2.C.Y - s1.C.Y}
+	// the distance between the stars
+	var deltaR = r12.GetLength()
 
-	// Calculate how strong the star is affected
-	var FScalar = G * (s1.Mass * s2.Mass) / math.Pow(math.Abs(r21), 2)
+	// the scalar acceleration of star s1 by star s2
+	scalarA := G * (s2.M) / math.Pow(deltaR, 2)
 
-	// Calculate the overall force by combining the scalar and the vector
-	var Fx = FScalar * rhat.X
-	var Fy = FScalar * rhat.Y
+	// calculate the direction vector of the vector from s1 to s2
+	directionVectorA := r12.GetDirVector()
 
-	// Pack the forces in a force structur
-	F := structs.Force{Fx, Fy}
+	// the vector acceleration of scalarA
+	A := directionVectorA.Multiply(scalarA)
 
-	return F
+	return A
 }
 
-// forces calculates the forces acting in between a given star and all the other stars in a given array.
-func forces(stars_arr []structs.Star2D, nr int) structs.Force {
+// 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 force structs.Force
+	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 {
 
-			// generate a new force and add it to the overall force of the star
-			fa := forceActing(stars_arr[nr], stars_arr[index])
-			stars_arr[nr].F.X += fa.X
-			stars_arr[nr].F.Y += fa.Y
+			// 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)
 
-			force.X += fa.X
-			force.Y += fa.Y
 		}
 	}
 
-	return force
+	return a
 }
 
-// forcesThread calculates the forces acting on a given amount of stars in a given range for a given slice of stars
+// 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 forcesThread(starSlice []structs.Star2D, localRangeStar2Dt int, localRangeEnd int, channel chan structs.Star2D) {
+func accelerationThread(starSlice []structs.Star2D, localRangeStart int, localRangeEnd int, channel chan structs.Star2D) {
 
 	// iterate over the given range
-	for index := localRangeStar2Dt; index < localRangeEnd; index++ {
+	for index := localRangeStart; index < localRangeEnd; index++ {
 
-		// Calculate the force acting inbetween the given star and all other stars
-		var force = forces(starSlice, index)
+		// Calculate the acceleration acting inbetween the given star and all other stars
+		var a = accelerations(starSlice, index)
 
 		// create a new star
-		newStar2D := structs.Star2D{
-			structs.Coord{starSlice[index].C.X, starSlice[index].C.Y},
-			structs.Force{force.X, force.Y},
-			starSlice[index].Mass,
-		}
+		newStar := starSlice[index].Copy()
+		newStar.AccelerateVelocity(a, 1)
 
-		// push the new Star2D into the channel
-		channel <- newStar2D
+		// push the new Star into the channel
+		channel <- newStar
 	}
 }
 
-// CalcAllForces calculates all the forces acting inbetween all the stars in the given starSlice slice and
-// returns a "new" slice contaning the forces
-func CalcAllForces(starSlice []structs.Star2D, threads int) []structs.Star2D {
-	// create a channel for bundling the stars generaten in the go-routines
+// 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)
@@ -93,43 +87,47 @@ func CalcAllForces(starSlice []structs.Star2D, threads int) []structs.Star2D {
 	// generate a new slice for storing the stars
 	var newSlice []structs.Star2D
 
-	llog.Good(fmt.Sprintf("Starting %d workers, each processing %d stars", threads, localRangeLen))
+	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
-		localRangeStar2Dt := i * localRangeLen
+		localRangeStart := i * localRangeLen
 		localRangeEnd := (i * localRangeLen) + localRangeLen
 
-		// calculate the forces for all the stars in the given slice in the given range and return them using the
+		// 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 forcesThread(starSlice, localRangeStar2Dt, localRangeEnd, 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
-		remainingStar2Ds := sliceLength - (localRangeLen * threads)
+		remainingStars := sliceLength - (localRangeLen * threads)
 		localRangeEnd := ((threads - 1) * localRangeLen) + localRangeLen
 
 		// Run the Thread
-		// go forcesThread(starSlice, localRangeEnd, localRangeEnd+remainingStar2Ds, channel)
-		forcesThread(starSlice, localRangeEnd, localRangeEnd+remainingStar2Ds, channel)
+		// go accelerationThread(starSlice, localRangeEnd, localRangeEnd+remainingStars, channel)
+		accelerationThread(starSlice, localRangeEnd, localRangeEnd+remainingStars, channel)
 	}
 
 	// Initialize a new progress bar
-	bar := pb.New(len(starSlice)).Prefix("Star2Ds: ")
+	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 newStar2D structs.Star2D = <-channel
+		var newStar = <-channel
 
 		// append the star from the channel to the newSlice for returning in the end
-		newSlice = append(newSlice, newStar2D)
+		newSlice = append(newSlice, newStar)
 
 		// increment the progress bar and the counter
 		bar.Increment()
@@ -141,26 +139,19 @@ func CalcAllForces(starSlice []structs.Star2D, threads int) []structs.Star2D {
 }
 
 // Calculate the new positions of the stars using the
-func NextTimestep(starSlice []structs.Star2D, deltat int) []structs.Star2D {
+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 {
 
-		// calculate the new position
-		newX := starSlice[index].C.X + starSlice[index].F.X*float64(deltat)
-		newY := starSlice[index].C.Y + starSlice[index].F.Y*float64(deltat)
-
-		// assemble the new star
-		newStar2D := structs.Star2D{
-			C:    structs.Coord{X: newX, Y: newY},
-			F:    structs.Force{},
-			Mass: starSlice[index].Mass,
-		}
+		// 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, newStar2D)
+		newSlice = append(newSlice, newStar)
 	}
 
 	return newSlice
diff --git a/main.go b/main.go
index 0ad2e69..7aa389f 100644
--- a/main.go
+++ b/main.go
@@ -7,37 +7,40 @@ import (
 	"./structs"
 	"fmt"
 	"git.darknebu.la/bit/logplus"
+	"math"
 )
 
 func main() {
+	logplus.SetLogLevel(logplus.LevelAll)
 	var threads int = 8
+	var path1 string = "out_0.png"
 	var frames int = 1
-	var stars int = 800
 
 	// the slice starsSlice stores the star structures
-	starsSlice := []structs.Star2D{}
+	starsSlice := []structs.Star2D{
+		//		{C: structs.Vec2{X:  30000,  Y: 30000},M: 5E8},
+		//		{C: structs.Vec2{X: -30000,  Y: 30000},M: 5E8},
+		//		{C: structs.Vec2{X: -30000           },M: 5E8},
+		//		{C: structs.Vec2{X:  30000, Y: -30000},M: 5E8},
+		{C: structs.Vec2{}, M: 5E8},
+	}
 
-	logplus.LogPositive("Opening the csv")
-	starsSlice = csv.Import("data/U_ALL.csv", 0, stars, starsSlice)
+	logplus.LogNeutral("Opening the csv")
+	starsSlice = csv.Import("data/U_ALL.csv", 0, 25000, starsSlice)
 
 	// Simulate the position of the stars after a specific time
 	for i := 0; i < frames; i++ {
-
-		// Print the iterator
 		logplus.LogPositive("--- --- --- --- ---")
 		logplus.LogPositive(fmt.Sprintf("Frames %d/%d", i, frames))
 
-		// Calculate the position of stars after one timestep
-		logplus.LogPositive("Calculate the new Star positions")
-		starsSlice = forces.NextTimestep(starsSlice, 500000)
+		logplus.LogNeutral("Calculate the new Star positions")
+		starsSlice = forces.NextTimestep(starsSlice, 25*math.Pow(10, 4+7))
 
-		// Calculate all the forces acting inside of the galaxy
-		logplus.LogPositive("Calculate the acting forces")
-		starsSlice = forces.CalcAllForces(starsSlice, threads)
+		logplus.LogNeutral("Calculate the acting accelerations")
+		starsSlice = forces.CalcAllAccelerations(starsSlice, threads)
 
-		// Save the slice
 		outputName := fmt.Sprintf("out_%d.png", i+1)
-		logplus.LogPositive(fmt.Sprintf("draw the slice and save it to %s\n", outputName))
+		logplus.LogNeutral(fmt.Sprintf("draw the slice and save it to %s\n", outputName))
 		draw.Slice(starsSlice, outputName)
 	}
 }
diff --git a/out_0.png b/out_0.png
new file mode 100644
index 0000000..830315d
--- /dev/null
+++ b/out_0.png
Binary files differdiff --git a/structs/star.go b/structs/star.go
new file mode 100644
index 0000000..72afc00
--- /dev/null
+++ b/structs/star.go
@@ -0,0 +1,29 @@
+package structs
+
+import "C"
+
+type Star2D struct {
+	C Vec2    // coordinates of the star
+	V Vec2    // velocity    of the star
+	M float64 // mass        of the star
+}
+
+func (s *Star2D) Copy() Star2D {
+	return Star2D{s.C.Copy(), s.V.Copy(), s.M}
+}
+
+// accelerate the star with the acceleration a for the time t
+func (s *Star2D) AccelerateVelocity(a Vec2, t float64) {
+	s.V = s.V.Add(a.Multiply(t))
+}
+
+// move the star with it's velocity for the time t
+func (s *Star2D) Move(t float64) {
+	s.C = s.C.Add(s.V.Multiply(t))
+}
+
+// accelerate and move the star with it's velocity and the acceleration a for the time t
+func (s *Star2D) Accelerate(a Vec2, t float64) {
+	s.AccelerateVelocity(a, t)
+	s.Move(t)
+}
diff --git a/structs/structs.go b/structs/structs.go
deleted file mode 100644
index ed70a84..0000000
--- a/structs/structs.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package structs
-
-/*
-	The structs package defines structs that are used to store information that is used for processing
-	star related data.
-*/
-
-// Force struct soring a force vector
-type Force struct {
-	X, Y float64
-}
-
-// Coord struct storing coordinates
-type Coord struct {
-	X, Y float64
-}
-
-// Star struct storing all necessary star information
-type Star2D struct {
-	C    Coord
-	F    Force
-	Mass float64
-}
diff --git a/structs/vector2D.go b/structs/vector2D.go
new file mode 100644
index 0000000..47e457f
--- /dev/null
+++ b/structs/vector2D.go
@@ -0,0 +1,63 @@
+package structs
+
+import (
+	"math"
+)
+
+type Vec2 struct {
+	X, Y float64
+}
+
+// creates a copy of the vector
+func (v *Vec2) Copy() Vec2 {
+	return Vec2{v.X, v.Y}
+}
+
+func (v *Vec2) Split() (x float64, y float64) {
+	return v.X, v.Y
+}
+
+// changes the length of the vector to the length l
+func (v *Vec2) SetLength(l float64) {
+	var k = l / v.GetLength()
+	var newV = v.Multiply(k)
+	//	v = newV
+	v.X, v.Y = newV.Split()
+}
+
+// changes the length of the vector to the length 1
+func (v *Vec2) SetLengthOne() {
+	v.SetLength(1)
+}
+
+// returns the direction Vector of this vector. This means a copy of this vector with a length of 1
+func (v *Vec2) GetDirVector() Vec2 {
+	var dirV = v.Copy()
+	dirV.SetLengthOne()
+	return dirV
+}
+
+// returns the length of the vector
+func (v *Vec2) GetLength() float64 {
+	return math.Sqrt(math.Pow(v.X, 2) + math.Pow(v.Y, 2))
+}
+
+// returns the product of the vector and a scalar s
+func (v *Vec2) Multiply(s float64) Vec2 {
+	return Vec2{v.X * s, v.Y * s}
+}
+
+// returns the quotient of the vector and a scalar s
+func (v *Vec2) Divide(s float64) Vec2 {
+	return Vec2{v.X / s, v.Y / s}
+}
+
+// returns the sum of this vector and the vector v2
+func (v1 *Vec2) Add(v2 Vec2) Vec2 {
+	return Vec2{v1.X + v2.X, v1.Y + v2.Y}
+}
+
+// returns the difference of this vector minus the vector v2
+func (v1 *Vec2) Subtract(v2 Vec2) Vec2 {
+	return Vec2{v1.X - v2.X, v1.Y - v2.Y}
+}