/* * refine.c * * Model Refintement * * (c) 2006-2007 Thomas White * * synth2d - Two-Dimensional Crystallographic Fourier Synthesis * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #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), "Refinement Algorithm"); 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), "Parameters to Refine"); 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), "Refine Against"); 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); }