YTEP-0024: Alternative Smoothing Kernels


Created: August 1, 2015 Author: Bili Dong

This YTEP proposes to add alternative smoothing kernels besides the current standard cubic spline one, make them available to the smoothing operations, and define a convenient interface for users to choose among them.



Detailed Description

Currently in yt, the standard cubic spline kernel is exclusively used for smoothing operations. It is a desired feature for yt to have support for varied smoothing kernels.

The implementations of the kernel functions themselves are straightforward. [DA2012] is referenced for the function forms and the kernel names.

The bigger challenge is the design of a convenient user interface for future users and a convenient application programming interface for future developers. Details of those designs are explained in the following sections.

User Interface

Future users can specify which kernel to use in the smoothing operations by passing a keyword argument kernel_name to the relevant functions. Currently, functions with potential access to kernels include Dataset.add_deposited_particle_field and Dataset.add_smoothed_particle_field [1]. The naming scheme for fields added through these functions is an extension of the scheme described in SPH Fields, which is proposed by Nathan Goldbaum in this yt-dev thread. So a particle field ("particletype", "fieldname") smoothed by a certain kernel can be accessed by ("deposit", "particletype_kernelname_smoothed_fieldname"), except for the cubic spline kernel, whose smoothed field remains to be ("deposit", "particletype_smoothed_fieldname") (the same as before).

For example, as demonstrated by the following code, the particle field ("PartType0", "Density") is smoothed using a quintic kernel and the resultant smoothed field could be accessed by ("deposit", "PartType0_quintic_smoothed_Density"). [2]

import yt

ds = yt.load("GadgetDiskGalaxy/snapshot_200.hdf5")
ds.add_smoothed_particle_field(("PartType0", "Density"), kernel_name="quintic")

yt.ProjectionPlot(ds, "z", ("deposit", "PartType0_quintic_smoothed_Density"))

Below is a table of available kernel_name and the corresponding name in [DA2012]. All kernels are in 3D (a.k.a. \nu = 3).

Kernel Names
kernel_name Name in [DA2012]
cubic Cubic spline
quartic Quartic spline
quintic Quintic spline
wendland2 Wendland C2
wendland4 Wendland C4
wendland6 Wendland C6
[1]Dataset.add_smoothed_particle_field is a wrapper of add_volume_weighted_smoothed_field. It is more convenient to use. So, for simplicity, add_volume_weighted_smoothed_field will be omitted in the following discussions.
[2]The dataset can be downloaded from here.

Application Programming Interface

When a kernel function is needed, get_kernel_func is used to retrieve it. Given the string of the kernel name, a kernel function of the type kernel_func is returned. Both get_kernel_func and kernel_func are defined in geometry/particle_deposit.pxd. The following snippet demonstrate their usage, assuming the source file is in the same directory as particle_deposit.pxd.

from .particle_deposit cimport kernel_func, get_kernel_func

cdef class DemoParticleSmoothOperation:
    cdef kernel_func sph_kernel
    def __init__(self, kernel_name):
        self.sph_kernel = get_kernel_func(kernel_name)

Once the kernel function is retrieved, self.sph_kernel could be utilized to do the smoothing.

The rest of the changes to the API is merely the passing of the keyword argument kernel_name. Below is a table demonstrating the potential passing routes:

Passing of kernel_name through Methods (or Functions)
# Method Pass to [3] File Path
1 SimpleSmooth (aliased as deposit_simple_smooth) [4]   yt/geometry/particle_deposit.pyx
2 VolumeWeightedSmooth (aliased as volume_weighted_smooth) [4]   yt/geometry/particle_smooth.pyx
3 SmoothedDensityEstimate (aliased as density_smooth) [4]   yt/geometry/particle_smooth.pyx
4 ARTIORootMeshSubset.deposit 1 yt/frontends/artio/
5 YTCoveringGridBase.deposit 1 yt/data_objects/
6 AMRGridPatch.deposit 1 yt/data_objects/
7 UnstructuredMesh.deposit 1 yt/data_objects/
8 OctreeSubset.deposit 1 yt/data_objects/
9 OctreeSubset.smooth 2, 3 yt/data_objects/
10 OctreeSubset.particle_operation 2, 3 yt/data_objects/
11 Dataset.add_deposited_particle_field 4 - 8 yt/data_objects/
12 Dataset.add_smoothed_particle_field 9 yt/data_objects/
[3]This column indicates the possibility that kernel_name could be passed to ‘Pass to’, which also depends on another parameter method.
[4](1, 2, 3) When a class is given, its __init__ method is meant.

To demonstrate how 4 - 10 utilize 1 - 3, the main structure of the smooth method is shown below (irrelevant parts are ignored; deposit and particle_operation are similar).

def smooth(self, method = None, kernel_name = "cubic", ...):
    cls = getattr(particle_smooth, "%s_smooth" % method, None)
    op = cls(..., kernel_name)

op is used for the actual smoothing operations thereafter.

For 11 & 12, they simply call the dataset’s deposit or smooth method to get the smoothing operations done.

Backwards Compatibility

New functionality is accessed by the keyword argument kernel_name with default value kernel_name = "cubic", so existing codes’ behavior won’t change.