Skip to main content

Arrow schema

openmassspec-core's arrow feature exposes a single record-batch schema that is identical across all vendors. One row = one spectrum; peak arrays live in LargeList<Float> columns alongside scalar metadata columns. Precursor fields are inlined as nullable scalar columns; an MS1 spectrum has all precursor_* columns null. The schema is part of this crate's stable public surface: any column addition is a minor-version bump, any removal or rename is breaking.

Schema (flat)

ColumnArrow typeNotes
indexUInt320-based, strictly increasing.
scan_numberUInt321-based, source-stable.
native_idUtf8Vendor native id (e.g. controllerType=0 ...).
ms_levelUInt81, 2, ...
polarityUtf8, nullable"positive" / "negative".
scan_modeUtf8, nullable"profile" / "centroid".
analyzerUtf8, nullable"itms", "tqms", "sqms", "tof", "ftms", "sector".
filterUtf8, nullableThermo-style scan filter string, when the vendor populates one.
retention_time_secFloat64Seconds.
total_ion_currentFloat64, nullableVendor-declared TIC, when present.
base_peak_mzFloat64, nullableVendor-declared base-peak m/z, when present.
base_peak_intensityFloat64, nullableVendor-declared base-peak intensity, when present.
low_mzFloat64, nullableLowest observed m/z, when the vendor declares one.
high_mzFloat64, nullableHighest observed m/z, when the vendor declares one.
ion_injection_time_msFloat64, nullable
inv_mobilityFloat64, nullableMean inverse reduced ion mobility (1/K0) for the spectrum.
faims_cvFloat64, nullableFAIMS compensation voltage in volts.
precursor_target_mzFloat64, nullableIsolation-window center m/z. Null for MS1.
precursor_selected_mzFloat64, nullableMonoisotopic-resolved precursor m/z.
precursor_isolation_widthFloat64, nullableTotal isolation width in m/z.
precursor_chargeInt32, nullableNull when not assigned.
precursor_intensityFloat64, nullable
precursor_collision_energyFloat64, nullableInterpretation depends on precursor_ce_is_nce.
precursor_ce_is_nceUInt8, nullable1 if precursor_collision_energy is normalized (NCE %), else 0.
precursor_native_idUtf8, nullableNative id of the precursor scan, when known.
precursor_activationUtf8, nullable"cid", "hcd", "etd", "ecd", "uvpd", "pqd", "pd", "sid", "ethcd", "irmpd", "mpid".
precursor_analyzerUtf8, nullableAnalyzer that recorded the precursor scan; same value set as analyzer.
precursor_ccsFloat64, nullableCollision cross-sectional area of the selected ion, in square angstroms.
mzLargeList<Float64>Ascending peaks.
intensityLargeList<Float32>Same length as mz.
inv_mobility_per_peakLargeList<Float32>, nullablePresent when the vendor carries a per-peak mobility array (e.g. Bruker TIMS).
mobility_array_kindUtf8, nullable"inverse_reduced_k0" / "drift_time_ms"; interpretation of inv_mobility_per_peak for every row in the batch.

SpectrumBatchBuilder::new(Option<MobilityArrayKind>) sets the mobility_array_kind value shared by every row in the batch. Pass None for instruments without ion mobility (inv_mobility_per_peak and mobility_array_kind stay null for every row).

Building a batch

use openmassspec_core::arrow::{spectrum_record_schema, SpectrumBatchBuilder};
use openmassspec_core::{MobilityArrayKind, SpectrumSource};
use opentimstdf::mzml::TdfSource;

let mut src = TdfSource::open("sample.d")?;
let mut b = SpectrumBatchBuilder::new(Some(MobilityArrayKind::InverseReducedVsPerCm2));
for s in src.iter_spectra() {
b.push(&s);
}
let batch = b.finish()?;
assert_eq!(batch.schema(), spectrum_record_schema());
# Ok::<(), Box<dyn std::error::Error>>(())

Why LargeList?

Peak arrays for a single TDF MS1 frame routinely cross the 2^31 byte boundary when stored back-to-back, especially in 32-bit float intensities. LargeList (64-bit offsets) avoids the silent truncation that List (32-bit offsets) would otherwise introduce.