diff options
author | Thomas White <taw@physics.org> | 2020-04-30 12:09:31 +0200 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2020-07-29 18:42:57 +0200 |
commit | 6253b9603cf27e91a5f147943f6c32a35fd4d956 (patch) | |
tree | 9e4385073f1d32db87ad876547b994e3a9365c32 /src | |
parent | 1f00febd2ce3492e080afebf8d1c6368a19ae4e7 (diff) |
Basic project persistence
Diffstat (limited to 'src')
-rw-r--r-- | src/crystfel_gui.c | 99 | ||||
-rw-r--r-- | src/crystfel_gui.h | 5 | ||||
-rw-r--r-- | src/gui_project.c | 280 | ||||
-rw-r--r-- | src/gui_project.h | 57 |
4 files changed, 377 insertions, 64 deletions
diff --git a/src/crystfel_gui.c b/src/crystfel_gui.c index 96b09d54..6838dcf8 100644 --- a/src/crystfel_gui.c +++ b/src/crystfel_gui.c @@ -48,6 +48,7 @@ #include "gui_peaksearch.h" #include "gui_index.h" #include "gui_backend_local.h" +#include "gui_project.h" static void show_help(const char *s) @@ -95,16 +96,6 @@ static void update_imageview(struct crystfelproject *proj) } -enum match_type_id - { - MATCH_EVERYTHING, - MATCH_CHEETAH_LCLS_H5, - MATCH_CHEETAH_CXI, - MATCH_CBF, - MATCH_CBFGZ, - }; - - static int match_filename(const char *fn, enum match_type_id mt) { const char *ext = NULL; @@ -131,32 +122,6 @@ static int match_filename(const char *fn, enum match_type_id mt) } -static void add_file_proj(struct crystfelproject *proj, - const char *filename) -{ - if ( proj->n_frames == proj->max_frames ) { - int n_max = proj->max_frames + 1024; - char **n_filenames; - char **n_events; - n_filenames = realloc(proj->filenames, - n_max*sizeof(char *)); - n_events = realloc(proj->events, - n_max*sizeof(char *)); - if ( (n_filenames == NULL) || (n_events == NULL) ) { - ERROR("Failed to allocate new filename\n"); - return; - } - proj->max_frames = n_max; - proj->filenames = n_filenames; - proj->events = n_events; - } - - proj->filenames[proj->n_frames] = strdup(filename); - proj->events[proj->n_frames] = NULL; - proj->n_frames++; -} - - static void add_files(struct crystfelproject *proj, GFile *folder, enum match_type_id type) { @@ -192,8 +157,10 @@ static void add_files(struct crystfelproject *proj, GFile *folder, char *bn = g_file_get_basename(file); if ( match_filename(bn, type) ) { - add_file_proj(proj, - g_file_get_path(file)); + /* FIXME: Expand events if appropriate */ + add_file_to_project(proj, + g_file_get_path(file), + NULL); } } @@ -206,18 +173,6 @@ static void add_files(struct crystfelproject *proj, GFile *folder, } -static enum match_type_id decode_matchtype(const char *type_id) -{ - if ( strcmp(type_id, "everything") == 0 ) return MATCH_EVERYTHING; - if ( strcmp(type_id, "lcls-cheetah-hdf5") == 0 ) return MATCH_CHEETAH_LCLS_H5; - if ( strcmp(type_id, "cheetah-cxi") == 0 ) return MATCH_CHEETAH_CXI; - if ( strcmp(type_id, "cbf") == 0 ) return MATCH_CBF; - if ( strcmp(type_id, "cbfgz") == 0 ) return MATCH_CBFGZ; - ERROR("Unknown match type id '%s'\n", type_id); - return MATCH_EVERYTHING; -} - - static void finddata_response_sig(GtkWidget *dialog, gint resp, struct crystfelproject *proj) { @@ -225,7 +180,6 @@ static void finddata_response_sig(GtkWidget *dialog, gint resp, DataTemplate *dtempl; char *geom_filename; const char *type_id; - int i; if ( (resp==GTK_RESPONSE_DELETE_EVENT) || (resp==GTK_RESPONSE_CANCEL) ) { gtk_widget_destroy(dialog); @@ -238,6 +192,7 @@ static void finddata_response_sig(GtkWidget *dialog, gint resp, if ( geom_filename == NULL ) return; dtempl = data_template_new_from_file(geom_filename); if ( dtempl == NULL ) return; + free(proj->geom_filename); proj->geom_filename = geom_filename; crystfel_image_view_set_datatemplate(CRYSTFEL_IMAGE_VIEW(proj->imageview), dtempl); @@ -246,16 +201,7 @@ static void finddata_response_sig(GtkWidget *dialog, gint resp, if ( top == NULL ) return; /* Totally clean up the old list */ - for ( i=0; i<proj->n_frames; i++ ) { - free(proj->filenames[i]); - free(proj->events[i]); - } - free(proj->filenames); - free(proj->events); - proj->n_frames = 0; - proj->max_frames = 0; - proj->filenames = NULL; - proj->events = NULL; + clear_project_files(proj); type_id = gtk_combo_box_get_active_id(GTK_COMBO_BOX(proj->type_combo)); add_files(proj, top, decode_matchtype(type_id)); @@ -301,6 +247,10 @@ static gint finddata_sig(GtkWidget *widget, struct crystfelproject *proj) gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 2.0); chooser = gtk_file_chooser_button_new("Select a folder", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); + if ( proj->data_top_folder != NULL ) { + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(chooser), + proj->data_top_folder); + } gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(chooser), TRUE, TRUE, 2.0); proj->file_chooser = chooser; @@ -321,7 +271,8 @@ static gint finddata_sig(GtkWidget *widget, struct crystfelproject *proj) "Individual CBF files ('*.cbf')"); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(combo), "cbfgz", "Individual gzipped CBF files ('*.cbf.gz')"); - gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); + gtk_combo_box_set_active(GTK_COMBO_BOX(combo), + proj->data_search_pattern); proj->type_combo = combo; hbox = gtk_hbox_new(FALSE, 0.0); @@ -331,6 +282,10 @@ static gint finddata_sig(GtkWidget *widget, struct crystfelproject *proj) gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label), FALSE, FALSE, 2.0); chooser = gtk_file_chooser_button_new("Select geometry file", GTK_FILE_CHOOSER_ACTION_OPEN); + if ( proj->geom_filename != NULL ) { + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(chooser), + proj->geom_filename); + } gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(chooser), TRUE, TRUE, 2.0); proj->geom_chooser = chooser; @@ -605,7 +560,6 @@ int main(int argc, char *argv[]) proj.file_chooser = NULL; proj.geom_chooser = NULL; proj.geom_filename = NULL; - proj.show_peaks = 0; proj.n_frames = 0; proj.max_frames = 0; proj.filenames = NULL; @@ -613,6 +567,12 @@ int main(int argc, char *argv[]) proj.peak_params = NULL; proj.unitcell_combo = NULL; proj.info_bar = NULL; + proj.backend_private = NULL; + proj.data_top_folder = NULL; + proj.data_search_pattern = 0; + + /* Default parameter values */ + proj.show_peaks = 0; proj.peak_search_params.method = PEAK_ZAEF; proj.peak_search_params.threshold = 800.0; proj.peak_search_params.min_sq_gradient = 100000; @@ -630,7 +590,6 @@ int main(int argc, char *argv[]) proj.peak_search_params.half_pixel_shift = 1; proj.peak_search_params.revalidate = 1; proj.backend = backend_local; - proj.backend_private = NULL; proj.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(proj.window), "CrystFEL"); @@ -734,6 +693,18 @@ int main(int argc, char *argv[]) /* Send messages to report region */ set_log_message_func(add_gui_message, &proj); + /* Load state from disk */ + if ( load_project(&proj) == 0 ) { + DataTemplate *dtempl; + proj.cur_frame = 0; + dtempl = data_template_new_from_file(proj.geom_filename); + if ( dtempl != NULL ) { + crystfel_image_view_set_datatemplate(CRYSTFEL_IMAGE_VIEW(proj.imageview), + dtempl); + } + update_imageview(&proj); + } + /* Initialise backend */ proj.backend->init(&proj); diff --git a/src/crystfel_gui.h b/src/crystfel_gui.h index fc286e5d..c4d27702 100644 --- a/src/crystfel_gui.h +++ b/src/crystfel_gui.h @@ -33,6 +33,8 @@ #include <peaks.h> +#include "gui_project.h" + struct peak_params { enum peak_search_method method; float threshold; /* zaef, pf8 */ @@ -80,6 +82,9 @@ struct crystfelproject { int cur_frame; char *geom_filename; + char *data_top_folder; /* For convenience only. Filenames in + * 'filenames' list should be complete */ + enum match_type_id data_search_pattern; int n_frames; int max_frames; diff --git a/src/gui_project.c b/src/gui_project.c new file mode 100644 index 00000000..4effc603 --- /dev/null +++ b/src/gui_project.c @@ -0,0 +1,280 @@ +/* + * gui_project.c + * + * GUI project persistence + * + * Copyright © 2020 Deutsches Elektronen-Synchrotron DESY, + * a research centre of the Helmholtz Association. + * + * Authors: + * 2020 Thomas White <taw@physics.org> + * + * 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 <http://www.gnu.org/licenses/>. + * + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "crystfel_gui.h" +#include "gui_backend_local.h" +#include "gui_project.h" + +static double parse_float(const char *val) +{ + float v; + + if (sscanf(val, "%f", &v) != 1) { + ERROR("Invalid float value '%s'\n", val); + return NAN; + } + + return v; +} + + +static int parse_int(const char *val) +{ + int v; + + if (sscanf(val, "%i", &v) != 1) { + ERROR("Invalid int value '%s'\n", val); + return 0; + } + + return v; +} + + +static struct crystfel_backend *parse_backend(const char *val) +{ + if ( strcmp(val, "local") == 0 ) { + return backend_local; + } + + ERROR("Invalid backend '%s'\n", val); + return NULL; +} + + +enum match_type_id decode_matchtype(const char *type_id) +{ + if ( strcmp(type_id, "everything") == 0 ) return MATCH_EVERYTHING; + if ( strcmp(type_id, "lcls-cheetah-hdf5") == 0 ) return MATCH_CHEETAH_LCLS_H5; + if ( strcmp(type_id, "cheetah-cxi") == 0 ) return MATCH_CHEETAH_CXI; + if ( strcmp(type_id, "cbf") == 0 ) return MATCH_CBF; + if ( strcmp(type_id, "cbfgz") == 0 ) return MATCH_CBFGZ; + ERROR("Unknown match type id '%s'\n", type_id); + return MATCH_EVERYTHING; +} + + +static void handle_var(const char *key, const char *val, + struct crystfelproject *proj) +{ + if ( strcmp(key, "peak_search_params.method") == 0 ) { + proj->peak_search_params.method = parse_peaksearch(val); + if ( proj->peak_search_params.method == PEAK_ERROR ) { + ERROR("Unrecognised peak search method '%s'\n", + val); + } + } + + if ( strcmp(key, "peak_search_params.threshold") == 0 ) { + proj->peak_search_params.threshold = parse_float(val); + } + + if ( strcmp(key, "peak_search_params.min_sq_gradient") == 0 ) { + proj->peak_search_params.min_sq_gradient = parse_float(val); + } + + if ( strcmp(key, "peak_search_params.min_snr") == 0 ) { + proj->peak_search_params.min_snr = parse_float(val); + } + + if ( strcmp(key, "peak_search_params.local_bg_radius") == 0 ) { + proj->peak_search_params.local_bg_radius = parse_int(val); + } + + if ( strcmp(key, "peak_search_params.min_res") == 0 ) { + proj->peak_search_params.min_res = parse_int(val); + } + + if ( strcmp(key, "peak_search_params.min_sig") == 0 ) { + proj->peak_search_params.min_sig = parse_float(val); + } + + if ( strcmp(key, "peak_search_params.max_res") == 0 ) { + proj->peak_search_params.max_res = parse_int(val); + } + + if ( strcmp(key, "peak_search_params.min_pix_count") == 0 ) { + proj->peak_search_params.min_pix_count = parse_int(val); + } + + if ( strcmp(key, "peak_search_params.max_pix_count") == 0 ) { + proj->peak_search_params.max_pix_count = parse_int(val); + } + + if ( strcmp(key, "peak_search_params.min_peak_over_neighbour") == 0 ) { + proj->peak_search_params.min_peak_over_neighbour = parse_float(val); + } + + if ( strcmp(key, "peak_search_params.pk_inn") == 0 ) { + proj->peak_search_params.pk_inn = parse_float(val); + } + + if ( strcmp(key, "peak_search_params.pk_mid") == 0 ) { + proj->peak_search_params.pk_mid = parse_float(val); + } + + if ( strcmp(key, "peak_search_params.pk_out") == 0 ) { + proj->peak_search_params.pk_out = parse_float(val); + } + + if ( strcmp(key, "peak_search_params.half_pixel_shift") == 0 ) { + proj->peak_search_params.half_pixel_shift = parse_int(val); + } + + if ( strcmp(key, "peak_search_params.revalidate") == 0 ) { + proj->peak_search_params.revalidate = parse_int(val); + } + + if ( strcmp(key, "backend") == 0 ) { + proj->backend = parse_backend(val); + } + + if ( strcmp(key, "geom") == 0 ) { + proj->geom_filename = strdup(val); + } + + if ( strcmp(key, "data_folder") == 0 ) { + proj->data_top_folder = strdup(val); + } + + if ( strcmp(key, "search_pattern") == 0 ) { + proj->data_search_pattern = decode_matchtype(val); + } +} + + +void clear_project_files(struct crystfelproject *proj) +{ + int i; + + for ( i=0; i<proj->n_frames; i++ ) { + free(proj->filenames[i]); + free(proj->events[i]); + } + free(proj->filenames); + free(proj->events); + proj->n_frames = 0; + proj->max_frames = 0; + proj->filenames = NULL; + proj->events = NULL; +} + + +void add_file_to_project(struct crystfelproject *proj, + const char *filename, const char *event) +{ + if ( proj->n_frames == proj->max_frames ) { + int n_max = proj->max_frames + 1024; + char **n_filenames; + char **n_events; + n_filenames = realloc(proj->filenames, + n_max*sizeof(char *)); + n_events = realloc(proj->events, + n_max*sizeof(char *)); + if ( (n_filenames == NULL) || (n_events == NULL) ) { + ERROR("Failed to allocate new filename\n"); + return; + } + proj->max_frames = n_max; + proj->filenames = n_filenames; + proj->events = n_events; + } + + proj->filenames[proj->n_frames] = strdup(filename); + proj->events[proj->n_frames] = safe_strdup(event); + proj->n_frames++; +} + + +int load_project(struct crystfelproject *proj) +{ + FILE *fh; + char line[1024]; + char *rval; + int image_list_mode = 0; + + fh = fopen("crystfel.project", "r"); + if ( fh == NULL ) return 1; + + do { + + char *sp; + + rval = fgets(line, 1023, fh); + if ( rval == NULL ) break; + + chomp(line); + + if ( line[0] == '\0' ) continue; + + if ( image_list_mode ) { + char *ev = NULL; + size_t n = strlen(line)-1; + for ( ; n>0; n-- ) { + if ( line[n] == ' ' ) { + line[n] = '\0'; + ev = &line[n+1]; + break; + } + } + add_file_to_project(proj, line, ev); + continue; + } + + if ( strcmp(line, "-----") == 0 ) { + image_list_mode = 1; + continue; + } + + sp = strchr(line, ' '); + if ( sp == NULL ) { + ERROR("Unrecognised line in crystfel.project " + "file: '%s'\n", line); + continue; + } + + sp[0] = '\0'; + + handle_var(line, sp+1, proj); + + } while ( rval != NULL ); + + fclose(fh); + + return 0; +} diff --git a/src/gui_project.h b/src/gui_project.h new file mode 100644 index 00000000..9fdb9a34 --- /dev/null +++ b/src/gui_project.h @@ -0,0 +1,57 @@ +/* + * gui_project.h + * + * GUI project persistence + * + * Copyright © 2020 Deutsches Elektronen-Synchrotron DESY, + * a research centre of the Helmholtz Association. + * + * Authors: + * 2020 Thomas White <taw@physics.org> + * + * 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 <http://www.gnu.org/licenses/>. + * + */ + +#ifndef GUI_PROJECT_H +#define GUI_PROJECT_H + +enum match_type_id +{ + MATCH_EVERYTHING, + MATCH_CHEETAH_LCLS_H5, + MATCH_CHEETAH_CXI, + MATCH_CBF, + MATCH_CBFGZ, +}; + +struct crystfelproject; + + +#include "crystfel_gui.h" + + +extern enum match_type_id decode_matchtype(const char *type_id); + +extern int load_project(struct crystfelproject *proj); + +extern void add_file_to_project(struct crystfelproject *proj, + const char *filename, + const char *event); + +extern void clear_project_files(struct crystfelproject *proj); + +#endif |