# load q values # ################# file_path = filedialog.askopenfilename(initialdir=datadir, title="Select q values", filetypes=[("NPZ", "*.npz")]) npzfile = np.load(file_path) qx = npzfile["qx"] # downstream qz = npzfile["qz"] # vertical up qy = npzfile["qy"] # outboard ################################### # bin data and q values if needed # ################################### if any(bin_factor != 1 for bin_factor in binning): diff_pattern = util.bin_data(array=diff_pattern, binning=binning, debugging=False) mask = util.bin_data(array=mask, binning=binning, debugging=False) mask[np.nonzero(mask)] = 1 qx = qx[::binning[0]] qy = qy[::binning[1]] qz = qz[::binning[2]] ############################ # plot diffraction pattern # ############################ nz, ny, nx = diff_pattern.shape print( "Data shape after binning=", nz, ny,
def reload_cdi_data( data, mask, scan_number, setup, normalize_method="skip", debugging=False, **kwargs, ): """ Reload forward CDI data, apply optional threshold, normalization and binning. :param data: the 3D data array :param mask: the 3D mask array :param scan_number: the scan number to load :param setup: an instance of the class Setup :param normalize_method: 'skip' to skip, 'monitor' to normalize by the default monitor, 'sum_roi' to normalize by the integrated intensity in a defined region of interest :param debugging: set to True to see plots :parama kwargs: - 'photon_threshold' = float, photon threshold to apply before binning :return: - the updated 3D data and mask arrays - the monitor values used for the intensity normalization """ valid.valid_ndarray(arrays=(data, mask), ndim=3) # check and load kwargs valid.valid_kwargs( kwargs=kwargs, allowed_kwargs={"photon_threshold"}, name="kwargs", ) photon_threshold = kwargs.get("photon_threshold", 0) valid.valid_item( photon_threshold, allowed_types=Real, min_included=0, name="photon_threshold", ) nbz, nby, nbx = data.shape frames_logical = np.ones(nbz) print((data < 0).sum(), " negative data points masked" ) # can happen when subtracting a background mask[data < 0] = 1 data[data < 0] = 0 # normalize by the incident X-ray beam intensity if normalize_method == "skip": print("Skip intensity normalization") monitor = [] else: if normalize_method == "sum_roi": monitor = data[:, setup.detector.sum_roi[0]:setup.detector.sum_roi[1], setup.detector.sum_roi[2]:setup.detector. sum_roi[3], ].sum(axis=(1, 2)) else: # use the default monitor of the beamline monitor = setup.loader.read_monitor( scan_number=scan_number, setup=setup, ) print("Intensity normalization using " + normalize_method) data, monitor = loader.normalize_dataset( array=data, monitor=monitor, norm_to_min=True, savedir=setup.detector.savedir, debugging=True, ) # pad the data to the shape defined by the ROI if (setup.detector.roi[1] - setup.detector.roi[0] > nby or setup.detector.roi[3] - setup.detector.roi[2] > nbx): start = ( 0, max(0, abs(setup.detector.roi[0])), max(0, abs(setup.detector.roi[2])), ) print("Paddind the data to the shape defined by the ROI") data = util.crop_pad( array=data, pad_start=start, output_shape=( data.shape[0], setup.detector.roi[1] - setup.detector.roi[0], setup.detector.roi[3] - setup.detector.roi[2], ), ) mask = util.crop_pad( array=mask, pad_value=1, pad_start=start, output_shape=( mask.shape[0], setup.detector.roi[1] - setup.detector.roi[0], setup.detector.roi[3] - setup.detector.roi[2], ), ) # apply optional photon threshold before binning if photon_threshold != 0: mask[data < photon_threshold] = 1 data[data < photon_threshold] = 0 print("Applying photon threshold before binning: < ", photon_threshold) # bin data and mask in the detector plane if needed # binning in the stacking dimension is done at the very end of the data processing if (setup.detector.binning[1] != 1) or (setup.detector.binning[2] != 1): print( "Binning the data: detector vertical axis by", setup.detector.binning[1], ", detector horizontal axis by", setup.detector.binning[2], ) data = util.bin_data( data, (1, setup.detector.binning[1], setup.detector.binning[2]), debugging=debugging, ) mask = util.bin_data( mask, (1, setup.detector.binning[1], setup.detector.binning[2]), debugging=debugging, ) mask[np.nonzero(mask)] = 1 return data, mask, frames_logical, monitor
############################## # load reciprocal space data # ############################## plt.ion() root = tk.Tk() root.withdraw() file_path = filedialog.askopenfilename( initialdir=root_folder, title="Select the diffraction pattern", filetypes=[("NPZ", "*.npz")], ) npzfile = np.load(file_path) diff_pattern = util.bin_data( npzfile[list(npzfile.files)[0]], (bin_factor, bin_factor, bin_factor), debugging=False, ) diff_pattern[diff_pattern < threshold] = 0 nz, ny, nx = diff_pattern.shape print("Data shape after binning:", nz, ny, nx) print("Data type:", diff_pattern.dtype) gu.multislices_plot( diff_pattern, sum_frames=True, plot_colorbar=True, cmap=my_cmap, title="diffraction pattern", scale="log", vmin=np.nan,
def load_cdi_data( scan_number, setup, bin_during_loading=False, flatfield=None, hotpixels=None, background=None, normalize="skip", debugging=False, **kwargs, ): """ Load forward CDI data and preprocess it. It applies beam stop correction and an optional photon threshold, normalization and binning. :param scan_number: the scan number to load :param setup: an instance of the class Setup :param bin_during_loading: True to bin the data during loading (faster) :param flatfield: the 2D flatfield array :param hotpixels: the 2D hotpixels array. 1 for a hotpixel, 0 for normal pixels. :param background: the 2D background array to subtract to the data :param normalize: 'skip' to skip, 'monitor' to normalize by the default monitor, 'sum_roi' to normalize by the integrated intensity in the region of interest defined by detector.sum_roi :param debugging: set to True to see plots :param kwargs: - 'photon_threshold': float, photon threshold to apply before binning - 'frames_pattern': 1D array of int, of length data.shape[0]. If frames_pattern is 0 at index, the frame at data[index] will be skipped, if 1 the frame will added to the stack. :return: - the 3D data and mask arrays - frames_logical: array of initial length the number of measured frames. In case of padding the length changes. A frame whose index is set to 1 means that it is used, 0 means not used, -1 means padded (added) frame. - the monitor values used for the intensity normalization """ valid.valid_item(bin_during_loading, allowed_types=bool, name="bin_during_loading") # check and load kwargs valid.valid_kwargs( kwargs=kwargs, allowed_kwargs={"photon_threshold", "frames_pattern"}, name="kwargs", ) photon_threshold = kwargs.get("photon_threshold", 0) valid.valid_item( photon_threshold, allowed_types=Real, min_included=0, name="photon_threshold", ) frames_pattern = kwargs.get("frames_pattern") valid.valid_1d_array(frames_pattern, allow_none=True, allowed_values={0, 1}, name="frames_pattern") rawdata, rawmask, monitor, frames_logical = setup.loader.load_check_dataset( scan_number=scan_number, setup=setup, frames_pattern=frames_pattern, bin_during_loading=bin_during_loading, flatfield=flatfield, hotpixels=hotpixels, background=background, normalize=normalize, debugging=debugging, ) ################################# # apply the beamstop correction # ################################# rawdata = beamstop_correction(data=rawdata, setup=setup, debugging=debugging) ##################################################### # apply an optional photon threshold before binning # ##################################################### if photon_threshold != 0: rawmask[rawdata < photon_threshold] = 1 rawdata[rawdata < photon_threshold] = 0 print("Applying photon threshold before binning: < ", photon_threshold) #################################################################################### # bin data and mask in the detector plane if not already done during loading # # binning in the stacking dimension is done at the very end of the data processing # #################################################################################### if not bin_during_loading and ((setup.detector.binning[1] != 1) or (setup.detector.binning[2] != 1)): print( "Binning the data: detector vertical axis by", setup.detector.binning[1], ", detector horizontal axis by", setup.detector.binning[2], ) rawdata = util.bin_data( rawdata, (1, setup.detector.binning[1], setup.detector.binning[2]), debugging=False, ) rawmask = util.bin_data( rawmask, (1, setup.detector.binning[1], setup.detector.binning[2]), debugging=False, ) rawmask[np.nonzero(rawmask)] = 1 ################################################ # pad the data to the shape defined by the ROI # ################################################ rawdata, rawmask = util.pad_from_roi( arrays=(rawdata, rawmask), roi=setup.detector.roi, binning=setup.detector.binning[1:], pad_value=(0, 1), ) return rawdata, rawmask, frames_logical, monitor
"skip" # we assume that normalization was already performed ) monitor = [] # we assume that normalization was already performed min_range = (nx / 2) * np.sqrt( 2 ) # used when fit_datarange is True, keep the full array because # we do not know the position of the origin of reciprocal space frames_logical = np.ones(nz) # bin data and mask if needed if ((detector.binning[0] != 1) or (detector.binning[1] != 1) or (detector.binning[2] != 1)): print("Binning the reloaded orthogonal data by", detector.binning) data = util.bin_data(data, binning=detector.binning, debugging=False) mask = util.bin_data(mask, binning=detector.binning, debugging=False) mask[np.nonzero(mask)] = 1 if len(q_values) != 0: qx = q_values[0] qz = q_values[1] qy = q_values[2] numz, numy, numx = len(qx), len(qz), len(qy) qx = qx[:numz - (numz % detector.binning[2]):detector.binning[2]] # along z downstream, same binning as along x qz = qz[:numy - (numy % detector.binning[1]):detector.binning[1]]
if not np.all(np.asarray(crop_center) - np.asarray(roi_size) // 2 >= 0): raise ValueError("crop_center incompatible with roi_size") if not ( crop_center[0] + roi_size[0] // 2 <= nbz and crop_center[1] + roi_size[1] // 2 <= nby and crop_center[2] + roi_size[2] // 2 <= nbx ): raise ValueError("crop_center incompatible with roi_size") ####################################################### # crop the data, and optionally the mask and q values # ####################################################### data = util.crop_pad( data, output_shape=roi_size, crop_center=crop_center, debugging=debug ) data = util.bin_data(data, binning=binning, debugging=debug) comment = ( f"{data.shape[0]}_{data.shape[1]}_{data.shape[2]}_" f"{binning[0]}_{binning[1]}_{binning[2]}" + comment ) np.savez_compressed(datadir + "S" + str(scan) + "_pynx" + comment + ".npz", data=data) fig, _, _ = gu.multislices_plot( data, sum_frames=True, scale="log", plot_colorbar=True, vmin=0, title="Cropped data", is_orthogonal=is_orthogonal, reciprocal_space=reciprocal_space,
hxrd=hxrd, debugging=debug, ) nz, ny, nx = data.shape # CXI convention: z downstream, y vertical up, x outboard print("Diffraction data shape", data.shape) qx = q_values[0] # axis=0, z downstream, qx in reciprocal space qz = q_values[1] # axis=1, y vertical, qz in reciprocal space qy = q_values[2] # axis=2, x outboard, qy in reciprocal space ############ # bin data # ############ qx = qx[:nz - (nz % binning[0]):binning[0]] qz = qz[:ny - (ny % binning[1]):binning[1]] qy = qy[:nx - (nx % binning[2]):binning[2]] data = util.bin_data(data, (binning[0], binning[1], binning[2]), debugging=False) nz, ny, nx = data.shape print("Diffraction data shape after binning", data.shape) # apply photon threshold data[data < photon_threshold] = 0 else: # load a reconstructed real space object comment = comment + "_CDI" file_path = filedialog.askopenfilename(initialdir=homedir, title="Select 3D data", filetypes=[("NPZ", "*.npz")]) amp = np.load(file_path)["amp"] amp = amp / abs(amp).max() # normalize amp nz, ny, nx = amp.shape # CXI convention: z downstream, y vertical up, x outboard print("CDI data shape", amp.shape) # nz1, ny1, nx1 = [value * pad_size for value in amp.shape]
sys.exit() ############################################### # bin the diffraction pattern and the mask to # # compensate the "rebin" option used in PyNX # ############################################### # update also the detector pixel sizes to take into account the binning setup.detector.binning = phasing_binning print( "Pixel sizes after phasing_binning (vertical, horizontal): ", setup.detector.pixelsize_y, setup.detector.pixelsize_x, "(m)", ) slice_2D = util.bin_data(array=slice_2D, binning=(phasing_binning[1], phasing_binning[2]), debugging=False) mask_2D = util.bin_data(array=mask_2D, binning=(phasing_binning[1], phasing_binning[2]), debugging=False) slice_2D[np.nonzero(mask_2D)] = 0 plt.figure() plt.imshow(np.log10(np.sqrt(slice_2D)), cmap=my_cmap, vmin=0, vmax=3.5) plt.title("2D diffraction amplitude") plt.colorbar() plt.pause(0.1) ########################################################## # load the 3D dataset in order to calculate the q values #