diff options
Diffstat (limited to 'src/partialator.c')
-rw-r--r-- | src/partialator.c | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/src/partialator.c b/src/partialator.c new file mode 100644 index 00000000..c023fcde --- /dev/null +++ b/src/partialator.c @@ -0,0 +1,486 @@ +/* + * partialator.c + * + * Scaling and post refinement for coherent nanocrystallography + * + * (c) 2006-2010 Thomas White <taw@physics.org> + * + * Part of CrystFEL - crystallography with a FEL + * + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <assert.h> +#include <pthread.h> + +#include "utils.h" +#include "hdf5-file.h" +#include "symmetry.h" +#include "reflections.h" +#include "stream.h" +#include "geometry.h" +#include "peaks.h" +#include "thread-pool.h" +#include "beam-parameters.h" +#include "post-refinement.h" +#include "hrs-scaling.h" + + +/* Maximum number of iterations of NLSq to do for each image per macrocycle. */ +#define MAX_CYCLES (100) + + +static void show_help(const char *s) +{ + printf("Syntax: %s [options]\n\n", s); + printf( +"Scaling and post refinement for coherent nanocrystallography.\n" +"\n" +" -h, --help Display this help message.\n" +"\n" +" -i, --input=<filename> Specify the name of the input 'stream'.\n" +" (must be a file, not e.g. stdin)\n" +" -o, --output=<filename> Output filename. Default: facetron.hkl.\n" +" -g. --geometry=<file> Get detector geometry from file.\n" +" -b, --beam=<file> Get beam parameters from file, which provides\n" +" initial values for parameters, and nominal\n" +" wavelengths if no per-shot value is found in \n" +" an HDF5 file.\n" +" -x, --prefix=<p> Prefix filenames from input file with <p>.\n" +" --basename Remove the directory parts of the filenames.\n" +" --no-check-prefix Don't attempt to correct the --prefix.\n" +" -y, --symmetry=<sym> Merge according to symmetry <sym>.\n" +" -n, --iterations=<n> Run <n> cycles of scaling and post-refinement.\n" +"\n" +" -j <n> Run <n> analyses in parallel.\n"); +} + + +struct refine_args +{ + const char *sym; + ReflItemList *obs; + double *i_full; + struct image *image; + FILE *graph; + FILE *pgraph; +}; + + +static void refine_image(int mytask, void *tasks) +{ + struct refine_args *all_args = tasks; + struct refine_args *pargs = &all_args[mytask]; + struct image *image = pargs->image; + double nominal_photon_energy = pargs->image->beam->photon_energy; + struct hdfile *hdfile; + struct cpeak *spots; + int n, i; + double dev, last_dev; + + hdfile = hdfile_open(image->filename); + if ( hdfile == NULL ) { + ERROR("Couldn't open '%s'\n", image->filename); + return; + } else if ( hdfile_set_image(hdfile, "/data/data0") ) { + ERROR("Couldn't select path\n"); + hdfile_close(hdfile); + return; + } + + if ( hdf5_read(hdfile, pargs->image, 0, nominal_photon_energy) ) { + ERROR("Couldn't read '%s'\n", image->filename); + hdfile_close(hdfile); + return; + } + + double a, b, c, al, be, ga; + cell_get_parameters(image->indexed_cell, &a, &b, &c, &al, &be, &ga); + STATUS("Initial cell: %5.2f %5.2f %5.2f nm %5.2f %5.2f %5.2f deg\n", + a/1.0e-9, b/1.0e-9, c/1.0e-9, + rad2deg(al), rad2deg(be), rad2deg(ga)); + + spots = find_intersections(image, image->indexed_cell, &n, 0); + dev = +INFINITY; + i = 0; + do { + last_dev = dev; + dev = pr_iterate(image, pargs->i_full, pargs->sym, &spots, &n); + STATUS("Iteration %2i: mean dev = %5.2f\n", i, dev); + i++; + } while ( (fabs(last_dev - dev) > 1.0) && (i < MAX_CYCLES) ); + mean_partial_dev(image, spots, n, pargs->sym, + pargs->i_full, pargs->graph); + if ( pargs->pgraph ) { + fprintf(pargs->pgraph, "%5i %5.2f\n", mytask, dev); + } + + free(image->data); + if ( image->flags != NULL ) free(image->flags); + hdfile_close(hdfile); + free(spots); + + /* Muppet proofing */ + image->data = NULL; + image->flags = NULL; +} + + +static void refine_all(struct image *images, int n_total_patterns, + struct detector *det, const char *sym, + ReflItemList *obs, double *i_full, int nthreads, + FILE *graph, FILE *pgraph) +{ + struct refine_args *tasks; + int i; + + tasks = malloc(n_total_patterns * sizeof(struct refine_args)); + for ( i=0; i<n_total_patterns; i++ ) { + + tasks[i].sym = sym; + tasks[i].obs = obs; + tasks[i].i_full = i_full; + tasks[i].image = &images[i]; + tasks[i].graph = graph; + tasks[i].pgraph = pgraph; + + } + + run_thread_range(n_total_patterns, nthreads, "Refining", + refine_image, tasks); + + free(tasks); +} + + +static void integrate_image(struct image *image) +{ + struct cpeak *spots; + int j, n; + struct hdfile *hdfile; + double nominal_photon_energy = image->beam->photon_energy; + + hdfile = hdfile_open(image->filename); + if ( hdfile == NULL ) { + ERROR("Couldn't open '%s'\n", image->filename); + return; + } else if ( hdfile_set_image(hdfile, "/data/data0") ) { + ERROR("Couldn't select path\n"); + hdfile_close(hdfile); + return; + } + + if ( hdf5_read(hdfile, image, 0, nominal_photon_energy) ) { + ERROR("Couldn't read '%s'\n", image->filename); + hdfile_close(hdfile); + return; + } + + /* Figure out which spots should appear in this pattern */ + spots = find_intersections(image, image->indexed_cell, &n, 0); + + /* For each reflection, estimate the partiality */ + for ( j=0; j<n; j++ ) { + + signed int h, k, l; + float i_partial; + float xc, yc; + + h = spots[j].h; + k = spots[j].k; + l = spots[j].l; + + /* Don't attempt to use spots with very small + * partialities, since it won't be accurate. */ + if ( spots[j].p < 0.1 ) continue; + + /* Actual measurement of this reflection from this + * pattern? */ + /* FIXME: Coordinates aren't whole numbers */ + if ( integrate_peak(image, spots[j].x, spots[j].y, + &xc, &yc, &i_partial, NULL, NULL, + 1, 1, 0) ) { + continue; + } + + } + + free(image->data); + if ( image->flags != NULL ) free(image->flags); + hdfile_close(hdfile); + image->cpeaks = spots; + + /* Muppet proofing */ + image->data = NULL; + image->flags = NULL; +} + + +int main(int argc, char *argv[]) +{ + int c; + char *infile = NULL; + char *outfile = NULL; + char *geomfile = NULL; + char *prefix = NULL; + char *sym = NULL; + FILE *fh; + int nthreads = 1; + int config_basename = 0; + int config_checkprefix = 1; + struct detector *det; + double *i_full; + unsigned int *cts; + ReflItemList *obs; + int i; + int n_total_patterns; + struct image *images; + int n_iter = 10; + struct beam_params *beam = NULL; + + /* Long options */ + const struct option longopts[] = { + {"help", 0, NULL, 'h'}, + {"input", 1, NULL, 'i'}, + {"output", 1, NULL, 'o'}, + {"geometry", 1, NULL, 'g'}, + {"beam", 1, NULL, 'b'}, + {"prefix", 1, NULL, 'x'}, + {"basename", 0, &config_basename, 1}, + {"no-check-prefix", 0, &config_checkprefix, 0}, + {"symmetry", 1, NULL, 'y'}, + {"iterations", 1, NULL, 'n'}, + {0, 0, NULL, 0} + }; + + /* Short options */ + while ((c = getopt_long(argc, argv, "hi:g:x:j:y:o:b:", + longopts, NULL)) != -1) + { + + switch (c) { + case 'h' : + show_help(argv[0]); + return 0; + + case 'i' : + infile = strdup(optarg); + break; + + case 'g' : + geomfile = strdup(optarg); + break; + + case 'x' : + prefix = strdup(optarg); + break; + + case 'j' : + nthreads = atoi(optarg); + break; + + case 'y' : + sym = strdup(optarg); + break; + + case 'o' : + outfile = strdup(optarg); + break; + + case 'n' : + n_iter = atoi(optarg); + break; + + case 'b' : + beam = get_beam_parameters(optarg); + if ( beam == NULL ) { + ERROR("Failed to load beam parameters" + " from '%s'\n", optarg); + return 1; + } + break; + + case 0 : + break; + + default : + return 1; + } + + } + + /* Sanitise input filename and open */ + if ( infile == NULL ) { + infile = strdup("-"); + } + if ( strcmp(infile, "-") == 0 ) { + fh = stdin; + } else { + fh = fopen(infile, "r"); + } + if ( fh == NULL ) { + ERROR("Failed to open input file '%s'\n", infile); + return 1; + } + free(infile); + + /* Sanitise output filename */ + if ( outfile == NULL ) { + outfile = strdup("facetron.hkl"); + } + + /* Sanitise prefix */ + if ( prefix == NULL ) { + prefix = strdup(""); + } else { + if ( config_checkprefix ) { + prefix = check_prefix(prefix); + } + } + + if ( sym == NULL ) sym = strdup("1"); + + /* Get detector geometry */ + det = get_detector_geometry(geomfile); + if ( det == NULL ) { + ERROR("Failed to read detector geometry from '%s'\n", geomfile); + return 1; + } + free(geomfile); + + if ( beam == NULL ) { + ERROR("You must provide a beam parameters file.\n"); + return 1; + } + + /* Prepare for iteration */ + i_full = new_list_intensity(); + obs = new_items(); + + n_total_patterns = count_patterns(fh); + STATUS("There are %i patterns to process\n", n_total_patterns); + + images = malloc(n_total_patterns * sizeof(struct image)); + if ( images == NULL ) { + ERROR("Couldn't allocate memory for images.\n"); + return 1; + } + + /* Fill in what we know about the images so far */ + rewind(fh); + for ( i=0; i<n_total_patterns; i++ ) { + + UnitCell *cell; + char *filename; + char *fnamereal; + + if ( find_chunk(fh, &cell, &filename) == 1 ) { + ERROR("Couldn't get all of the filenames and cells" + " from the input stream.\n"); + return 1; + } + + images[i].indexed_cell = cell; + + /* Mangle the filename now */ + if ( config_basename ) { + char *tmp; + tmp = safe_basename(filename); + free(filename); + filename = tmp; + } + fnamereal = malloc(1024); + snprintf(fnamereal, 1023, "%s%s", prefix, filename); + free(filename); + + images[i].filename = fnamereal; + images[i].div = beam->divergence; + images[i].bw = beam->bandwidth; + images[i].det = det; + images[i].beam = beam; + images[i].osf = 1.0; + images[i].profile_radius = 0.005e9; + + /* Muppet proofing */ + images[i].data = NULL; + images[i].flags = NULL; + + /* Get reflections from this image */ + integrate_image(&images[i]); + + progress_bar(i, n_total_patterns-1, "Loading pattern data"); + + } + fclose(fh); + free(prefix); + + cts = new_list_count(); + + /* Make initial estimates */ + STATUS("Performing initial scaling.\n"); + scale_intensities(images, n_total_patterns, sym); + + /* Iterate */ + for ( i=0; i<n_iter; i++ ) { + + FILE *fhg; + FILE *fhp; + char filename[1024]; + + STATUS("Post refinement iteration %i of %i\n", i+1, n_iter); + + snprintf(filename, 1023, "p-iteration-%i.dat", i+1); + fhg = fopen(filename, "w"); + if ( fhg == NULL ) { + ERROR("Failed to open '%s'\n", filename); + /* Nothing will be written later */ + } + + snprintf(filename, 1023, "g-iteration-%i.dat", i+1); + fhp = fopen(filename, "w"); + if ( fhp == NULL ) { + ERROR("Failed to open '%s'\n", filename); + /* Nothing will be written later */ + } + + /* Refine the geometry of all patterns to get the best fit */ + refine_all(images, n_total_patterns, det, sym, obs, i_full, + nthreads, fhg, fhp); + + /* Re-estimate all the full intensities */ + scale_intensities(images, n_total_patterns, sym); + + fclose(fhg); + fclose(fhp); + } + + /* Output results */ + write_reflections(outfile, obs, i_full, NULL, NULL, cts, NULL); + + /* Clean up */ + free(i_full); + delete_items(obs); + free(sym); + free(outfile); + free(det->panels); + free(det); + free(beam); + free(cts); + for ( i=0; i<n_total_patterns; i++ ) { + cell_free(images[i].indexed_cell); + free(images[i].filename); + } + free(images); + + return 0; +} |