n-body Pharo Smalltalk program
source code
"* The Computer Language Benchmarks Game
https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
contributed by Isaac Gouy *"!
Object subclass: #NBodySystem
instanceVariableNames: 'bodies'
classVariableNames: ''
poolDictionaries: ''
category: 'benchmarks game'!
Object subclass: #Body
instanceVariableNames: 'x y z vx vy vz mass'
classVariableNames: ''
poolDictionaries: ''
category: 'benchmarks game'!
Object subclass: #BenchmarksGame
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'benchmarks game'!
!Body class methodsFor: 'constants'!
daysPerYear
^365.24d0!
sun
^self new
x: 0.0d0
y: 0.0d0
z: 0.0d0
vx: 0.0d0
vy: 0.0d0
vz: 0.0d0
mass: self solarMass!
uranus
^self new
x: 1.28943695621391310d1
y: -1.51111514016986312d1
z: -2.23307578892655734d-1
vx: 2.96460137564761618d-3 * self daysPerYear
vy: 2.37847173959480950d-3 * self daysPerYear
vz: -2.96589568540237556d-5 * self daysPerYear
mass: 4.36624404335156298d-5 * self solarMass!
saturn
^self new
x: 8.34336671824457987d0
y: 4.12479856412430479d0
z: -4.03523417114321381d-1
vx: -2.76742510726862411d-3 * self daysPerYear
vy: 4.99852801234917238d-3 * self daysPerYear
vz: 2.30417297573763929d-5 * self daysPerYear
mass: 2.85885980666130812d-4 * self solarMass!
solarMass
^4.0d0 * self pi * self pi!
pi
^3.141592653589793d0!
jupiter
^self new
x: 4.84143144246472090d0
y: -1.16032004402742839d0
z: -1.03622044471123109d-1
vx: 1.66007664274403694d-3 * self daysPerYear
vy: 7.69901118419740425d-3 * self daysPerYear
vz: -6.90460016972063023d-5 * self daysPerYear
mass: 9.54791938424326609d-4 * self solarMass!
neptune
^self new
x: 1.53796971148509165d1
y: -2.59193146099879641d1
z: 1.79258772950371181d-1
vx: 2.68067772490389322d-3 * self daysPerYear
vy: 1.62824170038242295d-3 * self daysPerYear
vz: -9.51592254519715870d-5 * self daysPerYear
mass: 5.15138902046611451d-5 * self solarMass! !
!Body methodsFor: 'accessing'!
z
^z!
x
^x!
mass
^mass!
x: d1 y: d2 z: d3 vx: d4 vy: d5 vz: d6 mass: d7
x := d1.
y := d2.
z := d3.
vx := d4.
vy := d5.
vz := d6.
mass := d7!
y
^y! !
!Body methodsFor: 'nbody'!
offsetMomentum: anArray
| m |
m := self class solarMass.
vx := (anArray at: 1) negated / m.
vy := (anArray at: 2) negated / m.
vz := (anArray at: 3) negated / m!
decreaseVelocity: dx y: dy z: dz m: m
vx := vx - (dx * m).
vy := vy - (dy * m).
vz := vz - (dz * m)!
positionAfter: dt
x := x + (dt * vx).
y := y + (dt * vy).
z := z + (dt * vz)!
and: aBody velocityAfter: dt
| dx dy dz distance mag |
dx := x - aBody x.
dy := y - aBody y.
dz := z - aBody z.
distance := ((dx*dx) + (dy*dy) + (dz*dz)) sqrt.
mag := dt / (distance * distance * distance).
self decreaseVelocity: dx y: dy z: dz m: aBody mass * mag.
aBody increaseVelocity: dx y: dy z: dz m: mass * mag!
potentialEnergy: aBody
| dx dy dz distance |
dx := x - aBody x.
dy := y - aBody y.
dz := z - aBody z.
distance := ((dx*dx) + (dy*dy) + (dz*dz)) sqrt.
^mass * aBody mass / distance!
addMomentumTo: anArray
anArray at: 1 put: (anArray at: 1) + (vx * mass).
anArray at: 2 put: (anArray at: 2) + (vy * mass).
anArray at: 3 put: (anArray at: 3) + (vz * mass).
^anArray!
increaseVelocity: dx y: dy z: dz m: m
vx := vx + (dx * m).
vy := vy + (dy * m).
vz := vz + (dz * m)!
kineticEnergy
^0.5d0 * mass * ((vx * vx) + (vy * vy) + (vz * vz))! !
!NBodySystem methodsFor: 'initialize-release'!
initialize
bodies := OrderedCollection new
add: Body sun; add: Body jupiter; add: Body saturn;
add: Body uranus; add: Body neptune; yourself.
bodies first offsetMomentum:
(bodies inject: (Array with: 0.0d0 with: 0.0d0 with: 0.0d0)
into: [:m :each | each addMomentumTo: m])! !
!NBodySystem methodsFor: 'nbody'!
after: dt
1 to: bodies size do: [:i|
i+1 to: bodies size do: [:j|
(bodies at: i) and: (bodies at: j) velocityAfter: dt].
].
bodies do: [:each| each positionAfter: dt]!
energy
| e |
e := 0.0d0.
1 to: bodies size do: [:i|
e := e + (bodies at: i) kineticEnergy.
i+1 to: bodies size do: [:j|
e := e - ((bodies at: i) potentialEnergy: (bodies at: j))].
].
^e! !
!BenchmarksGame class methodsFor: 'initialize-release'!
do: n
| bodies |
bodies := NBodySystem new initialize.
Stdio stdout print: bodies energy digits: 9; nl.
n timesRepeat: [bodies after: 0.01d0].
Stdio stdout print: bodies energy digits: 9; nl! !
!StdioStream methodsFor: 'benchmarks game'!
nl
self nextPut: Character lf!
print: number digits: decimalPlaces
| precision rounded |
decimalPlaces <= 0 ifTrue: [^ number rounded printString].
precision := (10 raisedTo: decimalPlaces negated) asFloat.
rounded := number roundTo: precision.
self nextPutAll:
((rounded asScaledDecimal: decimalPlaces) printString copyUpTo: $s)! !
notes, command-line, and program output
NOTES:
64-bit Ubuntu quad core
Pharo 12.0.0
Pharo-12.0.0+SNAPSHOT.build.1507.sha.
a4f8da8972214b9c9c39c33e826394a109911041 (64 Bit)
Compiler: 5.4.0 20160609
Wed, 29 May 2024 02:46:20 GMT
MAKE:
cp /opt/src/pharo-vm-Linux-x86_64-stable/Pharo12.0-SNAPSHOT-64bit-a4f8da8.image nbody.pharo_run.image
cp /opt/src/pharo-vm-Linux-x86_64-stable/Pharo12.0-SNAPSHOT-64bit-a4f8da8.changes nbody.pharo_run.changes
ln -s /opt/src/pharo-vm-Linux-x86_64-stable/Pharo12.0-64bit-a4f8da8.sources .
cat Include/pharo/make.st
| prog |
(SystemWindow windowsIn: World
satisfying: [:w | w model canDiscardEdits])
do: [:w | w delete].
"load program to be measured"
prog := Smalltalk getSystemAttribute: 3.
(prog notNil) ifTrue: [prog asFileReference fileIn].
ImageCleaner cleanUpForRelease.
Smalltalk garbageCollect.
SmalltalkImage current snapshot: true andQuit: true.
/opt/src/pharo-vm-Linux-x86_64-stable/pharo --headless nbody.pharo_run.image Include/pharo/make.st nbody.pharo
cat Include/pharo/main.st
BenchmarksGame do: (Smalltalk getSystemAttribute: 3) asInteger.!
SmalltalkImage current snapshot: false andQuit: true!
33.01s to complete and log all make actions
COMMAND LINE:
/opt/src/pharo-vm-Linux-x86_64-stable/pharo --headless nbody.pharo_run.image Include/pharo/main.st 50000000
PROGRAM OUTPUT:
-0.169075164
-0.169059907