def get_h5(self,dfile,time) : """Retrives 2D image from event. @run run number @time time-stamp """ if dfile == 0 : filename = self.dataset_name + '.h5' else : filename = self.dataset_name + '__' + str(dfile).zfill(4) + '.h5' f = h5py.File(filename,'r') # Ascert that time-stamp exist in file if time in f.keys(): self.image = f[time][self.detector_address]['HistData'].value else: self.image = None self.img = None return # Apply common mode correction if self.comm == 1: self.image = pnccd_tbx.common_mode(img = self.image, edge = self.param1, side = self.param2, plot = self.param4) elif self.comm == 2: self.image = pnccd_tbx.common_mode_hart(img = self.image, msk = self.mask, max_int = self.param1, max_com = self.param2, length = self.param3, orient = self.orient, plot = self.param4) # Apply geometry self.img = pnccd_tbx.get_geometry(img = self.image, gap = self.gap, shift = self.shift, orient = self.orient) # Check if nQ > smallest dimension/2 then we extend the image with zero values if self.nQ > min(self.img.shape[0]/2,self.img.shape[1]/2) : self.img = pnccd_tbx.extend_image(img = self.img) # Check if carttesian coord background image exists if self.cart : self.img = self.img - self.backimg
def get_image(self,evt) : """Retrives 2D image from event. @run run number from Psana @time time-stamp from Psana """ self.run_nr = int(evt.run()) self.evt = evt self.img = self.src.image(self.evt) # Check if nQ > smallest dimension/2 then we extend the image with zero values if self.nQ > min(self.img.shape[0]/2,self.img.shape[1]/2) : self.img = pnccd_tbx.extend_image(img = self.img) # Check if carttesian coord background image exists if self.cart : self.img = self.img - self.backimg # CM correction, Make sure that no other CM is already implemented self.img = pnccd_tbx.common_mode(self.img, 150 , 100 , plot = 0) self.img = self.img*self.msk
def get_image(self, evt): """Retrives 2D image from event. @run run number from Psana @time time-stamp from Psana """ self.run_nr = int(evt.run()) self.evt = evt self.img = self.src.image(self.evt) # Check if nQ > smallest dimension/2 then we extend the image with zero values if self.nQ > min(self.img.shape[0] / 2, self.img.shape[1] / 2): self.img = pnccd_tbx.extend_image(img=self.img) # Check if carttesian coord background image exists if self.cart: self.img = self.img - self.backimg # CM correction, Make sure that no other CM is already implemented self.img = pnccd_tbx.common_mode(self.img, 150, 100, plot=0) self.img = self.img * self.msk
def __init__(self, dataset_name = None, detector_address = None, data_type = 'idx', mask_path = None, mask_angles = None, mask_widths = None, backimg_path = None, backmsk_path = None, geom_path = None, det_dist = None, det_pix = 0.075, beam_l = None, mask_thr = None, nQ = None, nPhi = None, dQ = 1, dPhi = 1, cent0 = None, r_max = None, dr = None, dx = None, dy = None, r_0 = None, q_bound = None, peak = None, dpeak = None): """The fluctuation scattering class stores processing parameters, initiates mask and background data and retrieves 2D images from events. Processing options of the 2D images include: * Transform from cartesian to polar coordinates * Beam center refinement * Dynamic masking * Normalization % SAXS calculation * Particle sizing * Computation of in-frame 2-point angular auto-correlations using FFTs @param dataset_name Experiment name and run number @param detector_address Adress to back or front detector @param data_type Type of data file format (h5 or xtc in the formats: idx|idx_ffb|smd|smd_ffb|h5) @param mask_path Full path to static image mask @param mask_angles Center of angluar slices (deg) that should be masked out (due to jet streaks etc), [Ang1 Ang2 ...] @param mask_widths Width of angular slices (deg) that should be masked out (due to jet streaks etc), [delta1 delta2 ...] @param backimg_path Full path to background image @param backmsk_path Full path to background mask @param geom_path Full path to geometry file (for h5 format) @param det_dist Override of detecor distance (in mm) @param det_pix Pixel size (in mm) @param beam_l Override of beam wavelength (in Angstrom) @param mask_thr Threshold for dynamic masking @param nQ Number of Q-bins to consider (in pixels) @param nPhi Number of Phi-bins to consider (in pixels) @param dQ Stepsize in Q (in pixels) @param dPhi Stepsize in Phi (in pixels) @param cent0 Initial beam center coordinates [xc,yc] @param r_max Maximum radial value to use for beamcenter refinement (in pixels) @param dr Stepsize in r (in pixels) @param dx Gridsize for beam center refinement in x, i.e xc+/-dx (in pixels) @param dy Gridsize for beam center refinement in y, i.e yc+/-dy (in pixles) @param r_0 Starting value for particle radius refinement [in Ang] @param q_bound Upper and Lower boundaries of q for Particle radius refinement [in Ang^-1] @param peak Q-values for peak maxima [q_peak1 q_peak2 ...] @param dpeak Delta Q used for peak integration of peak maxima [delta_q1 delta_q2 ...] """ # Initialize parameters and configuration files once self.data_type = data_type self.dataset_name = dataset_name self.detector_address = detector_address if (self.data_type == 'idx') or (self.data_type == 'idx_ffb') or (self.data_type == 'smd') or (self.data_type == 'smd_ffb') or (self.data_type == 'xtc') : self.ds = DataSource(self.dataset_name) self.src = Detector(self.detector_address, self.ds.env()) if mask_path is None : # Create a binary mask of ones, default mask only works for xtc/ffb evt = self.ds.events().next() self.mask_address = self.src.mask(evt,calib=True,status=True) self.msk = self.src.image(evt,self.mask_address) self.mask = np.copy(self.msk) else: self.msk = np.loadtxt(mask_path) self.mask = np.copy(self.msk) if geom_path is not None : geom = np.genfromtxt(geom_path,skiprows=1) self.gap = geom[0] self.shift = geom[1] self.orient = geom[2 ] self.comm = geom[3] self.param1 = geom[4] self.param2 = geom[5] self.param3 = geom[6] self.param4 = geom[7] if (self.data_type == 'h5'): if mask_path is None : # Create a binary mask of ones ## Add default binary mask here ## Default pnCCD dimensions dim1 = 1024 dim2 = 1024 self.mask = np.ones((dim1,dim2)) else: self.mask = np.loadtxt(mask_path) # Apply geometry self.msk = pnccd_tbx.get_geometry(img = self.mask, gap = self.gap, shift = self.shift, orient = self.orient) if self.detector_address == 'pnccdFront' : evt = self.ds.events().next() gain = self.src.gain(evt) self.gain = self.src.image(evt,gain) self.cart = 0 self.flat = 0 if backimg_path is None : self.backimg = None else : self.backimg = np.loadtxt(backimg_path).astype(np.float64) # Check if background image in cartesian coordinates exists if (self.backimg.shape == self.msk.shape): self.cart = 1 # Remove bg before transform to polar coordinates if backmsk_path is None : self.backmsk = None else : self.backmsk = np.loadtxt(backmsk_path).astype(np.float64) # Check if flat-field image exists if (self.backmsk is None) and (self.backimg is not None) and (self.cart==0): self.pcflat = pnccd_tbx.dynamic_flatfield(self.backimg) self.flat = 1 if det_dist is None : # Get detector distance from events for run in self.ds.runs(): self.det_dist = cspad_tbx.env_distance(self.detector_address, run.env(), 577) else : self.det_dist = det_dist self.det_pix = det_pix if beam_l is None : # Get wavelength from event, note it can change slightly between events. So in the future use average. self.beam_l = cspad_tbx.evt_wavelength(self.ds.events().next()) else : self.beam_l = beam_l if mask_thr is None : # No dynamic masking self.thr = None else : self.thr = mask_thr if nQ is None : # Use image dimensions as a guide, leave room for offset beamC if self.msk.shape[0] > self.msk.shape[1] : # nQ determined by smallest dimension self.nQ = int(self.msk.shape[1]/2)-20 else : self.nQ = int(self.msk.shape[0]/2)-20 else : self.nQ = nQ if (self.nQ % 10): # Ascert even number, speeds things up massively for FFT self.nQ = np.floor(self.nQ/10)*10 if (self.nQ % dQ): # Ascert clean divisor self.nQ = np.floor(self.nQ/dQ)*dQ if nPhi is None : # Estimate based on 2*pi*nQ self.nPhi = np.ceil(2*np.pi*self.nQ) else : self.nPhi = nPhi if (self.nPhi % 10): # Ascert even number, speeds things up massively for FFT self.nPhi = np.ceil(self.nPhi/10)*10 if (self.nPhi % dPhi): # Ascert clean divisor self.nPhi = np.ceil(self.nPhi/dPhi)*dPhi self.dQ = dQ self.dPhi = dPhi self.mask_angles = mask_angles self.mask_widths = mask_widths # Compute slices that should be masked in static mask if (self.mask_angles is not None) and (self.mask_widths is not None) : self.mask_angles = (self.mask_angles/360) * self.nPhi self.mask_widths = (self.mask_widths/360) * self.nPhi # Check if nQ > smallest dimension/2 then we extend the image with zero values if self.nQ > min(self.msk.shape[0]/2,self.msk.shape[1]/2) : self.msk = pnccd_tbx.extend_image(img = self.msk) self.mask = np.copy(self.msk) if (cent0 is None) or (sum(cent0) == 0): # Use center of gravity to estimate starting beamC self.cent0 = [int(round(self.msk.shape[1]/2)) , int(round(self.msk.shape[0]/2))] else : self.cent0 = cent0 self.cent = self.cent0 # Default center if r_max is None : # Default, Use half of nQ self.r_max = int(self.nQ*(3/4)) else : self.r_max = r_max if (self.r_max % dr): # Ascert clean divisor self.r_max = np.floor(self.r_max/dr)*dr self.dr = dr self.dx = dx self.dy = dy if r_0 is None : self.radius = 0 self.score = 0 self.r_0 = r_0 if q_bound is None or sum(q_bound)==0 : self.q_bound = [None,None] else : self.q_bound = [None,self.q_bound] # Compute q-spacing self.q = np.arange(0, self.nQ, self.dQ) self.q = self.q*self.det_pix/self.det_dist*4*np.pi/self.beam_l/2 # Compute Phi (Not accounting for curvature) self.phi = np.linspace(0, 2*np.pi, self.nPhi/self.dPhi,endpoint=False) # Compute indices for Peak maxima if (peak is not None) and (dpeak is not None) : self.peak = peak self.dpeak = dpeak self.ind1 = (self.q >= (self.peak[0] - self.dpeak[0])) & (self.q <= (self.peak[0] + self.dpeak[0]) ) self.ind2 = (self.q >= (self.peak[1] - self.dpeak[1])) & (self.q <= (self.peak[1] + self.dpeak[1]) ) else: self.peak = None self.dpeak = None
def __init__(self, dataset_name=None, detector_address=None, data_type='idx', mask_path=None, mask_angles=None, mask_widths=None, backimg_path=None, backmsk_path=None, geom_path=None, det_dist=None, det_pix=0.075, beam_l=None, mask_thr=None, nQ=None, nPhi=None, dQ=1, dPhi=1, cent0=None, r_max=None, dr=None, dx=None, dy=None, r_0=None, q_bound=None, peak=None, dpeak=None): """The fluctuation scattering class stores processing parameters, initiates mask and background data and retrieves 2D images from events. Processing options of the 2D images include: * Transform from cartesian to polar coordinates * Beam center refinement * Dynamic masking * Normalization % SAXS calculation * Particle sizing * Computation of in-frame 2-point angular auto-correlations using FFTs @param dataset_name Experiment name and run number @param detector_address Adress to back or front detector @param data_type Type of data file format (h5 or xtc in the formats: idx|idx_ffb|smd|smd_ffb|h5) @param mask_path Full path to static image mask @param mask_angles Center of angluar slices (deg) that should be masked out (due to jet streaks etc), [Ang1 Ang2 ...] @param mask_widths Width of angular slices (deg) that should be masked out (due to jet streaks etc), [delta1 delta2 ...] @param backimg_path Full path to background image @param backmsk_path Full path to background mask @param geom_path Full path to geometry file (for h5 format) @param det_dist Override of detecor distance (in mm) @param det_pix Pixel size (in mm) @param beam_l Override of beam wavelength (in Angstrom) @param mask_thr Threshold for dynamic masking @param nQ Number of Q-bins to consider (in pixels) @param nPhi Number of Phi-bins to consider (in pixels) @param dQ Stepsize in Q (in pixels) @param dPhi Stepsize in Phi (in pixels) @param cent0 Initial beam center coordinates [xc,yc] @param r_max Maximum radial value to use for beamcenter refinement (in pixels) @param dr Stepsize in r (in pixels) @param dx Gridsize for beam center refinement in x, i.e xc+/-dx (in pixels) @param dy Gridsize for beam center refinement in y, i.e yc+/-dy (in pixles) @param r_0 Starting value for particle radius refinement [in Ang] @param q_bound Upper and Lower boundaries of q for Particle radius refinement [in Ang^-1] @param peak Q-values for peak maxima [q_peak1 q_peak2 ...] @param dpeak Delta Q used for peak integration of peak maxima [delta_q1 delta_q2 ...] """ # Initialize parameters and configuration files once self.data_type = data_type self.dataset_name = dataset_name self.detector_address = detector_address if (self.data_type == 'idx') or (self.data_type == 'idx_ffb') or ( self.data_type == 'smd') or (self.data_type == 'smd_ffb') or (self.data_type == 'xtc'): self.ds = DataSource(self.dataset_name) self.src = Detector(self.detector_address, self.ds.env()) if mask_path is None: # Create a binary mask of ones, default mask only works for xtc/ffb evt = next(self.ds.events()) self.mask_address = self.src.mask(evt, calib=True, status=True) self.msk = self.src.image(evt, self.mask_address) self.mask = np.copy(self.msk) else: self.msk = np.loadtxt(mask_path) self.mask = np.copy(self.msk) if geom_path is not None: geom = np.genfromtxt(geom_path, skiprows=1) self.gap = geom[0] self.shift = geom[1] self.orient = geom[2] self.comm = geom[3] self.param1 = geom[4] self.param2 = geom[5] self.param3 = geom[6] self.param4 = geom[7] if (self.data_type == 'h5'): if mask_path is None: # Create a binary mask of ones ## Add default binary mask here ## Default pnCCD dimensions dim1 = 1024 dim2 = 1024 self.mask = np.ones((dim1, dim2)) else: self.mask = np.loadtxt(mask_path) # Apply geometry self.msk = pnccd_tbx.get_geometry(img=self.mask, gap=self.gap, shift=self.shift, orient=self.orient) if self.detector_address == 'pnccdFront': evt = next(self.ds.events()) gain = self.src.gain(evt) self.gain = self.src.image(evt, gain) self.cart = 0 self.flat = 0 if backimg_path is None: self.backimg = None else: self.backimg = np.loadtxt(backimg_path).astype(np.float64) # Check if background image in cartesian coordinates exists if (self.backimg.shape == self.msk.shape): self.cart = 1 # Remove bg before transform to polar coordinates if backmsk_path is None: self.backmsk = None else: self.backmsk = np.loadtxt(backmsk_path).astype(np.float64) # Check if flat-field image exists if (self.backmsk is None) and (self.backimg is not None) and (self.cart == 0): self.pcflat = pnccd_tbx.dynamic_flatfield(self.backimg) self.flat = 1 if det_dist is None: # Get detector distance from events for run in self.ds.runs(): self.det_dist = cspad_tbx.env_distance(self.detector_address, run.env(), 577) else: self.det_dist = det_dist self.det_pix = det_pix if beam_l is None: # Get wavelength from event, note it can change slightly between events. So in the future use average. self.beam_l = cspad_tbx.evt_wavelength(next(self.ds.events())) else: self.beam_l = beam_l if mask_thr is None: # No dynamic masking self.thr = None else: self.thr = mask_thr if nQ is None: # Use image dimensions as a guide, leave room for offset beamC if self.msk.shape[0] > self.msk.shape[ 1]: # nQ determined by smallest dimension self.nQ = int(self.msk.shape[1] / 2) - 20 else: self.nQ = int(self.msk.shape[0] / 2) - 20 else: self.nQ = nQ if (self.nQ % 10): # Ascert even number, speeds things up massively for FFT self.nQ = np.floor(self.nQ / 10) * 10 if (self.nQ % dQ): # Ascert clean divisor self.nQ = np.floor(self.nQ / dQ) * dQ if nPhi is None: # Estimate based on 2*pi*nQ self.nPhi = np.ceil(2 * np.pi * self.nQ) else: self.nPhi = nPhi if (self.nPhi % 10): # Ascert even number, speeds things up massively for FFT self.nPhi = np.ceil(self.nPhi / 10) * 10 if (self.nPhi % dPhi): # Ascert clean divisor self.nPhi = np.ceil(self.nPhi / dPhi) * dPhi self.dQ = dQ self.dPhi = dPhi self.mask_angles = mask_angles self.mask_widths = mask_widths # Compute slices that should be masked in static mask if (self.mask_angles is not None) and (self.mask_widths is not None): self.mask_angles = (self.mask_angles / 360) * self.nPhi self.mask_widths = (self.mask_widths / 360) * self.nPhi # Check if nQ > smallest dimension/2 then we extend the image with zero values if self.nQ > min(self.msk.shape[0] / 2, self.msk.shape[1] / 2): self.msk = pnccd_tbx.extend_image(img=self.msk) self.mask = np.copy(self.msk) if (cent0 is None) or ( sum(cent0) == 0): # Use center of gravity to estimate starting beamC self.cent0 = [ int(round(self.msk.shape[1] / 2)), int(round(self.msk.shape[0] / 2)) ] else: self.cent0 = cent0 self.cent = self.cent0 # Default center if r_max is None: # Default, Use half of nQ self.r_max = int(self.nQ * (3 / 4)) else: self.r_max = r_max if (self.r_max % dr): # Ascert clean divisor self.r_max = np.floor(self.r_max / dr) * dr self.dr = dr self.dx = dx self.dy = dy if r_0 is None: self.radius = 0 self.score = 0 self.r_0 = r_0 if q_bound is None or sum(q_bound) == 0: self.q_bound = [None, None] else: self.q_bound = [None, self.q_bound] # Compute q-spacing self.q = np.arange(0, self.nQ, self.dQ) self.q = self.q * self.det_pix / self.det_dist * 4 * np.pi / self.beam_l / 2 # Compute Phi (Not accounting for curvature) self.phi = np.linspace(0, 2 * np.pi, self.nPhi / self.dPhi, endpoint=False) # Compute indices for Peak maxima if (peak is not None) and (dpeak is not None): self.peak = peak self.dpeak = dpeak self.ind1 = (self.q >= (self.peak[0] - self.dpeak[0])) & ( self.q <= (self.peak[0] + self.dpeak[0])) self.ind2 = (self.q >= (self.peak[1] - self.dpeak[1])) & ( self.q <= (self.peak[1] + self.dpeak[1])) else: self.peak = None self.dpeak = None