Skip to content

Commit 45142e0

Browse files
committed
Merge branch '254_induced_eic_associate_order' into 'dev'
Associate induced EICs before clearing gap-fill features (#254) See merge request mass-spectrometry/corems!238
2 parents f8cd527 + d903555 commit 45142e0

2 files changed

Lines changed: 67 additions & 16 deletions

File tree

corems/mass_spectra/calc/lc_calc.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5769,22 +5769,22 @@ def process_consensus_features(self, load_representatives=True, perform_gap_fill
57695769
eics_mz.append(None)
57705770
self.induced_mass_features_dataframe['_eic_mz'] = eics_mz
57715771

5772-
# Clear mass features from samples to free memory
5773-
for sample_name in self.samples:
5774-
self._lcms[sample_name].induced_mass_features = {}
5775-
5776-
# Associate EICs with mass features if they were loaded
5777-
# This must happen after all operations complete to work on the actual sample objects
5772+
# Associate EICs while induced feature objects still exist (before any clear).
5773+
# Must run after the pipeline so sample.eics is populated on the main process.
57785774
if gather_eics:
57795775
print("\nAssociating EICs with mass features:")
57805776
from tqdm import tqdm
5781-
5777+
57825778
for sample_id in tqdm(range(len(self.samples)), unit="sample", ncols=80):
57835779
sample = self[sample_id]
57845780
if sample.eics: # Only if EICs were loaded
5785-
# Associate EICs with regular mass features
57865781
sample.associate_eics_with_mass_features(induced=False)
5787-
# Associate EICs with induced mass features
57885782
sample.associate_eics_with_mass_features(induced=True)
5789-
5783+
5784+
# Drop induced feature objects to free memory. EICs remain on sample.eics
5785+
# (and _eic_mz on the induced dataframe) for plotting/lookup.
5786+
if perform_gap_filling:
5787+
for sample_name in self.samples:
5788+
self._lcms[sample_name].induced_mass_features = {}
5789+
57905790
return results

tests/test_lcms_collection.py

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -307,12 +307,63 @@ def test_lcms_collection_gap_filling(lcms_collection):
307307

308308
# Sample 3 should have induced features (started with 0, all 50 clusters are missing)
309309
assert sample_3_induced == 50, "Sample 3 should have 50 induced mass features (one for each cluster)"
310-
311-
# By design, individual sample objects should have empty induced_mass_features dict
312-
# because they are collected into the induced_mass_features_dataframe
313-
assert len(lcms_collection[0].induced_mass_features) == 0
314-
assert len(lcms_collection[1].induced_mass_features) == 0
315-
assert len(lcms_collection[2].induced_mass_features) == 0
310+
311+
# Induced feature *objects* are always cleared after gap-fill (memory).
312+
for i in range(len(lcms_collection)):
313+
assert len(lcms_collection[i].induced_mass_features) == 0, (
314+
f"Sample {i} should clear induced_mass_features after gap-fill"
315+
)
316+
317+
# EICs are separate: gap-fill + gather_eics leaves chromatograms on sample.eics
318+
# keyed by m/z (including induced feature m/z).
319+
sample3 = lcms_collection[2]
320+
assert sample3.eics is not None and len(sample3.eics) > 0, (
321+
"Sample 3 should retain EICs on sample.eics after gap-fill with gather_eics=True"
322+
)
323+
if "_eic_mz" in induced_df.columns:
324+
induced_mzs = induced_df.loc[induced_df["sample_id"] == 2, "_eic_mz"].dropna()
325+
assert len(induced_mzs) > 0
326+
# At least some induced m/z values should resolve in sample.eics
327+
from corems.mass_spectra.factory.lc_class import LCMSBase
328+
matched = 0
329+
for mz in induced_mzs:
330+
if mz in sample3.eics:
331+
matched += 1
332+
elif hasattr(sample3, "get_eic_mz_for_mass_feature"):
333+
key = sample3.get_eic_mz_for_mass_feature(float(mz))
334+
if key is not None:
335+
matched += 1
336+
assert matched > 0, (
337+
"Induced feature m/z values should be present in sample.eics after gap-fill"
338+
)
339+
340+
341+
def test_lcms_collection_gap_fill_clears_induced_without_gather_eics(lcms_collection):
342+
"""Without gather_eics, induced objects are still cleared after gap-fill."""
343+
lcms_collection = copy.deepcopy(lcms_collection)
344+
if not lcms_collection.rt_alignment_attempted:
345+
lcms_collection.align_lcms_objects()
346+
lcms_collection.add_consensus_mass_features()
347+
348+
lcms_collection.process_consensus_features(
349+
load_representatives=False,
350+
perform_gap_filling=True,
351+
add_ms1=False,
352+
add_ms2=False,
353+
molecular_formula_search=False,
354+
ms2_spectral_search=False,
355+
spectral_lib=False,
356+
molecular_metadata=None,
357+
gather_eics=False,
358+
keep_raw_data=False,
359+
)
360+
361+
assert lcms_collection.induced_mass_features_dataframe is not None
362+
assert len(lcms_collection.induced_mass_features_dataframe) > 0
363+
for i in range(len(lcms_collection)):
364+
assert len(lcms_collection[i].induced_mass_features) == 0, (
365+
f"Sample {i} should clear induced_mass_features after gap-fill"
366+
)
316367

317368

318369
def test_lcms_collection_pivot_table(lcms_collection):

0 commit comments

Comments
 (0)