diff options
-rw-r--r-- | doc/reference/CrystFEL-sections.txt | 17 | ||||
-rw-r--r-- | src/symmetry.c | 868 | ||||
-rw-r--r-- | src/symmetry.h | 14 |
3 files changed, 274 insertions, 625 deletions
diff --git a/doc/reference/CrystFEL-sections.txt b/doc/reference/CrystFEL-sections.txt index c032fe76..b9135f1b 100644 --- a/doc/reference/CrystFEL-sections.txt +++ b/doc/reference/CrystFEL-sections.txt @@ -195,17 +195,14 @@ indexingprivate <SECTION> <FILE>symmetry</FILE> -check_list_symmetry -check_symmetry -has_bisecting_mirror_or_diad -has_perpendicular_mirror -is_polyhedral -rotational_order -num_equivs -num_general_equivs -get_asymm +SymOpList +<SUBSECTION> +free_symoplist +num_ops +get_pointgroup get_equiv -get_general_equiv +special_position +get_asymm get_twins </SECTION> diff --git a/src/symmetry.c b/src/symmetry.c index 3a9d505e..77ac3ec3 100644 --- a/src/symmetry.c +++ b/src/symmetry.c @@ -23,12 +23,6 @@ #include "utils.h" -#ifdef DEBUG -#define SYM_DEBUG STATUS -#else /* DEBUG */ -#define SYM_DEBUG(...) -#endif /* DEBUG */ - /** * SECTION:symmetry * @short_description: Point symmetry handling @@ -42,11 +36,26 @@ */ -struct sym_op { - signed int h; - signed int k; - signed int l; - int op; +enum lattice_type +{ + L_TRICLINIC, + L_MONOCLINIC, + L_ORTHORHOMBIC, + L_TETRAGONAL, + L_RHOMBOHEDRAL, + L_TRIGONAL, + L_HEXAGONAL, + L_CUBIC, +}; + + +struct sym_op +{ + signed int *h; + signed int *k; + signed int *l; /* Contributions to h, k and l from h, k, i and l */ + enum lattice_type latt; + char op[6]; }; @@ -59,416 +68,341 @@ struct sym_op { * @include: "symmetry.h" * @Image: * - * Wibble + * The SymOpList is an opaque data structure containing a list of point symmetry + * operations. It could represent an point group or a list of indexing + * ambiguities (twin laws), or similar. */ -struct _symoplist { - struct sym_op *items; +struct _symoplist +{ + struct sym_op *ops; int n_ops; int max_ops; }; -static void alloc_items(SymOpList *items) +static void alloc_ops(SymOpList *ops) { - items->items = realloc(items->items, - items->max_ops*sizeof(struct sym_op)); + ops->ops = realloc(ops->ops, ops->max_ops*sizeof(struct sym_op)); } -/** - * new_items: - * - * Creates a new %SymOpList. - * - * Returns: The new list, or NULL. - **/ -SymOpList *new_items() +/* Creates a new SymOpList */ +static SymOpList *new_symoplist() { SymOpList *new; new = malloc(sizeof(SymOpList)); if ( new == NULL ) return NULL; - new->max_ops = 1024; + new->max_ops = 16; new->n_ops = 0; - new->items = NULL; - alloc_items(new); + new->ops = NULL; + alloc_ops(new); return new; } -void delete_items(SymOpList *items) +/** + * free_symoplist: + * + * Frees a %SymOpList and all associated resources. + **/ +void free_symoplist(SymOpList *ops) { - if ( items == NULL ) return; - if ( items->items != NULL ) free(items->items); - free(items); + int i; + + if ( ops == NULL ) return; + for ( i=0; i<ops->n_ops; i++ ) { + free(ops->ops[i].h); + free(ops->ops[i].k); + free(ops->ops[i].l); + } + if ( ops->ops != NULL ) free(ops->ops); + free(ops); } -void add_item_with_op(SymOpList *items, signed int h, signed int k, - signed int l, int op) +/* Add a operation to a SymOpList */ +static void add_symop(SymOpList *ops, + signed int *h, signed int *k, signed int *l) { - if ( items->n_ops == items->max_ops ) { - items->max_ops += 1024; - alloc_items(items); + if ( ops->n_ops == ops->max_ops ) { + /* Pretty sure this never happens, but still... */ + ops->max_ops += 16; + alloc_ops(ops); } - items->items[items->n_ops].h = h; - items->items[items->n_ops].k = k; - items->items[items->n_ops].l = l; - items->items[items->n_ops].op = op; - items->n_ops++; + ops->ops[ops->n_ops].h = h; + ops->ops[ops->n_ops].k = k; + ops->ops[ops->n_ops].l = l; + ops->n_ops++; } -void add_item(SymOpList *items, signed int h, signed int k, signed int l) +int num_ops(const SymOpList *ops) { - add_item_with_op(items, h, k, l, 0); + return ops->n_ops; } -int find_item(SymOpList *items, - signed int h, signed int k, signed int l) +static signed int *v(signed int h, signed int k, signed int i, signed int l) { - int i; + signed int *vec = malloc(4*sizeof(signed int)); + vec[0] = h; vec[1] = k; vec[2] = i; vec[3] = l; + return vec; +} - for ( i=0; i<items->n_ops; i++ ) { - if ( items->items[i].h != h ) continue; - if ( items->items[i].k != k ) continue; - if ( items->items[i].l != l ) continue; - return 1; - } - return 0; + +/********************************* Triclinic **********************************/ + +static SymOpList *make_1bar() +{ + SymOpList *new = new_symoplist(); + add_symop(new, v(1,0,0,0), v(0,1,0,0), v(0,0,0,1)); + add_symop(new, v(-1,0,0,0), v(0,-1,0,0), v(0,0,0,-1)); + return new; } -static int find_op(SymOpList *items, int op) +static SymOpList *make_1() { - int i; + SymOpList *new = new_symoplist(); + add_symop(new, v(1,0,0,0), v(0,1,0,0), v(0,0,0,1)); + return new; +} - for ( i=0; i<items->n_ops; i++ ) { - if ( items->items[i].op == op ) return 1; - } - return 0; + +/********************************* Monoclinic *********************************/ + +static SymOpList *make_2m() +{ + return NULL; } -struct sym_op *get_item(SymOpList *items, int i) +static SymOpList *make_2() { - if ( i >= items->n_ops ) return NULL; - return &items->items[i]; + return NULL; } -int num_items(const SymOpList *items) +static SymOpList *make_m() { - return items->n_ops; + return NULL; } -void union_op_items(SymOpList *items, SymOpList *newi) +/******************************** Orthorhombic ********************************/ + +static SymOpList *make_mmm() { - int n, i; + return NULL; +} - n = num_items(newi); - for ( i=0; i<n; i++ ) { - struct sym_op *r = get_item(newi, i); - if ( find_op(items, r->op) ) continue; +static SymOpList *make_222() +{ + return NULL; +} - add_item_with_op(items, r->h, r->k, r->l, r->op); - } +static SymOpList *make_mm2() +{ + return NULL; } -void union_ops(SymOpList *items, SymOpList *newi) +/********************************* Tetragonal *********************************/ + +static SymOpList *make_4m() { - int n, i; + return NULL; +} - n = num_items(newi); - for ( i=0; i<n; i++ ) { - struct sym_op *r = get_item(newi, i); - if ( find_item(items, r->h, r->k, r->l) ) continue; +static SymOpList *make_4() +{ + return NULL; +} - add_item_with_op(items, r->h, r->k, r->l, r->op); - } +static SymOpList *make_4bar() +{ + return NULL; } -SymOpList *intersection_ops(SymOpList *i1, SymOpList *i2) +static SymOpList *make_4mmm() { - int n, i; - SymOpList *res = new_items(); + return NULL; +} - n = num_items(i1); - for ( i=0; i<n; i++ ) { - struct sym_op *r = get_item(i1, i); - if ( find_item(i2, r->h, r->k, r->l) ) { - add_item_with_op(res, r->h, r->k, r->l, r->op); - } +static SymOpList *make_422() +{ + return NULL; +} - } - return res; +static SymOpList *make_4bar2m() +{ + return NULL; } -/* Check if a reflection is in the asymmetric unit cell */ -static int check_cond(signed int h, signed int k, signed int l, const char *sym) +static SymOpList *make_4mm() { - /* Triclinic */ - if ( strcmp(sym, "1") == 0 ) - return ( 1 ); - if ( strcmp(sym, "-1") == 0 ) - return ( (l>0) - || ( (l==0) && (k>0) ) - || ( (l==0) && (k==0) && (h>=0) ) ); + return NULL; +} - /* Orthorhombic */ - if ( strcmp(sym, "mmm") == 0 ) - return ( (h>=0) && (k>=0) && (l>=0) ); - if ( strcmp(sym, "222") == 0 ) - return ( (h>=0) && (k>0) ) - || ( (h>0) && (k>=0) ) - || ( (h>=0) && (k==0) && (l>=0) ) - || ( (h==0) && (k>=0) && (l>=0) ); - /* Tetragonal */ - if ( strcmp(sym, "4/mmm") == 0 ) - return ( (((h>0) && (k>=0)) || ((h==0) && (k==0))) && (l>=0) - && (h>=k) ); /* Like 6/mmm */ - if ( strcmp(sym, "422") == 0 ) - return ( (((h>0) && (k>=0)) || ((h==0) && (k==0))) - && (h>=k) ); - if ( strcmp(sym, "4/m") == 0 ) - return ( (((h>0) && (k>=0)) || ((h==0) && (k==0))) && (l>=0) ); - if ( strcmp(sym, "4") == 0 ) - return ( ((h>0) && (k>=0)) || ((h==0) && (k==0)) ); +/******************************** Rhombohedral ********************************/ - /* Hexagonal */ - if ( strcmp(sym, "6") == 0 ) - return ( ((h>0) && (k>=0)) || ((h==0) && (k==0)) ); - if ( strcmp(sym, "6/m") == 0 ) - return ( (((h>0) && (k>=0)) || ((h==0) && (k==0))) && (l>=0) ); - if ( strcmp(sym, "6/mmm") == 0 ) - return ( (((h>0) && (k>=0)) || ((h==0) && (k==0))) && (l>=0) - && (h>=k) ); - /* TODO: Add more groups here */ +/********************************** Hexgonal **********************************/ - return 1; +static SymOpList *make_6m() +{ + return NULL; } -/* Macros for checking the above conditions and returning if satisfied */ -#define CHECK_COND(h, k, l, sym) \ - if ( check_cond((h), (k), (l), (sym)) ) { \ - *hp = (h); *kp = (k); *lp = (l); \ - return; \ - } +static SymOpList *make_6() +{ + return NULL; +} -int num_general_equivs(const char *sym) +static SymOpList *make_6bar() { - /* Triclinic */ - if ( strcmp(sym, "1") == 0 ) return 1; - if ( strcmp(sym, "-1") == 0 ) return 2; + return NULL; +} - /* Orthorhombic */ - if ( strcmp(sym, "222") == 0 ) return 4; - if ( strcmp(sym, "mmm") == 0 ) return 8; - /* Tetragonal */ - if ( strcmp(sym, "4") == 0 ) return 4; - if ( strcmp(sym, "4/m") == 0 ) return 8; - if ( strcmp(sym, "422") == 0 ) return 8; - if ( strcmp(sym, "4/mmm") == 0 ) return 16; +static SymOpList *make_6mmm() +{ + return NULL; +} - /* Hexagonal */ - if ( strcmp(sym, "6") == 0 ) return 6; - if ( strcmp(sym, "6/m") == 0 ) return 12; - if ( strcmp(sym, "6/mmm") == 0 ) return 24; - /* TODO: Add more groups here */ +static SymOpList *make_622() +{ + return NULL; +} + - return 1; +static SymOpList *make_6bar2m() +{ + return NULL; } -void get_general_equiv(signed int h, signed int k, signed int l, - signed int *he, signed int *ke, signed int *le, - const char *sym, int idx) +static SymOpList *make_6mm() { - signed int i = -h-k; + return NULL; +} - /* The returned indices when idx=0 *must* be the same as the input. - * After that, the order does not matter. */ - if ( strcmp(sym, "1") == 0 ) { - *he = h; *ke = k; *le = l; return; - } +/************************************ Cubic ***********************************/ - if ( strcmp(sym, "-1") == 0 ) { - switch ( idx ) { - case 0 : *he = h; *ke = k; *le = l; return; - case 1 : *he = -h; *ke = -k; *le = -l; return; - } - } - if ( strcmp(sym, "222") == 0 ) { - switch ( idx ) { - case 0 : *he = h; *ke = k; *le = l; return; - case 1 : *he = -h; *ke = -k; *le = l; return; - case 2 : *he = -h; *ke = k; *le = -l; return; - case 3 : *he = h; *ke = -k; *le = -l; return; - } - } - if ( strcmp(sym, "mmm") == 0 ) { - switch ( idx ) { - case 0 : *he = h; *ke = k; *le = l; return; - case 1 : *he = -h; *ke = -k; *le = l; return; - case 2 : *he = -h; *ke = k; *le = -l; return; - case 3 : *he = h; *ke = -k; *le = -l; return; - case 4 : *he = -h; *ke = -k; *le = -l; return; - case 5 : *he = h; *ke = k; *le = -l; return; - case 6 : *he = h; *ke = -k; *le = l; return; - case 7 : *he = -h; *ke = k; *le = l; return; - } - } +SymOpList *get_pointgroup(const char *sym) +{ + /* Triclinic */ + if ( strcmp(sym, "-1") == 0 ) return make_1bar(); + if ( strcmp(sym, "1") == 0 ) return make_1(); - if ( strcmp(sym, "4") == 0 ) { - switch ( idx ) { - case 0 : *he = h; *ke = k; *le = l; return; - case 1 : *he = -h; *ke = -k; *le = l; return; - case 2 : *he = -k; *ke = h; *le = l; return; - case 3 : *he = k; *ke = -h; *le = l; return; - } - } + /* 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(); - if ( strcmp(sym, "4/m") == 0 ) { - switch ( idx ) { - case 0 : *he = h; *ke = k; *le = l; return; - case 1 : *he = -h; *ke = -k; *le = l; return; - case 2 : *he = -k; *ke = h; *le = l; return; - case 3 : *he = k; *ke = -h; *le = l; return; - case 4 : *he = -h; *ke = -k; *le = -l; return; - case 5 : *he = h; *ke = k; *le = -l; return; - case 6 : *he = k; *ke = -h; *le = -l; return; - case 7 : *he = -k; *ke = h; *le = -l; return; - } - } + /* 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(); - if ( strcmp(sym, "422") == 0 ) { - switch ( idx ) { - case 0 : *he = h; *ke = k; *le = l; return; - case 1 : *he = -h; *ke = -k; *le = l; return; - case 2 : *he = -k; *ke = h; *le = l; return; - case 3 : *he = k; *ke = -h; *le = l; return; - case 4 : *he = -h; *ke = k; *le = -l; return; - case 5 : *he = h; *ke = -k; *le = -l; return; - case 6 : *he = k; *ke = h; *le = -l; return; - case 7 : *he = -k; *ke = -h; *le = -l; return; - } - } + /* Tetragonal */ + if ( strcmp(sym, "4/m") == 0 ) return make_4m(); + if ( strcmp(sym, "4") == 0 ) return make_4(); + if ( strcmp(sym, "4bar") == 0 ) return make_4bar(); + if ( strcmp(sym, "4/mmm") == 0 ) return make_4mmm(); + if ( strcmp(sym, "422") == 0 ) return make_422(); + if ( strcmp(sym, "4bar2m") == 0 ) return make_4bar2m(); + if ( strcmp(sym, "4mm") == 0 ) return make_4mm(); - if ( strcmp(sym, "4/mmm") == 0 ) { - switch ( idx ) { - case 0 : *he = h; *ke = k; *le = l; return; - case 1 : *he = -h; *ke = -k; *le = l; return; - case 2 : *he = -k; *ke = h; *le = l; return; - case 3 : *he = k; *ke = -h; *le = l; return; - case 4 : *he = -h; *ke = k; *le = -l; return; - case 5 : *he = h; *ke = -k; *le = -l; return; - case 6 : *he = k; *ke = h; *le = -l; return; - case 7 : *he = -k; *ke = -h; *le = -l; return; - case 8 : *he = -h; *ke = -k; *le = -l; return; - case 9 : *he = h; *ke = k; *le = -l; return; - case 10 : *he = k; *ke = -h; *le = -l; return; - case 11 : *he = -k; *ke = h; *le = -l; return; - case 12 : *he = h; *ke = -k; *le = l; return; - case 13 : *he = -h; *ke = k; *le = l; return; - case 14 : *he = -k; *ke = -h; *le = l; return; - case 15 : *he = k; *ke = h; *le = l; return; - } - } + /* Hexagonal */ + if ( strcmp(sym, "6/m") == 0 ) return make_6m(); + if ( strcmp(sym, "6") == 0 ) return make_6(); + if ( strcmp(sym, "6bar") == 0 ) return make_6bar(); + if ( strcmp(sym, "6/mmm") == 0 ) return make_6mmm(); + if ( strcmp(sym, "622") == 0 ) return make_622(); + if ( strcmp(sym, "6bar2m") == 0 ) return make_6bar2m(); + if ( strcmp(sym, "6mm") == 0 ) return make_6mm(); +} - if ( strcmp(sym, "6") == 0 ) { - switch ( idx ) { - case 0 : *he = h; *ke = k; *le = l; return; - case 1 : *he = i; *ke = h; *le = l; return; - case 2 : *he = k; *ke = i; *le = l; return; - case 3 : *he = -h; *ke = -k; *le = l; return; - case 4 : *he = -i; *ke = -h; *le = l; return; - case 5 : *he = -k; *ke = -i; *le = l; return; - } - } - if ( strcmp(sym, "6/m") == 0 ) { - switch ( idx ) { - case 0 : *he = h; *ke = k; *le = l; return; - case 1 : *he = i; *ke = h; *le = l; return; - case 2 : *he = k; *ke = i; *le = l; return; - case 3 : *he = -h; *ke = -k; *le = l; return; - case 4 : *he = -i; *ke = -h; *le = l; return; - case 5 : *he = -k; *ke = -i; *le = l; return; - case 6 : *he = h; *ke = k; *le = -l; return; - case 7 : *he = i; *ke = h; *le = -l; return; - case 8 : *he = k; *ke = i; *le = -l; return; - case 9 : *he = -h; *ke = -k; *le = -l; return; - case 10 : *he = -i; *ke = -h; *le = -l; return; - case 11 : *he = -k; *ke = -i; *le = -l; return; - } - } +/** + * num_ops: + * @ops: A %SymOpList + * + * Returns: the number of operations in @ops. + **/ +int num_ops(SymOpList *ops) +{ + return ops->n_ops; +} - if ( strcmp(sym, "6/mmm") == 0 ) { - switch ( idx ) { - case 0 : *he = h; *ke = k; *le = l; return; - case 1 : *he = i; *ke = h; *le = l; return; - case 2 : *he = k; *ke = i; *le = l; return; - case 3 : *he = -h; *ke = -k; *le = l; return; - case 4 : *he = -i; *ke = -h; *le = l; return; - case 5 : *he = -k; *ke = -i; *le = l; return; - case 6 : *he = k; *ke = h; *le = -l; return; - case 7 : *he = h; *ke = i; *le = -l; return; - case 8 : *he = i; *ke = k; *le = -l; return; - case 9 : *he = -k; *ke = -h; *le = -l; return; - case 10 : *he = -h; *ke = -i; *le = -l; return; - case 11 : *he = -i; *ke = -k; *le = -l; return; - case 12 : *he = -h; *ke = -k; *le = -l; return; - case 13 : *he = -i; *ke = -h; *le = -l; return; - case 14 : *he = -k; *ke = -i; *le = -l; return; - case 15 : *he = h; *ke = k; *le = -l; return; - case 16 : *he = i; *ke = h; *le = -l; return; - case 17 : *he = k; *ke = i; *le = -l; return; - case 18 : *he = -k; *ke = -h; *le = l; return; - case 19 : *he = -h; *ke = -i; *le = l; return; - case 20 : *he = -i; *ke = -k; *le = l; return; - case 21 : *he = k; *ke = h; *le = l; return; - case 22 : *he = h; *ke = i; *le = l; return; - case 23 : *he = i; *ke = k; *le = l; return; - } - } - /* TODO: Add more groups here */ +/** + * get_equiv: + * @ops: A %SymOpList + * @idx: Index of the operation to use + * @h: index of reflection + * @k: index of reflection + * @l: index of reflection + * @he: location to store h index of equivalent reflection + * @ke: location to store k index of equivalent reflection + * @le: location to store l index of equivalent reflection + * + * This function applies the @idx-th symmetry operation from @ops to the + * reflection @h, @k, @l, and stores the result at @he, @ke and @le. + * + * If you don't mind that the same equivalent might appear twice, simply call + * this function the number of times returned by num_ops(), using the actual + * point group. If repeating the same equivalent twice (for example, if the + * given reflection is a special high-symmetry one), call special_position() + * first to get a "specialised" SymOpList and use that instead. + **/ +void get_equiv(SymOpList *ops, int idx, + signed int h, signed int k, signed int l, + signed int *he, signed int *ke, signed int *le) +{ + signed int i = -h-k; + struct sym_op op = ops->ops[idx]; - ERROR("Unrecognised symmetry '%s'\n", sym); - abort(); + *he = h*op.h[0] + k*op.h[1] + i*op.h[2] + l*op.h[3]; + *ke = h*op.k[0] + k*op.h[1] + i*op.k[2] + l*op.k[3]; + *le = h*op.l[0] + k*op.h[1] + i*op.l[2] + l*op.l[3]; } -/* Given a reflection and a point group, this returns (by reference) the indices - * of the "idx"th equivalent reflection, taking special positions into account. - * It returns "idx" if successful. Otherwise, it returns the number of - * equivalents for the particular reflection (taking special positions into - * account). Therefore, set idx=-1 to get the number of equivalents. */ -static int special_position(signed int hs, signed int ks, signed int ls, - signed int *hp, signed int *kp, signed int *lp, - const char *sym, signed int idx) +/** + * special_position: + * @ops: A %SymOpList, usually corresponding to a point group + * @h: index of a reflection + * @k: index of a reflection + * @l: index of a reflection + * + * This function determines which operations in @ops map the reflection @h, @k, + * @l onto itself, and returns a new %SymOpList containing only the operations + * from @ops which do not do so. + * + * Returns: the "specialised" %SymOpList. + **/ +SymOpList *special_position(SymOpList *ops, + signed int h, signed int k, signed int l) { int n_general; int i; @@ -481,15 +415,15 @@ static int special_position(signed int hs, signed int ks, signed int ls, return 0; } - equivs = new_items(); - n_general = num_general_equivs(sym); + equivs = new_symoplist(); + n_general = num_general_equivs(ops); for ( i=0; i<n_general; i++ ) { signed int h, k, l; - /* Get equivalent according to the holohedral group */ - get_general_equiv(hs, ks, ls, &h, &k, &l, sym, i); + /* Get equivalent according to the point group */ + get_general_equiv(ops, i, hs, ks, ls, &h, &k, &l); /* Already got this one? */ if ( find_item(equivs, h, k, l) ) continue; @@ -498,7 +432,7 @@ static int special_position(signed int hs, signed int ks, signed int ls, *hp = h; *kp = k; *lp = l; - delete_items(equivs); + delete_ops(equivs); return n_equivs; } add_item(equivs, h, k, l); @@ -506,329 +440,47 @@ static int special_position(signed int hs, signed int ks, signed int ls, } - delete_items(equivs); + delete_ops(equivs); return n_equivs; } -void get_equiv(signed int h, signed int k, signed int l, - signed int *he, signed int *ke, signed int *le, - const char *sym, int idx) -{ - special_position(h, k, l, he, ke, le, sym, idx); -} - - -int num_equivs(signed int h, signed int k, signed int l, const char *sym) -{ - return special_position(h, k, l, NULL, NULL, NULL, sym, -1); -} - - -void get_asymm(signed int h, signed int k, signed int l, - signed int *hp, signed int *kp, signed int *lp, - const char *sym) +void get_asymm(SymOpList *ops, int idx, + signed int h, signed int k, signed int l, + signed int *hp, signed int *kp, signed int *lp) { int nequiv = num_equivs(h, k, l, sym); int p; - SYM_DEBUG("------ %i %i %i\n", h, k, l); for ( p=0; p<nequiv; p++ ) { signed int he, ke, le; get_equiv(h, k, l, &he, &ke, &le, sym, p); - SYM_DEBUG("%i : %i %i %i\n", p, he, ke, le); CHECK_COND(he, ke, le, sym); } - - /* Should never reach here */ - ERROR("No match found in %s for %i %i %i\n", sym, h, k, l); - abort(); } -/* This is kind of like a "numerical" left coset decomposition. - * Given a reflection index and a point group, it returns the list of twinning - * possibilities. +/** + * get_twins: * - * To count the number of possibilities, use num_items() on the result. + * Calculate twinning laws. + * + * To count the number of possibilities, use num_ops() on the result. */ -static SymOpList *coset_decomp(signed int hs, signed int ks, signed int ls, - const char *holo, const char *mero) +SymOpList *get_twins(SymOpList *source, SymOpList *target) { - int n_mero, n_holo; + int n_src, n_tgt; int i; signed int h, k, l; - SymOpList *twins = new_items(); - - /* Start by putting the given reflection into the asymmetric cell - * for its (probably merohedral) point group. */ - get_asymm(hs, ks, ls, &h, &k, &l, mero); - - /* How many equivalents in the holohedral point group are not - * equivalents according to the (possibly) merohedral group? */ - n_holo = num_general_equivs(holo); - n_mero = num_general_equivs(mero); - - for ( i=0; i<n_holo; i++ ) { + SymOpList *twins = new_symoplist(); - signed int h_holo, k_holo, l_holo; - signed int hs_holo, ks_holo, ls_holo; + n_src = num_ops(source); + n_tgt = num_ops(target); - /* Get equivalent according to the holohedral group */ - get_general_equiv(h, k, l, &hs_holo, &ks_holo, &ls_holo, - holo, i); + for ( i=0; i<n_src; i++ ) { - /* Put it into the asymmetric cell for the merohedral group */ - get_asymm(hs_holo, ks_holo, ls_holo, - &h_holo, &k_holo, &l_holo, mero); - - /* Already got this one? - * Note: The list "twins" starts empty, so the first iteration - * (i=0) will add the original reflection to the list along with - * the identity operation. */ - if ( find_item(twins, h_holo, k_holo, l_holo) ) continue; - - add_item_with_op(twins, h_holo, k_holo, l_holo, i); } return twins; } - - -/* Work out the twinning possibilities for this pattern. - * To use the result, call get_general_equiv() on each reflection using - * the holohedral point group (use get_holohedral() for this), and for "idx" - * give each "op" field from the list returned by this function. */ -SymOpList *get_twins(const char *holo, const char *mero) -{ - int i; - SymOpList *ops = new_items(); - int expected, actual; - SymOpList *items; - - /* Run the coset decomposition for every reflection in the "pattern", - * and see which gives the highest number of possibilities. This - * approach takes into account that a pattern consisting entirely of - * special reflections might have fewer twin possibilities. */ - for ( i=0; i<num_items(items); i++ ) { - - signed int h, k, l; - struct sym_op *item; - SymOpList *new_ops; - - item = get_item(items, i); - - h = item->h; - k = item->k; - l = item->l; - - new_ops = coset_decomp(h, k, l, holo, mero); - union_op_items(ops, new_ops); - delete_items(new_ops); - - } - - /* Idiot check */ - actual = num_items(ops); - expected = num_general_equivs(holo) / num_general_equivs(mero); - if ( actual != expected ) { - ERROR("Found %i twin possibilities, but expected %i.\n", - actual, expected); - ERROR("I couldn't find the number of twin laws that I expected." - " This is an internal error, and shouldn't happen. " - "Sorry.\n"); - abort(); - } - - return ops; -} - - -int find_unique_equiv(SymOpList *items, signed int h, signed int k, - signed int l, const char *mero, signed int *hu, - signed int *ku, signed int *lu) -{ - int i; - int found = 0; - - for ( i=0; i<num_equivs(h, k, l, mero); i++ ) { - - signed int he, ke, le; - int f; - get_equiv(h, k, l, &he, &ke, &le, mero, i); - f = find_item(items, he, ke, le); - - /* There must only be one equivalent. If there are more, it - * indicates that the user lied about the input symmetry. - * This situation should have been checked for earlier by - * calling check_symmetry() with 'items' and 'mero'. */ - - if ( f && !found ) { - *hu = he; *ku = ke; *lu = le; - return 1; - } - - } - - return 0; -} - - -/* Returns true if the point group is 23, m-3, 432, -43m or m-3m - * (i.e. T, Th, O, Td or Oh) */ -int is_polyhedral(const char *sym) -{ - /* Triclinic */ - if ( strcmp(sym, "1") == 0 ) return 0; - if ( strcmp(sym, "-1") == 0 ) return 0; - - /* Orthorhombic */ - if ( strcmp(sym, "222") == 0 ) return 0; - if ( strcmp(sym, "mmm") == 0 ) return 0; - - /* Tetragonal */ - if ( strcmp(sym, "4") == 0 ) return 0; - if ( strcmp(sym, "4/m") == 0 ) return 0; - if ( strcmp(sym, "422") == 0 ) return 0; - if ( strcmp(sym, "4/mmm") == 0 ) return 0; - - /* Hexagonal */ - if ( strcmp(sym, "6") == 0 ) return 0; - if ( strcmp(sym, "6/m") == 0 ) return 0; - if ( strcmp(sym, "6/mmm") == 0 ) return 0; - - /* TODO: Add more groups here */ - - ERROR("Don't know if '%s' is polyhedral or not.\n", sym); - abort(); -} - - -/* Returns the order of the characteristic axis of proper or improper rotation - * for the point group. This should be the rotation about the c axis. */ -int rotational_order(const char *sym) -{ - /* Triclinic */ - if ( strcmp(sym, "1") == 0 ) return 1; - if ( strcmp(sym, "-1") == 0 ) return 2; - - /* Orthorhombic */ - if ( strcmp(sym, "222") == 0 ) return 2; - if ( strcmp(sym, "mmm") == 0 ) return 2; - - /* Tetragonal */ - if ( strcmp(sym, "4") == 0 ) return 4; - if ( strcmp(sym, "4/m") == 0 ) return 4; - if ( strcmp(sym, "422") == 0 ) return 4; - if ( strcmp(sym, "4/mmm") == 0 ) return 4; - - /* Hexagonal */ - if ( strcmp(sym, "6") == 0 ) return 6; - if ( strcmp(sym, "6/m") == 0 ) return 6; - if ( strcmp(sym, "6/mmm") == 0 ) return 6; - - /* TODO: Add more groups here */ - - ERROR("Couldn't find rotational order for '%s'.\n", sym); - abort(); -} - - -int has_perpendicular_mirror(const char *sym) -{ - /* Triclinic */ - if ( strcmp(sym, "1") == 0 ) return 0; - if ( strcmp(sym, "-1") == 0 ) return 0; - - /* Orthorhombic */ - if ( strcmp(sym, "222") == 0 ) return 0; - if ( strcmp(sym, "mmm") == 0 ) return 1; - - /* Tetragonal */ - if ( strcmp(sym, "4") == 0 ) return 0; - if ( strcmp(sym, "4/m") == 0 ) return 1; - if ( strcmp(sym, "422") == 0 ) return 0; - if ( strcmp(sym, "4/mmm") == 0 ) return 1; - - /* Hexagonal */ - if ( strcmp(sym, "6") == 0 ) return 0; - if ( strcmp(sym, "6/m") == 0 ) return 1; - if ( strcmp(sym, "6/mmm") == 0 ) return 1; - - /* TODO: Add more groups here */ - - ERROR("Couldn't find mirror definition for '%s'.\n", sym); - abort(); -} - - -int has_bisecting_mirror_or_diad(const char *sym) -{ - /* Triclinic */ - if ( strcmp(sym, "1") == 0 ) return 0; - if ( strcmp(sym, "-1") == 0 ) return 0; - - /* Orthorhombic */ - if ( strcmp(sym, "222") == 0 ) return 1; - if ( strcmp(sym, "mmm") == 0 ) return 1; - - /* Tetragonal */ - if ( strcmp(sym, "4") == 0 ) return 0; - if ( strcmp(sym, "4/m") == 0 ) return 0; - if ( strcmp(sym, "422") == 0 ) return 0; - if ( strcmp(sym, "4/mmm") == 0 ) return 1; - - /* Hexagonal */ - if ( strcmp(sym, "6") == 0 ) return 0; - if ( strcmp(sym, "6/m") == 0 ) return 1; - if ( strcmp(sym, "6/mmm") == 0 ) return 1; - - /* TODO: Add more groups here */ - - ERROR("Couldn't find mirror definition for '%s'.\n", sym); - abort(); -} - - -int check_symmetry(SymOpList *items, const char *sym) -{ - int i; - unsigned char *flags; - - flags = new_list_flag(); - for ( i=0; i<num_items(items); i++ ) { - struct sym_op *it = get_item(items, i); - set_flag(flags, it->h, it->k, it->l, 1); - } - - for ( i=0; i<num_items(items); i++ ) { - - int j; - struct sym_op *it = get_item(items, i); - int found = 0; - - for ( j=0; j<num_equivs(it->h, it->k, it->l, sym); j++ ) { - - signed int he, ke, le; - get_equiv(it->h, it->k, it->l, &he, &ke, &le, sym, j); - - if ( abs(he) > INDMAX ) continue; - if ( abs(le) > INDMAX ) continue; - if ( abs(ke) > INDMAX ) continue; - - found += lookup_flag(flags, he, ke, le); - - } - - if ( found > 1 ) { - free(flags); - return 1; /* Symmetry is wrong! */ - } - - } - - free(flags); - - return 0; -} diff --git a/src/symmetry.h b/src/symmetry.h index fbb80d26..23c00160 100644 --- a/src/symmetry.h +++ b/src/symmetry.h @@ -24,6 +24,12 @@ **/ typedef struct _symoplist SymOpList; +extern void free_symoplist(SymOpList *ops); + +extern SymOpList *get_pointgroup(const char *sym); + +extern SymOpList *special_position(SymOpList *ops, + signed int h, signed int k, signed int l); extern void get_asymm(signed int h, signed int k, signed int l, signed int *hp, signed int *kp, signed int *lp, @@ -42,12 +48,6 @@ extern void get_general_equiv(signed int h, signed int k, signed int l, signed int *he, signed int *ke, signed int *le, const char *sym, int idx); -extern SymOpList *get_twins(const char *holo, const char *mero); - -/* Properties of point groups */ -extern int is_polyhedral(const char *sym); -extern int rotational_order(const char *sym); -extern int has_perpendicular_mirror(const char *sym); -extern int has_bisecting_mirror_or_diad(const char *sym); +extern SymOpList *get_twins(SymOpList *source, SymOpList *target); #endif /* SYMMETRY_H */ |