Skip to content

Commit 407219f

Browse files
authored
Refactor Pipelines (#251)
1 parent 1bd400d commit 407219f

16 files changed

Lines changed: 1546 additions & 1267 deletions

main/como/combine_distributions.py

Lines changed: 90 additions & 66 deletions
Large diffs are not rendered by default.

main/como/create_context_specific_model.py

Lines changed: 453 additions & 319 deletions
Large diffs are not rendered by default.

main/como/data_types.py

Lines changed: 107 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
from dataclasses import dataclass, field, fields
55
from enum import Enum
66
from pathlib import Path
7-
from typing import ClassVar, NamedTuple
7+
from typing import ClassVar, NamedTuple, NotRequired, TypedDict
88

99
import cobra
10+
import numpy as np
11+
import numpy.typing as npt
1012
import pandas as pd
1113
from loguru import logger
1214

@@ -78,11 +80,6 @@ class SourceTypes(str, Enum):
7880
proteomics = "proteomics"
7981

8082

81-
class PeakIdentificationParameters(NamedTuple):
82-
height: float = 0.02
83-
distance: float = 1.0
84-
85-
8683
class CobraCompartments:
8784
"""Convert from compartment "long-hand" to "short-hand".
8885
@@ -135,7 +132,9 @@ class CobraCompartments:
135132
"s": ["eyespot", "eyespot apparatus", "stigma"],
136133
}
137134

138-
_REVERSE_LOOKUP: ClassVar[dict[str, list[str]]] = {value.lower(): key for key, values in SHORTHAND.items() for value in values}
135+
_REVERSE_LOOKUP: ClassVar[dict[str, list[str]]] = {
136+
value.lower(): key for key, values in SHORTHAND.items() for value in values
137+
}
139138

140139
@classmethod
141140
def get_shorthand(cls, longhand: str) -> str | None:
@@ -163,14 +162,6 @@ def get_longhand(cls, shorthand: str) -> str | None:
163162
return longhand[0] if longhand else None
164163

165164

166-
class _BuildResults(NamedTuple):
167-
"""Results of building a context specific model."""
168-
169-
model: cobra.Model
170-
expression_index_list: list[int]
171-
infeasible_reactions: pd.DataFrame
172-
173-
174165
class _BoundaryReactions(NamedTuple):
175166
"""Boundary reactions to be used in the context specific model."""
176167

@@ -269,3 +260,104 @@ class _SourceWeights(_BaseDataType):
269260
mrna: int
270261
scrna: int
271262
proteomics: int
263+
264+
265+
@dataclass
266+
class ModelBuildSettings:
267+
troppo_epsilon: float = 1e-4
268+
min_reaction_flux: float = 1e-7
269+
solver_timeout: int = 1800 # time in seconds, defaults to 30 minutes
270+
271+
"""
272+
Verbosity
273+
Type: int
274+
Default value: 0
275+
Range: [0, 3]
276+
From: https://docs.gurobi.com/projects/optimizer/en/current/reference/parameters.html#csclientlog
277+
"""
278+
solver_verbosity: int = 0
279+
280+
"""
281+
Feasibility
282+
Type: double
283+
Default value: 1e-6
284+
Range: [1e-9, 1e-2]
285+
From: https://docs.gurobi.com/projects/optimizer/en/current/reference/parameters.html#feasibilitytol
286+
"""
287+
solver_feasibility: float = 1e-6
288+
289+
"""
290+
OptimalityTol
291+
Type: double
292+
Default value: 1e-6
293+
Range: [1e-9, 1e-2]
294+
From: https://docs.gurobi.com/projects/optimizer/en/current/reference/parameters.html#optimalitytol
295+
"""
296+
solver_optimality: float = 1e-6
297+
298+
"""
299+
IntFeasTol
300+
Type: double
301+
Default value: 1e-5
302+
Range: [1e-9, 1e-1]
303+
From: https://docs.gurobi.com/projects/optimizer/en/current/reference/parameters.html#intfeastol
304+
"""
305+
solver_integrality: float = 1e-6
306+
307+
"""
308+
MIPGap
309+
Relative MIP optimality gap
310+
Default value: 1e-4
311+
Range: [0, inf)
312+
From: https://docs.gurobi.com/projects/optimizer/en/current/reference/parameters.html#mipgap
313+
"""
314+
gurobi_mipgap: float = 1e-4
315+
316+
"""
317+
IntegralityFocus
318+
Type: int
319+
Default value: 0
320+
Range: [0, 1]
321+
From: https://docs.gurobi.com/projects/optimizer/en/current/reference/parameters.html#integralityfocus
322+
"""
323+
gurobi_integrality_focus: int = 0
324+
325+
"""
326+
NumericFocus
327+
Type: int
328+
Default value: 0
329+
Range: [0, 3]
330+
From: https://docs.gurobi.com/projects/optimizer/en/current/reference/parameters.html#numericfocus
331+
"""
332+
gurobi_numeric_focus: int = 2
333+
334+
def __post_init__(self): # noqa: C901
335+
"""Validate provided arguments.
336+
337+
:raises: ValueError if any check fails.
338+
"""
339+
if self.troppo_epsilon < 0:
340+
raise ValueError("ModelBuildSettings: `troppo_epsilon` must be a non-negative float")
341+
if self.min_reaction_flux < 0:
342+
raise ValueError("ModelBuildSettings: `min_reaction_flux` must be a non-negative float")
343+
if self.solver_verbosity not in {0, 1, 2, 3} or not isinstance(self.solver_verbosity, int):
344+
raise ValueError("ModelBuildSettings: `solver_verbosity` must be an integer in the range [0, 3]")
345+
if self.solver_timeout < 0 or not isinstance(self.solver_timeout, int):
346+
raise ValueError("ModelBuildSettings: `solver_timeout` must be a non-negative integer")
347+
if not (1e-9 < self.solver_feasibility < 1e-2):
348+
raise ValueError("ModelBuildSettings: `solver_feasibility` must be a float in the range [1e-9, 1e-2]")
349+
if not (1e-9 < self.solver_optimality < 1e-2):
350+
raise ValueError("ModelBuildSettings: `solver_optimality` must be a float in the range [1e-9, 1e-2]")
351+
if not (1e-9 < self.solver_integrality < 1e-1):
352+
raise ValueError("ModelBuildSettings: `solver_integrality` must be a float in the range [1e-9, 1e-1]")
353+
if self.gurobi_mipgap < 0:
354+
raise ValueError("ModelBuildSettings: `gurobi_mipgap` must be a float in the range [1e-4, inf.)")
355+
if self.gurobi_integrality_focus not in {0, 1} or not isinstance(self.gurobi_integrality_focus, int):
356+
raise ValueError("ModelBuildSettings: `gurobi_integrality_focus` must be an integer in the range [0, 1]")
357+
if self.gurobi_numeric_focus not in {0, 1, 2, 3} or not isinstance(self.gurobi_numeric_focus, int):
358+
raise ValueError("ModelBuildSettings: `gurobi_numeric_focus` must be an integer in the range [0, 3]")
359+
if self.troppo_epsilon < self.min_reaction_flux * 1000:
360+
logger.warning(
361+
"ModelBuildSettings: `troppo_epsilon` and `min_reaction_flux` have similar values. "
362+
"This can cause inconsistent model builds. Consider ~1000x fold change between the two. "
363+
)

0 commit comments

Comments
 (0)