compare_hkl.c 11.6 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
		return;
	}

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

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

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

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

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

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

	}
118

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

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

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

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

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

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

148
149
150
151
152
153
154
155
156
157
		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
158
159
160
161
162
163
164
165
166
167
	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++ ) {
168
169
170
171
172

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

Thomas White's avatar
Thomas White committed
173
		get_asymm(sym, h, k, l, &hs, &ks, &ls);
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
		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
195
	den = 0.0;
Thomas White's avatar
Thomas White committed
196
	ctot = 0;
197
	nout = 0;
Thomas White's avatar
Thomas White committed
198

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

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

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

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

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

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

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

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

	}

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

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

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

	}

	fclose(fh);
}


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

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

	/* Short options */
296
297
298
	while ((c = getopt_long(argc, argv, "ho:y:p:u",
	                        longopts, NULL)) != -1)
	{
299
300

		switch (c) {
Thomas White's avatar
Thomas White committed
301
		case 'h' :
302
303
304
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
305
		case 'o' :
Thomas White's avatar
Thomas White committed
306
			ratiofile = strdup(optarg);
307
308
			break;

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

313
314
315
316
		case 'p' :
			pdb = strdup(optarg);
			break;

317
318
319
320
		case 'u' :
			config_unity = 1;
			break;

Thomas White's avatar
Thomas White committed
321
		case 0 :
322
323
			break;

324
325
326
327
328
329
330
331
332
333
334
335
336
337
		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
338
		default :
339
340
341
342
343
			return 1;
		}

	}

344
345
346
347
348
	if ( argc != (optind+2) ) {
		ERROR("Please provide exactly two HKL files to compare.\n");
		return 1;
	}

Thomas White's avatar
Thomas White committed
349
350
	if ( sym_str == NULL ) {
		sym_str = strdup("1");
351
	}
Thomas White's avatar
Thomas White committed
352
353
	sym = get_pointgroup(sym_str);
	free(sym_str);
354

355
356
357
	afile = strdup(argv[optind++]);
	bfile = strdup(argv[optind]);

358
359
360
361
362
363
364
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

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

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

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

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

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

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

Thomas White's avatar
Thomas White committed
408
		if ( !find_equiv_in_list(list2, h, k, l, sym, &he, &ke, &le) ) {
409
410
			continue;
		}
411

412
413
		copy_data(add_refl(list1_transformed, h, k, l), refl1);

Thomas White's avatar
Thomas White committed
414
415
416
417
418
419
420
		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);
421
422
423
424
425
426
427
428
429

		if ( val1 < 3.0 * sig1 ) {
			rej1++;
			ig = 1;
		}
		if ( val2 < 3.0 * sig2 ) {
			rej2++;
			ig = 1;
		}
430
431
432
433
434

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

435
		//if ( ig ) continue;
436

Thomas White's avatar
Thomas White committed
437
438
439
440
441
442
443
444
		/* 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);
445
		set_redundancy(tr, 1);
446
447

	}
Thomas White's avatar
Thomas White committed
448

449
450
451
452
453
	if ( ratiofile != NULL ) {
		write_reflist(ratiofile, ratio, cell);
	}
	reflist_free(ratio);

454
455
	gsl_set_error_handler_off();

Thomas White's avatar
Thomas White committed
456
457
	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);
458

Thomas White's avatar
Thomas White committed
459
	ncom = num_reflections(list2_transformed);
Thomas White's avatar
Thomas White committed
460
	STATUS("%i,%i reflections: %i in common\n",
Thomas White's avatar
Thomas White committed
461
462
	       num_reflections(list1), num_reflections(list2), ncom);

463
	reflist_free(list1);
Thomas White's avatar
Thomas White committed
464
465
	reflist_free(list2);

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

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

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

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

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

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

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

498
499
	Rdiff = stat_rdiff_intensity(list1_transformed, arr2, &scale_rintint,
	                             config_unity);
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_transformed, 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_transformed, 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_transformed, 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_transformed, arr2, scale_r1i,
516
		            cell, sym, rmin_fix, rmax_fix);
Thomas White's avatar
Thomas White committed
517
518
	}

519
520
	return 0;
}