Field Creation
Quick Reference 📌
Section titled “Quick Reference 📌”add_field(ctx, shape[, options])allocates a field and returns a Field handle (userdata) pinned to the context lifetime.- Shape: Lua array of positive integers, one per dimension. Axis 0 is the slowest (outermost loop); axis
rank-1is the fastest (innermost). - Element type:
"double"(real, 8 bytes/element) or"complex_double"(interleavedre/im, 16 bytes/element). - Seeding:
fillsets every element at allocation time.initializer(Lua function) runs per-element after fill and supports 1D and 2D fields. - Representation metadata:
domain,value_kind, orrepresentation = { ... }tag the field as physical vs spectral and real vs complex-valued without changing the underlying storage type. - Coordinates:
originandspacingdefine the physical coordinate grid passed to the initializer. They are consumed during initialization only and are not stored on the field.
Method Signature 🧾
Section titled “Method Signature 🧾”add_field(ctx, shape[, options]) -> fieldReturns: Field handle (userdata) — pass it to operators, step functions, and field queries.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
type | string | "double" | "complex_double" stores interleaved {re, im} pairs. Unrecognized strings fall back to "double". |
fill | double or {re, im} | 0 | Seeds every element before the initializer runs. For complex fields, supply a {re, im} table; a bare number is ignored for complex storage. |
initializer | function | none | Per-element Lua callback called after fill. Supported for 1D and 2D fields only. See signatures below. |
origin | double | 0.0 | Physical coordinate of element index 0 along every axis (isotropic — same for all axes). |
spacing | double | 1.0 | Step size between adjacent elements in physical coordinates (isotropic). |
domain | string or enum | derived | Representation domain. Canonical values are "physical" and "spectral"; "spatial" and "frequency" are accepted aliases. |
value_kind | string or enum | derived | Scalar interpretation metadata. Canonical values are "real", "complex", and "complex_real_constraint"; aliases like "scalar", "hermitian", and "conjugate_symmetric" are accepted. |
representation | table | none | Nested { domain = ..., value_kind = ... } override. Parsed after the top-level domain / value_kind keys and takes precedence when both are present. |
Initializer Signatures 🔢
Section titled “Initializer Signatures 🔢”The initializer function is called once per element. Physical coordinates are derived from origin and spacing. Return a number for real fields or a {re, im} table for complex fields.
1D Fields — initializer(i, x)
Section titled “1D Fields — initializer(i, x)”| Argument | Description |
|---|---|
i | 0-based element index (0 to shape[1] - 1) |
x | Physical coordinate: origin + i * spacing |
-- Complex travelling wavelocal 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})2D Fields — initializer(ix, iy, x, y)
Section titled “2D Fields — initializer(ix, iy, x, y)”| Argument | Description |
|---|---|
ix | 0-based index along axis 0 (outer / row dimension, 0 to shape[1] - 1) |
iy | 0-based index along axis 1 (inner / column dimension, 0 to shape[2] - 1) |
x | Physical coordinate along axis 0: origin + ix * spacing |
y | Physical coordinate along axis 1: origin + iy * spacing |
-- Gaussian blob centred at (0, 0)local pattern = 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})The iteration order for 2D fields is: outer loop over ix (axis 0), inner loop over iy (axis 1), matching the row-major element layout returned by field:values().
Examples 🎉
Section titled “Examples 🎉”Real 2D Grid — Uniform Fill
Section titled “Real 2D Grid — Uniform Fill”local ctx = ooc.create()
local density = ooc.add_field(ctx, {256, 256}, { fill = 0.0 })ooc.log("rank=%d elements=%d", density:rank(), #density:values())Complex 1D — Phase-Encoded Waveform
Section titled “Complex 1D — Phase-Encoded Waveform”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[0] = %.3f + %.3fi", v[1][1], v[1][2])Real 2D — Radial Gaussian
Section titled “Real 2D — Radial Gaussian”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})Complex 2D — Spiral Phase Ramp
Section titled “Complex 2D — Spiral Phase Ramp”local phase = 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})Spectral Metadata on Complex Storage
Section titled “Spectral Metadata on Complex Storage”Use representation tags when a field should be treated as a spectral buffer or as Hermitian-constrained complex data:
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", spectrum:domain(), spectrum:value_kind())Seeding Without Initializer — fill + set_values
Section titled “Seeding Without Initializer — fill + set_values”For rank ≥ 3 or when the seed data comes from outside Lua, allocate with fill and then write via field:set_values():
local vol = ooc.add_field(ctx, {64, 64, 64}, { fill = 0.0 })
-- Build a flat table of 64^3 values, then write:local data = {}for i = 1, 64 * 64 * 64 do data[i] = math.random() endvol:set_values(data)Best Practices 💡
Section titled “Best Practices 💡”- Choose
typeup front — element size is fixed at allocation and determines byte layout for all operators attached to that field. - Prefer
fillfor constant seeds; useinitializerfor per-element geometry or waveform shapes (1D and 2D only). - For large fields or complex seeding logic,
add_stimulus_operator(e.g.stimulus_rd_seed) is more efficient than a Lua initializer. - Capture the returned Field handle — it is needed to attach operators and to call
:rank(),:shape(),:values(). - Fields are stored contiguously in row-major order;
shape[1]is the outermost dimension andshape[rank]is the innermost (fastest-varying).