aboutsummaryrefslogtreecommitdiff
path: root/src/symmetry.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/symmetry.c')
-rw-r--r--src/symmetry.c464
1 files changed, 464 insertions, 0 deletions
diff --git a/src/symmetry.c b/src/symmetry.c
new file mode 100644
index 0000000..65aef98
--- /dev/null
+++ b/src/symmetry.c
@@ -0,0 +1,464 @@
+/*
+ * symmetry.c
+ *
+ * Symmetry stuff
+ *
+ * (c) 2006-2008 Thomas White <taw27@cam.ac.uk>
+ *
+ * synth2d - Two-Dimensional Crystallographic Fourier Synthesis
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+
+#include "symmetry.h"
+#include "reflist.h"
+#include "model.h"
+
+#define is_odd(a) ((a)%2==1)
+
+/* Return a list of atoms containing the given atom and all its symmetry equivalents */
+AtomicModel *symmetry_generate_equivalent_atoms(AtomicModel *model, size_t j, ModelTarget target) {
+
+ AtomicModel *list;
+
+ list = model_new();
+ list->atoms[list->n_atoms] = model->atoms[j]; list->n_atoms++;
+
+ if ( target == MODEL_TARGET_DISPLAY ) {
+
+ if ( model->atoms[j].x == 0 ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = 1.0;
+ list->n_atoms++;
+ }
+
+ if ( model->atoms[j].y == 0 ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].y = 1.0;
+ list->n_atoms++;
+ }
+
+ if ( (model->atoms[j].x == 0) && (model->atoms[j].y == 0) ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = 1.0;
+ list->atoms[list->n_atoms].y = 1.0;
+ list->n_atoms++;
+ }
+
+ }
+
+ if ( model->sym & SYMMETRY_CENTRE ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = 1-list->atoms[list->n_atoms].x;
+ list->atoms[list->n_atoms].y = 1-list->atoms[list->n_atoms].y;
+ list->n_atoms++;
+ }
+
+ if ( model->sym & SYMMETRY_MIRROR_HORIZONTAL ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].y = 1-list->atoms[list->n_atoms].y;
+ list->n_atoms++;
+ }
+
+ if ( model->sym & SYMMETRY_MIRROR_VERTICAL ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = 1-list->atoms[list->n_atoms].x;
+ list->n_atoms++;
+ }
+
+ if ( model->sym & SYMMETRY_GLIDE_HORIZONTAL ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = fmod(0.5 + list->atoms[list->n_atoms].x, 1);
+ list->atoms[list->n_atoms].y = 1-list->atoms[list->n_atoms].y;
+ list->n_atoms++;
+ }
+
+ if ( model->sym & SYMMETRY_GLIDE_VERTICAL ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = 1-list->atoms[list->n_atoms].x;
+ list->atoms[list->n_atoms].y = fmod(0.5 + list->atoms[list->n_atoms].y, 1);
+ list->n_atoms++;
+ }
+
+ if ( model->sym & SYMMETRY_GLIDE_HORIZONTAL_QUARTER ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = fmod(0.5 + list->atoms[list->n_atoms].x, 1);
+ list->atoms[list->n_atoms].y = fmod(1.5 - list->atoms[list->n_atoms].y, 1);
+ list->n_atoms++;
+ }
+
+ if ( model->sym & SYMMETRY_GLIDE_VERTICAL_QUARTER ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = fmod(1.5 - list->atoms[list->n_atoms].x, 1);
+ list->atoms[list->n_atoms].y = fmod(0.5 + list->atoms[list->n_atoms].y, 1);
+ list->n_atoms++;
+ }
+
+ /* Fix cm */
+ if ( (model->sym & SYMMETRY_GLIDE_HORIZONTAL_QUARTER) && (model->sym & SYMMETRY_MIRROR_HORIZONTAL) ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = fmod(0.5 + list->atoms[list->n_atoms].x, 1);
+ list->atoms[list->n_atoms].y = 1 - fmod(1.5 - list->atoms[list->n_atoms].y, 1);
+ list->n_atoms++;
+ } else if ( (model->sym & SYMMETRY_GLIDE_VERTICAL_QUARTER) && (model->sym & SYMMETRY_MIRROR_VERTICAL) ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = 1 - fmod(1.5 - list->atoms[list->n_atoms].x, 1);
+ list->atoms[list->n_atoms].y = fmod(0.5 + list->atoms[list->n_atoms].y, 1);
+ list->n_atoms++;
+ }
+
+ /* Fix c2mm */
+ if ( (model->sym & SYMMETRY_GLIDE_VERTICAL_QUARTER) && (model->sym & SYMMETRY_MIRROR_HORIZONTAL) ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = fmod(1.5 - list->atoms[list->n_atoms].x, 1);
+ list->atoms[list->n_atoms].y = 1 - fmod(0.5 + list->atoms[list->n_atoms].y, 1);
+ list->n_atoms++;
+ }
+
+ if ( model->sym & SYMMETRY_MIRROR_HORIZONTAL_QUARTER ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = list->atoms[list->n_atoms].x;
+ list->atoms[list->n_atoms].y = fmod(1.5 - list->atoms[list->n_atoms].y, 1);
+ list->n_atoms++;
+ }
+
+ if ( model->sym & SYMMETRY_MIRROR_VERTICAL_QUARTER ) {
+ list->atoms[list->n_atoms] = model->atoms[j];
+ list->atoms[list->n_atoms].x = fmod(1.5 - list->atoms[list->n_atoms].x, 1);
+ list->atoms[list->n_atoms].y = list->atoms[list->n_atoms].y;
+ list->n_atoms++;
+ }
+
+ return list;
+
+}
+
+ReflectionList *symmetry_generate_equivalent_reflections(Symmetry sym, signed int h, signed int k, signed int l) {
+
+ ReflectionList *result;
+
+ result = reflist_new();
+
+ /* Remove the minus in front of 'l' to make even HOLZ conditional transforms real.
+ * This is generally the wrong thing to do. */
+ if ( sym & SYMMETRY_FRIEDEL ) reflist_addref_deltatheta(result, -h, -k, -l, 0, -1);
+
+ if ( sym & SYMMETRY_MIRROR_HORIZONTAL ) reflist_addref_deltatheta(result, h, -k, l, 0, 1);
+ if ( sym & SYMMETRY_MIRROR_VERTICAL ) reflist_addref_deltatheta(result, -h, k, l, 0, 1);
+ if ( sym & SYMMETRY_MIRROR_DIAGONAL ) reflist_addref_deltatheta(result, -h, -k, l, 0, 1);
+
+ if ( sym & SYMMETRY_GLIDE_HORIZONTAL ) reflist_addref_deltatheta(result, h, -k, l, M_PI, 1);
+ if ( sym & SYMMETRY_GLIDE_VERTICAL ) reflist_addref_deltatheta(result, -h, k, l, M_PI, 1);
+
+ if ( sym & SYMMETRY_GLIDE_HORIZONTAL_QUARTER ) {
+ if ( is_odd(abs(h)+abs(k)) ) {
+ reflist_addref_deltatheta(result, h, -k, l, M_PI, 1);
+ } else {
+ reflist_addref_deltatheta(result, h, -k, l, 0, 1);
+ }
+ }
+
+ if ( sym & SYMMETRY_GLIDE_VERTICAL_QUARTER ) {
+ if ( is_odd(abs(h)+abs(k)) ) {
+ reflist_addref_deltatheta(result, -h, k, l, M_PI, 1);
+ } else {
+ reflist_addref_deltatheta(result, -h, k, l, 0, 1);
+ }
+ }
+
+ if ( sym & SYMMETRY_ROTATION_4 ) {
+ if ( sym & SYMMETRY_GLIDE_DIAGONAL ) {
+ if ( is_odd(abs(h)+abs(k)) ) {
+ reflist_addref_deltatheta(result, h, -k, l, M_PI, 1);
+ reflist_addref_deltatheta(result, -h, k, l, M_PI, 1);
+ reflist_addref_deltatheta(result, -h, -k, l, 0, 1);
+ reflist_addref_deltatheta(result, k, h, l, 0, 1);
+ reflist_addref_deltatheta(result, -k, h, l, M_PI, 1);
+ reflist_addref_deltatheta(result, k, -h, l, M_PI, 1);
+ reflist_addref_deltatheta(result, -k, -h, l, 0, 1);
+ } else {
+ reflist_addref_deltatheta(result, h, -k, l, 0, 1);
+ reflist_addref_deltatheta(result, -h, k, l, 0, 1);
+ reflist_addref_deltatheta(result, -h, -k, l, 0, 1);
+ reflist_addref_deltatheta(result, k, h, l, 0, 1);
+ reflist_addref_deltatheta(result, -k, h, l, 0, 1);
+ reflist_addref_deltatheta(result, k, -h, l, 0, 1);
+ reflist_addref_deltatheta(result, -k, -h, l, 0, 1);
+ }
+ } else {
+ reflist_addref_deltatheta(result, -h, -k, l, 0, 1);
+ reflist_addref_deltatheta(result, -h, k, l, 0, 1);
+ reflist_addref_deltatheta(result, h, -k, l, 0, 1);
+ }
+ }
+
+ return result;
+
+}
+
+static double symmetry_realphase(double phk) {
+
+ if ( (phk >= 0) && (phk < M_PI_2) ) phk = 0;
+ else if ( (phk > M_PI_2) && (phk < M_PI) ) phk = M_PI;
+ else if ( (phk < 0) && (phk > -M_PI/2) ) phk = 0;
+ else if ( (phk <= -M_PI_2) && (phk > -M_PI) ) phk = M_PI;
+
+ return phk;
+
+}
+
+void symmetry_centricity(ReflectionList *reflections, unsigned int i, Symmetry sym, SymFlags flags) {
+
+ double am, ph;
+ signed int h, k;
+
+ ph = 0;
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+
+ am = reflections->refs[i].amplitude;
+ if ( flags & SYMFLAG_PHASES_KNOWN ) ph = fmod(reflections->refs[i].phase_known, 2*M_PI);
+ if ( flags & SYMFLAG_PHASES_CALC ) ph = fmod(reflections->refs[i].phase_calc, 2*M_PI);
+
+ if ( (sym & SYMMETRY_MIRROR_HORIZONTAL) && (sym & SYMMETRY_FRIEDEL) && (h == 0) ) {
+ ph = symmetry_realphase(ph);
+ }
+
+ if ( (sym & SYMMETRY_MIRROR_VERTICAL) && (sym & SYMMETRY_FRIEDEL) && (k == 0) ) {
+ ph = symmetry_realphase(ph);
+ }
+
+ if ( (sym & SYMMETRY_CENTRE) && (sym & SYMMETRY_FRIEDEL) ) {
+ ph = symmetry_realphase(ph);
+ }
+
+ if (( ( (sym & SYMMETRY_GLIDE_HORIZONTAL) && (sym & SYMMETRY_MIRROR_VERTICAL) )
+ || ( (sym & SYMMETRY_GLIDE_HORIZONTAL_QUARTER) && (sym & SYMMETRY_MIRROR_VERTICAL) )
+ || ( (sym & SYMMETRY_GLIDE_VERTICAL) && (sym & SYMMETRY_MIRROR_HORIZONTAL) )
+ || ( (sym & SYMMETRY_GLIDE_VERTICAL_QUARTER) && (sym & SYMMETRY_MIRROR_HORIZONTAL) ) )
+ && (is_odd(abs(h)+abs(k))) ) {
+ if ( (ph >= 0) && (ph < M_PI) ) ph = M_PI_2;
+ else if ( (ph >= M_PI_2) && (ph < 2*M_PI) ) ph = -M_PI_2;
+ else if ( (ph < 0) && (ph > -M_PI) ) ph = -M_PI_2;
+ else if ( (ph <= -M_PI) ) ph = M_PI_2;
+ }
+
+ if ( flags & SYMFLAG_PHASES_KNOWN ) reflections->refs[i].phase_known = ph;
+ if ( flags & SYMFLAG_PHASES_CALC ) reflections->refs[i].phase_calc = ph;
+
+}
+
+unsigned int symmetry_reflection_allowed(signed int h, signed int k, signed int l, Symmetry sym) {
+
+ if ( (sym & SYMMETRY_GLIDE_HORIZONTAL) && (h == 0) && (k % 2) ) return 0;
+ if ( (sym & SYMMETRY_GLIDE_HORIZONTAL_QUARTER) && (h == 0) && (k % 2) ) return 0;
+ if ( (sym & SYMMETRY_GLIDE_VERTICAL) && (k == 0) && (h % 2) ) return 0;
+ if ( (sym & SYMMETRY_GLIDE_VERTICAL_QUARTER) && (k == 0) && (h % 2) ) return 0;
+ if ( (sym & SYMMETRY_ROTATION_4 ) && ( sym & SYMMETRY_GLIDE_DIAGONAL ) && (k == 0) && (h % 2) ) return 0;
+ if ( (sym & SYMMETRY_ROTATION_4 ) && ( sym & SYMMETRY_GLIDE_DIAGONAL ) && (h == 0) && (k % 2) ) return 0;
+
+ return 1;
+
+}
+
+/* Symmetrise a list of reflections (expanding all equivalents to P1) */
+double symmetry_symmetrise(ReflectionList *reflections, Symmetry sym, SymFlags flags) {
+
+ unsigned int i = 0;
+ double r_sym = 0;
+ double r_sym_norm = 0;
+ unsigned int new_ref = 0;
+ unsigned int elim_ref = 0;
+ double am_elim = 0;
+ unsigned int n = reflections->n_reflections;
+
+ for ( i=1; i<n; i++ ) { /* Don't symmetrise 000 */
+
+ signed int h, k, l;
+
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+ l = reflections->refs[i].l;
+
+ if ( (h==0) && (k==0) && (l==0) ) continue;
+ if ( symmetry_reflection_allowed(h, k, l, sym) ) {
+
+ double ph = 69;
+ unsigned int j;
+ double av;
+ unsigned int av_n;
+ ReflectionList *equivalents;
+
+ equivalents = symmetry_generate_equivalent_reflections(sym, h, k, l);
+ symmetry_centricity(reflections, i, sym, flags);
+
+ /* First pass: calculate average amplitude, determine phase */
+ av = reflections->refs[i].amplitude; av_n = 1;
+ for ( j=1; j<equivalents->n_reflections; j++ ) {
+ unsigned int p;
+ p = reflist_inlist(reflections, equivalents->refs[j].h, equivalents->refs[j].k, equivalents->refs[j].l);
+ if ( p ) {
+ av += reflections->refs[p].amplitude;
+ av_n++;
+ }
+ }
+ av = av / av_n;
+ r_sym += fabs(av - reflections->refs[i].amplitude);
+ r_sym_norm += reflections->refs[i].amplitude;
+ if ( flags & SYMFLAG_PHASES_KNOWN ) ph = fmod(reflections->refs[i].phase_known, 2*M_PI);
+ if ( flags & SYMFLAG_PHASES_CALC ) ph = fmod(reflections->refs[i].phase_calc, 2*M_PI);
+ //printf("Phase of %3i %3i %3i is %f\n", h, k, l, ph);
+
+ /* Second pass: set all equivalent reflections to the average amplitude */
+ reflections->refs[i].amplitude = av;
+ for ( j=1; j<equivalents->n_reflections; j++ ) {
+
+ unsigned int p;
+ double phn;
+ p = reflist_inlist(reflections, equivalents->refs[j].h, equivalents->refs[j].k, equivalents->refs[j].l);
+ if ( p ) {
+ r_sym += fabs(av - reflections->refs[p].amplitude);
+ r_sym_norm += reflections->refs[p].amplitude;
+ reflections->refs[p].amplitude = av;
+ } else {
+ p = reflist_addref_am(reflections, equivalents->refs[j].h, equivalents->refs[j].k, equivalents->refs[j].l, av);
+ //printf("SY: Generating %3i %3i %3i am=%f\n", equivalents->refs[j].h,
+ // equivalents->refs[j].k, equivalents->refs[j].l, av);
+ new_ref++;
+ }
+ phn = (ph + equivalents->refs[j].delta_theta) * equivalents->refs[j].multiplier;
+ if ( flags & SYMFLAG_PHASES_KNOWN ) {
+ reflections->refs[p].phase_known = phn;
+ reflections->refs[p].phase_known_set = 1;
+ }
+ if ( flags & SYMFLAG_PHASES_CALC ) {
+ reflections->refs[p].phase_calc = phn;
+ reflections->refs[p].phase_calc_set = 1;
+ }
+ //printf("Set phase of %3i %3i %3i to %f (dt=%f, mul=%i)\n", equivalents->refs[j].h,
+ //equivalents->refs[j].k, equivalents->refs[j].l,
+ //phn, equivalents->refs[j].delta_theta, equivalents->refs[j].multiplier);
+
+
+ }
+
+ reflist_free(equivalents);
+
+ } else {
+
+ am_elim += reflections->refs[i].amplitude;
+ reflist_delref(reflections, h, k, l);
+ //printf("SY: Eliminating systematically absent reflection %i %i %i\n", h, k, l);
+ elim_ref++;
+ i--;
+
+ }
+
+ }
+
+ if ( r_sym > 0 ) {
+ r_sym = r_sym / r_sym_norm;
+ }
+ //printf("SY: R_sym = %.2f%%, %i reflections generated, %i reflections eliminated (total amplitude %f)\n", r_sym*100, new_ref, elim_ref, am_elim);
+
+ return r_sym;
+
+}
+
+Symmetry symmetry_encode(const char *symmetry) {
+
+ if ( strcmp(symmetry, "p1") == 0 ) return PLANEGROUP_P1;
+ if ( strcmp(symmetry, "p2") == 0 ) return PLANEGROUP_P2;
+ if ( strcmp(symmetry, "pm (m // x)") == 0 ) return PLANEGROUP_PM_X;
+ if ( strcmp(symmetry, "pm (m // y)") == 0 ) return PLANEGROUP_PM_Y;
+ if ( strcmp(symmetry, "pg (g // x)") == 0 ) return PLANEGROUP_PG_X;
+ if ( strcmp(symmetry, "pg (g // y)") == 0 ) return PLANEGROUP_PG_Y;
+ if ( strcmp(symmetry, "cm (m // x)") == 0 ) return PLANEGROUP_CM_X;
+ if ( strcmp(symmetry, "cm (m // y)") == 0 ) return PLANEGROUP_CM_Y;
+ if ( strcmp(symmetry, "p2mm") == 0 ) return PLANEGROUP_P2MM;
+ if ( strcmp(symmetry, "p2mg (m // x)") == 0 ) return PLANEGROUP_P2MG_X;
+ if ( strcmp(symmetry, "p2mg (m // y)") == 0 ) return PLANEGROUP_P2MG_Y;
+ if ( strcmp(symmetry, "p2gg") == 0 ) return PLANEGROUP_P2GG;
+ if ( strcmp(symmetry, "c2mm") == 0 ) return PLANEGROUP_C2MM;
+ if ( strcmp(symmetry, "p4") == 0 ) return PLANEGROUP_P4;
+ if ( strcmp(symmetry, "p4mm") == 0 ) return PLANEGROUP_P4MM;
+ if ( strcmp(symmetry, "p4gm") == 0 ) return PLANEGROUP_P4GM;
+ if ( strcmp(symmetry, "p3") == 0 ) return PLANEGROUP_P3;
+ if ( strcmp(symmetry, "p3m1") == 0 ) return PLANEGROUP_P3M1;
+ if ( strcmp(symmetry, "p31m") == 0 ) return PLANEGROUP_P31M;
+ if ( strcmp(symmetry, "p6") == 0 ) return PLANEGROUP_P6;
+ if ( strcmp(symmetry, "p6mm") == 0 ) return PLANEGROUP_P6MM;
+
+ fprintf(stderr, "Unrecognised symmetry identifier '%s'\n", symmetry);
+ return SYMMETRY_IDENTITY;
+
+}
+
+const char *symmetry_decode(Symmetry sym) {
+
+ if ( sym == PLANEGROUP_P1 ) return "p1";
+ if ( sym == PLANEGROUP_P2 ) return "p2";
+ if ( sym == PLANEGROUP_PM_X ) return "pm (m // x)";
+ if ( sym == PLANEGROUP_PM_Y ) return "pm (m // y)";
+ if ( sym == PLANEGROUP_PG_X ) return "pg (g // x)";
+ if ( sym == PLANEGROUP_PG_Y ) return "pg (g // y)";
+ if ( sym == PLANEGROUP_CM_X ) return "cm (m // x)";
+ if ( sym == PLANEGROUP_CM_Y ) return "cm (m // y)";
+ if ( sym == PLANEGROUP_P2MM ) return "p2mm";
+ if ( sym == PLANEGROUP_P2MG_X ) return "p2mg (m // x)";
+ if ( sym == PLANEGROUP_P2MG_Y ) return "p2mg (m // y)";
+ if ( sym == PLANEGROUP_P2GG ) return "p2gg";
+ if ( sym == PLANEGROUP_C2MM ) return "c2mm";
+ if ( sym == PLANEGROUP_P4 ) return "p4";
+ if ( sym == PLANEGROUP_P4MM ) return "p4mm";
+ if ( sym == PLANEGROUP_P4GM ) return "p4gm";
+ if ( sym == PLANEGROUP_P3 ) return "p3";
+ if ( sym == PLANEGROUP_P3M1 ) return "p3m1";
+ if ( sym == PLANEGROUP_P31M ) return "p31m";
+ if ( sym == PLANEGROUP_P6 ) return "p6";
+ if ( sym == PLANEGROUP_P6MM ) return "p6mm";
+ if ( sym == (PLANEGROUP_P1 | SYMMETRY_FRIEDEL) ) return "p1 & Friedel";
+ if ( sym == (PLANEGROUP_P2 | SYMMETRY_FRIEDEL) ) return "p2 & Friedel";
+ if ( sym == (PLANEGROUP_PM_X | SYMMETRY_FRIEDEL) ) return "pm (m // x) & Friedel";
+ if ( sym == (PLANEGROUP_PM_Y | SYMMETRY_FRIEDEL) ) return "pm (m // y) & Friedel";
+ if ( sym == (PLANEGROUP_PG_X | SYMMETRY_FRIEDEL) ) return "pg (g // x) & Friedel";
+ if ( sym == (PLANEGROUP_PG_Y | SYMMETRY_FRIEDEL) ) return "pg (g // y) & Friedel";
+ if ( sym == (PLANEGROUP_CM_X | SYMMETRY_FRIEDEL) ) return "cm (m // x) & Friedel";
+ if ( sym == (PLANEGROUP_CM_Y | SYMMETRY_FRIEDEL) ) return "cm (m // y) & Friedel";
+ if ( sym == (PLANEGROUP_P2MM | SYMMETRY_FRIEDEL) ) return "p2mm & Friedel";
+ if ( sym == (PLANEGROUP_P2MG_X | SYMMETRY_FRIEDEL) ) return "p2mg (m // x) & Friedel";
+ if ( sym == (PLANEGROUP_P2MG_Y | SYMMETRY_FRIEDEL) ) return "p2mg (m // y) & Friedel";
+ if ( sym == (PLANEGROUP_P2GG | SYMMETRY_FRIEDEL) ) return "p2gg & Friedel";
+ if ( sym == (PLANEGROUP_C2MM | SYMMETRY_FRIEDEL) ) return "c2mm & Friedel";
+ if ( sym == (PLANEGROUP_P4 | SYMMETRY_FRIEDEL) ) return "p4 & Friedel";
+ if ( sym == (PLANEGROUP_P4MM | SYMMETRY_FRIEDEL) ) return "p4mm & Friedel";
+ if ( sym == (PLANEGROUP_P4GM | SYMMETRY_FRIEDEL) ) return "p4gm & Friedel";
+ if ( sym == (PLANEGROUP_P3 | SYMMETRY_FRIEDEL) ) return "p3 & Friedel";
+ if ( sym == (PLANEGROUP_P3M1 | SYMMETRY_FRIEDEL) ) return "p3m1 & Friedel";
+ if ( sym == (PLANEGROUP_P31M | SYMMETRY_FRIEDEL) ) return "p31m & Friedel";
+ if ( sym == (PLANEGROUP_P6 | SYMMETRY_FRIEDEL) ) return "p6 & Friedel";
+ if ( sym == (PLANEGROUP_P6MM | SYMMETRY_FRIEDEL) ) return "p6mm & Friedel";
+
+ return "(unknown symmetry)";
+
+}
+
+void symmetry_symmetrise_array(fftw_complex *in, signed int width, signed int height, Symmetry sym) {
+
+ ReflectionList *reflections;
+
+ reflections = reflist_new_from_array(in, width, height);
+ symmetry_symmetrise(reflections, sym, SYMFLAG_PHASES_KNOWN);
+ reflist_fill_array(in, reflections, width, height);
+ reflist_free(reflections);
+
+}