diff options
-rw-r--r-- | libcrystfel/Makefile.am | 4 | ||||
-rw-r--r-- | libcrystfel/src/index.c | 18 | ||||
-rw-r--r-- | libcrystfel/src/index.h | 2 | ||||
-rw-r--r-- | libcrystfel/src/xds.c | 503 | ||||
-rw-r--r-- | libcrystfel/src/xds.h | 43 |
5 files changed, 567 insertions, 3 deletions
diff --git a/libcrystfel/Makefile.am b/libcrystfel/Makefile.am index ae315594..5f5ff7fa 100644 --- a/libcrystfel/Makefile.am +++ b/libcrystfel/Makefile.am @@ -9,7 +9,7 @@ libcrystfel_la_SOURCES = src/reflist.c src/utils.c src/cell.c src/detector.c \ src/reflist-utils.c src/filters.c \ src/render.c src/index.c src/dirax.c src/mosflm.c \ src/cell-utils.c src/integer_matrix.c src/crystal.c \ - src/grainspotter.c + src/grainspotter.c src/xds.c if HAVE_FFTW libcrystfel_la_SOURCES += src/reax.c @@ -26,7 +26,7 @@ libcrystfel_la_include_HEADERS = src/beam-parameters.h src/hdf5-file.h \ src/filters.h src/dirax.h src/mosflm.h \ src/index-priv.h src/reax.h src/cell-utils.h \ src/integer_matrix.h src/crystal.h \ - src/grainspotter.h + src/grainspotter.h src/xds.h AM_CPPFLAGS = -DDATADIR=\""$(datadir)"\" -I$(top_builddir)/lib -Wall AM_CPPFLAGS += -I$(top_srcdir)/lib @LIBCRYSTFEL_CFLAGS@ diff --git a/libcrystfel/src/index.c b/libcrystfel/src/index.c index eee2e814..20e7cf24 100644 --- a/libcrystfel/src/index.c +++ b/libcrystfel/src/index.c @@ -11,6 +11,7 @@ * 2010-2013 Thomas White <taw@physics.org> * 2010-2011 Richard Kirian <rkirian@asu.edu> * 2012 Lorenzo Galli + * 2013 Cornelius Gati <cornelius.gati@cfel.de> * * This file is part of CrystFEL. * @@ -44,6 +45,7 @@ #include "peaks.h" #include "dirax.h" #include "mosflm.h" +#include "xds.h" #include "detector.h" #include "index.h" #include "index-priv.h" @@ -84,6 +86,11 @@ IndexingPrivate **prepare_indexing(IndexingMethod *indm, UnitCell *cell, iprivs[n] = mosflm_prepare(&indm[n], cell, filename, det, beam, ltl); break; + + case INDEXING_XDS : + iprivs[n] = indexing_private(indm[n]); + break; + case INDEXING_REAX : iprivs[n] = reax_prepare(&indm[n], cell, filename, det, beam, ltl); @@ -153,6 +160,10 @@ void cleanup_indexing(IndexingMethod *indms, IndexingPrivate **privs) mosflm_cleanup(privs[n]); break; + case INDEXING_XDS : + free(priv[n]); + break; + case INDEXING_REAX : reax_cleanup(privs[n]); break; @@ -213,6 +224,10 @@ static int try_indexer(struct image *image, IndexingMethod indm, return run_mosflm(image, ipriv); break; + case INDEXING_XDS : + run_XDS(image, cell); + break; + case INDEXING_REAX : return reax_index(image, ipriv); break; @@ -385,6 +400,9 @@ IndexingMethod *build_indexer_list(const char *str) } else if ( strcmp(methods[i], "grainspotter") == 0) { list[++nmeth] = INDEXING_DEFAULTS_GRAINSPOTTER; + } else if ( strcmp(methods[i], "xds") == 0) { + list[i] = INDEXING_XDS; + } else if ( strcmp(methods[i], "reax") == 0) { list[++nmeth] = INDEXING_DEFAULTS_REAX; diff --git a/libcrystfel/src/index.h b/libcrystfel/src/index.h index 3c91486b..d550468b 100644 --- a/libcrystfel/src/index.h +++ b/libcrystfel/src/index.h @@ -69,7 +69,6 @@ **/ typedef enum { - INDEXING_NONE = 0, /* The core indexing methods themselves */ @@ -77,6 +76,7 @@ typedef enum { INDEXING_MOSFLM = 2, INDEXING_REAX = 3, INDEXING_GRAINSPOTTER = 4, + INDEXING_XDS = 5, /* Bits at the top of the IndexingMethod are flags which modify the * behaviour of the indexer. */ diff --git a/libcrystfel/src/xds.c b/libcrystfel/src/xds.c new file mode 100644 index 00000000..838b71b7 --- /dev/null +++ b/libcrystfel/src/xds.c @@ -0,0 +1,503 @@ +/* + * xds.c + * + * Invoke xds for crystal autoindexing + * + * Copyright © 2013 Deutsches Elektronen-Synchrotron DESY, + * a research centre of the Helmholtz Association. + * + * Authors: + * 2010-2013 Thomas White <taw@physics.org> + * 2013 Cornelius Gati <cornelius.gati@cfel.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/>. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <assert.h> +#include <sys/ioctl.h> +#include <errno.h> + +#if HAVE_FORKPTY_LINUX +#include <pty.h> +#elif HAVE_FORKPTY_BSD +#include <util.h> +#endif + + +#include "image.h" +#include "utils.h" +#include "peaks.h" +#include "cell.h" +#include "cell-utils.h" + + +#define xds_VERBOSE 0 + + +struct xds_data { + + /* Low-level stuff */ + int pty; + pid_t pid; + char *rbuffer; + int rbufpos; + int rbuflen; + + /* High-level stuff */ + char newmatfile[128]; + char spotfile[128]; + int step; + int finished_ok; + UnitCell *target_cell; +}; + +static void xds_parseline(const char *line, struct image *image, + struct xds_data *xds) +{ + + char *copy; + int i; + + copy = strdup(line); + for ( i=0; i<strlen(copy); i++ ) { + if ( copy[i] == '\r' ) copy[i]='r'; + if ( copy[i] == '\n' ) copy[i]='\0'; + } + STATUS("XDS: %s\n", copy); + free(copy); +} + + +static int xds_readable(struct image *image, struct xds_data *xds) +{ + int rval; + int no_string = 0; + + rval = read(xds->pty, xds->rbuffer+xds->rbufpos, + xds->rbuflen-xds->rbufpos); + if ( (rval == -1) || (rval == 0) ) return 1; + + xds->rbufpos += rval; + assert(xds->rbufpos <= xds->rbuflen); + + while ( (!no_string) && (xds->rbufpos > 0) ) { + + int i; + int block_ready = 0; + + /* See if there's a full line in the buffer yet */ + for ( i=0; i<xds->rbufpos-1; i++ ) { + /* Means the last value looked at is rbufpos-2 */ + + if ( (xds->rbuffer[i] == '\r') + && (xds->rbuffer[i+1] == '\n') ) { + block_ready = 1; + break; + } + + } + + if ( block_ready ) { + + unsigned int new_rbuflen; + unsigned int endbit_length; + char *block_buffer = NULL; + + block_buffer = malloc(i+1); + memcpy(block_buffer, xds->rbuffer, i); + block_buffer[i] = '\0'; + + if ( block_buffer[0] == '\r' ) { + memmove(block_buffer, block_buffer+1, i); + } + + xds_parseline(block_buffer, image, xds); + free(block_buffer); + endbit_length = i+2; + + /* Now the block's been parsed, it should be + * forgotten about */ + memmove(xds->rbuffer, + xds->rbuffer + endbit_length, + xds->rbuflen - endbit_length); + + /* Subtract the number of bytes removed */ + xds->rbufpos = xds->rbufpos + - endbit_length; + new_rbuflen = xds->rbuflen - endbit_length; + if ( new_rbuflen == 0 ) new_rbuflen = 256; + xds->rbuffer = realloc(xds->rbuffer, + new_rbuflen); + xds->rbuflen = new_rbuflen; + + } else { + + if ( xds->rbufpos==xds->rbuflen ) { + + /* More buffer space is needed */ + xds->rbuffer = realloc( + xds->rbuffer, + xds->rbuflen + 256); + xds->rbuflen = xds->rbuflen + 256; + /* The new space gets used at the next + * read, shortly... */ + + } + no_string = 1; + + } + + } + + return 0; +} + + + + + + +static int read_newmat(const char *filename, struct image *image) +{ + FILE * fh; + float axstar, aystar, azstar, bxstar, bystar, bzstar, cxstar, cystar, czstar; + char asx[11], asy[11], asz[11]; + char bsx[11], bsy[11], bsz[11]; + char csx[11], csy[11], csz[11]; + char *rval, line[1024]; + int r; + + fh = fopen("IDXREF.LP", "r"); + if ( fh == NULL ) { + ERROR("Couldn't open 'IDXREF.LP'\n"); + return 1; + } + + do { + rval = fgets(line, 1023, fh); + + } while (strcmp(line, " # COORDINATES OF REC. BASIS VECTOR LENGTH 1/LENGTH\n") != 0 ); + + /*free line after chunk*/ + rval = fgets(line, 1023, fh); + rval = fgets(line, 1023, fh); + + memcpy(asx, line+7, 10); asx[10] = '\0'; + memcpy(asy, line+17, 10); asy[10] = '\0'; + memcpy(asz, line+27, 10); asz[10] = '\0'; + + rval = fgets(line, 1023, fh); + + memcpy(bsx, line+7, 10); bsx[10] = '\0'; + memcpy(bsy, line+17, 10); bsy[10] = '\0'; + memcpy(bsz, line+27, 10); bsz[10] = '\0'; + + rval = fgets(line, 1023, fh); + + memcpy(csx, line+7, 10); csx[10] = '\0'; + memcpy(csy, line+17, 10); csy[10] = '\0'; + memcpy(csz, line+27, 10); csz[10] = '\0'; + + r = sscanf(asx, "%f", &cxstar); + r += sscanf(asy, "%f", &cystar); + r += sscanf(asz, "%f", &czstar); + r += sscanf(bsx, "%f", &bxstar); + r += sscanf(bsy, "%f", &bystar); + r += sscanf(bsz, "%f", &bzstar); + r += sscanf(csx, "%f", &axstar); + r += sscanf(csy, "%f", &aystar); + r += sscanf(csz, "%f", &azstar); + + if ( r != 9 ) { + STATUS("Fewer than 9 parameters found in NEWMAT file.\n"); + return 1;} + + fclose(fh); + + //printf("asx='%s'\n", asx); + //printf("asy='%s'\n", asy); + //printf("asz='%s'\n", asz); + //printf("cxstar='%f'\n", cxstar); + //printf("cystar='%f'\n", cystar); + //printf("czstar='%f'\n", czstar); + //printf("bsx='%s'\n", bsx); + //printf("bsy='%s'\n", bsy); + //printf("bsz='%s'\n", bsz); + //printf("axstar='%f'\n", axstar); + //printf("aystar='%f'\n", aystar); + //printf("azstar='%f'\n", azstar); + //printf("csx='%s'\n", csx); + //printf("csy='%s'\n", csy); + //printf("csz='%s'\n", csz); + //printf("bxstar='%f'\n", bxstar); + //printf("bystar='%f'\n", bystar); + //printf("bzstar='%f'\n", bzstar); + + image->candidate_cells[0] = cell_new(); + + cell_set_reciprocal(image->candidate_cells[0], + axstar*10e9, aystar*10e9, azstar*10e9, + bxstar*10e9, bystar*10e9, bzstar*10e9, + -cxstar*10e9, -cystar*10e9, -czstar*10e9); + image->ncells = 1; + + cell_print(image->candidate_cells[0]); + + return 0; +} + + +static void write_spot(struct image *image, const char *filename) +{ + FILE *fh; + int i; + double fclen = 99.0e-3; /* fake camera length in m */ + int n; + + fh = fopen("SPOT.XDS", "w"); + if ( !fh ) { + ERROR("Couldn't open temporary file '%s'\n", "SPOT.XDS"); + return; + } + + n = image_feature_count(image->features); + for ( i=0; i<n; i++ ) + + { + struct imagefeature *f; + struct panel *p; + double xs, ys, rx, ry, x, y; + + f = image_get_feature(image->features, i); + if ( f == NULL ) continue; + + p = find_panel(image->det, f->fs, f->ss); + if ( p == NULL ) continue; + + xs = (f->fs-p->min_fs)*p->fsx + (f->ss-p->min_ss)*p->ssx; + ys = (f->fs-p->min_fs)*p->fsy + (f->ss-p->min_ss)*p->ssy; + rx = ((xs + p->cnx) / p->res); + ry = ((ys + p->cny) / p->res); + + //printf("xs=%f ys=%f ----> rx=%f ry=%f\n", xs, ys, rx, ry); + + x = rx*fclen/p->clen; + y = ry*fclen/p->clen; /* Peak positions in m */ + + //printf("x=%f y=%f\n", x, y); + + x = (rx / 70e-6) + 1500; + y = (ry / 70e-6) + 1500; + + if (f->intensity <= 0) continue; + + fprintf(fh, "%10.2f %10.2f %10.2f %10.0f.\n", + x, y, 0.5, f->intensity); + + } + fclose(fh); +} + + +static char *write_inp(struct image *image) +{ + FILE *fh; + char *filename; + + filename = malloc(1024); + if ( filename == NULL ) return NULL; + + snprintf(filename, 1023, "XDS.INP"); + + fh = fopen(filename, "w"); + if ( !fh ) { + ERROR("Couldn't open temporary file '%s'\n", filename); + free(filename); + return NULL; + } + + fprintf(fh, "JOB= IDXREF\n"); + fprintf(fh, "ORGX= 1500\n"); + fprintf(fh, "ORGY= 1500\n"); + fprintf(fh, "DETECTOR_DISTANCE= 99.00\n"); //IMPORTANT + fprintf(fh, "OSCILLATION_RANGE= 0.300\n"); + fprintf(fh, "X-RAY_WAVELENGTH= 1.32\n"); // IMPORTANT + fprintf(fh, "NAME_TEMPLATE_OF_DATA_FRAMES=/home/dikay/insu/data_exp1/ins_ssad_1_???.img \n"); + fprintf(fh, "DATA_RANGE=1 1\n"); + fprintf(fh, "SPOT_RANGE=1 1\n"); + fprintf(fh, "SPACE_GROUP_NUMBER= 94\n"); //CatB 94 + fprintf(fh, "UNIT_CELL_CONSTANTS= 126.2 126.2 54.2 90 90 90\n"); //CatB 125.4 125.4 54.56 90 90 90 + //fprintf(fh, "SPACE_GROUP_NUMBER=194\n"); //PS1 194 + //fprintf(fh, "UNIT_CELL_CONSTANTS=281 281 165.2 90 90 120\n"); //PS1 281 281 165.2 90 90 120 + //fprintf(fh, "SPACE_GROUP_NUMBER= 0\n"); //LYS 96 + //fprintf(fh, "UNIT_CELL_CONSTANTS= 0 0 0 0 0 0\n"); //LYS 77.32 77.32 38.16 90 90 90 + fprintf(fh, "NX= 3000\n"); + fprintf(fh, "NY= 3000\n"); + fprintf(fh, "QX= 0.07\n"); + fprintf(fh, "QY= 0.07\n"); + fprintf(fh, "INDEX_ORIGIN=0 0 0\n"); + fprintf(fh, "DIRECTION_OF_DETECTOR_X-AXIS=1 0 0\n"); + fprintf(fh, "DIRECTION_OF_DETECTOR_Y-AXIS=0 1 0\n"); + fprintf(fh, "INCIDENT_BEAM_DIRECTION=0 0 1\n"); + fprintf(fh, "ROTATION_AXIS=0 1 0\n"); + fprintf(fh, "DETECTOR= CSPAD\n"); + fprintf(fh, "MINIMUM_VALID_PIXEL_VALUE= 1\n"); + fprintf(fh, "OVERLOAD= 200000000\n"); + fprintf(fh, "INDEX_ERROR= 0.4\n"); + //fprintf(fh, "INDEX_QUALITY= 0.5\n"); + //fprintf(fh, "REFINE(IDXREF)= ALL\n"); + //fprintf(fh, "MINIMUM_NUMBER_OF_PIXELS_IN_A_SPOT= 1\n"); + //fprintf(fh, "MAXIMUM_ERROR_OF_SPOT_POSITION= 20.0\n"); + + fclose(fh); + + return filename; +} + +void run_xds(struct image *image, UnitCell *cell) +{ + + unsigned int opts; + int status; + int rval; + int n; + struct xds_data *xds; + char *inp_filename; + + xds = malloc(sizeof(struct xds_data)); + if ( xds == NULL ) { + ERROR("Couldn't allocate memory for xds data.\n"); + return; + } + + xds->target_cell = cell; + + write_inp(image); + inp_filename = write_inp(image); + + if ( inp_filename == NULL ) { + ERROR("Failed to write XDS.INP file for XDS.\n"); + return; + } + + n= image_feature_count(image->features); + if (n < 25) return; + + snprintf(xds->spotfile, 127, "SPOT.XDS"); + + write_spot(image, xds->spotfile); + + xds->pid = forkpty(&xds->pty, NULL, NULL, NULL); + + if ( xds->pid == -1 ) { + ERROR("Failed to fork for XDS\n"); + free(xds); + return; + } + if ( xds->pid == 0 ) { + + /* Child process: invoke XDS */ + struct termios t; + + /* Turn echo off */ + tcgetattr(STDIN_FILENO, &t); + t.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); + tcsetattr(STDIN_FILENO, TCSANOW, &t); + + execlp("xds", "", (char *)NULL); + ERROR("Failed to invoke XDS.\n"); + _exit(0); + + } + + xds->rbuffer = malloc(256); + xds->rbuflen = 256; + xds->rbufpos = 0; + + /* Set non-blocking */ + opts = fcntl(xds->pty, F_GETFL); + fcntl(xds->pty, F_SETFL, opts | O_NONBLOCK); + + //xds->step = 1; /* This starts the "initialisation" procedure */ + xds->finished_ok = 0; + + do { + + fd_set fds; + struct timeval tv; + int sval; + + FD_ZERO(&fds); + FD_SET(xds->pty, &fds); + + tv.tv_sec = 30; + tv.tv_usec = 0; + + sval = select(xds->pty+1, &fds, NULL, NULL, &tv); + + if ( sval == -1 ) { + + const int err = errno; + + switch ( err ) { + + case EINTR: + STATUS("Restarting select()\n"); + break; + + default: + ERROR("select() failed: %s\n", strerror(err)); + rval = 1; + + } + + } else if ( sval != 0 ) { + rval = xds_readable(image, xds); + } else { + ERROR("No response from XDS..\n"); + rval = 1; + } + + } while ( !rval ); + + close(xds->pty); + free(xds->rbuffer); + waitpid(xds->pid, &status, 0); + + //FIXME// + //if ( xds->finished_ok == 1 ) { + // ERROR("XDS doesn't seem to be working properly.\n"); + //} else { + /* Read the XDS NEWMAT file and get cell if found */ + read_newmat(xds->newmatfile, image); + + //} + + free(xds); +} diff --git a/libcrystfel/src/xds.h b/libcrystfel/src/xds.h new file mode 100644 index 00000000..edf83b0b --- /dev/null +++ b/libcrystfel/src/xds.h @@ -0,0 +1,43 @@ +/* + * xds.h + * + * Invoke xds for crystal autoindexing + * + * Copyright © 2013 Deutsches Elektronen-Synchrotron DESY, + * a research centre of the Helmholtz Association. + * + * Authors: + * 2010-2013 Thomas White <taw@physics.org> + * 2013 Cornelius Gati <cornelius.gati@cfel.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 xds_H +#define xds_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "cell.h" + + +extern void run_xds(struct image *image, UnitCell *cell); + + +#endif /* XDS_H */ |