Skip to content
Oakfield Operator Calculus Function Reference Site

Field Examples

A 1024-element complex field seeded with a unit-magnitude sinusoid at angular frequency 3:

local ctx = ooc.create()
ooc.set_timestep(ctx, 0.01)
local wave = ooc.add_field(ctx, {1024}, {
type = "complex_double",
origin = -math.pi,
spacing = 2 * math.pi / 1024,
initializer = function(i, x)
return { math.cos(3 * x), math.sin(3 * x) }
end
})
local v = wave:values()
ooc.log("wave rank=%d first=%0.3f+%0.3fi", wave:rank(), v[1][1], v[1][2])

Tag a complex field as spectral and Hermitian-constrained when it stores the Fourier image of a real physical signal:

local ctx = ooc.create()
local spectrum = ooc.add_field(ctx, {256}, {
type = "complex_double",
representation = {
domain = "spectral",
value_kind = "complex_real_constraint",
},
fill = {0.0, 0.0}
})
ooc.log("domain=%s value_kind=%s components=%d",
spectrum:domain(), spectrum:value_kind(), spectrum:components())

If you provide both top-level domain / value_kind and representation = { ... }, the nested representation table wins.


A 256 × 256 real field with a Gaussian blob centred at the physical origin. The initializer receives row index ix, column index iy, and their physical coordinates x, y:

local ctx = ooc.create()
local blob = ooc.add_field(ctx, {256, 256}, {
origin = -1.0,
spacing = 2.0 / 256,
initializer = function(ix, iy, x, y)
return math.exp(-8 * (x * x + y * y))
end
})
-- Read center value: row 128 (0-based 127), col 128 (0-based 127)
local vals = blob:values()
local shape = blob:shape()
local cols = shape[2]
local center = vals[(127 * cols) + 128] -- 1-based: row*cols + col
ooc.log("center = %.4f", center)

Initialize a 512 × 512 complex field with a spiral phase pattern using math.atan:

local ctx = ooc.create()
local spiral = ooc.add_field(ctx, {512, 512}, {
type = "complex_double",
origin = -math.pi,
spacing = 2 * math.pi / 512,
initializer = function(ix, iy, x, y)
local theta = math.atan(y, x)
return { math.cos(theta), math.sin(theta) }
end
})

Reading Parameters and Checking Layout Mid-Run

Section titled “Reading Parameters and Checking Layout Mid-Run”

Add a field, then inspect its storage metadata, representation tags, and cached stats:

local ctx = ooc.create()
local field = ooc.add_field(ctx, {64}, {
type = "complex_double",
representation = {
domain = "spectral",
value_kind = "complex",
},
fill = {1.0, 0.0}
})
local info = ooc.field_info(ctx, 0)
ooc.log("format=%s bytes=%d elements=%d", info.format, info.byte_size, info.element_count)
ooc.log("domain=%s value_kind=%s", field:domain(), field:value_kind())
local snapshot = field:values()
ooc.log("first element = %s", tostring(snapshot[1]))
local stats = ooc.field_stats(ctx, field)
ooc.log("rms=%.4f max=%.4f", stats.rms, stats.max_abs)
stats:refresh()
local counts = ooc.field_continuity_counts(ctx, 0)
ooc.log("continuity dirty=%d stable=%d", counts.dirty, counts.stable)

After grabbing snapshots, feed them into Lua visualizations or write them to disk; the Field handle remains valid as long as the context is alive.


field:set_values(table) replaces the field buffer from a Lua table. The table must have at least as many entries as the field has elements.

Real field — sine wave:

local ctx = ooc.create()
local f = ooc.add_field(ctx, {256}, { fill = 0.0 })
local data = {}
for i = 1, 256 do
data[i] = math.sin(2 * math.pi * (i - 1) / 256)
end
f:set_values(data)

Complex field — unit phasors:

local ctx = ooc.create()
local g = ooc.add_field(ctx, {512}, { type = "complex_double" })
local data = {}
for i = 1, 512 do
local x = 2 * math.pi * (i - 1) / 512
data[i] = { math.cos(x), math.sin(x) }
end
g:set_values(data)

Higher-rank seeding (rank ≥ 3) — initializers are not supported for rank ≥ 3, so use set_values:

local ctx = ooc.create()
local vol = ooc.add_field(ctx, {32, 32, 32}, { fill = 0.0 })
local data = {}
for i = 1, 32 * 32 * 32 do data[i] = math.random() end
vol:set_values(data)

field_stats_compute returns an immediate stats table without needing a step context:

local ctx = ooc.create()
local field = ooc.add_field(ctx, {128}, {
type = "complex_double",
initializer = function(i, x)
local phase = 2 * math.pi * i / 128
return { math.cos(phase), math.sin(phase) }
end
})
local s = ooc.field_stats_compute(field)
ooc.log("mean=%.4f rms=%.4f max=%.4f coherence=%.4f",
s.mean, s.rms, s.max_abs, s.phase_coherence)

Process a subset of elements (e.g. every other row) and compute stats manually:

local ctx = ooc.create()
local field = ooc.add_field(ctx, {32, 32}, {
initializer = function(ix, iy, x, y)
return math.sin(0.2 * ix) * math.cos(0.15 * iy)
end
})
local shape = field:shape()
local cols = shape[2]
local vals = field:values()
local acc = ooc.field_stats_accumulator_begin()
-- Accumulate only the even rows
for row = 1, shape[1], 2 do
for col = 1, cols do
local v = vals[(row - 1) * cols + col]
ooc.field_stats_accumulate_real(acc, v)
end
end
local result = ooc.field_stats_accumulator_finish(acc)
ooc.log("even-row rms=%.4f count=%d", result.rms, result.count)

Reuse an accumulator across frames to avoid repeated allocation:

local ctx = ooc.create()
local field = ooc.add_field(ctx, {64}, {
initializer = function(i, x)
return math.sin(2 * math.pi * i / 64)
end
})
local acc = ooc.field_stats_accumulator_begin()
for step = 1, 100 do
ooc.field_stats_accumulator_begin(acc) -- reset in-place
for _, v in ipairs(field:values()) do
ooc.field_stats_accumulate_real(acc, v)
end
local s = ooc.field_stats_accumulator_finish(acc)
ooc.log("step %d rms=%.4f", step, s.rms)
end

Compute spectral entropy and phase-coherence metrics for a complex field:

local ctx = ooc.create()
local field = ooc.add_field(ctx, {256}, {
type = "complex_double",
initializer = function(i, x)
local phase = 2 * math.pi * i / 256
return { math.cos(phase), math.sin(phase) }
end
})
-- Step 1: base stats
local s = ooc.field_stats_compute(field)
-- Step 2: spectral stats — updates s.spectral_entropy, s.spectral_bandwidth, etc.
local ok, dom_k = ooc.field_stats_compute_spectral_view(field, s)
-- Step 3: phase metrics — updates s.phase_coherence, s.phase_coherence_ema, etc.
if ok then
ooc.field_stats_compute_phase_metrics(field, s, nil, dom_k)
end
-- Step 4: hysteresis lock state (requires ctx + field index)
ooc.field_stats_update_phase_lock(ctx, 0, s)
ooc.log("entropy=%.3f coherence=%.3f ema=%.3f lock=%d",
s.spectral_entropy, s.phase_coherence, s.phase_coherence_ema, s.phase_lock_state)

Adjust the global phase config before starting a run to set lock/unlock thresholds and EMA smoothing:

ooc.field_stats_set_phase_config({
lock_on = 0.85,
lock_off = 0.70,
smoothing_constant = 0.05,
weighted = true,
deramp_enabled = false,
})
local cfg = ooc.field_stats_get_phase_config()
ooc.log("lock_on=%.2f lock_off=%.2f alpha=%.3f",
cfg.lock_on, cfg.lock_off, cfg.smoothing_constant)

local ctx = ooc.create()
ooc.add_field(ctx, {32}, { fill = 0.0 })
ooc.add_field(ctx, {32}, {
type = "complex_double",
representation = {
domain = "spectral",
value_kind = "complex",
},
fill = {1.0, 0.0}
})
for i = 0, ooc.field_count(ctx) - 1 do
local info = ooc.field_info(ctx, i)
local stats = ooc.field_stats(ctx, i)
ooc.log("[%d] %s rms=%.4f max=%.4f",
i, info.format, stats.rms, stats.max_abs)
end