aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libcrystfel/src/utils.h20
-rw-r--r--src/post-refinement.c69
-rw-r--r--tests/pr_gradient_check.c3
3 files changed, 60 insertions, 32 deletions
diff --git a/libcrystfel/src/utils.h b/libcrystfel/src/utils.h
index b75693db..1adb69e6 100644
--- a/libcrystfel/src/utils.h
+++ b/libcrystfel/src/utils.h
@@ -139,6 +139,11 @@ static inline double modulus(double x, double y, double z)
return sqrt(x*x + y*y + z*z);
}
+static inline double modulus2d(double x, double y)
+{
+ return sqrt(x*x + y*y);
+}
+
static inline double modulus_squared(double x, double y, double z) {
return x*x + y*y + z*z;
}
@@ -165,6 +170,21 @@ static inline double angle_between(double x1, double y1, double z1,
return acos(cosine);
}
+/* Answer in radians */
+static inline double angle_between_2d(double x1, double y1,
+ double x2, double y2)
+{
+ double mod1 = modulus2d(x1, y1);
+ double mod2 = modulus2d(x2, y2);
+ double cosine = (x1*x2 + y1*y2) / (mod1*mod2);
+
+ /* Fix domain if outside due to rounding */
+ if ( cosine > 1.0 ) cosine = 1.0;
+ if ( cosine < -1.0 ) cosine = -1.0;
+
+ return acos(cosine);
+}
+
static inline int within_tolerance(double a, double b, double percent)
{
double tol = fabs(a) * (percent/100.0);
diff --git a/src/post-refinement.c b/src/post-refinement.c
index f6f4caa5..9e63736f 100644
--- a/src/post-refinement.c
+++ b/src/post-refinement.c
@@ -90,8 +90,7 @@ static double partiality_rgradient(double r, double profile_radius)
/* Return the gradient of parameter 'k' given the current status of 'image'. */
double gradient(Crystal *cr, int k, Reflection *refl, PartialityModel pmodel)
{
- double ds, azix, aziy;
- double ttlow, tthigh, tt;
+ double ds, azi;
double nom, den;
double g;
double asx, asy, asz;
@@ -99,9 +98,11 @@ double gradient(Crystal *cr, int k, Reflection *refl, PartialityModel pmodel)
double csx, csy, csz;
double xl, yl, zl;
signed int hs, ks, ls;
- double r1, r2, p;
+ double rlow, rhigh, p;
int clamp_low, clamp_high;
- double klow, khigh;
+ double philow, phihigh, phi;
+ double khigh, klow;
+ double tl, cet, cez;
double gr;
struct image *image = crystal_get_image(cr);
double r = crystal_get_profile_radius(cr);
@@ -116,33 +117,37 @@ double gradient(Crystal *cr, int k, Reflection *refl, PartialityModel pmodel)
zl = hs*asz + ks*bsz + ls*csz;
ds = 2.0 * resolution(crystal_get_cell(cr), hs, ks, ls);
- get_partial(refl, &r1, &r2, &p, &clamp_low, &clamp_high);
+ get_partial(refl, &rlow, &rhigh, &p, &clamp_low, &clamp_high);
+ /* "low" gives the largest Ewald sphere (wavelength short => k large)
+ * "high" gives the smallest Ewald sphere (wavelength long => k small)
+ */
klow = 1.0/(image->lambda - image->lambda*image->bw/2.0);
khigh = 1.0/(image->lambda + image->lambda*image->bw/2.0);
- ttlow = angle_between(0.0, 0.0, 1.0, xl, yl, zl+klow);
- tthigh = angle_between(0.0, 0.0, 1.0, xl, yl, zl+khigh);
- if ( (clamp_low == 0) && (clamp_high == 0) ) {
- tt = (ttlow+tthigh)/2.0;
- } else if ( clamp_high == 0 ) {
- tt = tthigh + image->div;
- } else if ( clamp_low == 0 ) {
- tt = ttlow - image->div;
- } else {
- tt = 0.0;
- /* Gradient should come out as zero in this case */
- }
- azix = angle_between(1.0, 0.0, 0.0, xl, yl, 0.0);
- aziy = angle_between(0.0, 1.0, 0.0, xl, yl, 0.0);
+ tl = sqrt(xl*xl + yl*yl);
+ ds = modulus(xl, yl, zl);
+
+ cet = -sin(image->div/2.0) * klow;
+ cez = -cos(image->div/2.0) * klow;
+ philow = M_PI_2 - angle_between_2d(tl-cet, zl-cez, 1.0, 0.0);
+
+ cet = -sin(image->div/2.0) * khigh;
+ cez = -cos(image->div/2.0) * khigh;
+ phihigh = M_PI_2 - angle_between_2d(tl-cet, zl-cez, 1.0, 0.0);
+
+ /* Approximation: philow and phihigh are very similar */
+ phi = (philow + phihigh) / 2.0;
+
+ azi = atan2(yl, xl);
/* Calculate the gradient of partiality wrt excitation error. */
g = 0.0;
if ( clamp_low == 0 ) {
- g -= partiality_gradient(r1, r);
+ g -= partiality_gradient(rlow, r);
}
if ( clamp_high == 0 ) {
- g += partiality_gradient(r2, r);
+ g += partiality_gradient(rhigh, r);
}
/* For many gradients, just multiply the above number by the gradient
@@ -167,40 +172,40 @@ double gradient(Crystal *cr, int k, Reflection *refl, PartialityModel pmodel)
case REF_R :
g = 0.0;
if ( clamp_low == 0 ) {
- g += partiality_rgradient(r1, r);
+ g += partiality_rgradient(rlow, r);
}
if ( clamp_high == 0 ) {
- g += partiality_rgradient(r2, r);
+ g += partiality_rgradient(rhigh, r);
}
return g;
/* Cell parameters and orientation */
case REF_ASX :
- return hs * sin(tt) * cos(azix) * g;
+ return hs * sin(phi) * cos(azi) * g;
case REF_BSX :
- return ks * sin(tt) * cos(azix) * g;
+ return ks * sin(phi) * cos(azi) * g;
case REF_CSX :
- return ls * sin(tt) * cos(azix) * g;
+ return ls * sin(phi) * cos(azi) * g;
case REF_ASY :
- return hs * sin(tt) * cos(aziy) * g;
+ return hs * sin(phi) * sin(azi) * g;
case REF_BSY :
- return ks * sin(tt) * cos(aziy) * g;
+ return ks * sin(phi) * sin(azi) * g;
case REF_CSY :
- return ls * sin(tt) * cos(aziy) * g;
+ return ls * sin(phi) * sin(azi) * g;
case REF_ASZ :
- return hs * cos(tt) * g;
+ return hs * cos(phi) * g;
case REF_BSZ :
- return ks * cos(tt) * g;
+ return ks * cos(phi) * g;
case REF_CSZ :
- return ls * cos(tt) * g;
+ return ls * cos(phi) * g;
}
diff --git a/tests/pr_gradient_check.c b/tests/pr_gradient_check.c
index cf11d18c..d5344801 100644
--- a/tests/pr_gradient_check.c
+++ b/tests/pr_gradient_check.c
@@ -425,6 +425,9 @@ int main(int argc, char *argv[])
val = test_gradients(cr, incr_val, REF_R, "R", pmodel);
if ( val > 0.1 ) fail = 1;
+ //incr_val = incr_frac * image.profile_radius;
+ //val += test_gradients(&image, incr_val, REF_R, "rad");
+
incr_val = incr_frac * ax;
val = test_gradients(cr, incr_val, REF_ASX, "ax*", pmodel);
if ( val > 0.1 ) fail = 1;