diff options
author | Thomas White <taw@physics.org> | 2020-08-07 17:43:18 +0200 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2020-08-07 18:07:07 +0200 |
commit | c0b01532441407dc97eaa9d44b540f1dd0223990 (patch) | |
tree | a1526e8bb84d38e8e6dfab05d2d95e1a5b5a3d10 /libcrystfel/src/asdf.c | |
parent | 08327436744a05e68daf1676f0fa4a82fb74408f (diff) |
Move indexers out of API
Diffstat (limited to 'libcrystfel/src/asdf.c')
-rw-r--r-- | libcrystfel/src/asdf.c | 1239 |
1 files changed, 0 insertions, 1239 deletions
diff --git a/libcrystfel/src/asdf.c b/libcrystfel/src/asdf.c deleted file mode 100644 index 1536a109..00000000 --- a/libcrystfel/src/asdf.c +++ /dev/null @@ -1,1239 +0,0 @@ -/* - * asdf.c - * - * Alexandra's Superior Direction Finder, or - * Algorithm Similar to DirAx, FFT-based - * - * Copyright © 2014-2020 Deutsches Elektronen-Synchrotron DESY, - * a research centre of the Helmholtz Association. - * - * Authors: - * 2014-2015 Alexandra Tolstikova <alexandra.tolstikova@desy.de> - * 2015,2017 Thomas White <taw@physics.org> - * - * 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 <http://www.gnu.org/licenses/>. - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <string.h> -#include <gsl/gsl_matrix.h> -#include <gsl/gsl_vector.h> -#include <gsl/gsl_blas.h> -#include <gsl/gsl_linalg.h> -#include <gsl/gsl_multifit.h> -#include <gsl/gsl_fit.h> - -#include "image.h" -#include "utils.h" -#include "peaks.h" -#include "cell-utils.h" -#include "asdf.h" -#include "cell.h" - -/** - * \file asdf.h - */ - -#ifdef HAVE_FFTW - -#define FFTW_NO_Complex /* Please use "double[2]", not C99 "complex", - * despite complex.h possibly already being - * included. For more information, refer to: - * http://www.fftw.org/doc/Complex-numbers.html */ - -#include <fftw3.h> - -struct fftw_vars { - int N; - fftw_plan p; - double *in; - fftw_complex *out; -}; - - -struct asdf_private { - IndexingMethod indm; - UnitCell *template; - struct fftw_vars fftw; -}; - - -/* Possible direct vector */ -struct tvector { - gsl_vector *t; - int n; // number of fitting reflections - int *fits; -}; - - -struct fftw_vars fftw_vars_new() -{ - int N = 1024; - - struct fftw_vars fftw; - - fftw.N = N; - fftw.in = fftw_malloc(N * sizeof(double)); - fftw.out = fftw_malloc(N * sizeof(fftw_complex)); - fftw.p = fftw_plan_dft_r2c_1d(N, fftw.in, fftw.out, FFTW_MEASURE); - - return fftw; -} - - -static void fftw_vars_free(struct fftw_vars fftw) -{ - fftw_free(fftw.in); - fftw_free(fftw.out); - fftw_destroy_plan(fftw.p); - fftw_cleanup(); -} - - -struct asdf_cell { - gsl_vector *axes[3]; - gsl_vector *reciprocal[3]; - - int n; // number of fitting reflections - double volume; - - int N_refls; // total number of reflections - int *reflections; // reflections[i] = 1 if reflections fits - double **indices; // indices[i] = [h, k, l] for all reflections (not rounded) - - int acl; // minimum number of reflections fitting to one of the axes[] - int n_max; // maximum number of reflections fitting to some t-vector -}; - - -struct tvector tvector_new(int n) -{ - struct tvector t; - - t.t = gsl_vector_alloc(3); - t.n = 0; - t.fits = malloc(sizeof(int) * n); - - return t; -} - - -static int tvector_free(struct tvector t) -{ - gsl_vector_free(t.t); - free(t.fits); - - return 1; -} - - -static int asdf_cell_free(struct asdf_cell *c) -{ - int i; - for ( i = 0; i < 3; i++ ) { - gsl_vector_free(c->axes[i]); - gsl_vector_free(c->reciprocal[i]); - } - - free(c->reflections); - for ( i = 0; i < c->N_refls; i++ ) { - free(c->indices[i]); - } - free(c->indices); - free(c); - - return 1; -} - - -static struct asdf_cell *asdf_cell_new(int n) -{ - struct asdf_cell *c; - c = malloc(sizeof(struct asdf_cell)); - - int i; - for ( i = 0; i < 3; i++ ) { - c->axes[i] = gsl_vector_alloc(3); - c->reciprocal[i] = gsl_vector_alloc(3); - } - - c->N_refls = n; - c->reflections = malloc(sizeof(int) * n); - if (c->reflections == NULL) return NULL; - - c->indices = malloc(sizeof(double *) * n); - if (c->indices == NULL) return NULL; - - for ( i = 0; i < n; i++ ) { - c->indices[i] = malloc(sizeof(double) * 3); - if (c->indices[i] == NULL) return NULL; - } - - c->n = 0; - - c->acl = 0; - c->n_max = 0; - - return c; -} - - -static int asdf_cell_memcpy(struct asdf_cell *dest, struct asdf_cell *src) -{ - int i; - for ( i = 0; i < 3; i++ ) { - gsl_vector_memcpy(dest->axes[i], src->axes[i]); - gsl_vector_memcpy(dest->reciprocal[i], src->reciprocal[i]); - } - - dest->volume = src->volume; - - int n = src->N_refls; - dest->N_refls = n; - - dest->n = src->n; - memcpy(dest->reflections, src->reflections, sizeof(int) * n); - - for (i = 0; i < n; i++ ) { - memcpy(dest->indices[i], src->indices[i], sizeof(double) * 3); - } - - dest->acl = src->acl; - dest->n_max = src->n_max; - return 1; -} - - -/* result = vec1 cross vec2 */ -static int cross_product(gsl_vector *vec1, gsl_vector *vec2, - gsl_vector **result) -{ - double c1[3], c2[3], p[3]; - int i; - for ( i = 0; i < 3; i++ ) { - c1[i] = gsl_vector_get(vec1, i); - c2[i] = gsl_vector_get(vec2, i); - } - - p[0] = c1[1] * c2[2] - c1[2] * c2[1]; - p[1] = - c1[0] * c2[2] + c1[2] * c2[0]; - p[2] = c1[0] * c2[1] - c1[1] * c2[0]; - - for ( i = 0; i < 3; i++ ) { - gsl_vector_set(*result, i, p[i]); - } - - return 1; -} - - -/* Returns triple product of three gsl_vectors */ -static double calc_volume(gsl_vector *vec1, gsl_vector *vec2, gsl_vector *vec3) -{ - double volume; - gsl_vector *cross = gsl_vector_alloc(3); - - cross_product(vec1, vec2, &cross); - gsl_blas_ddot(vec3, cross, &volume); - - gsl_vector_free(cross); - return volume; -} - - -static int calc_reciprocal(gsl_vector **direct, gsl_vector **reciprocal) -{ - double volume; - - cross_product(direct[1], direct[2], &reciprocal[0]); - gsl_blas_ddot(direct[0], reciprocal[0], &volume); - gsl_vector_scale(reciprocal[0], 1/volume); - - cross_product(direct[2], direct[0], &reciprocal[1]); - gsl_vector_scale(reciprocal[1], 1/volume); - - cross_product(direct[0], direct[1], &reciprocal[2]); - gsl_vector_scale(reciprocal[2], 1/volume); - - return 1; -} - - -static int compare_doubles(const void *a, const void *b) -{ - const double *da = (const double *) a; - const double *db = (const double *) b; - - return (*da > *db) - (*da < *db); -} - - -static double max(double a, double b, double c) -{ - double m = a; - if ( m < b ) m = b; - if ( m < c ) m = c; - return m; -} - - -/* Compares tvectors by length */ -static int compare_tvectors(const void *a, const void *b) -{ - struct tvector *ta = (struct tvector *) a; - struct tvector *tb = (struct tvector *) b; - - //~ if (ta->n == tb->n) { - return (gsl_blas_dnrm2(ta->t) > gsl_blas_dnrm2(tb->t)) - - (gsl_blas_dnrm2(ta->t) < gsl_blas_dnrm2(tb->t)); - //~ } - //~ - //~ return (ta->n > tb->n) - (ta->n < tb->n); -} - - -/* Calculates normal to a triplet c1, c2, c3. Returns 0 if reflections are on - * the same line */ -static int calc_normal(gsl_vector *c1, gsl_vector *c2, gsl_vector *c3, - gsl_vector *normal) -{ - gsl_vector *c12 = gsl_vector_alloc(3); - gsl_vector *c23 = gsl_vector_alloc(3); - gsl_vector *c31 = gsl_vector_alloc(3); - gsl_vector *res = gsl_vector_alloc(3); - - cross_product(c1, c2, &c12); - cross_product(c2, c3, &c23); - cross_product(c3, c1, &c31); - - int i; - for ( i = 0; i < 3; i++ ) { - gsl_vector_set(res, i, gsl_vector_get(c12, i) + - gsl_vector_get(c23, i) + - gsl_vector_get(c31, i)); - } - - gsl_vector_free(c12); - gsl_vector_free(c23); - gsl_vector_free(c31); - - double norm = gsl_blas_dnrm2(res); - if ( norm < 0.0001 ) { - gsl_vector_free(res); - return 0; - } else { - gsl_vector_scale(res, 1/norm); - gsl_vector_memcpy(normal, res); - gsl_vector_free(res); - } - - return 1; -} - - -static float find_ds_fft(double *projections, int N_projections, double d_max, - struct fftw_vars fftw) -{ - int n = N_projections; - double projections_sorted[n]; - memcpy(projections_sorted, projections, sizeof(double) * n); - qsort(projections_sorted, n, sizeof(double), compare_doubles); - - int i, k; - - int N = fftw.N; // number of points in fft calculation - double *in = fftw.in; - fftw_complex *out = fftw.out; - fftw_plan p = fftw.p; - - for ( i=0; i<N; i++ ) { - in[i] = 0; - } - - for ( i=0; i<n; i++ ) { - k = (int)((projections_sorted[i] - projections_sorted[0]) / - (projections_sorted[n - 1] - projections_sorted[0]) * - (N - 1)); - if ( (k>=N) || (k<0) ) { - ERROR("Bad k value in find_ds_fft() (k=%i, N=%i)\n", - k, N); - return -1.0; - } - in[k]++; - } - - fftw_execute_dft_r2c(p, in, out); - - int i_max = (int)(d_max * (projections_sorted[n - 1] - - projections_sorted[0])); - - int d = 1; - double max = 0; - double a; - for ( i=1; i<=i_max; i++ ) { - a = sqrt(out[i][0] * out[i][0] + out[i][1] * out[i][1]); - if (a > max) { - max = a; - d = i; - } - } - - double ds = (projections_sorted[n - 1] - projections_sorted[0]) / d; - - return ds; -} - - -/* Returns number of reflections fitting ds. - * A projected reflection fits a one-dimensional lattice with elementary - * lattice vector d* if its absolute distance to the nearest lattice - * point is less than LevelFit. */ -static int check_refl_fitting_ds(double *projections, int N_projections, - double ds, double LevelFit) -{ - if ( ds == 0 ) return 0; - - int i; - int n = 0; - for ( i = 0; i < N_projections; i++ ) { - if ( fabs(projections[i] - - ds * round(projections[i]/ds)) < LevelFit ) - { - n += 1; - } - } - - return n; -} - - -/* Refines d*, writes 1 to fits[i] if the i-th projection fits d* */ -static float refine_ds(double *projections, int N_projections, double ds, - double LevelFit, int *fits) -{ - double fit_refls[N_projections]; - double indices[N_projections]; - - int i; - - int N_fits = 0; - int N_new = N_projections; - - double c1, cov11, sumsq; - double ds_new = ds; - while ( N_fits < N_new ) { - N_fits = 0; - for ( i = 0; i < N_projections; i++ ) { - if ( fabs(projections[i] - ds_new * - round(projections[i] / ds_new)) < LevelFit ) - { - fit_refls[N_fits] = projections[i]; - indices[N_fits] = round(projections[i]/ds_new); - N_fits ++; - fits[i] = 1; - } else { - fits[i] = 0; - } - } - - - gsl_fit_mul(indices, 1, fit_refls, 1, N_fits, &c1, &cov11, - &sumsq); - N_new = check_refl_fitting_ds(projections, N_projections, c1, - LevelFit); - if ( N_new >= N_fits ) { - ds_new = c1; - } - } - - return ds_new; -} - - -static int check_refl_fitting_cell(struct asdf_cell *c, - gsl_vector **reflections, - int N_reflections, double IndexFit) -{ - double dist[3]; - - calc_reciprocal(c->axes, c->reciprocal); - c->n = 0; - int i, j, k; - for( i = 0; i < N_reflections; i += 1 ) { - - for ( j = 0; j < 3; j++ ) dist[j] = 0; - - for ( j = 0; j < 3; j++ ) { - gsl_blas_ddot(reflections[i], c->axes[j], - &c->indices[i][j]); - - for ( k = 0; k < 3; k++ ) { - dist[k] += gsl_vector_get(c->reciprocal[j], k) * - (c->indices[i][j] - round(c->indices[i][j])); - } - } - - /* A reflection fits if the distance (in reciprocal space) - * between the observed and calculated reflection position - * is less than Indexfit */ - - if ( dist[0]*dist[0] + dist[1]*dist[1] + dist[2]*dist[2] < - IndexFit * IndexFit ) { - c->reflections[i] = 1; - c->n++; - } else { - c->reflections[i] = 0; - } - } - - return 1; -} - - -/* Returns 0 when refinement doesn't converge (i.e. all fitting reflections - * lie in the same plane) */ -static int refine_asdf_cell(struct asdf_cell *c, gsl_vector **reflections, - int N_reflections, double IndexFit) -{ - gsl_matrix *X = gsl_matrix_alloc(c->n, 3); - - gsl_vector *r[] = {gsl_vector_alloc(c->n), - gsl_vector_alloc(c->n), - gsl_vector_alloc(c->n)}; - - gsl_vector *res = gsl_vector_alloc(3); - gsl_matrix *cov = gsl_matrix_alloc (3, 3); - double chisq; - - int i, j; - int n = 0; - for ( i = 0; i < N_reflections; i++ ) if ( c->reflections[i] == 1 ) - { - for ( j = 0; j < 3; j++ ) { - gsl_matrix_set(X, n, j, round(c->indices[i][j])); - gsl_vector_set(r[j], n, - gsl_vector_get(reflections[i], j)); - } - n++; - } - - gsl_multifit_linear_workspace *work = gsl_multifit_linear_alloc(c->n, - 3); - - for ( i = 0; i < 3; i++ ) { - gsl_multifit_linear (X, r[i], res, cov, &chisq, work); - - for (j = 0; j < 3; j++ ) { - gsl_vector_set(c->reciprocal[j], i, - gsl_vector_get(res, j)); - } - } - - calc_reciprocal(c->reciprocal, c->axes); - - double a[3]; - for ( i = 0; i < 3; i++ ) { - a[i] = gsl_blas_dnrm2(c->axes[i]); - } - - gsl_multifit_linear_free(work); - gsl_vector_free(res); - gsl_matrix_free(cov); - gsl_matrix_free(X); - for ( i = 0; i < 3; i++ ) { - gsl_vector_free(r[i]); - } - - if ( fabs(a[0]) > 10000 || fabs(a[1]) > 10000 || - fabs(a[2]) > 10000 || isnan(a[0]) ) - { - return 0; - } - - return 1; -} - - -static int reduce_asdf_cell(struct asdf_cell *cl) -{ - double a, b, c, alpha, beta, gamma, ab, bc, ca, bb, cc; - - gsl_vector *va = gsl_vector_alloc(3); - gsl_vector *vb = gsl_vector_alloc(3); - gsl_vector *vc = gsl_vector_alloc(3); - - int changed = 1; - - int n = 0; - while ( changed ) { - n += 1; - changed = 0; - - gsl_vector_memcpy(va, cl->axes[0]); - gsl_vector_memcpy(vb, cl->axes[1]); - gsl_vector_memcpy(vc, cl->axes[2]); - - a = gsl_blas_dnrm2(va); - b = gsl_blas_dnrm2(vb); - c = gsl_blas_dnrm2(vc); - - gsl_blas_ddot(va, vb, &ab); - gsl_blas_ddot(vb, vc, &bc); - gsl_blas_ddot(vc, va, &ca); - - alpha = acos(bc/b/c)/M_PI*180; - beta = acos(ca/a/c)/M_PI*180; - gamma = acos(ab/a/b)/M_PI*180; - - if ( changed == 0 ) { - - if ( gamma < 90 ) { - gsl_vector_scale(vb, -1); - gamma = 180 - gamma; - alpha = 180 - alpha; - } - - gsl_vector_add(vb, va); - bb = gsl_blas_dnrm2(vb); - if ( bb < b ) { - b = bb; - if ( a < b ) { - gsl_vector_memcpy(cl->axes[1], vb); - } else { - gsl_vector_memcpy(cl->axes[1], va); - gsl_vector_memcpy(cl->axes[0], vb); - } - changed = 1; - } - } - - if ( changed == 0 ) { - - if ( beta < 90 ) { - gsl_vector_scale(vc, -1); - beta = 180 - beta; - alpha = 180 - alpha; - } - - gsl_vector_add(vc, va); - cc = gsl_blas_dnrm2(vc); - if ( cc < c ) { - c = cc; - if ( b < c ) { - gsl_vector_memcpy(cl->axes[2], vc); - } else if ( a < c ) { - gsl_vector_memcpy(cl->axes[1], vc); - gsl_vector_memcpy(cl->axes[2], vb); - } else { - gsl_vector_memcpy(cl->axes[0], vc); - gsl_vector_memcpy(cl->axes[1], va); - gsl_vector_memcpy(cl->axes[2], vb); - } - changed = 1; - } - } - - if ( changed == 0 ) { - if ( alpha < 90 ) { - gsl_vector_scale(vc, -1); - beta = 180 - beta; - alpha = 180 - alpha; - } - - gsl_vector_add(vc, vb); - cc = gsl_blas_dnrm2(vc); - if ( cc < c ) { - c = cc; - if ( b < c ) { - gsl_vector_memcpy(cl->axes[2], vc); - } else if ( a < c ) { - gsl_vector_memcpy(cl->axes[1], vc); - gsl_vector_memcpy(cl->axes[2], vb); - } else { - gsl_vector_memcpy(cl->axes[0], vc); - gsl_vector_memcpy(cl->axes[1], va); - gsl_vector_memcpy(cl->axes[2], vb); - } - changed = 1; - } - } - - if (n > 30) changed = 0; - } - - cross_product(cl->axes[0], cl->axes[1], &vc); - gsl_blas_ddot(vc, cl->axes[2], &cl->volume); - if ( cl->volume < 0 ) { - gsl_vector_scale(cl->axes[2], -1); - cl->volume *= -1; - } - - gsl_vector_free(va); - gsl_vector_free(vb); - gsl_vector_free(vc); - - return 1; -} - - -static int check_cell_angles(gsl_vector *va, gsl_vector *vb, gsl_vector *vc, - double max_cos) -{ - double a, b, c, cosa, cosb, cosg, ab, bc, ca; - - a = gsl_blas_dnrm2(va); - b = gsl_blas_dnrm2(vb); - c = gsl_blas_dnrm2(vc); - - gsl_blas_ddot(va, vb, &ab); - gsl_blas_ddot(vb, vc, &bc); - gsl_blas_ddot(vc, va, &ca); - - cosa = bc/b/c; - cosb = ca/a/c; - cosg = ab/a/b; - - if ( fabs(cosa) > max_cos || fabs(cosb) > max_cos || - fabs(cosg) > max_cos ) { - return 0; - } - - return 1; -} - - -/* Returns min(t1.n, t2.n, t3.n) */ -static int find_acl(struct tvector t1, struct tvector t2, struct tvector t3) -{ - int i = t1.n, j = t2.n, k = t3.n; - if ( i <= j && i <= k ) return i; - if ( j <= i && j <= k ) return j; - if ( k <= i && k <= j ) return k; - ERROR("This point never reached!\n"); - abort(); -} - - -static int create_cell(struct tvector tvec1, struct tvector tvec2, - struct tvector tvec3, struct asdf_cell *c, - double IndexFit, double volume_min, double volume_max, - gsl_vector **reflections, int N_reflections) -{ - - double volume = calc_volume(tvec1.t, tvec2.t, tvec3.t); - if ( fabs(volume) < volume_min || fabs(volume) > volume_max ) return 0; - - gsl_vector_memcpy(c->axes[0], tvec1.t); - gsl_vector_memcpy(c->axes[1], tvec2.t); - gsl_vector_memcpy(c->axes[2], tvec3.t); - - c->volume = volume; - check_refl_fitting_cell(c, reflections, N_reflections, IndexFit); - - if ( c->n < 6 ) return 0; - - reduce_asdf_cell(c); - - /* If one of the cell angles > 135 or < 45 return 0 */ - if ( !check_cell_angles(c->axes[0], c->axes[1], - c->axes[2], 0.71) ) return 0; - - /* Index reflections with new cell axes */ - check_refl_fitting_cell(c, reflections, N_reflections, IndexFit); - - /* Refine cell until the number of fitting - * reflections stops increasing */ - int n = 0; - int cell_correct = 1; - while ( c->n - n > 0 && cell_correct ) { - - n = c->n; - cell_correct = refine_asdf_cell(c, reflections, N_reflections, - IndexFit); - check_refl_fitting_cell(c, reflections, N_reflections, - IndexFit); - } - - return cell_correct; -} - - -static int find_cell(struct tvector *tvectors, int N_tvectors, double IndexFit, - double volume_min, double volume_max, int n_max, - gsl_vector **reflections, int N_reflections, - struct asdf_cell *result) -{ - int i, j, k; - - /* Only tvectors with the number of fitting reflections > acl are - * considered */ - int acl = N_reflections < 18 ? 6 : N_reflections/3; - - struct asdf_cell *c = asdf_cell_new(N_reflections); - if (c == NULL) { - ERROR("Failed to allocate asdf_cell in find_cell!\n"); - return 0; - } - - /* Traversing a 3d array in slices perpendicular to the main diagonal */ - int sl; - for ( sl = 0; sl < 3 * N_tvectors - 1; sl++ ) { - - int i_min = sl < 2 * N_tvectors ? 0 : sl - 2 * N_tvectors; - int i_max = sl < N_tvectors ? sl : N_tvectors; - - for ( i = i_min; i < i_max; i++) if (tvectors[i].n > acl ) { - - int j_min = sl - N_tvectors - 2 * i - 1 < 0 ? - i + 1 : sl - N_tvectors - i; - int j_max = sl - N_tvectors - i < 0 ? - sl - i : N_tvectors; - - for ( j = j_min; j < j_max; j++ ) - if ( tvectors[j].n > acl ) { - - k = sl - i - j - 1; - - if ( k > j && tvectors[k].n > acl && - check_cell_angles(tvectors[i].t, - tvectors[j].t, - tvectors[k].t, 0.99) ) - { - - if ( !create_cell(tvectors[i], - tvectors[j], - tvectors[k], - c, IndexFit, - volume_min, - volume_max, - reflections, - N_reflections) ) - { - break; - } - - acl = find_acl(tvectors[i], - tvectors[j], - tvectors[k]); - c->acl = acl; - c->n_max = n_max; - - reduce_asdf_cell(c); - - /* If the new cell has more fitting - * reflections save it to result */ - if ( result->n < c->n ) { - asdf_cell_memcpy(result, c); - } - acl++; - - if ( acl > n_max ) break; - if ( tvectors[j].n <= acl || - tvectors[i].n <= acl ) break; - } - } - if ( acl > n_max ) break; - if ( tvectors[i].n <= acl ) break; - } - if ( acl > n_max ) break; - } - - asdf_cell_free(c); - - if ( result->n ) return 1; - return 0; -} - - -void swap(int *a, int *b) { - int c = *a; - *a = *b; - *b = c; -} - - -/* Generate triplets of integers < N_reflections in random sequence */ -static int **generate_triplets(int N_reflections, int N_triplets_max, int *N) -{ - int i, j, k, l, n; - - /* Number of triplets = c_n^3 if n - number of reflections */ - int N_triplets = N_reflections * (N_reflections - 1) * - (N_reflections - 2) / 6; - - if ( N_triplets > N_triplets_max || N_reflections > 1000 ) { - N_triplets = N_triplets_max; - } - *N = N_triplets; - - int **triplets = malloc(N_triplets * sizeof(int *)); - - if (triplets == NULL) { - ERROR("Failed to allocate triplets in generate_triplets!\n"); - return 0; - } - - int is_in_triplets; - n = 0; - - while ( n < N_triplets ) { - /* Generate three different integer numbers < N_reflections */ - i = rand() % N_reflections; - j = i; - k = i; - while ( j == i ) { - j = rand() % N_reflections; - } - while ( k == i || k == j ) { - k = rand() % N_reflections; - } - - /* Sort (i, j, k) */ - if ( i > k ) swap(&i, &k); - if ( i > j ) swap(&i, &j); - if ( j > k ) swap(&j, &k); - - /* Check if it's already in triplets[] */ - is_in_triplets = 0; - for ( l = 0; l < n; l++ ) { - if ( triplets[l][0] == i && - triplets[l][1] == j && - triplets[l][2] == k ) { - is_in_triplets = 1; - break; - } - } - - if ( is_in_triplets == 0 ) { - triplets[n] = malloc(3 * sizeof(int)); - if (triplets[n] == NULL) { - ERROR("Failed to allocate triplets " - " in generate_triplets!\n"); - return 0; - } - triplets[n][0] = i; - triplets[n][1] = j; - triplets[n][2] = k; - - n++; - } - } - - return triplets; -} - - -static int index_refls(gsl_vector **reflections, int N_reflections, - double d_max, double volume_min, double volume_max, - double LevelFit, double IndexFit, int N_triplets_max, - struct asdf_cell *c, struct fftw_vars fftw) -{ - - int i, k, n; - - int N_triplets; - int **triplets = generate_triplets(N_reflections, N_triplets_max, - &N_triplets); - if ( N_triplets == 0 ) { - return 0; - } - - gsl_vector *normal = gsl_vector_alloc(3); - - double projections[N_reflections]; - double ds; - - int *fits = malloc(N_reflections * sizeof(int)); - if (fits == NULL) { - ERROR("Failed to allocate fits in index_refls!\n"); - return 0; - } - - struct tvector *tvectors = malloc(N_triplets * sizeof(struct tvector)); - if (tvectors == NULL) { - ERROR("Failed to allocate tvectors in index_refls!\n"); - return 0; - } - - int N_tvectors = 0; - - int n_max = 0; // maximum number of reflections fitting one of tvectors - - for ( i = 0; i < N_triplets; i++ ) { - if ( calc_normal(reflections[triplets[i][0]], - reflections[triplets[i][1]], - reflections[triplets[i][2]], - normal) ) - { - - /* Calculate projections of reflections to normal */ - for ( k = 0; k < N_reflections; k++ ) { - gsl_blas_ddot(normal, reflections[k], - &projections[k]); - } - - /* Find ds - period in 1d lattice of projections */ - ds = find_ds_fft(projections, N_reflections, d_max, - fftw); - if ( ds < 0.0 ) { - ERROR("find_ds_fft() failed.\n"); - return 0; - } - - /* Refine ds, write 1 to fits[i] if reflections[i] - * fits ds */ - ds = refine_ds(projections, N_reflections, ds, LevelFit, - fits); - - /* n - number of reflections fitting ds */ - n = check_refl_fitting_ds(projections, N_reflections, - ds, LevelFit); - - /* normal/ds - possible direct vector */ - gsl_vector_scale(normal, 1/ds); - - if ( n > N_reflections/3 && n > 6 ) { - - tvectors[N_tvectors] = tvector_new(N_reflections); - - gsl_vector_memcpy(tvectors[N_tvectors].t, - normal); - memcpy(tvectors[N_tvectors].fits, fits, - N_reflections * sizeof(int)); - - tvectors[N_tvectors].n = n; - - N_tvectors++; - - if (n > n_max) n_max = n; - } - } - - if ( (i != 0 && i % 10000 == 0) || i == N_triplets - 1 ) { - - /* Sort tvectors by length */ - qsort(tvectors, N_tvectors, sizeof(struct tvector), - compare_tvectors); - - /* Three shortest independent tvectors with t.n > acl - * determine the final cell. acl is selected for the - * solution with the maximum number of fitting - * reflections */ - - find_cell(tvectors, N_tvectors, IndexFit, volume_min, - volume_max, n_max, reflections, - N_reflections, c); - - if ( c->n > 4 * n_max / 5 ) { - break; - } - } - } - free(fits); - - for ( i = 0; i < N_tvectors; i++ ) { - tvector_free(tvectors[i]); - } - free(tvectors); - - for ( i = 0; i < N_triplets; i++ ) { - free(triplets[i]); - } - free(triplets); - - gsl_vector_free(normal); - - if ( c->n ) return 1; - - return 0; -} - - -int run_asdf(struct image *image, void *ipriv) -{ - int i, j; - - double LevelFit = 1./1000; - double IndexFit = 1./500; - double d_max = 1000.; // thrice the maximum expected axis length - double volume_min = 100.; - double volume_max = 100000000.; - - int N_triplets_max = 10000; // maximum number of triplets - - struct asdf_private *dp = (struct asdf_private *)ipriv; - - if ( dp->indm & INDEXING_USE_CELL_PARAMETERS ) { - - double a, b, c, gamma, beta, alpha; - cell_get_parameters(dp->template, &a, &b, &c, - &alpha, &beta, &gamma); - - d_max = max(a, b, c) * 3 * 1e10; - - double volume = cell_get_volume(dp->template) / 1e30; - - /* Divide volume constraints by number of lattice points per - * unit cell since asdf always finds primitive cell */ - int latt_points_per_uc = 1; - char centering = cell_get_centering(dp->template); - if ( centering == 'A' || - centering == 'B' || - centering == 'C' || - centering == 'I' ) latt_points_per_uc = 2; - else if ( centering == 'F' ) latt_points_per_uc = 4; - - volume_min = volume * 0.9/latt_points_per_uc; - volume_max = volume * 1.1/latt_points_per_uc; - } - - int n = image_feature_count(image->features); - int N_reflections = 0; - gsl_vector *reflections[n]; - - for ( i=0; i<n; i++ ) { - struct imagefeature *f; - - f = image_get_feature(image->features, i); - if ( f == NULL ) continue; - - reflections[N_reflections] = gsl_vector_alloc(3); - gsl_vector_set(reflections[N_reflections], 0, f->rx/1e10); - gsl_vector_set(reflections[N_reflections], 1, f->ry/1e10); - gsl_vector_set(reflections[N_reflections], 2, f->rz/1e10); - N_reflections++; - } - - struct asdf_cell *c = asdf_cell_new(N_reflections); - if (c == NULL) { - ERROR("Failed to allocate asdf_cell in run_asdf!\n"); - return 0; - } - - if ( N_reflections == 0 ) return 0; - - j = index_refls(reflections, N_reflections, d_max, volume_min, - volume_max, LevelFit, IndexFit, N_triplets_max, c, - dp->fftw); - - for ( i = 0; i < N_reflections; i++ ) { - gsl_vector_free(reflections[i]); - } - - if ( j ) { - - UnitCell *uc; - Crystal *cr; - uc = cell_new(); - - cell_set_cartesian(uc, gsl_vector_get(c->axes[0], 0) * 1e-10, - gsl_vector_get(c->axes[0], 1) * 1e-10, - gsl_vector_get(c->axes[0], 2) * 1e-10, - gsl_vector_get(c->axes[1], 0) * 1e-10, - gsl_vector_get(c->axes[1], 1) * 1e-10, - gsl_vector_get(c->axes[1], 2) * 1e-10, - gsl_vector_get(c->axes[2], 0) * 1e-10, - gsl_vector_get(c->axes[2], 1) * 1e-10, - gsl_vector_get(c->axes[2], 2) * 1e-10); - - cr = crystal_new(); - if ( cr == NULL ) { - ERROR("Failed to allocate crystal.\n"); - return 0; - } - crystal_set_cell(cr, uc); - image_add_crystal(image, cr); - asdf_cell_free(c); - return 1; - - } - - asdf_cell_free(c); - return 0; -} - - -/** - * Prepare the ASDF indexing algorithm - */ -void *asdf_prepare(IndexingMethod *indm, UnitCell *cell) -{ - struct asdf_private *dp; - - /* Flags that asdf knows about */ - *indm &= INDEXING_METHOD_MASK | INDEXING_USE_CELL_PARAMETERS; - - dp = malloc(sizeof(struct asdf_private)); - if ( dp == NULL ) return NULL; - - dp->template = cell; - dp->indm = *indm; - - dp->fftw = fftw_vars_new(); - - return (void *)dp; -} - - -void asdf_cleanup(void *pp) -{ - struct asdf_private *p; - p = (struct asdf_private *)pp; - fftw_vars_free(p->fftw); - free(p); -} - - -const char *asdf_probe(UnitCell *cell) -{ - return "asdf"; -} - -#else /* HAVE_FFTW */ - -int run_asdf(struct image *image, void *ipriv) -{ - ERROR("This copy of CrystFEL was compiled without FFTW support.\n"); - return 0; -} - - -void *asdf_prepare(IndexingMethod *indm, UnitCell *cell) -{ - ERROR("This copy of CrystFEL was compiled without FFTW support.\n"); - ERROR("To use asdf indexing, recompile with FFTW.\n"); - return NULL; -} - - -const char *asdf_probe(UnitCell *cell) -{ - return NULL; -} - - -void asdf_cleanup(void *pp) -{ -} - -#endif /* HAVE_FFTW */ |