/* * ambigator.c * * Resolve indexing ambiguities * * Copyright © 2014 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * Copyright © 2014 Wolfgang Brehm * * Authors: * 2014 Thomas White * 2014 Wolfgang Brehm * * 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 static void show_help(const char *s) { printf("Syntax: %s [options] input.stream\n\n", s); printf( "Resolve indexing ambiguities.\n" "\n" " -h, --help Display this help message.\n" "\n" " -o, --output= Output stream.\n" " -y, --symmetry= Actual (\"target\") symmetry.\n" " -w Apparent (\"source\" or \"twinned\") symmetry.\n" " -n, --iterations= Iterate times.\n" " --highres= High resolution cutoff in A.\n" " --lowres= Low resolution cutoff in A.\n" " --end-assignments= Save end assignments to file .\n" " --fg-graph= Save f and g correlation values to file .\n" " --ncorr= Use correlations per crystal. Default 1000\n" " --stop-after= Use at most the first crystals.\n" ); } #define SERIAL(h, k, l) ((((h)+512)<<20) + (((k)+512)<<10) + ((l)+512)) #define GET_H(serial) ((((serial) & 0x3ff00000)>>20)-512) #define GET_K(serial) ((((serial) & 0x000ffc00)>>10)-512) #define GET_L(serial) (((serial) & 0x000003ff)-512) struct flist { int n; unsigned int *s; float *i; unsigned int *s_reidx; float *i_reidx; }; static struct flist *asymm_and_merge(RefList *in, const SymOpList *sym, UnitCell *cell, double rmin, double rmax, SymOpList *amb) { Reflection *refl; RefListIterator *iter; RefList *asym; struct flist *f; int n; asym = reflist_new(); if ( asym == NULL ) return NULL; for ( refl = first_refl(in, &iter); refl != NULL; refl = next_refl(refl, iter) ) { signed int h, k, l; signed int ha, ka, la; Reflection *cr; double res; get_indices(refl, &h, &k, &l); res = 2.0*resolution(cell, h, k, l); if ( res < rmin ) continue; if ( res > rmax ) continue; get_asymm(sym, h, k, l, &ha, &ka, &la); if ( amb != NULL ) { signed int hr, kr, lr; signed int hra, kra, lra; get_equiv(amb, NULL, 1, ha, ka, la, &hr, &kr, &lr); get_asymm(sym, hr, kr, lr, &hra, &kra, &lra); /* Skip twin-proof reflections */ if ( (ha==hra) && (ka==kra) && (la==lra) ) { //STATUS("%i %i %i is twin proof\n", h, k, l); continue; } } cr = find_refl(asym, ha, ka, la); if ( cr == NULL ) { cr = add_refl(asym, ha, ka, la); assert(cr != NULL); copy_data(cr, refl); } else { const double i = get_intensity(cr); const int r = get_redundancy(cr); set_intensity(cr, (r*i + get_intensity(refl))/(r+1)); set_redundancy(cr, r+1); } } f = malloc(sizeof(struct flist)); if ( f == NULL ) { ERROR("Failed to allocate flist\n"); return NULL; } n = num_reflections(asym); f->s = malloc(n*sizeof(unsigned int)); f->s_reidx = malloc(n*sizeof(unsigned int)); f->i = malloc(n*sizeof(float)); f->i_reidx = malloc(n*sizeof(float)); if ( (f->s == NULL) || (f->i == NULL) || (f->s_reidx == NULL) || (f->i_reidx == NULL) ) { ERROR("Failed to allocate flist\n"); return NULL; } f->n = 0; for ( refl = first_refl(asym, &iter); refl != NULL; refl = next_refl(refl, iter) ) { signed int h, k, l; get_indices(refl, &h, &k, &l); f->s[f->n] = SERIAL(h, k, l); f->i[f->n] = get_intensity(refl); f->n++; } assert(f->n == n); if ( amb != NULL ) { RefList *reidx = reflist_new(); if ( reidx == NULL ) return NULL; for ( refl = first_refl(asym, &iter); refl != NULL; refl = next_refl(refl, iter) ) { signed int h, k, l; signed int hr, kr, lr; signed int hra, kra, lra; Reflection *cr; get_indices(refl, &h, &k, &l); get_equiv(amb, NULL, 1, h, k, l, &hr, &kr, &lr); get_asymm(sym, hr, kr, lr, &hra, &kra, &lra); cr = add_refl(reidx, hra, kra, lra); copy_data(cr, refl); } n = 0; for ( refl = first_refl(reidx, &iter); refl != NULL; refl = next_refl(refl, iter) ) { signed int h, k, l; get_indices(refl, &h, &k, &l); f->s_reidx[n] = SERIAL(h, k, l); f->i_reidx[n++] = get_intensity(refl); } reflist_free(reidx); } reflist_free(asym); return f; } static float corr(struct flist *a, struct flist *b, int *pn, int a_reidx) { float s_xy = 0.0; float s_x = 0.0; float s_y = 0.0; float s_x2 = 0.0; float s_y2 = 0.0; int n = 0; float t1, t2; int ap = 0; int bp = 0; int done = 0; unsigned int *sa; float *ia; if ( a_reidx ) { sa = a->s_reidx; ia = a->i_reidx; } else { sa = a->s; ia = a->i; } if ( (a->n == 0) || (b->n == 0) ) { *pn = 0; return 0.0; } while ( 1 ) { while ( sa[ap] > b->s[bp] ) { if ( ++bp == b->n ) { done = 1; break; } } if ( done ) break; while ( sa[ap] < b->s[bp] ) { if ( ++ap == a->n ) { done = 1; break; } } if ( done ) break; if ( sa[ap] == b->s[bp] ) { float aint, bint; aint = ia[ap]; bint = b->i[bp]; s_xy += aint*bint; s_x += aint; s_y += bint; s_x2 += aint*aint; s_y2 += bint*bint; n++; if ( ++ap == a->n ) break; if ( ++bp == b->n ) break; } } *pn = n; t1 = s_x2 - s_x*s_x / n; t2 = s_y2 - s_y*s_y / n; if ( (t1 <= 0.0) || (t2 <= 0.0) ) return 0.0; return (s_xy - s_x*s_y/n) / sqrt(t1*t2); } struct cc_list { signed int *ind; float *cc; signed int *ind_reidx; float *cc_reidx; }; static struct cc_list *calc_ccs(struct flist **crystals, int n_crystals, int ncorr, SymOpList *amb, gsl_rng *rng) { struct cc_list *ccs; int i; gsl_permutation *p; assert(n_crystals >= ncorr); ncorr++; /* Extra value at end for sentinel */ ccs = malloc(n_crystals*sizeof(struct cc_list)); if ( ccs == NULL ) return NULL; p = gsl_permutation_alloc(n_crystals); gsl_permutation_init(p); for ( i=0; idata, n_crystals, sizeof(size_t)); for ( l=0; l 0 ) { STATUS("Warning: %i crystals had no correlation\n", ndud); } STATUS("Mean f = %f, changed %i assignments this time.\n", mf/nmf, nch); } int main(int argc, char *argv[]) { int c; const char *infile; char *outfile = NULL; char *end_ass_fn = NULL; char *fg_graph_fn = NULL; char *s_sym_str = NULL; SymOpList *s_sym; char *w_sym_str = NULL; SymOpList *w_sym; SymOpList *amb; int n_iter = 1; int n_crystals, n_chunks, max_crystals; int n_dif; struct flist **crystals; Stream *st; int i; int *assignments; int *orig_assignments; gsl_rng *rng; float highres, lowres; double rmin = 0.0; /* m^-1 */ double rmax = INFINITY; /* m^-1 */ FILE *fgfh = NULL; struct cc_list *ccs; int ncorr = 1000; int stop_after = 0; /* Long options */ const struct option longopts[] = { {"help", 0, NULL, 'h'}, {"output", 1, NULL, 'o'}, {"symmetry", 1, NULL, 'y'}, {"iterations", 1, NULL, 'n'}, {"highres", 1, NULL, 2}, {"lowres", 1, NULL, 3}, {"end-assignments", 1, NULL, 4}, {"fg-graph", 1, NULL, 5}, {"ncorr", 1, NULL, 6}, {"stop-after", 1, NULL, 7}, {0, 0, NULL, 0} }; /* Short options */ while ((c = getopt_long(argc, argv, "ho:y:n:w:", longopts, NULL)) != -1) { switch (c) { case 'h' : show_help(argv[0]); return 0; case 'o' : outfile = strdup(optarg); break; case 'y' : s_sym_str = strdup(optarg); break; case 'w' : w_sym_str = strdup(optarg); break; case 'n' : n_iter = atoi(optarg); break; case 2 : if ( sscanf(optarg, "%e", &highres) != 1 ) { ERROR("Invalid value for --highres\n"); return 1; } rmax = 1.0 / (highres/1e10); break; case 3 : if ( sscanf(optarg, "%e", &lowres) != 1 ) { ERROR("Invalid value for --lowres\n"); return 1; } rmin = 1.0 / (lowres/1e10); break; case 4 : end_ass_fn = strdup(optarg); break; case 5 : fg_graph_fn = strdup(optarg); break; case 6 : if ( sscanf(optarg, "%i", &ncorr) != 1 ) { ERROR("Invalid value for --ncorr\n"); return 1; } break; case 7 : if ( sscanf(optarg, "%i", &stop_after) != 1 ) { ERROR("Invalid value for --stop-after\n"); return 1; } break; case 0 : break; case '?' : break; default : ERROR("Unhandled option '%c'\n", c); break; } } if ( argc != (optind+1) ) { ERROR("Please provide exactly one stream filename.\n"); return 1; } infile = argv[optind++]; st = open_stream_for_read(infile); if ( st == NULL ) { ERROR("Failed to open input stream '%s'\n", infile); return 1; } /* Sanitise output filename */ if ( outfile == NULL ) { outfile = strdup("partialator.hkl"); } if ( s_sym_str == NULL ) { ERROR("You must specify the input symmetry (with -y)\n"); return 1; } s_sym = get_pointgroup(s_sym_str); free(s_sym_str); if ( w_sym_str == NULL ) { w_sym = NULL; amb = NULL; } else { w_sym = get_pointgroup(w_sym_str); free(w_sym_str); if ( w_sym == NULL ) return 1; amb = get_ambiguities(w_sym, s_sym); if ( amb == NULL ) return 1; STATUS("Ambiguity operations:\n"); describe_symmetry(amb); } crystals = NULL; n_crystals = 0; max_crystals = 0; n_chunks = 0; do { struct image cur; int i; cur.det = NULL; if ( read_chunk(st, &cur) != 0 ) { break; } image_feature_list_free(cur.features); for ( i=0; i 0.5); orig_assignments[i] = assignments[i]; } if ( fg_graph_fn != NULL ) { fgfh = fopen(fg_graph_fn, "w"); if ( fgfh == NULL ) { ERROR("Failed to open '%s'\n", fg_graph_fn); } } ccs = calc_ccs(crystals, n_crystals, ncorr, amb, rng); if ( ccs == NULL ) { ERROR("Failed to allocate CCs\n"); return 1; } /* FIXME: Free crystals */ for ( i=0; i