Field Handles & Methods
On this page
Quick Reference ๐
- Obtain a handle:
add_fieldat creation, orget_field(ctx, index)to look up an existing field. - Inspect:
:rank(),:shape(),:components(),:domain(),:value_kind(), and:values()snapshot the field into Lua. - Write back:
:set_values(table)replaces the field buffer from a Lua table. - Statistics:
field_stats(ctx, field)for a lazy step-cached proxy;field_stats_compute(field)for an immediate one-shot result; the accumulator API for manual rolling stats. - Spectral & phase:
field_stats_compute_spectral_viewandfield_stats_compute_phase_metricscompute frequency-domain and phase-coherence metrics. - Phase lock:
field_stats_update_phase_lockand thefield_stats_{get,set}_phase_configfunctions control hysteresis-based phase-lock detection.
Instance Methods ๐ง
Field handles expose the following methods. __tostring returns Field(<ptr>) or Field(nil) for debug printing; garbage-collection of the handle does not touch the underlying context storage.
field:rank()
Returns the number of dimensions (tensor rank) as an integer.
local r = field:rank() -- e.g. 2 for a {256, 256} field
field:shape()
Returns a Lua array of extents, one per axis, in declaration order (axis 1 = outermost, axis rank = innermost / fastest-varying).
local s = field:shape() -- e.g. {256, 512}
ooc.log("%d rows ร %d cols", s[1], s[2])
field:components()
Returns 1 for real ("double") fields and 2 for complex ("complex_double") fields.
field:domain()
Returns the fieldโs representation-domain tag as a string, typically "physical" or "spectral".
ooc.log("domain=%s", field:domain())
field:value_kind()
Returns the fieldโs value-kind tag as a string. Canonical outputs are "real", "complex", "complex_real_constraint", and "unknown".
ooc.log("value_kind=%s", field:value_kind())
field:values()
Materializes the entire field buffer into a Lua table (a copy). Mutating the returned table does not affect the field.
- Real fields โ flat array of numbers, row-major (axis
rankvaries fastest). - Complex fields โ array of
{re, im}two-element tables. - Raises a Lua error if the element format is unsupported.
-- Real snapshot
for i, v in ipairs(field:values()) do
ooc.log("[%d] = %.4f", i, v)
end
-- Complex snapshot
for i, z in ipairs(field:values()) do
ooc.log("[%d] = %.3f + %.3fi", i, z[1], z[2])
end
Tip
values()copies the full buffer into Lua, which is convenient for small fields or diagnostics. For large fields, prefer operating in-place with operators or exporting data via C-side hooks.
field:set_values(table)
Writes values from a Lua table back into the field buffer. The table must contain at least as many entries as the field has elements; excess entries are ignored.
- Real fields โ elements must be numbers.
- Complex fields โ each element may be:
- A bare number โ stored as
{re = value, im = 0}. - A
{re, im}two-element table.
- A bare number โ stored as
- Returns
trueon success; raises a Lua error if the table is too short or an element type is wrong.
-- Zero out a real field
local zeros = {}
local n = field:shape()[1] * field:shape()[2]
for i = 1, n do zeros[i] = 0.0 end
field:set_values(zeros)
-- Write complex values
local vals = {}
for i = 1, 1024 do
local x = (i - 1) * 2 * math.pi / 1024
vals[i] = { math.cos(x), math.sin(x) }
end
field:set_values(vals)
Context Functions ๐
field_count(ctx)
Returns the number of fields currently allocated in the context.
get_field(ctx, index)
Returns a Field handle for the given 0-based index. Raises a Lua error if the index is out of range.
local f = ooc.get_field(ctx, 0) -- first field
field_info(ctx, index)
Returns a table describing the field at the given 0-based index, or nil if the index is missing.
| Key | Type | Description |
|---|---|---|
index |
integer |
Field index (mirrors the argument) |
rank |
integer |
Number of dimensions |
element_count |
integer |
Total number of elements |
shape |
table |
Array of per-axis extents |
format |
string |
"real_double" or "complex_double" |
format_value |
integer |
Numeric enum value of format |
components |
integer |
1 (real) or 2 (complex) |
element_size |
integer |
Bytes per element (8 or 16) |
byte_size |
integer |
Total buffer size in bytes |
local info = ooc.field_info(ctx, 0)
ooc.log("format=%s bytes=%d", info.format, info.byte_size)
Tip
field_inforeports storage format such as"real_double"or"complex_double". For representation metadata like physical vs spectral or Hermitian-constrained complex values, usefield:domain()andfield:value_kind().
Field Statistics ๐
field_stats(ctx, index_or_field) โ Lazy Proxy
Returns a stats proxy whose values are cached per simulation step. On first access within a step the proxy recomputes stats; subsequent reads within the same step return the cached values.
local stats = ooc.field_stats(ctx, field)
ooc.log("rms=%.4f max=%.4f", stats.rms, stats.max_abs)
Call stats:refresh() to force a recompute regardless of the step cache. It returns true when the refresh succeeds and false if the snapshot could not be updated. Use pairs(stats) to iterate a full snapshot table.
Stats Fields
| Field | Type | Description |
|---|---|---|
mean_re |
double |
Mean of real components |
mean_im |
double |
Mean of imaginary components |
mean_abs |
double |
Mean of absolute values |z| |
rms |
double |
Root mean square of real components |
var_re |
double |
Variance of real components |
var_im |
double |
Variance of imaginary components |
var_abs |
double |
Variance of |z| |
max_abs |
double |
Maximum absolute value across all elements |
phase_coherence |
double |
Kuramoto order parameter (0โ1); 1 = fully coherent |
circularity |
double |
Complex circularity measure |
spectral_entropy |
double |
Shannon entropy of the spectral power distribution |
spectral_bandwidth |
double |
RMS spectral bandwidth |
phase_coherence_weighted |
double |
Amplitude-weighted phase coherence |
phase_coherence_ema |
double |
Exponential moving average of phase coherence |
phase_coherence_k0 |
double |
Phase coherence at the dominant wavenumber |
phase_sample_count |
integer |
Number of samples contributing to phase estimates |
phase_lock_state |
integer |
Hysteresis lock flag (0 = unlocked, 1 = locked) |
phase_regime |
integer |
Encoded phase-regime classification |
count |
integer |
Total element count included in stats |
continuity_dirty_ops |
integer |
Number of operators that wrote to the field (dirty) last step |
continuity_stable_ops |
integer |
Number of operators that left the field unchanged last step |
field_stats_compute(field) โ One-Shot
Immediately computes stats for the given Field handle and returns a plain table (not a proxy). No context or step index is required.
The returned table contains all fields listed above plus mean (the mean of real components, equivalent to mean_re for real fields).
local s = ooc.field_stats_compute(field)
ooc.log("mean=%.4f rms=%.4f max=%.4f", s.mean, s.rms, s.max_abs)
Use this when you need an immediate snapshot outside of a step loop, or when you want to compute stats for a temporarily constructed field.
Stats Accumulator API
The accumulator API lets you compute stats incrementally over arbitrary sequences of values โ useful for streaming data from external sources or computing stats over a subset of elements.
field_stats_accumulator_begin([acc])
Creates a new accumulator userdata, or resets an existing one if acc is passed. Returns the accumulator handle.
local acc = ooc.field_stats_accumulator_begin()
-- Or reuse an existing accumulator:
ooc.field_stats_accumulator_begin(acc)
field_stats_accumulate_real(acc, value)
Feeds a single real sample into the accumulator.
ooc.field_stats_accumulate_real(acc, 0.42)
field_stats_accumulate_complex(acc, re, im)
Feeds a single complex sample into the accumulator.
ooc.field_stats_accumulate_complex(acc, re, im)
field_stats_accumulator_finish(acc)
Finalizes the accumulation and returns a stats table with the computed values.
local result = ooc.field_stats_accumulator_finish(acc)
ooc.log("rms=%.4f count=%d", result.rms, result.count)
Full accumulator example:
local acc = ooc.field_stats_accumulator_begin()
for _, v in ipairs(my_field:values()) do
ooc.field_stats_accumulate_real(acc, v)
end
local s = ooc.field_stats_accumulator_finish(acc)
ooc.log("custom rms=%.4f max=%.4f", s.rms, s.max_abs)
Spectral & Phase Statistics
These functions require a pre-computed base stats table (from the proxy or one-shot compute) and update it with additional spectral or phase-coherence metrics.
field_stats_compute_spectral_view(field, stats_table)
Computes spectral statistics for field and updates stats_table in-place with spectral_entropy, spectral_bandwidth, and related fields.
Returns: ok (boolean), dominant_k (integer) โ the index of the dominant wavenumber bin. ok is false if the field is not complex or the FFT failed.
local stats = ooc.field_stats_compute(field)
local ok, dom_k = ooc.field_stats_compute_spectral_view(field, stats)
if ok then
ooc.log("spectral_entropy=%.4f dominant_k=%d", stats.spectral_entropy, dom_k)
end
field_stats_compute_phase_metrics(field, stats_table[, config_table[, dominant_k]])
Computes phase-coherence metrics and updates stats_table in-place with phase_coherence, phase_coherence_weighted, phase_coherence_ema, phase_coherence_k0, and phase_sample_count.
| Argument | Required | Description |
|---|---|---|
field |
yes | Field handle or field view |
stats_table |
yes | Existing stats table (updated in-place) |
config_table |
no | Phase config overrides for this call only (see Phase Configuration) |
dominant_k |
no | Dominant wavenumber from field_stats_compute_spectral_view; defaults to 0 |
local stats = ooc.field_stats_compute(field)
local ok, dom_k = ooc.field_stats_compute_spectral_view(field, stats)
ooc.field_stats_compute_phase_metrics(field, stats, nil, dom_k)
ooc.log("phase_coherence=%.4f ema=%.4f", stats.phase_coherence, stats.phase_coherence_ema)
field_stats_update_phase_lock(ctx, index, stats_table)
Updates the hysteresis-based phase_lock_state field in stats_table for the field at index (0-based), using the persistent lock state stored in the context. Updates stats_table in-place.
ooc.field_stats_update_phase_lock(ctx, 0, stats)
ooc.log("lock=%d regime=%d", stats.phase_lock_state, stats.phase_regime)
Phase Configuration
The phase coherence system uses a global configuration that controls EMA smoothing, hysteresis thresholds, and amplitude weighting.
field_stats_get_phase_config()
Returns the current global phase config as a table.
field_stats_set_phase_config(config_table)
Merges the provided table into the global phase config. Unknown keys are ignored.
| Key | Type | Description |
|---|---|---|
abs_threshold |
double |
Absolute amplitude threshold for phase inclusion |
rel_threshold |
double |
Amplitude threshold relative to max_abs |
weighted |
boolean |
Weight phase samples by amplitude |
lock_on |
double |
Coherence threshold to enter locked state |
lock_off |
double |
Coherence threshold to exit locked state (hysteresis) |
smoothing_constant |
double |
EMA alpha for phase_coherence_ema (also accepted as smoothing_seconds) |
deramp_enabled |
boolean |
Enable phase-ramp detrending before coherence computation (also accepted as deramp) |
ooc.field_stats_set_phase_config({
lock_on = 0.85,
lock_off = 0.70,
smoothing_constant = 0.05,
weighted = true,
})
local cfg = ooc.field_stats_get_phase_config()
ooc.log("lock_on=%.2f lock_off=%.2f", cfg.lock_on, cfg.lock_off)
Field Views & Continuity ๐
field_view_from_field(field)
Creates a lightweight field view from a Field handle. Field views are accepted by field_stats_compute_spectral_view and field_stats_compute_phase_metrics in place of a full Field handle. Useful when you want to pass a view into a function that expects either type.
local view = ooc.field_view_from_field(field)
local ok, dom_k = ooc.field_stats_compute_spectral_view(view, stats)
The returned table contains data (lightuserdata), count, type, and type_name. Treat it as an opaque bridge object tied to the lifetime of the original field.
field_continuity_counts(ctx, index)
Returns a table { index, dirty, stable } for the field at the given 0-based index, reflecting how many operators wrote to (dirty) or left unchanged (stable) the field during the most recent simulation step.
local counts = ooc.field_continuity_counts(ctx, 0)
ooc.log("dirty=%d stable=%d", counts.dirty, counts.stable)
Usage Examples ๐
Inspect a Field After Creation
local ctx = ooc.create()
local f = ooc.add_field(ctx, {8, 8}, { type = "complex_double", fill = {1, 0} })
ooc.log("rank=%d shape=%s components=%d",
f:rank(),
table.concat(f:shape(), "ร"),
f:components())
Read Values and Compute Stats
local stats = ooc.field_stats(ctx, field)
ooc.log("rms=%.4f max=%.4f coherence=%.4f",
stats.rms, stats.max_abs, stats.phase_coherence)
-- Force refresh if you need current-step values immediately:
stats:refresh()
-- Iterate all fields in a snapshot:
for key, val in pairs(stats) do
ooc.log("%s = %s", key, tostring(val))
end
Full Spectral + Phase Pipeline
ooc.step(ctx)
local s = ooc.field_stats_compute(field)
local ok, dom_k = ooc.field_stats_compute_spectral_view(field, s)
if ok then
ooc.field_stats_compute_phase_metrics(field, s, nil, dom_k)
ooc.field_stats_update_phase_lock(ctx, 0, s)
ooc.log("entropy=%.3f coherence=%.3f lock=%d", s.spectral_entropy, s.phase_coherence, s.phase_lock_state)
end