indexamajig.c 23.8 KB
Newer Older
Thomas White's avatar
Thomas White committed
1
/*
2
 * indexamajig.c
Thomas White's avatar
Thomas White committed
3
 *
Thomas White's avatar
Thomas White committed
4
 * Index patterns, output hkl+intensity etc.
Thomas White's avatar
Thomas White committed
5
 *
Thomas White's avatar
Thomas White committed
6
 * (c) 2006-2010 Thomas White <taw@physics.org>
Thomas White's avatar
Thomas White committed
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 <hdf5.h>
Thomas White's avatar
Thomas White committed
24
#include <gsl/gsl_errno.h>
25
#include <pthread.h>
Thomas White's avatar
Thomas White committed
26
#include <sys/time.h>
Thomas White's avatar
Thomas White committed
27
28
29

#include "utils.h"
#include "hdf5-file.h"
Thomas White's avatar
Thomas White committed
30
#include "index.h"
31
#include "peaks.h"
32
#include "diffraction.h"
Thomas White's avatar
Thomas White committed
33
#include "diffraction-gpu.h"
34
#include "detector.h"
35
#include "sfac.h"
Thomas White's avatar
Thomas White committed
36
#include "filters.h"
37
#include "reflections.h"
38
#include "thread-pool.h"
39
#include "beam-parameters.h"
40

41
42
43
44
45
46
47

enum {
	PEAK_ZAEF,
	PEAK_HDF5,
};


48
49
/* Information about the indexing process which is common to all patterns */
struct static_index_args
50
{
51
	pthread_mutex_t *gpu_mutex;     /* Protects "gctx" */
52
53
54
55
56
57
58
59
60
61
62
	UnitCell *cell;
	int config_cmfilter;
	int config_noisefilter;
	int config_writedrx;
	int config_dumpfound;
	int config_verbose;
	int config_alternate;
	int config_nearbragg;
	int config_gpu;
	int config_simulate;
	int config_nomatch;
Thomas White's avatar
Thomas White committed
63
	int config_polar;
64
	int config_sanity;
65
	int config_satcorr;
66
	int config_sa;
67
	int config_closer;
68
	float threshold;
Thomas White's avatar
Thomas White committed
69
	struct detector *det;
70
	IndexingMethod indm;
71
	IndexingPrivate *ipriv;
72
73
	const double *intensities;
	struct gpu_context *gctx;
74
	int peaks;
75
	double nominal_photon_energy;
76

77
78
79
	/* Output stream */
	pthread_mutex_t *output_mutex;  /* Protects the output stream */
	FILE *ofh;
80
81
82
};


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* Information about the indexing process for one pattern */
struct index_args
{
	/* "Input" */
	char *filename;
	struct static_index_args static_args;

	/* "Output" */
	int indexable;
	int sane;
};


/* Information needed to choose the next task and dispatch it */
struct queue_args
{
	FILE *fh;
	char *prefix;
	struct static_index_args static_args;

	int n_indexable;
	int n_sane;
};


Thomas White's avatar
Thomas White committed
108
109
110
111
112
113
static void show_help(const char *s)
{
	printf("Syntax: %s [options]\n\n", s);
	printf(
"Process and index FEL diffraction images.\n"
"\n"
114
" -h, --help               Display this help message.\n"
Thomas White's avatar
Thomas White committed
115
"\n"
116
" -i, --input=<filename>   Specify file containing list of images to process.\n"
Thomas White's avatar
Thomas White committed
117
"                           '-' means stdin, which is the default.\n"
118
" -o, --output=<filename>  Write indexed stream to this file. '-' for stdout.\n"
Thomas White's avatar
Thomas White committed
119
"\n"
120
"     --indexing=<method>  Use 'method' for indexing.  Choose from:\n"
Thomas White's avatar
Thomas White committed
121
"                           none     : no indexing (default)\n"
Thomas White's avatar
Thomas White committed
122
"                           dirax    : invoke DirAx\n"
123
"                           template : index by template matching\n"
124
" -g. --geometry=<file>    Get detector geometry from file.\n"
125
126
127
" -b, --beam=<file>        Get beam parameters from file (provides nominal\n"
"                           wavelength value if no per-shot value is found in\n"
"                           the HDF5 files.\n"
128
" -p, --pdb=<file>         PDB file from which to get the unit cell to match.\n"
Thomas White's avatar
Thomas White committed
129
"                           Default: 'molecule.pdb'.\n"
130
" -x, --prefix=<p>         Prefix filenames from input file with <p>.\n"
131
132
133
134
135
"     --peaks=<method>     Use 'method' for finding peaks.  Choose from:\n"
"                           zaef  : Use Zaefferer (2000) gradient detection.\n"
"                                    This is the default method.\n"
"                           hdf5  : Get from /processing/hitfinder/peakinfo\n"
"                                    in the HDF5 file.\n"
Thomas White's avatar
Thomas White committed
136
137
138
"\n"
"\nWith just the above options, this program does not do much of practical use."
"\nYou should also enable some of the following:\n\n"
139
"     --near-bragg         Output a list of reflection intensities to stdout.\n"
Thomas White's avatar
Thomas White committed
140
141
142
143
144
145
146
147
148
149
"                           When pixels with fractional indices within 0.1 of\n"
"                           integer values (the Bragg condition) are found,\n"
"                           the integral of pixels within a ten pixel radius\n"
"                           of the nearest-to-Bragg pixel will be reported as\n"
"                           the intensity.  The centroid of the pixels will\n"
"                           be given as the coordinates, as well as the h,k,l\n"
"                           (integer) indices of the reflection.  If a peak\n"
"                           was located by the initial peak search close to\n"
"                           the \"near Bragg\" location, its coordinates will\n"
"                           be taken as the centre instead.\n"
150
"     --simulate           Simulate the diffraction pattern using the indexed\n"
Thomas White's avatar
Thomas White committed
151
152
153
154
"                           unit cell.  The simulated pattern will be saved\n"
"                           as \"simulated.h5\".  You can TRY to combine this\n"
"                           with \"-j <n>\" with n greater than 1, but it's\n"
"                           not a good idea.\n"
155
"     --write-drx          Write 'xfel.drx' for visualisation of reciprocal\n"
156
157
158
"                           space.  Implied by any indexing method other than\n"
"                           'none'.  Beware: the units in this file are\n"
"                           reciprocal Angstroms.\n"
159
"     --dump-peaks         Write the results of the peak search to stdout.\n"
160
161
"                           The intensities in this list are from the\n"
"                           centroid/integration procedure.\n"
Thomas White's avatar
Thomas White committed
162
163
"\n"
"\nFor more control over the process, you might need:\n\n"
164
"     --no-match           Don't attempt to match the indexed cell to the\n"
165
166
"                           model, just proceed with the one generated by the\n"
"                           auto-indexing procedure.\n"
167
"     --check-sanity       Check that indexed locations approximately correspond\n"
168
"                           with detected peaks.\n"
169
"     --filter-cm          Perform common-mode noise subtraction on images\n"
Thomas White's avatar
Thomas White committed
170
171
"                           before proceeding.  Intensities will be extracted\n"
"                           from the image as it is after this processing.\n"
172
"     --filter-noise       Apply an aggressive noise filter which sets all\n"
Thomas White's avatar
Thomas White committed
173
174
175
"                           pixels in each 3x3 region to zero if any of them\n"
"                           have negative values.  Intensity measurement will\n"
"                           be performed on the image as it was before this.\n"
176
"     --unpolarized        Don't correct for the polarisation of the X-rays.\n"
177
178
"     --no-sat-corr        Don't correct values of saturated peaks using a\n"
"                           table included in the HDF5 file.\n"
179
"     --no-sa              Don't correct for the differing solid angles of\n"
180
"                           the pixels.\n"
181
"     --threshold=<n>      Only accept peaks above <n> ADU.  Default: 800.\n"
Thomas White's avatar
Thomas White committed
182
"\n"
183
"\nIf you used --simulate, you may also want:\n\n"
Thomas White's avatar
Thomas White committed
184
185
"     --intensities=<file> Specify file containing reflection intensities\n"
"                           to use when simulating.\n"
186
187
188
189
190
"\n"
"\nOptions for greater performance or verbosity:\n\n"
"     --verbose            Be verbose about indexing.\n"
"     --gpu                Use the GPU to speed up the simulation.\n"
" -j <n>                   Run <n> analyses in parallel.  Default 1.\n"
191
192
193
"\n"
"\nOptions you probably won't need:\n\n"
"     --no-check-prefix    Don't attempt to correct the --prefix.\n"
194
195
196
"     --no-closer-peak     Don't integrate from the location of a nearby peak\n"
"                           instead of the position closest to the reciprocal\n"
"                           lattice point.\n"
Thomas White's avatar
Thomas White committed
197
);
Thomas White's avatar
Thomas White committed
198
199
200
}


201
static struct image *get_simage(struct image *template, int alternate)
202
{
203
	struct image *image;
204
	struct panel panels[2];
205

206
207
	image = malloc(sizeof(*image));

208
	/* Simulate a diffraction pattern */
209
210
211
	image->twotheta = NULL;
	image->data = NULL;
	image->det = template->det;
212
213
214
	image->flags = NULL;
	image->f0_available = 0;
	image->f0 = 1.0;
215
216

	/* View head-on (unit cell is tilted) */
217
218
219
220
	image->orientation.w = 1.0;
	image->orientation.x = 0.0;
	image->orientation.y = 0.0;
	image->orientation.z = 0.0;
221
222
223

	/* Detector geometry for the simulation
	 * - not necessarily the same as the original. */
224
225
	image->width = 1024;
	image->height = 1024;
Thomas White's avatar
Thomas White committed
226
	image->det->n_panels = 2;
227

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
	if ( alternate ) {

		/* Upper */
		panels[0].min_x = 0;
		panels[0].max_x = 1023;
		panels[0].min_y = 512;
		panels[0].max_y = 1023;
		panels[0].cx = 523.6;
		panels[0].cy = 502.5;
		panels[0].clen = 56.4e-2;  /* 56.4 cm */
		panels[0].res = 13333.3;   /* 75 microns/pixel */

		/* Lower */
		panels[1].min_x = 0;
		panels[1].max_x = 1023;
		panels[1].min_y = 0;
		panels[1].max_y = 511;
		panels[1].cx = 520.8;
246
		panels[1].cy = 525.0;
247
248
249
		panels[1].clen = 56.7e-2;  /* 56.7 cm */
		panels[1].res = 13333.3;   /* 75 microns/pixel */

Thomas White's avatar
Thomas White committed
250
		image->det->panels = panels;
251

252
253
254
	} else {

		/* Copy pointer to old geometry */
Thomas White's avatar
Thomas White committed
255
		image->det->panels = template->det->panels;
256
257

	}
258

259
	image->lambda = ph_en_to_lambda(eV_to_J(1.8e3));
260
	image->features = template->features;
261
	image->filename = template->filename;
262
	image->indexed_cell = template->indexed_cell;
Thomas White's avatar
Thomas White committed
263
	image->f0 = template->f0;
264

Thomas White's avatar
Thomas White committed
265
	/* Prevent muppetry */
Thomas White's avatar
Thomas White committed
266
267
	image->cpeaks = NULL;
	image->n_cpeaks = 0;
Thomas White's avatar
Thomas White committed
268

269
270
	return image;
}
271
272


273
static void simulate_and_write(struct image *simage, struct gpu_context **gctx,
Thomas White's avatar
Thomas White committed
274
                               const double *intensities, UnitCell *cell)
275
{
276
	/* Set up GPU if necessary */
Thomas White's avatar
Thomas White committed
277
	if ( (gctx != NULL) && (*gctx == NULL) ) {
Thomas White's avatar
Thomas White committed
278
		*gctx = setup_gpu(0, simage, intensities);
279
280
	}

Thomas White's avatar
Thomas White committed
281
	if ( (gctx != NULL) && (*gctx != NULL) ) {
282
		get_diffraction_gpu(*gctx, simage, 24, 24, 40, cell);
283
	} else {
284
		get_diffraction(simage, 24, 24, 40,
Thomas White's avatar
Thomas White committed
285
		                intensities, NULL, cell, 0,
286
		                GRADIENT_MOSAIC);
287
	}
288
	record_image(simage, 0);
289

290
	hdf5_write("simulated.h5", simage->data, simage->width, simage->height,
291
292
293
294
		   H5T_NATIVE_FLOAT);
}


295
static void process_image(void *pp, int cookie)
296
{
297
	struct index_args *pargs = pp;
298
299
300
301
302
	struct hdfile *hdfile;
	struct image image;
	struct image *simage;
	float *data_for_measurement;
	size_t data_size;
303
	char *filename = pargs->filename;
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
	UnitCell *cell = pargs->static_args.cell;
	int config_cmfilter = pargs->static_args.config_cmfilter;
	int config_noisefilter = pargs->static_args.config_noisefilter;
	int config_writedrx = pargs->static_args.config_writedrx;
	int config_dumpfound = pargs->static_args.config_dumpfound;
	int config_verbose = pargs->static_args.config_verbose;
	int config_alternate  = pargs->static_args.config_alternate;
	int config_nearbragg = pargs->static_args.config_nearbragg;
	int config_gpu = pargs->static_args.config_gpu;
	int config_simulate = pargs->static_args.config_simulate;
	int config_nomatch = pargs->static_args.config_nomatch;
	int config_polar = pargs->static_args.config_polar;
	IndexingMethod indm = pargs->static_args.indm;
	const double *intensities = pargs->static_args.intensities;
	struct gpu_context *gctx = pargs->static_args.gctx;
319
320
321
322

	image.features = NULL;
	image.data = NULL;
	image.indexed_cell = NULL;
323
	image.id = cookie;
324
	image.filename = filename;
Thomas White's avatar
Thomas White committed
325
326
	image.cpeaks = NULL;
	image.n_cpeaks = 0;
327
	image.det = pargs->static_args.det;
328

329
330
331
332
333
334
	/* View head-on (unit cell is tilted) */
	image.orientation.w = 1.0;
	image.orientation.x = 0.0;
	image.orientation.y = 0.0;
	image.orientation.z = 0.0;

335
	STATUS("Processing '%s'\n", image.filename);
336

Thomas White's avatar
Thomas White committed
337
338
	pargs->sane = 0;
	pargs->indexable = 0;
339

340
341
	hdfile = hdfile_open(filename);
	if ( hdfile == NULL ) {
Thomas White's avatar
Thomas White committed
342
		return;
343
344
	} else if ( hdfile_set_first_image(hdfile, "/") ) {
		ERROR("Couldn't select path\n");
Thomas White's avatar
Thomas White committed
345
		return;
346
347
	}

348
349
	hdf5_read(hdfile, &image, pargs->static_args.config_satcorr,
	          pargs->static_args.nominal_photon_energy);
350
351
352
353
354
355
356
357
358
359
360
361
362

	if ( config_cmfilter ) {
		filter_cm(&image);
	}

	/* Take snapshot of image after CM subtraction but before
	 * the aggressive noise filter. */
	data_size = image.width*image.height*sizeof(float);
	data_for_measurement = malloc(data_size);

	if ( config_noisefilter ) {
		filter_noise(&image, data_for_measurement);
	} else {
363
		memcpy(data_for_measurement, image.data, data_size);
364
365
	}

366
	switch ( pargs->static_args.peaks )
367
368
369
370
371
372
373
374
375
	{
	case PEAK_HDF5 :
		/* Get peaks from HDF5 */
		if ( get_peaks(&image, hdfile) ) {
			ERROR("Failed to get peaks from HDF5 file.\n");
			return;
		}
		break;
	case PEAK_ZAEF :
376
		search_peaks(&image, pargs->static_args.threshold);
377
378
		break;
	}
Thomas White's avatar
Thomas White committed
379
380
381
382
383
384

	/* Get rid of noise-filtered version at this point
	 * - it was strictly for the purposes of peak detection. */
	free(image.data);
	image.data = data_for_measurement;

385
	if ( config_dumpfound ) {
386
387
		dump_peaks(&image, pargs->static_args.ofh,
		           pargs->static_args.output_mutex);
388
	}
389
390
391
392
393
394
395
396
397
398

	/* Not indexing nor writing xfel.drx?
	 * Then there's nothing left to do. */
	if ( (!config_writedrx) && (indm == INDEXING_NONE) ) {
		goto done;
	}

	/* Calculate orientation matrix (by magic) */
	if ( config_writedrx || (indm != INDEXING_NONE) ) {
		index_pattern(&image, cell, indm, config_nomatch,
399
		              config_verbose, pargs->static_args.ipriv);
400
401
402
403
	}

	/* No cell at this point?  Then we're done. */
	if ( image.indexed_cell == NULL ) goto done;
Thomas White's avatar
Thomas White committed
404
	pargs->indexable = 1;
405

Thomas White's avatar
Thomas White committed
406
	/* Sanity check */
407
	if ( pargs->static_args.config_sanity
408
	  && !peak_sanity_check(&image, image.indexed_cell, 0, 0.1) ) {
Thomas White's avatar
Thomas White committed
409
410
411
		STATUS("Failed peak sanity check.\n");
		goto done;
	} else {
Thomas White's avatar
Thomas White committed
412
		pargs->sane = 1;
Thomas White's avatar
Thomas White committed
413
414
	}

415
416
	/* Measure intensities if requested */
	if ( config_nearbragg ) {
417
		output_intensities(&image, image.indexed_cell,
418
419
420
421
		                   pargs->static_args.output_mutex,
		                   config_polar, pargs->static_args.config_sa,
		                   pargs->static_args.config_closer,
		                   pargs->static_args.ofh, 0, 0.1);
422
423
	}

424
425
	simage = get_simage(&image, config_alternate);

426
427
428
	/* Simulate if requested */
	if ( config_simulate ) {
		if ( config_gpu ) {
429
			pthread_mutex_lock(pargs->static_args.gpu_mutex);
430
			simulate_and_write(simage, &gctx, intensities,
Thomas White's avatar
Thomas White committed
431
			                   image.indexed_cell);
432
			pthread_mutex_unlock(pargs->static_args.gpu_mutex);
433
434
		} else {
			simulate_and_write(simage, NULL, intensities,
Thomas White's avatar
Thomas White committed
435
			                   image.indexed_cell);
436
437
438
439
440
441
442
443
444
		}
	}

	/* Finished with alternate image */
	if ( simage->twotheta != NULL ) free(simage->twotheta);
	if ( simage->data != NULL ) free(simage->data);
	free(simage);

	/* Only free cell if found */
445
	cell_free(image.indexed_cell);
446
447
448

done:
	free(image.data);
Thomas White's avatar
Thomas White committed
449
	free(image.flags);
450
	image_feature_list_free(image.features);
Thomas White's avatar
Thomas White committed
451
	free(image.cpeaks);
452
453
454
455
	hdfile_close(hdfile);
}


456
static void *get_image(void *qp)
457
{
458
459
460
461
	char line[1024];
	struct index_args *pargs;
	char *rval;
	struct queue_args *qargs = qp;
462

463
464
465
	/* Get the next filename */
	rval = fgets(line, 1023, qargs->fh);
	if ( rval == NULL ) return NULL;
466

467
	pargs = malloc(sizeof(struct index_args));
468

469
470
	memcpy(&pargs->static_args, &qargs->static_args,
	       sizeof(struct static_index_args));
471

472
473
474
	chomp(line);
	pargs->filename = malloc(strlen(qargs->prefix) + strlen(line) + 1);
	snprintf(pargs->filename, 1023, "%s%s", qargs->prefix, line);
475

476
477
	return pargs;
}
478
479


480
481
482
483
static void finalise_image(void *qp, void *pp)
{
	struct queue_args *qargs = qp;
	struct index_args *pargs = pp;
484

485
486
	qargs->n_indexable += pargs->indexable;
	qargs->n_sane += pargs->sane;
487

488
489
	free(pargs->filename);
	free(pargs);
490
491
492
}


Thomas White's avatar
Thomas White committed
493
494
495
int main(int argc, char *argv[])
{
	int c;
Thomas White's avatar
Thomas White committed
496
	struct gpu_context *gctx = NULL;
Thomas White's avatar
Thomas White committed
497
	char *filename = NULL;
498
	char *outfile = NULL;
Thomas White's avatar
Thomas White committed
499
	FILE *fh;
500
	FILE *ofh;
501
	char *rval = NULL;
Thomas White's avatar
Thomas White committed
502
	int n_images;
503
	int config_noindex = 0;
Thomas White's avatar
Thomas White committed
504
	int config_dumpfound = 0;
505
	int config_nearbragg = 0;
Thomas White's avatar
Thomas White committed
506
	int config_writedrx = 0;
507
	int config_simulate = 0;
508
509
	int config_cmfilter = 0;
	int config_noisefilter = 0;
510
	int config_nomatch = 0;
Thomas White's avatar
Thomas White committed
511
	int config_gpu = 0;
512
	int config_verbose = 0;
513
	int config_alternate = 0;
Thomas White's avatar
Thomas White committed
514
	int config_polar = 1;
515
	int config_sanity = 0;
516
	int config_satcorr = 1;
517
	int config_sa = 1;
518
	int config_checkprefix = 1;
519
	int config_closer = 1;
520
	float threshold = 800.0;
Thomas White's avatar
Thomas White committed
521
522
	struct detector *det;
	char *geometry = NULL;
Thomas White's avatar
Thomas White committed
523
524
	IndexingMethod indm;
	char *indm_str = NULL;
525
526
527
	UnitCell *cell;
	double *intensities = NULL;
	char *intfile = NULL;
Thomas White's avatar
Thomas White committed
528
	char *pdb = NULL;
529
	char *prefix = NULL;
530
531
	char *speaks = NULL;
	int peaks;
532
533
	int nthreads = 1;
	int i;
534
	pthread_mutex_t output_mutex = PTHREAD_MUTEX_INITIALIZER;
535
	pthread_mutex_t gpu_mutex = PTHREAD_MUTEX_INITIALIZER;
536
537
538
	char prepare_line[1024];
	char prepare_filename[1024];
	IndexingPrivate *ipriv;
539
	struct queue_args qargs;
540
541
	struct beam_params *beam = NULL;
	double nominal_photon_energy;
Thomas White's avatar
Thomas White committed
542
543
544
545
546

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
		{"input",              1, NULL,               'i'},
547
		{"output",             1, NULL,               'o'},
Thomas White's avatar
Thomas White committed
548
		{"gpu",                0, &config_gpu,         1},
549
		{"no-index",           0, &config_noindex,     1},
Thomas White's avatar
Thomas White committed
550
		{"dump-peaks",         0, &config_dumpfound,   1},
551
		{"peaks",              1, NULL,                2},
552
		{"near-bragg",         0, &config_nearbragg,   1},
Thomas White's avatar
Thomas White committed
553
554
		{"write-drx",          0, &config_writedrx,    1},
		{"indexing",           1, NULL,               'z'},
Thomas White's avatar
Thomas White committed
555
		{"geometry",           1, NULL,               'g'},
556
		{"beam",               1, NULL,               'b'},
557
		{"simulate",           0, &config_simulate,    1},
558
559
		{"filter-cm",          0, &config_cmfilter,    1},
		{"filter-noise",       0, &config_noisefilter, 1},
560
		{"no-match",           0, &config_nomatch,     1},
561
		{"verbose",            0, &config_verbose,     1},
562
		{"alternate",          0, &config_alternate,   1},
563
		{"intensities",        1, NULL,               'q'},
Thomas White's avatar
Thomas White committed
564
		{"pdb",                1, NULL,               'p'},
565
		{"prefix",             1, NULL,               'x'},
Thomas White's avatar
Thomas White committed
566
		{"unpolarized",        0, &config_polar,       0},
567
		{"check-sanity",       0, &config_sanity,      1},
568
569
		{"no-sat-corr",        0, &config_satcorr,     0},
		{"sat-corr",           0, &config_satcorr,     1}, /* Compat */
570
		{"no-sa",              0, &config_sa,          0},
571
		{"threshold",          1, NULL,               't'},
572
		{"no-check-prefix",    0, &config_checkprefix, 0},
573
		{"no-closer-peak",     0, &config_closer,      0},
Thomas White's avatar
Thomas White committed
574
575
576
577
		{0, 0, NULL, 0}
	};

	/* Short options */
578
	while ((c = getopt_long(argc, argv, "hi:wp:j:x:g:t:o:b:",
Thomas White's avatar
Thomas White committed
579
	                        longopts, NULL)) != -1) {
Thomas White's avatar
Thomas White committed
580
581

		switch (c) {
Thomas White's avatar
Thomas White committed
582
		case 'h' :
Thomas White's avatar
Thomas White committed
583
584
585
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
586
		case 'i' :
Thomas White's avatar
Thomas White committed
587
588
589
			filename = strdup(optarg);
			break;

590
591
592
593
		case 'o' :
			outfile = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
594
		case 'z' :
Thomas White's avatar
Thomas White committed
595
596
597
			indm_str = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
598
		case 'q' :
599
600
601
			intfile = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
602
		case 'p' :
Thomas White's avatar
Thomas White committed
603
604
605
			pdb = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
606
		case 'x' :
607
608
609
			prefix = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
610
		case 'j' :
611
612
613
			nthreads = atoi(optarg);
			break;

Thomas White's avatar
Thomas White committed
614
		case 'g' :
Thomas White's avatar
Thomas White committed
615
616
617
			geometry = strdup(optarg);
			break;

618
619
620
621
		case 't' :
			threshold = strtof(optarg, NULL);
			break;

622
623
624
625
626
627
628
629
630
		case 'b' :
			beam = get_beam_parameters(optarg);
			if ( beam == NULL ) {
				ERROR("Failed to load beam parameters"
				      " from '%s'\n", optarg);
				return 1;
			}
			break;

631
632
633
634
		case 2 :
			speaks = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
635
		case 0 :
Thomas White's avatar
Thomas White committed
636
637
			break;

Thomas White's avatar
Thomas White committed
638
		default :
Thomas White's avatar
Thomas White committed
639
640
641
642
643
644
645
646
647
648
649
650
651
652
			return 1;
		}

	}

	if ( filename == NULL ) {
		filename = strdup("-");
	}
	if ( strcmp(filename, "-") == 0 ) {
		fh = stdin;
	} else {
		fh = fopen(filename, "r");
	}
	if ( fh == NULL ) {
Thomas White's avatar
Thomas White committed
653
		ERROR("Failed to open input file '%s'\n", filename);
Thomas White's avatar
Thomas White committed
654
655
		return 1;
	}
Thomas White's avatar
Thomas White committed
656
	free(filename);
Thomas White's avatar
Thomas White committed
657

658
659
660
661
662
663
664
665
666
667
668
669
670
671
	if ( outfile == NULL ) {
		outfile = strdup("-");
	}
	if ( strcmp(outfile, "-") == 0 ) {
		ofh = stdout;
	} else {
		ofh = fopen(outfile, "w");
	}
	if ( ofh == NULL ) {
		ERROR("Failed to open output file '%s'\n", outfile);
		return 1;
	}
	free(outfile);

672
673
674
675
676
677
678
679
680
681
682
683
684
	if ( speaks == NULL ) {
		speaks = strdup("zaef");
		STATUS("You didn't specify a peak detection method.\n");
		STATUS("I'm using 'zaef' for you.\n");
	}
	if ( strcmp(speaks, "zaef") == 0 ) {
		peaks = PEAK_ZAEF;
	} else if ( strcmp(speaks, "hdf5") == 0 ) {
		peaks = PEAK_HDF5;
	} else {
		ERROR("Unrecognised peak detection method '%s'\n", speaks);
		return 1;
	}
Thomas White's avatar
Thomas White committed
685
	free(speaks);
686

687
	if ( intfile != NULL ) {
Thomas White's avatar
Thomas White committed
688
		ReflItemList *items;
689
690
		items = read_reflections(intfile, intensities,
		                         NULL, NULL, NULL);
Thomas White's avatar
Thomas White committed
691
		delete_items(items);
692
693
694
695
	} else {
		intensities = NULL;
	}

Thomas White's avatar
Thomas White committed
696
697
698
699
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

700
	if ( prefix == NULL ) {
Thomas White's avatar
Thomas White committed
701
		prefix = strdup("");
702
	} else {
703
704
705
		if ( config_checkprefix ) {
			prefix = check_prefix(prefix);
		}
706
707
	}

708
	if ( nthreads == 0 ) {
709
710
711
712
		ERROR("Invalid number of threads.\n");
		return 1;
	}

Thomas White's avatar
Thomas White committed
713
714
	if ( indm_str == NULL ) {
		STATUS("You didn't specify an indexing method, so I won't"
715
716
717
		       " try to index anything.\n"
		       "If that isn't what you wanted, re-run with"
		       " --indexing=<method>.\n");
Thomas White's avatar
Thomas White committed
718
719
720
721
722
		indm = INDEXING_NONE;
	} else if ( strcmp(indm_str, "none") == 0 ) {
		indm = INDEXING_NONE;
	} else if ( strcmp(indm_str, "dirax") == 0) {
		indm = INDEXING_DIRAX;
723
724
	} else if ( strcmp(indm_str, "template") == 0) {
		indm = INDEXING_TEMPLATE;
Thomas White's avatar
Thomas White committed
725
726
727
728
	} else {
		ERROR("Unrecognised indexing method '%s'\n", indm_str);
		return 1;
	}
729
	free(indm_str);
Thomas White's avatar
Thomas White committed
730

Thomas White's avatar
Thomas White committed
731
732
733
734
735
736
737
738
739
740
741
742
	if ( geometry == NULL ) {
		ERROR("You need to specify a geometry file with --geometry\n");
		return 1;
	}

	det = get_detector_geometry(geometry);
	if ( det == NULL ) {
		ERROR("Failed to read detector geometry from '%s'\n", geometry);
		return 1;
	}
	free(geometry);

743
	if ( (!config_nomatch) || (indm == INDEXING_TEMPLATE) ) {
744
745
		cell = load_cell_from_pdb(pdb);
		if ( cell == NULL ) {
746
747
748
			ERROR("Couldn't read unit cell (from %s)\n", pdb);
			return 1;
		}
749
750
751
	} else {
		STATUS("No cell needed because --no-match was used.\n");
		cell = NULL;
752
	}
753
	free(pdb);
754

755
756
757
758
759
	/* Start by writing the entire command line to stdout */
	fprintf(ofh, "Command line:");
	for ( i=0; i<argc; i++ ) {
		fprintf(ofh, " %s", argv[i]);
	}
760
761
	fprintf(ofh, "\n");
	fflush(ofh);
762

763
764
765
766
767
768
769
770
	if ( beam != NULL ) {
		nominal_photon_energy = beam->photon_energy;
	} else {
		STATUS("No beam parameters file was given, so I'm taking the"
		       " nominal photon energy to be 2 keV.\n");
		nominal_photon_energy = 2000.0;
	}

771
	/* Get first filename and use it to set up the indexing */
772
773
774
775
776
777
778
779
780
781
782
783
784
785
	if ( fh != stdin ) {
		rval = fgets(prepare_line, 1023, fh);
		if ( rval == NULL ) {
			ERROR("Failed to get filename to prepare indexing.\n");
			return 1;
		}
		chomp(prepare_line);
		snprintf(prepare_filename, 1023, "%s%s", prefix, prepare_line);
		rewind(fh);
	} else {
		STATUS("Reading input filenames from stdin, so can't (yet)");
		STATUS(" use the first file for preparing the indexing.\n");
		STATUS("Stuff might break.\n");
		prepare_filename[0] = '\0';
786
	}
787
788
	ipriv = prepare_indexing(indm, cell, prepare_filename, det,
	                         nominal_photon_energy);
789
790
791
792
793
	if ( ipriv == NULL ) {
		ERROR("Failed to prepare indexing.\n");
		return 1;
	}

Thomas White's avatar
Thomas White committed
794
	gsl_set_error_handler_off();
Thomas White's avatar
Thomas White committed
795

796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
	qargs.static_args.gpu_mutex = &gpu_mutex;
	qargs.static_args.cell = cell;
	qargs.static_args.config_cmfilter = config_cmfilter;
	qargs.static_args.config_noisefilter = config_noisefilter;
	qargs.static_args.config_writedrx = config_writedrx;
	qargs.static_args.config_dumpfound = config_dumpfound;
	qargs.static_args.config_verbose = config_verbose;
	qargs.static_args.config_alternate = config_alternate;
	qargs.static_args.config_nearbragg = config_nearbragg;
	qargs.static_args.config_gpu = config_gpu;
	qargs.static_args.config_simulate = config_simulate;
	qargs.static_args.config_nomatch = config_nomatch;
	qargs.static_args.config_polar = config_polar;
	qargs.static_args.config_sanity = config_sanity;
	qargs.static_args.config_satcorr = config_satcorr;
	qargs.static_args.config_sa = config_sa;
	qargs.static_args.config_closer = config_closer;
	qargs.static_args.threshold = threshold;
	qargs.static_args.det = det;
	qargs.static_args.indm = indm;
	qargs.static_args.ipriv = ipriv;
	qargs.static_args.intensities = intensities;
	qargs.static_args.gctx = gctx;
	qargs.static_args.peaks = peaks;
	qargs.static_args.output_mutex = &output_mutex;
	qargs.static_args.ofh = ofh;
822
	qargs.static_args.nominal_photon_energy = nominal_photon_energy;
823
824
825
826
827
828
829
830

	qargs.fh = fh;
	qargs.prefix = prefix;
	qargs.n_indexable = 0;
	qargs.n_sane = 0;

	n_images = run_threads(nthreads, process_image, get_image,
	                       finalise_image, &qargs, 0);
831

832
833
	cleanup_indexing(ipriv);

834
	free(prefix);
Thomas White's avatar
Thomas White committed
835
836
	free(det->panels);
	free(det);
837
	cell_free(cell);
838
	if ( fh != stdout ) fclose(fh);
Thomas White's avatar
Thomas White committed
839

Thomas White's avatar
Thomas White committed
840
	STATUS("There were %i images.  %i could be indexed, of which %i"
841
	       " looked sane.\n", n_images, qargs.n_indexable, qargs.n_sane);
Thomas White's avatar
Thomas White committed
842

Thomas White's avatar
Thomas White committed
843
844
845
846
	if ( gctx != NULL ) {
		cleanup_gpu(gctx);
	}

Thomas White's avatar
Thomas White committed
847
848
	return 0;
}