render_hkl.c 17.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * render_hkl.c
 *
 * Draw pretty renderings of reflection lists
 *
 * (c) 2006-2010 Thomas White <taw@physics.org>
 *
 * 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>
23
#ifdef HAVE_CAIRO
Thomas White's avatar
Thomas White committed
24
25
#include <cairo.h>
#include <cairo-pdf.h>
26
27
28
29
/* GSL is only used if Cairo is present */
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_linalg.h>
30
#endif
31
32
33

#include "utils.h"
#include "reflections.h"
34
#include "povray.h"
35
#include "symmetry.h"
36
#include "render.h"
37

38
39
40
41
enum {
	WGHT_I,
	WGHT_SQRTI,
	WGHT_COUNTS,
42
	WGHT_RAWCOUNTS,
43
};
44

45
46
47
48
static void show_help(const char *s)
{
	printf("Syntax: %s [options] <file.hkl>\n\n", s);
	printf(
49
"Render intensity lists in various ways.\n"
50
"\n"
51
"      --povray            Render a 3D animation using POV-ray.\n"
52
#ifdef HAVE_CAIRO
53
"      --zone-axis         Render a 2D zone axis pattern.\n"
54
#endif
55
"\n"
56
57
58
"      --boost=<val>       Squash colour scale by <val>.\n"
"  -p, --pdb=<file>        PDB file from which to get the unit cell.\n"
"  -y, --symmetry=<sym>    Expand reflections according to point group <sym>.\n"
59
60
61
62
63
64
65
"\n"
"  -c, --colscale=<scale>  Use the given colour scale.  Choose from:\n"
"                           mono    : Greyscale, black is zero.\n"
"                           invmono : Greyscale, white is zero.\n"
"                           colour  : Colours scale:\n"
"                                     black-blue-pink-red-orange-yellow-white\n"
"\n"
66
67
"  -w  --weighting=<wght>  Colour/shade the reciprocal lattice points\n"
"                           according to:\n"
68
69
70
71
72
73
"                            I      : the intensity of the reflection.\n"
"                            sqrtI  : the square root of the intensity.\n"
"                            count  : the number of hits for the reflection.\n"
"                                     (after correcting for 'epsilon')\n"
"                            rawcts : the raw number of hits for the\n"
"                                     reflection (no 'epsilon' correction).\n"
74
75
76
77
"\n"
"      --colour-key        Draw (only) the key for the current colour scale.\n"
"  -j <n>                  Run <n> instances of POV-ray in parallel.\n"
"  -h, --help              Display this help message.\n"
78
);
79
80
81
}


82
#ifdef HAVE_CAIRO
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
static int get_basis_change_coefficients(double *in, double *out)
{
	int s;
	gsl_matrix *m;
	gsl_matrix *inv;
	gsl_permutation *perm;

	m = gsl_matrix_alloc(3, 3);
	if ( m == NULL ) {
		ERROR("Couldn't allocate memory for matrix\n");
		return 1;
	}
	gsl_matrix_set(m, 0, 0, in[0]);
	gsl_matrix_set(m, 0, 1, in[1]);
	gsl_matrix_set(m, 0, 2, in[2]);
	gsl_matrix_set(m, 1, 0, in[3]);
	gsl_matrix_set(m, 1, 1, in[4]);
	gsl_matrix_set(m, 1, 2, in[5]);
	gsl_matrix_set(m, 2, 0, in[6]);
	gsl_matrix_set(m, 2, 1, in[7]);
	gsl_matrix_set(m, 2, 2, in[8]);

	/* Invert */
	perm = gsl_permutation_alloc(m->size1);
	if ( perm == NULL ) {
		ERROR("Couldn't allocate permutation\n");
		gsl_matrix_free(m);
		return 1;
	}
	inv = gsl_matrix_alloc(3, 3);
	if ( inv == NULL ) {
		ERROR("Couldn't allocate inverse\n");
		gsl_matrix_free(m);
		gsl_permutation_free(perm);
		return 1;
	}
	if ( gsl_linalg_LU_decomp(m, perm, &s) ) {
		ERROR("Couldn't decompose matrix\n");
		gsl_matrix_free(m);
		gsl_permutation_free(perm);
		return 1;
	}
	if ( gsl_linalg_LU_invert(m, perm, inv)  ) {
		ERROR("Couldn't invert matrix\n");
		gsl_matrix_free(m);
		gsl_permutation_free(perm);
		return 1;
	}
	gsl_permutation_free(perm);
	gsl_matrix_free(m);

	/* Transpose */
	gsl_matrix_transpose(inv);

	out[0] = gsl_matrix_get(inv, 0, 0);
	out[1] = gsl_matrix_get(inv, 0, 1);
	out[2] = gsl_matrix_get(inv, 0, 2);
	out[3] = gsl_matrix_get(inv, 1, 0);
	out[4] = gsl_matrix_get(inv, 1, 1);
	out[5] = gsl_matrix_get(inv, 1, 2);
	out[6] = gsl_matrix_get(inv, 2, 0);
	out[7] = gsl_matrix_get(inv, 2, 1);
	out[8] = gsl_matrix_get(inv, 2, 2);

	gsl_matrix_free(inv);

	return 0;

}


static void draw_circles(signed int xh, signed int xk, signed int xl,
                         signed int yh, signed int yk, signed int yl,
                         signed int zh, signed int zk, signed int zl,
                         double *ref, unsigned int *counts, ReflItemList *items,
                         const char *sym,
                         cairo_t *dctx, int wght, double boost, int colscale,
                         UnitCell *cell, double radius, double theta,
                         double as, double bs, double cx, double cy,
                         double scale,
                         signed int *max_ux, signed int *max_uy,
                         double *max_val, double *max_u, double *max_v,
                         double *max_res)
{
	signed int xi, yi;
	double in[9];
	double bc[9];

	if ( dctx == NULL ) {
		*max_u = 0.0;  *max_v = 0.0;  *max_val = 0.0;
		*max_res = 0.0;  *max_ux = 0;  *max_uy = 0;
	}

	in[0] = xh;  in[1] = xk;  in[2] = xl;
	in[3] = yh;  in[4] = yk;  in[5] = yl;
	in[6] = zh;  in[7] = zk;  in[8] = zl;
	if ( get_basis_change_coefficients(in, bc) ) {
		ERROR("Couldn't change basis.\n");
		return;
	}

	/* Loop across the two basis directions */
	for ( xi=-INDMAX; xi<INDMAX; xi++ ) {
	for ( yi=-INDMAX; yi<INDMAX; yi++ ) {

		double u, v, val, res;
		int nequiv, p;
		signed int h, k, l;

		h = xi*xh + yi*yh;
		k = xi*xk + yi*yk;
		l = xi*xl + yi*yl;

		/* Got this reflection? */
		if ( find_unique_equiv(items, h, k, l, sym, &h, &k, &l) == 0 ) {
			continue;
		}

		switch ( wght ) {
		case WGHT_I :
			val = lookup_intensity(ref, h, k, l);
			break;
		case WGHT_SQRTI :
			val = lookup_intensity(ref, h, k, l);
			val = (val>0.0) ? sqrt(val) : 0.0;
			break;
		case WGHT_COUNTS :
			val = lookup_count(counts, h, k, l);
			val /= (float)num_equivs(h, k, l, sym);
			break;
		case WGHT_RAWCOUNTS :
			val = lookup_count(counts, h, k, l);
			break;
		default :
			ERROR("Invalid weighting.\n");
			abort();
		}

		/* For each equivalent reflection... */
		nequiv = num_equivs(h, k, l, sym);
		for ( p=0; p<nequiv; p++ ) {

			signed int he, ke, le;
			signed int ux, uy, uz;

			get_equiv(h, k, l, &he, &ke, &le, sym, p);

			/* Calculate the indices in the 2D basis */
			ux = he*bc[0] + ke*bc[1] + le*bc[2];
			uy = he*bc[3] + ke*bc[4] + le*bc[5];
			uz = he*bc[6] + ke*bc[7] + le*bc[8];

			/* Reflection in the zone? */
			if ( uz != 0 ) continue;

			/* Absolute location in image based on 2D basis */
			u = (double)ux*as*sin(theta);
			v = (double)ux*as*cos(theta) + (double)uy*bs;

			if ( dctx != NULL ) {

				float r, g, b;

				cairo_arc(dctx, ((double)cx)+u*scale,
				                ((double)cy)+v*scale,
				                radius, 0, 2*M_PI);

				render_scale(val, *max_val/boost, colscale,
				             &r, &g, &b);
				cairo_set_source_rgb(dctx, r, g, b);
				cairo_fill(dctx);

			} else {

				/* Find max vectors in plane for scaling */
				if ( fabs(u) > fabs(*max_u) ) *max_u = fabs(u);
				if ( fabs(v) > fabs(*max_v) ) *max_v = fabs(v);

				/* Find max value for colour scale */
				if ( fabs(val) > fabs(*max_val) ) {
					*max_val = fabs(val);
				}

				/* Find max indices */
				if ( (uy==0) && (fabs(ux) > *max_ux) )
					*max_ux = fabs(ux);
				if ( (ux==0) && (fabs(uy) > *max_uy) )
					*max_uy = fabs(uy);

				/* Find max resolution */
				res = resolution(cell, he, ke, le);
				if ( res > *max_res ) *max_res = res;
			}

		}

	}
	}
}


284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
static void render_overlined_indices(cairo_t *dctx,
                                     signed int h, signed int k, signed int l)
{
	char tmp[256];
	cairo_text_extents_t size;
	double x, y;
	const double sh = 39.0;

	cairo_get_current_point(dctx, &x, &y);
	cairo_set_line_width(dctx, 4.0);

	/* Draw 'h' */
	snprintf(tmp, 255, "%i", abs(h));
	cairo_text_extents(dctx, tmp, &size);
	cairo_show_text(dctx, tmp);
	cairo_fill(dctx);
	if ( h < 0 ) {
		cairo_move_to(dctx, x+size.x_bearing, y-sh);
		cairo_rel_line_to(dctx, size.width, 0.0);
		cairo_stroke(dctx);
	}
	x += size.x_advance;

	/* Draw 'k' */
	cairo_move_to(dctx, x, y);
	snprintf(tmp, 255, "%i", abs(k));
	cairo_text_extents(dctx, tmp, &size);
	cairo_show_text(dctx, tmp);
	cairo_fill(dctx);
	if ( k < 0 ) {
		cairo_move_to(dctx, x+size.x_bearing, y-sh);
		cairo_rel_line_to(dctx, size.width, 0.0);
		cairo_stroke(dctx);
	}
	x += size.x_advance;

	/* Draw 'l' */
	cairo_move_to(dctx, x, y);
	snprintf(tmp, 255, "%i", abs(l));
	cairo_text_extents(dctx, tmp, &size);
	cairo_show_text(dctx, tmp);
	cairo_fill(dctx);
	if ( l < 0 ) {
		cairo_move_to(dctx, x+size.x_bearing, y-sh);
		cairo_rel_line_to(dctx, size.width, 0.0);
		cairo_stroke(dctx);
	}
}


334
static void render_za(UnitCell *cell, ReflItemList *items,
335
                      double *ref, unsigned int *counts,
336
                      double boost, const char *sym, int wght, int colscale)
337
{
Thomas White's avatar
Thomas White committed
338
339
	cairo_surface_t *surface;
	cairo_t *dctx;
340
	double max_u, max_v, max_res, max_val;
341
	double scale_u, scale_v, scale;
Thomas White's avatar
Thomas White committed
342
	double sep_u, sep_v, max_r;
343
	double u, v;
344
	signed int max_ux, max_uy;
Thomas White's avatar
Thomas White committed
345
	double as, bs, theta;
346
347
348
	double asx, asy, asz;
	double bsx, bsy, bsz;
	double csx, csy, csz;
Thomas White's avatar
Thomas White committed
349
	float wh, ht;
350
351
352
353
354
355
356
357
358
359
	signed int xh, xk, xl;
	signed int yh, yk, yl;
	signed int zh, zk, zl;
	double xx, xy, xz;
	double yx, yy, yz;
	char tmp[256];
	cairo_text_extents_t size;
	double cx, cy;
	const double border = 200.0;

360
	xh = 0;  xk = 1;  xl = 0;
361
362
	yh = 0;  yk = 0;  yl = 1;

363
	/* Vector product to determine the zone axis. */
364
365
366
367
	zh = xk*yl - xl*yk;
	zk = - xh*yl + xl*yh;
	zl = xh*yk - xk*yh;
	STATUS("Zone axis is %i %i %i\n", zh, zk, zl);
368

369
	/* Size of output and centre definition */
Thomas White's avatar
Thomas White committed
370
371
	wh = 1024;
	ht = 1024;
372

Thomas White's avatar
Thomas White committed
373
	/* Work out reciprocal lattice spacings and angles for this cut */
374
	if ( cell_get_reciprocal(cell, &asx, &asy, &asz,
Thomas White's avatar
Thomas White committed
375
	                          &bsx, &bsy, &bsz,
376
377
378
379
	                          &csx, &csy, &csz) ) {
		ERROR("Couldn't get reciprocal parameters\n");
		return;
	}
380
381
382
383
384
385
386
387
388
389
	xx = xh*asx + xk*bsx + xl*csx;
	xy = xh*asy + xk*bsy + xl*csy;
	xz = xh*asz + xk*bsz + xl*csz;
	yx = yh*asx + yk*bsx + yl*csx;
	yy = yh*asy + yk*bsy + yl*csy;
	yz = yh*asz + yk*bsz + yl*csz;
	theta = angle_between(xx, xy, xz, yx, yy, yz);
	as = modulus(xx, xy, xz) / 1e9;
	bs = modulus(yx, yy, yz) / 1e9;

390
	scale = 1.0;
391
392
393
394
	draw_circles(xh, xk, xl, yh, yk, yl, zh, zk, zl,
	             ref, counts, items, sym, NULL, wght, boost, colscale, cell,
	             0.0, theta, as, bs, cx, cy, scale,
	             &max_ux, &max_uy, &max_val, &max_u, &max_v, &max_res);
395

Thomas White's avatar
Thomas White committed
396
	max_res /= 1e9;
397
398
	printf("Maximum resolution is 1/d = %5.3f nm^-1, d = %5.3f nm\n",
	       max_res*2.0, 1.0/(max_res*2.0));
Thomas White's avatar
Thomas White committed
399

400
	if ( max_val <= 0.0 ) {
Thomas White's avatar
Thomas White committed
401
		max_r = 4.0;
402
		STATUS("Couldn't find max value.\n");
Thomas White's avatar
Thomas White committed
403
		goto out;
404
405
	}

Thomas White's avatar
Thomas White committed
406
	/* Choose whichever scaling factor gives the smallest value */
407
408
	scale_u = ((double)wh-border) / (2.0*max_u);
	scale_v = ((double)ht-border) / (2.0*max_v);
409
	scale = (scale_u < scale_v) ? scale_u : scale_v;
410

411
412
413
	sep_u = (double)scale*as*sin(theta);
	sep_v = (double)scale*as*cos(theta) + scale*bs;
	/* We are interested in the smaller of the two separations */
414
	max_r = (sep_u < sep_v) ? sep_u : sep_v;
415
	max_r /= 2.0;  /* Max radius is half the separation */
416
	max_r -= 1.0;  /* Add a tiny separation between circles */
417
418
419
	if ( max_r < 1.0 ) {
		ERROR("Circle radius is probably too small (%f).\n", max_r);
	}
Thomas White's avatar
Thomas White committed
420

421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
	surface = cairo_pdf_surface_create("za.pdf", wh, ht);

	if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) {
		fprintf(stderr, "Couldn't create Cairo surface\n");
		cairo_surface_destroy(surface);
		return;
	}

	dctx = cairo_create(surface);

	/* Black background */
	cairo_rectangle(dctx, 0.0, 0.0, wh, ht);
	cairo_set_source_rgb(dctx, 0.0, 0.0, 0.0);
	cairo_fill(dctx);

	/* Test size of text that goes to the right(ish) */
	cairo_set_font_size(dctx, 40.0);
	snprintf(tmp, 255, "%i%i%i", abs(xh), abs(xk), abs(xl));
	cairo_text_extents(dctx, tmp, &size);

	cx = 532.0 - size.width;
	cy = 512.0 - 20.0;

444
445
446
447
	draw_circles(xh, xk, xl, yh, yk, yl, zh, zk, zl,
	             ref, counts, items, sym, dctx, wght, boost, colscale, cell,
	             max_r, theta, as, bs, cx, cy, scale,
	             NULL, NULL, &max_val, NULL, NULL, NULL);
448

Thomas White's avatar
Thomas White committed
449
450
out:
	/* Centre marker */
451
452
	cairo_arc(dctx, (double)cx,
			(double)cy, max_r, 0, 2*M_PI);
Thomas White's avatar
Thomas White committed
453
454
455
	cairo_set_source_rgb(dctx, 1.0, 0.0, 0.0);
	cairo_fill(dctx);

456
	/* Draw indexing lines */
457
	cairo_set_line_cap(dctx, CAIRO_LINE_CAP_ROUND);
458
	cairo_set_line_width(dctx, 4.0);
459
	cairo_move_to(dctx, (double)cx, (double)cy);
460
461
	u = (1.0+max_ux)*as*sin(theta);
	v = (1.0+max_ux)*as*cos(theta);
462
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
463
464
465
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

466
	cairo_set_font_size(dctx, 40.0);
467
	snprintf(tmp, 255, "%i%i%i", abs(xh), abs(xk), abs(xl));
468
469
470
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, cx+u*scale + 20.0, cy+v*scale + size.height/2.0);
471
	render_overlined_indices(dctx, xh, xk, xl);
472
473
	cairo_fill(dctx);

474
	snprintf(tmp, 255, "%i%i%i", abs(yh), abs(yk), abs(yl));
475
476
477
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, (double)cx, (double)cy);
478
	u = 0.0;
479
	v = (1.0+max_uy)*bs;
480
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
481
482
483
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

484
485
	cairo_move_to(dctx, cx+u*scale - size.width/2.0,
	                    cy+v*scale + size.height + 20.0);
486
	render_overlined_indices(dctx, yh, yk, yl);
487
488
	cairo_fill(dctx);

Thomas White's avatar
Thomas White committed
489
490
491
	cairo_surface_finish(surface);
	cairo_destroy(dctx);
}
492

493

494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
static int render_key(int colscale)
{
	cairo_surface_t *surface;
	cairo_t *dctx;
	float wh, ht;
	float y;

	wh = 128;
	ht = 1024;

	surface = cairo_pdf_surface_create("key.pdf", wh, ht);

	if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) {
		fprintf(stderr, "Couldn't create Cairo surface\n");
		cairo_surface_destroy(surface);
		return 1;
	}

	dctx = cairo_create(surface);

	for ( y=0; y<ht; y++ ) {

		float r, g, b;

		cairo_rectangle(dctx, 0.0, y, wh, y+1.0);

		render_scale(ht-y, ht, colscale, &r, &g, &b);
		cairo_set_source_rgb(dctx, r, g, b);

		cairo_fill(dctx);

	}

	cairo_surface_finish(surface);
	cairo_destroy(dctx);

	return 0;
}
532
#endif
Thomas White's avatar
Thomas White committed
533
534
535
536
537
538
539
540
541
542


int main(int argc, char *argv[])
{
	int c;
	UnitCell *cell;
	char *infile;
	double *ref;
	int config_povray = 0;
	int config_zoneaxis = 0;
Thomas White's avatar
Thomas White committed
543
	int config_sqrt = 0;
544
	int config_colkey = 0;
Thomas White's avatar
Thomas White committed
545
	unsigned int nproc = 1;
546
	char *pdb = NULL;
547
	int r = 0;
548
	double boost = 1.0;
549
	char *sym = NULL;
550
551
	char *weighting = NULL;
	int wght;
552
553
	int colscale;
	char *cscale = NULL;
Thomas White's avatar
Thomas White committed
554
	unsigned int *cts;
Thomas White's avatar
Thomas White committed
555
556
557
558
559
560

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
		{"povray",             0, &config_povray,      1},
		{"zone-axis",          0, &config_zoneaxis,    1},
561
		{"pdb",                1, NULL,               'p'},
562
		{"boost",              1, NULL,               'b'},
563
		{"symmetry",           1, NULL,               'y'},
564
		{"weighting",          1, NULL,               'w'},
565
		{"colscale",           1, NULL,               'c'},
566
		{"counts",             0, &config_sqrt,        1},
567
		{"colour-key",         0, &config_colkey,      1},
Thomas White's avatar
Thomas White committed
568
569
570
571
		{0, 0, NULL, 0}
	};

	/* Short options */
572
573
	while ((c = getopt_long(argc, argv, "hj:p:w:c:y:",
	                        longopts, NULL)) != -1) {
Thomas White's avatar
Thomas White committed
574
575

		switch (c) {
Thomas White's avatar
Thomas White committed
576
		case 'h' :
Thomas White's avatar
Thomas White committed
577
578
579
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
580
		case 'j' :
Thomas White's avatar
Thomas White committed
581
582
583
			nproc = atoi(optarg);
			break;

584
585
586
587
		case 'p' :
			pdb = strdup(optarg);
			break;

588
589
590
591
		case 'b' :
			boost = atof(optarg);
			break;

592
593
594
595
		case 'y' :
			sym = strdup(optarg);
			break;

596
597
598
599
		case 'w' :
			weighting = strdup(optarg);
			break;

600
601
602
603
		case 'c' :
			cscale = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
604
		case 0 :
Thomas White's avatar
Thomas White committed
605
606
			break;

Thomas White's avatar
Thomas White committed
607
		default :
Thomas White's avatar
Thomas White committed
608
609
610
611
612
			return 1;
		}

	}

613
614
615
616
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

617
618
619
620
	if ( sym == NULL ) {
		sym = strdup("1");
	}

621
622
623
624
625
626
627
628
629
630
	if ( weighting == NULL ) {
		weighting = strdup("I");
	}

	if ( strcmp(weighting, "I") == 0 ) {
		wght = WGHT_I;
	} else if ( strcmp(weighting, "sqrtI") == 0 ) {
		wght = WGHT_SQRTI;
	} else if ( strcmp(weighting, "count") == 0 ) {
		wght = WGHT_COUNTS;
631
632
	} else if ( strcmp(weighting, "counts") == 0 ) {
		wght = WGHT_COUNTS;
633
634
	} else if ( strcmp(weighting, "rawcts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
635
636
637
638
	} else if ( strcmp(weighting, "rawcount") == 0 ) {
		wght = WGHT_RAWCOUNTS;
	} else if ( strcmp(weighting, "rawcounts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
639
640
641
642
	} else {
		ERROR("Unrecognised weighting '%s'\n", weighting);
		return 1;
	}
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
	free(weighting);

	if ( cscale == NULL ) {
		cscale = strdup("mono");
	}

	if ( strcmp(cscale, "mono") == 0 ) {
		colscale = SCALE_MONO;
	} else if ( strcmp(cscale, "invmono") == 0 ) {
		colscale = SCALE_INVMONO;
	} else if ( strcmp(cscale, "colour") == 0 ) {
		colscale = SCALE_COLOUR;
	} else if ( strcmp(cscale, "color") == 0 ) {
		colscale = SCALE_COLOUR;
	} else {
		ERROR("Unrecognised colour scale '%s'\n", cscale);
		return 1;
	}
	free(cscale);
662

663
664
665
666
	if ( config_colkey ) {
		return render_key(colscale);
	}

Thomas White's avatar
Thomas White committed
667
668
	infile = argv[optind];

669
	cell = load_cell_from_pdb(pdb);
670
671
672
673
	if ( cell == NULL ) {
		ERROR("Couldn't load unit cell from %s\n", pdb);
		return 1;
	}
Thomas White's avatar
Thomas White committed
674
	ref = new_list_intensity();
Thomas White's avatar
Thomas White committed
675
	cts = new_list_count();
Thomas White's avatar
Thomas White committed
676
	ReflItemList *items = read_reflections(infile, ref, NULL, cts);
Thomas White's avatar
Thomas White committed
677
678
679
680
681
682
	if ( ref == NULL ) {
		ERROR("Couldn't open file '%s'\n", infile);
		return 1;
	}

	if ( config_povray ) {
683
		r = povray_render_animation(cell, ref, cts, nproc);
Thomas White's avatar
Thomas White committed
684
	} else if ( config_zoneaxis ) {
685
#ifdef HAVE_CAIRO
686
		render_za(cell, items, ref, cts, boost, sym, wght, colscale);
687
688
689
690
691
#else
		ERROR("This version of CrystFEL was compiled without Cairo");
		ERROR(" support, which is required to plot a zone axis");
		ERROR(" pattern.  Sorry!\n");
#endif
Thomas White's avatar
Thomas White committed
692
693
694
695
	} else {
		ERROR("Try again with either --povray or --zone-axis.\n");
	}

696
	free(pdb);
697
	free(sym);
698
	delete_items(items);
699

700
	return r;
701
}