示例#1
0
    def make_map(self,
                 particle_type: int,
                 weights: unyt.array,
                 tilt: str = 'z') -> np.ndarray:

        cop = self.data.subfind_tab.FOF.GroupCentreOfPotential
        R500c = self.data.subfind_tab.FOF.Group_R_Crit500
        coord = self.data.subfind_particles[f'PartType{particle_type}'][
            'Coordinates']
        coord_rot = self.rotate_coordinates(particle_type, tilt=tilt)
        smoothing_lengths = self.data.subfind_particles[
            f'PartType{particle_type}']['SmoothingLength']
        aperture = unyt.unyt_quantity(5 * R500c / np.sqrt(3), coord.units)

        if particle_type == 0:
            temperature = self.data.subfind_particles['PartType0'][
                'Temperature']
            spatial_filter = np.where(
                (np.abs(coord_rot[:, 0]) < aperture)
                & (np.abs(coord_rot[:, 1]) < aperture)
                & (np.abs(coord_rot[:, 2]) < aperture)
                & (temperature.value > self.hot_gas_temperature_threshold))[0]
        else:
            spatial_filter = np.where((np.abs(coord_rot[:, 0]) < aperture)
                                      & (np.abs(coord_rot[:, 1]) < aperture) &
                                      (np.abs(coord_rot[:, 2]) < aperture))[0]

        read.pprint(coord_rot, cop, spatial_filter, sep='\n')
        x_max = np.max(coord_rot[spatial_filter, 0])
        x_min = np.min(coord_rot[spatial_filter, 0])
        y_max = np.max(coord_rot[spatial_filter, 1])
        y_min = np.min(coord_rot[spatial_filter, 1])
        x_range = x_max - x_min
        y_range = y_max - y_min
        x = (coord_rot[spatial_filter, 0] - x_min) / x_range
        y = (coord_rot[spatial_filter, 1] - y_min) / y_range
        h = smoothing_lengths[spatial_filter] / (2 * aperture)

        # Gather and handle coordinates to be processed
        x = np.asarray(x.value, dtype=np.float64)
        y = np.asarray(y.value, dtype=np.float64)
        m = np.asarray(weights[spatial_filter].value, dtype=np.float32)
        h = np.asarray(h.value, dtype=np.float32)
        smoothed_map = scatter(x=x, y=y, m=m, h=h, res=self.resolution).T
        smoothed_map = np.ma.masked_where(
            np.abs(smoothed_map) < 1.e-9, smoothed_map)

        surface_element = x_range * y_range / self.resolution**2
        setattr(Mapping, f'surface_element{particle_type}', surface_element)

        return smoothed_map  # * weights.units / coord.units ** 2
示例#2
0
def generate_volume(*args, parallel = False):
    """
    SWIFTSIMIO WRAPPER
    ------------------
    The key here is that only particles in the domain [0, 1] in x, [0, 1] in y and [0, 1] in z will be visible in the image.
    You may have particles outside of this range; they will not crash the code, and may even contribute to the image
    if their  smoothing lengths overlap with [0, 1]. You will need to re-scale your data such that it lives within
    this range.
    out will be a 3D numpy grid of shape [res, res, res]. You will need to re-scale this back to your original
    dimensions to get it in the correct units, and do not forget that it now represents the smoothed quantity per
    surface volume.

    ================================

    @jit(nopython=True, fastmath=True)
    def scatter(
        x: float64, y: float64, z: float64, m: float32, h: float32, res: int
        ) -> ndarray:

        Creates a voxel grid of:
        + x: the x-positions of the particles. Must be bounded by [0, 1].
        + y: the y-positions of the particles. Must be bounded by [0, 1].
        + z: the z-positions of the particles. Must be bounded by [0, 1].
        + m: the masses (or otherwise weights) of the particles
        + h: the smoothing lengths of the particles
        + res: the number of voxels along one axis, i.e. this returns a cube
               of res * res * res..

    ================================

    This ignores boundary effects.
    Note that 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.

    :param parallel: (boolean) default = False
        Triggers the use of Numba decorators for parallel rendering.

    :param kwargs: parse the kwargs used by swiftsimio.visualisation.volume_render.scatter_parallel

    :return: nd array
    """
    from swiftsimio.visualisation.volume_render import scatter, scatter_parallel

    print('[ SWIFTSIMIO ]\t ==> Invoking `volume_render` front-end binding.')
    if parallel:
        return scatter_parallel(*args)
    else:
        return scatter(*args)
示例#3
0
def getImage(parts, width, center, res):
    pos = parts["positions"]
    pos = pos - center + 0.5 * width
    pos /= width
    h = parts["smoothing_lengths"] / width

    m = np.ones(pos.shape[0])
    # Do the projection
    img = vis.scatter(pos[:, 0], pos[:, 1], m, h, res).T
    img /= width**3
    ind = img == 0
    img[ind] = img[~ind].min()
    img = np.log10(img)

    return img
示例#4
0
    y_max = np.max(snapshot['PartType0']['Coordinates'][depth_mask, 1])
    y_min = np.min(snapshot['PartType0']['Coordinates'][depth_mask, 1])
    x_range = x_max - x_min
    y_range = y_max - y_min
    x = (snapshot['PartType0']['Coordinates'][depth_mask, 0] - x_min) / x_range
    y = (snapshot['PartType0']['Coordinates'][depth_mask, 1] - y_min) / y_range
    h = snapshot['PartType0']['SmoothingLength'][depth_mask] / x_range

    # Gather and handle coordinates to be processed
    x = np.asarray(x.value, dtype=np.float64)
    y = np.asarray(y.value, dtype=np.float64)
    m = np.asarray(snapshot['PartType0']['Density'][depth_mask].value,
                   dtype=np.float32)
    h = np.asarray(h.value, dtype=np.float32)
    read.pprint(f'Computing map ({resolution} x {resolution})')
    smoothed_map = scatter(x=x, y=y, m=m, h=h, res=resolution).T
    smoothed_map = np.ma.masked_where(
        np.abs(smoothed_map) < 1.e-9, smoothed_map)

    fig, axes = plt.subplots()
    cmap = copy.copy(plt.get_cmap('twilight'))
    cmap.set_under('black')
    axes.axis("off")
    axes.set_aspect("equal")
    axes.imshow(smoothed_map.T,
                norm=LogNorm(),
                cmap=cmap,
                origin="lower",
                extent=[x_min, x_max, y_min, y_max])
    fig.savefig('box.png')
def density_map(particle_type: int, cluster_data) -> None:

    z = cluster_data.header.subfind_particles.Redshift
    CoP = cluster_data.subfind_tab.FOF.GroupCentreOfPotential
    M200c = cluster_data.subfind_tab.FOF.Group_M_Crit200
    R200c = cluster_data.subfind_tab.FOF.Group_R_Crit200
    R500c = cluster_data.subfind_tab.FOF.Group_R_Crit500
    M500c = cluster_data.subfind_tab.FOF.Group_M_Crit500
    coord = cluster_data.subfind_particles[f'PartType{particle_type}'][
        'Coordinates']
    boxsize = cluster_data.boxsize
    DM_part_mass = cluster_data.mass_DMpart

    if particle_type == 1:

        masses = np.ones_like(coord[:, 0].value,
                              dtype=np.float32) * DM_part_mass
        # Generate DM particle smoothing lengths
        smoothing_lengths = generate_smoothing_lengths(
            coord,
            boxsize,
            kernel_gamma=1.8,
            neighbours=57,
            speedup_fac=3,
            dimension=3,
        )

    else:
        masses = cluster_data.subfind_particles[f'PartType{particle_type}'][
            'Mass']
        smoothing_lengths = cluster_data.subfind_particles[
            f'PartType{particle_type}']['SmoothingLength']

    # Run aperture filter
    read.pprint('[Check] Particle max x: ',
                np.max(np.abs(coord[:, 0] - CoP[0])), '6 x R500c: ', 6 * R500c)
    read.pprint('[Check] Particle max y: ',
                np.max(np.abs(coord[:, 1] - CoP[1])), '6 x R500c: ', 6 * R500c)
    read.pprint('[Check] Particle max z: ',
                np.max(np.abs(coord[:, 2] - CoP[2])), '6 x R500c: ', 6 * R500c)

    # Rotate particles
    # coord_rot = rotation_align_with_vector(coord.value, CoP, np.array([0, 0, 1]))
    coord_rot = coord

    # After derotation create a cubic aperture filter inscribed within a sphere of radius 5xR500c and
    # Centred in the CoP. Each semi-side of the aperture has length 5 * R500c / sqrt(3).
    aperture = 5 * R500c / np.sqrt(3)
    mask = np.where((np.abs(coord_rot[:, 0] - CoP[0]) <= aperture)
                    & (np.abs(coord_rot[:, 1] - CoP[1]) <= aperture)
                    & (np.abs(coord_rot[:, 2] - CoP[2]) <= aperture))[0]

    # Gather and handle coordinates to be plotted
    x = coord_rot[mask, 0].value
    y = coord_rot[mask, 1].value
    x_max = np.max(x)
    x_min = np.min(x)
    y_max = np.max(y)
    y_min = np.min(y)
    x_range = x_max - x_min
    y_range = y_max - y_min

    # Test that we've got a square box
    read.pprint(x_range, y_range)

    map_input_m = np.asarray(masses.value, dtype=np.float32)
    map_input_h = np.asarray(smoothing_lengths.value, dtype=np.float32)
    mass_map = scatter(x=(x - x_min) / x_range,
                       y=(y - y_min) / y_range,
                       m=map_input_m[mask],
                       h=map_input_h[mask] / x_range,
                       res=map_resolution)
    mass_map_units = masses.units / coord.units**2

    # Mask zero values in the map with black
    mass_map = np.ma.masked_where(mass_map < 0.05, mass_map)
    read.pprint(mass_map)

    # Make figure
    fig, ax = plt.subplots(figsize=(6, 6), dpi=map_resolution // 6)
    ax.set_aspect('equal')
    fig.subplots_adjust(0, 0, 1, 1)
    ax.axis("off")
    ax.imshow(mass_map.T,
              norm=LogNorm(),
              cmap="inferno",
              origin="lower",
              extent=[x_min, x_max, y_min, y_max])

    t = ax.text(
        0.025,
        0.025,
        (f"Halo {cluster_id:d} {simulation_type}\n"
         f"Particles: {partType_atlas[str(particle_type)]}\n"
         f"$z={z:3.3f}$\n"
         f"$M_{{500c}}={latex_float(M500c.value)}$ M$_\odot$\n"
         f"$R_{{500c}}={latex_float(R500c.value)}$ Mpc\n"
         f"$M_{{200c}}={latex_float(M200c.value)}$ M$_\odot$\n"
         f"$R_{{200c}}={latex_float(R200c.value)}$ Mpc"),
        color="white",
        ha="left",
        va="bottom",
        transform=ax.transAxes,
    )
    t.set_bbox(dict(facecolor='black', alpha=0.2, edgecolor='none'))
    ax.text(CoP[0],
            CoP[1] + 1.02 * R500c,
            r"$R_{500c}$",
            color="white",
            ha="center",
            va="bottom")
    circle_r500 = plt.Circle((CoP[0], CoP[1]),
                             R500c,
                             color="white",
                             fill=False,
                             linestyle='-')
    ax.add_artist(circle_r500)
    plt.tight_layout()
    fig.savefig(
        f"{output_directory}/halo{cluster_id}_{redshift}_densitymap_type{particle_type}.png"
    )
    plt.close(fig)