Пример #1
0
    def initialize_pixels_with_beam(self, beam=None):
        """
        Calculate the pixel position in the reciprocal space and several corrections.
        :param beam: The beam object
        :return: None
        """
        if beam is None:
            return

        self._has_beam = True
        self._beam = beam

        wavevector = beam.get_wavevector()
        polar = beam.Polarization
        intensity = beam.get_photons_per_pulse() / beam.get_focus_area()

        # Get the reciprocal positions and the corrections
        (self.pixel_position_reciprocal, self.pixel_distance_reciprocal,
         self.polarization_correction, self.solid_angle_per_pixel
         ) = pg.get_reciprocal_position_and_correction(
             pixel_position=self.pixel_position,
             polarization=polar,
             wave_vector=wavevector,
             pixel_area=self.pixel_area,
             orientation=self.orientation)

        # Put all the corrections together
        self.linear_correction = intensity * self.Thomson_factor * xp.multiply(
            self.polarization_correction, self.solid_angle_per_pixel)
Пример #2
0
def solid_angle(pixel_center, pixel_area, orientation):
    """
    Calculate the solid angle for each pixel.

    :param pixel_center: The position of each pixel in real space. In pixel stack format.
    :param orientation: The orientation of the detector.
    :param pixel_area: The pixel area for each pixel. In pixel stack format.
    :return: Solid angle of each pixel.
    """
    orientation = xp.asarray(orientation)

    # Use 1D format
    pixel_center_1d = reshape_pixels_position_arrays_to_1d(pixel_center)
    pixel_center_norm_1d = xp.sqrt(xp.sum(xp.square(pixel_center_1d), axis=-1))
    pixel_area_1d = xp.reshape(pixel_area, np.prod(pixel_area.shape))

    # Calculate the direction of each pixel.
    pixel_center_direction_1d = pixel_center_1d / pixel_center_norm_1d[:, xp.newaxis]

    # Normalize the orientation vector
    orientation_norm = xp.sqrt(xp.sum(xp.square(orientation)))
    orientation_normalized = orientation / orientation_norm

    # The correction induced by projection which is a factor of cosine.
    cosine_1d = xp.abs(xp.dot(pixel_center_direction_1d, orientation_normalized))

    # Calculate the solid angle ignoring the projection
    solid_angle_1d = xp.divide(pixel_area_1d, xp.square(pixel_center_norm_1d))
    solid_angle_1d = xp.multiply(cosine_1d, solid_angle_1d)

    # Restore the pixel stack format
    solid_angle_stack = xp.reshape(solid_angle_1d, pixel_area.shape)

    return solid_angle_stack
Пример #3
0
 def add_correction_batch(self, pattern_batch):
     """
     Add corrections to a batch of image stack
     :param pattern_batch [image stack index,image stack shape]
     :return:
     """
     self.ensure_beam()
     return xp.multiply(pattern_batch, self.linear_correction[xp.newaxis])
Пример #4
0
 def add_correction_and_quantization(self, pattern):
     """
     Add corrections to image stack and apply quantization to the image stack
     :param pattern: The image stack.
     :return: images with linear correction applied and quantized
     """
     self.ensure_beam()
     return xp.random.poisson(xp.multiply(pattern, self.linear_correction))
Пример #5
0
 def add_correction(self, pattern):
     """
     Add linear correction to the image stack
     :param pattern: The image stack
     :return: image stack with linear correction applied
     """
     self.ensure_beam()
     return xp.multiply(pattern, self.linear_correction)
Пример #6
0
 def add_polarization_correction(self, pattern):
     """
     Add polarization correction to the image stack
     :param pattern: image stack
     :return: image stack with polarization correction applied
     """
     self.ensure_beam()
     return xp.multiply(pattern, self.polarization_correction)
Пример #7
0
 def add_solid_angle_correction(self, pattern):
     """
     Add solid angle corrections to the image stack.
     :param pattern: Pattern stack
     :return: Pattern stack with solid angle correction
     """
     self.ensure_beam()
     return xp.multiply(pattern, self.solid_angle_per_pixel)
Пример #8
0
 def add_correction_and_quantization_batch(self, pattern_batch):
     """
     Add corrections to a batch of image stack and apply quantization to the batch
     :param pattern_batch: [image stack index, image stack shape]
     :return:
     """
     self.ensure_beam()
     return xp.random.poisson(
         xp.multiply(pattern_batch, self.linear_correction[xp.newaxis]))
Пример #9
0
    def get_intensity_field(self, particle, device=None):
        """
        Generate a single diffraction pattern without any correction from the particle object.

        :param particle: The particle object.
        :return: A diffraction pattern.
        """
        self.ensure_beam()

        if device:
            deprecation_message("Device option is deprecated. "
                                "Everything now runs on the GPU.")

        import skopi.gpu.diffraction as pgd  # Only import GPU if needed
        diffraction_pattern = pgd.calculate_diffraction_pattern_gpu(
            self.pixel_position_reciprocal, particle, "intensity")

        return xp.multiply(diffraction_pattern, self.linear_correction)
Пример #10
0
def extract_slice(local_index, local_weight, volume):
    """
    Take one slice from the volume given the index and weight map.

    :param local_index: The index containing values to take.
    :param local_weight: The weight for each index.
    :param volume: The volume to slice from.
    :return: The slice or an array of zeros is if dimensions are incompatible.
    """
    local_index = xp.asarray(local_index)
    local_weight = xp.asarray(local_weight)
    volume = xp.asarray(volume)

    # Convert the index of the 3D diffraction volume to 1D
    pattern_shape = local_index.shape[:3]
    pixel_num = int(np.prod(pattern_shape))

    volume_num_1d = volume.shape[0]
    convertion_factor = xp.array(
        [volume_num_1d * volume_num_1d, volume_num_1d, 1], dtype=np.int64)

    index_2d = xp.reshape(local_index, [pixel_num, 8, 3])
    index_2d = xp.matmul(index_2d, convertion_factor)

    volume_1d = xp.reshape(volume, volume_num_1d ** 3)
    weight_2d = xp.reshape(local_weight, [pixel_num, 8])

    # Expand the data to merge
    try:
        data_to_merge = volume_1d[index_2d]
    except IndexError:
        print("Requested slice and diffraction volume have incompatible dimensions")
        return np.zeros(pattern_shape)

    # Merge the data
    data_merged = xp.sum(xp.multiply(weight_2d, data_to_merge), axis=-1)

    data = xp.reshape(data_merged, pattern_shape)
    return data
Пример #11
0
    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)
Пример #12
0
    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))
Пример #13
0
    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 psana_version==1:
            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