aboutsummaryrefslogtreecommitdiff
path: root/libcrystfel/src/indexers
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2021-03-19 14:19:24 +0100
committerThomas White <taw@physics.org>2021-03-19 14:19:24 +0100
commit6a4d681da9ac355b3b8d73861a6dcb5bc42ef2ba (patch)
treeb7978720281c9c02db4529e79f7c92b1009e00c4 /libcrystfel/src/indexers
parentefb6ec7b3899a90f8e1a977895e23042c35040f7 (diff)
parent99c7fa94b9aecf7b22d57410edb5a8665a5f10f7 (diff)
Merge branch 'tom/fromfile'
Diffstat (limited to 'libcrystfel/src/indexers')
-rw-r--r--libcrystfel/src/indexers/fromfile.c411
-rw-r--r--libcrystfel/src/indexers/fromfile.h43
2 files changed, 454 insertions, 0 deletions
diff --git a/libcrystfel/src/indexers/fromfile.c b/libcrystfel/src/indexers/fromfile.c
new file mode 100644
index 00000000..782934d7
--- /dev/null
+++ b/libcrystfel/src/indexers/fromfile.c
@@ -0,0 +1,411 @@
+/*
+ * fromfile.c
+ *
+ * Perform indexing from solution file
+ *
+ * Copyright © 2021 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2020 Pascal Hogan-Lamarre <pascal.hogan.lamarre@mail.utoronto.ca>
+ * 2021 Thomas White <thomas.white@desy.de>
+ *
+ * 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/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+#include <fenv.h>
+#include <unistd.h>
+#include <argp.h>
+
+#include "image.h"
+#include "uthash.h"
+
+/** \file fromfile.h */
+
+struct fromfile_options
+{
+ char *filename;
+};
+
+#define MAX_KEY_LEN (256)
+#define MAX_CRYSTALS (16)
+
+struct fromfile_key
+{
+ char filename[MAX_KEY_LEN];
+ char event[MAX_KEY_LEN];
+};
+
+
+struct fromfile_entry
+{
+ struct fromfile_key key_field;
+ Crystal *crystals[MAX_CRYSTALS];
+ int n_crystals;
+ UT_hash_handle hh;
+};
+
+
+struct fromfile_private
+{
+ struct fromfile_entry *sol_hash;
+};
+
+
+static int make_key(struct fromfile_key *key,
+ const char *filename, const char *ev)
+{
+ if ( (strlen(filename) > MAX_KEY_LEN) || (strlen(ev) > MAX_KEY_LEN) ) {
+ ERROR("Filename/event too long: %s %s\n", filename, ev);
+ return 1;
+ }
+
+ /* The entire structure is used as a key, not just the pre-terminator
+ * parts of the strings. Therefore it must be initialised to zero */
+ memset(key, 0, sizeof(struct fromfile_key));
+
+ strcpy(key->filename, filename);
+ strcpy(key->event, ev);
+
+ return 0;
+}
+
+
+struct fromfile_entry *add_unique(struct fromfile_entry **phead,
+ struct fromfile_key key)
+{
+ struct fromfile_entry *p;
+ struct fromfile_entry *head = *phead;
+
+ HASH_FIND(hh, head, &key, sizeof(struct fromfile_key), p);
+ if ( p == NULL ) {
+
+ struct fromfile_entry *item;
+
+ item = malloc(sizeof(struct fromfile_entry));
+ if ( item == NULL ) return NULL;
+
+ item->n_crystals = 0;
+ item->key_field = key;
+
+ HASH_ADD(hh, head, key_field, sizeof(struct fromfile_key), item);
+ *phead = head;
+ return item;
+
+ } else {
+ return p;
+ }
+}
+
+
+static int set_ua(UnitCell *cell, const char *ltsym)
+{
+ if ( strlen(ltsym) != 3 ) return 1;
+ cell_set_unique_axis(cell, ltsym[2]);
+ return 0;
+}
+
+
+static int set_lattice(UnitCell *cell, const char *ltsym)
+{
+ if ( (strlen(ltsym) != 2) && (strlen(ltsym) != 3) ) return 1;
+
+ switch ( ltsym[1] ) {
+ case 'P':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'I':
+ case 'F':
+ case 'R':
+ case 'H':
+ break;
+
+ default:
+ return 1;
+ }
+ cell_set_centering(cell, ltsym[1]);
+
+ switch ( ltsym[0] ) {
+
+ case 'a' :
+ cell_set_lattice_type(cell, L_TRICLINIC);
+ break;
+
+ case 'm' :
+ cell_set_lattice_type(cell, L_MONOCLINIC);
+ return set_ua(cell, ltsym);
+
+ case 'o' :
+ cell_set_lattice_type(cell, L_ORTHORHOMBIC);
+ break;
+
+ case 't' :
+ cell_set_lattice_type(cell, L_TETRAGONAL);
+ return set_ua(cell, ltsym);
+
+ case 'c' :
+ cell_set_lattice_type(cell, L_CUBIC);
+ break;
+
+ case 'r' :
+ cell_set_lattice_type(cell, L_RHOMBOHEDRAL);
+ break;
+
+ case 'h' :
+ cell_set_lattice_type(cell, L_HEXAGONAL);
+ return set_ua(cell, ltsym);
+
+ default :
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void *fromfile_prepare(IndexingMethod *indm, struct fromfile_options *opts)
+{
+ FILE *fh;
+ struct fromfile_private *dp;
+
+ if ( opts->filename == NULL ) {
+ ERROR("Please try again with --fromfile-input-file\n");
+ return NULL;
+ }
+
+ /* If filename is not absolute, jump out of working directory */
+ if ( opts->filename[0] == '/' ) {
+ fh = fopen(opts->filename, "r");
+ } else {
+ char *prefixed_fn = malloc(4+strlen(opts->filename));
+ if ( prefixed_fn == NULL ) return NULL;
+ strcpy(prefixed_fn, "../");
+ strcat(prefixed_fn, opts->filename);
+ fh = fopen(prefixed_fn, "r");
+ free(prefixed_fn);
+ }
+
+ if ( fh == NULL ) {
+ ERROR("Couldn't find solution file '%s'\n", opts->filename);
+ return NULL;
+ }
+
+ dp = malloc(sizeof(struct fromfile_private));
+ if ( dp == NULL ) return NULL;
+
+ dp->sol_hash = NULL;
+
+ /* Read indexing solutions */
+ do {
+
+ char *rval;
+ char line[1024];
+ int i, n;
+ char **bits;
+ float vals[11];
+ struct fromfile_key key;
+ Crystal *cr;
+ UnitCell *cell;
+ struct fromfile_entry *item = NULL;
+
+ rval = fgets(line, 1023, fh);
+ if ( rval == NULL ) break;
+
+ /* FIXME: Replace this with something that can handle quoted
+ * filenames with possible spaces */
+ chomp(line);
+ notrail(line);
+ n = assplode(line, " \t,", &bits, ASSPLODE_NONE);
+ if ( n < 14 ) {
+ ERROR("Badly formatted line '%s'\n", line);
+ return NULL;
+ }
+
+ /* filename, event, asx, asy, asz, bsx, bsy, bsz, csx, csy, csz,
+ * det_shift_x, det_shift_y, latticetype+centering */
+ for ( i=2; i<13; i++ ) {
+ if (sscanf(bits[i], "%f", &vals[i-2]) != 1)
+ {
+ ERROR("Invalid value for number %i\n", i);
+ return NULL;
+ }
+ }
+
+ if ( make_key(&key, bits[0], bits[1]) ) {
+ ERROR("Failed to make key for %s %s\n",
+ bits[0], bits[1]);
+ continue;
+ }
+
+ item = add_unique(&dp->sol_hash, key);
+ if ( item == NULL ) {
+ ERROR("Failed to add/find entry for %s %s\n",
+ bits[0], bits[1]);
+ continue;
+ }
+
+ if ( item->n_crystals == MAX_CRYSTALS ) {
+
+ ERROR("Too many crystals for %s %s\n", bits[0], bits[1]);
+
+ } else {
+
+ cr = crystal_new();
+
+ /* mm -> m */
+ crystal_set_det_shift(cr, vals[9]*1e-3, vals[10]*1e-3);
+
+ cell = cell_new();
+ cell_set_reciprocal(cell, vals[0]*1e9, vals[1]*1e9, vals[2]*1e9,
+ vals[3]*1e9, vals[4]*1e9, vals[5]*1e9,
+ vals[6]*1e9, vals[7]*1e9, vals[8]*1e9);
+ if ( set_lattice(cell, bits[13]) ) {
+ ERROR("Invalid lattice type '%s'\n", bits[13]);
+ } else {
+ crystal_set_cell(cr, cell);
+ item->crystals[item->n_crystals++] = cr;
+ }
+
+ }
+
+ for ( i=0; i<n; i++ ) free(bits[i]);
+ free(bits);
+
+ } while ( 1 );
+
+ fclose(fh);
+
+ STATUS("Read %i crystals from %s\n",
+ HASH_CNT(hh, dp->sol_hash), opts->filename);
+
+ return dp;
+}
+
+
+int fromfile_index(struct image *image, void *mpriv)
+{
+ struct fromfile_entry *p;
+ struct fromfile_private *dp = mpriv;
+ struct fromfile_key key;
+ int i;
+
+ make_key(&key, image->filename, image->ev);
+
+ HASH_FIND(hh, dp->sol_hash, &key, sizeof(struct fromfile_key), p);
+ if ( p == NULL ) {
+ STATUS("WARNING: No solution for %s %s\n",
+ image->filename, image->ev);
+ return 0;
+ }
+
+ for ( i=0; i<p->n_crystals; i++ ) {
+ Crystal *cr;
+ cr = crystal_copy_deep(p->crystals[i]);
+ image_add_crystal(image, cr);
+ }
+
+ return p->n_crystals;
+}
+
+
+void fromfile_cleanup(void *mpriv)
+{
+ struct fromfile_private *dp = mpriv;
+ struct fromfile_entry *item, *tmp;
+
+ HASH_ITER(hh, dp->sol_hash, item, tmp) {
+ int i;
+ HASH_DEL(dp->sol_hash, item);
+ for ( i=0; i<item->n_crystals; i++ ) {
+ Crystal *cr = item->crystals[i];
+ cell_free(crystal_get_cell(cr));
+ crystal_free(cr);
+ }
+ }
+
+ free(dp);
+}
+
+
+static void fromfile_show_help()
+{
+ printf("Parameters for 'fromfile' indexing:\n"
+" --fromfile-input-file\n"
+" Filename of indexing solution file\n"
+);
+}
+
+
+int fromfile_default_options(FromFileOptions **opts_ptr)
+{
+ FromFileOptions *opts;
+ opts = malloc(sizeof(struct fromfile_options));
+ if ( opts == NULL ) return ENOMEM;
+ opts->filename = NULL;
+ *opts_ptr = opts;
+ return 0;
+}
+
+
+static error_t fromfile_parse_arg(int key, char *arg,
+ struct argp_state *state)
+{
+ struct fromfile_options **opts_ptr = state->input;
+ int r;
+
+ switch ( key ) {
+
+ case ARGP_KEY_INIT :
+ r = fromfile_default_options(opts_ptr);
+ if ( r ) return r;
+ break;
+
+ case 1 :
+ fromfile_show_help();
+ return EINVAL;
+
+ case 2 :
+ (*opts_ptr)->filename = strdup(arg);
+ break;
+
+ default :
+ return ARGP_ERR_UNKNOWN;
+
+ }
+
+ return 0;
+}
+
+
+static struct argp_option fromfile_options[] = {
+
+ {"help-fromfile", 1, NULL, OPTION_NO_USAGE,
+ "Show options for 'from file' indexing", 99},
+
+ {"fromfile-input-file", 2, "filename", OPTION_HIDDEN, NULL},
+ {0}
+};
+
+
+struct argp fromfile_argp = { fromfile_options, fromfile_parse_arg,
+ NULL, NULL, NULL, NULL, NULL };
diff --git a/libcrystfel/src/indexers/fromfile.h b/libcrystfel/src/indexers/fromfile.h
new file mode 100644
index 00000000..5f1d24d9
--- /dev/null
+++ b/libcrystfel/src/indexers/fromfile.h
@@ -0,0 +1,43 @@
+/*
+ * fromfile.h
+ *
+ * Perform indexing from solution file
+ *
+ * Copyright © 2021 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2020 Pascal Hogan-Lamarre <pascal.hogan.lamarre@mail.utoronto.ca>
+ * 2021 Thomas White <thomas.white@desy.de>
+ *
+ * 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 FROMFILE_H
+#define FROMFILE_H
+
+#include <argp.h>
+
+#include "image.h"
+
+extern int fromfile_default_options(FromFileOptions **opts_ptr);
+extern void *fromfile_prepare(IndexingMethod *indm,
+ struct fromfile_options *opts);
+extern int fromfile_index(struct image *image, void *mpriv, int crystal_number);
+extern void fromfile_cleanup(void *mpriv);
+
+#endif /* FROMFILE_H */