/* * cell_tool.c * * Unit cell tool * * Copyright © 2018 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * * Authors: * 2012-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 #include #include #include #include "cell.h" #include "cell-utils.h" #include "reflist-utils.h" #include "reflist.h" static void show_help(const char *s) { printf("Syntax: %s [options]\n\n", s); printf( "Unit cell manipulation tool.\n" "\n" " -h, --help Display this help message.\n" " -p, --pdb= Get unit cell from (PDB or CrystFEL format).\n" " -o Output unit cell file.\n" "\n" " Actions:\n" " --find-ambi Find indexing ambiguities for the cell.\n" " --uncenter Calculate a primitive cell.\n" " --rings Calculate powder ring positions.\n" " --compare-cell Compare unit cell with cell from .\n" "\n" " -y Real point group of the structure.\n" " --tolerance= Set the tolerances for cell reduction.\n" " Default: 5,5,5,1.5.\n" ); } static int cells_are_similar(UnitCell *cell1, UnitCell *cell2, float *tols) { double a1, b1, c1, al1, be1, ga1; double a2, b2, c2, al2, be2, ga2; UnitCellTransformation *tfn1, *tfn2; UnitCell *pcell1, *pcell2; /* Compare primitive cells, not centered */ pcell1 = uncenter_cell(cell1, &tfn1); pcell2 = uncenter_cell(cell2, &tfn2); cell_get_parameters(pcell1, &a1, &b1, &c1, &al1, &be1, &ga1); cell_get_parameters(pcell2, &a2, &b2, &c2, &al2, &be2, &ga2); cell_free(pcell1); cell_free(pcell2); if ( !within_tolerance(a1, a2, tols[0]) ) return 0; if ( !within_tolerance(b1, b2, tols[1]) ) return 0; if ( !within_tolerance(c1, c2, tols[2]) ) return 0; if ( !within_tolerance(al1, al2, tols[3]) ) return 0; if ( !within_tolerance(be1, be2, tols[3]) ) return 0; if ( !within_tolerance(ga1, ga2, tols[3]) ) return 0; return 1; } struct sortmerefl { signed int h; signed int k; signed int l; double resolution; int multi; }; static int cmpres(const void *av, const void *bv) { const struct sortmerefl *a = av; const struct sortmerefl *b = bv; return a->resolution > b->resolution; } static int all_rings(UnitCell *cell, SymOpList *sym) { double ax, ay, az; double bx, by, bz; double cx, cy, cz; int hmax, kmax, lmax; double mres; signed int h, k, l; RefList *list; int i, n; RefListIterator *iter; Reflection *refl; struct sortmerefl *sortus; double highres = 2.0; /* Angstroms */ mres = 1.0/(highres*1e-10); cell_get_cartesian(cell, &ax, &ay, &az, &bx, &by, &bz, &cx, &cy, &cz); hmax = mres * modulus(ax, ay, az); kmax = mres * modulus(bx, by, bz); lmax = mres * modulus(cx, cy, cz); list = reflist_new(); for ( h=-hmax; h<=hmax; h++ ) { for ( k=-kmax; k<=kmax; k++ ) { for ( l=-lmax; l<=lmax; l++ ) { signed int ha, ka, la; if ( forbidden_reflection(cell, h, k, l) ) continue; if ( 2.0*resolution(cell, h, k, l) > mres ) continue; if ( sym != NULL ) { Reflection *refl; get_asymm(sym, h, k, l, &ha, &ka, &la); refl = find_refl(list, ha, ka, la); if ( refl == NULL ) { refl = add_refl(list, ha, ka, la); set_redundancy(refl, 1); } else { set_redundancy(refl, get_redundancy(refl)+1); } } else { Reflection *refl; refl = add_refl(list, h, k, l); set_redundancy(refl, 1); } } } } n = num_reflections(list); sortus = malloc(n*sizeof(struct sortmerefl)); i = 0; for ( refl = first_refl(list, &iter); refl != NULL; refl = next_refl(refl, iter) ) { signed int h, k, l; get_indices(refl, &h, &k, &l); sortus[i].h = h; sortus[i].k = k; sortus[i].l = l; sortus[i].resolution = 2.0*resolution(cell, h, k, l); /* one over d */ sortus[i].multi = get_redundancy(refl); i++; } qsort(sortus, n, sizeof(struct sortmerefl), cmpres); STATUS("\nAll powder rings up to %f Ångstrøms.\n", highres); STATUS("Note that screw axis or glide plane absences are not " "omitted from this list.\n"); STATUS("\n d (Å) 1/d (m^-1) h k l multiplicity\n"); STATUS("------------------------------------------------------\n"); for ( i=0; i The primitive unit cell:\n"); cell_print(cnew); STATUS("------------------> The decentering transformation:\n"); tfn_print(trans); if ( out_file != NULL ) { FILE *fh = fopen(out_file, "w"); if ( fh == NULL ) { ERROR("Failed to open '%s'\n", out_file); return 1; } write_cell(cnew, fh); fclose(fh); } return 0; } enum { CT_NOTHING, CT_FINDAMBI, CT_UNCENTER, CT_RINGS, CT_COMPARE, CT_CHOICES, }; int main(int argc, char *argv[]) { int c; char *cell_file = NULL; UnitCell *cell; char *toler = NULL; float tols[4] = {5.0, 5.0, 5.0, 1.5}; /* a,b,c,angles (%,%,%,deg) */ char *sym_str = NULL; SymOpList *sym = NULL; int mode = CT_NOTHING; char *comparecell = NULL; char *out_file = NULL; /* Long options */ const struct option longopts[] = { {"help", 0, NULL, 'h'}, {"pdb", 1, NULL, 'p'}, {"tolerance", 1, NULL, 2}, {"output", 1, NULL, 'o'}, /* Modes of operation */ {"find-ambi", 0, &mode, CT_FINDAMBI}, {"uncenter", 0, &mode, CT_UNCENTER}, {"uncentre", 0, &mode, CT_UNCENTER}, {"rings", 0, &mode, CT_RINGS}, {"compare-cell", 1, NULL, 3}, {"highres", 1, NULL, 5}, {0, 0, NULL, 0} }; /* Short options */ while ((c = getopt_long(argc, argv, "hp:y:o:", longopts, NULL)) != -1) { switch (c) { case 'h' : show_help(argv[0]); return 0; case 'p' : cell_file = strdup(optarg); break; case 'o' : out_file = strdup(optarg); break; case 'y' : sym_str = strdup(optarg); break; case 2 : toler = strdup(optarg); break; case 3 : comparecell = strdup(optarg); mode = CT_COMPARE; break; case 0 : break; default : return 1; } } if ( cell_file == NULL ) { ERROR("You must give a filename for the unit cell PDB file.\n"); return 1; } cell = load_cell_from_file(cell_file); if ( cell == NULL ) { ERROR("Failed to load cell from '%s'\n", cell_file); return 1; } free(cell_file); if ( toler != NULL ) { int ttt; ttt = sscanf(toler, "%f,%f,%f,%f", &tols[0], &tols[1], &tols[2], &tols[3] ); if ( ttt != 4 ) { ERROR("Invalid parameters for '--tolerance'\n"); return 1; } free(toler); } STATUS("------------------> The input unit cell:\n"); cell_print(cell); if ( validate_cell(cell) ) { ERROR("Cell is invalid.\n"); return 1; } if ( sym_str != NULL ) { sym = get_pointgroup(sym_str); if ( sym == NULL ) return 1; free(sym_str); } if ( mode == CT_NOTHING ) { ERROR("Please specify mode of operation (see --help)\n"); return 1; } if ( mode == CT_FINDAMBI ) return find_ambi(cell, sym, tols); if ( mode == CT_UNCENTER ) return uncenter(cell, out_file); if ( mode == CT_RINGS ) return all_rings(cell, sym); /* FIXME: Everything else */ ERROR("Sorry, this mode of operation is not yet implemented.\n"); return 1; }