analistica/ex-4/main.c

212 lines
5.9 KiB
C
Raw Normal View History

#include "lib.h"
2020-04-23 23:56:53 +02:00
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_min.h>
#include <gsl/gsl_deriv.h>
2020-04-23 23:56:53 +02:00
2020-05-30 11:22:29 +02:00
/* Process CLI arguments and print usage */
int parser(size_t *N, size_t *n, double *p_max,
size_t argc, char **argv, size_t *go) {
for (size_t i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-n")) *N = atol(argv[++i]);
else if (!strcmp(argv[i], "-b")) *n = atol(argv[++i]);
else if (!strcmp(argv[i], "-p")) *p_max = atof(argv[++i]);
2020-04-28 23:44:24 +02:00
else if (!strcmp(argv[i], "-o")) *go = 1;
2020-05-30 11:22:29 +02:00
else {
2020-04-30 22:28:06 +02:00
fprintf(stderr, "Usage: %s -[hnbpo]\n", argv[0]);
2020-04-23 23:56:53 +02:00
fprintf(stderr, "\t-h\tShow this message.\n");
2020-04-30 22:28:06 +02:00
fprintf(stderr, "\t-n N\tThe number of particles to generate. (default: 50000)\n");
fprintf(stderr, "\t-b N\tThe number of bins of the histogram. (default: 50)\n");
fprintf(stderr, "\t-p PMAX\tThe maximum value of momentum. (default: 10)\n");
2020-04-30 22:28:06 +02:00
fprintf(stderr, "\t-o\tPrint histogram to stdout.\n");
return 0;
2020-04-23 23:56:53 +02:00
}
}
2020-05-30 11:22:29 +02:00
return 1;
}
2020-05-30 11:22:29 +02:00
int main(int argc, char **argv) {
// Set default options.
2020-04-28 23:44:24 +02:00
size_t N = 50000;
size_t n = 50;
double p_max = 10;
size_t go = 0;
2020-05-12 22:38:14 +02:00
// Get eventual CLI arguments.
2020-04-28 23:44:24 +02:00
int res = parser(&N, &n, &p_max, argc, argv, &go);
2020-05-30 11:22:29 +02:00
if (go == 0 && res == 1) {
printf("Generating histogram with:\n"
"%ld points\n"
"%ld bins\n"
"p_max = %.3f\n\n", N, n, p_max);
}
else if (res == 0)
return EXIT_FAILURE;
2020-04-23 23:56:53 +02:00
// Initialize an RNG.
gsl_rng_env_setup();
gsl_rng *r = gsl_rng_alloc(gsl_rng_default);
2020-05-30 11:22:29 +02:00
/* Generate the angle θ uniformly distributed on a sphere using the
* inverse transform:
*
* θ = acos(1 - 2X)
*
* where X is a random uniform variable in [0,1), and the module p of
* the vector:
*
* p² = p_v² + p_h²
*
* uniformly distributed between 0 and p_max. The two components are
* then computed as:
*
* p_v = pcos(θ)
* p_h = psin(θ)
*
* The histogram is updated this way.
* The j-th bin where p_h goes in is given by:
*
* step = p_max / n
* j = floor(p_h / step)
*
* Thus an histogram was created and a structure containing the number of
* entries in each bin and the sum of |p_v| in each of them is created and
* filled while generating the events (struct bin).
*/
2020-04-23 23:56:53 +02:00
struct bin *histo = calloc(n, sizeof(struct bin));
// Some useful variables.
double step = p_max / n;
struct bin *b;
double theta;
double p;
double p_v;
double p_h;
size_t j;
2020-05-30 11:22:29 +02:00
for (size_t i = 0; i < N; i++) {
// Generate the event
2020-04-23 23:56:53 +02:00
theta = acos(1 - 2*gsl_rng_uniform(r));
p = p_max * gsl_rng_uniform(r);
2020-05-30 11:22:29 +02:00
// Compute the components
2020-04-23 23:56:53 +02:00
p_v = p * cos(theta);
p_h = p * sin(theta);
2020-05-30 11:22:29 +02:00
// Update the histogram
2020-04-23 23:56:53 +02:00
j = floor(p_h / step);
b = &histo[j];
b -> amo++;
b -> sum += fabs(p_v);
2020-05-30 11:22:29 +02:00
}
2020-04-23 23:56:53 +02:00
2020-05-30 11:22:29 +02:00
/* Compute the mean value of each bin and print it to stodut
* together with other useful things to make the histogram.
*/
if (go == 1) {
2020-04-28 23:44:24 +02:00
printf("bins: \t%ld\n", n);
printf("step: \t%.5f\n", step);
2020-05-30 11:22:29 +02:00
}
for (size_t i = 0; i < n; i++) {
histo[i].sum = histo[i].sum / histo[i].amo; // Average P_v
2020-04-28 23:44:24 +02:00
if (go == 1) printf("\n%.5f", histo[i].sum);
2020-05-30 11:22:29 +02:00
};
2020-06-01 15:45:10 +02:00
/* Compare the histogram with the expected function:
2020-05-30 11:22:29 +02:00
*
* x * log(p_max/x)/arctan(sqrt(p_max^2/x^2 - 1))
*
* using the χ² test.
*/
struct parameters params;
params.histo = histo;
params.n = n;
params.step = step;
gsl_function func;
func.function = &chi2;
func.params = &params;
2020-04-30 22:28:06 +02:00
double min_p = p_max - 5;
double max_p = p_max + 5;
2020-05-30 11:22:29 +02:00
// Initialize minimization
2020-04-30 22:28:06 +02:00
double x = p_max;
int max_iter = 100;
double prec = 1e-7;
int status = GSL_CONTINUE;
const gsl_min_fminimizer_type *T = gsl_min_fminimizer_brent;
gsl_min_fminimizer *s = gsl_min_fminimizer_alloc(T);
gsl_min_fminimizer_set(s, &func, x, min_p, max_p);
2020-05-30 11:22:29 +02:00
// Minimization
for (int iter = 0; status == GSL_CONTINUE && iter < max_iter; iter++) {
status = gsl_min_fminimizer_iterate(s);
x = gsl_min_fminimizer_x_minimum(s);
min_p = gsl_min_fminimizer_x_lower(s);
max_p = gsl_min_fminimizer_x_upper(s);
status = gsl_min_test_interval(min_p, max_p, 0, prec);
2020-05-30 11:22:29 +02:00
}
2020-04-23 23:56:53 +02:00
double result = x;
double res_chi = chi2(result, &params);
2020-05-30 11:22:29 +02:00
if (go == 0) {
2020-04-28 23:44:24 +02:00
printf("Results:\n");
printf("χ² = %.3f\n", res_chi);
printf("p_max = %.3f\n", result);
2020-05-30 11:22:29 +02:00
}
2020-05-30 11:22:29 +02:00
/* Compute the second derivative of χ² in its minimum for the result error.
*
* p_max = α
* 2
* (Eᵢ - Oᵢ)
* χ² = Σi
* Eᵢ
*
* 2
* Oᵢ
* αχ² = Σi Eᵢ1 - αE
* 2
* Eᵢ
*
* 2 2
* Oᵢ Oᵢ
* ²αχ² = Σi (αE)²2 + ²αE 1 -
* 2 2
* Eᵢ Eᵢ
*/
double expecto, A, B;
double error = 0;
2020-05-30 11:22:29 +02:00
for (size_t i = 0; i < n; i++) {
x = (i + 0.5) * step;
expecto = expected(x, result);
A = 2 * pow(exp1d(x, result) * histo[i].sum / expecto, 2);
B = exp2d(x, result) * (1 - pow((histo[i].sum / expecto), 2));
error = error + A + B;
2020-05-30 11:22:29 +02:00
};
2020-04-28 23:44:24 +02:00
error = 1/error;
2020-05-30 11:22:29 +02:00
if (go == 0)
printf("ΔP_max = %.3f\n", error);
2020-04-28 23:44:24 +02:00
// Check compatibility
double t = fabs(result - p_max)/error;
double alpha = 1 - erf(t/sqrt(2));
2020-05-30 11:22:29 +02:00
if (go == 0) {
2020-04-28 23:44:24 +02:00
printf("\nCompatibility:\n");
printf("t = %.3f\n", t);
printf("α = %.3f\n\n", alpha);
2020-05-30 11:22:29 +02:00
}
2020-05-30 11:22:29 +02:00
// Free memory
gsl_min_fminimizer_free(s);
2020-04-23 23:56:53 +02:00
gsl_rng_free(r);
free(histo);
return EXIT_SUCCESS;
2020-05-30 11:22:29 +02:00
}