1
#!/usr/bin/env racket
#lang racket

;; racket-nbody.rkt
;; NBODY in Racket programming language. Columned version.
;; compile: $ raco exe racket-nbody.rkt
;;     run: $ ./racket-nbody <n-iterations>
;;
;; unsafe-flvector-* is hot-hot-hot
;;

(module energy racket
  (provide take-energy)
  (require (only-in racket/math pi)
           racket/flonum
           racket/fixnum
           racket/unsafe/ops)

  (define-syntax (define-constant stx)
    (syntax-case stx () [(_ name constvalue)
                         (syntax (define-syntax (name s)
                                   (syntax-case s () (_ (identifier? #'name)  (syntax constvalue)))))]))

  (define-constant SOLAR-MASS (* 4 pi pi))
  (define-constant DAYS-PER-YEAR 365.24)
  (define-syntax-rule (dpe v) (* v DAYS-PER-YEAR))
  (define-syntax-rule (slr m) (* m SOLAR-MASS))
  (define-syntax-rule (fx1+ v) (fx+ v 1))
  (define-syntax-rule (fx1- v) (fx- v 1))
  (define-syntax-rule (fxzero? v) (fx= v 0))
  (define-syntax-rule (^2 x) (fl* x x))
  (define-syntax sum^2 (syntax-rules () ((_ x y z) (fl+ (^2 x) (^2 y) (^2 z)))))

  (define-syntax-rule (dsqt x) (let ((v x))(fl* v (flsqrt v))))
  (define-syntax-rule (dotimes n body ...) (do ((i_ (fx+ n 0) (fx1- i_)))((fxzero? i_)) body ...))
  (define-syntax subn! (syntax-rules () ((_ what withs) (set! what (fl- what withs)))))
  (define-syntax addn! (syntax-rules () ((_ what withs) (set! what (fl+ what withs)))))
  (define-constant body-size 7)
  (define bodies
    (flvector
     SOLAR-MASS 0.0 0.0 0.0 0.0 0.0 0.0
     (slr 9.54791938424326609e-04) 4.84143144246472090e+00 -1.16032004402742839e+00 -1.03622044471123109e-01 (dpe 1.66007664274403694e-03) (dpe 7.69901118419740425e-03) (dpe -6.90460016972063023e-05)
     (slr 2.85885980666130812e-04) 8.34336671824457987e+00 4.12479856412430479e+00 -4.03523417114321381e-01 (dpe -2.76742510726862411e-03) (dpe 4.99852801234917238e-03) (dpe 2.30417297573763929e-05)
     (slr 4.36624404335156298e-05) 1.28943695621391310e+01 -1.51111514016986312e+01 -2.23307578892655734e-01 (dpe 2.96460137564761618e-03) (dpe 2.37847173959480950e-03) (dpe -2.96589568540237556e-05)
     (slr 5.15138902046611451e-05) 1.53796971148509165e+01 -2.59193146099879641e+01 1.79258772950371181e-01 (dpe 2.68067772490389322e-03) (dpe 1.62824170038242295e-03) (dpe -9.51592254519715870e-05)
     ))
  (define n-body (fxquotient (flvector-length bodies) body-size))
  (define-syntax-rule (mkcol n) (for/flvector ((i (in-range 0 n-body) ))
                                  (flvector-ref bodies (+ n (* i body-size)))))

  (define-syntax (let-thval stx)
    (syntax-case stx ()
      [(_ ((a ix col) ...) body ...)
       #'(let-syntax ((a (make-set!-transformer
                          (lambda (stx)
                            (syntax-case stx (set!)
                              [a (identifier? (syntax a)) (syntax (unsafe-flvector-ref col ix))]
                              [(set! a val) (syntax (unsafe-flvector-set! col ix val))])))) ...)
           body ...)]))

  (define-syntax let-getset
    (syntax-rules ()
      [(_ ((a ix col) ...) body ...)
       (let-syntax ((a (syntax-rules ()
                         ((a op delta)
                          (unsafe-flvector-set!
                           col ix (op (unsafe-flvector-ref col ix) delta))))) ...)
         body ...)]))


  (define (take-energy n)
    (define-values (mass-vec x-vec y-vec z-vec vx-vec vy-vec vz-vec)
      (values (mkcol 0) (mkcol 1) (mkcol 2) (mkcol 3) (mkcol 4) (mkcol 5) (mkcol 6)))

    (define-constant dt 0.01)
    (define E 0.0)

    (dotimes
     n
     (do ((i 0 (fx1+ i)))
         ((fx= i n-body))
       (do ((j (fx1+ i) (fx1+ j)))
           ((fx= j n-body))
         (let-thval
          ((mass_i i mass-vec)
           (mass_j j mass-vec)
           (Xi i x-vec) (Yi i y-vec) (Zi i z-vec) (Xj j x-vec) (Yj j y-vec) (Zj j z-vec))
          (let-getset
           ((VXi i vx-vec)
            (VYi i vy-vec)
            (VZi i vz-vec)
            (VXj j vx-vec)
            (VYj j vy-vec)
            (VZj j vz-vec))
           (let* ((dx (fl- Xi Xj))
                  (dy (fl- Yi Yj))
                  (dz (fl- Zi Zj))
                  (mag (fl/ dt (dsqt (sum^2 dx dy dz)))))
             (VXi fl- (fl* dx mass_j mag))
             (VYi fl- (fl* dy mass_j mag))
             (VZi fl- (fl* dz mass_j mag))
             (VXj fl+ (fl* dx mass_i mag))
             (VYj fl+ (fl* dy mass_i mag))
             (VZj fl+ (fl* dz mass_i mag))
             )))))
     (do ((i 0 (fx1+ i)))
         ((fx= i n-body))
       (let-thval
        ((VX i vx-vec) (VY i vy-vec) (VZ i vz-vec))
        (let-getset
         ((X i x-vec)(Y i y-vec) (Z i z-vec))
         (X fl+ (fl* dt VX))
         (Y fl+ (fl* dt VY))
         (Z fl+ (fl* dt VZ))
         )))
     )

    (do ((i 0 (fx1+ i)))
        ((fx= i n-body))
      (let-thval
       ((mass_i i mass-vec)
        (VX i vx-vec)
        (VY i vy-vec)
        (VZ i vz-vec))
       (addn! E (fl* 0.5 mass_i (sum^2 VX VY VZ)))
      (do ((j (fx1+ i) (fx1+ j)))
          ((fx= j n-body))
        (let-thval
         ((Xi i x-vec) (Yi i y-vec) (Zi i z-vec)
          (Xj j x-vec) (Yj j y-vec) (Zj j z-vec) (mass_j j mass-vec))
         (subn! E (fl/ (fl* mass_i mass_j)
                       (flsqrt (sum^2 (fl- Xi Xj)
                                      (fl- Yi Yj)
                                      (fl- Zi Zj)))))))))
    E
    )
) ;; end-of-module energy

(require 'energy)
(provide (all-from-out 'energy))

;; (require (only-in 'energy take-energy))

(module* main #f
  (define-syntax-rule (->sec from to) (* 1e-3 (- from to)))
  (define (test n)
    (let* ((st (current-inexact-milliseconds))
           (e (take-energy n))
           (et (current-inexact-milliseconds)))
      (printf "~a  per ~a sec ~%" (~r e #:precision 9)
              (~r (->sec et st) #:precision 3))))
  (command-line
   #:program "racket-nbody"
   #:args args
   (cond ((pair? args) (test (string->number (car args))))
         #;(else (take-energy 100000))
         (else (printf "Usage: ~a <n-iterations>~%" "nbody"))))
)

For immediate assistance, please email our customer support: [email protected]

Download RAW File