compare_hkl.c 11.8 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
static void plot_shells(RefList *list1, double *arr2, double scale,
Thomas White's avatar
Thomas White committed
54
                        UnitCell *cell, const SymOpList *sym,
Thomas White's avatar
Thomas White committed
55
                        double rmin_fix, double rmax_fix)
Thomas White's avatar
Thomas White committed
56
57
{
	double num[NBINS];
Thomas White's avatar
Thomas White committed
58
	int cts[NBINS];
59
60
61
62
63
64
65
	int possible[NBINS];
	unsigned int *counted;
	unsigned int measurements[NBINS];
	unsigned int measured[NBINS];
	double total_vol, vol_per_shell;
	double rmins[NBINS];
	double rmaxs[NBINS];
66
	double snr[NBINS];
Thomas White's avatar
Thomas White committed
67
	double den;
68
69
	double rmin, rmax;
	signed int h, k, l;
Thomas White's avatar
Thomas White committed
70
	int i;
Thomas White's avatar
Thomas White committed
71
	int ctot;
Thomas White's avatar
Thomas White committed
72
	FILE *fh;
73
	int nout = 0;
Thomas White's avatar
Thomas White committed
74
75
76
77
78
79
	Reflection *refl1;
	RefListIterator *iter;
	double asx, asy, asz;
	double bsx, bsy, bsz;
	double csx, csy, csz;
	int hmax, kmax, lmax;
Thomas White's avatar
Thomas White committed
80
81

	if ( cell == NULL ) {
Thomas White's avatar
Thomas White committed
82
		ERROR("Need the unit cell to plot resolution shells.\n");
Thomas White's avatar
Thomas White committed
83
84
85
86
87
		return;
	}

	for ( i=0; i<NBINS; i++ ) {
		num[i] = 0.0;
Thomas White's avatar
Thomas White committed
88
		cts[i] = 0;
89
90
91
		possible[i] = 0;
		measured[i] = 0;
		measurements[i] = 0;
92
		snr[i] = 0;
Thomas White's avatar
Thomas White committed
93
94
	}

Thomas White's avatar
Thomas White committed
95
96
97
98
99
100
	/* Iterate over all common reflections and calculate min and max
	 * resolution */
	rmin = +INFINITY;  rmax = 0.0;
	for ( refl1 = first_refl(list1, &iter);
	      refl1 != NULL;
	      refl1 = next_refl(refl1, iter) ) {
Thomas White's avatar
Thomas White committed
101
102

		signed int h, k, l;
103
		double d;
Thomas White's avatar
Thomas White committed
104

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

107
		d = resolution(cell, h, k, l) * 2.0;
108
109
		if ( d > rmax ) rmax = d;
		if ( d < rmin ) rmin = d;
Thomas White's avatar
Thomas White committed
110
111

	}
112

113
	STATUS("1/d goes from %f to %f nm^-1\n", rmin/1e9, rmax/1e9);
114

115
116
	/* Widen the range just a little bit */
	rmin -= 0.001e9;
117
118
	rmax += 0.001e9;

119
120
121
	/* Fixed resolution shells if needed */
	if ( rmin_fix > 0.0 ) rmin = rmin_fix;
	if ( rmax_fix > 0.0 ) rmax = rmax_fix;
122

Thomas White's avatar
Thomas White committed
123
	/* Calculate the resolution bins */
124
125
126
127
128
129
130
131
132
133
	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);

134
		/* Shells of constant volume */
135
136
137
		rmaxs[i-1] = r;
		rmins[i] = r;

138
139
140
141
		/* Shells of constant thickness */
		//rmins[i] = rmins[i-1] + (rmax-rmin)/NBINS;
		//rmaxs[i-1] = rmins[i-1] + (rmax-rmin)/NBINS;

142
143
144
145
146
147
148
149
150
151
		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);

	/* Count the number of reflections possible in each shell */
	counted = new_list_count();
Thomas White's avatar
Thomas White committed
152
153
154
155
156
157
158
159
160
161
	cell_get_reciprocal(cell, &asx, &asy, &asz,
	                          &bsx, &bsy, &bsz,
	                          &csx, &csy, &csz);
	hmax = rmax / modulus(asx, asy, asz);
	kmax = rmax / modulus(bsx, bsy, bsz);
	lmax = rmax / modulus(csx, csy, csz);

	for ( h=-hmax; h<hmax; h++ ) {
	for ( k=-kmax; k<kmax; k++ ) {
	for ( l=-lmax; l<lmax; l++ ) {
162
163
164
165
166

		double d;
		signed int hs, ks, ls;
		int bin;

Thomas White's avatar
Thomas White committed
167
		get_asymm(sym, h, k, l, &hs, &ks, &ls);
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
		if ( lookup_count(counted, hs, ks, ls) ) continue;
		set_count(counted, hs, ks, ls, 1);

		d = resolution(cell, h, k, l) * 2.0;

		bin = -1;
		for ( i=0; i<NBINS; i++ ) {
			if ( (d>rmins[i]) && (d<=rmaxs[i]) ) {
				bin = i;
				break;
			}
		}
		if ( bin == -1 ) continue;

		possible[bin]++;

	}
	}
	}
	free(counted);

Thomas White's avatar
Thomas White committed
189
	den = 0.0;
Thomas White's avatar
Thomas White committed
190
	ctot = 0;
191
	nout = 0;
Thomas White's avatar
Thomas White committed
192

Thomas White's avatar
Thomas White committed
193
194
195
196
	for ( refl1 = first_refl(list1, &iter);
	      refl1 != NULL;
	      refl1 = next_refl(refl1, iter) ) {

Thomas White's avatar
Thomas White committed
197
		signed int h, k, l;
198
		double d;
Thomas White's avatar
Thomas White committed
199
		int bin;
200
		double i1, i2;
201
		int j;
Thomas White's avatar
Thomas White committed
202

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

205
		d = resolution(cell, h, k, l) * 2.0;
Thomas White's avatar
Thomas White committed
206

207
208
209
210
211
212
213
		bin = -1;
		for ( j=0; j<NBINS; j++ ) {
			if ( (d>rmins[j]) && (d<=rmaxs[j]) ) {
				bin = j;
				break;
			}
		}
214
215

		/* Outside resolution range? */
216
217
218
219
		if ( bin == -1 ) {
			nout++;
			continue;
		}
Thomas White's avatar
Thomas White committed
220

Thomas White's avatar
Thomas White committed
221
		i1 = get_intensity(refl1);
222
		i2 = scale * lookup_intensity(arr2, h, k, l);
Thomas White's avatar
Thomas White committed
223

Thomas White's avatar
Thomas White committed
224
		num[bin] += fabs(i1 - i2);
225
		den += i1 + i2;
Thomas White's avatar
Thomas White committed
226
		ctot++;
227
		cts[bin]++;
Thomas White's avatar
Thomas White committed
228
229
230

	}

231
232
233
234
235
	if ( nout ) {
		STATUS("Warning; %i reflections outside resolution range.\n",
		       nout);
	}

236
237
238
239
240
241
242
243
	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
244
245
	for ( i=0; i<NBINS; i++ ) {

246
		double r, cen;
247
		cen = rmins[i] + (rmaxs[i] - rmins[i])/2.0;
248
249
		r = (2.0*(num[i]/den)*((double)ctot/cts[i]))/sqrt(2.0);
		fprintf(fh, "%10.3f %10.2f\n", cen*1.0e-9, r*100.0);
Thomas White's avatar
Thomas White committed
250
251
252
253

	}

	fclose(fh);
Thomas White's avatar
Thomas White committed
254
255

	STATUS("Resolution shell information written to shells.dat.\n");
Thomas White's avatar
Thomas White committed
256
257
258
}


259
260
261
int main(int argc, char *argv[])
{
	int c;
262
	UnitCell *cell;
Thomas White's avatar
Thomas White committed
263
	char *ratiofile = NULL;
264
265
	char *afile = NULL;
	char *bfile = NULL;
Thomas White's avatar
Thomas White committed
266
267
	char *sym_str = NULL;
	SymOpList *sym;
268
	double scale, scale_r2, scale_rdig, R1, R2, R1i, Rdiff, pearson;
269
	double scale_rintint, scale_r1i, scale_r1, scale_r1fi;
Thomas White's avatar
Thomas White committed
270
271
272
	int ncom;
	RefList *list1;
	RefList *list2;
273
	RefList *list1_transformed;
Thomas White's avatar
Thomas White committed
274
275
	RefList *list2_transformed;
	RefList *ratio;
Thomas White's avatar
Thomas White committed
276
	int config_shells = 0;
277
	char *pdb = NULL;
278
279
	int rej1 = 0;
	int rej2 = 0;
280
281
	float rmin_fix = -1.0;
	float rmax_fix = -1.0;
Thomas White's avatar
Thomas White committed
282
283
	Reflection *refl1;
	RefListIterator *iter;
284
	double *arr2;
285
	int config_unity = 0;
286
287
288
289

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
Thomas White's avatar
Thomas White committed
290
		{"ratio" ,             1, NULL,               'o'},
291
		{"symmetry",           1, NULL,               'y'},
Thomas White's avatar
Thomas White committed
292
		{"shells",             0, &config_shells,     1},
293
		{"pdb",                1, NULL,               'p'},
294
295
		{"rmin",               1, NULL,               2},
		{"rmax",               1, NULL,               3},
296
297
298
299
		{0, 0, NULL, 0}
	};

	/* Short options */
300
301
302
	while ((c = getopt_long(argc, argv, "ho:y:p:u",
	                        longopts, NULL)) != -1)
	{
303
304

		switch (c) {
Thomas White's avatar
Thomas White committed
305
		case 'h' :
306
307
308
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
309
		case 'o' :
Thomas White's avatar
Thomas White committed
310
			ratiofile = strdup(optarg);
311
312
			break;

313
		case 'y' :
Thomas White's avatar
Thomas White committed
314
			sym_str = strdup(optarg);
315
316
			break;

317
318
319
320
		case 'p' :
			pdb = strdup(optarg);
			break;

321
322
323
324
		case 'u' :
			config_unity = 1;
			break;

Thomas White's avatar
Thomas White committed
325
		case 0 :
326
327
			break;

328
329
330
331
332
333
334
335
336
337
338
339
340
341
		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
342
		default :
343
344
345
346
347
			return 1;
		}

	}

348
349
350
351
352
	if ( argc != (optind+2) ) {
		ERROR("Please provide exactly two HKL files to compare.\n");
		return 1;
	}

Thomas White's avatar
Thomas White committed
353
354
	if ( sym_str == NULL ) {
		sym_str = strdup("1");
355
	}
Thomas White's avatar
Thomas White committed
356
357
	sym = get_pointgroup(sym_str);
	free(sym_str);
358

359
360
361
	afile = strdup(argv[optind++]);
	bfile = strdup(argv[optind]);

362
363
364
365
366
367
368
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

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

Thomas White's avatar
Thomas White committed
369
370
371
	list1 = read_reflections(afile);
	if ( list1 == NULL ) {
		ERROR("Couldn't read file '%s'\n", afile);
372
373
		return 1;
	}
Thomas White's avatar
Thomas White committed
374
375
376
377

	list2 = read_reflections(bfile);
	if ( list2 == NULL ) {
		ERROR("Couldn't read file '%s'\n", bfile);
378
379
380
		return 1;
	}

Thomas White's avatar
Thomas White committed
381
	/* Check that the intensities have the correct symmetry */
Thomas White's avatar
Thomas White committed
382
	if ( check_list_symmetry(list1, sym) ) {
Thomas White's avatar
Thomas White committed
383
		ERROR("The first input reflection list does not appear to"
Thomas White's avatar
Thomas White committed
384
		      " have symmetry %s\n", symmetry_name(sym));
Thomas White's avatar
Thomas White committed
385
386
		return 1;
	}
Thomas White's avatar
Thomas White committed
387
	if ( check_list_symmetry(list2, sym) ) {
Thomas White's avatar
Thomas White committed
388
		ERROR("The second input reflection list does not appear to"
Thomas White's avatar
Thomas White committed
389
		      " have symmetry %s\n", symmetry_name(sym));
Thomas White's avatar
Thomas White committed
390
391
392
		return 1;
	}

393
	/* Find common reflections (taking symmetry into account) */
394
	list1_transformed = reflist_new();
Thomas White's avatar
Thomas White committed
395
396
397
398
	list2_transformed = reflist_new();
	ratio = reflist_new();
	for ( refl1 = first_refl(list1, &iter);
	      refl1 != NULL;
Thomas White's avatar
Thomas White committed
399
400
	      refl1 = next_refl(refl1, iter) )
	{
Thomas White's avatar
Thomas White committed
401
		signed int h, k, l;
402
403
		signed int he, ke, le;
		double val1, val2;
404
405
		double sig1, sig2;
		int ig = 0;
406
		double d;
Thomas White's avatar
Thomas White committed
407
408
		Reflection *refl2;
		Reflection *tr;
409

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

Thomas White's avatar
Thomas White committed
412
		if ( !find_equiv_in_list(list2, h, k, l, sym, &he, &ke, &le) ) {
413
414
			continue;
		}
415

416
417
		copy_data(add_refl(list1_transformed, h, k, l), refl1);

Thomas White's avatar
Thomas White committed
418
419
420
421
422
423
424
		refl2 = find_refl(list2, he, ke, le);
		assert(refl2 != NULL);

		val1 = get_intensity(refl1);
		val2 = get_intensity(refl2);
		sig1 = get_esd_intensity(refl1);
		sig2 = get_esd_intensity(refl2);
425
426
427
428
429
430
431
432
433

		if ( val1 < 3.0 * sig1 ) {
			rej1++;
			ig = 1;
		}
		if ( val2 < 3.0 * sig2 ) {
			rej2++;
			ig = 1;
		}
434
435
436
437
438

		d = 0.5/resolution(cell, h, k, l);
		if ( d > 55.0e-10 ) ig = 1;
		//if ( d < 15.0e-10 ) ig = 1;

439
		//if ( ig ) continue;
440

Thomas White's avatar
Thomas White committed
441
442
443
444
445
446
447
448
		/* Add the old data from 'refl2' to a new list with the same
		 * indices as its equivalent in 'list1' */
		tr = add_refl(list2_transformed, h, k, l);
		copy_data(tr, refl2);

		/* Add divided version to 'output' list */
		tr = add_refl(ratio, h, k, l);
		set_int(tr, val1/val2);
449
		set_redundancy(tr, 1);
450
451

	}
Thomas White's avatar
Thomas White committed
452

453
454
455
456
457
	if ( ratiofile != NULL ) {
		write_reflist(ratiofile, ratio, cell);
	}
	reflist_free(ratio);

458
459
	gsl_set_error_handler_off();

Thomas White's avatar
Thomas White committed
460
461
	STATUS("%i reflections in '%s' had I < 3.0*sigma(I)\n", rej1, afile);
	STATUS("%i reflections in '%s' had I < 3.0*sigma(I)\n", rej2, bfile);
462

Thomas White's avatar
Thomas White committed
463
	ncom = num_reflections(list2_transformed);
Thomas White's avatar
Thomas White committed
464
	STATUS("%i,%i reflections: %i in common\n",
Thomas White's avatar
Thomas White committed
465
466
	       num_reflections(list1), num_reflections(list2), ncom);

467
	reflist_free(list1);
Thomas White's avatar
Thomas White committed
468
469
	reflist_free(list2);

470
471
472
473
474
	/* Trimming the other way round is not necessary,
	 * because of these two lines */
	arr2 = intensities_from_list(list2_transformed);
	reflist_free(list2_transformed);

475
	R1 = stat_r1_ignore(list1_transformed, arr2, &scale_r1fi, config_unity);
Thomas White's avatar
Thomas White committed
476
477
	STATUS("R1(F) = %5.4f %% (scale=%5.2e)"
	       " (ignoring negative intensities)\n",
478
	       R1*100.0, scale_r1fi);
Thomas White's avatar
Thomas White committed
479

480
	R1 = stat_r1_zero(list1_transformed, arr2, &scale_r1, config_unity);
Thomas White's avatar
Thomas White committed
481
482
	STATUS("R1(F) = %5.4f %% (scale=%5.2e)"
	       " (zeroing negative intensities)\n",
483
	       R1*100.0, scale_r1);
Thomas White's avatar
Thomas White committed
484

485
	R2 = stat_r2(list1_transformed, arr2, &scale_r2, config_unity);
486
	STATUS("R2(I) = %5.4f %% (scale=%5.2e)\n", R2*100.0, scale_r2);
Thomas White's avatar
Thomas White committed
487

488
	R1i = stat_r1_i(list1_transformed, arr2, &scale_r1i, config_unity);
489
	STATUS("R1(I) = %5.4f %% (scale=%5.2e)\n", R1i*100.0, scale_r1i);
Thomas White's avatar
Thomas White committed
490

491
492
	Rdiff = stat_rdiff_ignore(list1_transformed, arr2, &scale_rdig,
	                          config_unity);
Thomas White's avatar
Thomas White committed
493
494
	STATUS("Rint(F) = %5.4f %% (scale=%5.2e)"
	       " (ignoring negative intensities)\n",
495
	       Rdiff*100.0, scale_rdig);
Thomas White's avatar
Thomas White committed
496

497
	Rdiff = stat_rdiff_zero(list1_transformed, arr2, &scale, config_unity);
Thomas White's avatar
Thomas White committed
498
499
	STATUS("Rint(F) = %5.4f %% (scale=%5.2e)"
	       " (zeroing negative intensities)\n",
Thomas White's avatar
Thomas White committed
500
501
	       Rdiff*100.0, scale);

502
503
	Rdiff = stat_rdiff_intensity(list1_transformed, arr2, &scale_rintint,
	                             config_unity);
Thomas White's avatar
Thomas White committed
504
	STATUS("Rint(I) = %5.4f %% (scale=%5.2e)\n",
505
	       Rdiff*100.0, scale_rintint);
Thomas White's avatar
Thomas White committed
506

507
	pearson = stat_pearson_i(list1_transformed, arr2);
Thomas White's avatar
Thomas White committed
508
509
	STATUS("Pearson r(I) = %5.4f\n", pearson);

510
	pearson = stat_pearson_f_ignore(list1_transformed, arr2);
Thomas White's avatar
Thomas White committed
511
512
513
	STATUS("Pearson r(F) = %5.4f (ignoring negative intensities)\n",
	       pearson);

514
	pearson = stat_pearson_f_zero(list1_transformed, arr2);
Thomas White's avatar
Thomas White committed
515
516
	STATUS("Pearson r(F) = %5.4f (zeroing negative intensities)\n",
	       pearson);
Thomas White's avatar
Thomas White committed
517

Thomas White's avatar
Thomas White committed
518
	if ( config_shells ) {
519
		plot_shells(list1_transformed, arr2, scale_r1i,
520
		            cell, sym, rmin_fix, rmax_fix);
Thomas White's avatar
Thomas White committed
521
522
	}

523
524
	return 0;
}