OpenMS 3.6.0 Released
Dear OpenMS-Users,
We are proud to announce the release of OpenMS 3.6.0.
Grab it here
OpenMS 3.6.0 is a substantial release and an important step toward our next major version. It addresses many feature requests, including extended support for ion mobility (FAIMS and PASEF), arrow and parquet support, and new nanobind-based pyOpenMS bindings that enable more Pythonic and faster code. A restructured build system now supports building OpenMS with vcpkg, replacing the deprecated contrib repository. These are just a few of the many improvements in this release.
General:
- FIX: Normalize source-file paths when converting them to file URIs, including Windows paths with mixed separators (#10275)
- Updated the bundled PSI-MS controlled vocabulary from 4.1.155 to 4.2.2, including CV term-name changes in mzML/TraML output and vocabulary versions in mzTab-M/mzQC output (#8691)
- New native readers for Bruker timsTOF .d and Thermo .raw, which FileConverter and many other tools use, and for imzML (library and pyOpenMS) and Bruker MALDI imaging (library only); no TOPP tool reads imaging data yet. See OpenMS Library for capabilities and runtime requirements.
- New .idparquet, .featureparquet and .consensusparquet directory formats for native identification, feature and consensus-map storage, supported across TOPP tools (#9225, #9232, #9236, #9237, #9241, #9242, #9396, #9405).
- New: modification definition records let a tool register a named, non-vocabulary modification (an Id, formula and site not shipped in unimod.xml/PSI-MOD/XLMOD) so that files naming it stay readable by another process. ResidueModification::toDefinitionString()/fromDefinitionString() (de)serialise one record; ModificationsDB::registerDefinition()/hasDefinedModification() register and query them; the new ModificationDefinitionIO class collects the definitions a run’s identifications, features or consensus elements reference and attaches them to ProteinIdentification::SearchParameters under the “modification_definitions” meta value. ResidueModification::Provenance (DEFINED/CV/MASS_ONLY) records where a modification’s description came from. idXML, featureXML, consensusXML and the .idparquet/.featureparquet/.consensusparquet bundles all carry the definitions their peptidoforms reference and register them before parsing any sequence; ProForma writes a tool-defined modification as its chemistry plus an INFO: name (e.g. “[Formula:C9H11N2O8P1|INFO:NuXL:U-H2O]”) so a reader without the definition still gets the right mass, and resolves the name first when it is registered. OpenNuXL is the first consumer (see OpenNuXL below). BREAKING: an idXML, featureXML or consensusXML file naming such a modification is a hard load failure (“Cannot convert string to peptide modification”) in an OpenMS build without this support (#10003, #10026, #10028, #10036, #10037, #10038, #10039, #10040)
- Transparent .zip input for the XML formats (except mzIdentML) and Bruker .d directories; mzML, mzXML, mzData, featureXML, consensusXML, traML and mzIdentML output is compressed with gzip or bzip2 when the file name ends in .gz or .bz2, in any letter case. TOPP tools refuse a compressed output name for any other format (#7560, #9139, #9259, #10317).
- BREAKING: OpenMS::String/StringView replaced by std::string/std::string_view; StringList is std::vectorstd::string. Use OpenMS::StringUtils free functions for conversion, splitting, trimming and substitution. String, StringConversions and StringUtilsSimple shim headers were removed (#9450, #9468). “Migrating from OpenMS::String” in the developer documentation lists the replacement for each member of String and the changes the compiler does not catch.
- Core modularization reduces dependencies between KERNEL, FORMAT, PROCESSING, APPLICATIONS and QC. Shared utilities cover spectrum-type estimation, resampling, alignment defaults, filename recognition, ion-mobility metadata and data-processing provenance; compatibility entry points remain unless listed below (#10083, #10092, #10101). Include used types directly instead of relying on transitive headers; ToolInfo moved to DATASTRUCTURES/ToolInfo.h (#8946, #10083).
- Shared-data lookup uses the compiled-in path, then the executable location, then OPENMS_DATA_PATH, preventing stale installations from overriding bundled resources. Missing-file errors identify the resolved directory (#9635, #9636, #9650).
- A TOPP tool may keep its own sources and headers in a subfolder src/topp/
/ with a CMakeLists.txt of its own, next to the single-file src/topp/ .cpp layout. The class test of a tool-local class builds that class straight from the tool folder, so moving code out of the library does not cost it its test coverage. BREAKING (installed headers): OpenNuXL moved to src/topp/OpenNuXL/ and took the whole NuXL pipeline with it. Nothing outside this tool ever used it, so OpenMS/ANALYSIS/NUXL is gone: its thirteen headers are no longer installed and its classes are no longer part of libOpenMS. The five NuXL class tests are unchanged and still run (#10228). - The TOPP tool registry (which tools exist, and their TOPPAS/CTD category) is generated at build time from each tool’s openms_topp_tool() declaration in src/topp/executables.cmake, instead of being hard-coded as 154 literal entries in ToolHandler::getTOPPToolList(). The build writes share/OpenMS/TOOLS/OpenMS.tsv from the declarations, so a build option that removes a tool (e.g. DISABLE_OPENSWATH) now also removes it from the registry, and a tool built outside this repository can register itself by installing its own .tsv next to it, without an OpenMS rebuild. ToolHandler looks for a registry at the installation’s shared-data path, then next to the executable, then in the build tree if earlier locations contain no registry. It also reads .tsv files from directories named by OPENMS_TOOL_REGISTRY_PATH or the legacy OPENMS_TTD_INTERNAL_PATH, and caches the result after the first read. ToolHandler::getTypes() returns an empty list for a tool the registry does not know instead of throwing, matching its documented behavior. BREAKING (installed headers): ToolDescriptionFile, ToolDescriptionHandler and Internal::ToolDescription’s foreign-executable fields (FileMapping, MappingParam, ToolExternalDetails, external_details, is_internal) are removed; nothing used them once the .ttd XML format was replaced by the generated TSV (#10216).
- BREAKING: TOPPBase no longer takes a bool official, and neither do SearchEngineBase, TOPPOpenSwathBase, TOPPMapAlignerBase and TOPPFeatureLinkerBase, which only forwarded it. A tool is registered by its openms_topp_tool() declaration, the same declaration that builds it, so every tool that exists is registered and the flag named nothing. What it did instead was let a tool disown its own registration: OpenNuXL, PeakPickerIM, FeatureFinderLFQ, ProSE, QCEmbedder and ImageCreator each wrote an empty category into their CTD while the registry held a real one, so TOPPAS and every other CTD consumer saw them uncategorised; all six now carry their category. Out-of-tree code deriving from one of these classes drops the argument; something that is not a registered TOPP tool at all passes toolhandler_test = false instead, which is now the only way to skip the registry check (#10228).
- BREAKING (installed headers): Move tool-only helpers without pyOpenMS bindings into the CometAdapter, DecoyDatabase, INIUpdater, NucleicAcidSearchEngine, OpenSwathInfer, QualityControl and UniPEFF folders. Their 21 headers are no longer installed and 20 implementations no longer live in libOpenMS or libOpenMS_CLI. Class tests travel with the tools; reusable inference tests also remain available in library-only builds (#10239). Helpers built on a private dependency of libOpenMS stay in the library even with a single tool as user, so that no tool has to find that dependency itself: the Arrow/Parquet-based OpenSWATH exporters, OSW Parquet reader/writer, Percolator scoring, XIPMParquetConsumer and ParquetTableComparator. OpenSwathExport, OpenSwathPeakMapExtractor, OpenSwathPercolatorScoring, OpenSwathWorkflow and ParquetDiff link nothing but OpenMS (#10247).
- BREAKING: KNIME plugin support was removed. The ENABLE_PREPARE_KNIME_PACKAGE option and the prepare_knime_package targets are gone, as are the KNIME user tutorial, the LaTeX tutorial handout and the .knwf workflow collection under doc/tutorials (still available in the archived OpenMS/Tutorials repository). CTD generation is unaffected: -write_ctd and -write_cwl continue to work for Galaxy and CWL (#10135).
- The API documentation no longer generates Graphviz (dot) graphs: include, included-by, collaboration, directory and graphical class-hierarchy graphs are gone, class inheritance diagrams use doxygen’s built-in renderer, and the few hand-drawn diagrams are pre-rendered SVGs. This shrinks the HTML documentation by more than half and makes Graphviz optional; the ‘doc_dot’ target still builds all graphs. The OPENMS_HASDOXYGENDOT macro in the installed OpenMS/config.h, which was always 0 and no longer used, was removed (#10265).
Dependencies:
- Minimum versions: CMake 3.24, Eigen 3.4.0, Boost 1.81, Arrow/Parquet 23 and nanobind 3.1. Arrow/Parquet is required on all platforms; WITH_PARQUET was removed and versions 24+ are accepted. Compiler minimums are checked before vcpkg runs (#8366, #8370, #8422, #8679, #8699, #8991, #9042, #9095, #9196, #9221, #10112, #10133, #10221).
- C++23 is required (#9037). The minimum compilers are GCC 13, Clang 17, AppleClang 16 (Xcode 16) and Visual Studio 2022 17.14; configuring with an older one stops with a message.
- Zstandard (zstd) is now a required dependency (mzML zstd binary array compression; #9033). It is found via its CMake config package or as a plain library (e.g. libzstd-dev).
- Qt6 is required only with WITH_GUI=ON. Core/non-GUI code now uses standard C++ and platform APIs, libcurl for HTTP, boost-process for subprocesses and nlohmann/json. ZIP support uses libzip instead of minizip-ng. ExecutePipeline, INIUpdater and ImageCreator require the GUI build (#8808, #8841, #8936, #8937, #8938, #8939, #8940, #8965, #9041).
- BREAKING: Qt-based public APIs were removed: Date’s QDate constructor, QString-based filesystem parameters and QObject inheritance in ExternalProcess. Qt string interop and Qt5Port.h were removed; downstream code using Qt must link Qt6::Core explicitly.
- LibSVM, Xerces-C++, SQLite, Eigen, CURL and nlohmann/json no longer leak into the public dependency interface. Shared-library consumers no longer require CURL/Xerces development packages; OpenSwathAlgo’s Boost headers are private. See OpenMS Library for XMLHandler/Matrix API migration (#8511, #8547, #8558, #9712, #9737, #10084, #10103).
- Boost is used header-only: OpenMS, its tools and tests no longer link the compiled Boost.Regex, Boost.Iostreams and Boost.DateTime libraries, of which only header-only parts were used. Building needs just the Boost headers, and a static Boost works as well as a shared one. A static Boost used to be linked into the shared libOpenMS, which could fail at link time: the archives are not always built with -fPIC, and their own dependencies (zstd, lzma, ICU) had to be installed as development packages. The BOOST_USE_STATIC option and the Homebrew static-Boost link fixups (#10187) were removed; passing -DBOOST_USE_STATIC now only triggers CMake’s unused-variable warning (#3319).
- BREAKING (installed headers): two internal headers are no longer installed, and two public ones no longer pull in a private dependency. DATASTRUCTURES/MatrixEigen.h (the Eigen::Map views on Matrix) and SYSTEM/SIMDe.h both already documented themselves as internal – MatrixEigen.h says not to include it from public headers, SIMDe.h says to include it from .cpp files only – and only libOpenMS sources and class tests include them; they stay where they are in the source tree, so in-tree builds are unaffected. FORMAT/GzipIfstream.h and FORMAT/Bzip2Ifstream.h no longer include <zlib.h> and <bzlib.h>: they store the library handle as an opaque pointer (a forward-declared gzFile_s*, resp. a void*, which is what bzlib’s BZFILE is), so neither header needs the zlib/bzip2 include directory any more. External code that obtained Eigen, SIMDe, zlib or bzlib declarations through one of these headers has to include the library itself. find_package(OpenMS) no longer looks for Eigen at all: CMake omits the PRIVATE dependencies of a shared library from the exported link interface, and the OpenMS build always produces shared libraries, so OpenMSTargets.cmake names no Eigen target and a consumer needs neither the Eigen CMake package nor its headers. Previously find_package(OpenMS REQUIRED) failed outright when Eigen was absent. The lookup is kept for a static OpenMS, whose export does carry $<LINK_ONLY:Eigen3::Eigen>, and runs only for such an installation. Eigen is still required to build OpenMS and pyOpenMS (#10169).
- The class-test framework (CONCEPT/ClassTest.h, ClassTestUtils.h,
FuzzyStringComparator.h, MacrosTest.h) is no longer installed by default. It is an
in-repo development tool: its static library was already EXCLUDE_FROM_ALL and is not
exported, so an installation carried the headers without anything to link them
against.
cmake --install . --component OpenMSTestFramework_headersstill installs them explicitly. - CMake package: find_package(OpenMS CONFIG) provides namespaced imported targets, OpenMS::OpenMS, OpenMS::OpenSwathAlgo and, via COMPONENTS GUI, OpenMS::OpenMS_GUI together with the Qt6 modules it was built against; the un-namespaced names remain as aliases, while the bundled third-party libraries exist under the OpenMS:: namespace only. The build options of an installation are reported as OpenMS_WITH_GUI, OpenMS_WITH_HDF5, OpenMS_WITH_OPENTIMS, OpenMS_WITH_THERMO_RAW, OpenMS_WITH_OPENMP and OpenMS_BUILD_TOPP_TOOLS instead of the unprefixed WITH_* variables, which shadowed options of the consuming project, and the OPENMS_*_DIR variables no longer point into the prefix of a dependency found before them. The empty OPENMS_ADDCXX_FLAGS variable was dropped, and the Find modules of the OpenMS build (FindCOIN, FindLIBSVM, …) are no longer installed next to the package: they served the package’s former lookups of dependencies that are PRIVATE now. Consuming projects need CMake 3.24: find_package(OpenMS) rejects older versions with an explanatory message instead of failing later (#10158).
- The source tarball contains vcpkg.json, vcpkg-configuration.json and vcpkg-overlays/, so it builds with an external vcpkg (OPENMS_USE_VCPKG=ON and its CMAKE_TOOLCHAIN_FILE) as well as against system packages. With OPENMS_USE_VCPKG=ON, a missing or non-vcpkg toolchain stops the configure with a message that names the alternatives (#10327).
- The contrib (OpenMS/contrib) is deprecated and will be removed after 3.6: vcpkg builds the dependencies (see the vcpkg install guide and the CMake presets). It is no longer a git submodule; a build that still needs it takes it from a separate clone of OpenMS/contrib. Configuring with OPENMS_CONTRIB_LIBS, which requires OPENMS_USE_VCPKG=OFF, prints a deprecation warning (#10327).
- The dev container (.devcontainer/) builds with the vcpkg presets on Ubuntu 24.04 instead of
the contrib image. The Gitpod configuration and tools/quickbuild.sh/quickbuild-osx.sh, which
built contrib, were removed; use cmake –preset
-release instead (#10327). - Optional readers: WITH_OPENTIMS enables timsTOF support (default ON); opentims_DIR or opentims_ROOT selects a system installation before downloading. WITH_THERMO_RAW is ON by default on every supported platform; .NET 8+ is required at runtime (#9147, #9148, #9389, #9736, #10206).
- WITH_WNETALIGN (default OFF) fetches wnetalign/wnet/pylmcf when enabled. WITH_ONNX (default OFF) requires an external ONNX Runtime installation (#8992, #9453, #10255).
- HiGHS joins COIN-OR and GLPK as LP backends. LP_SOLVER=AUTO tries COIN-OR, GLPK, then downloads HiGHS (#9246).
- ENABLE_TDL now defaults to OFF; set it to ON for CWL support (#9067).
- macOS Intel builds discontinued; the minimum macOS version is 15 (Sequoia), for the installer and for the pyOpenMS wheels (#8450, #9037, #10202).
- vcpkg builds use OpenSSL 3.6.4, and the Linux DEBs and the macOS package bundle it (the 3.5.0 DEBs bundled 3.0.2). vcpkg.json pins the version because the baseline’s 3.6.2 is affected by the High-severity CVE-2026-45447.
- The SQLite amalgamation vendored with SQLiteCpp is updated from 3.49.2, which CVE-2025-6965 affects, to 3.53.1, the version vcpkg builds. Builds with USE_EXTERNAL_SQLITECPP=OFF, the default, compile it into libOpenMS.
- The bundled MaRaCluster is updated from 0.05.0 to 1.04.1 on Linux and Windows x86_64, and the macOS arm64 packages now include it too. MaRaClusterAdapter now converts the input files in MaRaCluster’s index step, single-threaded, before it clusters them: 1.04.1’s Windows build crashes in about one run in ten when it converts several files in parallel (OpenMS/THIRDPARTY#113, #10259).
PyOpenMS:
- BREAKING: boolean parameters are Python bools (#10116). Reading/writing Params now uses Python bool for boolean entries; assigning bool to non-boolean parameters raises TypeError; boolean-ness is preserved through Param updates, dict conversion, repr and INI round-trips. Param::setDefaults now gives existing string entries the defaults’ valid strings (values unchanged), so a partial Param cannot override an algorithm’s restrictions.
- Fixed keyword defaults that did not match the wrapped C++ signatures. Four bindings declared a parameter with no default after parameters that had one: the transf argument of MultipleTesting.lfdr, spectra in both IDMapper.annotate overloads and plugin_consumer in SwathFile.loadMzML. They are now optional and carry the C++ defaults (LfdrTransform.Probit, an empty MSExperiment and None). This also makes the generated type stubs valid Python again: _pyopenms_datastructures.pyi and _pyopenms_misc.pyi did not parse, both failing with “non-default argument follows default argument” (#10137).
- BREAKING: MultipleTesting.lfdr’s gridsize and cut defaults were 100 and 0.05, while the wrapped C++ signature (and its documentation) use 512 and 3.0, so Python callers who omitted them silently got different results than C++ callers. The bindings now use the C++ values (#10137).
- Wheels are now built in nanobind split mode against the CPython 3.11 stable ABI: each platform ships a single cp311-abi3 wheel that serves Python 3.11 and every later version, instead of one wheel per interpreter. Adding a new CPython minor version normally only means adding it to the test matrix. nanobind’s version-specific runtime moves into the separate nanobind-backend package, which is a new runtime dependency (nanobind-backend>=1.0, deliberately unpinned: newer backends serve extensions built against older backend ABI revisions). python_versions.json is now purely the list of versions the wheel is tested on; the version it is compiled for comes from abi3_minimum_cpython_version in pyproject.toml, so the two cannot drift apart.
- Wheels now ship the .pyi type stubs and the py.typed marker. The pyopenms_stubs target was never part of the build, so PYOPENMS_GENERATE_STUBS=ON defined it and nothing ran it. It is now built with the pyopenms target, requires every extension module to import before generating anything, and py.typed is written only once the stubs exist. On Windows the stub generator and the ctest suite are handed the contrib bin/ directory, where a contrib built with shared libraries keeps its DLLs; a failed import now names the DLL that could not be resolved (#10141).
- Stub generation uses named free_mem fallbacks on Windows and unsupported
platforms, avoiding invalid
definitions and re-exports in .pyi files. Generated stubs are syntax-checked after post-processing, before the build writes py.typed and its success stamp. - The type stubs export the aliases PeakMap, PeakSpectrum, Kernel_MassTrace, TM_DataPoint and MZTrafoModel_MODELTYPE, which mypy rejected with “does not explicitly export”. The nested enums that pyOpenMS also exports at module level, such as FileType and LogType, now have their types; type checkers saw them as Any. The package no longer exposes names its own imports left behind: the modules c, ctypes, importlib and warnings, and the future feature annotations.
- The wheel metadata declares the license as the SPDX expression BSD-3-Clause (Metadata-Version 2.4) and ships the license text as dist-info/licenses/LICENSE. Before, dist-info/LICENSE held only the string “BSD-3-Clause”.
- The Windows wheel is built against vcpkg’s static libraries (triplet x64-windows-static-md-release) instead of the prebuilt contrib. Every dependency is linked into OpenMS.dll, so the only native DLLs the wheel bundles besides OpenMS’s own are those of the MSVC runtime; the managed Thermo RawFileReader assemblies ship as before. Earlier Windows wheels carried an unrelated libcurl and a second zlib from the CI image. The dependency versions are those the main CI tests, e.g. Arrow 24, Xerces-C 3.3, bzip2 1.0.8 and libsvm 3.35 (#10327).
- The Linux wheels (x86_64 and aarch64) are built in the stock manylinux_2_34 images against static vcpkg libraries instead of the contrib. They carry the libraries the other builds already test, e.g. bzip2 1.0.8 instead of 1.0.5 (CVE-2019-12900), Xerces-C 3.3.0 instead of 3.2.0 (CVE-2018-1311), libsvm 3.35 and Arrow 24 (#10327).
- The Linux and Windows wheels take SQLiteCpp and SQLite from vcpkg, as the packages do, instead of the copies OpenMS vendors, which the macOS wheel keeps. All wheels carry SQLite 3.53.1 instead of 3.49.2 (#10327).
- The custom type casters build their result lists with the checked PyList_SetItem() instead of the PyList_SET_ITEM() macro, which is unavailable under the Limited API. Behaviour is unchanged; failures release the partially built list rather than leaking it.
- Building pyOpenMS in split mode requires CMake 3.26 or newer, for FindPython’s Development.SABIModule component. This applies to pyOpenMS only – the C++-only OpenMS build still requires no more than CMake 3.24. Configure with -DPYOPENMS_SPLIT_MODE=OFF for interpreter-specific modules; that mode refuses to produce a wheel, which would otherwise be mislabelled abi3.
- BREAKING (source builds): nanobind 3.1 or newer is required; nanobind 2.x no longer works. The custom type casters follow the nanobind 3 caster protocol, whose from_python() takes uint32_t instead of uint8_t flags. pyproject.toml asks for nanobind>=3.1,<4 and py-build-cmake~=0.5.1, and the CMake fallback fetches nanobind v3.1.0. nanobind discovery enforces that minimum instead of accepting whatever find_package() returns, and reports the version it selected (#10133, #10221).
- BREAKING: Python 3.10 is no longer supported. Wheels and source builds require Python 3.11 or newer; the wheel matrix covers 3.11 to 3.14. With 3.10 gone, pandas 3 is the floor for DataFrame support (the dataframes/all extras and the test requirements ask for pandas>=3), so string columns consistently use the pandas str dtype and Arrow-backed large_string. The pyarrow 24.0.0/25.0.0 exclusions were dropped: both only worked around cp310-specific problems (#10119).
- Autowrap/Cython replaced by nanobind, with PEP 561 type stubs, smaller binaries, faster builds and clearer errors. Fixed mutable-reference output parameters and restored missing default arguments; Python addons remain supported (#8699).
- BREAKING: pyopenms.String removed; use Python str (string arguments also accept bytes). MzMLFile.storeBuffer() and MSNumpressCoder.encodeNP() return str directly; encodeNPRaw() returns bytes (#8602, #8604, #10109).
- BREAKING: output arguments are return values. A method that filled a list or object
passed by the caller now returns it, and the old call raises TypeError. For example:
picked = oms.PeakPickerHiRes().pickExperiment(exp) # was pickExperiment(exp, picked, True)
traces = oms.MassTraceDetection().run(exp) # was run(exp, traces, 0)
trafo = aligner.align(feature_map) # was align(feature_map, trafo)
decomps = decomposer.getDecompositions(262.1) # was getDecompositions(decomps, 262.1)
proteins, peptides = oms.ProtXMLFile().load(path) # was load(path, proteins, peptides)
ok, errors, warnings = oms.MzMLFile().isSemanticallyValid(path)
names = oms.RNaseDB().getAllNames() # was getAllNames(names)
FileHandler.loadFeatures() and the load() of MzTabFile, SqMassFile, DTAFile, DTA2DFile,
EDTAFile, KroenikFile, ChromeleonFile and MRMFeatureQCFile changed the same way, 108 call
forms in all; the type stubs show the new form of each. MzMLFile, FeatureXMLFile,
ConsensusXMLFile and FileHandler.loadExperiment still fill their argument, and
IdXMLFile.load accepts both forms (#8699). PeptideIndexing.run(),
PosteriorErrorProbabilityModel.fit() and initPlots(), IDFilter.updateProteinGroups() and
AbsoluteQuantitation.optimizeCalibrationCurveIterative() keep their 3.5 arguments but
return a tuple, their 3.5 result followed by the updated lists. A check such as
if model.fit(...)is therefore always true; unpack the tuple instead (#10260). - BREAKING: strings inside returned containers are str instead of bytes: list and set elements, dict keys (EmpiricalFormula(“H2O”).getElementalComposition() is now {‘H’: 2, ‘O’: 1}), Param keys and tags, list-valued string meta values and string data arrays, as well as the few methods that returned bytes. Methods that return a single String already returned str. Drop .decode() calls and b"…" keys and comparisons.
- BREAKING: C++ char arguments take a one-character str and reject bytes, the only type 3.5 accepted: PeptideEvidence.setAABefore(“K”), not setAABefore(b"K"). This affects PeptideEvidence.setAABefore() and setAAAfter(), ResidueModification.setOrigin(), Ribonucleotide.setOrigin() and its constructor, GaussTraceFitter.getGnuplotFormula(), the separator of CsvFile.load() and AAIndex, whose methods are now static and which has no constructor: AAIndex.aliphatic(“A”) instead of AAIndex().aliphatic(b"A") (#10260).
- BREAKING: LogConfigHandler has no constructor any more. Use oms.LogConfigHandler.getInstance().setLogLevel(“ERROR”) instead of oms.LogConfigHandler().setLogLevel(“ERROR”).
- BREAKING: CrossLinksDB, ElementDB, ModificationsDB, ProteaseDB, ResidueDB, RibonucleotideDB and RNaseDB are callable singletons. ModificationsDB() and ModificationsDB.getInstance() return the one shared instance, but the names are no longer classes: isinstance(x, oms.ModificationsDB) is False, even for that instance. To check the type, use isinstance(x, type(oms.ModificationsDB.getInstance())).
- BREAKING: classes removed from pyOpenMS. PeptideSearchEngineFIAlgorithm is now ProSEAlgorithm, after the C++ rename; its exit codes are ProSEAlgorithm.ProSEAlgorithm_ExitCodes (#9137). OPXL_PreprocessedPairSpectra is PreprocessedPairSpectra. DPosition1 and DPosition2 are a float and an (x, y) tuple. ArrayWrapperDouble and ArrayWrapperFloat are not needed any more, because peak data comes back as NumPy arrays. ProteinInference was deleted (#9482); PeptideAndProteinQuant covers protein quantification. KDTreeFeatureMaps, KDTreeFeatureNode and PeakIndex were dropped because they handed out references that could outlive their data; use FeatureGroupingAlgorithmKD, and fm[i] or exp[s][p] (#9803). IdentificationRuns, Internal_MzMLValidator, IsotopePattern, Seed, TheoreticalIsotopePattern, TraceInfo and OSWFile are no longer bound; use IDRipper.rip(), MzMLFile.isSemanticallyValid() and CoarseIsotopePatternGenerator.
- BREAKING: MassTrace is now the kernel mass trace (getCentroidMZ(), getSize(), …), and Kernel_MassTrace is an alias for it. 3.5.0’s MassTrace was the FeatureFinder helper struct with max_rt and theoretical_int, which is gone.
- BREAKING: CVTerm_ControlledVocabulary, the term class of ControlledVocabulary, is now ControlledVocabulary.CVTerm, and XRefType_CVTerm_ControlledVocabulary is now ControlledVocabulary.CVTerm.XRefType. A term prints as CVTerm(id=‘MS:1002252’, name=‘Comet:xcorr’) (#10284).
- BREAKING: some nested enums were renamed. IonDetector.Type_IonDetector is now IonDetector.Type, FeatureDeconvolution.CHARGEMODE_FD and MetaboliteFeatureDeconvolution.CHARGEMODE_MFD are now CHARGEMODE, and OpenPepXLAlgorithm.OpenPepXLAlgorithm_ExitCodes, PeptideIndexing.PeptideIndexing_ExitCodes and PercolatorOutfile.PercolatorOutfile_ScoreType are now ExitCodes and ScoreType. getMapping() is now called on a member, e.g. IonSource.IonizationMethod.ESI.getMapping(), not on an instance of the enum class such as IonSource.IonizationMethod(). Thirty-two enums are no longer ints: int() raises TypeError, and == with a number is False without an error, so spec.getType() == 1 is now False for a centroided spectrum. Compare with a member such as SpectrumSettings.SpectrumType.CENTROID, or use .value. The 32 are AnnotationState, ChecksumType, DecoyTransitionType, DimensionDescription, IMFormat, MT_QUANTMETHOD, MZTrafoModel_MODELTYPE, DataFilters.FilterOperation, DataFilters.FilterType, DataProcessing.ProcessingAction, FeatureOverlapFilter.MergeIntensityMode, Instrument.IonOpticsType, InstrumentSettings.ScanMode, IonDetector.AcquisitionMode, IonDetector.Type, IonSource.InletType, IonSource.IonizationMethod, IonSource.Polarity, IsotopeModel.Averagines, the six MassAnalyzer enums, NonNegativeLeastSquaresSolver.RETURN_STATUS, Precursor.ActivationMethod, ProteinIdentification.PeakMassType, RetentionTime.RTType, RetentionTime.RTUnit, Sample.SampleState and SpectrumSettings.SpectrumType. Setters such as IonSource.setIonizationMethod() still accept an int (#8405, #8604).
- The names List, Union, np, numpy, print_function and common_meta_value_types, which 3.5.0 leaked from its implementation, and the streampos class are no longer exported.
- Getters and ordinary element access return owned copies, restoring 3.5 semantics after the initial nanobind port. Modify and assign back, e.g. s = exp.getSpectrum(0); s.setRT(1.0); exp[0] = s Explicit live access uses spectrum_view(i), spectrum_views(), iter_spectrum_views() and corresponding accessors on feature/consensus maps, identification lists, transition groups and data arrays. Views keep parents alive; resizing/reordering invalidates them. See src/pyOpenMS/OWNERSHIP.md for rules and exceptions (#9792, #9794).
- BREAKING: metadata enums are strongly typed; activation-method enum handling changed (#8405, #8604). LPWrapper, SolverParam and nested enums are no longer exposed; use high-level algorithms such as MRMFeatureSelector or FeatureDecharger (#9983).
- DataFrame methods get_df()/get_df_columns() become to_df()/df_columns(); _mv methods use _view (e.g. get_data_mv() -> data_view()). Deprecated aliases remain (#8655, #8857).
- Expanded DataFrame, Arrow/Parquet and zero-copy pyarrow support for spectra, chromatograms, mobilograms, experiments, feature/consensus maps, identification lists and transition groups. Added column discovery, container operations, hashing and snake_case scalar properties alongside existing getters/setters. Param supports dict construction and readable values, descriptions, restrictions and tags in str/repr (#8436, #8501, #8503, #8510, #8520, #8576, #8631, #8632, #8655, #8729, #9760, #10097).
- DataFrame exports preserve long strings and use nulls for missing strings instead of ‘None’, ’nan’ or ‘unknown’. Transition-group metadata handles str/bytes names equally; missing integer values produce float columns with NaN instead of errors (#8583).
- New/expanded bindings include ProForma, USI, PEFF, XIC/XIM Parquet, BrukerTimsFile, FileInfo, IsoelectricPoint, FAIMSHelper, SpectrumNativeIDParser, FileHandler I/O, rasterize2D, quantification results, rank aggregation, chemistry/spectrum generation, RANSAC seeding, ppm helpers and DRange1 (#8504, #8525, #8543, #8637, #8648, #8684, #8690, #8737, #8738, #8739, #8762, #8894, #8907, #9275, #9379, #9407, #9412, #9415, #9419, #9602).
- SpectrumAccessOpenMSCached is available and selected automatically for cached-data experiments. SystemSettings, TempDir and TempFiles are exposed; existing Python File settings/temp-file methods remain available (#9952, #10083).
- Ion mobility: explicit-unit setters for per-peak arrays, drift-time/unit getters and zero-copy peaks_struct() for chromatograms/mobilograms. Fixed unit detection and preservation of live NumPy buffers on same-length drift-array replacement (#8423, #8825, #8842, #9792).
- Fixed iterator/consumer lifetimes, borrowed-pointer ownership, out-of-range access, copy-constructor dispatch, AASequence string conversion and peak-buffer dtype offsets. set_peaks() keeps parallel data arrays consistent; enum/FileTypes and identification-file wrappers were completed or corrected (#8502, #8553, #8589, #8720, #9098, #9705, #9792, #9794, #9795).
- Fixed SimpleSearchEngineAlgorithm.search(), which ran the search and then raised std::bad_cast because its ExitCodes enum was not registered. It returns (exit_code, protein_ids) and fills pep_ids; the codes are SimpleSearchEngineAlgorithm.ExitCodes (#10260).
- Copying works again for the classes that supported it in 3.5.0. Sixty-one classes, most of them derived from DefaultParamHandler, ProgressLogger, CVTermList or CsvFile, either had no copy or inherited their base’s, so copy.copy() and copy.deepcopy() failed or returned the base class: a DefaultParamHandler for PeakPickerHiRes, for example. FeatureDistance, MultiplexResolverAlgorithm and SwathMapMassCorrection, which returned a DefaultParamHandler too, get their own copy and deepcopy as well. The copy constructor X(other) is back on 136 classes that had it in 3.5.0, and new on four more. It stays gone from six: FeatureFindingMetabo and OpenSwathOSWWriter have no C++ copy constructor any more, and MSDataSqlConsumer, CachedSwathFileConsumer, MzMLSwathFileConsumer and PeakWidthEstimator delete objects that their C++ copy shares, so a copy and its original freed them twice (MSDataSqlConsumer(other) aborted Python in 3.5.0). copy.copy() and copy.deepcopy() raise TypeError for FeatureFindingMetabo and these four (#10260).
- ControlledVocabulary.getTerm() and getTermByName() return a ControlledVocabulary.CVTerm again, as in 3.5.0, instead of a dict with id, name and description. With the dict, PeptideIdentificationList.to_df() and df_columns() kept PSI-MS accessions such as MS:1002252 as column names, although decode_ontology=True asks for the term names (#10284).
- Restored C++ default arguments that the port had dropped, e.g. Residue.getMonoWeight(), getAverageWeight() and getFormula() without a residue type, MSDataCachedConsumer(filename), MetaInfo.getValue(name), FineIsotopePatternGenerator(threshold), ModificationDefinition(mod, fixed), TextFile(filename, trim_lines, first_n), IDFilter.removeDuplicatePeptideHits(peptides) and IDConflictResolverAlgorithm.resolve(features) (#10260).
- Methods that update a list argument in C++ update a Python list passed there again, as in 3.5, besides returning the updated list, so both f(prots, peps) and prots = f(prots, peps) work. Without this, 3.5 code ran but its list silently stayed unchanged. Among them are IDFilter.removeUnreferencedProteins(), FalseDiscoveryRate.apply() and applyEstimated(), BasicProteinInferenceAlgorithm.run(), BayesianProteinInferenceAlgorithm.inferPosteriorProbabilities(), PeptideProteinResolution.run(), the PercolatorFeatureSetHelper feature methods and TransformationModel*.weightData(); pyopenms/addons/inout_lists.py lists all of them. Tuples and other sequences are not updated (#10260).
- Restored calls that 3.5 had: MapAlignmentAlgorithmIdentification.align() aligns several maps, returning one TransformationDescription per map or, in the 3.5 form align(maps, transformations, reference_index), filling the list passed in, and setReference() takes a PeptideIdentificationList; IDFilter.filterHitsByScore() takes a list of ProteinIdentification; IDFilter.updateProteinReferences() is a deprecated alias of removeDanglingProteinReferences(). OPXLHelper.computeDeltaScores() takes the identifications to score (it took no argument), and the OPXLHelper methods update a PeptideIdentificationList in place again instead of a copy. TransitionTSVFile and TransitionPQPFile accept bytes file names, like the other file classes (#10260).
- plot_spectrum() and mirror_plot_spectrum() plot annotated spectra again. They called .decode() on the peak annotations, which the bindings now return as str (#10260).
- The deprecated MSExperiment.get_df() and get_df_columns() accept long= again, 3.5.0’s name for long_format (#10260).
- FeatureMap.to_peptide_df() and peptide_df_columns() export the PeptideIdentifications assigned to features, one row per identification, with the feature_id of each. Merge the frame with FeatureMap.to_df() on feature_id (#10260).
- BREAKING: FeatureMap.get_assigned_peptide_identifications() returns the identifications unchanged. 3.5.0 added feature_id, ID_native_id and ID_filename as meta values to every peptide hit, to merge on all three. Merge FeatureMap.to_df() with to_peptide_df() on feature_id instead (#10260).
- BREAKING: FeatureMap.to_df() indexes features by feature_id as an unsigned 64-bit integer, where 3.5.0’s get_df() used text; the deprecated get_df() returns it as a column (#10260).
- Thermo .raw reading is included in every wheel, Linux aarch64 among them; install .NET 8+ and set DOTNET_ROOT for non-standard locations. Optional WNet/Bruker bindings are exposed only when built; use hasattr() for feature detection (#9946, #9957, #10070, #10205, #10206).
- See src/pyOpenMS/THREAD_SAFETY.md for concurrency rules and OpenMP oversubscription guidance; releasing the GIL does not guarantee thread safety (#9792, #9857).
- BREAKING: IMSWeights, NoiseEstimator, Ratio, SpectrumAccessQuadMZTransforming and SplineSpectrum_Navigator are no longer bound. The methods that take or return them are still exposed but cannot be used: RealMassDecomposer(weights), SignalToNoiseEstimatorMedianRapid.estimateNoise(), ConsensusFeature.addRatio(), setRatios() and getRatios(), and SplineInterpolatedPeaks.getNavigator().
- User guide: new pages on ProForma, USI and mzPAF, on glycans and glycopeptide fragment spectra, and on threads and parallel processing; new sections on PEFF files, FAIMS data, file summaries with FileInfo and the type stubs. Corrected the PEFFFile docstring (load() returns a tuple) and four PEFFEntry method docstrings that carried the description of their neighbour; the docstring examples of ProForma, IdentifierMSRunMapper and PEFFFile now render as code blocks.
TOPP tools:
Changes:
All tools:
- Boolean parameters accept flag syntax or explicit true/false, including overriding
an INI-enabled flag with ‘-flag false’ (#10116).
- A JSON INI (’-ini x.json’) reads input file lists in every shape they occur in. A CWL
runner emits a ‘File[]’ input as an array of File objects, which was rejected with a
json type error, so every tool with an input file list failed through its generated
CWL description once the list was set. Input and output file lists also accept an
array of path strings or an object with a ‘path’ array; a single file parameter takes
a path string or an object with a ‘path’ string (#10121).
- BREAKING: the advanced option ‘-instance algorithm:mz_tolerance and algorithm:rt_tolerance (re-exported by
MS1LabeledWorkflow as resolver:mz_tolerance / resolver:rt_tolerance) are now double
instead of int, with a minimum of 0.0. They were always read into double members, so a
fractional value was rejected on the command line and, in an INI file, silently stored as 0 –
disabling the blacklist proximity check. An INI carrying them as type=“int” must be updated
to type=“double” or the tool will refuse to start
Other tools:
- CometAdapter merges compatible variable modifications for faster searches and supports
DDA-PASEF .d input; native-ID translation avoids Comet mzParser crashes (#8407,
#9126, #9168). SageAdapter thread registration corrected (#8441).
- SimpleSearchEngine adds semi-/non-specific search and PSM annotations; candidate
processing scales better across threads (#9112, #9117).
- AssayGeneratorMetabo now applies its feature/masstrace and precursor m/z/RT filtering
options, which were previously ignored (#10120).
- FileConverter adds MSP and sqMass-to-XIC Parquet conversion, plus Bruker aggregation,
centroiding and range filters. FileInfo adds assigned/unassigned ID counts, FASTA
sequence statistics and nucleic-acid support; progress logging restored (#8395,
#8643, #8650, #8829, #9707).
- TextExporter supports XIC Parquet and fixes USI run resolution; IDMerger preserves
input order (#8470, #8737, #8738, #9240, #9657).
- MSstatsConverter exposes -remove_shared_peptides (default true), accepts design
subsets, and warns, as does ProteomicsLFQ, about BioReplicate IDs shared across
conditions (paired designs) (#7314, #8846, #9068, #9864).
- Epifany clarifies -exp_design behavior and reports unidentifiable input as an error
instead of aborting (#9864, #9901).
- MetaboliteAdductDecharger adds multimer detection (max_multimer/multimer_log_penalty).
MetaboliteSpectralMatcher adds optional CCS filtering (ccs_error_percent=0 disables
it), automatic 1/K0-to-CCS conversion and CCS mzTab columns; missing observed CCS
does not filter candidates (#8784, #8888, #9412).
- IDConflictResolver adds rank_aggregation; MaRaClusterAdapter records consensus-spectrum
origins/cluster size; OpenSwathChromatogramExtractor uses CompoundName for metabolite
chromatogram identifiers (#8864, #8907, #9271).
New tools:
- MS1LabeledWorkflow: one-command quantification of MS1-labeled (SILAC, Dimethyl, …) experiments,
the counterpart of ProteomicsLFQ and IsobaricWorkflow: per run FeatureFinderMultiplex, IDMapper,
IDConflictResolver and MultiplexResolver, then per-fraction alignment and linking (channels kept as
sub-features, fractions combined column-wise), protein inference/FDR and quantification, written as
consensusXML, mzTab and/or a QPX collection; optional match between runs (-match_between_runs)
lets unidentified multiplets take over identifications from other runs. The peptide identity is
the unlabeled sequence (the label belongs to the channel): label modifications are removed after
the multiplet resolution and the label state is kept on every identification (labeled_sequence,
removed_labels, label_channel), reported as mzTab opt_global columns and QPX cv_params; PSM-level
output (mzTab PSM section, QPX psm view) reports the peptidoform as searched, feature-level
output the peptide identity. Each column header describes its channel’s labels
(channel_description). A spectrum match mapped onto several multiplets stays with the closest
one; distinct spectra of one peptide on distinct multiplets are all quantified. The reported quantity
is the channel ratio, computed as MaxQuant does (median of the evidence ratios per peptide, median
of the peptide ratios per protein group, a minimum ratio count, and a normalized variant) rather
than as a ratio of aggregated intensities, so no ProteinQuantifier run is needed for it. The
reference channel is reported with its ratio of 1.0 wherever another channel was measured
against it, so a consumer sees a complete set of channels; the
per-channel abundances are reported next to it as summed intensities. Checks up front that
the labels were searched as modifications, that the design enumerates the channels of -labels,
and that -out_qpx is only requested for labels in the QPX vocabulary (#10044).
Channel/pattern order and unique input/design basenames are validated before processing.
Native Thermo RAW input is supported with WITH_THERMO_RAW and a .NET 8+ runtime;
scan metadata and MS1 peaks are extracted in one RAW read, including spectrum-reference repair.
FAIMS CVs are preserved through ID mapping, multiplet completion and linking. A protein’s
reference-channel ratio requires a comparison passing min_ratio_count in that fraction group (#10047).
- FeatureLinkerWNet: Wasserstein network-flow grouping across label-free maps; optional,
built with WITH_WNETALIGN=ON (#8992, #10255).
- UniPEFF: UniProtKB XML-to-PEFF conversion with sequence, modification, variant and
disulfide-bond annotations; disulfide connectivity is reported by default via bond-ordered
half-cystine labels; optional global annotation identifiers and external
unimod.obo (#9649, #9829). UniProt isoforms are reconstructed from their splice-variant
features and emitted as additional entries after the parent entry, with the features
UniProt annotates on that isoform; disable with -omit_isoforms (#9966, fixes #9830).
- OpenSwathInfer: peptidoform, peptide, protein and gene inference (#9280).
- OpenSwathExport: TSV/Parquet result export (#9377).
- OpenSwathPercolatorScoring: Percolator scoring of OpenSWATH results (#9695).
- OpenSwathPeakMapExtractor: targeted full-peakmap extraction (#9684).
- TransitionListEvidenceFilter: filter transition lists using mzML evidence (#9161).
- DIAuditor: quality metrics of DIA runs per run and per isolation window (MS1 sampling,
window layout incl. FAIMS/1/K0, cycle times, TIC and peak-count distributions), a
re-implementation of D. L. Tabb’s DIAuditor. Reads mzML, Thermo .raw and Bruker timsTOF .d
(diaPASEF) and writes its per-run and per-window tables and an mzQC file with the PSI-MS
DIA metrics (MS:4000190-MS:4000199). Warns when spectra carry several isolation windows
(e.g. MSX; demultiplex first) and when diaPASEF windows have an ion mobility array but no
ion mobility range, as TIMSCONVERT writes them, so windows differing only in ion mobility
count as one (#10271, #10312).
- ParquetDiff: compares two Parquet tables by primary key with a numeric tolerance instead of exact
bytes. FuzzyDiff is string-based and cannot read Parquet, which left the QPX psm/feature/pg exchange
surface with no comparison route at all. The key is auto-derived from a QPX file’s own file_type
metadata or given explicitly via -pk for any table; matched rows are compared cell-by-cell recursing
into list/struct columns, and schema drift (added/removed/retyped columns) is reported separately
from value drift. Tolerance mirrors FuzzyStringComparator – either -ratio or -absdiff must hold, so
a zero-vs-epsilon comparison stays expressible – and two NaNs compare equal. List-valued key columns
(e.g. QPX’s grouped_runs) are canonicalized by sorting before matching, and a duplicate primary key
is reported as an error in its own right. -schema validates a single file against a named QPX view
instead of diffing two files. Exit code is EXECUTION_OK when the comparison (or -schema validation)
passes and every input holds at least -min_rows rows, if set; otherwise INCOMPATIBLE_INPUT_DATA, so it
drops into CTest the way FuzzyDiff does (#9865, part of #9864)
- ParquetConverter: converts featureXML and consensusXML files to Parquet directories and
back (#8970).
Removed tools:
- BREAKING: GenericWrapper and its external-tool definitions removed; use direct TOPP
invocations or TOPPAS workflows (#8981, #9735).
- BREAKING: QuantmsIOConverter removed (renamed QPXConverter in #8756, then removed). QPX
output comes from the -out_qpx option of ProteomicsLFQ, IsobaricWorkflow, MS1LabeledWorkflow,
ProteinQuantifier and ProSE; the QPXFile export API remains (#9693).
- BREAKING: TriqlerConverter, ProteomicsLFQ -out_triqler and TriqlerFile removed. Use
-out_msstats, or convert -out_cxml/-out_qpx downstream (#9898).
GUI tools:
- TOPPView/TOPPAS accept generic Qt command-line options. TOPPView shows selectable MS2 precursor markers and isolation windows in 2D; the splash screen is dismissible (#4963, #9715, #9723).
- Fixed TOPPAS shutdown crashes, TOPPView extreme-zoom crashes and large-file context-menu delays, non-string metadata conversion, Windows spinbox sizing and Annotation1DItem DLL exports (#8997, #9206, #9263, #9723, #9831).
- Fragment annotations survive viewing and spectrum switches unchanged, including charge notation and multiline comments. Corrected duplicate charge display, neutral-loss ion ordinals and sequence diagrams with multiple modifications (#8766).
- TOPPView’s scan list shows each MSn scan under the scan its precursor refers to (mzML spectrumRef), so SPS-MS3 scans that are interleaved with later MS2 scans appear under their own MS2 scan. MS2 scans that follow an MS3 scan are no longer nested under the previous MS2 scan (#4215).
- BREAKING: SwathWizard and FLASHDeconvWizard removed; run the TOPP tools they wrapped, such as OpenSwathWorkflow and FLASHDeconv, directly (#9472).
OpenMS Library:
- mzML: read and write Zstandard (zstd) compressed binary data arrays (MS:1003780 zstd, MS:1003781 byte-shuffled zstd, MS:1003782 dictionary-encoded zstd and MS:1003783-MS:1003785 MS-Numpress followed by zstd). Writing is enabled with PeakFileOptions::setZstdCompression(), FileConverter -zstd_compression or FileFilter -peak_options:zstd_compression (#9033).
- Added GlycanStructure and TheoreticalGlycanSpectrumGenerator for composition-based diagnostic/oxonium and bounded B/Y/C/Z ions, structural and internal glycan fragments, and HCD/ETD/EThcD glycopeptide backbone retention with configurable stubs (#10176, #10204). Includes mzPAF annotations, neutral losses, resource limits, and pyOpenMS bindings.
- Added DIon, VIon and WIon to Residue::ResidueType, with side-chain loss methods on Residue,
fragment mass calculation in AASequence and MzPAF, TraML support and pyOpenMS bindings (#10175).
Added:
- File type aliases are now honoured end to end: TOPP tools accept an alias wherever they accept the preferred extension (and a tool declaring an alias accepts the preferred extension), TOPPAS connects tools and input-file lists by format rather than by literal suffix, GUI file dialogs offer every accepted extension (‘FASTA file (*.fasta *.fa *.faa)’), and INI/CTD supported_formats list them for input parameters. Output parameters keep the single canonical extension, so what OpenMS writes is unchanged (#490)
- FileTypes::sameFormat() compares two declared format strings by type when both are recognized and literally otherwise, so ‘fasta’ matches ‘fa’ while two different custom extensions stay distinct. FileTypes::supportsCompressedReading(type, compression) reports whether a reader accepts that specific container, and FileNameUtils::compressionType() reports which container a filename carries (hasCompressionSuffix() answers the same question as a bool). The pair takes the container because support is not uniform: the XML-based readers decompress .gz, .bz2 and .zip transparently through CompressedInputSource (except the mzIdentML reader, which parses the file itself and cannot read a compressed one), while Bruker TDF accepts only a ‘.d.zip’ archive that BrukerTimsFile unpacks. A compression suffix alone therefore no longer implies compatibility, so ‘.mgf.gz’ is rejected where ‘.mzML.gz’ is accepted, and both the CLI and TOPPAS apply the same rule. Compressed output is unaffected: XMLFile still selects gzip/bzip2 by filename (#490)
- FileTypes::supportsCompressedWriting(type, compression) is the writing counterpart: XMLFile compresses the formats marked with the new FileProperties::COMPRESSED_WRITEABLE with gzip or bzip2 and never writes a ZIP archive, while an OSWPQ bundle is always one. TOPPBase uses it to refuse output names whose writer would store plain data under them (#10317)
- FileTypes: a file type may now register additional accepted extensions besides its preferred one. FileTypes::typeToExtensions() lists them (preferred first) and nameToType() resolves them case-insensitively: ‘fa’/‘faa’ for FASTA, ‘pep.xml’ for pepXML, ‘prot.xml’ for protXML and ‘pqt’ for parquet. typeToName() still returns the single preferred extension, which is what OpenMS writes, and formats that merely share an extension family (e.g. CSV and TSV) remain distinct types (#490)
- MultiplexResolverAlgorithm: the multiplet completion and quant/ID conflict resolution of the MultiplexResolver tool as a library class (DefaultParamHandler with the tool’s ‘algorithm’ and ’labels’ sections), shared by MultiplexResolver and MS1LabeledWorkflow (#10044)
- ProteinGroupArrowExport: the QPX pg view fills its previously empty additional_intensities column with the channel ratio of that (protein group, fraction group, label) – named ratio and ratio_normalized under the row’s own channel label – and the number of contributing peptides with cv_params/ratio_count, when the producer annotated them (MS1LabeledWorkflow does). Rows without them are written as before (#10044)
- MS1LabelState: the label-state meta values of an MS1-labeled identification (labeled_sequence, removed_labels, label_channel) and the peptidoform a hit was matched with. The mzTab PSM section and the QPX psm view report that matched peptidoform (and derive the psm identity from it); the QPX feature and psm views write the three values to the previously empty cv_params column (ArrowIOHelpers::qpxCvParams). Identifications without a label state are exported as before (#10044)
- BrukerTimsFile (WITH_OPENTIMS): DDA-/DIA-PASEF and raw 4D access, tiered scan-to-1/K0 calibration, optional neighboring-MS1-frame aggregation, IM hill centroiding and frame/RT filtering. Range-limited reads reduce I/O/memory; aggregation is faster. DDA native IDs use ‘frame=… scan=… precursor=…’ for unique identification; exported PASEF spectra are marked CENTROID (#8975, #8999, #9151, #9154, #9233, #9243, #9380, #9387).
- ThermoRawFile: native .raw reading with openms-thermo-bridge 0.3.1 and .NET 8+. Preserves sample/method/trailer metadata, SHA-1 provenance, scan/instrument metadata, MSn/SPS precursor hierarchy and supplemental activation. Optional centroid charges, independent noise arrays and auxiliary detector/PDA data support mzML export. Fixed mixed-activation hierarchy reconstruction. Managed assemblies are installed with OpenMS; OPENMS_THERMO_MANAGED_DIR overrides their location (#9389, #9623, #10070, #10077, #10079).
- Imaging: IonImage, MSImagingGeometry/Region/Experiment, imzML read/write and on-disc access, streaming consumers, multi-region extraction and Bruker MALDI .d support. imzML preserves auxiliary float arrays/IM units; warns about unsupported integer/ string arrays and duplicate pixels (first spectrum used for geometry, all remain index-accessible). Both loaders reject zlib-compressed m/z/intensity arrays (#9381, #9383, #9521, #9654, #9903, #9908, #10002).
- Native Parquet: PSMArrowIO, FeatureMapArrowIO, ConsensusMapArrowIO, ArrowSchemaRegistry, ArrowExport and ProteinGroupArrowExport. Preserves map metadata/unique IDs and identification run links; rejects duplicate run IDs and dangling feature references. Native bundles no longer claim a QPX version (#8655, #8970, #8973, #9225, #9232, #9242, #9864).
- Percolator: in-process rescoring with combined or separate training/scoring and model persistence. Calls across instances must be serialized because of process-wide Percolator state (#9218).
- OpenSWATH: reusable inference/export APIs ported from PyProphet; KDE, ranking and multiple-testing statistics; workflow scheduling, memory-aware OSW output and CalibrationWorkflow. Calibration RT windows default to 60-600 s (set either bound to 0 to disable it). Added .oswpq archives, .xic chromatograms, .xim mobilograms, per-compound RT ranges and a FAIMS-aware adapter for pre-loaded experiments (#8524, #8737, #8743, #8813, #8871, #9190, #9271, #9280, #9377, #9842, #9932).
- PipEchoAlgorithm exposes the new match-between-runs method (#9647).
- FeatureGroupingAlgorithmWNet/WNetMatcher expose the Wasserstein grouping methods; optional, built with WITH_WNETALIGN=ON (#8992, #10255).
- Optional C++ ONNX predictors for AlphaPeptDeep RT, MS2 and CCS models, with verified model downloads and AASequence-based modification support. Unsupported modifications are rejected; Python bindings are not yet available (#9453, #9765).
- Standards: ProForma v2 parsing/serialization (LOSSLESS/CANONICAL), AASequence conversion, mass calculation and JSON support; MzPAF peak annotations; USI parsing/ construction; SpectrumNativeIDParser (#8637, #8648, #8684, #8686).
- MzPAF accepts and writes d/v/w satellite ions and the da/db/wa/wb subtypes, including validation, peak annotation conversion and pyOpenMS bindings (#10175). Satellite mass calculations use d = a + H - radical side-chain loss and v = y - HR. Direct residue/sequence mass and formula APIs reject unsupported or modified cleavage residues instead of returning the parent-ion mass. Theoretical spectrum generation for satellite ions remains unsupported.
- Added IsoelectricPoint, hydrophobicity profiles, protein SequenceCoverage, ModifiedSincSmoother, programmatic FileInfo, CCS conversion and MSExperiment rasterization. Extended PeakFileOptions and on-disc filtering, peak annotations, LightTransition APIs, MetaInfo iteration and ParamIterator STL support (#8217, #8362, #8421, #8512, #8526, #8544, #8621, #8728, #8735, #8739, #9179, #9419, #9602).
- IMPeakType tracks IM processing state independently of layout; IMFormat::CENTROIDED is deprecated. IM units are recognized across vendor array naming conventions (#9007, #9181).
- I/O: MGF SEQ fields round-trip; MSP reads numeric CCS and long lines; consensusXML preserves protein-group abundance arrays. PeptideIndexer settings and upstream IDMapper processing metadata are retained (#8489, #8816, #8852, #9186, #9844). API and behavior changes:
- XMLFile::save_() matches the .gz/.bz2 suffix in any letter case (FileNameUtils::compressionType()), as input handling does, so ‘x.mzML.GZ’ is written gzip-compressed rather than plain. MSDataWritingConsumer and PlainMSDataWritingConsumer throw Exception::UnableToCreateFile for a file name ending in .gz, .bz2 or .zip: they stream uncompressed mzML, which such a name would mislabel. Use MzMLFile::store() for compressed mzML (#10317).
- BREAKING: File settings methods move to SystemSettings (getSystemParameters, getTempDirectory, getUserDirectory, findDatabase, getOpenMSHomePath, getOpenMSConfigDir). File::TempDir becomes TempDir; File::getTemporaryFile becomes TempFiles::getTemporaryFile. Old C++ entry points are removed (#10083).
- BREAKING: XMLHandler no longer derives from xercesc::DefaultHandler; use
onStartElement(const char16_t*, const XMLAttributes&), onEndElement() and
onCharacters(). Matrix
uses std::vector storage and no longer inherits Eigen (#8511, #8547, #8558, #9712, #9737). - BREAKING: database getInstance() methods return const pointers (ElementDB, ResidueDB, ModificationsDB, CrossLinksDB, RibonucleotideDB, MonosaccharideDB, ProteaseDB and RNaseDB); use const T* or auto. Runtime modification interning is thread-safe. ElementDB::addElement() removed: use local CoarseIsotopePatternGenerator:: setIsotopeOverride(element, distribution), avoiding global isotope-state mutation.
- BREAKING: PeptideIdentification::get/setBaseName removed; use the run’s setPrimaryMSRunPath() and IdentifierMSRunMapper. IDFilter::updateProteinReferences renamed to removeDanglingProteinReferences; Exception::InvalidSize requires a context message (#8500, #8437, #9660).
- BREAKING: FileWatcher moved from SYSTEM to VISUAL; plain metadata/platform enums became enum classes; PeptideAndProteinQuant channel IDs are UInt; ChromatogramPeak intensity changed from double to float (#8516, #8591, #8622, #8857).
- BREAKING: IMFormat::CONCATENATED/MULTIPLE_SPECTRA renamed to IM_PEAK/IM_SPECTRUM; MIXED removed. determineIMFormat(experiment, ms_level) requires an explicit MS level (#8993, #9011).
- BREAKING: QuantmsIO renamed to QPXFile; LinearResampler removed in favor of LinearResamplerAlign (#8756, #9153).
- BREAKING: OpenSwath::Scoring removes pointer/C-array overloads of NormalizedManhattanDist, RootMeanSquareDeviation, SpectralAngle, normalize_sum and calcxcorr_legacy_mquest_; use std::vector overloads. ChromatogramExtractor::prepare_coordinates(TargetedExperiment) removed; convert via OpenSwathDataAccessHelper::convertTargetedExp and use LightTargetedExperiment (Python API unchanged) (#9252, #9271).
- BREAKING: NeighborSeq owns its peptide vector, fixing dangling references but changing class layout; C++ consumers must rebuild. IDBoostGraph rejects missing target_decoy annotations; BayesianProteinInferenceAlgorithm requires one merged identification run (#8480, #9488, #9613).
- Charged EmpiricalFormula isotope generation retains its 3.x implicit-hydrogen behavior with a deprecation warning; use addChargeAdduct(count, adduct=“H”) for the explicit replacement before OpenMS 4.0 (#4449, #9714, #9719).
- SignalToNoiseEstimatorMedian interpolates within histogram bins (floor 1), changing S/N-derived peak-picking/scoring results. Corrected MassTrace FWHM interpolation affects feature widths, peak filtering, linking tolerances and some quantified intensities; traces must be sorted along their x axis (#9781, #9967, #10052).
- EMGScoring init_mom now defaults to true; enzyme definitions are built in and Enzymes.xml is optional. Warnings go to stderr; logging and DataValue conversion diagnostics improved (#8409, #8572, #8593, #8620, #8754).
- ParamEntry::isBool() centralizes boolean-parameter recognition; ThermoRawFileMetadata exposes typed ThermoScan/ThermoReaction/ThermoPrecursor access (#10084, #10116).
- OpenMSTestFramework is a separate static library: tests/FuzzyDiff users must link it. Temporary-output schema validation is explicit via VALIDATE_TMP_FILES; test projects register unique-ID/exception support. OpenMS_locale removed (#9929). Performance:
- Faster decharging, peptide indexing/resolution, precursor purity/correction, OpenSWATH scoring and cross-correlation, plus fewer copies in search and extraction loops. AccurateMassSearchEngine honors observed-adduct-only searches; mzIdentML caches CV lookups and supports schema 1.3. Parquet PSM/metadata export avoids repeated scans and registry locking (#4787, #5867, #8618, #8635, #8651, #8656, #8763, #8764, #8785, #8787, #8806, #8848, #8849, #9686, #9689, #9692, #9801).
Fixes:
Chemistry and identifications:
- PercolatorAdapter’s in-process backend and Percolator::rescore() read a feature stored as
a string meta value as the number it holds, as the percolator executable does when it
parses the .pin file. Both went through DataValue’s conversion to double, which yields an
unrelated number for a string: SageAdapter stores all of Sage’s extra features as strings,
so they were constant and Percolator weighted them zero, losing identifications (on a small
dataset, every PSM). A feature value that is not a finite number is now an error, as for
the executable (#10310).
- MatchedIterator no longer stops at the first of two target elements with the same value
(e.g. two peaks with the same m/z). HyperScore, PScore, AScore, SpectrumAlignment (ppm) and
the QC metrics FragmentMassError and PSMExplainedIonCurrent ignored all peaks above such a
pair, so ProSE and SimpleSearchEngine mis-scored spectra with duplicate peaks. (#10291)
- MzIdentMLFile: search engine scores without a score order in the PSI-MS vocabulary take
it from OpenMS’ score registry, so Comet:expectation value, X!Tandem:expect, OMSSA:evalue,
OMSSA:pvalue, percolator:Q value and percolator:PEP are read as lower-is-better. Such
lower-is-better engine scores yield to a PSM-level q-value, which is then used. The
registry (Scores) now lists the X!Tandem and OMSSA scores by accession, so QPX and Arrow
exports also report them as additional scores (#8691).
- Fixed signed/stacked unknown mass shifts, precision-aware mass matching and spurious
zero-mass PSI-MOD assignments. Distinct modified residues remain distinct and
mass/formula round-trips no longer silently change peptidoforms (#10006, #10007,
#10010, #10029).
- Fixed UniMod ICAT formulas and site-specific neutral-loss masses; ProForma Formula
tags, anonymous mass shifts and stacked modifications retain mass/chemistry instead
of being dropped or serialized as empty brackets (#10003, #10026, #10030).
- QPX import reports unsupported modifications and checks reconstructed m/z. Modification
definitions are still not carried by the format, so unsupported modifications may
still be lost on import (#10004, #10012).
- AASequence::getFormula() and AASequence::getMonoWeight() handle Residue::Zp1Ion and
Residue::Zp2Ion, the radical z+1/z+2 electron-transfer fragments. Both types used to fall
through to the default branch, which logs an error and returns the internal mass without any
ion offset, and a C-terminal modification was never applied to them. getAverageWeight() and
getMZ() build on those two functions and are fixed with them (#10181).
- Corrected a/b neutral-loss fragment masses, negative-charge MzPAF parsing and
deisotoping precursor constraints (proton mass units; unknown precursor charge no
longer discards all isotope clusters). Unsupported deisotoping tolerances no longer
abort ProSE/SimpleSearchEngine (#9078, #9084, #9620, #10067, #10075).
- Fixed peptide-indexing crashes on short peptides, NucleicAcidSearchEngine multi-hit
handling, modified-sequence decoy duplicate detection, and copy operations on spectrum
generators, SpectrumAnnotator and Normalizer (#532, #8542, #8569, #8575, #8685, #10066).
- PeptideIndexer no longer exhausts memory when a peptide hit carries an empty sequence
(an empty AASequence, or one consisting of stop codons only). The empty needle flagged
the root node of the Aho-Corasick trie as a hit, and since the root’s suffix link points
to itself, the search collected hits until memory ran out. ACTrie::addNeedle() now skips
an empty needle with a warning, but still consumes a needle index, so the peptide indices
of the caller stay aligned and such hits are simply reported as unmatched (#2987).
- PeptideIndexer: ACTrieState returns empty hits when no query was set instead of crashing
(potentially happens when the number of threads is larger than number of proteins) (#10257)
- Fixed the m/z of H2O/NH3 neutral-loss peaks of x/y/z linear ions at charge >= 2 in
TheoreticalSpectrumGeneratorXLMS and SimpleTSGXLMS: the loss was subtracted from the already
charge-divided position and divided by the charge again, so these peaks sat at roughly half
their true m/z. OpenPepXL scores and annotations of such peaks change accordingly (#10148).
- TheoreticalSpectrumGeneratorXLMS placed the second isotope peak of the precursor (and of its
H2O/NH3 losses) at the charged mass instead of its m/z, e.g. about 2003 instead of 668 for a
2000 Da precursor at charge 3. OpenPepXL uses these peaks: on the test data only its
log_occupancy scores change; on other data the corrected peak can now match an experimental
peak and change matched ion counts and scores (#10194).
- ConsensusID rejected a single empty idXML run (valid XML with no peptide identifications)
and dropped search settings when combining empty runs; per-spectrum runs also lost their
MS-file metadata, and unannotated feature/consensus maps could crash. Empty runs, and
entirely empty input in RT/mz mode, now keep their original search settings and
spectra_data instead of being discarded (#10203).
- MaRaClusterAdapter passes -precursor_tolerance_units on to MaRaCluster. It appended the
unit’s index as a digit instead, so 20 ppm reached MaRaCluster as ‘-p 20.00’ and 0.05 Da
as ‘-p 0.051’, which MaRaCluster reads as 0.051 ppm: a tolerance in Da was never applied.
Quantification and numerical correctness:
- IsobaricWorkflow wrote every consensus feature with the same id (“e_0”), which is invalid
consensusXML (consensusElement/@id is xs:ID); each feature now gets its own unique ID
(#10201).
- ExperimentalDesign mappings use sample names consistently. Protein-group quantities
survive ID filtering; ProtXML excludes ProteinProphet’s unneeded/subsumed groups
(#6038, #8960, #9874).
- Fixed SimpleSVM constant-predictor indexing, degenerate EMG fits, NaN similarity scores,
small-sample quantiles/variance, ROCCurve negative cutoffs and FragmentMassError ppm
variance. Corrected DistanceMatrix cache invalidation/comparison and empty-cell
clustering access (#6239, #9488, #9495, #9497, #9594, #9610, #9617, #9618,
#9659, #9661, #9664, #9670, #9682).
- MRMFeatureSelector works with GLPK; LP/ILP failures now report status and throw instead
of returning silently empty results in feature selection/decharging (#9940, #9944,
#9956).
- MapAlignmentAlgorithmKD::filterCCs_ (used by FeatureGroupingAlgorithmKD, i.e. by
FeatureLinkerUnlabeledKD) rejected a connected component containing conflicting nonzero
charge states only via a continue that escaped the inner charge-scanning loop, so the
component still passed the conflict check and was grouped. Such components are now
correctly rejected, which changes alignment and linking results (#10157).
- MassTrace::updateWeightedMeanRT() weighted each peak by the RT distance to its
predecessor and started the sum at the second peak, so the first peak contributed to
neither the numerator nor the denominator. The centroid was biased towards later RT
and, for a two-point trace, was always the RT of the second peak whatever the
intensities. The intensity-weighted mean now uses mid-interval (trapezoidal) weights
over all peaks, which changes RT positions on the ’epd:enabled=false’ path of
FeatureFinderMetabo and MassTraceExtractor (#2777, #10225).
Data integrity and I/O:
- Sorting/filtering/set_peaks keeps peak annotations and binary arrays aligned in
spectra, chromatograms and mobilograms. select() checks bounds before mutation;
selectUnchecked() is available for validated C++ indices. Python raises IndexError
for invalid indices and ValueError for duplicates (#8645, #9795, #9807).
- MSExperiment::reset clears chromatograms; missing named protein data arrays/targeted
references throw ElementNotFound. Fixed stale targeted-reference caches and null
prediction access (#9488, #9492, #9211).
- mzML metadata round-trips preserve UTF-8, whitespace, timestamps, independent noise
grids, detector types/units and precursor-intensity units (#10077, #10079).
- MzMLFile writes activation and analyzer terms that are valid with PSI-MS 4.2.2. EThcD or
ETciD without a supplemental activation term also gets the generic dissociation method,
as PSI-MS now lists combined methods as activation attributes. SWIFT, cyclotron and
ion-storage analyzers, and the analyzer invented for incomplete instruments, use the
generic mass analyzer type; the OpenMS type is kept in a userParam and restored on
reading. HCID, EThcD and ETciD terms use their PSI-MS names (#8691).
- Reading an mzML file only partly (metadata only, or counting its spectra, as the first pass of
MzMLFile::transform() does) ends the progress it started, so the progress output of every later
file is no longer nested one level deeper (#10271).
- mzML chromatograms are written with a precursor or product only if they have one. A TIC used
to get an empty precursor and a product isolation window at m/z 0, and an MS1 chromatogram such
a product. The original DIAuditor, for example, read that product’s isolation window as the
last spectrum’s and crashed (#10271).
- mzML: the mass resolving power (MS:1000800) is written in the scan, the only place mzML allows
it. It used to be written as a userParam of the spectrum, so other readers, such as the
original DIAuditor, lost it once a file had been written by OpenMS (#10313).
- Thermo .raw: spectra carry the mass resolving power of the scan trailer (‘Orbitrap
Resolution:’, else ‘FT Resolution:’), as msconvert reports it (#10313).
- Bruker timsTOF .d: the start of the acquisition (with its time zone), the instrument model and
its serial number are read from analysis.tdf (#10313).
- mzML: the other scan attributes the reader keeps with the spectrum (filter string, preset scan
configuration, dwell time, scan rate, mass resolution, elution time, analyzer scan offset and
interchannel delay) are written in the scan as well, and scan terms it keeps under their
accession, such as the ion injection time (MS:1000927), as CV terms. Both used to be written
as userParams, which other readers do not find.
- Fixed INI required/advanced parsing, XQuest FDR-type restoration, mzIdentML missing
modification locations, PepXML source-run paths/redundant Comet scores and duplicate
IDMapper spectrum references (#5443, #8905, #9089, #9660, #9763, #9766).
- TOPP tools no longer exit with ILLEGAL_PARAMETERS when the file given via ‘-ini’
contains a tool-specific ‘common:
Documentation:
- New “File formats” page in the OpenMS documentation: which formats tools read and write compressed, the .idparquet, .featureparquet and .consensusparquet bundles (their files, the tools that use them, how to convert), and that imzML is read by the library and pyOpenMS only. The TextExporter page lists the Parquet bundles it reads.
- Corrected misleading Doxygen contracts in the sqMass/SQLite stack: countTableRows exception types, the SpectrumAccessSqMass usage example and getSpectraByRT / getMultipleSpectra semantics, SqMassFile::store replacement behaviour and the OpenSwathScoring fetchSpectrumSwath spectrum counts (#10148, #10244).
- The ProteomicsLFQ page describes match-between-runs with PIP-ECHO (-pip_echo) and lists Thermo .raw input. The PercolatorAdapter page describes the in-process backend, when the percolator executable is run instead, and how many threads each backend uses.
- Expanded experimental-design terminology and LFQ/fractionated/TMT/SILAC examples, targeted quantitation, FAIMS, RT units, file conversions, USI and MetaProSIP CSV docs (#4400, #8478, #8588, #8597, #8615, #9173, #9909).
- New pyOpenMS user-guide pages “Arrow and Parquet” (to_arrow() of spectra, feature maps, consensus maps and identifications; reading and writing the Parquet bundles) and “Mass Spectrometry Imaging” (loading imzML, ion images, regions, on-disc access, writing).
- Updated pyOpenMS type hints, docstrings, wrapping/ownership guidance and test templates; documented native-reader requirements, core-only builds and vcpkg configuration (#8483, #8507, #8548, #8561, #8674, #9162, #9629, #9736, #9752, #9792, #9812, #9928).
- New “Vendor formats” pages in the OpenMS and pyOpenMS documentation: the tools that read Thermo .raw files and Bruker timsTOF .d directories, FileConverter’s two Thermo readers and their defaults, and that the other tools apply Thermo’s peak picking too (#10303). Corrected the FileConverter, FeatureFinderIdentification and FeatureFinderMetaboIdent pages, the .NET requirement on the Windows installation page, and the macOS installation page (macOS 15, notarized installer).
- The user FAQ explains OpenMS.ini: that it is optional, where OpenMS looks for it and which entries it reads. The OpenMSInfo page describes the data, temp and user data paths as they are resolved now (#3009).
- The Windows installation page builds with the vcpkg presets instead of the contrib package, and the developer FAQ, the guide to adding a dependency (now via vcpkg.json and overlay ports), the external-code pages and the agent notes no longer refer to contrib. The orphaned install-contrib page is removed (#10144).
Build System:
- The Debian package of a nightly or branch build carries its prerelease identifier in its control version, for example 3.6.0~nightly.2026.09.27, so it sorts below the release and a later nightly above an earlier one. Before, every build of 3.6.0 was version 3.6.0 to apt, whether nightly or release.
- Public headers of OpenMS, OpenSwathAlgo, OpenMS_CLI, OpenMS_GUI and the test framework use CMake header file sets. Installation paths and components stay unchanged and private headers remain excluded. Building OpenMS and consuming its CMake package both require CMake 3.24. Linux x64 CI explicitly verifies public headers as standalone translation units, with missing includes in identification-data and GUI headers corrected; normal builds can opt in with OPENMS_VERIFY_INTERFACE_HEADER_SETS=ON (#10177).
- The TOPP tool framework (TOPPBase, ToolHandler, ParameterInformation, SearchEngineBase, TOPPExternalToolBase, MapAlignerBase, OpenSwathBase) moved out of libOpenMS into the new library libOpenMS_CLI (src/openms_cli; CMake target OpenMS_CLI, installed as OpenMS::OpenMS_CLI, package component CLI, export macro OPENMS_CLI_DLLAPI). Include paths are unchanged. The CTD/CWL parameter serializers read the parameter tag names from the new core header OpenMS/DATASTRUCTURES/ParamTags.h, so nothing in libOpenMS depends on the framework any more and its exported interface is purely scientific. BREAKING for external projects that build TOPP-style tools: link OpenMS::OpenMS_CLI (which carries OpenMS::OpenMS) instead of OpenMS::OpenMS (#10162).
- The installed CMake package is layered: the core libraries (libOpenMS, libOpenSwathAlgo and the
bundled third-party libraries; export set OpenMSTargets, install components library and cmake),
the TOPP tool framework (libOpenMS_CLI; OpenMSCLITargets, library_cli and cmake_cli) and the GUI
library (libOpenMS_GUI; OpenMSGUITargets, library_gui and cmake_gui) each have their own export
set and install components (openms_add_library(… EXPORT_SET
)). An installation may stop at any layer: OpenMSConfig.cmake provides the targets of the layers present, reports them with OpenMS_CLI_FOUND and OpenMS_WITH_GUI (now true only when the GUI library is installed) and refuses a required CLI or GUI component that is missing; TOPP-style external tools request COMPONENTS CLI. The pyOpenMS wheels build and install the core layer only again, the installed-consumer test covers a full and a core-only installation, and the deb/rpm/macOS packages include the new library components. The Applications component depends on the library layer its binaries link (library_gui in a WITH_GUI build, library_cli otherwise), so a component-selectable installation cannot leave the TOPP tools without libOpenMS_CLI. The deb/rpm component lists spell that component the way the install rules register it: CPack compares component names verbatim when it selects what to install, so a component-wise package built from the previous spelling would have contained none of the TOPP tools. Reconfiguring a build directory with another WITH_GUI setting no longer leaves a stale GUI target file behind (src/tests/package_layers checks this with stub libraries) (#10164). - Three places spelled the install component that every TOPP tool, TOPPView and TOPPAS is
registered under (“Applications”) in lower case: the cpack_add_component() declaration and
the CPACK_COMPONENTS_ALL lists of the deb/rpm packages. CPack folds CPACK_COMPONENT_
_* metadata (DISPLAY_NAME, DEPENDS, …) to upper case, so that lookup still worked, but compares the name verbatim when selecting what to install, so a component-wise deb/rpm build from these lists would have matched no install rule and shipped no TOPP tools at all. Both generators currently build monolithically, so the shipped packages were unaffected; the naming is now “Applications” everywhere (#10199). - vcpkg manifests, cross-platform CMake presets, overlay ports/triplets and binary caching support Linux, Windows and macOS; main build/test CI uses them. Release-only triplets avoid building duplicate Debug dependencies (#9511, #9800, #9927).
- BUILD_TOPP_TOOLS and INSTALL_OPENMS_EXAMPLES (both default ON) enable a core-only SDK; incompatible workflow-generation options fail configuration. Installed headers and external find_package(OpenMS) consumers are validated (#9752, #9774, #10103).
- Linux/macOS install RPATHs include linked dependency locations; vcpkg paths and macOS loader-relative paths are handled explicitly. Build-tree linking resolves private dependencies consistently, avoiding same-name library conflicts (#10114).
- Numeric conversion uses std::from_chars/to_chars, reducing compile time and improving throughput; scientific formatting uses portable shortest round-trip strings (#9648, #9668). Core/OpenSwathAlgo AUTOMOC is disabled (#10099).
- pyOpenMS uses py-build-cmake/cibuildwheel; improved dev RPATH, Windows DLL discovery, local nanobind detection and isolated builds. Thermo bridge assets are bundled from verified cached downloads (#8484, #8530, #8706, #8874, #8892, #8933, #9732, #9738, #10070).
- CI/release packaging updated across platforms, including Ubuntu 24.04, Visual Studio 2026 and automated backports/version bumps. Windows Release builds regain optimization; installer path/staging failures are fixed. macOS installers are signed/notarized and exclude pyOpenMS modules distributed as wheels (#8961, #9514, #9523, #9742, #9827, #9969, #10009).
- The macOS package installs bin/qt.conf, so ExecutePipeline, and with it TOPPAS pipelines on the command line, can load the Qt platform plugin (#10260, #10280).
- Fixed Arrow repository keys/version pins, Bioconda synchronization/tooling/dependency conflicts and package-list handling; build failures now propagate. Multi-architecture images publish a combined amd64/arm64 manifest (#9196, #9726, #9728, #9729, #9750, #9798, #9890, #9891, #9905, #9951, #9954, #10071). The nightly Bioconda deploy workflow called bioconda-utils build with –pkg-dir, an option that does not exist (–package-dir is correct), failing every nightly run since 2026-09-08 (#10167). A later upstream bioconda-utils release renamed –mulled-test to –mulled-build-and-test without keeping the old name, breaking the same workflow again; it now uses the current flag (#10227).
- Fixed compiler-cache saving and fork-PR workflow failures; documentation lint rules are pinned. Added effective Parquet schema/value checks and non-finite numeric comparisons; removed parallel-test output collisions and source-timestamp assumptions (#9785, #9787, #9859, #9861, #9877, #9878, #9879, #9887, #9899, #9906, #9937, #9973, #10018).
- Fixed a link-order bug that left libOpenMS.so with undefined libxml2 symbols when
Arrow is linked statically, which ARROW_USE_STATIC (our own option, default ON)
selects whenever a static Arrow target exists. libxml2 was listed as a direct
OpenMS dependency, which put it ahead of libarrow_bundled_dependencies.a on the
link line; an –as-needed linker then dropped it and
import pyopenmsfailed with “undefined symbol: xmlBufferFree”. It is now appended to Arrow’s link interface, where the ordering is correct. The symbols come from the bundled azure-storage-common, not from the AWS SDK, which brings its own XML parser (#10136). - Improved CMake 4/MSVC, clang/Xcode, OpenMP and non-vcpkg ONNX builds, plus Debian dependency packaging to avoid .deb conflicts. OpenMP requests fail clearly when unavailable; SIMD-only compilation works without a runtime. Fixed YAML CTD parsing and optional WNet tool registration (#8368, #8880, #9056, #9223, #8496, #9267, #9388, #9651, #9653, #9783, #9784, #9971).
- Documentation formulas use MathJax, removing Ghostscript. Removed obsolete developer scripts, ENABLE_STYLE_TESTING, doc_xml and stale examples/schemas. Runtime schema coverage is retained; QcMLFile/PepXMLFileMascot validation remains unavailable and now throws NotImplemented (#9740, #9757, #9771, #9945).
- The Debian package derives its libc6, libstdc++6, libgomp1 and libgcc-s1 dependencies
from the shipped binaries with dpkg-shlibdeps, so they cannot go stale as the declared
libc6 (>= 2.28) had, and the package does not install on distributions too old to run
it. This needed the install tree cleaned up first: the bundled tools were installed
verbatim, including ThermoRawFileParser’s NuGet runtimes/
/ directories, which carry libMono.Unix.so for nine runtime identifiers (android-arm, android-arm64, android-x64, android-x86, linux-arm, linux-arm64, linux-x64, osx-arm64, osx-x64). Most are foreign to whichever host builds the package, and dpkg-shlibdeps treats a foreign-architecture binary as an error rather than as missing information, so no package was produced at all. Only the runtime identifiers the build targets are installed now; the parser’s own Mono.Unix.dll.config maps the library to linux-x64, osx-x64 and osx-arm64 and to nothing else, so the others could never be loaded (#10202, #10207, #10211). - Debian package clean-up (#10230). Libraries no longer carry empty RUNPATH entries, which the dynamic loader reads as the current working directory: the release workflow links under PACKAGE_TYPE=none, whose install RPATH also names the build tree’s vcpkg directory, and packages after reconfiguring, so CMake kept most of the ‘:’ padding of the longer build-tree RPATH. libOpenSwathAlgo (and on arm64 the Thermo bridge) shipped with $ORIGIN/../lib/ and about 90 empty entries; CPack now removes them before building the package. The arm64 build takes the Thermo bridge from vcpkg, as every other platform does: vcpkg.json still left it out on linux & arm64 from when Thermo RAW reading was off there (#10206 turned it on), so the arm64 build fetched and built the bridge itself and packaged the bridge’s headers, CMake package, .pdb and a second copy of its managed assemblies. The vcpkg port also installs the Thermo RawFileReader license now, so every package ships it under share/OpenMS/LICENSES as the from-source build did; before, only the arm64 package had it. Depends is now exactly what dpkg-shlibdeps derives. The hand-written entries had gone stale: the Qt ones are derived anyway, and the derived plain t64 names made their “t64 | non-t64” alternatives unenforceable; nothing links yaml-cpp dynamically; and SQLite ships inside the package, so libsqlite3-0 was never used (#10259).
- The DEB installed the 53 third-party libraries it bundles and the Thermo bridge world-writable (mode 0777) in /usr/lib, among them libssl.so.3 and libcrypto.so.3, so any local user could replace code that the OpenMS tools load, also when root runs them. The macOS package installed the headers and resources of its Qt frameworks world-writable. Bundled libraries are now writable by their owner only (0755), like any installed library (#10324).
- The container image build failed on every nightly run once WITH_THERMO_RAW defaulted to ON on Linux aarch64 (#10206): the Dockerfile still installed the .NET SDK/runtime that openms-thermo-bridge needs only for amd64, so the arm64 build could not find the dotnet executable at configure time. Both installs are now unconditional (#10210).
- Linux wheels are built in a container with the checkout bind-mounted, which made git refuse the repository and left the embedded version a placeholder. The build marks the checkout safe, and any git failure now falls back to the “exported” version string instead of leaking the placeholder into VersionInfo and package file names (#10202).
- MACOSX_DEPLOYMENT_TARGET is declared once for the wheels; the workflow value silently overrode pyproject.toml, which moved the supported macOS floor without notice. A CI check compares the Mach-O load commands of each wheel against its platform tag, so a wheel can no longer install on a macOS it cannot run on (#10202).
- The macOS package states the macOS it needs. The build targets macOS 15, the macOS its Homebrew libraries are built for, instead of 14. The installer refuses older versions, and TOPPView, TOPPAS and INIFileEditor declare the build’s target in their Info.plist instead of macOS 12 (#10286).
- vcpkg builds OpenBLAS, which COIN-OR’s LAPACK pulls in, for a fixed CPU target on Linux: CORE2 (SSSE3, the baseline OpenMS itself is compiled for) on x86_64 and ARMV8 on arm64. It used to take the kernels for the CPU of the build machine, and the binary cache passed that build on to later builds and to the packages. The 2026-09-24 nightlies shipped an OpenBLAS that needs AVX2 on x86_64 and SVE on arm64, which not every supported CPU has, and clang debug builds failed on x86_64 machines with AVX-512 (#10264).
- The installers and the pyOpenMS wheels ship the license texts of the third-party code they contain; before, share/OpenMS/LICENSES held only the OpenMS license. It now also holds the licenses of the vcpkg ports, which the packages and the Linux and Windows wheels contain (vcpkg/), of Qt with where to get its source (Qt/, Windows and macOS), of the Homebrew formulae whose libraries the macOS package and wheel bundle (homebrew/), of the system libraries the wheel repair tools copy in, such as GCC’s OpenMP and Fortran runtimes (system/), and of the code that OpenMS carries in its source tree and compiles into libOpenMS, such as Percolator with its NOTICE file (vendored/). share/OpenMS/THIRD-PARTY-NOTICES.txt gathers them in one file: the third-party components, grouped by where they come from, and each text once. The DEB also installs it, after the OpenMS license, as /usr/share/doc/openms/copyright, and License.txt points to it (#10292).
- The tools the installers bundle from THIRDPARTY come with their license texts: Comet, MaRaCluster, Percolator and the assemblies of ThermoRawFileParser, and so do the assemblies of the in-process Thermo reader (openms-thermo-bridge 0.3.1). SpectraST is no longer bundled: it is GPL-licensed and was shipped without its license text or source code. SpectraSTSearchAdapter runs a separately installed spectrast given with -executable (OpenMS/THIRDPARTY abe0956, #10292).
- The Windows installer no longer includes ProteoWizard (msconvert and the instrument vendors’ libraries in THIRDPARTY/pwiz-bin). OpenMS does not use it; to convert other vendor formats with msconvert, install ProteoWizard from https://proteowizard.sourceforge.io/ (#10292).
- The Windows installer and the Linux x86_64 DEB no longer include X!Tandem (THIRDPARTY/XTandem). No OpenMS tool has run it since XTandemAdapter was removed in 3.4.0, and its Linux build embeds expat 2.0.1, which Critical CVEs such as CVE-2016-0718 affect. OpenMS still reads X!Tandem’s result files (#10344).
- TOPPView and TOPPAS show the notice that Thermo’s RawFileReader license asks for in their About dialog, in builds with the in-process Thermo reader (#10292).
Known issues:
- Three search engines that the installers bundle from THIRDPARTY contain outdated library code: Comet embeds zlib 1.2.11 and expat 2.2.9, MaRaCluster zlib 1.2.3, and Sage SQLite 3.41.2. Published vulnerabilities of these versions, such as CVE-2022-25235 (expat), CVE-2016-9841 (zlib) and CVE-2025-6965 (SQLite), concern malformed input or SQL statements, so run these engines only on files you trust. They will be rebuilt against current versions after this release.
- All installers and pyOpenMS wheels contain OpenSSL 3.6.4, which 13 advisories published with OpenSSL 3.6.5 on 2026-09-29 affect. The only one rated High, CVE-2026-84782, concerns DTLS connections, which OpenMS does not open. The other twelve are rated Low; among them, CVE-2026-35189 lets a malicious HTTPS server make OpenMS use excessive memory with a crafted certificate.
Best regards,
The OpenMS-Developers