一键导入
authoring-sf-programs-julia
Use when authoring a Madagascar sf* main program in Julia.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when authoring a Madagascar sf* main program in Julia.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Use when writing an end-to-end Madagascar processing flow for a named geophysical task (NMO, migration, well-tie, denoising, dataset fetch, etc.) — teaches how to discover the right recipe in book/ and adapt it.
Use when composing a Madagascar data-processing pipeline from existing sf* programs — includes discovery, parameter conventions, and piping patterns.
Use when writing or modifying an SConstruct file that drives a Madagascar data-processing flow (Flow/Plot/Result/Fetch/Command).
Use when authoring a new Madagascar sf* main program in C (the reference implementation — all other language APIs wrap this).
Use when authoring a Madagascar sf* main program in Chapel.
Use when authoring a Madagascar sf* main program in C++.
| name | authoring-sf-programs-julia |
| description | Use when authoring a Madagascar sf* main program in Julia. |
Load this skill when writing a new sf<name> program in Julia. Julia is a good fit
when your collaborators already work in that ecosystem, when you want direct access to
the Julia numerical stack (FFTW.jl, LinearAlgebra, LoopVectorization, etc.) without a
foreign-function call, or when you need seamless FFI to C but prefer Julia syntax over
Python.
The source file is named M<name>.jl and lives in user/<youruser>/. The build
system handles the rest. Framework support for Julia programs exists via
UserSconsTargets.jl (see Build integration). There are no existing M*.jl
programs in the tree yet; use api/julia/test/ as templates (especially clip.jl
for the core pattern and afdm.jl for a heavier numerical example).
The Julia API (m8r.jl) is a thin wrapper around libdrsf via ccall. All data
types map to their C equivalents: Float32, Int32, ComplexF32, Int16, UInt8.
See also: Shared language-agnostic conventions
Modelled on api/julia/test/clip.jl:
#!/usr/bin/env julia
# M<name>.jl — one-sentence description of what this program does.
#
# Additional comments, references, and notes go here.
# (No structured doc-scraper for Julia yet; the comment is for human readers.)
import m8r
# --- Parameter retrieval (from command line or par= file) ---
clip = m8r.getfloat("clip") # required — exits if absent
verb = m8r.getbool("verb", false) # optional — default false
niter = m8r.getint("niter", 100) # optional — default 100
# --- Open standard input / output ---
inp = m8r.input("in")
out = m8r.output("out")
# --- Read header fields from inp ---
n1 = m8r.histint(inp, "n1")
n2 = m8r.leftsize(inp, 1) # total samples / n1; works for any nd array
# --- Copy header to output, optionally modifying axes ---
m8r.putint(out, "n1", n1)
m8r.putfloat(out, "d1", m8r.histfloat(inp, "d1"))
m8r.putfloat(out, "o1", m8r.histfloat(inp, "o1"))
m8r.putstring(out, "label1", m8r.histstring(inp, "label1"))
m8r.putstring(out, "unit1", m8r.histstring(inp, "unit1"))
# --- Trace loop ---
trace = Array{Float32}(undef, n1)
for i2 in 1:n2
m8r.floatread(trace, n1, inp)
# ... process trace ...
clamp!(trace, -clip, clip)
m8r.floatwrite(trace, n1, out)
end
Key structural points:
import m8r (not using m8r) keeps the namespace explicit; using m8r is also
valid and exports rsf_read / rsf_write.m8r.__init__() is called automatically when the module loads; do not call
sf_init manually.m8r.leftsize(file, 1) returns total_samples / n1 — the product of all axes
beyond the first. Use this to drive the outer loop without hard-coding dimensions.m8r.input("vel") opens the file named by the command-line
argument vel=<path>.| Purpose | Julia call | Notes |
|---|---|---|
| Init | automatic on import m8r | __init__ calls sf_init via ccall |
| Open input | m8r.input("in") | "in" = stdin; any other string = file path from that CLI param |
| Open output | m8r.output("out") | "out" = stdout; other strings = named output files |
| Close file | m8r.close(file) | wraps sf_fileclose; called automatically by rsf_write |
| Hist int | m8r.histint(file, "n1") | read Int from header; returns 0 if key absent |
| Hist float | m8r.histfloat(file, "d1") | read Float32 from header |
| Hist string | m8r.histstring(file, "label1") | read string from header; "" if absent |
| Put int | m8r.putint(out, "n1", n) | write integer header key |
| Put float | m8r.putfloat(out, "d1", d) | write float header key |
| Put string | m8r.putstring(out, "label1", s) | write string header key |
| Get int param | m8r.getint("niter", 100) | CLI/par param; default if absent |
| Get float param | m8r.getfloat("clip") | returns 0f0 if absent and no default given |
| Get string param | m8r.getstring("vel", "") | returns default string if absent |
| Get bool param | m8r.getbool("verb", false) | "y" → true, "n" → false |
| Read floats | m8r.floatread(arr, n, inp) | arr must be Array{Float32,1} of length n |
| Write floats | m8r.floatwrite(arr, n, out) | arr must be Array{Float32,1} |
| Read ints | m8r.intread(arr, n, inp) | Array{Int32,1} |
| Write ints | m8r.intwrite(arr, n, out) | Array{Int32,1} |
| Read complex | m8r.complexread(arr, n, inp) | Array{ComplexF32,1} |
| Write complex | m8r.complexwrite(arr, n, out) | Array{ComplexF32,1} |
| Read short | m8r.shortread(arr, n, inp) | Array{Int16,1} |
| Write short | m8r.shortwrite(arr, n, out) | Array{Int16,1} |
| Left size | m8r.leftsize(file, dim) | samples in dims > dim; leftsize(f,0) = total |
| Set format | m8r.setformat(out, "complex") | must call before first write for non-float output |
| High-level read | dat, n, d, o, l, u = rsf_read(file_or_name) | returns array + axis metadata |
| High-level write | rsf_write(name, dat) | writes array to named RSF file |
| Pipe sf programs | sfspike(n1=10) |> sfsmooth |> rsf_read | all installed sf* programs are exported |
api/julia/SConstruct installs m8r.jl into $RSFROOT/lib/ at build time. The
framework-level dispatch for Julia programs happens in UserSconsTargets.jl
(located in the SCons framework tree). To add a Julia main program to your user
directory's build:
# user/<youruser>/SConstruct
import sys, os
sys.path.append('../../framework')
import bldutil
# New-style (preferred)
targets = bldutil.UserSconsTargets()
targets.jl = 'myprogram' # base name only — no M prefix, no .jl suffix
targets.build_all(env, glob_build, srcroot, bindir, libdir, pkgdir)
At configure time, Madagascar's build system checks for a Julia executable. If Julia
is not found, targets.jl programs are silently skipped; no error is raised. To
verify Julia was detected during configuration, inspect $RSFROOT/include/config.py
for a JULIA key, or check env.get('JULIA') inside the SConstruct.
Self-documentation for Julia programs is not yet scraped by framework/rsf/doc.py
(no comment['jl'] regex entry); write a clear comment block at the top of your
M<name>.jl for human readers, and plan to add sfdoc support manually if needed.
Files in api/julia/ and their purpose:
| File | Description |
|---|---|
api/julia/m8r.jl | Full Julia API module — the only file you import; wraps all C-API entry points via ccall and also auto-exports every installed sf* binary as a Julia function |
api/julia/SConstruct | SCons build file for the API; installs m8r.jl to $RSFROOT/lib/ |
api/julia/test/clip.jl | Minimal template: open in/out, read header, loop over traces with floatread/floatwrite — the closest thing to an M*.jl skeleton |
api/julia/test/afdm.jl | Full numerical example: acoustic finite-difference modelling; shows multi-file input, header axis assembly, putint/putfloat/putstring output header setup, and a @fastmath @inbounds compute kernel |
api/julia/test/runtests.jl | Comprehensive unit tests for every type (uchar, char, int, float, complex, short) covering getint/getfloat/getstring/getbool, histint/histfloat/histstring, putint/putfloat/putstring, read/write round-trips, and high-level rsf_read/rsf_write plus pipe-based sf* function calls |
Float32 and Int32 throughout (matching the C
API). Passing Float64 arrays to floatwrite requires explicit conversion:
m8r.floatwrite(Float32.(vec(arr)), n, out). The high-level rsf_write does this
conversion automatically.m8r.output("out") silently inherits the data type
from the most recent m8r.input("in") call (C API behaviour). For non-float output
(complex, int, short) call m8r.setformat(out, "complex") immediately after
m8r.output and before any write. The rsf_write(name, arr) variant avoids this
pitfall by writing a dummy pipe to force the correct type.sf_error in Julia: there is no m8r.error(...) binding. Use error("msg")
(Julia built-in) or throw(...) for fatal errors; the non-zero exit will propagate
correctly through Madagascar pipelines.sf* binaries are available as Julia functions
after using m8r. They accept an RSFFile, an array, or no argument, and return
an RSFFile pointing to a temporary file. Chain them with |>.ENV["RSFROOT"] at load time. If the
environment variable is not set, m8r.RSFROOT is nothing and sf* function
generation is skipped; the low-level read/write API still works.For file naming, self-documentation, parameter conventions, error handling, testing, and SCons build patterns that apply to all languages, see: