99from contextlib import closing
1010from multiprocessing import get_context
1111import multiprocessing .dummy as mp_dummy
12+ import sys
1213from .fdr import full_fdr
1314from .utils .column_preparation import prepare_columns
1415from .utils .knee_finder import find_knees
1516
1617logger = logging .getLogger (__name__ )
1718
19+ def is_gil_enabled ():
20+ if hasattr (sys , "_is_gil_enabled" ):
21+ return sys ._is_gil_enabled ()
22+ return True
23+
1824def boost (df : pl .DataFrame ,
1925 csm_fdr : (float , float ) = (0.0 , 1.0 ),
2026 pep_fdr : (float , float ) = (0.0 , 1.0 ),
@@ -26,6 +32,7 @@ def boost(df: pl.DataFrame,
2632 boost_level : str = "ppi" ,
2733 boost_between : bool = True ,
2834 method : str = "manhattan" ,
35+ decoy_adjunct : str = "REV_" ,
2936 countdown : int = 3 ,
3037 points : int = 10 ,
3138 n_jobs : int = - 1 ,
@@ -84,6 +91,7 @@ def boost(df: pl.DataFrame,
8491 neg_boost_cols = neg_boost_cols ,
8592 boost_level = boost_level ,
8693 boost_between = boost_between ,
94+ decoy_adjunct = decoy_adjunct ,
8795 countdown = countdown ,
8896 points = points ,
8997 n_jobs = n_jobs ,
@@ -102,11 +110,50 @@ def boost_manhattan(df: pl.DataFrame,
102110 neg_boost_cols : list = None ,
103111 boost_level : str = "ppi" ,
104112 boost_between : bool = True ,
113+ decoy_adjunct : str = "REV_" ,
105114 countdown : int = 3 ,
106115 points : int = 10 ,
107116 n_jobs : int = - 1 ,
108117 ** kwargs ):
109- df = prepare_columns (df )
118+ """
119+ Core Entry point for Manhattan optimization of FDR.
120+
121+ Parameters
122+ ----------
123+ df
124+ Input CSM/PSM dataframe
125+ csm_fdr
126+ Range of CSM-level FDR cutoffs
127+ pep_fdr
128+ Range of peptide-level FDR cutoffs
129+ prot_fdr
130+ Range of protein-level FDR cutoffs
131+ link_fdr
132+ Range of link-level FDR cutoffs
133+ ppi_fdr
134+ Range of protein pair level (PPI) FDR cutoffs
135+ boost_cols
136+ Columns where a HIGHER value is better (e.g. scores)
137+ neg_boost_cols
138+ Columns where a LOWER value is better (e.g. Mass Error)
139+ boost_level
140+ The FDR level to optimize for ('csm', 'pep', 'prot', 'link', 'ppi')
141+ boost_between
142+ Optimize only for between-protein links
143+ countdown
144+ Number of iterations without improvement before stopping
145+ points
146+ Grid points for Manhattan search
147+ n_jobs
148+ Number of parallel jobs. -1 for all available cores or automatic detection based on memory.
149+ kwargs
150+ Other parameters to be passed to `full_fdr`
151+
152+ Returns
153+ -------
154+ Best parameters found for the optimization
155+ """
156+ df = prepare_columns (df , decoy_adjunct = decoy_adjunct )
110157 param_ranges = (
111158 csm_fdr ,
112159 pep_fdr ,
@@ -127,8 +174,11 @@ def boost_manhattan(df: pl.DataFrame,
127174 best_params += [maxi ]
128175
129176 # Figure out knee points for starting
130- df = prepare_columns (df )
131- knee_points = find_knees (df .filter (pl .col ('fdr_group' ) == 'between' ), ** kwargs )
177+ knee_points = find_knees (
178+ df .filter (pl .col ('fdr_group' ) == 'between' ),
179+ decoy_adjunct = decoy_adjunct ,
180+ ** kwargs
181+ )
132182 for i , p in enumerate (knee_points ):
133183 best_params [i ] = p
134184 # Clip to param max
@@ -161,6 +211,7 @@ def boost_manhattan(df: pl.DataFrame,
161211 neg_boost_cols = neg_boost_cols ,
162212 boost_level = boost_level ,
163213 boost_between = boost_between ,
214+ decoy_adjunct = decoy_adjunct ,
164215 ** kwargs
165216 )
166217
@@ -173,11 +224,16 @@ def boost_manhattan(df: pl.DataFrame,
173224 n_jobs = max (max_mem_cpu , 1 )
174225 n_jobs = min (n_jobs , os .cpu_count ())
175226 logger .info (f"Using { n_jobs } CPUs based on available memory." )
176- if n_jobs == 1 :
177- mp = mp_dummy
227+ if not is_gil_enabled ():
228+ logger .info (f"Using { n_jobs } threads (GIL disabled)." )
229+ pool_obj = mp_dummy .Pool (n_jobs )
230+ elif n_jobs == 1 :
231+ pool_obj = mp_dummy .Pool (1 )
178232 else :
179- mp = get_context ('spawn' )
180- with closing (mp .Pool (n_jobs )) as pool :
233+ # spawn is the only method that reliably works across all OSs with PyInstaller
234+ pool_obj = get_context ('spawn' ).Pool (processes = n_jobs )
235+
236+ with closing (pool_obj ) as pool :
181237 while True :
182238 grids = []
183239 for param_index in range (n_params ):
@@ -255,6 +311,7 @@ def boost_manhattan(df: pl.DataFrame,
255311
256312def _optimization_template (cutoffs ,
257313 df : pl .DataFrame ,
314+ decoy_adjunct : str = 'REV_' ,
258315 min_len : int = 5 ,
259316 unique_csm : bool = True ,
260317 boost_cols : list = [],
@@ -263,7 +320,45 @@ def _optimization_template(cutoffs,
263320 boost_between : bool = True ,
264321 td_prob : int = 2 ,
265322 td_prot_prob : int = 10 ,
266- td_dd_ratio : float = 1.0 ) -> float :
323+ td_dd_ratio : float = 1.0 ,
324+ custom_aggs : dict = None ) -> float :
325+ """
326+ Template for parallel optimization and calculation of the score.
327+
328+ Parameters
329+ ----------
330+ cutoffs
331+ A list of cutoffs for the different levels
332+ df
333+ The input CSM dataframe
334+ decoy_adjunct
335+ The prefix/suffix for decoy proteins
336+ min_len
337+ Minimum peptide length
338+ unique_csm
339+ Unique CSM aggregation
340+ boost_cols
341+ Columns to filter for HIGHER values
342+ neg_boost_cols
343+ Columns to filter for LOWER values
344+ boost_level
345+ The level to optimize for
346+ boost_between
347+ Optimize for between links
348+ td_prob
349+ Minimum threshold for TT/TD counts (except protein)
350+ td_prot_prob
351+ Minimum threshold for TT/TD counts on protein level
352+ td_dd_ratio
353+ Minimum ratio for matching DD/TD
354+ custom_aggs
355+ Custom aggregation expressions for the FDR levels
356+
357+ Returns
358+ -------
359+ Resulting score (negative estimated true positives)
360+ """
361+ df_height = df .height
267362 fdrs = cutoffs [:5 ]
268363 col_levels = cutoffs [5 :]
269364 neg_col_levels = col_levels [len (boost_cols ):]
@@ -285,12 +380,14 @@ def _optimization_template(cutoffs,
285380 )
286381 result_all = full_fdr (
287382 df , * fdrs ,
383+ decoy_adjunct = decoy_adjunct ,
288384 min_len = min_len ,
289385 unique_csm = unique_csm ,
290386 prepare_column = False ,
291387 td_prob = 0 ,
292388 td_prot_prob = td_prot_prob ,
293- td_dd_ratio = 0
389+ td_dd_ratio = 0 ,
390+ custom_aggs = custom_aggs
294391 )
295392 result = result_all [boost_level ]
296393 if boost_between :
@@ -316,6 +413,6 @@ def _optimization_template(cutoffs,
316413 td_prob_bad = gl_tt * cutoffs [li ] < td_prob
317414 dd_prob_bad = gl_dd * td_dd_ratio > gl_td
318415 if td_prob_bad or dd_prob_bad :
319- return - tp / df . height
416+ return - tp / df_height
320417
321418 return - tp
0 commit comments