Skip to content

Waters MassLynx .raw directories

Waters MassLynx writes each acquisition (Xevo, SYNAPT, ACQUITY and other instruments) as a directory ending in .raw. OpenReadout returns MRM and SIR data as tables and traces, full-scan spectra, PDA traces and analog channels. Drift-resolved data (ion mobility, SONAR) is not read, and lock-mass correction is not applied.

Derived from public MetaboLights and PRIDE acquisitions compared with the depositors’ mzML conversions, and from rainbow’s public documentation pages for the binary files (rainbow, LGPL-3.0, run as a reference reader). Spectra are also checked against ProteoWizard conversions, made with Waters’ own library, of acquisitions from ProteoWizard’s test data (crates/openreadout-corpus-tests/tests/mz_agreement.rs). See docs/provenance/waters-raw.md. Format id: waters-raw; crate openreadout-waters. Confidence (computed by the evidence rubric, docs/assurance.md): high.

A MassLynx acquisition is a directory ending in .raw. Detection: a directory holding _HEADER.TXT or a _FUNCnnn.IDX (definite with the .raw extension, likely without).

Text files

  • _HEADER.TXT: lines $$ Key: value (parse_header_txt). Mapped into extra (traces and spectra[0]): Acquired Name → sample_name, Sample Description → description, SampleID → sample_id, User Name → operator, Instrument → instrument (XEVO-TQXS#WBA0260; the part before # is the model, the part after the serial unless NotSet), Job Code → job_code, Bottle Number → vial, MS Method → method, Inlet Method → inlet_method, Tune Method → tune_method, Version → header_version (also format_version); Acquired Date + Acquired Time (16-Jun-2021, 22:01:20) → acquired_at (header_datetime).
  • Cal Function n: c0,c1,…,Tk lines (Calibration, coefficients, kind, parse, apply, is_identity): the m/z calibration of function n. T0 (CalibrationKind::Linear): m = Σ cᵢ mᵢ with m the stored mass (rainbow’s pages). T1 (CalibrationKind::SquareRoot): √m = Σ cᵢ (√stored)ⁱ — inferred: bit-exact against the MTBLS7290 export after rounding to single precision. Other Cal … lines are kept verbatim in info --view full.
  • _extern.inf (parse_extern, ExternInfo, ExternFunction): Function Parameters - Function N - TYPE sections give each function’s type (kind: TOF MS FUNCTION, TOF MSMS FUNCTION, REFERENCE, …), Data Format (data_format) and its other key<TAB>value lines (parameters); Instrument Parameters - Function N: sections (MRM files) and a Polarity ES+/ES- line give polarity per function, or for the whole acquisition (ExternInfo::polarity) when it appears outside any function section; Created by Masslynx v4.1 → software_version; Lock Mass → lock_mass. Maps: functions.
  • _INLET.INF: inlet (LC) method text; copied into info --view full.

Binary files

file layout (little-endian) source
_FUNCnnn.IDX one record per scan (ScanIndex, parse_idx, idx_record_len, idx_record_len_for): u32 byte offset of the scan in _FUNCnnn.DAT (offset); u32 whose low 22 bits are the number of stored values (count) and high 10 bits a flag field (flags: 32 in the MRM files and MTBLS7290, 288 in PXD059722); f32 at +8 = the scan’s stored total ion current (stored_tic); f32 at +12 = retention time in minutes (rt_min); 6 bytes not interpreted. 22-byte records (IDX_RECORD) normally; 30-byte records (IDX_RECORD_WIDE): the u32 offset is then 0 and a u64 at +22 holds the offset. The record length is the one whose records tile the file and whose offsets step by count × bytes per value through the whole DAT (idx_record_len_for); 30-byte records occur with flags 0x120 (bit 0x100, FLAG_WIDE_CALIBRATED) and 0x60 (a continuum SYNAPT G2-Si file), so the flag decides only when both lengths fit offset/count/time: rainbow docs; TIC, 30-byte records: inferred
_FUNCnnn.DAT, 12-byte values per value: u32 intensity: 22-bit mantissa × 2^(e − 21) with e the low 6 bits of the top 10 (decode_intensity12); bits 6 and 7 of that 10-bit field are point flags (value12_flags): 0x40 (FLAG_LOCK_MASS_PEAK) marks the lock-mass peak of each lock-spray reference scan, 0x80 a few analyte peaks (meaning unknown); u32 mass word with a 5-bit exponent (top bits) and 27-bit mantissa: stored mass = mantissa × 2^(exponent − 27) (decode_mass27, decode_value12); a third u32 not interpreted. Centroids, ascending in m/z inferred; validated bit for bit (below)
_FUNCnnn.DAT, 8-byte values from the most significant bit: 5 bits x, a 31-bit fixed-point mass with x integer bits; 6 bits y, one bit not interpreted, 21 bits intensity × 2^(y − 21) (decode_value8): continuum (profile) and SQD scans rainbow docs; validated on 7 files (MSe, continuum DDA, drift-summed HD data, SQD)
_FUNCnnn.DAT, 6-byte values 48 bits: 23-bit mass base, 5-bit mass power (mass = base × 2^(power − 23)), 4-bit intensity power, signed 16-bit intensity base (intensity = base × 4^power) (decode_value6): quadrupole product-ion scans, and (wavelength nm, absorbance count) in photodiode-array functions rainbow docs; validated on the Xevo TQ-MS product-ion scans and the SQD PDA function
_FUNCnnn.DAT, 4-byte values one u32 per MRM transition: low 22 bits mantissa, high 10 bits exponent, value = mantissa × 2^(exponent − 21) (decode_packed32) inferred: every scan’s values sum to the stored TIC (2,561 scans); rainbow’s output is exactly twice these values
_FUNCnnn.DAT, 2-byte values one u16 per MRM transition or SIR mass: base in the high 13 bits × 4^(low 3 bits) (decode_packed16) rainbow docs; validated: all 16,548 values of MTBLS225 equal the depositor export
_FUNCTNS.INF 416-byte blocks (FUNCTION_BLOCK, FunctionBlock, parse_functions), one per function: u16 code at 0 (code; its low 5 bits the function type, function_type: FUNCTION_TOF_MS 0x12, FUNCTION_TOF_MSMS 0x10, FUNCTION_DAUGHTER 0x06 (quadrupole product-ion scan), FUNCTION_MRM 0x09, FUNCTION_PDA 0x0C, 0x00 quadrupole full scan; bit 0x20 set in negative-ion functions; bit 0x8000 the lock-spray reference function, is_reference_code); f32 at 0x18 (set_mass): a product-ion scan’s precursor; f32 start and end time in minutes at 10 and 14 (start_min, end_min); up to 32 f32 at 0xA0 (set_mz: MRM precursors / SIR masses, or the start mass of a scanning function) and 32 at 0x120 (second_mz: MRM products, or the end mass of a scanning function) 0xA0: rainbow docs; the rest inferred (scan windows equal the exports’)
_FUNCnnn.STS per-scan statistics, self-describing (StatsLayout, parse_stats_layout, header_len, record_len, fields, record_count, field, value): u16 header length, u16 (1), u16 record length, u16 field count; from byte 32 (STATS_PREFIX) one 48-byte descriptor per field (STATS_FIELD, StatField: u16 id, u16 kind — 0 byte, 1 i16, 2 i32, 3 f32 — u16 offset in the record, NUL-terminated name); then one record per scan. The fields named Set Mass (MS/MS precursor; descriptor id 77, STAT_SET_MASS, field_by_id, which is also the only, unnamed, field of files the MassLynx SDK writes), Collision Energy, Collision Energy2 and Cone are read inferred (self-describing; Set Mass equals the export’s precursor)
_CHROnnn.DAT 0x80-byte header (CHRO_HEADER) holding the axis labels, then (f32 time in minutes, f32 value) pairs rainbow docs
_CHROMS.INF u16 header length (0x80), u16 channel count, u16 record length; per channel: 4 bytes, the NUL-terminated description, $CC$,1.000000,3,0,0,bar whose last field is the unit (parse_chroms) inferred
_funcNNN.cdt, _funcNNN.ind drift-resolved data of ion-mobility (HDMS, HDMSe, HDDDA, HD-MRM) and SONAR functions: 200 bins of one pusher period (1/Pusher Frequency, 69.25 µs); the .ind header holds the bin count and per block three counts; the .cdt encoding is not decoded. The .DAT of such a function holds the drift-summed spectrum (its TIC equals the sum over the bins) inferred; bins not decoded
.EE, .CMP, _history.inf not interpreted; listed by info --view structure –

The bytes per value of a function are inferred as DAT length / Σ counts (bytes_per_value).

Calibration

A scanning function’s stored masses are calibrated with its Cal Function n line unless the index flag 0x100 is set: PXD059722 (centroided after acquisition, _history.inf present) stores masses equal to its export’s m/z bit for bit, while applying its Cal Function would move them by 1e-4. The calibrated 12-byte masses are rounded to single precision (all 132,053 MTBLS7290 export m/z are f32 values and match exactly that way); 6- and 8-byte masses keep double precision.

Mapping

  • spectra[0] (only when a function holds 12-, 8- or 6-byte values and is not a PDA/UV function, is_spectral): every scan of every scanning function, merged by retention time (ties by function number), as the exports list them. native_id function=F process=0 scan=S (S counted per function from 1); scan_number = S; ms_level from the block’s function type (0x10 TOF MS/MS and 0x06 product-ion scans are 2; an MSe high-energy TOF MS function — its _extern.inf section, subsections included, ramps a high collision energy (high_energy) — is 2 with isolation_window_mz = the scan window and precursor_mz its centre, extra.mse_high_energy), falling back to the _extern.inf type text (MSMS → 2); the lock-spray reference function is MS1 with extra.lock_mass_reference: true and each scan’s flagged lock-mass peak in extra.lock_mass_peak_mz; drift-resolved functions (drift_resolved) say extra.drift_bins; centroided for the 12-byte layout; precursor_mz = STS Set Mass (TOF MS/MS) or the block’s set mass (product-ion scans); collision_energy = STS Collision Energy (MS/MS only); activation HCD (beam-type CID, as the exports record for Waters TOF cells); scan_window_mz = the function block’s start/end mass; total_ion_current = the sum of the decoded intensities; extra: function, function_kind, stored_tic, calibration, cone_v, collision_energy2. Run extra: functions (per scanning function: number, kind, MS level, scans, bytes per value, lock_mass_reference, scan window), polarities, lock_mass, instrument_serial, stored_spectra, method_summary.
  • tables[]: one per function (FUNCnnn): columns rt_min, tic_stored, then one per MRM transition named precursor > product (583.4 > 209.2, shortest f32 text) or SIR mass, dtype uint32/uint16 (the packed storage word), unit counts; extra.function, polarity, bytes_per_value, function_kind.
  • traces[]: the functions whose scan times are evenly spaced within 1 % (channels TIC (stored) + transitions), one trace per photodiode-array function (PDA (FUNCnnn): time in s, then one channel per wavelength with extra.wavelength_nm, the stored signed absorbance counts), one trace per analog channel (_CHROnnn.DAT, e.g. System Pressure in bar) when its times are evenly spaced, then — when there are spectra — TIC (the stored TIC of every spectrum) and BPC (the most intense decoded value of every spectrum), both irregularly sampled (channels time in s, intensity).
  • find_spectrum resolves a scan number in the lowest-numbered scanning function.

check finding codes

truncated (IDX not whole records, DAT shorter than the index needs, CHRO pairs incomplete), missing_file, undecodable (a spectrum that fails to decode) (errors); missing_header, bad_functions_inf, function_count_mismatch, time_not_monotonic, tic_mismatch, statistics_count_mismatch (warnings).

Vocabulary (every public identifier in crates/openreadout-waters must appear here)

identifier meaning
WatersRawReader, WatersRawDataset, WATERS_ID, is_waters_dir, is_waters_dir_in, open, open_input, functions format reader, opened directory, the id waters-raw, directory test (on the local disk, or in a byte-source namespace), open (a local path, or an input held in memory or by the host), the functions of an opened directory
IDX_RECORD, IDX_RECORD_WIDE, FLAG_WIDE_CALIBRATED, FUNCTION_BLOCK, CHRO_HEADER, STATS_PREFIX, STATS_FIELD record/block/header sizes (22, 30, 416, 0x80, 32, 48 bytes) and the index flag bit 0x100
le_u16, le_i16, le_u32, le_i32, le_u64, le_f32 bounds-checked little-endian readers
ScanIndex, offset, count, flags, stored_tic, rt_min, parse_idx, idx_record_len one _FUNCnnn.IDX record, its parser and the record-length test
decode_packed32, decode_packed16, decode_mass27, decode_value12, decode_value8, decode_value6 DAT value decoders
FunctionBlock, code, start_min, end_min, set_mz, second_mz, parse_functions one _FUNCTNS.INF block and its parser
parse_header_txt, header_datetime $$ Key: value lines; date + time → ISO-8601
Calibration, CalibrationKind, Linear, SquareRoot, coefficients, kind, parse, apply, is_identity a Cal Function n line: coefficients and form (T0, T1)
StatsLayout, StatField, header_len, record_len, fields, id, name, record_count, field, value, parse_stats_layout the self-describing .STS layout
ExternInfo, ExternFunction, parse_extern, polarity, data_format, parameters, software_version, lock_mass what _extern.inf says, per function and for the acquisition
parse_chroms _CHROMS.INF channel descriptions
AnalogChannel, number, file, description, unit, conversion, points, trailing an analog channel: its number, DAT file, _CHROMS.INF description, unit, $CC$ string, (time, value) pairs, leftover bytes
decode_intensity12, value12_flags, FLAG_LOCK_MASS_PEAK 12-byte intensity word without its flag bits; the flags; the lock-mass-peak flag (0x40)
function_type, is_reference_code, set_mass, FUNCTION_TOF_MS, FUNCTION_TOF_MSMS, FUNCTION_DAUGHTER, FUNCTION_MRM, FUNCTION_PDA function block type (low 5 bits of the code) and its values, reference bit, product-ion precursor
field_by_id, STAT_SET_MASS .STS field by descriptor id; id 77 = Set Mass
WatersFunction, scans, idx_len, idx_record_len, dat_len, bytes_per_value, block, calibration, stats_layout, stats, high_energy, drift_resolved one function: scan index, file sizes, index record length, value width, function block, polarity, kind, data format, calibration, statistics layout and bytes

How this reader was derived, file by file: provenance log.