Example #1
0
def visualise_halo(
    output_path: Path,
    snapshot_path: Path,
    config: ImageConfig,
    halo: Halo,
):
    """
    Creates all of the visualisations in the config for the
    specified halo, and saves them to disk.

    Parameters
    ----------

    output_path: Path, str
        Output path to save images to. Inside this path, there will be
        a number of directories created (one per halo). This path must
        already exist.

    snapshot_path: Path,
        Path to the snapshot. For a sufficiently large volume, and
        a sufficiently small number of haloes, there will be little-to
        -no overlap in the read regions.

    config: ImageConfig
        Opened configuration file.

    halo: Halo
        The halo to read the data for and visualise.
    """

    # First need to find the maximum radius, amongst any
    # of the images.
    radii = [
        image.get_radius(stellar_half_mass=halo.radius_100_kpc_star,
                         r_200_crit=halo.radius_200_crit)
        for image in config.images
    ]

    max_radius = max(radii)

    extent_given_r = lambda r: [[halo.position[x] - r, halo.position[x] + r]
                                for x in range(3)]

    halo_mask = mask(filename=snapshot_path, spatial_only=True)
    halo_mask.constrain_spatial(restrict=extent_given_r(max_radius))

    data = load(filename=snapshot_path, mask=halo_mask)

    # Generate the smoothing lengths if required.
    if config.calculate_dark_matter_smoothing_lengths:
        data.dark_matter.smoothing_lengths = generate_smoothing_lengths(
            coordinates=data.dark_matter.coordinates,
            boxsize=data.metadata.boxsize,
            kernel_gamma=kernel_gamma,
        )

    if config.recalculate_stellar_smoothing_lengths and hasattr(data, "stars"):
        if len(data.stars.coordinates) > 0:
            data.stars.smoothing_lengths = generate_smoothing_lengths(
                coordinates=data.stars.coordinates,
                boxsize=data.metadata.boxsize,
                kernel_gamma=kernel_gamma,
            )

    halo_directory = output_path / f"halo_{halo.unique_id}"
    halo_directory.mkdir(exist_ok=True)

    for image in config.images:
        # Which projections should we make?
        projections = [Projection.DEFAULT]

        if image.face_on:
            projections.append(Projection.FACE_ON)

        if image.edge_on:
            projections.append(Projection.EDGE_ON)

        for projection in projections:
            scatter = create_scatter(
                snapshot=data,
                halo=halo,
                image=image,
                projection=projection,
                resolution=config.resolution,
            )

            save_figure_from_scatter(
                scatter=scatter,
                config=config,
                halo=halo,
                image=image,
                projection=projection,
                output_path=halo_directory,
            )

            if (projection == Projection.DEFAULT
                    and image.base_name == config.thumbnail_image):
                save_thumbnail_from_scatter(
                    scatter=scatter,
                    config=config,
                    halo=halo,
                    image=image,
                    projection=projection,
                    output_path=halo_directory,
                )
Example #2
0
def density_profile_compare_plot(
        run_name: str,
        snap_filepath_parent: str = None,
        velociraptor_properties_parent: str = None,
        snap_filepath_zoom: List[str] = None,
        velociraptor_properties_zoom: List[str] = None,
        output_directory: str = None) -> None:
    """
    This function compares the density profiles of DMO zooms to their
    corresponding parent halo. It also allows to assess numerical
    convergence by overlapping multiple profiles from zooms with different
    resolutions. The density profiles are then listed in the legend,
    where the DM particle mass is quoted.
    The zoom inputs are in the form of arrays of strings, to allow
    for multiple entries. Each entry is a zoom snap/VR output resolution.
    The function allows not to plot either the parent density profile
    or the zooms. At least one of them must be entered.

    :param run_name: str
        A custom and identifiable name for the run. Currently the standard
        name follows the scheme {AUTHOR_INITIALS}{HALO_ID}, e.g. SK0 or EA1.
        This argument must be defined.
    :param snap_filepath_parent: str
        The complete path to the snapshot of the parent box.
        If parameter is None, the density ptofile of the parent box is not
        displayed.
    :param snap_filepath_zoom: list(str)
        The list of complete paths to the snapshots of the zooms
        at different resolution. Note: the order must match that of
        the `velociraptor_properties_zoom` parameter. If parameter
        is None, the density ptofile of the zoom is not displayed and the
        `velociraptor_properties_zoom` parameter is ignored.
    :param velociraptor_properties_zoom: list(str)
        The list of complete paths to the VR outputs (properties) of the
        zooms at different resolution. Note: the order must match that of
        the `snap_filepath_zoom` parameter. If `snap_filepath_zoom` is None,
        then this parameter is ignored. If this parameter is None and
        `snap_filepath_zoom` is defined, raises an error.
    :param output_directory: str
        The output directory where to save the plot. This code assumes
        that the output directory exists. If it does not exist, matplotlib
        will return an error. This argument must be defined.
    :return: None
    """

    # ARGS CHECK #
    assert snap_filepath_parent or snap_filepath_zoom
    if snap_filepath_zoom and velociraptor_properties_zoom:
        assert len(snap_filepath_zoom) == len(velociraptor_properties_zoom)
    elif not snap_filepath_zoom:
        velociraptor_properties_zoom = None
    elif snap_filepath_zoom and not velociraptor_properties_zoom:
        raise ValueError
    assert output_directory

    fig, (ax,
          ax_residual) = plt.subplots(nrows=2,
                                      ncols=1,
                                      figsize=(7, 8),
                                      dpi=resolution // 8,
                                      sharex=True,
                                      gridspec_kw={'height_ratios': [3, 1]})

    # PARENT #
    if snap_filepath_parent:

        # Rendezvous over parent VR catalogue using zoom information
        with h5py.File(velociraptor_properties_zoom[0], 'r') as vr_file:

            idx, M200c, R200c, Xcminpot, Ycminpot, Zcminpot = find_object(
                vr_properties_catalog=velociraptor_properties_parent,
                sample_structType=10,
                sample_mass_lower_lim=vr_file['/Mass_200crit'][0] * 1e10 * 0.8,
                sample_x=vr_file['/Xcminpot'][0],
                sample_y=vr_file['/Ycminpot'][0],
                sample_z=vr_file['/Zcminpot'][0],
            )

            M200c = unyt.unyt_quantity(M200c, unyt.Solar_Mass)
            R200c = unyt.unyt_quantity(R200c, unyt.Mpc)
            xCen = unyt.unyt_quantity(Xcminpot, unyt.Mpc)
            yCen = unyt.unyt_quantity(Ycminpot, unyt.Mpc)
            zCen = unyt.unyt_quantity(Zcminpot, unyt.Mpc)

        # Construct spatial mask to feed into swiftsimio
        size = radius_bounds[1] * R200c
        mask = sw.mask(snap_filepath_parent)
        region = [[xCen - size, xCen + size], [yCen - size, yCen + size],
                  [zCen - size, zCen + size]]
        mask.constrain_spatial(region)
        data = sw.load(snap_filepath_parent, mask=mask)

        # Get DM particle coordinates and compute radial distance from CoP in R200 units
        posDM = data.dark_matter.coordinates / data.metadata.a

        r = np.sqrt(
            wrap(posDM[:, 0] - xCen, data.metadata.boxsize[0])**2 +
            wrap(posDM[:, 1] - yCen, data.metadata.boxsize[1])**2 +
            wrap(posDM[:, 2] - zCen, data.metadata.boxsize[2])**2)

        # Calculate particle mass and rho_crit
        unitLength = data.metadata.units.length
        unitMass = data.metadata.units.mass
        rho_crit = unyt.unyt_quantity(
            data.metadata.cosmology_raw['Critical density [internal units]'],
            unitMass / unitLength**3).to('Msun/Mpc**3')
        rhoMean = rho_crit * data.metadata.cosmology.Om0
        vol = data.metadata.boxsize[0]**3
        numPart = data.metadata.n_dark_matter
        particleMass = rhoMean * vol / numPart
        parent_mass_resolution = particleMass
        particleMasses = np.ones_like(r.value) * particleMass

        # Construct bins and compute density profile
        # NOTE: numpy.histogram does not preserve units, so restore them after.
        lbins = np.logspace(np.log10(radius_bounds[0]),
                            np.log10(radius_bounds[1]), bins)
        r_scaled = r / R200c
        hist, bin_edges = np.histogram(r_scaled,
                                       bins=lbins,
                                       weights=particleMasses)
        hist *= unyt.Solar_Mass
        bin_centre = np.sqrt(bin_edges[1:] * bin_edges[:-1])
        volume_shell = (4. * np.pi / 3.) * (R200c**3) * ((bin_edges[1:])**3 -
                                                         (bin_edges[:-1])**3)
        densities_parent = hist / volume_shell / rho_crit

        # Plot density profile for each selected halo in volume
        densities_parent[densities_parent == 0] = np.nan
        parent_label = (
            f'Parent: $m_\\mathrm{{DM}} = {latex_float(parent_mass_resolution.value[0])}\\ '
            f'{parent_mass_resolution.units.latex_repr}$')
        ax.plot(bin_centre,
                densities_parent,
                c="grey",
                linestyle="-",
                label=parent_label)

        # Compute convergence radius
        conv_radius = convergence_radius(r, particleMasses, rho_crit) / R200c
        ax.axvline(conv_radius, color='grey', linestyle='--')
        ax_residual.axvline(conv_radius, color='grey', linestyle='--')
        t = ax.text(conv_radius,
                    ax.get_ylim()[1],
                    'Convergence radius',
                    ha='center',
                    va='top',
                    rotation='vertical',
                    alpha=0.6)
        t.set_bbox(dict(facecolor='white', alpha=0.6, edgecolor='none'))

    # ZOOMS #
    if snap_filepath_zoom:

        # Set-up colors
        cmap_discrete = plt.cm.get_cmap(cmap_name,
                                        len(velociraptor_properties_zoom) + 3)
        cmaplist = [cmap_discrete(i) for i in range(cmap_discrete.N)]

        for snap_path, vrprop_path, color in zip(snap_filepath_zoom,
                                                 velociraptor_properties_zoom,
                                                 cmaplist):

            # Load velociraptor data
            with h5py.File(vrprop_path, 'r') as vr_file:
                M200c = vr_file['/Mass_200crit'][0] * 1e10
                R200c = vr_file['/R_200crit'][0]
                Xcminpot = vr_file['/Xcminpot'][0]
                Ycminpot = vr_file['/Ycminpot'][0]
                Zcminpot = vr_file['/Zcminpot'][0]

            M200c = unyt.unyt_quantity(M200c, unyt.Solar_Mass)
            R200c = unyt.unyt_quantity(R200c, unyt.Mpc)
            xCen = unyt.unyt_quantity(Xcminpot, unyt.Mpc)
            yCen = unyt.unyt_quantity(Ycminpot, unyt.Mpc)
            zCen = unyt.unyt_quantity(Zcminpot, unyt.Mpc)

            # Construct spatial mask to feed into swiftsimio
            size = radius_bounds[1] * R200c
            mask = sw.mask(snap_path)
            region = [[xCen - size, xCen + size], [yCen - size, yCen + size],
                      [zCen - size, zCen + size]]
            mask.constrain_spatial(region)
            data = sw.load(snap_path, mask=mask)

            # Get DM particle coordinates and compute radial distance from CoP in R200 units
            posDM = data.dark_matter.coordinates / data.metadata.a

            r = np.sqrt(
                wrap(posDM[:, 0] - xCen, data.metadata.boxsize[0])**2 +
                wrap(posDM[:, 1] - yCen, data.metadata.boxsize[1])**2 +
                wrap(posDM[:, 2] - zCen, data.metadata.boxsize[2])**2)

            # Calculate particle mass and rho_crit
            unitLength = data.metadata.units.length
            unitMass = data.metadata.units.mass
            rho_crit = unyt.unyt_quantity(
                data.metadata.
                cosmology_raw['Critical density [internal units]'],
                unitMass / unitLength**3).to('Msun/Mpc**3')
            particleMasses = data.dark_matter.masses.to('Msun')
            zoom_mass_resolution = particleMasses

            # Construct bins and compute density profile
            # NOTE: numpy.histogram does not preserve units, so restore them after.
            lbins = np.logspace(np.log10(radius_bounds[0]),
                                np.log10(radius_bounds[1]), bins)
            r_scaled = r / R200c
            hist, bin_edges = np.histogram(r_scaled,
                                           bins=lbins,
                                           weights=particleMasses)
            hist *= unyt.Solar_Mass
            bin_centre = np.sqrt(bin_edges[1:] * bin_edges[:-1])
            volume_shell = (4. * np.pi / 3.) * (R200c**3) * (
                (bin_edges[1:])**3 - (bin_edges[:-1])**3)
            densities_zoom = hist / volume_shell / rho_crit

            # Plot density profile for each selected halo in volume
            densities_zoom[densities_zoom == 0] = np.nan
            zoom_label = (
                f'Zoom: $m_\\mathrm{{DM}} = {latex_float(zoom_mass_resolution.value[0])}\\ '
                f'{zoom_mass_resolution.units.latex_repr}$')
            ax.plot(bin_centre,
                    densities_zoom,
                    c=color,
                    linestyle="-",
                    label=zoom_label)

            # Compute convergence radius
            conv_radius = convergence_radius(r, particleMasses,
                                             rho_crit) / R200c
            ax.axvline(conv_radius, color=color, linestyle='--')
            t = ax.text(conv_radius,
                        ax.get_ylim()[1],
                        'Convergence radius',
                        ha='center',
                        va='top',
                        rotation='vertical',
                        alpha=0.5)
            t.set_bbox(dict(facecolor='white', alpha=0.6, edgecolor='none'))

            # RESIDUALS #
            if snap_filepath_parent and snap_filepath_zoom:
                residual = (densities_zoom -
                            densities_parent) / densities_parent
                ax_residual.axhline(0, color='grey', linestyle='-')
                ax_residual.plot(bin_centre, residual, c=color, linestyle="-")
                ax_residual.axvline(conv_radius, color=color, linestyle='--')

    ax.text(
        0.025,
        0.025,
        (f"Halo {run_name:s} DMO\n"
         f"$z={data.metadata.z:3.3f}$\n"
         "Zoom VR output:\n"
         f"$M_{{200c}}={latex_float(M200c.value)}\\ {M200c.units.latex_repr}$\n"
         f"$R_{{200c}}={latex_float(R200c.value)}\\ {R200c.units.latex_repr}$"
         ),
        color="black",
        ha="left",
        va="bottom",
        backgroundcolor='white',
        alpha=0.5,
        transform=ax.transAxes,
    )

    ax.axvline(1, color="grey", linestyle='--')
    ax_residual.axvline(1, color="grey", linestyle='--')
    ax_residual.set_xlim(radius_bounds[0], radius_bounds[1])
    ax_residual.set_ylim(residual_bounds[0], residual_bounds[1])
    ax.set_xscale('log')
    ax.set_yscale('log')
    ax.set_ylabel(r"$\rho_{DM}\ /\ \rho_c$")
    ax_residual.set_ylabel(f"$\\Delta \\rho\\ /\\ \\rho_{{\\rm parent}}$")
    ax_residual.set_xlabel(r"$R\ /\ R_{200c}$")
    ax.legend(loc="upper right")
    fig.tight_layout()
    fig.savefig(f"{output_directory}/{run_name}_density_profile_compare.png")
    plt.close(fig)
    print(f"Saved: {output_directory}/{run_name}_density_profile_compare.png")
    plt.close('all')

    return
Example #3
0
plt.style.use(arguments.stylesheet_location)

simulation_lines = []
simulation_labels = []

fig, ax = plt.subplots()

ax.loglog()

for snapshot_filename, stats_filename, name in zip(snapshot_filenames,
                                                   stats_filenames, names):

    data = load_statistics(stats_filename)

    snapshot = load(snapshot_filename)
    boxsize = snapshot.metadata.boxsize.to("Mpc")
    box_volume = boxsize[0] * boxsize[1] * boxsize[2]

    # a, Redshift, BH mass
    scale_factor = data.a
    redshift = data.z
    bh_mass = data.bh_mass.to("Msun")
    bh_mass_density = bh_mass / box_volume

    # High z-order as we always want these to be on top of the observations
    simulation_lines.append(
        ax.plot(scale_factor, bh_mass_density, zorder=10000)[0])
    simulation_labels.append(name)

# Observational data plotting
def single_frame(num, max_pixel, nframes):

    snap = "%04d" % num

    # Define path
    path = '/cosma/home/dp004/dc-rope1/cosma7/SWIFT/hydro_1380_ani/data/ani_hydro_' + snap + ".hdf5"

    snap = "%05d" % num

    data = load(path)

    meta = data.metadata
    boxsize = meta.boxsize[0]
    z = meta.redshift

    print(boxsize, z)
    print("Physical Box Size:", boxsize / (1 + z))
    print("Boxes in frame:", (1 + z))

    # Define centre
    cent = np.array([boxsize / 2, boxsize / 2, boxsize / 2])

    # Define targets
    targets = [[0, 0, 0], ]

    # Define anchors dict for camera parameters
    anchors = {}
    anchors['sim_times'] = [0.0, 'same', 'same', 'same', 'same', 'same', 'same', 'same']
    anchors['id_frames'] = np.linspace(0, nframes, 8, dtype=int)
    anchors['id_targets'] = [0, 'same', 'same', 'same', 'same', 'same', 'same', 'same']
    anchors['r'] = [10, 'same', 'same', 'same', 'same', 'same', 'same', 'same']
    anchors['t'] = [10, 'same', 'same', 'same', 'same', 'same', 'same', 'same']
    anchors['p'] = [-20, 'same', 'same', 'same', 'same', 'same', 'same', 'same']
    anchors['zoom'] = [1., 'same', 'same', 'same', 'same', 'same', 'same', 'same']
    anchors['extent'] = [1, 'same', 'same', 'same', 'same', 'same', 'same', 'same']

    # Define the camera trajectory
    cam_data = camera_tools.get_camera_trajectory(targets, anchors)

    poss = data.dark_matter.coordinates.value
    hsmls = data.dark_matter.softenings.value / (1 + z)

    poss -= cent

    poss[np.where(poss > boxsize.value / 2)] -= boxsize.value
    poss[np.where(poss < - boxsize.value / 2)] += boxsize.value

    poss /= (1 + z)

    wrapped_boxes = int(np.ceil(1 + z))
    if wrapped_boxes < 5:
        wrapped_boxes = 5
    elif wrapped_boxes % 2 == 0:
        wrapped_boxes += 1
    half_wrapped_boxes = int(wrapped_boxes / 2)
    wrapped_poss = np.zeros((poss.shape[0] * wrapped_boxes ** 3, 3), dtype=np.float64)
    wrapped_hsmls = np.zeros(poss.shape[0] * wrapped_boxes ** 3, dtype=np.float64)
    print(wrapped_poss.shape[0]**(1/3))
    n = 0
    for i in range(-half_wrapped_boxes, half_wrapped_boxes + 1, 1):
        for j in range(-half_wrapped_boxes, half_wrapped_boxes + 1, 1):
            for k in range(-half_wrapped_boxes, half_wrapped_boxes + 1, 1):
                wrapped_poss[poss.shape[0] * n: poss.shape[0] * (n + 1), :] = poss + np.array([i * boxsize / (1 + z), j * boxsize / (1 + z), k * boxsize / (1 + z)])
                wrapped_hsmls[poss.shape[0] * n: poss.shape[0] * (n + 1)] = hsmls
                n += 1

    print(np.min(wrapped_poss, axis=0) * (1 + z), np.max(wrapped_poss, axis=0) * (1 + z))
    print(np.min(wrapped_poss, axis=0) * (1 + z) / boxsize,
          np.max(wrapped_poss, axis=0) * (1 + z) / boxsize)

    # Get images
    cmap = cmr.apple
    rgb_DM_box, ang_extent = getimage(cam_data, poss, hsmls, num, z, cmap)
    cmap = cmr.neutral
    rgb_DM_wrapped, ang_extent = getimage(cam_data, wrapped_poss,
                                          wrapped_hsmls, num, z, cmap)
    i = cam_data[num]
    extent = [0, 2 * np.tan(ang_extent[1]) * i['r'],
              0, 2 * np.tan(ang_extent[-1]) * i['r']]
    print(ang_extent, extent)

    blend = Blend.Blend(rgb_DM_wrapped, rgb_DM_box)
    rgb_DM = blend.Overlay()

    dpi = rgb_DM.shape[0]
    print(dpi, rgb_DM.shape)
    fig = plt.figure(figsize=(1, 1.77777777778), dpi=dpi)
    ax = fig.add_subplot(111)

    ax.imshow(rgb_DM, extent=ang_extent, origin='lower')
    ax.tick_params(axis='both', left=False, top=False, right=False,
                   bottom=False, labelleft=False,
                   labeltop=False, labelright=False, labelbottom=False)

    ax.text(0.975, 0.05, "$t=$%.1f Gyr" % cosmo.age(z).value,
            transform=ax.transAxes, verticalalignment="top",
            horizontalalignment='right', fontsize=1, color="w")

    ax.plot([0.05, 0.15], [0.025, 0.025], lw=0.1, color='w', clip_on=False,
            transform=ax.transAxes)

    ax.plot([0.05, 0.05], [0.022, 0.027], lw=0.15, color='w', clip_on=False,
            transform=ax.transAxes)
    ax.plot([0.15, 0.15], [0.022, 0.027], lw=0.15, color='w', clip_on=False,
            transform=ax.transAxes)

    ax.plot([0.05, 0.15], [0.105, 0.105], lw=0.1, color='w', clip_on=False,
            transform=ax.transAxes)

    ax.plot([0.05, 0.05], [0.102, 0.107], lw=0.15, color='w', clip_on=False,
            transform=ax.transAxes)
    ax.plot([0.15, 0.15], [0.102, 0.107], lw=0.15, color='w', clip_on=False,
            transform=ax.transAxes)

    axis_to_data = ax.transAxes + ax.transData.inverted()
    left = axis_to_data.transform((0.05, 0.075))
    right = axis_to_data.transform((0.15, 0.075))
    dist = extent[1] * (right[0] - left[0]) / (ang_extent[1] - ang_extent[0])

    print(left, right,
          (right[0] - left[0]) / (ang_extent[1] - ang_extent[0]), dist)

    if dist > 0.1:
        ax.text(0.1, 0.145, "%.1f cMpc" % (dist * (1 + z)),
                transform=ax.transAxes, verticalalignment="top",
                horizontalalignment='center', fontsize=1, color="w")
        ax.text(0.1, 0.065, "%.1f pMpc" % dist,
                transform=ax.transAxes, verticalalignment="top",
                horizontalalignment='center', fontsize=1, color="w")
    elif 100 > dist * 10**3 > 1:
        ax.text(0.1, 0.065, "%.1f pkpc" % dist * 10**3,
                transform=ax.transAxes, verticalalignment="top",
                horizontalalignment='center', fontsize=1, color="w")
    else:
        ax.text(0.1, 0.065, "%.1f pkpc" % dist * 10**6,
                transform=ax.transAxes, verticalalignment="top",
                horizontalalignment='center', fontsize=1, color="w")

    plt.margins(0, 0)

    fig.savefig('plots/Ani/Physical/DMphysical_animation_wrapped_' + snap + '.png',
                bbox_inches='tight', pad_inches=0)
    plt.close(fig)
Example #5
0
"""
Makes an image of snapshot 175.
"""

from swiftsimio import load
from swiftsimio.visualisation import project_gas_pixel_grid, scatter

import numpy as np

import matplotlib.pyplot as plt
from matplotlib.colors import Normalize

data = load("kelvinHelmholtz_0175.hdf5")

resolution = 1024
n_streamline = 512

grid = project_gas_pixel_grid(data, resolution)

sub_mask_velocity = 1024 * 2
x, y, _ = data.gas.coordinates[:].value.T
u, v, _ = data.gas.velocities[:].value.T
h = data.gas.smoothing_lengths.value

u_grid = scatter(x, y, u, h, resolution * 2).T
v_grid = scatter(x, y, v, h, resolution * 2).T
x = np.linspace(0, 1, resolution * 2)
y = np.linspace(0, 1, resolution * 2)

speed = np.sqrt(u_grid * u_grid + v_grid * v_grid)
def single_frame(num, max_pixel, nframes):

    snap = "%04d" % num

    # Define path
    path = '/cosma/home/dp004/dc-rope1/cosma7/SWIFT/hydro_1380/data/ani_hydro_' + snap + ".hdf5"

    snap = "%05d" % num

    data = load(path)

    meta = data.metadata
    boxsize = meta.boxsize[0]
    z = meta.redshift

    print(boxsize)

    # Define targets
    targets = [[boxsize / 2, boxsize / 2, boxsize / 2]]

    # Define anchors dict for camera parameters
    anchors = {}
    anchors['sim_times'] = [
        0.0, 'same', 'same', 'same', 'same', 'same', 'same', 'same'
    ]
    anchors['id_frames'] = np.linspace(0, nframes, 8, dtype=int)
    anchors['id_targets'] = [
        0, 'same', 'same', 'same', 'same', 'same', 'same', 'same'
    ]
    anchors['r'] = [
        boxsize.value + 5, 'same', 'same', 'same', 'same', 'same', 'same',
        'same'
    ]
    anchors['t'] = [5, 'same', 'same', 'same', 'same', 'same', 'same', 'same']
    anchors['p'] = [0, 'pass', 'pass', 'pass', 'pass', 'pass', 'pass', -360]
    anchors['zoom'] = [
        1., 'same', 'same', 'same', 'same', 'same', 'same', 'same'
    ]
    anchors['extent'] = [
        10, 'same', 'same', 'same', 'same', 'same', 'same', 'same'
    ]

    # Define the camera trajectory
    cam_data = camera_tools.get_camera_trajectory(targets, anchors)

    # Get colormap
    # cmap = cmaps.sunlight()
    cmap = ml.cm.magma

    poss = data.gas.coordinates.value
    hsmls = data.gas.smoothing_lengths.value

    # Get images
    rgb_gas, extent = getimage(cam_data,
                               poss,
                               hsmls,
                               num,
                               max_pixel,
                               cmap,
                               Type="gas")

    # Get colormap
    cmap = ml.cm.Greys_r

    poss = data.dark_matter.coordinates.value
    hsmls = data.dark_matter.softenings.value

    # Get images
    rgb_dm, extent = getimage(cam_data,
                              poss,
                              hsmls,
                              num,
                              max_pixel,
                              cmap,
                              Type="dm")

    blend = Blend.Blend(rgb_dm, rgb_gas)
    rgb_output = blend.Overlay()

    fig = plt.figure(figsize=(4, 4))
    ax = fig.add_subplot(111)

    ax.imshow(rgb_output, extent=extent, origin='lower')
    ax.tick_params(axis='both',
                   left=False,
                   top=False,
                   right=False,
                   bottom=False,
                   labelleft=False,
                   labeltop=False,
                   labelright=False,
                   labelbottom=False)

    ax.text(0.9,
            0.9,
            "%.3f Gyrs" % cosmo.age(z).value,
            bbox=dict(boxstyle="round,pad=0.3",
                      fc='w',
                      ec="k",
                      lw=1,
                      alpha=0.8),
            transform=ax.transAxes,
            horizontalalignment='right',
            fontsize=8)

    fig.savefig('plots/Ani/DMGas_animation_' + snap + '.png',
                bbox_inches='tight',
                dpi=300)
    plt.close(fig)
def contamination_map(run_name: str,
                      velociraptor_properties_zoom: str,
                      snap_filepath_zoom: str,
                      out_to_radius: Tuple[int, str] = (5, 'r200c'),
                      highres_radius: Tuple[int, str] = (6, 'r500c'),
                      output_directory: str = '.') -> None:
    # Rendezvous over parent VR catalogue using zoom information
    with h5py.File(velociraptor_properties_zoom, 'r') as vr_file:
        M200c = unyt.unyt_quantity(vr_file['/Mass_200crit'][0] * 1e10,
                                   unyt.Solar_Mass)
        R200c = unyt.unyt_quantity(vr_file['/R_200crit'][0], unyt.Mpc)
        R500c = unyt.unyt_quantity(vr_file['/SO_R_500_rhocrit'][0], unyt.Mpc)
        xCen = unyt.unyt_quantity(vr_file['/Xcminpot'][0], unyt.Mpc)
        yCen = unyt.unyt_quantity(vr_file['/Ycminpot'][0], unyt.Mpc)
        zCen = unyt.unyt_quantity(vr_file['/Zcminpot'][0], unyt.Mpc)

    # EAGLE-XL data path
    print(f"Rendering {snap_filepath_zoom}...")

    if out_to_radius[1] == 'r200c':
        size = out_to_radius[0] * R200c
    elif out_to_radius[1] == 'r500c':
        size = out_to_radius[0] * R500c
    elif out_to_radius[1] == 'Mpc' or out_to_radius[1] is None:
        size = unyt.unyt_quantity(out_to_radius[0], unyt.Mpc)
    else:
        raise ValueError(
            "The `out_to_radius` input is not in the correct format or not recognised."
        )

    if highres_radius[1] == 'r200c':
        _highres_radius = highres_radius[0] * R200c
    elif highres_radius[1] == 'r500c':
        _highres_radius = highres_radius[0] * R500c
    elif highres_radius[1] == 'Mpc' or highres_radius[1] is None:
        _highres_radius = unyt.unyt_quantity(highres_radius[0], unyt.Mpc)
    else:
        raise ValueError(
            "The `highres_radius` input is not in the correct format or not recognised."
        )

    mask = sw.mask(snap_filepath_zoom)
    region = [[xCen - size, xCen + size], [yCen - size, yCen + size],
              [zCen - size, zCen + size]]
    mask.constrain_spatial(region)

    # Load data using mask
    data = sw.load(snap_filepath_zoom, mask=mask)
    posDM = data.dark_matter.coordinates / data.metadata.a
    highres_coordinates = {
        'x':
        wrap(posDM[:, 0] - xCen, data.metadata.boxsize[0]),
        'y':
        wrap(posDM[:, 1] - yCen, data.metadata.boxsize[1]),
        'z':
        wrap(posDM[:, 2] - zCen, data.metadata.boxsize[2]),
        'r':
        np.sqrt(
            wrap(posDM[:, 0] - xCen, data.metadata.boxsize[0])**2 +
            wrap(posDM[:, 1] - yCen, data.metadata.boxsize[1])**2 +
            wrap(posDM[:, 2] - zCen, data.metadata.boxsize[2])**2)
    }
    del posDM
    posDM = data.boundary.coordinates / data.metadata.a
    lowres_coordinates = {
        'x':
        wrap(posDM[:, 0] - xCen, data.metadata.boxsize[0]),
        'y':
        wrap(posDM[:, 1] - yCen, data.metadata.boxsize[1]),
        'z':
        wrap(posDM[:, 2] - zCen, data.metadata.boxsize[2]),
        'r':
        np.sqrt(
            wrap(posDM[:, 0] - xCen, data.metadata.boxsize[0])**2 +
            wrap(posDM[:, 1] - yCen, data.metadata.boxsize[1])**2 +
            wrap(posDM[:, 2] - zCen, data.metadata.boxsize[2])**2)
    }
    del posDM

    # Flag contamination particles within 5 R200
    contaminated_idx = np.where(lowres_coordinates['r'] < _highres_radius)[0]
    contaminated_r200_idx = np.where(lowres_coordinates['r'] < 1. * R200c)[0]
    print(
        f"Total low-res DM: {len(lowres_coordinates['r'])} particles detected")
    print(
        f"Contaminating low-res DM (< R_clean): {len(contaminated_idx)} particles detected"
    )
    print(
        f"Contaminating low-res DM (< r200c): {len(contaminated_r200_idx)} particles detected"
    )

    # Make particle maps
    fig, ax = plt.subplots(figsize=(7, 7), dpi=1024 // 7)

    ax.set_aspect('equal')
    ax.set_ylabel(r"$y$ [Mpc]")
    ax.set_xlabel(r"$x$ [Mpc]")

    ax.plot(highres_coordinates['x'][::4],
            highres_coordinates['y'][::4],
            ',',
            c="C0",
            alpha=0.1,
            label='Highres')
    ax.plot(lowres_coordinates['x'][contaminated_idx],
            lowres_coordinates['y'][contaminated_idx],
            'x',
            c="red",
            alpha=1,
            label='Lowres contaminating')
    ax.plot(lowres_coordinates['x'][~contaminated_idx],
            lowres_coordinates['y'][~contaminated_idx],
            '.',
            c="green",
            alpha=0.2,
            label='Lowres clean')

    ax.text(
        0.025,
        0.025,
        (f"Halo {run_name:s} DMO\n"
         f"$z={data.metadata.z:3.3f}$\n"
         f"$M_{{200c}}={latex_float(M200c.value)}$ M$_\odot$\n"
         f"$R_{{200c}}={latex_float(R200c.value)}$ Mpc\n"
         f"$R_{{\\rm clean}}={latex_float(_highres_radius.value)}$ Mpc"),
        color="black",
        ha="left",
        va="bottom",
        transform=ax.transAxes,
    )
    ax.text(0,
            0 + 1.05 * R200c,
            r"$R_{200c}$",
            color="black",
            ha="center",
            va="bottom")
    ax.text(0,
            0 + 1.002 * 5 * R200c,
            r"$5 \times R_{200c}$",
            color="grey",
            ha="center",
            va="bottom")
    ax.text(0,
            0 + 1.02 * _highres_radius,
            r"$R_\mathrm{clean}$",
            color="red",
            ha="center",
            va="bottom")
    circle_r200 = plt.Circle((0, 0),
                             R200c,
                             color="black",
                             fill=False,
                             linestyle='-')
    circle_5r200 = plt.Circle((0, 0),
                              5 * R200c,
                              color="grey",
                              fill=False,
                              linestyle='--')
    circle_clean = plt.Circle((0, 0),
                              _highres_radius.value,
                              color="red",
                              fill=False,
                              linestyle=':')
    ax.add_artist(circle_r200)
    ax.add_artist(circle_5r200)
    ax.add_artist(circle_clean)
    ax.set_xlim([-size.value, size.value])
    ax.set_ylim([-size.value, size.value])
    plt.legend()
    fig.savefig(
        f"{output_directory}/{run_name}_contamination_map{out_to_radius[0]}{out_to_radius[1]}.png"
    )
    print(
        f"Saved: {output_directory}/{run_name}_contamination_map{out_to_radius[0]}{out_to_radius[1]}.png"
    )
    plt.close(fig)
images = {
    "dark_matter": {"masses": {"cmap": "inferno", "vmin": None, "vmax": None}},
    "gas": {
        "masses": {"cmap": "viridis", "vmin": None, "vmax": None},
        "temperatures": {"cmap": "twilight", "vmin": 1e4, "vmax": 1e8},
        "metal_mass_fractions": {
            "cmap": "cubehelix",
            "vmin": 1e-1 * 0.012,
            "vmax": 10 * 0.012,
        },
    },
    "stars": {"masses": {"cmap": "bone", "vmin": None, "vmax": None}},
}

# Do some pre-computation and set up the particles instances.
data = load(snapshot_filename)
run_name = data.metadata.header["RunName"].decode("utf-8")

instances = {
    ptype: {
        field: SPHViewerWrapper(getattr(data, ptype), smooth_over=field)
        for field in images[ptype].keys()
    }
    for ptype in images.keys()
}

# Need to load the catalogue data now, including halo positions and virial radii.
with h5py.File(catalogue_filename, "r") as handle:
    positions = unyt_array(
        [handle["Xc"][...], handle["Yc"][...], handle["Zc"][...]],
        units=data.units.length,
Example #9
0
import matplotlib.pyplot as plt
import numpy as np

from swiftsimio import load

from unyt import Gyr, erg, mh, kb

from makeIC import gamma, initial_density, initial_temperature, inject_temperature, mu, particle_mass

try:
    plt.style.use("mnras_durham")
except:
    pass

# Snapshot for grabbing the units.
snapshot = load("feedback_0000.hdf5")
units = snapshot.metadata.units
energy_units = units.mass * units.length**2 / (units.time**2)

data = np.loadtxt("energy.txt").T

# Assign correct units to each

time = data[0] * units.time
mass = data[1] * units.mass
total_energy = data[2] * energy_units
kinetic_energy = data[3] * energy_units
thermal_energy = data[4] * energy_units
radiative_cool = data[8] * energy_units

# Now we have to figure out how much energy we actually 'injected'
Example #10
0
def feedback_stats_dT(path_to_snap: str, path_to_catalogue: str) -> dict:
    # Read in halo properties
    with h5py.File(f'{path_to_catalogue}', 'r') as h5file:
        XPotMin = unyt.unyt_quantity(h5file['/Xcminpot'][0], unyt.Mpc)
        YPotMin = unyt.unyt_quantity(h5file['/Ycminpot'][0], unyt.Mpc)
        ZPotMin = unyt.unyt_quantity(h5file['/Zcminpot'][0], unyt.Mpc)
        R500c = unyt.unyt_quantity(h5file['/SO_R_500_rhocrit'][0], unyt.Mpc)

    # Read in particles
    mask = sw.mask(f'{path_to_snap}', spatial_only=True)
    region = [[
        XPotMin - radius_bounds[1] * R500c, XPotMin + radius_bounds[1] * R500c
    ], [
        YPotMin - radius_bounds[1] * R500c, YPotMin + radius_bounds[1] * R500c
    ], [
        ZPotMin - radius_bounds[1] * R500c, ZPotMin + radius_bounds[1] * R500c
    ]]
    mask.constrain_spatial(region)
    data = sw.load(f'{path_to_snap}', mask=mask)

    # Get positions for all BHs in the bounding region
    bh_positions = data.black_holes.coordinates
    bh_coordX = bh_positions[:, 0] - XPotMin
    bh_coordY = bh_positions[:, 1] - YPotMin
    bh_coordZ = bh_positions[:, 2] - ZPotMin
    bh_radial_distance = np.sqrt(bh_coordX**2 + bh_coordY**2 + bh_coordZ**2)

    # The central SMBH will probably be massive.
    # Narrow down the search to the BH with top 5% in mass
    bh_masses = data.black_holes.subgrid_masses.to_physical()
    bh_top_massive_index = np.where(
        bh_masses > np.percentile(bh_masses.value, 95))[0]

    # Get the central BH closest to centre of halo at z=0
    central_bh_index = np.argmin(bh_radial_distance[bh_top_massive_index])
    central_bh_id_target = data.black_holes.particle_ids[bh_top_massive_index][
        central_bh_index]

    # Initialise typed dictionary for the central BH
    central_bh = defaultdict(list)
    central_bh['x'] = []
    central_bh['y'] = []
    central_bh['z'] = []
    central_bh['dx'] = []
    central_bh['dy'] = []
    central_bh['dz'] = []
    central_bh['dr'] = []
    central_bh['mass'] = []
    central_bh['m500c'] = []
    central_bh['id'] = []
    central_bh['redshift'] = []
    central_bh['time'] = []

    # Retrieve BH data from other snaps
    # Clip redshift data (get snaps below that redshifts)
    z_clip = 5.
    all_snaps = get_allpaths_from_last(path_to_snap, z_max=z_clip)
    all_catalogues = get_allpaths_from_last(path_to_catalogue, z_max=z_clip)
    assert len(all_snaps) == len(all_catalogues), (
        f"Detected different number of high-z snaps and high-z catalogues. "
        f"Number of snaps: {len(all_snaps)}. Number of catalogues: {len(all_catalogues)}."
    )

    for i, (highz_snap,
            highz_catalogue) in enumerate(zip(all_snaps, all_catalogues)):

        if not SILENT_PROGRESSBAR:
            print((f"Analysing snap ({i + 1}/{len(all_snaps)}):\n"
                   f"\t{os.path.basename(highz_snap)}\n"
                   f"\t{os.path.basename(highz_catalogue)}"))

        with h5py.File(f'{highz_catalogue}', 'r') as h5file:
            XPotMin = unyt.unyt_quantity(h5file['/Xcminpot'][0],
                                         unyt.Mpc) / data.metadata.a
            YPotMin = unyt.unyt_quantity(h5file['/Ycminpot'][0],
                                         unyt.Mpc) / data.metadata.a
            ZPotMin = unyt.unyt_quantity(h5file['/Zcminpot'][0],
                                         unyt.Mpc) / data.metadata.a
            M500c = unyt.unyt_quantity(
                h5file['/SO_Mass_500_rhocrit'][0] * 1.e10, unyt.Solar_Mass)

        data = sw.load(highz_snap)
        bh_positions = data.black_holes.coordinates.to_physical()
        bh_coordX = bh_positions[:, 0] - XPotMin
        bh_coordY = bh_positions[:, 1] - YPotMin
        bh_coordZ = bh_positions[:, 2] - ZPotMin
        bh_radial_distance = np.sqrt(bh_coordX**2 + bh_coordY**2 +
                                     bh_coordZ**2)
        bh_masses = data.black_holes.subgrid_masses.to_physical()

        if BH_LOCK_ID:
            central_bh_index = np.where(
                data.black_holes.particle_ids.v == central_bh_id_target.v)[0]
        else:
            central_bh_index = np.argmin(bh_radial_distance)

        central_bh['x'].append(bh_positions[central_bh_index, 0])
        central_bh['y'].append(bh_positions[central_bh_index, 1])
        central_bh['z'].append(bh_positions[central_bh_index, 2])
        central_bh['dx'].append(bh_coordX[central_bh_index])
        central_bh['dy'].append(bh_coordY[central_bh_index])
        central_bh['dz'].append(bh_coordZ[central_bh_index])
        central_bh['dr'].append(bh_radial_distance[central_bh_index])
        central_bh['mass'].append(bh_masses[central_bh_index])
        central_bh['m500c'].append(M500c)
        central_bh['id'].append(
            data.black_holes.particle_ids[central_bh_index])
        central_bh['redshift'].append(data.metadata.redshift)
        central_bh['time'].append(data.metadata.time)

    if INCLUDE_SNIPS:
        unitLength = data.metadata.units.length
        unitMass = data.metadata.units.mass
        unitTime = data.metadata.units.time

        snip_handles = get_snip_handles(path_to_snap, z_max=z_clip)
        for snip_handle in tqdm(snip_handles,
                                desc=f"Analysing snipshots",
                                disable=SILENT_PROGRESSBAR):

            # Open the snipshot file from the I/O stream.
            # Cannot use Swiftsimio, since it automatically looks for PartType0,
            # which is not included in snipshot outputs.
            with h5py.File(snip_handle, 'r') as f:
                bh_positions = f['/PartType5/Coordinates'][...]
                bh_masses = f['/PartType5/SubgridMasses'][...]
                bh_ids = f['/PartType5/ParticleIDs'][...]
                redshift = f['Header'].attrs['Redshift'][0]
                time = f['Header'].attrs['Time'][0]
                a = f['Header'].attrs['Scale-factor'][0]

            if BH_LOCK_ID:
                central_bh_index = np.where(
                    bh_ids == central_bh_id_target.v)[0]
            else:
                raise ValueError((
                    "Trying to lock the central BH to the halo centre of potential "
                    "in snipshots, which do not have corresponding halo catalogues. "
                    "Please, lock the central BH to the particle ID found at z = 0. "
                    "While this set-up is not yet implemented, it would be possible to "
                    "interpolate the position of the CoP between snapshots w.r.t. cosmic time."
                ))

            # This time we need to manually convert to physical coordinates and assign units.
            # Catalogue-dependent quantities are not appended.
            central_bh['x'].append(
                unyt.unyt_quantity(bh_positions[central_bh_index, 0] / a,
                                   unitLength))
            central_bh['y'].append(
                unyt.unyt_quantity(bh_positions[central_bh_index, 1] / a,
                                   unitLength))
            central_bh['z'].append(
                unyt.unyt_quantity(bh_positions[central_bh_index, 2] / a,
                                   unitLength))
            # central_bh['dx'].append(np.nan)
            # central_bh['dy'].append(np.nan)
            # central_bh['dz'].append(np.nan)
            # central_bh['dr'].append(np.nan)
            central_bh['mass'].append(
                unyt.unyt_quantity(bh_masses[central_bh_index], unitMass))
            # central_bh['m500c'].append(np.nan)
            central_bh['id'].append(
                unyt.unyt_quantity(bh_ids[central_bh_index],
                                   unyt.dimensionless))
            central_bh['redshift'].append(
                unyt.unyt_quantity(redshift, unyt.dimensionless))
            central_bh['time'].append(unyt.unyt_quantity(time, unitTime))

    # Convert lists to Swiftsimio cosmo arrays
    for key in central_bh:
        central_bh[key] = sw.cosmo_array(central_bh[key]).flatten()
        if not SILENT_PROGRESSBAR:
            print(
                f"Central BH memory [{key}]: {central_bh[key].nbytes / 1024:.3f} kB"
            )

    return central_bh
Example #11
0
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats

from swiftsimio import load
from analyticSolution import analytic

schemes = ["minimal", "pressure-energy", "anarchy-pu", "gizmo-mfm"]
npart = 32
snap = 5
kernel = "wendland-C2"
names = ["Density-Energy", "Pressure-Energy", "ANARCHY-PU", "SPH-ALE"]
key = "P"
filename = "sedov"

sim = load(f"{npart}/{kernel}/{schemes[0]}/{filename}_{snap:04d}.hdf5")

# Set up plotting stuff
try:
    plt.style.use("spheric_durham")
except:
    rcParams = {
        "font.serif": ["STIX", "Times New Roman", "Times"],
        "font.family": ["serif"],
        "mathtext.fontset": "stix",
        "font.size": 8,
    }
    plt.rcParams.update(rcParams)

# See analyticSolution for params.
Example #12
0
walther_T_lower_error = np.log10(data_walther[1] * 1.0e4) - np.log10(
    data_walther[2] * 1.0e4
)
walther_T_upper_error = np.log10(data_walther[3] * 1.0e4) - np.log10(
    data_walther[1] * 1.0e4
)

############### Read in simulation data
density_units = "Solar_Mass / Mpc**3"
temperature_units = "K"

## First, get list of all snapshots
reg_exp = "%s*.hdf5" % snapshot_name
snap_list = glob.glob(reg_exp)
snap_data = sorted(
    [swiftsimio.load(snap) for snap in snap_list], key=lambda x: x.metadata.z
)

z = np.empty(len(snap_data), dtype=np.float32)
T_mean = unyt.unyt_array(np.empty_like(z), units=temperature_units)
T_std = unyt.unyt_array(np.empty_like(z), units=temperature_units)
rho_mean = unyt.unyt_array(np.empty_like(z), units=density_units)
rho_std = unyt.unyt_array(np.empty_like(z), units=density_units)

## loop through list
for index, data in enumerate(snap_data):
    # Stick redshift in a list
    z[index] = data.metadata.z

    # Convert units to something sensible so `np.mean` doesn't freak out
    data.gas.temperatures.convert_to_units(temperature_units)
def lum(
    num,
    data,
    kappa,
    z,
    BC_fac,
    cent,
    campos,
    IMF='Chabrier_300',
    filters=('FAKE.TH.FUV', ),
    Type='Total',
    log10t_BC=7.,
    extinction='default',
):

    kinp = np.load(
        '/cosma7/data/dp004/dc-payy1/my_files/'
        'los/kernel_sph-anarchy.npz',
        allow_pickle=True)
    lkernel = kinp['kernel']
    header = kinp['header']
    kbins = header.item()['bins']

    S_mass_ini = data.stars.initial_masses.value
    S_Z = data.stars.metal_mass_fractions.value
    S_age = util.calc_ages(z, data.stars.birth_scale_factors.value)
    G_Z = data.gas.metal_mass_fractions.value
    S_sml = data.stars.smoothing_lengths.value
    G_sml = data.gas.smoothing_lengths.value
    G_mass = data.gas.masses.value * 10**10
    S_coords = data.stars.coordinates.value - cent
    G_coords = data.gas.coordinates.value - cent
    S_mass = data.stars.masses.value * 10**10

    if S_sml.max() == 0.0:
        print("Ill-defined smoothing lengths")

        last_snap = "%04d" % (num - 1)

        # Define path
        path = '/cosma/home/dp004/dc-rope1/cosma7/SWIFT/hydro_1380_data/ani_hydro_' + last_snap + ".hdf5"

        olddata = load(path)
        old_hsmls = olddata.stars.smoothing_lengths.value
        S_sml[:old_hsmls.size] = old_hsmls
        S_sml[old_hsmls.size:] = np.median(old_hsmls)

    Lums = {f: np.zeros(len(S_mass), dtype=np.float64) for f in filters}

    model = models.define_model(
        F'BPASSv2.2.1.binary/{IMF}')  # DEFINE SED GRID -
    if extinction == 'default':
        model.dust_ISM = ('simple', {
            'slope': -1.
        })  # Define dust curve for ISM
        model.dust_BC = ('simple', {
            'slope': -1.
        })  # Define dust curve for birth cloud component
    elif extinction == 'Calzetti':
        model.dust_ISM = ('Starburst_Calzetti2000', {''})
        model.dust_BC = ('Starburst_Calzetti2000', {''})
    elif extinction == 'SMC':
        model.dust_ISM = ('SMC_Pei92', {''})
        model.dust_BC = ('SMC_Pei92', {''})
    elif extinction == 'MW':
        model.dust_ISM = ('MW_Pei92', {''})
        model.dust_BC = ('MW_Pei92', {''})
    elif extinction == 'N18':
        model.dust_ISM = ('MW_N18', {''})
        model.dust_BC = ('MW_N18', {''})
    else:
        ValueError("Extinction type not recognised")

    # Convert coordinates to physical
    S_coords = S_coords / (1 + z)
    G_coords = G_coords / (1 + z)

    # --- create rest-frame luminosities
    F = FLARE.filters.add_filters(filters, new_lam=model.lam)
    model.create_Lnu_grid(
        F)  # --- create new L grid for each filter. In units of erg/s/Hz

    okinds = G_coords[:, 2] * (1 + z) < campos

    MetSurfaceDensities = util.get_Z_LOS(S_coords, G_coords[okinds, :],
                                         G_mass[okinds], G_Z[okinds],
                                         G_sml[okinds], (0, 1, 2), lkernel,
                                         kbins)

    Mage = np.nansum(S_mass_ini * S_age) / np.nansum(S_mass_ini)
    Z = np.nanmean(G_Z[okinds])

    MetSurfaceDensities = DTM_fit(Z, Mage) * MetSurfaceDensities

    if Type == 'Total':
        # --- calculate V-band (550nm) optical depth for each star particle
        tauVs_ISM = kappa * MetSurfaceDensities
        tauVs_BC = BC_fac * (S_Z / 0.01)
        fesc = 0.0

    elif Type == 'Pure-stellar':
        tauVs_ISM = np.zeros(len(S_mass_ini))
        tauVs_BC = np.zeros(len(S_mass_ini))
        fesc = 1.0

    elif Type == 'Intrinsic':
        tauVs_ISM = np.zeros(len(S_mass_ini))
        tauVs_BC = np.zeros(len(S_mass_ini))
        fesc = 0.0

    elif Type == 'Only-BC':
        tauVs_ISM = np.zeros(len(S_mass_ini))
        tauVs_BC = BC_fac * (S_Z / 0.01)
        fesc = 0.0

    else:
        tauVs_ISM = None
        tauVs_BC = None
        fesc = None
        ValueError(F"Undefined Type {Type}")

    # --- calculate rest-frame Luminosity. In units of erg/s/Hz
    for f in filters:
        Lnu = models.generate_Lnu_array(model,
                                        S_mass_ini,
                                        S_age,
                                        S_Z,
                                        tauVs_ISM,
                                        tauVs_BC,
                                        F,
                                        f,
                                        fesc=fesc,
                                        log10t_BC=log10t_BC)
        Lums[f] = Lnu

    return Lums
def single_frame(num, max_pixel, nframes):

    snap = "%04d" % num

    # Define path
    path = '/cosma/home/dp004/dc-rope1/cosma7/SWIFT/hydro_1380_ani/data/ani_hydro_' + snap + ".hdf5"

    snap = "%05d" % num

    data = load(path)

    meta = data.metadata
    boxsize = meta.boxsize[0]
    z = meta.redshift

    print("Boxsize:", boxsize)

    # Define centre
    cent = np.array([11.76119931, 3.95795609, 1.26561173])

    # Define targets
    targets = [[0, 0, 0]]

    ang_v = -360 / (1380 - 60)

    decay = lambda t: (boxsize.value + 5) * np.exp(-0.01637823848547536 * t)
    anti_decay = lambda t: 1.5 * np.exp(0.005139614587492267 * (t - 901))

    id_frames = np.arange(0, 1381, dtype=int)
    rs = np.zeros(len(id_frames), dtype=float)
    rs[0:151] = decay(id_frames[0:151])
    rs[151:901] = 1.5
    rs[901:] = anti_decay(id_frames[901:])

    simtimes = np.zeros(len(id_frames), dtype=int)
    id_targets = np.zeros(len(id_frames), dtype=int)
    ts = np.full(len(id_frames), 5)
    ps = np.zeros(len(id_frames))
    ps[0:60] = 0
    ps[60:] = ang_v * (id_frames[60:] - 60)
    ps[-2:] = -360
    zoom = np.full(len(id_frames), 1)
    extent = np.full(len(id_frames), 10)

    # Define anchors dict for camera parameters
    anchors = {}
    anchors['sim_times'] = list(simtimes)
    anchors['id_frames'] = list(id_frames)
    anchors['id_targets'] = list(id_targets)
    anchors['r'] = list(rs)
    anchors['t'] = list(ts)
    anchors['p'] = list(ps)
    anchors['zoom'] = list(zoom)
    anchors['extent'] = list(extent)

    print("Processing frame with properties:")
    for key, val in anchors.items():
        print(key, "=", val[num])

    # Define the camera trajectory
    cam_data = camera_tools.get_camera_trajectory(targets, anchors)

    # Get colormap
    # cmap = cmaps.sunlight()

    hex_list = [
        "#590925", "#6c1c55", "#7e2e84", "#ba4051", "#f6511d", "#ffb400",
        "#f7ec59", "#fbf6ac", "#ffffff"
    ]
    float_list = [0, 0.2, 0.3, 0.4, 0.6, 0.7, 0.8, 0.9, 1]

    cmap = get_continuous_cmap(hex_list, float_list=float_list)
    norm = plt.Normalize(vmin=3.5, vmax=7.5, clip=True)

    poss = data.gas.coordinates.value
    temp = data.gas.temperatures.value
    mass = data.gas.masses.value * 10**10

    print(np.log10(temp.max()), np.log10(np.percentile(temp, 99)),
          np.log10(np.percentile(temp, 95)), np.log10(np.percentile(temp, 90)),
          np.log10(np.percentile(temp, 67.5)),
          np.log10(np.percentile(temp, 50)))

    # okinds = np.linalg.norm(poss - cent, axis=1) < 1
    # cent = np.average(poss[okinds], weights=rho_gas[okinds], axis=0)
    print("Centered on:", cent)

    poss -= cent
    hsmls = data.gas.smoothing_lengths.value

    poss[np.where(poss > boxsize.value / 2)] -= boxsize.value
    poss[np.where(poss < -boxsize.value / 2)] += boxsize.value

    # Get images
    rgb_output, ang_extent = getimage(cam_data, poss, temp, mass, hsmls, num,
                                      norm, cmap)

    i = cam_data[num]
    extent = [
        0, 2 * np.tan(ang_extent[1]) * i['r'], 0,
        2 * np.tan(ang_extent[-1]) * i['r']
    ]
    print(ang_extent, extent)

    dpi = rgb_output.shape[0] / 2
    print(dpi, rgb_output.shape)
    fig = plt.figure(figsize=(2, 2 * 1.77777777778), dpi=dpi)
    ax = fig.add_subplot(111)

    ax.imshow(rgb_output, extent=ang_extent, origin='lower')
    ax.tick_params(axis='both',
                   left=False,
                   top=False,
                   right=False,
                   bottom=False,
                   labelleft=False,
                   labeltop=False,
                   labelright=False,
                   labelbottom=False)

    ax.text(0.975,
            0.05,
            "$t=$%.1f Gyr" % cosmo.age(z).value,
            transform=ax.transAxes,
            verticalalignment="top",
            horizontalalignment='right',
            fontsize=1,
            color="w")

    ax.plot([0.05, 0.15], [0.025, 0.025],
            lw=0.1,
            color='w',
            clip_on=False,
            transform=ax.transAxes)

    ax.plot([0.05, 0.05], [0.022, 0.027],
            lw=0.15,
            color='w',
            clip_on=False,
            transform=ax.transAxes)
    ax.plot([0.15, 0.15], [0.022, 0.027],
            lw=0.15,
            color='w',
            clip_on=False,
            transform=ax.transAxes)

    axis_to_data = ax.transAxes + ax.transData.inverted()
    left = axis_to_data.transform((0.05, 0.075))
    right = axis_to_data.transform((0.15, 0.075))
    dist = extent[1] * (right[0] - left[0]) / (ang_extent[1] - ang_extent[0])

    print(left, right, (right[0] - left[0]) / (ang_extent[1] - ang_extent[0]),
          dist)

    ax.text(0.1,
            0.055,
            "%.2f cMpc" % dist,
            transform=ax.transAxes,
            verticalalignment="top",
            horizontalalignment='center',
            fontsize=1,
            color="w")

    sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
    sm._A = []  # # fake up the array of the scalar mappable
    cbaxes = ax.inset_axes([0.05, 0.95, 0.25, 0.015])
    cbar = plt.colorbar(sm, cax=cbaxes, orientation="horizontal")
    cbar.set_ticks([3.5, 5, 6, 7.5])
    labels = ["$\leq3.5$", "5", "6", "$7.5\leq$"]
    cbar.ax.set_xticklabels(labels)
    for tick in cbar.ax.xaxis.get_major_ticks():
        tick.label.set_fontsize("xx-small")
        tick.label.set_color("w")
        tick.label.set_y(3)
    cbar.ax.tick_params(axis='x', color='w', size=0.3, width=0.1)
    cbar.ax.set_xlabel(r"$\log_{10}\left(T / [\mathrm{K}]\right)$",
                       color='w',
                       fontsize=0.2,
                       labelpad=-0.1)
    cbar.outline.set_edgecolor('white')
    cbar.outline.set_linewidth(0.05)

    plt.margins(0, 0)

    fig.savefig('plots/Ani/GasTemp_flythrough_' + snap + '.png',
                bbox_inches='tight',
                pad_inches=0)

    plt.close(fig)
Example #15
0

if __name__ == "__main__":
    from swiftpipeline.argumentparser import ScriptArgumentParser

    arguments = ScriptArgumentParser(
        description="Basic density-temperature figure.")

    snapshot_filenames = [
        f"{directory}/{snapshot}" for directory, snapshot in zip(
            arguments.directory_list, arguments.snapshot_list)
    ]

    plt.style.use(arguments.stylesheet_location)

    snapshots = [load(filename) for filename in snapshot_filenames]

    fig, axes = setup_axes(number_of_simulations=arguments.number_of_inputs)

    for snapshot, ax in zip(snapshots, axes.flat):
        used_parameters = snapshot.metadata.parameters

        parameters = {
            k: float(used_parameters[v])
            for k, v in {
                "f_E,min": "EAGLEFeedback:SNII_energy_fraction_min",
                "f_E,max": "EAGLEFeedback:SNII_energy_fraction_max",
                "n_Z": "EAGLEFeedback:SNII_energy_fraction_n_Z",
                "n_n": "EAGLEFeedback:SNII_energy_fraction_n_n",
                "Z_pivot": "EAGLEFeedback:SNII_energy_fraction_Z_0",
                "n_pivot": "EAGLEFeedback:SNII_energy_fraction_n_0_H_p_cm3",
Example #16
0
import numpy
import matplotlib
matplotlib.use('Agg')
from matplotlib import pyplot
pyplot.rcParams.update({'font.size': 40})
from matplotlib.colors import LogNorm
from swiftsimio import load
from velociraptor.tools.lines import binned_median_line as bml
import unyt

spread = numpy.loadtxt('/cosma5/data/durham/dc-murr1/gas_spread.txt')
density = numpy.loadtxt(
    '/cosma5/data/durham/dc-murr1/gas_neighbour_density.txt')
snap = load('/cosma6/data/dp004/dc-borr1/swift-test-data/eagle_0037.hdf5')
dens = snap.gas.densities

fig, ax = pyplot.subplots(figsize=(20, 20))
x_bins = numpy.logspace(numpy.log10(numpy.amin(density)),
                        numpy.log10(numpy.amax(density)),
                        num=100)
y_bins = numpy.logspace(numpy.log10(numpy.amin(spread)),
                        numpy.log10(numpy.amax(spread)),
                        num=100)
h = ax.hist2d(density, spread, bins=[x_bins, y_bins], norm=LogNorm())
pyplot.colorbar(h[3], ax=ax)
ax.loglog()
ax.set_ylabel('Spread metric [Mpc]')
ax.set_xlabel(r"Neighbour local density [$M_{\odot}/(Mpc)^3$]")
ax.tick_params(length=10, width=3)

x_bins = unyt.unyt_array(x_bins, units=dens.units)
Example #17
0
    fig = plt.figure(figsize=(6.974, 6.974 * (8 / 9)))

    gs = GridSpec(8, 3, figure=fig)

    # Who even likes this, gridspec is horrible (it's a shame it's so useful)
    ax_first = [plt.subplot(gs[:3, x]) for x in range(3)]
    ax_residual_first = [plt.subplot(gs[3, x]) for x in range(3)]
    ax_second = [plt.subplot(gs[4:-1, x]) for x in range(3)]
    ax_residual_second = [plt.subplot(gs[-1, x]) for x in range(3)]

    ax = [ax_first, ax_second]
    ax_residual = [ax_residual_first, ax_residual_second]

    for axes, residual_axes, (scheme, name) in zip(ax, ax_residual, schemes.items()):
        try:
            data = load(f"{scheme}/{snapshot_name}")
        except (FileNotFoundError, OSError):
            continue

        for (
            axis,
            residual_axis,
            (part_property, part_property_name),
            vertical_plot_limit,
            log_vertical_axis,
        ) in zip(axes, residual_axes, plot.items(), ylim.values(), ylog.values()):
            try:
                analysis_function = locals()[f"plot_{part_property}"]
            except:
                continue
Example #18
0
""" Makes an image of snapshot 175.
"""

from swiftsimio import load
from swiftsimio.visualisation import project_gas_pixel_grid

import matplotlib.pyplot as plt

data = load("kelvinHelmholtz_0320.hdf5")

empty_grid = project_gas_pixel_grid(data, 7 * 300, None)
grid = project_gas_pixel_grid(data, 7 * 300, "internal_energy") / empty_grid

fig, a = plt.subplots(figsize=(7, 7))
fig.subplots_adjust(0, 0, 1, 1, 0, 0)

a.imshow(grid, cmap="Spectral", origin="lower")

a.set_xticks([])
a.set_yticks([])

fig.savefig("kelvin_helmholtz_highres_energy.png", dpi=300)
def contamination_radial_histogram(run_name: str,
                                   velociraptor_properties_zoom: str,
                                   snap_filepath_zoom: str,
                                   out_to_radius: Tuple[int,
                                                        str] = (5, 'r200c'),
                                   highres_radius: Tuple[int,
                                                         str] = (6, 'r500c'),
                                   output_directory: str = '.') -> None:
    # Rendezvous over parent VR catalogue using zoom information
    with h5py.File(velociraptor_properties_zoom, 'r') as vr_file:
        M200c = unyt.unyt_quantity(vr_file['/Mass_200crit'][0] * 1e10,
                                   unyt.Solar_Mass)
        R200c = unyt.unyt_quantity(vr_file['/R_200crit'][0], unyt.Mpc)
        R500c = unyt.unyt_quantity(vr_file['/SO_R_500_rhocrit'][0], unyt.Mpc)
        xCen = unyt.unyt_quantity(vr_file['/Xcminpot'][0], unyt.Mpc)
        yCen = unyt.unyt_quantity(vr_file['/Ycminpot'][0], unyt.Mpc)
        zCen = unyt.unyt_quantity(vr_file['/Zcminpot'][0], unyt.Mpc)

    # EAGLE-XL data path
    print(f"Rendering {snap_filepath_zoom}...")

    if out_to_radius[1] == 'r200c':
        size = out_to_radius[0] * R200c
    elif out_to_radius[1] == 'r500c':
        size = out_to_radius[0] * R500c
    elif out_to_radius[1] == 'Mpc' or out_to_radius[1] is None:
        size = unyt.unyt_quantity(out_to_radius[0], unyt.Mpc)

    if highres_radius[1] == 'r200c':
        _highres_radius = highres_radius[0] * R200c
    elif highres_radius[1] == 'r500c':
        _highres_radius = highres_radius[0] * R500c
    elif highres_radius[1] == 'Mpc' or highres_radius[1] is None:
        _highres_radius = unyt.unyt_quantity(highres_radius[0], unyt.Mpc)

    mask = sw.mask(snap_filepath_zoom)
    region = [[xCen - size, xCen + size], [yCen - size, yCen + size],
              [zCen - size, zCen + size]]
    mask.constrain_spatial(region)

    # Load data using mask
    data = sw.load(snap_filepath_zoom, mask=mask)
    posDM = data.dark_matter.coordinates / data.metadata.a
    highres_coordinates = {
        'x':
        wrap(posDM[:, 0] - xCen, data.metadata.boxsize[0]),
        'y':
        wrap(posDM[:, 1] - yCen, data.metadata.boxsize[1]),
        'z':
        wrap(posDM[:, 2] - zCen, data.metadata.boxsize[2]),
        'r':
        np.sqrt(
            wrap(posDM[:, 0] - xCen, data.metadata.boxsize[0])**2 +
            wrap(posDM[:, 1] - yCen, data.metadata.boxsize[1])**2 +
            wrap(posDM[:, 2] - zCen, data.metadata.boxsize[2])**2)
    }
    del posDM
    posDM = data.boundary.coordinates / data.metadata.a
    lowres_coordinates = {
        'x':
        wrap(posDM[:, 0] - xCen, data.metadata.boxsize[0]),
        'y':
        wrap(posDM[:, 1] - yCen, data.metadata.boxsize[1]),
        'z':
        wrap(posDM[:, 2] - zCen, data.metadata.boxsize[2]),
        'r':
        np.sqrt(
            wrap(posDM[:, 0] - xCen, data.metadata.boxsize[0])**2 +
            wrap(posDM[:, 1] - yCen, data.metadata.boxsize[1])**2 +
            wrap(posDM[:, 2] - zCen, data.metadata.boxsize[2])**2)
    }
    del posDM

    # Histograms
    contaminated_idx = np.where(lowres_coordinates['r'] < _highres_radius)[0]
    bins = np.linspace(0, size, 40)
    hist, bin_edges = np.histogram(lowres_coordinates['r'][contaminated_idx],
                                   bins=bins)
    lowres_coordinates['r_bins'] = (bin_edges[1:] + bin_edges[:-1]) / 2 / R200c
    lowres_coordinates['hist_contaminating'] = hist
    del hist, bin_edges
    hist, _ = np.histogram(lowres_coordinates['r'], bins=bins)
    lowres_coordinates['hist_all'] = hist
    del hist
    hist, _ = np.histogram(highres_coordinates['r'], bins=bins)
    highres_coordinates['r_bins'] = lowres_coordinates['r_bins']
    highres_coordinates['hist_all'] = hist
    del bins, hist

    # Make radial distribution plot
    fig, ax = plt.subplots()

    ax.set_yscale('log')
    ax.set_ylabel("Number of particles")
    ax.set_xlabel(r"$R\ /\ R_{200c}$")

    ax.step(highres_coordinates['r_bins'],
            highres_coordinates['hist_all'],
            where='mid',
            color='grey',
            label='Highres all')
    ax.step(lowres_coordinates['r_bins'],
            lowres_coordinates['hist_all'],
            where='mid',
            color='green',
            label='Lowres all')
    ax.step(lowres_coordinates['r_bins'],
            lowres_coordinates['hist_contaminating'],
            where='mid',
            color='red',
            label='Lowres contaminating')
    ax.text(
        0.025,
        0.025,
        (f"Halo {run_name:s} DMO\n"
         f"$z={data.metadata.z:3.3f}$\n"
         f"$M_{{200c}}={latex_float(M200c.value)}$ M$_\odot$\n"
         f"$R_{{200c}}={latex_float(R200c.value)}$ Mpc\n"
         f"$R_{{\\rm clean}}={latex_float(_highres_radius.value)}$ Mpc"),
        color="black",
        ha="left",
        va="bottom",
        transform=ax.transAxes,
    )

    ax.axvline(1, color="grey", linestyle='--')
    ax.axvline(_highres_radius / R200c, color="red", linestyle='--')
    ax.set_xlim([0, size.value])
    plt.legend()
    fig.tight_layout()
    fig.savefig(
        f"{output_directory}/{run_name}_contamination_hist{out_to_radius[0]}{out_to_radius[1]}.png"
    )
    print(
        f"Saved: {output_directory}/{run_name}_contamination_hist{out_to_radius[0]}{out_to_radius[1]}.png"
    )
    plt.close(fig)
Example #20
0
def single_frame(num, max_pixel, nframes):

    snap = "%04d" % num

    # Define path
    path = '/cosma/home/dp004/dc-rope1/cosma7/SWIFT/hydro_1380_ani/data/ani_hydro_' + snap + ".hdf5"

    snap = "%05d" % num

    img_dimens = (2048, 4096)

    data = load(path)

    meta = data.metadata
    boxsize = meta.boxsize[0]
    z = meta.redshift

    print("Boxsize:", boxsize)

    # Define centre
    cent = np.array([11.76119931, 3.95795609, 1.26561173])

    # Define targets
    targets = [[0, 0, 0]]

    id_frames = np.arange(0, 1381, dtype=int)
    rs = np.full(len(id_frames), 0., dtype=float)

    simtimes = np.zeros(len(id_frames), dtype=int)
    id_targets = np.zeros(len(id_frames), dtype=int)
    zoom = np.full(len(id_frames), 1)
    extent = np.full(len(id_frames), 10)

    hex_list = [
        "#000000", "#590925", "#6c1c55", "#7e2e84", "#ba4051", "#f6511d",
        "#ffb400", "#f7ec59", "#fbf6ac", "#ffffff"
    ]
    float_list = [0, 0.2, 0.3, 0.4, 0.45, 0.5, 0.7, 0.8, 0.9, 1]

    cmap = get_continuous_cmap(hex_list, float_list=float_list)

    poss = data.gas.coordinates.value
    mass = data.gas.masses.value * 10**10
    rho_gas = data.gas.densities.value

    # okinds = np.linalg.norm(poss - cent, axis=1) < 1
    # cent = np.average(poss[okinds], weights=rho_gas[okinds], axis=0)
    print("Centered on:", cent)

    poss -= cent
    hsmls = data.gas.smoothing_lengths.value

    poss[np.where(poss > boxsize.value / 2)] -= boxsize.value
    poss[np.where(poss < -boxsize.value / 2)] += boxsize.value

    cart_poss = np.copy(poss)
    poss = cart_to_spherical(poss)
    print(poss.min(axis=0), poss.max(axis=0))
    poss, rs = spherical_to_equirectangular(poss)
    print(poss.min(axis=0), poss.max(axis=0))

    max_rad = np.sqrt(3 * (boxsize.value / 2)**2)

    # Define range and extent for the images in arc seconds
    imgrange = ((-np.pi / 2, np.pi / 2), (-np.pi, np.pi))
    # imgrange = ((poss[:, 0].min(), poss[:, 0].max()),
    #             (poss[:, 1].min(), poss[:, 1].max()))
    imgextent = (-np.pi / 2, np.pi / 2, -np.pi, np.pi)

    ini_img = make_soft_img(poss, cart_poss, img_dimens, imgrange, mass, hsmls,
                            rs)

    img = np.zeros_like(ini_img)
    img[ini_img > 0] = np.log10(ini_img[ini_img > 0])

    vmax = 9
    vmin = 6

    print(np.max(img), np.min(img[img > 0]))

    img = cmap(get_normalised_image(img, vmin=vmin, vmax=vmax))

    # # Get colormap
    # cmap = ml.cm.Greys_r
    #
    # try:
    #     poss = data.stars.coordinates.value - cent
    #     mass = data.stars.masses.value * 10 ** 10
    #     hsmls = data.stars.smoothing_lengths.value
    #
    #     if hsmls.max() == 0.0:
    #         print("Ill-defined smoothing lengths")
    #
    #         last_snap = "%04d" % (num - 1)
    #
    #         # Define path
    #         path = '/cosma/home/dp004/dc-rope1/cosma7/SWIFT/hydro_1380_ani/data/ani_hydro_' + last_snap + ".hdf5"
    #
    #         data = load(path)
    #         old_hsmls = data.stars.smoothing_lengths.value
    #         hsmls[:old_hsmls.size] = old_hsmls
    #         hsmls[old_hsmls.size:] = np.median(old_hsmls)
    #
    #     print(np.min(hsmls), np.max(hsmls))
    #
    #     poss[np.where(poss > boxsize.value / 2)] -= boxsize.value
    #     poss[np.where(poss < - boxsize.value / 2)] += boxsize.value
    #
    #     for proj_ind in range(6):
    #
    #         ts = np.full(len(id_frames), t_projs[proj_ind])
    #         ps = np.full(len(id_frames), p_projs[proj_ind])
    #
    #         proj = projs[proj_ind]
    #
    #         # Define anchors dict for camera parameters
    #         anchors = {}
    #         anchors['sim_times'] = list(simtimes)
    #         anchors['id_frames'] = list(id_frames)
    #         anchors['id_targets'] = list(id_targets)
    #         anchors['r'] = list(rs)
    #         anchors['t'] = list(ts)
    #         anchors['p'] = list(ps)
    #         anchors['zoom'] = list(zoom)
    #         anchors['extent'] = list(extent)
    #
    #         print(f"Processing projection {proj} with properties:")
    #         for key, val in anchors.items():
    #             print(key, "=", val[num])
    #
    #         # Define the camera trajectory
    #         cam_data = camera_tools.get_camera_trajectory(targets, anchors)
    #
    #         # Get images
    #         star_imgs[proj], ang_extent = getimage(cam_data, poss, mass,
    #                                                hsmls, num,
    #                                                img_dimens, cmap,
    #                                                Type="star")
    # except AttributeError:
    #     for proj_ind in range(6):
    #         proj = projs[proj_ind]
    #         star_imgs[proj] = np.zeros_like(gas_imgs[proj])
    #
    # imgs = {}
    #
    # for proj_ind in range(6):
    #     proj = projs[proj_ind]
    #
    #     blend = Blend.Blend(gas_imgs[proj], star_imgs[proj])
    #     imgs[proj] = blend.Screen()
    #
    # cube = np.zeros((img_dimens * 3,
    #                  img_dimens * 4, 4),
    #                 dtype=np.float32)
    #
    # cube[img_dimens: img_dimens * 2, 0: img_dimens] = imgs[(1, 0, 0)]
    # cube[img_dimens: img_dimens * 2, img_dimens: img_dimens * 2] = imgs[(0, 1, 0)]
    # cube[img_dimens: img_dimens * 2, img_dimens * 2: img_dimens * 3] = imgs[(-1, 0, 0)]
    # cube[img_dimens: img_dimens * 2, img_dimens * 3: img_dimens * 4] = imgs[(0, -1, 0)]
    # cube[img_dimens * 2: img_dimens * 3, img_dimens: img_dimens * 2] = imgs[(0, 0, -1)]
    # cube[0: img_dimens, img_dimens: img_dimens * 2] = imgs[(0, 0, 1)]
    #
    # posx = imgs[(1, 0, 0)]
    # negx = imgs[(-1, 0, 0)]
    # posy = imgs[(0, 1, 0)]
    # negy = imgs[(0, -1, 0)]
    # posz = imgs[(0, 0, 1)]
    # negz = imgs[(0, 0, -1)]
    #
    # squareLength = posx.shape[0]
    # halfSquareLength = squareLength / 2
    #
    # outputWidth = squareLength * 2
    # outputHeight = squareLength * 1
    #
    # output = np.zeros((outputHeight, outputWidth, 4))
    #
    # for loopY in range(0, int(outputHeight)):  # 0..height-1 inclusive
    #
    #     print(loopY)
    #
    #     for loopX in range(0, int(outputWidth)):
    #         # 2. get the normalised u,v coordinates for the current pixel
    #
    #         U = float(loopX) / (outputWidth - 1)  # 0..1
    #         V = float(loopY) / (outputHeight - 1)  # no need for 1-... as the image output needs to start from the top anyway.
    #
    #         # 3. taking the normalised cartesian coordinates calculate the polar coordinate for the current pixel
    #
    #         theta = U * 2 * np.pi
    #         phi = V * np.pi
    #
    #         # 4. calculate the 3D cartesian coordinate which has been projected to a cubes face
    #
    #         cart = convertEquirectUVtoUnit2D(theta, phi, squareLength)
    #
    #         # 5. use this pixel to extract the colour
    #
    #         index = cart["index"]
    #
    #         if (index == "X+"):
    #             output[loopY, loopX] = posx[cart["y"], cart["x"]]
    #         elif (index == "X-"):
    #             output[loopY, loopX] = negx[cart["y"], cart["x"]]
    #         elif (index == "Y+"):
    #             output[loopY, loopX] = posy[cart["y"], cart["x"]]
    #         elif (index == "Y-"):
    #             output[loopY, loopX] = negy[cart["y"], cart["x"]]
    #         elif (index == "Z+"):
    #             output[loopY, loopX] = posz[cart["y"], cart["x"]]
    #         elif (index == "Z-"):
    #             output[loopY, loopX] = negz[cart["y"], cart["x"]]
    #
    dpi = img.shape[0]
    print(dpi, img.shape)
    fig = plt.figure(figsize=(1, 2), dpi=dpi)
    ax = fig.add_subplot(111)

    ax.imshow(img, origin='lower')
    ax.tick_params(axis='both',
                   left=False,
                   top=False,
                   right=False,
                   bottom=False,
                   labelleft=False,
                   labeltop=False,
                   labelright=False,
                   labelbottom=False)

    # ax.text(0.975, 0.05, "$t=$%.1f Gyr" % cosmo.age(z).value,
    #         transform=ax.transAxes, verticalalignment="top",
    #         horizontalalignment='right', fontsize=1, color="w")

    plt.margins(0, 0)

    ax.set_frame_on(False)

    fig.savefig('plots/Ani/360/Equirectangular_flythrough_' + snap + '.png',
                bbox_inches='tight',
                pad_inches=0)

    plt.close(fig)
Example #21
0
def dm_map_parent(
        run_name: str,
        velociraptor_properties_parent: str,
        snap_filepath_parent: str,
        velociraptor_properties_zoom: str,
        out_to_radius: Tuple[int, str] = (5, 'r200c'),
        highres_radius: Tuple[int, str] = (6, 'r500c'),
        output_directory: str = '.'
) -> None:
    print(f"Rendering {snap_filepath_parent}...")

    # Rendezvous over parent VR catalogue using zoom information
    with h5py.File(velociraptor_properties_zoom, 'r') as vr_file:
        idx, M200c, R200c, Xcminpot, Ycminpot, Zcminpot = find_object(
            vr_properties_catalog=velociraptor_properties_parent,
            sample_structType=10,
            sample_mass_lower_lim=vr_file['/Mass_200crit'][0] * 1e10 * 0.8,
            sample_x=vr_file['/Xcminpot'][0],
            sample_y=vr_file['/Ycminpot'][0],
            sample_z=vr_file['/Zcminpot'][0],
        )
    with h5py.File(velociraptor_properties_parent, 'r') as vr_file:
        R500c = unyt.unyt_quantity(vr_file['/SO_R_500_rhocrit'][idx], unyt.Mpc)

    M200c = unyt.unyt_quantity(M200c, unyt.Solar_Mass)
    R200c = unyt.unyt_quantity(R200c, unyt.Mpc)
    xCen = unyt.unyt_quantity(Xcminpot, unyt.Mpc)
    yCen = unyt.unyt_quantity(Ycminpot, unyt.Mpc)
    zCen = unyt.unyt_quantity(Zcminpot, unyt.Mpc)

    if out_to_radius[1] == 'r200c':
        size = out_to_radius[0] * R200c
    elif out_to_radius[1] == 'r500c':
        size = out_to_radius[0] * R500c
    elif out_to_radius[1] == 'Mpc' or out_to_radius[1] is None:
        size = unyt.unyt_quantity(out_to_radius[0], unyt.Mpc)

    if highres_radius[1] == 'r200c':
        _highres_radius = highres_radius[0] * R200c
    elif highres_radius[1] == 'r500c':
        _highres_radius = highres_radius[0] * R500c
    elif highres_radius[1] == 'Mpc' or highres_radius[1] is None:
        _highres_radius = unyt.unyt_quantity(highres_radius[0], unyt.Mpc)

    # Construct spatial mask to feed into swiftsimio
    mask = sw.mask(snap_filepath_parent)
    region = [
        [xCen - size, xCen + size],
        [yCen - size, yCen + size],
        [zCen - size, zCen + size]
    ]
    mask.constrain_spatial(region)
    data = sw.load(snap_filepath_parent, mask=mask)

    # Generate smoothing lengths for the dark matter
    data.dark_matter.smoothing_lengths = generate_smoothing_lengths(
        data.dark_matter.coordinates,
        data.metadata.boxsize,
        kernel_gamma=1.8,
        neighbours=57,
        speedup_fac=2,
        dimension=3,
    )

    # data.dark_matter.coordinates[:, 0] = wrap(
    #     data.dark_matter.coordinates[:, 0] - xCen,
    #     data.metadata.boxsize[0]
    # )
    # data.dark_matter.coordinates[:, 1] = wrap(
    #     data.dark_matter.coordinates[:, 1] - yCen,
    #     data.metadata.boxsize[1]
    # )
    # data.dark_matter.coordinates[:, 2] = wrap(
    #     data.dark_matter.coordinates[:, 2] - zCen,
    #     data.metadata.boxsize[2]
    # )
    
    dm_mass = dm_render(data, region=(
        [
            xCen - size,
            xCen + size,
            yCen - size,
            yCen + size
        ]
    ), resolution=resolution)

    # Make figure
    fig, ax = plt.subplots(figsize=(8, 8), dpi=resolution // 8)
    fig.subplots_adjust(0, 0, 1, 1)
    ax.axis("off")
    ax.imshow(dm_mass.T, norm=LogNorm(), cmap="inferno", origin="lower", extent=(region[0] + region[1]))
    info = ax.text(
        0.025,
        0.025,
        (
            f"Halo {run_name:s} DMO - parent\n"
            f"$z={data.metadata.z:3.3f}$\n"
            f"$M_{{200c}}={latex_float(M200c.value)}\\ {M200c.units.latex_repr}$\n"
            f"$R_{{200c}}={latex_float(R200c.value)}\\ {R200c.units.latex_repr}$\n"
            f"$R_\\mathrm{{clean}}={highres_radius[0]}\\ {highres_radius[1]}$"
        ),
        color="white",
        ha="left",
        va="bottom",
        alpha=0.8,
        transform=ax.transAxes,
    )
    info.set_bbox(dict(facecolor='black', alpha=0.2, edgecolor='grey'))
    ax.text(
        xCen,
        yCen + 1.05 * R200c,
        r"$R_{200c}$",
        color="black",
        ha="center",
        va="bottom"
    )
    ax.text(
        xCen,
        yCen + 1.02 * _highres_radius,
        r"$R_\mathrm{clean}$",
        color="white",
        ha="center",
        va="bottom"
    )
    circle_r200 = plt.Circle((xCen, yCen), R200c, color="black", fill=False, linestyle='-')
    circle_clean = plt.Circle((xCen, yCen), _highres_radius.value, color="white", fill=False, linestyle=':')
    ax.add_artist(circle_r200)
    ax.add_artist(circle_clean)
    ax.set_xlim([xCen.value - size.value, xCen.value + size.value])
    ax.set_ylim([yCen.value - size.value, yCen.value + size.value])
    fig.savefig(f"{output_directory}/{run_name}_dark_matter_map_parent.png")
    plt.close(fig)
    print(f"Saved: {output_directory}/{run_name}_dark_matter_map_parent.png")
    del data, dm_mass
    plt.close('all')

    return
Example #22
0
except:
    pass

time_to_plot = 25 * Myr
diffusion_parameters = [0.1 * x for x in range(11)]
plot_directory_name = "default_diffmax"

kinetic_energy_at_time = []
thermal_energy_at_time = []
radiative_energy_at_time = []

for diffusion in diffusion_parameters:
    directory_name = f"{plot_directory_name}_{diffusion:1.1f}"

# Snapshot for grabbing the units.
    snapshot = load(f"{directory_name}/feedback_0000.hdf5")
    units = snapshot.metadata.units
    energy_units = units.mass * units.length ** 2 / (units.time ** 2)

    data = np.loadtxt(f"{directory_name}/energy.txt").T

# Assign correct units to each

    time = data[0] * units.time
    mass = data[1] * units.mass
    total_energy = data[2] * energy_units
    kinetic_energy = data[3] * energy_units
    thermal_energy = data[4] * energy_units
    radiative_cool = data[8] * energy_units

# Now we have to figure out how much energy we actually 'injected'
arguments = ScriptArgumentParser(
    description=
    "Creates a plot showing the distribution of the gas densities recorded "
    "when the gas was last heated by SNII, split by redshift")

snapshot_filenames = [
    f"{directory}/{snapshot}" for directory, snapshot in zip(
        arguments.directory_list, arguments.snapshot_list)
]

names = arguments.name_list
output_path = arguments.output_directory

plt.style.use(arguments.stylesheet_location)

data = [load(snapshot_filename) for snapshot_filename in snapshot_filenames]
number_of_bins = 256

SNII_density_bins = unyt.unyt_array(np.logspace(-5, 6.5, number_of_bins),
                                    units="1/cm**3")
log_SNII_density_bin_width = np.log10(SNII_density_bins[1].value) - np.log10(
    SNII_density_bins[0].value)
SNII_density_centers = 0.5 * (SNII_density_bins[1:] + SNII_density_bins[:-1])

# Begin plotting

fig, axes = plt.subplots(3, 1, sharex=True, sharey=True)
axes = axes.flat

ax_dict = {
    "$z < 1$": axes[0],
Example #24
0
import sys
import matplotlib

matplotlib.use("Agg")

import matplotlib.pyplot as plt
import numpy as np
from scipy import stats

from swiftsimio import load
from swiftsimio.visualisation import project_gas_pixel_grid

snap = int(sys.argv[1])

sim = load(f"square_{snap:04d}.hdf5")
resolution = 512

# First create a grid that gets the particle density so we can divide it out later
unweighted_grid = project_gas_pixel_grid(sim, 512, None)

# Set up plotting stuff
try:
    plt.style.use("mnras_durham")
except:
    rcParams = {
        "font.serif": ["STIX", "Times New Roman", "Times"],
        "font.family": ["serif"],
        "mathtext.fontset": "stix",
        "font.size": 8,
    }
from swiftsimio import load
from swiftsimio.visualisation.projection import project_gas

data = load("/cosma6/data/dp004/dc-borr1/swift-test-data/eagle_0037.hdf5")

# First create a mass-weighted temperature dataset
data.gas.mass_weighted_temps = data.gas.masses * data.gas.temperatures

# Map in msun / mpc^2
mass_map = project_gas(data, resolution=1024, project="masses", parallel=True)
# Map in msun * K / mpc^2
mass_weighted_temp_map = project_gas(data,
                                     resolution=1024,
                                     project="mass_weighted_temps",
                                     parallel=True)

temp_map = mass_weighted_temp_map / mass_map

from unyt import K

temp_map.convert_to_units(K)

from matplotlib.pyplot import imsave
from matplotlib.colors import LogNorm

# Normalize and save
imsave("/cosma5/data/durham/dc-murr1/temp_map.png",
       LogNorm()(temp_map.value),
       cmap="hot")
    print(f"Rendering {snap_relative_filepaths[i]}...")
    # Load data using mask
    xCen = unyt.unyt_quantity(x[i], unyt.Mpc)
    yCen = unyt.unyt_quantity(y[i], unyt.Mpc)
    zCen = unyt.unyt_quantity(z[i], unyt.Mpc)
    size = unyt.unyt_quantity(out_to_radius * R200c[i], unyt.Mpc)
    mask = sw.mask(snapFile)
    region = [
        [xCen - size, xCen + size],
        [yCen - size, yCen + size],
        [zCen - size, zCen + size]
    ]
    mask.constrain_spatial(region)

    # Load data using mask
    data = sw.load(snapFile, mask=mask)
    posDM = data.dark_matter.coordinates / data.metadata.a
    coord_x = posDM[:, 0] - xCen
    coord_y = posDM[:, 1] - yCen
    coord_z = posDM[:, 2] - zCen
    del posDM

    # Make figure
    fig, ax = plt.subplots(figsize=(8, 8), dpi=1024 // 8)
    ax.set_aspect('equal')
    ax.plot(coord_x, coord_y, ',', c="C0", alpha=0.1)
    ax.set_xlim([-size.value, size.value])
    ax.set_ylim([-size.value, size.value])
    ax.set_ylabel(r"$y$ [Mpc]")
    ax.set_xlabel(r"$x$ [Mpc]")
    ax.text(
Example #27
0
def get_image(n):
    """
    Gets the image for snapshot n, and also returns the associated
    SWIFT metadata object.
    """
    filename = f"{snapshot_name}_{n:04d}.hdf5"

    data = load(filename)
    boxsize = data.metadata.boxsize[0].value

    output = np.zeros((resolution, resolution * 4), dtype=float)

    x, y, z = data.gas.coordinates.value.T

    # This is an oblong box but we can only make squares!
    for box, box_edges in enumerate([[0.0, 1.1], [0.9, 2.1], [1.9, 3.1],
                                     [2.9, 4.0]]):
        mask = np.logical_and(x >= box_edges[0], x <= box_edges[1])
        masked_x = x[mask] - np.float64(box)
        masked_y = y[mask]
        masked_z = z[mask]

        try:
            hsml = data.gas.smoothing_length.value[mask]
        except:
            hsml = data.gas.smoothing_lengths.value[mask]

        if plot == "density":
            mass = data.gas.masses.value[mask]
            image = slice(
                x=masked_y,
                y=masked_x,
                z=masked_z,
                m=mass,
                h=hsml,
                z_slice=0.5,
                res=resolution,
            )
        else:
            quantity = getattr(data.gas, plot).value[mask]
            # Need to divide out the particle density for non-projected density quantities
            image = scatter(
                x=masked_y,
                y=masked_x,
                z=masked_z,
                m=quantity,
                h=hsml,
                z_slice=0.5,
                res=resolution,
            ) / scatter(
                x=masked_y,
                y=masked_x,
                z=masked_z,
                m=np.ones_like(quantity),
                h=hsml,
                z_slice=0.5,
                res=resolution,
            )

        output[:, box * resolution:(box + 1) * resolution] = image

    return output, data.metadata
Example #28
0
def profile_3d_shells(
    path_to_snap: str,
    path_to_catalogue: str,
) -> tuple:
    # Read in halo properties
    vr_catalogue_handle = vr.load(path_to_catalogue)
    M500 = vr_catalogue_handle.spherical_overdensities.mass_500_rhocrit[0].to(
        'Msun')
    R500 = vr_catalogue_handle.spherical_overdensities.r_500_rhocrit[0].to(
        'Mpc')
    XPotMin = vr_catalogue_handle.positions.xcminpot[0].to('Mpc')
    YPotMin = vr_catalogue_handle.positions.ycminpot[0].to('Mpc')
    ZPotMin = vr_catalogue_handle.positions.zcminpot[0].to('Mpc')

    # Apply spatial mask to particles. SWIFTsimIO needs comoving coordinates
    # to filter particle coordinates, while VR outputs are in physical units.
    # Convert the region bounds to comoving, but keep the CoP and Rcrit in
    # physical units for later use.
    mask = sw.mask(path_to_snap, spatial_only=True)
    region = [[(XPotMin - R500), (XPotMin + R500)],
              [(YPotMin - R500), (YPotMin + R500)],
              [(ZPotMin - R500), (ZPotMin + R500)]]
    mask.constrain_spatial(region)
    data = sw.load(path_to_snap, mask=mask)

    # Select gas within sphere and main FOF halo
    fof_id = data.gas.fofgroup_ids
    tempGas = data.gas.temperatures
    deltaX = data.gas.coordinates[:, 0] - XPotMin
    deltaY = data.gas.coordinates[:, 1] - YPotMin
    deltaZ = data.gas.coordinates[:, 2] - ZPotMin
    radial_distance = np.sqrt(deltaX**2 + deltaY**2 + deltaZ**2) / R500
    index = np.where((radial_distance < 2) & (fof_id == 1)
                     & (tempGas > 1e5))[0]
    del deltaX, deltaY, deltaZ, fof_id, tempGas

    radial_distance = radial_distance[index]
    data.gas.masses = data.gas.masses[index]
    data.gas.temperatures = data.gas.temperatures[index]

    # Define radial bins and shell volumes
    lbins = np.logspace(-3, 2, 40) * radial_distance.units
    radial_bin_centres = 10.0**(
        0.5 * np.log10(lbins[1:] * lbins[:-1])) * radial_distance.units
    volume_shell = (4. * np.pi / 3.) * (R500**3) * ((lbins[1:])**3 -
                                                    (lbins[:-1])**3)

    mass_weights, _ = histogram_unyt(radial_distance,
                                     bins=lbins,
                                     weights=data.gas.masses)
    mass_weights[mass_weights == 0] = np.nan  # Replace zeros with Nans
    density_profile = mass_weights / volume_shell
    number_density_profile = (density_profile.to('g/cm**3') /
                              (unyt.mp * mean_molecular_weight)).to('cm**-3')

    mass_weighted_temperatures = (
        data.gas.temperatures *
        unyt.boltzmann_constant).to('keV') * data.gas.masses
    temperature_weights, _ = histogram_unyt(radial_distance,
                                            bins=lbins,
                                            weights=mass_weighted_temperatures)
    temperature_weights[temperature_weights ==
                        0] = np.nan  # Replace zeros with Nans
    temperature_profile = temperature_weights / mass_weights  # kBT in units of [keV]

    entropy_profile = temperature_profile / number_density_profile**(2 / 3)

    rho_crit = unyt.unyt_quantity(
        data.metadata.cosmology.critical_density(data.metadata.z).value,
        'g/cm**3').to('Msun/Mpc**3')
    density_profile /= rho_crit

    return radial_bin_centres, density_profile, temperature_profile, entropy_profile, M500, R500
import sys
import matplotlib

matplotlib.use("Agg")

import matplotlib.pyplot as plt
import numpy as np
from scipy import stats

from swiftsimio import load
from analyticSolution import analytic

snap = int(sys.argv[1])

sim = load(f"sedov_{snap:04d}.hdf5")

# Set up plotting stuff
try:
    plt.style.use("mnras_durham")
except:
    rcParams = {
        "font.serif": ["STIX", "Times New Roman", "Times"],
        "font.family": ["serif"],
        "mathtext.fontset": "stix",
        "font.size": 8,
    }
    plt.rcParams.update(rcParams)

# See analyticSolution for params.
Example #30
0
def plot_result(filename):
    """
    Create and save the plot
    """
    print("working on", filename)

    data = swiftsimio.load(filename)
    meta = data.metadata

    global imshow_kwargs
    imshow_kwargs["extent"] = [
        0.0 * meta.boxsize[0].v,
        0.9 * meta.boxsize[0].v,
        0.0 * meta.boxsize[1].v,
        0.9 * meta.boxsize[1].v,
    ]
    cutoff = int(0.05 * projection_kwargs["resolution"])

    mass_map = swiftsimio.visualisation.projection.project_gas(
        data, project="masses", **projection_kwargs)
    gamma = meta.hydro_scheme["Adiabatic index"][0]

    data.gas.mXHI = data.gas.ion_mass_fractions.HI * data.gas.masses
    data.gas.mXHII = data.gas.ion_mass_fractions.HII * data.gas.masses
    data.gas.mP = data.gas.pressures * data.gas.masses
    data.gas.mrho = data.gas.densities * data.gas.masses

    imf = data.gas.ion_mass_fractions
    mu = mean_molecular_weight(imf.HI, imf.HII, imf.HeI, imf.HeII, imf.HeIII)
    data.gas.mT = (gas_temperature(data.gas.internal_energies, mu, gamma) *
                   data.gas.masses)

    mass_weighted_hydrogen_map = swiftsimio.visualisation.projection.project_gas(
        data, project="mXHI", **projection_kwargs)
    mass_weighted_pressure_map = swiftsimio.visualisation.projection.project_gas(
        data, project="mP", **projection_kwargs)
    mass_weighted_density_map = swiftsimio.visualisation.projection.project_gas(
        data, project="mrho", **projection_kwargs)
    mass_weighted_temperature_map = swiftsimio.visualisation.projection.project_gas(
        data, project="mT", **projection_kwargs)

    hydrogen_map = mass_weighted_hydrogen_map / mass_map
    hydrogen_map = hydrogen_map[cutoff:-cutoff, cutoff:-cutoff]

    pressure_map = mass_weighted_pressure_map / mass_map
    pressure_map = pressure_map[cutoff:-cutoff, cutoff:-cutoff]
    pressure_map = pressure_map.to("g/cm/s**2")

    density_map = mass_weighted_density_map / mass_map
    density_map = density_map[cutoff:-cutoff, cutoff:-cutoff]
    density_map = density_map.to("kg/cm**3")
    density_map = density_map / unyt.proton_mass

    temperature_map = mass_weighted_temperature_map / mass_map
    temperature_map = temperature_map[cutoff:-cutoff, cutoff:-cutoff]
    temperature_map = temperature_map.to("K")

    fig = plt.figure(figsize=(12, 12), dpi=200)
    figname = filename[:-5] + ".png"

    ax1 = fig.add_subplot(221)
    ax2 = fig.add_subplot(222)
    ax3 = fig.add_subplot(223)
    ax4 = fig.add_subplot(224)

    try:
        im1 = ax1.imshow(
            density_map.T,
            **imshow_kwargs,
            norm=LogNorm(vmin=1e-4, vmax=1e-1),
            cmap="bone",
        )
        set_colorbar(ax1, im1)
        ax1.set_title(r"Hydrogen Number Density [cm$^{-3}$]")
    except ValueError:
        print(
            filename,
            "densities wrong? min",
            data.gas.densities.min(),
            "max",
            data.gas.densities.max(),
        )
        return

    try:
        im2 = ax2.imshow(
            hydrogen_map.T,
            **imshow_kwargs,
            norm=LogNorm(vmin=1e-3, vmax=1.0),
            cmap="cividis",
        )
        set_colorbar(ax2, im2)
        ax2.set_title("Hydrogen Mass Fraction [1]")
    except ValueError:
        print(
            filename,
            "mass fraction wrong? min",
            data.gas.ion_mass_fractions.HI.min(),
            "max",
            data.gas.ion_mass_fractions.HI.max(),
        )
        return

    try:
        im3 = ax3.imshow(
            pressure_map.T,
            **imshow_kwargs,
            norm=LogNorm(vmin=1e-15, vmax=1e-12),
            cmap="viridis",
        )
        set_colorbar(ax3, im3)
        ax3.set_title(r"Pressure [g/cm/s$^2$]")
    except ValueError:
        print(
            filename,
            "pressures wrong? min",
            data.gas.pressures.min(),
            "max",
            data.gas.pressures.max(),
        )
        return

    try:
        im4 = ax4.imshow(
            temperature_map.T,
            **imshow_kwargs,
            norm=LogNorm(vmin=1e2, vmax=4e4),
            cmap="inferno",
        )
        set_colorbar(ax4, im4)
        ax4.set_title(r"Temperature [K]")
    except ValueError:
        print(
            filename,
            "temperatures wrong? min",
            temperature_map.min(),
            "max",
            temperature_map.max(),
        )
        return

    for ax in [ax1, ax2, ax3, ax4]:
        ax.set_xlabel("[kpc]")
        ax.set_ylabel("[kpc]")

    title = filename.replace("_",
                             "\_")  # exception handle underscore for latex
    if meta.cosmology is not None:
        title += ", $z$ = {0:.2e}".format(meta.z)
    title += ", $t$ = {0:.2e}".format(meta.time.to("Myr"))
    fig.suptitle(title)

    plt.tight_layout()
    plt.savefig(figname)
    plt.close()
    gc.collect()
    return