Skip to content

parseSEG 0.9.0: survey joins match by stations; receiver-domain (O) relations - #2

Merged
xrfez merged 3 commits into
mainfrom
station-join
Nov 11, 2026
Merged

xrfez merged 3 commits into
mainfrom
station-join

Conversation

@xrfez

@xrfez xrfez commented Nov 11, 2026

Copy link
Copy Markdown
Owner

Why

Field record numbers and channel numbers in seismic data often differ from the relation (X) file's. A recorder numbers all its live channels; reshoots and renumbered post-plots move records. Meanwhile the header stations are right. The old join keyed on (record, channel) first, and with overwrite = true it replaced header stations from it. On a 3D land survey this assigned every trace of a shot the stations of another shot (the file's FFID was another shot's X record). The trace numbers also matched the X channels for only 23 of 1127 traces.

What changes

Station-first join. Traces are matched by their source and receiver line/point. Header stations are never replaced; the relations only fill stations a header lacks:

  • both stations in the header: coordinates by station only;
  • source station only: the receiver comes from the X records of that source station. When there are repeats, the one with the trace's record number is used; otherwise they must agree, or the trace is ambiguous;
  • receiver station only: the source comes from the O gathers of that receiver. Without O records, the X relation of the trace's record and channel is used, but only if its receiver is the header's;
  • no station: record and channel, the fallback.

overwrite now refreshes coordinates, offset and midpoint only. Auxiliary traces are left alone. joinStations exposes the station step. JoinMatch and JoinStats (new applySurvey overloads, printed by the CLI) say how traces matched.

Receiver-domain relations. O records (.ops files) are the X layout with source and receiver swapped, one gather per receiver. They are read with record letter O; X-lettered records in an .ops file are taken as O by default. receiverRelations(g) builds them from X, one receiver line in memory at a time: 11.2 M pairs → 1.07 M O records in about 3 s.

Lookups. records, relations (iterators), expectedChannels, recordsAt (the records of a source station / gathers of a receiver), channelOf, sameStation, relationCount(g, domain).

Fix. writeGeometry/copyWithGeometry reported a value that rounds to the bytes already in the file (shotpoint 99.5 into an espnum holding 100) as a write the journal dropped, a fatal error. It is now no change, with a regression test.

Behaviour changes for callers

  • A join no longer replaces stations a header has, even with overwrite.
  • The conversion guide's example used to relabel record.sgd's own stations through X; it now uses the file's real stations.
  • Tests that relied on stations being replaced now clear the station in the keys first, as a header without one would read.

Testing

nim test passes, including the 44 guide examples. The sample-file tests were run with the samples available here: the tgeomwrite and tcli survey blocks pass. segd_rev3_position_blocks needs the INOVA sample, which was not available. It now expects 2 changed traces instead of 5, because its 3 auxiliary traces are left alone. Please run the sample suite with the INOVA file.

🤖 Generated with Claude Code

xrfez and others added 3 commits November 11, 2026 18:29
…tions

Field record numbers and channel numbers in the data often differ from the
relation file's (a recorder numbers all its live channels; renumbered or
reshot records), while the header stations are right. The join now matches
by stations and never replaces a header station:

- both stations in the header: coordinates by station only;
- source station only: the receiver from the X records of that source
  station (the one with the trace's record number among repeats, else they
  must agree);
- receiver station only: the source from the O gathers of that receiver, or
  the X relation of record and channel if its receiver is the header's;
- no station: record and channel, the fallback.

`overwrite` now replaces coordinates only. Auxiliary traces are left alone.
`joinStations` exposes the station step; `JoinMatch` and `JoinStats` (from
new `applySurvey` overloads) say how traces matched. The CLI prints them.

Relations of both domains (`RelationDomain`): O records (record letter O, or
X records in an `.ops` file) are the X layout with source and receiver
swapped. New lookups: `records`, `relations`, `expectedChannels`,
`recordsAt`, `channelOf`, `sameStation`. `receiverRelations` builds the O
records of an X survey, one receiver line in memory at a time.

Also fixes writeGeometry/copyWithGeometry reporting a value that rounds to
the bytes already in the file (shotpoint 99.5 into an espnum holding 100) as
a write the journal dropped (a fatal error): such a trace is no change.

Docs (conversion guide, api.md, SPS spec notes) and tests follow; tests that
relied on the old (record, channel)-first join now use headers without the
station they fill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New since 0.8.0: survey joins match traces by their stations (header
stations are never replaced; record and channel only for traces without
stations; overwrite refreshes coordinates only); JoinMatch / JoinStats;
receiver-domain O relations (.ops), receiverRelations to build them from X;
relation lookups (records, relations, expectedChannels, recordsAt,
channelOf). Fix: a geometry value that rounds to the bytes already in the
file is no change (it was reported as a dropped journal write).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@xrfez
xrfez merged commit 9072517 into main Nov 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant