def scatter_parallel(x: float64, y: float64, m: float32, h: float32, res: int) -> ndarray: """ Same as scatter, but executes in parallel! This is actually trivial, we just make NUM_THREADS images and add them together at the end. """ number_of_particles = x.size core_particles = number_of_particles // NUM_THREADS output = zeros((res, res), dtype=float32) for thread in prange(NUM_THREADS): # Left edge is easy, just start at 0 and go to 'final' left_edge = thread * core_particles # Right edge is harder in case of left over particles... right_edge = thread + 1 if right_edge == NUM_THREADS: right_edge = number_of_particles else: right_edge *= core_particles output += scatter( x=x[left_edge:right_edge], y=y[left_edge:right_edge], m=m[left_edge:right_edge], h=h[left_edge:right_edge], res=res, ) return output
def scatter_parallel( x: float64, y: float64, m: float32, h: float32, res: int ) -> ndarray: """ Parallel implementation of scatter Creates a weighted scatter plot. Computes contributions from particles with positions (`x`,`y`) with smoothing lengths `h` weighted by quantities `m`. This ignores boundary effects. Parameters ---------- x : np.array[float64] array of x-positions of the particles. Must be bounded by [0, 1]. y : np.array[float64] array of y-positions of the particles. Must be bounded by [0, 1]. m : np.array[float32] array of masses (or otherwise weights) of the particles h : np.array[float32] array of smoothing lengths of the particles res : int the number of pixels along one axis, i.e. this returns a square of res * res. Returns ------- np.array[float32, float32, float32] pixel grid of quantity See Also -------- scatter : Creates 2D scatter plot from SWIFT data Notes ----- Explicitly defining the types in this function allows for a 25-50% performance improvement. In our testing, using numpy floats and integers is also an improvement over using the numba ones. Uses 4x the number of sampling points as in scatter_parallel in subsampled.py """ # Same as scatter, but executes in parallel! This is actually trivial, # we just make NUM_THREADS images and add them together at the end. number_of_particles = x.size core_particles = number_of_particles // NUM_THREADS output = zeros((res, res), dtype=float64) for thread in prange(NUM_THREADS): # Left edge is easy, just start at 0 and go to 'final' left_edge = thread * core_particles # Right edge is harder in case of left over particles... right_edge = thread + 1 if right_edge == NUM_THREADS: right_edge = number_of_particles else: right_edge *= core_particles output += scatter( x=x[left_edge:right_edge], y=y[left_edge:right_edge], m=m[left_edge:right_edge], h=h[left_edge:right_edge], res=res, ) return output
def slice_scatter_parallel( x: float64, y: float64, z: float64, m: float32, h: float32, z_slice: float64, res: int, ) -> ndarray: """ Parallel implementation of slice_scatter Creates a scatter plot of the given quantities for a particles in a data slice ignoring boundary effects. Parameters ---------- x : array of float64 x-positions of the particles. Must be bounded by [0, 1]. y : array of float64 y-positions of the particles. Must be bounded by [0, 1]. z : array of float64 z-positions of the particles. Must be bounded by [0, 1]. m : array of float32 masses (or otherwise weights) of the particles h : array of float32 smoothing lengths of the particles z_slice : float64 the position at which we wish to create the slice res : int the number of pixels. Returns ------- ndarray of float32 output array for scatterplot image See Also -------- scatter : Create 3D scatter plot of SWIFT data scatter_parallel : Create 3D scatter plot of SWIFT data in parallel slice_scatter : Create scatter plot of a slice of data Notes ----- Explicitly defining the types in this function allows for a 25-50% performance improvement. In our testing, using numpy floats and integers is also an improvement over using the numba ones. """ # Same as scatter, but executes in parallel! This is actually trivial, # we just make NUM_THREADS images and add them together at the end. number_of_particles = x.size core_particles = number_of_particles // NUM_THREADS output = zeros((res, res), dtype=float32) for thread in prange(NUM_THREADS): # Left edge is easy, just start at 0 and go to 'final' left_edge = thread * core_particles # Right edge is harder in case of left over particles... right_edge = thread + 1 if right_edge == NUM_THREADS: right_edge = number_of_particles else: right_edge *= core_particles output += slice_scatter( x=x[left_edge:right_edge], y=y[left_edge:right_edge], z=z[left_edge:right_edge], m=m[left_edge:right_edge], h=h[left_edge:right_edge], z_slice=z_slice, res=res, ) return output