/** This software was developed by the University of Tennessee as part of the Distributed Data Analysis of Neutron Scattering Experiments (DANSE) project funded by the US National Science Foundation. If you use DANSE applications to do scientific research that leads to publication, we ask that you acknowledge the use of the software with the following sentence: "This work benefited from DANSE software developed under NSF award DMR-0520547." copyright 2009, University of Tennessee */ #include "smearer.hh" #include #include using namespace std; #if defined(_MSC_VER) extern "C" { #include "winFuncs.h" } #endif /** * Constructor for BaseSmearer * * @param qmin: minimum Q value * @param qmax: maximum Q value * @param nbins: number of Q bins */ BaseSmearer :: BaseSmearer(double qmin, double qmax, int nbins) { // Number of bins this->nbins = nbins; this->qmin = qmin; this->qmax = qmax; // Flag to keep track of whether we have a smearing matrix or // whether we need to compute one has_matrix = false; even_binning = true; }; /** * Constructor for BaseSmearer * * Used for uneven binning * @param q: array of Q values * @param nbins: number of Q bins */ BaseSmearer :: BaseSmearer(double* q, int nbins) { // Number of bins this->nbins = nbins; this->q_values = q; // Flag to keep track of whether we have a smearing matrix or // whether we need to compute one has_matrix = false; even_binning = false; }; /** * Constructor for SlitSmearer * * @param width: slit width in Q units * @param height: slit height in Q units * @param qmin: minimum Q value * @param qmax: maximum Q value * @param nbins: number of Q bins */ SlitSmearer :: SlitSmearer(double width, double height, double qmin, double qmax, int nbins) : BaseSmearer(qmin, qmax, nbins){ this->height = height; this->width = width; }; /** * Constructor for SlitSmearer * * @param width: slit width in Q units * @param height: slit height in Q units * @param q: array of Q values * @param nbins: number of Q bins */ SlitSmearer :: SlitSmearer(double width, double height, double* q, int nbins) : BaseSmearer(q, nbins){ this->height = height; this->width = width; }; /** * Constructor for QSmearer * * @param width: array slit widths for each Q point, in Q units * @param qmin: minimum Q value * @param qmax: maximum Q value * @param nbins: number of Q bins */ QSmearer :: QSmearer(double* width, double qmin, double qmax, int nbins) : BaseSmearer(qmin, qmax, nbins){ this->width = width; }; /** * Constructor for QSmearer * * @param width: array slit widths for each Q point, in Q units * @param q: array of Q values * @param nbins: number of Q bins */ QSmearer :: QSmearer(double* width, double* q, int nbins) : BaseSmearer(q, nbins){ this->width = width; }; /** * Compute the slit smearing matrix * * For even binning (q_min to q_max with nbins): * * step = (q_max-q_min)/(nbins-1) * first bin goes from q_min to q_min+step * last bin goes from q_max to q_max+step * * For binning according to q array: * * Each q point represents a bin going from half the distance between it * and the previous point to half the distance between it and the next point. * * Example: bin i goes from (q_values[i-1]+q_values[i])/2 to (q_values[i]+q_values[i+1])/2 * * The exceptions are the first and last bins, which are centered at the first and * last q-values, respectively. The width of the first and last bins is the distance between * their respective neighboring q-value. */ void SlitSmearer :: compute_matrix(){ weights = new vector(nbins*nbins,0); // Check the length of the data if (nbins<2) return; int npts_h = height>0.0 ? npts : 1; int npts_w = width>0.0 ? npts : 1; // If both height and width are great than zero, // modify the number of points in each direction so // that the total number of points is still what // the user would expect (downgrade resolution) //if(npts_h>1 && npts_w>1){ // npts_h = (int)ceil(sqrt((double)npts)); // npts_w = npts_h; //} double shift_h, shift_w, hbin_size, wbin_size; // Make sure height and width are all positive (FWMH/2) // Assumption; height and width are all same for all q points if(npts_h == 1){ shift_h = 0.0; } else { shift_h = fabs(height); } if(npts_w == 1){ shift_w = 0.0; } else { shift_w = fabs(width); } // size of the h bin and w bin hbin_size = shift_h / nbins; wbin_size = shift_w / nbins; // Loop over all q-values for(int i=0; i0 when the height (=0) does not present. //Or height << width. else if((npts_w!=1 && npts_h == 1)|| (npts_w!=1 && npts_h != 1 && width/height > 100.0)){ shift_w = width; //del_w = width/((double)npts_w-1.0); double q_shifted_low = q - shift_w; // High limit of the resolution range double q_shifted_high = q + shift_w; // Go through all the q_js for weighting those points if(q_j >= q_shifted_low && q_j <= q_shifted_high) { // The weighting factor comes, // Give some weight (delq_bin) for the q_j within the resolution range // Weight should be same for all qs except // for the q bin size at j. // Note that the division by q_0 is only due to the precision problem // where q_high - q_low gets to very small. // Later, it will be normalized again. (*weights)[i*nbins+j] += (q_high - q_low)/q_0 ; } } else{ // Loop for width (;Height is analytical.) // Condition: height >>> width, otherwise, below is not accurate enough. // Smear weight numerical iteration for width >0 when the height (>0) presents. // When width = 0, the numerical iteration will be skipped. // The resolution calculation for the height is done by direct integration, // assuming the I(q'=sqrt(q_j^2-(q+shift_w)^2)) is constant within a q' bin, [q_high, q_low]. // In general, this weight numerical iteration for width >0 might be a rough approximation, // but it must be good enough when height >>> width. for(int k=(-npts_w + 1); k= q_shifted_low && q_j <= q_shifted_high) { // The weighting factor comes, // Give some weight (delq_bin) for the q_j within the resolution range // Weight should be same for all qs except // for the q bin size at j. // Note that the division by q_0 is only due to the precision problem // where q_high - q_low gets to very small. // Later, it will be normalized again. double q_shift_min = q - width; double u = (q_j * q_j - (q_shift) * (q_shift)); // The fabs below are not necessary but in case: the weight should never be imaginary. // At the edge of each sub_width. weight += u(at q_high bin) - u(0), where u(0) = 0, // and weighted by (2.0* npts_w -1.0)once for each q. //if (q == q_j) { if (q_low <= q_shift && q_high > q_shift) { //if (k==0) (*weights)[i*nbins+j] += (sqrt(fabs((q_high)*(q_high)-q_shift * q_shift)))/q_0;// * (2.0*double(npts_w)-1.0); } // For the rest of sub_width. weight += u(at q_high bin) - u(at q_low bin) else{// if (u > 0.0){ (*weights)[i*nbins+j] += (sqrt(fabs((q_high)*(q_high)- q_shift * q_shift))-sqrt(fabs((q_low)*(q_low)- q_shift * q_shift)))/q_0 ; } } } } } } }; /** * Compute the point smearing matrix */ void QSmearer :: compute_matrix(){ weights = new vector(nbins*nbins,0); // Loop over all q-values double step = (qmax-qmin)/((double)nbins-1.0); double q, q_min, q_max; double q_j, q_jmax, q_jmin; for(int i=0; i=0 && i0.0) ? sum/counts : 0.0; } }