aboutsummaryrefslogtreecommitdiff
path: root/libcrystfel/src/mosflm.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcrystfel/src/mosflm.c')
-rw-r--r--libcrystfel/src/mosflm.c283
1 files changed, 250 insertions, 33 deletions
diff --git a/libcrystfel/src/mosflm.c b/libcrystfel/src/mosflm.c
index 38f8478b..a03e621d 100644
--- a/libcrystfel/src/mosflm.c
+++ b/libcrystfel/src/mosflm.c
@@ -3,13 +3,13 @@
*
* Invoke the DPS auto-indexing algorithm through MOSFLM
*
- * Copyright © 2012 Deutsches Elektronen-Synchrotron DESY,
- * a research centre of the Helmholtz Association.
+ * Copyright © 2012-2013 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
* Copyright © 2012 Richard Kirian
*
* Authors:
* 2010 Richard Kirian <rkirian@asu.edu>
- * 2010-2012 Thomas White <taw@physics.org>
+ * 2010-2013 Thomas White <taw@physics.org>
*
* This file is part of CrystFEL.
*
@@ -80,6 +80,7 @@
#include "mosflm.h"
#include "utils.h"
#include "peaks.h"
+#include "cell-utils.h"
#define MOSFLM_VERBOSE 0
@@ -92,6 +93,14 @@ typedef enum {
} MOSFLMInputType;
+
+struct mosflm_private {
+ IndexingMethod indm;
+ float *ltl;
+ UnitCell *template;
+};
+
+
struct mosflm_data {
/* MOSFLM auto-indexing low-level stuff */
@@ -107,10 +116,85 @@ struct mosflm_data {
char sptfile[128];
int step;
int finished_ok;
- UnitCell *target_cell;
+ int done;
+ int success;
+
+ struct mosflm_private *mp;
};
+static int check_cell(struct mosflm_private *mp, struct image *image,
+ UnitCell *cell)
+{
+ UnitCell *out;
+ Crystal *cr;
+
+ /* If we sent lattice information, make sure that we got back what we
+ * asked for, not (e.g.) some "H" version of a rhombohedral R cell */
+ if ( mp->indm & INDEXING_USE_LATTICE_TYPE ) {
+
+ LatticeType latt_m, latt_r;
+ char cen_m, cen_r;
+
+ /* What we asked for */
+ latt_r = cell_get_lattice_type(mp->template);
+ cen_r = cell_get_centering(mp->template);
+
+ /* What we got back */
+ latt_m = cell_get_lattice_type(cell);
+ cen_m = cell_get_centering(cell);
+
+ if ( latt_r != latt_m ) {
+ ERROR("Lattice type produced by MOSFLM (%i) does not "
+ "match what was requested (%i). "
+ "Please report this.\n", latt_m, latt_r);
+ return 0;
+ }
+
+ if ( cen_r != cen_m ) {
+ ERROR("Centering produced by MOSFLM (%c) does not "
+ "match what was requested (%c). "
+ "Please report this.\n", cen_m, cen_r);
+ return 0;
+ }
+
+ }
+
+ if ( mp->indm & INDEXING_CHECK_CELL_COMBINATIONS ) {
+
+ out = match_cell(cell, mp->template, 0, mp->ltl, 1);
+ if ( out == NULL ) return 0;
+
+ } else if ( mp->indm & INDEXING_CHECK_CELL_AXES ) {
+
+ out = match_cell(cell, mp->template, 0, mp->ltl, 0);
+ if ( out == NULL ) return 0;
+
+ } else {
+ out = cell_new_from_cell(cell);
+ }
+
+ cr = crystal_new();
+ if ( cr == NULL ) {
+ ERROR("Failed to allocate crystal.\n");
+ return 0;
+ }
+
+ crystal_set_cell(cr, out);
+
+ if ( mp->indm & INDEXING_CHECK_PEAKS ) {
+ if ( !peak_sanity_check(image, &cr, 1) ) {
+ cell_free(out);
+ crystal_free(cr);
+ return 0;
+ }
+ }
+
+ image_add_crystal(image, cr);
+
+ return 1;
+}
+
static void mosflm_parseline(const char *line, struct image *image,
struct mosflm_data *dirax)
@@ -130,14 +214,54 @@ static void mosflm_parseline(const char *line, struct image *image,
}
-static int read_newmat(const char *filename, struct image *image)
+/* This is the opposite of spacegroup_for_lattice() below. */
+static LatticeType spacegroup_to_lattice(const char *sg)
+{
+ LatticeType latt;
+
+ if ( sg[1] == '1' ) {
+ latt = L_TRICLINIC;
+ } else if ( strncmp(sg+1, "23", 2) == 0 ) {
+ latt = L_CUBIC;
+ } else if ( strncmp(sg+1, "222", 3) == 0 ) {
+ latt = L_ORTHORHOMBIC;
+ } else if ( sg[1] == '2' ) {
+ latt = L_MONOCLINIC;
+ } else if ( sg[1] == '4' ) {
+ latt = L_TETRAGONAL;
+ } else if ( sg[1] == '6' ) {
+ latt = L_HEXAGONAL;
+ } else if ( sg[1] == '3' ) {
+ if ( sg[0] == 'H' ) {
+ latt = L_HEXAGONAL;
+ } else {
+ latt = L_RHOMBOHEDRAL;
+ }
+ } else {
+ ERROR("Couldn't understand '%s'\n", sg);
+ latt = L_TRICLINIC;
+ }
+
+ return latt;
+}
+
+
+
+static int read_newmat(struct mosflm_data *mosflm, const char *filename,
+ struct image *image)
{
- FILE * fh;
+ FILE *fh;
float asx, asy, asz;
float bsx, bsy, bsz;
float csx, csy, csz;
int n;
double c;
+ UnitCell *cell;
+ char symm[32];
+ char *rval;
+ int i;
+ char cen;
+ LatticeType latt;
fh = fopen(filename, "r");
if ( fh == NULL ) {
@@ -150,23 +274,54 @@ static int read_newmat(const char *filename, struct image *image)
STATUS("Fewer than 9 parameters found in NEWMAT file.\n");
return 1;
}
+
+ /* Skip the next six lines */
+ for ( i=0; i<6; i++ ) {
+ char tmp[1024];
+ rval = fgets(tmp, 1024, fh);
+ if ( rval == NULL ) {
+ ERROR("Failed to read newmat file.\n");
+ return 1;
+ }
+ }
+
+ rval = fgets(symm, 32, fh);
+ if ( rval == NULL ) {
+ ERROR("Failed to read newmat file.\n");
+ return 1;
+ }
+
fclose(fh);
+ if ( strncmp(symm, "SYMM ", 5) != 0 ) {
+ ERROR("Bad 'SYMM' line from MOSFLM.\n");
+ return 1;
+ }
+ cen = symm[5];
+ latt = spacegroup_to_lattice(symm+5);
+
/* MOSFLM "A" matrix is multiplied by lambda, so fix this */
c = 1.0/image->lambda;
- image->candidate_cells[0] = cell_new();
+ cell = cell_new();
/* The relationship between the coordinates in the spot file and the
* resulting matrix is diabolically complicated. This transformation
* seems to work, but is not derived by working through all the
* transformations. */
- cell_set_reciprocal(image->candidate_cells[0],
+ cell_set_reciprocal(cell,
-asy*c, -asz*c, asx*c,
-bsy*c, -bsz*c, bsx*c,
-csy*c, -csz*c, csx*c);
+ cell_set_centering(cell, cen);
+ cell_set_lattice_type(cell, latt);
+
+ if ( check_cell(mosflm->mp, image, cell) ) {
+ mosflm->success = 1;
+ mosflm->done = 1;
+ }
- image->ncells = 1;
+ cell_free(cell);
return 0;
}
@@ -319,7 +474,7 @@ static const char *spacegroup_for_lattice(UnitCell *cell)
if ( centering != 'H' ) {
g = "6";
} else {
- g = "32";
+ g = "3";
}
break;
@@ -343,8 +498,8 @@ static void mosflm_send_next(struct image *image, struct mosflm_data *mosflm)
char tmp[256];
double wavelength;
- switch ( mosflm->step ) {
-
+ switch ( mosflm->step )
+ {
case 1 :
mosflm_sendline("DETECTOR ROTATION HORIZONTAL"
" ANTICLOCKWISE ORIGIN LL FAST HORIZONTAL"
@@ -352,13 +507,22 @@ static void mosflm_send_next(struct image *image, struct mosflm_data *mosflm)
break;
case 2 :
- if ( mosflm->target_cell != NULL ) {
+ if ( (mosflm->mp->indm & INDEXING_USE_LATTICE_TYPE)
+ && (mosflm->mp->template != NULL) )
+ {
const char *symm;
- symm = spacegroup_for_lattice(mosflm->target_cell);
+
+ if ( cell_get_lattice_type(mosflm->mp->template)
+ == L_RHOMBOHEDRAL ) {
+ mosflm_sendline("CRYSTAL R\n", mosflm);
+ }
+
+ symm = spacegroup_for_lattice(mosflm->mp->template);
snprintf(tmp, 255, "SYMM %s\n", symm);
mosflm_sendline(tmp, mosflm);
+
} else {
- mosflm_sendline("SYMM P1\n", mosflm);
+ mosflm_sendline("\n", mosflm);
}
break;
@@ -403,10 +567,9 @@ static void mosflm_send_next(struct image *image, struct mosflm_data *mosflm)
mosflm->finished_ok = 1;
break;
- default:
+ default:
mosflm_sendline("exit\n", mosflm);
return;
-
}
mosflm->step++;
@@ -460,8 +623,7 @@ static int mosflm_readable(struct image *image, struct mosflm_data *mosflm)
switch ( type ) {
- case MOSFLM_INPUT_LINE :
-
+ case MOSFLM_INPUT_LINE :
block_buffer = malloc(i+1);
memcpy(block_buffer, mosflm->rbuffer, i);
block_buffer[i] = '\0';
@@ -475,12 +637,12 @@ static int mosflm_readable(struct image *image, struct mosflm_data *mosflm)
endbit_length = i+2;
break;
- case MOSFLM_INPUT_PROMPT :
+ case MOSFLM_INPUT_PROMPT :
mosflm_send_next(image, mosflm);
endbit_length = i+7;
break;
- default :
+ default :
/* Obviously, this never happens :) */
ERROR("Unrecognised MOSFLM input mode! "
@@ -527,7 +689,7 @@ static int mosflm_readable(struct image *image, struct mosflm_data *mosflm)
}
-void run_mosflm(struct image *image, UnitCell *cell)
+int run_mosflm(struct image *image, IndexingPrivate *ipriv)
{
struct mosflm_data *mosflm;
unsigned int opts;
@@ -537,11 +699,9 @@ void run_mosflm(struct image *image, UnitCell *cell)
mosflm = malloc(sizeof(struct mosflm_data));
if ( mosflm == NULL ) {
ERROR("Couldn't allocate memory for MOSFLM data.\n");
- return;
+ return 0;
}
- mosflm->target_cell = cell;
-
snprintf(mosflm->imagefile, 127, "xfel-%i_001.img", image->id);
write_img(image, mosflm->imagefile); /* Dummy image */
@@ -554,9 +714,9 @@ void run_mosflm(struct image *image, UnitCell *cell)
mosflm->pid = forkpty(&mosflm->pty, NULL, NULL, NULL);
if ( mosflm->pid == -1 ) {
- ERROR("Failed to fork for MOSFLM\n");
+ ERROR("Failed to fork for MOSFLM: %s\n", strerror(errno));
free(mosflm);
- return;
+ return 0;
}
if ( mosflm->pid == 0 ) {
@@ -584,7 +744,11 @@ void run_mosflm(struct image *image, UnitCell *cell)
mosflm->step = 1; /* This starts the "initialisation" procedure */
mosflm->finished_ok = 0;
+ mosflm->mp = (struct mosflm_private *)ipriv;
+ mosflm->done = 0;
+ mosflm->success = 0;
+ rval = 0;
do {
fd_set fds;
@@ -599,10 +763,22 @@ void run_mosflm(struct image *image, UnitCell *cell)
sval = select(mosflm->pty+1, &fds, NULL, NULL, &tv);
- if ( sval == -1 ) {
- int err = errno;
- ERROR("select() failed: %s\n", strerror(err));
- rval = 1;
+ 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 = mosflm_readable(image, mosflm);
} else {
@@ -610,7 +786,6 @@ void run_mosflm(struct image *image, UnitCell *cell)
rval = 1;
}
-
} while ( !rval );
close(mosflm->pty);
@@ -621,8 +796,50 @@ void run_mosflm(struct image *image, UnitCell *cell)
ERROR("MOSFLM doesn't seem to be working properly.\n");
} else {
/* Read the mosflm NEWMAT file and get cell if found */
- read_newmat(mosflm->newmatfile, image);
+ read_newmat(mosflm, mosflm->newmatfile, image);
}
+ rval = mosflm->success;
free(mosflm);
+ return rval;
+}
+
+
+IndexingPrivate *mosflm_prepare(IndexingMethod *indm, UnitCell *cell,
+ const char *filename, struct detector *det,
+ struct beam_params *beam, float *ltl)
+{
+ struct mosflm_private *mp;
+ int need_cell = 0;
+
+ if ( *indm & INDEXING_CHECK_CELL_COMBINATIONS ) need_cell = 1;
+ if ( *indm & INDEXING_CHECK_CELL_AXES ) need_cell = 1;
+ if ( *indm & INDEXING_USE_LATTICE_TYPE ) need_cell = 1;
+
+ if ( need_cell && (cell == NULL) ) {
+ ERROR("MOSFLM needs a unit cell for this set of flags.\n");
+ return NULL;
+ }
+
+ /* Flags that MOSFLM knows about */
+ *indm &= INDEXING_METHOD_MASK | INDEXING_CHECK_CELL_COMBINATIONS
+ | INDEXING_CHECK_CELL_AXES | INDEXING_CHECK_PEAKS
+ | INDEXING_USE_LATTICE_TYPE;
+
+ mp = malloc(sizeof(struct mosflm_private));
+ if ( mp == NULL ) return NULL;
+
+ mp->ltl = ltl;
+ mp->template = cell;
+ mp->indm = *indm;
+
+ return (IndexingPrivate *)mp;
+}
+
+
+void mosflm_cleanup(IndexingPrivate *pp)
+{
+ struct mosflm_private *p;
+ p = (struct mosflm_private *)pp;
+ free(p);
}