Inventory
Inventory is the top-level metadata object used by DASCore. It is the serialized manifest boundary and the object patch methods use to resolve fiber-array, acquisition, interrogator, and optical-path context. Like other objects in DASCore, it is functionally immutable.
Defining an Inventory
A minimal inventory can be created directly from DASCore’s inventory classes; in practice most users load one from YAML or a directory. See Quickstart and Simple Inventory for full walkthroughs.
import dascore as dc
from dascore.core import inventory as inv
acquisition = inv.Acquisition(
code="RAW", location_code="01", start_time="2024-05-01",
data_category="DAS", data_type="strain_rate", data_units="1/s",
sample_rate=250.0, gauge_length=10.0,
spatial_interval=1.0,
distance_map=inv.DistanceMap(instrument_distance=(0.0,), distance=(0.0,)),
interrogator=inv.Interrogator(model="DAS-1000"),
)
path = inv.OpticalPath(
name="l001_path", location_code="01", start_time="2024-05-01",
optical_components=(inv.FiberSegment(name="fiber 1", optical_length=1000.0),),
geometry=(inv.Geometry(
name="survey line",
distance=(0.0, 1000.0),
coordinates=((45.0, -112.0, 1200.0), (45.01, -112.02, 1180.0)),
),),
)
inventory = dc.Inventory(networks=(inv.Network(
code="DAS",
fiber_arrays=(inv.FiberArray(
code="L001", name="L001", start_time="2024-05-01",
acquisitions=(acquisition,), optical_paths=(path,),
),),
),))This inventory resolves patches with acquisition_key DAS.L001.01.RAW, providing acquisition values such as sample_rate, instrument values such as interrogator.model, and optical path context such as geometry, coupling, annotations, and optical components. FiberArray identifies the durable observing system; acquisition settings and path interpretation change without changing it.
Updating an Inventory Component
Since Inventory and its components are immutable, DASCore users follow the pattern of creating a new component with updated fields, then replacing it in the inventory. The original object remains unchanged.
fiber_array = inventory.networks[0].fiber_arrays[0]
acquisition = fiber_array.acquisitions[0]
corrected_acquisition = acquisition.new(
sample_rate=500.0,
description="Corrected from field log.",
)
inventory_v2 = inventory.replace(acquisition, corrected_acquisition)The same pattern applies to optical path revisions. For example, if a fiber breaks, one can discover the break by looking at continuous files, fix the end_time for the old OpticalPath, and add the new optical path as the current one.
fiber_array = inventory.networks[0].fiber_arrays[0]
opath = fiber_array.optical_paths[-1]
break_time = "2024-05-12T10:30:00.12"
break_distance = 600.0
closed_opath = opath.new(end_time=break_time)
kept, _ = opath.split_at(break_distance)
new_opath = kept.new(
start_time=break_time,
end_time=None,
description="Fiber break at 600 m; sensing continues on the near side.",
)
new_fiber_array = fiber_array.new(
optical_paths=(
fiber_array.optical_paths[:-1] + (closed_opath, new_opath)
)
)
inventory_v2 = inventory.replace(fiber_array, new_fiber_array)Intervals are half-open, so break_time itself belongs to the new epoch.
A convenience function addressing the fiber array directly is proposed but not implemented; the explicit form above is how this is done today:
inventory_v2 = inventory.register_fiber_break(
fiber_array="AA.F023", time=break_time, distance=break_distance
)Patch Resolution
Patch enrichment starts from acquisition_key (resolution rules):
patch = patch.update_attrs(acquisition_key="DAS.L001.01.RAW")
patch = patch.enrich(
inventory,
attrs=("sample_rate", "gauge_length", "interrogator.model"),
coords=("distance", "zone", "latitude", "longitude", "elevation"),
on_missing="null",
)Design Rule
replace is a correction (in place, retroactive); appending a closed path plus its successor is an epoch. Nothing mutates: every update builds a new inventory value.