/* * predict-refine.c * * Prediction refinement * * Copyright © 2012-2021 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * * Authors: * 2010-2020 Thomas White * 2016 Valerio Mariani * * 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 . * */ #include #include #include #include #include #include "image.h" #include "geometry.h" #include "cell-utils.h" /** \file predict-refine.h */ /* Maximum number of iterations of NLSq to do for each image per macrocycle. */ #define MAX_CYCLES (10) /* Weighting of excitation error term (m^-1) compared to position term (m) */ #define EXC_WEIGHT (4e-20) /* Parameters to refine */ static const enum gparam rv[] = { GPARAM_ASX, GPARAM_ASY, GPARAM_ASZ, GPARAM_BSX, GPARAM_BSY, GPARAM_BSZ, GPARAM_CSX, GPARAM_CSY, GPARAM_CSZ, GPARAM_DETX, GPARAM_DETY, }; static const int num_params = 11; struct reflpeak { Reflection *refl; struct imagefeature *peak; double Ih; /* normalised */ struct detgeom_panel *panel; /* panel the reflection appears on * (we assume this never changes) */ }; static void twod_mapping(double fs, double ss, double *px, double *py, struct detgeom_panel *p, double dx, double dy) { double xs, ys; xs = fs*p->fsx + ss*p->ssx; /* pixels */ ys = fs*p->fsy + ss*p->ssy; /* pixels */ *px = (xs + p->cnx) * p->pixel_pitch + dx; /* metres */ *py = (ys + p->cny) * p->pixel_pitch + dy; /* metres */ } static double r_dev(struct reflpeak *rp) { /* Excitation error term */ return get_exerr(rp->refl); } static double x_dev(struct reflpeak *rp, struct detgeom *det, double dx, double dy) { /* Peak position term */ double xpk, ypk, xh, yh; double fsh, ssh; twod_mapping(rp->peak->fs, rp->peak->ss, &xpk, &ypk, rp->panel, dx, dy); get_detector_pos(rp->refl, &fsh, &ssh); twod_mapping(fsh, ssh, &xh, &yh, rp->panel, dx, dy); return xh-xpk; } static double y_dev(struct reflpeak *rp, struct detgeom *det, double dx, double dy) { /* Peak position term */ double xpk, ypk, xh, yh; double fsh, ssh; twod_mapping(rp->peak->fs, rp->peak->ss, &xpk, &ypk, rp->panel, dx, dy); get_detector_pos(rp->refl, &fsh, &ssh); twod_mapping(fsh, ssh, &xh, &yh, rp->panel, dx, dy); return yh-ypk; } static int cmpd2(const void *av, const void *bv) { struct reflpeak *a, *b; a = (struct reflpeak *)av; b = (struct reflpeak *)bv; if ( fabs(r_dev(a)) < fabs(r_dev(b)) ) return -1; return 1; } static int check_outlier_transition(struct reflpeak *rps, int n, struct detgeom *det) { int i; if ( n < 3 ) return n; qsort(rps, n, sizeof(struct reflpeak), cmpd2); for ( i=1; ifeatures); i++ ) { struct imagefeature *f; double h, k, l, hd, kd, ld; Reflection *refl; double r[3]; /* Assume all image "features" are genuine peaks */ f = image_get_feature(image->features, i); if ( f == NULL ) continue; detgeom_transform_coords(&image->detgeom->panels[f->pn], f->fs, f->ss, image->lambda, dx, dy, r); /* Decimal and fractional Miller indices of nearest reciprocal * lattice point */ hd = r[0] * ax + r[1] * ay + r[2] * az; kd = r[0] * bx + r[1] * by + r[2] * bz; ld = r[0] * cx + r[1] * cy + r[2] * cz; h = lrint(hd); k = lrint(kd); l = lrint(ld); /* Don't pair with 000, because that can cause trouble later */ if ( (h==0) && (k==0) && (l==0) ) continue; if ( (abs(h)>=512) || (abs(k)>=512) || (abs(l)>=512) ) { ERROR("Peak %i (on panel %s at %.2f,%.2f) has indices too " "large for pairing (%.0f %.0f %.0f)\n", i, image->detgeom->panels[f->pn].name, f->fs, f->ss, h, k, l); continue; } refl = reflection_new(h, k, l); if ( refl == NULL ) { ERROR("Failed to create reflection\n"); return 0; } add_refl_to_list(refl, all_reflist); set_symmetric_indices(refl, h, k, l); /* It doesn't matter if the actual predicted location * doesn't fall on this panel. We're only interested * in how far away it is from the peak location. * The predicted position and excitation errors will be * filled in by update_predictions(). */ set_panel_number(refl, f->pn); rps[n].refl = refl; rps[n].peak = f; rps[n].panel = &image->detgeom->panels[f->pn]; n++; } /* Get the excitation errors and detector positions for the candidate * reflections */ crystal_set_reflections(cr, all_reflist); update_predictions(cr); /* Pass over the peaks again, keeping only the ones which look like * good pairings */ for ( i=0; ifs, 2.0) + pow(ss - rps[i].peak->ss, 2.0); if ( pd > 10.0 * 10.0 ) continue; /* FIXME Hardcoded distance (GitLab #38) */ rps[n_acc] = rps[i]; rps[n_acc].refl = reflection_new(h, k, l); copy_data(rps[n_acc].refl, refl); n_acc++; } reflist_free(all_reflist); /* Sort the pairings by excitation error and look for a transition * between good pairings and outliers */ n_final = check_outlier_transition(rps, n_acc, image->detgeom); /* Add the final accepted reflections to the caller's list */ if ( reflist != NULL ) { for ( i=0; ifeatures) * sizeof(struct reflpeak)); if ( rps == NULL ) return 1; reflist = reflist_new(); n_acc = pair_peaks(image, cr, reflist, rps); if ( n_acc < 3 ) { free(rps); reflist_free(reflist); return 1; } crystal_set_reflections(cr, reflist); update_predictions(cr); crystal_set_reflections(cr, NULL); qsort(rps, n_acc, sizeof(struct reflpeak), cmpd2); n = (n_acc-1) - n_acc/50; if ( n < 2 ) n = 2; /* n_acc is always >= 2 */ crystal_set_profile_radius(cr, fabs(r_dev(&rps[n]))); reflist_free(reflist); free(rps); return 0; } static int iterate(struct reflpeak *rps, int n, UnitCell *cell, struct image *image, double *total_x, double *total_y, double *total_z) { int i; gsl_matrix *M; gsl_vector *v; gsl_vector *shifts; double asx, asy, asz; double bsx, bsy, bsz; double csx, csy, csz; /* Number of parameters to refine */ M = gsl_matrix_calloc(num_params, num_params); v = gsl_vector_calloc(num_params); for ( i=0; i k ) continue; M_c = w * gradients[g] * gradients[k]; M_curr = gsl_matrix_get(M, k, g); gsl_matrix_set(M, k, g, M_curr + M_c); gsl_matrix_set(M, g, k, M_curr + M_c); } v_c = w * r_dev(&rps[i]); v_c *= -gradients[k]; v_curr = gsl_vector_get(v, k); gsl_vector_set(v, k, v_curr + v_c); } /* Positional x terms */ for ( k=0; k k ) continue; M_c = gradients[g] * gradients[k]; M_curr = gsl_matrix_get(M, k, g); gsl_matrix_set(M, k, g, M_curr + M_c); gsl_matrix_set(M, g, k, M_curr + M_c); } v_c = x_dev(&rps[i], image->detgeom, *total_x, *total_y); v_c *= -gradients[k]; v_curr = gsl_vector_get(v, k); gsl_vector_set(v, k, v_curr + v_c); } /* Positional y terms */ for ( k=0; k k ) continue; M_c = gradients[g] * gradients[k]; M_curr = gsl_matrix_get(M, k, g); gsl_matrix_set(M, k, g, M_curr + M_c); gsl_matrix_set(M, g, k, M_curr + M_c); } v_c = y_dev(&rps[i], image->detgeom, *total_x, *total_y); v_c *= -gradients[k]; v_curr = gsl_vector_get(v, k); gsl_vector_set(v, k, v_curr + v_c); } } int k; for ( k=0; kfeatures) * sizeof(struct reflpeak)); if ( rps == NULL ) return 1; reflist = reflist_new(); n = pair_peaks(image, cr, reflist, rps); if ( n < 10 ) { free(rps); reflist_free(reflist); return 1; } crystal_set_reflections(cr, reflist); crystal_get_det_shift(cr, &total_x, &total_y); orig_shift_x = total_x; orig_shift_y = total_y; /* Normalise the intensities to max 1 */ max_I = -INFINITY; for ( i=0; iintensity; if ( cur_I > max_I ) max_I = cur_I; } if ( max_I <= 0.0 ) { ERROR("All peaks negative?\n"); free(rps); return 1; } for ( i=0; iintensity / max_I; } //STATUS("Initial residual = %e\n", // pred_residual(rps, n, image->detgeom, total_x, total_y)); /* Refine */ for ( i=0; idetgeom, total_x, total_y)); } //STATUS("Final residual = %e\n", // pred_residual(rps, n, image->detgeom, total_x, total_y)); snprintf(tmp, 255, "predict_refine/final_residual = %e", pred_residual(rps, n, image->detgeom, total_x, total_y)); crystal_add_notes(cr, tmp); crystal_set_det_shift(cr, total_x, total_y); crystal_set_reflections(cr, NULL); reflist_free(reflist); n = pair_peaks(image, cr, NULL, rps); free_rps_noreflist(rps, n); if ( n < 10 ) { crystal_set_det_shift(cr, orig_shift_x, orig_shift_y); return 1; } return 0; }