about summary refs log tree commit diff
diff options
context:
space:
mode:
authorArun Isaac2021-03-16 15:01:45 +0530
committerArun Isaac2021-03-16 15:16:37 +0530
commit30104d8ee20733cf4e2195ef9a6cd202a7a257e5 (patch)
treed79c075e5091992a2c57d54d64f84d19b339e3c0
parentb90b54cd3f8d9242ff6d1189e65eaff7212fe44e (diff)
downloadnsmc-30104d8ee20733cf4e2195ef9a6cd202a7a257e5.tar.gz
nsmc-30104d8ee20733cf4e2195ef9a6cd202a7a257e5.tar.lz
nsmc-30104d8ee20733cf4e2195ef9a6cd202a7a257e5.zip
Deal in solid angle fractions, not absolute solid angles.
* src/extent-sampling.sc (volume-cone): Use
solid-angle-fraction->planar-angle instead of
solid-angle->planar-angle.
* src/nd-random.sc (planar-angle->solid-angle): Rename to
planar-angle->solid-angle-fraction and return a solid angle fraction.
(solid-angle->planar-angle): Rename to
solid-angle-fraction->planar-angle and accept a solid angle fraction.
(hollow-cone-random-vector): Use planar-angle->solid-angle-fraction
instead of planar-angle->solid-angle.
(beta-inc-unnormalized, incomplete-wallis-integral): Delete functions.
* include/nd-random.h (planar_angle_to_solid_angle): Rename to
planar_angle_to_solid_angle_fraction.
(solid_angle_to_planar_angle): Rename to
solid_angle_fraction_to_planar_angle.
* scm/nsmc/wrap.scm (planar-angle->solid-angle): Rename to
planar-angle->solid-angle-fraction.
-rw-r--r--include/nd-random.h4
-rw-r--r--scm/nsmc/wrap.scm4
-rw-r--r--src/extent-sampling.sc4
-rw-r--r--src/nd-random.sc56
4 files changed, 31 insertions, 37 deletions
diff --git a/include/nd-random.h b/include/nd-random.h
index 9755e57..3d3c298 100644
--- a/include/nd-random.h
+++ b/include/nd-random.h
@@ -30,7 +30,7 @@ void random_direction_vector (const gsl_rng* r, gsl_vector* x);
 void cone_random_vector (const gsl_rng* r, const gsl_vector* mean, double theta_max, gsl_vector* x);
 void hollow_cone_random_vector (const gsl_rng* r, const gsl_vector* mean, double theta_min, double theta_max, gsl_vector* x);
 
-double planar_angle_to_solid_angle (double planar_angle, unsigned int dimension);
-double solid_angle_to_planar_angle (double solid_angle, unsigned int dimension);
+double planar_angle_to_solid_angle_fraction (double planar_angle, unsigned int dimension);
+double solid_angle_fraction_to_planar_angle (double solid_angle, unsigned int dimension);
 
 #endif
diff --git a/scm/nsmc/wrap.scm b/scm/nsmc/wrap.scm
index 6ae4089..3e94192 100644
--- a/scm/nsmc/wrap.scm
+++ b/scm/nsmc/wrap.scm
@@ -64,9 +64,9 @@
                       (dynamic-func "angle_between_vectors" lib-nsmc)
                       (list '* '*)))
 
-(define-public planar-angle->solid-angle
+(define-public planar-angle->solid-angle-fraction
   (pointer->procedure double
-                      (dynamic-func "planar_angle_to_solid_angle" lib-nsmc)
+                      (dynamic-func "planar_angle_to_solid_angle_fraction" lib-nsmc)
                       (list double int)))
 
 ;; Random state
diff --git a/src/extent-sampling.sc b/src/extent-sampling.sc
index 48e6544..73f0e3d 100644
--- a/src/extent-sampling.sc
+++ b/src/extent-sampling.sc
@@ -142,8 +142,8 @@
   (declare volume double)
   (let* ((dimension (unsigned int) (: mean size))
          (vn double (ln-volume-of-ball dimension))
-         (theta-min double (solid-angle->planar-angle (* omega-min (surface-area-of-ball dimension)) dimension))
-         (theta-max double (solid-angle->planar-angle (* omega-max (surface-area-of-ball dimension)) dimension)))
+         (theta-min double (solid-angle-fraction->planar-angle omega-min dimension))
+         (theta-max double (solid-angle-fraction->planar-angle omega-max dimension)))
     (with-rstats stats
       (with-vector x dimension
         (for-i i number-of-samples
diff --git a/src/nd-random.sc b/src/nd-random.sc
index 7044758..79f6cde 100644
--- a/src/nd-random.sc
+++ b/src/nd-random.sc
@@ -60,51 +60,45 @@ sphere. Write the result to X."
                                            (* a (- mun 1))))
                                  b)))))))))
 
-(define (beta-inc-unnormalized a b x) ((static double) double double double)
-  (return (* (gsl-sf-beta-inc a b x)
-             (gsl-sf-beta a b))))
-
-(define (incomplete-wallis-integral theta m) ((static double) double (unsigned int))
-  "Return the incomplete Wallis integral \\int_0^\\theta \\sin^m x
-dx. THETA should be in [0,pi]."
-  (cond
-   ((or (< theta 0) (> theta M-PI))
-    (GSL-ERROR "Incomplete Wallis integral only allows theta in [0,pi]" GSL-EDOM))
-   ((< theta M-PI-2)
-    (return (/ (beta-inc-unnormalized (* 0.5 (+ m 1)) 0.5 (gsl-pow-2 (sin theta)))
-               2)))
-   (else
-    (return (/ (+ (gsl-sf-beta (* 0.5 (+ m 1)) 0.5)
-                  (beta-inc-unnormalized 0.5 (* 0.5 (+ m 1)) (gsl-pow-2 (cos theta))))
-               2)))))
-
-(define (planar-angle->solid-angle planar-angle dimension) (double double (unsigned int))
-  (return (/ (* 2
-                (pow M-PI (* 0.5 (- dimension 1)))
-                (incomplete-wallis-integral planar-angle (- dimension 2)))
-             (gsl-sf-gamma (* 0.5 (- dimension 1))))))
+(define (planar-angle->solid-angle-fraction theta dimension)
+  (double double (unsigned int))
+  (let* ((alpha double (* 0.5 (- dimension 1)))
+         (beta double 0.5)
+         (x double (gsl-pow-2 (sin theta))))
+    (cond
+     ((or (< theta 0) (> theta M-PI))
+      (GSL-ERROR "planar-angle->solid-angle-fraction only allows theta in [0,pi]" GSL-EDOM))
+     ;; gsl-sf-beta-inc underflows when x = 0. Work around that. TODO:
+     ;; Fix it upstream in gsl.
+     ((< (rerror theta M-PI) DBL-EPSILON)
+      (return 1))
+     ((< theta M-PI-2)
+      (return (* 0.5 (gsl-sf-beta-inc alpha beta x))))
+     (else
+      (return (- 1 (* 0.5 (gsl-sf-beta-inc alpha beta x))))))))
 
-(define (solid-angle->planar-angle solid-angle dimension) (double double (unsigned int))
+(define (solid-angle-fraction->planar-angle solid-angle-fraction dimension)
+  (double double (unsigned int))
   (define (f planar-angle params) (double double void*)
-    (return (- (planar-angle->solid-angle planar-angle dimension)
-               solid-angle)))
+    (return (- (planar-angle->solid-angle-fraction planar-angle dimension)
+               solid-angle-fraction)))
 
   (declare gsl-f (struct-variable gsl-function (function (address-of f))))
   ;; TODO: Equality comparisons to floating point values may be
   ;; problematic. Fix it.
   (cond
-   ((= solid-angle 0) (return 0))
-   ((= solid-angle (surface-area-of-ball dimension)) (return M-PI))
+   ((= solid-angle-fraction 0) (return 0))
+   ((= solid-angle-fraction 1) (return M-PI))
    (else (return (bisection (address-of gsl-f) 0 M-PI)))))
 
 (define (hollow-cone-random-vector r mean theta-min theta-max x)
   (void (const gsl-rng*) (const gsl-vector*) double double gsl-vector*)
   ;; Generate random vector around the nth canonical basis vector.
   (let* ((n size-t (: x size))
-         (theta double (solid-angle->planar-angle
+         (theta double (solid-angle-fraction->planar-angle
                         (gsl-ran-flat r
-                                      (planar-angle->solid-angle theta-min n)
-                                      (planar-angle->solid-angle theta-max n))
+                                      (planar-angle->solid-angle-fraction theta-min n)
+                                      (planar-angle->solid-angle-fraction theta-max n))
                         n)))
     (gsl-ran-dir-nd r (- n 1) (: x data))
     (gsl-vector-scale x (sin theta))