CoreMS 4.0.0__py3-none-any.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.
Files changed (171) hide show
  1. corems/__init__.py +63 -0
  2. corems/chroma_peak/__init__.py +0 -0
  3. corems/chroma_peak/calc/ChromaPeakCalc.py +480 -0
  4. corems/chroma_peak/calc/__init__.py +0 -0
  5. corems/chroma_peak/calc/subset.py +196 -0
  6. corems/chroma_peak/factory/__init__.py +0 -0
  7. corems/chroma_peak/factory/chroma_peak_classes.py +1178 -0
  8. corems/encapsulation/__init__.py +0 -0
  9. corems/encapsulation/constant.py +1283 -0
  10. corems/encapsulation/factory/__init__.py +0 -0
  11. corems/encapsulation/factory/parameters.py +392 -0
  12. corems/encapsulation/factory/processingSetting.py +1244 -0
  13. corems/encapsulation/input/__init__.py +0 -0
  14. corems/encapsulation/input/parameter_from_json.py +579 -0
  15. corems/encapsulation/output/__init__.py +0 -0
  16. corems/encapsulation/output/parameter_to_dict.py +142 -0
  17. corems/encapsulation/output/parameter_to_json.py +332 -0
  18. corems/mass_spectra/__init__.py +0 -0
  19. corems/mass_spectra/calc/GC_Calc.py +84 -0
  20. corems/mass_spectra/calc/GC_Deconvolution.py +558 -0
  21. corems/mass_spectra/calc/GC_RI_Calibration.py +44 -0
  22. corems/mass_spectra/calc/MZSearch.py +249 -0
  23. corems/mass_spectra/calc/SignalProcessing.py +656 -0
  24. corems/mass_spectra/calc/__init__.py +0 -0
  25. corems/mass_spectra/calc/lc_calc.py +5790 -0
  26. corems/mass_spectra/calc/lc_calc_operations.py +1127 -0
  27. corems/mass_spectra/factory/GC_Class.py +791 -0
  28. corems/mass_spectra/factory/__init__.py +0 -0
  29. corems/mass_spectra/factory/chromat_data.py +51 -0
  30. corems/mass_spectra/factory/lc_class.py +2721 -0
  31. corems/mass_spectra/input/__init__.py +0 -0
  32. corems/mass_spectra/input/andiNetCDF.py +200 -0
  33. corems/mass_spectra/input/boosterHDF5.py +216 -0
  34. corems/mass_spectra/input/brukerSolarix.py +153 -0
  35. corems/mass_spectra/input/brukerSolarix_utils.py +73 -0
  36. corems/mass_spectra/input/corems_hdf5.py +1710 -0
  37. corems/mass_spectra/input/massList.py +133 -0
  38. corems/mass_spectra/input/mzml.py +668 -0
  39. corems/mass_spectra/input/parserbase.py +239 -0
  40. corems/mass_spectra/input/rawFileReader.py +1839 -0
  41. corems/mass_spectra/output/__init__.py +0 -0
  42. corems/mass_spectra/output/export.py +2800 -0
  43. corems/mass_spectrum/__init__.py +0 -0
  44. corems/mass_spectrum/calc/AutoRecalibration.py +237 -0
  45. corems/mass_spectrum/calc/Calibration.py +602 -0
  46. corems/mass_spectrum/calc/CalibrationCalc.py +253 -0
  47. corems/mass_spectrum/calc/KendrickGroup.py +239 -0
  48. corems/mass_spectrum/calc/MassErrorPrediction.py +436 -0
  49. corems/mass_spectrum/calc/MassSpectrumCalc.py +303 -0
  50. corems/mass_spectrum/calc/MeanResolvingPowerFilter.py +212 -0
  51. corems/mass_spectrum/calc/NoiseCalc.py +371 -0
  52. corems/mass_spectrum/calc/NoiseCalc_Bayes.py +93 -0
  53. corems/mass_spectrum/calc/PeakPicking.py +994 -0
  54. corems/mass_spectrum/calc/__init__.py +0 -0
  55. corems/mass_spectrum/factory/MassSpectrumClasses.py +1753 -0
  56. corems/mass_spectrum/factory/__init__.py +0 -0
  57. corems/mass_spectrum/input/__init__.py +0 -0
  58. corems/mass_spectrum/input/baseClass.py +531 -0
  59. corems/mass_spectrum/input/boosterHDF5.py +161 -0
  60. corems/mass_spectrum/input/coremsHDF5.py +475 -0
  61. corems/mass_spectrum/input/massList.py +402 -0
  62. corems/mass_spectrum/input/numpyArray.py +133 -0
  63. corems/mass_spectrum/output/__init__.py +0 -0
  64. corems/mass_spectrum/output/export.py +841 -0
  65. corems/molecular_formula/__init__.py +0 -0
  66. corems/molecular_formula/calc/MolecularFormulaCalc.py +885 -0
  67. corems/molecular_formula/calc/__init__.py +0 -0
  68. corems/molecular_formula/factory/MolecularFormulaFactory.py +895 -0
  69. corems/molecular_formula/factory/__init__.py +0 -0
  70. corems/molecular_formula/input/__init__.py +0 -0
  71. corems/molecular_formula/input/masslist_ref.py +355 -0
  72. corems/molecular_id/__init__.py +0 -0
  73. corems/molecular_id/calc/ClusterFilter.py +251 -0
  74. corems/molecular_id/calc/MolecularFilter.py +122 -0
  75. corems/molecular_id/calc/SpectralSimilarity.py +632 -0
  76. corems/molecular_id/calc/__init__.py +0 -0
  77. corems/molecular_id/calc/math_distance.py +1637 -0
  78. corems/molecular_id/data/FAMES_REF.msp +980 -0
  79. corems/molecular_id/data/PNNLMetV20191015.msp +157267 -0
  80. corems/molecular_id/factory/EI_SQL.py +650 -0
  81. corems/molecular_id/factory/MolecularLookupTable.py +914 -0
  82. corems/molecular_id/factory/__init__.py +0 -0
  83. corems/molecular_id/factory/classification.py +884 -0
  84. corems/molecular_id/factory/lipid_molecular_metadata.py +50 -0
  85. corems/molecular_id/factory/molecularSQL.py +827 -0
  86. corems/molecular_id/factory/spectrum_search_results.py +119 -0
  87. corems/molecular_id/input/__init__.py +0 -0
  88. corems/molecular_id/input/nistMSI.py +148 -0
  89. corems/molecular_id/search/__init__.py +0 -0
  90. corems/molecular_id/search/compoundSearch.py +214 -0
  91. corems/molecular_id/search/database_interfaces.py +1527 -0
  92. corems/molecular_id/search/findOxygenPeaks.py +330 -0
  93. corems/molecular_id/search/lcms_spectral_search.py +348 -0
  94. corems/molecular_id/search/molecularFormulaSearch.py +1117 -0
  95. corems/molecular_id/search/priorityAssignment.py +723 -0
  96. corems/ms_peak/__init__.py +0 -0
  97. corems/ms_peak/calc/MSPeakCalc.py +1010 -0
  98. corems/ms_peak/calc/__init__.py +0 -0
  99. corems/ms_peak/factory/MSPeakClasses.py +542 -0
  100. corems/ms_peak/factory/__init__.py +0 -0
  101. corems/transient/__init__.py +0 -0
  102. corems/transient/calc/TransientCalc.py +362 -0
  103. corems/transient/calc/__init__.py +0 -0
  104. corems/transient/factory/TransientClasses.py +457 -0
  105. corems/transient/factory/__init__.py +0 -0
  106. corems/transient/input/__init__.py +0 -0
  107. corems/transient/input/brukerSolarix.py +461 -0
  108. corems/transient/input/midasDatFile.py +172 -0
  109. corems-4.0.0.dist-info/METADATA +475 -0
  110. corems-4.0.0.dist-info/RECORD +171 -0
  111. corems-4.0.0.dist-info/WHEEL +5 -0
  112. corems-4.0.0.dist-info/licenses/LICENSE +22 -0
  113. corems-4.0.0.dist-info/top_level.txt +4 -0
  114. examples/archive/scripts/CoreMS_tutorial.py +94 -0
  115. examples/archive/scripts/DI HR-MS Halogens Bruker.py +196 -0
  116. examples/archive/scripts/DI HR-MS MassList.py +385 -0
  117. examples/archive/scripts/GC-MS MetabRef.py +213 -0
  118. examples/archive/scripts/GC-MS NetCDF.py +217 -0
  119. examples/archive/scripts/HR-MS Thermo Raw 21T.py +136 -0
  120. examples/archive/scripts/LC-ICPMS_metal_peaks.py +297 -0
  121. examples/archive/scripts/LCMS-Thermo.py +460 -0
  122. examples/archive/scripts/LCMS_isotopes.py +283 -0
  123. examples/archive/scripts/MSParams_example.py +21 -0
  124. examples/archive/scripts/Molecular Formula Data Aggreation.py +84 -0
  125. examples/archive/scripts/Single Mz Search.py +69 -0
  126. examples/test_notebooks.py +145 -0
  127. ext_lib/ChemstationMSFileReader.dll +0 -0
  128. ext_lib/ChemstationMSFileReader.xml +126 -0
  129. ext_lib/RawFileReaderLicense.doc +0 -0
  130. ext_lib/ThermoFisher.CommonCore.BackgroundSubtraction.dll +0 -0
  131. ext_lib/ThermoFisher.CommonCore.BackgroundSubtraction.xml +2307 -0
  132. ext_lib/ThermoFisher.CommonCore.Data.dll +0 -0
  133. ext_lib/ThermoFisher.CommonCore.Data.xml +28974 -0
  134. ext_lib/ThermoFisher.CommonCore.MassPrecisionEstimator.dll +0 -0
  135. ext_lib/ThermoFisher.CommonCore.MassPrecisionEstimator.xml +241 -0
  136. ext_lib/ThermoFisher.CommonCore.RawFileReader.dll +0 -0
  137. ext_lib/ThermoFisher.CommonCore.RawFileReader.xml +31174 -0
  138. ext_lib/__init__.py +0 -0
  139. ext_lib/dotnet/OpenMcdf.Extensions.dll +0 -0
  140. ext_lib/dotnet/OpenMcdf.dll +0 -0
  141. ext_lib/dotnet/OpenMcdf.xml +1154 -0
  142. ext_lib/dotnet/System.IO.FileSystem.AccessControl.dll +0 -0
  143. ext_lib/dotnet/System.IO.FileSystem.AccessControl.xml +506 -0
  144. ext_lib/dotnet/System.Security.AccessControl.dll +0 -0
  145. ext_lib/dotnet/System.Security.AccessControl.xml +2043 -0
  146. ext_lib/dotnet/System.Security.Principal.Windows.dll +0 -0
  147. ext_lib/dotnet/System.Security.Principal.Windows.xml +1011 -0
  148. ext_lib/dotnet/ThermoFisher.CommonCore.BackgroundSubtraction.dll +0 -0
  149. ext_lib/dotnet/ThermoFisher.CommonCore.BackgroundSubtraction.xml +2307 -0
  150. ext_lib/dotnet/ThermoFisher.CommonCore.Data.dll +0 -0
  151. ext_lib/dotnet/ThermoFisher.CommonCore.Data.xml +29148 -0
  152. ext_lib/dotnet/ThermoFisher.CommonCore.MassPrecisionEstimator.dll +0 -0
  153. ext_lib/dotnet/ThermoFisher.CommonCore.MassPrecisionEstimator.xml +241 -0
  154. ext_lib/dotnet/ThermoFisher.CommonCore.RawFileReader.dll +0 -0
  155. ext_lib/dotnet/ThermoFisher.CommonCore.RawFileReader.xml +31492 -0
  156. ext_lib/version +18 -0
  157. support_code/atom_parsers/AtomsDescription.py +359 -0
  158. support_code/atom_parsers/CreateAtomsDescription.py +56 -0
  159. support_code/nmdc/filefinder.py +90 -0
  160. support_code/nmdc/lipidomics/lipidomics_workflow.py +748 -0
  161. support_code/nmdc/lipidomics/manifest_examples.py +49 -0
  162. support_code/nmdc/metabolomics/gcms_workflow.py +158 -0
  163. support_code/nmdc/metabolomics/lcms_metabolomics_targeted_search.py +59 -0
  164. support_code/nmdc/metabolomics/lcms_metabolomics_workflow.py +248 -0
  165. support_code/nmdc/metabolomics/metabolomics_collection.py +628 -0
  166. support_code/nmdc/metadata/dms_api.py +42 -0
  167. support_code/nmdc/nom/archived_scripts/nmdc_metadata_gen.py +288 -0
  168. support_code/nmdc/nom/archived_scripts/nom_grow_workflow.py +209 -0
  169. support_code/nmdc/nom/nom_workflow.py +312 -0
  170. support_code/windows_only_importers/BrukerCompassXtract.py +180 -0
  171. support_code/windows_only_importers/ThermoMSFileReader.py +405 -0
@@ -0,0 +1,895 @@
1
+ import re
2
+
3
+ from corems.encapsulation.constant import Atoms, Labels
4
+ from corems.molecular_formula.calc.MolecularFormulaCalc import MolecularFormulaCalc
5
+
6
+ __author__ = "Yuri E. Corilo"
7
+ __date__ = "Jun 24, 2019"
8
+
9
+
10
+ class MolecularFormulaBase(MolecularFormulaCalc):
11
+ """Base class for representing a molecular formula.
12
+
13
+ Parameters
14
+ ----------
15
+ molecular_formula : dict, list, str
16
+ The molecular formula.
17
+ ion_charge : int
18
+ The ion charge.
19
+ ion_type : str, optional
20
+ The ion type. Defaults to None.
21
+ adduct_atom : str, optional
22
+ The adduct atom. Defaults to None.
23
+ mspeak_parent : _MSPeak, optional
24
+ The parent mass spectrum peak object instance. Defaults to None.
25
+ external_mz : float, optional
26
+ The external m/z value. Defaults to None.
27
+
28
+ Raises
29
+ ------
30
+ TypeError
31
+ If the ion type is not 'DE_OR_PROTONATED', 'RADICAL' or 'ADDUCT'.
32
+
33
+ Attributes
34
+ ----------
35
+ isotopologue_count_percentile : float
36
+ The isotopologue count percentile.
37
+ O_C : float
38
+ The O/C ratio.
39
+ H_C : float
40
+ The H/C ratio.
41
+ dbe : float
42
+ The double bond equivalent.
43
+ mz_nominal_calc : int
44
+ The nominal m/z value.
45
+ mz_error : float
46
+ The m/z error.
47
+ mz_calc : float
48
+ The m/z value.
49
+ protonated_mz : float
50
+ The protonated or deprotonated m/z value.
51
+ radical_mz : float
52
+ The radical m/z value.
53
+ neutral_mass : float
54
+ The neutral mass.
55
+ ion_type : str
56
+ The ion type.
57
+ ion_charge : int
58
+ The ion charge.
59
+ atoms : list
60
+ The atoms in the molecular formula.
61
+ confidence_score : float
62
+ The confidence score of the molecular formula identification.
63
+ isotopologue_similarity : float
64
+ The isotopologue similarity score of the molecular formula identification.
65
+ average_mz_error_score : float
66
+ The average m/z error score of the molecular formula identification, including the isotopologues.
67
+ mz_error_score : float
68
+ The m/z error score of the molecular formula identification.
69
+ kmd : float
70
+ The Kendrick mass defect (KMD).
71
+ kendrick_mass : float
72
+ The Kendrick mass.
73
+ knm : float
74
+ The nominal Kendrick mass.
75
+ string : str
76
+ The molecular formula string.
77
+ string_formated : str
78
+ The molecular formula string formated with subscripts and superscripts.
79
+ class_label : str
80
+ The class label.
81
+ class_dict : dict
82
+ The class dictionary.
83
+
84
+ Methods
85
+ -------
86
+ * change_kendrick_base(kendrick_dict_base).
87
+ Change the Kendrick base.
88
+ * isotopologues(min_abundance, current_mono_abundance, dynamic_range).
89
+ Calculate the isotopologues.
90
+ * atoms_qnt(atom).
91
+ Get the atom quantity.
92
+ * atoms_symbol(atom).
93
+ Get the atom symbol without the mass number.
94
+ * to_dict().
95
+ Get the molecular formula as a dictionary.
96
+ * to_list().
97
+ Get the molecular formula as a list.
98
+ """
99
+
100
+ def __init__(
101
+ self,
102
+ molecular_formula,
103
+ ion_charge,
104
+ ion_type=None,
105
+ adduct_atom=None,
106
+ mspeak_parent=None,
107
+ external_mz=None,
108
+ ):
109
+ # clear dictionary of atoms with 0 value
110
+ if type(molecular_formula) is dict:
111
+ self._from_dict(molecular_formula, ion_type, adduct_atom)
112
+
113
+ elif type(molecular_formula) is list:
114
+ self._from_list(molecular_formula, ion_type, adduct_atom)
115
+
116
+ elif type(molecular_formula) is str:
117
+ self._from_str(molecular_formula, ion_type, adduct_atom)
118
+
119
+ self._ion_charge = ion_charge
120
+ self._external_mz = external_mz
121
+ self._confidence_score = None
122
+ self._isotopologue_similarity = None
123
+ self._mz_error_score = None
124
+ self._mass_error_average_score = None
125
+
126
+ self.is_isotopologue = False
127
+
128
+ # parent mass spectrum peak obj instance
129
+ self._mspeak_parent = mspeak_parent
130
+
131
+ self.expected_isotopologues = []
132
+ self.mspeak_mf_isotopologues_indexes = []
133
+
134
+ if self._mspeak_parent:
135
+ kendrick_dict_base = (
136
+ self._mspeak_parent._ms_parent.mspeaks_settings.kendrick_base
137
+ )
138
+ else:
139
+ kendrick_dict_base = {"C": 1, "H": 2}
140
+ self._kmd, self._kendrick_mass, self._nominal_km = self._calc_kmd(
141
+ kendrick_dict_base
142
+ )
143
+
144
+ def __repr__(self):
145
+ return "MolecularFormula({0},{1},ion type = {2}".format(
146
+ self._d_molecular_formula, self.ion_charge, self.ion_type
147
+ )
148
+
149
+ def __str__(self):
150
+ return "MolecularFormula {0}, ion_charge:{1}, ion type:{2}, m/z:{3} ".format(
151
+ self.string, self.ion_charge, self.ion_type, self.mz_calc
152
+ )
153
+
154
+ def __len__(self):
155
+ # crash if keys are not ordered
156
+ return len(self._d_molecular_formula.keys())
157
+
158
+ def __getitem__(self, atom):
159
+ # atom = list(self._d_molecular_formula.keys())[position]
160
+ if atom in self._d_molecular_formula.keys():
161
+ return self._d_molecular_formula[atom]
162
+ else:
163
+ return 0
164
+
165
+ def get(self, atom):
166
+ """Get the atom quantity of a specific atom.
167
+
168
+ Parameters
169
+ ----------
170
+ atom : str
171
+ The atom symbol.
172
+
173
+ Returns
174
+ -------
175
+ int
176
+ The atom quantity.
177
+ """
178
+ # atom = list(self._d_molecular_formula.keys())[position]
179
+ if atom in self._d_molecular_formula.keys():
180
+ return self._d_molecular_formula[atom]
181
+ else:
182
+ return 0
183
+
184
+ def _from_dict(self, molecular_formula, ion_type, adduct_atom):
185
+ self._d_molecular_formula = {
186
+ key: val for key, val in molecular_formula.items() if val != 0
187
+ }
188
+
189
+ if ion_type is not None:
190
+ self._d_molecular_formula[Labels.ion_type] = ion_type
191
+
192
+ if adduct_atom:
193
+ if adduct_atom in self._d_molecular_formula:
194
+ self._d_molecular_formula[adduct_atom] += 1
195
+ else:
196
+ self._d_molecular_formula[adduct_atom] = 1
197
+ self.adduct_atom = adduct_atom
198
+
199
+ def _from_list(self, molecular_formula_list, ion_type, adduct_atom):
200
+ # list has to be in the format
201
+ # ['C', 10, 'H', 21, '13C', 1, 'Cl', 1, etc]
202
+ self._d_molecular_formula = {}
203
+ for each in range(0, len(molecular_formula_list), 2):
204
+ atoms_label = molecular_formula_list[each]
205
+ atoms_count = int(molecular_formula_list[each + 1])
206
+
207
+ if atoms_count > 0:
208
+ self._d_molecular_formula[atoms_label] = int(atoms_count)
209
+
210
+ self._d_molecular_formula[Labels.ion_type] = ion_type
211
+ if adduct_atom:
212
+ self.adduct_atom = adduct_atom
213
+ if adduct_atom in self._d_molecular_formula:
214
+ self._d_molecular_formula[adduct_atom] += 1
215
+ else:
216
+ self._d_molecular_formula[adduct_atom] = 1
217
+ else:
218
+ self.adduct_atom = None
219
+
220
+ def _from_str(self, molecular_formula_str, ion_type, adduct_atom):
221
+ # string has to be in the format
222
+ #'C10 H21 13C1 Cl1 37Cl1 etc'
223
+ # Check if there are spaces in the string
224
+ if " " not in molecular_formula_str:
225
+ raise ValueError(
226
+ "The molecular formula string should have spaces, input: %s"
227
+ % molecular_formula_str
228
+ )
229
+
230
+ # Split the string by spaces
231
+ # Grab the text before a digit for each element after splitting on spaces (atoms)
232
+ elements = [re.sub(r"\d+$", "", x) for x in molecular_formula_str.split()]
233
+ # Grab the digits at the end of each element after splitting on spaces (counts)
234
+ counts = [re.findall(r"\d+$", x)[0] for x in molecular_formula_str.split()]
235
+ # Check that the number of elements and counts are the same
236
+ if len(elements) != len(counts):
237
+ raise ValueError(
238
+ "The number of elements and counts do not match, input: %s"
239
+ % molecular_formula_str
240
+ )
241
+
242
+ # Create a dictionary from the elements and counts and add it to the molecular formula
243
+ dict_ = dict(zip(elements, counts))
244
+ # Cast counts to integers
245
+ dict_ = {key: int(val) for key, val in dict_.items()}
246
+ self._from_dict(dict_, ion_type, adduct_atom)
247
+
248
+ def split(self, delimiters, string, maxsplit=0): # pragma: no cover
249
+ """Splits the molecular formula string.
250
+
251
+ Parameters
252
+ ----------
253
+ delimiters : list
254
+ The list of delimiters.
255
+ string : str
256
+ The molecular formula string.
257
+ maxsplit : int, optional
258
+ The maximum number of splits. Defaults to 0.
259
+
260
+ Returns
261
+ -------
262
+ list
263
+ The molecular formula list.
264
+
265
+ Notes
266
+ -----
267
+ Does not work when formula has atoms with same characters in a row that below to different atoms, i.e. C10H21NNa.
268
+ """
269
+ regexPattern = "|".join(map(re.escape, delimiters)) # pragma: no cover
270
+ isotopes = re.findall(regexPattern, string) # pragma: no cover
271
+ counts = re.split(regexPattern, string, maxsplit) # pragma: no cover
272
+
273
+ return [isotopes[0], int(counts[1])]
274
+
275
+ @property
276
+ def isotopologue_count_percentile(
277
+ self,
278
+ ):
279
+ if not len(self.expected_isotopologues) == 0:
280
+ return (
281
+ len(self.mspeak_mf_isotopologues_indexes)
282
+ / len(self.expected_isotopologues)
283
+ ) * 100
284
+ else:
285
+ return 100
286
+
287
+ @property
288
+ def O_C(self):
289
+ if "O" in self._d_molecular_formula.keys():
290
+ # gather all the Os and Hs, regardless of the isotopic composition
291
+ Os = sum(
292
+ [
293
+ self._d_molecular_formula.get(key)
294
+ for key in ["O"] + Atoms.isotopes["O"][1]
295
+ if key in self._d_molecular_formula.keys()
296
+ ]
297
+ )
298
+ Cs = sum(
299
+ [
300
+ self._d_molecular_formula.get(key)
301
+ for key in ["C"] + Atoms.isotopes["C"][1]
302
+ if key in self._d_molecular_formula.keys()
303
+ ]
304
+ )
305
+ return Os / Cs
306
+ else:
307
+ return 0
308
+
309
+ @property
310
+ def H_C(self):
311
+ # gather all the Cs and Hs, regardless of the isotopic composition
312
+ Cs = sum(
313
+ [
314
+ self._d_molecular_formula.get(key)
315
+ for key in ["C"] + Atoms.isotopes["C"][1]
316
+ if key in self._d_molecular_formula.keys()
317
+ ]
318
+ )
319
+ Hs = sum(
320
+ [
321
+ self._d_molecular_formula.get(key)
322
+ for key in ["H"] + Atoms.isotopes["H"][1]
323
+ if key in self._d_molecular_formula.keys()
324
+ ]
325
+ )
326
+ return Hs / Cs
327
+
328
+ @property
329
+ def A_I(self):
330
+ """Aromaticity index"""
331
+ return self._calc_aromaticity_index()
332
+
333
+ @property
334
+ def A_I_mod(self):
335
+ """Modified aromaticity index"""
336
+ return self._calc_aromaticity_index_mod()
337
+
338
+ @property
339
+ def nosc(self):
340
+ """Nominal oxidation state of carbon"""
341
+ return self._calc_nosc()
342
+
343
+ @property
344
+ def dbe(self):
345
+ return self._calc_dbe()
346
+
347
+ @property
348
+ def mz_nominal_calc(self):
349
+ return int(self._calc_mz())
350
+
351
+ @property
352
+ def mz_error(self):
353
+ return self._calc_assignment_mass_error()
354
+
355
+ @property
356
+ def mz_calc(self):
357
+ return self._calc_mz()
358
+
359
+ @property
360
+ def protonated_mz(self):
361
+ return self._protonated_mz(self.ion_charge)
362
+
363
+ @property
364
+ def radical_mz(self):
365
+ return self._radical_mz(self.ion_charge)
366
+
367
+ @property
368
+ def neutral_mass(self):
369
+ return self._neutral_mass()
370
+
371
+ def adduct_mz(self, adduct_atom):
372
+ """Get m/z of an adducted ion version of the molecular formula.
373
+
374
+ Parameters
375
+ ----------
376
+ adduct_atom : str
377
+ The adduct atom.
378
+
379
+ Returns
380
+ -------
381
+ float
382
+ The m/z value of the adducted ion version of the molecular formula.
383
+ """
384
+ return self._adduct_mz(adduct_atom, self.ion_charge)
385
+
386
+ @property
387
+ def ion_type(self):
388
+ ion_type = self._d_molecular_formula.get(Labels.ion_type)
389
+ if ion_type == Labels.protonated_de_ion:
390
+ if self.ion_charge > 0:
391
+ return Labels.protonated
392
+ else:
393
+ return Labels.de_protonated
394
+ else:
395
+ return ion_type
396
+
397
+ @ion_type.setter
398
+ def ion_type(self, ion_type):
399
+ if ion_type in [
400
+ Labels.protonated_de_ion,
401
+ Labels.adduct_ion,
402
+ Labels.radical_ion,
403
+ ]:
404
+ self._d_molecular_formula[Labels.ion_type] = ion_type
405
+ else:
406
+ raise TypeError(
407
+ "Ion type can only be: 'DE_OR_PROTONATED', 'RADICAL' or 'ADDUCT', not %s"
408
+ % ion_type
409
+ )
410
+
411
+ @property
412
+ def ion_charge(self):
413
+ return self._ion_charge
414
+
415
+ @property
416
+ def atoms(self):
417
+ """Get the atoms in the molecular formula."""
418
+ # if there is an adduct_atom, them reduce it from the atoms list
419
+ if self.adduct_atom is None:
420
+ return [
421
+ key
422
+ for key in self._d_molecular_formula.keys()
423
+ if key != Labels.ion_type
424
+ ]
425
+ else:
426
+ temp_dict = self._d_molecular_formula.copy()
427
+ temp_dict[self.adduct_atom] -= 1
428
+ return [
429
+ key
430
+ for key, val in temp_dict.items()
431
+ if key != Labels.ion_type and val > 0
432
+ ]
433
+
434
+ @property
435
+ def confidence_score(self):
436
+ if not self._confidence_score:
437
+ self._confidence_score = self._calc_confidence_score()
438
+
439
+ return self._confidence_score
440
+
441
+ @property
442
+ def isotopologue_similarity(self):
443
+ if not self._isotopologue_similarity:
444
+ self._isotopologue_similarity = self._calc_isotopologue_confidence()
445
+
446
+ return self._isotopologue_similarity
447
+
448
+ @property
449
+ def average_mz_error_score(self):
450
+ # includes the isotopologues
451
+
452
+ if not self._mass_error_average_score:
453
+ self._mass_error_average_score = self._calc_average_mz_score()
454
+
455
+ return self._mass_error_average_score
456
+
457
+ @property
458
+ def mz_error_score(self):
459
+ if not self._mz_error_score:
460
+ self._mz_error_score = self._calc_mz_confidence()
461
+
462
+ return self._mz_error_score
463
+
464
+ @property
465
+ def kmd(self):
466
+ return self._kmd
467
+
468
+ @property
469
+ def kendrick_mass(self):
470
+ return self._kendrick_mass
471
+
472
+ @property
473
+ def knm(self):
474
+ return self._nominal_km
475
+
476
+ def change_kendrick_base(self, kendrick_dict_base):
477
+ """Change the Kendrick base.
478
+
479
+ Parameters
480
+ ----------
481
+ kendrick_dict_base : dict
482
+ The Kendrick base dictionary. Ex: {"C": 1, "H": 2}
483
+ """
484
+ self._kmd, self._kendrick_mass, self._nominal_km = self._calc_kmd(
485
+ kendrick_dict_base
486
+ )
487
+
488
+ def isotopologues(self, min_abundance, current_mono_abundance, dynamic_range):
489
+ """Calculate the isotopologues for a given molecular formula.
490
+
491
+ Parameters
492
+ ----------
493
+ min_abundance : float
494
+ The minimum abundance.
495
+ current_mono_abundance : float
496
+ The current monoisotopic abundance.
497
+ dynamic_range : float
498
+ The dynamic range.
499
+
500
+ Yields
501
+ ------
502
+ MolecularFormulaIsotopologue
503
+ The molecular formula isotopologue.
504
+
505
+ Notes
506
+ -----
507
+ This calculation ignores the hydrogen isotopes.
508
+ """
509
+ isotopologues = []
510
+ for mf in self._cal_isotopologues(
511
+ self._d_molecular_formula,
512
+ min_abundance,
513
+ current_mono_abundance,
514
+ dynamic_range,
515
+ ):
516
+ isotopologues.append(mf)
517
+
518
+ # To account for differences in how the isotopologue outputs are sorted between IsoSpec versions.
519
+ sorted_isotopologues = sorted(isotopologues, key=lambda mf: mf[1], reverse=True)
520
+
521
+ for mf in sorted_isotopologues:
522
+ yield MolecularFormulaIsotopologue(
523
+ *mf,
524
+ current_mono_abundance,
525
+ self.ion_charge,
526
+ ion_type=self.ion_type,
527
+ adduct_atom=self.adduct_atom,
528
+ )
529
+
530
+ def atoms_qnt(self, atom):
531
+ """Get the atom quantity of a specific atom in the molecular formula."""
532
+ if atom in self._d_molecular_formula:
533
+ return self._d_molecular_formula.get(atom)
534
+ else:
535
+ raise Warning(
536
+ "Could not find %s in this Molecular Formula object" % str(atom)
537
+ )
538
+
539
+ def atoms_symbol(self, atom):
540
+ """Get the atom symbol without the mass number."""
541
+ return "".join([i for i in atom if not i.isdigit()])
542
+
543
+ @property
544
+ def string(self):
545
+ """Returns the molecular formula as a string."""
546
+ if self._d_molecular_formula:
547
+ if self.adduct_atom is None:
548
+ mol_form_dict = self._d_molecular_formula
549
+ else:
550
+ mol_form_dict = self._d_molecular_formula.copy()
551
+ if self.adduct_atom not in mol_form_dict.keys():
552
+ raise Exception("Adduct atom not found in molecular formula dict")
553
+ mol_form_dict[self.adduct_atom] -= 1
554
+ mol_form_dict = {
555
+ key: val for key, val in mol_form_dict.items() if val != 0
556
+ }
557
+ formula_srt = ""
558
+ for atom in Atoms.atoms_order:
559
+ if atom in mol_form_dict.keys():
560
+ formula_srt += atom + str(int(mol_form_dict.get(atom))) + " "
561
+ return formula_srt.strip()
562
+
563
+ else:
564
+ raise Exception("Molecular formula identification not performed yet")
565
+
566
+ @property
567
+ def string_formated(self):
568
+ SUB = str.maketrans("0123456789", "₀₁₂₃₄₅₆₇₈₉")
569
+ SUP = str.maketrans("0123456789", "⁰¹²³⁴⁵⁶⁷⁸⁹")
570
+
571
+ if self._d_molecular_formula:
572
+ formula_srt = ""
573
+ for atom in Atoms.atoms_order:
574
+ if atom in self.to_dict().keys():
575
+ formula_srt += atom.translate(SUP) + str(
576
+ int(self.to_dict().get(atom))
577
+ ).translate(SUB)
578
+ return formula_srt
579
+
580
+ else:
581
+ raise Exception("Molecular formula identification not performed yet")
582
+
583
+ def to_dict(self):
584
+ """Returns the molecular formula as a dictionary.
585
+
586
+ Returns
587
+ -------
588
+ dict
589
+ The molecular formula as a dictionary.
590
+ """
591
+ return self._d_molecular_formula
592
+
593
+ def to_list(self):
594
+ """Returns the molecular formula as a list.
595
+
596
+ Returns
597
+ -------
598
+ list
599
+ The molecular formula as a list.
600
+
601
+ Raises
602
+ ------
603
+ Exception
604
+ If the molecular formula identification was not performed yet.
605
+ """
606
+ # TODO ensure self._d_molecular_formula is a orderedDict
607
+
608
+ if self._d_molecular_formula:
609
+ formula_list = []
610
+
611
+ for atom, atom_number in self._d_molecular_formula.items():
612
+ if atom != Labels.ion_type:
613
+ formula_list.append(atom)
614
+ formula_list.append(atom_number)
615
+
616
+ return formula_list
617
+ else:
618
+ raise Exception("Molecular formula identification not performed yet")
619
+
620
+ @property
621
+ def class_label(self):
622
+ if self._d_molecular_formula:
623
+ formulalist = self.to_list()
624
+ classstring = ""
625
+
626
+ for each in range(0, len(formulalist), 2):
627
+ if (
628
+ formulalist[each] != "C"
629
+ and formulalist[each] != "H"
630
+ and formulalist[each] != "HC"
631
+ ):
632
+ classstring = (
633
+ classstring
634
+ + str(formulalist[each])
635
+ + str(formulalist[each + 1])
636
+ + " "
637
+ )
638
+
639
+ if classstring == "":
640
+ classstring = "HC"
641
+
642
+ classstring = classstring.strip()
643
+
644
+ if self._d_molecular_formula.get(Labels.ion_type) == Labels.radical_ion:
645
+ return classstring + " -R"
646
+
647
+ # elif self._d_molecular_formula.get(Labels.ion_type) == Labels.adduct_ion:
648
+
649
+ # return classstring + ' -A'
650
+
651
+ else:
652
+ return classstring
653
+
654
+ #'dict, tuple or string'
655
+
656
+ else:
657
+ raise Exception("Molecular formula identification not performed yet")
658
+
659
+ @property
660
+ def class_dict(self):
661
+ if self._d_molecular_formula:
662
+ class_dict = {}
663
+
664
+ for atom, qnt in self._d_molecular_formula.items():
665
+ if atom != Labels.ion_type and atom != "C" and atom != "H":
666
+ class_dict[atom] = qnt
667
+
668
+ return class_dict
669
+
670
+ raise Exception("Molecular formula identification not performed yet")
671
+
672
+
673
+ class MolecularFormulaIsotopologue(MolecularFormulaBase):
674
+ """Class for representing a molecular formula isotopologue.
675
+
676
+ Parameters
677
+ ----------
678
+ _d_molecular_formula : dict
679
+ The molecular formula as a dictionary.
680
+ prob_ratio : float
681
+ The probability ratio.
682
+ mono_abundance : float
683
+ The monoisotopic abundance.
684
+ ion_charge : int
685
+ The ion charge.
686
+ mspeak_parent : object, optional
687
+ The parent mass spectrum peak object instance. Defaults to None.
688
+ ion_type : str, optional
689
+ The ion type. Defaults to None.
690
+ adduct_atom : str, optional
691
+ The adduct atom. Defaults to None.
692
+
693
+ Attributes
694
+ ----------
695
+ prob_ratio : float
696
+ The probability ratio.
697
+ abundance_calc : float
698
+ The calculated abundance.
699
+ area_error : float
700
+ The area error.
701
+ abundance_error : float
702
+ The abundance error.
703
+ is_isotopologue : bool
704
+ The isotopologue flag. Defaults to True.
705
+ mspeak_index_mono_isotopic : int
706
+ The index of the monoisotopic peak in the mass spectrum peak list. Defaults to None.
707
+ mono_isotopic_formula_index : int
708
+ The index of the monoisotopic formula in the molecular formula list. Defaults to None.
709
+ """
710
+
711
+ def __init__(
712
+ self,
713
+ _d_molecular_formula,
714
+ prob_ratio,
715
+ mono_abundance,
716
+ ion_charge,
717
+ mspeak_parent=None,
718
+ ion_type=None,
719
+ adduct_atom=None,
720
+ ):
721
+ if ion_type is None:
722
+ # check if ion type or adduct_atom is in the molecular formula dict
723
+ if Labels.ion_type in _d_molecular_formula:
724
+ ion_type = _d_molecular_formula.get(Labels.ion_type)
725
+ else:
726
+ ion_type = None
727
+ else:
728
+ ion_type = Labels.ion_type_translate.get(ion_type)
729
+
730
+ if ion_type == Labels.adduct_ion:
731
+ adduct_atom_int = None
732
+ if adduct_atom in _d_molecular_formula.keys():
733
+ adduct_atom_int = adduct_atom
734
+ else:
735
+ # Check to see if adduct_atom should actually be an isotope of the adduct atom
736
+ for adduct_iso in Atoms.isotopes.get(adduct_atom)[1]:
737
+ if adduct_iso in _d_molecular_formula.keys():
738
+ adduct_atom_int = adduct_iso
739
+ adduct_atom = adduct_atom_int
740
+ if adduct_atom is None:
741
+ raise Exception("adduct_atom is required for adduct ion")
742
+ _d_molecular_formula[adduct_atom] -= 1
743
+ _d_molecular_formula = {
744
+ key: val for key, val in _d_molecular_formula.items() if val != 0
745
+ }
746
+
747
+ super().__init__(
748
+ molecular_formula=_d_molecular_formula,
749
+ ion_charge=ion_charge,
750
+ ion_type=ion_type,
751
+ adduct_atom=adduct_atom,
752
+ )
753
+ # prob_ratio is relative to the monoisotopic peak p_isotopologue/p_mono_isotopic
754
+
755
+ self.prob_ratio = prob_ratio
756
+
757
+ self.abundance_calc = mono_abundance * prob_ratio
758
+
759
+ self.is_isotopologue = True
760
+
761
+ self.mspeak_index_mono_isotopic = None
762
+
763
+ self.mono_isotopic_formula_index = None
764
+ # parent mass spectrum peak obj instance
765
+ self._mspeak_parent = mspeak_parent
766
+
767
+ @property
768
+ def area_error(self):
769
+ return self._calc_area_error()
770
+
771
+ @property
772
+ def abundance_error(self):
773
+ return self._calc_abundance_error()
774
+
775
+
776
+ class LCMSLibRefMolecularFormula(MolecularFormulaBase):
777
+ """Class for representing a molecular formula associated with a molecule in a LCMS library reference.
778
+
779
+ Parameters
780
+ ----------
781
+ molecular_formula : dict, list, str
782
+ The molecular formula.
783
+ ion_charge : int
784
+ The ion charge.
785
+ ion_type : str, optional
786
+ The ion type. Defaults to None.
787
+ adduct_atom : str, optional
788
+ The adduct atom. Defaults to None.
789
+ mspeak_parent : object, optional
790
+ The parent mass spectrum peak object instance. Defaults to None.
791
+ name : str, optional
792
+ The name of the reference molecule. Defaults to None.
793
+ kegg_id : str, optional
794
+ The KEGG ID of the reference molecule. Defaults to None.
795
+ cas : str, optional
796
+ The CAS number of the reference molecule. Defaults to None.
797
+
798
+ """
799
+
800
+ def __init__(
801
+ self,
802
+ molecular_formula,
803
+ ion_charge,
804
+ ion_type=None,
805
+ adduct_atom=None,
806
+ mspeak_parent=None,
807
+ name=None,
808
+ kegg_id=None,
809
+ cas=None,
810
+ ) -> None:
811
+ super().__init__(
812
+ molecular_formula,
813
+ ion_charge,
814
+ ion_type=ion_type,
815
+ adduct_atom=adduct_atom,
816
+ mspeak_parent=mspeak_parent,
817
+ )
818
+
819
+ self._name = name
820
+ self._kegg_id = kegg_id
821
+ self._cas = cas
822
+
823
+ @property
824
+ def name(self):
825
+ return self._name
826
+
827
+ @name.setter
828
+ def name(self, name):
829
+ if isinstance(name, str):
830
+ self._name = name
831
+ else:
832
+ raise TypeError("name: {} should be type string")
833
+
834
+ @property
835
+ def kegg_id(self):
836
+ return self._kegg_id
837
+
838
+ @kegg_id.setter
839
+ def kegg_id(self, kegg_id):
840
+ self._kegg_id = kegg_id
841
+ # if isinstance(kegg_id, str):
842
+ # self._kegg_id = kegg_id
843
+ # else:
844
+ # print(kegg_id)
845
+ # raise TypeError('name: {} should be type string')
846
+
847
+ @property
848
+ def cas(self):
849
+ return self._cas
850
+
851
+ @cas.setter
852
+ def cas(self, cas):
853
+ self._cas = cas
854
+ # if isinstance(cas, str):
855
+ # self._cas = cas
856
+ # else:
857
+ # raise TypeError('name: {} should be type string')
858
+
859
+
860
+ class MolecularFormula(MolecularFormulaBase):
861
+ """General class for representing a molecular formula.
862
+
863
+ Parameters
864
+ ----------
865
+ molecular_formula : dict, list, str
866
+ The molecular formula.
867
+ ion_charge : int
868
+ The ion charge.
869
+ ion_type : str, optional
870
+ The ion type. Defaults to None.
871
+ adduct_atom : str, optional
872
+ The adduct atom. Defaults to None.
873
+ mspeak_parent : object, optional
874
+ The parent mass spectrum peak object instance. Defaults to None.
875
+ external_mz : float, optional
876
+ The external m/z value. Defaults to False.
877
+ """
878
+
879
+ def __init__(
880
+ self,
881
+ molecular_formula,
882
+ ion_charge,
883
+ ion_type=None,
884
+ adduct_atom=None,
885
+ mspeak_parent=None,
886
+ external_mz=False,
887
+ ):
888
+ super().__init__(
889
+ molecular_formula,
890
+ ion_charge,
891
+ ion_type=ion_type,
892
+ adduct_atom=adduct_atom,
893
+ mspeak_parent=mspeak_parent,
894
+ external_mz=external_mz,
895
+ )