compare_hkl.c 9.28 KB
Newer Older
1
2
3
4
5
/*
 * compare_hkl.c
 *
 * Compare reflection lists
 *
Thomas White's avatar
Thomas White committed
6
 * (c) 2006-2011 Thomas White <taw@physics.org>
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * Part of CrystFEL - crystallography with a FEL
 *
 */


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
Thomas White's avatar
Thomas White committed
23
#include <assert.h>
24
#include <gsl/gsl_errno.h>
25
26

#include "utils.h"
Thomas White's avatar
Thomas White committed
27
#include "statistics.h"
28
#include "symmetry.h"
Thomas White's avatar
Thomas White committed
29
#include "reflist-utils.h"
30
31


Thomas White's avatar
Thomas White committed
32
/* Number of bins for plot of resolution shells */
33
#define NBINS (10)
Thomas White's avatar
Thomas White committed
34
35


36
37
static void show_help(const char *s)
{
38
	printf("Syntax: %s [options] <file1.hkl> <file2.hkl>\n\n", s);
39
40
41
42
	printf(
"Compare intensity lists.\n"
"\n"
"  -h, --help                 Display this help message.\n"
Thomas White's avatar
Thomas White committed
43
"  -o, --ratio=<filename>     Specify output filename for ratios.\n"
44
"  -y, --symmetry=<sym>       The symmetry of both the input files.\n"
45
"  -p, --pdb=<filename>       PDB file to use (default: molecule.pdb).\n"
Thomas White's avatar
Thomas White committed
46
"      --shells               Plot the figures of merit by resolution.\n"
47
48
"      --rmin=<res>           Fix lower resolution limit for --shells (m^-1).\n"
"      --rmax=<res>           Fix upper resolution limit for --shells (m^-1).\n"
49
50
51
52
"\n");
}


53
54
static void plot_shells(RefList *list1, RefList *list2, double scale,
                        UnitCell *cell, double rmin_fix, double rmax_fix)
Thomas White's avatar
Thomas White committed
55
56
{
	double num[NBINS];
Thomas White's avatar
Thomas White committed
57
	int cts[NBINS];
58
59
60
61
62
	unsigned int measurements[NBINS];
	unsigned int measured[NBINS];
	double total_vol, vol_per_shell;
	double rmins[NBINS];
	double rmaxs[NBINS];
63
	double snr[NBINS];
64
	double rmin, rmax;
Thomas White's avatar
Thomas White committed
65
	int i;
Thomas White's avatar
Thomas White committed
66
67
	Reflection *refl1;
	RefListIterator *iter;
68
69
70
	FILE *fh;
	double den;
	int ctot, nout;
Thomas White's avatar
Thomas White committed
71
72

	if ( cell == NULL ) {
Thomas White's avatar
Thomas White committed
73
		ERROR("Need the unit cell to plot resolution shells.\n");
Thomas White's avatar
Thomas White committed
74
75
76
77
78
		return;
	}

	for ( i=0; i<NBINS; i++ ) {
		num[i] = 0.0;
Thomas White's avatar
Thomas White committed
79
		cts[i] = 0;
80
81
		measured[i] = 0;
		measurements[i] = 0;
82
		snr[i] = 0;
Thomas White's avatar
Thomas White committed
83
84
	}

85
86
	/* Find resolution limits */
	resolution_limits(list1, cell, &rmin, &rmax);
87
	STATUS("1/d goes from %f to %f nm^-1\n", rmin/1e9, rmax/1e9);
88

89
90
	/* Widen the range just a little bit */
	rmin -= 0.001e9;
91
92
	rmax += 0.001e9;

93
94
95
	/* Fixed resolution shells if needed */
	if ( rmin_fix > 0.0 ) rmin = rmin_fix;
	if ( rmax_fix > 0.0 ) rmax = rmax_fix;
96

Thomas White's avatar
Thomas White committed
97
	/* Calculate the resolution bins */
98
99
100
101
102
103
104
105
106
107
	total_vol = pow(rmax, 3.0) - pow(rmin, 3.0);
	vol_per_shell = total_vol / NBINS;
	rmins[0] = rmin;
	for ( i=1; i<NBINS; i++ ) {

		double r;

		r = vol_per_shell + pow(rmins[i-1], 3.0);
		r = pow(r, 1.0/3.0);

108
		/* Shells of constant volume */
109
110
111
		rmaxs[i-1] = r;
		rmins[i] = r;

112
113
114
115
		/* Shells of constant thickness */
		//rmins[i] = rmins[i-1] + (rmax-rmin)/NBINS;
		//rmaxs[i-1] = rmins[i-1] + (rmax-rmin)/NBINS;

116
117
118
119
120
121
122
123
		STATUS("Shell %i: %f to %f\n", i-1,
		       rmins[i-1]/1e9, rmaxs[i-1]/1e9);

	}
	rmaxs[NBINS-1] = rmax;
	STATUS("Shell %i: %f to %f\n", NBINS-1,
	       rmins[NBINS-1]/1e9, rmaxs[NBINS-1]/1e9);

124
	den = 0.0;  ctot = 0;  nout = 0;
Thomas White's avatar
Thomas White committed
125
126
	for ( refl1 = first_refl(list1, &iter);
	      refl1 != NULL;
127
128
	      refl1 = next_refl(refl1, iter) )
	{
Thomas White's avatar
Thomas White committed
129
		signed int h, k, l;
130
		double d;
Thomas White's avatar
Thomas White committed
131
		int bin;
132
		double i1, i2;
133
		int j;
134
		Reflection *refl2;
Thomas White's avatar
Thomas White committed
135

Thomas White's avatar
Thomas White committed
136
		get_indices(refl1, &h, &k, &l);
137
		d = 2.0 * resolution(cell, h, k, l);
Thomas White's avatar
Thomas White committed
138

139
140
141
142
143
144
145
		bin = -1;
		for ( j=0; j<NBINS; j++ ) {
			if ( (d>rmins[j]) && (d<=rmaxs[j]) ) {
				bin = j;
				break;
			}
		}
146
147

		/* Outside resolution range? */
148
149
150
151
		if ( bin == -1 ) {
			nout++;
			continue;
		}
Thomas White's avatar
Thomas White committed
152

153
154
155
		refl2 = find_refl(list2, h, k, l);
		if ( refl2 == NULL ) continue;

Thomas White's avatar
Thomas White committed
156
		i1 = get_intensity(refl1);
157
		i2 = scale * get_intensity(refl2);
Thomas White's avatar
Thomas White committed
158

Thomas White's avatar
Thomas White committed
159
		num[bin] += fabs(i1 - i2);
160
		den += i1 + i2;
Thomas White's avatar
Thomas White committed
161
		ctot++;
162
		cts[bin]++;
Thomas White's avatar
Thomas White committed
163
164
	}

165
166
167
168
169
	if ( nout ) {
		STATUS("Warning; %i reflections outside resolution range.\n",
		       nout);
	}

170
171
172
173
174
175
176
177
	fh = fopen("shells.dat", "w");
	if ( fh == NULL ) {
		ERROR("Couldn't open 'shells.dat'\n");
		return;
	}

	fprintf(fh, "1/d centre   Rsplit / %%\n");

Thomas White's avatar
Thomas White committed
178
179
	for ( i=0; i<NBINS; i++ ) {

180
		double r, cen;
181
		cen = rmins[i] + (rmaxs[i] - rmins[i])/2.0;
182
		r = (2.0*(num[i]/den)*((double)ctot/cts[i]))/sqrt(2.0);
183
184
		fprintf(fh, "%10.3f %10.2f %10i\n",
		        cen*1.0e-9, r*100.0, cts[i]);
Thomas White's avatar
Thomas White committed
185
186
187
188

	}

	fclose(fh);
Thomas White's avatar
Thomas White committed
189
190

	STATUS("Resolution shell information written to shells.dat.\n");
Thomas White's avatar
Thomas White committed
191
192
193
}


194
195
196
int main(int argc, char *argv[])
{
	int c;
197
	UnitCell *cell;
Thomas White's avatar
Thomas White committed
198
	char *ratiofile = NULL;
199
200
	char *afile = NULL;
	char *bfile = NULL;
Thomas White's avatar
Thomas White committed
201
202
	char *sym_str = NULL;
	SymOpList *sym;
203
	double scale, scale_r2, scale_rdig, R1, R2, R1i, Rdiff, pearson;
204
	double scale_rintint, scale_r1i, scale_r1, scale_r1fi;
Thomas White's avatar
Thomas White committed
205
206
207
	int ncom;
	RefList *list1;
	RefList *list2;
208
209
	RefList *list1_raw;
	RefList *list2_raw;
Thomas White's avatar
Thomas White committed
210
	RefList *ratio;
Thomas White's avatar
Thomas White committed
211
	int config_shells = 0;
212
	char *pdb = NULL;
213
214
	float rmin_fix = -1.0;
	float rmax_fix = -1.0;
Thomas White's avatar
Thomas White committed
215
216
	Reflection *refl1;
	RefListIterator *iter;
217
	int config_unity = 0;
218
219
220
221

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
Thomas White's avatar
Thomas White committed
222
		{"ratio" ,             1, NULL,               'o'},
223
		{"symmetry",           1, NULL,               'y'},
Thomas White's avatar
Thomas White committed
224
		{"shells",             0, &config_shells,     1},
225
		{"pdb",                1, NULL,               'p'},
226
227
		{"rmin",               1, NULL,               2},
		{"rmax",               1, NULL,               3},
228
229
230
231
		{0, 0, NULL, 0}
	};

	/* Short options */
232
233
234
	while ((c = getopt_long(argc, argv, "ho:y:p:u",
	                        longopts, NULL)) != -1)
	{
235
236

		switch (c) {
Thomas White's avatar
Thomas White committed
237
		case 'h' :
238
239
240
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
241
		case 'o' :
Thomas White's avatar
Thomas White committed
242
			ratiofile = strdup(optarg);
243
244
			break;

245
		case 'y' :
Thomas White's avatar
Thomas White committed
246
			sym_str = strdup(optarg);
247
248
			break;

249
250
251
252
		case 'p' :
			pdb = strdup(optarg);
			break;

253
254
255
256
		case 'u' :
			config_unity = 1;
			break;

Thomas White's avatar
Thomas White committed
257
		case 0 :
258
259
			break;

260
261
262
263
264
265
266
267
268
269
270
271
272
273
		case 2 :
			if ( sscanf(optarg, "%e", &rmin_fix) != 1 ) {
				ERROR("Invalid value for --rmin\n");
				return 1;
			}
			break;

		case 3 :
			if ( sscanf(optarg, "%e", &rmax_fix) != 1 ) {
				ERROR("Invalid value for --rmax\n");
				return 1;
			}
			break;

Thomas White's avatar
Thomas White committed
274
		default :
275
276
277
278
279
			return 1;
		}

	}

280
281
282
283
284
	if ( argc != (optind+2) ) {
		ERROR("Please provide exactly two HKL files to compare.\n");
		return 1;
	}

Thomas White's avatar
Thomas White committed
285
286
	if ( sym_str == NULL ) {
		sym_str = strdup("1");
287
	}
Thomas White's avatar
Thomas White committed
288
289
	sym = get_pointgroup(sym_str);
	free(sym_str);
290

291
292
293
	afile = strdup(argv[optind++]);
	bfile = strdup(argv[optind]);

294
295
296
297
298
299
300
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

	cell = load_cell_from_pdb(pdb);
	free(pdb);

301
302
	list1_raw = read_reflections(afile);
	if ( list1_raw == NULL ) {
Thomas White's avatar
Thomas White committed
303
		ERROR("Couldn't read file '%s'\n", afile);
304
305
		return 1;
	}
Thomas White's avatar
Thomas White committed
306

307
308
	list2_raw = read_reflections(bfile);
	if ( list2_raw == NULL ) {
Thomas White's avatar
Thomas White committed
309
		ERROR("Couldn't read file '%s'\n", bfile);
310
311
312
		return 1;
	}

Thomas White's avatar
Thomas White committed
313
	/* Check that the intensities have the correct symmetry */
314
	if ( check_list_symmetry(list1_raw, sym) ) {
Thomas White's avatar
Thomas White committed
315
		ERROR("The first input reflection list does not appear to"
Thomas White's avatar
Thomas White committed
316
		      " have symmetry %s\n", symmetry_name(sym));
Thomas White's avatar
Thomas White committed
317
318
		return 1;
	}
319
	if ( check_list_symmetry(list2_raw, sym) ) {
Thomas White's avatar
Thomas White committed
320
		ERROR("The second input reflection list does not appear to"
Thomas White's avatar
Thomas White committed
321
		      " have symmetry %s\n", symmetry_name(sym));
Thomas White's avatar
Thomas White committed
322
323
324
		return 1;
	}

325
326
327
328
	list1 = asymmetric_indices(list1_raw, sym);
	list2 = asymmetric_indices(list2_raw, sym);

	/* Find common reflections and calculate ratio */
Thomas White's avatar
Thomas White committed
329
	ratio = reflist_new();
330
	ncom = 0;
Thomas White's avatar
Thomas White committed
331
332
	for ( refl1 = first_refl(list1, &iter);
	      refl1 != NULL;
Thomas White's avatar
Thomas White committed
333
334
	      refl1 = next_refl(refl1, iter) )
	{
Thomas White's avatar
Thomas White committed
335
		signed int h, k, l;
336
		double val1, val2;
Thomas White's avatar
Thomas White committed
337
338
		Reflection *refl2;
		Reflection *tr;
339

Thomas White's avatar
Thomas White committed
340
		get_indices(refl1, &h, &k, &l);
341

342
343
		refl2 = find_refl(list2, h, k, l);
		if ( refl2 == NULL ) continue;
344

345
		ncom++;
Thomas White's avatar
Thomas White committed
346
347
348
349
350
351
352

		val1 = get_intensity(refl1);
		val2 = get_intensity(refl2);

		/* Add divided version to 'output' list */
		tr = add_refl(ratio, h, k, l);
		set_int(tr, val1/val2);
353
		set_redundancy(tr, 1);
354
	}
Thomas White's avatar
Thomas White committed
355

356
357
358
359
360
	if ( ratiofile != NULL ) {
		write_reflist(ratiofile, ratio, cell);
	}
	reflist_free(ratio);

361
362
	gsl_set_error_handler_off();

Thomas White's avatar
Thomas White committed
363
	STATUS("%i,%i reflections: %i in common\n",
Thomas White's avatar
Thomas White committed
364
365
	       num_reflections(list1), num_reflections(list2), ncom);

366
	R1 = stat_r1_ignore(list1, list2, &scale_r1fi, config_unity);
Thomas White's avatar
Thomas White committed
367
368
	STATUS("R1(F) = %5.4f %% (scale=%5.2e)"
	       " (ignoring negative intensities)\n",
369
	       R1*100.0, scale_r1fi);
Thomas White's avatar
Thomas White committed
370

371
	R1 = stat_r1_zero(list1, list2, &scale_r1, config_unity);
Thomas White's avatar
Thomas White committed
372
373
	STATUS("R1(F) = %5.4f %% (scale=%5.2e)"
	       " (zeroing negative intensities)\n",
374
	       R1*100.0, scale_r1);
Thomas White's avatar
Thomas White committed
375

376
	R2 = stat_r2(list1, list2, &scale_r2, config_unity);
377
	STATUS("R2(I) = %5.4f %% (scale=%5.2e)\n", R2*100.0, scale_r2);
Thomas White's avatar
Thomas White committed
378

379
	R1i = stat_r1_i(list1, list2, &scale_r1i, config_unity);
380
	STATUS("R1(I) = %5.4f %% (scale=%5.2e)\n", R1i*100.0, scale_r1i);
Thomas White's avatar
Thomas White committed
381

382
	Rdiff = stat_rdiff_ignore(list1, list2, &scale_rdig,
383
	                          config_unity);
Thomas White's avatar
Thomas White committed
384
385
	STATUS("Rint(F) = %5.4f %% (scale=%5.2e)"
	       " (ignoring negative intensities)\n",
386
	       Rdiff*100.0, scale_rdig);
Thomas White's avatar
Thomas White committed
387

388
	Rdiff = stat_rdiff_zero(list1, list2, &scale, config_unity);
Thomas White's avatar
Thomas White committed
389
390
	STATUS("Rint(F) = %5.4f %% (scale=%5.2e)"
	       " (zeroing negative intensities)\n",
Thomas White's avatar
Thomas White committed
391
392
	       Rdiff*100.0, scale);

393
	Rdiff = stat_rdiff_intensity(list1, list2, &scale_rintint,
394
	                             config_unity);
Thomas White's avatar
Thomas White committed
395
	STATUS("Rint(I) = %5.4f %% (scale=%5.2e)\n",
396
	       Rdiff*100.0, scale_rintint);
Thomas White's avatar
Thomas White committed
397

398
	pearson = stat_pearson_i(list1, list2);
Thomas White's avatar
Thomas White committed
399
400
	STATUS("Pearson r(I) = %5.4f\n", pearson);

401
	pearson = stat_pearson_f_ignore(list1, list2);
Thomas White's avatar
Thomas White committed
402
403
404
	STATUS("Pearson r(F) = %5.4f (ignoring negative intensities)\n",
	       pearson);

405
	pearson = stat_pearson_f_zero(list1, list2);
Thomas White's avatar
Thomas White committed
406
407
	STATUS("Pearson r(F) = %5.4f (zeroing negative intensities)\n",
	       pearson);
Thomas White's avatar
Thomas White committed
408

Thomas White's avatar
Thomas White committed
409
	if ( config_shells ) {
410
		plot_shells(list1, list2, scale_rintint,
411
		            cell, rmin_fix, rmax_fix);
Thomas White's avatar
Thomas White committed
412
413
	}

414
415
	return 0;
}