Skip to content

Refactor/osw calibration#8743

Merged
timosachsenberg merged 48 commits into
OpenMS:developfrom
singjc:refactor/osw_calibration
Feb 6, 2026
Merged

Refactor/osw calibration#8743
timosachsenberg merged 48 commits into
OpenMS:developfrom
singjc:refactor/osw_calibration

Conversation

@singjc

@singjc singjc commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Description

iRT calibration logic in OpenSwathWorkflow is split across src/topp/OpenSwthWorkflow, src/openms/source/ANALYSIS/OPENSWATH/OpenSwathWorkflow and src/openms/include/OpenMS/APPLICATIONS/OpenSwathBase. This PR refactors the main calibration logic into a new separate reusable CalibrationWorkflow class.

Refactoring and Codebase Simplification:

  • Removed the OpenSwathCalibrationWorkflow class and all its methods from OpenSwathWorkflow.h, centralizing calibration logic elsewhere and reducing code duplication.
  • Removed the performCalibration method from OpenSwathBase.h, reflecting the refactored calibration workflow.

New Functionality and API Changes:

  • Added a new method loadMS1Map to OpenSwathWorkflow, which loads the first MS1 map from a set of swath maps, with an option to load data into memory. [1] [2] [3]
  • Added new parameters mz_estimation_percentile_ and im_estimation_percentile_ for finer control over mass and ion mobility window estimation in SwathMapMassCorrection.h.

Project Structure and Build System:

  • Added CalibrationWorkflow.h to the CMake sources list, ensuring the new calibration workflow header is included in the build.
  • Updated includes in OpenSwathWorkflow.cpp to reference the new CalibrationWorkflow.h.

Checklist

  • Make sure that you are listed in the AUTHORS file
  • Add relevant changes and new features to the CHANGELOG file
  • I have commented my code, particularly in hard-to-understand areas
  • New and existing unit tests pass locally with my changes
  • Updated or added python bindings for changed or new classes (Tick if no updates were necessary.)

How can I get additional information on failed tests during CI

Click to expand If your PR is failing you can check out
  • The details of the action statuses at the end of the PR or the "Checks" tab.
  • http://cdash.seqan.de/index.php?project=OpenMS and look for your PR. Use the "Show filters" capability on the top right to search for your PR number.
    If you click in the column that lists the failed tests you will get detailed error messages.

Advanced commands (admins / reviewer only)

Click to expand
  • /reformat (experimental) applies the clang-format style changes as additional commit. Note: your branch must have a different name (e.g., yourrepo:feature/XYZ) than the receiving branch (e.g., OpenMS:develop). Otherwise, reformat fails to push.
  • setting the label "NoJenkins" will skip tests for this PR on jenkins (saves resources e.g., on edits that do not affect tests)
  • commenting with rebuild jenkins will retrigger Jenkins-based CI builds

⚠️ Note: Once you opened a PR try to minimize the number of pushes to it as every push will trigger CI (automated builds and test) and is rather heavy on our infrastructure (e.g., if several pushes per day are performed).

Summary by CodeRabbit

  • New Features

    • Reusable calibration component supporting multiple iRT provisioning strategies and automatic RT/m/z/IM window estimation (percentile-based).
    • MS1 map loading helper for streamlined spectrum access.
  • Refactor

    • Calibration logic extracted into a dedicated, modular workflow; main OpenSwath workflow now delegates calibration to it and uses per-run extraction parameters.
  • Tests

    • New unit tests for normalization and calibration using synthetic chromatograms.

singjc added 30 commits February 2, 2026 20:38
…hWorkflow

- Introduced CalibrationWorkflow for modular calibration of RT, m/z, and ion mobility.
- Replaced manual calibration logic with a single call to CalibrationWorkflow, simplifying the calibration process.
- Added support for loading existing RT transformation files, skipping calibration if provided.
- Updated configuration mapping from TOPP parameters to CalibrationConfig for better parameter management.
- Enhanced logging for clarity during calibration steps and outcomes.
- Included new header file CalibrationWorkflow.h in OpenSwathWorkflow.cpp.
- Removed the dependency on a transformation file for calibration, allowing for a more flexible approach using iRT experiments.
- Introduced a new IrtExperiments structure to manage linear and nonlinear iRT data.
- Added a strategy for preparing iRT experiments based on static files or sampling from a full transition library.
- Updated performCalibration, performLinearCalibration, and performLinearThenNonlinearCalibration methods to utilize the new iRT structure and parameters.
- Enhanced logging for better traceability during calibration processes.
- Removed redundant validation functions and streamlined configuration checks.
- Improved handling of estimated extraction windows based on new parameters.
…CalibrationWorkflow and update related parameters
…in CalibrationWorkflow and SwathMapMassCorrection
…on in CalibrationWorkflow and SwathMapMassCorrection
…e fresh copies for each run, preventing parameter carry-over.
… info level and add progress indicators for calibration steps
…ng RT transformation and remove unnecessary info logs
…setters and use CalibrationWorkflow for RT normalization
… centralize RT/m/z normalization logic in CalibrationWorkflow
…del parameters to match original implementation
@coderabbitai

coderabbitai Bot commented Feb 5, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Refactors OpenSWATH calibration into a new public CalibrationWorkflow class and implementation, removes the old OpenSwathCalibrationWorkflow and TOPPOpenSwathBase::performCalibration, adds percentile-based window estimation parameters, updates OpenSwathWorkflow/TOPP to delegate to CalibrationWorkflow, and adds tests and build entries.

Changes

Cohort / File(s) Summary
CalibrationWorkflow
src/openms/include/OpenMS/ANALYSIS/OPENSWATH/CalibrationWorkflow.h, src/openms/source/ANALYSIS/OPENSWATH/CalibrationWorkflow.cpp
Adds new public CalibrationWorkflow (enum IrtStrategy, CalibrationResult, IrtExperiments) implementing iRT provisioning strategies, iRT loading, RT/m/z/IM calibration (linear and linear+nonlinear), normalization flows, window estimation/application, and public accessors.
OpenSwathWorkflow (refactor)
src/openms/include/OpenMS/ANALYSIS/OPENSWATH/OpenSwathWorkflow.h, src/openms/source/ANALYSIS/OPENSWATH/OpenSwathWorkflow.cpp, src/topp/OpenSwathWorkflow.cpp
Removes OpenSwathCalibrationWorkflow and its helpers/params; adds OpenSwathWorkflow::loadMS1Map; delegates calibration and iRT handling to CalibrationWorkflow; localizes per-run extraction params.
OpenSwathBase API
src/openms/include/OpenMS/APPLICATIONS/OpenSwathBase.h, src/openms/source/APPLICATIONS/OpenSwathBase.cpp
Removes TOPPOpenSwathBase::performCalibration(...) declaration and implementation from public API.
Window estimation (percentiles)
src/openms/include/OpenMS/ANALYSIS/OPENSWATH/SwathMapMassCorrection.h, src/openms/source/ANALYSIS/OPENSWATH/SwathMapMassCorrection.cpp
Adds mz_estimation_percentile_ and im_estimation_percentile_ (defaults 99.0, bounds 25–99.9) and replaces hard-coded 0.99 quantile with configurable percentiles in extraction-window estimation.
Build / Sources
src/openms/include/OpenMS/ANALYSIS/OPENSWATH/sources.cmake, src/openms/source/ANALYSIS/OPENSWATH/sources.cmake
Registers CalibrationWorkflow.h and CalibrationWorkflow.cpp in build source lists.
Tests
src/tests/class_tests/openms/executables.cmake, src/tests/class_tests/openms/source/CalibrationWorkflow_test.cpp
Adds CalibrationWorkflow_test and unit tests exercising doDataNormalization_ and performCalibration using synthetic chromatograms and parameterized fitting checks.
TOPP tests
src/tests/topp/CMakeLists.txt
Updates OpenSwathWorkflow TOPP tests to use explicit -Calibration:... keys, adds test scenarios (including multi-file per-run), and updates expected outputs.

Sequence Diagram(s)

sequenceDiagram
    participant TOPP as TOPP/OpenSwathWorkflow
    participant Cal as CalibrationWorkflow
    participant FS as FileHandler
    participant Sw as SwathMaps/SpectrumAccess
    participant Trans as TransformationStorage

    TOPP->>Sw: prepare swath_maps / load MS1 (optional)
    TOPP->>Cal: determineIrtStrategy(targeted_exp, num_runs)
    Cal-->>TOPP: IrtStrategy
    TOPP->>Cal: prepareIrtExperiments(strategy, targeted_exp, priority_peptides, run_idx, cached_irts)
    Cal->>FS: loadIrtExperimentFromFile_(file_path)
    FS-->>Cal: irt_experiment
    TOPP->>Cal: performCalibration(swath_maps, targeted_exp, cp, cp_ms1, irt_experiments, ...)
    Cal->>Sw: extract chromatograms / load MS1 (if needed)
    Cal->>Trans: compute RT/mz/IM transformations & estimate windows
    Cal-->>TOPP: CalibrationResult (trafo, windows)
    TOPP->>FS: optionally write trafo/mzML
Loading

Possibly related PRs

Suggested labels

OpenSwathAlgo

Suggested reviewers

  • jcharkow

Poem

🐰 I hopped through code and found a way,
IRTs now live where they should stay;
Calibration split, neat and spry,
Windows learned to quantify,
OpenSWATH sings — let's run and play! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.34% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Refactor/osw calibration' is vague and uses non-descriptive phrasing that doesn't clearly convey the main change; it lacks specificity about what is being refactored or why. Consider using a more specific title like 'Extract iRT calibration into reusable CalibrationWorkflow class' or 'Refactor OpenSwathWorkflow calibration logic into CalibrationWorkflow' to better describe the primary change.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/openms/source/ANALYSIS/OPENSWATH/OpenSwathWorkflow.cpp (1)

31-37: ⚠️ Potential issue | 🟡 Minor

Return the first MS1 map as documented.
The loop currently keeps the last MS1 map; break on the first match to align with the helper’s intent.

🐛 Suggested fix
-    for (SignedSize i = 0; i < boost::numeric_cast<SignedSize>(swath_maps.size()); ++i)
+    for (SignedSize i = 0; i < boost::numeric_cast<SignedSize>(swath_maps.size()); ++i)
     {
       // if (swath_maps[i].ms1 && use_ms1_traces_)
       if (swath_maps[i].ms1)
       {
         ms1_map = swath_maps[i].sptr;
+        break;
       }
     }
src/topp/OpenSwathWorkflow.cpp (1)

891-1062: ⚠️ Potential issue | 🟠 Major

SAMPLE_ONCE iRT sampling is re-run every run.
prepareIrtExperiments is always called with cached_irts=nullptr, so runs can get different sampled iRTs (especially when auto_irt:irt_seed is 0), which defeats SAMPLE_ONCE. Cache the first result and reuse it for subsequent runs.

🐛 Suggested fix
-    Size run_index = 0;
+    Size run_index = 0;
+    CalibrationWorkflow::IrtExperiments cached_irts;
+    bool has_cached_irts = false;
     for (const StringList& current_run_files : run_groups)
     {
@@
-        CalibrationWorkflow::IrtExperiments irt_experiments = calibration_wf.prepareIrtExperiments(
-          strategy, transition_exp, priority_pep_strings, run_index);
+        const CalibrationWorkflow::IrtExperiments* cached_ptr =
+          (strategy == IrtStrategy::SAMPLE_ONCE && has_cached_irts) ? &cached_irts : nullptr;
+        CalibrationWorkflow::IrtExperiments irt_experiments = calibration_wf.prepareIrtExperiments(
+          strategy, transition_exp, priority_pep_strings, run_index, cached_ptr);
+        if (strategy == IrtStrategy::SAMPLE_ONCE && !has_cached_irts && irt_experiments.is_prepared)
+        {
+          cached_irts = irt_experiments;
+          has_cached_irts = true;
+        }
🤖 Fix all issues with AI agents
In `@src/openms/include/OpenMS/ANALYSIS/OPENSWATH/OpenSwathWorkflow.h`:
- Around line 279-280: The public method declaration loadMS1Map(const
std::vector<OpenSwath::SwathMap>& swath_maps, bool load_into_memory) has only a
terse /// comment; replace it with a full Doxygen block matching header
guidelines (use `@brief`, `@param` swath_maps, `@param` load_into_memory, and `@return`)
similar to the neighbouring method's style so the API is properly documented;
update the comment directly above the OpenSwath::SpectrumAccessPtr
loadMS1Map(...) declaration in OpenSwathWorkflow.h.

In `@src/openms/source/ANALYSIS/OPENSWATH/CalibrationWorkflow.cpp`:
- Around line 239-258: The CalibrationResult currently leaves QC fields at
defaults; populate result.num_irt_peptides_used, result.rt_rsq and
result.coverage_fraction before returning (right after you set
result.estimated_rt_window and before storing transformations/endProgress). Set
them from the internal values produced during
performRTNormalization()/doDataNormalization_ (e.g. assign
result.num_irt_peptides_used = num_irt_peptides_used_; result.rt_rsq = rt_rsq_;
result.coverage_fraction = coverage_fraction_), or if those internal members do
not exist, compute them from the RT fitting data (e.g. count of IRT peptides
used, R² from the RT transformation stored in result.rt_trafo, and fraction of
RT coverage used) — alternatively remove these QC fields from the public
CalibrationResult if you cannot reliably populate them.
- Around line 447-450: Remove the no-op conditional around the
estimateBestPeptides flag: delete the empty "if (estimateBestPeptides) { }"
block (the variable is set via
irt_detection_param.getValue("estimateBestPeptides").toBool()) so there is no
unused empty branch; if any behavior was intended, implement it inside the block
instead of leaving it empty.

In `@src/tests/topp/CMakeLists.txt`:
- Around line 1866-1871: The -Calibration:files:linear_irt_file argument in the
add_test call for "TOPP_OpenSwathWorkflow_27" is currently a space-delimited
string and should be a semicolon-delimited list; modify the add_test invocation
to pass a semicolon-separated list of the .irt.TraML paths (escape semicolons so
CMake keeps them as a single CLI argument, e.g. replace the space-separated
sequence in the -Calibration:files:linear_irt_file value with semicolon
separators escaped for CMake like "\;"), or alternatively construct a CMake list
variable and pass that variable as the single -Calibration:files:linear_irt_file
argument so positional mapping is exercised correctly.
🧹 Nitpick comments (2)
src/tests/class_tests/openms/source/CalibrationWorkflow_test.cpp (1)

27-253: Consider extracting a small test fixture helper to remove duplicated setup.
Both sections build identical targeted experiments and chromatograms; a shared helper would keep the tests easier to maintain.

src/openms/include/OpenMS/ANALYSIS/OPENSWATH/CalibrationWorkflow.h (1)

134-165: Use OpenMS::Size for run counts/indices in the public API.
This keeps the interface consistent with OpenMS container-size conventions. Per the coding guidelines, OpenMS primitive types from OpenMS/CONCEPT/Types.h (e.g., Size, SignedSize) should be used instead of size_t for STL container sizes and related counts.

Suggested update
-    IrtStrategy determineIrtStrategy(
-      const OpenSwath::LightTargetedExperiment& full_transition_exp,
-      size_t num_runs = 1
-    ) const;
+    IrtStrategy determineIrtStrategy(
+      const OpenSwath::LightTargetedExperiment& full_transition_exp,
+      Size num_runs = 1
+    ) const;

     IrtExperiments prepareIrtExperiments(
       IrtStrategy strategy,
       const OpenSwath::LightTargetedExperiment& full_transition_exp,
       const std::vector<String>& priority_peptides,
-      size_t run_index = 0,
+      Size run_index = 0,
       const IrtExperiments* cached_irts = nullptr
     );

Also update the corresponding implementation in CalibrationWorkflow.cpp (lines 793 and 859).

Comment thread src/openms/include/OpenMS/ANALYSIS/OPENSWATH/OpenSwathWorkflow.h Outdated
Comment thread src/openms/source/ANALYSIS/OPENSWATH/CalibrationWorkflow.cpp
Comment thread src/openms/source/ANALYSIS/OPENSWATH/CalibrationWorkflow.cpp Outdated
Comment thread src/tests/topp/CMakeLists.txt

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/openms/include/OpenMS/ANALYSIS/OPENSWATH/CalibrationWorkflow.h`:
- Around line 308-312: The four public getter methods getEstimatedMzWindow,
getEstimatedImWindow, getEstimatedMs1MzWindow, and getEstimatedMs1ImWindow lack
Doxygen `@brief` documentation; add Doxygen blocks above each method in
CalibrationWorkflow.h using the required style: a single-line `@brief` describing
what the getter returns, a blank line, then any additional details (if needed)
and since there are no parameters or return tags required by your guideline you
may omit `@param` but ensure the brief clearly states the returned value (e.g.,
"Estimated m/z extraction window (populated after calibration)"); keep blocks
consistent across all four getters.
- Around line 67-69: Remove the extra blank line(s) immediately following the
access specifiers in the CalibrationWorkflow.h header: delete the empty line
after "public:" (above the "/// Results from calibration workflow" comment) and
likewise remove the blank line(s) after the matching "private:" block referenced
around lines 314-316 so access specifiers directly precede their first member
declarations; update within the class CalibrationWorkflow to keep no blank line
between the access label and the first comment/member.

In `@src/openms/source/ANALYSIS/OPENSWATH/CalibrationWorkflow.cpp`:
- Around line 279-331: The linear calibration path disables m/z correction but
still leaves IM correction enabled, causing SwathMapMassCorrection::correctIM to
run twice (once in performLinearCalibration_ and again in doDataNormalization_)
and distorting PASEF drift times; fix by disabling IM correction in the linear
step by updating linear_calibration_param (the Param passed into
performLinearCalibration_) to disable the IM/mobility correction flag used by
SwathMapMassCorrection (e.g., set the appropriate key such as "im_correction" or
the project’s mobility correction param to "none"/false) before calling
performLinearCalibration_, or alternatively disable that same IM/mobility
correction in calibration_params_configured passed to doDataNormalization_ if
you prefer IM correction only in the linear step.
🧹 Nitpick comments (2)
src/openms/include/OpenMS/ANALYSIS/OPENSWATH/CalibrationWorkflow.h (2)

126-157: Use OpenMS::Size for run counters in the public API.

This keeps the new API consistent with OpenMS size conventions and avoids mixing standard types with OpenMS types.

🔧 Suggested change
-    IrtStrategy determineIrtStrategy(
-      const OpenSwath::LightTargetedExperiment& full_transition_exp,
-      size_t num_runs = 1
-    ) const;
+    IrtStrategy determineIrtStrategy(
+      const OpenSwath::LightTargetedExperiment& full_transition_exp,
+      Size num_runs = 1
+    ) const;
@@
-    IrtExperiments prepareIrtExperiments(
-      IrtStrategy strategy,
-      const OpenSwath::LightTargetedExperiment& full_transition_exp,
-      const std::vector<String>& priority_peptides,
-      size_t run_index = 0,
-      const IrtExperiments* cached_irts = nullptr
-    );
+    IrtExperiments prepareIrtExperiments(
+      IrtStrategy strategy,
+      const OpenSwath::LightTargetedExperiment& full_transition_exp,
+      const std::vector<String>& priority_peptides,
+      Size run_index = 0,
+      const IrtExperiments* cached_irts = nullptr
+    );

Please update the corresponding .cpp definitions for signature parity. As per coding guidelines: Use OpenMS primitive types from OpenMS/CONCEPT/Types.h (e.g., Size, SignedSize) instead of standard types like int, unsigned int for STL container sizes.


218-220: Public helper name should not use a trailing underscore.

Trailing underscores are reserved for member variables; for a public API this reads like an internal method. Consider renaming (e.g., loadIrtExperimentFromFile) or moving it to the private section if it is internal-only. As per coding guidelines: Use lowerCamelCase for method names; use snake_case for variable names; use trailing underscore for private and protected member variables.

Comment thread src/openms/include/OpenMS/ANALYSIS/OPENSWATH/CalibrationWorkflow.h
Comment thread src/openms/include/OpenMS/ANALYSIS/OPENSWATH/CalibrationWorkflow.h Outdated
Comment thread src/openms/source/ANALYSIS/OPENSWATH/CalibrationWorkflow.cpp

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/openms/include/OpenMS/ANALYSIS/OPENSWATH/CalibrationWorkflow.h`:
- Around line 65-105: Add Doxygen `@brief` blocks for the public structs and
constructor/destructor: document the CalibrationResult struct (briefly
describing it holds RT/IM transformations and estimated extraction windows), the
IrtExperiments struct (briefly describing linear/nonlinear experiments, strategy
and readiness flag), the default constructor CalibrationWorkflow() and the
destructor ~CalibrationWorkflow(); follow project style by using an `@brief` line,
a blank line, then longer details as needed and include `@param` tags only if the
ctor/dtor have parameters (they do not), ensuring the comments sit immediately
above the declarations for CalibrationResult, IrtExperiments,
CalibrationWorkflow(), and ~CalibrationWorkflow().
- Around line 219-303: The Doxygen param tags are incorrect: update the comment
blocks for performRTNormalization and doDataNormalization_ so that swath_maps is
marked `@param`[in,out] (because the function mutates the provided swath_maps) and
irt_mzml_out is marked `@param`[in] (it's an input path), ensure the `@brief` is
followed by a blank line before the detailed description and that all parameters
use `@param`[in], `@param`[out] or `@param`[in,out] as appropriate (refer to
performRTNormalization, doDataNormalization_, swath_maps, and irt_mzml_out to
locate the exact blocks to edit).

Comment thread src/openms/include/OpenMS/ANALYSIS/OPENSWATH/CalibrationWorkflow.h
Comment thread src/openms/include/OpenMS/ANALYSIS/OPENSWATH/CalibrationWorkflow.h
@timosachsenberg
timosachsenberg merged commit 57f2b5e into OpenMS:develop Feb 6, 2026
39 checks passed
@timosachsenberg

Copy link
Copy Markdown
Contributor

Nice

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