def rotate_velocities(self,
                          particle_type: int,
                          tilt: str = 'z',
                          boost: unyt.unyt_array = None) -> unyt.array:

        velocities = self.data.subfind_particles[f'PartType{particle_type}'][
            'Velocity']
        if boost is not None:
            velocities[:, 0] -= boost[0]
            velocities[:, 1] -= boost[1]
            velocities[:, 2] -= boost[2]

        vx, vy, vz = velocities.value.T

        if tilt == 'y':
            new_vel = np.vstack((vx, vz, vy)).T
        elif tilt == 'z':
            new_vel = np.vstack((vx, -vy, vz)).T
        elif tilt == 'x':
            new_vel = np.vstack((-vz, -vy, vx)).T
        elif tilt == 'faceon':
            face_on_rotation_matrix = rotation_matrix_from_vector(
                self.angular_momentum_hot_gas.value)
            new_vel = np.einsum('ijk,ik->ij', face_on_rotation_matrix,
                                velocities.value)
        elif tilt == 'edgeon':
            edge_on_rotation_matrix = rotation_matrix_from_vector(
                self.angular_momentum_hot_gas.value, axis='y')
            new_vel = np.einsum('ijk,ik->ij', edge_on_rotation_matrix,
                                velocities.value)

        return new_vel * velocities.units
    def rotate_coordinates(self,
                           particle_type: int,
                           tilt: str = 'z') -> unyt.array:

        cop = self.data.subfind_tab.FOF.GroupCentreOfPotential
        coord = self.data.subfind_particles[f'PartType{particle_type}'][
            'Coordinates']
        coord[:, 0] -= cop[0]
        coord[:, 1] -= cop[1]
        coord[:, 2] -= cop[2]
        x, y, z = coord.value.T

        if tilt == 'y':
            new_coord = np.vstack((x, z, y)).T
        elif tilt == 'z':
            new_coord = np.vstack((x, y, z)).T
        elif tilt == 'x':
            new_coord = np.vstack((z, y, x)).T
        elif tilt == 'faceon':
            face_on_rotation_matrix = rotation_matrix_from_vector(
                self.angular_momentum_hot_gas.value)
            new_coord = np.einsum('ijk,ik->ij', face_on_rotation_matrix,
                                  coord.value)
        elif tilt == 'edgeon':
            edge_on_rotation_matrix = rotation_matrix_from_vector(
                self.angular_momentum_hot_gas.value, axis='y')
            new_coord = np.einsum('ijk,ik->ij', edge_on_rotation_matrix,
                                  coord.value)

        new_coord *= coord.units
        # new_coord[:, 0] += cop[0]
        # new_coord[:, 1] += cop[1]
        # new_coord[:, 2] += cop[2]
        return new_coord
Exemple #3
0
def calculate_integrated_quantities(data, ang_momentum, radius, mode):

    face_on_rotation_matrix = rotation_matrix_from_vector(ang_momentum)

    x, y, _ = np.matmul(face_on_rotation_matrix, data[:, :3].T)
    r = np.sqrt(x**2 + y**2)
    select = r <= radius

    surface = np.pi * radius**2
    if mode == 0:
        m = data[select, 9]
    if mode == 1:
        m = data[select, 9] + data[select, 8]

    # If we have gas within rhalfMs
    if len(m) > 0:
        Sigma_gas = np.log10(np.sum(m) / surface) - 6.0  # Msun / pc^2

        sfr = data[select, 10]
        sfr = sfr[sfr > 0]
        Sigma_SFR = np.log10(np.sum(sfr) / surface)  # Msun / yr / kpc^2

    else:
        Sigma_gas = -6
        Sigma_SFR = -6

    return Sigma_gas, Sigma_SFR
Exemple #4
0
def get_rotation(
    image_attributes: ImageAttributes, galaxy_attributes: GalaxyAttributes
):
    """
    Gets the rotation matrix and center if required.
    """

    if image_attributes.projection == "faceon":
        return (
            rotation_matrix_from_vector(galaxy_attributes.normal_vector),
            galaxy_attributes.center,
        )
    elif image_attributes.projection == "edgeon":
        return (
            rotation_matrix_from_vector(galaxy_attributes.normal_vector, "y"),
            galaxy_attributes.center,
        )
    else:
        return None, None
def rotate(coord: np.ndarray,
           angular_momentum_hot_gas: np.ndarray,
           tilt: str = 'x'):
    if tilt == 'x':
        rotation_matrix = rotation_matrix_from_vector(
            np.array([1, 0, 0], dtype=np.float))
    elif tilt == 'y':
        rotation_matrix = rotation_matrix_from_vector(
            np.array([0, 1, 0], dtype=np.float))
    elif tilt == 'z':
        rotation_matrix = rotation_matrix_from_vector(
            np.array([0, 0, 1], dtype=np.float))
    elif tilt == 'faceon':
        rotation_matrix = rotation_matrix_from_vector(angular_momentum_hot_gas)
    elif tilt == 'edgeon':
        rotation_matrix = rotation_matrix_from_vector(angular_momentum_hot_gas,
                                                      axis='y')

    new_coord = np.matmul(rotation_matrix, coord.T).T
    return new_coord
Exemple #6
0
   def rotate_coordinates(self, particle_type: int, tilt: str = 'z') -> unyt.array:

        cop = self.data.read_catalogue_subfindtab('/FOF/GroupCentreOfPotential')
        coord = self.data.read_snapshot(f'PartType{particle_type}/Coordinates')
        coord[:, 0] -= cop[0]
        coord[:, 1] -= cop[1]
        coord[:, 2] -= cop[2]
        x, y, z = coord.T

        if tilt == 'y':
            new_coord = np.vstack((x, z, y)).T
        elif tilt == 'z':
            new_coord = np.vstack((x, y, z)).T
        elif tilt == 'x':
            new_coord = np.vstack((z, y, x)).T
        elif tilt == 'faceon':
            face_on_rotation_matrix = rotation_matrix_from_vector(self.angular_momentum_hot_gas)
            new_coord = np.einsum('ijk,ik->ij', face_on_rotation_matrix, coord)
        elif tilt == 'edgeon':
            edge_on_rotation_matrix = rotation_matrix_from_vector(self.angular_momentum_hot_gas, axis='y')
            new_coord = np.einsum('ijk,ik->ij', edge_on_rotation_matrix, coord)

        return new_coord
Exemple #7
0
def KS_relation(data, ang_momentum, mode, method, size):

    image_diameter = 60
    extent = [-30, 30]  # kpc
    number_of_pixels = int(image_diameter / size + 1)

    face_on_rotation_matrix = rotation_matrix_from_vector(ang_momentum)

    if method == "grid":
        # Calculate the surface density maps using grid of pixel size

        partsDATA = data.copy()
        map_mass = project_gas(partsDATA, mode, number_of_pixels, extent,
                               face_on_rotation_matrix)
        map_metals = integrate_metallicity_using_grid(partsDATA,
                                                      number_of_pixels, extent,
                                                      face_on_rotation_matrix)

        star_formation_rate_mask = partsDATA[:, 10] > 0.0
        partsDATA = partsDATA[star_formation_rate_mask, :]
        map_SFR = project_gas(partsDATA, 2, number_of_pixels, extent,
                              face_on_rotation_matrix)

    else:
        partsDATA = data.copy()
        map_mass = project_gas_with_azimuthal_average(partsDATA, mode,
                                                      face_on_rotation_matrix,
                                                      size)
        map_metals = project_metals_with_azimuthal_average(
            partsDATA, face_on_rotation_matrix, size)

        star_formation_rate_mask = np.where(partsDATA[:, 10] > 0.0)[0]
        partsDATA = partsDATA[star_formation_rate_mask, :]

        if len(star_formation_rate_mask) > 0:
            map_SFR = project_gas_with_azimuthal_average(
                partsDATA, 2, face_on_rotation_matrix, size)
        else:
            map_SFR = np.zeros(len(map_mass))

    # Bounds
    map_SFR[map_SFR <= 0] = 1e-6
    map_mass[map_mass <= 0] = 1e-6

    surface_density = np.log10(map_mass.flatten())  # Msun / kpc^2
    surface_density -= 6  # Msun / pc^2
    SFR_surface_density = np.log10(map_SFR.flatten())  # Msun / yr / kpc^2
    tgas = surface_density - SFR_surface_density + 6.0

    return surface_density, SFR_surface_density, tgas, map_metals
Exemple #8
0
    def rotate_velocities(self, particle_type: int, tilt: str = 'z', boost = None) -> unyt.array:

        velocities = self.data.read_snapshot(f'PartType{particle_type}/Velocity')
        if boost is not None:
            velocities[:, 0] -= boost[0]
            velocities[:, 1] -= boost[1]
            velocities[:, 2] -= boost[2]

        vx, vy, vz = velocities.T

        if tilt == 'y':
            new_vel = np.vstack((vx, vz, vy)).T
        elif tilt == 'z':
            new_vel = np.vstack((vx, -vy, vz)).T
        elif tilt == 'x':
            new_vel = np.vstack((-vz, -vy, vx)).T
        elif tilt == 'faceon':
            face_on_rotation_matrix = rotation_matrix_from_vector(self.angular_momentum_hot_gas)
            new_vel = np.einsum('ijk,ik->ij', face_on_rotation_matrix, velocities)
        elif tilt == 'edgeon':
            edge_on_rotation_matrix = rotation_matrix_from_vector(self.angular_momentum_hot_gas, axis='y')
            new_vel = np.einsum('ijk,ik->ij', edge_on_rotation_matrix, velocities)

        return new_vel
Exemple #9
0
def test_slice(filename):
    """
    Checks that a slice of a single particle snapshot is invariant under
    rotations around the particle

    Parameters
    ----------
    filename: str
        name of file providing metadata to copy
    """
    # Start from the beginning, open the file
    output_filename = "single_particle.hdf5"
    create_single_particle_dataset(filename, output_filename)
    data = load(output_filename)

    # Compute rotation matrix for rotating around particle
    centre = data.gas.coordinates[0]
    rotate_vec = [0.5, 0.5, 0.5]
    matrix = rotation_matrix_from_vector(rotate_vec, axis="z")
    boxsize = data.metadata.boxsize

    z_range = boxsize[2]
    slice_z = centre[2] / z_range

    unrotated = slice_gas(data,
                          resolution=1024,
                          slice=slice_z,
                          project="masses",
                          parallel=True)

    rotated = slice_gas(
        data,
        resolution=1024,
        slice=slice_z,
        project="masses",
        rotation_center=centre,
        rotation_matrix=matrix,
        parallel=True,
    )

    # Check that we didn't miss the particle
    assert unrotated.any()
    assert rotated.any()

    assert array_equal(rotated, unrotated)

    remove(output_filename)
Exemple #10
0
def surface_ratios(data, ang_momentum, method, size):

    face_on_rotation_matrix = rotation_matrix_from_vector(ang_momentum)

    if method == "grid":
        image_diameter = 60
        extent = [-30, 30]  # kpc
        number_of_pixels = int(image_diameter / size + 1)

        # Calculate the maps using grid
        map_H2 = project_gas(data, 0, number_of_pixels, extent,
                             face_on_rotation_matrix)
        map_HI = project_gas(data, 3, number_of_pixels, extent,
                             face_on_rotation_matrix)

    else:
        # Calculate the maps using azimuthally-average shells
        map_H2 = project_gas_with_azimuthal_average(data, 0,
                                                    face_on_rotation_matrix,
                                                    size)
        map_HI = project_gas_with_azimuthal_average(data, 3,
                                                    face_on_rotation_matrix,
                                                    size)

    map_gas = map_H2 + map_HI

    # Bounds
    map_H2[map_H2 <= 0] = 1e-6
    map_gas[map_gas <= 0] = 1e-6
    H2_to_neutral_ratio = map_H2 / map_gas

    neutral_gas_surface_density = np.log10(
        map_gas.flatten())  # HI+H2 Msun / kpc^2
    molecular_gas_surface_density = np.log10(
        map_H2.flatten())  # H2 Msun / kpc^2

    neutral_gas_surface_density -= 6  # HI+H2 Msun / pc^2
    molecular_gas_surface_density -= 6  # H2 Msun / pc^2

    H2_to_neutral_ratio_density = np.log10(
        H2_to_neutral_ratio.flatten())  # no units

    return (
        neutral_gas_surface_density,
        molecular_gas_surface_density,
        H2_to_neutral_ratio_density,
    )
Exemple #11
0
def test_render(filename):
    """
    Checks that a volume render of a single particle snapshot is invariant under
    rotations around the particle

    Parameters
    ----------
    filename: str
        name of file providing metadata to copy
    """
    # Start from the beginning, open the file
    output_filename = "single_particle.hdf5"
    create_single_particle_dataset(filename, output_filename)
    data = load(output_filename)

    # Compute rotation matrix for rotating around particle
    centre = data.gas.coordinates[0]
    rotate_vec = [0.5, 0.5, 0.5]
    matrix = rotation_matrix_from_vector(rotate_vec, axis="z")
    boxsize = data.metadata.boxsize

    unrotated = render_gas(data,
                           resolution=256,
                           project="masses",
                           parallel=True)

    rotated = render_gas(
        data,
        resolution=256,
        project="masses",
        rotation_center=centre,
        rotation_matrix=matrix,
        parallel=True,
    )

    assert array_equal(rotated, unrotated)

    remove(output_filename)
def rotation_align_with_vector(coordinates: np.ndarray,
                               rotation_center: np.ndarray,
                               vector: np.ndarray) -> np.ndarray:

    # Normalise vector for more reliable handling
    vector /= np.linalg.norm(vector)

    # Get the de-rotation matrix:
    # axis='z' is the default and corresponds to face-on (looking down z-axis)
    # axis='y' corresponds to edge-on (maximum rotational signal)
    rotation_matrix = rotation_matrix_from_vector(vector, axis='y')

    if rotation_center is not None:
        # Rotate co-ordinates as required
        x, y, z = np.matmul(rotation_matrix, (coordinates - rotation_center).T)
        x += rotation_center[0]
        y += rotation_center[1]
        z += rotation_center[2]

    else:
        x, y, z = coordinates.T

    return np.vstack((x, y, z)).T
Exemple #13
0
def plot_galaxy_parts(partsDATA, parttype, ang_momentum, halo_data, index,
                      output_path, simulation_name):

    # Plot ranges
    r_limit = 5 * halo_data.half_mass_radius_star[index]
    r_img = 30.0
    if r_limit < r_img:
        r_img = r_limit
    xmin = -r_img
    ymin = -r_img
    xmax = r_img
    ymax = r_img

    pos_parts = partsDATA[:, 0:3].copy()
    face_on_rotation_matrix = rotation_matrix_from_vector(ang_momentum,
                                                          axis="z")
    edge_on_rotation_matrix = rotation_matrix_from_vector(ang_momentum,
                                                          axis="y")

    pos_face_on = np.matmul(face_on_rotation_matrix, pos_parts.T)
    pos_face_on = pos_face_on.T
    pos_edge_on = np.matmul(edge_on_rotation_matrix, pos_parts.T)
    pos_edge_on = pos_edge_on.T

    if parttype == 0:
        density = np.log10(partsDATA[:, 11])
    if parttype == 4:
        density = np.log10(partsDATA[:, 8])

    # Sort particles for better viewing
    arg_sort = np.argsort(density)
    density = density[arg_sort]
    pos_face_on = pos_face_on[arg_sort, :]
    pos_edge_on = pos_edge_on[arg_sort, :]

    denmin = np.min(density)
    denmax = np.max(density)

    rcParams.update(params)
    fig = plt.figure()
    ax = plt.subplot(1, 2, 1)

    if parttype == 4:
        title = "Stellar component"
    if parttype == 0:
        title = "Gas component"

    ax.set_title(title)
    ax.tick_params(labelleft=True, labelbottom=True, length=0)
    plt.xlabel("x [kpc]")
    plt.ylabel("y [kpc]")
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)

    plt.scatter(
        pos_face_on[:, 0],
        pos_face_on[:, 1],
        c=density,
        alpha=1,
        s=10,
        vmin=denmin,
        vmax=denmax,
        cmap="magma",
        edgecolors="none",
    )
    ax.autoscale(False)

    ax = plt.subplot(1, 2, 2)
    if parttype == 4:
        kappa = halo_data.kappa_co[index]
        mass = halo_data.log10_stellar_mass[index]
        ac = halo_data.axis_ca[index]
        cb = halo_data.axis_cb[index]
        ba = halo_data.axis_ba[index]
        radius = halo_data.half_mass_radius_star[index]
        title = r" $\kappa_{\mathrm{co}} = $%0.2f" % (kappa)
        title += " - $\log_{10}$ $M_{*}/M_{\odot} = $%0.2f" % (mass)
        title += " \n c/a = %0.2f," % (ac)
        title += " c/b = %0.2f," % (cb)
        title += " b/a = %0.2f" % (ba)
        title += "\n Stellar half mass radius %0.2f kpc" % (radius)
    if parttype == 0:
        kappa = halo_data.gas_kappa_co[index]
        mass = halo_data.log10_gas_mass[index]
        ac = halo_data.gas_axis_ca[index]
        cb = halo_data.gas_axis_cb[index]
        ba = halo_data.gas_axis_ba[index]
        radius = halo_data.half_mass_radius_star[index]
        title = r" $\kappa_{\mathrm{co}} = $%0.2f" % (kappa)
        title += " - $\log_{10}$ $M_{gas}/M_{\odot} = $%0.2f" % (mass)
        title += " \n c/a = %0.2f," % (ac)
        title += " c/b = %0.2f," % (cb)
        title += " b/a = %0.2f" % (ba)
        title += "\n Stellar half mass radius %0.2f kpc" % (radius)
    ax.set_title(title)

    ax.tick_params(labelleft=True, labelbottom=True, length=0)
    plt.xlabel("x [kpc]")
    plt.ylabel("z [kpc]")
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)

    plt.scatter(
        pos_edge_on[:, 0],
        pos_edge_on[:, 1],
        c=density,
        alpha=1,
        s=10,
        vmin=denmin,
        vmax=denmax,
        cmap="magma",
        edgecolors="none",
    )

    ax.autoscale(False)

    cbar_ax = fig.add_axes([0.86, 0.22, 0.018, 0.5])
    cbar_ax.tick_params(labelsize=15)
    cb = plt.colorbar(ticks=[4, 6, 8, 10], cax=cbar_ax)
    cb.set_label(label=r"$\log_{10}$ $\rho$ [M$_{\odot}$/kpc$^{3}$]",
                 labelpad=0.5)

    if parttype == 4:
        outfile = (f"{output_path}/galaxy_sparts_%i_" % (index) +
                   simulation_name + ".png")
    if parttype == 0:
        outfile = f"{output_path}/galaxy_parts_%i_" % (
            index) + simulation_name + ".png"
    fig.savefig(outfile, dpi=150)
    plt.close("all")
Exemple #14
0
def plot_galaxy(parts_data, parttype, ang_momentum, halo_data, index,
                output_path, simulation_name):
    # partsDATA contains particles data and is structured as follow
    # [ (:3)Position[Mpc]: (0)X | (1)Y | (2)Z ]
    if parttype == 4:
        cmap = plt.cm.magma
    if parttype == 0:
        cmap = plt.cm.viridis

    pos_parts = parts_data[:, 0:3].copy()
    face_on_rotation_matrix = rotation_matrix_from_vector(ang_momentum,
                                                          axis="z")
    edge_on_rotation_matrix = rotation_matrix_from_vector(ang_momentum,
                                                          axis="y")

    pos_face_on = np.matmul(face_on_rotation_matrix, pos_parts.T)
    pos_face_on = pos_face_on.T
    pos_edge_on = np.matmul(edge_on_rotation_matrix, pos_parts.T)
    pos_edge_on = pos_edge_on.T

    hsml_parts = parts_data[:, 7]
    mass = parts_data[:, 3]

    r_limit = 5 * halo_data.half_mass_radius_star[index]
    r_img = 30.0
    if r_limit < r_img:
        r_img = r_limit
    xmin = -r_img
    ymin = -r_img
    xmax = r_img
    ymax = r_img

    rcParams.update(params)
    fig = plt.figure()
    ax = plt.subplot(1, 2, 1)

    if parttype == 4:
        title = "Stellar component"
    if parttype == 0:
        title = "HI+H2 gas"
    ax.set_title(title)

    ###### plot one side ########################
    qv = QuickView(
        pos_face_on,
        mass=mass,
        hsml=hsml_parts,
        logscale=True,
        plot=False,
        r="infinity",
        p=0,
        t=0,
        extent=[xmin, xmax, ymin, ymax],
        x=0,
        y=0,
        z=0,
    )
    img = qv.get_image()
    ext = qv.get_extent()
    ax.tick_params(labelleft=True, labelbottom=True, length=0)
    plt.xlabel("x [kpc]")
    plt.ylabel("y [kpc]")
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)
    img = get_normalized_image(img)
    ax.imshow(img, cmap=cmap, extent=ext)
    ax.autoscale(False)

    ###### plot another side ########################
    ax = plt.subplot(1, 2, 2)
    if parttype == 4:
        kappa = halo_data.kappa_co[index]
        mass_galaxy = halo_data.log10_stellar_mass[index]
        ac = halo_data.axis_ca[index]
        cb = halo_data.axis_cb[index]
        ba = halo_data.axis_ba[index]
        title = r" $\kappa_{\mathrm{co}} = $%0.2f" % (kappa)
        title += " - $\log_{10}$ $M_{*}/M_{\odot} = $%0.2f" % (mass_galaxy)
        title += " \n c/a = %0.2f," % (ac)
        title += " c/b = %0.2f," % (cb)
        title += " b/a = %0.2f" % (ba)
    if parttype == 0:
        kappa = halo_data.gas_kappa_co[index]
        mass_galaxy = halo_data.log10_gas_mass[index]
        ac = halo_data.gas_axis_ca[index]
        cb = halo_data.gas_axis_cb[index]
        ba = halo_data.gas_axis_ba[index]
        title = r" $\kappa_{\mathrm{co}} = $%0.2f" % (kappa)
        title += " - $\log_{10}$ $M_{gas}/M_{\odot} = $%0.2f" % (mass_galaxy)
        title += " \n c/a = %0.2f," % (ac)
        title += " c/b = %0.2f," % (cb)
        title += " b/a = %0.2f" % (ba)
    ax.set_title(title)

    qv = QuickView(
        pos_edge_on,
        mass=mass,
        hsml=hsml_parts,
        logscale=True,
        plot=False,
        r="infinity",
        p=0,
        t=0,
        extent=[xmin, xmax, ymin, ymax],
        x=0,
        y=0,
        z=0,
    )
    img = qv.get_image()
    ext = qv.get_extent()
    ax.tick_params(labelleft=True, labelbottom=True, length=0)
    plt.xlabel("x [kpc]")
    plt.ylabel("z [kpc]")
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)
    img = get_normalized_image(img)
    ims = ax.imshow(img, cmap=cmap, extent=ext)
    ax.autoscale(False)

    cbar_ax = fig.add_axes([0.86, 0.22, 0.018, 0.5])
    cbar_ax.tick_params(labelsize=15)
    cb = plt.colorbar(ims, ticks=[4, 6, 8, 10, 12], cax=cbar_ax)
    cb.set_label(label=r"$\log_{10}$ $\Sigma$ [M$_{\odot}$/kpc$^{2}$]",
                 labelpad=0.5)

    if parttype == 0:
        outfile = f"{output_path}/galaxy_gas_%i_" % (
            index) + simulation_name + ".png"
    if parttype == 4:
        outfile = f"{output_path}/galaxy_stars_%i_" % (
            index) + simulation_name + ".png"
    fig.savefig(outfile, dpi=150)
    plt.close("all")

    return
Exemple #15
0
def create_scatter(
    snapshot: SWIFTDataset,
    halo: Halo,
    image: Image,
    projection: Projection,
    resolution: int,
) -> unyt_array:
    """
    Creates a projected image for a given image class, and snapshot.

    Parameters
    ----------

    snapshot: SWIFTDataset,
        The opened dataset.

    halo: Halo
        Halo with properties to visualise

    image: Image
        Image class to visualise this time around

    projection: Projection
        Which projection to make

    resolution: int
        Image size along each axis.

    Returns
    -------

    grid: unyt.unyt_array
        Output grid, in the requested units.
    """

    region_given_r = lambda r: [
        halo.position[0] - r,
        halo.position[0] + r,
        halo.position[1] - r,
        halo.position[1] + r,
        halo.position[2] - r,
        halo.position[2] + r,
    ]

    radius = image.get_radius(stellar_half_mass=halo.radius_100_kpc_star,
                              r_200_crit=halo.radius_200_crit)

    particle_data = getattr(snapshot, image.particle_type, "gas")

    region = region_given_r(radius)

    rotation_center = None
    rotation_matrix = None

    # If the L vector is poorly constrained this will complain,
    # but we don't really care.
    with np.testing.suppress_warnings() as sup:
        sup.filter(RuntimeWarning)
        if projection == Projection.EDGE_ON:
            rotation_center = halo.position.to(particle_data.coordinates.units)
            rotation_matrix = rotation_matrix_from_vector(halo.L.v, "y")
        elif projection == Projection.FACE_ON:
            rotation_center = halo.position.to(particle_data.coordinates.units)
            rotation_matrix = rotation_matrix_from_vector(halo.L.v, "z")

    if hasattr(particle_data, "smoothing_lengths"):
        backend = "fast"
    else:
        backend = "histogram"

    common_attributes = dict(
        data=particle_data,
        boxsize=snapshot.metadata.boxsize,
        resolution=resolution,
        region=region,
        mask=None,
        rotation_matrix=rotation_matrix,
        rotation_center=rotation_center,
        parallel=False,
        backend=backend,
    )

    mass_image = project_pixel_grid(project="masses", **common_attributes)

    if image.visualise == "projected_densities":
        # We're done!
        x_range = region[1] - region[0]
        y_range = region[3] - region[2]
        units = 1.0 / (x_range * y_range)
        units.convert_to_units(1.0 / (x_range.units * y_range.units))
        units *= particle_data.masses.units

        grid = unyt_array(mass_image, units=units)
    else:
        # Need to make the complementary image.
        cache_name = f"_CACHE_MASSWEIGHTED_{image.visualise}"
        cache = getattr(particle_data, cache_name, None)
        particle_array = getattr(particle_data, image.visualise)

        if cache is None:
            cache = particle_array * particle_data.masses

            setattr(
                particle_data,
                cache_name,
                cache,
            )

        weighted_image = project_pixel_grid(project=cache_name,
                                            **common_attributes)

        # Deal with zeroes:
        mass_image[mass_image == 0.0] = 1.0

        # K * 1e10 Msun -> K * Msun for the 'units' internally. So we need
        # to reconstruct the true ratio, although this should be ideally the
        # same as particle_array.units.
        units = cache.units / particle_data.masses.units

        grid = unyt_array(weighted_image / mass_image, units=units)

    # Fill if required
    output_units = None
    unit_steal = [image.output_units, image.vmin, image.vmax, grid]

    while output_units is None:
        potential_unit = unit_steal.pop(0)
        if potential_unit is not None:
            output_units = potential_unit.units

    grid.convert_to_units(output_units)

    if image.fill_below is not None:
        mask = grid < image.fill_below.to(output_units)
        grid[mask] = image.fill_below.to(output_units)

    return grid
Exemple #16
0
def render_luminosity_map(
    parts_data,
    luminosity,
    filtname,
    ang_momentum,
    halo_data,
    index,
    output_path,
    simulation_name,
):
    pos_parts = parts_data[:, 0:3].copy()

    face_on_rotation_matrix = rotation_matrix_from_vector(ang_momentum)
    edge_on_rotation_matrix = rotation_matrix_from_vector(ang_momentum,
                                                          axis="y")

    pos_face_on = np.matmul(face_on_rotation_matrix, pos_parts.T)
    pos_face_on = pos_face_on.T
    pos_edge_on = np.matmul(edge_on_rotation_matrix, pos_parts.T)
    pos_edge_on = pos_edge_on.T

    hsml_parts = parts_data[:, 7]

    r_limit = 5 * halo_data.half_mass_radius_star[index]
    r_img = 30.0
    if r_limit < r_img:
        r_img = r_limit
    xmin = -r_img
    ymin = -r_img
    xmax = r_img
    ymax = r_img

    rcParams.update(params)
    fig = plt.figure()
    ax = plt.subplot(1, 2, 1)

    ###### plot one side ########################
    qv = QuickView(
        pos_face_on,
        mass=luminosity,
        hsml=hsml_parts,
        logscale=True,
        plot=False,
        r="infinity",
        p=0,
        t=0,
        extent=[xmin, xmax, ymin, ymax],
        x=0,
        y=0,
        z=0,
    )
    img = qv.get_image()
    ext = qv.get_extent()
    ax.tick_params(labelleft=True, labelbottom=True, length=0)
    plt.xlabel("x [kpc]")
    plt.ylabel("y [kpc]")
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)
    img = get_normalized_image(img, vmin=img.max() - 2.3)
    ax.imshow(img, cmap="magma", extent=ext, vmin=img.max() - 2.3)
    ax.autoscale(False)

    ###### plot another side ########################
    ax = plt.subplot(1, 2, 2)
    qv = QuickView(
        pos_edge_on,
        mass=luminosity,
        hsml=hsml_parts,
        logscale=True,
        plot=False,
        r="infinity",
        p=90,
        t=0,
        extent=[xmin, xmax, ymin, ymax],
        x=0,
        y=0,
        z=0,
    )
    img = qv.get_image()
    ext = qv.get_extent()
    ax.tick_params(labelleft=True, labelbottom=True, length=0)
    plt.xlabel("x [kpc]")
    plt.ylabel("z [kpc]")
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)
    img = get_normalized_image(img, vmin=img.max() - 2.3)
    ims = ax.imshow(img, cmap="magma", vmin=img.max() - 2.3, extent=ext)
    ax.autoscale(False)

    cbar_ax = fig.add_axes([0.86, 0.22, 0.018, 0.5])
    cbar_ax.tick_params(labelsize=15)
    cb = plt.colorbar(ims, ticks=[4, 6, 8, 10, 12], cax=cbar_ax)
    cb.set_label(label=r"$\log_{10}$ $\Sigma$ [Jy/kpc$^{2}$]", labelpad=0.5)

    outfile = (f"{output_path}/galaxy_%s_map_%i_" % (filtname, index) +
               simulation_name + ".png")
    fig.savefig(outfile, dpi=150)
    plt.close("all")

    return
Exemple #17
0
    def process_single_halo(
            self,
            zoom_obj: Zoom = None,
            path_to_snap: str = None,
            path_to_catalogue: str = None,
            mask_radius: Tuple[float, str] = (6, 'r500'),
            map_centre: Union[str, list, np.ndarray] = 'vr_centre_of_potential',
            temperature_range: Optional[tuple] = None,
            depth_offset: Optional[float] = None,
            return_type: Union[type, str] = 'class',
            inscribe_mask: bool = False,
    ):
        sw_data, vr_data = self.get_handles_from_zoom(
            zoom_obj,
            path_to_snap,
            path_to_catalogue,
            mask_radius_r500=15,
        )

        map_centres_allowed = [
            'vr_centre_of_potential'
        ]

        if type(map_centre) is str and map_centre.lower() not in map_centres_allowed:
            raise AttributeError((
                f"String-commands for `map_centre` only support "
                f"`vr_centre_of_potential`. Got {map_centre} instead."
            ))
        elif (type(map_centre) is list or type(map_centre) is np.ndarray) and len(map_centre) != 3:
            raise AttributeError((
                f"List-commands for `map_centre` only support "
                f"length-3 lists. Got {map_centre} "
                f"(length {len(map_centre)}) instead."
            ))

        self.map_centre = map_centre

        centre_of_potential = [
            vr_data.positions.xcminpot[0].to('Mpc') / vr_data.a,
            vr_data.positions.ycminpot[0].to('Mpc') / vr_data.a,
            vr_data.positions.zcminpot[0].to('Mpc') / vr_data.a
        ]

        if self.map_centre == 'vr_centre_of_potential':
            _xCen = centre_of_potential[0]
            _yCen = centre_of_potential[1]
            _zCen = centre_of_potential[2]

        elif type(self.map_centre) is list or type(self.map_centre) is np.ndarray:
            _xCen = self.map_centre[0] * Mpc / vr_data.a
            _yCen = self.map_centre[1] * Mpc / vr_data.a
            _zCen = self.map_centre[2] * Mpc / vr_data.a

        if xlargs.debug:
            print(f"Centre of potential: {[float(f'{i.v:.3f}') for i in centre_of_potential]} Mpc")
            print(f"Map centre: {[float(f'{i.v:.3f}') for i in [_xCen, _yCen, _zCen]]} Mpc")

        self.depth = _zCen / sw_data.metadata.boxsize[0]

        if depth_offset is not None:
            self.depth += depth_offset * Mpc / sw_data.metadata.boxsize[0]

            if xlargs.debug:
                percent = f"{depth_offset * Mpc / _zCen * 100:.1f}"
                print((
                    f"Imposing offset in slicing depth: {depth_offset:.2f} Mpc.\n"
                    f"Percentage shift compared to centre: {percent} %"
                ))

        _r500 = vr_data.spherical_overdensities.r_500_rhocrit[0].to('Mpc') / vr_data.a

        if mask_radius[1] == 'r500':
            mask_radius_r500 = mask_radius[0] * _r500
        else:
            mask_radius_r500 = unyt_quantity(mask_radius[0], units=mask_radius[1])

        if inscribe_mask:
            mask_radius_r500 /= np.sqrt(3)

        region = [
            _xCen - mask_radius_r500,
            _xCen + mask_radius_r500,
            _yCen - mask_radius_r500,
            _yCen + mask_radius_r500
        ]

        if temperature_range is not None:

            temp_filter = np.where(
                (sw_data.gas.temperatures > temperature_range[0]) &
                (sw_data.gas.temperatures < temperature_range[1])
            )[0]

            if xlargs.debug:
                percent = f"{len(temp_filter) / len(sw_data.gas.temperatures) * 100:.1f}"
                print((
                    f"Filtering particles by temperature: {temperature_range} K.\n"
                    f"Total particles: {len(sw_data.gas.temperatures)}\n"
                    f"Particles within bounds: {len(temp_filter)} = {percent} %"
                ))

            sw_data.gas.coordinates = sw_data.gas.coordinates[temp_filter]
            sw_data.gas.smoothing_lengths = sw_data.gas.smoothing_lengths[temp_filter]
            sw_data.gas.masses = sw_data.gas.masses[temp_filter]
            sw_data.gas.densities = sw_data.gas.densities[temp_filter]
            sw_data.gas.temperatures = sw_data.gas.temperatures[temp_filter]

        # Rotate about CoP if required
        center = [_xCen, _yCen, _zCen]
        rotate_vec = [0, 0, 1]
        matrix = rotation_matrix_from_vector(rotate_vec, axis='z')

        common_kwargs = dict(
            rotation_matrix=matrix,
            rotation_center=center,
            data=sw_data,
            resolution=self.resolution,
            parallel=self.parallel,
            region=region,
            slice=self.depth
        )

        if self._project_quantity == 'entropies':
            number_density = (sw_data.gas.densities / mh).to('cm**-3') / mean_molecular_weight
            entropy = kb * sw_data.gas.temperatures / number_density ** (2 / 3)
            sw_data.gas.entropies_physical = entropy.to('keV*cm**2')

            gas_map = slice_gas(project='entropies_physical', **common_kwargs).to('keV*cm**2/Mpc**3')

        elif self._project_quantity == 'temperatures':
            sw_data.gas.mwtemps = sw_data.gas.masses * sw_data.gas.temperatures

            mass_weighted_temp_map = slice_gas(project='mwtemps', **common_kwargs)
            mass_map = slice_gas(project='masses', **common_kwargs)

            with np.errstate(divide='ignore', invalid='ignore'):
                gas_map = mass_weighted_temp_map / mass_map

            gas_map = gas_map.to('K')

        else:
            gas_map = slice_gas(project=self._project_quantity, **common_kwargs)

        units = gas_map.units
        gas_map = gas_map.value

        gas_map = np.ma.array(
            gas_map,
            mask=(gas_map <= 0.),
            fill_value=np.nan,
            copy=True,
            dtype=np.float64
        )

        output_values = [
            gas_map,
            region,
            units,
            [_xCen, _yCen, _zCen],
            _r500,
            sw_data.metadata.z
        ]
        output_names = [
            'map',
            'region',
            'units',
            'centre',
            'r500',
            'z'
        ]
        if return_type is tuple:
            output = tuple(output_values)
        elif return_type is dict:
            output = dict(zip(output_names, output_values))
        elif return_type == 'class':
            OutputClass = namedtuple('OutputClass', output_names)
            output = OutputClass(*output_values)
        else:
            raise TypeError(f"Return type {return_type} not recognised.")

        return output