Skip to content
Snippets Groups Projects
Commit d5480423 authored by Matthieu Schaller's avatar Matthieu Schaller
Browse files

Merge branch 'fix_random_cone_test' into 'master'

Fix random cone test

Closes #870

See merge request !1793
parents f5da7045 e82d2ee9
No related branches found
No related tags found
1 merge request!1793Fix random cone test
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
******************************************************************************/ ******************************************************************************/
#include <config.h> #include <config.h>
/* System includes. */
#include <fenv.h>
/* Local headers. */ /* Local headers. */
#include "swift.h" #include "swift.h"
...@@ -47,10 +50,9 @@ const int N_cube = 5; ...@@ -47,10 +50,9 @@ const int N_cube = 5;
* the uniformity of the distribution. * the uniformity of the distribution.
* @param tolerance The tolerance of each bin relative to the expected value. * @param tolerance The tolerance of each bin relative to the expected value.
*/ */
void test_cone(int64_t id_bh, const integertime_t ti_current, float test_cone(int64_t id_bh, const integertime_t ti_current,
const enum random_number_type type, double opening_angle, const enum random_number_type type, double opening_angle,
float unit_vector[3], const int N_test, const int N_bins, float unit_vector[3]) {
const double tolerance) {
/* Compute cosine that corresponds to the maximum opening angle */ /* Compute cosine that corresponds to the maximum opening angle */
const double cos_theta_max = cos(opening_angle); const double cos_theta_max = cos(opening_angle);
...@@ -58,56 +60,41 @@ void test_cone(int64_t id_bh, const integertime_t ti_current, ...@@ -58,56 +60,41 @@ void test_cone(int64_t id_bh, const integertime_t ti_current,
/* Initialize an array that will hold a random vector every step */ /* Initialize an array that will hold a random vector every step */
float rand_vector[3]; float rand_vector[3];
/* Initialize an array that will hold the binned number of drawn cosines, /* Generate a random unit vector within a cone around unit_vector */
i.e. this is the probability density function that we wish to test. */ random_direction_in_cone(id_bh, ti_current, type, opening_angle, unit_vector,
double binned_cosines[N_bins]; rand_vector);
for (int j = 0; j < N_bins; ++j) {
binned_cosines[j] = 0.; /* Check that this vector is actually within the cone we want */
const double cos_rand_unit = rand_vector[0] * unit_vector[0] +
rand_vector[1] * unit_vector[1] +
rand_vector[2] * unit_vector[2];
if (cos_rand_unit < 0.99999 * cos_theta_max) {
printf("Cos_opening_angle is: %f, Random cos is: %f\n", cos_theta_max,
cos_rand_unit);
error("Generated random unit vector is outside cone.");
} }
for (int k = 0; k < N_test; ++k) { return cos_rand_unit;
}
/* Generate a random unit vector within a cone around unit_vector */ int main(int argc, char *argv[]) {
random_direction_in_cone(id_bh, ti_current, type, opening_angle,
unit_vector, rand_vector);
/* Check that this vector is actually within the cone we want */
const double cos_rand_unit = rand_vector[0] * unit_vector[0] +
rand_vector[1] * unit_vector[1] +
rand_vector[2] * unit_vector[2];
if (cos_rand_unit < 0.99999 * cos_theta_max) {
printf("Cos_opening_angle is: %f, Random cos is: %f\n", cos_theta_max,
cos_rand_unit);
error("Generated random unit vector is outside cone.");
}
/* Add the unit vector to the probability density function array. The solid /* Initialize CPU frequency, this also starts time. */
* angle subtended by some angle theta grows as (1-cos(theta)). Furthermore, unsigned long long cpufreq = 0;
* we are limited to the spherical cap defined by the angles [0, theta_max]. clocks_set_cpufreq(cpufreq);
* Therefore the variable which we expect to be uniformly distributed is (1
* - cos(theta)) / (1 - cos(theta_max)). */
double uniform_variable = (1. - cos_rand_unit) / (1 - cos_theta_max);
for (int j = 0; j < N_bins; ++j) {
if ((uniform_variable > (double)j / (double)N_bins) &&
(uniform_variable < (double)(j + 1) / (double)N_bins)) {
binned_cosines[j] = binned_cosines[j] + 1. / (double)N_test;
}
}
}
/* Check whether the binned quantity is really uniformly distributed. If it /* Choke on FPEs */
* is, the density (value) of each bin should be 1/N_bin. */ #ifdef HAVE_FE_ENABLE_EXCEPT
for (int j = 0; j < N_bins; ++j) { feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
if ((binned_cosines[j] < (1. - tolerance) / (double)N_bins) || #endif
(binned_cosines[j] > (1. + tolerance) / (double)N_bins)) {
error(
"Generated distribution of random unit vectors within a cone exceeds "
"the limit imposed by the tolerance.");
}
}
}
int main(int argc, char *argv[]) { /* Get some randomness going */
const int seed = time(NULL);
message("Seed = %d", seed);
srand(seed);
/* Log the swift random seed */
message("SWIFT random seed = %d", SWIFT_RANDOM_SEED_XOR);
/* Test the random-vector-in-cone function, for different values of opening /* Test the random-vector-in-cone function, for different values of opening
* angle from 0 to pi/2 (in radians). For each of these opening angles we draw * angle from 0 to pi/2 (in radians). For each of these opening angles we draw
...@@ -132,15 +119,16 @@ int main(int argc, char *argv[]) { ...@@ -132,15 +119,16 @@ int main(int argc, char *argv[]) {
const double cos_unit = const double cos_unit =
random_unit_interval(id_bh, ti_current, random_number_BH_kick); random_unit_interval(id_bh, ti_current, random_number_BH_kick);
const double sin_unit = sqrtf(max(0., (1. - cos_unit) * (1. + cos_unit))); const double sin_unit = sqrtf(max(0., (1. - cos_unit) * (1. + cos_unit)));
const double phi_unit = random_unit_interval(id_bh * id_bh, ti_current, const double phi_unit =
random_number_BH_kick); (2. * M_PI) * random_unit_interval(id_bh * id_bh, ti_current,
random_number_BH_kick);
unit_vector[0] = sin_unit * cos(phi_unit); unit_vector[0] = sin_unit * cos(phi_unit);
unit_vector[1] = sin_unit * sin(phi_unit); unit_vector[1] = sin_unit * sin(phi_unit);
unit_vector[2] = cos_unit; unit_vector[2] = cos_unit;
/* Do the test. */ /* Do the test. */
test_cone(id_bh, ti_current, random_number_BH_kick, opening_angle, test_cone(id_bh, ti_current, random_number_BH_kick, opening_angle,
unit_vector, 100000, 10, 0.1); unit_vector);
} }
} }
...@@ -148,26 +136,72 @@ int main(int argc, char *argv[]) { ...@@ -148,26 +136,72 @@ int main(int argc, char *argv[]) {
* bins, but for just one opening angle and one randomly generated cone */ * bins, but for just one opening angle and one randomly generated cone */
const double opening_angle_0 = 0.2; const double opening_angle_0 = 0.2;
/* Generate an id for the bh and a time. We do this for every opening /* Compute cosine that corresponds to the maximum opening angle */
* angle and every cone. */ const double cos_theta_max = cos(opening_angle_0);
const long long id_bh_0 = rand() * (1LL << 31) + rand();
const integertime_t ti_current_0 = rand() * (1LL << 31) + rand();
/* Generate a random unit vector that defines a cone, along with the /* Generate a random unit vector that defines a cone, along with the
* opening angle. */ * opening angle. */
const long long id_bh_0 = rand() * (1LL << 31) + rand();
const integertime_t ti_current_0 = rand() * (1LL << 31) + rand();
float unit_vector_0[3]; float unit_vector_0[3];
const double cos_unit = const double cos_unit =
random_unit_interval(id_bh_0, ti_current_0, random_number_BH_kick); random_unit_interval(id_bh_0, ti_current_0, random_number_BH_kick);
const double sin_unit = sqrtf(max(0., (1. - cos_unit) * (1. + cos_unit))); const double sin_unit = sqrtf(max(0., (1. - cos_unit) * (1. + cos_unit)));
const double phi_unit = random_unit_interval(id_bh_0 * id_bh_0, ti_current_0, const double phi_unit =
random_number_BH_kick); (2. * M_PI) * random_unit_interval(id_bh_0 * id_bh_0, ti_current_0,
random_number_BH_kick);
unit_vector_0[0] = sin_unit * cos(phi_unit); unit_vector_0[0] = sin_unit * cos(phi_unit);
unit_vector_0[1] = sin_unit * sin(phi_unit); unit_vector_0[1] = sin_unit * sin(phi_unit);
unit_vector_0[2] = cos_unit; unit_vector_0[2] = cos_unit;
/* Do the test. */ /* Some parameters to test the uniformity of drawn vectors */
test_cone(id_bh_0, ti_current_0, random_number_BH_kick, opening_angle_0, int N_test = 10000000;
unit_vector_0, 100000000, 100, 0.01); int N_bins = 100;
float tolerance = 0.05;
/* Initialize an array that will hold the binned number of drawn cosines,
i.e. this is the probability density function that we wish to test. */
double binned_cosines[N_bins];
for (int j = 0; j < N_bins; ++j) {
binned_cosines[j] = 0.;
}
/* Draw N_test vectors and bin them to test uniformity */
for (int k = 0; k < N_test; ++k) {
const long long id_bh = rand() * (1LL << 31) + rand();
const integertime_t ti_current = rand() * (1LL << 31) + rand();
/* Do the test, with a newly generated BH id and time */
const float cos_rand_unit =
test_cone(id_bh, ti_current, random_number_BH_kick, opening_angle_0,
unit_vector_0);
/* Add the unit vector to the probability density function array. The solid
* angle subtended by some angle theta grows as (1-cos(theta)). Furthermore,
* we are limited to the spherical cap defined by the angles [0, theta_max].
* Therefore the variable which we expect to be uniformly distributed is (1
* - cos(theta)) / (1 - cos(theta_max)). */
double uniform_variable = (1. - cos_rand_unit) / (1 - cos_theta_max);
for (int j = 0; j < N_bins; ++j) {
if ((uniform_variable > (double)j / (double)N_bins) &&
(uniform_variable < (double)(j + 1) / (double)N_bins)) {
binned_cosines[j] = binned_cosines[j] + 1. / (double)N_test;
}
}
}
/* Check whether the binned quantity is really uniformly distributed. If it
* is, the density (value) of each bin should be 1/N_bin. */
for (int j = 0; j < N_bins; ++j) {
if ((binned_cosines[j] < (1. - tolerance) / (double)N_bins) ||
(binned_cosines[j] > (1. + tolerance) / (double)N_bins)) {
error(
"Generated distribution of random unit vectors within a cone exceeds "
"the limit imposed by the tolerance.");
}
}
/* We now repeat the same process, but we do not generate random unit vectors /* We now repeat the same process, but we do not generate random unit vectors
* to define the cones. Instead, we sample unit vectors along the grid * to define the cones. Instead, we sample unit vectors along the grid
...@@ -204,7 +238,7 @@ int main(int argc, char *argv[]) { ...@@ -204,7 +238,7 @@ int main(int argc, char *argv[]) {
/* Do the test. */ /* Do the test. */
test_cone(id_bh, ti_current, random_number_BH_kick, opening_angle, test_cone(id_bh, ti_current, random_number_BH_kick, opening_angle,
unit_vector, 100000, 10, 0.1); unit_vector);
} }
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment