Skip to content

pwiz-sharp: added mzPeak format support (read, write, msconvert) - #4311

Open
chambm wants to merge 2 commits into
chambem2/pwiz-sharpfrom
chambem2/pwiz-sharp-mzpeak
Open

pwiz-sharp: added mzPeak format support (read, write, msconvert)#4311
chambm wants to merge 2 commits into
chambem2/pwiz-sharpfrom
chambem2/pwiz-sharp-mzpeak

Conversation

@chambm

@chambm chambm commented Jun 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds mzPeak (Apache Parquet tables packed in a ZIP) as a first-class MSData format in pwiz-sharp — reader, writer, IReader/format plumbing, and msconvert --mzpeak output.
  • Full-document round-trip parity with mzMLb (metadata + binary) across all 8 vendor readers, gated in the vendor reader test harness (TestMzPeakRoundTrip).
  • Cross-stack read support for mzPeak files written by the independent mzPeak.NET (Apache-Arrow) stack: type/width-adaptive column reads (uint8 ms_level, float32 scalars, int32/uint32/uint64 ints), Parquet-statistics row-group discovery with multi-group merge, and the separate wavelength_spectra_* (UV/DAD) entries appended after the MS spectra.
  • Lazy per-row-group reads with bounded memory; parquet read in place from the ZIP (no extraction) when entries are Stored.

Test plan

  • MsData.Tests - 97/97 (mzPeak column/IReader/round-trip + cross-stack read tests against committed mzPeak.NET fixtures)
  • Thermo/Agilent/Bruker/Sciex/Waters/Mobilion/UIMF/UNIFI vendor reader tests - 112/112 (each includes the mzPeak round-trip)

See ai/todos/active/TODO-20260616_pwiz_sharp_mzpeak.md

Co-Authored-By: Claude noreply@anthropic.com

@chambm

chambm commented Jun 17, 2026

Copy link
Copy Markdown
Member Author

@mobiusklein I vibe coded this partly based on MzPeak.NET. Want to try it out?

@mobiusklein

mobiusklein commented Jun 17, 2026 via email

Copy link
Copy Markdown
Contributor

@chambm

chambm commented Jun 17, 2026

Copy link
Copy Markdown
Member Author

And I had just reinstalled Visual Studio too. This looks structurally correct, but I haven't run it yet. I know you're only prototyping so the null marking, chunked layout and so on aren't there yet, which is where a lot of the complexity lives. I saw the comments say something about no async runtime. I had to absorb the async dependency from ParquetSharp's Arrow interop layer. Is this a no-go scenario for you?

Right, we don't use async/await in Skyline as a rule due to its tendency to use the system thread pool which makes non-instrumented handle and leak detection annoyingly tricky. I did defer the chunked implementation but I'll kick it off now. This format seems really complicated to me: it'll be interesting to see how much traction it gets in the community.

@mobiusklein

Copy link
Copy Markdown
Contributor

Thank you for explaining. If the async was isolated to be entirely within a SpectrumList implementation and/or run on a same thread-TaskScheduler, would that be acceptable? The same thread scheduler seems like it would be safer for leak avoidance, but I have not dealt with this issue myself.

The only reason the original code used async anywhere was because ParquetSharp only lets you read Arrow arrays via an async enumerator interface they implement from the .NET Apache Arrow library, and that leaks into everything else. My attempts to write nesting depth-independent column readers against ParquetSharp weren't successful, but it was comparatively easy using Arrow's Visitor API. The Arrow API doesn't directly use the .NET Arrow library to do the conversion, that gets done in the C++ library bindings, but getting the Arrow arrays out is more complicated.

Which part is most complicated seeming to you?

chambm and others added 2 commits June 30, 2026 16:05
* Read/write mzPeak (Parquet-in-ZIP) as a first-class MSData format
* Full-metadata round-trip parity with mzMLb across all 8 vendor readers
* Cross-stack reads of mzPeak.NET files (adaptive types, UV/DAD spectra)
* Lazy row-group reads; msconvert --mzpeak; vendor harness round-trip gate

See ai/todos/active/TODO-20260616_pwiz_sharp_mzpeak.md

Co-Authored-By: Claude <noreply@anthropic.com>
… test teardown

* MzPeakReader detects mzPeak.NET's chunked layout (one parquet row per m/z
  chunk vs. one row per point) and routes through new MzPeakChunkCodec
* Port of mzPeak.NET's DeltaCodec / NoCompressionCodec / NullInterpolation:
  cumulative-sum from chunk start; seam nulls filled from per-spectrum
  mz_delta_model polynomial (or local-median spacing for wider gaps);
  intensities pass through with null=0
* CrossStackReadTests gains two chunked round-trip tests against a 2.3 MB
  mzpeaknet_small_chunked.mzpeak fixture; values match mzPeak.NET exactly
* MzPeakReaderAdapterTests: every MSData now via `using` so the new
  MzPeakArchive handle releases at end of test; ClassCleanup retries with
  GC pump so a stray leak surfaces loudly rather than silently failing

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants