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,723 @@
1
+ import os
2
+ import sys
3
+
4
+ from copy import deepcopy
5
+ from threading import Thread
6
+ from itertools import product
7
+
8
+ import tqdm
9
+
10
+ from corems.encapsulation.constant import Labels, Atoms
11
+ from corems.molecular_id.calc.MolecularFilter import MolecularFormulaSearchFilters
12
+ from corems.molecular_id.search.findOxygenPeaks import FindOxygenPeaks
13
+ from corems.molecular_id.search.molecularFormulaSearch import (
14
+ SearchMolecularFormulaWorker,
15
+ )
16
+ from corems.molecular_id.factory.molecularSQL import MolForm_SQL
17
+ from corems.molecular_id.calc.ClusterFilter import ClusteringFilter
18
+
19
+
20
+ class OxygenPriorityAssignment(Thread):
21
+ """A class for assigning priority to oxygen classes in a molecular search.
22
+
23
+ Parameters
24
+ ----------
25
+ mass_spectrum_obj : MassSpectrum
26
+ The mass spectrum object.
27
+ sql_db : bool, optional
28
+ Whether to use an SQL database. The default is False.
29
+
30
+ Attributes
31
+ ----------
32
+ mass_spectrum_obj : MassSpectrum
33
+ The mass spectrum object.
34
+ sql_db : MolForm_SQL
35
+ The SQL database object.
36
+
37
+ Methods
38
+ -------
39
+ * run().
40
+ Run the priority assignment process.
41
+ * create_data_base().
42
+ Create the molecular database for the specified heteroatomic classes.
43
+ * run_worker_mass_spectrum(assign_classes_order_tuples).
44
+ Run the molecular formula search for each class in the specified order.
45
+ * get_dict_molecular_database(classe_str_list).
46
+ Get the molecular database as a dictionary.
47
+ * ox_classes_and_peaks_in_order_().
48
+ Get the oxygen classes and associated peaks in order.
49
+ * get_classes_in_order(dict_ox_class_and_ms_peak)
50
+ Get the classes in order.
51
+ """
52
+
53
+ def __init__(self, mass_spectrum_obj, sql_db=False):
54
+ # TODO:- add support for other atoms and adducts: Done
55
+ # - add dbe range on search runtime : Done
56
+ # - add docs
57
+ # - improve performace : Done
58
+
59
+ Thread.__init__(self)
60
+ self.mass_spectrum_obj = mass_spectrum_obj
61
+ # initiated at create_molecular_database()
62
+ # self.dict_molecular_lookup_table = None
63
+
64
+ if not sql_db:
65
+ self.sql_db = MolForm_SQL(
66
+ url=mass_spectrum_obj.molecular_search_settings.url_database
67
+ )
68
+
69
+ else:
70
+ self.sql_db = sql_db
71
+
72
+ def run(self):
73
+ """Run the priority assignment process."""
74
+ # get Oxygen classes dict and the associate mspeak class
75
+ # list_of_classes_min_max_dbe = self.class_and_dbes_in_order()
76
+ # create database separated to give the user the chance to use mass spec filters
77
+
78
+ assign_classes_order_str_dict_tuple_list = self.create_data_base()
79
+
80
+ if assign_classes_order_str_dict_tuple_list:
81
+ self.run_worker_mass_spectrum(assign_classes_order_str_dict_tuple_list)
82
+
83
+ else:
84
+ raise RuntimeError("call create_data_base() first")
85
+
86
+ self.sql_db.close()
87
+
88
+ def create_data_base(self):
89
+ """Create the molecular database for the specified heteroatomic classes.
90
+
91
+ Returns
92
+ -------
93
+ assign_classes_order_str_dict_tuple_ : list
94
+ A list of tuples containing the class names and dictionaries of class attributes.
95
+ """
96
+
97
+ def create_molecular_database():
98
+ """Checks and creates the database entries for the specified heteroatomic classes."""
99
+ min_o = min(self.mass_spectrum_obj, key=lambda msp: msp[0]["O"])[0]["O"] - 2
100
+
101
+ if min_o <= 0:
102
+ min_o = 1
103
+
104
+ max_o = max(self.mass_spectrum_obj, key=lambda msp: msp[0]["O"])[0]["O"] + 2
105
+
106
+ # min_dbe = min(self.mass_spectrum_obj, key=lambda msp: msp[0].dbe)[0].dbe
107
+
108
+ # max_dbe = max(self.mass_spectrum_obj, key=lambda msp: msp[0].dbe)[0].dbe
109
+
110
+ # self.lookupTableSettings.use_pah_line_rule = False
111
+
112
+ # self.lookupTableSettings.min_dbe = min_dbe/2#min_dbe - 7 if (min_dbe - 7) > 0 else 0
113
+
114
+ # self.lookupTableSettings.max_dbe = max_dbe * 2 #max_dbe + 7
115
+
116
+ self.mass_spectrum_obj.reset_indexes()
117
+
118
+ self.mass_spectrum_obj.filter_by_noise_threshold()
119
+
120
+ # initial_ox = deepcopy(self.mass_spectrum_obj.molecular_search_settings.usedAtoms)
121
+
122
+ self.mass_spectrum_obj.molecular_search_settings.usedAtoms["O"] = (
123
+ min_o,
124
+ max_o,
125
+ )
126
+
127
+ self.nominal_mzs = self.mass_spectrum_obj.nominal_mz
128
+
129
+ # get the most abundant peak and them every 14Da, only allow Ox and its derivatives
130
+ if self.mass_spectrum_obj.parameters.mass_spectrum.verbose_processing:
131
+ print("Getting Oxygen Series")
132
+ find_formula_thread = FindOxygenPeaks(self.mass_spectrum_obj, self.sql_db)
133
+ find_formula_thread.run()
134
+
135
+ # mass spec obj indexes are set to interate over only the peaks with a molecular formula candidate
136
+ if self.mass_spectrum_obj.parameters.mass_spectrum.verbose_processing:
137
+ print("Getting Oxygen Series")
138
+ find_formula_thread.set_mass_spec_indexes_by_found_peaks()
139
+
140
+ # get the Ox class and the DBE for the lowest error molecular formula candidate
141
+ dict_ox_class_and_ms_peak = self.ox_classes_and_peaks_in_order_()
142
+
143
+ # sort the classes by abundance
144
+ if self.mass_spectrum_obj.parameters.mass_spectrum.verbose_processing:
145
+ print("Getting Oxygen Series Order")
146
+ assign_classes_order_str_dict_tuple_list = self.get_classes_in_order(
147
+ dict_ox_class_and_ms_peak
148
+ )
149
+
150
+ create_molecular_database()
151
+
152
+ return assign_classes_order_str_dict_tuple_list
153
+
154
+ def run_worker_mass_spectrum(self, assign_classes_order_tuples):
155
+ """Run the molecular formula search for each class in the specified order.
156
+
157
+ Parameters
158
+ ----------
159
+ assign_classes_order_tuples : list
160
+ A list of tuples containing the class names and dictionaries of class attributes.
161
+ """
162
+
163
+ def check_adduct_class(classe_dict):
164
+ """Check if the class contains any adduct atoms.
165
+
166
+ Parameters
167
+ ----------
168
+ classe_dict : dict
169
+ The dictionary of class attributes.
170
+
171
+ Returns
172
+ -------
173
+ bool
174
+ True if the class contains adduct atoms, False otherwise.
175
+ """
176
+ return any(
177
+ [
178
+ key in classe_dict.keys()
179
+ for key in self.mass_spectrum_obj.molecular_search_settings.adduct_atoms_neg
180
+ ]
181
+ )
182
+
183
+ def set_min_max_dbe_by_oxygen(classe_dict):
184
+ """Calculate the minimum and maximum DBE based on the number of oxygen atoms.
185
+
186
+ Parameters
187
+ ----------
188
+ classe_dict : dict
189
+ The dictionary of class attributes.
190
+ """
191
+ # calculates min and max DBE based on the Oxygen number
192
+ # ref :https://pubs.acs.org/doi/full/10.1021/ac200464q
193
+ # if class does not has O it use the pha rule
194
+ # ref : Vlad Lobodin manuscript to be include here
195
+
196
+ # atoms_exchanges = ['N']
197
+ # if 'O' in classe_dict.keys():
198
+ #
199
+ # Oxygen_number = classe_dict.get("O")
200
+ # for atom in atoms_exchanges:
201
+ # if atom in classe_dict.keys():
202
+ # Oxygen_number += classe_dict.get(atom)
203
+ #
204
+ # self.mass_spectrum_obj.molecular_search_settings.min_dbe = (Oxygen_number/3) - 0.5
205
+ # self.mass_spectrum_obj.molecular_search_settings.max_dbe = Oxygen_number*3 + 0.5 + 2
206
+ #
207
+ # else:
208
+
209
+ self.mass_spectrum_obj.molecular_search_settings.use_pah_line_rule = True
210
+
211
+ def run_search(possible_formulas_dict, mass_spectrum_obj, min_abundance):
212
+ """Run the molecular formula search for each mass spectrum peak.
213
+
214
+ Parameters
215
+ ----------
216
+ possible_formulas_dict : dict
217
+ A dictionary of possible molecular formulas.
218
+ mass_spectrum_obj : MassSpectrum
219
+ The mass spectrum object.
220
+ min_abundance : float
221
+ The minimum abundance threshold.
222
+
223
+ Returns
224
+ -------
225
+ list
226
+ A list of assigned peak indexes.
227
+ """
228
+ all_assigned_indexes = list()
229
+
230
+ for ms_peak in mass_spectrum_obj.sort_by_abundance():
231
+ if ms_peak:
232
+ continue
233
+ # already assigned a molecular formula
234
+
235
+ nominal_mz = ms_peak.nominal_mz_exp
236
+
237
+ # get mono isotopic peaks that was added a molecular formula obj
238
+ # TODO update error variables
239
+
240
+ possible_formulas_nominal = possible_formulas_dict.get(nominal_mz)
241
+
242
+ if possible_formulas_nominal:
243
+ ms_peak_indexes = SearchMolecularFormulaWorker().find_formulas(
244
+ possible_formulas_nominal,
245
+ min_abundance,
246
+ mass_spectrum_obj,
247
+ ms_peak,
248
+ )
249
+
250
+ all_assigned_indexes.extend(ms_peak_indexes)
251
+
252
+ # filter peaks by percentile threshold of found isotopologues
253
+ all_assigned_indexes = MolecularFormulaSearchFilters().filter_isotopologue(
254
+ all_assigned_indexes, mass_spectrum_obj
255
+ )
256
+
257
+ # filter noise by kendrick density
258
+ all_assigned_indexes = MolecularFormulaSearchFilters().filter_kendrick(
259
+ all_assigned_indexes, mass_spectrum_obj
260
+ )
261
+
262
+ # filter per min peaks per mono isotopic class
263
+ # this function should always be the last filter,
264
+ # thefore no need to return remaining indexes
265
+ MolecularFormulaSearchFilters().check_min_peaks(
266
+ all_assigned_indexes, mass_spectrum_obj
267
+ )
268
+
269
+ # error_average = self.mass_spectrum_obj.molecular_search_settings.mz_error_average
270
+
271
+ kmd_base = self.mass_spectrum_obj.mspeaks_settings.kendrick_base
272
+
273
+ self.mass_spectrum_obj.change_kendrick_base_all_mspeaks(kmd_base)
274
+
275
+ ClusteringFilter().filter_kendrick(self.mass_spectrum_obj)
276
+
277
+ min_abundance = self.mass_spectrum_obj.min_abundance
278
+
279
+ list_classes_str = [i[0] for i in assign_classes_order_tuples]
280
+ verbose = self.mass_spectrum_obj.parameters.mass_spectrum.verbose_processing
281
+ pbar = tqdm.tqdm(assign_classes_order_tuples, disable= not verbose)
282
+ dict_molecular_lookup_table = self.get_dict_molecular_database(list_classes_str)
283
+
284
+ for classe_tuple in pbar:
285
+ classe_str = classe_tuple[0]
286
+ classe_dict = classe_tuple[1]
287
+
288
+ set_min_max_dbe_by_oxygen(classe_dict)
289
+
290
+ # if len(classe_dict.keys()) == 2:
291
+ # if classe_dict.get('S') == 1:
292
+ # continue
293
+ # limits the dbe by the Ox class most abundant,
294
+ # need to add other atoms contribution to be more accurate
295
+ # but +-7 should be sufficient to cover the range
296
+
297
+ if self.mass_spectrum_obj.molecular_search_settings.isProtonated:
298
+ # tqdm.set_description_str(desc=None, refresh=True)
299
+ if verbose:
300
+ pbar.set_description_str(
301
+ desc="Started molecular formula search for class %s, (de)protonated "
302
+ % classe_str,
303
+ refresh=True,
304
+ )
305
+
306
+ ion_type = Labels.protonated_de_ion
307
+
308
+ possible_formulas_dict = dict_molecular_lookup_table.get(ion_type).get(
309
+ classe_str
310
+ )
311
+
312
+ if possible_formulas_dict:
313
+ run_search(
314
+ possible_formulas_dict, self.mass_spectrum_obj, min_abundance
315
+ )
316
+
317
+ if self.mass_spectrum_obj.molecular_search_settings.isRadical:
318
+ # print("Started molecular formula search for class %s, radical" % classe_str)
319
+ if verbose:
320
+ pbar.set_description_str(
321
+ desc="Started molecular formula search for class %s, radical"
322
+ % classe_str,
323
+ refresh=True,
324
+ )
325
+
326
+ ion_type = Labels.radical_ion
327
+
328
+ possible_formulas_dict = dict_molecular_lookup_table.get(ion_type).get(
329
+ classe_str
330
+ )
331
+
332
+ if possible_formulas_dict:
333
+ run_search(
334
+ possible_formulas_dict, self.mass_spectrum_obj, min_abundance
335
+ )
336
+
337
+ # looks for adduct, used_atom_valences should be 0
338
+ # this code does not support H exchance by halogen atoms
339
+ if self.mass_spectrum_obj.molecular_search_settings.isAdduct:
340
+ if verbose:
341
+ pbar.set_description_str(
342
+ desc="Started molecular formula search for class %s, adduct"
343
+ % classe_str,
344
+ refresh=True,
345
+ )
346
+ # print("Started molecular formula search for class %s, adduct" % classe_str)
347
+
348
+ ion_type = Labels.radical_ion
349
+
350
+ possible_formulas_dict = dict_molecular_lookup_table.get(ion_type).get(
351
+ classe_str
352
+ )
353
+
354
+ """ commenting unfinished code for release 2.0, see end of file for details"""
355
+ # possible_formulas_adduct =self.add_adducts(possible_formulas_dict)
356
+
357
+ # if possible_formulas_adduct:
358
+
359
+ run_search(
360
+ possible_formulas_dict, self.mass_spectrum_obj, min_abundance
361
+ )
362
+
363
+ def get_dict_molecular_database(self, classe_str_list):
364
+ """Get the molecular database as a dictionary.
365
+
366
+ Parameters
367
+ ----------
368
+ classe_str_list : list
369
+ A list of class names.
370
+
371
+ Returns
372
+ -------
373
+ dict
374
+ A dictionary containing the molecular database.
375
+ """
376
+ nominal_mzs = self.nominal_mzs
377
+ mf_search_settings = self.mass_spectrum_obj.molecular_search_settings
378
+ ion_charge = self.mass_spectrum_obj.polarity
379
+
380
+ sql_db = MolForm_SQL(url=mf_search_settings.url_database)
381
+
382
+ dict_res = {}
383
+
384
+ if mf_search_settings.isProtonated:
385
+ dict_res[Labels.protonated_de_ion] = sql_db.get_dict_by_classes(
386
+ classe_str_list,
387
+ Labels.protonated_de_ion,
388
+ nominal_mzs,
389
+ ion_charge,
390
+ mf_search_settings,
391
+ )
392
+
393
+ if mf_search_settings.isRadical:
394
+ dict_res[Labels.radical_ion] = sql_db.get_dict_by_classes(
395
+ classe_str_list,
396
+ Labels.radical_ion,
397
+ nominal_mzs,
398
+ ion_charge,
399
+ mf_search_settings,
400
+ )
401
+
402
+ if mf_search_settings.isAdduct:
403
+ adduct_list = (
404
+ mf_search_settings.adduct_atoms_neg
405
+ if ion_charge < 0
406
+ else mf_search_settings.adduct_atoms_pos
407
+ )
408
+ dict_res[Labels.adduct_ion] = sql_db.get_dict_by_classes(
409
+ classe_str_list,
410
+ Labels.adduct_ion,
411
+ nominal_mzs,
412
+ ion_charge,
413
+ mf_search_settings,
414
+ adducts=adduct_list,
415
+ )
416
+
417
+ return dict_res
418
+
419
+ def ox_classes_and_peaks_in_order_(self) -> dict:
420
+ """Get the oxygen classes and associated peaks in order.
421
+
422
+ Returns
423
+ -------
424
+ dict
425
+ A dictionary containing the oxygen classes and associated peaks.
426
+ """
427
+ # order is only valid in python 3.4 and above
428
+ # change to OrderedDict if your version is lower
429
+ dict_ox_class_and_ms_peak = dict()
430
+
431
+ for mspeak in self.mass_spectrum_obj.sort_by_abundance(reverse=True):
432
+ # change this filter to cia filter, give more option here, confidence, number of isotopologue found etc
433
+
434
+ ox_classe = mspeak.best_molecular_formula_candidate.class_label
435
+
436
+ if ox_classe in dict_ox_class_and_ms_peak.keys():
437
+ # get the most abundant of the same ox class
438
+ if mspeak.abundance > dict_ox_class_and_ms_peak[ox_classe].abundance:
439
+ dict_ox_class_and_ms_peak[ox_classe] = mspeak
440
+ else:
441
+ dict_ox_class_and_ms_peak[ox_classe] = mspeak
442
+
443
+ return dict_ox_class_and_ms_peak
444
+
445
+ def get_classes_in_order(self, dict_ox_class_and_ms_peak) -> [(str, dict)]:
446
+ """Get the classes in order.
447
+
448
+ Parameters
449
+ ----------
450
+ dict_ox_class_and_ms_peak : dict
451
+ A dictionary containing the oxygen classes and associated peaks.
452
+
453
+ Returns
454
+ -------
455
+ list
456
+ A list of tuples containing the class names and dictionaries of class attributes.
457
+
458
+ Notes
459
+ -----
460
+ structure is
461
+ ('HC', {'HC': 1})
462
+ """
463
+
464
+ usedAtoms = deepcopy(self.mass_spectrum_obj.molecular_search_settings.usedAtoms)
465
+
466
+ usedAtoms.pop("C")
467
+ usedAtoms.pop("H")
468
+ usedAtoms.pop("O")
469
+
470
+ min_n, max_n = usedAtoms.get("N") if usedAtoms.get("N") else (0, 0)
471
+ min_s, max_s = usedAtoms.get("S") if usedAtoms.get("S") else (0, 0)
472
+ min_p, max_p = usedAtoms.get("P") if usedAtoms.get("P") else (0, 0)
473
+
474
+ possible_n = [n for n in range(min_n, max_n + 1)]
475
+ possible_s = [s for s in range(min_s, max_s + 1)]
476
+ possible_p = [p for p in range(min_p, max_p + 1)]
477
+
478
+ # used to enforce order for commum atoms
479
+ # and track the atom index in on the tuple in all_atoms_tuples
480
+ atoms_in_order = ["N", "S", "P"]
481
+
482
+ # do number atoms prodcut and remove then from the usedAtoms dict
483
+ all_atoms_tuples = product(possible_n, possible_s, possible_p)
484
+ for atom in atoms_in_order:
485
+ usedAtoms.pop(atom, None)
486
+
487
+ # iterate over other atoms besides C,H, N, O, S and P
488
+
489
+ for selected_atom_label, min_max_tuple in usedAtoms.items():
490
+ min_x = min_max_tuple[0]
491
+ max_x = min_max_tuple[1]
492
+
493
+ possible_x = [x for x in range(min_x, max_x + 1)]
494
+ all_atoms_tuples = product(all_atoms_tuples, possible_x)
495
+
496
+ # merge tuples
497
+ all_atoms_tuples = [
498
+ all_atoms_combined[0] + (all_atoms_combined[1],)
499
+ for all_atoms_combined in all_atoms_tuples
500
+ ]
501
+
502
+ # add atom label to the atoms_in_order list
503
+
504
+ # important to index where the atom position is in on the tuple in all_atoms_tuples
505
+ atoms_in_order.append(selected_atom_label)
506
+
507
+ classes_strings_dict_tuples, hc_class = self.get_class_strings_dict(
508
+ all_atoms_tuples, atoms_in_order
509
+ )
510
+
511
+ combined_classes = self.combine_ox_class_with_other(
512
+ atoms_in_order, classes_strings_dict_tuples, dict_ox_class_and_ms_peak
513
+ )
514
+
515
+ combination_classes_ordered = self.sort_classes(
516
+ atoms_in_order, combined_classes
517
+ )
518
+
519
+ oxygen_class_str_dict_tuple = [
520
+ (ox_class, mspeak[0].class_dict)
521
+ for ox_class, mspeak in dict_ox_class_and_ms_peak.items()
522
+ ]
523
+
524
+ ## add classes together and ignores classes selected from the main series
525
+ for class_tuple in combination_classes_ordered:
526
+ if class_tuple not in oxygen_class_str_dict_tuple:
527
+ oxygen_class_str_dict_tuple.append(class_tuple)
528
+
529
+ return oxygen_class_str_dict_tuple
530
+
531
+ @staticmethod
532
+ def get_class_strings_dict(all_atoms_tuples, atoms_in_order) -> [(str, dict)]:
533
+ """Get the class strings and dictionaries.
534
+
535
+ Parameters
536
+ ----------
537
+ all_atoms_tuples : tuple
538
+ A tuple containing the atoms.
539
+ atoms_in_order : list
540
+ A list of atoms in order.
541
+
542
+ Returns
543
+ --------
544
+ list
545
+ A list of tuples containing the class strings and dictionaries.
546
+
547
+ """
548
+ classe_list = []
549
+ hc_class = []
550
+
551
+ for all_atoms_tuple in all_atoms_tuples:
552
+ classe_str = ""
553
+ classe_dict = dict()
554
+
555
+ for each_atoms_index, atoms_number in enumerate(all_atoms_tuple):
556
+ if atoms_number != 0:
557
+ classe_str = (
558
+ classe_str
559
+ + atoms_in_order[each_atoms_index]
560
+ + str(atoms_number)
561
+ + " "
562
+ )
563
+
564
+ classe_dict[atoms_in_order[each_atoms_index]] = atoms_number
565
+
566
+ classe_str = classe_str.strip()
567
+
568
+ if len(classe_str) > 0:
569
+ classe_list.append((classe_str, classe_dict))
570
+
571
+ elif len(classe_str) == 0:
572
+ hc_class.append(("HC", {"HC": 1}))
573
+
574
+ return classe_list, hc_class
575
+
576
+ @staticmethod
577
+ def combine_ox_class_with_other(
578
+ atoms_in_order, classes_strings_dict_tuples, dict_ox_class_and_ms_peak
579
+ ) -> [dict]:
580
+ """Combine the oxygen classes with other classes.
581
+
582
+ Parameters
583
+ ----------
584
+ atoms_in_order : list
585
+ A list of atoms in order.
586
+ classes_strings_dict_tuples : list
587
+
588
+ dict_ox_class_and_ms_peak : dict
589
+ A dictionary containing the oxygen classes and associated peaks.
590
+
591
+ Returns
592
+ -------
593
+ list
594
+ A list of dictionaries.
595
+ """
596
+ # sort methods that uses the key of classes dictionary and the atoms_in_order as reference
597
+ # c_tuple[1] = class_dict, because is one key:value map we loop through keys and get the first item only
598
+ # sort by len first then sort based on the atoms_in_order list
599
+ atoms_in_order = Atoms.atoms_order
600
+
601
+ Oxygen_mfs = dict_ox_class_and_ms_peak.values()
602
+
603
+ # sort_method = lambda word: (len(word[0]), [atoms_in_order.index(atom) for atom in list( word[1].keys())])
604
+
605
+ # print(classes_strings_dict_tuples)
606
+ # classe_in_order = sorted(classes_strings_dict_tuples, key = sort_method)
607
+ # print(classe_in_order)
608
+
609
+ combination = []
610
+
611
+ # _ ignoring the class_str
612
+ for _, other_classe_dict in classes_strings_dict_tuples:
613
+ # combination.extend([[other_classe_str + ' ' + Oxygen_mf[0].class_label , {**other_classe_dict, **Oxygen_mf[0].class_dict}] for Oxygen_mf in Oxygen_mfs])
614
+ combination.extend(
615
+ [
616
+ {**other_classe_dict, **Oxygen_mf[0].class_dict}
617
+ for Oxygen_mf in Oxygen_mfs
618
+ ]
619
+ )
620
+
621
+ return combination
622
+
623
+ @staticmethod
624
+ def sort_classes(atoms_in_order, combination_tuples) -> [(str, dict)]:
625
+ """Sort the classes.
626
+
627
+ Parameters
628
+ ----------
629
+ atoms_in_order : list
630
+ A list of atoms in order.
631
+ combination_tuples : list
632
+
633
+ Returns
634
+ -------
635
+ list
636
+ A list of tuples containing the class strings and dictionaries.
637
+ """
638
+ join_list_of_list_classes = list()
639
+ atoms_in_order = ["N", "S", "P", "O"] + atoms_in_order[3:]
640
+
641
+ sort_method = (
642
+ lambda atoms_keys: [atoms_in_order.index(atoms_keys)]
643
+ ) # (len(word[0]), print(word[1]))#[atoms_in_order.index(atom) for atom in list( word[1].keys())])
644
+ for class_dict in combination_tuples:
645
+ sorted_dict_keys = sorted(class_dict, key=sort_method)
646
+ class_str = " ".join(
647
+ [atom + str(class_dict[atom]) for atom in sorted_dict_keys]
648
+ )
649
+ new_class_dict = {atom: class_dict[atom] for atom in sorted_dict_keys}
650
+ join_list_of_list_classes.append((class_str, new_class_dict))
651
+
652
+ return join_list_of_list_classes
653
+
654
+ '''
655
+ The code bellow is unfinished, might be added to next release, 2.1
656
+ def add_adducts(self, possible_formulas):
657
+ """ Add adducts to the molecular formula candidates.
658
+
659
+ Parameters
660
+ ----------
661
+ possible_formulas : dict
662
+ A dictionary of possible molecular formulas.
663
+
664
+ Returns
665
+ -------
666
+ dict
667
+ A dictionary of possible molecular formulas with adducts.
668
+
669
+ """
670
+ ion_type = Labels.adduct_ion
671
+
672
+ if self.mass_spectrum_obj.polarity < 0:
673
+ adduct_atoms = self.mass_spectrum_obj.molecular_search_settings.adduct_atoms_neg
674
+ molform_model = MolecularFormulaDict
675
+ else:
676
+ adduct_atoms = self.mass_spectrum_obj.molecular_search_settings.adduct_atoms_pos
677
+ molform_model = MolecularFormulaTablePos
678
+
679
+ new_dict = {}
680
+
681
+ for nominal_mz, list_formulas in possible_formulas.items():
682
+
683
+ for adduct_atom in adduct_atoms:
684
+
685
+ adduct_atom_mass= Atoms.atomic_masses.get(adduct_atom)
686
+
687
+ for molecularFormulaTable in list_formulas:
688
+
689
+ formula_dict = json.loads(molecularFormulaTable.mol_formula)
690
+
691
+ if adduct_atom in formula_dict.keys():
692
+ formula_dict[adduct_atom] += 1
693
+ else:
694
+ formula_dict[adduct_atom] = 1
695
+
696
+ mz = adduct_atom_mass + molecularFormulaTable.mz
697
+ nm = int(mz)
698
+
699
+ new_formul_obj = molform_model( **{"mol_formula" : json.dumps(formula_dict),
700
+ "mz" : mz,
701
+ "ion_type" : ion_type,
702
+ "nominal_mz" : nm,
703
+ "ion_charge" : molecularFormulaTable.ion_charge,
704
+ "classe" : molecularFormulaTable.classe,
705
+ "C" : molecularFormulaTable.C,
706
+ "H" : molecularFormulaTable.H,
707
+ "N" : molecularFormulaTable.N,
708
+ "O" : molecularFormulaTable.O,
709
+ "S" : molecularFormulaTable.S,
710
+ "P" : molecularFormulaTable.P,
711
+ "H_C" : molecularFormulaTable.H_C,
712
+ "O_C" : molecularFormulaTable.O_C,
713
+ "DBE" : molecularFormulaTable.DBE,
714
+ })
715
+ if nm in new_dict:
716
+ new_dict[nm].append(new_formul_obj)
717
+
718
+ else:
719
+ new_dict[nm]= [new_formul_obj]
720
+
721
+ return new_dict
722
+
723
+ '''