Skip to content

Commit

Permalink
Merge pull request #150 from SWIFTSIM/complete-projections-new
Browse files Browse the repository at this point in the history
Made sure visualisation functions include periodic copies of particles (attempt 2)
  • Loading branch information
JBorrow authored Nov 16, 2022
2 parents 8535ed2 + 7777721 commit a2e8ff3
Show file tree
Hide file tree
Showing 15 changed files with 1,556 additions and 634 deletions.
1 change: 1 addition & 0 deletions docs/source/visualisation/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ common interface:
project="masses", # Variable to project, e.g. masses, temperatures, etc.
parallel=False, # Construct the image in (thread) parallel?
region=None, # None, or a list telling which region to render_func_name
periodic=True, # Whether or not to apply periodic boundary conditions
)
The output of these functions comes with associated units and has the correct
Expand Down
66 changes: 60 additions & 6 deletions docs/source/visualisation/projection.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ Example
# This creates a grid that has units msun / Mpc^2, and can be transformed like
# any other unyt quantity
mass_map = project_gas(data, resolution=1024, project="masses", parallel=True)
mass_map = project_gas(
data,
resolution=1024,
project="masses",
parallel=True,
periodic=True,
)
# Let's say we wish to save it as msun / kpc^2,
from unyt import msun, kpc
Expand Down Expand Up @@ -61,13 +67,20 @@ this:
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)
mass_map = project_gas(
data,
resolution=1024,
project="masses",
parallel=True,
periodic=True,
)
# Map in msun * K / mpc^2
mass_weighted_temp_map = project_gas(
data,
resolution=1024,
project="mass_weighted_temps",
parallel=True
parallel=True,
periodic=True,
)
temp_map = mass_weighted_temp_map / mass_map
Expand Down Expand Up @@ -132,13 +145,38 @@ Example:
resolution=1024,
project="entropies",
parallel=True,
backend="subsampled"
backend="subsampled",
periodic=True,
)
This will likely look very similar to the image that you make with the default
``backend="fast"``, but will have a well-converged distribution at any resolution
level.

Periodic boundaries
-------------------

Cosmological simulations and many other simulations use periodic boundary
conditions. This has implications for the particles at the edge of the
simulation box: they can contribute to pixels on multiple sides of the image.
If this effect is not taken into account, then the pixels close to the edge
will have values that are too low because of missing contributions.

All visualisation functions by default assume a periodic box. Rather than
simply projecting each individual particle once, four additional periodic copies
of each particle are also projected. Most copies will project outside the valid
pixel range, but the copies that do not ensure that pixels close to the edge
receive all necessary contributions. Thanks to Numba optimisations, the overhead
of these additional copies is relatively small.

There are some caveats with this approach. If you try to visualise a subset of
the particles in the box (e.g. using a mask), then only periodic copies of
particles in this subset will be used. If the subset does not include particles
on the other side of the periodic boundary, then these will still be missing
from the projection. The same is true if you visualise a region of the box.
The periodic boundary wrapping is also not compatible with rotations (see below)
and should therefore not be used together with a rotation.

Rotations
---------

Expand Down Expand Up @@ -214,7 +252,13 @@ is shown in the ``velociraptor`` section.
# Use project_gas_pixel_grid to generate projected images
common_arguments = dict(data=data, resolution=512, parallel=True, region=visualise_region)
common_arguments = dict(
data=data,
resolution=512,
parallel=True,
region=visualise_region,
periodic=False, # disable periodic boundaries when using rotations
)
un_rotated = project_gas_pixel_grid(**common_arguments)
Expand Down Expand Up @@ -280,7 +324,8 @@ mass density map for dark matter. We provide a utility to do this through
resolution=1024,
project="masses",
parallel=True,
region=None
region=None,
periodic=True,
)
from matplotlib.pyplot import imsave
Expand Down Expand Up @@ -322,6 +367,9 @@ To use this function, you will need:
+ Smoothing lengths for all particles, ``h``.
+ The resolution you wish to make your square image at, ``res``.

Optionally, you will also need:
+ the size of the simulation box in x and y, ``box_x`` and ``box_y``.

The key here is that only particles in the domain [0, 1] in x, and [0, 1] in y
will be visible in the image. You may have particles outside of this range;
they will not crash the code, and may even contribute to the image if their
Expand All @@ -338,3 +386,9 @@ such that it lives within this range. Then you may use the function as follows:
``out`` will be a 2D :mod:`numpy` grid of shape ``[res, res]``. You will need
to re-scale this back to your original dimensions to get it in the correct units,
and do not forget that it now represents the smoothed quantity per surface area.

If the optional arguments ``box_x`` and ``box_y`` are provided, they should
contain the simulation box size in the same re-scaled coordinates as ``x`` and
``y``. The projection backend will then correctly apply periodic boundary
wrapping. If ``box_x`` and ``box_y`` are not provided or set to 0, no
periodic boundaries are applied.
49 changes: 44 additions & 5 deletions docs/source/visualisation/slice.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ Example
z_slice=0.5 * data.metadata.boxsize[2],
resolution=1024,
project="masses",
parallel=True
parallel=True,
periodic=True,
)
# Let's say we wish to save it as g / cm^2,
Expand Down Expand Up @@ -72,7 +73,8 @@ in units of K / kpc^3 and we just want K) by dividing out by this:
z_slice=0.5 * data.metadata.boxsize[2],
resolution=1024,
project="masses",
parallel=True
parallel=True,
periodic=True,
)
# Map in msun * K / mpc^3
Expand All @@ -81,7 +83,8 @@ in units of K / kpc^3 and we just want K) by dividing out by this:
z_slice=0.5 * data.metadata.boxsize[2],
resolution=1024,
project="mass_weighted_temps",
parallel=True
parallel=True,
periodic=True,
)
temp_map = mass_weighted_temp_map / mass_map
Expand All @@ -101,6 +104,31 @@ loading data section should look something like:

.. image:: temp_slice.png

Periodic boundaries
-------------------

Cosmological simulations and many other simulations use periodic boundary
conditions. This has implications for the particles at the edge of the
simulation box: they can contribute to pixels on multiple sides of the image.
If this effect is not taken into account, then the pixels close to the edge
will have values that are too low because of missing contributions.

All visualisation functions by default assume a periodic box. Rather than
simply summing each individual particle once, eight additional periodic copies
of each particle are also accounted for. Most copies will contribute outside the
valid pixel range, but the copies that do not ensure that pixels close to the
edge receive all necessary contributions. Thanks to Numba optimisations, the
overhead of these additional copies is relatively small.

There are some caveats with this approach. If you try to visualise a subset of
the particles in the box (e.g. using a mask), then only periodic copies of
particles in this subset will be used. If the subset does not include particles
on the other side of the periodic boundary, then these will still be missing
from the slice. The same is true if you visualise a region of the box.
The periodic boundary wrapping is also not compatible with rotations (see below)
and should therefore not be used together with a rotation.


Rotations
---------

Expand Down Expand Up @@ -141,7 +169,8 @@ the above example is shown below.
project="masses",
rotation_matrix=matrix,
rotation_center=center,
parallel=True
parallel=True,
periodic=False, # disable periodic boundaries when using rotations
)
# Map in msun * K / mpc^3
Expand All @@ -152,7 +181,8 @@ the above example is shown below.
project="mass_weighted_temps",
rotation_matrix=matrix,
rotation_center=center,
parallel=True
parallel=True,
periodic=False,
)
temp_map = mass_weighted_temp_map / mass_map
Expand Down Expand Up @@ -192,6 +222,9 @@ To use this function, you will need:
+ Smoothing lengths for all particles, ``h``.
+ The resolution you wish to make your square image at, ``res``.

Optionally, you will also need:
+ the size of the simulation box in x, y and z, ``box_x``, ``box_y`` and ``box_z``.

The key here is that only particles in the domain [0, 1] in x and y will be
visible in the image. You may have particles outside of this range; they will
not crash the code, and may even contribute to the image if their smoothing
Expand All @@ -210,3 +243,9 @@ not need to lie in the domain [0, 1]. Then you may use the function as follows:
``out`` will be a 2D :mod:`numpy` grid of shape ``[res, res]``. You will need
to re-scale this back to your original dimensions to get it in the correct units,
and do not forget that it now represents the smoothed quantity per volume.

If the optional arguments ``box_x``, ``box_y`` and ``box_z`` are provided, they
should contain the simulation box size in the same re-scaled coordinates as
``x``, ``y`` and ``z``. The slicing function will then correctly apply
periodic boundary wrapping. If ``box_x``, ``box_y`` and ``box_z`` are not
provided or set to 0, no periodic boundaries are applied.
48 changes: 43 additions & 5 deletions docs/source/visualisation/volume_render.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ Example
data,
resolution=256,
project="masses",
parallel=True
parallel=True,
periodic=True,
)
This basic demonstration creates a mass density cube.
Expand All @@ -59,20 +60,46 @@ this:
data,
resolution=256,
project="masses",
parallel=True
parallel=True,
periodic=True,
)
# Map in msun * K / mpc^3
mass_weighted_temp_cube = render_gas(
data,
resolution=256,
project="mass_weighted_temps",
parallel=True
parallel=True,
periodic=True,
)
# A 256 x 256 x 256 cube with dimensions of temperature
temp_cube = mass_weighted_temp_cube / mass_cube
Periodic boundaries
-------------------

Cosmological simulations and many other simulations use periodic boundary
conditions. This has implications for the particles at the edge of the
simulation box: they can contribute to voxels on multiple sides of the image.
If this effect is not taken into account, then the voxels close to the edge
will have values that are too low because of missing contributions.

All visualisation functions by default assume a periodic box. Rather than
simply summing each individual particle once, eight additional periodic copies
of each particle are also taken into account. Most copies will contribute
outside the valid voxel range, but the copies that do not ensure that voxels
close to the edge receive all necessary contributions. Thanks to Numba
optimisations, the overhead of these additional copies is relatively small.

There are some caveats with this approach. If you try to visualise a subset of
the particles in the box (e.g. using a mask), then only periodic copies of
particles in this subset will be used. If the subset does not include particles
on the other side of the periodic boundary, then these will still be missing
from the voxel cube. The same is true if you visualise a region of the box.
The periodic boundary wrapping is also not compatible with rotations (see below)
and should therefore not be used together with a rotation.

Rotations
---------

Expand Down Expand Up @@ -110,7 +137,8 @@ the above example is shown below.
project="masses",
rotation_matrix=matrix,
rotation_center=center,
parallel=True
parallel=True,
periodic=False, # disable periodic boundaries for rotations
)
# Map in msun * K / mpc^3
Expand All @@ -120,7 +148,8 @@ the above example is shown below.
project="mass_weighted_temps",
rotation_matrix=matrix,
rotation_center=center,
parallel=True
parallel=True,
periodic=False,
)
# A 256 x 256 x 256 cube with dimensions of temperature
Expand Down Expand Up @@ -150,6 +179,9 @@ To use this function, you will need:
+ Smoothing lengths for all particles, ``h``.
+ The resolution you wish to make your cube at, ``res``.

Optionally, you will also need:
+ the size of the simulation box in x, y and z, ``box_x``, ``box_y`` and ``box_z``.

The key here is that only particles in the domain [0, 1] in x, [0, 1] in y,
and [0, 1] in z. will be visible in the cube. You may have particles outside
of this range; they will not crash the code, and may even contribute to the
Expand All @@ -168,3 +200,9 @@ function as follows:
need to re-scale this back to your original dimensions to get it in the
correct units, and do not forget that it now represents the smoothed quantity
per volume.

If the optional arguments ``box_x``, ``box_y`` and ``box_z`` are provided, they
should contain the simulation box size in the same re-scaled coordinates as
``x``, ``y`` and ``z``. The rendering function will then correctly apply
periodic boundary wrapping. If ``box_x``, ``box_y`` and ``box_z`` are not
provided or set to 0, no periodic boundaries are applied
Loading

0 comments on commit a2e8ff3

Please sign in to comment.