aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2020-04-30 12:09:31 +0200
committerThomas White <taw@physics.org>2020-07-29 18:42:57 +0200
commit6253b9603cf27e91a5f147943f6c32a35fd4d956 (patch)
tree9e4385073f1d32db87ad876547b994e3a9365c32
parent1f00febd2ce3492e080afebf8d1c6368a19ae4e7 (diff)
Basic project persistence
-rw-r--r--CMakeLists.txt3
-rw-r--r--src/crystfel_gui.c99
-rw-r--r--src/crystfel_gui.h5
-rw-r--r--src/gui_project.c280
-rw-r--r--src/gui_project.h57
5 files changed, 379 insertions, 65 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0ddee846..5a4b51d5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -385,7 +385,8 @@ list(APPEND CRYSTFEL_EXECUTABLES cell_tool)
if (GTK_FOUND)
set(CRYSTFEL_GUI_SOURCES src/crystfel_gui.c src/crystfelimageview.c
- src/gui_peaksearch.c src/gui_index.c src/gui_backend_local.c)
+ src/gui_peaksearch.c src/gui_index.c src/gui_backend_local.c
+ src/gui_project.c)
add_executable(crystfel ${CRYSTFEL_GUI_SOURCES})
target_include_directories(crystfel PRIVATE ${COMMON_INCLUDES} ${GTK_INCLUDE_DIRS})
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