Handles & Methods
Quick Reference 📌
Section titled “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 🔧
Section titled “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()
Section titled “field:rank()”Returns the number of dimensions (tensor rank) as an integer.
local r = field:rank() -- e.g. 2 for a {256, 256} fieldfield:shape()
Section titled “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()
Section titled “field:components()”Returns 1 for real ("double") fields and 2 for complex ("complex_double") fields.
field:domain()
Section titled “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()
Section titled “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()
Section titled “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 snapshotfor i, v in ipairs(field:values()) do ooc.log("[%d] = %.4f", i, v)end
-- Complex snapshotfor i, z in ipairs(field:values()) do ooc.log("[%d] = %.3f + %.3fi", i, z[1], z[2])endfield:set_values(table)
Section titled “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 fieldlocal zeros = {}local n = field:shape()[1] * field:shape()[2]for i = 1, n do zeros[i] = 0.0 endfield:set_values(zeros)
-- Write complex valueslocal vals = {}for i = 1, 1024 do local x = (i - 1) * 2 * math.pi / 1024 vals[i] = { math.cos(x), math.sin(x) }endfield:set_values(vals)Context Functions 📂
Section titled “Context Functions 📂”field_count(ctx)
Section titled “field_count(ctx)”Returns the number of fields currently allocated in the context.
get_field(ctx, index)
Section titled “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 fieldfield_info(ctx, index)
Section titled “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)Field Statistics 📊
Section titled “Field Statistics 📊”field_stats(ctx, index_or_field) — Lazy Proxy
Section titled “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
Section titled “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
Section titled “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
Section titled “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])
Section titled “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)
Section titled “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)
Section titled “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)
Section titled “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)endlocal s = ooc.field_stats_accumulator_finish(acc)ooc.log("custom rms=%.4f max=%.4f", s.rms, s.max_abs)Spectral & Phase Statistics
Section titled “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)
Section titled “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)endfield_stats_compute_phase_metrics(field, stats_table[, config_table[, dominant_k]])
Section titled “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)
Section titled “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
Section titled “Phase Configuration”The phase coherence system uses a global configuration that controls EMA smoothing, hysteresis thresholds, and amplitude weighting.
field_stats_get_phase_config()
Section titled “field_stats_get_phase_config()”Returns the current global phase config as a table.
field_stats_set_phase_config(config_table)
Section titled “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 📏
Section titled “Field Views & Continuity 📏”field_view_from_field(field)
Section titled “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)
Section titled “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 📖
Section titled “Usage Examples 📖”Inspect a Field After Creation
Section titled “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
Section titled “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))endFull Spectral + Phase Pipeline
Section titled “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