def test_get_weight_and_index_off_center(): """Test get_weight_and_index for off-centered points.""" pixel_position = xp.array([[0.1, 0.2, 0.3]]) voxel_length = 2. 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 xp.isclose(weight.sum(), 1.) assert xp.allclose(xp.dot(weight[0], index[0]), xp.array([ 2.05, 2.1 , 2.15]))
def add_phase_shift(self, pattern, displ): """ Add phase shift corresponding to displ to complex pattern. :param pattern: complex field pattern. :param displ: displ(acement) (position) of the particle (m). :return: modified complex field pattern. """ self.ensure_beam() pattern = xp.asarray(pattern) displ = xp.asarray(displ) return pattern * xp.exp(1j * xp.dot(self.pixel_position_reciprocal, displ))
def rotate_pixels_in_reciprocal_space(rot_mat, pixels_position): """ Rotate the pixel positions according to the rotation matrix Note that for np.dot(a,b) If a is an N-D array and b is an M-D array (where M>=2), it is a sum product over the last axis of a and the second-to-last axis of b. :param rot_mat: The rotation matrix for M v :param pixels_position: [the other dimensions, 3 for x,y,z] :return: np.dot(pixels_position, rot_mat.T) """ rot_mat = xp.asarray(rot_mat) return xp.dot(pixels_position, rot_mat.T)
def get_fxs_photons(self, particles, beam_focus_radius, jet_radius, device=None): raw_data = None state, coords = distribute_particles(particles, beam_focus_radius, jet_radius) for i in range(len(state)): this_data = self.get_pattern_without_corrections( particle=state[i], return_type="complex_field") this_data *= xp.exp( 1j * xp.dot(self.pixel_position_reciprocal, coords[i])) if raw_data is None: raw_data = this_data else: raw_data += this_data return self.add_correction_and_quantization(xp.square( xp.abs(raw_data)))
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