/* * get_hkl.c * * Small program to manipulate reflection lists * * Copyright © 2013-2014 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * * Authors: * 2009-2014 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 "version.h" #include "utils.h" #include "reflist-utils.h" #include "symmetry.h" #include "beam-parameters.h" #include "cell.h" #include "cell-utils.h" static void show_help(const char *s) { printf("Syntax: %s [options]\n\n", s); printf( "Manipulate reflection lists.\n" "\n" " -h, --help Display this help message.\n" " --version Print CrystFEL version number and exit.\n" "\n" " -i, --input= Read reflections from .\n" " -y, --symmetry= The symmetry of the input reflection list.\n" " -p, --pdb= PDB file with cell parameters (needed when\n" " using a resolution cutoff)\n" "\n" "You can add noise to the reflections with either of:\n" " --poisson Simulate Poisson samples.\n" " --noise Add 10%% random noise.\n" "\n" "To calculate Poisson samples accurately, you must also give:\n" " --adu-per-photon= Number of ADU per photon.\n" "\n" "You can artificially 'twin' the reflections, or expand them out.\n" " -w, --twin= Generate twinned data according to the given\n" " point group.\n" " -e, --expand= Expand reflections to this point group.\n" " --no-need-all-parts Output a twinned reflection even if not all\n" " the necessary equivalents were present.\n" "\n" "You can reindex the reflections according to an operation, e.g. k,h,-l:\n" " --reindex= Reindex according to .\n" "\n" "Use this option with care, and only if you understand why it might sometimes\n" " be necessary:\n" " --trim-centrics Remove reflections which are duplicated in the\n" " point group specified with the '-y' option.\n" "\n" "You can restrict which reflections are written out:\n" " -t, --template= Only include reflections mentioned in file.\n" " --cutoff-angstroms= Only include reflections with d < n Angstroms.\n" "\n" "You might sometimes need to do this:\n" " --multiplicity Multiply intensities by the number of\n" " equivalent reflections.\n" "\n" "Don't forget to specify the output filename:\n" " -o, --output= Output filename (default: stdout).\n" ); } /* Apply Poisson noise to all reflections */ static void poisson_reflections(RefList *list, double adu_per_photon) { Reflection *refl; RefListIterator *iter; gsl_rng *rng; rng = gsl_rng_alloc(gsl_rng_mt19937); for ( refl = first_refl(list, &iter); refl != NULL; refl = next_refl(refl, iter) ) { double val, c; val = get_intensity(refl); c = adu_per_photon * poisson_noise(rng, val/adu_per_photon); set_intensity(refl, c); } gsl_rng_free(rng); } /* Apply 10% uniform noise to all reflections */ static void noise_reflections(RefList *list) { Reflection *refl; RefListIterator *iter; for ( refl = first_refl(list, &iter); refl != NULL; refl = next_refl(refl, iter) ) { double val, r; val = get_intensity(refl); r = (double)random()/RAND_MAX; val += 0.1 * val * r; set_intensity(refl, val); } } static RefList *template_reflections(RefList *list, RefList *template) { Reflection *refl; RefListIterator *iter; RefList *out; out = reflist_new(); for ( refl = first_refl(template, &iter); refl != NULL; refl = next_refl(refl, iter) ) { signed int h, k, l; Reflection *new; Reflection *old; get_indices(refl, &h, &k, &l); old = find_refl(list, h, k, l); if ( old == NULL ) continue; new = add_refl(out, h, k, l); copy_data(new, old); } return out; } static RefList *twin_reflections(RefList *in, int need_all_parts, const SymOpList *holo, const SymOpList *mero) { Reflection *refl; RefListIterator *iter; RefList *out; SymOpMask *m; int n; out = reflist_new(); /* No need to free and reallocate this for every reflection */ m = new_symopmask(holo); for ( refl = first_refl(in, &iter); refl != NULL; refl = next_refl(refl, iter) ) { double total, sigma; int multi; signed int h, k, l; int j; int skip; /* Figure out where to put the twinned version, and check it's * not there already. */ get_indices(refl, &h, &k, &l); get_asymm(holo, h, k, l, &h, &k, &l); if ( find_refl(out, h, k, l) != NULL ) continue; special_position(holo, m, h, k, l); n = num_equivs(holo, m); total = 0.0; sigma = 0.0; multi = 0; skip = 0; for ( j=0; j m */ cutn1 /= 1e10; cutn2 /= 1e10; cutn3 /= 1e10; } else { char *rval; errno = 0; cutiso = strtod(cutoff_str, &rval); if ( *rval != '\0' ) { ERROR("Invalid value for --cutoff-angstroms.\n"); return 1; } have_cutoff_iso = 1; } free(cutoff_str); } if ( (holo_str != NULL) && (expand_str != NULL) ) { ERROR("You cannot 'twin' and 'expand' at the same time.\n"); ERROR("Decide which one you want to do first.\n"); return 1; } if ( beamfile != NULL ) { beam = get_beam_parameters(beamfile); if ( beam == NULL ) { ERROR("Failed to load beam parameters from '%s'\n", beamfile); return 1; } } if ( holo_str != NULL ) { holo = get_pointgroup(holo_str); free(holo_str); } else { holo = NULL; } if ( mero_str != NULL ) { mero = get_pointgroup(mero_str); free(mero_str); } else { mero = NULL; } if ( expand_str != NULL ) { expand = get_pointgroup(expand_str); free(expand_str); } else { expand = NULL; } if ( reindex_str != NULL ) { reindex = parse_symmetry_operations(reindex_str); if ( reindex == NULL ) return 1; set_symmetry_name(reindex, "Reindex"); } if ( (expand != NULL) || (holo != NULL) || config_trimc || config_multi ) { if ( mero == NULL ) { ERROR("You must specify the point group with -y.\n"); } } input = read_reflections(input_file); if ( input == NULL ) { ERROR("Problem reading input file %s\n", input_file); return 1; } free(input_file); STATUS("%i reflections in input.\n", num_reflections(input)); if ( (mero != NULL) && !config_trimc && check_list_symmetry(input, mero) ) { ERROR("The input reflection list does not appear to" " have symmetry %s\n", symmetry_name(mero)); return 1; } if ( config_poisson ) { if ( have_adu_per_photon ) { poisson_reflections(input, adu_per_photon); } else { ERROR("You must give the number of ADU per photon to " "use --poisson.\n"); return 1; } } if ( config_noise ) noise_reflections(input); if ( holo != NULL ) { RefList *new; STATUS("Twinning from %s into %s\n", symmetry_name(mero), symmetry_name(holo)); new = twin_reflections(input, config_nap, holo, mero); /* Replace old with new */ reflist_free(input); input = new; /* The symmetry of the list has changed */ free(mero); mero = holo; } if ( expand != NULL ) { RefList *new; STATUS("Expanding from %s into %s\n", symmetry_name(mero), symmetry_name(expand)); new = expand_reflections(input, mero, expand); /* Replace old with new */ reflist_free(input); input = new; } if ( config_trimc ) { RefList *new; /* Can't do this if point group is invalid */ if ( mero == NULL ) { ERROR("Need point group to trim centrics.\n"); return 1; } STATUS("Trimming duplicate reflections in %s\n", symmetry_name(mero)); new = trim_centrics(input, mero); reflist_free(input); input = new; STATUS("%i output reflections\n", num_reflections(input)); } if ( config_multi ) { Reflection *refl; RefListIterator *iter; SymOpMask *m; m = new_symopmask(mero); for ( refl = first_refl(input, &iter); refl != NULL; refl = next_refl(refl, iter) ) { double inty; signed int h, k, l; get_indices(refl, &h, &k, &l); inty = get_intensity(refl); special_position(mero, m, h, k, l); inty *= (double)num_equivs(mero, m); set_intensity(refl, inty); } free_symopmask(m); } if ( template ) { RefList *t = read_reflections(template); RefList *new = template_reflections(input, t); reflist_free(input); input = new; } if ( have_cutoff_iso ) { RefList *n; Reflection *refl; RefListIterator *iter; UnitCell *cell; if ( pdb == NULL ) { ERROR("You must provide a PDB file when using " "--cutoff-angstroms.\n"); return 1; } cell = load_cell_from_pdb(pdb); if ( cell == NULL ) { ERROR("Failed to load cell from '%s'\n", pdb); return 1; } free(pdb); n = reflist_new(); for ( refl = first_refl(input, &iter); refl != NULL; refl = next_refl(refl, iter) ) { signed int h, k, l; double res; get_indices(refl, &h, &k, &l); res = 2.0 * resolution(cell, h, k, l); if ( res < 1e10 / cutiso ) { Reflection *a; a = add_refl(n, h, k, l); copy_data(a, refl); } } cell_free(cell); reflist_free(input); input = n; } if ( have_cutoff_aniso ) { RefList *n; Reflection *refl; RefListIterator *iter; UnitCell *cell; double asx, asy, asz; double bsx, bsy, bsz; double csx, csy, csz; double as, bs, cs; if ( pdb == NULL ) { ERROR("You must provide a PDB file when using " "--cutoff-angstroms.\n"); return 1; } cell = load_cell_from_pdb(pdb); if ( cell == NULL ) { ERROR("Failed to load cell from '%s'\n", pdb); return 1; } free(pdb); cell_get_reciprocal(cell, &asx, &asy, &asz, &bsx, &bsy, &bsz, &csx, &csy, &csz); as = modulus(asx, asy, asz); bs = modulus(bsx, bsy, bsz); cs = modulus(csx, csy, csz); n = reflist_new(); for ( refl = first_refl(input, &iter); refl != NULL; refl = next_refl(refl, iter) ) { signed int h, k, l; double sum; get_indices(refl, &h, &k, &l); sum = pow(h*as*cutn1, 2.0); sum += pow(k*bs*cutn2, 2.0); sum += pow(l*cs*cutn3, 2.0); if ( sum < 1.0 ) { Reflection *a; a = add_refl(n, h, k, l); copy_data(a, refl); } } cell_free(cell); reflist_free(input); input = n; } if ( reindex != NULL ) { RefList *n; Reflection *refl; RefListIterator *iter; n = reflist_new(); for ( refl = first_refl(input, &iter); refl != NULL; refl = next_refl(refl, iter) ) { signed int h, k, l; Reflection *rn; get_indices(refl, &h, &k, &l); get_equiv(reindex, NULL, 0, h, k, l, &h, &k, &l); rn = add_refl(n, h, k, l); copy_data(rn, refl); } reflist_free(input); input = n; } write_reflist(output, input); reflist_free(input); return 0; }