/* * partialator.c * * Scaling and post refinement for coherent nanocrystallography * * Copyright © 2012 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * * Authors: * 2010-2012 Thomas White * * 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 . * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "post-refinement.h" #include "hrs-scaling.h" #include "scaling-report.h" 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= Specify the name of the input 'stream'.\n" " (must be a file, not e.g. stdin)\n" " -o, --output= Output filename. Default: partialator.hkl.\n" " -g. --geometry= Get detector geometry from file.\n" " -b, --beam= 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" " -y, --symmetry= Merge according to symmetry .\n" " -n, --iterations= Run cycles of scaling and post-refinement.\n" " --no-scale Fix all the scaling factors at unity.\n" " -r, --reference= Refine images against reflections in ,\n" " instead of taking the mean of the intensity\n" " estimates.\n" "\n" " -j Run analyses in parallel.\n"); } struct refine_args { RefList *full; Crystal *crystal; }; struct queue_args { int n_started; int n_done; Crystal **crystals; int n_crystals; struct refine_args task_defaults; }; static void refine_image(void *task, int id) { struct refine_args *pargs = task; Crystal *cr = pargs->crystal; pr_refine(cr, pargs->full); } static void *get_image(void *vqargs) { struct refine_args *task; struct queue_args *qargs = vqargs; task = malloc(sizeof(struct refine_args)); memcpy(task, &qargs->task_defaults, sizeof(struct refine_args)); task->crystal = qargs->crystals[qargs->n_started]; qargs->n_started++; return task; } static void done_image(void *vqargs, void *task) { struct queue_args *qargs = vqargs; qargs->n_done++; progress_bar(qargs->n_done, qargs->n_crystals, "Refining"); free(task); } static void refine_all(Crystal **crystals, int n_crystals, struct detector *det, RefList *full, int nthreads) { struct refine_args task_defaults; struct queue_args qargs; task_defaults.full = full; task_defaults.crystal = NULL; qargs.task_defaults = task_defaults; qargs.n_started = 0; qargs.n_done = 0; qargs.n_crystals = n_crystals; qargs.crystals = crystals; /* Don't have threads which are doing nothing */ if ( n_crystals < nthreads ) nthreads = n_crystals; run_threads(nthreads, refine_image, get_image, done_image, &qargs, n_crystals, 0, 0, 0); } /* Decide which reflections can be scaled */ static int select_scalable_reflections(RefList *list, RefList *reference) { Reflection *refl; RefListIterator *iter; int nobs = 0; for ( refl = first_refl(list, &iter); refl != NULL; refl = next_refl(refl, iter) ) { int sc = 1; double v, esd; /* This means the reflection was not found on the last check */ if ( get_redundancy(refl) == 0 ) sc = 0; if ( get_partiality(refl) < 0.1 ) sc = 0; v = fabs(get_intensity(refl)); esd = get_esd_intensity(refl); if ( v < 0.5*esd ) sc = 0; /* If we are scaling against a reference set, we additionally * require that this reflection is in the reference list. */ if ( reference != NULL ) { signed int h, k, l; get_indices(refl, &h, &k, &l); if ( find_refl(reference, h, k, l) == NULL ) sc = 0; } set_scalable(refl, sc); if ( sc ) nobs++; } return nobs; } static void select_reflections_for_refinement(Crystal **crystals, int n, RefList *full, int have_reference) { int i; for ( i=0; i= 2) || have_reference ) { set_refinable(refl, 1); n_acc++; } else { n_fewmatch++; } } else { n_nomatch++; set_refinable(refl, 0); } } } //STATUS("Image %4i: %i guide reflections accepted " // "(%i not scalable, %i few matches, %i total)\n", // i, n_acc, n_noscale, n_fewmatch, n_ref); /* This would be a silly situation, since there must be a match * if THIS pattern has a scalable part of the reflection! */ assert(n_nomatch == 0); } } static void display_progress(int n_images, int n_crystals) { if ( !isatty(STDERR_FILENO) ) return; if ( tcgetpgrp(STDERR_FILENO) != getpgrp() ) return; pthread_mutex_lock(&stderr_lock); fprintf(stderr, "\r%i images loaded, %i crystals.", n_images, n_crystals); pthread_mutex_unlock(&stderr_lock); fflush(stdout); } int main(int argc, char *argv[]) { int c; char *infile = NULL; char *outfile = NULL; char *geomfile = NULL; char *sym_str = NULL; SymOpList *sym; int nthreads = 1; struct detector *det; int i; struct image *images; int n_iter = 10; struct beam_params *beam = NULL; RefList *full; int n_images = 0; int n_crystals = 0; int nobs; char *reference_file = NULL; RefList *reference = NULL; int n_dud; int have_reference = 0; char cmdline[1024]; SRContext *sr; int noscale = 0; Stream *st; Crystal **crystals; /* 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'}, {"symmetry", 1, NULL, 'y'}, {"iterations", 1, NULL, 'n'}, {"no-scale", 0, &noscale, 1}, {"reference", 1, NULL, 'r'}, {0, 0, NULL, 0} }; cmdline[0] = '\0'; for ( i=1; idet = det; if ( read_chunk(st, cur) != 0 ) { break; } /* Won't be needing this, if it exists */ image_feature_list_free(cur->features); cur->features = NULL; cur->div = beam->divergence; cur->bw = beam->bandwidth; cur->width = det->max_fs; cur->height = det->max_ss; cur->data = NULL; cur->flags = NULL; cur->beam = NULL; n_images++; for ( i=0; in_crystals; i++ ) { Crystal *cr; Crystal **crystals_new; crystals_new = realloc(crystals, (n_crystals+1)*sizeof(Crystal *)); if ( crystals_new == NULL ) { ERROR("Failed to allocate memory for crystal " "list.\n"); return 1; } crystals = crystals_new; crystals[n_crystals] = cur->crystals[i]; cr = crystals[n_crystals]; crystal_set_image(cr, cur); /* Fill in initial estimates of stuff */ crystal_set_osf(cr, 1.0); crystal_set_profile_radius(cr, beam->profile_radius); crystal_set_user_flag(cr, 0); /* This is the raw list of reflections */ as = asymmetric_indices(crystal_get_reflections(cr), sym); crystal_set_reflections(cr, as); update_partialities(cr); nobs += select_scalable_reflections(as, reference); n_crystals++; } display_progress(n_images, n_crystals); } while ( 1 ); close_stream(st); /* Make initial estimates */ STATUS("\nPerforming initial scaling.\n"); if ( noscale ) STATUS("Scale factors fixed at 1.\n"); full = scale_intensities(crystals, n_crystals, reference, nthreads, noscale); sr = sr_titlepage(crystals, n_crystals, "scaling-report.pdf", infile, cmdline); sr_iteration(sr, 0, crystals, n_crystals, full); /* Iterate */ for ( i=0; i