The following highlights some DASCore features for working with IO.
Note
If you are working with remote UPath resources, especially HTTP or object store backends, see the Working with Remote Patches tutorial for examples, cache settings, and metadata-vs-read behavior.
Using UPath Resources
DASCore accepts both pathlib.Path and UPath inputs for many file-backed workflows. This is useful when your data lives on a non-local backend supported by fsspec.
The example below uses memory:// so it can run without any external network access.
from upath import UPathimport dascore as dcsource = dc.get_example_patch()remote_path = UPath("memory://dascore/tutorial/example_patch.h5")dc.write(source, remote_path, "DASDAE")summary = dc.scan(remote_path)[0]loaded = dc.read(remote_path)[0]print(summary.source_path)print(loaded.dims)
Patches can be written to disk using the io namespace. The following shows how to write a Patch to disk in the DASDAE format
from pathlib import Pathimport dascore as dcwrite_path = Path("output_file.h5")patch = dc.get_example_patch()patch.io.write(write_path, "dasdae")
PosixPath('output_file.h5')
Remote-style UPath destinations also work for supported formats.
from upath import UPathimport dascore as dcpatch = dc.get_example_patch()remote_write_path = UPath("memory://dascore/tutorial/output_file.pkl")patch.io.write(remote_write_path, "pickle")round_trip = dc.read(remote_write_path)[0]print(round_trip.dims)
('distance', 'time')
Scan Metadata Without Loading Data
dascore.scan returns PatchSummary objects. These results expose patch metadata, coordinate-summary envelopes, and source information without loading the data array into memory.
When a coordinate-summary envelope is insufficient, dascore.scan_payloads(...) exposes each formatter’s full CoordManager without loading the patch data array. Pass snap=False to request the exact stored coordinate values from formats that store per-sample arrays.
scan_payloads may read and retain large coordinate arrays, so prefer a specific file over an entire directory and discard each result promptly. Use dc.scan or dc.scan_to_df for compact directory indexing.
Note
Patch.attrs stores non-coordinate metadata only. Coordinate summaries such as time_min, time_max, and distance_step are accessed through PatchSummary.get_coord_summary(...) or via patch.summary.get_coord_summary(...).
Directory spools
A spool over a directory of dascore-readable files is created with the dascore.spool function. It is the same class as any other spool; the only difference is how it was constructed.
For example:
import dascorefrom dascore import examples as ex# Get a directory with several filesdiverse_spool = dascore.get_example_spool('diverse_das')path = ex.spool_to_directory(diverse_spool)# Create a spool for interacting with the files in the directory.spool = ( dascore.spool(path) .select(acquisition_key='DAS2.*') # sub-select one data source .select(time=(..., '2022-01-01')) # unselect anything after 2022 .chunk(time=2, overlap=0.5) # change the chunking of the patches)# Iterate each patch and do something with itfor patch in spool: ...
Converting Patches to Other Library Formats
The Patch.io namespace also includes functionality for converting Patch instances to datastructures used by other libraries including Pandas, Xarray, and ObsPy. See the external conversion recipe for examples.
Directory Indexer
The DBDirectoryIndexer tracks the contents of a directory which contains fiber data. It creates a small, hidden SQLite index named .dascore_index.sqlite3 at the top of the directory. Directory spools use this index internally and push metadata selections into SQLite before loading patch data. See the spool index note for the schema and lifecycle.
.dascore_index.sqlite3 is one of two hidden names DASCore gives a meaning at the top of a data directory. The other is .inventory, which is where a directory may keep the inventory describing the observing system its data was recorded through. Both are companions the directory keeps rather than content it holds, which is why both are hidden and neither is scanned as data.
import dascorefrom dascore.io.index.indexer import DBDirectoryIndexerfrom dascore import examples as ex# Get a directory with several filesdiverse_spool = dascore.get_example_spool('diverse_das')path = ex.spool_to_directory(diverse_spool)# Create an indexer and update the index. This scans new or changed files# (detected by per-file modification time and size), removes entries of# deleted files, and creates the index if one does not yet exist.DBDirectoryIndexer(path).update()# The index is queried through a spool. Opening one indexes the directory# if it has not been indexed yet, but does not rescan afterwards: call# spool.update() (or the indexer's, above) when the files change.df = dascore.spool(path).get_contents()# This dataframe can be used to ascertain data availability, detect gaps, etc.