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,827 @@
1
+ import sys
2
+
3
+ import json
4
+ import os
5
+
6
+ import tqdm
7
+ from sqlalchemy import (
8
+ Column,
9
+ Float,
10
+ ForeignKey,
11
+ Integer,
12
+ String,
13
+ and_,
14
+ create_engine,
15
+ event,
16
+ exc,
17
+ func,
18
+ )
19
+ from sqlalchemy.exc import SQLAlchemyError
20
+ from sqlalchemy.ext.associationproxy import association_proxy
21
+ from sqlalchemy.orm import declarative_base
22
+ from sqlalchemy.ext.hybrid import hybrid_method, hybrid_property
23
+ from sqlalchemy.orm import backref, relationship
24
+ from sqlalchemy.orm.scoping import scoped_session
25
+ from sqlalchemy.orm.session import sessionmaker
26
+ from sqlalchemy.sql.operators import exists
27
+ from sqlalchemy.sql.schema import UniqueConstraint
28
+
29
+ from corems.encapsulation.constant import Atoms, Labels
30
+
31
+ Base = declarative_base()
32
+
33
+
34
+ class HeteroAtoms(Base):
35
+ """HeteroAtoms class for the heteroAtoms table in the SQLite database.
36
+
37
+ Attributes
38
+ ----------
39
+ id : int
40
+ The primary key for the table.
41
+ name : str
42
+ The name of the heteroAtoms class.
43
+ halogensCount : int
44
+ The number of halogens in the heteroAtoms class.
45
+ carbonHydrogen : relationship
46
+ The relationship to the carbonHydrogen table.
47
+
48
+ Methods
49
+ -------
50
+ * __repr__()
51
+ Returns the string representation of the object.
52
+ * to_dict()
53
+ Returns the heteroAtoms class as a dictionary.
54
+ * halogens_count()
55
+ Returns the number of halogens as a float.
56
+
57
+
58
+ """
59
+
60
+ __tablename__ = "heteroAtoms"
61
+
62
+ id = Column(Integer, primary_key=True, unique=True, nullable=False)
63
+
64
+ name = Column(String, unique=True, nullable=False)
65
+
66
+ halogensCount = Column(Integer, unique=False, nullable=False)
67
+
68
+ carbonHydrogen = relationship(
69
+ "CarbonHydrogen", secondary="molecularformula", viewonly=True
70
+ )
71
+
72
+ def __repr__(self):
73
+ return "<HeteroAtoms Model {} class {}>".format(self.id, self.name)
74
+
75
+ @hybrid_property
76
+ def halogens_count(cls):
77
+ """Returns the number of halogens as a float."""
78
+ return cls.halogensCount.cast(Float)
79
+
80
+ def to_dict(self):
81
+ """Returns the heteroAtoms class as a dictionary."""
82
+ return json.loads(self.name)
83
+
84
+
85
+ class CarbonHydrogen(Base):
86
+ """CarbonHydrogen class for the carbonHydrogen table in the SQLite database.
87
+
88
+ Attributes
89
+ ----------
90
+ id : int
91
+ The primary key for the table.
92
+ C : int
93
+ The number of carbon atoms.
94
+ H : int
95
+ The number of hydrogen atoms.
96
+ heteroAtoms : relationship
97
+ The relationship to the heteroAtoms table.
98
+
99
+ Methods
100
+ -------
101
+ * __repr__()
102
+ Returns the string representation of the object.
103
+ * mass()
104
+ Returns the mass of the carbonHydrogen class as a float.
105
+ * c()
106
+ Returns the number of carbon atoms as a float.
107
+ * h()
108
+ Returns the number of hydrogen atoms as a float.
109
+ * dbe()
110
+ Returns the double bond equivalent as a float.
111
+
112
+ """
113
+
114
+ __tablename__ = "carbonHydrogen"
115
+ __table_args__ = (UniqueConstraint("C", "H", name="unique_c_h"),)
116
+
117
+ id = Column(Integer, primary_key=True, unique=True, nullable=False)
118
+
119
+ C = Column(Integer, nullable=False)
120
+
121
+ H = Column(Integer, nullable=False)
122
+
123
+ heteroAtoms = relationship(
124
+ "HeteroAtoms", secondary="molecularformula", viewonly=True
125
+ )
126
+
127
+ def __repr__(self):
128
+ """Returns the string representation of the object."""
129
+ return "<CarbonHydrogen Model {} C{} H{}>".format(self.id, self.C, self.H)
130
+
131
+ @property
132
+ def mass(self):
133
+ """Returns the mass of the carbonHydrogen class as a float."""
134
+ return (self.C * Atoms.atomic_masses.get("C")) + (
135
+ self.H * Atoms.atomic_masses.get("H")
136
+ )
137
+
138
+ @hybrid_property
139
+ def c(cls):
140
+ """Returns the number of carbon atoms as a float."""
141
+ return cls.C.cast(Float)
142
+
143
+ @hybrid_property
144
+ def h(cls):
145
+ """Returns the number of hydrogen atoms as a float."""
146
+ return cls.H.cast(Float)
147
+
148
+ @hybrid_property
149
+ def dbe(cls):
150
+ """Returns the double bond equivalent as a float."""
151
+ # return cls.C.cast(Float) - (cls.H.cast(Float) / 2) + 1
152
+ return float(cls.C) - float(cls.H / 2) + 1
153
+
154
+
155
+ # 264888.88 ms
156
+ class MolecularFormulaLink(Base):
157
+ """MolecularFormulaLink class for the molecularformula table in the SQLite database.
158
+
159
+ Attributes
160
+ ----------
161
+ heteroAtoms_id : int
162
+ The foreign key for the heteroAtoms table.
163
+ carbonHydrogen_id : int
164
+ The foreign key for the carbonHydrogen table.
165
+ mass : float
166
+ The mass of the molecular formula.
167
+ DBE : float
168
+ The double bond equivalent of the molecular formula.
169
+ carbonHydrogen : relationship
170
+ The relationship to the carbonHydrogen table.
171
+ heteroAtoms : relationship
172
+ The relationship to the heteroAtoms table.
173
+ C : association_proxy
174
+ The association proxy for the carbonHydrogen table.
175
+ H : association_proxy
176
+ The association proxy for the carbonHydrogen table.
177
+ classe : association_proxy
178
+ The association proxy for the heteroAtoms table.
179
+
180
+ Methods
181
+ -------
182
+ * __repr__()
183
+ Returns the string representation of the object.
184
+ * to_dict()
185
+ Returns the molecular formula as a dictionary.
186
+ * formula_string()
187
+ Returns the molecular formula as a string.
188
+ * classe_string()
189
+ Returns the heteroAtoms class as a string.
190
+ * _adduct_mz(ion_charge, adduct_atom)
191
+ Returns the m/z of the adduct ion as a float.
192
+ * _protonated_mz(ion_charge)
193
+ Returns the m/z of the protonated ion as a float.
194
+ * _radical_mz(ion_charge)
195
+ Returns the m/z of the radical ion as a float.
196
+
197
+
198
+
199
+ """
200
+
201
+ __tablename__ = "molecularformula"
202
+ __table_args__ = (
203
+ UniqueConstraint("heteroAtoms_id", "carbonHydrogen_id", name="unique_molform"),
204
+ )
205
+
206
+ # id = Column(Integer, primary_key=True,
207
+ # unique=True,
208
+ # nullable=False)
209
+
210
+ heteroAtoms_id = Column(Integer, ForeignKey("heteroAtoms.id"), primary_key=True)
211
+
212
+ carbonHydrogen_id = Column(
213
+ Integer, ForeignKey("carbonHydrogen.id"), primary_key=True
214
+ )
215
+
216
+ mass = Column(Float)
217
+
218
+ DBE = Column(Float)
219
+
220
+ carbonHydrogen = relationship(CarbonHydrogen, backref=backref("heteroAtoms_assoc"))
221
+
222
+ heteroAtoms = relationship(HeteroAtoms, backref=backref("carbonHydrogen_assoc"))
223
+
224
+ C = association_proxy("carbonHydrogen", "C")
225
+
226
+ H = association_proxy("carbonHydrogen", "H")
227
+
228
+ classe = association_proxy("heteroAtoms", "name")
229
+
230
+ def to_dict(self):
231
+ """Returns the molecular formula as a dictionary.
232
+
233
+ Returns
234
+ -------
235
+ dict
236
+ The molecular formula as a dictionary.
237
+ """
238
+ carbon = {"C": self.C, "H": self.H}
239
+ classe = json.loads(self.classe)
240
+ if self.classe == '{"HC": ""}':
241
+ return {**carbon}
242
+ else:
243
+ return {**carbon, **classe}
244
+
245
+ @property
246
+ def formula_string(self):
247
+ """Returns the molecular formula as a string."""
248
+ class_dict = self.to_dict()
249
+ class_str = " ".join(
250
+ [atom + str(class_dict[atom]) for atom in class_dict.keys()]
251
+ )
252
+ return class_str.strip()
253
+
254
+ @property
255
+ def classe_string(self):
256
+ """Returns the heteroAtoms class as a string."""
257
+ class_dict = json.loads(self.classe)
258
+ class_str = " ".join(
259
+ [atom + str(class_dict[atom]) for atom in class_dict.keys()]
260
+ )
261
+ return class_str.strip()
262
+
263
+ @hybrid_method
264
+ def _adduct_mz(self, ion_charge, adduct_atom):
265
+ """Returns the m/z of the adduct ion as a float."""
266
+ return (
267
+ self.mass
268
+ + (Atoms.atomic_masses.get(adduct_atom))
269
+ + (ion_charge * -1 * Atoms.electron_mass)
270
+ ) / abs(ion_charge)
271
+
272
+ @hybrid_method
273
+ def _protonated_mz(self, ion_charge):
274
+ """Returns the m/z of the protonated ion as a float."""
275
+ return (
276
+ self.mass
277
+ + (ion_charge * Atoms.atomic_masses.get("H"))
278
+ + (ion_charge * -1 * Atoms.electron_mass)
279
+ ) / abs(ion_charge)
280
+
281
+ @hybrid_method
282
+ def _radical_mz(self, ion_charge):
283
+ """Returns the m/z of the radical ion as a float."""
284
+ return (self.mass + (ion_charge * -1 * Atoms.electron_mass)) / abs(ion_charge)
285
+
286
+ def __repr__(self):
287
+ """Returns the string representation of the object."""
288
+ return "<MolecularFormulaLink Model {}>".format(self.formula_string)
289
+
290
+
291
+ class MolForm_SQL:
292
+ """MolForm_SQL class for the SQLite database.
293
+
294
+ Attributes
295
+ ----------
296
+ engine : sqlalchemy.engine.base.Engine
297
+ The SQLAlchemy engine.
298
+ session : sqlalchemy.orm.session.Session
299
+ The SQLAlchemy session.
300
+ type : str
301
+ The type of database.
302
+ chunks_count : int
303
+ The number of chunks to use when querying the database.
304
+
305
+ Methods
306
+ -------
307
+ * __init__(url=None, echo=False)
308
+ Initializes the database.
309
+ * __exit__(exc_type, exc_val, exc_tb)
310
+ Closes the database.
311
+ * initiate_database(url, database_name)
312
+ Creates the database.
313
+ * commit()
314
+ Commits the session.
315
+ * init_engine(url)
316
+ Initializes the SQLAlchemy engine.
317
+ * __enter__()
318
+
319
+ * get_dict_by_classes(classes, ion_type, nominal_mzs, ion_charge, molecular_search_settings, adducts=None)
320
+ Returns a dictionary of molecular formulas.
321
+ * check_entry(classe, ion_type, molecular_search_settings)
322
+ Checks if a molecular formula is in the database.
323
+ * get_all_classes()
324
+ Returns a list of all classes in the database.
325
+ * get_all()
326
+ Returns a list of all molecular formulas in the database.
327
+ * delete_entry(row)
328
+ Deletes a molecular formula from the database.
329
+ * purge(cls)
330
+ Deletes all molecular formulas from the database.
331
+ * clear_data()
332
+ Clears the database.
333
+ * close(commit=True)
334
+ Closes the database.
335
+ * add_engine_pidguard(engine)
336
+ Adds multiprocessing guards.
337
+
338
+ """
339
+
340
+ def __init__(self, url=None, echo=False):
341
+ self.engine = self.init_engine(url)
342
+
343
+ self.add_engine_pidguard(self.engine)
344
+
345
+ session_factory = sessionmaker(bind=self.engine)
346
+
347
+ Session = scoped_session(session_factory)
348
+
349
+ self.session = session_factory()
350
+
351
+ Base.metadata.create_all(self.engine)
352
+
353
+ self.session.commit()
354
+
355
+ def __exit__(self, exc_type, exc_val, exc_tb):
356
+ """Closes the database.
357
+
358
+ Parameters
359
+ ----------
360
+ exc_type : str
361
+ The exception type.
362
+ exc_val : str
363
+ The exception value.
364
+ exc_tb : str
365
+ The exception traceback.
366
+ """
367
+ # make sure the dbconnection gets closed
368
+
369
+ self.commit()
370
+ self.session.close()
371
+ self.engine.dispose()
372
+
373
+ def initiate_database(self, url, database_name): # CREATION
374
+ """Creates the database.
375
+
376
+ Parameters
377
+ ----------
378
+ url : str
379
+ The URL for the database.
380
+ database_name : str
381
+ The name of the database.
382
+ """
383
+ engine = create_engine(url)
384
+ conn = engine.connect()
385
+ conn.execute("commit")
386
+ conn.execute("create database " + database_name)
387
+ conn.close()
388
+
389
+ def commit(self):
390
+ """Commits the session."""
391
+ try:
392
+ self.session.commit()
393
+ except SQLAlchemyError as e:
394
+ self.session.rollback()
395
+ print(str(e))
396
+
397
+ def init_engine(self, url):
398
+ """Initializes the SQLAlchemy engine.
399
+
400
+ Parameters
401
+ ----------
402
+ url : str
403
+ The URL for the database.
404
+
405
+ Returns
406
+ -------
407
+ sqlalchemy.engine.base.Engine
408
+ The SQLAlchemy engine.
409
+
410
+ """
411
+ if not url or url == "None" or url == "False":
412
+ directory = os.getcwd()
413
+
414
+ if not os.path.isdir(directory + "/db"):
415
+ os.mkdir(directory + "/db")
416
+
417
+ url = "sqlite:///{DB}/db/molformulas.sqlite".format(DB=directory)
418
+
419
+ if url[0:6] == "sqlite":
420
+ self.type = "sqlite"
421
+ else:
422
+ self.type = "normal"
423
+
424
+ if url[0:6] == "sqlite":
425
+ engine = create_engine(url, echo=False)
426
+ self.chunks_count = 50
427
+
428
+ elif url[0:10] == "postgresql" or url[0:8] == "postgres":
429
+ # postgresql
430
+ self.chunks_count = 50000
431
+ engine = create_engine(url, echo=False, isolation_level="AUTOCOMMIT")
432
+
433
+ return engine # poolclass=NullPool
434
+
435
+ def __enter__(self):
436
+ """Returns the object."""
437
+ return self
438
+
439
+ def get_dict_by_classes(
440
+ self,
441
+ classes,
442
+ ion_type,
443
+ nominal_mzs,
444
+ ion_charge,
445
+ molecular_search_settings,
446
+ adducts=None,
447
+ ):
448
+ """Returns a dictionary of molecular formulas.
449
+
450
+ Parameters
451
+ ----------
452
+ classes : list
453
+ The list of classes.
454
+ ion_type : str
455
+ The ion type.
456
+ nominal_mzs : list
457
+ The list of nominal m/z values.
458
+ ion_charge : int
459
+ The ion charge.
460
+ molecular_search_settings : MolecularFormulaSearchSettings
461
+ The molecular formula search settings.
462
+ adducts : list, optional
463
+ The list of adducts. Default is None.
464
+
465
+ Returns
466
+ -------
467
+ dict
468
+ The dictionary of molecular formulas.
469
+
470
+ Notes
471
+ -----
472
+ Known issue, when using SQLite:
473
+ if the number of classes and nominal_m/zs are higher than 999 the query will fail
474
+ Solution: use postgres or split query
475
+ """
476
+ verbose = molecular_search_settings.verbose_processing
477
+
478
+ def query_normal(class_list, len_adduct):
479
+ """query for normal database
480
+
481
+ Parameters
482
+ ----------
483
+ class_list : list
484
+ The list of classes.
485
+ len_adduct : int
486
+ The length of the adduct.
487
+
488
+ Returns
489
+ -------
490
+ sqlalchemy.orm.query.Query
491
+ The query.
492
+ """
493
+ base_query = (
494
+ self.session.query(MolecularFormulaLink, CarbonHydrogen, HeteroAtoms)
495
+ .filter(MolecularFormulaLink.carbonHydrogen_id == CarbonHydrogen.id)
496
+ .filter(MolecularFormulaLink.heteroAtoms_id == HeteroAtoms.id)
497
+ )
498
+
499
+ return base_query.filter(
500
+ and_(
501
+ HeteroAtoms.name.in_(class_list),
502
+ and_(
503
+ MolecularFormulaLink.DBE >= molecular_search_settings.min_dbe,
504
+ MolecularFormulaLink.DBE <= molecular_search_settings.max_dbe,
505
+ and_(
506
+ (
507
+ (
508
+ CarbonHydrogen.h
509
+ + HeteroAtoms.halogens_count
510
+ - len_adduct
511
+ )
512
+ / CarbonHydrogen.c
513
+ )
514
+ >= molecular_search_settings.min_hc_filter,
515
+ (
516
+ (
517
+ CarbonHydrogen.h
518
+ + HeteroAtoms.halogens_count
519
+ - len_adduct
520
+ )
521
+ / CarbonHydrogen.c
522
+ )
523
+ <= molecular_search_settings.max_hc_filter,
524
+ CarbonHydrogen.C
525
+ >= molecular_search_settings.usedAtoms.get("C")[0],
526
+ CarbonHydrogen.c
527
+ <= molecular_search_settings.usedAtoms.get("C")[1],
528
+ CarbonHydrogen.h
529
+ >= molecular_search_settings.usedAtoms.get("H")[0],
530
+ CarbonHydrogen.h
531
+ <= molecular_search_settings.usedAtoms.get("H")[1],
532
+ ),
533
+ ),
534
+ )
535
+ )
536
+
537
+ def add_dict_formula(formulas, ion_type, ion_charge, adduct_atom=None):
538
+ """add molecular formula to dict
539
+
540
+ Parameters
541
+ ----------
542
+ formulas : sqlalchemy.orm.query.Query
543
+ The query.
544
+ ion_type : str
545
+ The ion type.
546
+ ion_charge : int
547
+ The ion charge.
548
+ adduct_atom : str, optional
549
+ The adduct atom. Default is None.
550
+
551
+ Returns
552
+ -------
553
+ dict
554
+ The dictionary of molecular formulas.
555
+
556
+ """
557
+ "organize data by heteroatom classes"
558
+ dict_res = {}
559
+
560
+ def nominal_mass_by_ion_type(formula_obj):
561
+ if ion_type == Labels.protonated_de_ion:
562
+ return int(formula_obj._protonated_mz(ion_charge))
563
+
564
+ elif ion_type == Labels.radical_ion:
565
+ return int(formula_obj._radical_mz(ion_charge))
566
+
567
+ elif ion_type == Labels.adduct_ion and adduct_atom:
568
+ return int(formula_obj._adduct_mz(ion_charge, adduct_atom))
569
+ for formula_obj, ch_obj, classe_obj in tqdm.tqdm(formulas, desc="Loading molecular formula database", disable = not verbose):
570
+ nominal_mz = nominal_mass_by_ion_type(formula_obj)
571
+
572
+ if self.type != "normal":
573
+ if not nominal_mz in nominal_mzs:
574
+ continue
575
+ classe = classe_obj.name
576
+
577
+ # classe_str = formula.classe_string
578
+
579
+ # pbar.set_description_str(desc="Loading molecular formula database for class %s " % classe_str)
580
+
581
+ formula_dict = formula_obj.to_dict()
582
+
583
+ if formula_dict.get("O"):
584
+ if (
585
+ formula_dict.get("O") / formula_dict.get("C")
586
+ >= molecular_search_settings.max_oc_filter
587
+ ):
588
+ # print(formula_dict.get("O") / formula_dict.get("C"), molecular_search_settings.max_oc_filter)
589
+ continue
590
+ elif (
591
+ formula_dict.get("O") / formula_dict.get("C")
592
+ <= molecular_search_settings.min_oc_filter
593
+ ):
594
+ # print(formula_dict.get("O") / formula_dict.get("C"), molecular_search_settings.min_oc_filter)
595
+ continue
596
+ # if formula_dict.get("P"):
597
+
598
+ # if not (formula_dict.get("O") -2)/ formula_dict.get("P") >= molecular_search_settings.min_op_filter:
599
+
600
+ # continue
601
+
602
+ if classe in dict_res.keys():
603
+ if nominal_mz in dict_res[classe].keys():
604
+ dict_res.get(classe).get(nominal_mz).append(formula_obj)
605
+
606
+ else:
607
+ dict_res.get(classe)[nominal_mz] = [formula_obj]
608
+
609
+ else:
610
+ dict_res[classe] = {nominal_mz: [formula_obj]}
611
+
612
+ return dict_res
613
+
614
+ len_adducts = 0
615
+ if ion_type == Labels.adduct_ion:
616
+ len_adducts = 1
617
+
618
+ query = query_normal(classes, len_adducts)
619
+
620
+ if ion_type == Labels.protonated_de_ion:
621
+ if self.type == "normal":
622
+ query = query.filter(
623
+ func.floor(MolecularFormulaLink._protonated_mz(ion_charge)).in_(
624
+ nominal_mzs
625
+ )
626
+ )
627
+
628
+ return add_dict_formula(query, ion_type, ion_charge)
629
+
630
+ if ion_type == Labels.radical_ion:
631
+ if self.type == "normal":
632
+ query = query.filter(
633
+ func.floor(MolecularFormulaLink._radical_mz(ion_charge)).in_(
634
+ nominal_mzs
635
+ )
636
+ )
637
+ return add_dict_formula(query, ion_type, ion_charge)
638
+
639
+ if ion_type == Labels.adduct_ion:
640
+ dict_res = {}
641
+ if adducts:
642
+ for atom in adducts:
643
+ if self.type == "normal":
644
+ query = query.filter(
645
+ func.floor(
646
+ MolecularFormulaLink._adduct_mz(ion_charge, atom)
647
+ ).in_(nominal_mzs)
648
+ )
649
+ dict_res[atom] = add_dict_formula(
650
+ query, ion_type, ion_charge, adduct_atom=atom
651
+ )
652
+ return dict_res
653
+ # dump all objs to memory
654
+ self.session.expunge_all()
655
+
656
+ def check_entry(self, classe, ion_type, molecular_search_settings):
657
+ """Checks if a molecular formula is in the database.
658
+
659
+ Parameters
660
+ ----------
661
+ classe : str
662
+ The class of the molecular formula.
663
+ ion_type : str
664
+ The ion type.
665
+ molecular_search_settings : MolecularFormulaSearchSettings
666
+ The molecular formula search settings.
667
+
668
+ Returns
669
+ -------
670
+ sqlalchemy.orm.query.Query
671
+ The query.
672
+ """
673
+ # get all classes, ion_type, ion charge as str add to a dict or list
674
+ # then check if class in database
675
+ has_class = self.session.query(
676
+ exists().where((MolecularFormulaLink.classe == classe))
677
+ )
678
+
679
+ return has_class
680
+
681
+ def get_all_classes(self):
682
+ """Returns a list of all classes in the database."""
683
+ query = self.session.query(
684
+ MolecularFormulaLink.classe.distinct().label("classe")
685
+ )
686
+
687
+ return query.all()
688
+
689
+ def get_all(
690
+ self,
691
+ ):
692
+ """Returns a list of all molecular formulas in the database."""
693
+ mol_formulas = self.session.query(MolecularFormulaLink).all()
694
+
695
+ return mol_formulas
696
+
697
+ def delete_entry(self, row):
698
+ """Deletes a molecular formula from the database."""
699
+ try:
700
+ self.session.delete(row)
701
+ self.session.commit()
702
+
703
+ except SQLAlchemyError as e:
704
+ self.session.rollback()
705
+ print(str(e))
706
+
707
+ def purge(self, cls):
708
+ """Deletes all molecular formulas from the database.
709
+
710
+ Notes
711
+ -------
712
+ Careful, this will delete the entire database table
713
+
714
+ """
715
+ self.session.query(cls).delete()
716
+ self.session.commit()
717
+
718
+ def clear_data(self):
719
+ """Clears the database."""
720
+ meta = Base.metadata
721
+ for table in reversed(meta.sorted_tables):
722
+ print("Clear table %s" % table)
723
+ self.session.execute(table.delete())
724
+ self.session.commit()
725
+
726
+ def close(self, commit=True):
727
+ """Closes the database.
728
+
729
+ Parameters
730
+ ----------
731
+ commit : bool, optional
732
+ Whether to commit the session. Default is True.
733
+ """
734
+ # make sure the dbconnection gets closed
735
+
736
+ if commit:
737
+ self.commit()
738
+ self.session.close()
739
+ self.engine.dispose()
740
+
741
+ def add_engine_pidguard(self, engine):
742
+ """Adds multiprocessing guards.
743
+
744
+ Forces a connection to be reconnected if it is detected
745
+ as having been shared to a sub-process.
746
+
747
+ Parameters
748
+ ----------
749
+ engine : sqlalchemy.engine.base.Engine
750
+ The SQLAlchemy engine.
751
+
752
+ """
753
+ import os
754
+ import warnings
755
+
756
+ @event.listens_for(engine, "connect")
757
+ def connect(dbapi_connection, connection_record):
758
+ """Forces a connection to be reconnected if it is detected
759
+
760
+ Parameters
761
+ ----------
762
+ dbapi_connection : sqlalchemy.engine.base.Engine
763
+ The SQLAlchemy engine.
764
+ connection_record : sqlalchemy.engine.base.Engine
765
+ The SQLAlchemy engine.
766
+ """
767
+ connection_record.info["pid"] = os.getpid()
768
+
769
+ @event.listens_for(engine, "checkout")
770
+ def checkout(dbapi_connection, connection_record, connection_proxy):
771
+ """Forces a connection to be reconnected if it is detected
772
+
773
+ Parameters
774
+ ----------
775
+ dbapi_connection : sqlalchemy.engine.base.Engine
776
+ The SQLAlchemy engine.
777
+ connection_record : sqlalchemy.engine.base.Engine
778
+ The SQLAlchemy engine.
779
+ connection_proxy : sqlalchemy.engine.base.Engine
780
+ The SQLAlchemy engine.
781
+
782
+ Raises
783
+ ------
784
+ exc.DisconnectionError
785
+ If the connection record belongs to a different process.
786
+
787
+ """
788
+ pid = os.getpid()
789
+ if connection_record.info["pid"] != pid:
790
+ # substitute log.debug() or similar here as desired
791
+ warnings.warn(
792
+ "Parent process %(orig)s forked (%(newproc)s) with an open "
793
+ "database connection, "
794
+ "which is being discarded and recreated."
795
+ % {"newproc": pid, "orig": connection_record.info["pid"]}
796
+ )
797
+ connection_record.connection = connection_proxy.connection = None
798
+ raise exc.DisconnectionError(
799
+ "Connection record belongs to pid %s, "
800
+ "attempting to check out in pid %s"
801
+ % (connection_record.info["pid"], pid)
802
+ )
803
+
804
+
805
+ if __name__ == "__main__":
806
+ sql = MolForm_SQL(url="sqlite:///")
807
+
808
+ dict_data = {"name": '{"O": 12}'}
809
+ dict_data2 = {"name": '{"O": 13}'}
810
+ hetero_obj = HeteroAtoms(**dict_data)
811
+ hetero_obj2 = HeteroAtoms(**dict_data2)
812
+ sql.session.add(hetero_obj)
813
+ sql.session.add(hetero_obj2)
814
+
815
+ print(sql.session.query(HeteroAtoms).all())
816
+ # molecular_search_settings = MolecularFormulaSearchSettings()
817
+ # sql = MolForm_SQL()
818
+ # query = sql.session.query(MolecularFormulaLink).filter_by(classe = '{"O": 12}').filter(MolecularFormulaLink._adduct_mz(+2, "Na") < 250)
819
+ # query = sql.get_by_classe('{"O": 12}', molecular_search_settings).filter(MolecularFormulaLink._adduct_mz(+2, "Na") < 250)
820
+ # classes = ['{"O": 12}']*1
821
+ # for i, classe in enumerate(classes):
822
+ # query = sql.get_by_classe(classe, molecular_search_settings)
823
+ # query = sql.session.query(MolecularFormulaLink).filter_by(classe = '{"O": 12}').filter(MolecularFormulaLink._adduct_mz(+2, "Na") < 250)
824
+ # for i in query.filter(MolecularFormulaLink.mass < 250):
825
+
826
+ # print(i._radical_mz(-1), i._protonated_mz(-1), i._adduct_mz(+2, "Na"), i.mass, i.to_dict(), i.formula_string)
827
+ #