aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile2
-rw-r--r--src/misc.c24
-rw-r--r--src/misc.h2
-rw-r--r--src/path.c89
-rw-r--r--src/test.c9
5 files changed, 90 insertions, 36 deletions
diff --git a/src/Makefile b/src/Makefile
index 75a75cb..2e9169a 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -18,7 +18,7 @@ test-vector: test-vector.o vector.o mt19937ar.o
test-likelihood: test-likelihood.o muon.o random.o optics.o quantum_efficiency.o mt19937ar.o pdg.o vector.o solid_angle.o scattering.o
-test-path: test-path.o mt19937ar.o vector.o path.o random.o
+test-path: test-path.o mt19937ar.o vector.o path.o random.o misc.o
test-charge: test-charge.o sno_charge.o misc.o
diff --git a/src/misc.c b/src/misc.c
index 74c729e..6a67d58 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -2,6 +2,30 @@
#include <math.h>
#include <stdlib.h> /* for size_t */
+int isclose(double a, double b, double rel_tol, double abs_tol)
+{
+ /* Returns 1 if a and b are "close". This algorithm is taken from Python's
+ * math.isclose() function.
+ *
+ * See https://www.python.org/dev/peps/pep-0485/. */
+ return fabs(a-b) <= fmax(rel_tol*fmax(fabs(a),fabs(b)),abs_tol);
+}
+
+int allclose(double *a, double *b, size_t n, double rel_tol, double abs_tol)
+{
+ /* Returns 1 if all the elements of a and b are "close". This algorithm is
+ * taken from Python's math.isclose() function.
+ *
+ * See https://www.python.org/dev/peps/pep-0485/. */
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ if (!isclose(a[i],b[i],rel_tol,abs_tol)) return 0;
+ }
+
+ return 1;
+}
+
double logsumexp(double *a, size_t n)
{
/* Returns the log of the sum of the exponentials of the array `a`.
diff --git a/src/misc.h b/src/misc.h
index bd114aa..295e59c 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -3,6 +3,8 @@
#include <stdlib.h> /* for size_t */
+int isclose(double a, double b, double rel_tol, double abs_tol);
+int allclose(double *a, double *b, size_t n, double rel_tol, double abs_tol);
double logsumexp(double *a, size_t n);
double norm(double x, double mu, double sigma);
double norm_cdf(double x, double mu, double sigma);
diff --git a/src/path.c b/src/path.c
index dff1dc7..1e53d79 100644
--- a/src/path.c
+++ b/src/path.c
@@ -33,6 +33,7 @@ path *path_init(double *pos, double *dir, double T0, double range, double theta0
{
size_t i, j;
double E, mom, beta, theta, phi;
+ double normal[3], k[3], tmp[3], tmp2[3];
path *p = malloc(sizeof(path));
@@ -87,6 +88,62 @@ path *path_init(double *pos, double *dir, double T0, double range, double theta0
}
}
+ /* Now, we rotate and translate the path so that it starts at `pos` and
+ * points in the direction `dir`. */
+
+ /* We need to compute an arbitrary vector which is orthogonal to the
+ * direction vector. To do this, all we need is another vector not parallel
+ * to the direction. */
+ k[0] = 0.0;
+ k[1] = 0.0;
+ k[2] = 1.0;
+
+ /* If k is approximately equal to the unit vector in the z direction, we
+ * switch to the unit vector in the x direction. */
+ if (allclose(k,dir,3,1e-9,1e-9)) {
+ k[0] = 1.0;
+ k[1] = 0.0;
+ k[2] = 0.0;
+ }
+
+ /* Take the cross product between `k` and `dir` to get a vector orthogonal
+ * to `dir`. */
+ CROSS(normal,k,dir);
+
+ /* Make sure it's normalized. */
+ normalize(normal);
+
+ /* Compute the angle required to rotate the unit vector to `dir`. */
+ phi = acos(DOT(k,dir));
+
+ /* Now we rotate and translate all the positions and rotate all the
+ * directions. */
+ for (i = 0; i < N; i++) {
+ tmp[0] = x[i];
+ tmp[1] = y[i];
+ tmp[2] = z[i];
+
+ rotate(tmp2,tmp,normal,phi);
+
+ ADD(tmp2,tmp2,pos);
+
+ x[i] = tmp2[0];
+ y[i] = tmp2[1];
+ z[i] = tmp2[2];
+
+ tmp[0] = dx[i];
+ tmp[1] = dy[i];
+ tmp[2] = dz[i];
+
+ normalize(tmp);
+
+ rotate(tmp2,tmp,normal,phi);
+
+ dx[i] = tmp2[0];
+ dy[i] = tmp2[1];
+ dz[i] = tmp2[2];
+ }
+
for (i = 0; i < 8; i++) {
p->acc[i] = gsl_interp_accel_alloc();
p->spline[i] = gsl_spline_alloc(gsl_interp_linear,N);
@@ -118,39 +175,19 @@ path *path_init(double *pos, double *dir, double T0, double range, double theta0
void path_eval(path *p, double s, double *pos, double *dir, double *T, double *t, double *theta0)
{
- double normal[3], k[3], tmp[3], phi;
-
if (s > p->spline[0]->x[p->spline[0]->size-1])
s = p->spline[0]->x[p->spline[0]->size-1];
- tmp[0] = gsl_spline_eval(p->spline[0],s,p->acc[0]);
- tmp[1] = gsl_spline_eval(p->spline[1],s,p->acc[1]);
- tmp[2] = gsl_spline_eval(p->spline[2],s,p->acc[2]);
+ pos[0] = gsl_spline_eval(p->spline[0],s,p->acc[0]);
+ pos[1] = gsl_spline_eval(p->spline[1],s,p->acc[1]);
+ pos[2] = gsl_spline_eval(p->spline[2],s,p->acc[2]);
*T = gsl_spline_eval(p->spline[3],s,p->acc[3]);
*t = gsl_spline_eval(p->spline[4],s,p->acc[4]);
- k[0] = 0.0;
- k[1] = 0.0;
- k[2] = 1.0;
-
- CROSS(normal,k,p->dir);
-
- normalize(normal);
-
- phi = acos(DOT(k,p->dir));
-
- rotate(pos,tmp,normal,phi);
-
- ADD(pos,pos,p->pos);
-
- tmp[0] = gsl_spline_eval(p->spline[5],s,p->acc[5]);
- tmp[1] = gsl_spline_eval(p->spline[6],s,p->acc[6]);
- tmp[2] = gsl_spline_eval(p->spline[7],s,p->acc[7]);
-
- normalize(tmp);
-
- rotate(dir,tmp,normal,phi);
+ dir[0] = gsl_spline_eval(p->spline[5],s,p->acc[5]);
+ dir[1] = gsl_spline_eval(p->spline[6],s,p->acc[6]);
+ dir[2] = gsl_spline_eval(p->spline[7],s,p->acc[7]);
/* FIXME: This should be the *residual* scattering RMS. */
*theta0 = p->theta0*sqrt(s);
diff --git a/src/test.c b/src/test.c
index baf0914..cc054c0 100644
--- a/src/test.c
+++ b/src/test.c
@@ -108,15 +108,6 @@ struct solid_angle_results {
{2.0,2.0,0.282707}
};
-int isclose(double a, double b, double rel_tol, double abs_tol)
-{
- /* Returns 1 if a and b are "close". This algorithm is taken from Python's
- * math.isclose() function.
- *
- * See https://www.python.org/dev/peps/pep-0485/. */
- return fabs(a-b) <= fmax(rel_tol*fmax(fabs(a),fabs(b)),abs_tol);
-}
-
int test_muon_get_T(char *err)
{
/* A very simple test to make sure the energy as a function of distance