def __init__(self, experiment, diffraction_rings=None, log_scale=False): self.experiment = experiment self.center = self.experiment.det.geometry.point_coord_indexes((0, 0)) # ! Wavenumber definition != beam's. self.wavenumber = np.linalg.norm(self.experiment.beam.get_wavevector()) self.distance = self.experiment.det.distance pixel_width = asnumpy(self.experiment.det.pixel_width) # Cupy doesn't have median yet. self.pix_width = np.median(pixel_width) recidet = ReciprocalDetector(self.experiment.det, self.experiment.beam) self.q_max = asnumpy( np.min(( # Max inscribed radius xp.max(recidet.pixel_position_reciprocal[..., 1]), -xp.min(recidet.pixel_position_reciprocal[..., 1]), xp.max(recidet.pixel_position_reciprocal[..., 0]), -xp.min(recidet.pixel_position_reciprocal[..., 0])))) self._auto_rings = False if diffraction_rings is not None: if diffraction_rings.lower() == "auto": self._auto_rings = True else: raise ValueError( "Unrecognized value '{}' for argument diffraction_rings" "".format(diffraction_rings)) if log_scale: self._norm = LogNorm() else: self._norm = None
def get_reciprocal_mesh(self, voxel_number_1d): """ Get the proper reciprocal mesh. :param voxel_number_1d: The voxel number along 1 dimension. :return: The reciprocal mesh, voxel length. """ dist_max = xp.max(self.pixel_distance_reciprocal) return pg.get_reciprocal_mesh(voxel_number_1d, dist_max)
def preferred_reciprocal_mesh_number(self, wave_vector): """ If one want to put the diffraction pattern into 3D reciprocal space, then one needs to select a proper voxel number for a proper voxel length for the reciprocal space. This function gives a reasonable estimation of this length and voxel number :param wave_vector: The wavevector of in this experiment. :return: The reciprocal mesh number along 1 dimension """ """ Return the prefered the reciprocal voxel grid number along 1 dimension. """ voxel_length = self.preferred_voxel_length(wave_vector) reciprocal_space_range = xp.max(self.pixel_distance_reciprocal) # The voxel number along 1 dimension is 2*voxel_half_num_1d+1 voxel_half_num_1d = int( xp.floor_divide(reciprocal_space_range, voxel_length) + 1) voxel_num_1d = int(2 * voxel_half_num_1d + 1) return voxel_num_1d
def initialize(self, geom, beam): """ Initialize the detector with user defined parameters :param geom: The dictionary containing all the necessary information to initialized the detector. :param beam: The beam object :return: None """ """ Doc: To use this class, the user has to provide the necessary information to initialize the detector. All the necessary entries are listed in the example notebook. """ # 'detector distance': detector distance in (m) ########################################################################################## # Extract necessary information ########################################################################################## # Define the hierarchy system. For simplicity, we only use two-layer structure. for key in {'panel number', 'panel pixel num x', 'panel pixel num y'}: if key not in geom: raise KeyError("Missing required '{}' key.".format(key)) self.panel_num = int(geom['panel number']) self.panel_pixel_num_x = int(geom['panel pixel num x']) self.panel_pixel_num_y = int(geom['panel pixel num y']) self._shape = (self.panel_num, self.panel_pixel_num_x, self.panel_pixel_num_y) # Define all properties the detector should have self._distance = None if 'pixel center z' in geom: if 'detector distance' in geom: raise ValueError("Please provide one of " "'pixel center z' or 'detector distance'.") self.center_z = xp.asarray(geom['pixel center z'], dtype=xp.float64) self._distance = float(self.center_z.mean()) else: if 'detector distance' not in geom: KeyError("Missing required 'detector distance' key.") self._distance = float(geom['detector distance']) self.center_z = self._distance * xp.ones(self._shape, dtype=xp.float64) # Below: [panel number, pixel num x, pixel num y] in (m) # Change dtype and make numpy/cupy array self.pixel_width = xp.asarray(geom['pixel width'], dtype=xp.float64) self.pixel_height = xp.asarray(geom['pixel height'], dtype=xp.float64) self.center_x = xp.asarray(geom['pixel center x'], dtype=xp.float64) self.center_y = xp.asarray(geom['pixel center y'], dtype=xp.float64) self.orientation = np.array([0, 0, 1]) # construct the the pixel position array self.pixel_position = xp.zeros(self._shape + (3, )) self.pixel_position[..., 0] = self.center_x self.pixel_position[..., 1] = self.center_y self.pixel_position[..., 2] = self.center_z # Pixel map if 'pixel map' in geom: # [panel number, pixel num x, pixel num y] self.pixel_index_map = xp.asarray(geom['pixel map'], dtype=xp.int64) # Detector pixel number info self.detector_pixel_num_x = asnumpy( xp.max(self.pixel_index_map[..., 0]) + 1) self.detector_pixel_num_y = asnumpy( xp.max(self.pixel_index_map[..., 1]) + 1) # Panel pixel number info # number of pixels in each panel in x/y direction self.panel_pixel_num_x = self.pixel_index_map.shape[1] self.panel_pixel_num_y = self.pixel_index_map.shape[2] # total number of pixels (px*py) self.pixel_num_total = np.prod(self._shape) ########################################################################################### # Do necessary calculation to finishes the initialization ########################################################################################### # self.geometry currently only work for the pre-defined detectors self.geometry = geom # Calculate the pixel area self.pixel_area = xp.multiply(self.pixel_height, self.pixel_width) # Get reciprocal space configurations and corrections. self.initialize_pixels_with_beam(beam=beam) ########################################################################################## # Do necessary calculation to finishes the initialization ########################################################################################## # Detector effects if 'pedestal' in geom: self._pedestal = xp.asarray(geom['pedestal'], dtype=xp.float64) else: self._pedestal = xp.zeros((self.panel_num, self.panel_pixel_num_x, self.panel_pixel_num_y)) if 'pixel rms' in geom: self._pixel_rms = xp.asarray(geom['pixel rms'], dtype=xp.float64) else: self._pixel_rms = xp.zeros((self.panel_num, self.panel_pixel_num_x, self.panel_pixel_num_y)) if 'pixel bkgd' in geom: self._pixel_bkgd = xp.asarray(geom['pixel bkgd'], dtype=xp.float64) else: self._pixel_bkgd = xp.zeros( (self.panel_num, self.panel_pixel_num_x, self.panel_pixel_num_y)) if 'pixel status' in geom: self._pixel_status = xp.asarray(geom['pixel status'], dtype=xp.float64) else: self._pixel_status = xp.zeros( (self.panel_num, self.panel_pixel_num_x, self.panel_pixel_num_y)) if 'pixel mask' in geom: self._pixel_mask = xp.asarray(geom['pixel mask'], dtype=xp.float64) else: self._pixel_mask = xp.zeros( (self.panel_num, self.panel_pixel_num_x, self.panel_pixel_num_y)) if 'pixel gain' in geom: self._pixel_gain = xp.asarray(geom['pixel gain'], dtype=xp.float64) else: self._pixel_gain = xp.ones((self.panel_num, self.panel_pixel_num_x, self.panel_pixel_num_y))
def initialize(self, geom, run_num=0, cframe=0): """ Initialize the detector :param geom: The *-end.data file which characterizes the geometry profile. :param run_num: The run_num containing the background, rms and gain and the other pixel pixel properties. :param cframe: The desired coordinate frame, 0 for psana and 1 for lab conventions. :return: None """ # Redirect the output stream old_stdout = sys.stdout f = six.StringIO() # f = open('Detector_initialization.log', 'w') sys.stdout = f ########################################################################################### # Initialize the geometry configuration ############################################################################################ self.geometry = GeometryAccess(geom, cframe=cframe) self.run_num = run_num # Set coordinate in real space (convert to m) temp = [ xp.asarray(t) * 1e-6 for t in self.geometry.get_pixel_coords(cframe=cframe) ] temp_index = [ xp.asarray(t) for t in self.geometry.get_pixel_coord_indexes(cframe=cframe) ] self.panel_num = np.prod(temp[0].shape[:-2]) self._distance = float(temp[2].mean()) self._shape = (self.panel_num, temp[0].shape[-2], temp[0].shape[-1]) self.pixel_position = xp.zeros(self._shape + (3, )) self.pixel_index_map = xp.zeros(self._shape + (2, )) for n in range(3): self.pixel_position[..., n] = temp[n].reshape(self._shape) for n in range(2): self.pixel_index_map[..., n] = temp_index[n].reshape(self._shape) self.pixel_index_map = self.pixel_index_map.astype(xp.int64) # Get the range of the pixel index self.detector_pixel_num_x = asnumpy( xp.max(self.pixel_index_map[..., 0]) + 1) self.detector_pixel_num_y = asnumpy( xp.max(self.pixel_index_map[..., 1]) + 1) self.panel_pixel_num_x = np.array([ self.pixel_index_map.shape[1], ] * self.panel_num) self.panel_pixel_num_y = np.array([ self.pixel_index_map.shape[2], ] * self.panel_num) self.pixel_num_total = np.sum( np.multiply(self.panel_pixel_num_x, self.panel_pixel_num_y)) tmp = float(self.geometry.get_pixel_scale_size() * 1e-6) # Convert to m self.pixel_width = xp.ones((self.panel_num, self.panel_pixel_num_x[0], self.panel_pixel_num_y[0])) * tmp self.pixel_height = xp.ones((self.panel_num, self.panel_pixel_num_x[0], self.panel_pixel_num_y[0])) * tmp # Calculate the pixel area self.pixel_area = xp.multiply(self.pixel_height, self.pixel_width) ########################################################################################### # Initialize the pixel effects ########################################################################################### # first we should parse the path parsed_path = geom.split('/') self.exp = parsed_path[-5] if self.exp == 'calib': self.exp = parsed_path[-6] self.group = parsed_path[-4] self.source = parsed_path[-3] self._pedestals = None self._pixel_rms = None self._pixel_mask = None self._pixel_bkgd = None self._pixel_status = None self._pixel_gain = None if six.PY2: try: cbase = self._get_cbase() self.calibdir = '/'.join(parsed_path[:-4]) pbits = 255 gcp = GenericCalibPars(cbase, self.calibdir, self.group, self.source, run_num, pbits) self._pedestals = gcp.pedestals() self._pixel_rms = gcp.pixel_rms() self._pixel_mask = gcp.pixel_mask() self._pixel_bkgd = gcp.pixel_bkgd() self._pixel_status = gcp.pixel_status() self._pixel_gain = gcp.pixel_gain() except NotImplementedError: # No GenericCalibPars information. pass else: try: self.det = self._get_det_id(self.group) except NotImplementedError: # No GenericCalibPars information. self.det = None # Redirect the output stream sys.stdout = old_stdout
def __init__(self, N_pixel, det_size, det_distance, beam=None): """ Initialize the detector :param N_pixel: Number of pixels per dimension. :param det_size: Length of detector sides (m). :param det_distance: Sample-Detector distance (m). """ super(SimpleSquareDetector, self).__init__() ar = xp.arange(N_pixel) sep = float(det_size) / N_pixel x = -det_size / 2 + sep / 2 + ar * sep y = -det_size / 2 + sep / 2 + ar * sep X, Y = xp.meshgrid(x, y, indexing='xy') Xar, Yar = xp.meshgrid(ar, ar, indexing='xy') self.panel_num = 1 self.panel_pixel_num_x = N_pixel self.panel_pixel_num_y = N_pixel self._shape = (1, N_pixel, N_pixel) # Define all properties the detector should have self._distance = det_distance self.center_z = self._distance * xp.ones(self._shape, dtype=xp.float64) p_center_x = xp.stack((X, )) p_center_y = xp.stack((Y, )) self.pixel_width = sep * xp.ones(self._shape, dtype=xp.float64) self.pixel_height = sep * xp.ones(self._shape, dtype=xp.float64) self.center_x = p_center_x self.center_y = p_center_y # construct the the pixel position array self.pixel_position = xp.zeros(self._shape + (3, )) self.pixel_position[..., 0] = self.center_x self.pixel_position[..., 1] = self.center_y self.pixel_position[..., 2] = self.center_z # Pixel map p_map_x = xp.stack((Xar, )) p_map_y = xp.stack((Yar, )) # [panel number, pixel num x, pixel num y] self.pixel_index_map = xp.stack((p_map_x, p_map_y), axis=-1) # Detector pixel number info self.detector_pixel_num_x = asnumpy( xp.max(self.pixel_index_map[..., 0]) + 1) self.detector_pixel_num_y = asnumpy( xp.max(self.pixel_index_map[..., 1]) + 1) # Panel pixel number info # number of pixels in each panel in x/y direction self.panel_pixel_num_x = self.pixel_index_map.shape[1] self.panel_pixel_num_y = self.pixel_index_map.shape[2] # total number of pixels (px*py) self.pixel_num_total = np.prod(self._shape) # Calculate the pixel area self.pixel_area = xp.multiply(self.pixel_height, self.pixel_width) # Get reciprocal space configurations and corrections. self.initialize_pixels_with_beam(beam=beam)