Field and window operations#

SFCField stores a represented field. WindowFunc stores an operator compatible with that representation. Their small algebra is the low-level language from which PyHermes tasks are assembled.

The complete window notebook demonstrates the same operations interactively, including built-in kernels, custom windows, and window composition.

Load a field#

from pyhermes.io import SFCField, WindowFunc

D = SFCField(
    data_path="./output/quijote8000_snap004_sfc.pkl",
    threads=8,
)

Field arithmetic#

Compatible fields support coefficient-wise arithmetic:

delta = D - D.field_mean_density(value_unit="grid")
cross_sum = field_a + field_b
local_product = field_a * field_b
rescaled = 2.0 * field_a

+ and - combine fields. * between two fields forms their local coefficient-space product; * with a scalar rescales a field. The result is another SFCField marked as a derived field.

Apply a window#

smooth = WindowFunc(
    {"type": "gaussian", "len_args": {"R": 10.0}},
    D.sfc_info,
    threads=8,
)
delta_smooth = delta @ smooth

@ is reserved for field–window convolution. The kernel is built lazily the first time smooth.as_array() or delta @ smooth is called, then cached on the object.

The two multiplications are deliberately different:

filtered = delta @ smooth       # convolution in real space
quadratic = filtered * filtered # local field product

This distinction mirrors the Hermes equations: first construct window-filtered fields, then multiply and average them.

Inspect values#

as_array() returns the represented coefficient array:

epsilon = delta_smooth.as_array()
mean_product = quadratic.as_array().mean()

To evaluate the reconstructed continuous field at positions, use:

values = delta_smooth.field_density_at_pos(
    positions,
    value_unit="physical",
)

Compatibility#

Fields and windows must agree in J, box_size, wavelet_mode, wavelet_level, and phi_resolution. Always construct a window from the sfc_info of the field it will act on. A visually similar array from another grid is not interchangeable.

Window arithmetic#

Window addition, subtraction, and scalar arithmetic combine materialised projected kernels. For example, a projected finite shell can be explored as a volume-weighted difference of two top-hats:

R, width = 40.0, 6.0
r_in, r_out = R - width / 2.0, R + width / 2.0

W_in = WindowFunc(
    {"type": "sphere", "len_args": {"R": r_in}}, D.sfc_info
)
W_out = WindowFunc(
    {"type": "sphere", "len_args": {"R": r_out}}, D.sfc_info
)
W_shell_projected = (
    r_out**3 * W_out - r_in**3 * W_in
) / (r_out**3 - r_in**3)

The built-in thick_shell is preferable for production because its complete continuous Fourier expression is projected once.

Likewise, W1 * W2 is a pointwise product of two already projected kernels. It is useful for experiments with separable factors, but it is not identical to projecting the bare continuous product once. See Window reference for the full numerical note.

A custom window#

Custom ordinary kernels use the same interface:

import numpy as np
from numba import njit

@njit
def transverse_gaussian(ki, kj, kk, R):
    q2 = (2.0 * np.pi * R) ** 2 * (ki * ki + kj * kj)
    return np.exp(-0.5 * q2)

W_perp = WindowFunc(
    {"func": transverse_gaussian, "len_args": {"R": 5.0}},
    D.sfc_info,
    threads=8,
)

ki, kj, and kk are cycle frequencies in grid coordinates. Physical lengths belong in len_args and are rescaled automatically. If both type and func are supplied, the callable is authoritative: type remains a descriptive name, but it does not activate same-named built-in argument defaults or validation.

Use the task layer when appropriate#

Direct operations are ideal for understanding an estimator, constructing a new physical field, or prototyping a custom statistic. For production Counting, 2PCF, and 3PCF runs, task classes also manage data/random fields, sampling grids, MPI distribution, dependencies among output products, and metadata. Low-level and high-level paths use the same field/window machinery.

Public tutorial#

The rendered window notebook demonstrates field arithmetic, ordinary windows, custom kernels, projected-kernel composition, smoothing versus binning roles, and Fourier-space sketches of the built-in library.