Skip to content

Commit 00563a9

Browse files
authored
Merge pull request OpenMS#8592 from OpenMS/copilot/fix-sps-ms3-workflow-exception
Handle MS2 spectra without corresponding MS3 in IsobaricWorkflow SPS-MS3 workflow
2 parents 94cc0ca + 2129029 commit 00563a9

File tree

1 file changed

+32
-0
lines changed

1 file changed

+32
-0
lines changed

src/topp/IsobaricWorkflow.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,10 @@ class TOPPIsobaricWorkflow :
576576

577577
channel_extractor.registerChannelsInOutputMap(cmap, mz_file);
578578

579+
// Collect peptide IDs without corresponding MS3 spectra (thread-safe collection)
580+
// Note: unassigned_pep_ids is shared across threads; push_back is protected by critical section
581+
PeptideIdentificationList unassigned_pep_ids;
582+
579583
#pragma omp parallel for /*num_threads(inner_threads)*/
580584
for (int64_t pep_idx = 0; pep_idx < static_cast<int64_t>(pep_ids.size()); ++pep_idx)
581585
{
@@ -589,6 +593,23 @@ class TOPPIsobaricWorkflow :
589593
std::vector<std::pair<double,unsigned>> channel_qc(quant_method->getNumberOfChannels(), std::make_pair(std::numeric_limits<double>::quiet_NaN(), 0));
590594

591595
auto [quant_spec_idx, id_spec_idx, ms1_spec_idx] = getSpecIdxs_(ms2spec_it->second, exp, has_ms3);
596+
597+
// Check if MS3 spectrum is missing for MS2 spectrum
598+
if (has_ms3 && quant_spec_idx == -1)
599+
{
600+
// Store peptide ID with file association for unassigned IDs
601+
PeptideIdentification unassigned_pep = pep;
602+
unassigned_pep.setIdentifier(ID_RUN_NAME_);
603+
unassigned_pep.setMetaValue(Constants::UserParam::ID_MERGE_INDEX, i);
604+
#pragma omp critical(unassigned_pep_ids_collection)
605+
{
606+
OpenMS_Log_warn << "MS2 spectrum " << spec_ref << " at index " << ms2spec_it->second
607+
<< " does not have a corresponding MS3 spectrum. Skipping quantification and adding to unassigned.\n";
608+
unassigned_pep_ids.push_back(std::move(unassigned_pep));
609+
}
610+
continue;
611+
}
612+
592613
auto [quant_purity, id_purity] = getPurities_(quant_spec_idx, id_spec_idx, ms1_spec_idx, exp, has_ms3, max_precursor_isotope_deviation, calc_id_purity, interpolate_precursor_purity);
593614

594615
if (has_ms3 && exp[quant_spec_idx].getMSLevel() != 3)
@@ -628,6 +649,17 @@ class TOPPIsobaricWorkflow :
628649
}
629650
channel_extractor.printStatsWithMissing(qc);
630651

652+
// Add peptide IDs without MS3 spectra to unassigned IDs
653+
if (!unassigned_pep_ids.empty())
654+
{
655+
OPENMS_LOG_INFO << "Adding " << unassigned_pep_ids.size()
656+
<< " peptide identifications without MS3 spectra to unassigned IDs." << std::endl;
657+
auto& cmap_unassigned = cmap.getUnassignedPeptideIdentifications();
658+
cmap_unassigned.insert(cmap_unassigned.end(),
659+
std::make_move_iterator(unassigned_pep_ids.begin()),
660+
std::make_move_iterator(unassigned_pep_ids.end()));
661+
}
662+
631663
// TODO if we want to support normalization, we either need to replace the quantifier with corrector and normalizer separately
632664
// or init the normalizer from the quantifier settings.
633665
// But honestly, most downstream software can do it better, so I would not bother. Just export to mzTab and do it in R/python.

0 commit comments

Comments
 (0)