Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
6c36248
sel works on string and categorical coordinates
atrabattoni Aug 11, 2026
e0d6c30
registered numpy defaults no longer override explicit arguments
atrabattoni Aug 11, 2026
ac305c3
a directory sink joins along the dimension it was chunked along
atrabattoni Aug 11, 2026
b61e9fe
a pandas DataFrame is a collection leaf of its own kind
atrabattoni Aug 11, 2026
3d7c9df
xd.stack collapses a collection level into a dimension
atrabattoni Aug 11, 2026
1fdc353
chunk ingress and egress can run in worker processes
atrabattoni Aug 11, 2026
45b3a1d
atoms compose with >>, trace ufuncs, and clone with fresh()
atrabattoni Aug 11, 2026
8e373ac
kernel atoms get their own layer, resampling goes polyphase
atrabattoni Aug 11, 2026
09e2814
task atoms speak physical units, with function forms at the top level
atrabattoni Aug 11, 2026
3cc1e79
atoms understand the continuous run: seams, flush, 0..n chunks
atrabattoni Aug 11, 2026
d66424c
assert_chunk_invariant: the evidence for chunk safety
atrabattoni Aug 11, 2026
3209d20
STFT streams exactly the eager frames
atrabattoni Aug 11, 2026
717d114
pin the edges of tracing, seams and folding
atrabattoni Aug 11, 2026
60f215b
process() is the dispatch boundary of chunked processing
atrabattoni Aug 11, 2026
d8aedd5
pin the edges of the realtime seam announcements
atrabattoni Aug 11, 2026
b6f47cd
fixture: a fake SeisBench model spanning the weight-set axes
atrabattoni Aug 11, 2026
be7de66
rework MLPicker into Annotate
atrabattoni Aug 11, 2026
8e4cb09
apply the preprocessing filter a weight set ships
atrabattoni Aug 11, 2026
ef316cc
Trigger moves to atoms/detect: per-phase thresholds, scalar annotatio…
atrabattoni Aug 11, 2026
05c42e5
label collection results with their tree path, merge and gather them
atrabattoni Aug 11, 2026
c54cb10
Picker, the pipeline a weight set describes
atrabattoni Aug 11, 2026
17beea2
process walks a collection the way the eager call does
atrabattoni Aug 11, 2026
8098b09
the GPU atom is asynchronous behind a bounded output queue
atrabattoni Aug 11, 2026
7c6de84
docs: a picking walkthrough, and the phase's release notes
atrabattoni Aug 11, 2026
bdd1a61
pin the corners Phase D's test moves uncovered
atrabattoni Aug 11, 2026
35b1616
resampling carries the labels of the samples it keeps
atrabattoni Aug 11, 2026
c3f689a
release notes: the resampled-labels fix
atrabattoni Aug 11, 2026
f1bf88c
restore the blank lines the docstring sections need
atrabattoni Aug 11, 2026
ab961cf
the seam a one-sample chunk leaves behind is still judged
atrabattoni Aug 12, 2026
2015beb
spell the root of a tile array out, and two error messages right
atrabattoni Aug 12, 2026
99249c3
the guides teach the pipeline this branch actually ships
atrabattoni Aug 12, 2026
de8dc39
release notes: the 0.2.9 story, not its development
atrabattoni Aug 12, 2026
caa8bf1
the realtime page says how a stream is processed, and the build is quiet
atrabattoni Aug 12, 2026
0df7ddf
release notes: tighter still on the three longest entries
atrabattoni Aug 12, 2026
aea2946
a resampled label, and a chunked kernel, no longer depend on the chun…
atrabattoni Aug 12, 2026
c0a176a
a fanned-out leaf writes to its own directory
atrabattoni Aug 12, 2026
7ae9e0c
picks keep the labels of the samples they were found at
atrabattoni Aug 12, 2026
4fcd343
release notes: keep the mislabelled-lanes fix, which 0.2.8 could hit
atrabattoni Aug 12, 2026
7c75bcf
release notes: lead the atoms story with the two faces of an operation
atrabattoni Aug 12, 2026
d7c97f8
the memory limit is a share of the machine, not a fixed eight gigabytes
atrabattoni Aug 12, 2026
424f7ae
a subscriber knows when the publisher has registered it
atrabattoni Aug 12, 2026
e429f03
chunks cross to the workers through shared memory of our own
atrabattoni Aug 12, 2026
0c2ed64
a worker does not have to import the test suite to run its tasks
atrabattoni Aug 12, 2026
db20081
an arena the collector takes is let go of, not just unnamed
atrabattoni Aug 12, 2026
f0cb74b
Remove warnings raising.
atrabattoni Aug 12, 2026
1604024
a reader that fails to build lets go of its file
atrabattoni Aug 13, 2026
ea649aa
an endpoint releases the socket it speaks through
atrabattoni Aug 13, 2026
1a9d064
a test that asserts silence names the silence it asserts
atrabattoni Aug 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 91 additions & 6 deletions docs/api/atoms.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ Methods
Atom.initialize
Atom.initialize_from_state
Atom.call
Atom.flush
Atom.reset
Atom.process
Atom.iter_chunks
Atom.gather
Atom.merge
Atom.save_state
Atom.set_state
Atom.load_state
Expand Down Expand Up @@ -75,13 +80,65 @@ Methods
Partial.get_state
```

## Decorators
## Decorators and composition

```{eval-rst}
.. autosummary::
:toctree: ../_autosummary

as_function
atomized
compose
```

## Task atoms

Public processing vocabulary with physical parameters only.

```{eval-rst}
.. autosummary::
:toctree: ../_autosummary

Decimate
Differentiate
Filter
Integrate
Resample
STFT
```

## Function forms

Every atom has a function form exported at the top level of `xdas`: called on
data it applies eagerly, called on `...` it returns the atom.

```{eval-rst}
.. currentmodule:: xdas
```

```{eval-rst}
.. autosummary::
:toctree: ../_autosummary

annotate
decimate
detrend
differentiate
filter
hilbert
integrate
medfilt
pick
rechunk
resample
sliding_mean_removal
stft
taper
trigger
```

```{eval-rst}
.. currentmodule:: xdas.atoms
```

## Signal processing
Expand All @@ -90,13 +147,41 @@ Methods
.. autosummary::
:toctree: ../_autosummary

DownSample
FIRFilter
IIRFilter
LFilter
MLPicker
ResamplePoly
SOSFilter
```

## Detection and picking

`Annotate` runs a SeisBench model window by window, `Trigger` turns the
characteristic function it produces into a pick table, and `Picker` is the
whole pipeline a weight set describes — its own filter, its own sampling rate,
its own per-phase thresholds. Each has a lowercase functional twin at the top
level of `xdas` (`xdas.annotate`, `xdas.trigger`, `xdas.pick`).

```{eval-rst}
.. autosummary::
:toctree: ../_autosummary

Annotate
Trigger
Picker
```

## Kernel atoms

Expert layer (`xdas.atoms.kernel`): exact stateful primitives with machine
parameters, designed by the task atoms from the data at the first call.

```{eval-rst}
.. autosummary::
:toctree: ../_autosummary

DownSample
LFilter
Polyphase
Rechunk
SOSFilter
UpSample
```
```
16 changes: 16 additions & 0 deletions docs/api/processing.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
:toctree: ../_autosummary

process
watch
get_source
get_writer
```

## Loaders
Expand Down Expand Up @@ -43,6 +46,7 @@
StreamWriter
ZMQPublisher
ZMQSubscriber
ResultWriter
```

### DataArrayWriter
Expand All @@ -66,4 +70,16 @@
ZMQPublisher.submit
ZMQPublisher.write
ZMQPublisher.result
ZMQPublisher.wait_for_subscribers
ZMQPublisher.close
```

### ZMQSubscriber

```{eval-rst}
.. autosummary::
:toctree: ../_autosummary

ZMQSubscriber.wait_until_subscribed
ZMQSubscriber.close
```
2 changes: 2 additions & 0 deletions docs/api/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@
.. autosummary::
:toctree: ../_autosummary

assert_chunk_invariant
dummy
inject_gaps
```
3 changes: 3 additions & 0 deletions docs/api/xdas.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
get_sampling_interval
sortby
split
stack
trim_overlaps
plot_availability
```

Expand Down Expand Up @@ -153,6 +155,7 @@ Methods
.. autosummary::
:toctree: ../_autosummary

DataCollection.select
DataCollection.query
DataCollection.issequence
DataCollection.ismapping
Expand Down
62 changes: 44 additions & 18 deletions docs/release-notes.md

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions docs/user-guide/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ output samples. When you split data into chunks and apply the filter independent
each chunk, the state is re-initialised at every boundary and the transient response
distorts the result near each chunk edge.

Use the stateful atom equivalents from {py:mod}`xdas.atoms` (e.g.
{py:class}`~xdas.atoms.IIRFilter`, {py:class}`~xdas.atoms.LFilter`) inside a
{py:class}`~xdas.atoms.Sequential` pipeline. These atoms carry the filter state across
chunk boundaries automatically when used with {py:func}`~xdas.processing.process`.
Build the pipeline out of atoms — `xd.filter(..., (1.0, 10.0))` rather than
`xs.filter(da, ...)` — and run it with {py:meth}`~xdas.atoms.Atom.process`. The atoms
carry the filter state across chunk boundaries, and flush and restart it wherever the
input actually has a gap or changes sampling rate, so the chunked answer is the eager
one. {py:func}`xdas.testing.assert_chunk_invariant` checks that on your own pipeline.

## Can I use xdas with seismic data that is not DAS?

Expand Down
3 changes: 2 additions & 1 deletion docs/user-guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ access large multi-file acquisitions as a single seamless array.
:link: pipeline/index
:link-type: doc
Building processing sequences with {py:class}`~xdas.atoms.Atom` objects and applying
them chunk-by-chunk on datasets larger than memory, including real-time streaming.
them chunk-by-chunk on datasets larger than memory, including real-time streaming and
phase picking with SeisBench models.
```

```{grid-item-card} How-To Guides
Expand Down
26 changes: 11 additions & 15 deletions docs/user-guide/io/obspy.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,17 @@ for station in stations:
*Xdas* reads seismological data through ObsPy, with the engine named `"obspy"`
after the library rather than after any one format: decoding is
{py:func}`obspy.read`, so miniSEED, SAC, GSE2, SEG-2 and everything else ObsPy
supports goes through the same path. `engine="miniseed"` still works as an
alias.
supports goes through the same path.

The engine mirrors {py:func}`obspy.read` exactly: **one contiguous ObsPy
`Trace` becomes one lazy `DataArray`**, and the collection mirrors the
`Stream`, nested on the four levels of the SEED hierarchy. Nothing is decoded
at this point — the scan only records where each trace lives.

```{note}
This part encourages experimenting with seismic data. Depending on the most common use cases users find, this could lead to changes in development direction.
The legacy `"miniseed"` engine is a different reader, kept for the code written
against it: it returns one stacked-channel array per file rather than a
collection. See [](data-formats.md).
```

## Reading
Expand All @@ -82,6 +83,7 @@ the directory layout does not have to be described, since the SEED identifiers
inside the files already say where each trace belongs.

```{code-cell}
import numpy as np
import xdas as xd

dc = xd.open("NX/*/*.mseed", engine="obspy")
Expand All @@ -103,7 +105,7 @@ semantics of `obspy.Stream.select`, with shell-style globbing on the keys:
dc.select(station="SX00[123]", channel="HH?")
```

`select` chooses *which* leaves are kept; {py:meth}`~xdas.DataCollection.sel`
`select` chooses *which* leaves are kept; {py:meth}`~xdas.DataMapping.sel`
trims *inside* each leaf by coordinate label. Indexing works too, and reads
like the seed id it is:

Expand Down Expand Up @@ -159,15 +161,12 @@ every copy and look at them, `xd.split(da, "overlaps")` cuts them apart.
## Stacking channels and stations

As often, the different channels of a station are synchronized. They can be
stacked into a two-dimensional array with {py:func}`xdas.concat`, which stays
lazy: the identifiers that vary along the new dimension become a coordinate,
the ones that do not stay scalar.
collapsed into a dimension of a two-dimensional array with
{py:func}`xdas.stack`, which stays lazy: the level's keys become the new
coordinate, and the identifiers that do not vary stay scalar.

```{code-cell}
def stack(node, dim):
return xd.concat([node[key][0] for key in sorted(node)], dim)

da = stack(dc["NX"]["SX001"]["00"], "channel")
da = xd.stack(dc["NX"]["SX001"]["00"], "channel")[0]
da
```

Expand All @@ -177,10 +176,7 @@ array, ready for array analysis:

```{code-cell}
sub = dc.sel(time=slice("2024-01-01T00:01:00", "2024-01-01T00:02:59.99"))
da = xd.concat(
[stack(sub["NX"][station]["00"], "channel") for station in sorted(sub["NX"])],
"station",
)
da = xd.stack(xd.stack(sub["NX"], "channel"), "station")["00"][0]
da
```

Expand Down
Loading
Loading