/* * cubeit.c * * "Full integration" of diffraction data * * (c) 2006-2010 Thomas White * * Part of CrystFEL - crystallography with a FEL * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" #include "hdf5-file.h" #include "diffraction.h" #include "render.h" #include "symmetry.h" #define MAX_THREADS (256) struct process_args { char *filename; int id; /* Thread control */ pthread_mutex_t control_mutex; /* Protects the scary stuff below */ int start; int finish; int done; UnitCell *cell; pthread_mutex_t vals_mutex; /* Protects "vals" */ double *vals; int xs; int ys; int zs; int config_angles; pthread_mutex_t angles_mutex; /* Protects "angles" */ unsigned int *angles; struct detector *det; signed int ht; signed int kt; signed int lt; char *sym; }; static void show_help(const char *s) { printf("Syntax: %s [options]\n\n", s); printf( "'Full integration' of diffraction data.\n" "\n" " -h, --help Display this help message.\n" "\n" " -i, --input= Specify the name of the input stream.\n" " Can be '-' for stdin.\n" " -g. --geometry= Get detector geometry from file.\n" " -x, --prefix=

Prefix filenames from input file with

.\n" " --basename Remove the directory parts of the filenames.\n" " --no-check-prefix Don't attempt to correct the --prefix.\n" " -j Run analyses in parallel.\n"); } static void interpolate_linear(double *vals, double v, int xs, int ys, int zs, int xv, int yv, double zv) { int k; double val1, val2; float f, c; c = (zv+0.5)*(float)zs; k = (int)c; if ( k == zs ) { /* Intensity belongs entirely to the next reflection */ return; } f = c - (float)k; assert(f >= 0.0); assert(k+1 <= zs); val1 = v*(1.0-f); val2 = v*f; vals[xs*ys*k + xs*yv + xv] += val1; /* Intensity may belong to the next reflection along */ if ( k+1 < zs ) { vals[xs*ys*(k+1) + xs*yv + xv] += val2; } } static void interpolate_bilinear(double *vals, double v, int xs, int ys, int zs, int xv, double yv, double zv) { int k; double val1, val2; float f, c; c = (yv+0.5)*(float)ys; k = (int)c; if ( k == ys ) { /* Intensity belongs entirely to the next reflection */ return; } f = c - (float)k; assert(f >= 0.0); assert(k+1 <= ys); val1 = v*(1.0-f); val2 = v*f; interpolate_linear(vals, val1, xs, ys, zs, xv, k, zv); /* Intensity may belong to the next reflection along */ if ( k+1 < ys ) { interpolate_linear(vals, val2, xs, ys, zs, xv, k+1, zv); } } static void interpolate_onto_grid(double *vals, double v, int xs, int ys, int zs, double xv, double yv, double zv) { int k; double val1, val2; float f, c; c = (xv+0.5)*(float)xs; k = (int)c; if ( k == xs ) { /* Intensity belongs entirely to the next reflection */ return; } f = c - (float)k; assert(f >= 0.0); assert(k+1 <= xs); val1 = v*(1.0-f); val2 = v*f; interpolate_bilinear(vals, val1, xs, ys, zs, k, yv, zv); /* Intensity may belong to the next reflection along */ if ( k+1 < xs ) { interpolate_bilinear(vals, val2, xs, ys, zs, k+1, yv, zv); } } static void process_image(struct process_args *pargs) { struct hdfile *hdfile; struct image image; double ax, ay, az; double bx, by, bz; double cx, cy, cz; int x, y; image.features = NULL; image.data = NULL; image.flags = NULL; image.indexed_cell = NULL; image.id = pargs->id; image.filename = pargs->filename; image.hits = NULL; image.n_hits = 0; image.det = pargs->det; /* View head-on (unit cell is tilted) */ image.orientation.w = 1.0; image.orientation.x = 0.0; image.orientation.y = 0.0; image.orientation.z = 0.0; STATUS("Processing '%s'\n", pargs->filename); hdfile = hdfile_open(pargs->filename); if ( hdfile == NULL ) { return; } else if ( hdfile_set_first_image(hdfile, "/") ) { ERROR("Couldn't select path\n"); hdfile_close(hdfile); return; } hdf5_read(hdfile, &image, 1); cell_get_cartesian(pargs->cell, &ax, &ay, &az, &bx, &by, &bz, &cx, &cy, &cz); fesetround(1); /* Round towards nearest */ for ( x=0; xsym); if ( (ha!=pargs->ht) || (ka!=pargs->kt) || (la!=pargs->lt) ) { continue; } dh = hd - h; dk = kd - k; dl = ld - l; double v = image.data[x+image.width*y]; pthread_mutex_lock(&pargs->vals_mutex); interpolate_onto_grid(pargs->vals, v, pargs->xs, pargs->ys, pargs->zs, dh, dk, dl); pthread_mutex_unlock(&pargs->vals_mutex); } } if ( pargs->config_angles ) { double asx, asy, asz; double bsx, bsy, bsz; double csx, csy, csz; double ang; int bin; cell_get_reciprocal(pargs->cell, &asx, &asy, &asz, &bsx, &bsy, &bsz, &csx, &csy, &csz); ang = angle_between(csx, csy, csz, 0.0, 0.0, 1.0); ang = rad2deg(ang); /* 0->180 deg */ bin = rint(ang); pthread_mutex_lock(&pargs->vals_mutex); pargs->angles[bin]++; pthread_mutex_unlock(&pargs->vals_mutex); } free(image.data); cell_free(pargs->cell); if ( image.flags != NULL ) free(image.flags); hdfile_close(hdfile); } static void *worker_thread(void *pargsv) { struct process_args *pargs = pargsv; int finish; do { int wakeup; process_image(pargs); pthread_mutex_lock(&pargs->control_mutex); pargs->done = 1; pargs->start = 0; pthread_mutex_unlock(&pargs->control_mutex); /* Go to sleep until told to exit or process next image */ do { pthread_mutex_lock(&pargs->control_mutex); /* Either of these can result in the thread waking up */ wakeup = pargs->start || pargs->finish; finish = pargs->finish; pthread_mutex_unlock(&pargs->control_mutex); usleep(20000); } while ( !wakeup ); } while ( !pargs->finish ); return NULL; } static void write_slice(const char *filename, double *vals, int z, int xs, int ys, int zs, double boost) { #ifdef HAVE_LIBPNG FILE *fh; png_structp png_ptr; png_infop info_ptr; png_bytep *row_pointers; int x, y, zf; float max = 0.0; int w, h; int pw, ph; int zoom = 32; pw = xs * zoom; ph = ys * zoom; w = xs; h = ys; for ( zf=0; zf max ) max = val; } } } fh = fopen(filename, "wb"); if ( !fh ) { ERROR("Couldn't open output file.\n"); return; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if ( !png_ptr ) { ERROR("Couldn't create PNG write structure.\n"); fclose(fh); return; } info_ptr = png_create_info_struct(png_ptr); if ( !info_ptr ) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); ERROR("Couldn't create PNG info structure.\n"); fclose(fh); return; } if ( setjmp(png_jmpbuf(png_ptr)) ) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fh); ERROR("PNG write failed.\n"); return; } png_init_io(png_ptr, fh); png_set_IHDR(png_ptr, info_ptr, pw, ph, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); row_pointers = malloc(ph*sizeof(png_bytep *)); /* Write the image data */ max /= boost; if ( max <= 6 ) { max = 10; } for ( y=0; y MAX_THREADS) ) { ERROR("Invalid number of threads.\n"); return 1; } /* FIXME: Get indices on command line (or elsewhere) */ get_asymm(3, 4, 5, &ht, &kt, <, sym); /* Initialise worker arguments */ for ( i=0; ifilename = malloc(1024); worker_active[i] = 0; worker_args[i]->xs = gs; worker_args[i]->ys = gs; worker_args[i]->zs = gs; worker_args[i]->config_angles = config_angles; worker_args[i]->vals = vals; worker_args[i]->angles = angles; worker_args[i]->det = det; pthread_mutex_init(&worker_args[i]->control_mutex, NULL); pthread_mutex_init(&worker_args[i]->vals_mutex, NULL); pthread_mutex_init(&worker_args[i]->angles_mutex, NULL); worker_args[i]->ht = ht; worker_args[i]->kt = kt; worker_args[i]->lt = lt; worker_args[i]->sym = sym; } n_images = 0; /* Start threads off */ for ( i=0; ifilename, 1023, "%s%s", prefix, filename); pargs->cell = cell; free(filename); n_images++; pthread_mutex_lock(&pargs->control_mutex); pargs->done = 0; pargs->start = 1; pargs->finish = 0; pthread_mutex_unlock(&pargs->control_mutex); worker_active[i] = 1; r = pthread_create(&workers[i], NULL, worker_thread, pargs); if ( r != 0 ) { worker_active[i] = 0; ERROR("Couldn't start thread %i\n", i); } } /* Keep threads busy until the end of the data */ do { int i; rval = 0; for ( i=0; icontrol_mutex); done = pargs->done; pthread_mutex_unlock(&pargs->control_mutex); if ( !done ) continue; /* Get the next filename */ rval = find_chunk(fh, &cell, &filename); if ( rval == 1 ) break; if ( config_basename ) { char *tmp; tmp = basename(filename); free(filename); filename = tmp; } snprintf(pargs->filename, 1023, "%s%s", prefix, filename); pargs->cell = cell; free(filename); n_images++; STATUS("Done %i images\n", n_images); /* Wake the thread up ... */ pthread_mutex_lock(&pargs->control_mutex); pargs->done = 0; pargs->start = 1; pthread_mutex_unlock(&pargs->control_mutex); } } while ( rval == 0 ); /* Join threads */ for ( i=0; icontrol_mutex); pargs->finish = 1; pthread_mutex_unlock(&pargs->control_mutex); /* Wait for it to join */ pthread_join(workers[i], NULL); free: if ( worker_args[i]->filename != NULL ) { free(worker_args[i]->filename); } } fclose(fh); for ( i=0; i