/* * rejection.c * * Crystal rejection for scaling * * Copyright © 2012-2018 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * * Authors: * 2010-2018 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 "crystal.h" #include "reflist.h" #include "rejection.h" #include "cell-utils.h" #include "post-refinement.h" #include "merge.h" static double mean_intensity(RefList *list) { Reflection *refl; RefListIterator *iter; double total = 0.0; int n = 0; for ( refl = first_refl(list, &iter); refl != NULL; refl = next_refl(refl, iter) ) { total += get_intensity(refl); n++; } return total/n; } /* Reject really obvious outliers */ void early_rejection(Crystal **crystals, int n) { int i; double m = 0.0; double mean_m; FILE *fh = fopen("reject.dat", "w"); int n_flag = 0; for ( i=0; icontrib_crystals[0]), h, k, l); /* Mean of contributions */ for ( j=0; jn_contrib; j++ ) { double Ii, G, B; G = crystal_get_osf(c->contrib_crystals[j]); B = crystal_get_Bfac(c->contrib_crystals[j]); Ii = correct_reflection(c->contribs[j], G, B, res); Ex += Ii - K; Ex2 += (Ii - K) * (Ii - K); } if ( c->n_contrib < 2 ) continue; set_temp1(refl, Ex); set_temp2(refl, Ex2); } return 0; } static double calculate_cchalf(RefList *template, RefList *full, Crystal *exclude, int *pnref) { Reflection *trefl; RefListIterator *iter; double sig2E, sig2Y; int n = 0; double wSum = 0.0; double wSum2 = 0.0; double mean = 0.0; double S = 0.0; double all_sum_var = 0.0; signed int oh = 0; signed int ok = 0; signed int ol = 0; /* "template" is the list of reflections to be included in CChalf */ for ( trefl = first_refl(template, &iter); trefl != NULL; trefl = next_refl(trefl, iter) ) { signed int h, k, l; double refl_mean, refl_var; double Ex, Ex2, K; int n_removed = 0; double w = 1.0; double meanOld; double res; struct reflection_contributions *c; Reflection *refl; Reflection *exrefl; /* The values we need are stored in the "full" list, not the * template list */ get_indices(trefl, &h, &k, &l); if ( (h==oh) && (k==ok) && (l==ol) ) continue; oh = h; ok = k; ol = l; refl = find_refl(full, h, k, l); if ( refl == NULL ) continue; /* However, there might not have * been enough measurements for * it to appear in "full" */ /* We use the mean (merged) intensity as the reference point * for shifting the data in the variance calculation */ K = get_intensity(refl); Ex = get_temp1(refl); Ex2 = get_temp2(refl); c = get_contributions(refl); assert(c != NULL); /* Resolution from first contributing crystal, like above */ res = resolution(crystal_get_cell(c->contrib_crystals[0]), h, k, l); /* Remove contribution(s) from the excluded crystal. * If the crystal is marked as bad, we should not remove it * because it did not contribute in the first place. */ if ( exclude != NULL && !crystal_get_user_flag(exclude) ) { exrefl = find_refl(crystal_get_reflections(exclude), h, k, l); } else { exrefl = NULL; } while ( exrefl != NULL ) { double G, B; G = crystal_get_osf(exclude); B = crystal_get_Bfac(exclude); if ( get_partiality(exrefl) > MIN_PART_MERGE ) { double Ii = correct_reflection(exrefl, G, B, res); /* Remove contribution of this reflection */ Ex -= Ii - K; Ex2 -= (Ii - K)*(Ii - K); n_removed++; } exrefl = next_found_refl(exrefl); } if ( c->n_contrib - n_removed < 2 ) continue; refl_mean = K + (Ex / (c->n_contrib - n_removed)); refl_var = (Ex2 - (Ex*Ex)/(c->n_contrib - n_removed)) / (c->n_contrib - n_removed - 1); refl_var /= (c->n_contrib - n_removed) / 2.0; all_sum_var += refl_var; n++; /* Running variance calculation to get sig2Y */ wSum += w; wSum2 += w*w; meanOld = mean; mean = meanOld + (w/wSum) * (refl_mean - meanOld); S += w * (refl_mean - meanOld) * (refl_mean - mean); } sig2E = all_sum_var / n; sig2Y = S / (wSum - 1.0); if ( pnref != NULL ) { *pnref = n; } return (sig2Y - 0.5*sig2E) / (sig2Y + 0.5*sig2E); } static void check_deltacchalf(Crystal **crystals, int n, RefList *full) { double cchalf; int i; double *vals; double mean, sd; int nref = 0; int nnan = 0; int nnon = 0; if ( calculate_refl_mean_var(full) ) { STATUS("No reflection contributions for deltaCChalf " "calculation (using reference reflections?)\n"); return; } cchalf = calculate_cchalf(full, full, NULL, &nref); STATUS("Overall CChalf = %f %% (%i reflections)\n", cchalf*100.0, nref); vals = malloc(n*sizeof(double)); if ( vals == NULL ) { ERROR("Not enough memory for deltaCChalf check\n"); return; } for ( i=0; i 0 ) { STATUS("WARNING: %i patterns had no reflections in deltaCChalf " "calculation (I set deltaCChalf=zero for them)\n", nnon); } if ( nnan > 0 ) { STATUS("WARNING: %i NaN or inf deltaCChalf values were " "replaced with zero\n", nnan); } mean = gsl_stats_mean(vals, 1, n); sd = gsl_stats_sd_m(vals, 1, n, mean); STATUS("deltaCChalf = %f ± %f %%\n", mean*100.0, sd*100.0); for ( i=0; i max_B ) { crystal_set_user_flag(crystals[i], PRFLAG_BIGB); } if ( crystal_get_user_flag(crystals[i]) == 0 ) n_acc++; } show_duds(crystals, n); if ( n_acc < 2 ) { ERROR("Not enough crystals left to proceed (%i). Sorry.\n", n_acc); exit(1); } }