/* * partialator.c * * Scaling and post refinement for coherent nanocrystallography * * Copyright © 2012-2015 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * * Authors: * 2010-2015 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 "version.h" #include "post-refinement.h" #include "hrs-scaling.h" #include "scaling-report.h" #include "rejection.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" " --version Print CrystFEL version number and exit.\n" "\n" " -i, --input= Specify the name of the input 'stream'.\n" " -o, --output= Output filename. Default: partialator.hkl.\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" " -m, --model= Specify partiality model.\n" " --min-measurements= Minimum number of measurements to require.\n" " --no-polarisation Disable polarisation correction.\n" " --max-adu= Saturation value of detector.\n" " -j Run analyses in parallel.\n"); } struct refine_args { RefList *full; Crystal *crystal; PartialityModel pmodel; int no_scale; struct prdata prdata; }; struct queue_args { int n_started; int n_done; Crystal **crystals; int n_crystals; struct srdata *srdata; struct refine_args task_defaults; }; static void refine_image(void *task, int id) { struct refine_args *pargs = task; Crystal *cr = pargs->crystal; pargs->prdata = pr_refine(cr, pargs->full, pargs->pmodel, pargs->no_scale); } 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; struct refine_args *pargs = task; qargs->n_done++; if ( pargs->prdata.refined ) { qargs->srdata->n_refined += pargs->prdata.refined; qargs->srdata->n_filtered += pargs->prdata.n_filtered; } progress_bar(qargs->n_done, qargs->n_crystals, "Refining"); free(task); } static void refine_all(Crystal **crystals, int n_crystals, RefList *full, int nthreads, PartialityModel pmodel, int no_scale, struct srdata *srdata) { struct refine_args task_defaults; struct queue_args qargs; task_defaults.full = full; task_defaults.crystal = NULL; task_defaults.pmodel = pmodel; task_defaults.prdata.refined = 0; task_defaults.prdata.n_filtered = 0; task_defaults.no_scale = no_scale; qargs.task_defaults = task_defaults; qargs.n_started = 0; qargs.n_done = 0; qargs.n_crystals = n_crystals; qargs.crystals = crystals; qargs.srdata = srdata; /* 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); STATUS("%5.2f eigenvalues filtered on final iteration per successfully " "refined crystal\n", (double)srdata->n_filtered/srdata->n_refined); } 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); } static const char *str_flags(Crystal *cr) { switch ( crystal_get_user_flag(cr) ) { case 0 : return "OK"; case 1 : return "bad scaling"; case 2 : return "not enough reflections"; case 3 : return "PR solve failed"; case 4 : return "PR lost too many reflections"; case 5 : return "Early rejection"; default : return "Unknown flag"; } } static RefList *apply_max_adu(RefList *list, double max_adu) { RefList *nlist; Reflection *refl; RefListIterator *iter; nlist = reflist_new(); if ( nlist == NULL ) return NULL; for ( refl = first_refl(list, &iter); refl != NULL; refl = next_refl(refl, iter) ) { if ( get_peak(refl) < max_adu ) { signed int h, k, l; get_indices(refl, &h, &k, &l); Reflection *nrefl = add_refl(nlist, h, k, l); copy_data(nrefl, refl); } } reflist_free(list); return nlist; } static void skip_to_end(FILE *fh) { int c; do { c = fgetc(fh); } while ( (c != '\n') && (c != EOF) ); } static int set_initial_params(Crystal *cr, FILE *fh) { if ( fh != NULL ) { int err; int n; float osf, B; err = fscanf(fh, "%i %f %f", &n, &osf, &B); if ( err != 3 ) { ERROR("Failed to read parameters.\n"); return 1; } crystal_set_osf(cr, osf); crystal_set_Bfac(cr, B*1e-20); skip_to_end(fh); } else { crystal_set_osf(cr, 0.0); crystal_set_Bfac(cr, 0.0); } return 0; } static void show_duds(Crystal **crystals, int n_crystals) { int j; int n_dud = 0; int n_noscale = 0; int n_noref = 0; int n_solve = 0; int n_early = 0; for ( j=0; jdiv = NAN; cur->bw = NAN; cur->det = NULL; if ( read_chunk_2(st, cur, STREAM_READ_REFLECTIONS | STREAM_READ_UNITCELL) != 0 ) { break; } if ( isnan(cur->div) || isnan(cur->bw) ) { ERROR("Chunk doesn't contain beam parameters.\n"); return 1; } n_images++; for ( i=0; in_crystals; i++ ) { Crystal *cr; Crystal **crystals_new; RefList *cr_refl; 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]; /* Image pointer will change due to later reallocs */ crystal_set_image(cr, NULL); /* This is the raw list of reflections */ cr_refl = crystal_get_reflections(cr); cr_refl = apply_max_adu(cr_refl, max_adu); if ( polarisation ) { polarisation_correction(cr_refl, crystal_get_cell(cr), cur); } as = asymmetric_indices(cr_refl, sym); crystal_set_reflections(cr, as); crystal_set_user_flag(cr, 0); reflist_free(cr_refl); if ( set_initial_params(cr, sparams_fh) ) { ERROR("Failed to set initial parameters\n"); return 1; } n_crystals++; } if ( n_images % 100 == 0 ) { display_progress(n_images, n_crystals); } } while ( 1 ); display_progress(n_images, n_crystals); fprintf(stderr, "\n"); if ( sparams_fh != NULL ) fclose(sparams_fh); close_stream(st); /* Fill in image pointers */ for ( i=0; idiv, str_flags(crystals[i])); } fclose(fh); } /* Clean up */ for ( i=0; i