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 intoextra(traces andspectra[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 unlessNotSet),Job Code→job_code,Bottle Number→vial,MS Method→method,Inlet Method→inlet_method,Tune Method→tune_method,Version→header_version(alsoformat_version);Acquired Date+Acquired Time(16-Jun-2021,22:01:20) →acquired_at(header_datetime).Cal Function n: c0,c1,…,Tklines (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. OtherCal …lines are kept verbatim ininfo --view full._extern.inf(parse_extern,ExternInfo,ExternFunction):Function Parameters - Function N - TYPEsections give each function’s type (kind:TOF MS FUNCTION,TOF MSMS FUNCTION,REFERENCE, …),Data Format(data_format) and its otherkey<TAB>valuelines (parameters);Instrument Parameters - Function N:sections (MRM files) and aPolarity ES+/ES-line givepolarityper 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 intoinfo --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_idfunction=F process=0 scan=S(S counted per function from 1);scan_number= S;ms_levelfrom 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.infsection, subsections included, ramps a high collision energy (high_energy) — is 2 withisolation_window_mz= the scan window andprecursor_mzits centre,extra.mse_high_energy), falling back to the_extern.inftype text (MSMS→ 2); the lock-spray reference function is MS1 withextra.lock_mass_reference: trueand each scan’s flagged lock-mass peak inextra.lock_mass_peak_mz; drift-resolved functions (drift_resolved) sayextra.drift_bins;centroidedfor the 12-byte layout;precursor_mz= STSSet Mass(TOF MS/MS) or the block’s set mass (product-ion scans);collision_energy= STSCollision Energy(MS/MS only);activationHCD(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. Runextra: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): columnsrt_min,tic_stored, then one per MRM transition namedprecursor > product(583.4 > 209.2, shortest f32 text) or SIR mass, dtypeuint32/uint16(the packed storage word), unitcounts;extra.function,polarity,bytes_per_value,function_kind.traces[]: the functions whose scan times are evenly spaced within 1 % (channelsTIC (stored)+ transitions), one trace per photodiode-array function (PDA (FUNCnnn):timein s, then one channel per wavelength withextra.wavelength_nm, the stored signed absorbance counts), one trace per analog channel (_CHROnnn.DAT, e.g.System Pressureinbar) when its times are evenly spaced, then — when there are spectra —TIC(the stored TIC of every spectrum) andBPC(the most intense decoded value of every spectrum), both irregularly sampled (channelstimein s,intensity).find_spectrumresolves 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.