aboutsummaryrefslogtreecommitdiff
path: root/src/refine.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/refine.c')
-rw-r--r--src/refine.c359
1 files changed, 359 insertions, 0 deletions
diff --git a/src/refine.c b/src/refine.c
new file mode 100644
index 0000000..314cdc1
--- /dev/null
+++ b/src/refine.c
@@ -0,0 +1,359 @@
+/*
+ * refine.c
+ *
+ * Model Refintement
+ *
+ * (c) 2006-2007 Thomas White <taw27@cam.ac.uk>
+ *
+ * synth2d - Two-Dimensional Crystallographic Fourier Synthesis
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+
+#include "refine.h"
+#include "model.h"
+#include "reflist.h"
+#include "statistics.h"
+#include "displaywindow.h"
+#include "main.h"
+#include "refine-rns.h"
+#include "refine-lmder.h"
+#include "refine-lsq.h"
+#include "refine-cgrad.h"
+#include "refine-brent.h"
+
+static gboolean refine_update_model(gpointer data) {
+
+ AtomicModel *model = data;
+
+ model_notify_update(model);
+
+ model->refine_window->display_callback = 0;
+ g_static_mutex_unlock(&model->refine_window->display_mutex);
+
+ return FALSE;
+
+}
+
+void refine_schedule_update(AtomicModel *model) {
+ g_static_mutex_lock(&model->refine_window->display_mutex);
+ model->refine_window->display_callback = g_idle_add(refine_update_model, model);
+}
+
+static void *refine_work(void *data) {
+
+ RefinementWindow *refinementwindow;
+ AtomicModel *model;
+ ReflectionList *reflections;
+ RefinementSpec spec;
+
+ refinementwindow = data;
+ refinementwindow->running = 1;
+
+ model = refinementwindow->model;
+ reflections = main_reflist();
+ spec = refinementwindow->spec;
+
+ switch ( refinementwindow->type ) {
+ case REFINE_TYPE_NONE : break;
+ case REFINE_TYPE_NEIGHBOURSEARCH : {
+ const char *str;
+ float shiftf;
+ str = gtk_entry_get_text(GTK_ENTRY(refinementwindow->nbsearch_shift));
+ sscanf(str, "%f", &shiftf);
+ refine_neighboursearch(model, reflections, spec, shiftf);
+ break;
+ }
+ case REFINE_TYPE_BRENT : refine_brent(model, reflections, spec); break;
+ case REFINE_TYPE_LMDER : refine_lmder(model, reflections, spec); break;
+ case REFINE_TYPE_LSQ : refine_lsq(model, reflections, spec); break;
+ case REFINE_TYPE_CGRAD : refine_cgrad(model, reflections, spec); break;
+ }
+
+ refinementwindow->running = 0;
+
+ return NULL;
+
+}
+
+/* Refine the model described by model_atoms_list_store against reflections */
+static void refine_go(RefinementWindow *refinementwindow) {
+
+ AtomicModel *model;
+
+ model = model_get_current();
+
+ assert(refinementwindow->run_semaphore == 0);
+ model_lock(model);
+ refinementwindow->run_semaphore = 1;
+ g_static_mutex_init(&refinementwindow->display_mutex);
+ assert(refinementwindow->work_thread == NULL);
+ refinementwindow->display_callback = 0;
+ refinementwindow->work_thread = g_thread_create(refine_work, refinementwindow, TRUE, NULL);
+
+}
+
+static void refine_stop(RefinementWindow *refinementwindow) {
+
+ assert(refinementwindow->run_semaphore == 1);
+ assert(refinementwindow->work_thread != NULL);
+ refinementwindow->run_semaphore = 0;
+ if ( refinementwindow->display_callback ) {
+ g_idle_remove_by_data(refinementwindow);
+ g_static_mutex_unlock(&refinementwindow->display_mutex);
+ }
+ g_thread_join(refinementwindow->work_thread);
+ refinementwindow->work_thread = NULL;
+ model_unlock(refinementwindow->model);
+
+}
+
+static gint refine_button_stop(GtkWidget *widget, RefinementWindow *refinementwindow) {
+
+ gtk_widget_set_sensitive(refinementwindow->go, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->stop, FALSE);
+
+ refine_stop(refinementwindow);
+
+ return 0;
+
+}
+
+static gint refine_button_go(GtkWidget *widget, RefinementWindow *refinementwindow) {
+
+ RefinementSpec spec;
+ RefinementType type;
+
+ spec = REFINE_SPEC_NONE;
+ type = REFINE_TYPE_NONE;
+
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->spec_x)) ) spec = spec | REFINE_SPEC_X;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->spec_y)) ) spec = spec | REFINE_SPEC_Y;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->spec_z)) ) spec = spec | REFINE_SPEC_Z;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->spec_b)) ) spec = spec | REFINE_SPEC_B;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->spec_occ)) ) spec = spec | REFINE_SPEC_OCC;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->spec_thickness)) ) spec = spec | REFINE_SPEC_THICKNESS;
+
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->type_neighboursearch)) ) type = REFINE_TYPE_NEIGHBOURSEARCH;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->type_brent)) ) type = REFINE_TYPE_BRENT;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->type_lmder)) ) type = REFINE_TYPE_LMDER;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->type_lsq)) ) type = REFINE_TYPE_LSQ;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->type_cgrad)) ) type = REFINE_TYPE_CGRAD;
+
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(refinementwindow->target_intensities)) ) spec = spec | REFINE_SPEC_INTENSITIES;
+
+ refinementwindow->spec = spec;
+ refinementwindow->type = type;
+
+ gtk_widget_set_sensitive(refinementwindow->go, FALSE);
+ gtk_widget_set_sensitive(refinementwindow->stop, TRUE);
+
+ refine_go(refinementwindow);
+
+ return 0;
+
+}
+
+static gint refine_response(GtkWidget *refine_window, gint response, RefinementWindow *refinementwindow) {
+
+ if ( refinementwindow->running ) refine_stop(refinementwindow);
+
+ /* Avoid double-freeing if the refinement window already got closed */
+ if ( refinementwindow->model->refine_window ) {
+ gtk_widget_destroy(refine_window);
+ refinementwindow->model->refine_window = NULL;
+ free(refinementwindow);
+ }
+
+ return 0;
+
+}
+
+gint refine_type_neighboursearch(GtkWidget *widget, RefinementWindow *refinementwindow) {
+ gtk_widget_set_sensitive(refinementwindow->spec_x, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_y, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_z, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_b, FALSE);
+ gtk_widget_set_sensitive(refinementwindow->spec_occ, FALSE);
+ gtk_widget_set_sensitive(refinementwindow->spec_thickness, FALSE);
+ return 0;
+}
+
+gint refine_type_brent(GtkWidget *widget, RefinementWindow *refinementwindow) {
+ gtk_widget_set_sensitive(refinementwindow->spec_x, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_y, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_z, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_b, FALSE);
+ gtk_widget_set_sensitive(refinementwindow->spec_occ, FALSE);
+ gtk_widget_set_sensitive(refinementwindow->spec_thickness, FALSE);
+ return 0;
+}
+
+gint refine_type_cgrad(GtkWidget *widget, RefinementWindow *refinementwindow) {
+ gtk_widget_set_sensitive(refinementwindow->spec_x, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_y, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_z, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_b, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_occ, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_thickness, FALSE);
+ return 0;
+}
+
+gint refine_type_lmder(GtkWidget *widget, RefinementWindow *refinementwindow) {
+ gtk_widget_set_sensitive(refinementwindow->spec_x, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_y, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_z, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_b, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_occ, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_thickness, FALSE);
+ return 0;
+}
+
+gint refine_type_lsq(GtkWidget *widget, RefinementWindow *refinementwindow) {
+ gtk_widget_set_sensitive(refinementwindow->spec_x, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_y, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_z, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_b, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_occ, TRUE);
+ gtk_widget_set_sensitive(refinementwindow->spec_thickness, FALSE);
+ return 0;
+}
+
+void refine_open(AtomicModel *model) {
+
+ GtkWidget *refine_window;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *buttons;
+
+ if ( model->refine_window ) return;
+ model->refine_window = malloc(sizeof(RefinementWindow));
+ model->refine_window->model = model;
+ model->refine_window->run_semaphore = 0;
+ model->refine_window->running = 0;
+ model->refine_window->work_thread = NULL;
+ model->refine_window->display_callback = 0;
+
+ refine_window = gtk_dialog_new_with_buttons("Refine Model", GTK_WINDOW(displaywindow_gtkwindow()),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+ g_signal_connect(G_OBJECT(refine_window), "response", G_CALLBACK(refine_response), model->refine_window);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(refine_window)->vbox), GTK_WIDGET(hbox), FALSE, FALSE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 5);
+
+ label = gtk_label_new("");
+ gtk_label_set_markup(GTK_LABEL(label), "<span weight=\"bold\">Refinement Algorithm</span>");
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), FALSE, FALSE, 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), table, TRUE, TRUE, 0);
+
+ model->refine_window->type_neighboursearch = gtk_radio_button_new_with_label(NULL, "Random Neighbour Search");
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(model->refine_window->type_neighboursearch), 1, 3, 2, 3);
+ g_signal_connect(G_OBJECT(model->refine_window->type_neighboursearch), "toggled", G_CALLBACK(refine_type_neighboursearch), model->refine_window);
+
+ label = gtk_label_new("Step Length:");
+ gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(label), 1, 2, 3, 4);
+
+ model->refine_window->nbsearch_shift = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(model->refine_window->nbsearch_shift), 10);
+ gtk_entry_set_width_chars(GTK_ENTRY(model->refine_window->nbsearch_shift), 8);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(model->refine_window->nbsearch_shift), 2, 3, 3, 4);
+ gtk_entry_set_text(GTK_ENTRY(model->refine_window->nbsearch_shift), "0.001");
+
+ model->refine_window->type_brent = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(model->refine_window->type_neighboursearch),
+ "Sequential Brent Minimisation");
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(model->refine_window->type_brent), 1, 3, 4, 5);
+ g_signal_connect(G_OBJECT(model->refine_window->type_brent), "toggled", G_CALLBACK(refine_type_brent), model->refine_window);
+
+ model->refine_window->type_lmder = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(model->refine_window->type_neighboursearch),
+ "GSL Levenberg-Marquardt");
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(model->refine_window->type_lmder), 1, 3, 5, 6);
+ g_signal_connect(G_OBJECT(model->refine_window->type_lmder), "toggled", G_CALLBACK(refine_type_lmder), model->refine_window);
+
+ model->refine_window->type_lsq = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(model->refine_window->type_neighboursearch),
+ "Least Squares");
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(model->refine_window->type_lsq), 1, 3, 6, 7);
+ g_signal_connect(G_OBJECT(model->refine_window->type_lsq), "toggled", G_CALLBACK(refine_type_lsq), model->refine_window);
+
+ model->refine_window->type_cgrad = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(model->refine_window->type_neighboursearch),
+ "Conjugate Gradient");
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(model->refine_window->type_cgrad), 1, 3, 7, 8);
+ g_signal_connect(G_OBJECT(model->refine_window->type_cgrad), "toggled", G_CALLBACK(refine_type_cgrad), model->refine_window);
+
+ label = gtk_label_new("");
+ gtk_label_set_markup(GTK_LABEL(label), "<span weight=\"bold\">Parameters to Refine</span>");
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), FALSE, FALSE, 10);
+
+ hbox = gtk_hbox_new(TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 5);
+ model->refine_window->spec_x = gtk_check_button_new_with_label("x");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(model->refine_window->spec_x), FALSE, TRUE, 0);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(model->refine_window->spec_x), TRUE);
+ model->refine_window->spec_y = gtk_check_button_new_with_label("y");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(model->refine_window->spec_y), FALSE, TRUE, 0);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(model->refine_window->spec_y), TRUE);
+ model->refine_window->spec_z = gtk_check_button_new_with_label("z");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(model->refine_window->spec_z), FALSE, TRUE, 0);
+
+ model->refine_window->spec_b = gtk_check_button_new_with_label("Debye-Waller parameters");
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(model->refine_window->spec_b), FALSE, FALSE, 5);
+
+ hbox = gtk_hbox_new(TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 5);
+ model->refine_window->spec_occ = gtk_check_button_new_with_label("Occupancies");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(model->refine_window->spec_occ), FALSE, FALSE, 0);
+ model->refine_window->spec_thickness = gtk_check_button_new_with_label("Thickness");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(model->refine_window->spec_thickness), FALSE, FALSE, 0);
+
+ label = gtk_label_new("");
+ gtk_label_set_markup(GTK_LABEL(label), "<span weight=\"bold\">Refine Against</span>");
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), FALSE, FALSE, 10);
+
+ hbox = gtk_hbox_new(TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 5);
+
+ model->refine_window->target_amplitudes = gtk_radio_button_new_with_label(NULL, "Amplitudes");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(model->refine_window->target_amplitudes), FALSE, TRUE, 3);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(model->refine_window->target_amplitudes), TRUE);
+ model->refine_window->target_intensities = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(model->refine_window->target_amplitudes),
+ "Intensities");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(model->refine_window->target_intensities), FALSE, TRUE, 3);
+
+ /* Control buttons */
+ buttons = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(vbox), GTK_WIDGET(buttons), FALSE, FALSE, 5);
+ /* Stop */
+ model->refine_window->stop = gtk_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
+ gtk_box_pack_start(GTK_BOX(buttons), GTK_WIDGET(model->refine_window->stop), TRUE, TRUE, 5);
+ g_signal_connect(G_OBJECT(model->refine_window->stop), "clicked", G_CALLBACK(refine_button_stop), model->refine_window);
+ /* Go */
+ model->refine_window->go = gtk_button_new_with_label("Run");
+ gtk_button_set_image(GTK_BUTTON(model->refine_window->go), gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_BUTTON));
+ gtk_box_pack_start(GTK_BOX(buttons), GTK_WIDGET(model->refine_window->go), TRUE, TRUE, 5);
+ g_signal_connect(G_OBJECT(model->refine_window->go), "clicked", G_CALLBACK(refine_button_go), model->refine_window);
+
+ gtk_widget_set_sensitive(model->refine_window->go, TRUE);
+ gtk_widget_set_sensitive(model->refine_window->stop, FALSE);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(model->refine_window->type_lmder), TRUE);
+ gtk_widget_show_all(refine_window);
+
+}
+