render_hkl.c 15.9 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
static void render_za(UnitCell *cell, ReflItemList *items,
285
                      double *ref, unsigned int *counts,
286
                      double boost, const char *sym, int wght, int colscale)
287
{
Thomas White's avatar
Thomas White committed
288
289
	cairo_surface_t *surface;
	cairo_t *dctx;
290
	double max_u, max_v, max_res, max_val;
291
	double scale_u, scale_v, scale;
Thomas White's avatar
Thomas White committed
292
	double sep_u, sep_v, max_r;
293
	double u, v;
294
	signed int max_ux, max_uy;
Thomas White's avatar
Thomas White committed
295
	double as, bs, theta;
296
297
298
	double asx, asy, asz;
	double bsx, bsy, bsz;
	double csx, csy, csz;
Thomas White's avatar
Thomas White committed
299
	float wh, ht;
300
301
302
303
304
305
306
307
308
309
	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;

310
	xh = 0;  xk = 1;  xl = 0;
311
312
	yh = 0;  yk = 0;  yl = 1;

313
	/* Vector product to determine the zone axis. */
314
315
316
317
	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);
318

319
	/* Size of output and centre definition */
Thomas White's avatar
Thomas White committed
320
321
	wh = 1024;
	ht = 1024;
322
323
	cx = 512.0;
	cy = 500.0;
324

Thomas White's avatar
Thomas White committed
325
	surface = cairo_pdf_surface_create("za.pdf", wh, ht);
326

Thomas White's avatar
Thomas White committed
327
328
329
330
331
	if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) {
		fprintf(stderr, "Couldn't create Cairo surface\n");
		cairo_surface_destroy(surface);
		return;
	}
332

Thomas White's avatar
Thomas White committed
333
	dctx = cairo_create(surface);
334

Thomas White's avatar
Thomas White committed
335
336
337
338
	/* 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);
339

Thomas White's avatar
Thomas White committed
340
	/* Work out reciprocal lattice spacings and angles for this cut */
341
	if ( cell_get_reciprocal(cell, &asx, &asy, &asz,
Thomas White's avatar
Thomas White committed
342
	                          &bsx, &bsy, &bsz,
343
344
345
346
	                          &csx, &csy, &csz) ) {
		ERROR("Couldn't get reciprocal parameters\n");
		return;
	}
347
348
349
350
351
352
353
354
355
356
	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;

357
358
359
360
	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);
361

Thomas White's avatar
Thomas White committed
362
	max_res /= 1e9;
363
364
	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
365

366
	if ( max_val <= 0.0 ) {
Thomas White's avatar
Thomas White committed
367
		max_r = 4.0;
368
		STATUS("Couldn't find max value.\n");
Thomas White's avatar
Thomas White committed
369
		goto out;
370
371
	}

Thomas White's avatar
Thomas White committed
372
	/* Choose whichever scaling factor gives the smallest value */
373
374
	scale_u = ((double)wh-border) / (2.0*max_u);
	scale_v = ((double)ht-border) / (2.0*max_v);
375
	scale = (scale_u < scale_v) ? scale_u : scale_v;
376

377
378
379
	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 */
380
	max_r = (sep_u < sep_v) ? sep_u : sep_v;
381
	max_r /= 2.0;  /* Max radius is half the separation */
382
	max_r -= 1.0;  /* Add a tiny separation between circles */
383
384
385
	if ( max_r < 1.0 ) {
		ERROR("Circle radius is probably too small (%f).\n", max_r);
	}
Thomas White's avatar
Thomas White committed
386

387
388
389
390
	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);
391

Thomas White's avatar
Thomas White committed
392
393
out:
	/* Centre marker */
394
395
	cairo_arc(dctx, (double)cx,
			(double)cy, max_r, 0, 2*M_PI);
Thomas White's avatar
Thomas White committed
396
397
398
	cairo_set_source_rgb(dctx, 1.0, 0.0, 0.0);
	cairo_fill(dctx);

399
400
	/* Draw indexing lines */
	cairo_set_line_width(dctx, 4.0);
401
	cairo_move_to(dctx, (double)cx, (double)cy);
402
403
404
	u = (1.0+max_ux)*as*sin(theta);
	v = (1.0+max_ux)*as*cos(theta);
	STATUS("max u %i\n", max_ux);
405
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
406
407
408
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

409
410
411
412
413
414
	cairo_set_font_size(dctx, 40.0);
	snprintf(tmp, 255, "%i%i%i", xh, xk, xl);
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, cx+u*scale + 20.0, cy+v*scale + size.height/2.0);
	cairo_show_text(dctx, tmp);
415
416
	cairo_fill(dctx);

417
418
419
420
	snprintf(tmp, 255, "%i%i%i", yh, yk, yl);
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, (double)cx, (double)cy);
421
	u = 0.0;
422
	v = (1.0+max_uy)*bs;
423
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
424
425
426
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

427
428
429
	cairo_move_to(dctx, cx+u*scale - size.width/2.0,
	                    cy+v*scale + size.height + 20.0);
	cairo_show_text(dctx, tmp);
430
431
	cairo_fill(dctx);

Thomas White's avatar
Thomas White committed
432
433
434
	cairo_surface_finish(surface);
	cairo_destroy(dctx);
}
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473

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;
}
474
#endif
Thomas White's avatar
Thomas White committed
475
476
477
478
479
480
481
482
483
484


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
485
	int config_sqrt = 0;
486
	int config_colkey = 0;
Thomas White's avatar
Thomas White committed
487
	unsigned int nproc = 1;
488
	char *pdb = NULL;
489
	int r = 0;
490
	double boost = 1.0;
491
	char *sym = NULL;
492
493
	char *weighting = NULL;
	int wght;
494
495
	int colscale;
	char *cscale = NULL;
Thomas White's avatar
Thomas White committed
496
	unsigned int *cts;
Thomas White's avatar
Thomas White committed
497
498
499
500
501
502

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
		{"povray",             0, &config_povray,      1},
		{"zone-axis",          0, &config_zoneaxis,    1},
503
		{"pdb",                1, NULL,               'p'},
504
		{"boost",              1, NULL,               'b'},
505
		{"symmetry",           1, NULL,               'y'},
506
		{"weighting",          1, NULL,               'w'},
507
		{"colscale",           1, NULL,               'c'},
508
		{"counts",             0, &config_sqrt,        1},
509
		{"colour-key",         0, &config_colkey,      1},
Thomas White's avatar
Thomas White committed
510
511
512
513
		{0, 0, NULL, 0}
	};

	/* Short options */
514
515
	while ((c = getopt_long(argc, argv, "hj:p:w:c:y:",
	                        longopts, NULL)) != -1) {
Thomas White's avatar
Thomas White committed
516
517

		switch (c) {
Thomas White's avatar
Thomas White committed
518
		case 'h' :
Thomas White's avatar
Thomas White committed
519
520
521
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
522
		case 'j' :
Thomas White's avatar
Thomas White committed
523
524
525
			nproc = atoi(optarg);
			break;

526
527
528
529
		case 'p' :
			pdb = strdup(optarg);
			break;

530
531
532
533
		case 'b' :
			boost = atof(optarg);
			break;

534
535
536
537
		case 'y' :
			sym = strdup(optarg);
			break;

538
539
540
541
		case 'w' :
			weighting = strdup(optarg);
			break;

542
543
544
545
		case 'c' :
			cscale = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
546
		case 0 :
Thomas White's avatar
Thomas White committed
547
548
			break;

Thomas White's avatar
Thomas White committed
549
		default :
Thomas White's avatar
Thomas White committed
550
551
552
553
554
			return 1;
		}

	}

555
556
557
558
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

559
560
561
562
	if ( sym == NULL ) {
		sym = strdup("1");
	}

563
564
565
566
567
568
569
570
571
572
	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;
573
574
	} else if ( strcmp(weighting, "counts") == 0 ) {
		wght = WGHT_COUNTS;
575
576
	} else if ( strcmp(weighting, "rawcts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
577
578
579
580
	} else if ( strcmp(weighting, "rawcount") == 0 ) {
		wght = WGHT_RAWCOUNTS;
	} else if ( strcmp(weighting, "rawcounts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
581
582
583
584
	} else {
		ERROR("Unrecognised weighting '%s'\n", weighting);
		return 1;
	}
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
	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);
604

605
606
607
608
	if ( config_colkey ) {
		return render_key(colscale);
	}

Thomas White's avatar
Thomas White committed
609
610
	infile = argv[optind];

611
	cell = load_cell_from_pdb(pdb);
612
613
614
615
	if ( cell == NULL ) {
		ERROR("Couldn't load unit cell from %s\n", pdb);
		return 1;
	}
Thomas White's avatar
Thomas White committed
616
	ref = new_list_intensity();
Thomas White's avatar
Thomas White committed
617
	cts = new_list_count();
Thomas White's avatar
Thomas White committed
618
	ReflItemList *items = read_reflections(infile, ref, NULL, cts);
Thomas White's avatar
Thomas White committed
619
620
621
622
623
624
	if ( ref == NULL ) {
		ERROR("Couldn't open file '%s'\n", infile);
		return 1;
	}

	if ( config_povray ) {
625
		r = povray_render_animation(cell, ref, cts, nproc);
Thomas White's avatar
Thomas White committed
626
	} else if ( config_zoneaxis ) {
627
#ifdef HAVE_CAIRO
628
		render_za(cell, items, ref, cts, boost, sym, wght, colscale);
629
630
631
632
633
#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
634
635
636
637
	} else {
		ERROR("Try again with either --povray or --zone-axis.\n");
	}

638
	free(pdb);
639
	free(sym);
640
	delete_items(items);
641

642
	return r;
643
}