/******************************************************************************* * This file is part of SWIFT. * Copyright (C) 2019 Matthieu Schaller (schaller@strw.leidenuniv.nl) * 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 "../config.h" #include /* Local headers. */ #include "swift.h" /** * @brief Compute the Pearson correlation coefficient for two sets of numbers * * The pearson correlation coefficient between two sets of numbers can be * calculated as: * * - * * r_xy = ---------------------- * (var(x) * var(y))^.5 * * In the case that both sets are purely uncorrelated the value of the * Pearson correlation function is expected to be close to 0. In the case that * there is positive correlation r_xy > 0 and in the case of negative * correlation, the function has r_xy < 0. * * @param mean1 average of first series of numbers * @param mean2 average of second series of numbers * @param total12 sum of x_i * y_i of both series of numbers * @param var1 variance of the first series of numbers * @param var2 variance of the second series of numbers * @param number of elements in both series * */ double pearsonfunc(double mean1, double mean2, double total12, double var1, double var2, int counter) { const double mean12 = total12 / (double)counter; const double correlation = (mean12 - mean1 * mean2)/ sqrt(var1 * var2); return fabs(correlation); } 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); /* Time-step size */ const int time_bin = 29; /* Try a few different values for the ID */ for (int i = 0; i < 20; ++i) { const long long id = rand() * (1LL << 31) + rand(); const integertime_t increment = (1LL << time_bin); const long long idoffset = id + 2; message("Testing id=%lld time_bin=%d", id, time_bin); double total = 0., total2 = 0.; int count = 0; /* Pearson correlation variables for different times */ double sum_previous_current = 0.; double previous = 0.; /* Pearson correlation for two different IDs */ double pearsonIDs = 0.; double totalID = 0.; double total2ID = 0.; /* Pearson correlation for different processes */ double pearson_star_sf = 0.; double pearson_star_se = 0.; double pearson_star_bh = 0.; double pearson_sf_se = 0.; double pearson_sf_bh = 0.; double pearson_se_bh = 0.; /* Calculate the mean and for these processes */ double total_sf = 0.; double total_se = 0.; double total_bh = 0.; double total2_sf = 0.; double total2_se = 0.; double total2_bh = 0.; /* 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) { ti_current += increment; const double r = random_unit_interval(id, ti_current, random_number_star_formation); total += r; total2 += r * r; count++; /* Calculate for correlation between time. * For this we use the pearson correlation of time i and i-1 */ sum_previous_current += r * previous; previous = r; /* Calculate if there is a correlation between different ids */ const double r_2ndid = random_unit_interval(idoffset, ti_current, random_number_star_formation); /* Pearson correlation for small different IDs */ pearsonIDs += r * r_2ndid; totalID += r_2ndid; total2ID += r_2ndid * r_2ndid; /* Calculate random numbers for the different processes and check * that they are uncorrelated */ const double r_sf = random_unit_interval(id, ti_current, random_number_stellar_feedback); const double r_se = random_unit_interval(id, ti_current, random_number_stellar_enrichment); const double r_bh = random_unit_interval(id, ti_current, random_number_BH_feedback); /* Calculate the correlation between the different processes */ total_sf += r_sf; total_se += r_se; total_bh += r_bh; total2_sf += r_sf * r_sf; total2_se += r_se * r_se; total2_bh += r_bh * r_bh; pearson_star_sf += r * r_sf; pearson_star_se += r * r_se; pearson_star_bh += r * r_bh; pearson_sf_se += r_sf * r_se; pearson_sf_bh += r_sf * r_bh; pearson_se_bh += r_se * r_bh; } const double mean = total / (double)count; const double var = total2 / (double)count - mean * mean; /* Pearson correlation calculation for different times */ //const double mean_xy = sum_previous_current / ((double)count - 1.f); //const double correlation = (mean_xy - mean * mean) / var; const double correlation = pearsonfunc(mean,mean, sum_previous_current, var, var, count-1); /* Mean for different IDs */ const double meanID = totalID / (double)count; const double varID = total2ID / (double)count - meanID * meanID; /* Pearson correlation between different IDs*/ const double correlationID = pearsonfunc(mean, meanID, pearsonIDs, var, varID, count); /* Mean and for different processes */ const double mean_sf = total_sf / (double)count; const double mean_se = total_se / (double)count; const double mean_bh = total_bh / (double)count; const double var_sf = total2_sf / (double)count - mean_sf * mean_sf; const double var_se = total2_se / (double)count - mean_se * mean_se; const double var_bh = total2_bh / (double)count - mean_bh * mean_bh; /* Correlation between different processes */ const double corr_star_sf = pearsonfunc(mean,mean_sf,pearson_star_sf, var, var_sf, count); const double corr_star_se = pearsonfunc(mean,mean_se,pearson_star_se, var, var_se, count); const double corr_star_bh = pearsonfunc(mean,mean_bh,pearson_star_bh, var, var_bh, count); const double corr_sf_se = pearsonfunc(mean_sf,mean_se,pearson_sf_se, var_sf, var_se, count); const double corr_sf_bh = pearsonfunc(mean_sf,mean_bh,pearson_sf_bh, var_sf, var_bh, count); const double corr_se_bh = pearsonfunc(mean_se,mean_bh,pearson_se_bh, var_se, var_bh, count); /* Verify that the mean and variance match the expected values for a uniform * distribution */ const double tolmean = 2e-4; const double tolvar = 1e-3; const double tolcorr = 3e-4; if ((fabs(mean - 0.5) / 0.5 > tolmean) || (fabs(var - 1. / 12.) / (1. / 12.) > tolvar) || (correlation > tolcorr) || (correlationID > tolcorr) || (fabs(meanID - 0.5) / 0.5 > tolmean) || (fabs(varID - 1. / 12.) / (1. / 12.) > tolvar) || (corr_star_sf > tolcorr) || (corr_star_se > tolcorr) || (corr_star_bh > tolcorr) || (corr_sf_se > tolcorr) || (corr_sf_bh > tolcorr) || (corr_se_bh > tolcorr) || (fabs(mean_sf - 0.5) / 0.5 > tolmean) || (fabs(mean_se - 0.5) / 0.5 > tolmean) || (fabs(mean_bh - 0.5) / 0.5 > tolmean) || (fabs(var_sf - 1. / 12.) / (1. / 12.) > tolvar) || (fabs(var_se - 1. / 12.) / (1. / 12.) > tolvar) || (fabs(var_bh - 1. / 12.) / (1. / 12.) > tolvar)) { message("Test failed!"); message("Global result:"); message( "Result: count=%d mean=%f var=%f, correlation=%f", count, mean, var, correlation); message( "Expected: count=%d mean=%f var=%f, correlation=%f", count, 0.5f, 1. / 12., 0.); message("ID part"); message("Result: count%d mean=%f var=%f" " correlation=%f", count, meanID, varID, correlationID); message("Expected: count%d mean=%f var=%f" " correlation=%f", count, .5f, 1. / 12., 0.); message("Different physical processes:"); message("Means: stars=%f stellar feedback=%f stellar " " enrichement=%f black holes=%f", mean, mean_sf, mean_se, mean_bh); message("Expected: stars=%f stellar feedback=%f stellar " " enrichement=%f black holes=%f", .5f, .5f, .5f, .5f); message("Var: stars=%f stellar feedback=%f stellar " " enrichement=%f black holes=%f", var, var_sf, var_se, var_bh); message("Expected: stars=%f stellar feedback=%f stellar " " enrichement=%f black holes=%f", 1./12., 1./12., 1/12., 1./12.); message("Correlation: stars-sf=%f stars-se=%f stars-bh=%f" "sf-se=%f sf-bh=%f se-bh=%f", corr_star_sf, corr_star_se, corr_star_bh, corr_sf_se, corr_sf_bh, corr_se_bh); message("Expected: stars-sf=%f stars-se=%f stars-bh=%f" "sf-se=%f sf-bh=%f se-bh=%f", 0., 0., 0., 0., 0., 0.); return 1; } } return 0; }