aboutsummaryrefslogtreecommitdiff
path: root/src/normalise.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/normalise.c')
-rw-r--r--src/normalise.c721
1 files changed, 721 insertions, 0 deletions
diff --git a/src/normalise.c b/src/normalise.c
new file mode 100644
index 0000000..a08ff97
--- /dev/null
+++ b/src/normalise.c
@@ -0,0 +1,721 @@
+/*
+ * normalise.c
+ *
+ * Normalisation 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 <stdlib.h>
+#include <stdio.h>
+#include <gtk/gtk.h>
+#include <math.h>
+#include <string.h>
+
+#include "displaywindow.h"
+#include "main.h"
+#include "data.h"
+#include "elements.h"
+
+static int normalise_window_open = 0;
+GtkWidget *normalise_tree;
+GtkListStore *normalise_list_store;
+enum {
+ NORMALISE_ATOMS_COLUMN_NUMBER,
+ NORMALISE_ATOMS_COLUMN_Z,
+ NORMALISE_ATOMS_COLUMN_ELEMENT,
+ NORMALISE_ATOMS_COLUMN_REF,
+ NORMALISE_ATOMS_COLUMNS,
+};
+
+ReflectionList *normalise_undo_copy = NULL;
+
+static void normalise_undo() {
+ printf("NM: Undoing normalisation.\n");
+ if ( normalise_undo_copy ) {
+ main_substitutereflections(normalise_undo_copy);
+ free(normalise_undo_copy);
+ normalise_undo_copy = NULL;
+ } else {
+ error_report("Nothing to undo...");
+ return;
+ }
+}
+
+/* Returns sin(theta)/lambda = 1/(2d) */
+double resolution(signed int h, signed int k, signed int l,
+ double a, double b, double c, double gamma)
+{
+ static int complained = 0;
+ double one_over_dsq;
+
+ if ( (l != 0) && !complained ) {
+ printf("Warning: you asked for the resolution of a HOLZ "
+ "reflection. The value will be wrong unless alpha "
+ "and beta are 90 degrees.\n");
+ complained = 1;
+ }
+
+ /* This is just the formula for a monoclinic structure with
+ * b and c swapped round. */
+ one_over_dsq = (h*h)/(a*a*sin(gamma)*sin(gamma));
+ one_over_dsq += (k*k)/(b*b*sin(gamma)*sin(gamma));
+ one_over_dsq += (l*l)/(c*c);
+ one_over_dsq -= (2*h*k*cos(gamma))/(a*b*sin(gamma)*sin(gamma));
+ return 0.5 * sqrt(one_over_dsq);
+}
+
+void normalise_execute(ReflectionList *reflections, double level) {
+
+ GtkTreeIter iter;
+ unsigned int ref;
+ gboolean ival;
+ unsigned int i;
+
+ printf("NM: Normalising (%f)\n", level);
+
+ ival = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(normalise_list_store), &iter);
+ if ( !ival ) {
+ error_report("You must define some atoms for the unit cell!");
+ return;
+ }
+
+ if ( normalise_undo_copy ) {
+ free(normalise_undo_copy);
+ }
+ normalise_undo_copy = malloc(sizeof(ReflectionList));
+ memcpy(normalise_undo_copy, reflections, sizeof(ReflectionList));
+
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+
+ double am = reflections->refs[i].amplitude;
+
+ /* Only attempt to normalise reflections which actually exist */
+ if ( am > 0 ) {
+
+ double sfac = 0;
+ double s;
+ double a = data_a() * 10;
+ double b = data_b() * 10;
+ double c = data_c() * 10; /* Change to Angstroms */
+ double gamma = data_gamma();
+ signed int h = reflections->refs[i].h;
+ signed int k = reflections->refs[i].k;
+ signed int l = reflections->refs[i].l;
+
+ /* Determine the value of 's' = sin(theta)/lambda = 1/2d */
+ s = resolution(h, k, l, a, b, c, gamma);
+
+ /* Step through the list of elements, adding up the contribution to this particular reflection from each */
+ ival = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(normalise_list_store), &iter);
+ while ( ival ) {
+ gtk_tree_model_get(GTK_TREE_MODEL(normalise_list_store), &iter, NORMALISE_ATOMS_COLUMN_REF, &ref, -1);
+ ival = gtk_tree_model_iter_next(GTK_TREE_MODEL(normalise_list_store), &iter);
+ sfac = elements[ref].sfac_c;
+ sfac += elements[ref].sfac_a1 * exp(-elements[ref].sfac_b1 * s * s);
+ sfac += elements[ref].sfac_a2 * exp(-elements[ref].sfac_b2 * s * s);
+ sfac += elements[ref].sfac_a3 * exp(-elements[ref].sfac_b3 * s * s);
+ sfac += elements[ref].sfac_a4 * exp(-elements[ref].sfac_b4 * s * s);
+ }
+ sfac = sfac*sfac;
+
+ am = pow((am/sfac), level) * pow(am, 1-level);
+
+ reflections->refs[i].amplitude = am;
+
+ }
+
+ }
+
+ displaywindow_switchview();
+ displaywindow_statusbar("Amplitudes normalised");
+
+}
+
+static gint normalise_window_close(GtkWidget *widget, gint response, GtkWidget *normalise_level) {
+
+ if ( response == GTK_RESPONSE_APPLY ) {
+ main_normalise(gtk_range_get_value(GTK_RANGE(normalise_level)));
+ }
+
+ if ( response == GTK_RESPONSE_REJECT ) {
+ normalise_undo();
+ }
+
+ if ( (response == GTK_RESPONSE_CLOSE) || (response == GTK_RESPONSE_NONE) || (response == GTK_RESPONSE_DELETE_EVENT) ) {
+ normalise_window_open = 0;
+ gtk_widget_destroy(widget);
+ }
+
+ return 0;
+}
+
+static void normalise_atoms_number(GtkListStore *normalise_list_store) {
+
+ GtkTreeIter iter;
+ gboolean ival;
+ unsigned int i = 1;
+
+ ival = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(normalise_list_store), &iter);
+
+ while ( ival ) {
+ gtk_list_store_set(GTK_LIST_STORE(normalise_list_store), &iter, NORMALISE_ATOMS_COLUMN_NUMBER, i, -1);
+ ival = gtk_tree_model_iter_next(GTK_TREE_MODEL(normalise_list_store), &iter);
+ i++;
+ }
+
+}
+
+static void normalise_delete_atom(GtkWidget *widget, GtkWidget *tree_view) {
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(tree_view), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(normalise_list_store), &iter, path);
+ gtk_list_store_remove(GTK_LIST_STORE(normalise_list_store), &iter);
+ normalise_atoms_number(normalise_list_store);
+
+}
+
+static void normalise_add_atom(GtkWidget *widget, GtkWidget *atom_define) {
+
+ GtkTreeIter iter;
+ unsigned int number;
+
+ number = gtk_combo_box_get_active(GTK_COMBO_BOX(atom_define));
+ gtk_list_store_append(normalise_list_store, &iter);
+ printf("Adding element #%i, Z=%i, name=%s\n", number, elements[number].z, elements[number].element_name);
+ gtk_list_store_set(normalise_list_store, &iter, NORMALISE_ATOMS_COLUMN_Z, elements[number].z,
+ NORMALISE_ATOMS_COLUMN_ELEMENT, elements[number].element_name,
+ NORMALISE_ATOMS_COLUMN_REF, number, -1);
+ normalise_atoms_number(normalise_list_store);
+
+}
+
+static void normalise_selection_changed(GtkTreeSelection *selection, GtkWidget *delete_button) {
+
+ gtk_widget_set_sensitive(delete_button, gtk_tree_selection_get_selected(selection, NULL, NULL));
+
+}
+
+static void normalise_dialog_do_list(GtkWidget *vbox) {
+
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ GtkWidget *scrolledwindow;
+ GtkWidget *add_button;
+ GtkWidget *delete_button;
+ GtkWidget *button_box;
+ GtkWidget *atom_define;
+
+ unsigned int i = 0;
+
+ normalise_list_store = gtk_list_store_new(NORMALISE_ATOMS_COLUMNS, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INT);
+
+ normalise_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(normalise_list_store));
+ g_object_unref(G_OBJECT(normalise_list_store));
+
+ renderer = gtk_cell_renderer_text_new();
+
+ column = gtk_tree_view_column_new_with_attributes("#", renderer, "text", NORMALISE_ATOMS_COLUMN_NUMBER, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(normalise_tree), column);
+
+ column = gtk_tree_view_column_new_with_attributes("Z", renderer, "text", NORMALISE_ATOMS_COLUMN_Z, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(normalise_tree), column);
+
+ column = gtk_tree_view_column_new_with_attributes("Element", renderer, "text", NORMALISE_ATOMS_COLUMN_ELEMENT, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(normalise_tree), column);
+
+ scrolledwindow = gtk_scrolled_window_new(gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(normalise_tree)),
+ gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(normalise_tree)));
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(scrolledwindow), GTK_WIDGET(normalise_tree));
+
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(scrolledwindow), TRUE, TRUE, 5);
+
+ button_box = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), button_box, FALSE, FALSE, 5);
+
+ add_button = gtk_button_new_from_stock(GTK_STOCK_ADD);
+ gtk_box_pack_end(GTK_BOX(button_box), add_button, FALSE, FALSE, 5);
+
+ atom_define = gtk_combo_box_new_text();
+ elements_initialise();
+ while ( elements[i].z > 0 ) {
+ gtk_combo_box_append_text(GTK_COMBO_BOX(atom_define), elements[i].element_name);
+ i++;
+ }
+ gtk_combo_box_set_active(GTK_COMBO_BOX(atom_define), 0);
+ gtk_box_pack_end(GTK_BOX(button_box), GTK_WIDGET(atom_define), FALSE, FALSE, 5);
+ g_signal_connect(G_OBJECT(add_button), "clicked", G_CALLBACK(normalise_add_atom), atom_define);
+
+ delete_button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
+ gtk_box_pack_end(GTK_BOX(button_box), delete_button, FALSE, FALSE, 5);
+ g_signal_connect(G_OBJECT(delete_button), "clicked", G_CALLBACK(normalise_delete_atom), normalise_tree);
+
+ g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(normalise_tree))), "changed",
+ G_CALLBACK(normalise_selection_changed), delete_button);
+ gtk_widget_set_sensitive(delete_button,
+ gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(normalise_tree)), NULL, NULL));
+
+}
+
+void normalise_dialog_open() {
+
+ GtkWidget *normalise_window;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *normalise_level;
+ GtkWidget *normalise_level_hbox;
+
+ if ( normalise_window_open ) {
+ return;
+ }
+ normalise_window_open = 1;
+
+ normalise_window = gtk_dialog_new_with_buttons("Sharpen / Normalise", GTK_WINDOW(displaywindow_gtkwindow()),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_UNDO, GTK_RESPONSE_REJECT,
+ GTK_STOCK_EXECUTE, GTK_RESPONSE_APPLY, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+ gtk_window_set_default_size(GTK_WINDOW(normalise_window), -1, 300);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(normalise_window)->vbox), GTK_WIDGET(hbox), TRUE, TRUE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 5);
+
+ normalise_dialog_do_list(vbox);
+
+ normalise_level_hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(normalise_level_hbox), FALSE, FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(normalise_level_hbox), GTK_WIDGET(gtk_label_new("No sharpening")), FALSE, FALSE, 5);
+ normalise_level = gtk_hscale_new_with_range(0, 1, 0.1);
+ gtk_box_pack_start(GTK_BOX(normalise_level_hbox), GTK_WIDGET(normalise_level), TRUE, TRUE, 5);
+ gtk_range_set_value(GTK_RANGE(normalise_level), 1);
+ gtk_scale_set_draw_value(GTK_SCALE(normalise_level), TRUE);
+ gtk_box_pack_start(GTK_BOX(normalise_level_hbox), GTK_WIDGET(gtk_label_new("Normalisation")), FALSE, FALSE, 5);
+
+ g_signal_connect(G_OBJECT(normalise_window), "response", G_CALLBACK(normalise_window_close), normalise_level);
+
+ gtk_widget_show_all(normalise_window);
+
+}
+
+static void normalise_gpwrite(FILE *gnuplot, const char *string) {
+ fwrite(string, strlen(string), 1, gnuplot);
+}
+
+void normalise_wilsonplot(ReflectionList *reflections) {
+
+ FILE *fh;
+ double a = data_a();
+ double b = data_b();
+ double c = data_c();
+ double gamma = data_gamma();
+ unsigned int i;
+ FILE *gnuplot;
+ double sigma = 0;
+ unsigned int n = 0;
+
+ for ( i=1; i<reflections->n_reflections; i++ ) {
+ if ( reflections->refs[i].amplitude > 0 ) {
+ sigma += reflections->refs[i].amplitude * reflections->refs[i].amplitude;
+ n++;
+ }
+ }
+ sigma = sigma / n;
+
+ fh = fopen("synth2d-dethermalise.dat", "w");
+ for ( i=1; i<reflections->n_reflections; i++ ) {
+
+ double am_sq = reflections->refs[i].amplitude * reflections->refs[i].amplitude;
+
+ /* Only include reflections which actually exist */
+ if ( am_sq > 0 ) {
+
+ double s2;
+ signed int h = reflections->refs[i].h;
+ signed int k = reflections->refs[i].k;
+ signed int l = reflections->refs[i].l;
+ s2 = pow(resolution(h, k, l, a, b, c, gamma), 2);
+ fprintf(fh, "%f %f\n", s2, log(am_sq)); /* "log" is actually "ln" */
+
+ }
+ }
+ fclose(fh);
+
+ gnuplot = popen("gnuplot -persist -", "w");
+ if ( !gnuplot ) {
+ error_report("Couldn't invoke gnuplot. Please check your PATH.");
+ return;
+ }
+
+ normalise_gpwrite(gnuplot, "set autoscale\n");
+ normalise_gpwrite(gnuplot, "unset log\n");
+ normalise_gpwrite(gnuplot, "unset label\n");
+ normalise_gpwrite(gnuplot, "set xtic auto\n");
+ normalise_gpwrite(gnuplot, "set ytic auto\n");
+ normalise_gpwrite(gnuplot, "set grid\n");
+ normalise_gpwrite(gnuplot, "set grid\n");
+ normalise_gpwrite(gnuplot, "set bmargin 7cm\n");
+ normalise_gpwrite(gnuplot, "set ylabel 'ln(I)' font \"Helvetica,14\"\n");
+ normalise_gpwrite(gnuplot, "set xlabel 's^2 / nm^(-2)' font \"Helvetica,14\"\n");
+ normalise_gpwrite(gnuplot, "set title 'Wilson Plot' font \"Helvetica,14\"\n");
+ normalise_gpwrite(gnuplot, "plot 'synth2d-dethermalise.dat'\n");
+ normalise_gpwrite(gnuplot, "K=7; B=0.05\n");
+ normalise_gpwrite(gnuplot, "fit log(K)-2*B*x 'synth2d-dethermalise.dat' via K,B\n");
+ normalise_gpwrite(gnuplot, "set label 'ln(K) = %3.5g',log(K),', B = %3.5g nm^2',B at screen 0.1, screen 0.1 font \"Helvetica,14\"\n");
+ normalise_gpwrite(gnuplot, "replot log(K)-2*B*x lw 2 lc 3\n");
+
+ if ( pclose(gnuplot) == -1 ) {
+ error_report("gnuplot returned an error code.");
+ return;
+ }
+
+}
+
+GtkWidget *normalise_k_box;
+GtkWidget *normalise_b_box;
+ReflectionList *normalise_dt_undo_copy = NULL;
+
+static void normalise_dt_undo() {
+ printf("NM: Undoing dethermalisationn.\n");
+ if ( normalise_dt_undo_copy ) {
+ main_substitutereflections(normalise_dt_undo_copy);
+ free(normalise_dt_undo_copy);
+ normalise_dt_undo_copy = NULL;
+ } else {
+ error_report("Nothing to undo...");
+ return;
+ }
+}
+
+void normalise_dethermalise(ReflectionList *reflections, double level)
+{
+ unsigned int i;
+ double kf;
+ double bf;
+ const char *ks;
+ const char *bs;
+ double a = data_a();
+ double b = data_b();
+ double c = data_c();
+ double gamma = data_gamma();
+
+ printf("NM: Wilson Normalising...\n");
+
+ if ( normalise_dt_undo_copy ) {
+ free(normalise_dt_undo_copy);
+ }
+ normalise_dt_undo_copy = malloc(sizeof(ReflectionList));
+ memcpy(normalise_dt_undo_copy, reflections, sizeof(ReflectionList));
+
+ ks = gtk_entry_get_text(GTK_ENTRY(normalise_k_box));
+ bs = gtk_entry_get_text(GTK_ENTRY(normalise_b_box));
+ if ( sscanf(ks, "%lf", &kf) != 1 ) {
+ error_report("Invalid value for 'ln(K)'");
+ return;
+ }
+ if ( sscanf(bs, "%lf", &bf) != 1 ) {
+ error_report("Invalid value for 'B'");
+ return;
+ }
+
+ printf("NM: ln(K)=%f, B=%f => K=%f\n", kf, bf, exp(kf));
+ kf = exp(kf);
+
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+
+ double am_sq = pow(reflections->refs[i].amplitude, 2.0);
+
+ /* Only include reflections which actually exist */
+ if ( am_sq > 0.0 ) {
+
+ double am_e;
+ double am = sqrt(am_sq);
+ signed int h = reflections->refs[i].h;
+ signed int k = reflections->refs[i].k;
+ signed int l = reflections->refs[i].l;
+ double s2 = pow(resolution(h, k, l, a, b, c, gamma), 2.0);
+
+ am_e = sqrt(am_sq/(kf*exp(-2.0*bf*s2)));
+
+ am = pow((am_e), level) * pow(am, 1.0-level);
+ reflections->refs[i].amplitude = am;
+
+ }
+
+ }
+
+ displaywindow_switchview();
+ displaywindow_statusbar("Amplitudes normalised");
+}
+
+static unsigned int normalise_dtw_open = 0;
+
+static gint normalise_dt_window_close(GtkWidget *widget, gint response,
+ GtkWidget *normalise_level)
+{
+
+ if ( response == GTK_RESPONSE_APPLY ) {
+ main_dethermalise(gtk_range_get_value(GTK_RANGE(normalise_level)));
+ }
+
+ if ( response == GTK_RESPONSE_REJECT ) {
+ normalise_dt_undo();
+ }
+
+ if ( (response == GTK_RESPONSE_CLOSE) || (response == GTK_RESPONSE_NONE)
+ || (response == GTK_RESPONSE_DELETE_EVENT) ) {
+ normalise_dtw_open = 0;
+ gtk_widget_destroy(widget);
+ }
+
+ return 0;
+}
+
+void normalise_dethermalise_open() {
+
+ GtkWidget *normalise_dt_window;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *table;
+ GtkWidget *k_label;
+ GtkWidget *b_label;
+ GtkWidget *b_units;
+ GtkWidget *normalise_dt_level;
+ GtkWidget *normalise_dt_level_hbox;
+
+ if ( normalise_dtw_open ) {
+ return;
+ }
+ normalise_dtw_open = 1;
+
+ normalise_dt_window = gtk_dialog_new_with_buttons("Normalise", GTK_WINDOW(displaywindow_gtkwindow()),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_UNDO, GTK_RESPONSE_REJECT,
+ GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, GTK_STOCK_EXECUTE, GTK_RESPONSE_APPLY, NULL);
+ gtk_window_set_default_size(GTK_WINDOW(normalise_dt_window), -1, 100);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(normalise_dt_window)->vbox), GTK_WIDGET(hbox), TRUE, TRUE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 5);
+
+ table = gtk_table_new(3, 2, FALSE);
+ k_label = gtk_label_new("ln(K) = ");
+ gtk_table_attach_defaults(GTK_TABLE(table), k_label, 1, 2, 1, 2);
+ gtk_misc_set_alignment(GTK_MISC(k_label), 1, 0.5);
+ b_label = gtk_label_new("B = ");
+ gtk_table_attach_defaults(GTK_TABLE(table), b_label, 1, 2, 2, 3);
+ gtk_misc_set_alignment(GTK_MISC(b_label), 1, 0.5);
+ normalise_k_box = gtk_entry_new();
+ gtk_table_attach_defaults(GTK_TABLE(table), normalise_k_box, 2, 3, 1, 2);
+ normalise_b_box = gtk_entry_new();
+ gtk_table_attach_defaults(GTK_TABLE(table), normalise_b_box, 2, 3, 2, 3);
+ b_units = gtk_label_new(" nm^-2");
+ gtk_table_attach_defaults(GTK_TABLE(table), b_units, 3, 4, 2, 3);
+ gtk_misc_set_alignment(GTK_MISC(b_units), 0, 0.5);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 5);
+
+ normalise_dt_level_hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(normalise_dt_level_hbox), FALSE, FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(normalise_dt_level_hbox), GTK_WIDGET(gtk_label_new("No sharpening")), FALSE, FALSE, 5);
+ normalise_dt_level = gtk_hscale_new_with_range(0, 1, 0.1);
+ gtk_box_pack_start(GTK_BOX(normalise_dt_level_hbox), GTK_WIDGET(normalise_dt_level), TRUE, TRUE, 5);
+ gtk_range_set_value(GTK_RANGE(normalise_dt_level), 1);
+ gtk_scale_set_draw_value(GTK_SCALE(normalise_dt_level), TRUE);
+ gtk_box_pack_start(GTK_BOX(normalise_dt_level_hbox), GTK_WIDGET(gtk_label_new("Normalisation")), FALSE, FALSE, 5);
+
+ g_signal_connect(G_OBJECT(normalise_dt_window), "response", G_CALLBACK(normalise_dt_window_close), normalise_dt_level);
+
+ gtk_widget_show_all(normalise_dt_window);
+
+}
+
+void normalise_falloffplot(ReflectionList *reflections) {
+
+ FILE *fh;
+ double a = data_a();
+ double b = data_b();
+ double c = data_c();
+ double gamma = data_gamma();
+ unsigned int i;
+ FILE *gnuplot;
+
+ fh = fopen("synth2d-falloff.dat", "w");
+ for ( i=1; i<reflections->n_reflections; i++ ) {
+
+ double am = reflections->refs[i].amplitude;
+
+ /* Only include reflections which actually exist */
+ if ( am > 0 ) {
+
+ signed int h = reflections->refs[i].h;
+ signed int k = reflections->refs[i].k;
+ signed int l = reflections->refs[i].l;
+ double s = resolution(h, k, l, a, b, c, gamma);
+
+ fprintf(fh, "%f %f\n", s, log(am)); /* "log" is actually "ln" */
+
+ }
+ }
+ fclose(fh);
+
+ gnuplot = popen("gnuplot -persist -", "w");
+ if ( !gnuplot ) {
+ error_report("Couldn't invoke gnuplot. Please check your PATH.");
+ return;
+ }
+
+ normalise_gpwrite(gnuplot, "set autoscale\n");
+ normalise_gpwrite(gnuplot, "unset log\n");
+ normalise_gpwrite(gnuplot, "unset label\n");
+ normalise_gpwrite(gnuplot, "set xtic auto\n");
+ normalise_gpwrite(gnuplot, "set ytic auto\n");
+ normalise_gpwrite(gnuplot, "unset grid\n");
+ normalise_gpwrite(gnuplot, "set ylabel 'ln F' font \"Helvetica,14\"\n");
+ normalise_gpwrite(gnuplot, "set xlabel 's / nm^(-1)' font \"Helvetica,14\"\n");
+ normalise_gpwrite(gnuplot, "set title 'Resolution Falloff Plot' font \"Helvetica,14\"\n");
+ normalise_gpwrite(gnuplot, "plot 'synth2d-falloff.dat'\n");
+ normalise_gpwrite(gnuplot, "a=-14; b=10; c=0.01\n");
+ normalise_gpwrite(gnuplot, "fit a+b*exp(-c*x) 'synth2d-falloff.dat' via a,b,c\n");
+ normalise_gpwrite(gnuplot, "set label 'a = %3.5g',a,', b = %3.5g',b, ', c = %3.5g',c at graph 0.4, graph 0.7 font \"Helvetica,14\"\n");
+ normalise_gpwrite(gnuplot, "replot a+b*exp(-c*x) lc 3 lw 2\n");
+
+ if ( pclose(gnuplot) == -1 ) {
+ error_report("gnuplot returned an error code.");
+ return;
+ }
+
+}
+
+typedef struct {
+ GtkWidget *a;
+ GtkWidget *b;
+ GtkWidget *c;
+} NormaliseExpDialog;
+
+void normalise_exponential(ReflectionList *reflections, double a, double b, double c) {
+
+ size_t i;
+ double al = data_a();
+ double bl = data_b();
+ double cl = data_c();
+ double gamma = data_gamma();
+
+ printf("NM: Exponential normalisation, a=%f, b=%f, c=%f\n", a, b, c);
+
+ for ( i=1; i<reflections->n_reflections; i++ ) {
+
+ double am;
+
+ am = reflections->refs[i].amplitude;
+
+ if ( am > 0.0 ) {
+
+ const signed int h = reflections->refs[i].h;
+ const signed int k = reflections->refs[i].k;
+ const signed int l = reflections->refs[i].l;
+ const double s = resolution(h, k, l, al, bl, cl, gamma);
+ const double n = a + b*exp(-c*s);
+
+ reflections->refs[i].amplitude = am / exp(n);
+
+ }
+
+ }
+
+ displaywindow_switchview();
+ displaywindow_statusbar("Amplitudes normalised");
+
+
+}
+
+static gint normalise_exponential_response(GtkWidget *window, gint response, NormaliseExpDialog *dialog) {
+
+ if ( response == GTK_RESPONSE_OK ) {
+
+ const char *as;
+ const char *bs;
+ const char *cs;
+ double a, b, c;
+
+ as = gtk_entry_get_text(GTK_ENTRY(dialog->a));
+ bs = gtk_entry_get_text(GTK_ENTRY(dialog->b));
+ cs = gtk_entry_get_text(GTK_ENTRY(dialog->c));
+
+ if ( sscanf(as, "%lf", &a) != 1 ) {
+ error_report("Invalid value for 'a'");
+ return 0;
+ }
+ if ( sscanf(bs, "%lf", &b) != 1 ) {
+ error_report("Invalid value for 'b'");
+ return 0;
+ }
+ if ( sscanf(cs, "%lf", &c) != 1 ) {
+ error_report("Invalid value for 'c'");
+ return 0;
+ }
+
+ main_normalise_exponential(a, b, c);
+
+ }
+
+ gtk_widget_destroy(window);
+
+ return 0;
+}
+
+void normalise_exponential_open() {
+
+ NormaliseExpDialog *dialog;
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *table;
+ GtkWidget *label;
+
+ dialog = malloc(sizeof(NormaliseExpDialog));
+
+ window = gtk_dialog_new_with_buttons("Exponential Normalisation", GTK_WINDOW(displaywindow_gtkwindow()),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), GTK_WIDGET(hbox), TRUE, TRUE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 5);
+
+ table = gtk_table_new(2, 3, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 5);
+
+ label = gtk_label_new("a = ");
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2);
+ gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+ label = gtk_label_new("b = ");
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 3);
+ gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+ label = gtk_label_new("c = ");
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 3, 4);
+ gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+
+ dialog->a = gtk_entry_new();
+ gtk_table_attach_defaults(GTK_TABLE(table), dialog->a, 2, 3, 1, 2);
+ dialog->b = gtk_entry_new();
+ gtk_table_attach_defaults(GTK_TABLE(table), dialog->b, 2, 3, 2, 3);
+ dialog->c = gtk_entry_new();
+ gtk_table_attach_defaults(GTK_TABLE(table), dialog->c, 2, 3, 3, 4);
+
+ g_signal_connect(G_OBJECT(window), "response", G_CALLBACK(normalise_exponential_response), dialog);
+
+ gtk_widget_show_all(window);
+
+}