/* * 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 "utils.h" #include "hdf5-file.h" #include "diffraction.h" #include "render.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; }; 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; f = c - (float)k; assert(f >= 0.0); assert(k < zs); val1 = v*(1.0-f); val2 = v*f; vals[xs*ys*k + xs*yv + xv] += val1; 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; f = c - (float)k; assert(f >= 0.0); assert(k < ys); val1 = v*(1.0-f); val2 = v*f; interpolate_linear(vals, val1, xs, ys, zs, xv, k, zv); 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; f = c - (float)k; assert(f >= 0.0); assert(k < xs); val1 = v*(1.0-f); val2 = v*f; interpolate_bilinear(vals, val1, xs, ys, zs, k, yv, zv); 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; const signed int ht = 3; const signed int kt = 4; const signed int lt = 5; 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); for ( x=0; xvals_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; float max = 0.0; int w, h; int pw, ph; int zoom = 32; pw = xs * zoom; ph = ys * zoom; w = xs; h = ys; for ( y=0; y 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(h*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; } /* 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); } 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; 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 != NULL ); /* 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