diff options
author | Thomas White <taw@physics.org> | 2010-10-27 20:02:59 +0200 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2012-02-22 15:27:04 +0100 |
commit | 533c10431f319c5cc943e49e4cefe58e8ce6c2cf (patch) | |
tree | feae83731545f90d9a0b0105ba0a333e9815726c /src/geometry.c | |
parent | f47803a3d004131493b20f9a3a3b5d9cccdaaf2a (diff) |
facetron: Work on geometry
Diffstat (limited to 'src/geometry.c')
-rw-r--r-- | src/geometry.c | 188 |
1 files changed, 128 insertions, 60 deletions
diff --git a/src/geometry.c b/src/geometry.c index cca2d050..2b94e7ba 100644 --- a/src/geometry.c +++ b/src/geometry.c @@ -15,18 +15,93 @@ #include <stdlib.h> +#include <gsl/gsl_poly.h> +#include <assert.h> #include "utils.h" #include "cell.h" #include "image.h" #include "peaks.h" +#include "beam-parameters.h" -#define MAX_CPEAKS (1024) +#define MAX_CPEAKS (256 * 256) + + +static signed int locate_peak(double x, double y, double z, double lambda, + struct detector *det, double *xdap, double *ydap) +{ + int p; + signed int found = -1; + const double den = 1.0/lambda + z; + + for ( p=0; p<det->n_panels; p++ ) { + + double xd, yd, cl; + double xda, yda; + + /* Camera length for this panel */ + cl = det->panels[p].clen; + + /* Coordinates of peak relative to central beam, in m */ + xd = cl * x / den; + yd = cl * y / den; + + /* Convert to pixels */ + xd *= det->panels[p].res; + yd *= det->panels[p].res; + + /* Add the coordinates of the central beam */ + xda = xd + det->panels[p].cx; + yda = yd + det->panels[p].cy; + + /* Now, is this on this panel? */ + if ( xda < det->panels[p].min_x ) continue; + if ( xda > det->panels[p].max_x ) continue; + if ( yda < det->panels[p].min_y ) continue; + if ( yda > det->panels[p].max_y ) continue; + + /* If peak appears on multiple panels, reject it */ + if ( found != -1 ) return -1; + + /* Woohoo! */ + found = p; + *xdap = xda; + *ydap = yda; + + } + + return found; +} + + +static double excitation_error(double xl, double yl, double zl, + double ds_sq, double lambda) +{ + double tt; + double a, b, c; + double r1, r2; + int n; + + tt = angle_between(0.0, 0.0, 1.0, xl, yl, zl+1.0/lambda); + + a = 1.0; + b = - cos(tt) * 2.0/lambda; + c = pow(lambda, -2.0) - ds_sq; + + /* FIXME: I don't trust GSL's quadratic solver */ + n = gsl_poly_solve_quadratic(a, b, c, &r1, &r2); + assert(n == 2); + + r1 -= 1.0/lambda; + r2 -= 1.0/lambda; + + if ( r1 > r2 ) return r2; + return r1; +} struct cpeak *find_intersections(struct image *image, UnitCell *cell, - double divergence, double bandwidth, int *n, int output) { double asx, asy, asz; @@ -37,6 +112,11 @@ struct cpeak *find_intersections(struct image *image, UnitCell *cell, int hmax, kmax, lmax; double mres; signed int h, k, l; + double bandwidth = image->bw; + double divergence = image->div; + double lambda = image->lambda; + const double profile_cutoff = 0.05e9; /* 0.1 nm^-1 */ + double llow, lhigh; /* Wavelength */ cpeaks = malloc(sizeof(struct cpeak)*MAX_CPEAKS); if ( cpeaks == NULL ) { @@ -48,103 +128,91 @@ struct cpeak *find_intersections(struct image *image, UnitCell *cell, &bsx, &bsy, &bsz, &csx, &csy, &csz); + /* FIXME: Account for left-handed indexing */ + asz = -asz; bsz = -bsz; csz = -csz; + mres = 1.0 / 8.0e-10; /* 8 Angstroms */ hmax = mres / modulus(asx, asy, asz); kmax = mres / modulus(bsx, bsy, bsz); lmax = mres / modulus(csx, csy, csz); + /* "low" gives the largest Ewald sphere, + * "high" gives the smallest Ewald sphere. */ + llow = lambda - lambda*bandwidth/2.0; + lhigh = lambda + lambda*bandwidth/2.0; + for ( h=-hmax; h<hmax; h++ ) { for ( k=-kmax; k<kmax; k++ ) { for ( l=-lmax; l<lmax; l++ ) { double xl, yl, zl; - double ds_sq, dps_sq; - double delta, divfact; - double llow, lhigh; - double xd, yd, cl; + double ds, ds_sq; + double rlow, rhigh; /* "Excitation error" */ + signed int plow, phigh; + double xdalow, xdahigh; + double ydalow, ydahigh; double xda, yda; - int p; - int found = 0; + /* Ignore central beam */ if ( (h==0) && (k==0) && (l==0) ) continue; - llow = image->lambda - image->lambda*bandwidth/2.0; - lhigh = image->lambda + image->lambda*bandwidth/2.0; - /* Get the coordinates of the reciprocal lattice point */ zl = h*asz + k*bsz + l*csz; - if ( zl < 0.0 ) continue; /* Do this check very early */ + if ( zl > 0.0 ) continue; /* Throw out if it's "in front" */ xl = h*asx + k*bsx + l*csx; yl = h*asy + k*bsy + l*csy; + /* Calculate reciprocal lattice point modulus (and square) */ ds_sq = modulus_squared(xl, yl, zl); /* d*^2 */ - delta = divergence/image->lambda; - dps_sq = ds_sq + pow(delta, 2.0); /* d'*^2 */ - - /* In range? */ - divfact = 2.0 * delta * sqrt(xl*xl + yl*yl); - if ( ds_sq - 2.0*zl/llow > 0.0 ) continue; - if ( ds_sq - 2.0*zl/lhigh < 0.0 ) continue; - - /* Work out which panel this peak would fall on */ - for ( p=0; p<image->det->n_panels; p++ ) { - - /* Camera length for this panel */ - cl = image->det->panels[p].clen; - - /* Coordinates of peak relative to central beam, in m */ - xd = cl*xl / (ds_sq/(2.0*zl) - zl); - yd = cl*yl / (ds_sq/(2.0*zl) - zl); - - /* Convert to pixels */ - xd *= image->det->panels[p].res; - yd *= image->det->panels[p].res; - - /* Add the coordinates of the central beam */ - xda = xd + image->det->panels[p].cx; - yda = yd + image->det->panels[p].cy; - - /* Now, is this on this panel? */ - if ( xda < image->det->panels[p].min_x ) continue; - if ( xda > image->det->panels[p].max_x ) continue; - if ( yda < image->det->panels[p].min_y ) continue; - if ( yda > image->det->panels[p].max_y ) continue; - - /* Woohoo! */ - found = 1; - break; - + ds = sqrt(ds_sq); + if ( ds > mres ) continue; /* Outside resolution range */ + + /* Calculate excitation errors */ + rlow = excitation_error(xl, yl, zl, ds_sq, llow); + rhigh = excitation_error(xl, yl, zl, ds_sq, lhigh); + + if ( (fabs(rlow) > profile_cutoff) + && (fabs(rhigh) > profile_cutoff) ) { + /* Reflection is not close to Bragg at either of + * the two extremes of wavelength, so skip it. */ + continue; } - if ( !found ) continue; - + /* Locate peak on detector, and check it doesn't span panels */ + plow = locate_peak(xl, yl, zl, llow, image->det, + &xdalow, &ydalow); + if ( plow == -1 ) continue; + phigh = locate_peak(xl, yl, zl, lhigh, image->det, + &xdahigh, &ydahigh); + if ( phigh == -1 ) continue; + if ( plow != phigh ) continue; + + xda = xdahigh; + yda = ydahigh; cpeaks[np].h = h; cpeaks[np].k = k; cpeaks[np].l = l; - cpeaks[np].x = xda; - cpeaks[np].y = yda; + cpeaks[np].x = xdahigh; + cpeaks[np].y = ydahigh; np++; if ( output ) { - printf("%i %i %i 0.0 (at %f,%f)\n", h, k, l, xda, yda); + printf("%3i %3i %3i %6f (at %5.2f,%5.2f) %9e %9e\n", + h, k, l, 0.0, xda, yda, rlow, rhigh); } + if ( np == MAX_CPEAKS ) goto out; + } } } +out: *n = np; return cpeaks; } -/* Return the partiality of this reflection in this image */ -double partiality(struct image *image, signed int h, signed int k, signed int l) -{ - return 1.0; -} - - double integrate_all(struct image *image, struct cpeak *cpeaks, int n) { double itot = 0.0; |