/* * check_hkl.c * * Characterise reflection lists * * Copyright © 2012-2020 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * * Authors: * 2010-2017 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 "utils.h" #include "symmetry.h" #include "reflist.h" #include "reflist-utils.h" #include "cell-utils.h" static void show_help(const char *s) { printf("Syntax: %s [options] \n\n", s); printf( "Characterise an intensity list.\n" "\n" " -h, --help Display this help message.\n" " --version Print CrystFEL version number and exit.\n" " -y, --symmetry= The symmetry of the input file.\n" " -p, --pdb= Unit cell file to use (PDB or CrystFEL format).\n" " --rmin= Low resolution cutoff (1/d in m^-1).\n" " --rmax= High resolution cutoff (1/d in m^-1).\n" " --lowres= Low resolution cutoff in (d in A).\n" " --highres= High resolution cutoff in (d in A).\n" " --sigma-cutoff= Discard reflections with I/sigma(I) < n.\n" " --nshells= Use resolution shells or bins.\n" " --wilson Calculate a Wilson plot\n" " --ltest Perform an L-test (for twinning)\n" " --shell-file= Write results table to .\n" " --ignore-negs Ignore reflections with negative intensities.\n" " --zero-negs Set negative intensities to zero.\n" "\n"); } static int add_ltest(RefList *list, double i1, int *bins, int nbins, double step, const SymOpList *sym, double *lt, double *l2t, signed int h1, signed int k1, signed int l1, signed int h2, signed int k2, signed int l2) { Reflection *refl; double i2, L; int bin; if ( SERIAL(h1, k1, l1) > SERIAL(h2, k2, l2) ) return 0; refl = find_refl(list, h2, k2, l2); if ( refl == NULL ) { signed int h, k, l; if ( !find_equiv_in_list(list, h2, k2, l2, sym, &h, &k, &l) ) { return 0; } refl = find_refl(list, h, k, l); } i2 = get_intensity(refl); L = (i1-i2) / (i1+i2); if ( isnan(L) ) { /* This happens with --zero-negs and two negative intensities, * because L=(0-0)/(0+0) */ return 0; } bin = fabs(L)/step; if ( (bin < 0) || (isnan(L)) ) { bin = 0; } else if ( bin >= nbins ) { bin = nbins-1; } bins[bin]++; *lt += fabs(L); *l2t += pow(L, 2.0); return 1; } static void l_test(RefList *list, UnitCell *cell, const SymOpList *sym, double rmin_fix, double rmax_fix, int nbins, const char *filename) { Reflection *refl; RefListIterator *iter; int *bins; FILE *fh; int npairs, i; double tot; double lt = 0.0; double l2t = 0.0; const double step = 1.0/nbins; int hd, kd, ld; const char cen = cell_get_centering(cell); bins = malloc(nbins*sizeof(int)); if ( bins == NULL ) return; for ( i=0; i = %.3f (ideal untwinned %.3f, twinned %.3f)\n", lt/npairs, 1.0/2.0, 3.0/8.0); STATUS(" = %.3f (ideal untwinned %.3f, twinned %.3f)\n", l2t/npairs, 1.0/3.0, 1.0/5.0); fh = fopen(filename, "w"); if ( fh == NULL ) return; tot = 0.0; fprintf(fh, " |L| N(|L|) untwinned twinned\n"); fprintf(fh, "%.3f %7.3f %9.3f %7.3f\n", 0.0, tot, 0.0, 0.0); for ( i=0; i 0.0 ) rmin = rmin_fix; if ( rmax_fix > 0.0 ) rmax = rmax_fix; s2min = pow(rmin/2.0, 2.0); s2max = pow(rmax/2.0, 2.0); s2step = (s2max - s2min)/nbins; plot_i = malloc(nbins*sizeof(double)); if ( plot_i == NULL ) return; for ( i=0; i/eE nrefl\n"); for ( i=0; i 0.0 ) rmin = rmin_fix; if ( rmax_fix > 0.0 ) rmax = rmax_fix; total_vol = pow(rmax, 3.0) - pow(rmin, 3.0); vol_per_shell = total_vol / nshells; rmins[0] = rmin; for ( i=1; irmins[i]) && (d<=rmaxs[i]) ) { bin = i; break; } } if ( bin == -1 ) continue; if ( find_refl(counted, hs, ks, ls) != NULL ) continue; add_refl(counted, hs, ks, ls); possible[bin]++; possible_tot++; } } } reflist_free(counted); /* Calculate means */ for ( refl = first_refl(list, &iter); refl != NULL; refl = next_refl(refl, iter) ) { signed int h, k, l, hs, ks, ls; double d, val, esd; int bin; int j; get_indices(refl, &h, &k, &l); if ( forbidden_reflection(cell, h, k, l) ) continue; get_asymm(sym, h, k, l, &hs, &ks, &ls); d = resolution(cell, hs, ks, ls) * 2.0; val = get_intensity(refl); esd = get_esd_intensity(refl); bin = -1; for ( j=0; jrmins[j]) && (d<=rmaxs[j]) ) { bin = j; break; } } if ( bin == -1 ) continue; measured[bin]++; mean[bin] += get_intensity(refl); if ( !isfinite(val/esd) ) nsilly++; } for ( i=0; irmins[j]) && (d<=rmaxs[j]) ) { bin = j; break; } } if ( bin == -1 ) { nout++; continue; } /* measured[bin] was done earlier */ measurements[bin] += get_redundancy(refl); if ( isfinite(val/esd) ) { snr[bin] += val / esd; snr_total += val / esd; snr_measured[bin]++; } else { nsilly++; } nrefl++; nmeastot += get_redundancy(refl); var[bin] += pow(val-mean[bin], 2.0); } STATUS("Overall values within specified resolution range:\n"); STATUS("%li measurements in total.\n", nmeastot); STATUS("%li reflections in total.\n", nrefl); STATUS("%li reflections possible.\n", possible_tot); STATUS("Overall = %f\n", snr_total/(double)nrefl); STATUS("Overall redundancy = %f measurements/unique reflection\n", nmeastot/(double)nrefl); STATUS("Overall completeness = %f %%\n", 100.0*nrefl/(double)possible_tot); if ( nout ) { STATUS("WARNING; %li reflections outside resolution range.\n", nout); } if ( nsilly ) { STATUS("WARNING; %li reflections had infinite or invalid values" " of I/sigma(I).\n", nsilly); } fprintf(fh, "Center 1/nm # refs Possible Compl " "Meas Red SNR Std dev Mean d(A) " "Min 1/nm Max 1/nm\n"); for ( i=0; i 0.0 ) { double res = 2.0*resolution(cell, h, k, l); if ( res < rmin_fix ) { nres++; continue; } } if ( rmax_fix > 0.0 ) { double res = 2.0*resolution(cell, h, k, l); if ( res > rmax_fix ) { nres++; continue; } } if ( ig ) continue; new = add_refl(list, h, k, l); copy_data(new, refl); } STATUS("Discarded %i reflections (out of %i) with I/sigma(I) < %f\n", rej, num_reflections(raw_list), sigma_cutoff); reflist_free(raw_list); if ( ignorenegs && (nneg > 0) ) { STATUS("Discarded %i reflections because they had negative " "intensities.\n", nneg); } if ( zeronegs && (nneg > 0) ) { STATUS("Set %i negative intensities to zero\n", nneg); } if ( nres > 0 ) { STATUS("%i reflections rejected because they were outside the " "resolution range.\n", nres); } if ( wilson ) { if ( !have_nshells ) nshells = 50; wilson_plot(list, cell, sym, rmin_fix, rmax_fix, nshells, shell_file); } else if ( ltest ) { if ( !have_nshells ) nshells = 50; if ( !ignorenegs && !zeronegs ) { ERROR("For the L-test you must specify either" "--ignore-negs or --zero-negs.\n"); return 1; } l_test(list, cell, sym, rmin_fix, rmax_fix, nshells, shell_file); } else { plot_shells(list, cell, sym, rmin_fix, rmax_fix, nshells, shell_file); } free_symoplist(sym); reflist_free(list); cell_free(cell); free(shell_file); return 0; }