Skip to content
Oakfield Operator Calculus Function Reference Site

Advection Operators

sim_add_analytic_warp_operator(ctx, field, opts)

Apply nonlinear analytic deformations to field values using special function profiles. Useful for implementing nonlinear response curves, soft saturation, and phase-space warping.

sim_add_analytic_warp_operator(ctx, field, [options]) -> operator

Returns: Operator handle (userdata)

The operator applies a profile function ϕ\phi with symmetric gradient estimation:

uu+Δtλ(2δ)ϕ(u+bias)u \leftarrow u + \Delta t \cdot \lambda \cdot (2\delta) \cdot \phi'(u + \text{bias})

where ϕ\phi' is approximated via symmetric finite differences using the delta parameter.

Available profiles:

  • digamma: ϕ(z)=ψ(z)=ddzlnΓ(z)\phi(z) = \psi(z) = \frac{d}{dz}\ln\Gamma(z) — logarithmic derivative of gamma function
  • trigamma: ϕ(z)=ψ1(z)=d2dz2lnΓ(z)\phi(z) = \psi_1(z) = \frac{d^2}{dz^2}\ln\Gamma(z) — second derivative
  • power: ϕ(z)=zp\phi(z) = z^p where pp is the exponent parameter
  • tanh: ϕ(z)=tanh(z)\phi(z) = \tanh(z) — hyperbolic tangent saturation
  • hyperexp: ϕ(z)=k=0K1λλ+ε+k\phi(z) = \sum_{k=0}^{K-1} \frac{\lambda}{\lambda + \varepsilon + k} — hyperexponential sum
  • qhyperexp: ϕq(z)=k=0K1λλ+εqk\phi_q(z) = \sum_{k=0}^{K-1} \frac{\lambda}{\lambda + \varepsilon q^k} — q-deformed hyperexponential

Core Parameters:

ParameterTypeDefaultRangeDescription
profileenum "digamma"see aboveAnalytic profile function
deltadouble 1e-3≥0Symmetric offset for gradient estimation
lambdadouble 1.0unboundedScaling applied to warp response
biasdouble 0.0unboundedAdditive bias before profile evaluation

Power Profile:

ParameterTypeDefaultRangeDescription
exponentdouble 2.0≥0Power exponent for profile = "power"

Hyperexp/Qhyperexp:

ParameterTypeDefaultRangeDescription
hyperexp_epsilondouble 1.0≥0Pole shift control parameter
hyperexp_depthinteger 8≥1Truncation depth for sum
hyperexp_qdouble 0.9[0, 1]q-deformation parameter

Complex Field Handling:

ParameterTypeDefaultDescription
complex_modeenum "component"component: process re/im independently; polar: preserve phase direction

Continuity Guards:

ParameterTypeDefaultRangeDescription
continuity_modeenum "none"none, strict, clamped, limitedSingularity handling policy
continuity_clamp_mindouble -1e6unboundedLower bound for clamped mode
continuity_clamp_maxdouble 1e6unboundedUpper bound for clamped mode
continuity_tolerancedouble 1e-9≥0Blend radius for limited mode
  • Operates pointwise; no spatial boundary handling required
  • Field values should be in a domain where the profile function is well-defined
  • For digamma/trigamma, avoid non-positive integers (poles of gamma function)
  • Stability depends on the profile and lambda parameter
  • Large lambda values can cause rapid field evolution; reduce timestep accordingly
  • The continuity_mode options help guard against singularities:
    • strict: Error on singular inputs
    • clamped: Clamp outputs to [continuity_clamp_min, continuity_clamp_max]
    • limited: Smooth blend near singularities using tolerance
  • Pointwise operation; scales linearly with field size
  • hyperexp and qhyperexp profiles require O(K)O(K) operations per sample where KK = hyperexp_depth
  • Complex fields in polar mode require additional magnitude/phase conversions
-- Power-law nonlinearity with exponent 1.5
ooc.sim_add_analytic_warp_operator(ctx, field, {
profile = "power",
exponent = 1.5,
lambda = 0.4
})
-- Soft saturation using tanh
ooc.sim_add_analytic_warp_operator(ctx, field, {
profile = "tanh",
lambda = 2.0,
bias = 0.0
})
-- Digamma warp with continuity protection
ooc.sim_add_analytic_warp_operator(ctx, field, {
profile = "digamma",
lambda = 0.1,
continuity_mode = "clamped",
continuity_clamp_min = -10.0,
continuity_clamp_max = 10.0
})
-- Hyperexponential with q-deformation (complex field, polar mode)
ooc.sim_add_analytic_warp_operator(ctx, complex_field, {
profile = "qhyperexp",
hyperexp_depth = 16,
hyperexp_epsilon = 0.25,
hyperexp_q = 0.85,
complex_mode = "polar"
})
-- Trigamma profile for second-derivative response
ooc.sim_add_analytic_warp_operator(ctx, field, {
profile = "trigamma",
delta = 1e-4,
lambda = 0.05
})

sim_add_spatial_derivative_operator(ctx, src, dst, opts)

Compute first-order spatial derivatives u/x\partial u / \partial x using finite difference stencils. Fundamental building block for advection, gradient computation, and PDE discretization.

sim_add_spatial_derivative_operator(ctx, input, output, [options]) -> operator

Returns: Operator handle (userdata)

The operator computes ux\frac{\partial u}{\partial x} (or uy\frac{\partial u}{\partial y} when axis = 1) using finite differences:

Central difference (default):

uxiui+1ui12Δx\frac{\partial u}{\partial x}\bigg|_i \approx \frac{u_{i+1} - u_{i-1}}{2\Delta x}

Forward difference:

uxiui+1uiΔx\frac{\partial u}{\partial x}\bigg|_i \approx \frac{u_{i+1} - u_i}{\Delta x}

Backward difference:

uxiuiui1Δx\frac{\partial u}{\partial x}\bigg|_i \approx \frac{u_i - u_{i-1}}{\Delta x}

When skew_forward = true, the central scheme is biased toward the forward direction (useful for upwind schemes).

ParameterTypeDefaultRangeDescription
methodenum "central"central, forward, backwardFinite difference stencil
axisinteger 0[0, 1]Derivative axis (0 = x, 1 = y)
skew_forwardboolean falseBias central scheme toward upwind
spacingdouble 1.0[1e-9, 10.0]Grid spacing Δx\Delta x (alias: dx)
boundaryenum "periodic"see belowBoundary handling policy
accumulateboolean falseAdd to output instead of overwriting

Boundary options: periodic, neumann, dirichlet, reflective

Note: Lua accepts derivative as an alias for method.

  • Periodic: Wraps indices modulo field length
  • Neumann: Zero normal derivative; ghost cells mirror interior values
  • Dirichlet: Zero values at boundaries
  • Reflective: Mirror-reflects values across boundary
  • Pure derivative operators are unconditionally stable
  • Truncation error:
    • Central: O(Δx2)O(\Delta x^2)
    • Forward/Backward: O(Δx)O(\Delta x)
  • For advection problems, use upwind schemes (forward for positive velocity, backward for negative) to ensure stability
  • Central schemes can introduce dispersion errors in advection; skew_forward provides a compromise
  • Nonlocal operation requiring neighbor access
  • Does not use dt scaling by default (pure spatial operator)
  • For 2D gradients requiring both /x\partial/\partial x and /y\partial/\partial y, consider sim_add_gradient_operator instead

Read current configuration:

local cfg = ooc.sim_spatial_derivative_config(ctx, op_index)
-- Returns: { input_field, output_field, spacing, method, method_index, axis, skew_forward, boundary, accumulate }

Update configuration:

ooc.sim_spatial_derivative_update(ctx, op_index, {
axis = 1,
method = "backward",
spacing = 0.05,
boundary = "neumann"
})
-- Basic central difference
ooc.sim_add_spatial_derivative_operator(ctx, u, du_dx, {
method = "central",
spacing = 0.1
})
-- Forward difference for upwind advection (positive velocity)
ooc.sim_add_spatial_derivative_operator(ctx, u, du_dx, {
method = "forward",
spacing = 0.05,
boundary = "periodic"
})
-- Y-derivative with Dirichlet boundaries
ooc.sim_add_spatial_derivative_operator(ctx, u, du_dy, {
method = "central",
axis = 1,
spacing = 0.1,
boundary = "dirichlet"
})
-- Accumulate derivative into existing field
ooc.sim_add_spatial_derivative_operator(ctx, u, rhs, {
method = "backward",
spacing = dx,
accumulate = true
})
-- Query and modify at runtime
local cfg = ooc.sim_spatial_derivative_config(ctx, op_index)
if cfg then
ooc.log("∂/∂x: axis=%d method=%s dx=%.3g", cfg.axis, cfg.method, cfg.spacing)
end
ooc.sim_spatial_derivative_update(ctx, op_index, {
method = "backward",
skew_forward = false,
boundary = "neumann"
})

sim_add_gradient_operator(ctx, input, output_x, output_y, opts)

Compute 2D gradient components (xu,yu)(\partial_x u, \partial_y u) using finite difference stencils. Outputs the X and Y partial derivatives to separate fields.

sim_add_gradient_operator(ctx, input, output_x, output_y, [options]) -> operator

Returns: Operator handle (userdata)

For a scalar field u(x,y)u(x, y), the gradient is:

u=(ux,uy)\nabla u = \left( \frac{\partial u}{\partial x}, \frac{\partial u}{\partial y} \right)

The discrete approximation depends on the selected stencil:

  • central2 (2nd-order central): uxui+1ui12Δx\frac{\partial u}{\partial x} \approx \frac{u_{i+1} - u_{i-1}}{2 \Delta x}
  • central4 (4th-order central): uxui+2+8ui+18ui1+ui212Δx\frac{\partial u}{\partial x} \approx \frac{-u_{i+2} + 8u_{i+1} - 8u_{i-1} + u_{i-2}}{12 \Delta x}
  • forward2 (2nd-order forward): ux3ui+4ui+1ui+22Δx\frac{\partial u}{\partial x} \approx \frac{-3u_i + 4u_{i+1} - u_{i+2}}{2 \Delta x}
  • backward2 (2nd-order backward): ux3ui4ui1+ui22Δx\frac{\partial u}{\partial x} \approx \frac{3u_i - 4u_{i-1} + u_{i-2}}{2 \Delta x}
ParameterTypeDefaultRangeDescription
spacing_xdouble 1.0[1e-9, 10.0]Grid spacing in X direction
spacing_ydouble spacing_x[1e-9, 10.0]Grid spacing in Y direction (defaults to spacing_x if unset)
axis_xinteger 0[0, 7]Axis index for X derivative
axis_yinteger 1[0, 7]Axis index for Y derivative (must differ from axis_x)
stencilenum "central2"see belowFinite difference stencil type
boundaryenum "periodic"see belowBoundary condition handling
accumulateboolean falseAdd to output instead of overwriting
scale_by_dtboolean trueScale accumulated writes by dt

Stencil options: forward2, backward2, central2, forward4, central4

Boundary options: periodic, neumann, dirichlet, reflective

  • Periodic: Wraps around domain edges using modular indexing
  • Neumann: Zero-gradient at boundaries (ghost cells mirror interior)
  • Dirichlet: Zero values at boundaries
  • Reflective: Mirror-reflects values at boundaries
  • Central difference schemes are unconditionally stable for pure gradient computation
  • Higher-order stencils (central4) reduce truncation error from O(Δx2)O(\Delta x^2) to O(Δx4)O(\Delta x^4)
  • Forward/backward stencils introduce directional bias; use for upwind schemes in advection problems
  • Outputs to two separate fields; ensure both are allocated before calling
  • Complex fields are processed component-wise (real and imaginary gradients computed independently)
  • Stencil width affects memory access patterns; central4 requires wider halos
-- Basic 2D gradient with default central differences
local ux = ooc.sim_add_field(ctx, {256, 256}, { fill = 0.0 })
local uy = ooc.sim_add_field(ctx, {256, 256}, { fill = 0.0 })
ooc.sim_add_gradient_operator(ctx, u, ux, uy, {
spacing_x = 0.1,
spacing_y = 0.1
})
-- High-order gradient with Neumann boundaries
ooc.sim_add_gradient_operator(ctx, u, ux, uy, {
stencil = "central4",
spacing_x = 0.05,
boundary = "neumann"
})
-- Upwind gradient for advection (forward in X, backward in Y)
ooc.sim_add_gradient_operator(ctx, u, ux, uy, {
stencil = "forward2",
boundary = "periodic"
})