aboutsummaryrefslogtreecommitdiff
path: root/src/cdm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cdm.c')
-rw-r--r--src/cdm.c1202
1 files changed, 1202 insertions, 0 deletions
diff --git a/src/cdm.c b/src/cdm.c
new file mode 100644
index 0000000..d0a1a91
--- /dev/null
+++ b/src/cdm.c
@@ -0,0 +1,1202 @@
+/*
+ * cdm.c
+ *
+ * "Conventional Direct Methods" - triplet and tangent stuff
+ *
+ * (c) 2006-2009 Thomas White <taw27@cam.ac.uk>
+ *
+ * synth2d - Two-Dimensional Crystallographic Fourier Synthesis
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <gtk/gtk.h>
+#include <math.h>
+#include <string.h>
+#include <gsl/gsl_sf_bessel.h>
+#include <assert.h>
+#include <stdint.h>
+#include <fftw3.h>
+
+#include "displaywindow.h"
+#include "symmetry.h"
+#include "main.h"
+#include "gtk-symmetry.h"
+#include "data.h"
+
+typedef struct {
+ GtkWidget *emin;
+ GtkWidget *gmin;
+ GtkWidget *amin;
+ GtkWidget *symmetry;
+ GtkWidget *refine;
+ GtkWidget *auto_iterate;
+} CDMWindow;
+
+static CDMContext *the_cdmctx = NULL;
+
+static void cdm_solutionwindow_open(CDMContext *cdm);
+
+/* ........................ The Maths ........................ */
+
+static ReflectionList *cdm_findstrongreflections(ReflectionList *reflections_orig, Symmetry sym, double emin) {
+
+ ReflectionList *strongest_reflections;
+ ReflectionList *reflections;
+// unsigned int target;
+ unsigned int i;
+
+ /* Initialise reflection list */
+ reflections = reflist_copy(reflections_orig);
+ strongest_reflections = reflist_new_parent(reflections_orig);
+
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+ reflections->refs[i].parent_index = i;
+ }
+
+ for ( i=1; i<reflections->n_reflections; i++ ) {
+ if ( (reflections->refs[i].amplitude >= emin) && (reflections->refs[i].h != 0) && (reflections->refs[i].k != 0) ) {
+ reflist_addref_parent(strongest_reflections, reflections->refs[i].h, reflections->refs[i].k, reflections->refs[i].l,
+ reflections->refs[i].parent_index);
+ }
+ }
+
+#if 0
+ while ( reflections->n_reflections > 1 ) {
+
+ unsigned int j;
+ double am_max = 0;
+ unsigned int j_max = 0;
+
+ /* Find the next strongest reflection */
+ for ( j=1; j<reflections->n_reflections; j++ ) {
+
+ double am = reflections->refs[j].amplitude;
+ signed int h, k, l;
+
+ if ( am == 0 ) continue; /* Avoid Trouble if emin is negative... */
+
+ h = reflections->refs[j].h;
+ k = reflections->refs[j].k;
+ l = reflections->refs[j].l;
+
+ if ( am >= am_max ) {
+ am_max = am;
+ j_max = j;
+ }
+
+ }
+
+ /* Add reflection to the new list, with a link back to the original copy */
+ reflist_addref_parent(strongest_reflections, reflections->refs[j_max].h, reflections->refs[j_max].k, reflections->refs[j_max].l,
+ reflections->refs[j_max].parent_index);
+ reflist_delref(reflections, reflections->refs[j_max].h, reflections->refs[j_max].k, reflections->refs[j_max].l);
+
+ }
+
+ /* Chop off everything but the first 40% of the reflections */
+ target = 4*strongest_reflections->n_reflections/10;
+ while ( strongest_reflections->n_reflections > target ) {
+ reflist_delref(strongest_reflections, strongest_reflections->refs[strongest_reflections->n_reflections-1].h,
+ strongest_reflections->refs[strongest_reflections->n_reflections-1].k,
+ strongest_reflections->refs[strongest_reflections->n_reflections-1].l);
+ }
+#endif
+
+ return strongest_reflections;
+
+}
+
+#if 0
+static TripletList *cdm_sort_triplets(TripletList *triplet_list) {
+
+ TripletList *sorted_triplets;
+ TripletList *triplet_copy;
+ unsigned int target;
+
+ sorted_triplets = malloc(sizeof(TripletList));
+
+ triplet_copy = malloc(sizeof(TripletList));
+ memcpy(triplet_copy, triplet_list, sizeof(TripletList));
+
+ target = 9*triplet_copy->n_triplets/10;
+ while ( triplet_copy->n_triplets > target ) {
+
+ unsigned int i;
+ double G_max = 0;
+ unsigned int i_max = 0;
+
+ /* Locate most concentrated triplet */
+ for ( i=0; i<triplet_copy->n_triplets; i++ ) {
+ if ( triplet_copy->triplets[i].G > G_max ) {
+ i_max = i;
+ G_max = triplet_copy->triplets[i].G;
+ }
+ }
+
+ /* Copy the best triplet into the new list */
+ sorted_triplets->triplets[sorted_triplets->n_triplets].G = triplet_copy->triplets[i_max].G;
+ sorted_triplets->triplets[sorted_triplets->n_triplets].p.h = triplet_copy->triplets[i_max].p.h;
+ sorted_triplets->triplets[sorted_triplets->n_triplets].p.k = triplet_copy->triplets[i_max].p.k;
+ sorted_triplets->triplets[sorted_triplets->n_triplets].p.l = triplet_copy->triplets[i_max].p.l;
+ sorted_triplets->triplets[sorted_triplets->n_triplets].q.h = triplet_copy->triplets[i_max].q.h;
+ sorted_triplets->triplets[sorted_triplets->n_triplets].q.k = triplet_copy->triplets[i_max].q.k;
+ sorted_triplets->triplets[sorted_triplets->n_triplets].q.l = triplet_copy->triplets[i_max].q.l;
+ sorted_triplets->n_triplets++;
+
+ /* Remove the best triplet from the original list */
+ for ( i=i_max+1; i<triplet_copy->n_triplets; i++ ) {
+ triplet_copy->triplets[i-1].G = triplet_copy->triplets[i].G;
+ triplet_copy->triplets[i-1].p.h = triplet_copy->triplets[i].p.h;
+ triplet_copy->triplets[i-1].p.k = triplet_copy->triplets[i].p.k;
+ triplet_copy->triplets[i-1].p.l = triplet_copy->triplets[i].p.l;
+ triplet_copy->triplets[i-1].q.h = triplet_copy->triplets[i].q.h;
+ triplet_copy->triplets[i-1].q.k = triplet_copy->triplets[i].q.k;
+ triplet_copy->triplets[i-1].q.l = triplet_copy->triplets[i].q.l;
+ }
+ triplet_copy->n_triplets--;
+
+ }
+ free(triplet_copy);
+
+ return sorted_triplets;
+
+}
+#endif
+
+static TripletList *cdm_findtriplets(ReflectionList *strongest_reflections, Symmetry sym, double emin, double gmin) {
+
+ TripletList *triplet_list;
+ unsigned int p;
+ unsigned int q;
+// TripletList *sorted_triplets;
+ unsigned int n_total_triplets;
+
+ /* Initialise triplet list */
+ triplet_list = malloc(sizeof(TripletList));
+ triplet_list->n_triplets = 0;
+
+ /* Iterate doubly over the reflections */
+ n_total_triplets = 0;
+ for ( p=1; p<strongest_reflections->n_reflections; p++ ) {
+ for ( q=1; q<strongest_reflections->n_reflections; q++ ) {
+
+ double E1;
+ double E2;
+ double E3;
+ double G;
+ unsigned int r;
+ signed int ph, pk, pl, qh, qk, ql, rh, rk, rl;
+
+ ph = strongest_reflections->refs[p].h;
+ pk = strongest_reflections->refs[p].k;
+ pl = strongest_reflections->refs[p].l;
+ qh = strongest_reflections->refs[q].h;
+ qk = strongest_reflections->refs[q].k;
+ ql = strongest_reflections->refs[q].l;
+
+ assert(ph || pk || pl);
+ assert(qh || qk || ql);
+
+ /* Determine the third reflection in the triplet */
+ rh = -ph-qh;
+ rk = -pk-qk;
+ if ( pl != ql ) {
+ printf("CDM: pl != ql: %3i %3i\n", pl, ql);
+ continue;
+ }
+ //assert(pl == ql); /* This failure mode should have been weeded out ages ago */
+ rl = pl;
+
+ /* See if the third reflection is available */
+ if ( (r = reflist_inlist(strongest_reflections, rh, rk, rl)) ) {
+
+ /* Trust me on this ... */
+ E1 = strongest_reflections->parent->refs[strongest_reflections->refs[p].parent_index].amplitude;
+ E2 = strongest_reflections->parent->refs[strongest_reflections->refs[q].parent_index].amplitude;
+ E3 = strongest_reflections->parent->refs[strongest_reflections->refs[r].parent_index].amplitude;
+
+ G = E1 * E2 * E3;
+
+ /* Convincing enough? */
+ if ( G > gmin ) {
+ triplet_list->triplets[triplet_list->n_triplets].p.h = ph;
+ triplet_list->triplets[triplet_list->n_triplets].p.k = pk;
+ triplet_list->triplets[triplet_list->n_triplets].p.l = pl;
+ triplet_list->triplets[triplet_list->n_triplets].q.h = qh;
+ triplet_list->triplets[triplet_list->n_triplets].q.k = qk;
+ triplet_list->triplets[triplet_list->n_triplets].q.l = ql;
+ triplet_list->triplets[triplet_list->n_triplets].G = G;
+ triplet_list->n_triplets++;
+ if ( triplet_list->n_triplets == MAX_TRIPLETS ) {
+ printf("DM: Too many triplets!\n");
+ return NULL;
+ }
+ //printf("DM: Found triplet %3i,%3i %3i : %3i,%3i %3i : %3i %3i,%3i G = %f\n",
+ // ph, pk, pl, qh, qk, ql, rh, rk, rl, G);
+ }
+ n_total_triplets++;
+
+ }
+
+ }
+ }
+
+ printf("DM: Have %i concentrated triplets (%0.1f%%)\n", triplet_list->n_triplets, ((double)triplet_list->n_triplets/n_total_triplets)*100);
+
+ //sorted_triplets = cdm_sort_triplets(triplet_list);
+ //free(triplet_list);
+ //return sorted_triplets;
+
+ return triplet_list;
+
+}
+
+static ReflectionList *cdm_definebasis(ReflectionList *reflections_orig, TripletList *triplet_list, Symmetry sym, double min_alpha) {
+
+ signed int j, jmin;
+ ReflectionList *convergence;
+ ReflectionList *basis;
+ ReflectionList *reflections;
+
+ if ( reflections_orig->n_reflections <= 1 ) {
+ printf("DM: No reflections!\n");
+ return NULL;
+ }
+
+ /* Circumvent normal creation mechanism in order to enact nastiness */
+ reflections = malloc(sizeof(ReflectionList));
+ if ( !reflections ) return NULL;
+ /* Start with the entire list of reflections and work backwards */
+ memcpy(reflections, reflections_orig, sizeof(ReflectionList));
+
+ //printf("DM: Finding maximally connected starting set among %i reflections\n", reflections->n_reflections);
+
+ convergence = reflist_new_parent(reflections_orig->parent);
+
+ while ( reflections->n_reflections > 1 ) { /* Remember 0 0 0 */
+
+ double alpha_min = 999999;
+ signed int h_min = 999999;
+ signed int k_min = 999999;
+ signed int l_min = 999999;
+ unsigned int i;
+ unsigned int i_min = 0;
+ unsigned int p;
+ ReflectionList *equivalents;
+
+ for ( i=1; i<reflections->n_reflections; i++ ) {
+
+ signed int h, k, l;
+ unsigned int t;
+ double alpha = 0;
+
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+ l = reflections->refs[i].l;
+ assert( (h != 0) || (k != 0) || (l != 0) );
+
+ for ( t=0; t<triplet_list->n_triplets; t++ ) {
+
+ signed int ph = triplet_list->triplets[t].p.h;
+ signed int pk = triplet_list->triplets[t].p.k;
+
+ /* Does this triplet concern this reflection? */
+ if ( (ph == h) && (pk == k) ) {
+
+ signed int qh = triplet_list->triplets[t].q.h;
+ signed int qk = triplet_list->triplets[t].q.k;
+ signed int rh = -ph-qh;
+ signed int rk = -pk-qk;
+ double G = triplet_list->triplets[t].G;
+
+ /* Are the other reflections in the triplet still in the list? */
+ if ( reflist_inlist_2d(reflections, qh, qk) && reflist_inlist_2d(reflections, rh, rk) ) {
+ alpha += G * (gsl_sf_bessel_I1(G) / gsl_sf_bessel_I0(G));
+ //printf("%3i %3i %3i alpha=%f * (%f / %f) = %f\n", h, k, l, G, gsl_sf_bessel_I1(G), gsl_sf_bessel_I0(G), alpha);
+ }
+
+ }
+
+ }
+
+ if ( alpha < alpha_min ) {
+ alpha_min = alpha;
+ h_min = h;
+ k_min = k;
+ l_min = l;
+ i_min = reflections->refs[i].parent_index;
+ }
+
+ }
+
+ if ( alpha_min == 99999 ) {
+ printf("DM: Convergence procedure isn't working sensibly: alpha is too high for all reflections.\n");
+ printf("DM: Have you normalised properly?\n");
+ return NULL;
+ }
+
+ /* Remove the reflection h_min,k_min from the basis list */
+ reflist_delref(reflections, h_min, k_min, l_min);
+ //printf("DM: %3i %3i %3i removed from convergence list, alpha = %f, %i reflections remaining\n",
+ // h_min, k_min, l_min, alpha_min, reflections->n_reflections);
+
+ /* Remove all equivalent reflections from the basis list */
+ equivalents = symmetry_generate_equivalent_reflections(sym, h_min, k_min, l_min);
+
+ for ( p=1; p<equivalents->n_reflections; p++ ) {
+
+ signed int h, k, l;
+
+ h = equivalents->refs[p].h;
+ k = equivalents->refs[p].k;
+ l = equivalents->refs[p].l;
+
+ reflist_delref(reflections, h, k, l);
+ //printf("DM: Removing symmetry equivalent %3i %3i %3i\n", h, k, l);
+
+ }
+
+ reflist_free(equivalents);
+
+ /* Add the first reflections (but not the equivalents) */
+ reflist_addref_alpha_parent(convergence, h_min, k_min, l_min, alpha_min, i_min);
+
+ }
+
+ /* "Convergence" is in increasing order of connectivity. Reverse the order, examining
+ the last 50 reflections on the convergence list */
+ basis = reflist_new_parent(reflections_orig->parent);
+ jmin = (convergence->n_reflections)-13;
+ if ( jmin < 1 ) jmin = 1;
+ for ( j=(convergence->n_reflections)-1; j>=jmin; j-- ) {
+ if ( (convergence->refs[j].alpha < min_alpha) || ( basis->n_reflections<10) ) {
+ unsigned int parent;
+ //printf("DM: Adding %3i %3i %3i to starting set\n", convergence->refs[j].h, convergence->refs[j].k, convergence->refs[j].l);
+ parent = convergence->refs[j].parent_index;
+ reflist_addref_parent(basis, convergence->refs[j].h, convergence->refs[j].k, convergence->refs[j].l, parent);
+ }
+ }
+
+ return basis;
+
+}
+
+static int cdm_phaserelationships(CDMContext *cdm) {
+
+ if ( cdm->strongest_reflections == NULL ) {
+ /* Get the strongest reflections */
+ cdm->strongest_reflections = cdm_findstrongreflections(cdm->reflections, cdm->sym, cdm->emin);
+ if ( !cdm->strongest_reflections ) {
+ printf("DM: Error while searching for strongest reflections.\n");
+ return -1;
+ } else {
+ printf("DM: Have %i strong reflections (%0.1f%%).\n", cdm->strongest_reflections->n_reflections-1,
+ (((double)cdm->strongest_reflections->n_reflections-1)/(cdm->reflections->n_reflections-1))*100);
+ if ( cdm->strongest_reflections->n_reflections == 1 ) {
+ printf("DM: No strong reflections found!\n");
+ return -1;
+ }
+ }
+ } else {
+ printf("DM: Already have strongest reflections.\n");
+ }
+
+ if ( cdm->triplet_list == NULL ) {
+ /* Find the triplets */
+ cdm->triplet_list = cdm_findtriplets(cdm->strongest_reflections, cdm->sym, cdm->emin, cdm->gmin);
+ if ( !cdm->triplet_list ) {
+ printf("DM: Error while searching for triplets.\n");
+ return -1;
+ }
+ } else {
+ printf("DM: Already have triplet list.\n");
+ }
+
+ if ( cdm->basis_list == NULL ) {
+ /* Determine an appropriate starting point */
+ cdm->basis_list = cdm_definebasis(cdm->strongest_reflections, cdm->triplet_list, cdm->sym, cdm->amin);
+ if ( !cdm->basis_list ) {
+ printf("DM: Error while defining basis set.\n");
+ return -1;
+ }
+ printf("DM: %i reflections in the starting set\n", cdm->basis_list->n_reflections-1);
+ } else {
+ printf("DM: Already have basis set.\n");
+ }
+
+ return 0;
+
+}
+
+static unsigned int cdm_phasebasis(ReflectionList *basis_list, ReflectionList *reflections, Symmetry sym) {
+
+ unsigned int i;
+ unsigned int n_assigned = 0;
+
+ /* Unset all phases */
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+ reflections->refs[i].phase_calc_set = 0;
+ }
+
+ /* Assign random phases to the basis set */
+ for ( i=1; i<basis_list->n_reflections; i++ ) {
+
+ ReflectionList *equivalents;
+ unsigned int p, j;
+ signed int h, k, l;
+
+ j = basis_list->refs[i].parent_index;
+ h = reflections->refs[j].h;
+ k = reflections->refs[j].k;
+ l = reflections->refs[j].l;
+
+ reflections->refs[j].phase_calc = (((double)random()/RAND_MAX) * (M_PI)) - (((double)random()/RAND_MAX) * (M_PI));
+ reflections->refs[j].phase_calc_set = 1;
+ n_assigned++;
+
+ /* Centricity */
+ symmetry_centricity(reflections, j, sym, SYMFLAG_PHASES_CALC);
+ //printf("Set phase of %3i %3i %3i to %f\n", h, k, l, reflections->refs[j].phase_calc);
+
+ /* Assign all symmetry equivalents as well */
+ equivalents = symmetry_generate_equivalent_reflections(sym, h, k, l);
+
+ for ( p=1; p<equivalents->n_reflections; p++ ) {
+
+ unsigned int q;
+
+ h = equivalents->refs[p].h;
+ k = equivalents->refs[p].k;
+ l = equivalents->refs[p].l;
+
+ if ( (q = reflist_inlist(reflections, h, k, l)) ) {
+
+ double equivalent_phase;
+
+ equivalent_phase = (reflections->refs[j].phase_calc + equivalents->refs[p].delta_theta) * equivalents->refs[p].multiplier;
+
+ reflections->refs[q].phase_calc = equivalent_phase;
+ reflections->refs[q].phase_calc_set = 1;
+ symmetry_centricity(reflections, q, sym, SYMFLAG_PHASES_CALC);
+
+ //printf("DM: Setting equivalent reflection %3i %3i %3i to %f\n", h, k, l, equivalent_phase);
+ n_assigned++;
+
+ } else {
+ //printf("DM: Need to set phase of %3i %3i %3i\n", h, k, l);
+ }
+
+ }
+
+ reflist_free(equivalents);
+
+ }
+
+ return n_assigned;
+
+}
+
+static unsigned int cdm_assign_code(ReflectionList *reflections, ReflectionList *basis_list, Symmetry sym, unsigned int phasing_code) {
+
+ unsigned int i;
+ unsigned int n_assigned = 0;
+
+ /* Unset all phases */
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+ reflections->refs[i].phase_calc_set = 0;
+ }
+
+ /* Assign phases to the basis set */
+ for ( i=1; i<basis_list->n_reflections; i++ ) {
+
+ ReflectionList *equivalents;
+ unsigned int p, j;
+ signed int h, k, l;
+
+ j = basis_list->refs[i].parent_index;
+ h = reflections->refs[j].h;
+ k = reflections->refs[j].k;
+ l = reflections->refs[j].l;
+
+ if ( phasing_code & (1<<(i-1)) ) {
+ reflections->refs[j].phase_calc = M_PI;
+ } else {
+ reflections->refs[j].phase_calc = 0;
+ }
+ reflections->refs[j].phase_calc_set = 1;
+ n_assigned++;
+
+ /* Centricity */
+ symmetry_centricity(reflections, j, sym, SYMFLAG_PHASES_CALC);
+ //printf("Set phase of %3i %3i %3i to %f\n", h, k, l, reflections->refs[j].phase_calc);
+
+ /* Assign all symmetry equivalents as well */
+ equivalents = symmetry_generate_equivalent_reflections(sym, h, k, l);
+
+ for ( p=1; p<equivalents->n_reflections; p++ ) {
+
+ unsigned int q;
+
+ h = equivalents->refs[p].h;
+ k = equivalents->refs[p].k;
+ l = equivalents->refs[p].l;
+
+ if ( (q = reflist_inlist(reflections, h, k, l)) ) {
+
+ double equivalent_phase;
+
+ equivalent_phase = (reflections->refs[j].phase_calc + equivalents->refs[p].delta_theta) * equivalents->refs[p].multiplier;
+
+ reflections->refs[q].phase_calc = equivalent_phase;
+ reflections->refs[q].phase_calc_set = 1;
+ symmetry_centricity(reflections, q, sym, SYMFLAG_PHASES_CALC);
+
+ //printf("DM: Setting equivalent reflection %3i %3i %3i to %f\n", h, k, l, equivalent_phase);
+ n_assigned++;
+
+ } else {
+ //printf("DM: Need to set phase of %3i %3i %3i\n", h, k, l);
+ }
+
+ }
+
+ reflist_free(equivalents);
+
+ }
+
+ return n_assigned;
+
+}
+
+static unsigned int cdm_expand(CDMContext *cdm) {
+
+ unsigned int total_assigned = 0;
+ unsigned int total_refined = 0;
+ unsigned int n_assigned, n_refined;
+ ReflectionList *reflections = cdm->reflections;
+ ReflectionList *strongest_reflections = cdm->strongest_reflections;
+ TripletList *triplet_list = cdm->triplet_list;
+ Symmetry sym = cdm->sym;
+ double min_alpha = cdm->amin;
+ unsigned int refinement = cdm->refine;
+
+ /* Expand as far as possible */
+ do {
+
+ unsigned int i;
+ n_assigned = 0;
+ n_refined = 0;
+
+ for ( i=0; i<strongest_reflections->n_reflections; i++ ) {
+
+ double beta;
+ unsigned int t;
+ unsigned int n_tri = 0;
+ double alpha;
+ double sigma_sin = 0;
+ double sigma_cos = 0;
+ signed int h = strongest_reflections->refs[i].h;
+ signed int k = strongest_reflections->refs[i].k;
+ signed int l = strongest_reflections->refs[i].l;
+ unsigned int j = strongest_reflections->refs[i].parent_index;
+ unsigned int refine, assign;
+
+ if ( !refinement && reflections->refs[j].phase_calc_set ) continue; /* Already phased? */
+
+ /* Calculate the most likely phase for this reflection based on the active triplets */
+ for ( t=0; t<triplet_list->n_triplets; t++ ) {
+
+ signed int ph = triplet_list->triplets[t].p.h;
+ signed int pk = triplet_list->triplets[t].p.k;
+
+ /* Does this triplet concern this reflection? */
+ if ( (ph == h) && (pk == k) ) {
+
+ signed int qh = triplet_list->triplets[t].q.h;
+ signed int qk = triplet_list->triplets[t].q.k;
+ signed int rh = -ph-qh;
+ signed int rk = -pk-qk;
+ unsigned int q = reflist_inlist_2d(reflections, qh, qk);
+ unsigned int r = reflist_inlist_2d(reflections, rh, rk);
+
+ if ( !q ) {
+ printf("DM: q: %3i %3i not in list!\n", qh, qk);
+ continue;
+ }
+ if ( !r ) {
+ printf("DM: r: %3i %3i not in list!\n", rh, rk);
+ continue;
+ }
+
+ /* Does this triplet concern already phased reflections? */
+ if ( reflections->refs[q].phase_calc_set && reflections->refs[r].phase_calc_set ) {
+
+ double omega = reflections->refs[q].phase_calc + reflections->refs[r].phase_calc;
+
+ sigma_sin += triplet_list->triplets[t].G * sin(omega);
+ sigma_cos += triplet_list->triplets[t].G * cos(omega);
+
+ n_tri++;
+
+
+ }
+
+ }
+
+ }
+
+ alpha = sqrt(sigma_sin*sigma_sin + sigma_cos*sigma_cos);
+ assign = 0; refine = 0;
+ if ( !reflections->refs[j].phase_calc_set && (alpha > min_alpha) ) assign = 1;
+ if ( refinement && reflections->refs[j].phase_calc_set && (alpha > reflections->refs[j].alpha) ) refine = 1;
+ /* Assign phase if it's reliable enough */
+ if ( assign || refine ) {
+
+ ReflectionList *equivalents;
+ unsigned int p;
+
+ beta = atan2(sigma_sin, sigma_cos);
+ if ( assign ) {
+ reflections->refs[j].phase_calc = beta;
+ reflections->refs[j].phase_calc_set = 1;
+ reflections->refs[j].alpha = alpha;
+ n_assigned++;
+ //printf("DM: Assigned %3i %3i phase %f (alpha=%f from %i triplets)\n", h, k, beta, alpha, n_tri);
+ } else {
+ reflections->refs[j].phase_calc = beta;
+ reflections->refs[j].alpha = alpha;
+ n_refined++;
+ //printf("DM: Refined %3i %3i phase %f (alpha=%f from %i triplets)\n", h, k, beta, alpha, n_tri);
+ }
+
+ /* Centricity */
+ symmetry_centricity(reflections, j, sym, SYMFLAG_PHASES_CALC);
+
+ /* Assign all symmetry equivalents as well */
+ equivalents = symmetry_generate_equivalent_reflections(sym, h, k, l);
+
+ for ( p=1; p<equivalents->n_reflections; p++ ) {
+
+ signed int h, k, l;
+ unsigned int q;
+
+ h = equivalents->refs[p].h;
+ k = equivalents->refs[p].k;
+ l = equivalents->refs[p].l;
+
+ if ( (q = reflist_inlist(reflections, h, k, l)) ) {
+
+ double equivalent_phase;
+
+ equivalent_phase = (beta + equivalents->refs[p].delta_theta) * equivalents->refs[p].multiplier;
+
+ reflections->refs[q].phase_calc = equivalent_phase;
+ reflections->refs[q].phase_calc_set = 1;
+ reflections->refs[q].alpha = alpha;
+ symmetry_centricity(reflections, q, sym, SYMFLAG_PHASES_CALC);
+
+ //printf("DM: Setting equivalent reflection %3i %3i %3i to %f\n", h, k, l, equivalent_phase);
+ n_assigned++;
+
+ } else {
+ //printf("DM: Need to set phase of %3i %3i %3i, but it isn't in the list\n", h, k, l);
+ }
+
+ }
+
+ reflist_free(equivalents);
+
+ }
+
+ }
+ //printf("DM: This cycle: %i phases assigned, %i refined\n", n_assigned, n_refined);
+ total_assigned += n_assigned;
+ total_refined += n_refined;
+
+ } while (n_refined+n_assigned > 0);
+
+ cdm->n_assigned_expansion = total_assigned;
+ cdm->n_refined = total_refined;
+ return total_assigned;
+
+}
+
+static void cdm_sortsolutions(CDMContext *cdm) {
+
+
+
+}
+
+unsigned int cdm_systematic_expansion(CDMContext *cdm) {
+
+ unsigned int i;
+ unsigned int n_solutions;
+ PhasingSolution *prev;
+ fftw_complex *cdm_in;
+ fftw_complex *cdm_out;
+ fftw_plan cdm_plan;
+ signed int h, k;
+ ReflectionList *reflections;
+ PhasingSolution *sol;
+
+ if ( !(cdm->sym & SYMMETRY_CENTRE) ) {
+ error_report("Can only automatically iterate in a centrosymmetric planegroup");
+ return 0;
+ }
+
+ if ( cdm->basis_list->n_reflections > (sizeof(int)*8) ) {
+ error_report("Too many solutions to enumerate");
+ return 0;
+ }
+
+ /* Enumerate the solutions */
+ n_solutions = 1<<(cdm->basis_list->n_reflections-1);
+ prev = NULL;
+ for ( i=1; i<=n_solutions; i++ ) {
+
+ PhasingSolution *new;
+
+ new = malloc(sizeof(PhasingSolution));
+ new->n = i;
+ new->phasing_code = i-1; /* phasing_code might not always equal n */
+
+ new->next = NULL;
+ if ( i == 1 ) {
+ cdm->solutions = new;
+ } else {
+ prev->next = new;
+ }
+ prev = new;
+
+ }
+ printf("DM: Enumerated %i solutions\n", n_solutions);
+
+ /* Prepare */
+ cdm_in = fftw_malloc(data_width()*data_height()*sizeof(fftw_complex));
+ cdm_out = fftw_malloc(data_width()*data_height()*sizeof(fftw_complex));
+ cdm_plan = fftw_plan_dft_2d(data_width(), data_height(), cdm_in, cdm_out,
+ FFTW_BACKWARD, FFTW_MEASURE | FFTW_PRESERVE_INPUT);
+
+ for ( h=0; h<data_width(); h++ ) {
+ for ( k=0; k<data_height(); k++ ) {
+ cdm_in[k+data_height()*h][0] = 0;
+ cdm_in[k+data_height()*h][1] = 0;
+ }
+ }
+
+ /* Step through each basis set in turn, and expand phases */
+ reflections = cdm->reflections;
+ sol = cdm->solutions;
+ do {
+
+ unsigned int basis_assigned, expnd_assigned;
+ int x, y;
+ double max, unflatness, entropy;
+
+ printf("%7i, phasing code %06X", sol->n, sol->phasing_code);
+ basis_assigned = cdm_assign_code(reflections, cdm->basis_list, cdm->sym, sol->phasing_code);
+ expnd_assigned = cdm_expand(cdm);
+
+ /* Transfer to Fourier array */
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+ if ( reflections->refs[i].phase_calc_set ) {
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+ if ( h < 0 ) { h = data_width()+h; }
+ if ( k < 0 ) { k = data_height()+k; }
+ cdm_in[k + data_height()*h][0] = reflections->refs[i].amplitude * cos(reflections->refs[i].phase_calc);
+ cdm_in[k + data_height()*h][1] = reflections->refs[i].amplitude * sin(reflections->refs[i].phase_calc);
+ }
+ }
+
+ fftw_execute(cdm_plan);
+ displaywindow_switchview();
+ while ( gtk_events_pending() ) gtk_main_iteration();
+
+ /* Calculate "unflatness" and entropy of map, and record */
+ max = 0;
+ for ( y=0; y<data_height(); y++ ) {
+ for ( x=0; x<data_width(); x++ ) {
+ double re = cdm_out[y+data_height()*x][0];
+ double im = cdm_out[y+data_height()*x][1];
+ double am = sqrt(re*re + im*im);
+ if ( am > max ) max = am;
+ }
+ }
+ unflatness = 0; entropy = 0;
+ for ( y=0; y<data_height(); y++ ) {
+ for ( x=0; x<data_width(); x++ ) {
+ double re = cdm_out[y+data_height()*x][0];
+ double im = cdm_out[y+data_height()*x][1];
+ double am = sqrt(re*re + im*im);
+ unflatness += (am/max) * (am/max) * (am/max) * (am/max);
+ entropy += (am/max) * log(am/max);
+ }
+ }
+ unflatness /= (data_height() * data_width());
+ entropy = -entropy;
+ sol->unflatness = unflatness;
+ sol->entropy = entropy;
+ printf(" : %i + %i (+%i) phased, unflatness=%.5f, entropy=%.5f\n", basis_assigned, expnd_assigned, cdm->n_refined, unflatness, entropy);
+
+ sol = sol->next;
+
+ } while ( sol );
+
+ /* Finalise */
+ fftw_destroy_plan(cdm_plan);
+ fftw_free(cdm_in);
+ fftw_free(cdm_out);
+
+ cdm_sortsolutions(cdm);
+ cdm_solutionwindow_open(cdm);
+
+ return 0;
+
+}
+
+unsigned int cdm_tangentexpansion(CDMContext *cdm) {
+
+ int res;
+
+ /* Set up the phase relationships */
+ res = cdm_phaserelationships(cdm);
+ if ( res ) return res;
+
+ if ( !cdm->auto_iterate ) {
+
+ unsigned int basis_assigned, expnd_assigned;
+
+ /* Phase the initial reflections */
+ basis_assigned = cdm_phasebasis(cdm->basis_list, cdm->reflections, cdm->sym);
+
+ /* Expand */
+ expnd_assigned = cdm_expand(cdm);
+
+ /* Report */
+ printf("DM: %i + %i (+%i) phases assigned\n", basis_assigned, expnd_assigned, cdm->n_refined);
+
+ return basis_assigned + expnd_assigned;
+
+ } else {
+
+ return cdm_systematic_expansion(cdm);
+
+ }
+
+}
+
+/* ..................... The Other Stuff ..................... */
+
+static int cdm_window_open = 0;
+
+static void cdm_execute(CDMWindow *cdm) {
+
+ char *string;
+ int total_assigned;
+ Symmetry sym;
+ float emin, gmin, amin;
+ const char *str;
+ CDMContext *cdmctx;
+
+ sym = gtk_symmetry_get_symmetry(GTK_SYMMETRY(cdm->symmetry));
+
+ str = gtk_entry_get_text(GTK_ENTRY(cdm->emin));
+ if ( !sscanf(str, "%f", &emin) ) {
+ error_report("Plase specify minimum |E|");
+ return;
+ }
+ str = gtk_entry_get_text(GTK_ENTRY(cdm->gmin));
+ if ( !sscanf(str, "%f", &gmin) ) {
+ error_report("Plase specify minimum G");
+ return;
+ }
+ str = gtk_entry_get_text(GTK_ENTRY(cdm->amin));
+ if ( !sscanf(str, "%f", &amin) ) {
+ error_report("Plase specify minimum α");
+ return;
+ }
+
+ if ( the_cdmctx == NULL ) {
+ printf("DM: Creating new context.\n");
+ the_cdmctx = malloc(sizeof(CDMContext));
+ if ( the_cdmctx == NULL ) {
+ error_report("Couldn't create CDM control structure");
+ return;
+ }
+ the_cdmctx->auto_iterate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cdm->auto_iterate));
+ the_cdmctx->refine = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cdm->refine));
+ the_cdmctx->sym = sym;
+ the_cdmctx->emin = emin;
+ the_cdmctx->gmin = gmin;
+ the_cdmctx->amin = amin;
+ the_cdmctx->strongest_reflections = NULL;
+ the_cdmctx->triplet_list = NULL;
+ the_cdmctx->basis_list = NULL;
+ } else {
+ int restart = 0;
+ if ( the_cdmctx->sym != sym ) {
+ restart = 1;
+ }
+ if ( the_cdmctx->emin != emin ) {
+ restart = 1;
+ }
+ if ( the_cdmctx->gmin != gmin ) {
+ restart = 1;
+ }
+ /* The others do not require a re-calculation */
+ if ( restart ) {
+ printf("DM: Conditions have changed. Recreating context...\n");
+ /* Tidy up */
+ free(the_cdmctx->triplet_list);
+ free(the_cdmctx->strongest_reflections);
+ free(the_cdmctx->basis_list);
+ free(the_cdmctx);
+ the_cdmctx = malloc(sizeof(CDMContext));
+ if ( the_cdmctx == NULL ) {
+ error_report("Couldn't create CDM control structure");
+ return;
+ }
+ the_cdmctx->auto_iterate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cdm->auto_iterate));
+ the_cdmctx->refine = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cdm->refine));
+ the_cdmctx->sym = sym;
+ the_cdmctx->emin = emin;
+ the_cdmctx->gmin = gmin;
+ the_cdmctx->amin = amin;
+ the_cdmctx->strongest_reflections = NULL;
+ the_cdmctx->triplet_list = NULL;
+ the_cdmctx->basis_list = NULL;
+ }
+
+ }
+ cdmctx = the_cdmctx;
+
+ if ( !cdmctx->auto_iterate ) {
+
+ /* Do one expansion based on a random starting set, display the result */
+ total_assigned = main_cdm_tangentexpansion(cdmctx);
+ displaywindow_switchview();
+
+ string = malloc(64);
+ snprintf(string, 63, "%i phases assigned", total_assigned);
+ displaywindow_statusbar(string);
+ free(string);
+
+ } else {
+
+ /* Systematically iterate over all possible starting sets, rank by FoM */
+ main_cdm_tangentexpansion(cdmctx);
+
+ }
+
+}
+
+static gint cdm_window_response(GtkWidget *widget, gint response, CDMWindow *cdm) {
+
+ if ( response == GTK_RESPONSE_OK ) {
+ cdm_execute(cdm);
+ }
+
+ if ( response != GTK_RESPONSE_OK ) {
+ cdm_window_open = 0;
+ gtk_widget_destroy(widget);
+ }
+
+ return 0;
+
+}
+
+void cdm_dialog_open() {
+
+ CDMWindow *cdm;
+ GtkWidget *cdm_window;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *table;
+ GtkWidget *emin_label;
+ GtkWidget *gmin_label;
+ GtkWidget *amin_label;
+
+ if ( cdm_window_open ) {
+ return;
+ }
+ cdm_window_open = 1;
+
+ cdm = malloc(sizeof(CDMWindow));
+
+ cdm_window = gtk_dialog_new_with_buttons("Tangent Formula", GTK_WINDOW(displaywindow_gtkwindow()),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL, GTK_STOCK_EXECUTE, GTK_RESPONSE_OK, NULL);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(cdm_window)->vbox), GTK_WIDGET(hbox), FALSE, FALSE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 5);
+
+ cdm->symmetry = gtk_symmetry_new(2, 2, TRUE);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(cdm->symmetry), TRUE, TRUE, 5);
+
+ table = gtk_table_new(5, 2, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 5);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), FALSE, FALSE, 0);
+
+ emin_label = gtk_label_new("Minimum |E|:");
+ gtk_misc_set_alignment(GTK_MISC(emin_label), 1, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(emin_label), 1, 2, 1, 2);
+ cdm->emin = gtk_entry_new();
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(cdm->emin), 2, 3, 1, 2);
+ gtk_entry_set_text(GTK_ENTRY(cdm->emin), "0.0001");
+
+ gmin_label = gtk_label_new("Minimum G:");
+ gtk_misc_set_alignment(GTK_MISC(gmin_label), 1, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(gmin_label), 1, 2, 2, 3);
+ cdm->gmin = gtk_entry_new();
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(cdm->gmin), 2, 3, 2, 3);
+ gtk_entry_set_text(GTK_ENTRY(cdm->gmin), "0.00024");
+
+ amin_label = gtk_label_new("Minimum α:");
+ gtk_misc_set_alignment(GTK_MISC(amin_label), 1, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(amin_label), 1, 2, 3, 4);
+ cdm->amin = gtk_entry_new();
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(cdm->amin), 2, 3, 3, 4);
+ gtk_entry_set_text(GTK_ENTRY(cdm->amin), "0.0001");
+
+ cdm->refine = gtk_check_button_new_with_label("Refine Phases");
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(cdm->refine), 1, 3, 4, 5);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cdm->refine), TRUE);
+
+ cdm->auto_iterate = gtk_check_button_new_with_label("Automatically Iterate");
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(cdm->auto_iterate), 1, 3, 5, 6);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cdm->auto_iterate), FALSE);
+
+ g_signal_connect(G_OBJECT(cdm_window), "response", G_CALLBACK(cdm_window_response), cdm);
+ gtk_widget_show_all(cdm_window);
+
+}
+
+enum {
+ SOLUTION_COLUMN_NUMBER,
+ SOLUTION_COLUMN_PHASECODE,
+ SOLUTION_COLUMN_UNFLATNESS,
+ SOLUTION_COLUMN_ENTROPY,
+ SOLUTION_COLUMNS
+};
+
+void cdm_display_phasing_solution(CDMContext *cdm, PhasingSolution *sol, ReflectionList *reflections) {
+
+ cdm_assign_code(reflections, cdm->basis_list, cdm->sym, sol->phasing_code);
+ cdm_expand(cdm);
+
+ displaywindow_switchview();
+
+}
+
+static gint cdm_solutionwindow_response(GtkWidget *solution_window, gint response, gpointer data) {
+ gtk_widget_destroy(solution_window);
+ return 0;
+}
+
+static void cdm_solutionwindow_selectionchanged(GtkTreeSelection *selection, CDMContext *cdm) {
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ gint snum;
+ PhasingSolution *sol_it;
+ PhasingSolution *sol;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(cdm->solution_tree_view), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(cdm->solution_list_store), &iter, path);
+ gtk_tree_model_get(GTK_TREE_MODEL(cdm->solution_list_store), &iter, SOLUTION_COLUMN_NUMBER, &snum, -1);
+
+ sol_it = cdm->solutions; sol = NULL;
+ do {
+ if ( sol_it->n == snum ) {
+ sol = sol_it;
+ break;
+ }
+ sol_it = sol_it->next;
+ } while ( sol_it );
+ if ( sol ) {
+ printf("DM: Displaying solution %7i, phasing code %06X\n", sol->n, sol->phasing_code);
+ main_display_phasing_solution(cdm, sol);
+ } else {
+ printf("DM: Can't find solution %i\n", snum);
+ error_report("Can't find solution!\n");
+ }
+
+}
+
+static void cdm_solutionwindow_open(CDMContext *cdm) {
+
+ GtkWidget *solution_window;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkWidget *scrolledwindow;
+ GtkWidget *solution_tree;
+ GtkListStore *solution_list_store;
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ GtkTreeIter iter;
+ PhasingSolution *sol;
+
+ solution_window = gtk_dialog_new_with_buttons("Phasing Solutions", GTK_WINDOW(displaywindow_gtkwindow()),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+ gtk_window_set_default_size(GTK_WINDOW(solution_window), 400, 500);
+
+ /* Window layout */
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(solution_window)->vbox), GTK_WIDGET(hbox), TRUE, TRUE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 5);
+
+ /* List and Tree */
+ solution_list_store = gtk_list_store_new(SOLUTION_COLUMNS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+ solution_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(solution_list_store));
+ g_object_unref(G_OBJECT(solution_list_store));
+ cdm->solution_tree_view = solution_tree;
+ cdm->solution_list_store = solution_list_store;
+
+ /* Set up columns */
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes("#", renderer, "text", SOLUTION_COLUMN_NUMBER, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(solution_tree), column);
+ column = gtk_tree_view_column_new_with_attributes("Phase", renderer, "text", SOLUTION_COLUMN_PHASECODE, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(solution_tree), column);
+ column = gtk_tree_view_column_new_with_attributes("Unflatness", renderer, "text", SOLUTION_COLUMN_UNFLATNESS, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(solution_tree), column);
+ column = gtk_tree_view_column_new_with_attributes("Entropy", renderer, "text", SOLUTION_COLUMN_ENTROPY, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(solution_tree), column);
+
+ /* Scrollbar */
+ scrolledwindow = gtk_scrolled_window_new(gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(solution_tree)),
+ gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(solution_tree)));
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(scrolledwindow), GTK_WIDGET(solution_tree));
+
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(scrolledwindow), TRUE, TRUE, 5);
+
+ /* Add the solutions */
+ sol = cdm->solutions;
+ do {
+ char tmp[32];
+ gtk_list_store_append(solution_list_store, &iter);
+ snprintf(tmp, 31, "%06X", sol->phasing_code);
+ gtk_list_store_set(solution_list_store, &iter, SOLUTION_COLUMN_NUMBER, sol->n, SOLUTION_COLUMN_PHASECODE, tmp,
+ SOLUTION_COLUMN_UNFLATNESS, sol->unflatness, SOLUTION_COLUMN_ENTROPY, sol->entropy, -1);
+ sol = sol->next;
+ } while ( sol );
+ g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(solution_tree))), "changed",
+ G_CALLBACK(cdm_solutionwindow_selectionchanged), cdm);
+
+
+ g_signal_connect(G_OBJECT(solution_window), "response", G_CALLBACK(cdm_solutionwindow_response), cdm);
+ gtk_widget_show_all(solution_window);
+
+}