Field Creation
On this page
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 ๐งพ
add_field(ctx, shape[, options]) -> field
Returns: Field handle (userdata) โ pass it to operators, step functions, and field queries.
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. |
Note
Representation metadata does not change storage allocation. A real field still uses
"double"storage and a complex field still uses"complex_double"storage. By default,"double"fields start asphysical + real, while"complex_double"fields start asphysical + complex.
Caution
Not every representation combination is valid. Spectral fields require complex storage, and
complex_real_constraintis only valid in the spectral domain. Thehybriddomain exists in core enums but is not currently accepted byadd_field.
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)
| Argument | Description |
|---|---|
i |
0-based element index (0 to shape[1] - 1) |
x |
Physical coordinate: origin + i * spacing |
-- Complex travelling wave
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
})
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
})
Caution
Initializers for rank โฅ 3 fields raise a Lua error. Use
fillat creation time and thenfield:set_values()(or a stimulus operator) to write higher-dimensional data.
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 ๐
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
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
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
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
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
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() end
vol:set_values(data)
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).