compare_hkl.c 11.4 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
25

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


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


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


52
static void plot_shells(RefList *list1, double *arr2, double scale,
Thomas White's avatar
Thomas White committed
53
54
                        UnitCell *cell, const char *sym,
                        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
63
64
	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];
65
	double snr[NBINS];
Thomas White's avatar
Thomas White committed
66
	double den;
67
68
	double rmin, rmax;
	signed int h, k, l;
Thomas White's avatar
Thomas White committed
69
	int i;
Thomas White's avatar
Thomas White committed
70
	int ctot;
Thomas White's avatar
Thomas White committed
71
	FILE *fh;
72
	int nout = 0;
Thomas White's avatar
Thomas White committed
73
74
75
76
77
78
	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
79
80

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

Thomas White's avatar
Thomas White committed
85
	fh = fopen("shells.dat", "w");
Thomas White's avatar
Thomas White committed
86
	if ( fh == NULL ) {
Thomas White's avatar
Thomas White committed
87
		ERROR("Couldn't open 'shells.dat'\n");
Thomas White's avatar
Thomas White committed
88
89
90
91
92
		return;
	}

	for ( i=0; i<NBINS; i++ ) {
		num[i] = 0.0;
Thomas White's avatar
Thomas White committed
93
		cts[i] = 0;
94
95
96
		possible[i] = 0;
		measured[i] = 0;
		measurements[i] = 0;
97
		snr[i] = 0;
Thomas White's avatar
Thomas White committed
98
99
	}

Thomas White's avatar
Thomas White committed
100
101
102
103
104
105
	/* 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
106
107

		signed int h, k, l;
108
		double d;
Thomas White's avatar
Thomas White committed
109

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

112
		d = resolution(cell, h, k, l) * 2.0;
113
114
		if ( d > rmax ) rmax = d;
		if ( d < rmin ) rmin = d;
Thomas White's avatar
Thomas White committed
115
116

	}
117

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

120
121
	/* Widen the range just a little bit */
	rmin -= 0.001e9;
122
123
	rmax += 0.001e9;

124
125
126
	/* Fixed resolution shells if needed */
	if ( rmin_fix > 0.0 ) rmin = rmin_fix;
	if ( rmax_fix > 0.0 ) rmax = rmax_fix;
127

Thomas White's avatar
Thomas White committed
128
	/* Calculate the resolution bins */
129
130
131
132
133
134
135
136
137
138
	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);

139
		/* Shells of constant volume */
140
141
142
		rmaxs[i-1] = r;
		rmins[i] = r;

143
144
145
146
		/* Shells of constant thickness */
		//rmins[i] = rmins[i-1] + (rmax-rmin)/NBINS;
		//rmaxs[i-1] = rmins[i-1] + (rmax-rmin)/NBINS;

147
148
149
150
151
152
153
154
155
156
		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
157
158
159
160
161
162
163
164
165
166
	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++ ) {
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193

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

		get_asymm(h, k, l, &hs, &ks, &ls, sym);
		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
194
	den = 0.0;
Thomas White's avatar
Thomas White committed
195
	ctot = 0;
196
	nout = 0;
Thomas White's avatar
Thomas White committed
197

Thomas White's avatar
Thomas White committed
198
199
200
201
	for ( refl1 = first_refl(list1, &iter);
	      refl1 != NULL;
	      refl1 = next_refl(refl1, iter) ) {

Thomas White's avatar
Thomas White committed
202
		signed int h, k, l;
203
		double d;
Thomas White's avatar
Thomas White committed
204
		int bin;
205
		double i1, i2;
206
		int j;
Thomas White's avatar
Thomas White committed
207

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

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

212
213
214
215
216
217
218
		bin = -1;
		for ( j=0; j<NBINS; j++ ) {
			if ( (d>rmins[j]) && (d<=rmaxs[j]) ) {
				bin = j;
				break;
			}
		}
219
220

		/* Outside resolution range? */
221
222
223
224
		if ( bin == -1 ) {
			nout++;
			continue;
		}
Thomas White's avatar
Thomas White committed
225

Thomas White's avatar
Thomas White committed
226
		i1 = get_intensity(refl1);
227
		i2 = scale * lookup_intensity(arr2, h, k, l);
Thomas White's avatar
Thomas White committed
228

Thomas White's avatar
Thomas White committed
229
		num[bin] += fabs(i1 - i2);
230
		den += i1;
Thomas White's avatar
Thomas White committed
231
		ctot++;
232
		cts[bin]++;
Thomas White's avatar
Thomas White committed
233
234
235

	}

236
237
238
239
240
	if ( nout ) {
		STATUS("Warning; %i reflections outside resolution range.\n",
		       nout);
	}

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

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

	}

	fclose(fh);
}


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

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
Thomas White's avatar
Thomas White committed
283
		{"ratio" ,             1, NULL,               'o'},
284
		{"symmetry",           1, NULL,               'y'},
Thomas White's avatar
Thomas White committed
285
		{"shells",             0, &config_shells,     1},
286
		{"pdb",                1, NULL,               'p'},
287
288
		{"rmin",               1, NULL,               2},
		{"rmax",               1, NULL,               3},
289
290
291
292
		{0, 0, NULL, 0}
	};

	/* Short options */
293
	while ((c = getopt_long(argc, argv, "ho:y:p:", longopts, NULL)) != -1) {
294
295

		switch (c) {
Thomas White's avatar
Thomas White committed
296
		case 'h' :
297
298
299
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
300
		case 'o' :
Thomas White's avatar
Thomas White committed
301
			ratiofile = strdup(optarg);
302
303
			break;

304
305
306
307
		case 'y' :
			sym = strdup(optarg);
			break;

308
309
310
311
		case 'p' :
			pdb = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
312
		case 0 :
313
314
			break;

315
316
317
318
319
320
321
322
323
324
325
326
327
328
		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
329
		default :
330
331
332
333
334
			return 1;
		}

	}

335
336
337
338
339
	if ( argc != (optind+2) ) {
		ERROR("Please provide exactly two HKL files to compare.\n");
		return 1;
	}

340
341
342
343
	if ( sym == NULL ) {
		sym = strdup("1");
	}

344
345
346
	afile = strdup(argv[optind++]);
	bfile = strdup(argv[optind]);

347
348
349
350
351
352
353
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

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

Thomas White's avatar
Thomas White committed
354
355
356
	list1 = read_reflections(afile);
	if ( list1 == NULL ) {
		ERROR("Couldn't read file '%s'\n", afile);
357
358
		return 1;
	}
Thomas White's avatar
Thomas White committed
359
360
361
362

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

Thomas White's avatar
Thomas White committed
366
	/* Check that the intensities have the correct symmetry */
Thomas White's avatar
Thomas White committed
367
	if ( check_list_symmetry(list1, sym) ) {
Thomas White's avatar
Thomas White committed
368
369
370
371
		ERROR("The first input reflection list does not appear to"
		      " have symmetry %s\n", sym);
		return 1;
	}
Thomas White's avatar
Thomas White committed
372
	if ( check_list_symmetry(list2, sym) ) {
Thomas White's avatar
Thomas White committed
373
374
375
376
377
		ERROR("The second input reflection list does not appear to"
		      " have symmetry %s\n", sym);
		return 1;
	}

378
	/* Find common reflections (taking symmetry into account) */
Thomas White's avatar
Thomas White committed
379
380
381
382
383
384
	list2_transformed = reflist_new();
	ratio = reflist_new();
	deleteme = reflist_new();
	for ( refl1 = first_refl(list1, &iter);
	      refl1 != NULL;
	      refl1 = next_refl(refl1, iter) ) {
385

Thomas White's avatar
Thomas White committed
386
		signed int h, k, l;
387
388
		signed int he, ke, le;
		double val1, val2;
389
390
		double sig1, sig2;
		int ig = 0;
391
		double d;
Thomas White's avatar
Thomas White committed
392
393
		Reflection *refl2;
		Reflection *tr;
394

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

Thomas White's avatar
Thomas White committed
397
398
399
		if ( !find_equiv_in_list(list2, h, k, l, sym, &he, &ke, &le) ) {
			/* No common reflection */
			add_refl(deleteme, h, k, l);
400
401
			continue;
		}
402

Thomas White's avatar
Thomas White committed
403
404
405
406
407
408
409
		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);
410
411
412
413
414
415
416
417
418

		if ( val1 < 3.0 * sig1 ) {
			rej1++;
			ig = 1;
		}
		if ( val2 < 3.0 * sig2 ) {
			rej2++;
			ig = 1;
		}
419
420
421
422
423

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

424
		//if ( ig ) continue;
425

Thomas White's avatar
Thomas White committed
426
427
428
429
430
431
432
433
		/* 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);
434
		set_redundancy(tr, 1);
435
436

	}
Thomas White's avatar
Thomas White committed
437

438
439
440
441
442
	if ( ratiofile != NULL ) {
		write_reflist(ratiofile, ratio, cell);
	}
	reflist_free(ratio);

Thomas White's avatar
Thomas White committed
443
444
	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);
445

Thomas White's avatar
Thomas White committed
446
	ncom = num_reflections(list2_transformed);
Thomas White's avatar
Thomas White committed
447
	STATUS("%i,%i reflections: %i in common\n",
Thomas White's avatar
Thomas White committed
448
449
450
451
452
453
	       num_reflections(list1), num_reflections(list2), ncom);

	/* Trim reflections from 'list1' which had no equivalents in 'list2' */
	for ( refl1 = first_refl(deleteme, &iter);
	      refl1 != NULL;
	      refl1 = next_refl(refl1, iter) ) {
Thomas White's avatar
Thomas White committed
454

Thomas White's avatar
Thomas White committed
455
456
457
458
459
460
461
462
463
464
465
466
467
		signed int h, k, l;
		Reflection *del;

		get_indices(refl1, &h, &k, &l);
		del = find_refl(list1, h, k, l);
		assert(del != NULL);

		delete_refl(del);

	}
	reflist_free(deleteme);
	reflist_free(list2);

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

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

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

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

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

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

494
	Rdiff = stat_rdiff_zero(list1, arr2, &scale);
Thomas White's avatar
Thomas White committed
495
496
	STATUS("Rint(F) = %5.4f %% (scale=%5.2e)"
	       " (zeroing negative intensities)\n",
Thomas White's avatar
Thomas White committed
497
498
	       Rdiff*100.0, scale);

499
	Rdiff = stat_rdiff_intensity(list1, arr2, &scale_rintint);
Thomas White's avatar
Thomas White committed
500
	STATUS("Rint(I) = %5.4f %% (scale=%5.2e)\n",
501
	       Rdiff*100.0, scale_rintint);
Thomas White's avatar
Thomas White committed
502

503
	pearson = stat_pearson_i(list1, arr2);
Thomas White's avatar
Thomas White committed
504
505
	STATUS("Pearson r(I) = %5.4f\n", pearson);

506
	pearson = stat_pearson_f_ignore(list1, arr2);
Thomas White's avatar
Thomas White committed
507
508
509
	STATUS("Pearson r(F) = %5.4f (ignoring negative intensities)\n",
	       pearson);

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

Thomas White's avatar
Thomas White committed
514
	if ( config_shells ) {
515
		plot_shells(list1, arr2, scale_r1i,
516
		            cell, sym, rmin_fix, rmax_fix);
Thomas White's avatar
Thomas White committed
517
518
	}

519
520
	return 0;
}