IsoSpecPy 2.4.0__tar.gz → 2.6.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.
- isospecpy-2.6.0/PKG-INFO +269 -0
- isospecpy-2.6.0/README.md +239 -0
- isospecpy-2.6.0/VERSION +1 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/pyproject.toml +19 -2
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/aligned_ptr.h +77 -11
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/allocator.h +8 -1
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/btrd.h +4 -4
- isospecpy-2.6.0/src/IsoSpec++/composition.cpp +85 -0
- isospecpy-2.6.0/src/IsoSpec++/composition.h +135 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/cwrapper.cpp +222 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/cwrapper.h +68 -1
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/dirtyAllocator.h +2 -1
- isospecpy-2.6.0/src/IsoSpec++/element_lookup.cpp +100 -0
- isospecpy-2.6.0/src/IsoSpec++/element_lookup.h +36 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/element_tables.cpp +10 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/element_tables.h +1 -1
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/fasta.cpp +28 -1
- isospecpy-2.6.0/src/IsoSpec++/fasta.h +120 -0
- isospecpy-2.6.0/src/IsoSpec++/fasta_mods.cpp +276 -0
- isospecpy-2.6.0/src/IsoSpec++/fasta_mods.h +77 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/fixedEnvelopes.cpp +638 -239
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/fixedEnvelopes.h +25 -9
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_dispatch.cpp +90 -32
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernel_impl.h +17 -6
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernels.h +11 -2
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/isoMath.cpp +71 -13
- isospecpy-2.6.0/src/IsoSpec++/isoMath.h +189 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/isoSpec++.cpp +302 -144
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/isoSpec++.h +250 -34
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/marginalTrek++.cpp +142 -54
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/marginalTrek++.h +37 -26
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/misc.cpp +2 -7
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/misc.h +4 -1
- isospecpy-2.6.0/src/IsoSpec++/operators.h +64 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/platform.h +15 -1
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/pod_vector.h +3 -4
- isospecpy-2.4.0/src/IsoSpec++/operators.cpp → isospecpy-2.6.0/src/IsoSpec++/python-build.cpp +17 -18
- isospecpy-2.6.0/src/IsoSpec++/unimod.cpp +179 -0
- isospecpy-2.6.0/src/IsoSpec++/unimod.h +79 -0
- isospecpy-2.6.0/src/IsoSpec++/unimod_support.h +2169 -0
- isospecpy-2.6.0/src/IsoSpec++/unimod_table_data.h +1027 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/unity-build.cpp +4 -1
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/IsoSpecPy.py +320 -76
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/PeriodicTbl.py +17 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/approximations.py +2 -2
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/isoFFI.py +55 -16
- isospecpy-2.4.0/PKG-INFO +0 -159
- isospecpy-2.4.0/README.md +0 -137
- isospecpy-2.4.0/VERSION +0 -1
- isospecpy-2.4.0/src/IsoSpec++/fasta.h +0 -70
- isospecpy-2.4.0/src/IsoSpec++/isoMath.h +0 -107
- isospecpy-2.4.0/src/IsoSpec++/operators.h +0 -150
- isospecpy-2.4.0/src/IsoSpec++/python-build.cpp +0 -23
- {isospecpy-2.4.0 → isospecpy-2.6.0}/LICENCE +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/skbuild/CMakeLists.txt +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/IsaDispatch.cmake +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/allocator.cpp +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/conf.h +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/dirtyAllocator.cpp +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernels_avx.cpp +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernels_baseline.cpp +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernels_v3.cpp +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernels_v4.cpp +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/iso_simd.h +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/mman.cpp +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/mman.h +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/platform_incl.h +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpec++/summator.h +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/Advanced.py +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/Distributions.py +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/Formulas.py +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/IsoSpecPyOld.py +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/__init__.py +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/__main__.py +0 -0
- {isospecpy-2.4.0 → isospecpy-2.6.0}/src/IsoSpecPy/confs_passthrough.py +0 -0
isospecpy-2.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: IsoSpecPy
|
|
3
|
+
Version: 2.6.0
|
|
4
|
+
Summary: IsoSpecPy is a Python library for computing isotopic distributions of molecules.
|
|
5
|
+
Keywords: isotopic distribution,mass spectrometry,chemistry,isotopic envelope,isotopologues
|
|
6
|
+
Author: Michał Startek, Mateusz Łącki
|
|
7
|
+
License-Expression: BSD-2-Clause
|
|
8
|
+
License-File: LICENCE
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Project-URL: Homepage, https://github.com/MatteoLacki/IsoSpec
|
|
23
|
+
Project-URL: Repository, https://github.com/MatteoLacki/IsoSpec
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Requires-Dist: cffi
|
|
26
|
+
Provides-Extra: testing
|
|
27
|
+
Requires-Dist: pytest; extra == "testing"
|
|
28
|
+
Requires-Dist: OldIsoSpecPy; extra == "testing"
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# IsoSpec
|
|
32
|
+
|
|
33
|
+
IsoSpec is a fine-structure isotopic distribution calculator for chemical formulas — given a molecule, it computes the masses and probabilities of its isotopologues. It is fast enough to handle large molecules (proteins, oligonucleotides) where the full distribution has astronomically many configurations, and it returns provably-optimal subsets that cover a chosen fraction of the total probability mass.
|
|
34
|
+
|
|
35
|
+
IsoSpec is primarily used as a library by mass spectrometry software. It is implemented in C++ (`src/IsoSpec++/`) and shipped with first-class bindings for Python (`IsoSpecPy`, on PyPI), R (`IsoSpecR`, on CRAN) and Rust (`isospec`, the crate in `rust/`).
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
### Python
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install IsoSpecPy
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The wheel bundles the C++ library — no separate native install required. Compatible with CPython and PyPy on Linux, macOS, Windows, and Cygwin/MinGW. Python ≥ 3.9.
|
|
46
|
+
|
|
47
|
+
To build from source: `pip install .` from a checkout. A C++20 compiler is required.
|
|
48
|
+
|
|
49
|
+
### R
|
|
50
|
+
|
|
51
|
+
```r
|
|
52
|
+
install.packages("IsoSpecR")
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
From source: `cd src && R CMD build IsoSpecR && R CMD INSTALL IsoSpecR_*.tar.gz`.
|
|
56
|
+
|
|
57
|
+
### Rust
|
|
58
|
+
|
|
59
|
+
```toml
|
|
60
|
+
[dependencies]
|
|
61
|
+
isospec = "0.1"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The build script compiles the bundled C++ library; a C++20 compiler is all that is needed. See `rust/README.md`.
|
|
65
|
+
|
|
66
|
+
### C++ library
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cd src/IsoSpec++
|
|
70
|
+
make # produces libIsoSpec++.so
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Or via CMake from the repo root:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cmake -B build -DCMAKE_BUILD_TYPE=Release
|
|
77
|
+
cmake --build build
|
|
78
|
+
sudo cmake --install build
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Requires a C++20 compiler. CMake produces both shared and static libraries and installs headers under `${CMAKE_INSTALL_INCLUDEDIR}/IsoSpec++`.
|
|
82
|
+
|
|
83
|
+
## Quick start
|
|
84
|
+
|
|
85
|
+
The most common usage is `IsoTotalProb`: ask for the smallest set of isotopologues whose summed probability covers a chosen fraction of the spectrum (typically 0.99–0.9999). The result is a materialized envelope — arrays of masses and probabilities you can read directly.
|
|
86
|
+
|
|
87
|
+
### Python
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import IsoSpecPy
|
|
91
|
+
|
|
92
|
+
# Isotopologues covering at least 99.9% of the probability mass of water.
|
|
93
|
+
iso = IsoSpecPy.IsoTotalProb(formula="H2O1", prob_to_cover=0.999)
|
|
94
|
+
|
|
95
|
+
for mass, prob in zip(iso.masses, iso.probs):
|
|
96
|
+
print(mass, prob)
|
|
97
|
+
|
|
98
|
+
# From an amino-acid sequence:
|
|
99
|
+
iso = IsoSpecPy.IsoTotalProb(peptide_sequence="AAAPPGQAAC", prob_to_cover=0.999)
|
|
100
|
+
print(list(zip(iso.masses, iso.probs)))
|
|
101
|
+
|
|
102
|
+
# ...optionally carrying [UNIMOD:<id>] modification tags (the notation this
|
|
103
|
+
# monorepo's SAGE search-engine fork writes: [UNIMOD:<id>]-SEQUENCE prefix
|
|
104
|
+
# for an N-terminal mod, X[UNIMOD:<id>] inline for an internal one,
|
|
105
|
+
# SEQUENCE-[UNIMOD:<id>] suffix for a C-terminal one):
|
|
106
|
+
iso = IsoSpecPy.IsoTotalProb(peptide_sequence="PEPTC[UNIMOD:4]DEK", prob_to_cover=0.999)
|
|
107
|
+
print(list(zip(iso.masses, iso.probs)))
|
|
108
|
+
|
|
109
|
+
# Mind the water: peptide_sequence= yields the *residue* composition, without
|
|
110
|
+
# the terminal H2O of a free peptide, so the masses above are 18.0106 Da
|
|
111
|
+
# lighter than the neutral molecule. Add it explicitly for the real peptide
|
|
112
|
+
# (the C++ Iso::FromFASTAWithMods below adds it by default -- the two APIs
|
|
113
|
+
# differ here, and this is the older Python behaviour kept for compatibility):
|
|
114
|
+
iso = IsoSpecPy.IsoTotalProb(peptide_sequence="PEPTC[UNIMOD:4]DEK", formula="H2O1",
|
|
115
|
+
prob_to_cover=0.999)
|
|
116
|
+
|
|
117
|
+
# Or get just the composition (element -> atom count), no envelope:
|
|
118
|
+
composition = IsoSpecPy.ParsePeptideSequence("PEPTC[UNIMOD:4]DEK")
|
|
119
|
+
print(dict(composition)) # {'H': 60, 'C': 39, 'N': 10, 'O': 16, 'S': 1}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Resolves against a table of ~980 Unimod entries embedded in the library (isotope-labelled and glycan/derivatization "brick" modifications are excluded -- they aren't representable as a pure elemental delta). Pass `unimod_db_path="/path/to/table.csv"` to either function to resolve against a different table instead (same `id,name,mono_mass,composition` CSV shape as the embedded default).
|
|
123
|
+
|
|
124
|
+
See `Examples/Python/` for radiolabelling, custom elements, binned spectra, and FASTA/Unimod modifications.
|
|
125
|
+
|
|
126
|
+
### C++
|
|
127
|
+
|
|
128
|
+
```cpp
|
|
129
|
+
#include "IsoSpec++/isoSpec++.h"
|
|
130
|
+
#include "IsoSpec++/fixedEnvelopes.h"
|
|
131
|
+
|
|
132
|
+
using namespace IsoSpec;
|
|
133
|
+
|
|
134
|
+
int main() {
|
|
135
|
+
FixedEnvelope iso = FixedEnvelope::FromTotalProb("H2O1", 0.999, true, true);
|
|
136
|
+
|
|
137
|
+
for (size_t i = 0; i < iso.confs_no(); ++i) {
|
|
138
|
+
std::cout << iso.mass(i) << '\t' << iso.prob(i) << '\n';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
From a peptide sequence, optionally carrying `[UNIMOD:<id>]` modification tags (`fasta_mods.h`; same notation as the Python/R examples above):
|
|
144
|
+
|
|
145
|
+
```cpp
|
|
146
|
+
#include "IsoSpec++/isoSpec++.h"
|
|
147
|
+
#include "IsoSpec++/fasta_mods.h"
|
|
148
|
+
#include "IsoSpec++/fixedEnvelopes.h"
|
|
149
|
+
|
|
150
|
+
using namespace IsoSpec;
|
|
151
|
+
|
|
152
|
+
int main() {
|
|
153
|
+
FixedEnvelope iso = FixedEnvelope::FromTotalProb(
|
|
154
|
+
Iso::FromFASTAWithMods("PEPTC[UNIMOD:4]DEK"), 0.999, true, true);
|
|
155
|
+
|
|
156
|
+
for (size_t i = 0; i < iso.confs_no(); ++i) {
|
|
157
|
+
std::cout << iso.mass(i) << '\t' << iso.prob(i) << '\n';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`Iso::FromFASTAWithMods` takes an optional trailing `unimod_db_path` argument to resolve against a different Unimod table instead of the one embedded at compile time. For just the composition, no envelope, call `parse_fasta_with_mods`/`parse_fasta_with_mods_full` directly (or the allocation-free `_into` forms, for a hot loop over many sequences) — see `fasta_mods.h`.
|
|
163
|
+
|
|
164
|
+
Quickest way to build:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
clang++ -std=c++20 water.cpp src/IsoSpec++/unity-build.cpp -o water
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
(`unity-build.cpp` is a single translation unit that `#include`s every source file — see `Examples/C++/COMPILING`.)
|
|
171
|
+
|
|
172
|
+
### Rust
|
|
173
|
+
|
|
174
|
+
```rust
|
|
175
|
+
use isospec::{Iso, PeptideOptions};
|
|
176
|
+
|
|
177
|
+
fn main() -> Result<(), isospec::Error> {
|
|
178
|
+
let iso = Iso::from_formula("H2O1")?;
|
|
179
|
+
for (mass, prob) in iso.envelope().total_prob(0.999)?.iter() {
|
|
180
|
+
println!("{mass}\t{prob}");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// A modified peptide; unlike Python's peptide_sequence=, the default
|
|
184
|
+
// here includes the terminal water.
|
|
185
|
+
let peptide = Iso::from_peptide("PEPTC[UNIMOD:4]DEK", &PeptideOptions::default())?;
|
|
186
|
+
println!("{}", peptide.monoisotopic_mass());
|
|
187
|
+
Ok(())
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
See `rust/examples/` for binned spectra, generators with configurations, and labelled elements.
|
|
192
|
+
|
|
193
|
+
### R
|
|
194
|
+
|
|
195
|
+
```r
|
|
196
|
+
library(IsoSpecR)
|
|
197
|
+
water <- c(H = 2, O = 1)
|
|
198
|
+
IsoSpecify(molecule = water, stopCondition = 0.999)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
`IsoSpecify` only ever takes a raw named-integer-vector `molecule` -- it has no sequence-string parameter -- so a `[UNIMOD:<id>]`-annotated peptide sequence takes two calls instead of one: `RParsePeptideSequence()` to resolve the sequence into a composition, then `IsoSpecify()` as above.
|
|
202
|
+
|
|
203
|
+
```r
|
|
204
|
+
composition <- RParsePeptideSequence("PEPTC[UNIMOD:4]DEK")
|
|
205
|
+
print(composition) # H C N O S
|
|
206
|
+
# 60 39 10 16 1
|
|
207
|
+
IsoSpecify(molecule = composition, stopCondition = 0.999)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Like the Python `ParsePeptideSequence`, this returns the residue composition without a free peptide's terminal H2O -- add `c(H = 2, O = 1)` to it for the neutral molecule. A modification whose delta removes more atoms of an element than the bare sequence provides gives a negative count (`"G[UNIMOD:11]"` nets `H -1`, `S -1`); `IsoSpecify` rejects such a vector rather than quietly dropping those elements.
|
|
211
|
+
|
|
212
|
+
The rest of the API takes the same named vector, and treats an envelope as what `IsoSpecify` returns, a matrix with columns `mass` and `prob`:
|
|
213
|
+
|
|
214
|
+
```r
|
|
215
|
+
insulin <- c(C = 254, H = 377, N = 65, O = 75, S = 6)
|
|
216
|
+
IsoProperties(insulin)$averageMass # also mono/lightest/heaviest/mode peaks, variance
|
|
217
|
+
IsoBinned(insulin, binWidth = 1) # unit-resolution distribution, computed directly
|
|
218
|
+
IsoStochastic(insulin, ionicCurrent = 1e4, seed = 1) # simulated, reproducible measurement
|
|
219
|
+
wassersteinDistance(IsoSpecify(insulin, 0.999), IsoSpecify(c(C = 254, H = 377, N = 65, O = 74, S = 7), 0.999))
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
with `envelopeConvolve`, `envelopeLinearCombination`, `envelopeBin` and `envelopeResample` for envelope arithmetic, and `orientedWassersteinDistance`, `abyssalWassersteinDistance` and `wassersteinMatch` beside `wassersteinDistance`.
|
|
223
|
+
|
|
224
|
+
See `Examples/R/` for radiolabelling, full-spectrum extraction, Unimod-annotated sequences, and binned, simulated and compared envelopes.
|
|
225
|
+
|
|
226
|
+
## Advanced features
|
|
227
|
+
|
|
228
|
+
- **Alternative algorithms** — for cases where `IsoTotalProb` isn't the right shape:
|
|
229
|
+
- `IsoThreshold` — all isotopologues with probability above a fixed threshold.
|
|
230
|
+
- `IsoStochastic` — simulate a measured spectrum by sampling integer ion counts.
|
|
231
|
+
- `IsoBinned` — histogram-style envelope at a chosen bin width.
|
|
232
|
+
- **FASTA/peptide-sequence support** — build an `Iso` directly from an amino-acid sequence, with `[UNIMOD:<id>]` modification tags recognized inline; optionally include the N/C-terminal water.
|
|
233
|
+
- **Custom isotopic tables** — override natural abundances per element (e.g. for radio- or stable-isotope labelling). See `Examples/*/radiolabelling.*`.
|
|
234
|
+
- **Fixed-envelope arithmetic** — addition, normalization, convolution, binning, resampling, Wasserstein distances.
|
|
235
|
+
- **Reproducible sampling** — stochastic envelopes and resampling take a seed (`seed=` in Python and R, `seeded_rng()` in C++, `with_seed` in Rust); a seed gives the same counts on every platform and in every binding.
|
|
236
|
+
- **Nominal-mass mode** — compute distributions over nucleon counts instead of real masses.
|
|
237
|
+
- **Thread safety** — the library never parallelises its own work, but independent molecules and envelopes may be used from any number of threads, and a shared molecule or envelope may be read from several at once.
|
|
238
|
+
- **Streaming generators (for performance)** — the tabulated functions above materialize the full envelope into arrays. For large molecules where that uses too much memory, or for pipelines that consume one configuration at a time (e.g. binning on the fly), use the generator classes instead: `IsoThresholdGenerator`, `IsoLayeredGenerator`, `IsoOrderedGenerator`, `IsoStochasticGenerator`. They yield one isotopologue per call to `advanceToNextConfiguration()` without ever storing the full set. `IsoOrderedGenerator` additionally streams in strict order of decreasing probability. Generators are in C++, Python and Rust; R has the materialized functions only.
|
|
239
|
+
|
|
240
|
+
Algorithmic details are in the papers cited below; the Supporting Information of each is the better starting point for implementation specifics.
|
|
241
|
+
|
|
242
|
+
## Repository layout
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
src/IsoSpec++/ C++ core library (the algorithms live here)
|
|
246
|
+
src/IsoSpecPy/ Python binding, loaded via cffi
|
|
247
|
+
src/IsoSpecR/ R binding, via Rcpp
|
|
248
|
+
rust/ Rust crate (Cargo.toml at the repository root), via cxx
|
|
249
|
+
Examples/ Working examples in each language
|
|
250
|
+
tests/ C, C++, and Python test suites (R's are in src/IsoSpecR/tests, Rust's in rust/tests)
|
|
251
|
+
skbuild/ scikit-build-core entry point used when installing the Python wheel
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Changes
|
|
255
|
+
|
|
256
|
+
`CHANGELOG` lists the major changes in each release (the Rust crate keeps its own, `rust/CHANGELOG.md`).
|
|
257
|
+
|
|
258
|
+
## Citation
|
|
259
|
+
|
|
260
|
+
If IsoSpec is useful in your research, please cite:
|
|
261
|
+
|
|
262
|
+
- Łącki, M. K.; Valkenborg, D.; Startek, M. P. *IsoSpec2: Ultrafast Fine Structure Calculator.* Analytical Chemistry **2020**, *92* (14), 9472–9475. <https://doi.org/10.1021/acs.analchem.0c00959>
|
|
263
|
+
- Łącki, M. K.; Startek, M.; Valkenborg, D.; Gambin, A. *IsoSpec: Hyperfast Fine Structure Calculator.* Analytical Chemistry **2017**, *89* (6), 3272–3277. <https://doi.org/10.1021/acs.analchem.6b01459>
|
|
264
|
+
|
|
265
|
+
The Supporting Information of each paper has the algorithmic detail.
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
2-clause BSD (see `LICENCE`). If you need different licensing terms, contact the authors. The authors appreciate (but do not require) being told when IsoSpec is used in other software.
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# IsoSpec
|
|
2
|
+
|
|
3
|
+
IsoSpec is a fine-structure isotopic distribution calculator for chemical formulas — given a molecule, it computes the masses and probabilities of its isotopologues. It is fast enough to handle large molecules (proteins, oligonucleotides) where the full distribution has astronomically many configurations, and it returns provably-optimal subsets that cover a chosen fraction of the total probability mass.
|
|
4
|
+
|
|
5
|
+
IsoSpec is primarily used as a library by mass spectrometry software. It is implemented in C++ (`src/IsoSpec++/`) and shipped with first-class bindings for Python (`IsoSpecPy`, on PyPI), R (`IsoSpecR`, on CRAN) and Rust (`isospec`, the crate in `rust/`).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
### Python
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install IsoSpecPy
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The wheel bundles the C++ library — no separate native install required. Compatible with CPython and PyPy on Linux, macOS, Windows, and Cygwin/MinGW. Python ≥ 3.9.
|
|
16
|
+
|
|
17
|
+
To build from source: `pip install .` from a checkout. A C++20 compiler is required.
|
|
18
|
+
|
|
19
|
+
### R
|
|
20
|
+
|
|
21
|
+
```r
|
|
22
|
+
install.packages("IsoSpecR")
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
From source: `cd src && R CMD build IsoSpecR && R CMD INSTALL IsoSpecR_*.tar.gz`.
|
|
26
|
+
|
|
27
|
+
### Rust
|
|
28
|
+
|
|
29
|
+
```toml
|
|
30
|
+
[dependencies]
|
|
31
|
+
isospec = "0.1"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The build script compiles the bundled C++ library; a C++20 compiler is all that is needed. See `rust/README.md`.
|
|
35
|
+
|
|
36
|
+
### C++ library
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd src/IsoSpec++
|
|
40
|
+
make # produces libIsoSpec++.so
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Or via CMake from the repo root:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
cmake -B build -DCMAKE_BUILD_TYPE=Release
|
|
47
|
+
cmake --build build
|
|
48
|
+
sudo cmake --install build
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Requires a C++20 compiler. CMake produces both shared and static libraries and installs headers under `${CMAKE_INSTALL_INCLUDEDIR}/IsoSpec++`.
|
|
52
|
+
|
|
53
|
+
## Quick start
|
|
54
|
+
|
|
55
|
+
The most common usage is `IsoTotalProb`: ask for the smallest set of isotopologues whose summed probability covers a chosen fraction of the spectrum (typically 0.99–0.9999). The result is a materialized envelope — arrays of masses and probabilities you can read directly.
|
|
56
|
+
|
|
57
|
+
### Python
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import IsoSpecPy
|
|
61
|
+
|
|
62
|
+
# Isotopologues covering at least 99.9% of the probability mass of water.
|
|
63
|
+
iso = IsoSpecPy.IsoTotalProb(formula="H2O1", prob_to_cover=0.999)
|
|
64
|
+
|
|
65
|
+
for mass, prob in zip(iso.masses, iso.probs):
|
|
66
|
+
print(mass, prob)
|
|
67
|
+
|
|
68
|
+
# From an amino-acid sequence:
|
|
69
|
+
iso = IsoSpecPy.IsoTotalProb(peptide_sequence="AAAPPGQAAC", prob_to_cover=0.999)
|
|
70
|
+
print(list(zip(iso.masses, iso.probs)))
|
|
71
|
+
|
|
72
|
+
# ...optionally carrying [UNIMOD:<id>] modification tags (the notation this
|
|
73
|
+
# monorepo's SAGE search-engine fork writes: [UNIMOD:<id>]-SEQUENCE prefix
|
|
74
|
+
# for an N-terminal mod, X[UNIMOD:<id>] inline for an internal one,
|
|
75
|
+
# SEQUENCE-[UNIMOD:<id>] suffix for a C-terminal one):
|
|
76
|
+
iso = IsoSpecPy.IsoTotalProb(peptide_sequence="PEPTC[UNIMOD:4]DEK", prob_to_cover=0.999)
|
|
77
|
+
print(list(zip(iso.masses, iso.probs)))
|
|
78
|
+
|
|
79
|
+
# Mind the water: peptide_sequence= yields the *residue* composition, without
|
|
80
|
+
# the terminal H2O of a free peptide, so the masses above are 18.0106 Da
|
|
81
|
+
# lighter than the neutral molecule. Add it explicitly for the real peptide
|
|
82
|
+
# (the C++ Iso::FromFASTAWithMods below adds it by default -- the two APIs
|
|
83
|
+
# differ here, and this is the older Python behaviour kept for compatibility):
|
|
84
|
+
iso = IsoSpecPy.IsoTotalProb(peptide_sequence="PEPTC[UNIMOD:4]DEK", formula="H2O1",
|
|
85
|
+
prob_to_cover=0.999)
|
|
86
|
+
|
|
87
|
+
# Or get just the composition (element -> atom count), no envelope:
|
|
88
|
+
composition = IsoSpecPy.ParsePeptideSequence("PEPTC[UNIMOD:4]DEK")
|
|
89
|
+
print(dict(composition)) # {'H': 60, 'C': 39, 'N': 10, 'O': 16, 'S': 1}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Resolves against a table of ~980 Unimod entries embedded in the library (isotope-labelled and glycan/derivatization "brick" modifications are excluded -- they aren't representable as a pure elemental delta). Pass `unimod_db_path="/path/to/table.csv"` to either function to resolve against a different table instead (same `id,name,mono_mass,composition` CSV shape as the embedded default).
|
|
93
|
+
|
|
94
|
+
See `Examples/Python/` for radiolabelling, custom elements, binned spectra, and FASTA/Unimod modifications.
|
|
95
|
+
|
|
96
|
+
### C++
|
|
97
|
+
|
|
98
|
+
```cpp
|
|
99
|
+
#include "IsoSpec++/isoSpec++.h"
|
|
100
|
+
#include "IsoSpec++/fixedEnvelopes.h"
|
|
101
|
+
|
|
102
|
+
using namespace IsoSpec;
|
|
103
|
+
|
|
104
|
+
int main() {
|
|
105
|
+
FixedEnvelope iso = FixedEnvelope::FromTotalProb("H2O1", 0.999, true, true);
|
|
106
|
+
|
|
107
|
+
for (size_t i = 0; i < iso.confs_no(); ++i) {
|
|
108
|
+
std::cout << iso.mass(i) << '\t' << iso.prob(i) << '\n';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
From a peptide sequence, optionally carrying `[UNIMOD:<id>]` modification tags (`fasta_mods.h`; same notation as the Python/R examples above):
|
|
114
|
+
|
|
115
|
+
```cpp
|
|
116
|
+
#include "IsoSpec++/isoSpec++.h"
|
|
117
|
+
#include "IsoSpec++/fasta_mods.h"
|
|
118
|
+
#include "IsoSpec++/fixedEnvelopes.h"
|
|
119
|
+
|
|
120
|
+
using namespace IsoSpec;
|
|
121
|
+
|
|
122
|
+
int main() {
|
|
123
|
+
FixedEnvelope iso = FixedEnvelope::FromTotalProb(
|
|
124
|
+
Iso::FromFASTAWithMods("PEPTC[UNIMOD:4]DEK"), 0.999, true, true);
|
|
125
|
+
|
|
126
|
+
for (size_t i = 0; i < iso.confs_no(); ++i) {
|
|
127
|
+
std::cout << iso.mass(i) << '\t' << iso.prob(i) << '\n';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`Iso::FromFASTAWithMods` takes an optional trailing `unimod_db_path` argument to resolve against a different Unimod table instead of the one embedded at compile time. For just the composition, no envelope, call `parse_fasta_with_mods`/`parse_fasta_with_mods_full` directly (or the allocation-free `_into` forms, for a hot loop over many sequences) — see `fasta_mods.h`.
|
|
133
|
+
|
|
134
|
+
Quickest way to build:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
clang++ -std=c++20 water.cpp src/IsoSpec++/unity-build.cpp -o water
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
(`unity-build.cpp` is a single translation unit that `#include`s every source file — see `Examples/C++/COMPILING`.)
|
|
141
|
+
|
|
142
|
+
### Rust
|
|
143
|
+
|
|
144
|
+
```rust
|
|
145
|
+
use isospec::{Iso, PeptideOptions};
|
|
146
|
+
|
|
147
|
+
fn main() -> Result<(), isospec::Error> {
|
|
148
|
+
let iso = Iso::from_formula("H2O1")?;
|
|
149
|
+
for (mass, prob) in iso.envelope().total_prob(0.999)?.iter() {
|
|
150
|
+
println!("{mass}\t{prob}");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// A modified peptide; unlike Python's peptide_sequence=, the default
|
|
154
|
+
// here includes the terminal water.
|
|
155
|
+
let peptide = Iso::from_peptide("PEPTC[UNIMOD:4]DEK", &PeptideOptions::default())?;
|
|
156
|
+
println!("{}", peptide.monoisotopic_mass());
|
|
157
|
+
Ok(())
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
See `rust/examples/` for binned spectra, generators with configurations, and labelled elements.
|
|
162
|
+
|
|
163
|
+
### R
|
|
164
|
+
|
|
165
|
+
```r
|
|
166
|
+
library(IsoSpecR)
|
|
167
|
+
water <- c(H = 2, O = 1)
|
|
168
|
+
IsoSpecify(molecule = water, stopCondition = 0.999)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`IsoSpecify` only ever takes a raw named-integer-vector `molecule` -- it has no sequence-string parameter -- so a `[UNIMOD:<id>]`-annotated peptide sequence takes two calls instead of one: `RParsePeptideSequence()` to resolve the sequence into a composition, then `IsoSpecify()` as above.
|
|
172
|
+
|
|
173
|
+
```r
|
|
174
|
+
composition <- RParsePeptideSequence("PEPTC[UNIMOD:4]DEK")
|
|
175
|
+
print(composition) # H C N O S
|
|
176
|
+
# 60 39 10 16 1
|
|
177
|
+
IsoSpecify(molecule = composition, stopCondition = 0.999)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Like the Python `ParsePeptideSequence`, this returns the residue composition without a free peptide's terminal H2O -- add `c(H = 2, O = 1)` to it for the neutral molecule. A modification whose delta removes more atoms of an element than the bare sequence provides gives a negative count (`"G[UNIMOD:11]"` nets `H -1`, `S -1`); `IsoSpecify` rejects such a vector rather than quietly dropping those elements.
|
|
181
|
+
|
|
182
|
+
The rest of the API takes the same named vector, and treats an envelope as what `IsoSpecify` returns, a matrix with columns `mass` and `prob`:
|
|
183
|
+
|
|
184
|
+
```r
|
|
185
|
+
insulin <- c(C = 254, H = 377, N = 65, O = 75, S = 6)
|
|
186
|
+
IsoProperties(insulin)$averageMass # also mono/lightest/heaviest/mode peaks, variance
|
|
187
|
+
IsoBinned(insulin, binWidth = 1) # unit-resolution distribution, computed directly
|
|
188
|
+
IsoStochastic(insulin, ionicCurrent = 1e4, seed = 1) # simulated, reproducible measurement
|
|
189
|
+
wassersteinDistance(IsoSpecify(insulin, 0.999), IsoSpecify(c(C = 254, H = 377, N = 65, O = 74, S = 7), 0.999))
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
with `envelopeConvolve`, `envelopeLinearCombination`, `envelopeBin` and `envelopeResample` for envelope arithmetic, and `orientedWassersteinDistance`, `abyssalWassersteinDistance` and `wassersteinMatch` beside `wassersteinDistance`.
|
|
193
|
+
|
|
194
|
+
See `Examples/R/` for radiolabelling, full-spectrum extraction, Unimod-annotated sequences, and binned, simulated and compared envelopes.
|
|
195
|
+
|
|
196
|
+
## Advanced features
|
|
197
|
+
|
|
198
|
+
- **Alternative algorithms** — for cases where `IsoTotalProb` isn't the right shape:
|
|
199
|
+
- `IsoThreshold` — all isotopologues with probability above a fixed threshold.
|
|
200
|
+
- `IsoStochastic` — simulate a measured spectrum by sampling integer ion counts.
|
|
201
|
+
- `IsoBinned` — histogram-style envelope at a chosen bin width.
|
|
202
|
+
- **FASTA/peptide-sequence support** — build an `Iso` directly from an amino-acid sequence, with `[UNIMOD:<id>]` modification tags recognized inline; optionally include the N/C-terminal water.
|
|
203
|
+
- **Custom isotopic tables** — override natural abundances per element (e.g. for radio- or stable-isotope labelling). See `Examples/*/radiolabelling.*`.
|
|
204
|
+
- **Fixed-envelope arithmetic** — addition, normalization, convolution, binning, resampling, Wasserstein distances.
|
|
205
|
+
- **Reproducible sampling** — stochastic envelopes and resampling take a seed (`seed=` in Python and R, `seeded_rng()` in C++, `with_seed` in Rust); a seed gives the same counts on every platform and in every binding.
|
|
206
|
+
- **Nominal-mass mode** — compute distributions over nucleon counts instead of real masses.
|
|
207
|
+
- **Thread safety** — the library never parallelises its own work, but independent molecules and envelopes may be used from any number of threads, and a shared molecule or envelope may be read from several at once.
|
|
208
|
+
- **Streaming generators (for performance)** — the tabulated functions above materialize the full envelope into arrays. For large molecules where that uses too much memory, or for pipelines that consume one configuration at a time (e.g. binning on the fly), use the generator classes instead: `IsoThresholdGenerator`, `IsoLayeredGenerator`, `IsoOrderedGenerator`, `IsoStochasticGenerator`. They yield one isotopologue per call to `advanceToNextConfiguration()` without ever storing the full set. `IsoOrderedGenerator` additionally streams in strict order of decreasing probability. Generators are in C++, Python and Rust; R has the materialized functions only.
|
|
209
|
+
|
|
210
|
+
Algorithmic details are in the papers cited below; the Supporting Information of each is the better starting point for implementation specifics.
|
|
211
|
+
|
|
212
|
+
## Repository layout
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
src/IsoSpec++/ C++ core library (the algorithms live here)
|
|
216
|
+
src/IsoSpecPy/ Python binding, loaded via cffi
|
|
217
|
+
src/IsoSpecR/ R binding, via Rcpp
|
|
218
|
+
rust/ Rust crate (Cargo.toml at the repository root), via cxx
|
|
219
|
+
Examples/ Working examples in each language
|
|
220
|
+
tests/ C, C++, and Python test suites (R's are in src/IsoSpecR/tests, Rust's in rust/tests)
|
|
221
|
+
skbuild/ scikit-build-core entry point used when installing the Python wheel
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Changes
|
|
225
|
+
|
|
226
|
+
`CHANGELOG` lists the major changes in each release (the Rust crate keeps its own, `rust/CHANGELOG.md`).
|
|
227
|
+
|
|
228
|
+
## Citation
|
|
229
|
+
|
|
230
|
+
If IsoSpec is useful in your research, please cite:
|
|
231
|
+
|
|
232
|
+
- Łącki, M. K.; Valkenborg, D.; Startek, M. P. *IsoSpec2: Ultrafast Fine Structure Calculator.* Analytical Chemistry **2020**, *92* (14), 9472–9475. <https://doi.org/10.1021/acs.analchem.0c00959>
|
|
233
|
+
- Łącki, M. K.; Startek, M.; Valkenborg, D.; Gambin, A. *IsoSpec: Hyperfast Fine Structure Calculator.* Analytical Chemistry **2017**, *89* (6), 3272–3277. <https://doi.org/10.1021/acs.analchem.6b01459>
|
|
234
|
+
|
|
235
|
+
The Supporting Information of each paper has the algorithmic detail.
|
|
236
|
+
|
|
237
|
+
## License
|
|
238
|
+
|
|
239
|
+
2-clause BSD (see `LICENCE`). If you need different licensing terms, contact the authors. The authors appreciate (but do not require) being told when IsoSpec is used in other software.
|
isospecpy-2.6.0/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.6.0
|
|
@@ -13,6 +13,15 @@ regex = "^\\s*(?P<value>[0-9]+(?:\\.[0-9]+)*)"
|
|
|
13
13
|
|
|
14
14
|
[tool.scikit-build]
|
|
15
15
|
cmake.source-dir = "skbuild"
|
|
16
|
+
# The compiled part is not a Python extension module: it is a plain C-ABI
|
|
17
|
+
# shared library that isoFFI.py dlopen()s through cffi's ABI mode, and it never
|
|
18
|
+
# includes Python.h or links libpython. So the wheel is tagged py3-none-<plat>
|
|
19
|
+
# rather than per-interpreter (cp3XX) or Stable ABI (abi3): one binary per
|
|
20
|
+
# platform serves every CPython -- free-threaded builds included, which abi3
|
|
21
|
+
# does not cover -- and PyPy too. cibuildwheel builds it once per platform and
|
|
22
|
+
# only *tests* it under each remaining interpreter. Should the library ever
|
|
23
|
+
# start using the CPython API, this must go back to per-interpreter tags.
|
|
24
|
+
wheel.py-api = "py3"
|
|
16
25
|
|
|
17
26
|
[project]
|
|
18
27
|
name = "IsoSpecPy"
|
|
@@ -23,10 +32,18 @@ license = "BSD-2-Clause"
|
|
|
23
32
|
license-files = ["LICENCE"]
|
|
24
33
|
authors = [{name = "Michał Startek"}, {name = "Mateusz Łącki"}]
|
|
25
34
|
readme = "README.md"
|
|
26
|
-
requires-python = ">=3.
|
|
35
|
+
requires-python = ">=3.9"
|
|
27
36
|
classifiers = [
|
|
28
37
|
"Programming Language :: Python :: 3",
|
|
29
|
-
"Programming Language :: Python :: 3.
|
|
38
|
+
"Programming Language :: Python :: 3.9",
|
|
39
|
+
"Programming Language :: Python :: 3.10",
|
|
40
|
+
"Programming Language :: Python :: 3.11",
|
|
41
|
+
"Programming Language :: Python :: 3.12",
|
|
42
|
+
"Programming Language :: Python :: 3.13",
|
|
43
|
+
"Programming Language :: Python :: 3.14",
|
|
44
|
+
"Programming Language :: Python :: 3.15",
|
|
45
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
46
|
+
"Programming Language :: Python :: Implementation :: PyPy",
|
|
30
47
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
31
48
|
"Development Status :: 5 - Production/Stable",
|
|
32
49
|
"Operating System :: OS Independent",
|