Beispiel #1
0
// TimeStepParallel does the same as TimeStep but with channels
func TimeStepParallel(R, V [][3]float64, L, M, h float64) ([][3]float64, [][3]float64) {
	N := len(R)
	A := make([][3]float64, N)
	nR := make([][3]float64, N)
	nV := make([][3]float64, N)
	c := make(chan ForceReturn, N)
	for i := 0; i < N; i++ {
		go InternalForceParallel(i, R, L, c)
	}
	for n := 0; n < N; n++ {
		info := <-c
		i := info.i
		Fi := info.F
		A[i] = vector.Scale(Fi, 1.0/M)
		nR[i] = space.PutInBox(verlet.NextR(R[i], V[i], A[i], h), L)
	}
	for i := 0; i < N; i++ {
		go InternalForceParallel(i, nR, L, c)
	}
	for n := 0; n < N; n++ {
		info := <-c
		i := info.i
		nFi := info.F
		nAi := vector.Scale(nFi, 1.0/M)
		nV[i] = verlet.NextV(V[i], A[i], nAi, h)
	}
	return nR, nV
}
Beispiel #2
0
// InitPositionFCC initializes particle positions in a face-centered cubic configuration
func InitPositionFCC(N int, L float64) [][3]float64 {
	R := make([][3]float64, N)
	Ncube := 1
	for N > 4*Ncube*Ncube*Ncube {
		Ncube++
	}
	o := -L / 2
	origin := [3]float64{o, o, o}
	rs := L / float64(Ncube)
	roffset := rs / 2
	i := 0
	for x := 0; x < Ncube; x++ {
		x := float64(x)
		for y := 0; y < Ncube; y++ {
			y := float64(y)
			for z := 0; z < Ncube; z++ {
				z := float64(z)
				pos := vector.Scale([3]float64{x, y, z}, rs)
				pos = vector.Sum(pos, origin)
				R[i] = pos
				i++
				R[i] = vector.Sum(pos, [3]float64{roffset, roffset, 0})
				i++
				R[i] = vector.Sum(pos, [3]float64{roffset, 0, roffset})
				i++
				R[i] = vector.Sum(pos, [3]float64{0, roffset, roffset})
				i++
			}
		}
	}
	return R
}
Beispiel #3
0
// TimeStep evolves the system by one unit of time using the Velocity Verlet algorithm for molecular dynamics.
func TimeStep(R, V [][3]float64, L, M, h float64) ([][3]float64, [][3]float64) {
	N := len(R)
	A := make([][3]float64, N)
	nR := make([][3]float64, N)
	nV := make([][3]float64, N)
	for i := 0; i < N; i++ {
		Fi := InternalForce(i, R, L)
		A[i] = vector.Scale(Fi, 1.0/M)
		nR[i] = space.PutInBox(verlet.NextR(R[i], V[i], A[i], h), L)
	}
	for i := 0; i < N; i++ {
		nFi := InternalForce(i, nR, L)
		nAi := vector.Scale(nFi, 1.0/M)
		nV[i] = verlet.NextV(V[i], A[i], nAi, h)
	}
	return nR, nV
}
Beispiel #4
0
// PairwiseLennardJonesForce calculates the force vector on particle Ri due to Rj using the Lennard Jones potential.
func PairwiseLennardJonesForce(Ri, Rj [3]float64, L float64) [3]float64 {
	if space.PointsAreEqual(Ri, Rj, L) {
		panic(fmt.Sprintf("%v and %v are equal, the pairwise force is infinite", Ri, Rj))
	}
	r := space.Displacement(Ri, Rj, L)
	magR := vector.Length(r)
	f := 4 * (-12*math.Pow(magR, -13) + 6*math.Pow(magR, -7))
	return vector.Scale(r, f/magR)
}
Beispiel #5
0
// InitVelocity initializes particle velocities selected from a random distribution.
// Ensures that the net momentum of the system is zero and scales the average kinetic energy to match a given temperature.
func InitVelocity(N int, T0 float64, M float64) [][3]float64 {
	V := make([][3]float64, N)
	rand.Seed(1)
	netP := [3]float64{0, 0, 0}
	netE := 0.0
	for n := 0; n < N; n++ {
		for i := 0; i < 3; i++ {
			newP := rand.Float64() - 0.5
			netP[i] += newP
			netE += newP * newP
			V[n][i] = newP
		}
	}
	netP = vector.Scale(netP, 1.0/float64(N))
	vscale := math.Sqrt(3.0 * float64(N) * T0 / (M * netE))
	for i, v := range V {
		correctedV := vector.Scale(vector.Difference(v, netP), vscale)
		V[i] = correctedV
	}
	return V
}
Beispiel #6
0
// InitPositionCubic initializes particle positions in a simple cubic configuration.
func InitPositionCubic(N int, L float64) [][3]float64 {
	R := make([][3]float64, N)
	Ncube := 1
	for N > Ncube*Ncube*Ncube {
		Ncube++
	}
	rs := L / float64(Ncube)
	roffset := (L - rs) / 2
	i := 0
	for x := 0; x < Ncube; x++ {
		x := float64(x)
		for y := 0; y < Ncube; y++ {
			y := float64(y)
			for z := 0; z < Ncube; z++ {
				z := float64(z)
				pos := vector.Scale([3]float64{x, y, z}, rs)
				offset := [3]float64{roffset, roffset, roffset}
				R[i] = vector.Difference(pos, offset)
				i++
			}
		}
	}
	return R
}
Beispiel #7
0
// NextR calculates the next position vector based on current position, velocity, and acceleration.
func NextR(r, v, a [3]float64, h float64) [3]float64 {
	return vector.Sum(vector.Sum(r, vector.Scale(v, h)), vector.Scale(a, 0.5*h*h))
}
Beispiel #8
0
// NextV calculates the next velocity vector based on current velocity and acceleration and future acceleration.
func NextV(v, a1, a2 [3]float64, h float64) [3]float64 {
	return vector.Sum(v, vector.Scale(vector.Sum(a1, a2), 0.5*h))
}