aboutsummaryrefslogtreecommitdiff
path: root/src/hrs-scaling.c
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2015-03-01 13:49:30 +0100
committerThomas White <taw@physics.org>2015-03-12 16:37:25 +0100
commitd7b326f4e75cf6bda8c1a097a92923820aa4b6e3 (patch)
tree5432a940f284a05278a7fb162b62f49ff8e6e162 /src/hrs-scaling.c
parentd629386cb7b89cacea1673523f7d39f2fd23ec61 (diff)
partialator: Add B-factor scaling and rejection
Diffstat (limited to 'src/hrs-scaling.c')
-rw-r--r--src/hrs-scaling.c170
1 files changed, 148 insertions, 22 deletions
diff --git a/src/hrs-scaling.c b/src/hrs-scaling.c
index 7f15f54d..0225d625 100644
--- a/src/hrs-scaling.c
+++ b/src/hrs-scaling.c
@@ -3,11 +3,11 @@
*
* Intensity scaling using generalised HRS target function
*
- * Copyright © 2012-2014 Deutsches Elektronen-Synchrotron DESY,
+ * Copyright © 2012-2015 Deutsches Elektronen-Synchrotron DESY,
* a research centre of the Helmholtz Association.
*
* Authors:
- * 2010-2014 Thomas White <taw@physics.org>
+ * 2010-2015 Thomas White <taw@physics.org>
*
* This file is part of CrystFEL.
*
@@ -37,6 +37,7 @@
#include <gsl/gsl_vector.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_eigen.h>
+#include <gsl/gsl_fit.h>
#include "image.h"
#include "peaks.h"
@@ -45,6 +46,7 @@
#include "cell.h"
#include "utils.h"
#include "reflist.h"
+#include "cell-utils.h"
/* Minimum partiality of a reflection for it to be used for scaling */
@@ -63,6 +65,7 @@ struct scale_queue_args
Crystal **crystals;
int n_started;
PartialityModel pmodel;
+ UnitCell *cell;
};
@@ -71,6 +74,7 @@ struct scale_worker_args
Crystal *crystal;
RefList *reference;
PartialityModel pmodel;
+ int crystal_number;
};
@@ -83,6 +87,7 @@ static void *create_scale_job(void *vqargs)
wargs->reference = qargs->reference;
wargs->pmodel = qargs->pmodel;
+ wargs->crystal_number = qargs->n_started;
wargs->crystal = qargs->crystals[qargs->n_started++];
return wargs;
@@ -96,9 +101,35 @@ static void run_scale_job(void *vwargs, int cookie)
RefList *reference = wargs->reference;
Reflection *refl;
RefListIterator *iter;
- double num = 0.0;
- double den = 0.0;
- double g;
+ int n = 0;
+ double *x;
+ double *y;
+ double *w;
+ int max_n = 256;
+ double c0, c1, cov00, cov01, cov11, chisq;
+ double G, B;
+ int r;
+ int debug = 0;
+ FILE *fh;
+
+ /* If this crystal's scaling was dodgy, it doesn't contribute to the
+ * merged intensities */
+ if ( crystal_get_user_flag(cr) != 0 ) return;
+
+ x = malloc(max_n*sizeof(double));
+ y = malloc(max_n*sizeof(double));
+ w = malloc(max_n*sizeof(double));
+ if ( (x==NULL) || (y==NULL) || (w==NULL) ) {
+ ERROR("Failed to allocate memory for scaling.\n");
+ return;
+ }
+
+ if ( wargs->crystal_number == 0 ) {
+ char fn[256];
+ snprintf(fn, 255, "scale-debug.%i", wargs->crystal_number);
+ debug = 1;
+ fh = fopen(fn, "w");
+ }
for ( refl = first_refl(crystal_get_reflections(cr), &iter);
refl != NULL;
@@ -107,30 +138,80 @@ static void run_scale_job(void *vwargs, int cookie)
signed int h, k, l;
double Ih, Ihl, corr;
Reflection *r;
+ double res;
+
+ get_indices(refl, &h, &k, &l);
+ res = resolution(crystal_get_cell(cr), h, k, l);
if ( (get_partiality(refl) < MIN_PART_SCALE)
- || (get_intensity(refl) < 3.0*get_esd_intensity(refl)) ) {
+ || (get_intensity(refl) < 5.0*get_esd_intensity(refl)) ) {
continue;
}
/* Look up by asymmetric indices */
- get_indices(refl, &h, &k, &l);
r = find_refl(reference, h, k, l);
- if ( r == NULL ) continue;
+ if ( r == NULL ) {
+ continue;
+ }
Ih = get_intensity(r);
-
corr = get_partiality(refl) * get_lorentz(refl);
-
Ihl = get_intensity(refl) / corr;
- num += Ih * Ihl;
- den += Ih * Ih;
+ if ( Ihl <= 0.0 ) continue;
+ if ( Ih <= 0.0 ) continue;
+ if ( isnan(Ih) || isinf(Ihl) ) continue;
+ if ( isnan(Ih) || isinf(Ih) ) continue;
+
+ if ( n == max_n ) {
+ max_n *= 2;
+ x = realloc(x, max_n*sizeof(double));
+ y = realloc(y, max_n*sizeof(double));
+ w = realloc(w, max_n*sizeof(double));
+ if ( (x==NULL) || (y==NULL) || (w==NULL) ) {
+ ERROR("Failed to allocate memory for scaling.\n");
+ return;
+ }
+ }
+
+ x[n] = res*res;
+ y[n] = log(Ihl/Ih);
+ w[n] = 1.0;//log(get_esd_intensity(refl)*corr);
+ if ( debug ) {
+ fprintf(fh, "%i %10.2e %10.2f %10.2f %.2f %.2f %.2f\n",
+ n, x[n], y[n], w[n], Ihl, Ih, res/1e9);
+ }
+ n++;
}
- g = num / den;
- crystal_set_osf(cr, g); /* If it's NaN, it'll get rejected later */
+ if ( n < 2 ) {
+ crystal_set_user_flag(cr, 1);
+ return;
+ }
+
+ r = gsl_fit_wlinear(x, 1, w, 1, y, 1, n, &c0, &c1,
+ &cov00, &cov01, &cov11, &chisq);
+
+ G = 1.0/exp(c0);
+ B = -c1/2.0;
+ if ( debug ) {
+ printf("intercept = %e, gradient = %e\n", c0, c1);
+ printf("Scale factor = %f\n", G);
+ printf("Relative B = %.2f A^2\n", B * 1e20);
+ fclose(fh);
+ }
+
+ free(x);
+ free(y);
+ free(w);
+ if ( r || isnan(c0) ) {
+ crystal_set_user_flag(cr, 1);
+ return;
+ }
+
+ crystal_set_osf(cr, G);
+ crystal_set_Bfac(cr, B);
}
@@ -174,6 +255,7 @@ struct merge_worker_args
RefList *full;
pthread_rwlock_t *full_lock;
PartialityModel pmodel;
+ int crystal_number;
};
@@ -187,6 +269,7 @@ static void *create_merge_job(void *vqargs)
wargs->full_lock = &qargs->full_lock;
wargs->pmodel = qargs->pmodel;
+ wargs->crystal_number = qargs->n_started;
wargs->crystal = qargs->crystals[qargs->n_started++];
return wargs;
@@ -200,13 +283,23 @@ static void run_merge_job(void *vwargs, int cookie)
RefList *full = wargs->full;
Reflection *refl;
RefListIterator *iter;
- double G;
+ double G, B;
+ FILE *fh;
+ int debug = 0;
/* If this crystal's scaling was dodgy, it doesn't contribute to the
* merged intensities */
if ( crystal_get_user_flag(cr) != 0 ) return;
G = crystal_get_osf(cr);
+ B = crystal_get_Bfac(cr);
+
+ if ( wargs->crystal_number == 0 ) {
+ char fn[256];
+ snprintf(fn, 255, "merge-debug.%i", wargs->crystal_number);
+ debug = 1;
+ fh = fopen(fn, "w");
+ }
for ( refl = first_refl(crystal_get_reflections(cr), &iter);
refl != NULL;
@@ -216,7 +309,7 @@ static void run_merge_job(void *vwargs, int cookie)
signed int h, k, l;
double num, den;
int red;
- double Ihl, corr;
+ double Ihl, corr, res;
if ( get_partiality(refl) < MIN_PART_MERGE ) continue;
@@ -262,19 +355,27 @@ static void run_merge_job(void *vwargs, int cookie)
}
+ res = resolution(crystal_get_cell(cr), h, k, l);
corr = get_partiality(refl) * get_lorentz(refl);
Ihl = get_intensity(refl) / corr;
- num += Ihl / G;
+ num += Ihl * G * exp(2.0*B*res);
den += 1.0;
red++;
+ if ( debug ) {
+ fprintf(fh, "%.2f %.2f %f %e\n", res/1e9,
+ Ihl*G*exp(2.0*B*res),
+ G, B);
+ }
+
set_temp1(f, num);
set_temp2(f, den);
set_redundancy(f, red);
unlock_reflection(f);
}
+ if ( debug ) fclose(fh);
}
@@ -449,10 +550,33 @@ static void reject_outliers(double *old_osfs, int n, Crystal **crystals)
int i;
for ( i=0; i<n; i++ ) {
+
double osf = crystal_get_osf(crystals[i]);
- if ( isnan(osf) || (osf < 0.0) || (osf > 3.0) ) {
+ double Bfac = crystal_get_Bfac(crystals[i]);
+ int bad = 0;
+
+ if ( isnan(osf) || (osf < 0.0) || (osf > 10.0) ) bad = 1;
+ if ( isnan(Bfac) || (Bfac<-40e-20) || (Bfac>40e-20) ) bad = 1;
+
+ if ( bad ) {
crystal_set_user_flag(crystals[i], 1);
+ //STATUS("crystal %i bad: osf=%f B=%f A^2\n",
+ // i, osf, Bfac*1e20);
+ } else {
+ //STATUS("OK %i: osf=%f B=%f A^2\n",
+ // i, osf, Bfac*1e20);
}
+
+ }
+}
+
+
+static void reset_scaling_flag(Crystal *crystal)
+{
+ /* Every pattern gets another chance at being scaled, but stays flagged
+ * if it was flagged for any other reason */
+ if ( crystal_get_user_flag(crystal) == 1 ) {
+ crystal_set_user_flag(crystal, 0);
}
}
@@ -490,8 +614,9 @@ RefList *scale_intensities(Crystal **crystals, int n,
int done;
for ( i=0; i<n; i++ ) {
- crystal_set_user_flag(crystals[i], 0);
+ reset_scaling_flag(crystals[i]);
crystal_set_osf(crystals[i], 1.0);
+ crystal_set_Bfac(crystals[i], 0.0);
}
if ( noscale ) {
@@ -518,26 +643,27 @@ RefList *scale_intensities(Crystal **crystals, int n,
for ( j=0; j<n; j++ ) {
old_osfs[j] = crystal_get_osf(crystals[j]);
- crystal_set_user_flag(crystals[j], 0);
+ reset_scaling_flag(crystals[j]);
}
iterate_scale(crystals, n, full, n_threads, pmodel);
+ reject_outliers(old_osfs, n, crystals);
/* Normalise the scale factors */
for ( j=0; j<n; j++ ) {
double osf = crystal_get_osf(crystals[j]);
- if ( !isnan(osf) ) {
+ if ( crystal_get_user_flag(crystals[j]) == 0 ) {
total_sf += osf;
n_sf++;
}
}
norm_sf = total_sf / n_sf;
+ STATUS("norm = %f\n", norm_sf);
for ( j=0; j<n; j++ ) {
crystal_set_osf(crystals[j],
crystal_get_osf(crystals[j])/norm_sf);
}
- reject_outliers(old_osfs, n, crystals);
done = test_convergence(old_osfs, n, crystals);
/* Generate list for next iteration */