Skip to content
Merged
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Documentation contents
halo_catalogues/index
masking/index
iterating/index
visualisation/index
modules/index

Citing SWIFTGalaxy
Expand Down
30 changes: 30 additions & 0 deletions docs/source/visualisation/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Visualisation
=============

:class:`~swiftgalaxy.reader.SWIFTGalaxy` objects behave just like :class:`~swiftsimio.reader.SWIFTDataset` objects for the purposes of using the :mod:`~swiftsimio.visualisation` tools. Keep in mind that a :class:`~swiftgalaxy.reader.SWIFTGalaxy` has usually applied a mask to particles and has recentered and/or transformed the coordinate frame. The mask is one reason that it is usually best to set ``periodic=False`` when calling visualisation routines.

.. warning::
The :mod:`swiftsimio` visualisation tools do correctly handle periodic boundaries when coordinates have been rotated. The visualisation tools cannot currently detect whether a :class:`~swiftgalaxy.reader.SWIFTGalaxy` object has been rotated, and can give incorrect results if periodic boundaries are used. It is therefore recommended to always set ``periodic=False`` in all calls to :mod:`swiftsimio` visualisation routines.

When a :class:`~swiftgalaxy.reader.SWIFTGalaxy` has been recentered (the default behaviour) the visualisation ``region`` should be given relative to the centre, not the box coordinates. For example:

.. code-block:: python

from swiftsimio.visualisation.projection import project_gas
sg = SWIFTGalaxy(..., auto_recenter=True) # the default
image = project_gas(
sg,
project="masses",
parallel=True,
periodic=False,
resolution=256,
region=cosmo_array(
[-0.5, 0.5, -0.5, 0.5],
u.Mpc,
comoving=True,
scale_factor=sg.metadata.a,
scale_exponent=1,
)
)

For general information on the visualisation routines consult the swiftsimio documentation pages.
57 changes: 29 additions & 28 deletions examples/SWIFTGalaxy_Colibre_QuickStart.ipynb

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions swiftgalaxy/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def _apply_rotmat(coords: cosmo_array, rotation_matrix: np.ndarray) -> cosmo_arr


def _apply_4transform(
coords: cosmo_array, transform: np.ndarray, transform_units: unyt.unyt_quantity
coords: cosmo_array, transform: np.ndarray, transform_units: unyt.unit_object.Unit
) -> cosmo_array:
"""
Apply an arbitary coordinate transformation (translation mixed with rotation) to a
Expand All @@ -158,7 +158,7 @@ def _apply_4transform(
The coordinate array to be transformed.
transform : :class:`~numpy.ndarray`
The 4x4 transformation matrix.
transform_units : :class:`unyt.unyt_quantity`
transform_units : :class:`unyt.unit_object.Unit`
The units assumed in the translation portion of the transformation matrix.

Returns
Expand Down
127 changes: 127 additions & 0 deletions tests/test_visualisation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import pytest
import numpy as np
import unyt as u
from swiftsimio import cosmo_array, cosmo_quantity
from swiftsimio.visualisation.projection import project_gas
from swiftsimio.visualisation.slice import slice_gas
from swiftsimio.visualisation.volume_render import render_gas


@pytest.mark.parametrize("periodic", [False, True])
class TestRecenteredVisualisation:

@pytest.mark.parametrize("z_cut", [False, True])
def test_recentered_projection(self, sg, sg_autorecentre_off, z_cut, periodic):
"""
We should be able to make the same projections whether we recentered or not.
"""
z_limits = [1.9, 2.1] if z_cut else []
recentered_z_limits = [-0.1, 0.1] if z_cut else []
kwargs = {
"resolution": 4,
"project": "masses",
"parallel": True,
"periodic": periodic,
}
ref_img = project_gas(
sg_autorecentre_off,
region=cosmo_array(
[1.5, 2.5, 1.5, 2.5] + z_limits,
u.Mpc,
comoving=True,
scale_factor=1,
scale_exponent=1,
),
**kwargs,
)
recentered_img = project_gas(
sg,
region=cosmo_array(
[-0.5, 0.5, -0.5, 0.5] + recentered_z_limits,
u.Mpc,
comoving=True,
scale_factor=1,
scale_exponent=1,
),
**kwargs,
)
assert (ref_img > 0).any()
assert np.allclose(ref_img, recentered_img)

def test_recentered_slice(self, sg, sg_autorecentre_off, periodic):
"""
We should be able to make the same slice whether we recentered or not.
"""
z_slice = cosmo_quantity(
1.95, u.Mpc, comoving=True, scale_factor=1, scale_exponent=1
)
recentered_z_slice = cosmo_quantity(
-0.05, u.Mpc, comoving=True, scale_factor=1, scale_exponent=1
)
kwargs = {
"resolution": 4,
"project": "masses",
"parallel": True,
"periodic": periodic,
}
ref_img = slice_gas(
sg_autorecentre_off,
z_slice=z_slice,
region=cosmo_array(
[1.5, 2.5, 1.5, 2.5],
u.Mpc,
comoving=True,
scale_factor=1,
scale_exponent=1,
),
**kwargs,
)
recentered_img = slice_gas(
sg,
z_slice=recentered_z_slice,
region=cosmo_array(
[-0.5, 0.5, -0.5, 0.5],
u.Mpc,
comoving=True,
scale_factor=1,
scale_exponent=1,
),
**kwargs,
)
assert (ref_img > 0).any()
assert np.allclose(ref_img, recentered_img)

def test_recentered_volume_render(self, sg, sg_autorecentre_off, periodic):
"""
We should be able to make the same rendering whether we recentered or not.
"""
kwargs = {
"resolution": 4,
"project": "masses",
"parallel": True,
"periodic": periodic,
}
ref_img = render_gas(
sg_autorecentre_off,
region=cosmo_array(
[1.5, 2.5, 1.5, 2.5, 1.5, 2.5],
u.Mpc,
comoving=True,
scale_factor=1,
scale_exponent=1,
),
**kwargs,
)
recentered_img = render_gas(
sg,
region=cosmo_array(
[-0.5, 0.5, -0.5, 0.5, -0.5, 0.5],
u.Mpc,
comoving=True,
scale_factor=1,
scale_exponent=1,
),
**kwargs,
)
assert (ref_img > 0).any()
assert np.allclose(ref_img, recentered_img)
5 changes: 4 additions & 1 deletion tests/toysnap.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ def create_toysnap(
"""
Creates a sample dataset of a toy galaxy.
"""
if os.path.isfile(snapfile):
return

sd = Writer(cosmo_units, np.ones(3, dtype=float) * boxsize)

Expand Down Expand Up @@ -663,7 +665,8 @@ def create_toysnap(


def remove_toysnap(snapfile=toysnap_filename):
os.remove(snapfile)
if os.path.isfile(snapfile):
os.remove(snapfile)
return


Expand Down