symmetry.c 36.9 KB
Newer Older
1
2
3
4
5
/*
 * symmetry.c
 *
 * Symmetry
 *
6
7
8
9
 * Copyright © 2012 Deutsches Elektronen-Synchrotron DESY,
 *                  a research centre of the Helmholtz Association.
 *
 * Authors:
10
 *   2010-2012 Thomas White <taw@physics.org>
11
 *
Thomas White's avatar
Thomas White committed
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * This file is part of CrystFEL.
 *
 * CrystFEL is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * CrystFEL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with CrystFEL.  If not, see <http://www.gnu.org/licenses/>.
26
27
28
29
30
31
32
33
34
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdlib.h>
#include <stdio.h>
35
#include <string.h>
36
#include <math.h>
Thomas White's avatar
Thomas White committed
37
#include <assert.h>
38

39
#include "symmetry.h"
40
#include "utils.h"
41
#include "integer_matrix.h"
42

43

Thomas White's avatar
Thomas White committed
44
45
46
47
48
49
50
51
52
53
54
55
/**
 * SECTION:symmetry
 * @short_description: Point symmetry handling
 * @title: Symmetry
 * @section_id:
 * @see_also:
 * @include: "symmetry.h"
 * @Image:
 *
 * Routines to handle point symmetry.
 */

56

Thomas White's avatar
Thomas White committed
57
58
struct _symoplist
{
59
	IntegerMatrix **ops;
60
61
	int n_ops;
	int max_ops;
Thomas White's avatar
Thomas White committed
62
	char *name;
63
	int num_equivs;
64
65
66
};


Thomas White's avatar
Thomas White committed
67
68
69
70
71
72
73
struct _symopmask
{
	const SymOpList *list;
	int *mask;
};


74

Thomas White's avatar
Thomas White committed
75
static void alloc_ops(SymOpList *ops)
76
{
77
	ops->ops = realloc(ops->ops, ops->max_ops*sizeof(IntegerMatrix *));
78
79
80
}


Thomas White's avatar
Thomas White committed
81
82
/**
 * new_symopmask:
Thomas White's avatar
Thomas White committed
83
 * @list: A %SymOpList
Thomas White's avatar
Thomas White committed
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
 *
 * Returns: a new %SymOpMask, which you can use when filtering out special
 * reflections.
 **/
SymOpMask *new_symopmask(const SymOpList *list)
{
	SymOpMask *m;
	int i;

	m = malloc(sizeof(struct _symopmask));
	if ( m == NULL ) return NULL;

	m->list = list;
	m->mask = malloc(sizeof(int)*list->n_ops);
	if ( m->mask == NULL ) {
		free(m);
		return NULL;
	}

	for ( i=0; i<list->n_ops; i++ ) {
		m->mask[i] = 1;
	}

	return m;
}


Thomas White's avatar
Thomas White committed
111
112
/* Creates a new SymOpList */
static SymOpList *new_symoplist()
113
114
115
116
{
	SymOpList *new;
	new = malloc(sizeof(SymOpList));
	if ( new == NULL ) return NULL;
Thomas White's avatar
Thomas White committed
117
	new->max_ops = 16;
118
	new->n_ops = 0;
Thomas White's avatar
Thomas White committed
119
	new->ops = NULL;
Thomas White's avatar
Thomas White committed
120
	new->name = NULL;
121
	new->num_equivs = 1;
Thomas White's avatar
Thomas White committed
122
	alloc_ops(new);
123
124
125
126
	return new;
}


Thomas White's avatar
Thomas White committed
127
128
/**
 * free_symoplist:
Thomas White's avatar
Thomas White committed
129
 * @ops: A %SymOpList to free
Thomas White's avatar
Thomas White committed
130
131
132
133
 *
 * Frees a %SymOpList and all associated resources.
 **/
void free_symoplist(SymOpList *ops)
134
{
Thomas White's avatar
Thomas White committed
135
136
137
138
	int i;

	if ( ops == NULL ) return;
	for ( i=0; i<ops->n_ops; i++ ) {
139
		intmat_free(ops->ops[i]);
Thomas White's avatar
Thomas White committed
140
141
	}
	if ( ops->ops != NULL ) free(ops->ops);
Thomas White's avatar
Thomas White committed
142
	if ( ops->name != NULL ) free(ops->name);
Thomas White's avatar
Thomas White committed
143
	free(ops);
144
145
}

Thomas White's avatar
Thomas White committed
146
147
/**
 * free_symopmask:
Thomas White's avatar
Thomas White committed
148
 * @m: A %SymOpMask to free
Thomas White's avatar
Thomas White committed
149
150
151
152
 *
 * Frees a %SymOpMask and all associated resources.
 **/
void free_symopmask(SymOpMask *m)
Thomas White's avatar
Thomas White committed
153
{
Thomas White's avatar
Thomas White committed
154
155
156
	if ( m == NULL ) return;
	free(m->mask);
	free(m);
Thomas White's avatar
Thomas White committed
157
158
159
}


Thomas White's avatar
Thomas White committed
160
161
/* This returns the number of operations in "ops".  This might be different
 * to num_equivs() if the point group is being constructed. */
162
163
164
165
166
167
static int num_ops(const SymOpList *ops)
{
	return ops->n_ops;
}


168
169
170
171
172
173
174
175
/**
 * add_symop:
 * @ops: A %SymOpList
 * @m: An %IntegerMatrix
 *
 * Adds @m to @ops.
 **/
void add_symop(SymOpList *ops, IntegerMatrix *m)
176
{
Thomas White's avatar
Thomas White committed
177
178
179
	if ( ops->n_ops == ops->max_ops ) {
		ops->max_ops += 16;
		alloc_ops(ops);
180
181
	}

182
	ops->ops[ops->n_ops++] = m;
Thomas White's avatar
Thomas White committed
183
184
185
}


186
187
188
/* Add a operation to a SymOpList, starting from v(..) */
static void add_symop_v(SymOpList *ops,
                        signed int *h, signed int *k, signed int *l)
Thomas White's avatar
Thomas White committed
189
{
190
191
	IntegerMatrix *m;
	int i;
Thomas White's avatar
Thomas White committed
192

193
194
	m = intmat_new(3, 3);
	assert(m != NULL);
Thomas White's avatar
Thomas White committed
195

196
197
198
	for ( i=0; i<3; i++ ) intmat_set(m, 0, i, h[i]);
	for ( i=0; i<3; i++ ) intmat_set(m, 1, i, k[i]);
	for ( i=0; i<3; i++ ) intmat_set(m, 2, i, l[i]);
Thomas White's avatar
Thomas White committed
199

200
201
202
	free(h);
	free(k);
	free(l);
Thomas White's avatar
Thomas White committed
203

204
205
	add_symop(ops, m);
}
Thomas White's avatar
Thomas White committed
206
207


208
209
210
211
212
213
214
static signed int *v(signed int h, signed int k, signed int i, signed int l)
{
	signed int *vec = malloc(3*sizeof(signed int));
	if ( vec == NULL ) return NULL;
	/* Convert back to 3-index form now */
	vec[0] = h-i;  vec[1] = k-i;  vec[2] = l;
	return vec;
Thomas White's avatar
Thomas White committed
215
216
217
}


Thomas White's avatar
Thomas White committed
218
219
/**
 * num_equivs:
Thomas White's avatar
Thomas White committed
220
221
 * @ops: A %SymOpList
 * @m: A %SymOpMask, which has been shown to special_position()
Thomas White's avatar
Thomas White committed
222
223
 *
 * Returns: the number of equivalent reflections for a general reflection
Thomas White's avatar
Thomas White committed
224
225
 * in point group "ops", which were not flagged by your call to
 * special_position().
Thomas White's avatar
Thomas White committed
226
 **/
Thomas White's avatar
Thomas White committed
227
int num_equivs(const SymOpList *ops, const SymOpMask *m)
Thomas White's avatar
Thomas White committed
228
{
229
230
231
232
233
234
235
236
237
238
239
240
	int n = num_ops(ops);
	int i;
	int c;

	if ( m == NULL ) return n;

	c = 0;
	for ( i=0; i<n; i++ ) {
		if ( m->mask[i] ) c++;
	}

	return c;
Thomas White's avatar
Thomas White committed
241
242
243
}


244
static void add_identity(SymOpList *s)
245
{
246
247
	int i, ni;
	int found;
Thomas White's avatar
Thomas White committed
248

249
250
251
252
253
254
255
256
257
258
259
	found = 0;
	ni = num_ops(s);
	for ( i=0; i<ni; i++ ) {
		if ( intmat_is_identity(s->ops[i]) ) {
			found = 1;
			break;
		}
	}
	if ( !found ) {
		add_symop_v(s, v(1,0,0,0), v(0,1,0,0), v(0,0,0,1));  /* I */
	}
Thomas White's avatar
Thomas White committed
260
261
262
}


263
264
265
/* Fill in the other operations for a point group starting from its
 * generators */
static void expand_ops(SymOpList *s)
Thomas White's avatar
Thomas White committed
266
{
267
	int added;
Thomas White's avatar
Thomas White committed
268

269
	add_identity(s);
Thomas White's avatar
Thomas White committed
270

271
	do {
Thomas White's avatar
Thomas White committed
272

273
		int i, ni;
Thomas White's avatar
Thomas White committed
274

275
		added = 0;
Thomas White's avatar
Thomas White committed
276

277
278
		ni = num_ops(s);
		for ( i=0; i<ni; i++ ) {
Thomas White's avatar
Thomas White committed
279

280
281
			int j;
			IntegerMatrix *opi = s->ops[i];
282

283
284
			/* Apply op 'i' to all the current ops in the list */
			for ( j=0; j<ni; j++ ) {
Thomas White's avatar
Thomas White committed
285

286
287
288
289
				IntegerMatrix *opj = s->ops[j];
				IntegerMatrix *m;
				int k, nk;
				int found;
Thomas White's avatar
Thomas White committed
290

291
292
				m = intmat_intmat_mult(opi, opj);
				assert(m != NULL);
Thomas White's avatar
Thomas White committed
293

294
295
296
297
298
299
300
301
302
				nk = num_ops(s);
				found = 0;
				for ( k=0; k<nk; k++ ) {
					if ( intmat_equals(m, s->ops[k]) ) {
						found = 1;
						intmat_free(m);
						break;
					}
				}
Thomas White's avatar
Thomas White committed
303

304
305
306
307
				if ( !found ) {
					add_symop(s, m);
					added++;
				}
Thomas White's avatar
Thomas White committed
308
309
310
311
312

			}

		}

313
	} while ( added );
Thomas White's avatar
Thomas White committed
314
315
316
}


317
318
319
/* Transform all the operations in a SymOpList by a given matrix.
 * The matrix must have a determinant of +/- 1 (otherwise its inverse would
 * not also be an integer matrix). */
320
static void transform_ops(SymOpList *s, IntegerMatrix *t)
321
322
{
	int n, i;
323
	IntegerMatrix *inv;
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
	signed int det;

	det = intmat_det(t);
	if ( det == -1 ) {
		ERROR("Warning: mirrored SymOpList.\n");
	} else if ( det != 1 ) {
		ERROR("Invalid transformation for SymOpList.\n");
		return;
	}

	inv = intmat_inverse(t);
	if ( inv == NULL ) {
		ERROR("Failed to invert matrix.\n");
		return;
	}

	n = num_ops(s);
	for ( i=0; i<n; i++ ) {

343
		IntegerMatrix *r, *f;
344

345
		r = intmat_intmat_mult(s->ops[i], t);
346
347
348
349
350
351
352
353
354
355
356
357
		if ( r == NULL ) {
			ERROR("Matrix multiplication failed.\n");
			return;
		}

		f = intmat_intmat_mult(inv, r);
		if ( f == NULL ) {
			ERROR("Matrix multiplication failed.\n");
			return;
		}
		intmat_free(r);

358
359
		intmat_free(s->ops[i]);
		s->ops[i] = intmat_copy(f);
360
361
362
363
364
365
366
367
		intmat_free(f);

	}

	intmat_free(inv);
}


Thomas White's avatar
Thomas White committed
368
369
370
371
372
/********************************* Triclinic **********************************/

static SymOpList *make_1bar()
{
	SymOpList *new = new_symoplist();
373
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,-1));  /* -I */
Thomas White's avatar
Thomas White committed
374
	new->name = strdup("-1");
375
376
	expand_ops(new);
	return new;
377
378
379
}


Thomas White's avatar
Thomas White committed
380
static SymOpList *make_1()
381
{
Thomas White's avatar
Thomas White committed
382
	SymOpList *new = new_symoplist();
Thomas White's avatar
Thomas White committed
383
	new->name = strdup("1");
384
385
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
386
}
387

Thomas White's avatar
Thomas White committed
388
389
390
391
392

/********************************* Monoclinic *********************************/

static SymOpList *make_2m()
{
Thomas White's avatar
Thomas White committed
393
	SymOpList *new = new_symoplist();
394
395
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,1)); /* 2 // l */
	add_symop_v(new, v(1,0,0,0), v(0,1,0,0), v(0,0,0,-1));  /* m -| l */
Thomas White's avatar
Thomas White committed
396
	new->name = strdup("2/m");
397
398
	expand_ops(new);
	return new;
399
400
401
}


Thomas White's avatar
Thomas White committed
402
static SymOpList *make_2()
403
{
Thomas White's avatar
Thomas White committed
404
	SymOpList *new = new_symoplist();
405
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,1)); /* 2 // l */
Thomas White's avatar
Thomas White committed
406
	new->name = strdup("2");
407
408
	expand_ops(new);
	return new;
409
410
411
}


Thomas White's avatar
Thomas White committed
412
static SymOpList *make_m()
413
{
Thomas White's avatar
Thomas White committed
414
	SymOpList *new = new_symoplist();
415
	add_symop_v(new, v(1,0,0,0), v(0,1,0,0), v(0,0,0,-1));  /* m -| l */
Thomas White's avatar
Thomas White committed
416
	new->name = strdup("m");
417
418
	expand_ops(new);
	return new;
419
420
421
}


Thomas White's avatar
Thomas White committed
422
423
424
/******************************** Orthorhombic ********************************/

static SymOpList *make_mmm()
425
{
Thomas White's avatar
Thomas White committed
426
	SymOpList *new = new_symoplist();
427
428
429
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,1)); /* 2 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,-1)); /* 2 // k */
	add_symop_v(new, v(1,0,0,0), v(0,-1,0,0), v(0,0,0,1));  /* m -| k */
Thomas White's avatar
Thomas White committed
430
	new->name = strdup("mmm");
431
432
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
433
}
434
435


Thomas White's avatar
Thomas White committed
436
437
static SymOpList *make_222()
{
Thomas White's avatar
Thomas White committed
438
	SymOpList *new = new_symoplist();
439
440
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,1)); /* 2 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,-1)); /* 2 // k */
Thomas White's avatar
Thomas White committed
441
	new->name = strdup("222");
442
443
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
444
}
445
446


Thomas White's avatar
Thomas White committed
447
448
static SymOpList *make_mm2()
{
Thomas White's avatar
Thomas White committed
449
	SymOpList *new = new_symoplist();
450
451
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,1)); /* 2 // l */
	add_symop_v(new, v(1,0,0,0), v(0,-1,0,0), v(0,0,0,1));  /* m -| k */
Thomas White's avatar
Thomas White committed
452
	new->name = strdup("mm2");
453
454
	expand_ops(new);
	return new;
455
456
457
}


Thomas White's avatar
Thomas White committed
458
459
460
/********************************* Tetragonal *********************************/

static SymOpList *make_4m()
461
{
Thomas White's avatar
Thomas White committed
462
	SymOpList *new = new_symoplist();
463
464
	add_symop_v(new, v(0,-1,0,0), v(1,0,0,0), v(0,0,0,1)); /* 4 // l */
	add_symop_v(new, v(1,0,0,0), v(0,1,0,0), v(0,0,0,-1)); /* m -| l */
Thomas White's avatar
Thomas White committed
465
	new->name = strdup("4/m");
466
467
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
468
}
469
470


Thomas White's avatar
Thomas White committed
471
472
static SymOpList *make_4()
{
Thomas White's avatar
Thomas White committed
473
	SymOpList *new = new_symoplist();
474
	add_symop_v(new, v(0,-1,0,0), v(1,0,0,0), v(0,0,0,1)); /* 4 // l */
Thomas White's avatar
Thomas White committed
475
	new->name = strdup("4");
476
477
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
478
}
479
480


Thomas White's avatar
Thomas White committed
481
482
483
static SymOpList *make_4mm()
{
	SymOpList *new = new_symoplist();
484
485
	add_symop_v(new, v(0,-1,0,0), v(1,0,0,0), v(0,0,0,1)); /* 4 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,1)); /* m -| l */
486
	new->name = strdup("4mm");
487
488
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
489
490
491
492
493
494
}


static SymOpList *make_422()
{
	SymOpList *new = new_symoplist();
495
496
	add_symop_v(new, v(0,-1,0,0), v(1,0,0,0), v(0,0,0,1));  /* 4 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,-1)); /* 2 // k */
Thomas White's avatar
Thomas White committed
497
	new->name = strdup("422");
498
499
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
500
501
502
}


Thomas White's avatar
Thomas White committed
503
504
static SymOpList *make_4bar()
{
Thomas White's avatar
Thomas White committed
505
	SymOpList *new = new_symoplist();
506
	add_symop_v(new, v(0,1,0,0), v(-1,0,0,0), v(0,0,0,-1)); /* -4 // l */
Thomas White's avatar
Thomas White committed
507
	new->name = strdup("-4");
508
509
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
510
511
512
513
514
515
}


static SymOpList *make_4bar2m()
{
	SymOpList *new = new_symoplist();
516
517
	add_symop_v(new, v(0,1,0,0), v(-1,0,0,0), v(0,0,0,-1)); /* -4 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,-1)); /* 2 // k */
Thomas White's avatar
Thomas White committed
518
	new->name = strdup("-42m");
519
520
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
521
522
523
524
525
526
}


static SymOpList *make_4barm2()
{
	SymOpList *new = new_symoplist();
527
528
	add_symop_v(new, v(0,1,0,0), v(-1,0,0,0), v(0,0,0,-1)); /* -4 // l */
	add_symop_v(new, v(0,1,0,0), v(1,0,0,0), v(0,0,0,-1)); /* 2 // h+k */
Thomas White's avatar
Thomas White committed
529
	new->name = strdup("-4m2");
530
531
	expand_ops(new);
	return new;
532
533
534
}


Thomas White's avatar
Thomas White committed
535
static SymOpList *make_4mmm()
536
{
Thomas White's avatar
Thomas White committed
537
	SymOpList *new = new_symoplist();
538
539
540
	add_symop_v(new, v(0,-1,0,0), v(1,0,0,0), v(0,0,0,1)); /* 4 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,1)); /* m -| k */
	add_symop_v(new, v(1,0,0,0), v(0,1,0,0), v(0,0,0,-1)); /* m -| l */
Thomas White's avatar
Thomas White committed
541
	new->name = strdup("4/mmm");
542
543
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
544
}
545
546


Thomas White's avatar
Thomas White committed
547
548
549
/************************** Trigonal (Rhombohedral) ***************************/

static SymOpList *make_3_R()
Thomas White's avatar
Thomas White committed
550
{
Thomas White's avatar
Thomas White committed
551
	SymOpList *new = new_symoplist();
552
	add_symop_v(new, v(0,0,0,1), v(1,0,0,0), v(0,1,0,0)); /* 3 // h+k+l */
Thomas White's avatar
Thomas White committed
553
	new->name = strdup("3_R");
554
555
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
556
}
557
558


Thomas White's avatar
Thomas White committed
559
static SymOpList *make_3bar_R()
Thomas White's avatar
Thomas White committed
560
{
Thomas White's avatar
Thomas White committed
561
	SymOpList *new = new_symoplist();
562
563
	add_symop_v(new, v(0,0,0,1), v(1,0,0,0), v(0,1,0,0)); /* -3 // h+k+l */
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,-1)); /* -I */
Thomas White's avatar
Thomas White committed
564
	new->name = strdup("-3_R");
565
566
	expand_ops(new);
	return new;
567
568
569
}


Thomas White's avatar
Thomas White committed
570
static SymOpList *make_32_R()
571
{
Thomas White's avatar
Thomas White committed
572
	SymOpList *new = new_symoplist();
573
574
	add_symop_v(new, v(0,0,0,1), v(1,0,0,0), v(0,1,0,0)); /* 3 // h+k+l */
	add_symop_v(new, v(0,-1,0,0), v(-1,0,0,0), v(0,0,0,-1)); /* 2 -| 3 */
Thomas White's avatar
Thomas White committed
575
	new->name = strdup("32_R");
576
577
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
578
}
Thomas White's avatar
Thomas White committed
579

Thomas White's avatar
Thomas White committed
580

Thomas White's avatar
Thomas White committed
581
582
583
static SymOpList *make_3m_R()
{
	SymOpList *new = new_symoplist();
584
585
	add_symop_v(new, v(0,0,0,1), v(1,0,0,0), v(0,1,0,0)); /* 3 // h+k+l */
	add_symop_v(new, v(0,1,0,0), v(1,0,0,0), v(0,0,0,1)); /* m */
Thomas White's avatar
Thomas White committed
586
	new->name = strdup("3m_R");
587
588
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
589
}
Thomas White's avatar
Thomas White committed
590

591

Thomas White's avatar
Thomas White committed
592
593
594
static SymOpList *make_3barm_R()
{
	SymOpList *new = new_symoplist();
595
596
597
	add_symop_v(new, v(0,0,0,1), v(1,0,0,0), v(0,1,0,0)); /* -3 // h+k+l */
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,-1)); /* -I */
	add_symop_v(new, v(0,1,0,0), v(1,0,0,0), v(0,0,0,1));    /* m */
Thomas White's avatar
Thomas White committed
598
	new->name = strdup("-3m_R");
599
600
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
601
}
602

Thomas White's avatar
Thomas White committed
603
604
605
606

/*************************** Trigonal (Hexagonal) *****************************/

static SymOpList *make_3_H()
Thomas White's avatar
Thomas White committed
607
{
Thomas White's avatar
Thomas White committed
608
	SymOpList *new = new_symoplist();
609
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,1)); /* 3 // l */
Thomas White's avatar
Thomas White committed
610
	new->name = strdup("3_H");
611
612
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
613
614
615
616
617
618
}


static SymOpList *make_3bar_H()
{
	SymOpList *new = new_symoplist();
619
620
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,1));    /* 3 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,-1)); /* -I */
Thomas White's avatar
Thomas White committed
621
	new->name = strdup("-3_H");
622
623
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
624
625
626
627
628
629
}


static SymOpList *make_321_H()
{
	SymOpList *new = new_symoplist();
630
631
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,1));  /* 3 // l */
	add_symop_v(new, v(0,1,0,0), v(1,0,0,0), v(0,0,0,-1)); /* 2 // h */
Thomas White's avatar
Thomas White committed
632
	new->name = strdup("321_H");
633
634
	expand_ops(new);
	return new;
635
}
636

637

Thomas White's avatar
Thomas White committed
638
639
640
static SymOpList *make_312_H()
{
	SymOpList *new = new_symoplist();
641
642
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,1));    /* 3 // l */
	add_symop_v(new, v(0,-1,0,0), v(-1,0,0,0), v(0,0,0,-1)); /* 2 // h+k */
Thomas White's avatar
Thomas White committed
643
	new->name = strdup("312_H");
644
645
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
646
647
648
649
650
651
}


static SymOpList *make_3m1_H()
{
	SymOpList *new = new_symoplist();
652
653
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,1)); /* 3 // l */
	add_symop_v(new, v(0,-1,0,0), v(-1,0,0,0), v(0,0,0,1)); /* m -| i */
Thomas White's avatar
Thomas White committed
654
	new->name = strdup("3m1_H");
655
656
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
657
658
659
660
661
662
}


static SymOpList *make_31m_H()
{
	SymOpList *new = new_symoplist();
663
664
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,1)); /* 3 // l */
	add_symop_v(new, v(0,1,0,0), v(1,0,0,0), v(0,0,0,1)); /* m -| (k+i) */
Thomas White's avatar
Thomas White committed
665
	new->name = strdup("31m_H");
666
667
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
668
669
670
671
672
673
}


static SymOpList *make_3barm1_H()
{
	SymOpList *new = new_symoplist();
674
675
676
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,1));    /* 3 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,-1)); /* -I */
	add_symop_v(new, v(0,1,0,0), v(1,0,0,0), v(0,0,0,-1));   /* 2 // h */
Thomas White's avatar
Thomas White committed
677
	new->name = strdup("-3m1_H");
678
679
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
680
681
682
683
684
685
}


static SymOpList *make_3bar1m_H()
{
	SymOpList *new = new_symoplist();
686
687
688
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,1));    /* 3 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,-1)); /* -I */
	add_symop_v(new, v(0,-1,0,0), v(-1,0,0,0), v(0,0,0,-1)); /* 2 // h+k */
Thomas White's avatar
Thomas White committed
689
	new->name = strdup("-31m_H");
690
691
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
692
693
694
695
696
}


/********************************** Hexgonal **********************************/

Thomas White's avatar
Thomas White committed
697
698
static SymOpList *make_6()
{
Thomas White's avatar
Thomas White committed
699
	SymOpList *new = new_symoplist();
700
	add_symop_v(new, v(0,0,-1,0), v(-1,0,0,0), v(0,0,0,1)); /* 6 // l */
Thomas White's avatar
Thomas White committed
701
	new->name = strdup("6");
702
703
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
704
}
705
706


Thomas White's avatar
Thomas White committed
707
static SymOpList *make_6bar()
708
{
Thomas White's avatar
Thomas White committed
709
	SymOpList *new = new_symoplist();
710
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,-1)); /* -6 // l */
Thomas White's avatar
Thomas White committed
711
	new->name = strdup("-6");
712
713
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
714
}
Thomas White's avatar
Thomas White committed
715

Thomas White's avatar
Thomas White committed
716

Thomas White's avatar
Thomas White committed
717
static SymOpList *make_6m()
Thomas White's avatar
Thomas White committed
718
{
Thomas White's avatar
Thomas White committed
719
	SymOpList *new = new_symoplist();
720
721
	add_symop_v(new, v(0,0,-1,0), v(-1,0,0,0), v(0,0,0,1)); /* 6 // l */
	add_symop_v(new, v(1,0,0,0), v(0,1,0,0), v(0,0,0,-1));  /* m -| l */
Thomas White's avatar
Thomas White committed
722
	new->name = strdup("6/m");
723
724
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
725
}
Thomas White's avatar
Thomas White committed
726

Thomas White's avatar
Thomas White committed
727

Thomas White's avatar
Thomas White committed
728
729
static SymOpList *make_622()
{
Thomas White's avatar
Thomas White committed
730
	SymOpList *new = new_symoplist();
731
732
	add_symop_v(new, v(0,0,-1,0), v(-1,0,0,0), v(0,0,0,1)); /* 6 // l */
	add_symop_v(new, v(0,1,0,0), v(1,0,0,0), v(0,0,0,-1));   /* 2 // h */
Thomas White's avatar
Thomas White committed
733
	new->name = strdup("622");
734
735
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
736
737
738
739
740
741
}


static SymOpList *make_6mm()
{
	SymOpList *new = new_symoplist();
742
743
	add_symop_v(new, v(0,0,-1,0), v(-1,0,0,0), v(0,0,0,1)); /* 6 // l */
	add_symop_v(new, v(0,-1,0,0), v(-1,0,0,0), v(0,0,0,1)); /* m -| i */
Thomas White's avatar
Thomas White committed
744
	new->name = strdup("6mm");
745
746
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
747
748
749
750
751
752
}


static SymOpList *make_6barm2()
{
	SymOpList *new = new_symoplist();
753
754
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,-1)); /* -6 // l */
	add_symop_v(new, v(0,-1,0,0), v(-1,0,0,0), v(0,0,0,1)); /* m -| i */
Thomas White's avatar
Thomas White committed
755
	new->name = strdup("-6m2");
756
757
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
758
759
}

760

Thomas White's avatar
Thomas White committed
761
762
static SymOpList *make_6bar2m()
{
Thomas White's avatar
Thomas White committed
763
	SymOpList *new = new_symoplist();
764
765
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,-1)); /* -6 // l */
	add_symop_v(new, v(0,1,0,0), v(1,0,0,0), v(0,0,0,1));  /* m -| (k+i) */
Thomas White's avatar
Thomas White committed
766
	new->name = strdup("-62m");
767
768
	expand_ops(new);
	return new;
769
770
771
}


Thomas White's avatar
Thomas White committed
772
static SymOpList *make_6mmm()
773
{
Thomas White's avatar
Thomas White committed
774
	SymOpList *new = new_symoplist();
775
776
777
	add_symop_v(new, v(0,0,1,0), v(1,0,0,0), v(0,0,0,-1)); /* -6 // l */
	add_symop_v(new, v(0,-1,0,0), v(-1,0,0,0), v(0,0,0,1)); /* m -| i */
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,-1)); /* -I */
Thomas White's avatar
Thomas White committed
778
	new->name = strdup("6/mmm");
779
780
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
781
}
Thomas White's avatar
Thomas White committed
782

Thomas White's avatar
Thomas White committed
783

Thomas White's avatar
Thomas White committed
784
/************************************ Cubic ***********************************/
785

Thomas White's avatar
Thomas White committed
786
787
788
static SymOpList *make_23()
{
	SymOpList *new = new_symoplist();
789
790
791
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,1)); /* 2 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,-1)); /* 2 // k */
	add_symop_v(new, v(0,1,0,0), v(0,0,0,1), v(1,0,0,0)); /* 3 // h+k+l */
Thomas White's avatar
Thomas White committed
792
	new->name = strdup("23");
793
794
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
795
796
797
798
799
800
}


static SymOpList *make_m3bar()
{
	SymOpList *new = new_symoplist();
801
802
803
804
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,1)); /* 2 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,-1)); /* 2 // k */
	add_symop_v(new, v(0,1,0,0), v(0,0,0,1), v(1,0,0,0)); /* 3 // h+k+l */
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,-1)); /* -I */
Thomas White's avatar
Thomas White committed
805
	new->name = strdup("m-3");
806
807
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
808
809
810
811
812
813
}


static SymOpList *make_432()
{
	SymOpList *new = new_symoplist();
814
815
816
	add_symop_v(new, v(0,-1,0,0), v(1,0,0,0), v(0,0,0,1)); /* 4 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,-1));/* 2 // k */
	add_symop_v(new, v(0,1,0,0), v(0,0,0,1), v(1,0,0,0));  /* 3 // h+k+l */
Thomas White's avatar
Thomas White committed
817
	new->name = strdup("432");
818
819
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
820
821
822
823
824
825
}


static SymOpList *make_4bar3m()
{
	SymOpList *new = new_symoplist();
826
827
828
	add_symop_v(new, v(0,1,0,0), v(-1,0,0,0), v(0,0,0,-1)); /* -4 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,-1)); /* 2 // k */
	add_symop_v(new, v(0,1,0,0), v(0,0,0,1), v(1,0,0,0));   /* 3 // h+k+l */
Thomas White's avatar
Thomas White committed
829
	new->name = strdup("-43m");
830
831
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
832
833
834
835
836
837
}


static SymOpList *make_m3barm()
{
	SymOpList *new = new_symoplist();
838
839
840
841
	add_symop_v(new, v(0,-1,0,0), v(1,0,0,0), v(0,0,0,1)); /* 4 // l */
	add_symop_v(new, v(-1,0,0,0), v(0,1,0,0), v(0,0,0,-1));/* 2 // k */
	add_symop_v(new, v(0,1,0,0), v(0,0,0,1), v(1,0,0,0));  /* 3 // h+k+l */
	add_symop_v(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,-1)); /* -I */
Thomas White's avatar
Thomas White committed
842
	new->name = strdup("m-3m");
843
844
	expand_ops(new);
	return new;
Thomas White's avatar
Thomas White committed
845
846
847
}


Thomas White's avatar
Thomas White committed
848
static SymOpList *getpg_uac(const char *sym)
Thomas White's avatar
Thomas White committed
849
850
851
852
{
	/* Triclinic */
	if ( strcmp(sym, "-1") == 0 ) return make_1bar();
	if ( strcmp(sym, "1") == 0 ) return make_1();
Thomas White's avatar
Thomas White committed
853

Thomas White's avatar
Thomas White committed
854
855
856
857
	/* Monoclinic */
	if ( strcmp(sym, "2/m") == 0 ) return make_2m();
	if ( strcmp(sym, "2") == 0 ) return make_2();
	if ( strcmp(sym, "m") == 0 ) return make_m();
858

Thomas White's avatar
Thomas White committed
859
860
861
862
	/* Orthorhombic */
	if ( strcmp(sym, "mmm") == 0 ) return make_mmm();
	if ( strcmp(sym, "222") == 0 ) return make_222();
	if ( strcmp(sym, "mm2") == 0 ) return make_mm2();
863

Thomas White's avatar
Thomas White committed
864
865
866
	/* Tetragonal */
	if ( strcmp(sym, "4/m") == 0 ) return make_4m();
	if ( strcmp(sym, "4") == 0 ) return make_4();
Thomas White's avatar
Thomas White committed
867
	if ( strcmp(sym, "-4") == 0 ) return make_4bar();
Thomas White's avatar
Thomas White committed
868
869
	if ( strcmp(sym, "4/mmm") == 0 ) return make_4mmm();
	if ( strcmp(sym, "422") == 0 ) return make_422();
Thomas White's avatar
Thomas White committed
870
871
	if ( strcmp(sym, "-42m") == 0 ) return make_4bar2m();
	if ( strcmp(sym, "-4m2") == 0 ) return make_4barm2();
Thomas White's avatar
Thomas White committed
872
	if ( strcmp(sym, "4mm") == 0 ) return make_4mm();
Thomas White's avatar
Thomas White committed
873

Thomas White's avatar
Thomas White committed
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
	/* Trigonal (rhombohedral) */
	if ( strcmp(sym, "3_R") == 0 ) return make_3_R();
	if ( strcmp(sym, "-3_R") == 0 ) return make_3bar_R();
	if ( strcmp(sym, "32_R") == 0 ) return make_32_R();
	if ( strcmp(sym, "3m_R") == 0 ) return make_3m_R();
	if ( strcmp(sym, "-3m_R") == 0 ) return make_3barm_R();

	/* Trigonal (hexagonal) */
	if ( strcmp(sym, "3_H") == 0 ) return make_3_H();
	if ( strcmp(sym, "-3_H") == 0 ) return make_3bar_H();
	if ( strcmp(sym, "321_H") == 0 ) return make_321_H();
	if ( strcmp(sym, "312_H") == 0 ) return make_312_H();
	if ( strcmp(sym, "3m1_H") == 0 ) return make_3m1_H();
	if ( strcmp(sym, "31m_H") == 0 ) return make_31m_H();
	if ( strcmp(sym, "-3m1_H") == 0 ) return make_3barm1_H();
	if ( strcmp(sym, "-31m_H") == 0 ) return make_3bar1m_H();

Thomas White's avatar
Thomas White committed
891
892
893
	/* Hexagonal */
	if ( strcmp(sym, "6/m") == 0 ) return make_6m();
	if ( strcmp(sym, "6") == 0 ) return make_6();
Thomas White's avatar
Thomas White committed
894
	if ( strcmp(sym, "-6") == 0 ) return make_6bar();
Thomas White's avatar
Thomas White committed
895
896
	if ( strcmp(sym, "6/mmm") == 0 ) return make_6mmm();
	if ( strcmp(sym, "622") == 0 ) return make_622();
Thomas White's avatar
Thomas White committed
897
898
	if ( strcmp(sym, "-62m") == 0 ) return make_6bar2m();
	if ( strcmp(sym, "-6m2") == 0 ) return make_6barm2();
Thomas White's avatar
Thomas White committed
899
	if ( strcmp(sym, "6mm") == 0 ) return make_6mm();
Thomas White's avatar
Thomas White committed
900

Thomas White's avatar
Thomas White committed
901
902
903
904
	/* Cubic */
	if ( strcmp(sym, "23") == 0 ) return make_23();
	if ( strcmp(sym, "m-3") == 0 ) return make_m3bar();
	if ( strcmp(sym, "432") == 0 ) return make_432();
905
	if ( strcmp(sym, "-43m") == 0 ) return make_4bar3m();
Thomas White's avatar
Thomas White committed
906
907
	if ( strcmp(sym, "m-3m") == 0 ) return make_m3barm();

Thomas White's avatar
Thomas White committed
908
909
	ERROR("Unknown point group '%s'\n", sym);
	return NULL;
Thomas White's avatar
Thomas White committed
910
}
Thomas White's avatar
Thomas White committed
911

912

913
914
915
916
917
918
919
920
921
922
923
924
925
926
static int char_count(const char *a, char b)
{
	size_t i;
	int n;

	i = 0;  n = 0;
	do {
		if ( a[i] == b ) n++;
		if ( a[i] == '\0' ) return n;
		i++;
	} while ( 1 );
}


Thomas White's avatar
Thomas White committed
927
static SymOpList *getpg_arbitrary_ua(const char *sym, size_t s)
928
929
930
931
{
	char ua;
	char *pg_type;
	SymOpList *pg;
932
	IntegerMatrix *t;
933
934
935
936
937
938
939
940
941
942
943
944
945
946

	if ( strncmp(sym+s, "ua", 2) == 0 ) {
		ua = sym[s+2];
	} else {
		ERROR("Unrecognised point group '%s'\n", sym);
		return NULL;
	}

	pg_type = strndup(sym, s-1);
	if ( pg_type == NULL ) {
		ERROR("Couldn't allocate string.\n");
		return NULL;
	}

Thomas White's avatar
Thomas White committed
947
	pg = getpg_uac(pg_type);
948
949
950
951
952
953
954
	if ( pg == NULL ) {
		ERROR("Unrecognised point group type '%s'\n",
		      pg_type);
		return NULL;
	}
	free(pg_type);

955
956
957
	t = intmat_new(3, 3);
	if ( t == NULL ) return NULL;