def interpolate_run( img_gen, tags, mask, x_center, y_center, pixsize, detdist, wavelen, prefix, how='fetch', interp_method='floor', ring_locations=None, q_resolution=0, phi_resolution=0, radius_unit='inv_ang', nphi=None, qmin=None, qmax=None, qmin_pix=None, qmax_pix=None, detector_gain=None, index_query_fname=None): """ Description =========== Interpolates polar rings from detector images using loki.RingData and saves the output to a file specified by prefix. Parameters ========== img_gen, generator of 2d np.array float images, this should generate each image in a run tags, list, string, the tags associated w each image generated by img_gen, (should be in order with generation) mask, 2d np.array bool, a masked image, True is unmasked, False is masked, should have same dimensions of images generated by img_gen x_center, float, pixel unit where beam hits detector, x dimension( fast dimension), measured from 0,0 pixel corner y_center, float, pixel unit where beam hits detector, y dimension( slow dimension), measured from 0,0 pixel corner detdist, float, sample to detector distance in meter wavelen, float, wavelength of photons in angstroms pixsize, float pixel size in meter prefix str, file prefix, include directory path if necessary how, str, either ('fetch' or 'polar') method of interpolating the ring. 'fetch' is the new version, which requires q_resolution and phi_resolution parameters. Uses RingData.RingFetch. 'polar' is the old method which makes a polar image using RingData.InterpSimple Required Parmeters if using 'fetch' method ========================================== interp_method, str, should be either ['floor', 'nearest', 'nearest4', 'weighted4' ] ring_locations, list, range of ring radii or ring momentum transfer magnitudes q_resolution, float , resolution of rings in inverse angstroms phi_resolution float, resolution of rings in degrees Required Parameters if using 'polar' method =========================================== nphi, int, azimuthal dimension of polar image, (try to keep at least single pixel resolution at qmax, you can average over polar pixels later) qmin, qmax, float, min q and max q bounds of each polar image being created (in inverse angstroms) qmin_pix, qmax_pix, float, min q and max q bounds of each polar image being created (in pixel units) Optional Parameters =================== index_query_fname, str, filename created by loki.queryRingIndices detector_gain, float, absolute gain of detector Returns ======= the output filename """ assert( how in [ 'fetch', 'polar' , 'polar_n'] ) assert(radius_unit in ['inv_ang', 'pixels']) num_imgs = len(tags) if isinstance( wavelen, (int, float, long, complex)) and isinstance( detdist, (int, float, long, complex)): wavelen, detdist = [wavelen] * num_imgs, [detdist] * num_imgs else: assert(isinstance(wavelen, (list, np.ndarray))) assert(isinstance(detdist, (list, np.ndarray))) assert(len(wavelen) == len(detdist) == num_imgs) if detector_gain is None: detector_gain, photon_conversion_factor = -1, [1] * num_imgs else: photon_conversion_factor = [ detector_gain * 3.65 * w / 12398.42 for w in wavelen] with h5py.File(prefix + '.hdf5', 'w') as output_hdf: #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #====================================================================== #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if how=='polar' or how == 'polar_n': assert( nphi is not None) for i_tag, tag in enumerate(tags): pix2invang = lambda qpix: np.sin(np.arctan( qpix * pixsize / detdist[i_tag]) / 2) * 4 * np.pi / wavelen[i_tag] invang2pix = lambda qia: np.tan( 2 * np.arcsin(qia * wavelen[i_tag] / 4 / np.pi)) * detdist[i_tag] / pixsize if qmin_pix is None or qmax_pix is None: assert(qmin is not None) assert (qmax is not None) qmin_pix = invang2pix(qmin) qmax_pix = invang2pix(qmax) # Initialize the interpolater interpolater = InterpSimple( x_center, y_center, qmax_pix, qmin_pix, nphi, raw_img_shape=mask.shape ) if how == 'polar_n': interpolater.set_polar_tree(index_query_fname, weighted=False) pmeth = interpolater.nearest_query else: pmeth = interpolater.nearest # make a polar image mask pmask = pmeth( mask.astype(float) ) #.round() pmask = pmask.astype(int).astype(bool) # Make the polar images polar_img = pmask * pmeth( img_gen.next()) \ * photon_conversion_factor[i_tag] output_hdf.create_dataset('ring_intensities/%s'%tag, data=polar_img, dtype=np.float32) output_hdf.create_dataset('ring_mask/%s'%tag, data=pmask.astype(np.int8), dtype=np.int8) ring_radii = np.arange(qmin_pix, qmax_pix) ring_mag = np.array( [pix2invang(q_pix)for q_pix in ring_radii]) output_hdf.create_dataset( 'ring_radii/%s'%tag, data = ring_radii) output_hdf.create_dataset( 'ring_momentum_transfer/%s'%tag, data = ring_mag) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #============================================================================ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ else: # using default 'fetch' method assert(phi_resolution is not None) assert(q_resolution is not None) assert(ring_locations is not None) fetcher = RingFetch( a=x_center, b=y_center, img_shape=mask.shape, mask=mask, q_resolution=q_resolution, phi_resolution=phi_resolution, pixsize=pixsize, interp_method=interp_method, index_query_fname=index_query_fname) ring_radii = np.zeros((num_imgs, len(ring_locations))) ring_mag = np.zeros_like(ring_radii) for i_tag, tag in enumerate(tags): fetcher.set_params(wavelen[i_tag], detdist[i_tag]) fetcher.set_photon_factor(photon_conversion_factor[i_tag]) fetcher.set_working_image(img_gen.next()) intensities = np.zeros( (len(ring_locations), fetcher.num_phi_nodes)) if radius_unit == 'inv_ang': for ring_index, ring_q in enumerate(ring_locations): intensities[ring_index] = \ fetcher.fetch_a_ring(q=ring_q) ring_radii[i_tag, ring_index] = int( round(fetcher.q2r(ring_q))) ring_mag[i_tag, ring_index] = ring_q else: for ring_index, ring_radius in enumerate(ring_locations): intensities[ring_index] = \ fetcher.fetch_a_ring(radius=ring_radius) ring_radii[i_tag, ring_index] = ring_radius ring_mag[i_tag, ring_index] = fetcher.r2q(ring_radius) output_hdf.create_dataset('ring_intensities/%s' % tag, data=intensities, dtype=np.float32) # define meta parameters not specified nphi = intensities.shape[1] pmask = np.ones((len(ring_locations), nphi)) output_hdf.create_dataset( 'ring_radii', data=ring_radii, dtype=np.float32) output_hdf.create_dataset( 'ring_moementum_transfer', data=ring_mag, dtype=np.float32) output_hdf.create_dataset('ring_mask', data=pmask.astype(np.int8)) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #============================================================================ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ phi_values = np.arange(nphi) * 2 * np.pi / nphi # save meta data output_hdf.create_dataset('how', data=how) output_hdf.create_dataset('interp_method', data=interp_method) output_hdf.create_dataset('x_center', data=x_center, dtype=np.float32) output_hdf.create_dataset('y_center', data=y_center, dtype=np.float32) output_hdf.create_dataset('wavelen', data=wavelen, dtype=np.float32) output_hdf.create_dataset('pixsize', data=pixsize, dtype=np.float32) output_hdf.create_dataset('detdist', data=detdist, dtype=np.float32) output_hdf.create_dataset( 'detgain', data=detector_gain, dtype=np.float32) output_hdf.create_dataset( 'photon_factor', data=photon_conversion_factor, dtype=np.float32) output_hdf.create_dataset( 'q_resolution', data=q_resolution, dtype=np.float32) output_hdf.create_dataset( 'phi_resolution', data=phi_resolution, dtype=np.float32) output_hdf.create_dataset('num_phi', data=nphi, dtype=np.float32) output_hdf.create_dataset( 'ring_phis', data=phi_values, dtype=np.float32) # save print ("saving data to file %s!" % (prefix + '.hdf5')) # output_hdf.close() return prefix + '.hdf5'
# adjust so our edge is a multiple of rbin factor interp_rmax = int( interp_rmin + np.ceil( (interp_rmax - interp_rmin) / rbin_fct)*rbin_fct ) nphi = int( 2 * np.pi * interp_rmax ) if phibins>0: phibin_fct = np.ceil( nphi / float( phibins ) ) else: phibin_fct=1 nphi = int( np.ceil( 2 * np.pi * interp_rmax/phibin_fct)*phibin_fct) # number of azimuthal samples per bin rbin_new = (interp_rmax- interp_rmin ) / rbin_fct phibin_new = nphi / phibin_fct binned_pol_img_sh = ( int(rbin_new), int(phibin_new) ) print("polar image dimensions: %d x %d"%(rbin_new, phibin_new)) Interp = InterpSimple( cent[0], cent[1] , interp_rmax, interp_rmin, nphi, img_sh) pmask = Interp.nearest(mask).astype(int).astype(float) pmask_bn = bin_ndarray( pmask, binned_pol_img_sh) # print pmask.shape,pmask_bn.shape # if (rbin_fct==1 and phibin_fct==1): # print('not binning polar img') # sys.exit() #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~~~ data get parameters #load the data events for the given run ds_str = 'exp=cxilp6715:run=%d:smd' % run ds = psana.MPIDataSource(ds_str)
np.ceil((interp_rmax - interp_rmin) / rbin_fct) * rbin_fct) nphi = int(2 * np.pi * interp_rmax) if phibins > 0: phibin_fct = np.ceil(nphi / float(phibins)) else: phibin_fct = 1 nphi = int(np.ceil(2 * np.pi * interp_rmax / phibin_fct) * phibin_fct) # number of azimuthal samples per bin rbin_new = (interp_rmax - interp_rmin) / rbin_fct phibin_new = nphi / phibin_fct binned_pol_img_sh = (int(rbin_new), int(phibin_new)) print("polar image dimensions: %d x %d" % (rbin_new, phibin_new)) Interp = InterpSimple(cent[0], cent[1], interp_rmax, interp_rmin, nphi, img_sh) pmask = Interp.nearest(mask).astype(int).astype(float) pmask_bn = bin_ndarray(pmask, binned_pol_img_sh) # print pmask.shape,pmask_bn.shape # if (rbin_fct==1 and phibin_fct==1): # print('not binning polar img') # sys.exit() #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~~~ data get parameters #load the data events for the given run ds_str = 'exp=cxilr6716:run=%d:smd' % run ds = psana.MPIDataSource(ds_str) events = ds.events()
def interpolate_run(img_gen, tags, mask, x_center, y_center, pixsize, detdist, wavelen, prefix, how='fetch', interp_method='floor', ring_locations=None, q_resolution=0, phi_resolution=0, radius_unit='inv_ang', nphi=None, qmin=None, qmax=None, qmin_pix=None, qmax_pix=None, detector_gain=None, index_query_fname=None): """ Description =========== Interpolates polar rings from detector images using loki.RingData and saves the output to a file specified by prefix. Parameters ========== img_gen, generator of 2d np.array float images, this should generate each image in a run tags, list, string, the tags associated w each image generated by img_gen, (should be in order with generation) mask, 2d np.array bool, a masked image, True is unmasked, False is masked, should have same dimensions of images generated by img_gen x_center, float, pixel unit where beam hits detector, x dimension( fast dimension), measured from 0,0 pixel corner y_center, float, pixel unit where beam hits detector, y dimension( slow dimension), measured from 0,0 pixel corner detdist, float, sample to detector distance in meter wavelen, float, wavelength of photons in angstroms pixsize, float pixel size in meter prefix str, file prefix, include directory path if necessary how, str, either ('fetch' or 'polar') method of interpolating the ring. 'fetch' is the new version, which requires q_resolution and phi_resolution parameters. Uses RingData.RingFetch. 'polar' is the old method which makes a polar image using RingData.InterpSimple Required Parmeters if using 'fetch' method ========================================== interp_method, str, should be either ['floor', 'nearest', 'nearest4', 'weighted4' ] ring_locations, list, range of ring radii or ring momentum transfer magnitudes q_resolution, float , resolution of rings in inverse angstroms phi_resolution float, resolution of rings in degrees Required Parameters if using 'polar' method =========================================== nphi, int, azimuthal dimension of polar image, (try to keep at least single pixel resolution at qmax, you can average over polar pixels later) qmin, qmax, float, min q and max q bounds of each polar image being created (in inverse angstroms) qmin_pix, qmax_pix, float, min q and max q bounds of each polar image being created (in pixel units) Optional Parameters =================== index_query_fname, str, filename created by loki.queryRingIndices detector_gain, float, absolute gain of detector Returns ======= the output filename """ assert (how in ['fetch', 'polar', 'polar_n']) assert (radius_unit in ['inv_ang', 'pixels']) num_imgs = len(tags) if isinstance(wavelen, (int, float, long, complex)) and isinstance( detdist, (int, float, long, complex)): wavelen, detdist = [wavelen] * num_imgs, [detdist] * num_imgs else: assert (isinstance(wavelen, (list, np.ndarray))) assert (isinstance(detdist, (list, np.ndarray))) assert (len(wavelen) == len(detdist) == num_imgs) if detector_gain is None: detector_gain, photon_conversion_factor = -1, [1] * num_imgs else: photon_conversion_factor = [ detector_gain * 3.65 * w / 12398.42 for w in wavelen ] with h5py.File(prefix + '.hdf5', 'w') as output_hdf: #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #====================================================================== #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if how == 'polar' or how == 'polar_n': assert (nphi is not None) for i_tag, tag in enumerate(tags): pix2invang = lambda qpix: np.sin( np.arctan(qpix * pixsize / detdist[i_tag]) / 2 ) * 4 * np.pi / wavelen[i_tag] invang2pix = lambda qia: np.tan(2 * np.arcsin(qia * wavelen[ i_tag] / 4 / np.pi)) * detdist[i_tag] / pixsize if qmin_pix is None or qmax_pix is None: assert (qmin is not None) assert (qmax is not None) qmin_pix = invang2pix(qmin) qmax_pix = invang2pix(qmax) # Initialize the interpolater interpolater = InterpSimple(x_center, y_center, qmax_pix, qmin_pix, nphi, raw_img_shape=mask.shape) if how == 'polar_n': interpolater.set_polar_tree(index_query_fname, weighted=False) pmeth = interpolater.nearest_query else: pmeth = interpolater.nearest # make a polar image mask pmask = pmeth(mask.astype(float)) #.round() pmask = pmask.astype(int).astype(bool) # Make the polar images polar_img = pmask * pmeth( img_gen.next()) \ * photon_conversion_factor[i_tag] output_hdf.create_dataset('ring_intensities/%s' % tag, data=polar_img, dtype=np.float32) output_hdf.create_dataset('ring_mask/%s' % tag, data=pmask.astype(np.int8), dtype=np.int8) ring_radii = np.arange(qmin_pix, qmax_pix) ring_mag = np.array( [pix2invang(q_pix) for q_pix in ring_radii]) output_hdf.create_dataset('ring_radii/%s' % tag, data=ring_radii) output_hdf.create_dataset('ring_momentum_transfer/%s' % tag, data=ring_mag) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #============================================================================ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ else: # using default 'fetch' method assert (phi_resolution is not None) assert (q_resolution is not None) assert (ring_locations is not None) fetcher = RingFetch(a=x_center, b=y_center, img_shape=mask.shape, mask=mask, q_resolution=q_resolution, phi_resolution=phi_resolution, pixsize=pixsize, interp_method=interp_method, index_query_fname=index_query_fname) ring_radii = np.zeros((num_imgs, len(ring_locations))) ring_mag = np.zeros_like(ring_radii) for i_tag, tag in enumerate(tags): fetcher.set_params(wavelen[i_tag], detdist[i_tag]) fetcher.set_photon_factor(photon_conversion_factor[i_tag]) fetcher.set_working_image(img_gen.next()) intensities = np.zeros( (len(ring_locations), fetcher.num_phi_nodes)) if radius_unit == 'inv_ang': for ring_index, ring_q in enumerate(ring_locations): intensities[ring_index] = \ fetcher.fetch_a_ring(q=ring_q) ring_radii[i_tag, ring_index] = int( round(fetcher.q2r(ring_q))) ring_mag[i_tag, ring_index] = ring_q else: for ring_index, ring_radius in enumerate(ring_locations): intensities[ring_index] = \ fetcher.fetch_a_ring(radius=ring_radius) ring_radii[i_tag, ring_index] = ring_radius ring_mag[i_tag, ring_index] = fetcher.r2q(ring_radius) output_hdf.create_dataset('ring_intensities/%s' % tag, data=intensities, dtype=np.float32) # define meta parameters not specified nphi = intensities.shape[1] pmask = np.ones((len(ring_locations), nphi)) output_hdf.create_dataset('ring_radii', data=ring_radii, dtype=np.float32) output_hdf.create_dataset('ring_moementum_transfer', data=ring_mag, dtype=np.float32) output_hdf.create_dataset('ring_mask', data=pmask.astype(np.int8)) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #============================================================================ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ phi_values = np.arange(nphi) * 2 * np.pi / nphi # save meta data output_hdf.create_dataset('how', data=how) output_hdf.create_dataset('interp_method', data=interp_method) output_hdf.create_dataset('x_center', data=x_center, dtype=np.float32) output_hdf.create_dataset('y_center', data=y_center, dtype=np.float32) output_hdf.create_dataset('wavelen', data=wavelen, dtype=np.float32) output_hdf.create_dataset('pixsize', data=pixsize, dtype=np.float32) output_hdf.create_dataset('detdist', data=detdist, dtype=np.float32) output_hdf.create_dataset('detgain', data=detector_gain, dtype=np.float32) output_hdf.create_dataset('photon_factor', data=photon_conversion_factor, dtype=np.float32) output_hdf.create_dataset('q_resolution', data=q_resolution, dtype=np.float32) output_hdf.create_dataset('phi_resolution', data=phi_resolution, dtype=np.float32) output_hdf.create_dataset('num_phi', data=nphi, dtype=np.float32) output_hdf.create_dataset('ring_phis', data=phi_values, dtype=np.float32) # save print("saving data to file %s!" % (prefix + '.hdf5')) # output_hdf.close() return prefix + '.hdf5'
# sum all the images in this run if image_sum is None: image_sum = img else: image_sum += img # interpolation begins here if shot_counter == 0: # create SimpleInterp object if it's the first shot img_shape = img.shape interpolator = InterpSimple.InterpSimple(ring_center[0], ring_center[1], qRmax, qRmin, num_phi, img_shape, bin_fac=bin_fac, use_zoom=False) # threshold mask threshold_mask = img < bright_threshold # apply threshold to img directly img *= threshold_mask polar_interp = interpolator.nearest_naive_bin(img) d = {'cspad': {'polar_intensity': polar_interp}} # save per-event data smldata.event(d) shot_counter += 1
if img is None: continue # sum all the images in this run if image_sum is None: image_sum = img else: image_sum += img # interpolation begins here if shot_counter == 0: # create SimpleInterp object if it's the first shot img_shape = img.shape interpolator = InterpSimple (ring_center[0], ring_center[1], qRmax, qRmin, num_phi, img_shape, bin_fac = bin_fac, use_zoom = False) # threshold mask threshold_mask = img<bright_threshold # apply threshold to img directly img *= threshold_mask polar_interp = interpolator.nearest_naive_bin( img ) d = {'cspad':{'polar_intensity': polar_interp}} # save per-event data smldata.event(d) shot_counter += 1 total_shots +=1
# min ring radii # desired dimension of image, these will be approximate rbins =35 phibins = 360 interp_rmin = 100 interp_rmax = 450 rbin_fct = np.floor( (interp_rmax - interp_rmin) / rbins) # adjust so our edge is a multiple of rbin factor interp_rmax = int( interp_rmin + np.ceil( (interp_rmax - interp_rmin) / rbin_fct)*rbin_fct ) nphi = int( 2 * np.pi * interp_rmax ) phibin_fct = np.ceil( nphi / float( phibins ) ) nphi = int( np.ceil( 2 * np.pi * interp_rmax/phibin_fct)*phibin_fct) # number of azimuthal samples per bin rbin_new = (interp_rmax- interp_rmin ) / rbin_fct phibin_new = nphi / phibin_fct binned_pol_img_sh = ( int(rbin_new), int(phibin_new) ) print("polar image dimensions: %d x %d"%(rbin_new, phibin_new)) Interp = InterpSimple( cent[0], cent[1] , interp_rmax, interp_rmin, nphi, img_sh) pmask = Interp.nearest(mask).astype(int).astype(float) pmask_bn = bin_ndarray( pmask, binned_pol_img_sh) pmask_bn = pmask_bn.astype(int) pmask_bn = np.array(pmask_bn==pmask_bn.max(), dtype = int) #np.save('/reg/d/psdm/cxi/cxilp6715/scratch/water_data/binned_pmask_basic.npy', pmask_bn) np.save('/reg/d/psdm/cxi/cxilp6715/results/shared_files/binned_pmask_basic3.npy', pmask_bn)