/* * gui_export.c * * Export data from CrystFEL GUI * * Copyright © 2021 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * * Authors: * 2021 Thomas White * * This file is part of CrystFEL. * * CrystFEL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CrystFEL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CrystFEL. If not, see . * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "version.h" #include "gui_project.h" #include "crystfel_gui.h" #include "gtk-util-routines.h" struct export_window { struct crystfelproject *proj; GtkWidget *window; GtkWidget *cell_chooser; GtkWidget *limit_res; GtkWidget *min_res; GtkWidget *max_res; GtkWidget *dataset; GtkWidget *format; }; static int export_to_xds(struct gui_merge_result *result, const char *filename, UnitCell *cell, double min_res, double max_res) { RefList *reflist; char *sym_str; SymOpList *sym; int r; reflist = read_reflections_2(result->hkl, &sym_str); if ( reflist == NULL ) return 1; if ( sym_str == NULL ) return 1; sym = get_pointgroup(sym_str); if ( sym == NULL ) return 1; r = write_to_xds(reflist, sym, cell, min_res, max_res, filename); free_symoplist(sym); free(sym_str); reflist_free(reflist); return r; } static int export_to_mtz(struct gui_merge_result *result, const char *filename, UnitCell *cell, double min_res, double max_res, int bij) { RefList *reflist; char *sym_str; SymOpList *sym; int r; char *crystal_name; char *dir_name; char *dir_basename; reflist = read_reflections_2(result->hkl, &sym_str); if ( reflist == NULL ) return 1; if ( sym_str == NULL ) return 1; sym = get_pointgroup(sym_str); if ( sym == NULL ) return 1; dir_name = getcwd(NULL, 0); dir_basename = safe_basename(dir_name); crystal_name = result->indexing_result_name; if ( crystal_name == NULL ) { crystal_name = "unknown"; } r = write_to_mtz(reflist, sym, cell, min_res, max_res, filename, result->name, crystal_name, dir_basename, bij); free(dir_name); free(dir_basename); free_symoplist(sym); free(sym_str); reflist_free(reflist); return r; } static void reminder(GtkWidget *window, const char *message) { GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, NULL); gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), message); gtk_window_set_title(GTK_WINDOW(dialog), "Reminder"); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } static int export_data(struct export_window *win, char *filename) { gchar *cell_filename; const char *dataset; const char *format; struct gui_merge_result *result; UnitCell *cell; int r = 0; double min_res = 0; double max_res = +INFINITY; dataset = gtk_combo_box_get_active_id(GTK_COMBO_BOX(win->dataset)); if ( dataset == NULL ) { error_box(win->proj, "Please select the dataset to export.\n"); return 1; } format = gtk_combo_box_get_active_id(GTK_COMBO_BOX(win->format)); if ( format == NULL ) { error_box(win->proj, "Please select the data format to use.\n"); return 1; } cell_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(win->cell_chooser)); if ( cell_filename == NULL ) { error_box(win->proj, "Please choose the unit cell file.\n"); return 1; } cell = load_cell_from_file(cell_filename); if ( cell == NULL ) { ERROR("Failed to load unit cell file %s\n", cell_filename); return 1; } if ( get_bool(win->limit_res) ) { min_res = 1e10/get_float(win->min_res); max_res = 1e10/get_float(win->max_res); } result = find_merge_result_by_name(win->proj, dataset); if ( result == NULL ) { ERROR("Couldn't find merged dataset '%s'\n", dataset); return 1; } STATUS("Exporting dataset %s to %s, in format %s, using unit cell %s," "%f to %f m^-1\n", dataset, filename, format, cell_filename, min_res, max_res); if ( strcmp(format, "mtz") == 0 ) { r = export_to_mtz(result, filename, cell, min_res, max_res, 0); reminder(win->window, "CrystFEL does not know the space " "group of your structure.\n\n" "The space group written into the MTZ header is just " "a representation of the processing done within " "CrystFEL.\n\n" "You may need to change the space group in the MTZ " "header, to allow structure solution programs to find " "the correct space group.\n\n" "" "Click here for some background information"); } else if ( strcmp(format, "mtz-bij") == 0 ) { r = export_to_mtz(result, filename, cell, min_res, max_res, 1); reminder(win->window, "CrystFEL does not know the space " "group of your structure.\n\n" "The space group written into the MTZ header is just " "a representation of the processing done within " "CrystFEL.\n\n" "You may need to change the space group in the MTZ " "header, to allow structure solution programs to find " "the correct space group.\n\n" "" "Click here for some background information"); } else if ( strcmp(format, "xds") == 0 ) { r = export_to_xds(result, filename, cell, min_res, max_res); reminder(win->window, "CrystFEL does not know the space " "group of your structure.\n\n" "The space group written into the XDS file " "(header SPACE_GROUP_NUMBER=...) is just a " "representation of the processing done within " "CrystFEL.\n\n" "You may need to change the space group in the XDS " "header, to allow structure solution programs to find " "the correct space group.\n\n" "" "Click here for some background information"); } else { ERROR("Unrecognised export format '%s'\n", format); return 1; } if ( r ) { ERROR("Export failed\n"); } g_free(cell_filename); return 0; } static void export_response_sig(GtkWidget *dialog, gint resp, struct export_window *win) { int r = 0; if ( resp == GTK_RESPONSE_ACCEPT ) { gchar *filename; filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); r = export_data(win, filename); g_free(filename); } if ( !r ) gtk_widget_destroy(dialog); } static void format_changed_sig(GtkWidget *format, struct export_window *win) { const char *new_format; gchar *cur_name; new_format = gtk_combo_box_get_active_id(GTK_COMBO_BOX(format)); cur_name = gtk_file_chooser_get_current_name(GTK_FILE_CHOOSER(win->window)); strip_extension(cur_name); if ( cur_name[0] == '\0' ) { if ( strncmp(new_format, "mtz", 3) == 0 ) { gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(win->window), "data_from_crystfel.mtz"); } else if ( strcmp(new_format, "xds") == 0 ) { gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(win->window), "XDS_ASCII.HKL"); } } else { gchar *new_name = malloc(strlen(cur_name)+5); if ( new_name != NULL ) { strcpy(new_name, cur_name); if ( strncmp(new_format, "mtz", 3) == 0 ) { strcat(new_name, ".mtz"); } else if ( strcmp(new_format, "xds") == 0 ) { strcat(new_name, ".HKL"); } gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(win->window), new_name); free(new_name); } } g_free(cur_name); } gint export_sig(GtkWidget *widget, struct crystfelproject *proj) { GtkWidget *dialog; GtkWidget *vbox; GtkWidget *hbox; GtkWidget *label; char tmp[64]; struct export_window *win; int i; win = malloc(sizeof(struct export_window)); if ( win == NULL ) return 0; win->proj = proj; dialog = gtk_file_chooser_dialog_new("Export data", GTK_WINDOW(proj->window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); win->window = dialog; g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(export_response_sig), win); vbox = gtk_vbox_new(FALSE, 0.0); gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), GTK_WIDGET(vbox)); gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); hbox = gtk_hbox_new(FALSE, 0.0); gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 4.0); label = gtk_label_new("Results to export:"); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 4.0); win->dataset = gtk_combo_box_text_new(); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(win->dataset), FALSE, FALSE, 4.0); for ( i=0; in_merge_results; i++ ) { gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(win->dataset), proj->merge_results[i].name, proj->merge_results[i].name); } label = gtk_label_new("Format"); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 4.0); win->format = gtk_combo_box_text_new(); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(win->format), FALSE, FALSE, 4.0); if ( libcrystfel_can_write_mtz() ) { gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(win->format), "mtz", "MTZ"); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(win->format), "mtz-bij", "MTZ, Bijvoet pairs together"); } gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(win->format), "xds", "XDS ASCII"); gtk_combo_box_set_active(GTK_COMBO_BOX(win->format), 0); g_signal_connect(G_OBJECT(win->format), "changed", G_CALLBACK(format_changed_sig), win); format_changed_sig(win->format, win); label = gtk_label_new("Unit cell file:"); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 4.0); win->cell_chooser = gtk_file_chooser_button_new("Unit cell file", GTK_FILE_CHOOSER_ACTION_OPEN); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(win->cell_chooser), TRUE); /* Use the "FoM" cell file because there should only be one * point of truth for the "final" cell parameters. Eventually, I hope * to determine this automatically. */ if ( proj->fom_cell_filename != NULL ) { gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(win->cell_chooser), proj->fom_cell_filename); } gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(win->cell_chooser), FALSE, FALSE, 4.0); hbox = gtk_hbox_new(FALSE, 0.0); gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 4.0); win->limit_res = gtk_check_button_new_with_label("Restrict resolution range:"); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(win->limit_res), FALSE, FALSE, 4.0); win->min_res = gtk_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(win->min_res), 4); snprintf(tmp, 64, "%.2f", proj->export_res_min); gtk_entry_set_text(GTK_ENTRY(win->min_res), tmp); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(win->min_res), FALSE, FALSE, 4.0); label = gtk_label_new("to"); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 4.0); win->max_res = gtk_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(win->max_res), 4); snprintf(tmp, 64, "%.2f", proj->export_res_max); gtk_entry_set_text(GTK_ENTRY(win->max_res), tmp); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(win->max_res), FALSE, FALSE, 4.0); label = gtk_label_new("Å"); gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 4.0); g_signal_connect(G_OBJECT(win->limit_res), "toggled", G_CALLBACK(i_maybe_disable), win->min_res); g_signal_connect(G_OBJECT(win->limit_res), "toggled", G_CALLBACK(i_maybe_disable), win->max_res); gtk_widget_set_sensitive(win->min_res, FALSE); gtk_widget_set_sensitive(win->max_res, FALSE); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE); gtk_widget_show_all(dialog); return FALSE; }