/******************************************************************************* * This file is part of SWIFT. * Copyright (C) 2019 Folkert Nobels (nobels@strw.leidenuniv.nl) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * ******************************************************************************/ /* Config parameters. */ #include /* System includes. */ #include /* Local headers. */ #include "swift.h" /** * @brief Test to check that the pseodo-random numbers in SWIFT are random * enough for our purpose. * * @param argc Unused * @param argv Unused * @return 0 if everything is fine, 1 if random numbers are not random enough. */ int main(int argc, char* argv[]) { /* Initialize CPU frequency, this also starts time. */ unsigned long long cpufreq = 0; clocks_set_cpufreq(cpufreq); /* Choke on FPEs */ #ifdef HAVE_FE_ENABLE_EXCEPT feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); #endif /* 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); /* Time-step size */ const int time_bin = 33; const double boundary[6] = {1e-5, 1e-6, 1e-7, 1e-8, 1e-9, 1e-10}; int count[6] = {0}; unsigned long long int total = 0; /* Try a few different values for the ID */ for (int i = 0; i < 10; ++i) { const long long id = rand() * (1LL << 31) + rand(); const integertime_t increment = (1LL << time_bin); message("Testing id=%lld time_bin=%d", id, time_bin); /* Check that the numbers are uniform over the full-range of useful * time-steps */ for (integertime_t ti_current = 0LL; ti_current < max_nr_timesteps; ti_current += increment) { total += 1; ti_current += increment; const double r = random_unit_interval(id, ti_current, random_number_star_formation); /* Count the number of random numbers below the boundaries */ if (r < boundary[0]) count[0] += 1; if (r < boundary[1]) count[1] += 1; if (r < boundary[2]) count[2] += 1; if (r < boundary[3]) count[3] += 1; if (r < boundary[4]) count[4] += 1; if (r < boundary[5]) count[5] += 1; } /* Print counted number of random numbers below the boundaries */ message("Categories | %6.0e %6.0e %6.0e %6.0e %6.0e %6.0e", boundary[0], boundary[1], boundary[2], boundary[3], boundary[4], boundary[5]); message("total = %12lld | %6d %6d %6d %6d %6d %6d", total, count[0], count[1], count[2], count[3], count[4], count[5]); /* Calculate the expected amount of random numbers in this range */ double expected_result[6]; int expected_result_int[6]; expected_result[0] = total * boundary[0]; expected_result[1] = total * boundary[1]; expected_result[2] = total * boundary[2]; expected_result[3] = total * boundary[3]; expected_result[4] = total * boundary[4]; expected_result[5] = total * boundary[5]; expected_result_int[0] = (int)expected_result[0]; expected_result_int[1] = (int)expected_result[1]; expected_result_int[2] = (int)expected_result[2]; expected_result_int[3] = (int)expected_result[3]; expected_result_int[4] = (int)expected_result[4]; expected_result_int[5] = (int)expected_result[5]; /* Print the expected numbers */ message("expected | %6d %6d %6d %6d %6d %6d", expected_result_int[0], expected_result_int[1], expected_result_int[2], expected_result_int[3], expected_result_int[4], expected_result_int[5]); int std_expected_result[6]; /* Calculate the allowed standard error deviation the maximum of: * 1. the standard error of the expected number doing sqrt(N_expected) * 2. The standard error of the counted number doing sqrt(N_count) * 3. 1 to prevent low number statistics to crash for 1 while expected * close to zero. * * 1 and 2 are for large numbers essentially the same but for small numbers * it becomes imporatant (e.g. count=6 expected=.9, allowed 5+.9 so 6 * fails, but sqrt(6) ~ 2.5 so it should be fine) */ std_expected_result[0] = (int)max3(sqrt(expected_result[0]), 1, sqrt(count[0])); std_expected_result[1] = (int)max3(sqrt(expected_result[1]), 1, sqrt(count[1])); std_expected_result[2] = (int)max3(sqrt(expected_result[2]), 1, sqrt(count[2])); std_expected_result[3] = (int)max3(sqrt(expected_result[3]), 1, sqrt(count[3])); std_expected_result[4] = (int)max3(sqrt(expected_result[4]), 1, sqrt(count[4])); std_expected_result[5] = (int)max3(sqrt(expected_result[5]), 1, sqrt(count[5])); /* We want 5 sigma (can be changed if necessary) */ const int numb_sigma = 5; /* Print the differences and the 5 sigma differences */ message("Difference | %6d %6d %6d %6d %6d %6d", abs(expected_result_int[0] - count[0]), abs(expected_result_int[1] - count[1]), abs(expected_result_int[2] - count[2]), abs(expected_result_int[3] - count[3]), abs(expected_result_int[4] - count[4]), abs(expected_result_int[5] - count[5])); message("5 sigma difference | %6d %6d %6d %6d %6d %6d", numb_sigma * std_expected_result[0], numb_sigma * std_expected_result[1], numb_sigma * std_expected_result[2], numb_sigma * std_expected_result[3], numb_sigma * std_expected_result[4], numb_sigma * std_expected_result[5]); /* Fail if it is not within numb_sigma (5) of the expected difference. */ if (count[0] > expected_result_int[0] + numb_sigma * std_expected_result[0] || count[0] < expected_result_int[0] - numb_sigma * std_expected_result[0] || count[1] > expected_result_int[1] + numb_sigma * std_expected_result[1] || count[1] < expected_result_int[1] - numb_sigma * std_expected_result[1] || count[2] > expected_result_int[2] + numb_sigma * std_expected_result[2] || count[2] < expected_result_int[2] - numb_sigma * std_expected_result[2] || count[3] > expected_result_int[3] + numb_sigma * std_expected_result[3] || count[3] < expected_result_int[3] - numb_sigma * std_expected_result[3] || count[4] > expected_result_int[4] + numb_sigma * std_expected_result[4] || count[4] < expected_result_int[4] - numb_sigma * std_expected_result[4] || count[5] > expected_result_int[5] + numb_sigma * std_expected_result[5] || count[5] < expected_result_int[5] - numb_sigma * std_expected_result[5]) { message("Not all criteria satisfied!"); return 1; } } message("All good!"); return 0; }