IsoSpecPy 2.5.0__py3-none-win_arm64.whl
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/Advanced.py +32 -0
- IsoSpecPy/Distributions.py +93 -0
- IsoSpecPy/Formulas.py +71 -0
- IsoSpecPy/IsoSpec++/aligned_ptr.h +638 -0
- IsoSpecPy/IsoSpec++/allocator.h +69 -0
- IsoSpecPy/IsoSpec++/btrd.h +206 -0
- IsoSpecPy/IsoSpec++/composition.h +126 -0
- IsoSpecPy/IsoSpec++/conf.h +38 -0
- IsoSpecPy/IsoSpec++/cwrapper.h +271 -0
- IsoSpecPy/IsoSpec++/dirtyAllocator.h +58 -0
- IsoSpecPy/IsoSpec++/element_lookup.h +36 -0
- IsoSpecPy/IsoSpec++/element_tables.h +50 -0
- IsoSpecPy/IsoSpec++/fasta.h +70 -0
- IsoSpecPy/IsoSpec++/fasta_mods.h +70 -0
- IsoSpecPy/IsoSpec++/fixedEnvelopes.h +418 -0
- IsoSpecPy/IsoSpec++/isa_kernel_impl.h +192 -0
- IsoSpecPy/IsoSpec++/isa_kernels.h +172 -0
- IsoSpecPy/IsoSpec++/isoMath.h +121 -0
- IsoSpecPy/IsoSpec++/isoSpec++.h +801 -0
- IsoSpecPy/IsoSpec++/iso_simd.h +48 -0
- IsoSpecPy/IsoSpec++/marginalTrek++.h +614 -0
- IsoSpecPy/IsoSpec++/misc.h +229 -0
- IsoSpecPy/IsoSpec++/mman.h +67 -0
- IsoSpecPy/IsoSpec++/operators.h +150 -0
- IsoSpecPy/IsoSpec++/platform.h +180 -0
- IsoSpecPy/IsoSpec++/platform_incl.h +33 -0
- IsoSpecPy/IsoSpec++/pod_vector.h +400 -0
- IsoSpecPy/IsoSpec++/summator.h +118 -0
- IsoSpecPy/IsoSpec++/unimod.h +80 -0
- IsoSpecPy/IsoSpec++/unimod_support.h +2169 -0
- IsoSpecPy/IsoSpec++/unimod_table_data.h +1027 -0
- IsoSpecPy/IsoSpecPy.py +1088 -0
- IsoSpecPy/IsoSpecPyOld.py +290 -0
- IsoSpecPy/PeriodicTbl.py +51 -0
- IsoSpecPy/__init__.py +19 -0
- IsoSpecPy/__main__.py +25 -0
- IsoSpecPy/approximations.py +122 -0
- IsoSpecPy/confs_passthrough.py +16 -0
- IsoSpecPy/isoFFI.py +290 -0
- bin/IsoSpecCppPy.dll +0 -0
- isospecpy-2.5.0.dist-info/METADATA +220 -0
- isospecpy-2.5.0.dist-info/RECORD +45 -0
- isospecpy-2.5.0.dist-info/WHEEL +5 -0
- isospecpy-2.5.0.dist-info/licenses/LICENCE +35 -0
- lib/IsoSpecCppPy.lib +0 -0
IsoSpecPy/isoFFI.py
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import cffi
|
|
2
|
+
import platform
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class IsoFFI:
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self.ffi = cffi.FFI()
|
|
9
|
+
self.ffi.cdef(
|
|
10
|
+
"""
|
|
11
|
+
void * setupIso(int dimNumber,
|
|
12
|
+
const int* isotopeNumbers,
|
|
13
|
+
const int* atomCounts,
|
|
14
|
+
const double* isotopeMasses,
|
|
15
|
+
const double* isotopeProbabilities);
|
|
16
|
+
|
|
17
|
+
void * isoFromFasta(const char* fasta, bool use_nominal_masses, bool add_water);
|
|
18
|
+
|
|
19
|
+
double getLightestPeakMassIso(void* iso);
|
|
20
|
+
double getLightestPeakLProbIso(void* iso);
|
|
21
|
+
void getLightestPeakSignature(void* iso, int* space);
|
|
22
|
+
double getHeaviestPeakMassIso(void* iso);
|
|
23
|
+
double getHeaviestPeakLProbIso(void* iso);
|
|
24
|
+
void getHeaviestPeakSignature(void* iso, int* space);
|
|
25
|
+
double getMonoisotopicPeakMassIso(void* iso);
|
|
26
|
+
double getMonoisotopicPeakLProbIso(void* iso);
|
|
27
|
+
void getMonoisotopicPeakSignature(void* iso, int* space);
|
|
28
|
+
double getModeLProbIso(void* iso);
|
|
29
|
+
double getModeMassIso(void* iso);
|
|
30
|
+
double getTheoreticalAverageMassIso(void* iso);
|
|
31
|
+
double getIsoVariance(void* iso);
|
|
32
|
+
double getIsoStddev(void* iso);
|
|
33
|
+
double* getMarginalLogSizeEstimates(void* iso, double target_total_prob);
|
|
34
|
+
|
|
35
|
+
void deleteIso(void* iso);
|
|
36
|
+
|
|
37
|
+
void* setupIsoThresholdGenerator(void* iso,
|
|
38
|
+
double threshold,
|
|
39
|
+
bool _absolute,
|
|
40
|
+
int _tabSize,
|
|
41
|
+
int _hashSize,
|
|
42
|
+
bool reorder_marginals);
|
|
43
|
+
double massIsoThresholdGenerator(void* generator);
|
|
44
|
+
double lprobIsoThresholdGenerator(void* generator);
|
|
45
|
+
double probIsoThresholdGenerator(void* generator);
|
|
46
|
+
bool advanceToNextConfigurationIsoThresholdGenerator(void* generator);
|
|
47
|
+
void deleteIsoThresholdGenerator(void* generator);
|
|
48
|
+
void get_conf_signatureIsoThresholdGenerator(void* generator, int* space);
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
void* setupIsoLayeredGenerator(void* iso,
|
|
53
|
+
int _tabSize,
|
|
54
|
+
int _hashSize,
|
|
55
|
+
bool reorder_marginals,
|
|
56
|
+
double t_prob_hint);
|
|
57
|
+
double massIsoLayeredGenerator(void* generator);
|
|
58
|
+
double lprobIsoLayeredGenerator(void* generator);
|
|
59
|
+
double probIsoLayeredGenerator(void* generator);
|
|
60
|
+
bool advanceToNextConfigurationIsoLayeredGenerator(void* generator);
|
|
61
|
+
void deleteIsoLayeredGenerator(void* generator);
|
|
62
|
+
void get_conf_signatureIsoLayeredGenerator(void* generator, int* space);
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
void* setupIsoOrderedGenerator(void* iso,
|
|
66
|
+
int _tabSize,
|
|
67
|
+
int _hashSize);
|
|
68
|
+
double massIsoOrderedGenerator(void* generator);
|
|
69
|
+
double lprobIsoOrderedGenerator(void* generator);
|
|
70
|
+
double probIsoOrderedGenerator(void* generator);
|
|
71
|
+
bool advanceToNextConfigurationIsoOrderedGenerator(void* generator);
|
|
72
|
+
void deleteIsoOrderedGenerator(void* generator);
|
|
73
|
+
void get_conf_signatureIsoOrderedGenerator(void* generator, int* space);
|
|
74
|
+
|
|
75
|
+
void* setupIsoStochasticGenerator(void* iso,
|
|
76
|
+
size_t no_molecules,
|
|
77
|
+
double precision,
|
|
78
|
+
double beta_bias);
|
|
79
|
+
double massIsoStochasticGenerator(void* generator);
|
|
80
|
+
double lprobIsoStochasticGenerator(void* generator);
|
|
81
|
+
double probIsoStochasticGenerator(void* generator);
|
|
82
|
+
bool advanceToNextConfigurationIsoStochasticGenerator(void* generator);
|
|
83
|
+
void deleteIsoStochasticGenerator(void* generator);
|
|
84
|
+
void get_conf_signatureIsoStochasticGenerator(void* generator, int* space);
|
|
85
|
+
|
|
86
|
+
void* setupThresholdFixedEnvelope(void* iso,
|
|
87
|
+
double threshold,
|
|
88
|
+
bool absolute,
|
|
89
|
+
bool get_confs);
|
|
90
|
+
|
|
91
|
+
void* setupTotalProbFixedEnvelope(void* iso,
|
|
92
|
+
double taget_coverage,
|
|
93
|
+
bool optimize,
|
|
94
|
+
bool get_confs);
|
|
95
|
+
|
|
96
|
+
void* setupStochasticFixedEnvelope(void* iso,
|
|
97
|
+
size_t no_molecules,
|
|
98
|
+
double precision,
|
|
99
|
+
double beta_bias,
|
|
100
|
+
bool get_confs);
|
|
101
|
+
|
|
102
|
+
void* setupBinnedFixedEnvelope(void* iso,
|
|
103
|
+
double target_total_prob,
|
|
104
|
+
double bin_width,
|
|
105
|
+
double bin_middle);
|
|
106
|
+
|
|
107
|
+
void* setupFixedEnvelope(double* masses, double* probs, size_t size, bool mass_sorted, bool prob_sorted, double total_prob);
|
|
108
|
+
void* setupFixedEnvelopeWithConfs(double* masses, double* probs, int* confs, size_t size, int allDim, bool mass_sorted, bool prob_sorted, double total_prob);
|
|
109
|
+
void* copyFixedEnvelope(void* other);
|
|
110
|
+
void deleteFixedEnvelope(void* tabulator, bool releaseEverything);
|
|
111
|
+
|
|
112
|
+
const double* massesFixedEnvelope(void* tabulator);
|
|
113
|
+
const double* probsFixedEnvelope(void* tabulator);
|
|
114
|
+
const int* confsFixedEnvelope(void* tabulator);
|
|
115
|
+
size_t confs_noFixedEnvelope(void* tabulator);
|
|
116
|
+
|
|
117
|
+
typedef void (*IsoSpecArrayDeleter)(void* array, size_t size);
|
|
118
|
+
|
|
119
|
+
double* massesFixedEnvelopeWithDeleter(void* tabulator, size_t* size_out, IsoSpecArrayDeleter* deleter_out);
|
|
120
|
+
double* probsFixedEnvelopeWithDeleter(void* tabulator, size_t* size_out, IsoSpecArrayDeleter* deleter_out);
|
|
121
|
+
int* confsFixedEnvelopeWithDeleter(void* tabulator, size_t* size_out, IsoSpecArrayDeleter* deleter_out);
|
|
122
|
+
void freeReleasedArrayWithDeleter(void* array, size_t size, IsoSpecArrayDeleter deleter);
|
|
123
|
+
|
|
124
|
+
double empiricAverageMass(void* tabulator);
|
|
125
|
+
double empiricVariance(void* tabulator);
|
|
126
|
+
double empiricStddev(void* tabulator);
|
|
127
|
+
|
|
128
|
+
double wassersteinDistance(void* tabulator1, void* tabulator2);
|
|
129
|
+
double orientedWassersteinDistance(void* tabulator1, void* tabulator2);
|
|
130
|
+
double abyssalWassersteinDistance(void* tabulator1, void* tabulator2, double abyss_depth, double other_scale);
|
|
131
|
+
// double abyssalWassersteinDistanceGrad(void* const* envelopes, const double* scales, double* ret_gradient, size_t N, double abyss_depth_exp, double abyss_depth_the);
|
|
132
|
+
|
|
133
|
+
struct ws_match_res{
|
|
134
|
+
double res1;
|
|
135
|
+
double res2;
|
|
136
|
+
double flow;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
struct ws_match_res wassersteinMatch(void* tabulator1, void* tabulator2, double flow_dist, double other_scale);
|
|
140
|
+
|
|
141
|
+
void* addEnvelopes(void* tabulator1, void* tabulator2);
|
|
142
|
+
void* convolveEnvelopes(void* tabulator1, void* tabulator2);
|
|
143
|
+
|
|
144
|
+
double getTotalProbOfEnvelope(void* envelope);
|
|
145
|
+
void scaleEnvelope(void* envelope, double factor);
|
|
146
|
+
void normalizeEnvelope(void* envelope);
|
|
147
|
+
void shiftMassEnvelope(void* envelope, double d_mass);
|
|
148
|
+
void resampleEnvelope(void* envelope, size_t ionic_current, double beta_bias);
|
|
149
|
+
void* binnedEnvelope(void* envelope, double width, double middle);
|
|
150
|
+
void* linearCombination(void* const * const envelopes, const double* intensities, size_t count);
|
|
151
|
+
|
|
152
|
+
void sortEnvelopeByMass(void* envelope);
|
|
153
|
+
void sortEnvelopeByProb(void* envelope);
|
|
154
|
+
|
|
155
|
+
void freeReleasedArray(void* array);
|
|
156
|
+
void array_add(double* array, size_t N, double what);
|
|
157
|
+
void array_mul(double* array, size_t N, double what);
|
|
158
|
+
void array_fma(double* array, size_t N, double mul, double add);
|
|
159
|
+
|
|
160
|
+
void parse_fasta_c(const char* fasta, int atomCounts[6]);
|
|
161
|
+
|
|
162
|
+
void* isoFromFastaWithMods(const char* sequence, bool use_nominal_masses, bool add_water, const char* unimod_db_path);
|
|
163
|
+
void* parseFastaWithModsC(const char* sequence, const char* unimod_db_path);
|
|
164
|
+
size_t compositionSizeC(void* composition);
|
|
165
|
+
const char* const* compositionSymbolsC(void* composition);
|
|
166
|
+
const int* compositionCountsC(void* composition);
|
|
167
|
+
void deleteCompositionC(void* composition);
|
|
168
|
+
|
|
169
|
+
void* expandCompositionC(const char* const* symbols, const int* counts, size_t size, bool use_nominal_masses);
|
|
170
|
+
const int* expandedIsotopeNumbersC(void* expanded);
|
|
171
|
+
const int* expandedAtomCountsC(void* expanded);
|
|
172
|
+
const double* expandedIsotopeMassesC(void* expanded);
|
|
173
|
+
const double* expandedIsotopeProbabilitiesC(void* expanded);
|
|
174
|
+
void deleteExpandedCompositionC(void* expanded);
|
|
175
|
+
|
|
176
|
+
const char* activeSimdLevel(void);
|
|
177
|
+
|
|
178
|
+
// Must be kept in sync by hand with ISOSPEC_NUMBER_OF_ISOTOPIC_ENTRIES
|
|
179
|
+
// in element_tables.h -- see PeriodicTbl.py's comment on why this
|
|
180
|
+
// can't be read from isospec_number_of_isotopic_entries (the real
|
|
181
|
+
// compiled variable, right below) instead: cffi's dlopen ABI mode
|
|
182
|
+
// can't access plain extern const globals, only #define constants
|
|
183
|
+
// like this one. A stale value here silently drops table entries in
|
|
184
|
+
// Python without erroring (already happened once, #51/deuterium).
|
|
185
|
+
#define NUMBER_OF_ISOTOPIC_ENTRIES 293
|
|
186
|
+
extern const size_t isospec_number_of_isotopic_entries;
|
|
187
|
+
extern const int elem_table_atomicNo[NUMBER_OF_ISOTOPIC_ENTRIES];
|
|
188
|
+
extern const double elem_table_probability[NUMBER_OF_ISOTOPIC_ENTRIES];
|
|
189
|
+
extern const double elem_table_mass[NUMBER_OF_ISOTOPIC_ENTRIES];
|
|
190
|
+
extern const double elem_table_massNo[NUMBER_OF_ISOTOPIC_ENTRIES];
|
|
191
|
+
extern const int elem_table_extraNeutrons[NUMBER_OF_ISOTOPIC_ENTRIES];
|
|
192
|
+
extern const char* elem_table_element[NUMBER_OF_ISOTOPIC_ENTRIES];
|
|
193
|
+
extern const char* elem_table_symbol[NUMBER_OF_ISOTOPIC_ENTRIES];
|
|
194
|
+
extern const bool elem_table_Radioactive[NUMBER_OF_ISOTOPIC_ENTRIES];
|
|
195
|
+
"""
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
mod_dir = Path(__file__).resolve().parent
|
|
199
|
+
|
|
200
|
+
libnames = ["IsoSpecCppPy*", "IsoSpec++*"]
|
|
201
|
+
libprefix = ["", "lib", "Lib"]
|
|
202
|
+
extension = [".so", ".dylib", ".dll"]
|
|
203
|
+
try:
|
|
204
|
+
if platform.system() == "Linux":
|
|
205
|
+
extension = [".so", ".pyd"]
|
|
206
|
+
elif platform.system() == "Windows":
|
|
207
|
+
extension = [".dll", ".pyd"]
|
|
208
|
+
except:
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
prebuilt = ["", "prebuilt-"]
|
|
212
|
+
|
|
213
|
+
def cprod(ll1, ll2):
|
|
214
|
+
res = []
|
|
215
|
+
for l1 in ll1:
|
|
216
|
+
for l2 in ll2:
|
|
217
|
+
res.append(l1 + l2)
|
|
218
|
+
return res
|
|
219
|
+
|
|
220
|
+
paths_to_check = cprod(prebuilt, cprod(libprefix, cprod(libnames, extension)))
|
|
221
|
+
dpc = []
|
|
222
|
+
|
|
223
|
+
search_dirs = [
|
|
224
|
+
mod_dir,
|
|
225
|
+
mod_dir.parent,
|
|
226
|
+
mod_dir.parent / "bin",
|
|
227
|
+
mod_dir.parent / "lib",
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
# Editable installs (scikit-build-core) redirect this module's
|
|
231
|
+
# __file__ to the source tree, but build the compiled extension
|
|
232
|
+
# straight into the installed package's own site-packages
|
|
233
|
+
# directory instead -- mod_dir above never sees it. Search that
|
|
234
|
+
# directory too, when it isn't already mod_dir.
|
|
235
|
+
try:
|
|
236
|
+
import importlib.util
|
|
237
|
+
|
|
238
|
+
installed_pkg = importlib.util.find_spec("IsoSpecPy")
|
|
239
|
+
for loc in installed_pkg.submodule_search_locations or []:
|
|
240
|
+
loc = Path(loc)
|
|
241
|
+
if loc not in search_dirs:
|
|
242
|
+
search_dirs.append(loc)
|
|
243
|
+
except (ImportError, AttributeError, ValueError):
|
|
244
|
+
pass
|
|
245
|
+
|
|
246
|
+
for dirpath in search_dirs:
|
|
247
|
+
dpc.extend([dirpath / p for p in paths_to_check])
|
|
248
|
+
|
|
249
|
+
paths_to_check = dpc
|
|
250
|
+
# expand glob patterns using pathlib (keep only actual matches, like glob.glob did)
|
|
251
|
+
expanded = []
|
|
252
|
+
for p in paths_to_check:
|
|
253
|
+
expanded.extend(p.parent.glob(p.name))
|
|
254
|
+
paths_to_check = expanded
|
|
255
|
+
try:
|
|
256
|
+
import importlib
|
|
257
|
+
|
|
258
|
+
paths_to_check.insert(
|
|
259
|
+
0, Path(importlib.util.find_spec("IsoSpecCppPy").origin)
|
|
260
|
+
)
|
|
261
|
+
except (ImportError, AttributeError):
|
|
262
|
+
pass
|
|
263
|
+
|
|
264
|
+
errors = []
|
|
265
|
+
|
|
266
|
+
self.clib = None
|
|
267
|
+
for libpath in set(paths_to_check):
|
|
268
|
+
try:
|
|
269
|
+
self.clib = self.ffi.dlopen(str(libpath))
|
|
270
|
+
self.libpath = libpath
|
|
271
|
+
break
|
|
272
|
+
except (IndexError, OSError) as e:
|
|
273
|
+
errmsg = (
|
|
274
|
+
"Load libIsoSpec++.so, tried: "
|
|
275
|
+
+ str(libpath)
|
|
276
|
+
+ "\n"
|
|
277
|
+
+ "Got error: "
|
|
278
|
+
+ str(type(e))
|
|
279
|
+
+ ": "
|
|
280
|
+
+ str(e)
|
|
281
|
+
)
|
|
282
|
+
errors.append(errmsg)
|
|
283
|
+
|
|
284
|
+
if self.clib == None:
|
|
285
|
+
raise ImportError(
|
|
286
|
+
"Cannot find or load the C++ part of the library\n" + "\n".join(errors)
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
isoFFI = IsoFFI() # This is done while including the module
|
bin/IsoSpecCppPy.dll
ADDED
|
Binary file
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: IsoSpecPy
|
|
3
|
+
Version: 2.5.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) and R (`IsoSpecR`, on CRAN).
|
|
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
|
+
### C++ library
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cd src/IsoSpec++
|
|
61
|
+
make # produces libIsoSpec++.so
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Or via CMake from the repo root:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
cmake -B build -DCMAKE_BUILD_TYPE=Release
|
|
68
|
+
cmake --build build
|
|
69
|
+
sudo cmake --install build
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Requires a C++20 compiler. CMake produces both shared and static libraries and installs headers under `${CMAKE_INSTALL_INCLUDEDIR}/IsoSpec++`.
|
|
73
|
+
|
|
74
|
+
## Quick start
|
|
75
|
+
|
|
76
|
+
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.
|
|
77
|
+
|
|
78
|
+
### Python
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
import IsoSpecPy
|
|
82
|
+
|
|
83
|
+
# Isotopologues covering at least 99.9% of the probability mass of water.
|
|
84
|
+
iso = IsoSpecPy.IsoTotalProb(formula="H2O1", prob_to_cover=0.999)
|
|
85
|
+
|
|
86
|
+
for mass, prob in zip(iso.masses, iso.probs):
|
|
87
|
+
print(mass, prob)
|
|
88
|
+
|
|
89
|
+
# From an amino-acid sequence:
|
|
90
|
+
iso = IsoSpecPy.IsoTotalProb(peptide_sequence="AAAPPGQAAC", prob_to_cover=0.999)
|
|
91
|
+
print(list(zip(iso.masses, iso.probs)))
|
|
92
|
+
|
|
93
|
+
# ...optionally carrying [UNIMOD:<id>] modification tags (the notation this
|
|
94
|
+
# monorepo's SAGE search-engine fork writes: [UNIMOD:<id>]-SEQUENCE prefix
|
|
95
|
+
# for an N-terminal mod, X[UNIMOD:<id>] inline for an internal one,
|
|
96
|
+
# SEQUENCE-[UNIMOD:<id>] suffix for a C-terminal one):
|
|
97
|
+
iso = IsoSpecPy.IsoTotalProb(peptide_sequence="PEPTC[UNIMOD:4]DEK", prob_to_cover=0.999)
|
|
98
|
+
print(list(zip(iso.masses, iso.probs)))
|
|
99
|
+
|
|
100
|
+
# Mind the water: peptide_sequence= yields the *residue* composition, without
|
|
101
|
+
# the terminal H2O of a free peptide, so the masses above are 18.0106 Da
|
|
102
|
+
# lighter than the neutral molecule. Add it explicitly for the real peptide
|
|
103
|
+
# (the C++ Iso::FromFASTAWithMods below adds it by default -- the two APIs
|
|
104
|
+
# differ here, and this is the older Python behaviour kept for compatibility):
|
|
105
|
+
iso = IsoSpecPy.IsoTotalProb(peptide_sequence="PEPTC[UNIMOD:4]DEK", formula="H2O1",
|
|
106
|
+
prob_to_cover=0.999)
|
|
107
|
+
|
|
108
|
+
# Or get just the composition (element -> atom count), no envelope:
|
|
109
|
+
composition = IsoSpecPy.ParsePeptideSequence("PEPTC[UNIMOD:4]DEK")
|
|
110
|
+
print(dict(composition)) # {'H': 60, 'C': 39, 'N': 10, 'O': 16, 'S': 1}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
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).
|
|
114
|
+
|
|
115
|
+
See `Examples/Python/` for radiolabelling, custom elements, binned spectra, and FASTA/Unimod modifications.
|
|
116
|
+
|
|
117
|
+
### C++
|
|
118
|
+
|
|
119
|
+
```cpp
|
|
120
|
+
#include "IsoSpec++/isoSpec++.h"
|
|
121
|
+
#include "IsoSpec++/fixedEnvelopes.h"
|
|
122
|
+
|
|
123
|
+
using namespace IsoSpec;
|
|
124
|
+
|
|
125
|
+
int main() {
|
|
126
|
+
FixedEnvelope iso = FixedEnvelope::FromTotalProb("H2O1", 0.999, true, true);
|
|
127
|
+
|
|
128
|
+
for (size_t i = 0; i < iso.confs_no(); ++i) {
|
|
129
|
+
std::cout << iso.mass(i) << '\t' << iso.prob(i) << '\n';
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
From a peptide sequence, optionally carrying `[UNIMOD:<id>]` modification tags (`fasta_mods.h`; same notation as the Python/R examples above):
|
|
135
|
+
|
|
136
|
+
```cpp
|
|
137
|
+
#include "IsoSpec++/isoSpec++.h"
|
|
138
|
+
#include "IsoSpec++/fasta_mods.h"
|
|
139
|
+
#include "IsoSpec++/fixedEnvelopes.h"
|
|
140
|
+
|
|
141
|
+
using namespace IsoSpec;
|
|
142
|
+
|
|
143
|
+
int main() {
|
|
144
|
+
FixedEnvelope iso = FixedEnvelope::FromTotalProb(
|
|
145
|
+
Iso::FromFASTAWithMods("PEPTC[UNIMOD:4]DEK"), 0.999, true, true);
|
|
146
|
+
|
|
147
|
+
for (size_t i = 0; i < iso.confs_no(); ++i) {
|
|
148
|
+
std::cout << iso.mass(i) << '\t' << iso.prob(i) << '\n';
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`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`.
|
|
154
|
+
|
|
155
|
+
Quickest way to build:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
clang++ -std=c++20 water.cpp src/IsoSpec++/unity-build.cpp -o water
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
(`unity-build.cpp` is a single translation unit that `#include`s every source file — see `Examples/C++/COMPILING`.)
|
|
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
|
+
See `Examples/R/` for radiolabelling, full-spectrum extraction, and Unimod-annotated sequences.
|
|
183
|
+
|
|
184
|
+
## Advanced features
|
|
185
|
+
|
|
186
|
+
- **Alternative algorithms** — for cases where `IsoTotalProb` isn't the right shape:
|
|
187
|
+
- `IsoThreshold` — all isotopologues with probability above a fixed threshold.
|
|
188
|
+
- `IsoStochastic` — simulate a measured spectrum by sampling integer ion counts.
|
|
189
|
+
- `IsoBinned` — histogram-style envelope at a chosen bin width.
|
|
190
|
+
- **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.
|
|
191
|
+
- **Custom isotopic tables** — override natural abundances per element (e.g. for radio- or stable-isotope labelling). See `Examples/*/radiolabelling.*`.
|
|
192
|
+
- **Fixed-envelope arithmetic** — addition, normalization, convolution, Wasserstein distance.
|
|
193
|
+
- **Nominal-mass mode** — compute distributions over nucleon counts instead of real masses.
|
|
194
|
+
- **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.
|
|
195
|
+
|
|
196
|
+
Algorithmic details are in the papers cited below; the Supporting Information of each is the better starting point for implementation specifics.
|
|
197
|
+
|
|
198
|
+
## Repository layout
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
src/IsoSpec++/ C++ core library (the algorithms live here)
|
|
202
|
+
src/IsoSpecPy/ Python binding, loaded via cffi
|
|
203
|
+
src/IsoSpecR/ R binding, via Rcpp
|
|
204
|
+
Examples/ Working examples in each language
|
|
205
|
+
tests/ C, C++, and Python test suites
|
|
206
|
+
skbuild/ scikit-build-core entry point used when installing the Python wheel
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Citation
|
|
210
|
+
|
|
211
|
+
If IsoSpec is useful in your research, please cite:
|
|
212
|
+
|
|
213
|
+
- Łą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>
|
|
214
|
+
- Łą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>
|
|
215
|
+
|
|
216
|
+
The Supporting Information of each paper has the algorithmic detail.
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
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,45 @@
|
|
|
1
|
+
bin/IsoSpecCppPy.dll,sha256=XUfxu6zbvOIZ1eYki0tuP2fWiCXGoaXU5vaXr4GAQvc,262144
|
|
2
|
+
IsoSpecPy/__init__.py,sha256=Tjgv2E5pcPq4iSFiuZD4oJiOpqzaMuzkvzQVU843rrE,504
|
|
3
|
+
IsoSpecPy/__main__.py,sha256=Xr6SHPmCkpA3rPFbSBwxd2xl85eEKs6XDTLVWKZxcp4,1034
|
|
4
|
+
IsoSpecPy/Advanced.py,sha256=70LP-AOVr3lsfmCP_zivaXU0auhKWfgt6I8icbptxxg,1090
|
|
5
|
+
IsoSpecPy/approximations.py,sha256=e9kLSARQ-VMoXFayfyp8byrbVLxk6IFwoGz1iHXzKlI,4241
|
|
6
|
+
IsoSpecPy/confs_passthrough.py,sha256=Ythe_zSlI2Z69ajCCftubZSqLvHKz2kSRjF1Vc-pE6M,284
|
|
7
|
+
IsoSpecPy/Distributions.py,sha256=-GayrDO1bfs5EdPBMFf5K_b8QRgY-bqgg8qKH7P62fE,2582
|
|
8
|
+
IsoSpecPy/Formulas.py,sha256=blOy63xIfJcfR5WDYHNSCX3CMsdsOvVWpcAraKm67uE,1730
|
|
9
|
+
IsoSpecPy/isoFFI.py,sha256=HyWpphPVTHwM_yin3Cik3VCXHTp-KBNzGP4ucjgl4ZM,13350
|
|
10
|
+
IsoSpecPy/IsoSpec++/aligned_ptr.h,sha256=5Ul3I3Qkrwrb_V8cpguS50K1FQVro10PrwpvTZ9jlfs,23323
|
|
11
|
+
IsoSpecPy/IsoSpec++/allocator.h,sha256=dyWhQvpCZnDEby0YMyFbA_dVhYrKwMv8Pk4hLubYaLw,1662
|
|
12
|
+
IsoSpecPy/IsoSpec++/btrd.h,sha256=tPbQ6GZk1XpT9ESt4xEqL8TERKzbEnNRIKKGSq4nlNo,6226
|
|
13
|
+
IsoSpecPy/IsoSpec++/composition.h,sha256=sOE3Gf4iae9ky_A46UY2mWD0sBpLTuBCgxy8CrzQDWI,6078
|
|
14
|
+
IsoSpecPy/IsoSpec++/conf.h,sha256=N_dBUbO3RVO9LoSAvjRWtnrjVOqMbcKgbp5q9bJp93M,1008
|
|
15
|
+
IsoSpecPy/IsoSpec++/cwrapper.h,sha256=TMmCCRXn_dmSDc7MMIYX5F1la_0UqoOCDAxm0IVukqk,14525
|
|
16
|
+
IsoSpecPy/IsoSpec++/dirtyAllocator.h,sha256=aB1ebPacCfIPtGXmcxfCP7XJZpu7AuNQrsKlcOE48aI,1472
|
|
17
|
+
IsoSpecPy/IsoSpec++/element_lookup.h,sha256=uAGQJZlMVLFpCRJ6wzPuU3do6_W9niUrTq9A2UEW-fs,1394
|
|
18
|
+
IsoSpecPy/IsoSpec++/element_tables.h,sha256=Y8Okqc2_4ce7znXt9LArBR4JCaK0Wh_-Ih6Nh9YnLfE,1844
|
|
19
|
+
IsoSpecPy/IsoSpec++/fasta.h,sha256=OwJVrrsV6P6fFmhjohxwRJkazOJhJxP1Qc9FxB7bQIE,2325
|
|
20
|
+
IsoSpecPy/IsoSpec++/fasta_mods.h,sha256=pGBIp7ni3jzgOScMY9IiJnSlp4JSry0UEV1KG4P_hiU,3508
|
|
21
|
+
IsoSpecPy/IsoSpec++/fixedEnvelopes.h,sha256=_oTh3R0F9QXePOzqdnLmYzt_Qg9bW_DbfuhtEjD_4Uk,17639
|
|
22
|
+
IsoSpecPy/IsoSpec++/isa_kernel_impl.h,sha256=qKPfLZgYHgBfwQnHUplhMalsS595SPhXTsQhGGHcylA,7974
|
|
23
|
+
IsoSpecPy/IsoSpec++/isa_kernels.h,sha256=NPTB5NYBNY8mZ6fKVt-PtYiFhwXT4g6HVYoWQgw44UA,8753
|
|
24
|
+
IsoSpecPy/IsoSpec++/iso_simd.h,sha256=lkQ7wVZHp9XAMgW4FEIe1t3mWbctJKHueQPKdAX0_B4,2111
|
|
25
|
+
IsoSpecPy/IsoSpec++/isoMath.h,sha256=2tGDWvSruE-eJ2Kcnm0FUakcURYzCxiVdp7S7YepNLk,4275
|
|
26
|
+
IsoSpecPy/IsoSpec++/isoSpec++.h,sha256=weTRGJ8jY5ktTi_50KeJdQq3GXYrtQ4RtLvngRWBy78,36434
|
|
27
|
+
IsoSpecPy/IsoSpec++/marginalTrek++.h,sha256=82iOh5EVrQEjd3w09_oqvqvkwCOMt64o2QUN2JkRGO8,28321
|
|
28
|
+
IsoSpecPy/IsoSpec++/misc.h,sha256=zoBy5nhsZo0rdIQN4d1AbuGQdUQ-rywLJVV3FMcasC8,6100
|
|
29
|
+
IsoSpecPy/IsoSpec++/mman.h,sha256=RxwibELl7IRwWbn672Gg4-DeDGXXL6tFhM12kIMx5EE,1751
|
|
30
|
+
IsoSpecPy/IsoSpec++/operators.h,sha256=tD5hL-lPpLQ_LOEZMH61eenn-5L67Io-JJ8v7NovUpc,4131
|
|
31
|
+
IsoSpecPy/IsoSpec++/platform.h,sha256=gzaU4INxV7WQn7tbmFP2GuegdLnuIox-giHz5Wigimk,7092
|
|
32
|
+
IsoSpecPy/IsoSpec++/platform_incl.h,sha256=6MW4V759ZXdHaHtfH9o5nNmOXj2kCx8E_SiRO1mgBiM,966
|
|
33
|
+
IsoSpecPy/IsoSpec++/pod_vector.h,sha256=apnrfZS_4mNZ_xRoa6TmP1atyMC79HYG6ofeemt7_pk,11823
|
|
34
|
+
IsoSpecPy/IsoSpec++/summator.h,sha256=M-2IV9NU4PTWXIa3fq9Nz3StR9ZT22cZFH1utnmcf98,2425
|
|
35
|
+
IsoSpecPy/IsoSpec++/unimod.h,sha256=MOBn1HTHn4uLQRYwwH6w9Ow8xtDGchHAFayofiiiHxE,3368
|
|
36
|
+
IsoSpecPy/IsoSpec++/unimod_support.h,sha256=ESWUkCGzeA5ou9-2vGSMlNRBcMNIaxrdWLhmKftCxUk,122473
|
|
37
|
+
IsoSpecPy/IsoSpec++/unimod_table_data.h,sha256=LRlguv9E5dhRHRlBKwom4e7BEFpSRIEt_N4YcV2A3fY,37860
|
|
38
|
+
IsoSpecPy/IsoSpecPy.py,sha256=AG0DWfxBQYLyl7TgC5WI1AVjfPqQ0j1e0yKhQIvTveU,50472
|
|
39
|
+
IsoSpecPy/IsoSpecPyOld.py,sha256=6w1sZBhtyA87zGrAibsAvVDxKfqAZwbmYk_57x70GsI,11383
|
|
40
|
+
IsoSpecPy/PeriodicTbl.py,sha256=5EeB5zLJlBnWGodde-AevsCNrI0S1sgn9Nod1t1_xVs,2587
|
|
41
|
+
lib/IsoSpecCppPy.lib,sha256=S9UHc4qUqCVfgH0C3CVZklGo_NGasEruJGUpWEhn4eU,27540
|
|
42
|
+
isospecpy-2.5.0.dist-info/METADATA,sha256=81b8S8_GyeGmWCnqkbMMrvinLWgEzYZ5LSFpNPwvhKU,10480
|
|
43
|
+
isospecpy-2.5.0.dist-info/WHEEL,sha256=5341l7rLjEaIZp8mesTxb1JV3JsiKV2GLmJQcYtx6lg,102
|
|
44
|
+
isospecpy-2.5.0.dist-info/licenses/LICENCE,sha256=gfZw5llAwrHH4rkp5FJuq9VAuamp1x7x8MDmDjj8dpw,1705
|
|
45
|
+
isospecpy-2.5.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
IsoSpec is provided under the terms of 2-clause BSD licence.
|
|
2
|
+
If you require other licensing terms, please contact the authors.
|
|
3
|
+
|
|
4
|
+
We would appreciate if you let us know if you use this library in
|
|
5
|
+
your own software, but you are under no legal obligation to do so.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2015-2025, Michał Startek and Mateusz Łącki
|
|
12
|
+
|
|
13
|
+
All rights reserved.
|
|
14
|
+
|
|
15
|
+
Redistribution and use in source and binary forms, with or without
|
|
16
|
+
modification, are permitted provided that the following conditions are met:
|
|
17
|
+
|
|
18
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
19
|
+
list of conditions and the following disclaimer.
|
|
20
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
21
|
+
this list of conditions and the following disclaimer in the documentation
|
|
22
|
+
and/or other materials provided with the distribution.
|
|
23
|
+
|
|
24
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
25
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
26
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
27
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
28
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
29
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
30
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
31
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
32
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
33
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
34
|
+
|
|
35
|
+
|
lib/IsoSpecCppPy.lib
ADDED
|
Binary file
|