def test_auto_corr_scat_factor(): num_levels, num_bufs = 3, 4 tot_channels, lags = utils.multi_tau_lags(num_levels, num_bufs) beta = 0.5 relaxation_rate = 10.0 baseline = 1.0 g2 = corr.auto_corr_scat_factor(lags, beta, relaxation_rate, baseline) assert_array_almost_equal(g2, np.array([1.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]), decimal=8)
def test_multi_tau_lags(): multi_tau_levels = 3 multi_tau_channels = 8 delay_steps = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28] tot_channels, lag_steps = core.multi_tau_lags(multi_tau_levels, multi_tau_channels) assert_array_equal(16, tot_channels) assert_array_equal(delay_steps, lag_steps)
def multi_tau_auto_corr(num_levels, num_bufs, labels, images): ##comments, please add start_image, end_image, the default as None from skxray.core import roi from skxray.core import utils as core """ This function computes one-time correlations. It uses a scheme to achieve long-time correlations inexpensively by downsampling the data, iteratively combining successive frames. The longest lag time computed is num_levels * num_bufs. Parameters ---------- num_levels : int how many generations of downsampling to perform, i.e., the depth of the binomial tree of averaged frames num_bufs : int, must be even maximum lag step to compute in each generation of downsampling labels : array labeled array of the same shape as the image stack; each ROI is represented by a distinct label (i.e., integer) images : iterable of 2D arrays dimensions are: (rr, cc) Returns ------- g2 : array matrix of normalized intensity-intensity autocorrelation shape (num_levels, number of labels(ROI)) lag_steps : array delay or lag steps for the multiple tau analysis shape num_levels Notes ----- The normalized intensity-intensity time-autocorrelation function is defined as :math :: g_2(q, t') = \frac{<I(q, t)I(q, t + t')> }{<I(q, t)>^2} ; t' > 0 Here, I(q, t) refers to the scattering strength at the momentum transfer vector q in reciprocal space at time t, and the brackets <...> refer to averages over time t. The quantity t' denotes the delay time This implementation is based on code in the language Yorick by Mark Sutton, based on published work. [1]_ References ---------- .. [1] D. Lumma, L. B. Lurio, S. G. J. Mochrie and M. Sutton, "Area detector based photon correlation in the regime of short data batches: Data reduction for dynamic x-ray scattering," Rev. Sci. Instrum., vol 70, p 3274-3289, 2000. """ # In order to calculate correlations for `num_bufs`, images must be # kept for up to the maximum lag step. These are stored in the array # buffer. This algorithm only keeps number of buffers and delays but # several levels of delays number of levels are kept in buf. Each # level has twice the delay times of the next lower one. To save # needless copying, of cyclic storage of images in buf is used. if num_bufs % 2 != 0: raise ValueError("number of channels(number of buffers) in " "multiple-taus (must be even)") if hasattr(images, 'frame_shape'): # Give a user-friendly error if we can detect the shape from pims. if labels.shape != images.frame_shape: raise ValueError("Shape of the image stack should be equal to" " shape of the labels array") # get the pixels in each label label_mask, pixel_list = roi.extract_label_indices(labels) num_rois = np.max(label_mask) # number of pixels per ROI num_pixels = np.bincount(label_mask, minlength=(num_rois + 1)) num_pixels = num_pixels[1:] if np.any(num_pixels == 0): raise ValueError("Number of pixels of the required roi's" " cannot be zero, " "num_pixels = {0}".format(num_pixels)) # G holds the un normalized auto-correlation result. We # accumulate computations into G as the algorithm proceeds. G = np.zeros(((num_levels + 1) * num_bufs / 2, num_rois), dtype=np.float64) # matrix of past intensity normalizations past_intensity_norm = np.zeros(((num_levels + 1) * num_bufs / 2, num_rois), dtype=np.float64) # matrix of future intensity normalizations future_intensity_norm = np.zeros( ((num_levels + 1) * num_bufs / 2, num_rois), dtype=np.float64) # Ring buffer, a buffer with periodic boundary conditions. # Images must be keep for up to maximum delay in buf. buf = np.zeros((num_levels, num_bufs, np.sum(num_pixels)), dtype=np.float64) # to track processing each level track_level = np.zeros(num_levels) # to increment buffer cur = np.ones(num_levels, dtype=np.int64) # to track how many images processed in each level img_per_level = np.zeros(num_levels, dtype=np.int64) start_time = time.time() # used to log the computation time (optionally) for n, img in enumerate(images): cur[0] = (1 + cur[0]) % num_bufs # increment buffer # Put the image into the ring buffer. buf[0, cur[0] - 1] = (np.ravel(img))[pixel_list] # Compute the correlations between the first level # (undownsampled) frames. This modifies G, # past_intensity_norm, future_intensity_norm, # and img_per_level in place! _process(buf, G, past_intensity_norm, future_intensity_norm, label_mask, num_bufs, num_pixels, img_per_level, level=0, buf_no=cur[0] - 1) # check whether the number of levels is one, otherwise # continue processing the next level processing = num_levels > 1 # Compute the correlations for all higher levels. level = 1 while processing: if not track_level[level]: track_level[level] = 1 processing = False else: prev = 1 + (cur[level - 1] - 2) % num_bufs cur[level] = 1 + cur[level] % num_bufs buf[level, cur[level] - 1] = (buf[level - 1, prev - 1] + buf[level - 1, cur[level - 1] - 1]) / 2 # make the track_level zero once that level is processed track_level[level] = 0 # call the _process function for each multi-tau level # for multi-tau levels greater than one # Again, this is modifying things in place. See comment # on previous call above. _process( buf, G, past_intensity_norm, future_intensity_norm, label_mask, num_bufs, num_pixels, img_per_level, level=level, buf_no=cur[level] - 1, ) level += 1 # Checking whether there is next level for processing processing = level < num_levels # ending time for the process end_time = time.time() logger.info("Processing time for {0} images took {1} seconds." "".format(n, (end_time - start_time))) # the normalization factor if len(np.where(past_intensity_norm == 0)[0]) != 0: g_max = np.where(past_intensity_norm == 0)[0][0] else: g_max = past_intensity_norm.shape[0] # g2 is normalized G g2 = (G[:g_max] / (past_intensity_norm[:g_max] * future_intensity_norm[:g_max])) # Convert from num_levels, num_bufs to lag frames. tot_channels, lag_steps = core.multi_tau_lags(num_levels, num_bufs) lag_steps = lag_steps[:g_max] return g2, lag_steps
def multi_tau_auto_corr(num_levels, num_bufs, labels, images): ##comments, please add start_image, end_image, the default as None from skxray.core import roi from skxray.core import utils as core """ This function computes one-time correlations. It uses a scheme to achieve long-time correlations inexpensively by downsampling the data, iteratively combining successive frames. The longest lag time computed is num_levels * num_bufs. Parameters ---------- num_levels : int how many generations of downsampling to perform, i.e., the depth of the binomial tree of averaged frames num_bufs : int, must be even maximum lag step to compute in each generation of downsampling labels : array labeled array of the same shape as the image stack; each ROI is represented by a distinct label (i.e., integer) images : iterable of 2D arrays dimensions are: (rr, cc) Returns ------- g2 : array matrix of normalized intensity-intensity autocorrelation shape (num_levels, number of labels(ROI)) lag_steps : array delay or lag steps for the multiple tau analysis shape num_levels Notes ----- The normalized intensity-intensity time-autocorrelation function is defined as :math :: g_2(q, t') = \frac{<I(q, t)I(q, t + t')> }{<I(q, t)>^2} ; t' > 0 Here, I(q, t) refers to the scattering strength at the momentum transfer vector q in reciprocal space at time t, and the brackets <...> refer to averages over time t. The quantity t' denotes the delay time This implementation is based on code in the language Yorick by Mark Sutton, based on published work. [1]_ References ---------- .. [1] D. Lumma, L. B. Lurio, S. G. J. Mochrie and M. Sutton, "Area detector based photon correlation in the regime of short data batches: Data reduction for dynamic x-ray scattering," Rev. Sci. Instrum., vol 70, p 3274-3289, 2000. """ # In order to calculate correlations for `num_bufs`, images must be # kept for up to the maximum lag step. These are stored in the array # buffer. This algorithm only keeps number of buffers and delays but # several levels of delays number of levels are kept in buf. Each # level has twice the delay times of the next lower one. To save # needless copying, of cyclic storage of images in buf is used. if num_bufs % 2 != 0: raise ValueError("number of channels(number of buffers) in " "multiple-taus (must be even)") if hasattr(images, "frame_shape"): # Give a user-friendly error if we can detect the shape from pims. if labels.shape != images.frame_shape: raise ValueError("Shape of the image stack should be equal to" " shape of the labels array") # get the pixels in each label label_mask, pixel_list = roi.extract_label_indices(labels) num_rois = np.max(label_mask) # number of pixels per ROI num_pixels = np.bincount(label_mask, minlength=(num_rois + 1)) num_pixels = num_pixels[1:] if np.any(num_pixels == 0): raise ValueError( "Number of pixels of the required roi's" " cannot be zero, " "num_pixels = {0}".format(num_pixels) ) # G holds the un normalized auto-correlation result. We # accumulate computations into G as the algorithm proceeds. G = np.zeros(((num_levels + 1) * num_bufs / 2, num_rois), dtype=np.float64) # matrix of past intensity normalizations past_intensity_norm = np.zeros(((num_levels + 1) * num_bufs / 2, num_rois), dtype=np.float64) # matrix of future intensity normalizations future_intensity_norm = np.zeros(((num_levels + 1) * num_bufs / 2, num_rois), dtype=np.float64) # Ring buffer, a buffer with periodic boundary conditions. # Images must be keep for up to maximum delay in buf. buf = np.zeros((num_levels, num_bufs, np.sum(num_pixels)), dtype=np.float64) # to track processing each level track_level = np.zeros(num_levels) # to increment buffer cur = np.ones(num_levels, dtype=np.int64) # to track how many images processed in each level img_per_level = np.zeros(num_levels, dtype=np.int64) start_time = time.time() # used to log the computation time (optionally) for n, img in enumerate(images): cur[0] = (1 + cur[0]) % num_bufs # increment buffer # Put the image into the ring buffer. buf[0, cur[0] - 1] = (np.ravel(img))[pixel_list] # Compute the correlations between the first level # (undownsampled) frames. This modifies G, # past_intensity_norm, future_intensity_norm, # and img_per_level in place! _process( buf, G, past_intensity_norm, future_intensity_norm, label_mask, num_bufs, num_pixels, img_per_level, level=0, buf_no=cur[0] - 1, ) # check whether the number of levels is one, otherwise # continue processing the next level processing = num_levels > 1 # Compute the correlations for all higher levels. level = 1 while processing: if not track_level[level]: track_level[level] = 1 processing = False else: prev = 1 + (cur[level - 1] - 2) % num_bufs cur[level] = 1 + cur[level] % num_bufs buf[level, cur[level] - 1] = (buf[level - 1, prev - 1] + buf[level - 1, cur[level - 1] - 1]) / 2 # make the track_level zero once that level is processed track_level[level] = 0 # call the _process function for each multi-tau level # for multi-tau levels greater than one # Again, this is modifying things in place. See comment # on previous call above. _process( buf, G, past_intensity_norm, future_intensity_norm, label_mask, num_bufs, num_pixels, img_per_level, level=level, buf_no=cur[level] - 1, ) level += 1 # Checking whether there is next level for processing processing = level < num_levels # ending time for the process end_time = time.time() logger.info("Processing time for {0} images took {1} seconds." "".format(n, (end_time - start_time))) # the normalization factor if len(np.where(past_intensity_norm == 0)[0]) != 0: g_max = np.where(past_intensity_norm == 0)[0][0] else: g_max = past_intensity_norm.shape[0] # g2 is normalized G g2 = G[:g_max] / (past_intensity_norm[:g_max] * future_intensity_norm[:g_max]) # Convert from num_levels, num_bufs to lag frames. tot_channels, lag_steps = core.multi_tau_lags(num_levels, num_bufs) lag_steps = lag_steps[:g_max] return g2, lag_steps