Пример #1
0
def take_n_slices(volume, voxel_length, pixel_momentum, orientations,
                  inverse=False):
    """
    Take several slices.

    :param volume: The volume to slice from.
    :param voxel_length: The length unit of the voxel
    :param pixel_momentum: The coordinate of each pixel in the
        reciprocal space measured in A.
    :param orientations: The orientations of the slices.
    :param inverse: Whether to use the inverse of the rotation or not.
    :return: n slices.
    """
    # Preprocess
    slice_num = orientations.shape[0]
    pattern_shape = pixel_momentum.shape[:-1]

    # Create variable to hold the slices
    slices_holder = xp.zeros((slice_num,) + pattern_shape, dtype=volume.dtype)

    for l in range(slice_num):
        slices_holder[l] = take_slice(volume, voxel_length, pixel_momentum,
                                      orientations[l], inverse)

    return slices_holder
Пример #2
0
def test_get_weight_and_index_center_even():
    """Test get_weight_and_index centering for even-sized meshes."""
    pixel_position = xp.zeros((1,3), dtype=float)
    voxel_length = 1.
    voxel_num_1d = 4
    index, weight = mapping.get_weight_and_index(
        pixel_position, voxel_length, voxel_num_1d)
    assert xp.all(index[0][0] == xp.array([1, 1, 1]))
    assert xp.allclose(weight[0], 0.125)
Пример #3
0
def test_get_weight_and_index_center_odd():
    """Test get_weight_and_index centering for odd-sized meshes."""
    pixel_position = xp.zeros((1,3), dtype=float)
    voxel_length = 1.
    voxel_num_1d = 5
    index, weight = mapping.get_weight_and_index(
        pixel_position, voxel_length, voxel_num_1d)
    assert xp.all(index[0][0] == xp.array([2, 2, 2]))
    assert weight[0][0] == 1
    assert xp.all(weight[0][1:] == 0)
Пример #4
0
    def assemble_image_stack(self, image_stack):
        """
        Assemble the image stack into a 2D diffraction pattern.
        For this specific object, since it only has one panel, the result is to remove the
        first dimension.

        :param image_stack: The [1, num_x, num_y] numpy array.
        :return: The [num_x, num_y] numpy array.
        """
        if self.pixel_index_map is None:
            raise RuntimeError(
                "This detector does not have pixel mapping information.")
        # construct the image holder:
        image = xp.zeros(
            (self.detector_pixel_num_x, self.detector_pixel_num_y))
        for l in range(self.panel_num):
            image[self.pixel_index_map[l, :, :, 0],
                  self.pixel_index_map[l, :, :, 1]] = image_stack[l, :, :]

        return image
Пример #5
0
    def assemble_image_stack_batch(self, image_stack_batch):
        """
        Assemble the image stack batch into a stack of 2D diffraction patterns.
        For this specific object, since it has only one panel, the result is a simple reshape.

        :param image_stack_batch: The [stack_num, 1, num_x, num_y] numpy array
        :return: The [stack_num, num_x, num_y] numpy array
        """
        if self.pixel_index_map is None:
            raise RuntimeError(
                "This detector does not have pixel mapping information.")

        stack_num = image_stack_batch.shape[0]

        # construct the image holder:
        image = xp.zeros(
            (stack_num, self.detector_pixel_num_x, self.detector_pixel_num_y))
        for l in range(self.panel_num):
            idx_map_1 = self.pixel_index_map[l, :, :, 0]
            idx_map_2 = self.pixel_index_map[l, :, :, 1]
            image[:, idx_map_1, idx_map_2] = image_stack_batch[:, l]

        return image
Пример #6
0
def calculate_diffraction_pattern_gpu(reciprocal_space, particle, return_type='intensity'):
    """
    Calculate the diffraction field of the specified reciprocal space.

    :param reciprocal_space: The reciprocal space over which to calculate the diffraction field as s-vectors, where q=2*pi*s
    :param particle: The particle object to calculate the diffraction field.
    :param return_type: 'intensity' to return the intensity field. 'complex_field' to return the full diffraction field.
    :return: The diffraction field.
    """
    """This function can be used to calculate the diffraction field for
    arbitrary reciprocal space """
    # convert the reciprocal space into a 1d series.
    shape = reciprocal_space.shape
    pixel_number = int(np.prod(shape[:-1]))
    reciprocal_space_1d = xp.reshape(reciprocal_space, [pixel_number, 3])
    reciprocal_norm_1d = xp.sqrt(xp.sum(xp.square(reciprocal_space_1d), axis=-1))
    qvectors_1d = 2*np.pi*reciprocal_space_1d

    # Calculate atom form factor for the reciprocal space, passing in sin(theta)/lambda in per Angstrom
    form_factor = pd.calculate_atomic_factor(particle=particle,
                                             q_space=reciprocal_norm_1d * (1e-10 / 2.),  # For unit compatibility
                                             pixel_num=pixel_number)

    # Get atom position
    atom_position = np.ascontiguousarray(particle.atom_pos[:])
    atom_type_num = len(particle.split_idx) - 1

    # create
    pattern_cos = xp.zeros(pixel_number, dtype=xp.float64)
    pattern_sin = xp.zeros(pixel_number, dtype=xp.float64)

    # atom_number = atom_position.shape[0]
    split_index = xp.array(particle.split_idx)

    cuda_split_index = cuda.to_device(split_index)
    cuda_atom_position = cuda.to_device(atom_position)
    cuda_reciprocal_position = cuda.to_device(qvectors_1d)
    cuda_form_factor = cuda.to_device(form_factor)

    # Calculate the pattern
    calculate_pattern_gpu_back_engine[(pixel_number + 511) // 512, 512](
        cuda_form_factor, cuda_reciprocal_position, cuda_atom_position,
        pattern_cos, pattern_sin, atom_type_num, cuda_split_index,
        pixel_number)

    # Add the hydration layer
    if particle.mesh is not None:
        water_position = np.ascontiguousarray(particle.mesh[particle.solvent_mask,:])
        water_num = np.sum(particle.solvent_mask)
        water_prefactor = particle.solvent_mean_electron_density * particle.mesh_voxel_size**3

        cuda_water_position = cuda.to_device(water_position)

        calculate_solvent_pattern_gpu_back_engine[(pixel_number + 511) // 512, 512](
            cuda_reciprocal_position, cuda_water_position,
            pattern_cos, pattern_sin, water_prefactor, water_num,
            pixel_number)

        # Add another contribution if defined, e.g. virus void...
        if particle.other_mask is not None:
            other_position = np.ascontiguousarray(particle.mesh[particle.other_mask,:])
            other_num = np.sum(particle.other_mask)
            other_prefactor = particle.other_mean_electron_density * particle.mesh_voxel_size**3

            cuda_other_position = cuda.to_device(other_position)

            calculate_solvent_pattern_gpu_back_engine[(pixel_number + 511) // 512, 512](
                cuda_reciprocal_position, cuda_other_position,
                pattern_cos, pattern_sin, other_prefactor, other_num,
                pixel_number)

    if return_type == "intensity":
        pattern = np.reshape(np.square(np.abs(pattern_cos + 1j * pattern_sin)), shape[:-1])
        return xp.asarray(pattern)
    elif return_type == "complex_field":
        pattern = np.reshape(pattern_cos + 1j * pattern_sin, shape[:-1])
        return xp.asarray(pattern)
    else:
        print("Please set the parameter return_type = 'intensity' or 'complex_field'")
        print("This time, this program return the complex field.")
        pattern = np.reshape(pattern_cos + 1j * pattern_sin, shape[:-1])
        return xp.asarray(pattern)
Пример #7
0
def get_weight_and_index(pixel_position, voxel_length, voxel_num_1d):
    """
    Obtain the weight of the pixel for adjacent voxels.
    In this function, pixel position is first cast to the shape [pixel number,3].

    :param pixel_position: The position of each pixel in the space.
    :param voxel_length:
    :param voxel_num_1d:
    :return:
    """

    # Extract the detector shape
    detector_shape = pixel_position.shape[:-1]
    pixel_num = np.prod(detector_shape)

    # Cast the position infor to the shape [pixel number, 3]
    pixel_position = xp.asarray(pixel_position)
    pixel_position_1d = xp.reshape(pixel_position, (pixel_num, 3))

    # convert_to_voxel_unit
    pixel_position_1d_voxel_unit = pixel_position_1d / voxel_length

    # shift the center position
    shift = (voxel_num_1d - 1) / 2.
    pixel_position_1d_voxel_unit += shift

    # Get one nearest neighbor
    tmp_index = xp.floor(pixel_position_1d_voxel_unit).astype(np.int64)

    # Generate the holders
    indexes = xp.zeros((pixel_num, 8, 3), dtype=np.int64)
    weight = xp.ones((pixel_num, 8), dtype=np.float64)

    # Calculate the floors and the ceilings
    dfloor = pixel_position_1d_voxel_unit - tmp_index
    dceiling = 1 - dfloor

    # Assign the correct values to the indexes
    indexes[:, 0, :] = tmp_index

    indexes[:, 1, 0] = tmp_index[:, 0]
    indexes[:, 1, 1] = tmp_index[:, 1]
    indexes[:, 1, 2] = tmp_index[:, 2] + 1

    indexes[:, 2, 0] = tmp_index[:, 0]
    indexes[:, 2, 1] = tmp_index[:, 1] + 1
    indexes[:, 2, 2] = tmp_index[:, 2]

    indexes[:, 3, 0] = tmp_index[:, 0]
    indexes[:, 3, 1] = tmp_index[:, 1] + 1
    indexes[:, 3, 2] = tmp_index[:, 2] + 1

    indexes[:, 4, 0] = tmp_index[:, 0] + 1
    indexes[:, 4, 1] = tmp_index[:, 1]
    indexes[:, 4, 2] = tmp_index[:, 2]

    indexes[:, 5, 0] = tmp_index[:, 0] + 1
    indexes[:, 5, 1] = tmp_index[:, 1]
    indexes[:, 5, 2] = tmp_index[:, 2] + 1

    indexes[:, 6, 0] = tmp_index[:, 0] + 1
    indexes[:, 6, 1] = tmp_index[:, 1] + 1
    indexes[:, 6, 2] = tmp_index[:, 2]

    indexes[:, 7, :] = tmp_index + 1

    # Assign the correct values to the weight
    weight[:, 0] = xp.prod(dceiling, axis=-1)
    weight[:, 1] = dceiling[:, 0] * dceiling[:, 1] * dfloor[:, 2]
    weight[:, 2] = dceiling[:, 0] * dfloor[:, 1] * dceiling[:, 2]
    weight[:, 3] = dceiling[:, 0] * dfloor[:, 1] * dfloor[:, 2]
    weight[:, 4] = dfloor[:, 0] * dceiling[:, 1] * dceiling[:, 2]
    weight[:, 5] = dfloor[:, 0] * dceiling[:, 1] * dfloor[:, 2]
    weight[:, 6] = dfloor[:, 0] * dfloor[:, 1] * dceiling[:, 2]
    weight[:, 7] = xp.prod(dfloor, axis=-1)

    # Change the shape of the index and weight variable
    indexes = xp.reshape(indexes, detector_shape + (8, 3))
    weight = xp.reshape(weight, detector_shape + (8, ))

    return indexes, weight
Пример #8
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)
Пример #9
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))
Пример #10
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