msdt 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of msdt might be problematic. Click here for more details.

msdt-1.0.0/MANIFEST.in ADDED
@@ -0,0 +1,2 @@
1
+ recursive-exclude models *
2
+ exclude msdt_models_v1.zip
msdt-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.4
2
+ Name: msdt
3
+ Version: 1.0.0
4
+ Summary: Multi-medium DT50 persistence prediction: DreaMS 1024-d embedding -> logDT50 interval, p(P)/p(vP) and P/vP decision across soil/sediment/water_ph7/water_ph9
5
+ Author: DT50 project
6
+ License: MIT
7
+ Project-URL: Homepage, https://pypi.org/project/msdt/
8
+ Keywords: DT50,half-life,DreaMS,mass-spectrometry,persistence,uncertainty
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: Microsoft :: Windows
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
13
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: numpy>=1.24
17
+ Requires-Dist: scipy>=1.13
18
+ Requires-Dist: torch>=2.0
19
+
20
+ # msdt — Multi-medium DT50 Persistence Predictor
21
+
22
+ Predict chemical biotransformation persistence from a DreaMS mass-spectrometry
23
+ embedding (1024-d) with four pre-trained heteroscedastic neural networks:
24
+
25
+ | medium | NLL (val) | R² | model |
26
+ |---|---|---|---|
27
+ | soil | -0.619 | 0.777 | two-stage, STAGE2 pure-NLL |
28
+ | sediment | -0.560 | 0.358 | bagging 0.8, 20-member ensemble |
29
+ | water_ph7 | 0.636 | 0.103 | 10-member ensemble, VAR_SCALE 1.16 |
30
+ | water_ph9 | -0.396 | 0.545 | single, β-NLL (β=0.70) |
31
+
32
+ For each medium and scenario (`prec` = precision-oriented 0.7, `rec` =
33
+ recall-oriented 0.7) it returns the predictive interval, persistence
34
+ probabilities `p(P)` (≥120 d) / `p(vP)` (≥180 d), and the P/vP decision made
35
+ with the corresponding best threshold (from 5-fold CV on the training set).
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pip install msdt
41
+ ```
42
+
43
+ > Note: `torch` is declared as a dependency; pip installs the PyPI build
44
+ > (CPU on Windows). For GPU inference, install the CUDA build first, e.g.
45
+ > `pip install torch --index-url https://download.pytorch.org/whl/cu126`.
46
+
47
+ ### Model weights (required)
48
+
49
+ Weights (~210 MB zip) are **not** bundled in the wheel. Download
50
+ `msdt_models_v1.zip`, extract it, and point `MSDT_MODELS_DIR` at the extracted
51
+ `models` directory:
52
+
53
+ ```bash
54
+ set MSDT_MODELS_DIR=D:\path\to\extracted\models # Windows
55
+ export MSDT_MODELS_DIR=/path/to/extracted/models # Linux
56
+ ```
57
+
58
+ Layout expected:
59
+
60
+ ```
61
+ models/
62
+ soil/model_final.pth
63
+ sediment/model_final.pth
64
+ water_ph7/model_final.pth
65
+ water_ph9/model_final.pth
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ ```python
71
+ import msdt
72
+
73
+ # Single compound
74
+ r = msdt.predict(medium="soil", scenario="prec", dreams=dreams_1024d)
75
+ print(r["interval_days"], r["p_P"], r["p_vP"], r["is_P"], r["is_vP"])
76
+
77
+ # Batch (N, 1024)
78
+ b = msdt.predict_batch(medium="water_ph7", scenario="rec", dreams=dreams_Nx1024)
79
+ ```
80
+
81
+ Parameters:
82
+
83
+ | parameter | values |
84
+ |---|---|
85
+ | `medium` | `"soil"` `"sediment"` `"water_ph7"` `"water_ph9"` |
86
+ | `scenario` | `"prec"` (precision ≥ 0.7, max recall) / `"rec"` (recall ≥ 0.7, max precision) |
87
+ | `dreams` | `(1024,)` or `(N, 1024)` float — raw DreaMS embedding, standardised internally |
88
+
89
+ ## Output
90
+
91
+ Single (`predict`) returns a dict; batch (`predict_batch`) returns the same
92
+ keys as arrays of length N (`interval_*` as `(N, 2)`):
93
+
94
+ | field | meaning |
95
+ |---|---|
96
+ | `mu_log10` / `sigma_latent_log10` | predictive mean / deployable σ (log10 days) |
97
+ | `interval_log10` / `interval_days` | 95% interval μ ± 1.96·σ_latent, log10 and days |
98
+ | `p_P` / `p_vP` | P(logDT50 ≥ 120 d) / P(logDT50 ≥ 180 d) |
99
+ | `threshold_P` / `threshold_vP` | best threshold for the chosen scenario |
100
+ | `is_P` / `is_vP` | `p ≥ threshold` → `True` (classified as P / vP) |
101
+
102
+ ## Thresholds (5-fold CV, training set)
103
+
104
+ | medium | P·prec | P·rec | vP·prec | vP·rec |
105
+ |---|---|---|---|---|
106
+ | soil | 0.118 | 0.132 | 0.020 | 0.006 |
107
+ | sediment | 0.237 | 0.048 | 0.055 | 0.014 |
108
+ | water_ph7 | 0.285 | 0.591 | 0.281 | 0.534 |
109
+ | water_ph9 | 0.429 | 0.381 | 0.414 | 0.321 |
110
+
111
+ ## References
112
+
113
+ - Salz et al., *Environ. Sci. Technol.* 2026 — DT50 with known label noise α
114
+ - Seitzer et al., ICLR 2022 — β-NLL
115
+ - Lakshminarayanan et al., NeurIPS 2017 — deep ensembles
116
+ - Cator et al., 2022 — bootstrapped deep ensembles
msdt-1.0.0/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # msdt — Multi-medium DT50 Persistence Predictor
2
+
3
+ Predict chemical biotransformation persistence from a DreaMS mass-spectrometry
4
+ embedding (1024-d) with four pre-trained heteroscedastic neural networks:
5
+
6
+ | medium | NLL (val) | R² | model |
7
+ |---|---|---|---|
8
+ | soil | -0.619 | 0.777 | two-stage, STAGE2 pure-NLL |
9
+ | sediment | -0.560 | 0.358 | bagging 0.8, 20-member ensemble |
10
+ | water_ph7 | 0.636 | 0.103 | 10-member ensemble, VAR_SCALE 1.16 |
11
+ | water_ph9 | -0.396 | 0.545 | single, β-NLL (β=0.70) |
12
+
13
+ For each medium and scenario (`prec` = precision-oriented 0.7, `rec` =
14
+ recall-oriented 0.7) it returns the predictive interval, persistence
15
+ probabilities `p(P)` (≥120 d) / `p(vP)` (≥180 d), and the P/vP decision made
16
+ with the corresponding best threshold (from 5-fold CV on the training set).
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install msdt
22
+ ```
23
+
24
+ > Note: `torch` is declared as a dependency; pip installs the PyPI build
25
+ > (CPU on Windows). For GPU inference, install the CUDA build first, e.g.
26
+ > `pip install torch --index-url https://download.pytorch.org/whl/cu126`.
27
+
28
+ ### Model weights (required)
29
+
30
+ Weights (~210 MB zip) are **not** bundled in the wheel. Download
31
+ `msdt_models_v1.zip`, extract it, and point `MSDT_MODELS_DIR` at the extracted
32
+ `models` directory:
33
+
34
+ ```bash
35
+ set MSDT_MODELS_DIR=D:\path\to\extracted\models # Windows
36
+ export MSDT_MODELS_DIR=/path/to/extracted/models # Linux
37
+ ```
38
+
39
+ Layout expected:
40
+
41
+ ```
42
+ models/
43
+ soil/model_final.pth
44
+ sediment/model_final.pth
45
+ water_ph7/model_final.pth
46
+ water_ph9/model_final.pth
47
+ ```
48
+
49
+ ## Usage
50
+
51
+ ```python
52
+ import msdt
53
+
54
+ # Single compound
55
+ r = msdt.predict(medium="soil", scenario="prec", dreams=dreams_1024d)
56
+ print(r["interval_days"], r["p_P"], r["p_vP"], r["is_P"], r["is_vP"])
57
+
58
+ # Batch (N, 1024)
59
+ b = msdt.predict_batch(medium="water_ph7", scenario="rec", dreams=dreams_Nx1024)
60
+ ```
61
+
62
+ Parameters:
63
+
64
+ | parameter | values |
65
+ |---|---|
66
+ | `medium` | `"soil"` `"sediment"` `"water_ph7"` `"water_ph9"` |
67
+ | `scenario` | `"prec"` (precision ≥ 0.7, max recall) / `"rec"` (recall ≥ 0.7, max precision) |
68
+ | `dreams` | `(1024,)` or `(N, 1024)` float — raw DreaMS embedding, standardised internally |
69
+
70
+ ## Output
71
+
72
+ Single (`predict`) returns a dict; batch (`predict_batch`) returns the same
73
+ keys as arrays of length N (`interval_*` as `(N, 2)`):
74
+
75
+ | field | meaning |
76
+ |---|---|
77
+ | `mu_log10` / `sigma_latent_log10` | predictive mean / deployable σ (log10 days) |
78
+ | `interval_log10` / `interval_days` | 95% interval μ ± 1.96·σ_latent, log10 and days |
79
+ | `p_P` / `p_vP` | P(logDT50 ≥ 120 d) / P(logDT50 ≥ 180 d) |
80
+ | `threshold_P` / `threshold_vP` | best threshold for the chosen scenario |
81
+ | `is_P` / `is_vP` | `p ≥ threshold` → `True` (classified as P / vP) |
82
+
83
+ ## Thresholds (5-fold CV, training set)
84
+
85
+ | medium | P·prec | P·rec | vP·prec | vP·rec |
86
+ |---|---|---|---|---|
87
+ | soil | 0.118 | 0.132 | 0.020 | 0.006 |
88
+ | sediment | 0.237 | 0.048 | 0.055 | 0.014 |
89
+ | water_ph7 | 0.285 | 0.591 | 0.281 | 0.534 |
90
+ | water_ph9 | 0.429 | 0.381 | 0.414 | 0.321 |
91
+
92
+ ## References
93
+
94
+ - Salz et al., *Environ. Sci. Technol.* 2026 — DT50 with known label noise α
95
+ - Seitzer et al., ICLR 2022 — β-NLL
96
+ - Lakshminarayanan et al., NeurIPS 2017 — deep ensembles
97
+ - Cator et al., 2022 — bootstrapped deep ensembles
@@ -0,0 +1,112 @@
1
+ """msdt - multi-medium DT50 persistence prediction library.
2
+
3
+ Combines the four medium-optimal heteroscedastic models
4
+ (soil / sediment / water_ph7 / water_ph9). Given a DreaMS mass-spectrometry
5
+ embedding (1024-d) it returns:
6
+ - predictive interval (mu +/- 1.96*sigma_latent, log10-days and days)
7
+ - persistence probabilities p(P) / p(vP) (120 d / 180 d thresholds)
8
+ - P / vP decisions made with the best threshold of the chosen scenario
9
+ (``prec`` = precision-oriented 0.7, ``rec`` = recall-oriented 0.7)
10
+
11
+ Usage:
12
+ import msdt
13
+ out = msdt.predict("soil", "prec", dreams_1024d, models_dir="D:/models")
14
+ outs = msdt.predict_batch("water_ph7", "rec", dreams_Nx1024, models_dir="D:/models")
15
+ """
16
+ from __future__ import annotations
17
+
18
+ from typing import Any, Dict, List, Optional, Union
19
+
20
+ import numpy as np
21
+
22
+ from .engine import (
23
+ MEDIUM_CFG,
24
+ MEDIUMS,
25
+ SCENARIOS,
26
+ get_engine,
27
+ validate_scenario,
28
+ _validate_vector,
29
+ )
30
+
31
+ __all__ = ["predict", "predict_batch", "MEDIUMS", "SCENARIOS"]
32
+ __version__ = "1.0.0"
33
+
34
+
35
+ def _single_result(medium: str, scenario: str, r: Dict[str, Any]) -> Dict[str, Any]:
36
+ return {
37
+ "medium": medium,
38
+ "scenario": scenario,
39
+ "mu_log10": float(r["mu_log10"][0]),
40
+ "sigma_latent_log10": float(r["sigma_latent_log10"][0]),
41
+ "interval_log10": [float(r["interval_log10"][0, 0]), float(r["interval_log10"][0, 1])],
42
+ "interval_days": [float(r["interval_days"][0, 0]), float(r["interval_days"][0, 1])],
43
+ "p_P": float(r["p_P"][0]),
44
+ "p_vP": float(r["p_vP"][0]),
45
+ "threshold_P": float(r["threshold_P"]),
46
+ "threshold_vP": float(r["threshold_vP"]),
47
+ "is_P": bool(r["is_P"][0]),
48
+ "is_vP": bool(r["is_vP"][0]),
49
+ }
50
+
51
+
52
+ def predict(
53
+ medium: str,
54
+ scenario: str,
55
+ dreams: Union[np.ndarray, List[float]],
56
+ models_dir: Optional[str] = None,
57
+ ) -> Dict[str, Any]:
58
+ """Predict for a single compound.
59
+
60
+ Args:
61
+ medium: "soil" | "sediment" | "water_ph7" | "water_ph9"
62
+ scenario: "prec" (precision >= 0.7, max recall) | "rec" (recall >= 0.7, max precision)
63
+ dreams: DreaMS embedding, shape (1024,)
64
+ models_dir: optional directory containing {medium}/model_final.pth;
65
+ overrides MSDT_MODELS_DIR
66
+
67
+ Returns:
68
+ dict with predictive interval, p(P)/p(vP), thresholds and P/vP decisions
69
+ """
70
+ medium = str(medium).lower().strip()
71
+ scenario = validate_scenario(scenario)
72
+ x = _validate_vector(dreams, batch=False)
73
+ r = get_engine(medium, models_dir).run(x, scenario)
74
+ return _single_result(medium, scenario, r)
75
+
76
+
77
+ def predict_batch(
78
+ medium: str,
79
+ scenario: str,
80
+ dreams: Union[np.ndarray, List[List[float]]],
81
+ models_dir: Optional[str] = None,
82
+ ) -> Dict[str, Any]:
83
+ """Predict for a batch of compounds.
84
+
85
+ Args:
86
+ medium: "soil" | "sediment" | "water_ph7" | "water_ph9"
87
+ scenario: "prec" | "rec"
88
+ dreams: DreaMS embedding matrix, shape (N, 1024)
89
+ models_dir: optional directory containing {medium}/model_final.pth
90
+
91
+ Returns:
92
+ dict; scalar fields become arrays of length N (interval_* are (N, 2))
93
+ """
94
+ medium = str(medium).lower().strip()
95
+ scenario = validate_scenario(scenario)
96
+ x = _validate_vector(dreams, batch=True)
97
+ r = get_engine(medium, models_dir).run(x, scenario)
98
+ return {
99
+ "medium": medium,
100
+ "scenario": scenario,
101
+ "n": int(len(x)),
102
+ "mu_log10": r["mu_log10"],
103
+ "sigma_latent_log10": r["sigma_latent_log10"],
104
+ "interval_log10": r["interval_log10"],
105
+ "interval_days": r["interval_days"],
106
+ "p_P": r["p_P"],
107
+ "p_vP": r["p_vP"],
108
+ "threshold_P": float(r["threshold_P"]),
109
+ "threshold_vP": float(r["threshold_vP"]),
110
+ "is_P": r["is_P"],
111
+ "is_vP": r["is_vP"],
112
+ }